From 7907238c1a898d3eb2faeed01e5f6074dcf8393d Mon Sep 17 00:00:00 2001 From: Primakov Alexandr Alexandrovich Date: Fri, 24 Oct 2025 14:35:30 +0300 Subject: [PATCH] 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. --- .npmrc | 1 - .prettierignore | 7 - .prettierrc.json | 7 - @types/emotion.d.ts | 10 - @types/index.d.ts | 19 - Jenkinsfile | 31 - VITE_BUILD_GUIDE.md | 82 +++ babel.config.js | 6 - d-scripts/re-run.sh | 2 - d-scripts/stop.sh | 1 - d-scripts/up-nginx.sh | 1 - eslint.config.mjs | 13 - ijl.config.js | 88 --- src/index.ejs => index.html | 20 +- jest.config.js | 9 - package-lock.json | 1122 +++++++++++++++++++++++++++++++++- package.json | 31 +- readme.md | 122 +++- src/dashboard.tsx | 12 +- src/index.tsx | 37 +- src/pages/terms/Terms.tsx | 291 --------- src/pages/terms/index.ts | 2 - src/terms.js | 3 - stubs/api/test.js | 11 + stubs/api/user.js | 8 + src/terms.html => terms.html | 61 +- vite.config.ts | 85 +++ 27 files changed, 1461 insertions(+), 621 deletions(-) delete mode 100644 .npmrc delete mode 100644 .prettierignore delete mode 100644 .prettierrc.json delete mode 100644 @types/emotion.d.ts delete mode 100644 @types/index.d.ts delete mode 100644 Jenkinsfile create mode 100644 VITE_BUILD_GUIDE.md delete mode 100644 babel.config.js delete mode 100644 d-scripts/re-run.sh delete mode 100644 d-scripts/stop.sh delete mode 100644 d-scripts/up-nginx.sh delete mode 100644 eslint.config.mjs delete mode 100644 ijl.config.js rename src/index.ejs => index.html (52%) delete mode 100644 jest.config.js delete mode 100644 src/pages/terms/Terms.tsx delete mode 100644 src/pages/terms/index.ts delete mode 100644 src/terms.js create mode 100644 stubs/api/test.js create mode 100644 stubs/api/user.js rename src/terms.html => terms.html (96%) create mode 100644 vite.config.ts 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 +