diff --git a/.npmrc b/.npmrc deleted file mode 100644 index cafe685..0000000 --- a/.npmrc +++ /dev/null @@ -1 +0,0 @@ -package-lock=true diff --git a/.prettierignore b/.prettierignore deleted file mode 100644 index fc5ced8..0000000 --- a/.prettierignore +++ /dev/null @@ -1,7 +0,0 @@ -# Ignore artifacts: -build -dist -coverage -stubs -logs -d-scripts \ No newline at end of file diff --git a/.prettierrc.json b/.prettierrc.json deleted file mode 100644 index b5bbaff..0000000 --- a/.prettierrc.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "tabWidth": 2, - "semi": true, - "jsxBracketSameLine": true, - "arrowParens": "avoid", - "singleQuote": true -} diff --git a/@types/emotion.d.ts b/@types/emotion.d.ts deleted file mode 100644 index 66b1208..0000000 --- a/@types/emotion.d.ts +++ /dev/null @@ -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 - } -} diff --git a/@types/index.d.ts b/@types/index.d.ts deleted file mode 100644 index 9421318..0000000 --- a/@types/index.d.ts +++ /dev/null @@ -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; -} diff --git a/Jenkinsfile b/Jenkinsfile deleted file mode 100644 index 861c015..0000000 --- a/Jenkinsfile +++ /dev/null @@ -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' - } - } - } -} \ No newline at end of file diff --git a/VITE_BUILD_GUIDE.md b/VITE_BUILD_GUIDE.md new file mode 100644 index 0000000..6c572a3 --- /dev/null +++ b/VITE_BUILD_GUIDE.md @@ -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 + +``` + +### terms.html (Terms) +```html + +``` + +## 🎯 Кроссплатформенность + +✅ **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 сам всё делает правильно! ✨ + diff --git a/babel.config.js b/babel.config.js deleted file mode 100644 index faa86eb..0000000 --- a/babel.config.js +++ /dev/null @@ -1,6 +0,0 @@ -module.exports = { - presets: [ - ['@babel/preset-env', { targets: { node: 'current' } }], - '@babel/preset-typescript', - ], -}; diff --git a/d-scripts/re-run.sh b/d-scripts/re-run.sh deleted file mode 100644 index 37cc50c..0000000 --- a/d-scripts/re-run.sh +++ /dev/null @@ -1,2 +0,0 @@ -sh stop.sh; -sh up-nginx.sh; \ No newline at end of file diff --git a/d-scripts/stop.sh b/d-scripts/stop.sh deleted file mode 100644 index dcd9568..0000000 --- a/d-scripts/stop.sh +++ /dev/null @@ -1 +0,0 @@ -docker stop adminka_nginx2; diff --git a/d-scripts/up-nginx.sh b/d-scripts/up-nginx.sh deleted file mode 100644 index 6a5ac30..0000000 --- a/d-scripts/up-nginx.sh +++ /dev/null @@ -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; \ No newline at end of file diff --git a/eslint.config.mjs b/eslint.config.mjs deleted file mode 100644 index c692093..0000000 --- a/eslint.config.mjs +++ /dev/null @@ -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, -]; \ No newline at end of file diff --git a/ijl.config.js b/ijl.config.js deleted file mode 100644 index fc85bd5..0000000 --- a/ijl.config.js +++ /dev/null @@ -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: {}, -}; diff --git a/src/index.ejs b/index.html similarity index 52% rename from src/index.ejs rename to index.html index aa7e4e6..e48e5a8 100644 --- a/src/index.ejs +++ b/index.html @@ -3,17 +3,23 @@ - - - bro-js admin - + BROJS.RU - Платформа обучения фронтенд-разработке + - +
- + - \ No newline at end of file + + diff --git a/jest.config.js b/jest.config.js deleted file mode 100644 index 46304a9..0000000 --- a/jest.config.js +++ /dev/null @@ -1,9 +0,0 @@ -module.exports = { - clearMocks: true, - collectCoverage: true, - collectCoverageFrom: ['./src/**/*.ts?(x)'], - coverageDirectory: 'coverage', - coverageProvider: 'v8', - preset: 'ts-jest', - testEnvironment: 'jsdom', -}; diff --git a/package-lock.json b/package-lock.json index cd24ccf..5d1fb7b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -31,6 +31,7 @@ "devDependencies": { "@eslint/js": "^9.9.0", "@types/jest": "^29.5.12", + "@vitejs/plugin-react": "^5.1.0", "babel-jest": "^29.7.0", "css-loader": "^7.1.2", "eslint": "^8.57.0", @@ -45,7 +46,9 @@ "sass-loader": "^16.0.6", "style-loader": "^4.0.0", "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" } }, "node_modules/@babel/code-frame": { @@ -1415,6 +1418,38 @@ "@babel/core": "^7.0.0-0" } }, + "node_modules/@babel/plugin-transform-react-jsx-self": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.27.1.tgz", + "integrity": "sha512-6UzkCs+ejGdZ5mFFC/OCUrv028ab2fp1znZmCZjAOBKiBK2jXD1O+BPSfX8X2qjJ75fZBMSnQn3Rq2mrBJK2mw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-jsx-source": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.27.1.tgz", + "integrity": "sha512-zbwoTsBruTeKB9hSq73ha66iFeJHuaFkUbwvqElnygoNbj/jHRsSeokowZFN3CZ64IvEqcmmkVe89OPXc7ldAw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, "node_modules/@babel/plugin-transform-react-pure-annotations": { "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-pure-annotations/-/plugin-transform-react-pure-annotations-7.27.1.tgz", @@ -2353,6 +2388,448 @@ "integrity": "sha512-snKqtPW01tN0ui7yu9rGv69aJXr/a/Ywvl11sUjNtEcRc+ng/mQriFL0wLXMef74iHa/EkftbDzU9F8iFbH+zg==", "license": "MIT" }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.11.tgz", + "integrity": "sha512-Xt1dOL13m8u0WE8iplx9Ibbm+hFAO0GsU2P34UNoDGvZYkY8ifSiy6Zuc1lYxfG7svWE2fzqCUmFp5HCn51gJg==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.11.tgz", + "integrity": "sha512-uoa7dU+Dt3HYsethkJ1k6Z9YdcHjTrSb5NUy66ZfZaSV8hEYGD5ZHbEMXnqLFlbBflLsl89Zke7CAdDJ4JI+Gg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.11.tgz", + "integrity": "sha512-9slpyFBc4FPPz48+f6jyiXOx/Y4v34TUeDDXJpZqAWQn/08lKGeD8aDp9TMn9jDz2CiEuHwfhRmGBvpnd/PWIQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.11.tgz", + "integrity": "sha512-Sgiab4xBjPU1QoPEIqS3Xx+R2lezu0LKIEcYe6pftr56PqPygbB7+szVnzoShbx64MUupqoE0KyRlN7gezbl8g==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.11.tgz", + "integrity": "sha512-VekY0PBCukppoQrycFxUqkCojnTQhdec0vevUL/EDOCnXd9LKWqD/bHwMPzigIJXPhC59Vd1WFIL57SKs2mg4w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.11.tgz", + "integrity": "sha512-+hfp3yfBalNEpTGp9loYgbknjR695HkqtY3d3/JjSRUyPg/xd6q+mQqIb5qdywnDxRZykIHs3axEqU6l1+oWEQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.11.tgz", + "integrity": "sha512-CmKjrnayyTJF2eVuO//uSjl/K3KsMIeYeyN7FyDBjsR3lnSJHaXlVoAK8DZa7lXWChbuOk7NjAc7ygAwrnPBhA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.11.tgz", + "integrity": "sha512-Dyq+5oscTJvMaYPvW3x3FLpi2+gSZTCE/1ffdwuM6G1ARang/mb3jvjxs0mw6n3Lsw84ocfo9CrNMqc5lTfGOw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.11.tgz", + "integrity": "sha512-TBMv6B4kCfrGJ8cUPo7vd6NECZH/8hPpBHHlYI3qzoYFvWu2AdTvZNuU/7hsbKWqu/COU7NIK12dHAAqBLLXgw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.11.tgz", + "integrity": "sha512-Qr8AzcplUhGvdyUF08A1kHU3Vr2O88xxP0Tm8GcdVOUm25XYcMPp2YqSVHbLuXzYQMf9Bh/iKx7YPqECs6ffLA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.11.tgz", + "integrity": "sha512-TmnJg8BMGPehs5JKrCLqyWTVAvielc615jbkOirATQvWWB1NMXY77oLMzsUjRLa0+ngecEmDGqt5jiDC6bfvOw==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.11.tgz", + "integrity": "sha512-DIGXL2+gvDaXlaq8xruNXUJdT5tF+SBbJQKbWy/0J7OhU8gOHOzKmGIlfTTl6nHaCOoipxQbuJi7O++ldrxgMw==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.11.tgz", + "integrity": "sha512-Osx1nALUJu4pU43o9OyjSCXokFkFbyzjXb6VhGIJZQ5JZi8ylCQ9/LFagolPsHtgw6himDSyb5ETSfmp4rpiKQ==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.11.tgz", + "integrity": "sha512-nbLFgsQQEsBa8XSgSTSlrnBSrpoWh7ioFDUmwo158gIm5NNP+17IYmNWzaIzWmgCxq56vfr34xGkOcZ7jX6CPw==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.11.tgz", + "integrity": "sha512-HfyAmqZi9uBAbgKYP1yGuI7tSREXwIb438q0nqvlpxAOs3XnZ8RsisRfmVsgV486NdjD7Mw2UrFSw51lzUk1ww==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.11.tgz", + "integrity": "sha512-HjLqVgSSYnVXRisyfmzsH6mXqyvj0SA7pG5g+9W7ESgwA70AXYNpfKBqh1KbTxmQVaYxpzA/SvlB9oclGPbApw==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.11.tgz", + "integrity": "sha512-HSFAT4+WYjIhrHxKBwGmOOSpphjYkcswF449j6EjsjbinTZbp8PJtjsVK1XFJStdzXdy/jaddAep2FGY+wyFAQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.11.tgz", + "integrity": "sha512-hr9Oxj1Fa4r04dNpWr3P8QKVVsjQhqrMSUzZzf+LZcYjZNqhA3IAfPQdEh1FLVUJSiu6sgAwp3OmwBfbFgG2Xg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.11.tgz", + "integrity": "sha512-u7tKA+qbzBydyj0vgpu+5h5AeudxOAGncb8N6C9Kh1N4n7wU1Xw1JDApsRjpShRpXRQlJLb9wY28ELpwdPcZ7A==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.11.tgz", + "integrity": "sha512-Qq6YHhayieor3DxFOoYM1q0q1uMFYb7cSpLD2qzDSvK1NAvqFi8Xgivv0cFC6J+hWVw2teCYltyy9/m/14ryHg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.11.tgz", + "integrity": "sha512-CN+7c++kkbrckTOz5hrehxWN7uIhFFlmS/hqziSFVWpAzpWrQoAG4chH+nN3Be+Kzv/uuo7zhX716x3Sn2Jduw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openharmony-arm64": { + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.11.tgz", + "integrity": "sha512-rOREuNIQgaiR+9QuNkbkxubbp8MSO9rONmwP5nKncnWJ9v5jQ4JxFnLu4zDSRPf3x4u+2VN4pM4RdyIzDty/wQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.11.tgz", + "integrity": "sha512-nq2xdYaWxyg9DcIyXkZhcYulC6pQ2FuCgem3LI92IwMgIZ69KHeY8T4Y88pcwoLIjbed8n36CyKoYRDygNSGhA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.11.tgz", + "integrity": "sha512-3XxECOWJq1qMZ3MN8srCJ/QfoLpL+VaxD/WfNRm1O3B4+AZ/BnLVgFbUV3eiRYDMXetciH16dwPbbHqwe1uU0Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.11.tgz", + "integrity": "sha512-3ukss6gb9XZ8TlRyJlgLn17ecsK4NSQTmdIXRASVsiS2sQ6zPPZklNJT5GR5tE/MUarymmy8kCEf5xPCNCqVOA==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.11.tgz", + "integrity": "sha512-D7Hpz6A2L4hzsRpPaCYkQnGOotdUpDzSGRIv9I+1ITdHROSFUWW95ZPZWQmGka1Fg7W3zFJowyn9WGwMJ0+KPA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, "node_modules/@eslint-community/eslint-utils": { "version": "4.4.0", "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", @@ -3537,6 +4014,321 @@ "node": ">=14.0.0" } }, + "node_modules/@rolldown/pluginutils": { + "version": "1.0.0-beta.43", + "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-beta.43.tgz", + "integrity": "sha512-5Uxg7fQUCmfhax7FJke2+8B6cqgeUJUD9o2uXIKXhD+mG0mL6NObmVoi9wXEU1tY89mZKgAYA6fTbftx3q2ZPQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.52.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.52.5.tgz", + "integrity": "sha512-8c1vW4ocv3UOMp9K+gToY5zL2XiiVw3k7f1ksf4yO1FlDFQ1C2u72iACFnSOceJFsWskc2WZNqeRhFRPzv+wtQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.52.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.52.5.tgz", + "integrity": "sha512-mQGfsIEFcu21mvqkEKKu2dYmtuSZOBMmAl5CFlPGLY94Vlcm+zWApK7F/eocsNzp8tKmbeBP8yXyAbx0XHsFNA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.52.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.52.5.tgz", + "integrity": "sha512-takF3CR71mCAGA+v794QUZ0b6ZSrgJkArC+gUiG6LB6TQty9T0Mqh3m2ImRBOxS2IeYBo4lKWIieSvnEk2OQWA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.52.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.52.5.tgz", + "integrity": "sha512-W901Pla8Ya95WpxDn//VF9K9u2JbocwV/v75TE0YIHNTbhqUTv9w4VuQ9MaWlNOkkEfFwkdNhXgcLqPSmHy0fA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-freebsd-arm64": { + "version": "4.52.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.52.5.tgz", + "integrity": "sha512-QofO7i7JycsYOWxe0GFqhLmF6l1TqBswJMvICnRUjqCx8b47MTo46W8AoeQwiokAx3zVryVnxtBMcGcnX12LvA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-freebsd-x64": { + "version": "4.52.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.52.5.tgz", + "integrity": "sha512-jr21b/99ew8ujZubPo9skbrItHEIE50WdV86cdSoRkKtmWa+DDr6fu2c/xyRT0F/WazZpam6kk7IHBerSL7LDQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.52.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.52.5.tgz", + "integrity": "sha512-PsNAbcyv9CcecAUagQefwX8fQn9LQ4nZkpDboBOttmyffnInRy8R8dSg6hxxl2Re5QhHBf6FYIDhIj5v982ATQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.52.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.52.5.tgz", + "integrity": "sha512-Fw4tysRutyQc/wwkmcyoqFtJhh0u31K+Q6jYjeicsGJJ7bbEq8LwPWV/w0cnzOqR2m694/Af6hpFayLJZkG2VQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.52.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.52.5.tgz", + "integrity": "sha512-a+3wVnAYdQClOTlyapKmyI6BLPAFYs0JM8HRpgYZQO02rMR09ZcV9LbQB+NL6sljzG38869YqThrRnfPMCDtZg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.52.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.52.5.tgz", + "integrity": "sha512-AvttBOMwO9Pcuuf7m9PkC1PUIKsfaAJ4AYhy944qeTJgQOqJYJ9oVl2nYgY7Rk0mkbsuOpCAYSs6wLYB2Xiw0Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loong64-gnu": { + "version": "4.52.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.52.5.tgz", + "integrity": "sha512-DkDk8pmXQV2wVrF6oq5tONK6UHLz/XcEVow4JTTerdeV1uqPeHxwcg7aFsfnSm9L+OO8WJsWotKM2JJPMWrQtA==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-gnu": { + "version": "4.52.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.52.5.tgz", + "integrity": "sha512-W/b9ZN/U9+hPQVvlGwjzi+Wy4xdoH2I8EjaCkMvzpI7wJUs8sWJ03Rq96jRnHkSrcHTpQe8h5Tg3ZzUPGauvAw==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.52.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.52.5.tgz", + "integrity": "sha512-sjQLr9BW7R/ZiXnQiWPkErNfLMkkWIoCz7YMn27HldKsADEKa5WYdobaa1hmN6slu9oWQbB6/jFpJ+P2IkVrmw==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-musl": { + "version": "4.52.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.52.5.tgz", + "integrity": "sha512-hq3jU/kGyjXWTvAh2awn8oHroCbrPm8JqM7RUpKjalIRWWXE01CQOf/tUNWNHjmbMHg/hmNCwc/Pz3k1T/j/Lg==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.52.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.52.5.tgz", + "integrity": "sha512-gn8kHOrku8D4NGHMK1Y7NA7INQTRdVOntt1OCYypZPRt6skGbddska44K8iocdpxHTMMNui5oH4elPH4QOLrFQ==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.52.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.52.5.tgz", + "integrity": "sha512-hXGLYpdhiNElzN770+H2nlx+jRog8TyynpTVzdlc6bndktjKWyZyiCsuDAlpd+j+W+WNqfcyAWz9HxxIGfZm1Q==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.52.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.52.5.tgz", + "integrity": "sha512-arCGIcuNKjBoKAXD+y7XomR9gY6Mw7HnFBv5Rw7wQRvwYLR7gBAgV7Mb2QTyjXfTveBNFAtPt46/36vV9STLNg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-openharmony-arm64": { + "version": "4.52.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.52.5.tgz", + "integrity": "sha512-QoFqB6+/9Rly/RiPjaomPLmR/13cgkIGfA40LHly9zcH1S0bN2HVFYk3a1eAyHQyjs3ZJYlXvIGtcCs5tko9Cw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ] + }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.52.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.52.5.tgz", + "integrity": "sha512-w0cDWVR6MlTstla1cIfOGyl8+qb93FlAVutcor14Gf5Md5ap5ySfQ7R9S/NjNaMLSFdUnKGEasmVnu3lCMqB7w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.52.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.52.5.tgz", + "integrity": "sha512-Aufdpzp7DpOTULJCuvzqcItSGDH73pF3ko/f+ckJhxQyHtp67rHw3HMNxoIdDMUITJESNE6a8uh4Lo4SLouOUg==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-gnu": { + "version": "4.52.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.52.5.tgz", + "integrity": "sha512-UGBUGPFp1vkj6p8wCRraqNhqwX/4kNQPS57BCFc8wYh0g94iVIW33wJtQAx3G7vrjjNtRaxiMUylM0ktp/TRSQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.52.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.52.5.tgz", + "integrity": "sha512-TAcgQh2sSkykPRWLrdyy2AiceMckNf5loITqXxFI5VuQjS5tSuw3WlwdN8qv8vzjLAUTvYaH/mVjSFpbkFbpTg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, "node_modules/@sinclair/typebox": { "version": "0.27.8", "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz", @@ -3617,9 +4409,9 @@ } }, "node_modules/@types/estree": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.6.tgz", - "integrity": "sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==", + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", + "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", "license": "MIT" }, "node_modules/@types/glob": { @@ -3717,12 +4509,12 @@ "license": "MIT" }, "node_modules/@types/node": { - "version": "22.7.4", - "resolved": "https://registry.npmjs.org/@types/node/-/node-22.7.4.tgz", - "integrity": "sha512-y+NPi1rFzDs1NdQHHToqeiX2TIS79SWEAw9GYhkkx8bD0ChpfqC+n2j5OXOCpzfojBEBt6DnEnnG9MY0zk1XLg==", + "version": "24.9.1", + "resolved": "https://registry.npmjs.org/@types/node/-/node-24.9.1.tgz", + "integrity": "sha512-QoiaXANRkSXK6p0Duvt56W208du4P9Uye9hWLWgGMDTEoKPhuenzNcC4vGUmrNkiOKTlIrBoyNQYNpSwfEZXSg==", "license": "MIT", "dependencies": { - "undici-types": "~6.19.2" + "undici-types": "~7.16.0" } }, "node_modules/@types/parse-json": { @@ -4014,6 +4806,27 @@ "devOptional": true, "license": "ISC" }, + "node_modules/@vitejs/plugin-react": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-5.1.0.tgz", + "integrity": "sha512-4LuWrg7EKWgQaMJfnN+wcmbAW+VSsCmqGohftWjuct47bv8uE4n/nPpq4XjJPsxgq00GGG5J8dvBczp8uxScew==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/core": "^7.28.4", + "@babel/plugin-transform-react-jsx-self": "^7.27.1", + "@babel/plugin-transform-react-jsx-source": "^7.27.1", + "@rolldown/pluginutils": "1.0.0-beta.43", + "@types/babel__core": "^7.20.5", + "react-refresh": "^0.18.0" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "peerDependencies": { + "vite": "^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0" + } + }, "node_modules/@webassemblyjs/ast": { "version": "1.12.1", "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.12.1.tgz", @@ -5524,6 +6337,15 @@ "node": ">=10" } }, + "node_modules/cosmiconfig/node_modules/yaml": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", + "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", + "license": "ISC", + "engines": { + "node": ">= 6" + } + }, "node_modules/create-jest": { "version": "29.7.0", "resolved": "https://registry.npmjs.org/create-jest/-/create-jest-29.7.0.tgz", @@ -6415,6 +7237,48 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/esbuild": { + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.11.tgz", + "integrity": "sha512-KohQwyzrKTQmhXDW1PjCv3Tyspn9n5GcY2RTDqeORIdIJY8yKIF7sTSopFmn/wpMPW4rdPXI0UE5LJLuq3bx0Q==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.25.11", + "@esbuild/android-arm": "0.25.11", + "@esbuild/android-arm64": "0.25.11", + "@esbuild/android-x64": "0.25.11", + "@esbuild/darwin-arm64": "0.25.11", + "@esbuild/darwin-x64": "0.25.11", + "@esbuild/freebsd-arm64": "0.25.11", + "@esbuild/freebsd-x64": "0.25.11", + "@esbuild/linux-arm": "0.25.11", + "@esbuild/linux-arm64": "0.25.11", + "@esbuild/linux-ia32": "0.25.11", + "@esbuild/linux-loong64": "0.25.11", + "@esbuild/linux-mips64el": "0.25.11", + "@esbuild/linux-ppc64": "0.25.11", + "@esbuild/linux-riscv64": "0.25.11", + "@esbuild/linux-s390x": "0.25.11", + "@esbuild/linux-x64": "0.25.11", + "@esbuild/netbsd-arm64": "0.25.11", + "@esbuild/netbsd-x64": "0.25.11", + "@esbuild/openbsd-arm64": "0.25.11", + "@esbuild/openbsd-x64": "0.25.11", + "@esbuild/openharmony-arm64": "0.25.11", + "@esbuild/sunos-x64": "0.25.11", + "@esbuild/win32-arm64": "0.25.11", + "@esbuild/win32-ia32": "0.25.11", + "@esbuild/win32-x64": "0.25.11" + } + }, "node_modules/escalade": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", @@ -7516,6 +8380,15 @@ "node": ">=6" } }, + "node_modules/fork-ts-checker-webpack-plugin/node_modules/yaml": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", + "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", + "license": "ISC", + "engines": { + "node": ">= 6" + } + }, "node_modules/form-data": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", @@ -11675,6 +12548,16 @@ } } }, + "node_modules/react-refresh": { + "version": "0.18.0", + "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.18.0.tgz", + "integrity": "sha512-QgT5//D3jfjJb6Gsjxv0Slpj23ip+HtOpnNgnb2S5zU3CB26G/IDPGoy4RJB42wzFE46DRsstbW6tKHoKbhAxw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/react-router": { "version": "6.26.2", "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.26.2.tgz", @@ -11977,6 +12860,48 @@ "rimraf": "bin.js" } }, + "node_modules/rollup": { + "version": "4.52.5", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.52.5.tgz", + "integrity": "sha512-3GuObel8h7Kqdjt0gxkEzaifHTqLVW56Y/bjN7PSQtkKr0w3V/QYSdt6QWYtd7A1xUtYQigtdUfgj1RvWVtorw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "1.0.8" + }, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=18.0.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "@rollup/rollup-android-arm-eabi": "4.52.5", + "@rollup/rollup-android-arm64": "4.52.5", + "@rollup/rollup-darwin-arm64": "4.52.5", + "@rollup/rollup-darwin-x64": "4.52.5", + "@rollup/rollup-freebsd-arm64": "4.52.5", + "@rollup/rollup-freebsd-x64": "4.52.5", + "@rollup/rollup-linux-arm-gnueabihf": "4.52.5", + "@rollup/rollup-linux-arm-musleabihf": "4.52.5", + "@rollup/rollup-linux-arm64-gnu": "4.52.5", + "@rollup/rollup-linux-arm64-musl": "4.52.5", + "@rollup/rollup-linux-loong64-gnu": "4.52.5", + "@rollup/rollup-linux-ppc64-gnu": "4.52.5", + "@rollup/rollup-linux-riscv64-gnu": "4.52.5", + "@rollup/rollup-linux-riscv64-musl": "4.52.5", + "@rollup/rollup-linux-s390x-gnu": "4.52.5", + "@rollup/rollup-linux-x64-gnu": "4.52.5", + "@rollup/rollup-linux-x64-musl": "4.52.5", + "@rollup/rollup-openharmony-arm64": "4.52.5", + "@rollup/rollup-win32-arm64-msvc": "4.52.5", + "@rollup/rollup-win32-ia32-msvc": "4.52.5", + "@rollup/rollup-win32-x64-gnu": "4.52.5", + "@rollup/rollup-win32-x64-msvc": "4.52.5", + "fsevents": "~2.3.2" + } + }, "node_modules/run-parallel": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", @@ -13034,6 +13959,54 @@ "license": "MIT", "peer": true }, + "node_modules/tinyglobby": { + "version": "0.2.15", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz", + "integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "fdir": "^6.5.0", + "picomatch": "^4.0.3" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, + "node_modules/tinyglobby/node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/tinyglobby/node_modules/picomatch": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, "node_modules/tmpl": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", @@ -13393,9 +14366,9 @@ } }, "node_modules/undici-types": { - "version": "6.19.8", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.19.8.tgz", - "integrity": "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==", + "version": "7.16.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.16.0.tgz", + "integrity": "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==", "license": "MIT" }, "node_modules/unicode-canonical-property-names-ecmascript": { @@ -13550,6 +14523,119 @@ "node": ">= 0.8" } }, + "node_modules/vite": { + "version": "7.1.12", + "resolved": "https://registry.npmjs.org/vite/-/vite-7.1.12.tgz", + "integrity": "sha512-ZWyE8YXEXqJrrSLvYgrRP7p62OziLW7xI5HYGWFzOvupfAlrLvURSzv/FyGyy0eidogEM3ujU+kUG1zuHgb6Ug==", + "dev": true, + "license": "MIT", + "dependencies": { + "esbuild": "^0.25.0", + "fdir": "^6.5.0", + "picomatch": "^4.0.3", + "postcss": "^8.5.6", + "rollup": "^4.43.0", + "tinyglobby": "^0.2.15" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^20.19.0 || >=22.12.0", + "jiti": ">=1.21.0", + "less": "^4.0.0", + "lightningcss": "^1.21.0", + "sass": "^1.70.0", + "sass-embedded": "^1.70.0", + "stylus": ">=0.54.8", + "sugarss": "^5.0.0", + "terser": "^5.16.0", + "tsx": "^4.8.1", + "yaml": "^2.4.2" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "jiti": { + "optional": true + }, + "less": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + }, + "tsx": { + "optional": true + }, + "yaml": { + "optional": true + } + } + }, + "node_modules/vite-plugin-sass": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/vite-plugin-sass/-/vite-plugin-sass-0.1.0.tgz", + "integrity": "sha512-gLwvs3ozfDAOZCqs+PepkTd4078m8tfq50IlmTW/OphlWsW95uP7lQ5A3NezfUfTZDTCOA4nFlYnOWRpsKYOqw==", + "dev": true, + "license": "ISC" + }, + "node_modules/vite/node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/vite/node_modules/picomatch": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, "node_modules/void-elements": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/void-elements/-/void-elements-3.1.0.tgz", @@ -14016,12 +15102,18 @@ "license": "ISC" }, "node_modules/yaml": { - "version": "1.10.2", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", - "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.1.tgz", + "integrity": "sha512-lcYcMxX2PO9XMGvAJkJ3OsNMw+/7FKes7/hgerGUYWIoWu5j/+YQqcZr5JnPZWzOsEBgMbSbiSTn/dv/69Mkpw==", + "dev": true, "license": "ISC", + "optional": true, + "peer": true, + "bin": { + "yaml": "bin.mjs" + }, "engines": { - "node": ">= 6" + "node": ">= 14.6" } }, "node_modules/yargs": { diff --git a/package.json b/package.json index 425e692..a9577e0 100644 --- a/package.json +++ b/package.json @@ -3,18 +3,20 @@ "version": "2.0.1", "description": "", "main": "./src/index.tsx", - "scripts": { - "docker:rerun": "docker stop adminka_nginx2 && sh d-scripts/up-nginx.sh", - "predeploy": "npm i && npm run build:prod", - "redeploy": "npm run predeploy && npm run docker:rerun || sh d-scripts/up-nginx.sh", - "clean": "rimraf dist", - "eslint": "npx eslint src", - "prettier": "prettier --write .", - "test": "jest --coverage", - "start": "brojs server --port=8099 --with-open-browser", - "build": "npm run clean && brojs build --dev", - "build:prod": "npm run clean && brojs build" - }, + "scripts": { + "docker:rerun": "docker stop adminka_nginx2 && sh d-scripts/up-nginx.sh", + "predeploy": "npm i && npm run build:prod", + "redeploy": "npm run predeploy && npm run docker:rerun || sh d-scripts/up-nginx.sh", + "clean": "rimraf dist", + "eslint": "npx eslint src", + "prettier": "prettier --write .", + "test": "jest --coverage", + "dev": "vite", + "start": "vite", + "build": "vite build", + "build:prod": "vite build --mode production", + "preview": "vite preview" + }, "keywords": [], "author": "", "license": "MIT", @@ -41,6 +43,7 @@ "devDependencies": { "@eslint/js": "^9.9.0", "@types/jest": "^29.5.12", + "@vitejs/plugin-react": "^5.1.0", "babel-jest": "^29.7.0", "css-loader": "^7.1.2", "eslint": "^8.57.0", @@ -55,6 +58,8 @@ "sass-loader": "^16.0.6", "style-loader": "^4.0.0", "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" } } diff --git a/readme.md b/readme.md index 32ba23a..3aff36c 100644 --- a/readme.md +++ b/readme.md @@ -2,14 +2,15 @@ Лендинг платформы для обучения фронтенд-разработке -## 🚀 Особенности v3.0 +## 🚀 Особенности v3.0 (Vite) -- ⚡ **Минимальные зависимости** - только необходимое +- ⚡ **Vite** - мгновенный запуск (vs 3+ сек у webpack) - 📄 **Статический HTML** для идеального SEO - 🎨 **SCSS + CSS Modules** для гибких стилей - 📱 **Адаптивный дизайн** с responsive шрифтами -- 🎯 **React** только там, где нужна динамика -- 🔥 **Легкий bundle** terms.html (10 KB + 1.5 KB CSS, **без JS!**) +- 🎯 **React** только для главной страницы +- 🔌 **Express stubs** из `./stubs/api` работают как раньше! +- 🗜️ **Легкий bundle** terms.html (13 KB + 1.5 KB CSS, **без JS!**) ## 📦 Установка @@ -20,13 +21,14 @@ npm install ## 🛠️ Разработка ```bash -npm start # Dev сервер на http://localhost:8099 +npm start # Dev сервер на http://localhost:8099 ``` ## 🏗️ Сборка ```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 - Динамическая страница "В разработке" -- Файлы: `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.html` - **Чистый HTML** без JavaScript - Полный текст пользовательского соглашения - 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 компонентов) ```typescript -import * as styles from './styles/main.module.scss'; +import styles from './styles/main.module.scss'; element.className = styles.app; ``` @@ -71,7 +99,7 @@ h1 { ## 📱 Адаптивность -Все размеры шрифтов автоматически уменьшаются на мобильных устройствах (< 768px): +Все размеры шрифтов автоматически уменьшаются на мобильных (< 768px): - H1: 2.5rem → 1.75rem - H2: 1.75rem → 1.5rem - H3: 1.25rem → 1.1rem @@ -80,50 +108,78 @@ h1 { ## 🗂️ Структура ``` -src/ -├── styles/ -│ ├── main.module.scss # CSS Modules для React -│ ├── main.module.scss.d.ts # TypeScript типы -│ └── terms.scss # SCSS для статики -├── pages/ -│ └── under-construction/ # Главная страница -├── index.tsx # Entry для React -├── terms.js # Entry для CSS -├── terms.html # Статический HTML -└── index.ejs # Шаблон для React +bro.landing/ +├── 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 +│ └── terms.scss # SCSS для Terms +├── stubs/ +│ └── api/ +│ ├── test.js # Пример: GET /api/test +│ └── user.js # Пример: GET /api/user +└── dist/ # Build output + ├── index.html # Главная + ├── main.[hash].js # React bundle + ├── terms.html # Terms статика + └── terms.[hash].css # Terms стили ``` ## 🌐 Деплой -После `npm run build:prod`: -- `index.html` → `brojs.ru/` -- `terms.html` → `brojs.ru/terms` -- Статика → `static.brojs.ru/landing/main/` +### Production URLs +После `npm run build` и деплоя: +- **Главная**: `brojs.ru/` → `dist/index.html` + - 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 +- **Vite 7** - молниеносная сборка - **React 18** - только для динамических частей - **TypeScript** - типизация -- **Webpack 5** - сборка с multiple entry points - **SCSS** - препроцессор - **CSS Modules** - изоляция стилей ### Библиотеки - **React Router DOM** - клиентский роутинг -- **i18next** - интернационализация - **Lottie React** - анимации ### Dev зависимости -- **sass** + **sass-loader** - компиляция SCSS -- **css-loader** - обработка CSS (с поддержкой CSS Modules) -- **style-loader** - инжект CSS в dev режиме -- **mini-css-extract-plugin** - извлечение CSS в production +- **@vitejs/plugin-react** - React Fast Refresh +- **sass** - компиляция SCSS + +## ⚡ Почему Vite? + +- 🚀 **Мгновенный запуск** (HMR из коробки) +- ⚡ **Быстрая сборка** (esbuild + Rollup) +- 🎯 **Простая конфигурация** (70 строк vs 500+) +- 📦 **Меньше зависимостей** +- 🔥 **Современный стандарт** ## 📚 Документация Полная документация в [cloud.md](./cloud.md) -## 🤝 Участие +--- -Проект использует минималистичный подход - добавляем зависимости только по мере необходимости! +**Простота + Скорость + Мощь!** 🎉 diff --git a/src/dashboard.tsx b/src/dashboard.tsx index 8aabaf9..e09238a 100644 --- a/src/dashboard.tsx +++ b/src/dashboard.tsx @@ -1,12 +1,22 @@ -import React from 'react'; +import React, { useEffect } from 'react'; import { Routes, Route } from 'react-router-dom'; import { UnderConstructionPage } from './pages'; +// Компонент для редиректа на terms.html +const TermsRedirect = () => { + useEffect(() => { + window.location.href = '/terms.html'; + }, []); + + return
Загрузка Terms...
; +}; + export const Dashboard = () => { return ( } /> + } /> } /> ); diff --git a/src/index.tsx b/src/index.tsx index c658798..83987b3 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -1,40 +1,11 @@ import React from 'react'; -import i18next from 'i18next'; -import { i18nextReactInitConfig } from '@brojs/cli'; -import { createRoot, hydrateRoot } from 'react-dom/client' - +import { createRoot } from 'react-dom/client'; 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'); -// Применяем класс к app контейнеру if (MOUNT_NODE) { - MOUNT_NODE.className = styles.app || 'app'; + const root = createRoot(MOUNT_NODE); + root.render(); } - -(async () => { - await Promise.all([i18nextPromise]); - - // Если страница была пре-рендерена, используем hydrate вместо render - const hasPrerenderedContent = MOUNT_NODE.hasChildNodes(); - - if (hasPrerenderedContent) { - hydrateRoot(MOUNT_NODE, ); - } else { - const rootElement = createRoot(MOUNT_NODE); - rootElement.render(); - - if (module.hot) { - module.hot.accept('./app', async () => { - await i18next.reloadResources(); - rootElement.render(); - }); - } - } -})(); - -export const mount = () => console.log('mounted'); -export const unmount = () => console.log('unmounted'); diff --git a/src/pages/terms/Terms.tsx b/src/pages/terms/Terms.tsx deleted file mode 100644 index ab48933..0000000 --- a/src/pages/terms/Terms.tsx +++ /dev/null @@ -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 ( - <> - - Пользовательское соглашение - BROJS.RU - - - - - - - {/* Заголовок */} - - - Пользовательское соглашение - - - для BROJS.RU - - - Последнее обновление: 25 мая 2025 г. - - - - - - {/* 1. Термины */} - - - 1. Термины - - - Платформа — сайт https://brojs.ru, предоставляющий услуги обучения фронтенд-разработке. - Пользователь — лицо, зарегистрированное на Платформе. - Микрофронтенд-проект — код, конфигурации и иные материалы, созданные Пользователем. - Gravatar — сторонний сервис (https://gravatar.com), предоставляющий аватары на основе email-адресов пользователей. - Интеллектуальная собственность — результаты интеллектуальной деятельности, включая, но не ограничиваясь, программные коды, дизайны, тексты, графику и другие объекты, защищенные законом. - - - - {/* 2. Условия использования */} - - - 2. Условия использования - - - - 2.1. Регистрация - - Регистрация осуществляется через: - -
  • Аккаунт Yandex;
  • -
  • Email (с подтверждением через ссылку).
  • -
    - - - 2.2. Обязанности Пользователя - - Пользователь обязуется: - -
  • Не передавать учетные данные третьим лицам;
  • -
  • Не использовать Платформу для распространения незаконного контента или совершения мошеннических действий;
  • -
  • Соблюдать конфиденциальность личных данных других участников Платформы.
  • -
    -
    - - {/* 3. Персональные данные */} - - - 3. Персональные данные - - - - 3.1. Собираемые данные - - Платформа собирает: - -
  • Никнейм;
  • -
  • Email;
  • -
  • ФИО (при наличии договора с учебным заведением);
  • -
  • Данные о посещении занятий (через QR-код).
  • -
    - - - 3.2. Аватар через Gravatar - - -
  • Платформа не хранит аватары на своих серверах. Для отображения используется Gravatar.
  • -
  • Ссылка на аватар формируется на основе хэша email пользователя.
  • -
  • Пользователь может активировать/отозвать согласие на использование Gravatar в настройках профиля.
  • -
  • Отказ от Gravatar приведет к отображению стандартного изображения.
  • -
    - - - 3.3. Цели обработки данных - - -
  • Предоставление доступа к Платформе;
  • -
  • Передача данных о посещении учебным заведениям (ФИО, email, дата и время) в формате Excel.
  • -
    - - - 3.4. Хранение и передача данных - - -
  • Персональные данные хранятся в СУБД PostgreSQL через Keycloak.
  • -
  • Данные о посещении передаются учебным заведениям на основании договоров с преподавателями.
  • -
  • Передача данных осуществляется с применением шифрования и протоколов безопасности.
  • -
    - - - 3.5. Срок хранения - - -
  • Персональные данные удаляются в течение 30 дней после удаления аккаунта.
  • -
  • Микрофронтенд-проекты хранятся 6 месяцев после завершения обучения.
  • -
    - - - 3.6. Отзыв согласия - - -
  • Для отзыва согласия на обработку персональных данных необходимо направить письмо на primakov.pro@yandex.ru.
  • -
  • Отзыв приведет к удалению всех данных пользователя вручную.
  • -
  • Частичное удаление отдельных категорий данных возможно по заявлению пользователя.
  • -
    -
    - - {/* 4. Интеллектуальная собственность */} - - - 4. Интеллектуальная собственность - - - - 4.1. Права Пользователя - - -
  • Пользователь сохраняет авторские права на созданные проекты.
  • -
  • Платформа не имеет прав на использование материалов Пользователя без явного согласия.
  • -
    - - - 4.2. Права Администрации - - -
  • Администрация вправе удалить контент при нарушении условий соглашения или через 6 месяцев после завершения обучения.
  • -
  • Проверка подлинности загружаемого материала осуществляется преподавателем, отвечающим за группу.
  • -
    -
    - - {/* 5. Ответственность */} - - - 5. Ответственность - - - - 5.1. Ограничение ответственности - - Администрация не несет ответственности за: - -
  • Утрату данных из-за действий Пользователя;
  • -
  • Использование данных учебными заведениями после их передачи;
  • -
  • Некорректное отображение аватаров через Gravatar.
  • -
    - - - 5.2. Основания для блокировки аккаунта - - -
  • Нарушение авторских прав;
  • -
  • Распространение спама/вирусов;
  • -
  • Предоставление недостоверных данных (включая ФИО).
  • -
    - - - 5.3. Компенсация ущерба - - -
  • В случае нарушения правил или утечки данных, Администрация обязана принять меры для минимизации последствий.
  • -
    -
    - - {/* 6. Уведомления */} - - - 6. Уведомления - - - - 6.1. Информационные сообщения - - Платформа вправе отправлять Пользователю: - -
  • Уведомления о технических работах, изменениях функционала;
  • -
  • Сообщения о нарушениях или блокировке аккаунта;
  • -
  • Рекламу собственных услуг или услуг третьих лиц.
  • -
    - - - 6.2. Отказ от уведомлений - - -
  • Отказ от рекламных сообщений возможен через настройки Личного кабинета.
  • -
  • Отказ от информационных уведомлений может ограничить доступ к функциям Платформы.
  • -
    -
    - - {/* 7. Безопасность данных */} - - - 7. Безопасность данных - - - - 7.1. Технические меры - - -
  • Данные хранятся в СУБД PostgreSQL через Keycloak.
  • -
  • Шифрование данных при передаче (HTTPS).
  • -
  • Периодические тестирования системы на уязвимости.
  • -
    - - - 7.2. Двухфакторная аутентификация - - -
  • Пользователи могут добровольно активировать двухфакторную аутентификацию (OTP) через Личный кабинет.
  • -
    -
    - - {/* 8. Применимое право и разрешение споров */} - - - 8. Применимое право и разрешение споров - - - - 8.1. Применимое право - - -
  • Соглашение регулируется законодательством РФ. Для пользователей из стран СНГ применяются нормы ЕАЭС.
  • -
  • При расширении географии услуг Платформа будет соблюдать законодательство стран ЕСВР и ЕС.
  • -
    - - - 8.2. Разрешение споров - - -
  • Споры разрешаются в суде по месту нахождения администрации Платформы.
  • -
    -
    - - {/* 9. Изменения соглашения */} - - - 9. Изменения соглашения - - Изменения вступают в силу после публикации на сайте. - - - {/* 10. Контакты */} - - - 10. Контакты - - - Для обращений: primakov.pro@yandex.ru - - - - - - {/* Footer */} - - - © 2025 BROJS.RU. Все права защищены. - - -
    -
    -
    - - ); -}; - diff --git a/src/pages/terms/index.ts b/src/pages/terms/index.ts deleted file mode 100644 index c6f0d2b..0000000 --- a/src/pages/terms/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export { Terms } from './Terms'; - diff --git a/src/terms.js b/src/terms.js deleted file mode 100644 index 8981cc7..0000000 --- a/src/terms.js +++ /dev/null @@ -1,3 +0,0 @@ -// Entry point for terms page styles -import './styles/terms.scss'; - diff --git a/stubs/api/test.js b/stubs/api/test.js new file mode 100644 index 0000000..159d104 --- /dev/null +++ b/stubs/api/test.js @@ -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, + })); +}; + diff --git a/stubs/api/user.js b/stubs/api/user.js new file mode 100644 index 0000000..a674fcb --- /dev/null +++ b/stubs/api/user.js @@ -0,0 +1,8 @@ +// Пример stub для /api/user +module.exports.default = { + id: 1, + name: 'Test User', + email: 'user@brojs.ru', + role: 'student' +}; + diff --git a/src/terms.html b/terms.html similarity index 96% rename from src/terms.html rename to terms.html index cc06c51..b7958d5 100644 --- a/src/terms.html +++ b/terms.html @@ -1,4 +1,4 @@ - + @@ -8,7 +8,7 @@ - + @@ -18,24 +18,25 @@

    Пользовательское соглашение

    для BROJS.RU

    Последнее обновление: 25 мая 2025 г.

    - +
    - +

    1. Термины

    Платформа — сайт https://brojs.ru, предоставляющий услуги обучения фронтенд-разработке.

    Пользователь — лицо, зарегистрированное на Платформе.

    Микрофронтенд-проект — код, конфигурации и иные материалы, созданные Пользователем.

    Gravatar — сторонний сервис (https://gravatar.com), предоставляющий аватары на основе email-адресов пользователей.

    Интеллектуальная собственность — результаты интеллектуальной деятельности, включая, но не ограничиваясь, программные коды, дизайны, тексты, графику и другие объекты, защищенные законом.

    - +

    2. Условия использования

    +

    2.1. Регистрация

    Регистрация осуществляется через:

    • Аккаунт Yandex;
    • Email (с подтверждением через ссылку).
    - +

    2.2. Обязанности Пользователя

    Пользователь обязуется:

      @@ -43,8 +44,9 @@
    • Не использовать Платформу для распространения незаконного контента или совершения мошеннических действий;
    • Соблюдать конфиденциальность личных данных других участников Платформы.
    - +

    3. Персональные данные

    +

    3.1. Собираемые данные

    Платформа собирает:

      @@ -53,7 +55,7 @@
    • ФИО (при наличии договора с учебным заведением);
    • Данные о посещении занятий (через QR-код).
    - +

    3.2. Аватар через Gravatar

    • Платформа не хранит аватары на своих серверах. Для отображения используется Gravatar.
    • @@ -61,47 +63,49 @@
    • Пользователь может активировать/отозвать согласие на использование Gravatar в настройках профиля.
    • Отказ от Gravatar приведет к отображению стандартного изображения.
    - +

    3.3. Цели обработки данных

    • Предоставление доступа к Платформе;
    • Передача данных о посещении учебным заведениям (ФИО, email, дата и время) в формате Excel.
    - +

    3.4. Хранение и передача данных

    • Персональные данные хранятся в СУБД PostgreSQL через Keycloak.
    • Данные о посещении передаются учебным заведениям на основании договоров с преподавателями.
    • Передача данных осуществляется с применением шифрования и протоколов безопасности.
    - +

    3.5. Срок хранения

    • Персональные данные удаляются в течение 30 дней после удаления аккаунта.
    • Микрофронтенд-проекты хранятся 6 месяцев после завершения обучения.
    - +

    3.6. Отзыв согласия

    • Для отзыва согласия на обработку персональных данных необходимо направить письмо на primakov.pro@yandex.ru.
    • Отзыв приведет к удалению всех данных пользователя вручную.
    • Частичное удаление отдельных категорий данных возможно по заявлению пользователя.
    - +

    4. Интеллектуальная собственность

    +

    4.1. Права Пользователя

    • Пользователь сохраняет авторские права на созданные проекты.
    • Платформа не имеет прав на использование материалов Пользователя без явного согласия.
    - +

    4.2. Права Администрации

    • Администрация вправе удалить контент при нарушении условий соглашения или через 6 месяцев после завершения обучения.
    • Проверка подлинности загружаемого материала осуществляется преподавателем, отвечающим за группу.
    - +

    5. Ответственность

    +

    5.1. Ограничение ответственности

    Администрация не несет ответственности за:

      @@ -109,20 +113,21 @@
    • Использование данных учебными заведениями после их передачи;
    • Некорректное отображение аватаров через Gravatar.
    - +

    5.2. Основания для блокировки аккаунта

    • Нарушение авторских прав;
    • Распространение спама/вирусов;
    • Предоставление недостоверных данных (включая ФИО).
    - +

    5.3. Компенсация ущерба

    • В случае нарушения правил или утечки данных, Администрация обязана принять меры для минимизации последствий.
    - +

    6. Уведомления

    +

    6.1. Информационные сообщения

    Платформа вправе отправлять Пользователю:

      @@ -130,51 +135,51 @@
    • Сообщения о нарушениях или блокировке аккаунта;
    • Рекламу собственных услуг или услуг третьих лиц.
    - +

    6.2. Отказ от уведомлений

    • Отказ от рекламных сообщений возможен через настройки Личного кабинета.
    • Отказ от информационных уведомлений может ограничить доступ к функциям Платформы.
    - +

    7. Безопасность данных

    +

    7.1. Технические меры

    • Данные хранятся в СУБД PostgreSQL через Keycloak.
    • Шифрование данных при передаче (HTTPS).
    • Периодические тестирования системы на уязвимости.
    - +

    7.2. Двухфакторная аутентификация

    • Пользователи могут добровольно активировать двухфакторную аутентификацию (OTP) через Личный кабинет.
    - +

    8. Применимое право и разрешение споров

    +

    8.1. Применимое право

    • Соглашение регулируется законодательством РФ. Для пользователей из стран СНГ применяются нормы ЕАЭС.
    • При расширении географии услуг Платформа будет соблюдать законодательство стран ЕСВР и ЕС.
    - +

    8.2. Разрешение споров

    • Споры разрешаются в суде по месту нахождения администрации Платформы.
    - +

    9. Изменения соглашения

    Изменения вступают в силу после публикации на сайте.

    - +

    10. Контакты

    Для обращений: primakov.pro@yandex.ru

    - + - - diff --git a/vite.config.ts b/vite.config.ts new file mode 100644 index 0000000..8339ecc --- /dev/null +++ b/vite.config.ts @@ -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 +