Remove legacy configuration files and scripts, transitioning to Vite for build and development processes. Introduce new HTML files for the landing and terms pages, along with stubs for API responses. Update package.json and package-lock.json to include Vite and related dependencies, enhancing the project structure and build efficiency.
This commit is contained in:
parent
ebf0daacce
commit
7907238c1a
@ -1,7 +0,0 @@
|
|||||||
# Ignore artifacts:
|
|
||||||
build
|
|
||||||
dist
|
|
||||||
coverage
|
|
||||||
stubs
|
|
||||||
logs
|
|
||||||
d-scripts
|
|
||||||
@ -1,7 +0,0 @@
|
|||||||
{
|
|
||||||
"tabWidth": 2,
|
|
||||||
"semi": true,
|
|
||||||
"jsxBracketSameLine": true,
|
|
||||||
"arrowParens": "avoid",
|
|
||||||
"singleQuote": true
|
|
||||||
}
|
|
||||||
10
@types/emotion.d.ts
vendored
10
@types/emotion.d.ts
vendored
@ -1,10 +0,0 @@
|
|||||||
import '@emotion/react';
|
|
||||||
|
|
||||||
import { lightTheme } from '../src/app.theme';
|
|
||||||
|
|
||||||
declare module '@emotion/react' {
|
|
||||||
export interface Theme {
|
|
||||||
colors: typeof lightTheme.colors,
|
|
||||||
shadows: typeof lightTheme.shadows
|
|
||||||
}
|
|
||||||
}
|
|
||||||
19
@types/index.d.ts
vendored
19
@types/index.d.ts
vendored
@ -1,19 +0,0 @@
|
|||||||
declare const IS_PROD: string;
|
|
||||||
|
|
||||||
declare module '*.svg' {
|
|
||||||
const value: string;
|
|
||||||
|
|
||||||
export default value;
|
|
||||||
}
|
|
||||||
|
|
||||||
declare module '*.jpg' {
|
|
||||||
const value: string;
|
|
||||||
|
|
||||||
export default value;
|
|
||||||
}
|
|
||||||
|
|
||||||
declare module '*.png' {
|
|
||||||
const value: string;
|
|
||||||
|
|
||||||
export default value;
|
|
||||||
}
|
|
||||||
31
Jenkinsfile
vendored
31
Jenkinsfile
vendored
@ -1,31 +0,0 @@
|
|||||||
pipeline {
|
|
||||||
agent {
|
|
||||||
docker {
|
|
||||||
image 'node:20'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
stages {
|
|
||||||
stage('install') {
|
|
||||||
steps {
|
|
||||||
sh 'node -v'
|
|
||||||
sh 'npm -v'
|
|
||||||
sh 'npm ci'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
stage('eslint') {
|
|
||||||
steps {
|
|
||||||
sh 'npm run eslint'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
stage('clean-all') {
|
|
||||||
steps {
|
|
||||||
sh 'rm -rf .[!.]*'
|
|
||||||
sh 'rm -rf ./*'
|
|
||||||
sh 'ls -a'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
82
VITE_BUILD_GUIDE.md
Normal file
82
VITE_BUILD_GUIDE.md
Normal file
@ -0,0 +1,82 @@
|
|||||||
|
# 🚀 Production сборка с Vite
|
||||||
|
|
||||||
|
## ✅ Как работает
|
||||||
|
|
||||||
|
### Встроенные переменные Vite
|
||||||
|
|
||||||
|
Vite автоматически определяет режим сборки:
|
||||||
|
- **Dev**: `mode = 'development'`
|
||||||
|
- **Production**: `mode = 'production'`
|
||||||
|
|
||||||
|
В `vite.config.ts`:
|
||||||
|
```typescript
|
||||||
|
export default defineConfig(({ mode }) => {
|
||||||
|
const isProd = mode === 'production';
|
||||||
|
|
||||||
|
return {
|
||||||
|
base: isProd
|
||||||
|
? 'https://static.brojs.ru/landing/main/' // Production CDN
|
||||||
|
: '/', // Dev локально
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
## 🌐 Команды
|
||||||
|
|
||||||
|
### Dev режим
|
||||||
|
```bash
|
||||||
|
npm start # mode = 'development'
|
||||||
|
npm run dev # mode = 'development'
|
||||||
|
```
|
||||||
|
- Base: `/`
|
||||||
|
- URL: `http://localhost:8099/`
|
||||||
|
- Ассеты: локальные пути
|
||||||
|
|
||||||
|
### Production сборка
|
||||||
|
```bash
|
||||||
|
npm run build # mode = 'production'
|
||||||
|
```
|
||||||
|
- Base: `https://static.brojs.ru/landing/main/`
|
||||||
|
- Все пути автоматически заменяются на CDN!
|
||||||
|
|
||||||
|
## 📦 Результат production сборки
|
||||||
|
|
||||||
|
### index.html (главная)
|
||||||
|
```html
|
||||||
|
<script src="https://static.brojs.ru/landing/main/main.[hash].js"></script>
|
||||||
|
```
|
||||||
|
|
||||||
|
### terms.html (Terms)
|
||||||
|
```html
|
||||||
|
<link rel="stylesheet" href="https://static.brojs.ru/landing/main/terms.[hash].css">
|
||||||
|
```
|
||||||
|
|
||||||
|
## 🎯 Кроссплатформенность
|
||||||
|
|
||||||
|
✅ **Windows**: работает
|
||||||
|
✅ **Linux**: работает
|
||||||
|
✅ **macOS**: работает
|
||||||
|
|
||||||
|
Vite использует встроенный параметр `mode`, который работает **везде без дополнительных пакетов**!
|
||||||
|
|
||||||
|
## 🔧 Альтернативный способ (если нужен кастомный env)
|
||||||
|
|
||||||
|
Если понадобится установить свои переменные:
|
||||||
|
|
||||||
|
### Установи cross-env
|
||||||
|
```bash
|
||||||
|
npm install --save-dev cross-env
|
||||||
|
```
|
||||||
|
|
||||||
|
### Обнови package.json
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"scripts": {
|
||||||
|
"build": "cross-env NODE_ENV=production vite build"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Но это **не нужно** для нашего случая! Vite сам всё делает правильно! ✨
|
||||||
|
|
||||||
@ -1,6 +0,0 @@
|
|||||||
module.exports = {
|
|
||||||
presets: [
|
|
||||||
['@babel/preset-env', { targets: { node: 'current' } }],
|
|
||||||
'@babel/preset-typescript',
|
|
||||||
],
|
|
||||||
};
|
|
||||||
@ -1,2 +0,0 @@
|
|||||||
sh stop.sh;
|
|
||||||
sh up-nginx.sh;
|
|
||||||
@ -1 +0,0 @@
|
|||||||
docker stop adminka_nginx2;
|
|
||||||
@ -1 +0,0 @@
|
|||||||
docker run --name adminka_nginx2 -v $PWD/nginx.conf:/etc/nginx/nginx.conf:ro -v $PWD/dist:/usr/share/nginx/html --rm -d -p 3072:80 nginx;
|
|
||||||
@ -1,13 +0,0 @@
|
|||||||
import globals from "globals";
|
|
||||||
import pluginJs from "@eslint/js";
|
|
||||||
import tseslint from "typescript-eslint";
|
|
||||||
import pluginReact from "eslint-plugin-react";
|
|
||||||
|
|
||||||
|
|
||||||
export default [
|
|
||||||
{files: ["**/*.{js,mjs,cjs,ts,jsx,tsx}"]},
|
|
||||||
{languageOptions: { globals: globals.browser }},
|
|
||||||
pluginJs.configs.recommended,
|
|
||||||
...tseslint.configs.recommended,
|
|
||||||
pluginReact.configs.flat.recommended,
|
|
||||||
];
|
|
||||||
@ -1,88 +0,0 @@
|
|||||||
/* eslint-disable @typescript-eslint/no-require-imports */
|
|
||||||
/* eslint-disable no-undef */
|
|
||||||
const path = require('path');
|
|
||||||
const pkg = require('./package');
|
|
||||||
const HtmlWebpackPlugin = require('html-webpack-plugin');
|
|
||||||
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
|
|
||||||
const webpack = require('webpack');
|
|
||||||
|
|
||||||
const isProd = process.env.NODE_ENV === 'production';
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
apiPath: 'stubs/api',
|
|
||||||
apps: {
|
|
||||||
main: {
|
|
||||||
version: 'master',
|
|
||||||
name: 'cleanName',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
webpackConfig: {
|
|
||||||
entry: {
|
|
||||||
index: './src/index.tsx',
|
|
||||||
terms: './src/terms.js', // Entry для стилей terms
|
|
||||||
},
|
|
||||||
output: {
|
|
||||||
publicPath: isProd
|
|
||||||
? 'https://static.brojs.ru/landing/main/'
|
|
||||||
: `/static/${pkg.name}/${process.env.VERSION || pkg.version}/`,
|
|
||||||
filename: '[name].js?[contenthash]',
|
|
||||||
},
|
|
||||||
module: {
|
|
||||||
rules: [
|
|
||||||
{
|
|
||||||
test: /\.module\.scss$/,
|
|
||||||
use: [
|
|
||||||
isProd ? MiniCssExtractPlugin.loader : 'style-loader',
|
|
||||||
{
|
|
||||||
loader: 'css-loader',
|
|
||||||
options: {
|
|
||||||
modules: {
|
|
||||||
localIdentName: isProd ? '[hash:base64:8]' : '[name]__[local]--[hash:base64:5]',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
'sass-loader'
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
test: /\.scss$/,
|
|
||||||
exclude: /\.module\.scss$/,
|
|
||||||
use: [
|
|
||||||
isProd ? MiniCssExtractPlugin.loader : 'style-loader',
|
|
||||||
'css-loader',
|
|
||||||
'sass-loader'
|
|
||||||
],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
plugins: [
|
|
||||||
// Главная страница (с React)
|
|
||||||
new HtmlWebpackPlugin({
|
|
||||||
template: './src/index.ejs',
|
|
||||||
filename: 'index.html',
|
|
||||||
chunks: ['index'],
|
|
||||||
}),
|
|
||||||
// Terms страница (статика + SCSS)
|
|
||||||
new HtmlWebpackPlugin({
|
|
||||||
template: './src/terms.html',
|
|
||||||
filename: 'terms.html',
|
|
||||||
chunks: isProd ? [] : ['terms'], // В production не нужен JS
|
|
||||||
cssPath: isProd
|
|
||||||
? 'https://static.brojs.ru/landing/main/terms.css'
|
|
||||||
: `/static/${pkg.name}/${process.env.VERSION || pkg.version}/terms.css`,
|
|
||||||
}),
|
|
||||||
// Извлечение CSS в отдельные файлы для production
|
|
||||||
...(isProd ? [
|
|
||||||
new MiniCssExtractPlugin({
|
|
||||||
filename: '[name].css',
|
|
||||||
})
|
|
||||||
] : []),
|
|
||||||
new webpack.DefinePlugin({
|
|
||||||
IS_PROD: process.env.NODE_ENV === 'production',
|
|
||||||
}),
|
|
||||||
],
|
|
||||||
},
|
|
||||||
navigations: {},
|
|
||||||
features: {},
|
|
||||||
config: {},
|
|
||||||
};
|
|
||||||
@ -3,17 +3,23 @@
|
|||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||||
<meta charset="UTF-8">
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
<meta http-equiv="X-UA-Compatible" content="ie=edge">
|
|
||||||
<link href="https://fonts.googleapis.com/css?family=Montserrat:400,600,700,900&subset=cyrillic,cyrillic-ext" rel="stylesheet" />
|
<link href="https://fonts.googleapis.com/css?family=Montserrat:400,600,700,900&subset=cyrillic,cyrillic-ext" rel="stylesheet" />
|
||||||
<title>bro-js admin</title>
|
<title>BROJS.RU - Платформа обучения фронтенд-разработке</title>
|
||||||
<style>body {margin: 0; padding: 0;}</style>
|
|
||||||
<meta name="yandex-verification" content="98f7e15d1ad66018" />
|
<meta name="yandex-verification" content="98f7e15d1ad66018" />
|
||||||
|
<style>
|
||||||
|
body {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<noscript><div><img src="https://mc.yandex.ru/watch/87860751" style="position:absolute; left:-9999px;" alt="" /></div></noscript>
|
<noscript>
|
||||||
|
<div><img src="https://mc.yandex.ru/watch/87860751" style="position:absolute; left:-9999px;" alt="" /></div>
|
||||||
|
</noscript>
|
||||||
<div id="app"></div>
|
<div id="app"></div>
|
||||||
<script src="https://static.brojs.ru/fire.app/1.8.4/index.js"></script>
|
<script type="module" src="/src/index.tsx"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
||||||
@ -1,9 +0,0 @@
|
|||||||
module.exports = {
|
|
||||||
clearMocks: true,
|
|
||||||
collectCoverage: true,
|
|
||||||
collectCoverageFrom: ['./src/**/*.ts?(x)'],
|
|
||||||
coverageDirectory: 'coverage',
|
|
||||||
coverageProvider: 'v8',
|
|
||||||
preset: 'ts-jest',
|
|
||||||
testEnvironment: 'jsdom',
|
|
||||||
};
|
|
||||||
1122
package-lock.json
generated
1122
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
13
package.json
13
package.json
@ -11,9 +11,11 @@
|
|||||||
"eslint": "npx eslint src",
|
"eslint": "npx eslint src",
|
||||||
"prettier": "prettier --write .",
|
"prettier": "prettier --write .",
|
||||||
"test": "jest --coverage",
|
"test": "jest --coverage",
|
||||||
"start": "brojs server --port=8099 --with-open-browser",
|
"dev": "vite",
|
||||||
"build": "npm run clean && brojs build --dev",
|
"start": "vite",
|
||||||
"build:prod": "npm run clean && brojs build"
|
"build": "vite build",
|
||||||
|
"build:prod": "vite build --mode production",
|
||||||
|
"preview": "vite preview"
|
||||||
},
|
},
|
||||||
"keywords": [],
|
"keywords": [],
|
||||||
"author": "",
|
"author": "",
|
||||||
@ -41,6 +43,7 @@
|
|||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@eslint/js": "^9.9.0",
|
"@eslint/js": "^9.9.0",
|
||||||
"@types/jest": "^29.5.12",
|
"@types/jest": "^29.5.12",
|
||||||
|
"@vitejs/plugin-react": "^5.1.0",
|
||||||
"babel-jest": "^29.7.0",
|
"babel-jest": "^29.7.0",
|
||||||
"css-loader": "^7.1.2",
|
"css-loader": "^7.1.2",
|
||||||
"eslint": "^8.57.0",
|
"eslint": "^8.57.0",
|
||||||
@ -55,6 +58,8 @@
|
|||||||
"sass-loader": "^16.0.6",
|
"sass-loader": "^16.0.6",
|
||||||
"style-loader": "^4.0.0",
|
"style-loader": "^4.0.0",
|
||||||
"ts-jest": "^29.2.3",
|
"ts-jest": "^29.2.3",
|
||||||
"typescript-eslint": "^8.1.0"
|
"typescript-eslint": "^8.1.0",
|
||||||
|
"vite": "^7.1.12",
|
||||||
|
"vite-plugin-sass": "^0.1.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
118
readme.md
118
readme.md
@ -2,14 +2,15 @@
|
|||||||
|
|
||||||
Лендинг платформы для обучения фронтенд-разработке
|
Лендинг платформы для обучения фронтенд-разработке
|
||||||
|
|
||||||
## 🚀 Особенности v3.0
|
## 🚀 Особенности v3.0 (Vite)
|
||||||
|
|
||||||
- ⚡ **Минимальные зависимости** - только необходимое
|
- ⚡ **Vite** - мгновенный запуск (vs 3+ сек у webpack)
|
||||||
- 📄 **Статический HTML** для идеального SEO
|
- 📄 **Статический HTML** для идеального SEO
|
||||||
- 🎨 **SCSS + CSS Modules** для гибких стилей
|
- 🎨 **SCSS + CSS Modules** для гибких стилей
|
||||||
- 📱 **Адаптивный дизайн** с responsive шрифтами
|
- 📱 **Адаптивный дизайн** с responsive шрифтами
|
||||||
- 🎯 **React** только там, где нужна динамика
|
- 🎯 **React** только для главной страницы
|
||||||
- 🔥 **Легкий bundle** terms.html (10 KB + 1.5 KB CSS, **без JS!**)
|
- 🔌 **Express stubs** из `./stubs/api` работают как раньше!
|
||||||
|
- 🗜️ **Легкий bundle** terms.html (13 KB + 1.5 KB CSS, **без JS!**)
|
||||||
|
|
||||||
## 📦 Установка
|
## 📦 Установка
|
||||||
|
|
||||||
@ -26,7 +27,8 @@ npm start # Dev сервер на http://localhost:8099
|
|||||||
## 🏗️ Сборка
|
## 🏗️ Сборка
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
npm run build:prod # Production сборка в ./dist
|
npm run build # Production сборка в ./dist
|
||||||
|
npm run preview # Просмотр production сборки
|
||||||
```
|
```
|
||||||
|
|
||||||
## 📄 Страницы
|
## 📄 Страницы
|
||||||
@ -34,20 +36,46 @@ npm run build:prod # Production сборка в ./dist
|
|||||||
### Главная `/`
|
### Главная `/`
|
||||||
- **React** приложение с анимацией Lottie
|
- **React** приложение с анимацией Lottie
|
||||||
- Динамическая страница "В разработке"
|
- Динамическая страница "В разработке"
|
||||||
- Файлы: `index.html` + `index.js` (916 KB) + `index.css` (190 B)
|
- Dev: `http://localhost:8099/`
|
||||||
|
- Prod: `brojs.ru/` → загружает JS с `https://static.brojs.ru/landing/main/`
|
||||||
|
|
||||||
### Terms `/terms`
|
### Terms `/terms`
|
||||||
|
- `/terms` → автоматический редирект на `/terms.html`
|
||||||
- **Чистый HTML** без JavaScript
|
- **Чистый HTML** без JavaScript
|
||||||
- Полный текст пользовательского соглашения
|
- Полный текст пользовательского соглашения
|
||||||
- SEO-оптимизирован
|
- SEO-оптимизирован
|
||||||
- Адаптивный дизайн
|
- Адаптивный дизайн
|
||||||
- Файлы: `terms.html` (10.5 KB) + `terms.css` (1.5 KB)
|
- Dev: `http://localhost:8099/terms`
|
||||||
|
- Prod: `brojs.ru/terms` → загружает CSS с `https://static.brojs.ru/landing/main/`
|
||||||
|
|
||||||
|
## 🔌 API Stubs
|
||||||
|
|
||||||
|
Создавай заглушки API в `./stubs/api/`:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
// stubs/api/test.js → /api/test
|
||||||
|
module.exports = (req, res) => {
|
||||||
|
res.json({ message: 'Hello from stub!' });
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
// stubs/api/user.js → /api/user
|
||||||
|
module.exports.default = {
|
||||||
|
id: 1,
|
||||||
|
name: 'John Doe'
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
Примеры:
|
||||||
|
- `http://localhost:8099/api/test`
|
||||||
|
- `http://localhost:8099/api/user`
|
||||||
|
|
||||||
## 🎨 Стилизация
|
## 🎨 Стилизация
|
||||||
|
|
||||||
### CSS Modules (для React компонентов)
|
### CSS Modules (для React компонентов)
|
||||||
```typescript
|
```typescript
|
||||||
import * as styles from './styles/main.module.scss';
|
import styles from './styles/main.module.scss';
|
||||||
element.className = styles.app;
|
element.className = styles.app;
|
||||||
```
|
```
|
||||||
|
|
||||||
@ -71,7 +99,7 @@ h1 {
|
|||||||
|
|
||||||
## 📱 Адаптивность
|
## 📱 Адаптивность
|
||||||
|
|
||||||
Все размеры шрифтов автоматически уменьшаются на мобильных устройствах (< 768px):
|
Все размеры шрифтов автоматически уменьшаются на мобильных (< 768px):
|
||||||
- H1: 2.5rem → 1.75rem
|
- H1: 2.5rem → 1.75rem
|
||||||
- H2: 1.75rem → 1.5rem
|
- H2: 1.75rem → 1.5rem
|
||||||
- H3: 1.25rem → 1.1rem
|
- H3: 1.25rem → 1.1rem
|
||||||
@ -80,50 +108,78 @@ h1 {
|
|||||||
## 🗂️ Структура
|
## 🗂️ Структура
|
||||||
|
|
||||||
```
|
```
|
||||||
src/
|
bro.landing/
|
||||||
├── styles/
|
├── index.html # Entry для главной
|
||||||
|
├── terms.html # Entry для Terms (статика)
|
||||||
|
├── vite.config.ts # Конфигурация Vite
|
||||||
|
├── src/
|
||||||
|
│ ├── index.tsx # React entry
|
||||||
|
│ ├── app.tsx # React App
|
||||||
|
│ ├── dashboard.tsx # Роутинг
|
||||||
|
│ ├── pages/
|
||||||
|
│ │ └── under-construction/
|
||||||
|
│ └── styles/
|
||||||
│ ├── main.module.scss # CSS Modules для React
|
│ ├── main.module.scss # CSS Modules для React
|
||||||
│ ├── main.module.scss.d.ts # TypeScript типы
|
│ └── terms.scss # SCSS для Terms
|
||||||
│ └── terms.scss # SCSS для статики
|
├── stubs/
|
||||||
├── pages/
|
│ └── api/
|
||||||
│ └── under-construction/ # Главная страница
|
│ ├── test.js # Пример: GET /api/test
|
||||||
├── index.tsx # Entry для React
|
│ └── user.js # Пример: GET /api/user
|
||||||
├── terms.js # Entry для CSS
|
└── dist/ # Build output
|
||||||
├── terms.html # Статический HTML
|
├── index.html # Главная
|
||||||
└── index.ejs # Шаблон для React
|
├── main.[hash].js # React bundle
|
||||||
|
├── terms.html # Terms статика
|
||||||
|
└── terms.[hash].css # Terms стили
|
||||||
```
|
```
|
||||||
|
|
||||||
## 🌐 Деплой
|
## 🌐 Деплой
|
||||||
|
|
||||||
После `npm run build:prod`:
|
### Production URLs
|
||||||
- `index.html` → `brojs.ru/`
|
После `npm run build` и деплоя:
|
||||||
- `terms.html` → `brojs.ru/terms`
|
- **Главная**: `brojs.ru/` → `dist/index.html`
|
||||||
- Статика → `static.brojs.ru/landing/main/`
|
- JS: `https://static.brojs.ru/landing/main/main.[hash].js`
|
||||||
|
- **Terms**: `brojs.ru/terms` → `dist/terms.html`
|
||||||
|
- CSS: `https://static.brojs.ru/landing/main/terms.[hash].css`
|
||||||
|
|
||||||
|
### Vite автоматически подставляет CDN пути
|
||||||
|
В `vite.config.ts`:
|
||||||
|
```typescript
|
||||||
|
base: isProd
|
||||||
|
? 'https://static.brojs.ru/landing/main/' // Production
|
||||||
|
: '/' // Dev
|
||||||
|
```
|
||||||
|
|
||||||
|
Vite **автоматически** заменит все пути к ассетам на CDN URL в production!
|
||||||
|
|
||||||
## 🔧 Технологии
|
## 🔧 Технологии
|
||||||
|
|
||||||
### Core
|
### Core
|
||||||
|
- **Vite 7** - молниеносная сборка
|
||||||
- **React 18** - только для динамических частей
|
- **React 18** - только для динамических частей
|
||||||
- **TypeScript** - типизация
|
- **TypeScript** - типизация
|
||||||
- **Webpack 5** - сборка с multiple entry points
|
|
||||||
- **SCSS** - препроцессор
|
- **SCSS** - препроцессор
|
||||||
- **CSS Modules** - изоляция стилей
|
- **CSS Modules** - изоляция стилей
|
||||||
|
|
||||||
### Библиотеки
|
### Библиотеки
|
||||||
- **React Router DOM** - клиентский роутинг
|
- **React Router DOM** - клиентский роутинг
|
||||||
- **i18next** - интернационализация
|
|
||||||
- **Lottie React** - анимации
|
- **Lottie React** - анимации
|
||||||
|
|
||||||
### Dev зависимости
|
### Dev зависимости
|
||||||
- **sass** + **sass-loader** - компиляция SCSS
|
- **@vitejs/plugin-react** - React Fast Refresh
|
||||||
- **css-loader** - обработка CSS (с поддержкой CSS Modules)
|
- **sass** - компиляция SCSS
|
||||||
- **style-loader** - инжект CSS в dev режиме
|
|
||||||
- **mini-css-extract-plugin** - извлечение CSS в production
|
## ⚡ Почему Vite?
|
||||||
|
|
||||||
|
- 🚀 **Мгновенный запуск** (HMR из коробки)
|
||||||
|
- ⚡ **Быстрая сборка** (esbuild + Rollup)
|
||||||
|
- 🎯 **Простая конфигурация** (70 строк vs 500+)
|
||||||
|
- 📦 **Меньше зависимостей**
|
||||||
|
- 🔥 **Современный стандарт**
|
||||||
|
|
||||||
## 📚 Документация
|
## 📚 Документация
|
||||||
|
|
||||||
Полная документация в [cloud.md](./cloud.md)
|
Полная документация в [cloud.md](./cloud.md)
|
||||||
|
|
||||||
## 🤝 Участие
|
---
|
||||||
|
|
||||||
Проект использует минималистичный подход - добавляем зависимости только по мере необходимости!
|
**Простота + Скорость + Мощь!** 🎉
|
||||||
|
|||||||
@ -1,12 +1,22 @@
|
|||||||
import React from 'react';
|
import React, { useEffect } from 'react';
|
||||||
import { Routes, Route } from 'react-router-dom';
|
import { Routes, Route } from 'react-router-dom';
|
||||||
|
|
||||||
import { UnderConstructionPage } from './pages';
|
import { UnderConstructionPage } from './pages';
|
||||||
|
|
||||||
|
// Компонент для редиректа на terms.html
|
||||||
|
const TermsRedirect = () => {
|
||||||
|
useEffect(() => {
|
||||||
|
window.location.href = '/terms.html';
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
return <div>Загрузка Terms...</div>;
|
||||||
|
};
|
||||||
|
|
||||||
export const Dashboard = () => {
|
export const Dashboard = () => {
|
||||||
return (
|
return (
|
||||||
<Routes>
|
<Routes>
|
||||||
<Route path="/" element={<UnderConstructionPage />} />
|
<Route path="/" element={<UnderConstructionPage />} />
|
||||||
|
<Route path="/terms" element={<TermsRedirect />} />
|
||||||
<Route path="*" element={<UnderConstructionPage />} />
|
<Route path="*" element={<UnderConstructionPage />} />
|
||||||
</Routes>
|
</Routes>
|
||||||
);
|
);
|
||||||
|
|||||||
@ -1,40 +1,11 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import i18next from 'i18next';
|
import { createRoot } from 'react-dom/client';
|
||||||
import { i18nextReactInitConfig } from '@brojs/cli';
|
|
||||||
import { createRoot, hydrateRoot } from 'react-dom/client'
|
|
||||||
|
|
||||||
import App from './app';
|
import App from './app';
|
||||||
import * as styles from './styles/main.module.scss';
|
import './styles/main.module.scss';
|
||||||
|
|
||||||
i18next.t = i18next.t.bind(i18next);
|
|
||||||
const i18nextPromise = i18nextReactInitConfig(i18next);
|
|
||||||
const MOUNT_NODE = document.getElementById('app');
|
const MOUNT_NODE = document.getElementById('app');
|
||||||
|
|
||||||
// Применяем класс к app контейнеру
|
|
||||||
if (MOUNT_NODE) {
|
if (MOUNT_NODE) {
|
||||||
MOUNT_NODE.className = styles.app || 'app';
|
const root = createRoot(MOUNT_NODE);
|
||||||
|
root.render(<App />);
|
||||||
}
|
}
|
||||||
|
|
||||||
(async () => {
|
|
||||||
await Promise.all([i18nextPromise]);
|
|
||||||
|
|
||||||
// Если страница была пре-рендерена, используем hydrate вместо render
|
|
||||||
const hasPrerenderedContent = MOUNT_NODE.hasChildNodes();
|
|
||||||
|
|
||||||
if (hasPrerenderedContent) {
|
|
||||||
hydrateRoot(MOUNT_NODE, <App />);
|
|
||||||
} else {
|
|
||||||
const rootElement = createRoot(MOUNT_NODE);
|
|
||||||
rootElement.render(<App />);
|
|
||||||
|
|
||||||
if (module.hot) {
|
|
||||||
module.hot.accept('./app', async () => {
|
|
||||||
await i18next.reloadResources();
|
|
||||||
rootElement.render(<App />);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})();
|
|
||||||
|
|
||||||
export const mount = () => console.log('mounted');
|
|
||||||
export const unmount = () => console.log('unmounted');
|
|
||||||
|
|||||||
@ -1,291 +0,0 @@
|
|||||||
import React from 'react';
|
|
||||||
import { Box, Container, Heading, Text, VStack, Divider, Link } from '@chakra-ui/react';
|
|
||||||
import { Helmet } from 'react-helmet';
|
|
||||||
|
|
||||||
export const Terms = () => {
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<Helmet>
|
|
||||||
<title>Пользовательское соглашение - BROJS.RU</title>
|
|
||||||
<meta name="description" content="Пользовательское соглашение для платформы обучения фронтенд-разработке BROJS.RU" />
|
|
||||||
</Helmet>
|
|
||||||
|
|
||||||
<Box bg="gray.50" minH="100vh" py={8}>
|
|
||||||
<Container maxW="4xl" bg="white" shadow="lg" borderRadius="md" p={{ base: 6, md: 10 }}>
|
|
||||||
<VStack spacing={6} align="stretch">
|
|
||||||
{/* Заголовок */}
|
|
||||||
<Box textAlign="center" mb={4}>
|
|
||||||
<Heading as="h1" size="2xl" mb={2} color="blue.600">
|
|
||||||
Пользовательское соглашение
|
|
||||||
</Heading>
|
|
||||||
<Text fontSize="sm" color="gray.600">
|
|
||||||
для BROJS.RU
|
|
||||||
</Text>
|
|
||||||
<Text fontSize="sm" color="gray.500" mt={2}>
|
|
||||||
Последнее обновление: 25 мая 2025 г.
|
|
||||||
</Text>
|
|
||||||
</Box>
|
|
||||||
|
|
||||||
<Divider />
|
|
||||||
|
|
||||||
{/* 1. Термины */}
|
|
||||||
<Box>
|
|
||||||
<Heading as="h2" size="lg" mb={3} color="gray.800">
|
|
||||||
1. Термины
|
|
||||||
</Heading>
|
|
||||||
<VStack spacing={2} align="stretch">
|
|
||||||
<Text><strong>Платформа</strong> — сайт <Link href="https://brojs.ru" color="blue.500" isExternal>https://brojs.ru</Link>, предоставляющий услуги обучения фронтенд-разработке.</Text>
|
|
||||||
<Text><strong>Пользователь</strong> — лицо, зарегистрированное на Платформе.</Text>
|
|
||||||
<Text><strong>Микрофронтенд-проект</strong> — код, конфигурации и иные материалы, созданные Пользователем.</Text>
|
|
||||||
<Text><strong>Gravatar</strong> — сторонний сервис (<Link href="https://gravatar.com" color="blue.500" isExternal>https://gravatar.com</Link>), предоставляющий аватары на основе email-адресов пользователей.</Text>
|
|
||||||
<Text><strong>Интеллектуальная собственность</strong> — результаты интеллектуальной деятельности, включая, но не ограничиваясь, программные коды, дизайны, тексты, графику и другие объекты, защищенные законом.</Text>
|
|
||||||
</VStack>
|
|
||||||
</Box>
|
|
||||||
|
|
||||||
{/* 2. Условия использования */}
|
|
||||||
<Box>
|
|
||||||
<Heading as="h2" size="lg" mb={3} color="gray.800">
|
|
||||||
2. Условия использования
|
|
||||||
</Heading>
|
|
||||||
|
|
||||||
<Heading as="h3" size="md" mb={2} color="gray.700">
|
|
||||||
2.1. Регистрация
|
|
||||||
</Heading>
|
|
||||||
<Text mb={2}>Регистрация осуществляется через:</Text>
|
|
||||||
<Box as="ul" pl={6} mb={3}>
|
|
||||||
<li>Аккаунт Yandex;</li>
|
|
||||||
<li>Email (с подтверждением через ссылку).</li>
|
|
||||||
</Box>
|
|
||||||
|
|
||||||
<Heading as="h3" size="md" mb={2} color="gray.700">
|
|
||||||
2.2. Обязанности Пользователя
|
|
||||||
</Heading>
|
|
||||||
<Text mb={2}>Пользователь обязуется:</Text>
|
|
||||||
<Box as="ul" pl={6}>
|
|
||||||
<li>Не передавать учетные данные третьим лицам;</li>
|
|
||||||
<li>Не использовать Платформу для распространения незаконного контента или совершения мошеннических действий;</li>
|
|
||||||
<li>Соблюдать конфиденциальность личных данных других участников Платформы.</li>
|
|
||||||
</Box>
|
|
||||||
</Box>
|
|
||||||
|
|
||||||
{/* 3. Персональные данные */}
|
|
||||||
<Box>
|
|
||||||
<Heading as="h2" size="lg" mb={3} color="gray.800">
|
|
||||||
3. Персональные данные
|
|
||||||
</Heading>
|
|
||||||
|
|
||||||
<Heading as="h3" size="md" mb={2} color="gray.700">
|
|
||||||
3.1. Собираемые данные
|
|
||||||
</Heading>
|
|
||||||
<Text mb={2}>Платформа собирает:</Text>
|
|
||||||
<Box as="ul" pl={6} mb={3}>
|
|
||||||
<li>Никнейм;</li>
|
|
||||||
<li>Email;</li>
|
|
||||||
<li>ФИО (при наличии договора с учебным заведением);</li>
|
|
||||||
<li>Данные о посещении занятий (через QR-код).</li>
|
|
||||||
</Box>
|
|
||||||
|
|
||||||
<Heading as="h3" size="md" mb={2} color="gray.700">
|
|
||||||
3.2. Аватар через Gravatar
|
|
||||||
</Heading>
|
|
||||||
<Box as="ul" pl={6} mb={3}>
|
|
||||||
<li>Платформа не хранит аватары на своих серверах. Для отображения используется Gravatar.</li>
|
|
||||||
<li>Ссылка на аватар формируется на основе хэша email пользователя.</li>
|
|
||||||
<li>Пользователь может активировать/отозвать согласие на использование Gravatar в настройках профиля.</li>
|
|
||||||
<li>Отказ от Gravatar приведет к отображению стандартного изображения.</li>
|
|
||||||
</Box>
|
|
||||||
|
|
||||||
<Heading as="h3" size="md" mb={2} color="gray.700">
|
|
||||||
3.3. Цели обработки данных
|
|
||||||
</Heading>
|
|
||||||
<Box as="ul" pl={6} mb={3}>
|
|
||||||
<li>Предоставление доступа к Платформе;</li>
|
|
||||||
<li>Передача данных о посещении учебным заведениям (ФИО, email, дата и время) в формате Excel.</li>
|
|
||||||
</Box>
|
|
||||||
|
|
||||||
<Heading as="h3" size="md" mb={2} color="gray.700">
|
|
||||||
3.4. Хранение и передача данных
|
|
||||||
</Heading>
|
|
||||||
<Box as="ul" pl={6} mb={3}>
|
|
||||||
<li>Персональные данные хранятся в СУБД PostgreSQL через Keycloak.</li>
|
|
||||||
<li>Данные о посещении передаются учебным заведениям на основании договоров с преподавателями.</li>
|
|
||||||
<li>Передача данных осуществляется с применением шифрования и протоколов безопасности.</li>
|
|
||||||
</Box>
|
|
||||||
|
|
||||||
<Heading as="h3" size="md" mb={2} color="gray.700">
|
|
||||||
3.5. Срок хранения
|
|
||||||
</Heading>
|
|
||||||
<Box as="ul" pl={6} mb={3}>
|
|
||||||
<li>Персональные данные удаляются в течение 30 дней после удаления аккаунта.</li>
|
|
||||||
<li>Микрофронтенд-проекты хранятся 6 месяцев после завершения обучения.</li>
|
|
||||||
</Box>
|
|
||||||
|
|
||||||
<Heading as="h3" size="md" mb={2} color="gray.700">
|
|
||||||
3.6. Отзыв согласия
|
|
||||||
</Heading>
|
|
||||||
<Box as="ul" pl={6}>
|
|
||||||
<li>Для отзыва согласия на обработку персональных данных необходимо направить письмо на <Link href="mailto:primakov.pro@yandex.ru" color="blue.500">primakov.pro@yandex.ru</Link>.</li>
|
|
||||||
<li>Отзыв приведет к удалению всех данных пользователя вручную.</li>
|
|
||||||
<li>Частичное удаление отдельных категорий данных возможно по заявлению пользователя.</li>
|
|
||||||
</Box>
|
|
||||||
</Box>
|
|
||||||
|
|
||||||
{/* 4. Интеллектуальная собственность */}
|
|
||||||
<Box>
|
|
||||||
<Heading as="h2" size="lg" mb={3} color="gray.800">
|
|
||||||
4. Интеллектуальная собственность
|
|
||||||
</Heading>
|
|
||||||
|
|
||||||
<Heading as="h3" size="md" mb={2} color="gray.700">
|
|
||||||
4.1. Права Пользователя
|
|
||||||
</Heading>
|
|
||||||
<Box as="ul" pl={6} mb={3}>
|
|
||||||
<li>Пользователь сохраняет авторские права на созданные проекты.</li>
|
|
||||||
<li>Платформа не имеет прав на использование материалов Пользователя без явного согласия.</li>
|
|
||||||
</Box>
|
|
||||||
|
|
||||||
<Heading as="h3" size="md" mb={2} color="gray.700">
|
|
||||||
4.2. Права Администрации
|
|
||||||
</Heading>
|
|
||||||
<Box as="ul" pl={6}>
|
|
||||||
<li>Администрация вправе удалить контент при нарушении условий соглашения или через 6 месяцев после завершения обучения.</li>
|
|
||||||
<li>Проверка подлинности загружаемого материала осуществляется преподавателем, отвечающим за группу.</li>
|
|
||||||
</Box>
|
|
||||||
</Box>
|
|
||||||
|
|
||||||
{/* 5. Ответственность */}
|
|
||||||
<Box>
|
|
||||||
<Heading as="h2" size="lg" mb={3} color="gray.800">
|
|
||||||
5. Ответственность
|
|
||||||
</Heading>
|
|
||||||
|
|
||||||
<Heading as="h3" size="md" mb={2} color="gray.700">
|
|
||||||
5.1. Ограничение ответственности
|
|
||||||
</Heading>
|
|
||||||
<Text mb={2}>Администрация не несет ответственности за:</Text>
|
|
||||||
<Box as="ul" pl={6} mb={3}>
|
|
||||||
<li>Утрату данных из-за действий Пользователя;</li>
|
|
||||||
<li>Использование данных учебными заведениями после их передачи;</li>
|
|
||||||
<li>Некорректное отображение аватаров через Gravatar.</li>
|
|
||||||
</Box>
|
|
||||||
|
|
||||||
<Heading as="h3" size="md" mb={2} color="gray.700">
|
|
||||||
5.2. Основания для блокировки аккаунта
|
|
||||||
</Heading>
|
|
||||||
<Box as="ul" pl={6} mb={3}>
|
|
||||||
<li>Нарушение авторских прав;</li>
|
|
||||||
<li>Распространение спама/вирусов;</li>
|
|
||||||
<li>Предоставление недостоверных данных (включая ФИО).</li>
|
|
||||||
</Box>
|
|
||||||
|
|
||||||
<Heading as="h3" size="md" mb={2} color="gray.700">
|
|
||||||
5.3. Компенсация ущерба
|
|
||||||
</Heading>
|
|
||||||
<Box as="ul" pl={6}>
|
|
||||||
<li>В случае нарушения правил или утечки данных, Администрация обязана принять меры для минимизации последствий.</li>
|
|
||||||
</Box>
|
|
||||||
</Box>
|
|
||||||
|
|
||||||
{/* 6. Уведомления */}
|
|
||||||
<Box>
|
|
||||||
<Heading as="h2" size="lg" mb={3} color="gray.800">
|
|
||||||
6. Уведомления
|
|
||||||
</Heading>
|
|
||||||
|
|
||||||
<Heading as="h3" size="md" mb={2} color="gray.700">
|
|
||||||
6.1. Информационные сообщения
|
|
||||||
</Heading>
|
|
||||||
<Text mb={2}>Платформа вправе отправлять Пользователю:</Text>
|
|
||||||
<Box as="ul" pl={6} mb={3}>
|
|
||||||
<li>Уведомления о технических работах, изменениях функционала;</li>
|
|
||||||
<li>Сообщения о нарушениях или блокировке аккаунта;</li>
|
|
||||||
<li>Рекламу собственных услуг или услуг третьих лиц.</li>
|
|
||||||
</Box>
|
|
||||||
|
|
||||||
<Heading as="h3" size="md" mb={2} color="gray.700">
|
|
||||||
6.2. Отказ от уведомлений
|
|
||||||
</Heading>
|
|
||||||
<Box as="ul" pl={6}>
|
|
||||||
<li>Отказ от рекламных сообщений возможен через настройки Личного кабинета.</li>
|
|
||||||
<li>Отказ от информационных уведомлений может ограничить доступ к функциям Платформы.</li>
|
|
||||||
</Box>
|
|
||||||
</Box>
|
|
||||||
|
|
||||||
{/* 7. Безопасность данных */}
|
|
||||||
<Box>
|
|
||||||
<Heading as="h2" size="lg" mb={3} color="gray.800">
|
|
||||||
7. Безопасность данных
|
|
||||||
</Heading>
|
|
||||||
|
|
||||||
<Heading as="h3" size="md" mb={2} color="gray.700">
|
|
||||||
7.1. Технические меры
|
|
||||||
</Heading>
|
|
||||||
<Box as="ul" pl={6} mb={3}>
|
|
||||||
<li>Данные хранятся в СУБД PostgreSQL через Keycloak.</li>
|
|
||||||
<li>Шифрование данных при передаче (HTTPS).</li>
|
|
||||||
<li>Периодические тестирования системы на уязвимости.</li>
|
|
||||||
</Box>
|
|
||||||
|
|
||||||
<Heading as="h3" size="md" mb={2} color="gray.700">
|
|
||||||
7.2. Двухфакторная аутентификация
|
|
||||||
</Heading>
|
|
||||||
<Box as="ul" pl={6}>
|
|
||||||
<li>Пользователи могут добровольно активировать двухфакторную аутентификацию (OTP) через Личный кабинет.</li>
|
|
||||||
</Box>
|
|
||||||
</Box>
|
|
||||||
|
|
||||||
{/* 8. Применимое право и разрешение споров */}
|
|
||||||
<Box>
|
|
||||||
<Heading as="h2" size="lg" mb={3} color="gray.800">
|
|
||||||
8. Применимое право и разрешение споров
|
|
||||||
</Heading>
|
|
||||||
|
|
||||||
<Heading as="h3" size="md" mb={2} color="gray.700">
|
|
||||||
8.1. Применимое право
|
|
||||||
</Heading>
|
|
||||||
<Box as="ul" pl={6} mb={3}>
|
|
||||||
<li>Соглашение регулируется законодательством РФ. Для пользователей из стран СНГ применяются нормы ЕАЭС.</li>
|
|
||||||
<li>При расширении географии услуг Платформа будет соблюдать законодательство стран ЕСВР и ЕС.</li>
|
|
||||||
</Box>
|
|
||||||
|
|
||||||
<Heading as="h3" size="md" mb={2} color="gray.700">
|
|
||||||
8.2. Разрешение споров
|
|
||||||
</Heading>
|
|
||||||
<Box as="ul" pl={6}>
|
|
||||||
<li>Споры разрешаются в суде по месту нахождения администрации Платформы.</li>
|
|
||||||
</Box>
|
|
||||||
</Box>
|
|
||||||
|
|
||||||
{/* 9. Изменения соглашения */}
|
|
||||||
<Box>
|
|
||||||
<Heading as="h2" size="lg" mb={3} color="gray.800">
|
|
||||||
9. Изменения соглашения
|
|
||||||
</Heading>
|
|
||||||
<Text>Изменения вступают в силу после публикации на сайте.</Text>
|
|
||||||
</Box>
|
|
||||||
|
|
||||||
{/* 10. Контакты */}
|
|
||||||
<Box>
|
|
||||||
<Heading as="h2" size="lg" mb={3} color="gray.800">
|
|
||||||
10. Контакты
|
|
||||||
</Heading>
|
|
||||||
<Text>
|
|
||||||
Для обращений: <Link href="mailto:primakov.pro@yandex.ru" color="blue.500">primakov.pro@yandex.ru</Link>
|
|
||||||
</Text>
|
|
||||||
</Box>
|
|
||||||
|
|
||||||
<Divider mt={6} />
|
|
||||||
|
|
||||||
{/* Footer */}
|
|
||||||
<Box textAlign="center" pt={4}>
|
|
||||||
<Text fontSize="sm" color="gray.500">
|
|
||||||
© 2025 BROJS.RU. Все права защищены.
|
|
||||||
</Text>
|
|
||||||
</Box>
|
|
||||||
</VStack>
|
|
||||||
</Container>
|
|
||||||
</Box>
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
@ -1,2 +0,0 @@
|
|||||||
export { Terms } from './Terms';
|
|
||||||
|
|
||||||
@ -1,3 +0,0 @@
|
|||||||
// Entry point for terms page styles
|
|
||||||
import './styles/terms.scss';
|
|
||||||
|
|
||||||
11
stubs/api/test.js
Normal file
11
stubs/api/test.js
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
// Пример stub файла для /api/test
|
||||||
|
module.exports = (req, res) => {
|
||||||
|
res.setHeader('Content-Type', 'application/json');
|
||||||
|
res.end(JSON.stringify({
|
||||||
|
message: 'Hello from stub!',
|
||||||
|
timestamp: new Date().toISOString(),
|
||||||
|
method: req.method,
|
||||||
|
url: req.url,
|
||||||
|
}));
|
||||||
|
};
|
||||||
|
|
||||||
8
stubs/api/user.js
Normal file
8
stubs/api/user.js
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
// Пример stub для /api/user
|
||||||
|
module.exports.default = {
|
||||||
|
id: 1,
|
||||||
|
name: 'Test User',
|
||||||
|
email: 'user@brojs.ru',
|
||||||
|
role: 'student'
|
||||||
|
};
|
||||||
|
|
||||||
@ -1,4 +1,4 @@
|
|||||||
<!DOCTYPE html>
|
<!doctype html>
|
||||||
<html lang="ru">
|
<html lang="ru">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
@ -8,7 +8,7 @@
|
|||||||
<meta name="description" content="Пользовательское соглашение для платформы обучения фронтенд-разработке BROJS.RU. Условия использования, обработка персональных данных, права и обязанности сторон.">
|
<meta name="description" content="Пользовательское соглашение для платформы обучения фронтенд-разработке BROJS.RU. Условия использования, обработка персональных данных, права и обязанности сторон.">
|
||||||
<meta name="yandex-verification" content="98f7e15d1ad66018">
|
<meta name="yandex-verification" content="98f7e15d1ad66018">
|
||||||
<link href="https://fonts.googleapis.com/css?family=Montserrat:400,600,700,900&subset=cyrillic,cyrillic-ext" rel="stylesheet">
|
<link href="https://fonts.googleapis.com/css?family=Montserrat:400,600,700,900&subset=cyrillic,cyrillic-ext" rel="stylesheet">
|
||||||
<link rel="stylesheet" href="<%= htmlWebpackPlugin.options.cssPath %>">
|
<link rel="stylesheet" href="/src/styles/terms.scss">
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<noscript><div><img src="https://mc.yandex.ru/watch/87860751" style="position:absolute; left:-9999px;" alt=""></div></noscript>
|
<noscript><div><img src="https://mc.yandex.ru/watch/87860751" style="position:absolute; left:-9999px;" alt=""></div></noscript>
|
||||||
@ -29,6 +29,7 @@
|
|||||||
<p><strong>Интеллектуальная собственность</strong> — результаты интеллектуальной деятельности, включая, но не ограничиваясь, программные коды, дизайны, тексты, графику и другие объекты, защищенные законом.</p>
|
<p><strong>Интеллектуальная собственность</strong> — результаты интеллектуальной деятельности, включая, но не ограничиваясь, программные коды, дизайны, тексты, графику и другие объекты, защищенные законом.</p>
|
||||||
|
|
||||||
<h2>2. Условия использования</h2>
|
<h2>2. Условия использования</h2>
|
||||||
|
|
||||||
<h3>2.1. Регистрация</h3>
|
<h3>2.1. Регистрация</h3>
|
||||||
<p>Регистрация осуществляется через:</p>
|
<p>Регистрация осуществляется через:</p>
|
||||||
<ul>
|
<ul>
|
||||||
@ -45,6 +46,7 @@
|
|||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
<h2>3. Персональные данные</h2>
|
<h2>3. Персональные данные</h2>
|
||||||
|
|
||||||
<h3>3.1. Собираемые данные</h3>
|
<h3>3.1. Собираемые данные</h3>
|
||||||
<p>Платформа собирает:</p>
|
<p>Платформа собирает:</p>
|
||||||
<ul>
|
<ul>
|
||||||
@ -89,6 +91,7 @@
|
|||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
<h2>4. Интеллектуальная собственность</h2>
|
<h2>4. Интеллектуальная собственность</h2>
|
||||||
|
|
||||||
<h3>4.1. Права Пользователя</h3>
|
<h3>4.1. Права Пользователя</h3>
|
||||||
<ul>
|
<ul>
|
||||||
<li>Пользователь сохраняет авторские права на созданные проекты.</li>
|
<li>Пользователь сохраняет авторские права на созданные проекты.</li>
|
||||||
@ -102,6 +105,7 @@
|
|||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
<h2>5. Ответственность</h2>
|
<h2>5. Ответственность</h2>
|
||||||
|
|
||||||
<h3>5.1. Ограничение ответственности</h3>
|
<h3>5.1. Ограничение ответственности</h3>
|
||||||
<p>Администрация не несет ответственности за:</p>
|
<p>Администрация не несет ответственности за:</p>
|
||||||
<ul>
|
<ul>
|
||||||
@ -123,6 +127,7 @@
|
|||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
<h2>6. Уведомления</h2>
|
<h2>6. Уведомления</h2>
|
||||||
|
|
||||||
<h3>6.1. Информационные сообщения</h3>
|
<h3>6.1. Информационные сообщения</h3>
|
||||||
<p>Платформа вправе отправлять Пользователю:</p>
|
<p>Платформа вправе отправлять Пользователю:</p>
|
||||||
<ul>
|
<ul>
|
||||||
@ -138,6 +143,7 @@
|
|||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
<h2>7. Безопасность данных</h2>
|
<h2>7. Безопасность данных</h2>
|
||||||
|
|
||||||
<h3>7.1. Технические меры</h3>
|
<h3>7.1. Технические меры</h3>
|
||||||
<ul>
|
<ul>
|
||||||
<li>Данные хранятся в СУБД PostgreSQL через Keycloak.</li>
|
<li>Данные хранятся в СУБД PostgreSQL через Keycloak.</li>
|
||||||
@ -151,6 +157,7 @@
|
|||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
<h2>8. Применимое право и разрешение споров</h2>
|
<h2>8. Применимое право и разрешение споров</h2>
|
||||||
|
|
||||||
<h3>8.1. Применимое право</h3>
|
<h3>8.1. Применимое право</h3>
|
||||||
<ul>
|
<ul>
|
||||||
<li>Соглашение регулируется законодательством РФ. Для пользователей из стран СНГ применяются нормы ЕАЭС.</li>
|
<li>Соглашение регулируется законодательством РФ. Для пользователей из стран СНГ применяются нормы ЕАЭС.</li>
|
||||||
@ -173,8 +180,6 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script src="https://static.brojs.ru/fire.app/1.8.4/index.js"></script>
|
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
||||||
85
vite.config.ts
Normal file
85
vite.config.ts
Normal file
@ -0,0 +1,85 @@
|
|||||||
|
import { defineConfig } from 'vite';
|
||||||
|
import react from '@vitejs/plugin-react';
|
||||||
|
import path from 'path';
|
||||||
|
import fs from 'fs';
|
||||||
|
|
||||||
|
// Express middleware для stubs
|
||||||
|
const stubsMiddleware = () => ({
|
||||||
|
name: 'stubs-middleware',
|
||||||
|
configureServer(server: any) {
|
||||||
|
const stubsPath = path.resolve(__dirname, 'stubs/api');
|
||||||
|
|
||||||
|
server.middlewares.use('/api', (req: any, res: any, next: any) => {
|
||||||
|
// Получаем путь запроса без /api
|
||||||
|
const apiPath = req.url.replace(/\?.*$/, ''); // убираем query params
|
||||||
|
const stubFile = path.join(stubsPath, `${apiPath}.js`);
|
||||||
|
|
||||||
|
// Проверяем существует ли stub файл
|
||||||
|
if (fs.existsSync(stubFile)) {
|
||||||
|
try {
|
||||||
|
// Очищаем кеш модуля для hot reload
|
||||||
|
delete require.cache[require.resolve(stubFile)];
|
||||||
|
const stub = require(stubFile);
|
||||||
|
|
||||||
|
// Если это функция, вызываем её
|
||||||
|
if (typeof stub === 'function') {
|
||||||
|
stub(req, res, next);
|
||||||
|
} else if (stub.default && typeof stub.default === 'function') {
|
||||||
|
stub.default(req, res, next);
|
||||||
|
} else {
|
||||||
|
// Если это просто объект, отдаём как JSON
|
||||||
|
res.setHeader('Content-Type', 'application/json');
|
||||||
|
res.end(JSON.stringify(stub.default || stub));
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error(`Error loading stub ${stubFile}:`, error);
|
||||||
|
res.statusCode = 500;
|
||||||
|
res.end(JSON.stringify({ error: 'Internal Server Error' }));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
next();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
export default defineConfig(({ mode }) => {
|
||||||
|
const isProd = mode === 'production';
|
||||||
|
|
||||||
|
return {
|
||||||
|
plugins: [
|
||||||
|
react(),
|
||||||
|
stubsMiddleware()
|
||||||
|
],
|
||||||
|
base: isProd ? 'https://static.brojs.ru/landing/main/' : '/',
|
||||||
|
server: {
|
||||||
|
port: 8099,
|
||||||
|
open: '/',
|
||||||
|
},
|
||||||
|
build: {
|
||||||
|
outDir: 'dist',
|
||||||
|
assetsDir: '.', // Все ассеты в корень dist
|
||||||
|
rollupOptions: {
|
||||||
|
input: {
|
||||||
|
main: path.resolve(__dirname, 'index.html'),
|
||||||
|
terms: path.resolve(__dirname, 'terms.html'),
|
||||||
|
},
|
||||||
|
output: {
|
||||||
|
entryFileNames: '[name].[hash].js',
|
||||||
|
chunkFileNames: '[name].[hash].js',
|
||||||
|
assetFileNames: '[name].[hash].[ext]'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
css: {
|
||||||
|
modules: {
|
||||||
|
localsConvention: 'camelCase',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
resolve: {
|
||||||
|
alias: {
|
||||||
|
'@': path.resolve(__dirname, './src'),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}}); // Двойная скобка для закрытия return и defineConfig
|
||||||
|
|
||||||
Loading…
x
Reference in New Issue
Block a user