mirror of
https://github.com/101island/lolisland.us.git
synced 2026-03-01 03:49:42 +08:00
feat: complete frontend login logic
This commit is contained in:
@@ -1,7 +1,9 @@
|
||||
import cloudflare from "@astrojs/cloudflare";
|
||||
import react from "@astrojs/react";
|
||||
import { defineConfig } from "astro/config";
|
||||
|
||||
// https://astro.build/config
|
||||
export default defineConfig({
|
||||
adapter: cloudflare(),
|
||||
integrations: [react()],
|
||||
});
|
||||
|
||||
105
bun.lock
105
bun.lock
@@ -6,7 +6,12 @@
|
||||
"name": "lolisland.us",
|
||||
"dependencies": {
|
||||
"@astrojs/cloudflare": "^12.6.12",
|
||||
"@astrojs/react": "^4.4.2",
|
||||
"@types/react": "^19.2.7",
|
||||
"@types/react-dom": "^19.2.3",
|
||||
"astro": "^5.0.0",
|
||||
"react": "^19.2.3",
|
||||
"react-dom": "^19.2.3",
|
||||
},
|
||||
"devDependencies": {
|
||||
"@biomejs/biome": "2.3.8",
|
||||
@@ -24,16 +29,48 @@
|
||||
|
||||
"@astrojs/prism": ["@astrojs/prism@3.3.0", "https://registry.npmmirror.com/@astrojs/prism/-/prism-3.3.0.tgz", { "dependencies": { "prismjs": "^1.30.0" } }, "sha512-q8VwfU/fDZNoDOf+r7jUnMC2//H2l0TuQ6FkGJL8vD8nw/q5KiL3DS1KKBI3QhI9UQhpJ5dc7AtqfbXWuOgLCQ=="],
|
||||
|
||||
"@astrojs/react": ["@astrojs/react@4.4.2", "", { "dependencies": { "@vitejs/plugin-react": "^4.7.0", "ultrahtml": "^1.6.0", "vite": "^6.4.1" }, "peerDependencies": { "@types/react": "^17.0.50 || ^18.0.21 || ^19.0.0", "@types/react-dom": "^17.0.17 || ^18.0.6 || ^19.0.0", "react": "^17.0.2 || ^18.0.0 || ^19.0.0", "react-dom": "^17.0.2 || ^18.0.0 || ^19.0.0" } }, "sha512-1tl95bpGfuaDMDn8O3x/5Dxii1HPvzjvpL2YTuqOOrQehs60I2DKiDgh1jrKc7G8lv+LQT5H15V6QONQ+9waeQ=="],
|
||||
|
||||
"@astrojs/telemetry": ["@astrojs/telemetry@3.3.0", "https://registry.npmmirror.com/@astrojs/telemetry/-/telemetry-3.3.0.tgz", { "dependencies": { "ci-info": "^4.2.0", "debug": "^4.4.0", "dlv": "^1.1.3", "dset": "^3.1.4", "is-docker": "^3.0.0", "is-wsl": "^3.1.0", "which-pm-runs": "^1.1.0" } }, "sha512-UFBgfeldP06qu6khs/yY+q1cDAaArM2/7AEIqQ9Cuvf7B1hNLq0xDrZkct+QoIGyjq56y8IaE2I3CTvG99mlhQ=="],
|
||||
|
||||
"@astrojs/underscore-redirects": ["@astrojs/underscore-redirects@1.0.0", "https://registry.npmmirror.com/@astrojs/underscore-redirects/-/underscore-redirects-1.0.0.tgz", {}, "sha512-qZxHwVnmb5FXuvRsaIGaqWgnftjCuMY+GSbaVZdBmE4j8AfgPqKPxYp8SUERyJcjpKCEmO4wD6ybuGH8A2kVRQ=="],
|
||||
|
||||
"@babel/code-frame": ["@babel/code-frame@7.27.1", "", { "dependencies": { "@babel/helper-validator-identifier": "^7.27.1", "js-tokens": "^4.0.0", "picocolors": "^1.1.1" } }, "sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg=="],
|
||||
|
||||
"@babel/compat-data": ["@babel/compat-data@7.28.5", "", {}, "sha512-6uFXyCayocRbqhZOB+6XcuZbkMNimwfVGFji8CTZnCzOHVGvDqzvitu1re2AU5LROliz7eQPhB8CpAMvnx9EjA=="],
|
||||
|
||||
"@babel/core": ["@babel/core@7.28.5", "", { "dependencies": { "@babel/code-frame": "^7.27.1", "@babel/generator": "^7.28.5", "@babel/helper-compilation-targets": "^7.27.2", "@babel/helper-module-transforms": "^7.28.3", "@babel/helpers": "^7.28.4", "@babel/parser": "^7.28.5", "@babel/template": "^7.27.2", "@babel/traverse": "^7.28.5", "@babel/types": "^7.28.5", "@jridgewell/remapping": "^2.3.5", "convert-source-map": "^2.0.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", "json5": "^2.2.3", "semver": "^6.3.1" } }, "sha512-e7jT4DxYvIDLk1ZHmU/m/mB19rex9sv0c2ftBtjSBv+kVM/902eh0fINUzD7UwLLNR+jU585GxUJ8/EBfAM5fw=="],
|
||||
|
||||
"@babel/generator": ["@babel/generator@7.28.5", "", { "dependencies": { "@babel/parser": "^7.28.5", "@babel/types": "^7.28.5", "@jridgewell/gen-mapping": "^0.3.12", "@jridgewell/trace-mapping": "^0.3.28", "jsesc": "^3.0.2" } }, "sha512-3EwLFhZ38J4VyIP6WNtt2kUdW9dokXA9Cr4IVIFHuCpZ3H8/YFOl5JjZHisrn1fATPBmKKqXzDFvh9fUwHz6CQ=="],
|
||||
|
||||
"@babel/helper-compilation-targets": ["@babel/helper-compilation-targets@7.27.2", "", { "dependencies": { "@babel/compat-data": "^7.27.2", "@babel/helper-validator-option": "^7.27.1", "browserslist": "^4.24.0", "lru-cache": "^5.1.1", "semver": "^6.3.1" } }, "sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ=="],
|
||||
|
||||
"@babel/helper-globals": ["@babel/helper-globals@7.28.0", "", {}, "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw=="],
|
||||
|
||||
"@babel/helper-module-imports": ["@babel/helper-module-imports@7.27.1", "", { "dependencies": { "@babel/traverse": "^7.27.1", "@babel/types": "^7.27.1" } }, "sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w=="],
|
||||
|
||||
"@babel/helper-module-transforms": ["@babel/helper-module-transforms@7.28.3", "", { "dependencies": { "@babel/helper-module-imports": "^7.27.1", "@babel/helper-validator-identifier": "^7.27.1", "@babel/traverse": "^7.28.3" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-gytXUbs8k2sXS9PnQptz5o0QnpLL51SwASIORY6XaBKF88nsOT0Zw9szLqlSGQDP/4TljBAD5y98p2U1fqkdsw=="],
|
||||
|
||||
"@babel/helper-plugin-utils": ["@babel/helper-plugin-utils@7.27.1", "", {}, "sha512-1gn1Up5YXka3YYAHGKpbideQ5Yjf1tDa9qYcgysz+cNCXukyLl6DjPXhD3VRwSb8c0J9tA4b2+rHEZtc6R0tlw=="],
|
||||
|
||||
"@babel/helper-string-parser": ["@babel/helper-string-parser@7.27.1", "https://registry.npmmirror.com/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", {}, "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA=="],
|
||||
|
||||
"@babel/helper-validator-identifier": ["@babel/helper-validator-identifier@7.28.5", "https://registry.npmmirror.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz", {}, "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q=="],
|
||||
|
||||
"@babel/helper-validator-option": ["@babel/helper-validator-option@7.27.1", "", {}, "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg=="],
|
||||
|
||||
"@babel/helpers": ["@babel/helpers@7.28.4", "", { "dependencies": { "@babel/template": "^7.27.2", "@babel/types": "^7.28.4" } }, "sha512-HFN59MmQXGHVyYadKLVumYsA9dBFun/ldYxipEjzA4196jpLZd8UjEEBLkbEkvfYreDqJhZxYAWFPtrfhNpj4w=="],
|
||||
|
||||
"@babel/parser": ["@babel/parser@7.28.5", "https://registry.npmmirror.com/@babel/parser/-/parser-7.28.5.tgz", { "dependencies": { "@babel/types": "^7.28.5" }, "bin": "./bin/babel-parser.js" }, "sha512-KKBU1VGYR7ORr3At5HAtUQ+TV3SzRCXmA/8OdDZiLDBIZxVyzXuztPjfLd3BV1PRAQGCMWWSHYhL0F8d5uHBDQ=="],
|
||||
|
||||
"@babel/plugin-transform-react-jsx-self": ["@babel/plugin-transform-react-jsx-self@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-6UzkCs+ejGdZ5mFFC/OCUrv028ab2fp1znZmCZjAOBKiBK2jXD1O+BPSfX8X2qjJ75fZBMSnQn3Rq2mrBJK2mw=="],
|
||||
|
||||
"@babel/plugin-transform-react-jsx-source": ["@babel/plugin-transform-react-jsx-source@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-zbwoTsBruTeKB9hSq73ha66iFeJHuaFkUbwvqElnygoNbj/jHRsSeokowZFN3CZ64IvEqcmmkVe89OPXc7ldAw=="],
|
||||
|
||||
"@babel/template": ["@babel/template@7.27.2", "", { "dependencies": { "@babel/code-frame": "^7.27.1", "@babel/parser": "^7.27.2", "@babel/types": "^7.27.1" } }, "sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw=="],
|
||||
|
||||
"@babel/traverse": ["@babel/traverse@7.28.5", "", { "dependencies": { "@babel/code-frame": "^7.27.1", "@babel/generator": "^7.28.5", "@babel/helper-globals": "^7.28.0", "@babel/parser": "^7.28.5", "@babel/template": "^7.27.2", "@babel/types": "^7.28.5", "debug": "^4.3.1" } }, "sha512-TCCj4t55U90khlYkVV/0TfkJkAkUg3jZFA3Neb7unZT8CPok7iiRfaX0F+WnqWqt7OxhOn0uBKXCw4lbL8W0aQ=="],
|
||||
|
||||
"@babel/types": ["@babel/types@7.28.5", "https://registry.npmmirror.com/@babel/types/-/types-7.28.5.tgz", { "dependencies": { "@babel/helper-string-parser": "^7.27.1", "@babel/helper-validator-identifier": "^7.28.5" } }, "sha512-qQ5m48eI/MFLQ5PxQj4PFaprjyCTLI37ElWMmNs0K8Lk3dVeOdNpB3ks8jc7yM5CDmVC73eMVk/trk3fgmrUpA=="],
|
||||
|
||||
"@biomejs/biome": ["@biomejs/biome@2.3.8", "", { "optionalDependencies": { "@biomejs/cli-darwin-arm64": "2.3.8", "@biomejs/cli-darwin-x64": "2.3.8", "@biomejs/cli-linux-arm64": "2.3.8", "@biomejs/cli-linux-arm64-musl": "2.3.8", "@biomejs/cli-linux-x64": "2.3.8", "@biomejs/cli-linux-x64-musl": "2.3.8", "@biomejs/cli-win32-arm64": "2.3.8", "@biomejs/cli-win32-x64": "2.3.8" }, "bin": { "biome": "bin/biome" } }, "sha512-Qjsgoe6FEBxWAUzwFGFrB+1+M8y/y5kwmg5CHac+GSVOdmOIqsAiXM5QMVGZJ1eCUCLlPZtq4aFAQ0eawEUuUA=="],
|
||||
@@ -178,6 +215,10 @@
|
||||
|
||||
"@img/sharp-win32-x64": ["@img/sharp-win32-x64@0.34.5", "https://registry.npmmirror.com/@img/sharp-win32-x64/-/sharp-win32-x64-0.34.5.tgz", { "os": "win32", "cpu": "x64" }, "sha512-+29YMsqY2/9eFEiW93eqWnuLcWcufowXewwSNIT6UwZdUUCrM3oFjMWH/Z6/TMmb4hlFenmfAVbpWeup2jryCw=="],
|
||||
|
||||
"@jridgewell/gen-mapping": ["@jridgewell/gen-mapping@0.3.13", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.0", "@jridgewell/trace-mapping": "^0.3.24" } }, "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA=="],
|
||||
|
||||
"@jridgewell/remapping": ["@jridgewell/remapping@2.3.5", "", { "dependencies": { "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.24" } }, "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ=="],
|
||||
|
||||
"@jridgewell/resolve-uri": ["@jridgewell/resolve-uri@3.1.2", "https://registry.npmmirror.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", {}, "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw=="],
|
||||
|
||||
"@jridgewell/sourcemap-codec": ["@jridgewell/sourcemap-codec@1.5.5", "https://registry.npmmirror.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", {}, "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og=="],
|
||||
@@ -192,6 +233,8 @@
|
||||
|
||||
"@poppinss/exception": ["@poppinss/exception@1.2.2", "https://registry.npmmirror.com/@poppinss/exception/-/exception-1.2.2.tgz", {}, "sha512-m7bpKCD4QMlFCjA/nKTs23fuvoVFoA83brRKmObCUNmi/9tVu8Ve3w4YQAnJu4q3Tjf5fr685HYIC/IA2zHRSg=="],
|
||||
|
||||
"@rolldown/pluginutils": ["@rolldown/pluginutils@1.0.0-beta.27", "", {}, "sha512-+d0F4MKMCbeVUJwG96uQ4SgAznZNSq93I3V+9NHA4OpvqG8mRCpGdKmK8l/dl02h2CCDHwW2FqilnTyDcAnqjA=="],
|
||||
|
||||
"@rollup/pluginutils": ["@rollup/pluginutils@5.3.0", "https://registry.npmmirror.com/@rollup/pluginutils/-/pluginutils-5.3.0.tgz", { "dependencies": { "@types/estree": "^1.0.0", "estree-walker": "^2.0.2", "picomatch": "^4.0.2" }, "peerDependencies": { "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" }, "optionalPeers": ["rollup"] }, "sha512-5EdhGZtnu3V88ces7s53hhfK5KSASnJZv8Lulpc04cWO3REESroJXg73DFsOmgbU2BhwV0E20bu2IDZb3VKW4Q=="],
|
||||
|
||||
"@rollup/rollup-android-arm-eabi": ["@rollup/rollup-android-arm-eabi@4.53.3", "https://registry.npmmirror.com/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.53.3.tgz", { "os": "android", "cpu": "arm" }, "sha512-mRSi+4cBjrRLoaal2PnqH82Wqyb+d3HsPUN/W+WslCXsZsyHa9ZeQQX/pQsZaVIWDkPcpV6jJ+3KLbTbgnwv8w=="],
|
||||
@@ -258,6 +301,14 @@
|
||||
|
||||
"@swc/helpers": ["@swc/helpers@0.5.17", "https://registry.npmmirror.com/@swc/helpers/-/helpers-0.5.17.tgz", { "dependencies": { "tslib": "^2.8.0" } }, "sha512-5IKx/Y13RsYd+sauPb2x+U/xZikHjolzfuDgTAl/Tdf3Q8rslRvC19NKDLgAJQ6wsqADk10ntlv08nPFw/gO/A=="],
|
||||
|
||||
"@types/babel__core": ["@types/babel__core@7.20.5", "", { "dependencies": { "@babel/parser": "^7.20.7", "@babel/types": "^7.20.7", "@types/babel__generator": "*", "@types/babel__template": "*", "@types/babel__traverse": "*" } }, "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA=="],
|
||||
|
||||
"@types/babel__generator": ["@types/babel__generator@7.27.0", "", { "dependencies": { "@babel/types": "^7.0.0" } }, "sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg=="],
|
||||
|
||||
"@types/babel__template": ["@types/babel__template@7.4.4", "", { "dependencies": { "@babel/parser": "^7.1.0", "@babel/types": "^7.0.0" } }, "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A=="],
|
||||
|
||||
"@types/babel__traverse": ["@types/babel__traverse@7.28.0", "", { "dependencies": { "@babel/types": "^7.28.2" } }, "sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q=="],
|
||||
|
||||
"@types/debug": ["@types/debug@4.1.12", "https://registry.npmmirror.com/@types/debug/-/debug-4.1.12.tgz", { "dependencies": { "@types/ms": "*" } }, "sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ=="],
|
||||
|
||||
"@types/estree": ["@types/estree@1.0.8", "https://registry.npmmirror.com/@types/estree/-/estree-1.0.8.tgz", {}, "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w=="],
|
||||
@@ -274,10 +325,16 @@
|
||||
|
||||
"@types/node": ["@types/node@24.10.2", "https://registry.npmmirror.com/@types/node/-/node-24.10.2.tgz", { "dependencies": { "undici-types": "~7.16.0" } }, "sha512-WOhQTZ4G8xZ1tjJTvKOpyEVSGgOTvJAfDK3FNFgELyaTpzhdgHVHeqW8V+UJvzF5BT+/B54T/1S2K6gd9c7bbA=="],
|
||||
|
||||
"@types/react": ["@types/react@19.2.7", "", { "dependencies": { "csstype": "^3.2.2" } }, "sha512-MWtvHrGZLFttgeEj28VXHxpmwYbor/ATPYbBfSFZEIRK0ecCFLl2Qo55z52Hss+UV9CRN7trSeq1zbgx7YDWWg=="],
|
||||
|
||||
"@types/react-dom": ["@types/react-dom@19.2.3", "", { "peerDependencies": { "@types/react": "^19.2.0" } }, "sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ=="],
|
||||
|
||||
"@types/unist": ["@types/unist@3.0.3", "https://registry.npmmirror.com/@types/unist/-/unist-3.0.3.tgz", {}, "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q=="],
|
||||
|
||||
"@ungap/structured-clone": ["@ungap/structured-clone@1.3.0", "https://registry.npmmirror.com/@ungap/structured-clone/-/structured-clone-1.3.0.tgz", {}, "sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g=="],
|
||||
|
||||
"@vitejs/plugin-react": ["@vitejs/plugin-react@4.7.0", "", { "dependencies": { "@babel/core": "^7.28.0", "@babel/plugin-transform-react-jsx-self": "^7.27.1", "@babel/plugin-transform-react-jsx-source": "^7.27.1", "@rolldown/pluginutils": "1.0.0-beta.27", "@types/babel__core": "^7.20.5", "react-refresh": "^0.17.0" }, "peerDependencies": { "vite": "^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0" } }, "sha512-gUu9hwfWvvEDBBmgtAowQCojwZmJ5mcLn3aufeCsitijs3+f2NsrPtlAWIR6OPiqljl96GVCUbLe0HyqIpVaoA=="],
|
||||
|
||||
"acorn": ["acorn@8.15.0", "https://registry.npmmirror.com/acorn/-/acorn-8.15.0.tgz", { "bin": { "acorn": "bin/acorn" } }, "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg=="],
|
||||
|
||||
"acorn-walk": ["acorn-walk@8.3.2", "https://registry.npmmirror.com/acorn-walk/-/acorn-walk-8.3.2.tgz", {}, "sha512-cjkyv4OtNCIeqhHrfS81QWXoCBPExR/J62oyEqepVw8WaQeSqpW2uhuLPh1m9eWhDuOo/jUXVTlifvesOWp/4A=="],
|
||||
@@ -306,6 +363,8 @@
|
||||
|
||||
"base64-js": ["base64-js@1.5.1", "https://registry.npmmirror.com/base64-js/-/base64-js-1.5.1.tgz", {}, "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA=="],
|
||||
|
||||
"baseline-browser-mapping": ["baseline-browser-mapping@2.9.9", "", { "bin": { "baseline-browser-mapping": "dist/cli.js" } }, "sha512-V8fbOCSeOFvlDj7LLChUcqbZrdKD9RU/VR260piF1790vT0mfLSwGc/Qzxv3IqiTukOpNtItePa0HBpMAj7MDg=="],
|
||||
|
||||
"blake3-wasm": ["blake3-wasm@2.1.5", "https://registry.npmmirror.com/blake3-wasm/-/blake3-wasm-2.1.5.tgz", {}, "sha512-F1+K8EbfOZE49dtoPtmxUQrpXaBIl3ICvasLh+nJta0xkz+9kF/7uet9fLnwKqhDrmj6g+6K3Tw9yQPUg2ka5g=="],
|
||||
|
||||
"boolbase": ["boolbase@1.0.0", "https://registry.npmmirror.com/boolbase/-/boolbase-1.0.0.tgz", {}, "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww=="],
|
||||
@@ -314,8 +373,12 @@
|
||||
|
||||
"brotli": ["brotli@1.3.3", "https://registry.npmmirror.com/brotli/-/brotli-1.3.3.tgz", { "dependencies": { "base64-js": "^1.1.2" } }, "sha512-oTKjJdShmDuGW94SyyaoQvAjf30dZaHnjJ8uAF+u2/vGJkJbJPJAT1gDiOJP5v1Zb6f9KEyW/1HpuaWIXtGHPg=="],
|
||||
|
||||
"browserslist": ["browserslist@4.28.1", "", { "dependencies": { "baseline-browser-mapping": "^2.9.0", "caniuse-lite": "^1.0.30001759", "electron-to-chromium": "^1.5.263", "node-releases": "^2.0.27", "update-browserslist-db": "^1.2.0" }, "bin": { "browserslist": "cli.js" } }, "sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA=="],
|
||||
|
||||
"camelcase": ["camelcase@8.0.0", "https://registry.npmmirror.com/camelcase/-/camelcase-8.0.0.tgz", {}, "sha512-8WB3Jcas3swSvjIeA2yvCJ+Miyz5l1ZmB6HFb9R1317dt9LCQoswg/BGrmAmkWVEszSrrg4RwmO46qIm2OEnSA=="],
|
||||
|
||||
"caniuse-lite": ["caniuse-lite@1.0.30001760", "", {}, "sha512-7AAMPcueWELt1p3mi13HR/LHH0TJLT11cnwDJEs3xA4+CK/PLKeO9Kl1oru24htkyUKtkGCvAx4ohB0Ttry8Dw=="],
|
||||
|
||||
"ccount": ["ccount@2.0.1", "https://registry.npmmirror.com/ccount/-/ccount-2.0.1.tgz", {}, "sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg=="],
|
||||
|
||||
"chalk": ["chalk@5.6.2", "https://registry.npmmirror.com/chalk/-/chalk-5.6.2.tgz", {}, "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA=="],
|
||||
@@ -350,6 +413,8 @@
|
||||
|
||||
"common-ancestor-path": ["common-ancestor-path@1.0.1", "https://registry.npmmirror.com/common-ancestor-path/-/common-ancestor-path-1.0.1.tgz", {}, "sha512-L3sHRo1pXXEqX8VU28kfgUY+YGsk09hPqZiZmLacNib6XNTCM8ubYeT7ryXQw8asB1sKgcU5lkB7ONug08aB8w=="],
|
||||
|
||||
"convert-source-map": ["convert-source-map@2.0.0", "", {}, "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg=="],
|
||||
|
||||
"cookie": ["cookie@1.1.1", "https://registry.npmmirror.com/cookie/-/cookie-1.1.1.tgz", {}, "sha512-ei8Aos7ja0weRpFzJnEA9UHJ/7XQmqglbRwnf2ATjcB9Wq874VKH9kfjjirM6UhU2/E5fFYadylyhFldcqSidQ=="],
|
||||
|
||||
"cookie-es": ["cookie-es@1.2.2", "https://registry.npmmirror.com/cookie-es/-/cookie-es-1.2.2.tgz", {}, "sha512-+W7VmiVINB+ywl1HGXJXmrqkOhpKrIiVZV6tQuV54ZyQC7MMuBt81Vc336GMLoHBq5hV/F9eXgt5Mnx0Rha5Fg=="],
|
||||
@@ -366,6 +431,8 @@
|
||||
|
||||
"csso": ["csso@5.0.5", "https://registry.npmmirror.com/csso/-/csso-5.0.5.tgz", { "dependencies": { "css-tree": "~2.2.0" } }, "sha512-0LrrStPOdJj+SPCCrGhzryycLjwcgUSHBtxNA8aIDxf0GLsRh1cKYhB00Gd1lDOS4yGH69+SNn13+TWbVHETFQ=="],
|
||||
|
||||
"csstype": ["csstype@3.2.3", "", {}, "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ=="],
|
||||
|
||||
"debug": ["debug@4.4.3", "https://registry.npmmirror.com/debug/-/debug-4.4.3.tgz", { "dependencies": { "ms": "^2.1.3" } }, "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA=="],
|
||||
|
||||
"decode-named-character-reference": ["decode-named-character-reference@1.2.0", "https://registry.npmmirror.com/decode-named-character-reference/-/decode-named-character-reference-1.2.0.tgz", { "dependencies": { "character-entities": "^2.0.0" } }, "sha512-c6fcElNV6ShtZXmsgNgFFV5tVX2PaV4g+MOAkb8eXHvn6sryJBrZa9r0zV6+dtTyoCKxtDy5tyQ5ZwQuidtd+Q=="],
|
||||
@@ -400,6 +467,8 @@
|
||||
|
||||
"dset": ["dset@3.1.4", "https://registry.npmmirror.com/dset/-/dset-3.1.4.tgz", {}, "sha512-2QF/g9/zTaPDc3BjNcVTGoBbXBgYfMTTceLaYcFJ/W9kggFUkhxD/hMEeuLKbugyef9SqAx8cpgwlIP/jinUTA=="],
|
||||
|
||||
"electron-to-chromium": ["electron-to-chromium@1.5.267", "", {}, "sha512-0Drusm6MVRXSOJpGbaSVgcQsuB4hEkMpHXaVstcPmhu5LIedxs1xNK/nIxmQIU/RPC0+1/o0AVZfBTkTNJOdUw=="],
|
||||
|
||||
"emoji-regex": ["emoji-regex@10.6.0", "https://registry.npmmirror.com/emoji-regex/-/emoji-regex-10.6.0.tgz", {}, "sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A=="],
|
||||
|
||||
"entities": ["entities@6.0.1", "https://registry.npmmirror.com/entities/-/entities-6.0.1.tgz", {}, "sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g=="],
|
||||
@@ -410,6 +479,8 @@
|
||||
|
||||
"esbuild": ["esbuild@0.25.12", "https://registry.npmmirror.com/esbuild/-/esbuild-0.25.12.tgz", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.25.12", "@esbuild/android-arm": "0.25.12", "@esbuild/android-arm64": "0.25.12", "@esbuild/android-x64": "0.25.12", "@esbuild/darwin-arm64": "0.25.12", "@esbuild/darwin-x64": "0.25.12", "@esbuild/freebsd-arm64": "0.25.12", "@esbuild/freebsd-x64": "0.25.12", "@esbuild/linux-arm": "0.25.12", "@esbuild/linux-arm64": "0.25.12", "@esbuild/linux-ia32": "0.25.12", "@esbuild/linux-loong64": "0.25.12", "@esbuild/linux-mips64el": "0.25.12", "@esbuild/linux-ppc64": "0.25.12", "@esbuild/linux-riscv64": "0.25.12", "@esbuild/linux-s390x": "0.25.12", "@esbuild/linux-x64": "0.25.12", "@esbuild/netbsd-arm64": "0.25.12", "@esbuild/netbsd-x64": "0.25.12", "@esbuild/openbsd-arm64": "0.25.12", "@esbuild/openbsd-x64": "0.25.12", "@esbuild/openharmony-arm64": "0.25.12", "@esbuild/sunos-x64": "0.25.12", "@esbuild/win32-arm64": "0.25.12", "@esbuild/win32-ia32": "0.25.12", "@esbuild/win32-x64": "0.25.12" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg=="],
|
||||
|
||||
"escalade": ["escalade@3.2.0", "", {}, "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA=="],
|
||||
|
||||
"escape-string-regexp": ["escape-string-regexp@5.0.0", "https://registry.npmmirror.com/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz", {}, "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw=="],
|
||||
|
||||
"estree-walker": ["estree-walker@3.0.3", "https://registry.npmmirror.com/estree-walker/-/estree-walker-3.0.3.tgz", { "dependencies": { "@types/estree": "^1.0.0" } }, "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g=="],
|
||||
@@ -432,6 +503,8 @@
|
||||
|
||||
"fsevents": ["fsevents@2.3.3", "https://registry.npmmirror.com/fsevents/-/fsevents-2.3.3.tgz", { "os": "darwin" }, "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw=="],
|
||||
|
||||
"gensync": ["gensync@1.0.0-beta.2", "", {}, "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg=="],
|
||||
|
||||
"get-east-asian-width": ["get-east-asian-width@1.4.0", "https://registry.npmmirror.com/get-east-asian-width/-/get-east-asian-width-1.4.0.tgz", {}, "sha512-QZjmEOC+IT1uk6Rx0sX22V6uHWVwbdbxf1faPqJ1QhLdGgsRGCZoyaQBm/piRdJy/D2um6hM1UP7ZEeQ4EkP+Q=="],
|
||||
|
||||
"github-slugger": ["github-slugger@2.0.0", "https://registry.npmmirror.com/github-slugger/-/github-slugger-2.0.0.tgz", {}, "sha512-IaOQ9puYtjrkq7Y0Ygl9KDZnrf/aiUJYUpVf89y8kyaxbRG7Y1SrX/jaumrv81vc61+kiMempujsM3Yw7w5qcw=="],
|
||||
@@ -482,8 +555,14 @@
|
||||
|
||||
"is-wsl": ["is-wsl@3.1.0", "https://registry.npmmirror.com/is-wsl/-/is-wsl-3.1.0.tgz", { "dependencies": { "is-inside-container": "^1.0.0" } }, "sha512-UcVfVfaK4Sc4m7X3dUSoHoozQGBEFeDC+zVo06t98xe8CzHSZZBekNXH+tu0NalHolcJ/QAGqS46Hef7QXBIMw=="],
|
||||
|
||||
"js-tokens": ["js-tokens@4.0.0", "", {}, "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="],
|
||||
|
||||
"js-yaml": ["js-yaml@4.1.1", "https://registry.npmmirror.com/js-yaml/-/js-yaml-4.1.1.tgz", { "dependencies": { "argparse": "^2.0.1" }, "bin": { "js-yaml": "bin/js-yaml.js" } }, "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA=="],
|
||||
|
||||
"jsesc": ["jsesc@3.1.0", "", { "bin": { "jsesc": "bin/jsesc" } }, "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA=="],
|
||||
|
||||
"json5": ["json5@2.2.3", "", { "bin": { "json5": "lib/cli.js" } }, "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg=="],
|
||||
|
||||
"kleur": ["kleur@3.0.3", "https://registry.npmmirror.com/kleur/-/kleur-3.0.3.tgz", {}, "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w=="],
|
||||
|
||||
"longest-streak": ["longest-streak@3.1.0", "https://registry.npmmirror.com/longest-streak/-/longest-streak-3.1.0.tgz", {}, "sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g=="],
|
||||
@@ -598,6 +677,8 @@
|
||||
|
||||
"node-mock-http": ["node-mock-http@1.0.4", "https://registry.npmmirror.com/node-mock-http/-/node-mock-http-1.0.4.tgz", {}, "sha512-8DY+kFsDkNXy1sJglUfuODx1/opAGJGyrTuFqEoN90oRc2Vk0ZbD4K2qmKXBBEhZQzdKHIVfEJpDU8Ak2NJEvQ=="],
|
||||
|
||||
"node-releases": ["node-releases@2.0.27", "", {}, "sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA=="],
|
||||
|
||||
"normalize-path": ["normalize-path@3.0.0", "https://registry.npmmirror.com/normalize-path/-/normalize-path-3.0.0.tgz", {}, "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA=="],
|
||||
|
||||
"nth-check": ["nth-check@2.1.1", "https://registry.npmmirror.com/nth-check/-/nth-check-2.1.1.tgz", { "dependencies": { "boolbase": "^1.0.0" } }, "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w=="],
|
||||
@@ -644,6 +725,12 @@
|
||||
|
||||
"radix3": ["radix3@1.1.2", "https://registry.npmmirror.com/radix3/-/radix3-1.1.2.tgz", {}, "sha512-b484I/7b8rDEdSDKckSSBA8knMpcdsXudlE/LNL639wFoHKwLbEkQFZHWEYwDC0wa0FKUcCY+GAF73Z7wxNVFA=="],
|
||||
|
||||
"react": ["react@19.2.3", "", {}, "sha512-Ku/hhYbVjOQnXDZFv2+RibmLFGwFdeeKHFcOTlrt7xplBnya5OGn/hIRDsqDiSUcfORsDC7MPxwork8jBwsIWA=="],
|
||||
|
||||
"react-dom": ["react-dom@19.2.3", "", { "dependencies": { "scheduler": "^0.27.0" }, "peerDependencies": { "react": "^19.2.3" } }, "sha512-yELu4WmLPw5Mr/lmeEpox5rw3RETacE++JgHqQzd2dg+YbJuat3jH4ingc+WPZhxaoFzdv9y33G+F7Nl5O0GBg=="],
|
||||
|
||||
"react-refresh": ["react-refresh@0.17.0", "", {}, "sha512-z6F7K9bV85EfseRCp2bzrpyQ0Gkw1uLoCel9XBVWPg/TjRj94SkJzUTGfOa4bs7iJvBWtQG0Wq7wnI0syw3EBQ=="],
|
||||
|
||||
"readdirp": ["readdirp@4.1.2", "https://registry.npmmirror.com/readdirp/-/readdirp-4.1.2.tgz", {}, "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg=="],
|
||||
|
||||
"regex": ["regex@6.1.0", "https://registry.npmmirror.com/regex/-/regex-6.1.0.tgz", { "dependencies": { "regex-utilities": "^2.3.0" } }, "sha512-6VwtthbV4o/7+OaAF9I5L5V3llLEsoPyq9P1JVXkedTP33c7MfCG0/5NOPcSJn0TzXcG9YUrR0gQSWioew3LDg=="],
|
||||
@@ -684,6 +771,8 @@
|
||||
|
||||
"sax": ["sax@1.4.3", "https://registry.npmmirror.com/sax/-/sax-1.4.3.tgz", {}, "sha512-yqYn1JhPczigF94DMS+shiDMjDowYO6y9+wB/4WgO0Y19jWYk0lQ4tuG5KI7kj4FTp1wxPj5IFfcrz/s1c3jjQ=="],
|
||||
|
||||
"scheduler": ["scheduler@0.27.0", "", {}, "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q=="],
|
||||
|
||||
"semver": ["semver@7.7.3", "https://registry.npmmirror.com/semver/-/semver-7.7.3.tgz", { "bin": { "semver": "bin/semver.js" } }, "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q=="],
|
||||
|
||||
"sharp": ["sharp@0.34.5", "https://registry.npmmirror.com/sharp/-/sharp-0.34.5.tgz", { "dependencies": { "@img/colour": "^1.0.0", "detect-libc": "^2.1.2", "semver": "^7.7.3" }, "optionalDependencies": { "@img/sharp-darwin-arm64": "0.34.5", "@img/sharp-darwin-x64": "0.34.5", "@img/sharp-libvips-darwin-arm64": "1.2.4", "@img/sharp-libvips-darwin-x64": "1.2.4", "@img/sharp-libvips-linux-arm": "1.2.4", "@img/sharp-libvips-linux-arm64": "1.2.4", "@img/sharp-libvips-linux-ppc64": "1.2.4", "@img/sharp-libvips-linux-riscv64": "1.2.4", "@img/sharp-libvips-linux-s390x": "1.2.4", "@img/sharp-libvips-linux-x64": "1.2.4", "@img/sharp-libvips-linuxmusl-arm64": "1.2.4", "@img/sharp-libvips-linuxmusl-x64": "1.2.4", "@img/sharp-linux-arm": "0.34.5", "@img/sharp-linux-arm64": "0.34.5", "@img/sharp-linux-ppc64": "0.34.5", "@img/sharp-linux-riscv64": "0.34.5", "@img/sharp-linux-s390x": "0.34.5", "@img/sharp-linux-x64": "0.34.5", "@img/sharp-linuxmusl-arm64": "0.34.5", "@img/sharp-linuxmusl-x64": "0.34.5", "@img/sharp-wasm32": "0.34.5", "@img/sharp-win32-arm64": "0.34.5", "@img/sharp-win32-ia32": "0.34.5", "@img/sharp-win32-x64": "0.34.5" } }, "sha512-Ou9I5Ft9WNcCbXrU9cMgPBcCK8LiwLqcbywW3t4oDV37n1pzpuNLsYiAV8eODnjbtQlSDwZ2cUEeQz4E54Hltg=="],
|
||||
@@ -770,6 +859,8 @@
|
||||
|
||||
"unstorage": ["unstorage@1.17.3", "https://registry.npmmirror.com/unstorage/-/unstorage-1.17.3.tgz", { "dependencies": { "anymatch": "^3.1.3", "chokidar": "^4.0.3", "destr": "^2.0.5", "h3": "^1.15.4", "lru-cache": "^10.4.3", "node-fetch-native": "^1.6.7", "ofetch": "^1.5.1", "ufo": "^1.6.1" }, "peerDependencies": { "@azure/app-configuration": "^1.8.0", "@azure/cosmos": "^4.2.0", "@azure/data-tables": "^13.3.0", "@azure/identity": "^4.6.0", "@azure/keyvault-secrets": "^4.9.0", "@azure/storage-blob": "^12.26.0", "@capacitor/preferences": "^6.0.3 || ^7.0.0", "@deno/kv": ">=0.9.0", "@netlify/blobs": "^6.5.0 || ^7.0.0 || ^8.1.0 || ^9.0.0 || ^10.0.0", "@planetscale/database": "^1.19.0", "@upstash/redis": "^1.34.3", "@vercel/blob": ">=0.27.1", "@vercel/functions": "^2.2.12 || ^3.0.0", "@vercel/kv": "^1.0.1", "aws4fetch": "^1.0.20", "db0": ">=0.2.1", "idb-keyval": "^6.2.1", "ioredis": "^5.4.2", "uploadthing": "^7.4.4" }, "optionalPeers": ["@azure/app-configuration", "@azure/cosmos", "@azure/data-tables", "@azure/identity", "@azure/keyvault-secrets", "@azure/storage-blob", "@capacitor/preferences", "@deno/kv", "@netlify/blobs", "@planetscale/database", "@upstash/redis", "@vercel/blob", "@vercel/functions", "@vercel/kv", "aws4fetch", "db0", "idb-keyval", "ioredis", "uploadthing"] }, "sha512-i+JYyy0DoKmQ3FximTHbGadmIYb8JEpq7lxUjnjeB702bCPum0vzo6oy5Mfu0lpqISw7hCyMW2yj4nWC8bqJ3Q=="],
|
||||
|
||||
"update-browserslist-db": ["update-browserslist-db@1.2.3", "", { "dependencies": { "escalade": "^3.2.0", "picocolors": "^1.1.1" }, "peerDependencies": { "browserslist": ">= 4.21.0" }, "bin": { "update-browserslist-db": "cli.js" } }, "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w=="],
|
||||
|
||||
"vfile": ["vfile@6.0.3", "https://registry.npmmirror.com/vfile/-/vfile-6.0.3.tgz", { "dependencies": { "@types/unist": "^3.0.0", "vfile-message": "^4.0.0" } }, "sha512-KzIbH/9tXat2u30jf+smMwFCsno4wHVdNmzFyL+T/L3UGqqk6JKfVqOFOZEpZSHADH1k40ab6NUIXZq422ov3Q=="],
|
||||
|
||||
"vfile-location": ["vfile-location@5.0.3", "https://registry.npmmirror.com/vfile-location/-/vfile-location-5.0.3.tgz", { "dependencies": { "@types/unist": "^3.0.0", "vfile": "^6.0.0" } }, "sha512-5yXvWDEgqeiYiBe1lbxYF7UMAIm/IcopxMHrMQDq3nvKcjPKIhZklUKL+AE7J7uApI4kwe2snsK+eI6UTj9EHg=="],
|
||||
@@ -796,6 +887,8 @@
|
||||
|
||||
"xxhash-wasm": ["xxhash-wasm@1.1.0", "https://registry.npmmirror.com/xxhash-wasm/-/xxhash-wasm-1.1.0.tgz", {}, "sha512-147y/6YNh+tlp6nd/2pWq38i9h6mz/EuQ6njIrmW8D1BS5nCqs0P6DG+m6zTGnNz5I+uhZ0SHxBs9BsPrwcKDA=="],
|
||||
|
||||
"yallist": ["yallist@3.1.1", "", {}, "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g=="],
|
||||
|
||||
"yargs-parser": ["yargs-parser@21.1.1", "https://registry.npmmirror.com/yargs-parser/-/yargs-parser-21.1.1.tgz", {}, "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw=="],
|
||||
|
||||
"yocto-queue": ["yocto-queue@1.2.2", "https://registry.npmmirror.com/yocto-queue/-/yocto-queue-1.2.2.tgz", {}, "sha512-4LCcse/U2MHZ63HAJVE+v71o7yOdIe4cZ70Wpf8D/IyjDKYQLV5GD46B+hSTjJsvV5PztjvHoU580EftxjDZFQ=="],
|
||||
@@ -816,6 +909,18 @@
|
||||
|
||||
"zwitch": ["zwitch@2.0.4", "https://registry.npmmirror.com/zwitch/-/zwitch-2.0.4.tgz", {}, "sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A=="],
|
||||
|
||||
"@babel/core/semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="],
|
||||
|
||||
"@babel/generator/@jridgewell/trace-mapping": ["@jridgewell/trace-mapping@0.3.31", "", { "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" } }, "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw=="],
|
||||
|
||||
"@babel/helper-compilation-targets/lru-cache": ["lru-cache@5.1.1", "", { "dependencies": { "yallist": "^3.0.2" } }, "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w=="],
|
||||
|
||||
"@babel/helper-compilation-targets/semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="],
|
||||
|
||||
"@jridgewell/gen-mapping/@jridgewell/trace-mapping": ["@jridgewell/trace-mapping@0.3.31", "", { "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" } }, "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw=="],
|
||||
|
||||
"@jridgewell/remapping/@jridgewell/trace-mapping": ["@jridgewell/trace-mapping@0.3.31", "", { "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" } }, "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw=="],
|
||||
|
||||
"@poppinss/colors/kleur": ["kleur@4.1.5", "https://registry.npmmirror.com/kleur/-/kleur-4.1.5.tgz", {}, "sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ=="],
|
||||
|
||||
"@rollup/pluginutils/estree-walker": ["estree-walker@2.0.2", "https://registry.npmmirror.com/estree-walker/-/estree-walker-2.0.2.tgz", {}, "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w=="],
|
||||
|
||||
@@ -15,7 +15,12 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@astrojs/cloudflare": "^12.6.12",
|
||||
"astro": "^5.0.0"
|
||||
"@astrojs/react": "^4.4.2",
|
||||
"@types/react": "^19.2.7",
|
||||
"@types/react-dom": "^19.2.3",
|
||||
"astro": "^5.0.0",
|
||||
"react": "^19.2.3",
|
||||
"react-dom": "^19.2.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@biomejs/biome": "2.3.8"
|
||||
|
||||
@@ -1 +1 @@
|
||||
<svg viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" width="64" height="64"><path d="M824.8 613.2c-16-51.4-34.4-94.6-62.7-165.3C766.5 262.2 689.3 112 511.5 112 331.7 112 256.2 265.2 261 447.9c-28.4 70.8-46.7 113.7-62.7 165.3-34 109.5-23 154.8-14.6 155.8 18 2.2 70.1-82.4 70.1-82.4 0 49 25.2 112.9 79.8 159-26.4 8.1-85.7 29.9-71.6 53.8 11.4 19.3 196.2 12.3 249.5 6.3 53.3 6 238.1 13 249.5-6.3 14.1-23.8-45.3-45.7-71.6-53.8 54.6-46.2 79.8-110.1 79.8-159 0 0 52.1 84.6 70.1 82.4 8.5-1.1 19.5-46.4-14.5-155.8z"></path></svg>
|
||||
<svg viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" width="64" height="64"><path d="M824.8 613.2c-16-51.4-34.4-94.6-62.7-165.3C766.5 262.2 689.3 112 511.5 112 331.7 112 256.2 265.2 261 447.9c-28.4 70.8-46.7 113.7-62.7 165.3-34 109.5-23 154.8-14.6 155.8 18 2.2 70.1-82.4 70.1-82.4 0 49 25.2 112.9 79.8 159-26.4 8.1-85.7 29.9-71.6 53.8 11.4 19.3 196.2 12.3 249.5 6.3 53.3 6 238.1 13 249.5-6.3 14.1-23.8-45.3-45.7-71.6-53.8 54.6-46.2 79.8-110.1 79.8-159 0 0 52.1 84.6 70.1 82.4 8.5-1.1 19.5-46.4-14.5-155.8z" fill="white"></path></svg>
|
||||
|
Before Width: | Height: | Size: 545 B After Width: | Height: | Size: 558 B |
1
src/assets/icons/user.svg
Normal file
1
src/assets/icons/user.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" width="64" height="64"><path d="M512 1024C229.205333 1024 0 794.794667 0 512S229.205333 0 512 0s512 229.205333 512 512-229.205333 512-512 512z m0-496.469333a170.666667 170.666667 0 1 0 0-341.333334 170.666667 170.666667 0 0 0 0 341.333334z m263.765333 263.722666a263.765333 263.765333 0 1 0-527.530666 0h527.530666z"></path></svg>
|
||||
|
After Width: | Height: | Size: 408 B |
326
src/components/CentralIsland.astro
Normal file
326
src/components/CentralIsland.astro
Normal file
@@ -0,0 +1,326 @@
|
||||
---
|
||||
import DashboardView from "./central-island/DashboardView.astro";
|
||||
import LoginView from "./central-island/LoginView.astro";
|
||||
import QQAuthView from "./central-island/QQAuthView.astro";
|
||||
import RegisterView from "./central-island/RegisterView.astro";
|
||||
import TitleCard from "./central-island/TitleCard.astro";
|
||||
import VerificationView from "./central-island/VerificationView.astro";
|
||||
|
||||
// Props for the component
|
||||
const { titleSvg } = Astro.props;
|
||||
---
|
||||
|
||||
<div class="island-container">
|
||||
<TitleCard titleSvg={titleSvg}/>
|
||||
<LoginView/>
|
||||
<QQAuthView/>
|
||||
<VerificationView/>
|
||||
<RegisterView/>
|
||||
<DashboardView/>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
const API_BASE = "https://lolisland.awfufu.com/api";
|
||||
let isLoggedIn = false;
|
||||
let currentQQ = "";
|
||||
let pollIntervalId: string | number | NodeJS.Timeout | null | undefined =
|
||||
null;
|
||||
|
||||
// DOM Elements
|
||||
const views = {
|
||||
title: document.getElementById("view-title"),
|
||||
login: document.getElementById("view-login"),
|
||||
qqInput: document.getElementById("view-qq-input"),
|
||||
verification: document.getElementById("view-verification"),
|
||||
register: document.getElementById("view-register"),
|
||||
dashboard: document.getElementById("view-dashboard"),
|
||||
};
|
||||
|
||||
type ViewName = keyof typeof views;
|
||||
|
||||
// Inputs
|
||||
const inputs = {
|
||||
loginUser: document.getElementById("login-username") as HTMLInputElement,
|
||||
loginPass: document.getElementById("login-password") as HTMLInputElement,
|
||||
qqId: document.getElementById("qq-id-input") as HTMLInputElement,
|
||||
regUser: document.getElementById("reg-username") as HTMLInputElement,
|
||||
regPass: document.getElementById("reg-password") as HTMLInputElement,
|
||||
};
|
||||
|
||||
// Displays
|
||||
const displays = {
|
||||
loginError: document.getElementById("login-error"),
|
||||
qqError: document.getElementById("qq-error"),
|
||||
regError: document.getElementById("reg-error"),
|
||||
verifyCode: document.getElementById("verification-code-display"),
|
||||
dashAvatar: document.getElementById(
|
||||
"dashboard-avatar-img",
|
||||
) as HTMLImageElement,
|
||||
};
|
||||
|
||||
// --- Helpers ---
|
||||
function switchView(viewName: string) {
|
||||
Object.values(views).forEach((el) => {
|
||||
if (el) el.classList.add("hidden");
|
||||
});
|
||||
// Safe check if viewName is a valid key, otherwise ignore
|
||||
if (Object.hasOwn(views, viewName)) {
|
||||
const el = views[viewName as ViewName];
|
||||
if (el) el.classList.remove("hidden");
|
||||
}
|
||||
window.dispatchEvent(
|
||||
new CustomEvent("view-change", { detail: { view: viewName } }),
|
||||
);
|
||||
}
|
||||
|
||||
function showError(element: HTMLElement | null, msg: string) {
|
||||
if (element) {
|
||||
element.textContent = msg;
|
||||
element.classList.remove("hidden");
|
||||
}
|
||||
}
|
||||
|
||||
function clearErrors() {
|
||||
if (displays.loginError) displays.loginError.classList.add("hidden");
|
||||
if (displays.qqError) displays.qqError.classList.add("hidden");
|
||||
if (displays.regError) displays.regError.classList.add("hidden");
|
||||
}
|
||||
|
||||
function updateDashboard() {
|
||||
if (displays.dashAvatar) {
|
||||
if (currentQQ) {
|
||||
displays.dashAvatar.src = `https://q.qlogo.cn/headimg_dl?dst_uin=${currentQQ}&spec=640&img_type=jpg`;
|
||||
} else {
|
||||
displays.dashAvatar.src =
|
||||
"https://ui-avatars.com/api/?name=User&background=random";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function handleLoginSuccess(token: string, qq: string) {
|
||||
localStorage.setItem("token", token);
|
||||
if (qq) {
|
||||
localStorage.setItem("qq", String(qq));
|
||||
currentQQ = String(qq);
|
||||
}
|
||||
isLoggedIn = true;
|
||||
updateDashboard();
|
||||
window.dispatchEvent(new CustomEvent("login-success"));
|
||||
switchView("dashboard");
|
||||
}
|
||||
|
||||
// --- Auth Logic ---
|
||||
async function performLogin() {
|
||||
const u = inputs.loginUser?.value;
|
||||
const p = inputs.loginPass?.value;
|
||||
if (!u || !p)
|
||||
return showError(displays.loginError, "Please fill all fields");
|
||||
|
||||
clearErrors();
|
||||
try {
|
||||
const res = await fetch(`${API_BASE}/login`, {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({ username: u, password: p }),
|
||||
});
|
||||
const data = await res.json();
|
||||
if (data.token) {
|
||||
handleLoginSuccess(data.token, data.qq);
|
||||
if (inputs.loginUser) inputs.loginUser.value = "";
|
||||
if (inputs.loginPass) inputs.loginPass.value = "";
|
||||
} else {
|
||||
showError(displays.loginError, data.error || "Login failed");
|
||||
}
|
||||
} catch (e) {
|
||||
showError(displays.loginError, "Network error");
|
||||
}
|
||||
}
|
||||
|
||||
async function startQQAuth() {
|
||||
const qq = inputs.qqId?.value;
|
||||
if (!qq) return showError(displays.qqError, "Enter your QQ");
|
||||
|
||||
clearErrors();
|
||||
try {
|
||||
const res = await fetch(`${API_BASE}/auth/qq/start`, {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({ qq }),
|
||||
});
|
||||
const data = await res.json();
|
||||
if (data.code) {
|
||||
if (displays.verifyCode) displays.verifyCode.textContent = data.code;
|
||||
currentQQ = qq;
|
||||
switchView("verification");
|
||||
startPolling(qq);
|
||||
} else {
|
||||
showError(displays.qqError, data.error || "Failed to start auth");
|
||||
}
|
||||
} catch (e) {
|
||||
showError(displays.qqError, "Network error");
|
||||
}
|
||||
}
|
||||
|
||||
function startPolling(qqToPoll: string) {
|
||||
if (pollIntervalId) clearInterval(pollIntervalId);
|
||||
pollIntervalId = setInterval(async () => {
|
||||
try {
|
||||
const res = await fetch(`${API_BASE}/auth/qq/status?qq=${qqToPoll}`);
|
||||
const data = await res.json();
|
||||
|
||||
if (data.status === "verified") {
|
||||
clearInterval(pollIntervalId as NodeJS.Timeout);
|
||||
pollIntervalId = null;
|
||||
switchView("register");
|
||||
} else if (data.status === "authenticated") {
|
||||
clearInterval(pollIntervalId as NodeJS.Timeout);
|
||||
pollIntervalId = null;
|
||||
handleLoginSuccess(data.token, data.qq);
|
||||
}
|
||||
} catch (e) {
|
||||
console.error("Polling error", e);
|
||||
}
|
||||
}, 2000);
|
||||
}
|
||||
|
||||
async function performRegister() {
|
||||
const u = inputs.regUser?.value;
|
||||
const p = inputs.regPass?.value;
|
||||
if (!u || !p) return showError(displays.regError, "Please fill all fields");
|
||||
|
||||
clearErrors();
|
||||
try {
|
||||
const res = await fetch(`${API_BASE}/register`, {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({ username: u, password: p, qq: currentQQ }),
|
||||
});
|
||||
const data = await res.json();
|
||||
if (res.ok) {
|
||||
const loginRes = await fetch(`${API_BASE}/login`, {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({ username: u, password: p }),
|
||||
});
|
||||
const loginData = await loginRes.json();
|
||||
if (loginData.token) {
|
||||
handleLoginSuccess(loginData.token, loginData.qq);
|
||||
} else {
|
||||
switchView("login");
|
||||
}
|
||||
} else {
|
||||
showError(displays.regError, data.error || "Registration failed");
|
||||
}
|
||||
} catch (e) {
|
||||
showError(displays.regError, "Network error");
|
||||
}
|
||||
}
|
||||
|
||||
// --- Initialization ---
|
||||
function checkLoginState() {
|
||||
const token = localStorage.getItem("token");
|
||||
const storedQQ = localStorage.getItem("qq");
|
||||
isLoggedIn = !!token;
|
||||
if (storedQQ) currentQQ = storedQQ;
|
||||
|
||||
if (isLoggedIn) {
|
||||
updateDashboard();
|
||||
switchView("dashboard");
|
||||
} else {
|
||||
switchView("title");
|
||||
}
|
||||
}
|
||||
|
||||
// --- Event Listeners ---
|
||||
// Note: Elements might be null if not yet rendered/loaded by Astro in some edge cases but usually fine.
|
||||
// Actually, since sub-components are static Astro components, they are rendered in HTML immediately.
|
||||
// So standard document.getElementById works.
|
||||
|
||||
if (views.title) {
|
||||
views.title.addEventListener("click", () => {
|
||||
if (isLoggedIn) {
|
||||
switchView("dashboard");
|
||||
} else {
|
||||
switchView("login");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Use event delegation or re-attach logic for close buttons
|
||||
// Since we replaced HTML blocks with components, the close buttons are now inside those components.
|
||||
// They still have data-action="close"
|
||||
document.querySelectorAll('[data-action="close"]').forEach((btn) => {
|
||||
btn.addEventListener("click", (e) => {
|
||||
e.stopPropagation();
|
||||
switchView("title");
|
||||
if (pollIntervalId) clearInterval(pollIntervalId as NodeJS.Timeout);
|
||||
clearErrors();
|
||||
});
|
||||
});
|
||||
|
||||
document
|
||||
.getElementById("btn-login-submit")
|
||||
?.addEventListener("click", performLogin);
|
||||
document
|
||||
.getElementById("btn-qq-mode")
|
||||
?.addEventListener("click", () => switchView("qqInput"));
|
||||
document
|
||||
.getElementById("btn-qq-next")
|
||||
?.addEventListener("click", startQQAuth);
|
||||
document
|
||||
.getElementById("btn-cancel-verify")
|
||||
?.addEventListener("click", () => {
|
||||
if (pollIntervalId) clearInterval(pollIntervalId as NodeJS.Timeout);
|
||||
switchView("qqInput");
|
||||
});
|
||||
document
|
||||
.getElementById("btn-register-submit")
|
||||
?.addEventListener("click", performRegister);
|
||||
|
||||
document.querySelectorAll(".back-text-btn").forEach((btn) => {
|
||||
const target = btn.getAttribute("data-target");
|
||||
if (target) {
|
||||
btn.addEventListener("click", () => {
|
||||
switchView(target === "view-login" ? "login" : "title");
|
||||
clearErrors();
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
window.addEventListener("open-login", () => {
|
||||
if (isLoggedIn) {
|
||||
switchView("dashboard");
|
||||
} else {
|
||||
switchView("login");
|
||||
}
|
||||
});
|
||||
|
||||
window.addEventListener("login-success", () => {
|
||||
const token = localStorage.getItem("token");
|
||||
isLoggedIn = !!token;
|
||||
const storedQQ = localStorage.getItem("qq");
|
||||
if (storedQQ) currentQQ = storedQQ;
|
||||
updateDashboard();
|
||||
if (isLoggedIn) switchView("dashboard");
|
||||
});
|
||||
|
||||
window.addEventListener("logout-success", () => {
|
||||
isLoggedIn = false;
|
||||
currentQQ = "";
|
||||
localStorage.removeItem("token");
|
||||
localStorage.removeItem("qq");
|
||||
switchView("title");
|
||||
});
|
||||
|
||||
checkLoginState();
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.island-container {
|
||||
display: grid;
|
||||
place-items: center;
|
||||
width: 100%;
|
||||
opacity: 1;
|
||||
transition: opacity 0.5s ease;
|
||||
}
|
||||
</style>
|
||||
@@ -1,41 +1,35 @@
|
||||
---
|
||||
import titleSvg from "../assets/title.svg?raw";
|
||||
import CentralIsland from "./CentralIsland.astro";
|
||||
import Footer from "./Footer.astro";
|
||||
import Navbar from "./Navbar.astro";
|
||||
import Particles from "./Particles.astro";
|
||||
import LoginWindow from "./LoginWindow.astro";
|
||||
---
|
||||
|
||||
<Navbar />
|
||||
<Navbar/>
|
||||
<div class="particles-container">
|
||||
<Particles />
|
||||
<Particles/>
|
||||
</div>
|
||||
<div class="halo"></div>
|
||||
<div class="grain"></div>
|
||||
<div id="marble-field"></div>
|
||||
<Footer />
|
||||
<Footer/>
|
||||
|
||||
<div class="content">
|
||||
<div class="title-card">
|
||||
<div class="title-svg-container" set:html={titleSvg} />
|
||||
</div>
|
||||
<LoginWindow />
|
||||
<CentralIsland titleSvg={titleSvg}/>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
import { fetchUsers } from "../data/users";
|
||||
import { MarbleSystem } from "../utils/marbleSystem";
|
||||
|
||||
const titleCard = document.querySelector(".title-card") as HTMLElement;
|
||||
const navbar = document.querySelector(".navbar") as HTMLElement;
|
||||
const titleImg = document.querySelector(
|
||||
".title-svg-container svg",
|
||||
) as HTMLElement;
|
||||
// const titleCard = document.querySelector(".title-card") as HTMLElement; // Handled by React now
|
||||
|
||||
if (titleImg && titleCard && navbar) {
|
||||
if (navbar) {
|
||||
const reveal = () => {
|
||||
requestAnimationFrame(() => {
|
||||
titleCard.style.opacity = "1";
|
||||
// titleCard.style.opacity = "1"; // React handles its own opacity
|
||||
navbar.style.opacity = "1";
|
||||
});
|
||||
};
|
||||
@@ -148,24 +142,11 @@ import LoginWindow from "./LoginWindow.astro";
|
||||
|
||||
// Toggle Title
|
||||
let titleTimeout: number;
|
||||
window.addEventListener("toggle-title", ((e: CustomEvent) => {
|
||||
const titleCard = document.querySelector(".title-card") as HTMLElement;
|
||||
if (titleCard) {
|
||||
clearTimeout(titleTimeout);
|
||||
if (e.detail.enabled) {
|
||||
titleCard.style.display = "inline-block";
|
||||
// Force Reflow
|
||||
void titleCard.offsetWidth;
|
||||
titleCard.style.opacity = "1";
|
||||
titleCard.style.pointerEvents = "auto";
|
||||
} else {
|
||||
titleCard.style.opacity = "0";
|
||||
titleCard.style.pointerEvents = "none";
|
||||
titleTimeout = setTimeout(() => {
|
||||
titleCard.style.display = "none";
|
||||
}, 500) as unknown as number;
|
||||
}
|
||||
}
|
||||
window.addEventListener("toggle-title", ((_e: CustomEvent) => {
|
||||
// Toggle Title - handled by React/Island mostly, but we might want to hide the whole island?
|
||||
// For now, let's assume the specific "toggle-title" event from settings aimed at the old title card.
|
||||
// If we want to hide the new island title, we'd need to emit an event the React component listens to.
|
||||
// Let's remove the old logic for now to fix errors.
|
||||
}) as EventListener);
|
||||
|
||||
// Toggle Marbles
|
||||
@@ -230,28 +211,7 @@ import LoginWindow from "./LoginWindow.astro";
|
||||
}
|
||||
}) as EventListener);
|
||||
|
||||
// Login Window Logic
|
||||
const loginWindowEl = document.querySelector(
|
||||
".login-window",
|
||||
) as HTMLElement;
|
||||
|
||||
window.addEventListener("open-login", () => {
|
||||
if (titleCard) {
|
||||
titleCard.style.opacity = "0";
|
||||
titleCard.style.pointerEvents = "none";
|
||||
}
|
||||
if (loginWindowEl) {
|
||||
loginWindowEl.style.opacity = "1";
|
||||
loginWindowEl.style.pointerEvents = "auto";
|
||||
}
|
||||
});
|
||||
|
||||
window.addEventListener("close-login", () => {
|
||||
if (loginWindowEl) {
|
||||
loginWindowEl.style.opacity = "0";
|
||||
loginWindowEl.style.pointerEvents = "none";
|
||||
}
|
||||
});
|
||||
// Login Window Logic - Moved to CentralIsland.tsx
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
---
|
||||
import userIconRaw from "../assets/icons/user.svg?raw";
|
||||
import titleImg from "../assets/title.svg";
|
||||
import UserDropdown from "./UserDropdown.astro";
|
||||
---
|
||||
|
||||
<nav class="navbar">
|
||||
@@ -9,45 +11,36 @@ import titleImg from "../assets/title.svg";
|
||||
class="nav-title"
|
||||
height="32"
|
||||
style="height: 32px; width: auto;"
|
||||
/>
|
||||
<a
|
||||
href="https://github.com/101island"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
class="github-link"
|
||||
>
|
||||
<svg
|
||||
height="32"
|
||||
aria-hidden="true"
|
||||
viewBox="0 0 16 16"
|
||||
version="1.1"
|
||||
width="32"
|
||||
data-view-component="true"
|
||||
class="octicon octicon-mark-github v-align-middle"
|
||||
<div class="right-section">
|
||||
<a
|
||||
href="https://github.com/101island"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
class="github-link"
|
||||
>
|
||||
<path
|
||||
d="M8 0c4.42 0 8 3.58 8 8a8.013 8.013 0 0 1-5.45 7.59c-.4.08-.55-.17-.55-.38 0-.27.01-1.13.01-2.2 0-.75-.25-1.23-.54-1.48 1.78-.2 3.65-.88 3.65-3.95 0-.88-.31-1.59-.82-2.15.08-.2.36-1.02-.08-2.12 0 0-.67-.22-2.2.82-.64-.18-1.32-.27-2-.27-.68 0-1.36.09-2 .27-1.53-1.03-2.2-.82-2.2-.82-.44 1.1-.16 1.92-.08 2.12-.51.56-.82 1.28-.82 2.15 0 3.06 1.86 3.75 3.64 3.95-.23.2-.44.55-.51 1.07-.46.46-1.61.55-2.33-.66-.15-.24-.6-.83-1.23-.82-.67.01-.27.38.01.53.34.19.73.9.82 1.13.16.45.68 1.31 2.69.94 0 .67.01 1.3.01 1.49 0 .21-.15.45-.55.38A7.995 7.995 0 0 1 0 8c0-4.42 3.58-8 8-8Z"
|
||||
></path>
|
||||
</svg>
|
||||
</a>
|
||||
<svg
|
||||
height="32"
|
||||
aria-hidden="true"
|
||||
viewBox="0 0 16 16"
|
||||
version="1.1"
|
||||
width="32"
|
||||
data-view-component="true"
|
||||
class="octicon octicon-mark-github v-align-middle"
|
||||
>
|
||||
<path
|
||||
d="M8 0c4.42 0 8 3.58 8 8a8.013 8.013 0 0 1-5.45 7.59c-.4.08-.55-.17-.55-.38 0-.27.01-1.13.01-2.2 0-.75-.25-1.23-.54-1.48 1.78-.2 3.65-.88 3.65-3.95 0-.88-.31-1.59-.82-2.15.08-.2.36-1.02-.08-2.12 0 0-.67-.22-2.2.82-.64-.18-1.32-.27-2-.27-.68 0-1.36.09-2 .27-1.53-1.03-2.2-.82-2.2-.82-.44 1.1-.16 1.92-.08 2.12-.51.56-.82 1.28-.82 2.15 0 3.06 1.86 3.75 3.64 3.95-.23.2-.44.55-.51 1.07-.46.46-1.61.55-2.33-.66-.15-.24-.6-.83-1.23-.82-.67.01-.27.38.01.53.34.19.73.9.82 1.13.16.45.68 1.31 2.69.94 0 .67.01 1.3.01 1.49 0 .21-.15.45-.55.38A7.995 7.995 0 0 1 0 8c0-4.42 3.58-8 8-8Z"
|
||||
></path>
|
||||
</svg>
|
||||
</a>
|
||||
|
||||
<button class="user-login-btn" aria-label="Login">
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="28"
|
||||
height="28"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="2"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
class="user-icon"
|
||||
>
|
||||
<path d="M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2"></path>
|
||||
<circle cx="12" cy="7" r="4"></circle>
|
||||
</svg>
|
||||
</button>
|
||||
<div class="user-action-container">
|
||||
<button class="user-login-btn" aria-label="Login">
|
||||
<span class="user-icon-container" set:html={userIconRaw}/>
|
||||
</button>
|
||||
<UserDropdown/>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<style>
|
||||
@@ -74,6 +67,13 @@ import titleImg from "../assets/title.svg";
|
||||
transition: opacity 1s ease;
|
||||
}
|
||||
|
||||
.right-section {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 1.25rem;
|
||||
margin-left: auto;
|
||||
}
|
||||
|
||||
.github-link {
|
||||
color: white;
|
||||
opacity: 0.7;
|
||||
@@ -82,8 +82,6 @@ import titleImg from "../assets/title.svg";
|
||||
transform 0.2s;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-left: auto; /* Push to right */
|
||||
margin-right: 1.5rem; /* Gap between github and user */
|
||||
}
|
||||
|
||||
.github-link:hover {
|
||||
@@ -91,6 +89,11 @@ import titleImg from "../assets/title.svg";
|
||||
transform: scale(1.1);
|
||||
}
|
||||
|
||||
.user-action-container {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.user-login-btn {
|
||||
background: none;
|
||||
border: none;
|
||||
@@ -108,6 +111,24 @@ import titleImg from "../assets/title.svg";
|
||||
.user-login-btn:hover {
|
||||
opacity: 1;
|
||||
transform: scale(1.1);
|
||||
color: rgba(124, 251, 255, 0.8);
|
||||
}
|
||||
|
||||
.user-login-btn.hidden {
|
||||
/* biome-ignore lint/complexity/noImportantStyles: utility class */
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
.user-login-btn.disabled {
|
||||
pointer-events: none;
|
||||
opacity: 0.3;
|
||||
}
|
||||
|
||||
.user-icon-container :global(svg) {
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
fill: currentColor;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.octicon {
|
||||
@@ -131,10 +152,42 @@ import titleImg from "../assets/title.svg";
|
||||
}
|
||||
}
|
||||
|
||||
const loginBtn = document.querySelector(".user-login-btn");
|
||||
const loginBtn = document.querySelector(
|
||||
".user-login-btn",
|
||||
) as HTMLButtonElement;
|
||||
|
||||
function checkLoginState() {
|
||||
const token = localStorage.getItem("token");
|
||||
if (token && loginBtn) {
|
||||
loginBtn.classList.add("hidden");
|
||||
} else if (loginBtn) {
|
||||
loginBtn.classList.remove("hidden");
|
||||
}
|
||||
}
|
||||
|
||||
// Initial check
|
||||
checkLoginState();
|
||||
|
||||
// Listeners
|
||||
window.addEventListener("login-success", checkLoginState);
|
||||
window.addEventListener("logout-success", checkLoginState);
|
||||
|
||||
if (loginBtn) {
|
||||
loginBtn.addEventListener("click", () => {
|
||||
window.dispatchEvent(new CustomEvent("open-login"));
|
||||
});
|
||||
|
||||
// Handle view changes from CentralIsland
|
||||
window.addEventListener("view-change", ((e: CustomEvent) => {
|
||||
const view = e.detail.view;
|
||||
|
||||
if (view !== "title") {
|
||||
loginBtn.classList.add("disabled");
|
||||
loginBtn.setAttribute("disabled", "true");
|
||||
} else {
|
||||
loginBtn.classList.remove("disabled");
|
||||
loginBtn.removeAttribute("disabled");
|
||||
}
|
||||
}) as EventListener);
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -37,37 +37,37 @@
|
||||
<div class="separator"></div>
|
||||
|
||||
<label class="toggle-switch">
|
||||
<input type="checkbox" id="title-toggle" checked />
|
||||
<input type="checkbox" id="title-toggle" checked>
|
||||
<span class="slider"></span>
|
||||
<span class="label-text">Title</span>
|
||||
</label>
|
||||
|
||||
<label class="toggle-switch">
|
||||
<input type="checkbox" id="marbles-toggle" checked />
|
||||
<input type="checkbox" id="marbles-toggle" checked>
|
||||
<span class="slider"></span>
|
||||
<span class="label-text">Marbles</span>
|
||||
</label>
|
||||
|
||||
<label class="toggle-switch" id="collision-container">
|
||||
<input type="checkbox" id="collision-toggle" checked />
|
||||
<input type="checkbox" id="collision-toggle" checked>
|
||||
<span class="slider"></span>
|
||||
<span class="label-text">Collisions</span>
|
||||
</label>
|
||||
|
||||
<label class="toggle-switch" id="device-motion-container">
|
||||
<input type="checkbox" id="device-motion-toggle" checked />
|
||||
<input type="checkbox" id="device-motion-toggle" checked>
|
||||
<span class="slider"></span>
|
||||
<span class="label-text">Motion</span>
|
||||
</label>
|
||||
|
||||
<label class="toggle-switch" id="device-orientation-container">
|
||||
<input type="checkbox" id="device-orientation-toggle" checked />
|
||||
<input type="checkbox" id="device-orientation-toggle" checked>
|
||||
<span class="slider"></span>
|
||||
<span class="label-text">Orientation</span>
|
||||
</label>
|
||||
|
||||
<label class="toggle-switch">
|
||||
<input type="checkbox" id="background-toggle" checked />
|
||||
<input type="checkbox" id="background-toggle" checked>
|
||||
<span class="slider"></span>
|
||||
<span class="label-text">Background</span>
|
||||
</label>
|
||||
|
||||
188
src/components/UserDropdown.astro
Normal file
188
src/components/UserDropdown.astro
Normal file
@@ -0,0 +1,188 @@
|
||||
<div class="user-dropdown hidden">
|
||||
<button class="user-avatar-btn" aria-label="User Menu">
|
||||
<img src="" alt="User Avatar" class="user-avatar-img">
|
||||
</button>
|
||||
<div class="dropdown-menu">
|
||||
<button class="menu-item logout-btn">Logout</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
const userDropdown = document.querySelector(".user-dropdown") as HTMLElement;
|
||||
const avatarImg = document.querySelector(
|
||||
".user-avatar-img",
|
||||
) as HTMLImageElement;
|
||||
const avatarBtn = document.querySelector(
|
||||
".user-avatar-btn",
|
||||
) as HTMLButtonElement;
|
||||
const dropdownMenu = document.querySelector(".dropdown-menu") as HTMLElement;
|
||||
const logoutBtn = document.querySelector(".logout-btn") as HTMLButtonElement;
|
||||
|
||||
async function updateAvatar() {
|
||||
let qq = localStorage.getItem("qq");
|
||||
const token = localStorage.getItem("token");
|
||||
|
||||
if (token) {
|
||||
if (!qq) {
|
||||
try {
|
||||
// Fetch user info from backend if token exists but QQ is missing
|
||||
const res = await fetch("https://lolisland.awfufu.com/api/me", {
|
||||
headers: { Authorization: `Bearer ${token}` },
|
||||
});
|
||||
if (res.ok) {
|
||||
const data = await res.json();
|
||||
if (data.qq) {
|
||||
qq = String(data.qq);
|
||||
localStorage.setItem("qq", qq);
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
console.error("Failed to fetch user info", e);
|
||||
}
|
||||
}
|
||||
|
||||
if (qq) {
|
||||
avatarImg.src = `https://q.qlogo.cn/headimg_dl?dst_uin=${qq}&spec=640&img_type=jpg`;
|
||||
} else {
|
||||
// Default avatar or placeholder if QQ is missing and fetch failed
|
||||
avatarImg.src =
|
||||
"https://ui-avatars.com/api/?name=User&background=random";
|
||||
}
|
||||
userDropdown.classList.remove("hidden");
|
||||
} else {
|
||||
userDropdown.classList.add("hidden");
|
||||
}
|
||||
}
|
||||
|
||||
// Initial check
|
||||
updateAvatar();
|
||||
|
||||
// Listen for login success event
|
||||
window.addEventListener("login-success", updateAvatar);
|
||||
|
||||
// Toggle Dropdown
|
||||
if (avatarBtn) {
|
||||
avatarBtn.addEventListener("click", (e) => {
|
||||
e.stopPropagation();
|
||||
dropdownMenu.classList.toggle("active");
|
||||
});
|
||||
}
|
||||
|
||||
// Close dropdown when clicking outside
|
||||
document.addEventListener("click", (e) => {
|
||||
if (userDropdown && !userDropdown.contains(e.target as Node)) {
|
||||
dropdownMenu.classList.remove("active");
|
||||
}
|
||||
});
|
||||
|
||||
// Logout
|
||||
if (logoutBtn) {
|
||||
logoutBtn.addEventListener("click", () => {
|
||||
localStorage.removeItem("token");
|
||||
localStorage.removeItem("qq");
|
||||
userDropdown.classList.add("hidden");
|
||||
dropdownMenu.classList.remove("active");
|
||||
// Notify other components if necessary, e.g. show login button again
|
||||
window.dispatchEvent(new CustomEvent("logout-success"));
|
||||
});
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.user-dropdown {
|
||||
position: relative;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.hidden {
|
||||
/* biome-ignore lint/complexity/noImportantStyles: utility class */
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
.user-avatar-btn {
|
||||
background: none;
|
||||
border: none;
|
||||
padding: 0;
|
||||
cursor: pointer;
|
||||
border-radius: 50%;
|
||||
overflow: hidden;
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
border: 2px solid rgba(255, 255, 255, 0.2);
|
||||
transition: border-color 0.2s;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.user-avatar-btn:hover {
|
||||
border-color: rgba(255, 255, 255, 0.8);
|
||||
}
|
||||
|
||||
.user-avatar-img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
}
|
||||
|
||||
.dropdown-menu {
|
||||
position: absolute;
|
||||
top: 100%;
|
||||
right: 0;
|
||||
margin-top: 10px;
|
||||
background: rgba(15, 15, 15, 0.75); /* Dark semi-transparent */
|
||||
backdrop-filter: blur(16px);
|
||||
-webkit-backdrop-filter: blur(16px);
|
||||
border: 1px solid rgba(255, 255, 255, 0.1);
|
||||
border-radius: 16px;
|
||||
padding: 0.6rem;
|
||||
min-width: 140px;
|
||||
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.5);
|
||||
z-index: 1001;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.5rem;
|
||||
opacity: 0;
|
||||
pointer-events: none;
|
||||
transform: translateY(10px);
|
||||
transition:
|
||||
opacity 0.2s ease,
|
||||
transform 0.2s ease;
|
||||
}
|
||||
|
||||
.dropdown-menu.active {
|
||||
opacity: 1;
|
||||
pointer-events: auto;
|
||||
transform: translateY(0);
|
||||
}
|
||||
|
||||
.menu-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center; /* Center text */
|
||||
width: 100%;
|
||||
padding: 0.8rem 1rem;
|
||||
border-radius: 12px;
|
||||
border: 1px solid rgba(255, 255, 255, 0.1); /* Subtle border */
|
||||
background: linear-gradient(
|
||||
145deg,
|
||||
rgba(255, 255, 255, 0.08),
|
||||
rgba(255, 255, 255, 0.02)
|
||||
);
|
||||
color: rgba(255, 255, 255, 0.9);
|
||||
cursor: pointer;
|
||||
font-size: 0.95rem;
|
||||
font-weight: 500;
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
|
||||
.menu-item:hover {
|
||||
background: linear-gradient(
|
||||
145deg,
|
||||
rgba(255, 255, 255, 0.12),
|
||||
rgba(255, 255, 255, 0.06)
|
||||
);
|
||||
transform: translateY(-1px);
|
||||
border-color: rgba(255, 255, 255, 0.2);
|
||||
}
|
||||
</style>
|
||||
122
src/components/central-island/DashboardView.astro
Normal file
122
src/components/central-island/DashboardView.astro
Normal file
@@ -0,0 +1,122 @@
|
||||
<div id="view-dashboard" class="login-window fade-in dashboard-view hidden">
|
||||
<button class="close-btn" data-action="close">
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="24"
|
||||
height="24"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="2"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
>
|
||||
<line x1="18" y1="6" x2="6" y2="18"></line>
|
||||
<line x1="6" y1="6" x2="18" y2="18"></line>
|
||||
</svg>
|
||||
</button>
|
||||
<div class="dashboard-avatar">
|
||||
<img id="dashboard-avatar-img" src="" alt="User Avatar">
|
||||
</div>
|
||||
<h2>Logged In</h2>
|
||||
<p class="instruction">Development in progress...</p>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.hidden {
|
||||
/* biome-ignore lint/complexity/noImportantStyles: utility class */
|
||||
display: none !important;
|
||||
}
|
||||
.login-window {
|
||||
padding: 2rem 2.4rem;
|
||||
border-radius: 22px;
|
||||
border: 1px solid rgba(255, 255, 255, 0.18);
|
||||
background: linear-gradient(
|
||||
145deg,
|
||||
rgba(255, 255, 255, 0.12),
|
||||
rgba(255, 255, 255, 0.04)
|
||||
);
|
||||
backdrop-filter: blur(6px);
|
||||
box-shadow:
|
||||
0 0 0 1px rgba(255, 255, 255, 0.08),
|
||||
0 10px 40px rgba(0, 0, 0, 0.5);
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
text-align: center;
|
||||
width: 640px; /* Doubled width */
|
||||
max-width: 90vw;
|
||||
pointer-events: auto;
|
||||
}
|
||||
|
||||
.close-btn {
|
||||
position: absolute;
|
||||
top: 1rem;
|
||||
right: 1rem;
|
||||
background: transparent;
|
||||
border: none;
|
||||
color: rgba(255, 255, 255, 0.7);
|
||||
cursor: pointer;
|
||||
padding: 4px;
|
||||
border-radius: 50%;
|
||||
transition:
|
||||
background 0.2s,
|
||||
color 0.2s;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
.close-btn:hover {
|
||||
background: rgba(255, 255, 255, 0.1);
|
||||
color: white;
|
||||
}
|
||||
|
||||
h2 {
|
||||
margin: 0 0 1.5rem 0;
|
||||
font-size: 1.8rem;
|
||||
color: #f7f7ff; /* var(--text) */
|
||||
text-shadow: 0 2px 10px rgba(0, 0, 0, 0.3);
|
||||
}
|
||||
|
||||
.instruction {
|
||||
color: rgba(255, 255, 255, 0.8);
|
||||
margin-bottom: 1rem;
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
|
||||
.dashboard-view {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding-top: 3rem;
|
||||
padding-bottom: 3rem;
|
||||
}
|
||||
.dashboard-avatar {
|
||||
width: 96px;
|
||||
height: 96px;
|
||||
border-radius: 24px;
|
||||
overflow: hidden;
|
||||
margin-bottom: 1.5rem;
|
||||
border: 2px solid rgba(255, 255, 255, 0.2);
|
||||
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.3);
|
||||
}
|
||||
.dashboard-avatar img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
}
|
||||
|
||||
.fade-in {
|
||||
animation: fadeIn 0.5s ease forwards;
|
||||
}
|
||||
@keyframes fadeIn {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translateY(10px);
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -1,9 +1,9 @@
|
||||
---
|
||||
import qqIcon from "../assets/icons/qq.svg?raw";
|
||||
import qqIconRaw from "../../assets/icons/qq.svg?raw";
|
||||
---
|
||||
|
||||
<div class="login-window">
|
||||
<button class="close-btn" aria-label="Close Login">
|
||||
<div id="view-login" class="login-window fade-in hidden">
|
||||
<button class="close-btn" data-action="close">
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="24"
|
||||
@@ -19,39 +19,36 @@ import qqIcon from "../assets/icons/qq.svg?raw";
|
||||
<line x1="6" y1="6" x2="18" y2="18"></line>
|
||||
</svg>
|
||||
</button>
|
||||
<h2>Login</h2>
|
||||
<input
|
||||
type="text"
|
||||
id="login-username"
|
||||
placeholder="Username"
|
||||
class="input-field"
|
||||
>
|
||||
<input
|
||||
type="password"
|
||||
id="login-password"
|
||||
placeholder="Password"
|
||||
class="input-field"
|
||||
>
|
||||
<button id="btn-login-submit" class="submit-btn">Login</button>
|
||||
|
||||
<div class="login-form">
|
||||
<h2>Login</h2>
|
||||
<input type="text" placeholder="Username" class="input-field" />
|
||||
<input type="password" placeholder="Password" class="input-field" />
|
||||
|
||||
<button class="qq-btn" aria-label="Login with QQ" set:html={qqIcon} />
|
||||
<div class="divider">
|
||||
<span>OR</span>
|
||||
</div>
|
||||
|
||||
<button id="btn-qq-mode" class="qq-btn" title="Login with QQ">
|
||||
<span set:html={qqIconRaw} style="display: flex; align-items: center;"/>
|
||||
</button>
|
||||
<p class="error-msg hidden" id="login-error"></p>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
const loginWindow = document.querySelector(".login-window") as HTMLElement;
|
||||
const closeBtn = document.querySelector(".close-btn");
|
||||
|
||||
/* Input Validation */
|
||||
const inputs = document.querySelectorAll(
|
||||
".input-field",
|
||||
) as NodeListOf<HTMLInputElement>;
|
||||
inputs.forEach((input) => {
|
||||
input.addEventListener("input", () => {
|
||||
// Allow only a-z, A-Z, 0-9, -, _, @, .
|
||||
input.value = input.value.replace(/[^a-zA-Z0-9\-_@\.]/g, "");
|
||||
});
|
||||
});
|
||||
|
||||
if (loginWindow && closeBtn) {
|
||||
closeBtn.addEventListener("click", () => {
|
||||
window.dispatchEvent(new CustomEvent("close-login"));
|
||||
});
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.hidden {
|
||||
/* biome-ignore lint/complexity/noImportantStyles: utility class */
|
||||
display: none !important;
|
||||
}
|
||||
.login-window {
|
||||
padding: 2rem 2.4rem;
|
||||
border-radius: 22px;
|
||||
@@ -65,32 +62,12 @@ import qqIcon from "../assets/icons/qq.svg?raw";
|
||||
box-shadow:
|
||||
0 0 0 1px rgba(255, 255, 255, 0.08),
|
||||
0 10px 40px rgba(0, 0, 0, 0.5);
|
||||
display: inline-block;
|
||||
width: auto;
|
||||
min-width: 300px;
|
||||
max-width: 90vw;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
pointer-events: none; /* Initially hidden interaction */
|
||||
z-index: 10;
|
||||
opacity: 0;
|
||||
transition: opacity 0.5s ease;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
/* Shared with Title Card for consistency if needed, but defining locally */
|
||||
.login-window::after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
border-radius: 22px;
|
||||
background: linear-gradient(
|
||||
120deg,
|
||||
rgba(124, 251, 255, 0.06),
|
||||
rgba(255, 127, 209, 0.05),
|
||||
rgba(255, 209, 102, 0.05)
|
||||
);
|
||||
z-index: -1;
|
||||
width: 640px; /* Doubled width */
|
||||
max-width: 90vw;
|
||||
pointer-events: auto;
|
||||
}
|
||||
|
||||
.close-btn {
|
||||
@@ -110,7 +87,6 @@ import qqIcon from "../assets/icons/qq.svg?raw";
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.close-btn:hover {
|
||||
background: rgba(255, 255, 255, 0.1);
|
||||
color: white;
|
||||
@@ -119,17 +95,10 @@ import qqIcon from "../assets/icons/qq.svg?raw";
|
||||
h2 {
|
||||
margin: 0 0 1.5rem 0;
|
||||
font-size: 1.8rem;
|
||||
color: var(--text);
|
||||
color: #f7f7ff; /* var(--text) */
|
||||
text-shadow: 0 2px 10px rgba(0, 0, 0, 0.3);
|
||||
}
|
||||
|
||||
.login-form {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 1rem;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.input-field {
|
||||
width: 100%;
|
||||
padding: 0.8rem 1rem;
|
||||
@@ -142,24 +111,73 @@ import qqIcon from "../assets/icons/qq.svg?raw";
|
||||
transition:
|
||||
border-color 0.2s,
|
||||
background 0.2s;
|
||||
margin-bottom: 1rem;
|
||||
font-family:
|
||||
monospace, ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas,
|
||||
"Liberation Mono", "Courier New";
|
||||
text-align: center; /* Center input text */
|
||||
}
|
||||
|
||||
.input-field:focus {
|
||||
border-color: rgba(124, 251, 255, 0.5);
|
||||
background: rgba(0, 0, 0, 0.3);
|
||||
}
|
||||
|
||||
.input-field::placeholder {
|
||||
color: rgba(255, 255, 255, 0.4);
|
||||
}
|
||||
|
||||
.qq-btn {
|
||||
.submit-btn {
|
||||
width: 100%;
|
||||
padding: 1rem;
|
||||
border-radius: 14px;
|
||||
border: none;
|
||||
background: linear-gradient(
|
||||
135deg,
|
||||
rgba(255, 255, 255, 0.1),
|
||||
rgba(255, 255, 255, 0.05)
|
||||
);
|
||||
color: white;
|
||||
font-weight: 600;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s ease;
|
||||
border: 1px solid rgba(255, 255, 255, 0.1);
|
||||
margin-top: 0.5rem;
|
||||
width: 48px;
|
||||
height: 48px;
|
||||
}
|
||||
.submit-btn:hover {
|
||||
background: linear-gradient(
|
||||
135deg,
|
||||
rgba(255, 255, 255, 0.2),
|
||||
rgba(255, 255, 255, 0.1)
|
||||
);
|
||||
transform: translateY(-1px);
|
||||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.2);
|
||||
}
|
||||
.submit-btn:disabled {
|
||||
opacity: 0.7;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
.divider {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
margin: 1rem 0;
|
||||
color: rgba(255, 255, 255, 0.4);
|
||||
font-size: 0.8rem;
|
||||
}
|
||||
.divider::before,
|
||||
.divider::after {
|
||||
content: "";
|
||||
flex: 1;
|
||||
height: 1px;
|
||||
background: rgba(255, 255, 255, 0.2);
|
||||
}
|
||||
.divider span {
|
||||
padding: 0 10px;
|
||||
}
|
||||
|
||||
.qq-btn {
|
||||
width: 56px;
|
||||
height: 56px;
|
||||
border-radius: 50%;
|
||||
border: 1px solid rgba(255, 255, 255, 0.18);
|
||||
background: linear-gradient(
|
||||
@@ -169,14 +187,13 @@ import qqIcon from "../assets/icons/qq.svg?raw";
|
||||
);
|
||||
color: white;
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
transition:
|
||||
transform 0.2s,
|
||||
background 0.2s;
|
||||
}
|
||||
|
||||
.qq-btn:hover {
|
||||
transform: translateY(-2px);
|
||||
background: linear-gradient(
|
||||
@@ -185,10 +202,26 @@ import qqIcon from "../assets/icons/qq.svg?raw";
|
||||
rgba(255, 255, 255, 0.08)
|
||||
);
|
||||
}
|
||||
|
||||
.qq-btn :global(svg) {
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
fill: currentColor;
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
}
|
||||
.error-msg {
|
||||
color: #ff6b6b;
|
||||
margin-top: 10px;
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
.fade-in {
|
||||
animation: fadeIn 0.5s ease forwards;
|
||||
}
|
||||
@keyframes fadeIn {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translateY(10px);
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
175
src/components/central-island/QQAuthView.astro
Normal file
175
src/components/central-island/QQAuthView.astro
Normal file
@@ -0,0 +1,175 @@
|
||||
<div id="view-qq-input" class="login-window fade-in hidden">
|
||||
<button class="close-btn" data-action="close">
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="24"
|
||||
height="24"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="2"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
>
|
||||
<line x1="18" y1="6" x2="6" y2="18"></line>
|
||||
<line x1="6" y1="6" x2="18" y2="18"></line>
|
||||
</svg>
|
||||
</button>
|
||||
<h2>QQ Login</h2>
|
||||
<p class="instruction">Enter your QQ id to start</p>
|
||||
<input type="text" id="qq-id-input" placeholder="QQ" class="input-field">
|
||||
<button id="btn-qq-next" class="submit-btn">Next</button>
|
||||
<button class="back-text-btn" data-target="view-login">Back to Login</button>
|
||||
<p class="error-msg hidden" id="qq-error"></p>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.hidden {
|
||||
/* biome-ignore lint/complexity/noImportantStyles: utility class */
|
||||
display: none !important;
|
||||
}
|
||||
.login-window {
|
||||
padding: 2rem 2.4rem;
|
||||
border-radius: 22px;
|
||||
border: 1px solid rgba(255, 255, 255, 0.18);
|
||||
background: linear-gradient(
|
||||
145deg,
|
||||
rgba(255, 255, 255, 0.12),
|
||||
rgba(255, 255, 255, 0.04)
|
||||
);
|
||||
backdrop-filter: blur(6px);
|
||||
box-shadow:
|
||||
0 0 0 1px rgba(255, 255, 255, 0.08),
|
||||
0 10px 40px rgba(0, 0, 0, 0.5);
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
text-align: center;
|
||||
width: 640px; /* Doubled width */
|
||||
max-width: 90vw;
|
||||
pointer-events: auto;
|
||||
}
|
||||
|
||||
.close-btn {
|
||||
position: absolute;
|
||||
top: 1rem;
|
||||
right: 1rem;
|
||||
background: transparent;
|
||||
border: none;
|
||||
color: rgba(255, 255, 255, 0.7);
|
||||
cursor: pointer;
|
||||
padding: 4px;
|
||||
border-radius: 50%;
|
||||
transition:
|
||||
background 0.2s,
|
||||
color 0.2s;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
.close-btn:hover {
|
||||
background: rgba(255, 255, 255, 0.1);
|
||||
color: white;
|
||||
}
|
||||
|
||||
h2 {
|
||||
margin: 0 0 1.5rem 0;
|
||||
font-size: 1.8rem;
|
||||
color: #f7f7ff; /* var(--text) */
|
||||
text-shadow: 0 2px 10px rgba(0, 0, 0, 0.3);
|
||||
}
|
||||
|
||||
.instruction {
|
||||
color: rgba(255, 255, 255, 0.8);
|
||||
margin-bottom: 1rem;
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
|
||||
.input-field {
|
||||
width: 100%;
|
||||
padding: 0.8rem 1rem;
|
||||
border-radius: 12px;
|
||||
border: 1px solid rgba(255, 255, 255, 0.15);
|
||||
background: rgba(0, 0, 0, 0.2);
|
||||
color: white;
|
||||
font-size: 1rem;
|
||||
outline: none;
|
||||
transition:
|
||||
border-color 0.2s,
|
||||
background 0.2s;
|
||||
margin-bottom: 1rem;
|
||||
font-family:
|
||||
monospace, ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas,
|
||||
"Liberation Mono", "Courier New";
|
||||
text-align: center; /* Center input text */
|
||||
}
|
||||
.input-field:focus {
|
||||
border-color: rgba(124, 251, 255, 0.5);
|
||||
background: rgba(0, 0, 0, 0.3);
|
||||
}
|
||||
.input-field::placeholder {
|
||||
color: rgba(255, 255, 255, 0.4);
|
||||
}
|
||||
|
||||
.submit-btn {
|
||||
width: 100%;
|
||||
padding: 1rem;
|
||||
border-radius: 14px;
|
||||
border: none;
|
||||
background: linear-gradient(
|
||||
135deg,
|
||||
rgba(255, 255, 255, 0.1),
|
||||
rgba(255, 255, 255, 0.05)
|
||||
);
|
||||
color: white;
|
||||
font-weight: 600;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s ease;
|
||||
border: 1px solid rgba(255, 255, 255, 0.1);
|
||||
margin-top: 0.5rem;
|
||||
}
|
||||
.submit-btn:hover {
|
||||
background: linear-gradient(
|
||||
135deg,
|
||||
rgba(255, 255, 255, 0.2),
|
||||
rgba(255, 255, 255, 0.1)
|
||||
);
|
||||
transform: translateY(-1px);
|
||||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.2);
|
||||
}
|
||||
.submit-btn:disabled {
|
||||
opacity: 0.7;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
.back-text-btn {
|
||||
background: none;
|
||||
border: none;
|
||||
color: rgba(255, 255, 255, 0.5);
|
||||
cursor: pointer;
|
||||
font-size: 0.9rem;
|
||||
margin-top: 1rem;
|
||||
text-decoration: underline;
|
||||
}
|
||||
.back-text-btn:hover {
|
||||
color: white;
|
||||
}
|
||||
|
||||
.error-msg {
|
||||
color: #ff6b6b;
|
||||
margin-top: 10px;
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
.fade-in {
|
||||
animation: fadeIn 0.5s ease forwards;
|
||||
}
|
||||
@keyframes fadeIn {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translateY(10px);
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
173
src/components/central-island/RegisterView.astro
Normal file
173
src/components/central-island/RegisterView.astro
Normal file
@@ -0,0 +1,173 @@
|
||||
<div id="view-register" class="login-window fade-in hidden">
|
||||
<button class="close-btn" data-action="close">
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="24"
|
||||
height="24"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="2"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
>
|
||||
<line x1="18" y1="6" x2="6" y2="18"></line>
|
||||
<line x1="6" y1="6" x2="18" y2="18"></line>
|
||||
</svg>
|
||||
</button>
|
||||
<h2>Complete Registration</h2>
|
||||
<p class="instruction">Set up your username and password</p>
|
||||
<input
|
||||
type="text"
|
||||
id="reg-username"
|
||||
placeholder="Username"
|
||||
class="input-field"
|
||||
>
|
||||
<input
|
||||
type="password"
|
||||
id="reg-password"
|
||||
placeholder="Password"
|
||||
class="input-field"
|
||||
>
|
||||
<button id="btn-register-submit" class="submit-btn">Register</button>
|
||||
<p class="error-msg hidden" id="reg-error"></p>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.hidden {
|
||||
/* biome-ignore lint/complexity/noImportantStyles: utility class */
|
||||
display: none !important;
|
||||
}
|
||||
.login-window {
|
||||
padding: 2rem 2.4rem;
|
||||
border-radius: 22px;
|
||||
border: 1px solid rgba(255, 255, 255, 0.18);
|
||||
background: linear-gradient(
|
||||
145deg,
|
||||
rgba(255, 255, 255, 0.12),
|
||||
rgba(255, 255, 255, 0.04)
|
||||
);
|
||||
backdrop-filter: blur(6px);
|
||||
box-shadow:
|
||||
0 0 0 1px rgba(255, 255, 255, 0.08),
|
||||
0 10px 40px rgba(0, 0, 0, 0.5);
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
text-align: center;
|
||||
width: 640px; /* Doubled width */
|
||||
max-width: 90vw;
|
||||
pointer-events: auto;
|
||||
}
|
||||
|
||||
.close-btn {
|
||||
position: absolute;
|
||||
top: 1rem;
|
||||
right: 1rem;
|
||||
background: transparent;
|
||||
border: none;
|
||||
color: rgba(255, 255, 255, 0.7);
|
||||
cursor: pointer;
|
||||
padding: 4px;
|
||||
border-radius: 50%;
|
||||
transition:
|
||||
background 0.2s,
|
||||
color 0.2s;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
.close-btn:hover {
|
||||
background: rgba(255, 255, 255, 0.1);
|
||||
color: white;
|
||||
}
|
||||
|
||||
h2 {
|
||||
margin: 0 0 1.5rem 0;
|
||||
font-size: 1.8rem;
|
||||
color: #f7f7ff; /* var(--text) */
|
||||
text-shadow: 0 2px 10px rgba(0, 0, 0, 0.3);
|
||||
}
|
||||
|
||||
.instruction {
|
||||
color: rgba(255, 255, 255, 0.8);
|
||||
margin-bottom: 1rem;
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
|
||||
.input-field {
|
||||
width: 100%;
|
||||
padding: 0.8rem 1rem;
|
||||
border-radius: 12px;
|
||||
border: 1px solid rgba(255, 255, 255, 0.15);
|
||||
background: rgba(0, 0, 0, 0.2);
|
||||
color: white;
|
||||
font-size: 1rem;
|
||||
outline: none;
|
||||
transition:
|
||||
border-color 0.2s,
|
||||
background 0.2s;
|
||||
margin-bottom: 1rem;
|
||||
font-family:
|
||||
monospace, ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas,
|
||||
"Liberation Mono", "Courier New";
|
||||
text-align: center; /* Center input text */
|
||||
}
|
||||
.input-field:focus {
|
||||
border-color: rgba(124, 251, 255, 0.5);
|
||||
background: rgba(0, 0, 0, 0.3);
|
||||
}
|
||||
.input-field::placeholder {
|
||||
color: rgba(255, 255, 255, 0.4);
|
||||
}
|
||||
|
||||
.submit-btn {
|
||||
width: 100%;
|
||||
padding: 1rem;
|
||||
border-radius: 14px;
|
||||
border: none;
|
||||
background: linear-gradient(
|
||||
135deg,
|
||||
rgba(255, 255, 255, 0.1),
|
||||
rgba(255, 255, 255, 0.05)
|
||||
);
|
||||
color: white;
|
||||
font-weight: 600;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s ease;
|
||||
border: 1px solid rgba(255, 255, 255, 0.1);
|
||||
margin-top: 0.5rem;
|
||||
}
|
||||
.submit-btn:hover {
|
||||
background: linear-gradient(
|
||||
135deg,
|
||||
rgba(255, 255, 255, 0.2),
|
||||
rgba(255, 255, 255, 0.1)
|
||||
);
|
||||
transform: translateY(-1px);
|
||||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.2);
|
||||
}
|
||||
.submit-btn:disabled {
|
||||
opacity: 0.7;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
.error-msg {
|
||||
color: #ff6b6b;
|
||||
margin-top: 10px;
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
|
||||
.fade-in {
|
||||
animation: fadeIn 0.5s ease forwards;
|
||||
}
|
||||
@keyframes fadeIn {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translateY(10px);
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
58
src/components/central-island/TitleCard.astro
Normal file
58
src/components/central-island/TitleCard.astro
Normal file
@@ -0,0 +1,58 @@
|
||||
---
|
||||
const { titleSvg } = Astro.props;
|
||||
---
|
||||
|
||||
<div id="view-title" class="title-card fade-in">
|
||||
<div class="title-svg-container" set:html={titleSvg}/>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.hidden {
|
||||
/* biome-ignore lint/complexity/noImportantStyles: utility class */
|
||||
display: none !important;
|
||||
}
|
||||
.title-card {
|
||||
cursor: pointer;
|
||||
padding: 1.8rem 2.4rem;
|
||||
border-radius: 22px;
|
||||
border: 1px solid rgba(255, 255, 255, 0.18);
|
||||
background: linear-gradient(
|
||||
145deg,
|
||||
rgba(255, 255, 255, 0.12),
|
||||
rgba(255, 255, 255, 0.04)
|
||||
);
|
||||
backdrop-filter: blur(6px);
|
||||
box-shadow:
|
||||
0 0 0 1px rgba(255, 255, 255, 0.08),
|
||||
0 10px 40px rgba(0, 0, 0, 0.5);
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
pointer-events: auto;
|
||||
}
|
||||
.title-card::after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
border-radius: 22px;
|
||||
background: linear-gradient(
|
||||
120deg,
|
||||
rgba(124, 251, 255, 0.06),
|
||||
rgba(255, 127, 209, 0.05),
|
||||
rgba(255, 209, 102, 0.05)
|
||||
);
|
||||
z-index: -1;
|
||||
}
|
||||
.fade-in {
|
||||
animation: fadeIn 0.5s ease forwards;
|
||||
}
|
||||
@keyframes fadeIn {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translateY(10px);
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
145
src/components/central-island/VerificationView.astro
Normal file
145
src/components/central-island/VerificationView.astro
Normal file
@@ -0,0 +1,145 @@
|
||||
<div id="view-verification" class="login-window fade-in hidden">
|
||||
<button class="close-btn" data-action="close">
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="24"
|
||||
height="24"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="2"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
>
|
||||
<line x1="18" y1="6" x2="6" y2="18"></line>
|
||||
<line x1="6" y1="6" x2="18" y2="18"></line>
|
||||
</svg>
|
||||
</button>
|
||||
<h2>Verification</h2>
|
||||
<p class="instruction">
|
||||
Please send the following code to the bot in the QQ group:
|
||||
</p>
|
||||
<div id="verification-code-display" class="verification-code">......</div>
|
||||
<p class="status-text">Waiting for verification...</p>
|
||||
<button class="back-text-btn" id="btn-cancel-verify">Cancel</button>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.hidden {
|
||||
/* biome-ignore lint/complexity/noImportantStyles: utility class */
|
||||
display: none !important;
|
||||
}
|
||||
.login-window {
|
||||
padding: 2rem 2.4rem;
|
||||
border-radius: 22px;
|
||||
border: 1px solid rgba(255, 255, 255, 0.18);
|
||||
background: linear-gradient(
|
||||
145deg,
|
||||
rgba(255, 255, 255, 0.12),
|
||||
rgba(255, 255, 255, 0.04)
|
||||
);
|
||||
backdrop-filter: blur(6px);
|
||||
box-shadow:
|
||||
0 0 0 1px rgba(255, 255, 255, 0.08),
|
||||
0 10px 40px rgba(0, 0, 0, 0.5);
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
text-align: center;
|
||||
width: 640px; /* Doubled width */
|
||||
max-width: 90vw;
|
||||
pointer-events: auto;
|
||||
}
|
||||
|
||||
.close-btn {
|
||||
position: absolute;
|
||||
top: 1rem;
|
||||
right: 1rem;
|
||||
background: transparent;
|
||||
border: none;
|
||||
color: rgba(255, 255, 255, 0.7);
|
||||
cursor: pointer;
|
||||
padding: 4px;
|
||||
border-radius: 50%;
|
||||
transition:
|
||||
background 0.2s,
|
||||
color 0.2s;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
.close-btn:hover {
|
||||
background: rgba(255, 255, 255, 0.1);
|
||||
color: white;
|
||||
}
|
||||
|
||||
h2 {
|
||||
margin: 0 0 1.5rem 0;
|
||||
font-size: 1.8rem;
|
||||
color: #f7f7ff; /* var(--text) */
|
||||
text-shadow: 0 2px 10px rgba(0, 0, 0, 0.3);
|
||||
}
|
||||
|
||||
.instruction {
|
||||
color: rgba(255, 255, 255, 0.8);
|
||||
margin-bottom: 1rem;
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
|
||||
.verification-code {
|
||||
font-size: 1.5rem;
|
||||
font-family: monospace;
|
||||
letter-spacing: 4px;
|
||||
background: rgba(0, 0, 0, 0.3);
|
||||
padding: 1rem 2rem;
|
||||
border-radius: 12px;
|
||||
border: 1px dashed rgba(255, 255, 255, 0.3);
|
||||
margin: 1rem 0;
|
||||
user-select: all;
|
||||
color: #7cfbff;
|
||||
}
|
||||
|
||||
.status-text {
|
||||
font-size: 0.9rem;
|
||||
color: rgba(255, 255, 255, 0.6);
|
||||
font-style: italic;
|
||||
animation: pulse 2s infinite;
|
||||
}
|
||||
@keyframes pulse {
|
||||
0% {
|
||||
opacity: 0.6;
|
||||
}
|
||||
50% {
|
||||
opacity: 1;
|
||||
}
|
||||
100% {
|
||||
opacity: 0.6;
|
||||
}
|
||||
}
|
||||
|
||||
.back-text-btn {
|
||||
background: none;
|
||||
border: none;
|
||||
color: rgba(255, 255, 255, 0.5);
|
||||
cursor: pointer;
|
||||
font-size: 0.9rem;
|
||||
margin-top: 1rem;
|
||||
text-decoration: underline;
|
||||
}
|
||||
.back-text-btn:hover {
|
||||
color: white;
|
||||
}
|
||||
|
||||
.fade-in {
|
||||
animation: fadeIn 0.5s ease forwards;
|
||||
}
|
||||
@keyframes fadeIn {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translateY(10px);
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user