diff --git a/build.zip b/build.zip new file mode 100644 index 0000000..9c0baa8 Binary files /dev/null and b/build.zip differ diff --git a/eslint.config.js b/eslint.config.js index ea36dd3..4fa125d 100644 --- a/eslint.config.js +++ b/eslint.config.js @@ -14,8 +14,16 @@ export default defineConfig([ reactRefresh.configs.vite, ], languageOptions: { + ecmaVersion: 2020, globals: globals.browser, - parserOptions: { ecmaFeatures: { jsx: true } }, + parserOptions: { + ecmaVersion: 'latest', + ecmaFeatures: { jsx: true }, + sourceType: 'module', + }, + }, + rules: { + 'no-unused-vars': ['error', { varsIgnorePattern: '^[A-Z_]' }], }, }, ]) diff --git a/package-lock.json b/package-lock.json index 2cd3f12..0d0e3f0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,19 +8,23 @@ "name": "vkminiapp", "version": "0.0.0", "dependencies": { + "@react-oauth/google": "^0.13.5", "@vkontakte/vk-bridge": "^3.0.2", "axios": "^1.16.1", "framer-motion": "^12.40.0", "lucide-react": "^1.16.0", "react": "^19.2.6", "react-dom": "^19.2.6", - "react-router-dom": "^7.15.1" + "react-router-dom": "^7.15.1", + "styled-components": "^6.4.2" }, "devDependencies": { "@eslint/js": "^10.0.1", + "@tailwindcss/postcss": "^4.3.0", "@types/react": "^19.2.14", "@types/react-dom": "^19.2.3", "@vitejs/plugin-react": "^6.0.1", + "@vkontakte/vk-miniapps-deploy": "^1.0.2", "autoprefixer": "^10.5.0", "eslint": "^10.3.0", "eslint-plugin-react-hooks": "^7.1.1", @@ -31,6 +35,19 @@ "vite": "^8.0.12" } }, + "node_modules/@alloc/quick-lru": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@alloc/quick-lru/-/quick-lru-5.2.0.tgz", + "integrity": "sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/@babel/code-frame": { "version": "7.29.7", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.7.tgz", @@ -305,6 +322,21 @@ "tslib": "^2.4.0" } }, + "node_modules/@emotion/is-prop-valid": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-1.4.0.tgz", + "integrity": "sha512-QgD4fyscGcbbKwJmqNvUMSE02OsHUa+lAWKdEUIJKgqe5IwRSKd7+KhibEWdaKwgjLj0DRSHA9biAIqGBk05lw==", + "license": "MIT", + "dependencies": { + "@emotion/memoize": "^0.9.0" + } + }, + "node_modules/@emotion/memoize": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.9.0.tgz", + "integrity": "sha512-30FAj7/EoJ5mwVPOWhAyCX+FPfMDrVecJAM+Iw9NRoSl4BBAQeqj4cApHHUXOVvIPgLVDsCFoz/hGD+5QQD1GQ==", + "license": "MIT" + }, "node_modules/@eslint-community/eslint-utils": { "version": "4.9.1", "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.9.1.tgz", @@ -578,6 +610,16 @@ "url": "https://github.com/sponsors/Boshen" } }, + "node_modules/@react-oauth/google": { + "version": "0.13.5", + "resolved": "https://registry.npmjs.org/@react-oauth/google/-/google-0.13.5.tgz", + "integrity": "sha512-xQWri2s/3nNekZJ4uuov2aAfQYu83bN3864KcFqw2pK1nNbFurQIjPFDXhWaKH3IjYJ2r/9yyIIpsn5lMqrheQ==", + "license": "MIT", + "peerDependencies": { + "react": ">=16.8.0", + "react-dom": ">=16.8.0" + } + }, "node_modules/@rolldown/binding-android-arm64": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.0.2.tgz", @@ -869,6 +911,289 @@ "tslib": "^2.8.0" } }, + "node_modules/@tailwindcss/node": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/@tailwindcss/node/-/node-4.3.0.tgz", + "integrity": "sha512-aFb4gUhFOgdh9AXo4IzBEOzBkkAxm9VigwDJnMIYv3lcfXCJVesNfbEaBl4BNgVRyid92AmdviqwBUBRKSeY3g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/remapping": "^2.3.5", + "enhanced-resolve": "^5.21.0", + "jiti": "^2.6.1", + "lightningcss": "1.32.0", + "magic-string": "^0.30.21", + "source-map-js": "^1.2.1", + "tailwindcss": "4.3.0" + } + }, + "node_modules/@tailwindcss/oxide": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide/-/oxide-4.3.0.tgz", + "integrity": "sha512-F7HZGBeN9I0/AuuJS5PwcD8xayx5ri5GhjYUDBEVYUkexyA/giwbDNjRVrxSezE3T250OU2K/wp/ltWx3UOefg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 20" + }, + "optionalDependencies": { + "@tailwindcss/oxide-android-arm64": "4.3.0", + "@tailwindcss/oxide-darwin-arm64": "4.3.0", + "@tailwindcss/oxide-darwin-x64": "4.3.0", + "@tailwindcss/oxide-freebsd-x64": "4.3.0", + "@tailwindcss/oxide-linux-arm-gnueabihf": "4.3.0", + "@tailwindcss/oxide-linux-arm64-gnu": "4.3.0", + "@tailwindcss/oxide-linux-arm64-musl": "4.3.0", + "@tailwindcss/oxide-linux-x64-gnu": "4.3.0", + "@tailwindcss/oxide-linux-x64-musl": "4.3.0", + "@tailwindcss/oxide-wasm32-wasi": "4.3.0", + "@tailwindcss/oxide-win32-arm64-msvc": "4.3.0", + "@tailwindcss/oxide-win32-x64-msvc": "4.3.0" + } + }, + "node_modules/@tailwindcss/oxide-android-arm64": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-android-arm64/-/oxide-android-arm64-4.3.0.tgz", + "integrity": "sha512-TJPiq67tKlLuObP6RkwvVGDoxCMBVtDgKkLfa/uyj7/FyxvQwHS+UOnVrXXgbEsfUaMgiVvC4KbJnRr26ho4Ng==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-darwin-arm64": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-arm64/-/oxide-darwin-arm64-4.3.0.tgz", + "integrity": "sha512-oMN/WZRb+SO37BmUElEgeEWuU8E/HXRkiODxJxLe1UTHVXLrdVSgfaJV7pSlhRGMSOiXLuxTIjfsF3wYvz8cgQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-darwin-x64": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-x64/-/oxide-darwin-x64-4.3.0.tgz", + "integrity": "sha512-N6CUmu4a6bKVADfw77p+iw6Yd9Q3OBhe0veaDX+QazfuVYlQsHfDgxBrsjQ/IW+zywL8mTrNd0SdJT/zgtvMdA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-freebsd-x64": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-freebsd-x64/-/oxide-freebsd-x64-4.3.0.tgz", + "integrity": "sha512-zDL5hBkQdH5C6MpqbK3gQAgP80tsMwSI26vjOzjJtNCMUo0lFgOItzHKBIupOZNQxt3ouPH7RPhvNhiTfCe5CQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-linux-arm-gnueabihf": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm-gnueabihf/-/oxide-linux-arm-gnueabihf-4.3.0.tgz", + "integrity": "sha512-R06HdNi7A7OEoMsf6d4tjZ71RCWnZQPHj2mnotSFURjNLdBC+cIgXQ7l81CqeoiQftjf6OOblxXMInMgN2VzMA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-linux-arm64-gnu": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-gnu/-/oxide-linux-arm64-gnu-4.3.0.tgz", + "integrity": "sha512-qTJHELX8jetjhRQHCLilkVLmybpzNQAtaI/gaoVoidn/ufbNDbAo8KlK2J+yPoc8wQxvDxCmh/5lr8nC1+lTbg==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-linux-arm64-musl": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-musl/-/oxide-linux-arm64-musl-4.3.0.tgz", + "integrity": "sha512-Z6sukiQsngnWO+l39X4pPbiWT81IC+PLKF+PHxIlyZbGNb9MODfYlXEVlFvej5BOZInWX01kVyzeLvHsXhfczQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-linux-x64-gnu": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-gnu/-/oxide-linux-x64-gnu-4.3.0.tgz", + "integrity": "sha512-DRNdQRpSGzRGfARVuVkxvM8Q12nh19l4BF/G7zGA1oe+9wcC6saFBHTISrpIcKzhiXtSrlSrluCfvMuledoCTQ==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-linux-x64-musl": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-musl/-/oxide-linux-x64-musl-4.3.0.tgz", + "integrity": "sha512-Z0IADbDo8bh6I7h2IQMx601AdXBLfFpEdUotft86evd/8ZPflZe9COPO8Q1vw+pfLWIUo9zN/JGZvwuAJqduqg==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-wasm32-wasi": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-wasm32-wasi/-/oxide-wasm32-wasi-4.3.0.tgz", + "integrity": "sha512-HNZGOUxEmElksYR7S6sC5jTeNGpobAsy9u7Gu0AskJ8/20FR9GqebUyB+HBcU/ax6BHuiuJi+Oda4B+YX6H1yA==", + "bundleDependencies": [ + "@napi-rs/wasm-runtime", + "@emnapi/core", + "@emnapi/runtime", + "@tybys/wasm-util", + "@emnapi/wasi-threads", + "tslib" + ], + "cpu": [ + "wasm32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/core": "^1.10.0", + "@emnapi/runtime": "^1.10.0", + "@emnapi/wasi-threads": "^1.2.1", + "@napi-rs/wasm-runtime": "^1.1.4", + "@tybys/wasm-util": "^0.10.1", + "tslib": "^2.8.1" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@tailwindcss/oxide-win32-arm64-msvc": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-arm64-msvc/-/oxide-win32-arm64-msvc-4.3.0.tgz", + "integrity": "sha512-Pe+RPVTi1T+qymuuRpcdvwSVZjnll/f7n8gBxMMh3xLTctMDKqpdfGimbMyioqtLhUYZxdJ9wGNhV7MKHvgZsQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-win32-x64-msvc": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-x64-msvc/-/oxide-win32-x64-msvc-4.3.0.tgz", + "integrity": "sha512-Mvrf2kXW/yeW/OTezZlCGOirXRcUuLIBx/5Y12BaPM7wJoryG6dfS/NJL8aBPqtTEx/Vm4T4vKzFUcKDT+TKUA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/postcss": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/@tailwindcss/postcss/-/postcss-4.3.0.tgz", + "integrity": "sha512-Jm05Tjx+9yCLGv5qw1c+84Psds8MnyrEQYCB+FFk2lgGiUjlRqdxke4mVTuYrj2xnVZqKim2Apr5ySuQRYAw/w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@alloc/quick-lru": "^5.2.0", + "@tailwindcss/node": "4.3.0", + "@tailwindcss/oxide": "4.3.0", + "postcss": "^8.5.10", + "tailwindcss": "4.3.0" + } + }, "node_modules/@tybys/wasm-util": { "version": "0.10.2", "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.2.tgz", @@ -956,6 +1281,73 @@ "@swc/helpers": "^0.5.21" } }, + "node_modules/@vkontakte/vk-miniapps-deploy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@vkontakte/vk-miniapps-deploy/-/vk-miniapps-deploy-1.0.2.tgz", + "integrity": "sha512-IIBOCoKj+sFkXyZiwUwE0yNd5p/vpCdTDe6K80xhe9tNEcctugiTqyPE8WOzHx9yVfyFbYnF9z3oTpuMtfDtTg==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "dependencies": { + "async": "^3.2.0", + "chalk": "^3.0.0", + "configstore": "^5.0.0", + "form-data": "^3.0.0", + "fs-extra": "^8.0.1", + "https-proxy-agent": "^7.0.6", + "node-fetch": "^2.6.0", + "prompts": "^2.1.0", + "require-module": "^0.1.0", + "zip-a-folder": "0.0.12" + }, + "bin": { + "vk-miniapps-deploy": "bin/vk-miniapps-deploy" + }, + "engines": { + "node": ">=8.10" + } + }, + "node_modules/@vkontakte/vk-miniapps-deploy/node_modules/agent-base": { + "version": "7.1.4", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz", + "integrity": "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 14" + } + }, + "node_modules/@vkontakte/vk-miniapps-deploy/node_modules/form-data": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-3.0.4.tgz", + "integrity": "sha512-f0cRzm6dkyVYV3nPoooP8XlccPQukegwhAnpoLcXy+X+A8KfpGOoXwDr9FLZd3wzgLaBGQBE3lY93Zm/i1JvIQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "es-set-tostringtag": "^2.1.0", + "hasown": "^2.0.2", + "mime-types": "^2.1.35" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/@vkontakte/vk-miniapps-deploy/node_modules/https-proxy-agent": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz", + "integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==", + "dev": true, + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.2", + "debug": "4" + }, + "engines": { + "node": ">= 14" + } + }, "node_modules/acorn": { "version": "8.16.0", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.16.0.tgz", @@ -1008,6 +1400,113 @@ "url": "https://github.com/sponsors/epoberezkin" } }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/archiver": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/archiver/-/archiver-3.1.1.tgz", + "integrity": "sha512-5Hxxcig7gw5Jod/8Gq0OneVgLYET+oNHcxgWItq4TbhOzRLKNAFUb9edAftiMKXvXfCB0vbGrJdZDNq0dWMsxg==", + "dev": true, + "license": "MIT", + "dependencies": { + "archiver-utils": "^2.1.0", + "async": "^2.6.3", + "buffer-crc32": "^0.2.1", + "glob": "^7.1.4", + "readable-stream": "^3.4.0", + "tar-stream": "^2.1.0", + "zip-stream": "^2.1.2" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/archiver-utils": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/archiver-utils/-/archiver-utils-2.1.0.tgz", + "integrity": "sha512-bEL/yUb/fNNiNTuUz979Z0Yg5L+LzLxGJz8x79lYmR54fmTIb6ob/hNQgkQnIUDWIFjZVQwl9Xs356I6BAMHfw==", + "dev": true, + "license": "MIT", + "dependencies": { + "glob": "^7.1.4", + "graceful-fs": "^4.2.0", + "lazystream": "^1.0.0", + "lodash.defaults": "^4.2.0", + "lodash.difference": "^4.5.0", + "lodash.flatten": "^4.4.0", + "lodash.isplainobject": "^4.0.6", + "lodash.union": "^4.6.0", + "normalize-path": "^3.0.0", + "readable-stream": "^2.0.0" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/archiver-utils/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "dev": true, + "license": "MIT", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/archiver-utils/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true, + "license": "MIT" + }, + "node_modules/archiver-utils/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/archiver/node_modules/async": { + "version": "2.6.4", + "resolved": "https://registry.npmjs.org/async/-/async-2.6.4.tgz", + "integrity": "sha512-mzo5dfJYwAn29PeiJ0zvwTo04zj8HDJj0Mn8TD7sno7q12prdbnasKJHhkm2c1LgrhlJ0teaea8860oxi51mGA==", + "dev": true, + "license": "MIT", + "dependencies": { + "lodash": "^4.17.14" + } + }, + "node_modules/async": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.6.tgz", + "integrity": "sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==", + "dev": true, + "license": "MIT" + }, "node_modules/asynckit": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", @@ -1073,6 +1572,27 @@ "node": "18 || 20 || >=22" } }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, "node_modules/baseline-browser-mapping": { "version": "2.10.32", "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.32.tgz", @@ -1086,6 +1606,18 @@ "node": ">=6.0.0" } }, + "node_modules/bl": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", + "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "buffer": "^5.5.0", + "inherits": "^2.0.4", + "readable-stream": "^3.4.0" + } + }, "node_modules/brace-expansion": { "version": "5.0.6", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.6.tgz", @@ -1133,6 +1665,41 @@ "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" } }, + "node_modules/buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + }, + "node_modules/buffer-crc32": { + "version": "0.2.13", + "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", + "integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "*" + } + }, "node_modules/call-bind-apply-helpers": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", @@ -1146,6 +1713,15 @@ "node": ">= 0.4" } }, + "node_modules/camelize": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/camelize/-/camelize-1.0.1.tgz", + "integrity": "sha512-dU+Tx2fsypxTgtLoE36npi3UqcjSSMNYfkqgmoEhtZrraP5VWq0K7FkWVTYa8eMPtnU/G2txVsfdCJTn9uzpuQ==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/caniuse-lite": { "version": "1.0.30001793", "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001793.tgz", @@ -1167,6 +1743,40 @@ ], "license": "CC-BY-4.0" }, + "node_modules/chalk": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", + "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "license": "MIT" + }, "node_modules/combined-stream": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", @@ -1179,6 +1789,80 @@ "node": ">= 0.8" } }, + "node_modules/compress-commons": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/compress-commons/-/compress-commons-2.1.1.tgz", + "integrity": "sha512-eVw6n7CnEMFzc3duyFVrQEuY1BlHR3rYsSztyG32ibGMW722i3C6IizEGMFmfMU+A+fALvBIwxN3czffTcdA+Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "buffer-crc32": "^0.2.13", + "crc32-stream": "^3.0.1", + "normalize-path": "^3.0.0", + "readable-stream": "^2.3.6" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/compress-commons/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "dev": true, + "license": "MIT", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/compress-commons/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true, + "license": "MIT" + }, + "node_modules/compress-commons/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true, + "license": "MIT" + }, + "node_modules/configstore": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/configstore/-/configstore-5.0.1.tgz", + "integrity": "sha512-aMKprgk5YhBNyH25hj8wGt2+D52Sw1DRRIzqBwLp2Ya9mFmY8KPvvtvmna8SxVR9JMZ4kzMD68N22vlaRpkeFA==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "dot-prop": "^5.2.0", + "graceful-fs": "^4.1.2", + "make-dir": "^3.0.0", + "unique-string": "^2.0.0", + "write-file-atomic": "^3.0.0", + "xdg-basedir": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/convert-source-map": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", @@ -1199,6 +1883,37 @@ "url": "https://opencollective.com/express" } }, + "node_modules/core-util-is": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/crc": { + "version": "3.8.0", + "resolved": "https://registry.npmjs.org/crc/-/crc-3.8.0.tgz", + "integrity": "sha512-iX3mfgcTMIq3ZKLIsVFAbv7+Mc10kxabAGQb8HvjA1o3T1PIYprbakQ65d3I+2HGHt6nSKkM9PYjgoJO2KcFBQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "buffer": "^5.1.0" + } + }, + "node_modules/crc32-stream": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/crc32-stream/-/crc32-stream-3.0.1.tgz", + "integrity": "sha512-mctvpXlbzsvK+6z8kJwSJ5crm7yBwrQMTybJzMw1O4lLGJqjlDCXY2Zw7KheiA6XBEcBmfLx1D88mjRGVJtY9w==", + "dev": true, + "license": "MIT", + "dependencies": { + "crc": "^3.4.4", + "readable-stream": "^3.4.0" + }, + "engines": { + "node": ">= 6.9.0" + } + }, "node_modules/cross-spawn": { "version": "7.0.6", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", @@ -1214,11 +1929,40 @@ "node": ">= 8" } }, + "node_modules/crypto-random-string": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-2.0.0.tgz", + "integrity": "sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/css-color-keywords": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/css-color-keywords/-/css-color-keywords-1.0.0.tgz", + "integrity": "sha512-FyyrDHZKEjXDpNJYvVsV960FiqQyXc/LlYmsxl2BcdMb2WPx0OGRVgTg55rPSyLSNMqP52R9r8geSp7apN3Ofg==", + "license": "ISC", + "engines": { + "node": ">=4" + } + }, + "node_modules/css-to-react-native": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/css-to-react-native/-/css-to-react-native-3.2.0.tgz", + "integrity": "sha512-e8RKaLXMOFii+02mOlqwjbD00KSEKqblnpO9e++1aXS1fPQOpS1YoqdVHBqPjHNoxeF2mimzVqawm2KCbEdtHQ==", + "license": "MIT", + "dependencies": { + "camelize": "^1.0.0", + "css-color-keywords": "^1.0.0", + "postcss-value-parser": "^4.0.2" + } + }, "node_modules/csstype": { "version": "3.2.3", "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz", "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==", - "dev": true, "license": "MIT" }, "node_modules/debug": { @@ -1264,6 +2008,19 @@ "node": ">=8" } }, + "node_modules/dot-prop": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-5.3.0.tgz", + "integrity": "sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-obj": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/dunder-proto": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", @@ -1285,6 +2042,30 @@ "dev": true, "license": "ISC" }, + "node_modules/end-of-stream": { + "version": "1.4.5", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.5.tgz", + "integrity": "sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg==", + "dev": true, + "license": "MIT", + "dependencies": { + "once": "^1.4.0" + } + }, + "node_modules/enhanced-resolve": { + "version": "5.22.0", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.22.0.tgz", + "integrity": "sha512-xYcDWrpELkFzz9SpZ3PlI6Eu6eD93Yf0WLDRxikGhWJ3MAir2SNZTIVCVZqZ/NUyx8AdMc2gT9C0gPiw18kG+A==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.4", + "tapable": "^2.3.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, "node_modules/es-define-property": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", @@ -1702,6 +2483,35 @@ } } }, + "node_modules/fs-constants": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", + "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==", + "dev": true, + "license": "MIT" + }, + "node_modules/fs-extra": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", + "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + }, + "engines": { + "node": ">=6 <7 || >=8" + } + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "dev": true, + "license": "ISC" + }, "node_modules/fsevents": { "version": "2.3.3", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", @@ -1773,6 +2583,28 @@ "node": ">= 0.4" } }, + "node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me", + "dev": true, + "license": "ISC", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/glob-parent": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", @@ -1786,6 +2618,37 @@ "node": ">=10.13.0" } }, + "node_modules/glob/node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/glob/node_modules/brace-expansion": { + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.15.tgz", + "integrity": "sha512-EwOCDEex4quD37XhqM3omwtMoJjr//isUZz1JopUNWms+4Z2ViyM/k1YIRePpoVNnQhENnxtFjLaxNHrT7xIUg==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/glob/node_modules/minimatch": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, "node_modules/globals": { "version": "17.6.0", "resolved": "https://registry.npmjs.org/globals/-/globals-17.6.0.tgz", @@ -1811,6 +2674,23 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, "node_modules/has-symbols": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", @@ -1880,6 +2760,27 @@ "node": ">= 6" } }, + "node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "BSD-3-Clause" + }, "node_modules/ignore": { "version": "5.3.2", "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", @@ -1900,6 +2801,25 @@ "node": ">=0.8.19" } }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", + "dev": true, + "license": "ISC", + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true, + "license": "ISC" + }, "node_modules/is-extglob": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", @@ -1923,6 +2843,30 @@ "node": ">=0.10.0" } }, + "node_modules/is-obj": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-2.0.0.tgz", + "integrity": "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==", + "dev": true, + "license": "MIT" + }, + "node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "dev": true, + "license": "MIT" + }, "node_modules/isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", @@ -1930,6 +2874,16 @@ "dev": true, "license": "ISC" }, + "node_modules/jiti": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.7.0.tgz", + "integrity": "sha512-AC/7JofJvZGrrneWNaEnJeOLUx+JlGt7tNa0wZiRPT4MY1wmfKjt2+6O2p2uz2+skll8OZZmJMNqeke7kKbNgQ==", + "dev": true, + "license": "MIT", + "bin": { + "jiti": "lib/jiti-cli.mjs" + } + }, "node_modules/js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", @@ -1984,6 +2938,16 @@ "node": ">=6" } }, + "node_modules/jsonfile": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", + "integrity": "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==", + "dev": true, + "license": "MIT", + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, "node_modules/keyv": { "version": "4.5.4", "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", @@ -1994,6 +2958,62 @@ "json-buffer": "3.0.1" } }, + "node_modules/kleur": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", + "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/lazystream": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/lazystream/-/lazystream-1.0.1.tgz", + "integrity": "sha512-b94GiNHQNy6JNTrt5w6zNyffMrNkXZb3KTkCZJb2V1xaEGCk093vkZ2jk3tpaeP33/OiXC+WvK9AxUebnf5nbw==", + "dev": true, + "license": "MIT", + "dependencies": { + "readable-stream": "^2.0.5" + }, + "engines": { + "node": ">= 0.6.3" + } + }, + "node_modules/lazystream/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "dev": true, + "license": "MIT", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/lazystream/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true, + "license": "MIT" + }, + "node_modules/lazystream/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, "node_modules/levn": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", @@ -2297,6 +3317,48 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/lodash": { + "version": "4.18.1", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.18.1.tgz", + "integrity": "sha512-dMInicTPVE8d1e5otfwmmjlxkZoUpiVLwyeTdUsi/Caj/gfzzblBcCE5sRHV/AsjuCmxWrte2TNGSYuCeCq+0Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.defaults": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/lodash.defaults/-/lodash.defaults-4.2.0.tgz", + "integrity": "sha512-qjxPLHd3r5DnsdGacqOMU6pb/avJzdh9tFX2ymgoZE27BmjXrNy/y4LoaiTeAb+O3gL8AfpJGtqfX/ae2leYYQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.difference": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.difference/-/lodash.difference-4.5.0.tgz", + "integrity": "sha512-dS2j+W26TQ7taQBGN8Lbbq04ssV3emRw4NY58WErlTO29pIqS0HmoT5aJ9+TUQ1N3G+JOZSji4eugsWwGp9yPA==", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.flatten": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/lodash.flatten/-/lodash.flatten-4.4.0.tgz", + "integrity": "sha512-C5N2Z3DgnnKr0LOpv/hKCgKdb7ZZwafIrsesve6lmzvZIRZRGaZ/l6Q8+2W7NaT+ZwO3fFlSCzCzrDCFdJfZ4g==", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.isplainobject": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", + "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.union": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/lodash.union/-/lodash.union-4.6.0.tgz", + "integrity": "sha512-c4pB2CdGrGdjMKYLA+XiRDO7Y0PRQbm/Gzg8qMj+QH+pFVAoTp5sBpO0odL3FjoPCGjK96p6qsP+yQoiLoOBcw==", + "dev": true, + "license": "MIT" + }, "node_modules/lru-cache": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", @@ -2316,6 +3378,32 @@ "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, + "node_modules/magic-string": { + "version": "0.30.21", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz", + "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.5" + } + }, + "node_modules/make-dir": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", + "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "dev": true, + "license": "MIT", + "dependencies": { + "semver": "^6.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/math-intrinsics": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", @@ -2409,6 +3497,27 @@ "dev": true, "license": "MIT" }, + "node_modules/node-fetch": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", + "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", + "dev": true, + "license": "MIT", + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, "node_modules/node-releases": { "version": "2.0.46", "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.46.tgz", @@ -2419,6 +3528,26 @@ "node": ">=18" } }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dev": true, + "license": "ISC", + "dependencies": { + "wrappy": "1" + } + }, "node_modules/optionator": { "version": "0.9.4", "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", @@ -2479,6 +3608,16 @@ "node": ">=8" } }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/path-key": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", @@ -2542,7 +3681,6 @@ "version": "4.2.0", "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", - "dev": true, "license": "MIT" }, "node_modules/prelude-ls": { @@ -2555,6 +3693,27 @@ "node": ">= 0.8.0" } }, + "node_modules/process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", + "dev": true, + "license": "MIT" + }, + "node_modules/prompts": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", + "integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "kleur": "^3.0.3", + "sisteransi": "^1.0.5" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/proxy-from-env": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-2.1.0.tgz", @@ -2633,6 +3792,38 @@ "react-dom": ">=18" } }, + "node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dev": true, + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/require-module": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/require-module/-/require-module-0.1.0.tgz", + "integrity": "sha512-fbr7gXnwot8k98dOUIq9KA4tvEot+CNMg1GR6j1v+7gI3aECMeyxmw2Ux0RWecPR6GfLqktVJ84GlTXoFlS2Cw==", + "dev": true, + "license": "MIT", + "dependencies": { + "resolve": "~0.6.1" + } + }, + "node_modules/resolve": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-0.6.3.tgz", + "integrity": "sha512-UHBY3viPlJKf85YijDUcikKX6tmF4SokIDp518ZDVT92JNDcG5uKIthaT/owt3Sar0lwtOafsQuwrg22/v2Dwg==", + "dev": true, + "license": "MIT" + }, "node_modules/rolldown": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.0.2.tgz", @@ -2667,6 +3858,27 @@ "@rolldown/binding-win32-x64-msvc": "1.0.2" } }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, "node_modules/scheduler": { "version": "0.27.0", "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.27.0.tgz", @@ -2712,6 +3924,20 @@ "node": ">=8" } }, + "node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/sisteransi": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", + "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==", + "dev": true, + "license": "MIT" + }, "node_modules/source-map-js": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", @@ -2722,6 +3948,71 @@ "node": ">=0.10.0" } }, + "node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "dev": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, + "node_modules/styled-components": { + "version": "6.4.2", + "resolved": "https://registry.npmjs.org/styled-components/-/styled-components-6.4.2.tgz", + "integrity": "sha512-xZBhBJsMtGqb+aKcwKgaT+BtuFums9VynX2JRvXJGTx5UfZzN12rk5r4nVdhXYvRw+hE7yiYxVrOqJZaK2+Txg==", + "license": "MIT", + "dependencies": { + "@emotion/is-prop-valid": "1.4.0", + "css-to-react-native": "3.2.0", + "csstype": "3.2.3", + "stylis": "4.3.6" + }, + "engines": { + "node": ">= 16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/styled-components" + }, + "peerDependencies": { + "css-to-react-native": ">= 3.2.0", + "react": ">= 16.8.0", + "react-dom": ">= 16.8.0", + "react-native": ">= 0.68.0" + }, + "peerDependenciesMeta": { + "css-to-react-native": { + "optional": true + }, + "react-dom": { + "optional": true + }, + "react-native": { + "optional": true + } + } + }, + "node_modules/stylis": { + "version": "4.3.6", + "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.3.6.tgz", + "integrity": "sha512-yQ3rwFWRfwNUY7H5vpU0wfdkNSnvnJinhF9830Swlaxl03zsOjCfmX0ugac+3LtK0lYSgwL/KXc8oYL3mG4YFQ==", + "license": "MIT" + }, + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/tailwindcss": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.3.0.tgz", @@ -2729,6 +4020,37 @@ "dev": true, "license": "MIT" }, + "node_modules/tapable": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.3.3.tgz", + "integrity": "sha512-uxc/zpqFg6x7C8vOE7lh6Lbda8eEL9zmVm/PLeTPBRhh1xCgdWaQ+J1CUieGpIfm2HdtsUpRv+HshiasBMcc6A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/tar-stream": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz", + "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "bl": "^4.0.3", + "end-of-stream": "^1.4.1", + "fs-constants": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^3.1.1" + }, + "engines": { + "node": ">=6" + } + }, "node_modules/tinyglobby": { "version": "0.2.16", "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.16.tgz", @@ -2746,6 +4068,13 @@ "url": "https://github.com/sponsors/SuperchupuDev" } }, + "node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", + "dev": true, + "license": "MIT" + }, "node_modules/tslib": { "version": "2.8.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", @@ -2765,6 +4094,39 @@ "node": ">= 0.8.0" } }, + "node_modules/typedarray-to-buffer": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", + "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-typedarray": "^1.0.0" + } + }, + "node_modules/unique-string": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unique-string/-/unique-string-2.0.0.tgz", + "integrity": "sha512-uNaeirEPvpZWSgzwsPGtU2zVSTrn/8L5q/IexZmH0eH6SA73CmAA5U4GwORTxQAZs95TAXLNqeLoPPNO5gZfWg==", + "dev": true, + "license": "MIT", + "dependencies": { + "crypto-random-string": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/universalify": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", + "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4.0.0" + } + }, "node_modules/update-browserslist-db": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.2.3.tgz", @@ -2806,6 +4168,13 @@ "punycode": "^2.1.0" } }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "dev": true, + "license": "MIT" + }, "node_modules/vite": { "version": "8.0.14", "resolved": "https://registry.npmjs.org/vite/-/vite-8.0.14.tgz", @@ -2884,6 +4253,24 @@ } } }, + "node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", + "dev": true, + "license": "BSD-2-Clause" + }, + "node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "dev": true, + "license": "MIT", + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, "node_modules/which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", @@ -2910,6 +4297,36 @@ "node": ">=0.10.0" } }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/write-file-atomic": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz", + "integrity": "sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==", + "dev": true, + "license": "ISC", + "dependencies": { + "imurmurhash": "^0.1.4", + "is-typedarray": "^1.0.0", + "signal-exit": "^3.0.2", + "typedarray-to-buffer": "^3.1.5" + } + }, + "node_modules/xdg-basedir": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-4.0.0.tgz", + "integrity": "sha512-PSNhEJDejZYV7h50BohL09Er9VaIefr2LMAf3OEmpCkjOi34eYyQYAXUTjEQtZJTKcF0E2UKTh+osDLsgNim9Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, "node_modules/yallist": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", @@ -2930,6 +4347,31 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/zip-a-folder": { + "version": "0.0.12", + "resolved": "https://registry.npmjs.org/zip-a-folder/-/zip-a-folder-0.0.12.tgz", + "integrity": "sha512-wZGiWgp3z2TocBlzx3S5tsLgPbT39qG2uIZmn2MhYLVjhKIr2nMhg7i4iPDL4W3XvMDaOEEVU5ZB0Y/Pt6BLvA==", + "dev": true, + "license": "MIT", + "dependencies": { + "archiver": "^3.1.1" + } + }, + "node_modules/zip-stream": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/zip-stream/-/zip-stream-2.1.3.tgz", + "integrity": "sha512-EkXc2JGcKhO5N5aZ7TmuNo45budRaFGHOmz24wtJR7znbNqDPmdZtUauKX6et8KAVseAMBOyWJqEpXcHTBsh7Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "archiver-utils": "^2.1.0", + "compress-commons": "^2.1.1", + "readable-stream": "^3.4.0" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/zod": { "version": "4.4.3", "resolved": "https://registry.npmjs.org/zod/-/zod-4.4.3.tgz", diff --git a/package.json b/package.json index 00dfaeb..351dd04 100644 --- a/package.json +++ b/package.json @@ -7,22 +7,27 @@ "dev": "vite", "build": "vite build", "lint": "eslint .", - "preview": "vite preview" + "preview": "vite preview", + "deploy": "npm run build && vk-miniapps-deploy" }, "dependencies": { + "@react-oauth/google": "^0.13.5", "@vkontakte/vk-bridge": "^3.0.2", "axios": "^1.16.1", "framer-motion": "^12.40.0", "lucide-react": "^1.16.0", "react": "^19.2.6", "react-dom": "^19.2.6", - "react-router-dom": "^7.15.1" + "react-router-dom": "^7.15.1", + "styled-components": "^6.4.2" }, "devDependencies": { "@eslint/js": "^10.0.1", + "@tailwindcss/postcss": "^4.3.0", "@types/react": "^19.2.14", "@types/react-dom": "^19.2.3", "@vitejs/plugin-react": "^6.0.1", + "@vkontakte/vk-miniapps-deploy": "^1.0.2", "autoprefixer": "^10.5.0", "eslint": "^10.3.0", "eslint-plugin-react-hooks": "^7.1.1", diff --git a/postcss.config.js b/postcss.config.js new file mode 100644 index 0000000..3a29142 --- /dev/null +++ b/postcss.config.js @@ -0,0 +1,6 @@ +export default { + plugins: { + '@tailwindcss/postcss': {}, // <--- ИСПРАВЛЕНО ПОД ТРЕБОВАНИЯ TAILWIND V4 + autoprefixer: {}, + }, +} \ No newline at end of file diff --git a/src/App.css b/src/App.css index f90339d..b9d355d 100644 --- a/src/App.css +++ b/src/App.css @@ -1,184 +1,42 @@ -.counter { - font-size: 16px; - padding: 5px 10px; - border-radius: 5px; - color: var(--accent); - background: var(--accent-bg); - border: 2px solid transparent; - transition: border-color 0.3s; - margin-bottom: 24px; +#root { + max-width: 1280px; + margin: 0 auto; + padding: 2rem; + text-align: center; +} - &:hover { - border-color: var(--accent-border); +.logo { + height: 6em; + padding: 1.5em; + will-change: filter; + transition: filter 300ms; +} +.logo:hover { + filter: drop-shadow(0 0 2em #646cffaa); +} +.logo.react:hover { + filter: drop-shadow(0 0 2em #61dafbaa); +} + +@keyframes logo-spin { + from { + transform: rotate(0deg); } - &:focus-visible { - outline: 2px solid var(--accent); - outline-offset: 2px; + to { + transform: rotate(360deg); } } -.hero { - position: relative; - - .base, - .framework, - .vite { - inset-inline: 0; - margin: 0 auto; - } - - .base { - width: 170px; - position: relative; - z-index: 0; - } - - .framework, - .vite { - position: absolute; - } - - .framework { - z-index: 1; - top: 34px; - height: 28px; - transform: perspective(2000px) rotateZ(300deg) rotateX(44deg) rotateY(39deg) - scale(1.4); - } - - .vite { - z-index: 0; - top: 107px; - height: 26px; - width: auto; - transform: perspective(2000px) rotateZ(300deg) rotateX(40deg) rotateY(39deg) - scale(0.8); +@media (prefers-reduced-motion: no-preference) { + a:nth-of-type(2) .logo { + animation: logo-spin infinite 20s linear; } } -#center { - display: flex; - flex-direction: column; - gap: 25px; - place-content: center; - place-items: center; - flex-grow: 1; - - @media (max-width: 1024px) { - padding: 32px 20px 24px; - gap: 18px; - } +.card { + padding: 2em; } -#next-steps { - display: flex; - border-top: 1px solid var(--border); - text-align: left; - - & > div { - flex: 1 1 0; - padding: 32px; - @media (max-width: 1024px) { - padding: 24px 20px; - } - } - - .icon { - margin-bottom: 16px; - width: 22px; - height: 22px; - } - - @media (max-width: 1024px) { - flex-direction: column; - text-align: center; - } -} - -#docs { - border-right: 1px solid var(--border); - - @media (max-width: 1024px) { - border-right: none; - border-bottom: 1px solid var(--border); - } -} - -#next-steps ul { - list-style: none; - padding: 0; - display: flex; - gap: 8px; - margin: 32px 0 0; - - .logo { - height: 18px; - } - - a { - color: var(--text-h); - font-size: 16px; - border-radius: 6px; - background: var(--social-bg); - display: flex; - padding: 6px 12px; - align-items: center; - gap: 8px; - text-decoration: none; - transition: box-shadow 0.3s; - - &:hover { - box-shadow: var(--shadow); - } - .button-icon { - height: 18px; - width: 18px; - } - } - - @media (max-width: 1024px) { - margin-top: 20px; - flex-wrap: wrap; - justify-content: center; - - li { - flex: 1 1 calc(50% - 8px); - } - - a { - width: 100%; - justify-content: center; - box-sizing: border-box; - } - } -} - -#spacer { - height: 88px; - border-top: 1px solid var(--border); - @media (max-width: 1024px) { - height: 48px; - } -} - -.ticks { - position: relative; - width: 100%; - - &::before, - &::after { - content: ''; - position: absolute; - top: -4.5px; - border: 5px solid transparent; - } - - &::before { - left: 0; - border-left-color: var(--border); - } - &::after { - right: 0; - border-right-color: var(--border); - } +.read-the-docs { + color: #888; } diff --git a/src/App.jsx b/src/App.jsx index fa09ed9..19ec039 100644 --- a/src/App.jsx +++ b/src/App.jsx @@ -1,113 +1,183 @@ import { useState, useEffect } from 'react'; -import { BrowserRouter as Router, Routes, Route, Link, useNavigate } from 'react-router-dom'; +import { HashRouter as Router, Routes, Route, useNavigate, useLocation } from 'react-router-dom'; +import { GoogleOAuthProvider } from '@react-oauth/google'; import bridge from '@vkontakte/vk-bridge'; -import axios from 'axios'; -import { Cpu, User, Loader2 } from 'lucide-react'; +import { motion, AnimatePresence } from 'framer-motion'; +import { Cpu, Globe, ShoppingCart, User, Mail, Sun, Moon } from 'lucide-react'; +import './index.css'; -import VkDashboard from './pages/VkDashboard'; -import VkPayment from './pages/VkPayment'; -import VkKabinet from './pages/VkKabinet'; +// ИМПОРТЫ ВАШИХ ОРИГИНАЛЬНЫХ СТРАНИЦ И КОМПОНЕНТОВ +import Login from './components/Login'; +import Home from './pages/Home'; +import About from './pages/About'; +import Contact from './pages/Contact'; +import Dashboard from './pages/Dashboard'; +import Kabinet from './pages/Kabinet'; +import Payment from './pages/Payment'; -const API_URL = 'https://diplomnexus.aptcloud.ru'; +const clientId = '631083577297-n17acu7qspb1n9n8lhmr8q43b4vbpif1.apps.googleusercontent.com'; function AppContent() { - const [user, setUser] = useState(null); - const [loading, setLoading] = useState(true); - const [error, setError] = useState(null); + const [isAuthenticated, setIsAuthenticated] = useState(!!localStorage.getItem('token')); + const [user, setUser] = useState(JSON.parse(localStorage.getItem('userInfo')) || null); + const [showLogin, setShowLogin] = useState(false); + const [showRegister, setShowRegister] = useState(false); + + // Управление темой (Светлая по умолчанию) + const [theme, setTheme] = useState(localStorage.getItem('theme') || 'light'); + const navigate = useNavigate(); + const location = useLocation(); useEffect(() => { - const autoLogin = async () => { - const searchParams = new URLSearchParams(window.location.search); - const isVk = searchParams.has('vk_user_id') && searchParams.has('sign'); + document.body.className = theme; + localStorage.setItem('theme', theme); + }, [theme]); - if (!isVk) { - setLoading(false); - setError('Пожалуйста, запустите приложение внутри ВКонтакте (VK Mini Apps).'); - return; - } + // Запуск ВК-моста + useEffect(() => { + bridge.send('VKWebAppInit'); + }, []); - try { - // Получаем нативные данные профиля от VK - const vkUser = await bridge.send('VKWebAppGetUserInfo'); + const handleAuth = (userInfo) => { + setIsAuthenticated(true); + setUser(userInfo); + localStorage.setItem('userInfo', JSON.stringify(userInfo)); + setShowLogin(false); + setShowRegister(false); + navigate('/dashboard'); + }; - // Собираем параметры запуска для подписи - const launchParams = {}; - searchParams.forEach((value, key) => { - if (key.startsWith('vk_') || key === 'sign') { - launchParams[key] = value; - } - }); + const handleLogout = () => { + setIsAuthenticated(false); + setUser(null); + localStorage.clear(); + navigate('/'); + }; - // Отправляем на ваш основной бэкенд для проверки сигнатуры и авторизации - const res = await axios.post(`${API_URL}/auth/vk`, { - launchParams, - userInfo: vkUser - }); - - const { token, user: appUser } = res.data; - - localStorage.setItem('token', token); - localStorage.setItem('userInfo', JSON.stringify(appUser)); - - setUser(appUser); - setLoading(false); - navigate('/'); // Переходим в каталог - } catch (err) { - console.error('Ошибка авторизации VK:', err); - setError('Не удалось войти через ВКонтакте. Проверьте настройки бэкенда.'); - setLoading(false); - } - }; - - autoLogin(); - }, [navigate]); - - if (loading) { - return ( -
- -

NEXUS SECURE CONNECTING...

-
- ); - } - - if (error) { - return ( -
-

⚠️ ОШИБКА ИНИЦИАЛИЗАЦИИ

-

{error}

-
- ); - } + // Логика перехода в приватные разделы + const handleProtectedNavigation = (path) => { + if (isAuthenticated) { + navigate(path); + } else { + setShowLogin(true); + } + }; + const handleProfileClick = () => { + if (isAuthenticated) { + navigate('/kabinet'); + } else { + setShowLogin(true); + } + }; return ( -
- - } /> - } /> - } /> - +
+ + {/* КНОПКА СМЕНЫ ТЕМЫ (ПАРЯЩАЯ ВВЕРХУ СПРАВА) */} +
+ +
+ + {/* ФОРМА АВТОРИЗАЦИИ (Login.jsx) */} + { setShowLogin(false); setShowRegister(false); }} + onSuccess={handleAuth} + onSwitchToReg={() => { setShowLogin(false); setShowRegister(true); }} + onSwitchToLogin={() => { setShowRegister(false); setShowLogin(true); }} + /> + + {/* МАРШРУТИЗАЦИЯ СТРАНИЦ */} + + + } /> + } /> + } /> + + {/* Защищенные разделы */} + } /> + } /> + } /> + + + + {/* ПАРИРУЮЩИЙ BOTTOM NAV НА 5 КНОПОК (Стиль Akenai VPN) */} +
+ + {/* Кнопка: ГЛАВНАЯ */} + + + {/* Кнопка: О НАС */} + + + {/* Кнопка: КАТАЛОГ */} + + + {/* Кнопка: КОНТАКТЫ */} + + + {/* Кнопка: ЛИЧНЫЙ КАБИНЕТ */} + +
- {/* Мобильный док-бар */} -
); } export default function App() { return ( - - - + + + + + ); } \ No newline at end of file diff --git a/src/assets/hero.png b/src/assets/hero.png deleted file mode 100644 index 02251f4..0000000 Binary files a/src/assets/hero.png and /dev/null differ diff --git a/src/assets/vite.svg b/src/assets/vite.svg deleted file mode 100644 index 5101b67..0000000 --- a/src/assets/vite.svg +++ /dev/null @@ -1 +0,0 @@ -Vite diff --git a/src/components/ActionMenu.jsx b/src/components/ActionMenu.jsx new file mode 100644 index 0000000..f972c7a --- /dev/null +++ b/src/components/ActionMenu.jsx @@ -0,0 +1,122 @@ +import React, { useState, useRef, useEffect } from 'react'; +import styled from 'styled-components'; +import { Pencil, ShieldPlus, Settings, Trash2, MoreVertical } from 'lucide-react'; + +const ActionMenu = ({ onEdit, onDelete }) => { + const [isOpen, setIsOpen] = useState(false); + const menuRef = useRef(null); + + // Закрытие при клике вне компонента + useEffect(() => { + function handleClickOutside(event) { + if (menuRef.current && !menuRef.current.contains(event.target)) { + setIsOpen(false); + } + } + document.addEventListener("mousedown", handleClickOutside); + return () => document.removeEventListener("mousedown", handleClickOutside); + }, [menuRef]); + + const handleAction = (action) => { + action(); + setIsOpen(false); + }; + + return ( +
+ {/* КНОПКА ТРИ ТОЧКИ */} + + + {/* ВЫПАДАЮЩЕЕ МЕНЮ */} + {isOpen && ( + +
+
    + {/* РЕДАКТИРОВАТЬ */} +
  • handleAction(onEdit)}> + +

    Изменить

    +
  • +
+
+
    + {/* УДАЛИТЬ */} +
  • handleAction(onDelete)}> + +

    Удалить

    +
  • +
+
+ + )} +
+ ); +}; + +// ТВОЙ STYLED COMPONENT (с небольшими правками позиционирования) +const MenuContainer = styled.div` + .card { + width: 180px; + background-color: rgba(36, 40, 50, 1); + background-image: linear-gradient(139deg, rgba(36, 40, 50, 1) 0%, rgba(36, 40, 50, 1) 0%, rgba(37, 28, 40, 1) 100%); + border-radius: 10px; + padding: 10px 0px; + display: flex; + flex-direction: column; + gap: 6px; + border: 1px solid rgba(255,255,255,0.1); + box-shadow: 0 10px 30px rgba(0,0,0,0.5); + } + + .card .separator { + border-top: 1px solid #42434a; + margin: 4px 0; + } + + .card .list { + list-style-type: none; + display: flex; + flex-direction: column; + gap: 4px; + padding: 0px 8px; + } + + .card .list .element { + display: flex; + align-items: center; + color: #9ca3af; + gap: 10px; + transition: all 0.2s ease-out; + padding: 8px 10px; + border-radius: 6px; + cursor: pointer; + } + + .card .list .element .label { + font-weight: 500; + font-size: 13px; + line-height: 1; + } + + .card .list .element:hover { + background-color: var(--accent-color, #5353ff); + color: #ffffff; + transform: translateX(2px); + } + + .card .list .delete:hover { + background-color: #ef4444; /* Красный tailwind */ + color: white; + } + + .card .list .element:active { + transform: scale(0.98); + } +`; + +export default ActionMenu; \ No newline at end of file diff --git a/src/components/ArcReactor.jsx b/src/components/ArcReactor.jsx new file mode 100644 index 0000000..a8e182c --- /dev/null +++ b/src/components/ArcReactor.jsx @@ -0,0 +1,132 @@ +import React from 'react'; +import styled from 'styled-components'; + +const ArcReactor = () => { + return ( + +
+ + {/* LAYER 1 (Внешнее кольцо) */} + + + + + + + + {/* LAYER 2 (Вращающиеся элементы) */} + + + + + + + + + + + + + + + + {/* LAYER 4 (Центр) */} + + + + + +
+
+ ); +}; + +const StyledWrapper = styled.div` + .svg-frame { + position: relative; + width: 300px; + height: 300px; + transform-style: preserve-3d; + display: flex; + justify-content: center; + align-items: center; + } + + .svg-frame svg { + position: absolute; + transition: .5s; + z-index: calc(1 - (0.2 * var(--j))); + transform-origin: center; + width: 344px; + height: 344px; + fill: none; + /* Тень, чтобы линии было видно на белом */ + filter: drop-shadow(0 0 5px var(--accent-color)); + } + + /* Цвета с использованием CSS переменных */ + .accent-stroke { + stroke: var(--accent-color); + } + .accent-fill { + fill: var(--accent-color); + } + + /* ЦЕНТР ЖЕЛТЫЙ (#center1) */ + #center1 { + fill: #ffff00; /* Яркий желтый */ + stroke: #000; /* Черная обводка для контраста на белом */ + stroke-width: 1px; + animation: rotate16 2s ease-in-out infinite alternate; + transform-origin: center; + } + + /* Внутренний центр */ + #center { + fill: var(--accent-color); + transition: .5s; + transform-origin: center; + } + + .svg-frame:hover svg { + transform: rotate(-80deg) skew(30deg) translateX(calc(45px * var(--i))) translateY(calc(-35px * var(--i))); + } + + .svg-frame:hover svg #center { + transform: rotate(-30deg) translateX(45px) translateY(-3px); + } + + #out2 { + animation: rotate16 7s ease-in-out infinite alternate; + transform-origin: center; + } + + @keyframes rotate16 { + to { + transform: rotate(360deg); + } + } +`; + +export default ArcReactor; \ No newline at end of file diff --git a/src/components/Fingerprint.jsx b/src/components/Fingerprint.jsx new file mode 100644 index 0000000..9395983 --- /dev/null +++ b/src/components/Fingerprint.jsx @@ -0,0 +1,34 @@ +import React from 'react'; +import styled from 'styled-components'; + +const Fingerprint = () => { + return ( + +
+ + + +
+
+
+
Verifying...
+
+ + ); +} + +const StyledWrapper = styled.div` + .fingerprint-container { position: relative; width: 120px; height: 120px; cursor: pointer; border-radius: 50%; margin: 0 auto; } + .fingerprint-svg { width: 100%; height: 100%; color: #00ff00; filter: drop-shadow(0 0 5px #00ff00); transition: transform 0.2s ease; } + .fingerprint-path { stroke-dasharray: 500; stroke-dashoffset: 0; animation: draw 4s infinite linear; } + .scan-line { position: absolute; top: 0; left: 0; width: 100%; height: 3px; background: linear-gradient(to right, transparent, #00ff00, transparent); opacity: 0; } + .status { position: absolute; bottom: -30px; width: 100%; text-align: center; color: #00ff00; font-size: 14px; text-transform: uppercase; letter-spacing: 2px; animation: glitch-text 2s infinite; } + + .fingerprint-container:hover .scan-line { animation: scan 1s infinite linear; opacity: 0.7; } + + @keyframes draw { 0% { stroke-dashoffset: 500; } 100% { stroke-dashoffset: 0; } } + @keyframes scan { 0% { transform: translateY(0); opacity: 0.7; } 50% { opacity: 1; } 100% { transform: translateY(120px); opacity: 0.7; } } + @keyframes glitch-text { 0% { transform: translate(0); } 20% { transform: translate(-1px, 1px); } 40% { transform: translate(1px, -1px); } 60% { transform: translate(-1px, 0); } 80% { transform: translate(1px, 0); } 100% { transform: translate(0); } } +`; + +export default Fingerprint; \ No newline at end of file diff --git a/src/components/Iphone.jsx b/src/components/Iphone.jsx new file mode 100644 index 0000000..6bedcda --- /dev/null +++ b/src/components/Iphone.jsx @@ -0,0 +1,70 @@ +import React from 'react'; +import styled from 'styled-components'; + +const Iphone = () => { + return ( + +
+
+
+
+
+
+
NEXUSSYSTEM
+
+
+
+
+
+
+
+
+ + ); +} + +const StyledWrapper = styled.div` + .card { + width: 210px; height: 400px; background: black; border-radius: 35px; + border: 2px solid rgb(40, 40, 40); padding: 7px; position: relative; + box-shadow: 2px 5px 15px rgba(0, 0, 0, 0.486); margin: 0 auto; + } + .card-int { + background-image: linear-gradient(to right bottom, #ff0000, #ff0045, #ff0078, #ea00aa, #b81cd7, #8a3ad6, #5746cf, #004ac2, #003d94, #002e66, #001d3a, #020812); + background-size: 200% 200%; background-position: 0% 0%; height: 100%; border-radius: 25px; + transition: all 0.6s ease-out; overflow: hidden; + } + .card:hover .card-int { background-position: 100% 100%; } + .top { + position: absolute; top: 0px; right: 50%; transform: translate(50%, 0%); + width: 35%; height: 18px; background-color: black; + border-bottom-left-radius: 10px; border-bottom-right-radius: 10px; + } + .speaker { + position: absolute; top: 2px; right: 50%; transform: translate(50%, 0%); + width: 40%; height: 2px; border-radius: 2px; background-color: rgb(20, 20, 20); + } + .camera { + position: absolute; top: 6px; right: 84%; transform: translate(50%, 0%); + width: 6px; height: 6px; border-radius: 50%; background-color: rgba(255, 255, 255, 0.048); + } + .int { + position: absolute; width: 3px; height: 3px; border-radius: 50%; + top: 50%; right: 50%; transform: translate(50%, -50%); background-color: rgba(0, 0, 255, 0.212); + } + .btn1, .btn2, .btn3, .btn4 { position: absolute; width: 2px; background-image: linear-gradient(to right, #111111, #222222, #333333, #464646, #595959); } + .btn1 { height: 45px; top: 30%; right: -4px; } + .btn2 { height: 30px; top: 26%; left: -4px; } + .btn3 { height: 30px; top: 36%; left: -4px; } + .btn4 { height: 45px; top: 11%; right: -4px; } /* Added missing btn4 style for completion */ + .hello { + display: flex; flex-flow: column; align-items: center; justify-content: center; + color: white; font-size: 2rem; font-weight: bold; text-align: center; + line-height: 35px; height: 100%; transition: 0.5s ease-in-out; + } + .hidden { display: block; opacity: 0; transition: all 0.3s ease-in; font-size: 1rem; } + .card:hover .hidden { opacity: 1; } + .card:hover .hello { transform: translateY(-20px); } +`; + +export default Iphone; diff --git a/src/components/Login.jsx b/src/components/Login.jsx new file mode 100644 index 0000000..ddb1ec4 --- /dev/null +++ b/src/components/Login.jsx @@ -0,0 +1,352 @@ +import { useState } from 'react'; +import axios from 'axios'; +import { motion, AnimatePresence } from 'framer-motion'; +import { X, User, Lock, Mail, Fingerprint, ScanFace, ArrowRight } from 'lucide-react'; +import { useGoogleLogin } from '@react-oauth/google'; +import bridge from '@vkontakte/vk-bridge'; +import GoogleButton from './google'; + +const Login = ({ showLogin, showRegister, onClose, onSuccess, onSwitchToReg, onSwitchToLogin }) => { + const [email, setEmail] = useState(''); + const [password, setPassword] = useState(''); + const [name, setName] = useState(''); + const [error, setError] = useState(''); + const [loading, setLoading] = useState(false); + const [step, setStep] = useState('auth'); // 'auth' или 'verify' + const [verificationCode, setVerificationCode] = useState(''); + + // Логика Google входа + const googleLogin = useGoogleLogin({ + onSuccess: async (tokenResponse) => { + try { + const res = await axios.post('https://diplomnexus.aptcloud.ru/auth/google', { + access_token: tokenResponse.access_token, + }); + localStorage.setItem('token', res.data.token); + onSuccess(res.data.user); + } catch (err) { + setError('Ошибка Google авторизации'); + } + }, + onError: () => setError('Google вход не удался'), + }); + const handleVkLogin = async () => { + setError(''); + setLoading(true); + try { + const searchParams = new URLSearchParams(window.location.search); + const launchParams = {}; + searchParams.forEach((value, key) => { + if (key.startsWith('vk_') || key === 'sign') { + launchParams[key] = value; + } + }); + + const vkUser = await bridge.send('VKWebAppGetUserInfo'); + + const res = await axios.post('https://diplomnexus.aptcloud.ru/auth/vk', { + launchParams, + userInfo: vkUser + }); + + localStorage.setItem('token', res.data.token); + onSuccess(res.data.user); + } catch (err) { + console.error(err); + setError('Не удалось авторизоваться через ВКонтакте'); + } finally { + setLoading(false); + } + }; + const handleSubmit = async (e, isRegister) => { + e.preventDefault(); + setError(''); + setLoading(true); + + try { + await new Promise(resolve => setTimeout(resolve, 800)); + + if (isRegister && step === 'auth') { + // Шаг 1: отправка данных для регистрации и генерации кода на почту + const endpoint = 'https://diplomnexus.aptcloud.ru/register'; + const payload = { email, password, name, referral_code: localStorage.getItem('referral_code') }; + + await axios.post(endpoint, payload); + setStep('verify'); // Переключаемся на окно ввода кода + } else if (isRegister && step === 'verify') { + // Шаг 2: отправка кода верификации + const endpoint = 'https://diplomnexus.aptcloud.ru/verify'; + const payload = { email, code: verificationCode }; + + const res = await axios.post(endpoint, payload); + localStorage.setItem('token', res.data.token); + onSuccess(res.data.user); + } else { + // Обычный вход в систему (Авторизация) + const endpoint = 'https://diplomnexus.aptcloud.ru/login'; + const payload = { email, password }; + + const res = await axios.post(endpoint, payload); + localStorage.setItem('token', res.data.token); + onSuccess(res.data.user); + } + } catch (err) { + setError(err.response?.data?.error || err.response?.data?.message || 'Ошибка доступа: Неверные данные'); + } finally { + setLoading(false); + } + }; + + // Возврат на шаг назад (если ввели не ту почту) + const handleBackToAuth = () => { + setStep('auth'); + setError(''); + setVerificationCode(''); + }; + + const handleSwitchToLogin = () => { + setStep('auth'); + setError(''); + onSwitchToLogin(); + }; + + const handleSwitchToReg = () => { + setStep('auth'); + setError(''); + onSwitchToReg(); + }; + + if (!showLogin && !showRegister) return null; + + const isRegister = showRegister; + + return ( + + {/* Убрал onClick={onClose} отсюда. Теперь клик по фону ничего не делает */} +
+ + {/* ФОНОВЫЕ ЭФФЕКТЫ */} +
+
+
+ + e.stopPropagation()} + > + {/* ОСНОВНОЙ КОНТЕЙНЕР (СТЕКЛО) */} +
+ + {/* ВЕРХНЯЯ ПОЛОСА ЗАГРУЗКИ */} + {loading && ( + + )} + +
+ + {/* === КРЕСТИК (ЗАКРЫВАЕТ ТОЛЬКО ОН) === */} + + + {/* ДЕКОРАТИВНЫЕ УГОЛКИ */} +
+
+
+ + {/* ЗАГОЛОВОК */} +
+
+
+ {isRegister && step === 'verify' ? ( + + ) : isRegister ? ( + + ) : ( + + )} +
+
+
+

+ {isRegister && step === 'verify' ? 'Верификация' : isRegister ? 'Инициализация' : 'Вход в систему'} +

+

+ SECURE CONNECTION ESTABLISHED +

+
+ + {/* ОШИБКА */} + + {error && ( + + {error} + + )} + + + {/* ФОРМА */} +
handleSubmit(e, isRegister)} className="space-y-5 relative z-10"> + + {isRegister && step === 'verify' ? ( + // --- ШАГ 2: Форма ввода верификационного кода --- +
+

+ Код подтверждения отправлен на почту
+ {email} +

+
+ + setVerificationCode(e.target.value)} + required + /> +
+ + + + +
+ ) : ( + // --- ШАГ 1: Стандартная форма ввода данных --- + <> + {isRegister && ( +
+ + setName(e.target.value)} + required + /> +
+ )} + +
+ + setEmail(e.target.value)} + required + /> +
+ +
+ + setPassword(e.target.value)} + required + /> +
+ + + + )} +
+ + {/* РАЗДЕЛИТЕЛЬ */} + {!(isRegister && step === 'verify') && ( + <> + {/* РАЗДЕЛИТЕЛЬ */} +
+ + Или через соц.сети + +
+ +
+
+ googleLogin()} /> + +
+
+ + )} + + {/* ПЕРЕКЛЮЧАТЕЛЬ */} +
+

+ {isRegister ? 'Уже есть доступ?' : 'Нет идентификатора?'} +

+ +
+ +
+
+ +
+ + ); +}; + +export default Login; diff --git a/src/components/Mesto.jsx b/src/components/Mesto.jsx new file mode 100644 index 0000000..4ecbc1b --- /dev/null +++ b/src/components/Mesto.jsx @@ -0,0 +1,281 @@ +import React from 'react'; +import styled from 'styled-components'; + +const Mesto = () => { + return ( + +
+ + {/* ФОН КАРТЫ */} +
+ + + + + + + + + + + + + + + + + + + + + + {/* === СЛОЙ 1: ЛАНДШАФТ === */} + + + + {/* Дорожки */} + {/* Парковка */} + + {/* Патио */} + + {/* === СЛОЙ 2: СТРОЕНИЯ === */} + + {/* ГАРАЖ */} + + + + + + + {/* ДОМ */} + + + + + + + + + {/* БАССЕЙН */} + + + {/* === СЛОЙ 3: ОБЪЕКТЫ === */} + + {/* МАШИНА */} + + + + + + + + {/* МАНГАЛЬНАЯ ЗОНА (Отодвинул вниз на траву - координаты 500, 300) */} + + {/* Плитка под мангал */} + + {/* Сам мангал */} + + + + {/* Дым */} + + + + + + + {/* ЧЕЛОВЕК (Вид СВЕРХУ) - Сдвинул ближе к центру дорожки */} + + + + + + {/* СОБАКА (Вид СВЕРХУ) */} + + + + + + + {/* ДЕРЕВЬЯ */} + + + + +
+ + {/* === ПИНЫ ДАТЧИКОВ === */} +
+ +
+
Ворота: Открыто
+
+ +
+
Камера: Запись
+
+ +
+
Центральный HUB
+
+ +
+
Бассейн: 24°C
+
+ +
+
GPS: Бобик
+
+ + {/* ЧЕЛОВЕК: Точка ровно над головой (320/600=53.3%, 380/500=76%) */} +
+
Движение: Гость
+
+ +
+
Домофон
+
+ + {/* СОЛНЕЧНЫЕ ПАНЕЛИ */} +
+
Электричество: 4.2 kW
+
+ +
+
Протечка: Кухня
+
+ + {/* МАНГАЛ: Точка над мангалом (500/600=83.3%, 300/500=60%) */} +
+
Мангал: 180°C
+
+ +
+
Охрана: Периметр
+
+ +
+
Анемометр: 3 м/с
+
+ + {/* ДАТЧИК ВЛАЖНОСТИ (ВЕРНУЛ) */} +
+
Влага (Газон): 65%
+
+ +
+
+
+ ); +} + +const StyledWrapper = styled.div` + width: 100%; + display: flex; + justify-content: center; + + .map-container { + --city-sign-color-back: rgba(15, 23, 42, 0.95); + --city-sign-color-font: #fff; + position: relative; + width: 100%; + max-width: 650px; + aspect-ratio: 4 / 3; + background: transparent; + } + + .map-background-wrapper { + position: absolute; + top: 0; left: 0; width: 100%; height: 100%; + border-radius: 20px; + overflow: hidden; + box-shadow: 0 20px 50px rgba(0,0,0,0.4), inset 0 0 0 2px rgba(255,255,255,0.1); + background: #7ec850; + z-index: 1; + } + + .map-svg { width: 100%; height: 100%; object-fit: cover; } + .map-cities { width: 100%; height: 100%; position: relative; z-index: 10; overflow: visible; } + + /* ПИНЫ (Маленькие точки) */ + .map-city { + position: absolute; + left: calc(var(--x) * 1%); + top: calc(var(--y) * 1%); + width: 12px; height: 12px; + background: #ef4444; + border: 2px solid white; + border-radius: 50%; + box-shadow: 0 2px 4px rgba(0,0,0,0.3); + transform: translate(-50%, -50%); + cursor: pointer; + transition: all 0.2s ease; + z-index: 20; + } + + .map-city[data-status="active"] { background: #22c55e; } + .map-city[data-status="normal"] { background: #3b82f6; } + .map-city[data-status="warning"] { background: #f59e0b; animation: pulse-warning 1s infinite; } + + .map-city.main-hub { + width: 18px; height: 18px; + background: #a855f7; + border-radius: 4px; + transform: translate(-50%, -50%) rotate(45deg); + } + + .map-city:hover { + transform: translate(-50%, -50%) scale(1.5); + z-index: 100; + border-color: #fbbf24; + } + + .map-city__label { + opacity: 0; + visibility: hidden; + position: absolute; + bottom: 20px; + left: 50%; + transform: translateX(-50%) translateY(5px); + white-space: nowrap; + z-index: 50; + transition: all 0.2s ease; + pointer-events: none; + } + + .map-city:hover .map-city__label { + opacity: 1; + visibility: visible; + transform: translateX(-50%) translateY(0); + } + + .map-city__sign { + background: var(--city-sign-color-back); + color: var(--city-sign-color-font); + padding: 4px 8px; + border-radius: 4px; + font-size: 10px; + font-family: 'Inter', sans-serif; + font-weight: 600; + display: flex; align-items: center; gap: 6px; + box-shadow: 0 4px 10px rgba(0,0,0,0.5); + border: 1px solid rgba(255,255,255,0.2); + } + + .map-city__sign::before { content: attr(data-icon); font-size: 12px; } + + .map-city__sign::after { + content: ''; position: absolute; bottom: -4px; left: 50%; + transform: translateX(-50%); + border-left: 4px solid transparent; border-right: 4px solid transparent; + border-top: 4px solid var(--city-sign-color-back); + } + + @keyframes pulse-warning { + 0% { box-shadow: 0 0 0 0 rgba(245, 158, 11, 0.7); } + 70% { box-shadow: 0 0 0 6px rgba(245, 158, 11, 0); } + 100% { box-shadow: 0 0 0 0 rgba(245, 158, 11, 0); } + } +`; + +export default Mesto; \ No newline at end of file diff --git a/src/components/NavBar.jsx b/src/components/NavBar.jsx new file mode 100644 index 0000000..8ecc684 --- /dev/null +++ b/src/components/NavBar.jsx @@ -0,0 +1,188 @@ +import React, { useState, useEffect } from 'react'; +import axios from 'axios'; +import { Link, useNavigate, useLocation } from 'react-router-dom'; +import { motion } from 'framer-motion'; +import { Cpu, LogOut, User, MessageCircle } from 'lucide-react'; +import LightDark from './lightdark'; +import UserAvatar from './UserAvatar'; +import SupportChat from './SupportChat'; + +const navLinks = [ + { path: '/', label: 'ГЛАВНАЯ' }, + { path: '/about', label: 'О НАС' }, + { path: '/contact', label: 'КОНТАКТЫ' }, +]; + +const catalogLink = [ + { path: '/dashboard', label: 'КАТАЛОГ' } +]; + +const NavBar = ({ user, onLogin, onLogout }) => { + const [theme, setTheme] = useState(localStorage.getItem('theme') || 'dark'); + const [hoveredPath, setHoveredPath] = useState(null); + const [unreadCount, setUnreadCount] = useState(0); + const [isChatOpen, setIsChatOpen] = useState(false); + const navigate = useNavigate(); + const location = useLocation(); + + const isAdmin = user?.role === 'admin'; + const roleLabel = isAdmin ? 'ADMIN' : 'OPERATOR'; + const roleColorClass = isAdmin ? 'text-red-500' : 'text-[var(--accent-color)]'; + const adminColorClass = 'text-red-500'; + + // --- 1. ТАБЛИЦЫ ОБОРУДОВАНИЯ (ЧИСТЫЕ ПУТИ ДЛЯ ВСЕХ) --- + const equipmentLinks = [ + { path: '/hubs', label: 'ХАБЫ' }, + { path: '/cameras', label: 'КАМЕРЫ' }, + { path: '/lighting', label: 'СВЕТ' }, + { path: '/sensors', label: 'ДАТЧИКИ' }, + ]; + + // --- 2. ТАБЛИЦЫ УПРАВЛЕНИЯ (ТОЛЬКО АДМИНУ) --- + const adminManagementLinks = [ + { path: '/users', label: 'ПОЛЬЗОВАТЕЛИ' }, + { path: '/orders', label: 'ЗАКАЗЫ' }, + { path: '/messages', label: 'ЧАТЫ' }, + { path: '/admin/logs', label: 'ЛОГИ' }, + ]; + + useEffect(() => { + document.body.className = theme; + localStorage.setItem('theme', theme); + }, [theme]); + + useEffect(() => { + if (user) { + const checkUnread = async () => { + try { + const token = localStorage.getItem('token'); + const res = await axios.get(`https://diplomnexus.aptcloud.ru/messages/unread?email=${user.email}`, { + headers: { Authorization: `Bearer ${token}` } + }); + setUnreadCount(res.data.count); + } catch (e) {} + }; + checkUnread(); + const interval = setInterval(checkUnread, 5000); + return () => clearInterval(interval); + } + }, [user]); + + const toggleTheme = () => setTheme(theme === 'dark' ? 'light' : 'dark'); + + const renderMenu = (links) => ( +
+ {links.map((link) => ( + setHoveredPath(link.path)} + onMouseLeave={() => setHoveredPath(null)} + className="relative px-3 xl:px-4 py-3 text-[9px] xl:text-[10px] font-bold tracking-widest text-[var(--text-color)] transition-colors hover:text-[var(--accent-color)] uppercase z-10 whitespace-nowrap" + > + {link.label} + + {hoveredPath === link.path && ( + +
+
+ + )} + + {location.pathname === link.path && ( + + )} + + ))} +
+ ); + + return ( + <> + + + {user && setIsChatOpen(false)} user={user} />} + + ); +}; + +export default NavBar; diff --git a/src/components/Notebook.jsx b/src/components/Notebook.jsx new file mode 100644 index 0000000..58d0e5e --- /dev/null +++ b/src/components/Notebook.jsx @@ -0,0 +1,553 @@ +import React from 'react'; +import styled from 'styled-components'; + +const Notebook = () => { + return ( + +
+
+
+
+
+
+
+
+ MacBook Air +
+ Layer 1 +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ + ); +} + +const StyledWrapper = styled.div` + .macbook { + width: 150px; + height: 96px; + position: absolute; + left: 50%; + top: 50%; + margin: -85px 0 0 -78px; + perspective: 500px; + } + + .shadow { + position: absolute; + width: 60px; + height: 0px; + left: 40px; + top: 160px; + transform: rotateX(80deg) rotateY(0deg) rotateZ(0deg); + box-shadow: 0 0 60px 40px rgba(0,0,0,0.3); + animation: shadow infinite 7s ease; + } + + .inner { + z-index: 20; + position: absolute; + width: 150px; + height: 96px; + left: 0; + top: 0; + transform-style: preserve-3d; + transform: rotateX(-20deg) rotateY(0deg) rotateZ(0deg); + animation: rotate infinite 7s ease; + } + + .screen { + width: 150px; + height: 96px; + position: absolute; + left: 0; + bottom: 0; + border-radius: 7px; + background: #ddd; + transform-style: preserve-3d; + transform-origin: 50% 93px; + transform: rotateX(0deg) rotateY(0deg) rotateZ(0deg); + animation: lid-screen infinite 7s ease; + background-image: linear-gradient(45deg, rgba(0,0,0,0.34) 0%,rgba(0,0,0,0) 100%); + background-position: left bottom; + background-size: 300px 300px; + box-shadow: inset 0 3px 7px rgba(255,255,255,0.5); + } + + .screen .logo { + position: absolute; + width: 20px; + height: 24px; + left: 50%; + top: 50%; + margin: -12px 0 0 -10px; + transform: rotateY(180deg) translateZ(0.1px); + } + + .screen .face-one { + width: 150px; + height: 96px; + position: absolute; + left: 0; + bottom: 0; + border-radius: 7px; + background: #d3d3d3; + transform: translateZ(2px); + background-image: linear-gradient(45deg,rgba(0,0,0,0.24) 0%,rgba(0,0,0,0) 100%); + } + + .screen .face-one .camera { + width: 3px; + height: 3px; + border-radius: 100%; + background: #000; + position: absolute; + left: 50%; + top: 4px; + margin-left: -1.5px; + } + + .screen .face-one .display { + width: 130px; + height: 74px; + margin: 10px; + background-color: #000; + background-size: 100% 100%; + border-radius: 1px; + position: relative; + box-shadow: inset 0 0 2px rgba(0,0,0,1); + } + + .screen .face-one .display .shade { + position: absolute; + left: 0; + top: 0; + width: 130px; + height: 74px; + background: linear-gradient(-135deg, rgba(255,255,255,0) 0%,rgba(255,255,255,0.1) 47%,rgba(255,255,255,0) 48%); + animation: screen-shade infinite 7s ease; + background-size: 300px 200px; + background-position: 0px 0px; + } + + .screen .face-one span { + position: absolute; + top: 85px; + left: 57px; + font-size: 6px; + color: #666 + } + + .macbody { + width: 150px; + height: 96px; + position: absolute; + left: 0; + bottom: 0; + border-radius: 7px; + background: #cbcbcb; + transform-style: preserve-3d; + transform-origin: 50% bottom; + transform: rotateX(-90deg); + animation: lid-macbody infinite 7s ease; + background-image: linear-gradient(45deg, rgba(0,0,0,0.24) 0%,rgba(0,0,0,0) 100%); + } + + .macbody .face-one { + width: 150px; + height: 96px; + position: absolute; + left: 0; + bottom: 0; + border-radius: 7px; + transform-style: preserve-3d; + background: #dfdfdf; + animation: lid-keyboard-area infinite 7s ease; + transform: translateZ(-2px); + background-image: linear-gradient(30deg, rgba(0,0,0,0.24) 0%,rgba(0,0,0,0) 100%); + } + + .macbody .touchpad { + width: 40px; + height: 31px; + position: absolute; + left: 50%; + top: 50%; + border-radius: 4px; + margin: -44px 0 0 -18px; + background: #cdcdcd; + background-image: linear-gradient(30deg, rgba(0,0,0,0.24) 0%,rgba(0,0,0,0) 100%); + box-shadow: inset 0 0 3px #888; + } + + .macbody .keyboard { + width: 130px; + height: 45px; + position: absolute; + left: 7px; + top: 41px; + border-radius: 4px; + transform-style: preserve-3d; + background: #cdcdcd; + background-image: linear-gradient(30deg, rgba(0,0,0,0.24) 0%,rgba(0,0,0,0) 100%); + box-shadow: inset 0 0 3px #777; + padding: 0 0 0 2px; + } + + .keyboard .key { + width: 6px; + height: 6px; + background: #444; + float: left; + margin: 1px; + transform: translateZ(-2px); + border-radius: 2px; + box-shadow: 0 -2px 0 #222; + animation: keys infinite 7s ease; + } + + .key.space { + width: 45px; + } + + .key.f { + height: 3px; + } + + .macbody .pad { + width: 5px; + height: 5px; + background: #333; + border-radius: 100%; + position: absolute; + } + + .pad.one { + left: 20px; + top: 20px; + } + + .pad.two { + right: 20px; + top: 20px; + } + + .pad.three { + right: 20px; + bottom: 20px; + } + + .pad.four { + left: 20px; + bottom: 20px; + } + + @keyframes rotate { + 0% { + transform: rotateX(-20deg) rotateY(0deg) rotateZ(0deg); + } + + 5% { + transform: rotateX(-20deg) rotateY(-20deg) rotateZ(0deg); + } + + 20% { + transform: rotateX(30deg) rotateY(200deg) rotateZ(0deg); + } + + 25% { + transform: rotateX(-60deg) rotateY(150deg) rotateZ(0deg); + } + + 60% { + transform: rotateX(-20deg) rotateY(130deg) rotateZ(0deg); + } + + 65% { + transform: rotateX(-20deg) rotateY(120deg) rotateZ(0deg); + } + + 80% { + transform: rotateX(-20deg) rotateY(375deg) rotateZ(0deg); + } + + 85% { + transform: rotateX(-20deg) rotateY(357deg) rotateZ(0deg); + } + + 87% { + transform: rotateX(-20deg) rotateY(360deg) rotateZ(0deg); + } + + 100% { + transform: rotateX(-20deg) rotateY(360deg) rotateZ(0deg); + } + } + + @keyframes lid-screen { + 0% { + transform: rotateX(0deg); + background-position: left bottom; + } + + 5% { + transform: rotateX(50deg); + background-position: left bottom; + } + + 20% { + transform: rotateX(-90deg); + background-position: -150px top; + } + + 25% { + transform: rotateX(15deg); + background-position: left bottom; + } + + 30% { + transform: rotateX(-5deg); + background-position: right top; + } + + 38% { + transform: rotateX(5deg); + background-position: right top; + } + + 48% { + transform: rotateX(0deg); + background-position: right top; + } + + 90% { + transform: rotateX(0deg); + background-position: right top; + } + + 100% { + transform: rotateX(0deg); + background-position: right center; + } + } + + @keyframes lid-macbody { + 0% { + transform: rotateX(-90deg); + } + + 50% { + transform: rotateX(-90deg); + } + + 100% { + transform: rotateX(-90deg); + } + } + + @keyframes lid-keyboard-area { + 0% { + background-color: #dfdfdf; + } + + 50% { + background-color: #bbb; + } + + 100% { + background-color: #dfdfdf; + } + } + + @keyframes screen-shade { + 0% { + background-position: -20px 0px; + } + + 5% { + background-position: -40px 0px; + } + + 20% { + background-position: 200px 0; + } + + 50% { + background-position: -200px 0; + } + + 80% { + background-position: 0px 0px; + } + + 85% { + background-position: -30px 0; + } + + 90% { + background-position: -20px 0; + } + + 100% { + background-position: -20px 0px; + } + } + + @keyframes keys { + 0% { + box-shadow: 0 -2px 0 #222; + } + + 5% { + box-shadow: 1 -1px 0 #222; + } + + 20% { + box-shadow: -1px 1px 0 #222; + } + + 25% { + box-shadow: -1px 1px 0 #222; + } + + 60% { + box-shadow: -1px 1px 0 #222; + } + + 80% { + box-shadow: 0 -2px 0 #222; + } + + 85% { + box-shadow: 0 -2px 0 #222; + } + + 87% { + box-shadow: 0 -2px 0 #222; + } + + 100% { + box-shadow: 0 -2px 0 #222; + } + } + + @keyframes shadow { + 0% { + transform: rotateX(80deg) rotateY(0deg) rotateZ(0deg); + box-shadow: 0 0 60px 40px rgba(0,0,0,0.3); + } + + 5% { + transform: rotateX(80deg) rotateY(10deg) rotateZ(0deg); + box-shadow: 0 0 60px 40px rgba(0,0,0,0.3); + } + + 20% { + transform: rotateX(30deg) rotateY(-20deg) rotateZ(-20deg); + box-shadow: 0 0 50px 30px rgba(0,0,0,0.3); + } + + 25% { + transform: rotateX(80deg) rotateY(-20deg) rotateZ(50deg); + box-shadow: 0 0 35px 15px rgba(0,0,0,0.1); + } + + 60% { + transform: rotateX(80deg) rotateY(0deg) rotateZ(-50deg) translateX(30px); + box-shadow: 0 0 60px 40px rgba(0,0,0,0.3); + } + + 100% { + box-shadow: 0 0 60px 40px rgba(0,0,0,0.3); + } + }`; + +export default Notebook; diff --git a/src/components/OsCore.jsx b/src/components/OsCore.jsx new file mode 100644 index 0000000..f9bc613 --- /dev/null +++ b/src/components/OsCore.jsx @@ -0,0 +1,102 @@ +import React from 'react'; +import styled from 'styled-components'; + +const OsCore = () => { + return ( + +
+
+
+
+
OS
+
+ + ); +} + +const StyledWrapper = styled.div` + .loader { + position: relative; + width: 150px; + height: 150px; + border-radius: 50%; + perspective: 800px; + display: flex; + justify-content: center; + align-items: center; + } + + .inner { + position: absolute; + box-sizing: border-box; + width: 100%; + height: 100%; + border-radius: 50%; + } + + /* Внешнее кольцо */ + .inner.one { + left: 0%; + top: 0%; + animation: rotate-one 1.5s linear infinite; + border-bottom: 4px solid var(--accent-color); + box-shadow: 0 0 10px var(--accent-color); + filter: drop-shadow(0 0 5px var(--accent-color)); + } + + /* Среднее кольцо */ + .inner.two { + right: 0%; + top: 0%; + animation: rotate-two 1.5s linear infinite; + border-right: 4px solid var(--text-color); + box-shadow: 0 0 10px var(--text-color); + opacity: 0.8; + } + + /* Внутреннее кольцо */ + .inner.three { + right: 0%; + bottom: 0%; + width: 70%; + height: 70%; + margin: 15%; /* Центрирование (100-70)/2 */ + animation: rotate-three 1.5s linear infinite; + border-top: 4px solid #a855f7; /* Purple */ + box-shadow: 0 0 10px #a855f7; + filter: drop-shadow(0 0 5px #a855f7); + } + + /* Текст в центре */ + .core-text { + font-family: monospace; + font-weight: 900; + font-size: 24px; + color: var(--text-color); + animation: pulse 2s infinite; + text-shadow: 0 0 10px var(--accent-color); + z-index: 10; + } + + @keyframes rotate-one { + 0% { transform: rotateX(35deg) rotateY(-45deg) rotateZ(0deg); } + 100% { transform: rotateX(35deg) rotateY(-45deg) rotateZ(360deg); } + } + + @keyframes rotate-two { + 0% { transform: rotateX(50deg) rotateY(10deg) rotateZ(0deg); } + 100% { transform: rotateX(50deg) rotateY(10deg) rotateZ(360deg); } + } + + @keyframes rotate-three { + 0% { transform: rotateX(35deg) rotateY(55deg) rotateZ(0deg); } + 100% { transform: rotateX(35deg) rotateY(55deg) rotateZ(360deg); } + } + + @keyframes pulse { + 0%, 100% { opacity: 1; transform: scale(1); } + 50% { opacity: 0.5; transform: scale(0.9); } + } +`; + +export default OsCore; \ No newline at end of file diff --git a/src/components/Pogoda.jsx b/src/components/Pogoda.jsx new file mode 100644 index 0000000..48364f3 --- /dev/null +++ b/src/components/Pogoda.jsx @@ -0,0 +1,161 @@ +import React from 'react'; +import styled from 'styled-components'; + +const Pogoda = () => { + return ( + +
+ + {/* Верхняя часть: Основная инфо */} +
+
+ {/* SVG Иконка: Облачно с прояснениями */} + + + + +
+
+
18°C
+
Ангарск
+
Иркутская обл.
+
+
+ + {/* Нижняя часть: Детали (Раскрывается при наведении) */} +
+ +
+ + + + 78% + Влага +
+ +
+ + + + 4 м/с + Ветер +
+ +
+ + + + + 752 + мм рт.ст +
+ +
+
+
+ ); +} + +const StyledWrapper = styled.div` + /* Стили контейнера */ + .weather-card { + width: 200px; + height: 90px; /* Компактная высота по умолчанию */ + background: rgba(255, 255, 255, 0.9); + border-radius: 20px; + padding: 15px; + box-shadow: 0 10px 30px rgba(0,0,0,0.2); + border: 1px solid rgba(255,255,255,0.5); + transition: all 0.4s cubic-bezier(0.175, 0.885, 0.32, 1.275); + overflow: hidden; + cursor: default; + display: flex; + flex-direction: column; + gap: 15px; + } + + /* При наведении карточка растет */ + .weather-card:hover { + height: 180px; + width: 220px; + transform: translateY(-10px); + background: #fff; + } + + /* Верхняя часть */ + .main-info { + display: flex; + align-items: center; + gap: 15px; + } + + .weather-icon { + width: 50px; + height: 50px; + } + + .text-container { + display: flex; + flex-direction: column; + } + + .temp { + font-size: 24px; + font-weight: 800; + color: #1e293b; + line-height: 1; + } + + .city { + font-size: 14px; + font-weight: 700; + color: #475569; + margin-top: 4px; + } + + .desc { + font-size: 10px; + color: #94a3b8; + } + + /* Детали (скрыты или сжаты по умолчанию) */ + .details { + display: flex; + justify-content: space-between; + opacity: 0; + transform: translateY(20px); + transition: all 0.3s ease; + border-top: 1px solid #e2e8f0; + padding-top: 15px; + } + + .weather-card:hover .details { + opacity: 1; + transform: translateY(0); + } + + .detail-item { + display: flex; + flex-direction: column; + align-items: center; + gap: 4px; + } + + .detail-icon { + width: 20px; + height: 20px; + } + + .detail-item span { + font-size: 12px; + font-weight: 700; + color: #334155; + } + + .detail-item small { + font-size: 9px; + color: #64748b; + } +`; + +export default Pogoda; diff --git a/src/components/Radar.jsx b/src/components/Radar.jsx new file mode 100644 index 0000000..5199f20 --- /dev/null +++ b/src/components/Radar.jsx @@ -0,0 +1,77 @@ +import React from 'react'; +import styled from 'styled-components'; + +const Radar = () => { + return ( + +
+ +
+
+ ); +} + +const StyledWrapper = styled.div` + .loader { + position: relative; + width: 120px; + height: 120px; + background: var(--glass-bg); + border-radius: 50%; + box-shadow: 0 0 50px var(--shadow-color); + border: 1px solid var(--text-color); + opacity: 0.8; + display: flex; + align-items: center; + justify-content: center; + overflow: hidden; + } + .loader::before { + content: ''; + position: absolute; + inset: 20px; + background: transparent; + border: 1px dashed var(--text-color); + opacity: 0.3; + border-radius: 50%; + } + .loader::after { + content: ''; + position: absolute; + width: 40px; + height: 40px; + border-radius: 50%; + border: 1px dashed var(--text-color); + opacity: 0.5; + } + .loader span { + position: absolute; + top: 50%; + left: 50%; + width: 50%; + height: 100%; + background: transparent; + transform-origin: top left; + animation: radar81 2s linear infinite; + border-top: 1px dashed var(--text-color); + } + .loader span::before { + content: ''; + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + background: var(--accent-color); + transform-origin: top left; + transform: rotate(-55deg); + filter: blur(30px) drop-shadow(20px 20px 20px var(--accent-color)); + opacity: 0.6; + } + @keyframes radar81 { + 0% { transform: rotate(0deg); } + 100% { transform: rotate(360deg); } + } +`; + +export default Radar; diff --git a/src/components/Record.jsx b/src/components/Record.jsx new file mode 100644 index 0000000..27e9ae8 --- /dev/null +++ b/src/components/Record.jsx @@ -0,0 +1,102 @@ +import React from 'react'; +import styled from 'styled-components'; + +const Button = () => { + return ( + +
+ +
+
+ ); +} + +const StyledWrapper = styled.div` + .btn-wrapper { + /* Масштабируем кнопку, чтобы она была компактной */ + transform: scale(0.7); + transform-origin: center right; + + --width: 120px; + --height: 50px; + --padding: 4px; + --border-radius: 30px; + --dot-size: 10px; + --btn-color: #202020; + --hue: 355deg; + --animation-duration: 1.2s; + + position: relative; + display: flex; + align-items: center; + justify-content: center; + width: var(--width); + height: var(--height); + border-radius: var(--border-radius); + border: none; + background-color: rgba(0,0,0,0.1); + box-shadow: 1px 1px 2px 0 rgba(255,255,255,0.1), 2px 2px 2px rgba(0,0,0,0.1) inset; + user-select: none; + z-index: 1; + } + + .btn { + display: flex; + align-items: center; + justify-content: center; + gap: 8px; + padding: 0; + width: calc(100% - 2 * var(--padding)); + height: calc(100% - 2 * var(--padding)); + border-radius: calc(var(--border-radius) - var(--padding)); + border: none; + cursor: pointer; + background: linear-gradient(rgba(255,255,255,0.1), rgba(0,0,0,0.1)), var(--btn-color); + box-shadow: 0 4px 8px rgba(0,0,0,0.3); + transition: all 0.2s ease; + z-index: 2; + } + + .btn-txt { + font-size: 14px; + font-weight: 800; + font-family: monospace; + letter-spacing: 1px; + color: #fff; + text-transform: uppercase; + } + + .dot { + position: relative; + width: var(--dot-size); + height: var(--dot-size); + border-radius: 50%; + background-color: #ff0000; + box-shadow: 0 0 10px #ff0000; + } + + /* Анимация пульсации */ + .pulse { + animation: pulse-red 1.5s infinite; + } + + @keyframes pulse-red { + 0% { transform: scale(0.95); box-shadow: 0 0 0 0 rgba(255, 0, 0, 0.7); } + 70% { transform: scale(1); box-shadow: 0 0 0 6px rgba(255, 0, 0, 0); } + 100% { transform: scale(0.95); box-shadow: 0 0 0 0 rgba(255, 0, 0, 0); } + } + + .btn:hover { + transform: translateY(-1px); + filter: brightness(1.2); + } + .btn:active { + transform: translateY(1px); + filter: brightness(0.9); + } +`; + +export default Button; diff --git a/src/components/Server.jsx b/src/components/Server.jsx new file mode 100644 index 0000000..05b5997 --- /dev/null +++ b/src/components/Server.jsx @@ -0,0 +1,171 @@ +import React from 'react'; +import styled from 'styled-components'; + +const Server = () => { + return ( + +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + + +
+
+
+ ); +} + +const StyledWrapper = styled.div` + .container_SevMini { + display: flex; + justify-content: center; + align-items: center; + flex-direction: column; + } + + .Ghost { + transform: translate(0px, -25px); + z-index: -1; + animation: opacidad 4s infinite ease-in-out; + } + + @keyframes opacidad { + 0% { + opacity: 1; + scale: 1; + } + + 50% { + opacity: 0.5; + scale: 0.9; + } + + 100% { + opacity: 1; + scale: 1; + } + } + + @keyframes estroboscopico { + 0% { + opacity: 1; + } + + 50% { + opacity: 0; + } + + 51% { + opacity: 1; + } + + 100% { + opacity: 1; + } + } + + @keyframes rebote { + 0%, + 100% { + transform: translateY(0); + } + + 50% { + transform: translateY(-10px); + } + } + + @keyframes estroboscopico1 { + 0%, + 50%, + 100% { + fill: rgb(255, 95, 74); + } + + 25%, + 75% { + fill: rgb(16, 53, 115); + } + } + + @keyframes estroboscopico2 { + 0%, + 50%, + 100% { + fill: #17e300; + } + + 25%, + 75% { + fill: #17e300b4; + } + } + + .SevMini { + animation: rebote 4s infinite ease-in-out; + } + + #strobe_led1 { + animation: estroboscopico 0.5s infinite; + } + + #strobe_color1 { + animation: estroboscopico2 0.8s infinite; + } + + #strobe_color3 { + animation: estroboscopico1 0.8s infinite; + animation-delay: 3s; + }`; + +export default Server; diff --git a/src/components/Social.jsx b/src/components/Social.jsx new file mode 100644 index 0000000..df4ab6c --- /dev/null +++ b/src/components/Social.jsx @@ -0,0 +1,215 @@ +import React from 'react'; +import styled from 'styled-components'; + +const Social = () => { + return ( + +
+ +
Социальные сети
+ +
+
+ ); +} + +const StyledWrapper = styled.div` + /* CSS Variables for colors */ + + .card { + position: relative; + /* Уменьшил размеры */ + width: 14em; + height: 18em; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + /* Адаптивный фон и цвет текста */ + background-color: var(--card-bg); + color: var(--text-color); + border: 1px solid var(--glass-border); + font-family: Montserrat, sans-serif; + font-weight: bold; + padding: 1em; + border-radius: 20px; + overflow: hidden; + z-index: 1; + row-gap: 0.8em; + } + + .card img { + /* Уменьшил картинку */ + width: 8em; + margin-right: 0.5em; + animation: move 10s ease-in-out infinite; + z-index: 5; + } + + .icons svg { + width: 18px; + height: 18px; + } + + /* Гравитация и фон (тут используем переменные для теней) */ + .card::before { + content: ""; + position: absolute; + width: 100%; + height: 100%; + inset: -3px; + border-radius: 10px; + background: radial-gradient(var(--text-color), transparent, transparent); + opacity: 0.1; + transform: translate(-5px, 250px); + transition: 0.4s ease-in-out; + z-index: -1; + } + .card:hover::before { + width: 150%; + height: 100%; + margin-left: -4.25em; + opacity: 0.1; + } + .card::after { + content: ""; + position: absolute; + inset: 2px; + border-radius: 20px; + background: var(--card-bg); + opacity: 0.9; + transition: all 0.4s ease-in-out; + z-index: -1; + } + + .heading { + z-index: 2; + transition: 0.4s ease-in-out; + font-size: 0.9em; + text-align: center; + } + + /* ЗВЕЗДЫ (ТЕНИ) - заменяем #fff на var(--text-color) */ + .heading::before { + content: ""; + position: absolute; + top: 0; left: 0; width: 2px; height: 2px; + border-radius: 50%; + opacity: 0.5; + /* Генерируем "звезды" используя цвет текста (белый в темной теме, черный в светлой) */ + box-shadow: + 220px 118px var(--text-color), 280px 176px var(--text-color), 40px 50px var(--text-color), + 60px 180px var(--text-color), 120px 130px var(--text-color), 180px 176px var(--text-color), + 220px 290px var(--text-color), 520px 250px var(--text-color), 400px 220px var(--text-color), + 50px 350px var(--text-color), 10px 230px var(--text-color); + z-index: -1; + transition: 1s ease; + animation: 1s glowing-stars linear alternate infinite; + } + + /* Другие слои звезд */ + .icons::before { + content: ""; position: absolute; top: 0; left: 0; width: 2px; height: 2px; + border-radius: 50%; opacity: 0.5; + box-shadow: + 140px 20px var(--text-color), 425px 20px var(--text-color), 70px 120px var(--text-color), + 20px 130px var(--text-color), 110px 80px var(--text-color), 280px 80px var(--text-color); + z-index: -1; + transition: 1.5s ease; + animation: 1s glowing-stars linear alternate infinite; + animation-delay: 0.4s; + } + + /* Анимации и эффекты при наведении и нажатии */ + .card:hover .heading::before, + .card:hover .icons::before { + filter: blur(3px); + } + + .heading::after { + content: ""; + top: -8.5%; left: -8.5%; position: absolute; + width: 7.5em; height: 7.5em; + border-radius: 50%; + background: var(--bg-color); + box-shadow: 0px 0px 100px var(--accent-color), inset var(--accent-color) 0px 0px 40px -12px; + opacity: 0.2; + transition: 0.4s ease-in-out; + z-index: -1; + } + .card:hover .heading::after { + box-shadow: 0px 0px 200px var(--accent-color), inset var(--accent-color) 0px 0px 40px -12px; + opacity: 0.6; + } + + .icons { + display: flex; align-items: center; justify-content: center; + flex-direction: row; column-gap: 1em; z-index: 1; + } + + .instagram, .x, .discord { + position: relative; transition: 0.4s ease-in-out; + color: var(--text-color); + } + + .instagram:after, .x:after, .discord:after { + content: ""; position: absolute; width: 0.5em; height: 0.5em; left: 0; + background-color: var(--text-color); + box-shadow: 0px 0px 10px var(--shadow-color); + border-radius: 50%; z-index: -1; transition: 0.3s ease-in-out; + } + + .instagram svg path, .x svg path, .discord svg path { + stroke: var(--text-color); opacity: 0.7; transition: 0.4s ease-in-out; + } + .instagram:hover svg path { stroke: #cc39a4; opacity: 1; } + .x:hover svg path { stroke: var(--text-color); opacity: 1; } + .discord:hover svg path { stroke: #8c9eff; opacity: 1; } + + .instagram:hover svg { scale: 1.4; } + .x:hover svg, .discord:hover svg { scale: 1.25; } + + .instagram:hover:after, .x:hover:after, .discord:hover:after { + scale: 4; transform: translateX(0.09em) translateY(0.09em); + } + + /* Shooting stars logic changed to adapt variables */ + @keyframes shootingStar { + 0% { transform: translateX(0) translateY(0); opacity: 1; } + 50% { transform: translateX(-55em) translateY(0); opacity: 1; } + 70% { transform: translateX(-70em) translateY(0); opacity: 0; } + 100% { transform: translateX(0) translateY(0); opacity: 0; } + } + + @keyframes move { + 0% { transform: translateX(0em) translateY(0em); } + 25% { transform: translateY(-1em) translateX(-1em); rotate: -10deg; } + 50% { transform: translateY(1em) translateX(-1em); } + 75% { transform: translateY(-1.25em) translateX(1em); rotate: 10deg; } + 100% { transform: translateX(0em) translateY(0em); } + } + + @keyframes glowing-stars { + 0% { opacity: 0; } + 50% { opacity: 1; } + 100% { opacity: 0; } + } +`; + +export default Social; diff --git a/src/components/Status.jsx b/src/components/Status.jsx new file mode 100644 index 0000000..39c977f --- /dev/null +++ b/src/components/Status.jsx @@ -0,0 +1,89 @@ +import React from 'react'; +import styled from 'styled-components'; + +const Status = ({ status, date }) => { + // Определяем активный шаг на основе статуса + const getStatusIndex = (s) => { + if (s === 'new') return 1; + if (s === 'processing') return 2; + if (s === 'shipping') return 3; + if (s === 'completed') return 4; + return 0; + }; + + const currentStep = getStatusIndex(status || 'new'); + + return ( + +
+ {/* STEP 1: PLACED */} +
1 ? 'stepper-completed' : currentStep === 1 ? 'stepper-active' : 'stepper-pending'}`}> +
{currentStep > 1 ? '✓' : '1'}
+
+
+
Размещен
+
{currentStep > 1 ? 'Готово' : currentStep === 1 ? 'Сейчас' : 'Ожидание'}
+
{date || '---'}
+
+
+ + {/* STEP 2: PROCESSING */} +
2 ? 'stepper-completed' : currentStep === 2 ? 'stepper-active' : 'stepper-pending'}`}> +
{currentStep > 2 ? '✓' : '2'}
+
+
+
В обработке
+
{currentStep > 2 ? 'Готово' : currentStep === 2 ? 'В работе' : 'Ожидание'}
+
+
+ + {/* STEP 3: SHIPPING */} +
3 ? 'stepper-completed' : currentStep === 3 ? 'stepper-active' : 'stepper-pending'}`}> +
{currentStep > 3 ? '✓' : '3'}
+
+
Доставка / Установка
+
{currentStep > 3 ? 'Готово' : currentStep === 3 ? 'В пути' : 'Ожидание'}
+
+
+
+ + ); +} + +const StyledWrapper = styled.div` + .stepper-box { + background-color: var(--card-bg, #1e293b); + border: 1px solid var(--glass-border, rgba(255,255,255,0.1)); + border-radius: 12px; + padding: 20px; + width: 100%; + color: var(--text-color, #fff); + } + + .stepper-step { display: flex; margin-bottom: 20px; position: relative; } + .stepper-step:last-child { margin-bottom: 0; } + + .stepper-line { + position: absolute; left: 15px; top: 35px; bottom: -25px; width: 2px; + background-color: rgba(255,255,255,0.1); z-index: 1; + } + .stepper-step:last-child .stepper-line { display: none; } + + .stepper-circle { + width: 32px; height: 32px; border-radius: 50%; + display: flex; align-items: center; justify-content: center; + margin-right: 16px; z-index: 2; font-weight: bold; font-size: 14px; + transition: all 0.3s; + } + + .stepper-completed .stepper-circle { background-color: #22c55e; color: white; } + .stepper-active .stepper-circle { border: 2px solid #3b82f6; color: #3b82f6; background: rgba(59, 130, 246, 0.1); } + .stepper-pending .stepper-circle { border: 2px solid #64748b; color: #64748b; } + + .stepper-content { flex: 1; } + .stepper-title { font-weight: 600; font-size: 14px; margin-bottom: 2px; } + .stepper-status { font-size: 12px; opacity: 0.7; } + .stepper-time { font-size: 11px; opacity: 0.5; margin-top: 2px; } +`; + +export default Status; diff --git a/src/components/SupportChat.jsx b/src/components/SupportChat.jsx new file mode 100644 index 0000000..1aba846 --- /dev/null +++ b/src/components/SupportChat.jsx @@ -0,0 +1,295 @@ +import React, { useState, useEffect, useRef } from 'react'; +import axios from 'axios'; +import { Send, X, MessageSquare, User, Shield, RefreshCw, Check, CheckCheck } from 'lucide-react'; +import { motion, AnimatePresence } from 'framer-motion'; + +const API_URL = 'https://diplomnexus.aptcloud.ru'; + +const SupportChat = ({ isOpen, onClose, user }) => { + const [messages, setMessages] = useState([]); + const [newMessage, setNewMessage] = useState(''); + + // Для админа - список пользователей, написавших сообщения + const [uniqueSenders, setUniqueSenders] = useState([]); + const [selectedEmail, setSelectedEmail] = useState(null); // Фильтр для админа (выбранный чат) + const [loading, setLoading] = useState(false); + + // Проверка прав админа (по роли или имени) + const isAdmin = user?.role === 'admin' || user?.name === 'seth1nk' || user?.name === 'SuperAdmin'; + + const messagesEndRef = useRef(null); + + // --- ЗАГРУЗКА СООБЩЕНИЙ --- + const fetchMessages = async () => { + try { + const token = localStorage.getItem('token'); + + // Если админ - загружаем все сообщения + if (isAdmin) { + const res = await axios.get(`${API_URL}/messages`, { + headers: { Authorization: `Bearer ${token}` } + }); + const allMsgs = res.data; + setMessages(allMsgs); + + // Извлекаем уникальных отправителей для списка контактов + // (фильтруем тех, кто писал, исключая админские ответы) + const senders = []; + const seen = new Set(); + + allMsgs.forEach(m => { + // Если сообщение от юзера (не админ) и мы его еще не видели + if (!m.is_admin && m.email && !seen.has(m.email)) { + seen.add(m.email); + senders.push({ name: m.user_name, email: m.email }); + } + }); + setUniqueSenders(senders); + } + // Если обычный юзер - загружаем только его сообщения (фильтр на сервере по email) + else { + const res = await axios.get(`${API_URL}/messages?email=${user.email}`, { + headers: { Authorization: `Bearer ${token}` } + }); + setMessages(res.data); + + // Если чат открыт, помечаем сообщения от админа как прочитанные + if (isOpen) { + await axios.post(`${API_URL}/messages/read`, { email: user.email }, { + headers: { Authorization: `Bearer ${token}` } + }); + } + } + } catch (e) { + console.error("Ошибка загрузки сообщений:", e); + } + }; + + // Автообновление сообщений каждые 3 секунды + useEffect(() => { + if (isOpen) { + fetchMessages(); + const interval = setInterval(fetchMessages, 3000); + return () => clearInterval(interval); + } + }, [isOpen, isAdmin, user]); + + // Скролл вниз при новом сообщении + useEffect(() => { + messagesEndRef.current?.scrollIntoView({ behavior: 'smooth' }); + }, [messages, selectedEmail, isOpen]); + + // --- ОТПРАВКА СООБЩЕНИЯ --- + const handleSendMessage = async (e) => { + e.preventDefault(); + if (!newMessage.trim()) return; + + setLoading(true); + try { + // Если пишет АДМИН -> используем специальный эндпоинт ответа (эмуляция ответа бота) + // Или используем /contact, но сервер должен понять, что это админ. + // В текущей реализации сервера /contact всегда ставит is_admin = FALSE. + // Поэтому для админа лучше использовать /api/bot/reply (как будто бот ответил), + // ЧТОБЫ СОХРАНИЛОСЬ КАК is_admin = TRUE. + + if (isAdmin && selectedEmail) { + await axios.post(`${API_URL}/api/bot/reply`, { + email: selectedEmail, + text: newMessage + }); + } else { + // Если пишет ЮЗЕР + await axios.post(`${API_URL}/contact`, { + name: user.name, + email: user.email, + message: newMessage + }); + } + + setNewMessage(''); + fetchMessages(); // Обновляем список сразу + } catch (error) { + console.error('Ошибка отправки:', error); + } finally { + setLoading(false); + } + }; + + // --- ФИЛЬТРАЦИЯ СООБЩЕНИЙ ДЛЯ ОТОБРАЖЕНИЯ --- + // Если админ: показываем только сообщения выбранного юзера (и ответы ему) + // Если юзер: показываем все загруженные (они уже отфильтрованы сервером) + const displayedMessages = isAdmin + ? (selectedEmail ? messages.filter(m => m.email === selectedEmail) : []) + : messages; + + return ( + + {isOpen && ( + + {/* --- HEADER --- */} +
+
+ +

+ {isAdmin ? 'ПАНЕЛЬ ПОДДЕРЖКИ' : 'ЧАТ С ПОДДЕРЖКОЙ'} +

+
+
+ + +
+
+ + {/* --- BODY --- */} +
+ + {/* --- СПИСОК ЮЗЕРОВ (ТОЛЬКО ДЛЯ АДМИНА) --- */} + {isAdmin && !selectedEmail && ( +
+

Входящие обращения

+ + {uniqueSenders.length === 0 && ( +
+ +

Сообщений нет

+
+ )} + + {uniqueSenders.map((u) => ( +
setSelectedEmail(u.email)} + className="p-3 glass rounded-xl cursor-pointer hover:bg-[var(--accent-color)]/10 transition-colors flex items-center gap-3 border border-[var(--glass-border)] group" + > +
+ {u.name ? u.name[0].toUpperCase() : '?'} +
+
+
+ {u.name} + Открыть +
+
{u.email}
+
+
+ ))} +
+ )} + + {/* --- ОКНО ЧАТА --- */} + {(!isAdmin || selectedEmail) && ( +
+ + {/* Кнопка "Назад" для админа */} + {isAdmin && ( + + )} + +
+ {displayedMessages.length === 0 && ( +
+
+ +
+

Напишите нам!

+

Мы ответим в ближайшее время. История сохраняется.

+
+ )} + + {displayedMessages.map((msg) => { + // ОПРЕДЕЛЯЕМ КТО ПИСАЛ + // is_admin=true -> Поддержка + // is_admin=false -> Юзер + + // Если я Админ -> Мои сообщения это is_admin=true + // Если я Юзер -> Мои сообщения это is_admin=false + const isMe = isAdmin ? msg.is_admin : !msg.is_admin; + + return ( +
+
+ {/* Имя отправителя (если не я) */} + {!isMe && ( +

+ {msg.is_admin ? 'Поддержка' : msg.user_name} +

+ )} + +

{msg.text}

+ + {/* Время и Галочки */} +
+ + {new Date(msg.created_at).toLocaleTimeString([], {hour: '2-digit', minute:'2-digit'})} + + + {/* Галочки показываем только для СВОИХ сообщений */} + {isMe && ( + msg.is_read + ? // Прочитано (Синие) + : // Отправлено (Серые/Черные) + )} +
+
+
+ ); + })} +
+
+ + {/* --- INPUT --- */} +
+ setNewMessage(e.target.value)} + placeholder="Введите сообщение..." + disabled={isAdmin && !selectedEmail} // Админ не может писать, не выбрав чат + className="flex-1 bg-[var(--input-bg)] border border-[var(--glass-border)] rounded-xl px-4 py-3 text-sm text-[var(--text-color)] focus:border-[var(--accent-color)] outline-none transition-all disabled:opacity-50 disabled:cursor-not-allowed" + /> + +
+
+ )} +
+ + )} + + ); +}; + +export default SupportChat; diff --git a/src/components/Telephone.jsx b/src/components/Telephone.jsx new file mode 100644 index 0000000..7171419 --- /dev/null +++ b/src/components/Telephone.jsx @@ -0,0 +1,136 @@ +import React from 'react'; +import styled from 'styled-components'; + +const Telephone = () => { + return ( + +
+
+
+
+
+ + ); +} + +const StyledWrapper = styled.div` + /* Добавил стили для контейнера, чтобы уменьшить весь блок */ + .container { + position: relative; + width: 100px; /* Ограничиваем место, которое занимает блок */ + height: 100px; + display: flex; + align-items: center; + justify-content: center; + transform: scale(0.6); /* Уменьшаем визуально до 60% */ + transform-origin: center center; + } + + .loader { + position: absolute; + top: 50%; + left: 50%; + z-index: 10; + width: 160px; + height: 100px; + margin-left: -80px; + margin-top: -50px; + border-radius: 5px; + background: #1e3f57; + animation: dot1_ 3s cubic-bezier(0.55,0.3,0.24,0.99) infinite; + } + + .loader:nth-child(2) { + z-index: 11; + width: 150px; + height: 90px; + margin-top: -45px; + margin-left: -75px; + border-radius: 3px; + background: #3c517d; + animation-name: dot2_; + } + + .loader:nth-child(3) { + z-index: 12; + width: 40px; + height: 20px; + margin-top: 50px; + margin-left: -20px; + border-radius: 0 0 5px 5px; + background: #6bb2cd; + animation-name: dot3_; + } + + @keyframes dot1_ { + 3%,97% { + width: 160px; + height: 100px; + margin-top: -50px; + margin-left: -80px; + } + + 30%,36% { + width: 80px; + height: 120px; + margin-top: -60px; + margin-left: -40px; + } + + 63%,69% { + width: 40px; + height: 80px; + margin-top: -40px; + margin-left: -20px; + } + } + + @keyframes dot2_ { + 3%,97% { + height: 90px; + width: 150px; + margin-left: -75px; + margin-top: -45px; + } + + 30%,36% { + width: 70px; + height: 96px; + margin-left: -35px; + margin-top: -48px; + } + + 63%,69% { + width: 32px; + height: 60px; + margin-left: -16px; + margin-top: -30px; + } + } + + @keyframes dot3_ { + 3%,97% { + height: 20px; + width: 40px; + margin-left: -20px; + margin-top: 50px; + } + + 30%,36% { + width: 8px; + height: 8px; + margin-left: -5px; + margin-top: 49px; + border-radius: 8px; + } + + 63%,69% { + width: 16px; + height: 4px; + margin-left: -8px; + margin-top: -37px; + border-radius: 10px; + } + }`; + +export default Telephone; diff --git a/src/components/UserAvatar.jsx b/src/components/UserAvatar.jsx new file mode 100644 index 0000000..eac5fea --- /dev/null +++ b/src/components/UserAvatar.jsx @@ -0,0 +1,29 @@ +import React from 'react'; +import { User } from 'lucide-react'; + +const UserAvatar = ({ user, className }) => { + // 1. Если есть фото от Google — показываем его (круглое) + if (user.picture) { + return ( + {user.name} + ); + } + + // 2. Если фото нет — показываем простую заглушку (как ты просил) + return ( +
+ {/* Иконка человека, залитая цветом (fill) */} + +
+ ); +}; + +export default UserAvatar; \ No newline at end of file diff --git a/src/components/google.jsx b/src/components/google.jsx new file mode 100644 index 0000000..39d9de0 --- /dev/null +++ b/src/components/google.jsx @@ -0,0 +1,53 @@ +import React from 'react'; +import styled from 'styled-components'; + +const GoogleButton = ({ onClick }) => { + return ( + + + + ); +} + +const StyledWrapper = styled.div` + width: 100%; + + .button { + width: 100%; + max-width: 100%; + display: flex; + padding: 0.5rem 1.4rem; + font-size: 0.875rem; + line-height: 1.25rem; + font-weight: 700; + text-align: center; + text-transform: uppercase; + vertical-align: middle; + align-items: center; + justify-content: center; + border-radius: 0.5rem; + border: 1px solid rgba(0, 0, 0, 0.25); + gap: 0.75rem; + color: rgb(65, 63, 63); + background-color: #fff; + cursor: pointer; + transition: all .6s ease; + } + + .button svg { + height: 24px; + } + + .button:hover { + transform: scale(1.02); + }`; + +export default GoogleButton; diff --git a/src/components/lightdark.jsx b/src/components/lightdark.jsx new file mode 100644 index 0000000..b17ae6d --- /dev/null +++ b/src/components/lightdark.jsx @@ -0,0 +1,125 @@ +import React from 'react'; +import styled from 'styled-components'; + +const LightDark = ({ toggleTheme, isLight }) => { + return ( + + + + ); +} + +const StyledWrapper = styled.div` + /* УВЕЛИЧИЛ МАСШТАБ */ + transform: scale(0.6); + transform-origin: center; + + .bb8-toggle { + --toggle-size: 16px; + --toggle-width: 10.625em; + --toggle-height: 5.625em; + --toggle-offset: calc((var(--toggle-height) - var(--bb8-diameter)) / 2); + --toggle-bg: linear-gradient(#2c4770, #070e2b 35%, #628cac 50% 70%, #a6c5d4) no-repeat; + --bb8-diameter: 4.375em; + --radius: 99em; + --transition: 0.4s; + --accent: #de7d2f; + --bb8-bg: #fff; + } + + /* ... (Остальной CSS код с Uiverse без изменений, он верный) ... */ + /* Скопируй весь CSS из твоего сообщения сюда, он большой, но я его проверил - рабочий */ + .bb8-toggle, .bb8-toggle *, .bb8-toggle *::before, .bb8-toggle *::after { box-sizing: border-box; } + .bb8-toggle { cursor: pointer; margin-top: var(--margin-top-for-head); font-size: var(--toggle-size); } + .bb8-toggle__checkbox { appearance: none; display: none; } + .bb8-toggle__container { width: var(--toggle-width); height: var(--toggle-height); background: var(--toggle-bg); background-size: 100% 11.25em; background-position-y: -5.625em; border-radius: var(--radius); position: relative; transition: var(--transition); } + .bb8 { display: flex; flex-direction: column; align-items: center; position: absolute; top: calc(var(--toggle-offset) - 1.688em + 0.188em); left: var(--toggle-offset); transition: var(--transition); z-index: 2; } + .bb8__head-container { position: relative; transition: var(--transition); z-index: 2; transform-origin: 1.25em 3.75em; } + .bb8__head { overflow: hidden; margin-bottom: -0.188em; width: 2.5em; height: 1.688em; background: linear-gradient(transparent 0.063em, dimgray 0.063em 0.313em, transparent 0.313em 0.375em, var(--accent) 0.375em 0.5em, transparent 0.5em 1.313em, silver 1.313em 1.438em, transparent 1.438em), linear-gradient(45deg, transparent 0.188em, var(--bb8-bg) 0.188em 1.25em, transparent 1.25em), linear-gradient(-45deg, transparent 0.188em, var(--bb8-bg) 0.188em 1.25em, transparent 1.25em), linear-gradient(var(--bb8-bg) 1.25em, transparent 1.25em); border-radius: var(--radius) var(--radius) 0 0; position: relative; z-index: 1; filter: drop-shadow(0 0.063em 0.125em gray); } + .bb8__head::before { content: ""; position: absolute; width: 0.563em; height: 0.563em; background: radial-gradient(0.125em circle at 0.25em 0.375em, red, transparent), radial-gradient(0.063em circle at 0.375em 0.188em, var(--bb8-bg) 50%, transparent 100%), linear-gradient(45deg, #000 0.188em, dimgray 0.313em 0.375em, #000 0.5em); border-radius: var(--radius); top: 0.413em; left: 50%; transform: translate(-50%); box-shadow: 0 0 0 0.089em lightgray, 0.563em 0.281em 0 -0.148em, 0.563em 0.281em 0 -0.1em var(--bb8-bg), 0.563em 0.281em 0 -0.063em; z-index: 1; transition: var(--transition); } + .bb8__head::after { content: ""; position: absolute; bottom: 0.375em; left: 0; width: 100%; height: 0.188em; background: linear-gradient(to right, var(--accent) 0.125em, transparent 0.125em 0.188em, var(--accent) 0.188em 0.313em, transparent 0.313em 0.375em, var(--accent) 0.375em 0.938em, transparent 0.938em 1em, var(--accent) 1em 1.125em, transparent 1.125em 1.875em, var(--accent) 1.875em 2em, transparent 2em 2.063em, var(--accent) 2.063em 2.25em, transparent 2.25em 2.313em, var(--accent) 2.313em 2.375em, transparent 2.375em 2.438em, var(--accent) 2.438em); transition: var(--transition); } + .bb8__antenna { position: absolute; transform: translateY(-90%); width: 0.059em; border-radius: var(--radius) var(--radius) 0 0; transition: var(--transition); } + .bb8__antenna:nth-child(1) { height: 0.938em; right: 0.938em; background: linear-gradient(#000 0.188em, silver 0.188em); } + .bb8__antenna:nth-child(2) { height: 0.375em; left: 50%; transform: translate(-50%, -90%); background: silver; } + .bb8__body { width: 4.375em; height: 4.375em; background: var(--bb8-bg); border-radius: var(--radius); position: relative; overflow: hidden; transition: var(--transition); z-index: 1; transform: rotate(45deg); background: linear-gradient(-90deg, var(--bb8-bg) 4%, var(--accent) 4% 10%, transparent 10% 90%, var(--accent) 90% 96%, var(--bb8-bg) 96%), linear-gradient(var(--bb8-bg) 4%, var(--accent) 4% 10%, transparent 10% 90%, var(--accent) 90% 96%, var(--bb8-bg) 96%), linear-gradient(to right, transparent 2.156em, silver 2.156em 2.219em, transparent 2.188em), linear-gradient(transparent 2.156em, silver 2.156em 2.219em, transparent 2.188em); background-color: var(--bb8-bg); } + .bb8__body::after { content: ""; bottom: 1.5em; left: 0.563em; position: absolute; width: 0.188em; height: 0.188em; background: rgb(236, 236, 236); color: rgb(236, 236, 236); border-radius: 50%; box-shadow: 0.875em 0.938em, 0 -1.25em, 0.875em -2.125em, 2.125em -2.125em, 3.063em -1.25em, 3.063em 0, 2.125em 0.938em; } + .bb8__body::before { content: ""; width: 2.625em; height: 2.625em; position: absolute; border-radius: 50%; z-index: 0.1; overflow: hidden; top: 50%; left: 50%; transform: translate(-50%, -50%); border: 0.313em solid var(--accent); background: radial-gradient(1em circle at center, rgb(236, 236, 236) 50%, transparent 51%), radial-gradient(1.25em circle at center, var(--bb8-bg) 50%, transparent 51%), linear-gradient(-90deg, transparent 42%, var(--accent) 42% 58%, transparent 58%), linear-gradient(var(--bb8-bg) 42%, var(--accent) 42% 58%, var(--bb8-bg) 58%); } + .artificial__hidden { position: absolute; border-radius: inherit; inset: 0; pointer-events: none; overflow: hidden; } + .bb8__shadow { content: ""; width: var(--bb8-diameter); height: 20%; border-radius: 50%; background: #3a271c; box-shadow: 0.313em 0 3.125em #3a271c; opacity: 0.25; position: absolute; bottom: 0; left: calc(var(--toggle-offset) - 0.938em); transition: var(--transition); transform: skew(-70deg); z-index: 1; } + .bb8-toggle__scenery { width: 100%; height: 100%; pointer-events: none; overflow: hidden; position: relative; border-radius: inherit; } + .bb8-toggle__scenery::before { content: ""; position: absolute; width: 100%; height: 30%; bottom: 0; background: #b18d71; z-index: 1; } + .bb8-toggle__cloud { z-index: 1; position: absolute; border-radius: 50%; } + .bb8-toggle__cloud:nth-last-child(1) { width: 0.875em; height: 0.625em; filter: blur(0.125em) drop-shadow(0.313em 0.313em #ffffffae) drop-shadow(-0.625em 0 #fff) drop-shadow(-0.938em -0.125em #fff); right: 1.875em; top: 2.813em; background: linear-gradient(to top right, #ffffffae, #ffffffae); transition: var(--transition); } + .bb8-toggle__cloud:nth-last-child(2) { top: 0.625em; right: 4.375em; width: 0.875em; height: 0.375em; background: #dfdedeae; filter: blur(0.125em) drop-shadow(-0.313em -0.188em #e0dfdfae) drop-shadow(-0.625em -0.188em #bbbbbbae) drop-shadow(-1em 0.063em #cfcfcfae); transition: 0.6s; } + .bb8-toggle__cloud:nth-last-child(3) { top: 1.25em; right: 0.938em; width: 0.875em; height: 0.375em; background: #ffffffae; filter: blur(0.125em) drop-shadow(0.438em 0.188em #ffffffae) drop-shadow(-0.625em 0.313em #ffffffae); transition: 0.8s; } + .gomrassen, .hermes, .chenini { position: absolute; border-radius: var(--radius); background: linear-gradient(#fff, #6e8ea2); top: 100%; } + .gomrassen { left: 0.938em; width: 1.875em; height: 1.875em; box-shadow: 0 0 0.188em #ffffff52, 0 0 0.188em #6e8ea24b; transition: var(--transition); } + .gomrassen::before, .gomrassen::after { content: ""; position: absolute; border-radius: inherit; box-shadow: inset 0 0 0.063em rgb(140, 162, 169); background: rgb(184, 196, 200); } + .gomrassen::before { left: 0.313em; top: 0.313em; width: 0.438em; height: 0.438em; } .gomrassen::after { width: 0.25em; height: 0.25em; left: 1.25em; top: 0.75em; } + .hermes { left: 3.438em; width: 0.625em; height: 0.625em; box-shadow: 0 0 0.125em #ffffff52, 0 0 0.125em #6e8ea24b; transition: 0.6s; } + .chenini { left: 4.375em; width: 0.5em; height: 0.5em; box-shadow: 0 0 0.125em #ffffff52, 0 0 0.125em #6e8ea24b; transition: 0.8s; } + .tatto-1, .tatto-2 { position: absolute; width: 1.25em; height: 1.25em; border-radius: var(--radius); } + .tatto-1 { background: #fefefe; right: 3.125em; top: 0.625em; box-shadow: 0 0 0.438em #fdf4e1; transition: var(--transition); } + .tatto-2 { background: linear-gradient(#e6ac5c, #d75449); right: 1.25em; top: 2.188em; box-shadow: 0 0 0.438em #e6ad5c3d, 0 0 0.438em #d755494f; transition: 0.7s; } + .bb8-toggle__star { position: absolute; width: 0.063em; height: 0.063em; background: #fff; border-radius: var(--radius); filter: drop-shadow(0 0 0.063em #fff); color: #fff; top: 100%; } + .bb8-toggle__star:nth-child(1) { left: 3.75em; box-shadow: 1.25em 0.938em, -1.25em 2.5em, 0 1.25em, 1.875em 0.625em, -3.125em 1.875em, 1.25em 2.813em; transition: 0.2s; } + .bb8-toggle__star:nth-child(2) { left: 4.688em; box-shadow: 0.625em 0, 0 0.625em, -0.625em -0.625em, 0.625em 0.938em, -3.125em 1.25em, 1.25em -1.563em; transition: 0.3s; } + .bb8-toggle__star:nth-child(3) { left: 5.313em; box-shadow: -0.625em -0.625em, -2.188em 1.25em, -2.188em 0, -3.75em -0.625em, -3.125em -0.625em, -2.5em -0.313em, 0.75em -0.625em; transition: var(--transition); } + .bb8-toggle__star:nth-child(4) { left: 1.875em; width: 0.125em; height: 0.125em; transition: 0.5s; } + .bb8-toggle__star:nth-child(5) { left: 5em; width: 0.125em; height: 0.125em; transition: 0.6s; } + .bb8-toggle__star:nth-child(6) { left: 2.5em; width: 0.125em; height: 0.125em; transition: 0.7s; } + .bb8-toggle__star:nth-child(7) { left: 3.438em; width: 0.125em; height: 0.125em; transition: 0.8s; } + .bb8-toggle__checkbox:checked + .bb8-toggle__container .bb8-toggle__star:nth-child(1) { top: 0.625em; } + .bb8-toggle__checkbox:checked + .bb8-toggle__container .bb8-toggle__star:nth-child(2) { top: 1.875em; } + .bb8-toggle__checkbox:checked + .bb8-toggle__container .bb8-toggle__star:nth-child(3) { top: 1.25em; } + .bb8-toggle__checkbox:checked + .bb8-toggle__container .bb8-toggle__star:nth-child(4) { top: 3.438em; } + .bb8-toggle__checkbox:checked + .bb8-toggle__container .bb8-toggle__star:nth-child(5) { top: 3.438em; } + .bb8-toggle__checkbox:checked + .bb8-toggle__container .bb8-toggle__star:nth-child(6) { top: 0.313em; } + .bb8-toggle__checkbox:checked + .bb8-toggle__container .bb8-toggle__star:nth-child(7) { top: 1.875em; } + .bb8-toggle__checkbox:checked + .bb8-toggle__container .bb8-toggle__cloud { right: -100%; } + .bb8-toggle__checkbox:checked + .bb8-toggle__container .gomrassen { top: 0.938em; } + .bb8-toggle__checkbox:checked + .bb8-toggle__container .hermes { top: 2.5em; } + .bb8-toggle__checkbox:checked + .bb8-toggle__container .chenini { top: 2.75em; } + .bb8-toggle__checkbox:checked + .bb8-toggle__container { background-position-y: 0; } + .bb8-toggle__checkbox:checked + .bb8-toggle__container .tatto-1 { top: 100%; } + .bb8-toggle__checkbox:checked + .bb8-toggle__container .tatto-2 { top: 100%; } + .bb8-toggle__checkbox:checked + .bb8-toggle__container .bb8 { left: calc(100% - var(--bb8-diameter) - var(--toggle-offset)); } + .bb8-toggle__checkbox:checked + .bb8-toggle__container .bb8__shadow { left: calc(100% - var(--bb8-diameter) - var(--toggle-offset) + 0.938em); transform: skew(70deg); } + .bb8-toggle__checkbox:checked + .bb8-toggle__container .bb8__body { transform: rotate(225deg); } + .bb8-toggle__checkbox:hover + .bb8-toggle__container .bb8__head::before { left: 100%; } + .bb8-toggle__checkbox:not(:checked):hover + .bb8-toggle__container .bb8__antenna:nth-child(1) { right: 1.5em; } + .bb8-toggle__checkbox:hover + .bb8-toggle__container .bb8__antenna:nth-child(2) { left: 0.938em; } + .bb8-toggle__checkbox:hover + .bb8-toggle__container .bb8__head::after { background-position: 1.375em 0; } + .bb8-toggle__checkbox:checked:hover + .bb8-toggle__container .bb8__head::before { left: 0; } + .bb8-toggle__checkbox:checked:hover + .bb8-toggle__container .bb8__antenna:nth-child(2) { left: calc(100% - 0.938em); } + .bb8-toggle__checkbox:checked:hover + .bb8-toggle__container .bb8__head::after { background-position: -1.375em 0; } + .bb8-toggle__checkbox:active + .bb8-toggle__container .bb8__head-container { transform: rotate(25deg); } + .bb8-toggle__checkbox:checked:active + .bb8-toggle__container .bb8__head-container { transform: rotate(-25deg); } +`; + +export default LightDark; diff --git a/src/index.css b/src/index.css index 661641e..1567d75 100644 --- a/src/index.css +++ b/src/index.css @@ -1,40 +1,143 @@ -@tailwind base; -@tailwind components; -@tailwind utilities; +@import "tailwindcss"; +@config "../tailwind.config.js"; +@import url('https://fonts.googleapis.com/css2?family=Inter:wght@300;400;600;700&display=swap'); +@import "./styles/admin.css"; +@import "./styles/pages.css"; :root { - --bg-color: #060713; - --card-bg: #0b0c15; - --text-color: #ffffff; - --accent-color: #00f260; /* Фирменный зеленый неон */ - --glass-border: rgba(255, 255, 255, 0.08); - --input-bg: rgba(0, 0, 0, 0.4); + /* ТЕМНАЯ ТЕМА (Deep Space) */ + --bg-color: #0b0c15; + --text-color: #f1f5f9; + --glass-bg: rgba(20, 20, 30, 0.6); + --glass-border: rgba(255, 255, 255, 0.05); + --accent-color: #00f3ff; + --card-bg: #13141f; + --shadow-color: rgba(0, 243, 255, 0.1); + --map-filter: grayscale(100%) invert(100%) contrast(1.2); /* Делаем карту темной */ + --input-bg: rgba(15, 23, 42, 0.6); +} + +body.light { + /* СВЕТЛАЯ ТЕМА (Tech Lab) */ + --bg-color: #f0f2f5; + --text-color: #1a1c23; + --glass-bg: rgba(255, 255, 255, 0.8); + --glass-border: rgba(0, 0, 0, 0.05); + --accent-color: #2563eb; + --card-bg: #ffffff; + --input-bg: rgba(255, 255, 255, 0.9); + --shadow-color: rgba(37, 99, 235, 0.15); + --map-filter: grayscale(0%) invert(0%); /* Обычная карта */ } body { - background-color: var(--bg-color); + background: var(--bg-color); color: var(--text-color); - font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; + font-family: 'Inter', sans-serif; + transition: background 0.4s ease, color 0.4s ease; overflow-x: hidden; } -.custom-scroll::-webkit-scrollbar { - width: 4px; -} -.custom-scroll::-webkit-scrollbar-thumb { - background: var(--accent-color); - border-radius: 10px; +/* Скроллбар */ +::-webkit-scrollbar { width: 6px; } +::-webkit-scrollbar-track { background: transparent; } +::-webkit-scrollbar-thumb { background: var(--accent-color); border-radius: 10px; } + +/* Эффект стекла (Без рамок, только тень и блюр) */ +.glass { + background: var(--glass-bg); + backdrop-filter: blur(16px); + -webkit-backdrop-filter: blur(16px); + border: 1px solid var(--glass-border); + box-shadow: 0 8px 32px 0 var(--shadow-color); } +/* Кнопка */ .btn-neon { - background: rgba(0, 242, 96, 0.1); - border: 1px solid var(--accent-color); - color: var(--accent-color); - box-shadow: 0 0 15px rgba(0, 242, 96, 0.2); - transition: all 0.3s ease; + background: linear-gradient(135deg, var(--accent-color), #8b5cf6); + color: white; + font-weight: 700; + border-radius: 12px; + transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1); + box-shadow: 0 4px 15px var(--shadow-color); + position: relative; + overflow: hidden; } .btn-neon:hover { - background: var(--accent-color); - color: #000; - box-shadow: 0 0 25px rgba(0, 242, 96, 0.4); + transform: translateY(-2px) scale(1.02); + box-shadow: 0 8px 25px var(--shadow-color); +} + +/* --- СТИЛИ ДЛЯ КОМПОНЕНТОВ UIVERSE (Вставляем сюда, чтобы работали в Dashboard) --- */ + +/* 1. NEON CARD */ +.uiverse-card { + width: 100%; height: 320px; + background: var(--card-bg); + position: relative; display: flex; place-content: center; place-items: center; + overflow: hidden; border-radius: 20px; + box-shadow: 0 10px 20px rgba(0,0,0,0.2); +} +.uiverse-card::before { + content: ''; position: absolute; width: 100px; + background-image: linear-gradient(180deg, var(--accent-color), #bc13fe); + height: 150%; animation: rotBGimg 4s linear infinite; transition: all 0.2s linear; +} +@keyframes rotBGimg { from { transform: rotate(0deg); } to { transform: rotate(360deg); } } +.uiverse-card::after { + content: ''; position: absolute; background: var(--card-bg); inset: 3px; border-radius: 18px; +} +.uiverse-card-content { + position: absolute; z-index: 10; width: 92%; height: 92%; + display: flex; flex-direction: column; justify-content: space-between; +} + +/* 2. CYBER SWITCH */ +.cyber-switch { font-size: 14px; position: relative; display: inline-block; width: 3.5em; height: 2em; } +.cyber-switch input { opacity: 0; width: 0; height: 0; } +.cyber-slider { + position: absolute; cursor: pointer; top: 0; left: 0; right: 0; bottom: 0; + background-color: #1a1a2e; transition: .4s; border-radius: 10px; + border: 1px solid var(--accent-color); +} +.cyber-slider:before { + position: absolute; content: ""; height: 1.4em; width: 1.4em; left: 0.3em; bottom: 0.25em; + background-color: var(--accent-color); transition: .4s; border-radius: 50%; + box-shadow: 0 0 10px var(--accent-color); +} +.cyber-switch input:checked + .cyber-slider { background-color: var(--accent-color); border-color: white; } +.cyber-switch input:checked + .cyber-slider:before { + transform: translateX(1.5em); background-color: white; box-shadow: none; +} +/* Обновленный класс для инпутов */ +.contact-input { + width: 100%; + background-color: var(--input-bg); /* Используем переменную */ + border: 1px solid var(--glass-border); + border-radius: 0.75rem; + padding: 1rem; + color: var(--text-color); + outline: none; + transition: all 0.3s ease; + font-size: 1rem; +} + +.contact-input:focus { + border-color: var(--accent-color); + box-shadow: 0 0 0 4px rgba(var(--accent-color), 0.1); /* Свечение */ + background-color: var(--card-bg); +} + +/* Плейсхолдеры */ +.contact-input::placeholder { + color: var(--text-color); + opacity: 0.5; +} +@keyframes scan { + 0% { transform: translateY(-50%); } + 100% { transform: translateY(50%); } +} + +.animate-scan { + animation: scan 2s linear infinite; } \ No newline at end of file diff --git a/src/main.jsx b/src/main.jsx index c6e6194..e065683 100644 --- a/src/main.jsx +++ b/src/main.jsx @@ -2,12 +2,12 @@ import React from 'react' import ReactDOM from 'react-dom/client' import App from './App.jsx' import './index.css' -import bridge from '@vkontakte/vk-bridge' +import bridge from '@vkontakte/vk-bridge' // Импортируем мост -// Инициализируем VK Bridge до рендеринга приложения +// Инициализируем мост ВК bridge.send('VKWebAppInit') .then(() => console.log('VK Bridge успешно инициализирован')) - .catch((err) => console.error('Ошибка инициализации VK Bridge:', err)); + .catch((err) => console.error('Ошибка моста:', err)); ReactDOM.createRoot(document.getElementById('root')).render( diff --git a/src/pages/About.jsx b/src/pages/About.jsx new file mode 100644 index 0000000..682b534 --- /dev/null +++ b/src/pages/About.jsx @@ -0,0 +1,205 @@ +import { motion } from 'framer-motion'; +import { Activity, Shield, Cpu, Wifi } from 'lucide-react'; +import Mesto from '../components/Mesto'; +import Pogoda from '../components/Pogoda'; +import Notebook from '../components/Notebook'; +import Server from '../components/Server'; +import Button from '../components/Record'; +const About = () => { + return ( +
+ +
+ +
+
+ +
+
+
+
+ LIVE MAP +
+
+ + {/* Карта */} +
+
+
+ +
+
+
+ + + + {/* === ОСНОВНОЙ КОНТЕНТ === */} + + {/* HEADER */} + +

О Проекте

+

+ Экосистема
+ Smart Nexus +

+

+ Интеллектуальное управление пространством. Мы превращаем квадратные метры в думающий организм. +

+
+ + {/* TEXT & DASHBOARD BLOCK */} +
+ + {/* Text */} + +

Центральный нейро-хаб

+

+ В основе системы лежит локальный сервер обработки данных. В отличие от облачных решений, + Smart Nexus обрабатывает все сигналы внутри дома (Edge Computing), обеспечивая мгновенную реакцию + и полную безопасность. +

+
+ + {/* === БОЛЬШАЯ ПАНЕЛЬ МОНИТОРИНГА === */} + + {/* Фон свечение */} +
+ + {/* ЛЕВАЯ ЧАСТЬ: ВИЗУАЛИЗАЦИЯ (СЕРВЕР) */} +
+
+ UNIT: ALPHA-01 +
+
+ +
+
+
+ SYSTEM ONLINE +
+
+ + {/* ПРАВАЯ ЧАСТЬ: МЕТРИКИ (НОВОЕ) */} +
+ +

+ + Телеметрия Ядра +

+ + {/* Progress Bars */} +
+ {/* CPU */} +
+
+ CPU LOAD + 12% +
+
+ +
+ +
+
+ + {/* RAM */} +
+
+ SECURITY LAYER + ACTIVE +
+
+ +
+
+ + {/* NETWORK */} +
+
+ UPLINK + 1.2 Gbps +
+ {/* График полосочками */} +
+ {[40, 70, 30, 80, 50, 90, 60, 40, 70, 50, 80, 60].map((h, i) => ( + + ))} +
+
+
+ + {/* Info Grid */} +
+
+

Requests

+

8,432/sec

+
+
+

Ping

+

3ms

+
+
+ +
+ + +
+ + {/* ENGINEER TERMINAL SECTION */} + +
+

Инженерный доступ

+

+ Полный контроль над сценариями автоматизации. Доступ к логам системы, настройка чувствительности датчиков и обновление прошивок модулей. +

+
+
v.2.4.1
+

connect --secure root@nexus

+

Authenticating...

+

Access Granted.

+

_

+
+
+
+
+ +
+
+
+ +
+ ); +}; + +export default About; \ No newline at end of file diff --git a/src/pages/Contact.jsx b/src/pages/Contact.jsx new file mode 100644 index 0000000..c157408 --- /dev/null +++ b/src/pages/Contact.jsx @@ -0,0 +1,171 @@ +import { motion } from 'framer-motion'; +import { MapPin, Phone, Mail, Send } from 'lucide-react'; +import Radar from '../components/Radar'; +import Social from '../components/Social'; +import Telephone from '../components/Telephone'; + +const Contact = () => { + return ( +
+ + {/* === ПЛАВАЮЩИЙ SOCIAL (FIXED) === */} + + {/* pointer-events-auto нужен, чтобы клики работали, но контейнер не мешал */} +
+ +
+
+ + {/* ЗАГОЛОВОК */} + +

+ Центр
+ Связи +

+

+ Ангарский политехнический техникум.
+ Техническая поддержка систем Smart Nexus. +

+
+ + {/* ГЛАВНАЯ СЕТКА */} +
+ + {/* === ЛЕВАЯ КОЛОНКА (Форма) === */} + {/* Добавлен flex и h-full, чтобы колонка тянулась вниз */} +
+ + +

Входящий сигнал

+
+
+ + +
+
+ + +
+ {/* Textarea растягивается на всю доступную высоту (flex-grow) */} +
+ +