diff --git a/.github/workflows/deploy-static.yml b/.github/workflows/deploy-static.yml index 9ea80ba..6d0f260 100644 --- a/.github/workflows/deploy-static.yml +++ b/.github/workflows/deploy-static.yml @@ -4,14 +4,30 @@ on: push: branches: - release + pull_request: + types: + - closed + branches: + - release + workflow_dispatch: permissions: contents: write jobs: build-and-deploy: + if: | + github.event_name == 'push' || + github.event_name == 'workflow_dispatch' || + (github.event_name == 'pull_request' && github.event.pull_request.merged == true) + runs-on: ubuntu-latest + env: + DEPLOY_ENV: "CDN" + CDN_BASEURL: "https://cdn.jsdelivr.net/gh/scarletborder/bloggerv2@static/" + API_ENDPOINT: "https://blog.scarletborder.cn" + steps: - name: Checkout release branch uses: actions/checkout@v5 @@ -26,8 +42,8 @@ jobs: - name: Setup Node.js uses: actions/setup-node@v4 with: - node-version: '22' - cache: 'pnpm' + node-version: "22" + cache: "pnpm" - name: Install dependencies run: pnpm install --frozen-lockfile @@ -38,34 +54,38 @@ jobs: - name: Find built assets and generate report id: generate-report run: | - # 定义 CDN 基础路径 - CDN_BASE="https://cdn.jsdelivr.net/gh/scarletborder/bloggerv2@static/" - - # 查找带有 hash 的 JS 文件 (例如: index-xxxxxxxx.js) - JS_FILE=$(find dist/assets -name "index-*.js" | head -n 1) - # 提取文件名,例如 index-xxxxxxxx.js - JS_FILENAME=$(basename "$JS_FILE") - # 构造完整的 JS CDN URL - JS_CDN_URL="${CDN_BASE}assets/${JS_FILENAME}" - - # 查找带有 hash 的 CSS 文件 (例如: index-xxxxxxxx.css) - CSS_FILE=$(find dist/assets -name "index-*.css" | head -n 1) - # 提取文件名,例如 index-xxxxxxxx.css - CSS_FILENAME=$(basename "$CSS_FILE") - # 构造完整的 CSS CDN URL - CSS_CDN_URL="${CDN_BASE}assets/${CSS_FILENAME}" - - # 生成报告内容 - REPORT_CONTENT="\n" - REPORT_CONTENT+="" - - # 将报告内容写入文件 - echo -e "$REPORT_CONTENT" > build_report.txt - - # 将报告内容作为工作流输出 (可选,方便其他步骤或工作流使用) [5, 7, 8, 10] - echo "report_content=$(echo -e "$REPORT_CONTENT" | sed 's/"/\\"/g' | sed ':a;N;s/\n/\\n/g;ba')" >> $GITHUB_OUTPUT - echo "js_cdn_url=${JS_CDN_URL}" >> $GITHUB_OUTPUT - echo "css_cdn_url=${CSS_CDN_URL}" >> $GITHUB_OUTPUT + CDN_BASE="${{ env.CDN_BASEURL }}" + REPORT_FILE="build_report.txt" + + # 清空报告文件,以便重新写入 + > "$REPORT_FILE" + + echo "--- Generating CSS tags ---" + # 查找所有 .css 文件,排序以保证顺序一致,然后生成 标签 + for CSS_FILE in $(find dist/assets -name "*.css" | sort); do + CSS_FILENAME=$(basename "$CSS_FILE") + CSS_CDN_URL="${CDN_BASE}assets/${CSS_FILENAME}" + echo "Found CSS: ${CSS_FILENAME}" + echo "" >> "$REPORT_FILE" + done + + echo "--- Generating JS " >> "$REPORT_FILE" + done + + echo "--- Build Report Generated ---" + cat "$REPORT_FILE" + + # 将完整的、多行的报告内容设置为 GitHub Actions 的输出 + # 使用 <> $GITHUB_OUTPUT + cat "$REPORT_FILE" >> $GITHUB_OUTPUT + echo "EOF" >> $GITHUB_OUTPUT - name: Upload Build Report as Artifact uses: actions/upload-artifact@v4 # 使用 v4 版本上传 Artifact [1, 4, 6, 11] @@ -100,6 +120,6 @@ jobs: publish_dir: ./dist publish_branch: static force_orphan: true - user_name: 'github-actions[bot]' - user_email: 'github-actions[bot]@users.noreply.github.com' - commit_message: 'Deploy static assets from release branch' \ No newline at end of file + user_name: "github-actions[bot]" + user_email: "github-actions[bot]@users.noreply.github.com" + commit_message: "Deploy static assets from release branch" diff --git a/.github/workflows/manual-deploy.yml b/.github/workflows/manual-deploy.yml index 8e4608e..c7a50da 100644 --- a/.github/workflows/manual-deploy.yml +++ b/.github/workflows/manual-deploy.yml @@ -9,8 +9,8 @@ on: default: 'true' type: choice options: - - 'true' - - 'false' + - 'true' + - 'false' permissions: contents: write diff --git a/.github/workflows/purge-jsdelivr-cache.yml b/.github/workflows/purge-jsdelivr-cache.yml index 19449ae..8e3210b 100644 --- a/.github/workflows/purge-jsdelivr-cache.yml +++ b/.github/workflows/purge-jsdelivr-cache.yml @@ -28,4 +28,4 @@ jobs: # 等待所有后台 curl 进程完成 wait - echo "All purge requests have been sent." \ No newline at end of file + echo "All purge requests have been sent." diff --git a/.husky/pre-commit b/.husky/pre-commit new file mode 100644 index 0000000..2312dc5 --- /dev/null +++ b/.husky/pre-commit @@ -0,0 +1 @@ +npx lint-staged diff --git a/eslint.config.js b/eslint.config.js index 4397596..ec943c2 100644 --- a/eslint.config.js +++ b/eslint.config.js @@ -1,24 +1,35 @@ -import js from '@eslint/js' -import globals from 'globals' -import reactHooks from 'eslint-plugin-react-hooks' -import reactRefresh from 'eslint-plugin-react-refresh' -import tseslint from 'typescript-eslint' -import { globalIgnores, defineConfig } from 'eslint/config' +import js from '@eslint/js'; +import globals from 'globals'; +import reactHooks from 'eslint-plugin-react-hooks'; +import reactRefresh from 'eslint-plugin-react-refresh'; +import tseslint from 'typescript-eslint'; +import { globalIgnores } from 'eslint/config'; +import tencentEslintConfig from 'eslint-config-tencent/flat'; + +const GlobalConstants = { + __API_ENDPOINT__: 'readonly', +}; export default tseslint.config([ - globalIgnores(['dist']), + globalIgnores(['dist', 'vite.config.ts']), + ...tencentEslintConfig({ + tsconfigRootDir: process.cwd(), // eslint-disable-line no-undef + project: './tsconfig.app.json', + }), { - files: ['**/*.{ts,tsx}'], + files: ['src/**/*.{ts,tsx}'], extends: [ js.configs.recommended, - tseslint.configs.recommended, reactHooks.configs.flat.recommended, reactRefresh.configs.vite, ], languageOptions: { ecmaVersion: 2020, - globals: globals.browser, + globals: { + ...globals.browser, + ...GlobalConstants, + }, }, }, reactHooks.configs.flat.recommended, -]) +]); diff --git a/index.html b/index.html index 0108668..fc8beef 100644 --- a/index.html +++ b/index.html @@ -3,14 +3,7 @@ - - - - - + 绯境之外~Outside of Scarlet diff --git a/package.json b/package.json index 0d830fa..178247b 100644 --- a/package.json +++ b/package.json @@ -4,6 +4,7 @@ "version": "0.0.0", "type": "module", "scripts": { + "prepare": "husky", "dev": "vite", "build": "tsc -b && vite build", "lint": "eslint .", @@ -32,6 +33,8 @@ "react-dom": "^19.2.0", "react-router-dom": "^7.9.5", "swiper": "^12.0.3", + "tdesign-icons-react": "^0.6.1", + "tdesign-react": "^1.15.8", "vite-plugin-remove-console": "^2.2.0", "zod": "^4.1.12" }, @@ -44,9 +47,12 @@ "@vitejs/plugin-react": "^5.1.0", "babel-plugin-react-compiler": "^1.0.0", "eslint": "^9.39.1", + "eslint-config-tencent": "^1.1.3", "eslint-plugin-react-hooks": "^7.0.1", "eslint-plugin-react-refresh": "^0.4.24", "globals": "^16.5.0", + "husky": "^9.1.7", + "prettier": "^3.6.2", "typescript": "~5.9.3", "typescript-eslint": "^8.46.4", "vite": "npm:rolldown-vite@7.2.2", @@ -58,5 +64,16 @@ "overrides": { "vite": "npm:rolldown-vite@7.2.2" } + }, + "lint-staged": { + "*.{json,md}": [ + "prettier --write" + ], + "*.{js,ts,tsx}": [ + "eslint --fix" + ] + }, + "prettier": { + "singleQuote": true } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index f1a0798..5a31a41 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -77,6 +77,12 @@ importers: swiper: specifier: ^12.0.3 version: 12.0.3 + tdesign-icons-react: + specifier: ^0.6.1 + version: 0.6.1(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + tdesign-react: + specifier: ^1.15.8 + version: 1.15.8(react-dom@19.2.0(react@19.2.0))(react@19.2.0) vite-plugin-remove-console: specifier: ^2.2.0 version: 2.2.0 @@ -101,13 +107,16 @@ importers: version: 5.3.3 '@vitejs/plugin-react': specifier: ^5.1.0 - version: 5.1.1(rolldown-vite@7.2.2(esbuild@0.25.12)) + version: 5.1.1(rolldown-vite@7.2.2(@types/node@24.10.1)(esbuild@0.25.12)) babel-plugin-react-compiler: specifier: ^1.0.0 version: 1.0.0 eslint: specifier: ^9.39.1 version: 9.39.1 + eslint-config-tencent: + specifier: ^1.1.3 + version: 1.1.3(@babel/core@7.28.5)(@typescript-eslint/parser@8.46.4(eslint@9.39.1)(typescript@5.9.3))(eslint@9.39.1)(prettier@3.6.2)(typescript@5.9.3) eslint-plugin-react-hooks: specifier: ^7.0.1 version: 7.0.1(eslint@9.39.1) @@ -117,6 +126,12 @@ importers: globals: specifier: ^16.5.0 version: 16.5.0 + husky: + specifier: ^9.1.7 + version: 9.1.7 + prettier: + specifier: ^3.6.2 + version: 3.6.2 typescript: specifier: ~5.9.3 version: 5.9.3 @@ -125,16 +140,16 @@ importers: version: 8.46.4(eslint@9.39.1)(typescript@5.9.3) vite: specifier: npm:rolldown-vite@7.2.2 - version: rolldown-vite@7.2.2(esbuild@0.25.12) + version: rolldown-vite@7.2.2(@types/node@24.10.1)(esbuild@0.25.12) vite-plugin-babel: specifier: ^1.3.2 - version: 1.3.2(@babel/core@7.28.5)(rolldown-vite@7.2.2(esbuild@0.25.12)) + version: 1.3.2(@babel/core@7.28.5)(rolldown-vite@7.2.2(@types/node@24.10.1)(esbuild@0.25.12)) vite-plugin-compression: specifier: ^0.5.1 - version: 0.5.1(rolldown-vite@7.2.2(esbuild@0.25.12)) + version: 0.5.1(rolldown-vite@7.2.2(@types/node@24.10.1)(esbuild@0.25.12)) vitest: specifier: ^4.0.8 - version: 4.0.8(esbuild@0.25.12) + version: 4.0.8(@types/node@24.10.1)(esbuild@0.25.12) packages: @@ -156,6 +171,13 @@ packages: resolution: {integrity: sha512-e7jT4DxYvIDLk1ZHmU/m/mB19rex9sv0c2ftBtjSBv+kVM/902eh0fINUzD7UwLLNR+jU585GxUJ8/EBfAM5fw==} engines: {node: '>=6.9.0'} + '@babel/eslint-parser@7.28.5': + resolution: {integrity: sha512-fcdRcWahONYo+JRnJg1/AekOacGvKx12Gu0qXJXFi2WBqQA1i7+O5PaxRB7kxE/Op94dExnCiiar6T09pvdHpA==} + engines: {node: ^10.13.0 || ^12.13.0 || >=14.0.0} + peerDependencies: + '@babel/core': ^7.11.0 + eslint: ^7.5.0 || ^8.0.0 || ^9.0.0 + '@babel/generator@7.28.5': resolution: {integrity: sha512-3EwLFhZ38J4VyIP6WNtt2kUdW9dokXA9Cr4IVIFHuCpZ3H8/YFOl5JjZHisrn1fATPBmKKqXzDFvh9fUwHz6CQ==} engines: {node: '>=6.9.0'} @@ -215,6 +237,10 @@ packages: peerDependencies: '@babel/core': ^7.0.0-0 + '@babel/runtime@7.26.10': + resolution: {integrity: sha512-2WJMeRQPHKSPemqk/awGrAiuFfzBmOIPXKizAsVhWH9YJqLZ0H+HS4c8loHGgW6utJ3E/ejXQUsiGaQy2NZ9Fw==} + engines: {node: '>=6.9.0'} + '@babel/runtime@7.28.4': resolution: {integrity: sha512-Q/N6JNWvIvPnLDvjlE1OUBLPQHH6l3CltCEsHIujp45zQUSSh8K+gHnaEX45yAT1nyngnINhvWtzN+Nb9D8RAQ==} engines: {node: '>=6.9.0'} @@ -449,6 +475,10 @@ packages: resolution: {integrity: sha512-gtF186CXhIl1p4pJNGZw8Yc6RlshoePRvE0X91oPGb3vZ8pM3qOS9W9NGPat9LziaBV7XrJWGylNQXkGcnM3IQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@eslint/js@8.57.1': + resolution: {integrity: sha512-d9zaMRSTIKDLhctzH12MtXvJKSSUhaHcjV+2Z+GK+EEY7XKpP5yR4x+N3TAcHTcu963nIr+TMcCb4DBCYX1z6Q==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + '@eslint/js@9.39.1': resolution: {integrity: sha512-S26Stp4zCy88tH94QbBv3XCuzRQiZ9yXofEILmglYTh/Ug/a9/umqvgFtYBAo3Lp0nsI/5/qH1CCrbdK3AP1Tw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -535,6 +565,9 @@ packages: '@napi-rs/wasm-runtime@1.0.7': resolution: {integrity: sha512-SeDnOO0Tk7Okiq6DbXmmBODgOAb9dp9gjlphokTUxmt8U3liIP1ZsozBahH69j/RJv+Rfs6IwUKHTgQYJ/HBAw==} + '@nicolo-ribaudo/eslint-scope-5-internals@5.1.1-v1': + resolution: {integrity: sha512-54/JRvkLIzzDWshCWfuhadfrfZVPiElY8Fcgmg1HroEly/EDSszzhBAsarCux+D/kOslTRquNzuyGSmUSTTHGg==} + '@nodelib/fs.scandir@2.1.5': resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} engines: {node: '>= 8'} @@ -554,6 +587,9 @@ packages: '@oxc-project/types@0.96.0': resolution: {integrity: sha512-r/xkmoXA0xEpU6UGtn18CNVjXH6erU3KCpCDbpLmbVxBFor1U9MqN5Z2uMmCHJuXjJzlnDR+hWY+yPoLo8oHDw==} + '@popperjs/core@2.11.8': + resolution: {integrity: sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==} + '@react-spring/animated@10.0.3': resolution: {integrity: sha512-7MrxADV3vaUADn2V9iYhaIL6iOWRx9nCJjYrsk2AHD2kwPr6fg7Pt0v+deX5RnCDmCKNnD6W5fasiyM8D+wzJQ==} peerDependencies: @@ -667,6 +703,9 @@ packages: '@rolldown/pluginutils@1.0.0-beta.47': resolution: {integrity: sha512-8QagwMH3kNCuzD8EWL8R2YPW5e4OrHNSAHRFDdmFqEwEaD/KcNKjVoumo+gP2vW5eKB2UPbM6vTYiGZX0ixLnw==} + '@rtsao/scc@1.1.0': + resolution: {integrity: sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g==} + '@standard-schema/spec@1.0.0': resolution: {integrity: sha512-m2bOd0f2RT9k8QJx1JN85cZYyH1RqFBdlwtkSlf4tBDYLCiiZnv1fIIwacK6cqwXavOydf0NPToMQgpKq+dVlA==} @@ -703,9 +742,15 @@ packages: '@types/json-schema@7.0.15': resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==} + '@types/json5@0.0.29': + resolution: {integrity: sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==} + '@types/lodash@4.17.20': resolution: {integrity: sha512-H3MHACvFUEiujabxhaI/ImO6gUrd8oOurg7LQtS7mbwIXA/cUqWrvBsaeJ23aZEPk1TAYkurjfMbSELfoCXlGA==} + '@types/node@24.10.1': + resolution: {integrity: sha512-GNWcUTRBgIRJD5zj+Tq0fKOJ5XZajIiBroOF0yvj2bSU1WvNdYS/dn9UxwsujGW4JX06dnHyjV2y9rRaybH0iQ==} + '@types/react-dom@19.2.3': resolution: {integrity: sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==} peerDependencies: @@ -720,9 +765,26 @@ packages: '@types/react@19.2.4': resolution: {integrity: sha512-tBFxBp9Nfyy5rsmefN+WXc1JeW/j2BpBHFdLZbEVfs9wn3E3NRFxwV0pJg8M1qQAexFpvz73hJXFofV0ZAu92A==} + '@types/sortablejs@1.15.9': + resolution: {integrity: sha512-7HP+rZGE2p886PKV9c9OJzLBI6BBJu1O7lJGYnPyG3fS4/duUCcngkNCjsLwIMV+WMqANe3tt4irrXHSIe68OQ==} + '@types/trusted-types@2.0.7': resolution: {integrity: sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==} + '@types/validator@13.15.8': + resolution: {integrity: sha512-/NAHBJ0RwpsbLzzbLoLm/GnvCGB+A0/p5S61RUIsh7j3MP2dMkdUbWNdFqnluLlUheAs1CR2GlX2R7uzb7Tc0w==} + + '@typescript-eslint/eslint-plugin@7.18.0': + resolution: {integrity: sha512-94EQTWZ40mzBc42ATNIBimBEDltSJ9RQHCC8vc/PDbxi4k8dVwUAv4o98dk50M1zB+JGFxp43FP7f8+FP8R6Sw==} + engines: {node: ^18.18.0 || >=20.0.0} + peerDependencies: + '@typescript-eslint/parser': ^7.0.0 + eslint: ^8.56.0 + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + '@typescript-eslint/eslint-plugin@8.46.4': resolution: {integrity: sha512-R48VhmTJqplNyDxCyqqVkFSZIx1qX6PzwqgcXn1olLrzxcSBDlOsbtcnQuQhNtnNiJ4Xe5gREI1foajYaYU2Vg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -731,6 +793,16 @@ packages: eslint: ^8.57.0 || ^9.0.0 typescript: '>=4.8.4 <6.0.0' + '@typescript-eslint/parser@7.18.0': + resolution: {integrity: sha512-4Z+L8I2OqhZV8qA132M4wNL30ypZGYOQVBfMgxDH/K5UX0PNqTu1c6za9ST5r9+tavvHiTWmBnKzpCJ/GlVFtg==} + engines: {node: ^18.18.0 || >=20.0.0} + peerDependencies: + eslint: ^8.56.0 + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + '@typescript-eslint/parser@8.46.4': resolution: {integrity: sha512-tK3GPFWbirvNgsNKto+UmB/cRtn6TZfyw0D6IKrW55n6Vbs7KJoZtI//kpTKzE/DUmmnAFD8/Ca46s7Obs92/w==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -744,6 +816,10 @@ packages: peerDependencies: typescript: '>=4.8.4 <6.0.0' + '@typescript-eslint/scope-manager@7.18.0': + resolution: {integrity: sha512-jjhdIE/FPF2B7Z1uzc6i3oWKbGcHb87Qw7AWj6jmEqNOfDFbJWtjt/XfwCpvNkpGWlcJaog5vTR+VV8+w9JflA==} + engines: {node: ^18.18.0 || >=20.0.0} + '@typescript-eslint/scope-manager@8.46.4': resolution: {integrity: sha512-tMDbLGXb1wC+McN1M6QeDx7P7c0UWO5z9CXqp7J8E+xGcJuUuevWKxuG8j41FoweS3+L41SkyKKkia16jpX7CA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -754,6 +830,16 @@ packages: peerDependencies: typescript: '>=4.8.4 <6.0.0' + '@typescript-eslint/type-utils@7.18.0': + resolution: {integrity: sha512-XL0FJXuCLaDuX2sYqZUUSOJ2sG5/i1AAze+axqmLnSkNEVMVYLF+cbwlB2w8D1tinFuSikHmFta+P+HOofrLeA==} + engines: {node: ^18.18.0 || >=20.0.0} + peerDependencies: + eslint: ^8.56.0 + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + '@typescript-eslint/type-utils@8.46.4': resolution: {integrity: sha512-V4QC8h3fdT5Wro6vANk6eojqfbv5bpwHuMsBcJUJkqs2z5XnYhJzyz9Y02eUmF9u3PgXEUiOt4w4KHR3P+z0PQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -761,16 +847,35 @@ packages: eslint: ^8.57.0 || ^9.0.0 typescript: '>=4.8.4 <6.0.0' + '@typescript-eslint/types@7.18.0': + resolution: {integrity: sha512-iZqi+Ds1y4EDYUtlOOC+aUmxnE9xS/yCigkjA7XpTKV6nCBd3Hp/PRGGmdwnfkV2ThMyYldP1wRpm/id99spTQ==} + engines: {node: ^18.18.0 || >=20.0.0} + '@typescript-eslint/types@8.46.4': resolution: {integrity: sha512-USjyxm3gQEePdUwJBFjjGNG18xY9A2grDVGuk7/9AkjIF1L+ZrVnwR5VAU5JXtUnBL/Nwt3H31KlRDaksnM7/w==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@typescript-eslint/typescript-estree@7.18.0': + resolution: {integrity: sha512-aP1v/BSPnnyhMHts8cf1qQ6Q1IFwwRvAQGRvBFkWlo3/lH29OXA3Pts+c10nxRxIBrDnoMqzhgdwVe5f2D6OzA==} + engines: {node: ^18.18.0 || >=20.0.0} + peerDependencies: + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + '@typescript-eslint/typescript-estree@8.46.4': resolution: {integrity: sha512-7oV2qEOr1d4NWNmpXLR35LvCfOkTNymY9oyW+lUHkmCno7aOmIf/hMaydnJBUTBMRCOGZh8YjkFOc8dadEoNGA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: typescript: '>=4.8.4 <6.0.0' + '@typescript-eslint/utils@7.18.0': + resolution: {integrity: sha512-kK0/rNa2j74XuHVcoCZxdFBMF+aq/vH83CXAOHieC+2Gis4mF8jJXT5eAfyD3K0sAxtPuwxaIOIOvhwzVDt/kw==} + engines: {node: ^18.18.0 || >=20.0.0} + peerDependencies: + eslint: ^8.56.0 + '@typescript-eslint/utils@8.46.4': resolution: {integrity: sha512-AbSv11fklGXV6T28dp2Me04Uw90R2iJ30g2bgLz529Koehrmkbs1r7paFqr1vPCZi7hHwYxYtxfyQMRC8QaVSg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -778,6 +883,10 @@ packages: eslint: ^8.57.0 || ^9.0.0 typescript: '>=4.8.4 <6.0.0' + '@typescript-eslint/visitor-keys@7.18.0': + resolution: {integrity: sha512-cDF0/Gf81QpY3xYyJKDV14Zwdmid5+uuENhjH2EqFaF0ni+yAyq/LzMaIJdhNJXZI7uLzwIlA+V7oWoyn6Curg==} + engines: {node: ^18.18.0 || >=20.0.0} + '@typescript-eslint/visitor-keys@8.46.4': resolution: {integrity: sha512-/++5CYLQqsO9HFGLI7APrxBJYo+5OCMpViuhV8q5/Qa3o5mMrF//eQHks+PXcsAVaLdn817fMuS7zqoXNNZGaw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -890,10 +999,54 @@ packages: argparse@2.0.1: resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} + array-buffer-byte-length@1.0.2: + resolution: {integrity: sha512-LHE+8BuR7RYGDKvnrmcuSq3tDcKv9OFEXQt/HpbZhY7V6h0zlUXutnAD82GiFx9rdieCMjkvtcsPqBwgUl1Iiw==} + engines: {node: '>= 0.4'} + + array-includes@3.1.9: + resolution: {integrity: sha512-FmeCCAenzH0KH381SPT5FZmiA/TmpndpcaShhfgEN9eCVjnFBqq3l1xrI42y8+PPLI6hypzou4GXw00WHmPBLQ==} + engines: {node: '>= 0.4'} + + array-union@2.1.0: + resolution: {integrity: sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==} + engines: {node: '>=8'} + + array.prototype.findlast@1.2.5: + resolution: {integrity: sha512-CVvd6FHg1Z3POpBLxO6E6zr+rSKEQ9L6rZHAaY7lLfhKsWYUBBOuMs0e9o24oopj6H+geRCX0YJ+TJLBK2eHyQ==} + engines: {node: '>= 0.4'} + + array.prototype.findlastindex@1.2.6: + resolution: {integrity: sha512-F/TKATkzseUExPlfvmwQKGITM3DGTK+vkAsCZoDc5daVygbJBnjEUCbgkAvVFsgfXfX4YIqZ/27G3k3tdXrTxQ==} + engines: {node: '>= 0.4'} + + array.prototype.flat@1.3.3: + resolution: {integrity: sha512-rwG/ja1neyLqCuGZ5YYrznA62D4mZXg0i1cIskIUKSiqF3Cje9/wXAls9B9s1Wa2fomMsIv8czB8jZcPmxCXFg==} + engines: {node: '>= 0.4'} + + array.prototype.flatmap@1.3.3: + resolution: {integrity: sha512-Y7Wt51eKJSyi80hFrJCePGGNo5ktJCslFuboqJsbf57CCPcm5zztluPlc4/aD8sWsKvlwatezpV4U1efk8kpjg==} + engines: {node: '>= 0.4'} + + array.prototype.tosorted@1.1.4: + resolution: {integrity: sha512-p6Fx8B7b7ZhL/gmUsAy0D15WhvDccw3mnGNbZpi3pmeJdxtWsj2jEaI4Y6oo3XiHfzuSgPwKc04MYt6KgvC/wA==} + engines: {node: '>= 0.4'} + + arraybuffer.prototype.slice@1.0.4: + resolution: {integrity: sha512-BNoCY6SXXPQ7gF2opIP4GBE+Xw7U+pHMYKuzjgCN3GwiaIR09UUeKfheyIry77QtrCBlC0KK0q5/TER/tYh3PQ==} + engines: {node: '>= 0.4'} + assertion-error@2.0.1: resolution: {integrity: sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==} engines: {node: '>=12'} + async-function@1.0.0: + resolution: {integrity: sha512-hsU18Ae8CDTR6Kgu9DYf0EbCr/a5iGL0rytQDobUcdpYOKokk8LEjVphnXkDkgpi0wYVsqrXuP0bZxJaTqdgoA==} + engines: {node: '>= 0.4'} + + available-typed-arrays@1.0.7: + resolution: {integrity: sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==} + engines: {node: '>= 0.4'} + babel-plugin-react-compiler@1.0.0: resolution: {integrity: sha512-Ixm8tFfoKKIPYdCCKYTsqv+Fd4IJ0DQqMyEimo+pxUOMUR9cVPlwTrFt9Avu+3cb6Zp3mAzl+t1MrG2fxxKsxw==} @@ -904,6 +1057,9 @@ packages: resolution: {integrity: sha512-gYjt7OIqdM0PcttNYP2aVrr2G0bMALkBaoehD4BuRGjAOtipg0b6wHg1yNL+s5zSnLZZrGHOw4IrND8CD+3oIQ==} hasBin: true + boolbase@1.0.0: + resolution: {integrity: sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==} + brace-expansion@1.1.12: resolution: {integrity: sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==} @@ -919,6 +1075,18 @@ packages: engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} hasBin: true + call-bind-apply-helpers@1.0.2: + resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==} + engines: {node: '>= 0.4'} + + call-bind@1.0.8: + resolution: {integrity: sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww==} + engines: {node: '>= 0.4'} + + call-bound@1.0.4: + resolution: {integrity: sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==} + engines: {node: '>= 0.4'} + callsites@3.1.0: resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} engines: {node: '>=6'} @@ -934,6 +1102,9 @@ packages: resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} engines: {node: '>=10'} + classnames@2.5.1: + resolution: {integrity: sha512-saHYOzhIQs6wy2sVxTM6bUDsQO4F50V9RQ22qBpEdCW+I+/Wmke2HOl6lS6dTpdxVhb88/I6+Hs+438c3lfUow==} + codemirror@6.0.2: resolution: {integrity: sha512-VhydHotNW5w1UGK0Qj96BwSk/Zqbp9WbnyK2W/eVMv4QyF41INRGpjUhFJY7/uDNuudSc33a/PKr4iDqRduvHw==} @@ -965,12 +1136,40 @@ packages: resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} engines: {node: '>= 8'} + cssesc@3.0.0: + resolution: {integrity: sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==} + engines: {node: '>=4'} + hasBin: true + csstype@3.1.3: resolution: {integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==} + data-view-buffer@1.0.2: + resolution: {integrity: sha512-EmKO5V3OLXh1rtK2wgXRansaK1/mtVdTUEiEI0W8RkvgT05kfxaH29PliLnpLP73yYO6142Q72QNa8Wx/A5CqQ==} + engines: {node: '>= 0.4'} + + data-view-byte-length@1.0.2: + resolution: {integrity: sha512-tuhGbE6CfTM9+5ANGf+oQb72Ky/0+s3xKUpHvShfiz2RxMFgFPjsXuRLBVMtvMs15awe45SRb83D6wH4ew6wlQ==} + engines: {node: '>= 0.4'} + + data-view-byte-offset@1.0.1: + resolution: {integrity: sha512-BS8PfmtDGnrgYdOonGZQdLZslWIeCGFP9tpan0hi1Co2Zr2NKADsvGYA8XxuG/4UWgJ6Cjtv+YJnB6MM69QGlQ==} + engines: {node: '>= 0.4'} + + dayjs@1.11.10: + resolution: {integrity: sha512-vjAczensTgRcqDERK0SR2XMwsF/tSvnvlv6VcF2GIhg6Sx4yOIt/irsr1RDJsKiIyBzJDpCoXiWWq28MqH2cnQ==} + dayjs@1.11.19: resolution: {integrity: sha512-t5EcLVS6QPBNqM2z8fakk/NKel+Xzshgt8FFKAn+qwlD1pzZWxh0nVCrvFK7ZDb6XucZeF9z8C7CBWTRIVApAw==} + debug@3.2.7: + resolution: {integrity: sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + debug@4.4.3: resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==} engines: {node: '>=6.0'} @@ -987,6 +1186,14 @@ packages: deep-is@0.1.4: resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} + define-data-property@1.1.4: + resolution: {integrity: sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==} + engines: {node: '>= 0.4'} + + define-properties@1.2.1: + resolution: {integrity: sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==} + engines: {node: '>= 0.4'} + detect-libc@2.1.2: resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==} engines: {node: '>=8'} @@ -994,15 +1201,62 @@ packages: dexie@4.2.1: resolution: {integrity: sha512-Ckej0NS6jxQ4Po3OrSQBFddayRhTCic2DoCAG5zacOfOVB9P2Q5Xc5uL/nVa7ZVs+HdMnvUPzLFCB/JwpB6Csg==} + dir-glob@3.0.1: + resolution: {integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==} + engines: {node: '>=8'} + + doctrine@2.1.0: + resolution: {integrity: sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==} + engines: {node: '>=0.10.0'} + + dom-helpers@5.2.1: + resolution: {integrity: sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==} + dompurify@3.3.0: resolution: {integrity: sha512-r+f6MYR1gGN1eJv0TVQbhA7if/U7P87cdPl3HN5rikqaBSBxLiCb/b9O+2eG0cxz0ghyU+mU1QkbsOwERMYlWQ==} + dunder-proto@1.0.1: + resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==} + engines: {node: '>= 0.4'} + electron-to-chromium@1.5.250: resolution: {integrity: sha512-/5UMj9IiGDMOFBnN4i7/Ry5onJrAGSbOGo3s9FEKmwobGq6xw832ccET0CE3CkkMBZ8GJSlUIesZofpyurqDXw==} + es-abstract@1.24.0: + resolution: {integrity: sha512-WSzPgsdLtTcQwm4CROfS5ju2Wa1QQcVeT37jFjYzdFz1r9ahadC8B8/a4qxJxM+09F18iumCdRmlr96ZYkQvEg==} + engines: {node: '>= 0.4'} + + es-define-property@1.0.1: + resolution: {integrity: sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==} + engines: {node: '>= 0.4'} + + es-errors@1.3.0: + resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==} + engines: {node: '>= 0.4'} + + es-iterator-helpers@1.2.1: + resolution: {integrity: sha512-uDn+FE1yrDzyC0pCo961B2IHbdM8y/ACZsKD4dG6WqrjV53BADjwa7D+1aom2rsNVfLyDgU/eigvlJGJ08OQ4w==} + engines: {node: '>= 0.4'} + es-module-lexer@1.7.0: resolution: {integrity: sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==} + es-object-atoms@1.1.1: + resolution: {integrity: sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==} + engines: {node: '>= 0.4'} + + es-set-tostringtag@2.1.0: + resolution: {integrity: sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==} + engines: {node: '>= 0.4'} + + es-shim-unscopables@1.1.0: + resolution: {integrity: sha512-d9T8ucsEhh8Bi1woXCf+TIKDIROLG5WCkxg8geBCbvk22kzwC5G2OnXVMO6FUsvQlgUUXQ2itephWDLqDzbeCw==} + engines: {node: '>= 0.4'} + + es-to-primitive@1.3.0: + resolution: {integrity: sha512-w+5mJ3GuFL+NjVtJlvydShqE1eN3h3PbI7/5LAsYJP/2qtuMXjfL2LpHSRqo4b4eSF5K/DH1JXKUAHSB2UW50g==} + engines: {node: '>= 0.4'} + esbuild@0.25.12: resolution: {integrity: sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg==} engines: {node: '>=18'} @@ -1016,6 +1270,63 @@ packages: resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} engines: {node: '>=10'} + eslint-config-tencent@1.1.3: + resolution: {integrity: sha512-8RAev4+j2kJ3YzXbrQ032fYV4q49AW7b1FeeZ2NXBcL8xt6asA1n5NPuPCAM8PKFHYLb2SBSv8x0blDkm6UU4g==} + peerDependencies: + '@babel/core': ^7.14.6 + eslint: '>= 7.28.0 < 10.0.0' + + eslint-import-resolver-node@0.3.9: + resolution: {integrity: sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g==} + + eslint-module-utils@2.12.1: + resolution: {integrity: sha512-L8jSWTze7K2mTg0vos/RuLRS5soomksDPoJLXIslC7c8Wmut3bx7CPpJijDcBZtxQ5lrbUdM+s0OlNbz0DCDNw==} + engines: {node: '>=4'} + peerDependencies: + '@typescript-eslint/parser': '*' + eslint: '*' + eslint-import-resolver-node: '*' + eslint-import-resolver-typescript: '*' + eslint-import-resolver-webpack: '*' + peerDependenciesMeta: + '@typescript-eslint/parser': + optional: true + eslint: + optional: true + eslint-import-resolver-node: + optional: true + eslint-import-resolver-typescript: + optional: true + eslint-import-resolver-webpack: + optional: true + + eslint-plugin-chalk@1.0.0: + resolution: {integrity: sha512-FTi6Wi5dSrkXEVHHojRwyRZZnNFXGnTytuWlrJ3P9HkmMZWTZC3vUaDpyb6jNkumdlrqK0FN8eI3XJG70FwBNA==} + engines: {node: '>=12'} + peerDependencies: + eslint: '>=1.0.0' + + eslint-plugin-import@2.32.0: + resolution: {integrity: sha512-whOE1HFo/qJDyX4SnXzP4N6zOWn79WhnCUY/iDR0mPfQZO8wcYE4JClzI2oZrhBnnMUCBCHZhO6VQyoBU95mZA==} + engines: {node: '>=4'} + peerDependencies: + '@typescript-eslint/parser': '*' + eslint: ^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8 || ^9 + peerDependenciesMeta: + '@typescript-eslint/parser': + optional: true + + eslint-plugin-prettier@3.4.1: + resolution: {integrity: sha512-htg25EUYUeIhKHXjOinK4BgCcDwtLHjqaxCDsMy5nbnUMkKFvIhMVCp+5GFUXQ4Nr8lBsPqtGAqBenbpFqAA2g==} + engines: {node: '>=6.0.0'} + peerDependencies: + eslint: '>=5.0.0' + eslint-config-prettier: '*' + prettier: '>=1.13.0' + peerDependenciesMeta: + eslint-config-prettier: + optional: true + eslint-plugin-react-hooks@7.0.1: resolution: {integrity: sha512-O0d0m04evaNzEPoSW+59Mezf8Qt0InfgGIBJnpC0h3NH/WjUAR7BIKUfysC6todmtiZ/A0oUVS8Gce0WhBrHsA==} engines: {node: '>=18'} @@ -1027,10 +1338,34 @@ packages: peerDependencies: eslint: '>=8.40' + eslint-plugin-react@7.37.5: + resolution: {integrity: sha512-Qteup0SqU15kdocexFNAJMvCJEfa2xUKNV4CC1xsVMrIIqEy3SQ/rqyxCWNzfrd3/ldy6HMlD2e0JDVpDg2qIA==} + engines: {node: '>=4'} + peerDependencies: + eslint: ^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9.7 + + eslint-plugin-vue@9.33.0: + resolution: {integrity: sha512-174lJKuNsuDIlLpjeXc5E2Tss8P44uIimAfGD0b90k0NoirJqpG7stLuU9Vp/9ioTOrQdWVREc4mRd1BD+CvGw==} + engines: {node: ^14.17.0 || >=16.0.0} + peerDependencies: + eslint: ^6.2.0 || ^7.0.0 || ^8.0.0 || ^9.0.0 + + eslint-scope@5.1.1: + resolution: {integrity: sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==} + engines: {node: '>=8.0.0'} + + eslint-scope@7.2.2: + resolution: {integrity: sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + eslint-scope@8.4.0: resolution: {integrity: sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + eslint-visitor-keys@2.1.0: + resolution: {integrity: sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==} + engines: {node: '>=10'} + eslint-visitor-keys@3.4.3: resolution: {integrity: sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} @@ -1053,6 +1388,10 @@ packages: resolution: {integrity: sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + espree@9.6.1: + resolution: {integrity: sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + esquery@1.6.0: resolution: {integrity: sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==} engines: {node: '>=0.10'} @@ -1061,6 +1400,10 @@ packages: resolution: {integrity: sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==} engines: {node: '>=4.0'} + estraverse@4.3.0: + resolution: {integrity: sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==} + engines: {node: '>=4.0'} + estraverse@5.3.0: resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==} engines: {node: '>=4.0'} @@ -1079,6 +1422,9 @@ packages: fast-deep-equal@3.1.3: resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} + fast-diff@1.3.0: + resolution: {integrity: sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==} + fast-glob@3.3.3: resolution: {integrity: sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==} engines: {node: '>=8.6.0'} @@ -1124,6 +1470,10 @@ packages: flatted@3.3.3: resolution: {integrity: sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==} + for-each@0.3.5: + resolution: {integrity: sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==} + engines: {node: '>= 0.4'} + fs-extra@10.1.0: resolution: {integrity: sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==} engines: {node: '>=12'} @@ -1133,10 +1483,36 @@ packages: engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} os: [darwin] + function-bind@1.1.2: + resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} + + function.prototype.name@1.1.8: + resolution: {integrity: sha512-e5iwyodOHhbMr/yNrc7fDYG4qlbIvI5gajyzPnb5TCwyhjApznQh1BMFou9b30SevY43gCJKXycoCBjMbsuW0Q==} + engines: {node: '>= 0.4'} + + functions-have-names@1.2.3: + resolution: {integrity: sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==} + + generator-function@2.0.1: + resolution: {integrity: sha512-SFdFmIJi+ybC0vjlHN0ZGVGHc3lgE0DxPAT0djjVg+kjOnSqclqmj0KQ7ykTOLP6YxoqOvuAODGdcHJn+43q3g==} + engines: {node: '>= 0.4'} + gensync@1.0.0-beta.2: resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==} engines: {node: '>=6.9.0'} + get-intrinsic@1.3.0: + resolution: {integrity: sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==} + engines: {node: '>= 0.4'} + + get-proto@1.0.1: + resolution: {integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==} + engines: {node: '>= 0.4'} + + get-symbol-description@1.1.0: + resolution: {integrity: sha512-w9UMqWwJxHNOvoNzSJ2oPF5wvYcvP7jUvYzhp67yEhTi17ZDBBC1z9pTdGuzjD+EFIqLSYRweZjqfiPzQ06Ebg==} + engines: {node: '>= 0.4'} + glob-parent@5.1.2: resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} engines: {node: '>= 6'} @@ -1145,6 +1521,10 @@ packages: resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==} engines: {node: '>=10.13.0'} + globals@13.24.0: + resolution: {integrity: sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==} + engines: {node: '>=8'} + globals@14.0.0: resolution: {integrity: sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==} engines: {node: '>=18'} @@ -1153,22 +1533,65 @@ packages: resolution: {integrity: sha512-c/c15i26VrJ4IRt5Z89DnIzCGDn9EcebibhAOjw5ibqEHsE1wLUgkPn9RDmNcUKyU87GeaL633nyJ+pplFR2ZQ==} engines: {node: '>=18'} + globalthis@1.0.4: + resolution: {integrity: sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==} + engines: {node: '>= 0.4'} + + globby@11.1.0: + resolution: {integrity: sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==} + engines: {node: '>=10'} + + gopd@1.2.0: + resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==} + engines: {node: '>= 0.4'} + graceful-fs@4.2.11: resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} graphemer@1.4.0: resolution: {integrity: sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==} + has-bigints@1.1.0: + resolution: {integrity: sha512-R3pbpkcIqv2Pm3dUwgjclDRVmWpTJW2DcMzcIhEXEx1oh/CEMObMm3KLmRJOdvhM7o4uQBnwr8pzRK2sJWIqfg==} + engines: {node: '>= 0.4'} + has-flag@4.0.0: resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} engines: {node: '>=8'} + has-property-descriptors@1.0.2: + resolution: {integrity: sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==} + + has-proto@1.2.0: + resolution: {integrity: sha512-KIL7eQPfHQRC8+XluaIw7BHUwwqL19bQn4hzNgdr+1wXoU0KKj6rufu47lhY7KbJR2C6T6+PfyN0Ea7wkSS+qQ==} + engines: {node: '>= 0.4'} + + has-symbols@1.1.0: + resolution: {integrity: sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==} + engines: {node: '>= 0.4'} + + has-tostringtag@1.0.2: + resolution: {integrity: sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==} + engines: {node: '>= 0.4'} + + hasown@2.0.2: + resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} + engines: {node: '>= 0.4'} + hermes-estree@0.25.1: resolution: {integrity: sha512-0wUoCcLp+5Ev5pDW2OriHC2MJCbwLwuRx+gAqMTOkGKJJiBCLjtrvy4PWUGn6MIVefecRpzoOZ/UV6iGdOr+Cw==} hermes-parser@0.25.1: resolution: {integrity: sha512-6pEjquH3rqaI6cYAXYPcz9MS4rY6R4ngRgrgfDshRptUZIc3lw0MCIJIGDj9++mfySOuPTHB4nrSW99BCvOPIA==} + hoist-non-react-statics@3.3.2: + resolution: {integrity: sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==} + + husky@9.1.7: + resolution: {integrity: sha512-5gs5ytaNjBrh5Ow3zrvdUUY+0VxIuWVL4i9irt6friV+BqdCfmV11CQTWMiBYWHbXhco+J1kHfTOUkePhCDvMA==} + engines: {node: '>=18'} + hasBin: true + ignore@5.3.2: resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==} engines: {node: '>= 4'} @@ -1185,25 +1608,124 @@ packages: resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} engines: {node: '>=0.8.19'} + internal-slot@1.1.0: + resolution: {integrity: sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw==} + engines: {node: '>= 0.4'} + intersection-observer@0.12.2: resolution: {integrity: sha512-7m1vEcPCxXYI8HqnL8CKI6siDyD+eIWSwgB3DZA+ZTogxk9I4CDnj4wilt9x/+/QbHI4YG5YZNmC6458/e9Ktg==} deprecated: The Intersection Observer polyfill is no longer needed and can safely be removed. Intersection Observer has been Baseline since 2019. + is-array-buffer@3.0.5: + resolution: {integrity: sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A==} + engines: {node: '>= 0.4'} + + is-async-function@2.1.1: + resolution: {integrity: sha512-9dgM/cZBnNvjzaMYHVoxxfPj2QXt22Ev7SuuPrs+xav0ukGB0S6d4ydZdEiM48kLx5kDV+QBPrpVnFyefL8kkQ==} + engines: {node: '>= 0.4'} + + is-bigint@1.1.0: + resolution: {integrity: sha512-n4ZT37wG78iz03xPRKJrHTdZbe3IicyucEtdRsV5yglwc3GyUfbAfpSeD0FJ41NbUNSt5wbhqfp1fS+BgnvDFQ==} + engines: {node: '>= 0.4'} + + is-boolean-object@1.2.2: + resolution: {integrity: sha512-wa56o2/ElJMYqjCjGkXri7it5FbebW5usLw/nPmCMs5DeZ7eziSYZhSmPRn0txqeW4LnAmQQU7FgqLpsEFKM4A==} + engines: {node: '>= 0.4'} + + is-callable@1.2.7: + resolution: {integrity: sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==} + engines: {node: '>= 0.4'} + + is-core-module@2.16.1: + resolution: {integrity: sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==} + engines: {node: '>= 0.4'} + + is-data-view@1.0.2: + resolution: {integrity: sha512-RKtWF8pGmS87i2D6gqQu/l7EYRlVdfzemCJN/P3UOs//x1QE7mfhvzHIApBTRf7axvT6DMGwSwBXYCT0nfB9xw==} + engines: {node: '>= 0.4'} + + is-date-object@1.1.0: + resolution: {integrity: sha512-PwwhEakHVKTdRNVOw+/Gyh0+MzlCl4R6qKvkhuvLtPMggI1WAHt9sOwZxQLSGpUaDnrdyDsomoRgNnCfKNSXXg==} + engines: {node: '>= 0.4'} + is-extglob@2.1.1: resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} engines: {node: '>=0.10.0'} + is-finalizationregistry@1.1.1: + resolution: {integrity: sha512-1pC6N8qWJbWoPtEjgcL2xyhQOP491EQjeUo3qTKcmV8YSDDJrOepfG8pcC7h/QgnQHYSv0mJ3Z/ZWxmatVrysg==} + engines: {node: '>= 0.4'} + + is-generator-function@1.1.2: + resolution: {integrity: sha512-upqt1SkGkODW9tsGNG5mtXTXtECizwtS2kA161M+gJPc1xdb/Ax629af6YrTwcOeQHbewrPNlE5Dx7kzvXTizA==} + engines: {node: '>= 0.4'} + is-glob@4.0.3: resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} engines: {node: '>=0.10.0'} + is-map@2.0.3: + resolution: {integrity: sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==} + engines: {node: '>= 0.4'} + + is-negative-zero@2.0.3: + resolution: {integrity: sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==} + engines: {node: '>= 0.4'} + + is-number-object@1.1.1: + resolution: {integrity: sha512-lZhclumE1G6VYD8VHe35wFaIif+CTy5SJIi5+3y4psDgWu4wPDoBhF8NxUOinEc7pHgiTsT6MaBb92rKhhD+Xw==} + engines: {node: '>= 0.4'} + is-number@7.0.0: resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} engines: {node: '>=0.12.0'} + is-regex@1.2.1: + resolution: {integrity: sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==} + engines: {node: '>= 0.4'} + + is-set@2.0.3: + resolution: {integrity: sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==} + engines: {node: '>= 0.4'} + + is-shared-array-buffer@1.0.4: + resolution: {integrity: sha512-ISWac8drv4ZGfwKl5slpHG9OwPNty4jOWPRIhBpxOoD+hqITiwuipOQ2bNthAzwA3B4fIjO4Nln74N0S9byq8A==} + engines: {node: '>= 0.4'} + + is-string@1.1.1: + resolution: {integrity: sha512-BtEeSsoaQjlSPBemMQIrY1MY0uM6vnS1g5fmufYOtnxLGUZM2178PKbhsk7Ffv58IX+ZtcvoGwccYsh0PglkAA==} + engines: {node: '>= 0.4'} + + is-symbol@1.1.1: + resolution: {integrity: sha512-9gGx6GTtCQM73BgmHQXfDmLtfjjTUDSyoxTCbp5WtoixAhfgsDirWIcVQ/IHpvI5Vgd5i/J5F7B9cN/WlVbC/w==} + engines: {node: '>= 0.4'} + + is-typed-array@1.1.15: + resolution: {integrity: sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==} + engines: {node: '>= 0.4'} + + is-weakmap@2.0.2: + resolution: {integrity: sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==} + engines: {node: '>= 0.4'} + + is-weakref@1.1.1: + resolution: {integrity: sha512-6i9mGWSlqzNMEqpCp93KwRS1uUOodk2OJ6b+sq7ZPDSy2WuI5NFIxp/254TytR8ftefexkWn5xNiHUNpPOfSew==} + engines: {node: '>= 0.4'} + + is-weakset@2.0.4: + resolution: {integrity: sha512-mfcwb6IzQyOKTs84CQMrOwW4gQcaTOAWJ0zzJCl2WSPDrWk/OzDaImWFH3djXhb24g4eudZfLRozAvPGw4d9hQ==} + engines: {node: '>= 0.4'} + + isarray@2.0.5: + resolution: {integrity: sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==} + isexe@2.0.0: resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} + iterator.prototype@1.1.5: + resolution: {integrity: sha512-H0dkQoCa3b2VEeKQBOxFph+JAbcrQdE7KC0UkqwpLmv2EC4P41QXP+rqo9wYodACiG5/WM5s9oDApTU8utwj9g==} + engines: {node: '>= 0.4'} + js-cookie@3.0.5: resolution: {integrity: sha512-cEiJEAEoIbWfCZYKWhVwFuvPX1gETRYPw6LlaTKoxD3s2AkXzkCjnp6h0V77ozyqj0jakteJ4YqDJT830+lVGw==} engines: {node: '>=14'} @@ -1229,6 +1751,10 @@ packages: json-stable-stringify-without-jsonify@1.0.1: resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==} + json5@1.0.2: + resolution: {integrity: sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==} + hasBin: true + json5@2.2.3: resolution: {integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==} engines: {node: '>=6'} @@ -1237,6 +1763,10 @@ packages: jsonfile@6.2.0: resolution: {integrity: sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg==} + jsx-ast-utils@3.3.5: + resolution: {integrity: sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ==} + engines: {node: '>=4.0'} + katex@0.16.25: resolution: {integrity: sha512-woHRUZ/iF23GBP1dkDQMh1QBad9dmr8/PAwNA54VrSOVYgI12MAcE14TqnDdQOdzyEonGzMepYnqBMYdsoAr8Q==} hasBin: true @@ -1322,18 +1852,29 @@ packages: resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} engines: {node: '>=10'} + lodash-es@4.17.21: + resolution: {integrity: sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==} + lodash.merge@4.6.2: resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} lodash@4.17.21: resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==} + loose-envify@1.4.0: + resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==} + hasBin: true + lru-cache@5.1.1: resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} magic-string@0.30.21: resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==} + math-intrinsics@1.1.0: + resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==} + engines: {node: '>= 0.4'} + merge2@1.4.1: resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} engines: {node: '>= 8'} @@ -1349,6 +1890,12 @@ packages: resolution: {integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==} engines: {node: '>=16 || 14 >=14.17'} + minimist@1.2.8: + resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} + + mitt@3.0.1: + resolution: {integrity: sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw==} + ms@2.1.3: resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} @@ -1363,10 +1910,49 @@ packages: node-releases@2.0.27: resolution: {integrity: sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA==} + nth-check@2.1.1: + resolution: {integrity: sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==} + + object-assign@4.1.1: + resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} + engines: {node: '>=0.10.0'} + + object-inspect@1.13.4: + resolution: {integrity: sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==} + engines: {node: '>= 0.4'} + + object-keys@1.1.1: + resolution: {integrity: sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==} + engines: {node: '>= 0.4'} + + object.assign@4.1.7: + resolution: {integrity: sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw==} + engines: {node: '>= 0.4'} + + object.entries@1.1.9: + resolution: {integrity: sha512-8u/hfXFRBD1O0hPUjioLhoWFHRmt6tKA4/vZPyckBr18l1KE9uHrFaFaUi8MDRTpi4uak2goyPTSNJLXX2k2Hw==} + engines: {node: '>= 0.4'} + + object.fromentries@2.0.8: + resolution: {integrity: sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ==} + engines: {node: '>= 0.4'} + + object.groupby@1.0.3: + resolution: {integrity: sha512-+Lhy3TQTuzXI5hevh8sBGqbmurHbbIjAi0Z4S63nthVLmLxfbj4T54a4CfZrXIrt9iP4mVAPYMo/v99taj3wjQ==} + engines: {node: '>= 0.4'} + + object.values@1.2.1: + resolution: {integrity: sha512-gXah6aZrcUxjWg2zR2MwouP2eHlCBzdV4pygudehaKXSGW4v2AsRQUK+lwwXhii6KFZcunEnmSUoYp5CXibxtA==} + engines: {node: '>= 0.4'} + optionator@0.9.4: resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==} engines: {node: '>= 0.8.0'} + own-keys@1.0.1: + resolution: {integrity: sha512-qFOyK5PjiWZd+QQIh+1jhdb9LpxTF0qs7Pm8o5QHYZ0M3vKqSqzsZaEB6oWlxZ+q2sJBMI/Ktgd2N5ZwQoRHfg==} + engines: {node: '>= 0.4'} + p-limit@3.1.0: resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==} engines: {node: '>=10'} @@ -1387,9 +1973,19 @@ packages: resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} engines: {node: '>=8'} + path-parse@1.0.7: + resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} + + path-type@4.0.0: + resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==} + engines: {node: '>=8'} + pathe@2.0.3: resolution: {integrity: sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==} + performance-now@2.1.0: + resolution: {integrity: sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==} + picocolors@1.1.1: resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} @@ -1401,6 +1997,14 @@ packages: resolution: {integrity: sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==} engines: {node: '>=12'} + possible-typed-array-names@1.1.0: + resolution: {integrity: sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==} + engines: {node: '>= 0.4'} + + postcss-selector-parser@6.1.2: + resolution: {integrity: sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==} + engines: {node: '>=4'} + postcss@8.5.6: resolution: {integrity: sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==} engines: {node: ^10 || ^12 || >=14} @@ -1409,10 +2013,22 @@ packages: resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} engines: {node: '>= 0.8.0'} + prettier-linter-helpers@1.0.0: + resolution: {integrity: sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==} + engines: {node: '>=6.0.0'} + + prettier@3.6.2: + resolution: {integrity: sha512-I7AIg5boAr5R0FFtJ6rCfD+LFsWHp81dolrFD8S79U9tb8Az2nGrJncnMSnys+bpQJfRUzqs9hnA81OAA3hCuQ==} + engines: {node: '>=14'} + hasBin: true + prismjs@1.30.0: resolution: {integrity: sha512-DEvV2ZF2r2/63V+tK8hQvrR2ZGn10srHbXviTlcv7Kpzw8jWiNTqbVgjO3IY8RxrrOUF8VPMQQFysYYYv0YZxw==} engines: {node: '>=6'} + prop-types@15.8.1: + resolution: {integrity: sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==} + punycode@2.3.1: resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} engines: {node: '>=6'} @@ -1424,6 +2040,9 @@ packages: queue-microtask@1.2.3: resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} + raf@3.4.1: + resolution: {integrity: sha512-Sq4CW4QhwOHE8ucn6J34MqtZCeWFP2aQSmrlroYgqAV1PjStIhJXxYuTgUIfkEk7zTLjmIjLmU5q+fbD1NnOJA==} + react-device-detect@2.2.3: resolution: {integrity: sha512-buYY3qrCnQVlIFHrC5UcUoAj7iANs/+srdkwsnNjI7anr3Tt7UY6MqNxtMLlr0tMBied0O49UZVK8XKs3ZIiPw==} peerDependencies: @@ -1438,6 +2057,12 @@ packages: react-fast-compare@3.2.2: resolution: {integrity: sha512-nsO+KSNgo1SbJqJEYRE9ERzo7YtYbou/OqjSQKxV7jcKox7+usiUVZOAC+XnDOABXggQTno0Y1CpVnuWEc1boQ==} + react-is@16.13.1: + resolution: {integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==} + + react-is@18.3.1: + resolution: {integrity: sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==} + react-refresh@0.18.0: resolution: {integrity: sha512-QgT5//D3jfjJb6Gsjxv0Slpj23ip+HtOpnNgnb2S5zU3CB26G/IDPGoy4RJB42wzFE46DRsstbW6tKHoKbhAxw==} engines: {node: '>=0.10.0'} @@ -1459,10 +2084,27 @@ packages: react-dom: optional: true + react-transition-group@4.4.5: + resolution: {integrity: sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g==} + peerDependencies: + react: '>=16.6.0' + react-dom: '>=16.6.0' + react@19.2.0: resolution: {integrity: sha512-tmbWg6W31tQLeB5cdIBOicJDJRR2KzXsV7uSK9iNfLWQ5bIZfxuPEHp7M8wiHyHnn0DD1i7w3Zmin0FtkrwoCQ==} engines: {node: '>=0.10.0'} + reflect.getprototypeof@1.0.10: + resolution: {integrity: sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw==} + engines: {node: '>= 0.4'} + + regenerator-runtime@0.14.1: + resolution: {integrity: sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==} + + regexp.prototype.flags@1.5.4: + resolution: {integrity: sha512-dYqgNSZbDwkaJ2ceRd9ojCGjBq+mOm9LmtXnAnEGyHhN/5R7iDW2TRw3h+o/jCFxus3P2LfWIIiwowAjANm7IA==} + engines: {node: '>= 0.4'} + resize-observer-polyfill@1.5.1: resolution: {integrity: sha512-LwZrotdHOo12nQuZlHEmtuXdqGoOD0OhaxopaNFxWzInpEgaLWoVuAMbTzixuosCx2nEG58ngzW3vxdWoxIgdg==} @@ -1470,6 +2112,15 @@ packages: resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} engines: {node: '>=4'} + resolve@1.22.11: + resolution: {integrity: sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ==} + engines: {node: '>= 0.4'} + hasBin: true + + resolve@2.0.0-next.5: + resolution: {integrity: sha512-U7WjGVG9sH8tvjW5SmGbQuui75FiyjAX72HX15DwBBwF9dNiQZRQAg9nnPhYy+TUnE0+VcrttuvNI8oSxZcocA==} + hasBin: true + reusify@1.1.0: resolution: {integrity: sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==} engines: {iojs: '>=1.0.0', node: '>=0.10.0'} @@ -1522,6 +2173,18 @@ packages: run-parallel@1.2.0: resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} + safe-array-concat@1.1.3: + resolution: {integrity: sha512-AURm5f0jYEOydBj7VQlVvDrjeFgthDdEF5H1dP+6mNpoXOMo1quQqJ4wvJDyRZ9+pO3kGWoOdmV08cSv2aJV6Q==} + engines: {node: '>=0.4'} + + safe-push-apply@1.0.0: + resolution: {integrity: sha512-iKE9w/Z7xCzUMIZqdBsp6pEQvwuEebH4vdpjcDWnyzaI6yl6O9FHvVpmGelvEHNsoY6wGblkxR6Zty/h00WiSA==} + engines: {node: '>= 0.4'} + + safe-regex-test@1.1.0: + resolution: {integrity: sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==} + engines: {node: '>= 0.4'} + scheduler@0.27.0: resolution: {integrity: sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==} @@ -1541,6 +2204,18 @@ packages: set-cookie-parser@2.7.2: resolution: {integrity: sha512-oeM1lpU/UvhTxw+g3cIfxXHyJRc/uidd3yK1P242gzHds0udQBYzs3y8j4gCCW+ZJ7ad0yctld8RYO+bdurlvw==} + set-function-length@1.2.2: + resolution: {integrity: sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==} + engines: {node: '>= 0.4'} + + set-function-name@2.0.2: + resolution: {integrity: sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==} + engines: {node: '>= 0.4'} + + set-proto@1.0.0: + resolution: {integrity: sha512-RJRdvCo6IAnPdsvP/7m6bsQqNnn1FCBX5ZNtFL98MmFF/4xAIJTIg1YbHW5DC2W5SKZanrC6i4HsJqlajw/dZw==} + engines: {node: '>= 0.4'} + shade-blend-color@1.0.0: resolution: {integrity: sha512-Tnp/ppF5h3YhPCpeHiZJ2DRnvmo4luu9qpMhuksCT+QInIXJ9alA3Vd9klfEi+RY8Oh7MaK5vzH/qcLo892L1g==} @@ -1552,9 +2227,32 @@ packages: resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} engines: {node: '>=8'} + side-channel-list@1.0.0: + resolution: {integrity: sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==} + engines: {node: '>= 0.4'} + + side-channel-map@1.0.1: + resolution: {integrity: sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==} + engines: {node: '>= 0.4'} + + side-channel-weakmap@1.0.2: + resolution: {integrity: sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==} + engines: {node: '>= 0.4'} + + side-channel@1.1.0: + resolution: {integrity: sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==} + engines: {node: '>= 0.4'} + siginfo@2.0.0: resolution: {integrity: sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==} + slash@3.0.0: + resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==} + engines: {node: '>=8'} + + sortablejs@1.15.6: + resolution: {integrity: sha512-aNfiuwMEpfBM/CN6LY0ibyhxPfPbyFeBTYJKCvzkJ2GkUpazIt3H+QIPAMHwqQ7tMKaHz1Qj+rJJCqljnf4p3A==} + source-map-js@1.2.1: resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} engines: {node: '>=0.10.0'} @@ -1569,10 +2267,37 @@ packages: std-env@3.10.0: resolution: {integrity: sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg==} + stop-iteration-iterator@1.1.0: + resolution: {integrity: sha512-eLoXW/DHyl62zxY4SCaIgnRhuMr6ri4juEYARS8E6sCEqzKpOiE521Ucofdx+KnDZl5xmvGYaaKCk5FEOxJCoQ==} + engines: {node: '>= 0.4'} + strict-uri-encode@2.0.0: resolution: {integrity: sha512-QwiXZgpRcKkhTj2Scnn++4PKtWsH0kpzZ62L2R6c/LUVYv7hVnZqcg2+sMuT6R7Jusu1vviK/MFsu6kNJfWlEQ==} engines: {node: '>=4'} + string.prototype.matchall@4.0.12: + resolution: {integrity: sha512-6CC9uyBL+/48dYizRf7H7VAYCMCNTBeM78x/VTUe9bFEaxBepPJDa1Ow99LqI/1yF7kuy7Q3cQsYMrcjGUcskA==} + engines: {node: '>= 0.4'} + + string.prototype.repeat@1.0.0: + resolution: {integrity: sha512-0u/TldDbKD8bFCQ/4f5+mNRrXwZ8hg2w7ZR8wa16e8z9XpePWl3eGEcUD0OXpEH/VJH/2G3gjUtR3ZOiBe2S/w==} + + string.prototype.trim@1.2.10: + resolution: {integrity: sha512-Rs66F0P/1kedk5lyYyH9uBzuiI/kNRmwJAR9quK6VOtIpZ2G+hMZd+HQbbv25MgCA6gEffoMZYxlTod4WcdrKA==} + engines: {node: '>= 0.4'} + + string.prototype.trimend@1.0.9: + resolution: {integrity: sha512-G7Ok5C6E/j4SGfyLCloXTrngQIQU3PWtXGst3yM7Bea9FRURf1S42ZHlZZtsNque2FN2PoUhfZXYLNWwEr4dLQ==} + engines: {node: '>= 0.4'} + + string.prototype.trimstart@1.0.8: + resolution: {integrity: sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==} + engines: {node: '>= 0.4'} + + strip-bom@3.0.0: + resolution: {integrity: sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==} + engines: {node: '>=4'} + strip-json-comments@3.1.1: resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} engines: {node: '>=8'} @@ -1584,10 +2309,26 @@ packages: resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} engines: {node: '>=8'} + supports-preserve-symlinks-flag@1.0.0: + resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} + engines: {node: '>= 0.4'} + swiper@12.0.3: resolution: {integrity: sha512-BHd6U1VPEIksrXlyXjMmRWO0onmdNPaTAFduzqR3pgjvi7KfmUCAm/0cj49u2D7B0zNjMw02TSeXfinC1hDCXg==} engines: {node: '>= 4.7.0'} + tdesign-icons-react@0.6.1: + resolution: {integrity: sha512-O+hfqf2HEDhZC3e7Rr+pkflnYVW1eMtRqcShhmegwWvj097rP910nGzWBGFNbuQEfoueRlCZ0iSacqYF71JeNQ==} + peerDependencies: + react: '>=16.13.1' + react-dom: '>=16.13.1' + + tdesign-react@1.15.8: + resolution: {integrity: sha512-2+XLIeC895UsTBMbWupLx5kH67cM32zeo+6BbjwXTwYyGdfioSM74ZyCoVfn2IPeJ73pv8DdAMffgRVVUQaSbA==} + peerDependencies: + react: '>=16.13.1' + react-dom: '>=16.13.1' + tinybench@2.9.0: resolution: {integrity: sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==} @@ -1606,12 +2347,24 @@ packages: resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} engines: {node: '>=8.0'} + ts-api-utils@1.4.3: + resolution: {integrity: sha512-i3eMG77UTMD0hZhgRS562pv83RC6ukSAC2GMNWc+9dieh/+jDM5u5YG+NHX6VNDRHQcHwmsTHctP9LhbC3WxVw==} + engines: {node: '>=16'} + peerDependencies: + typescript: '>=4.2.0' + ts-api-utils@2.1.0: resolution: {integrity: sha512-CUgTZL1irw8u29bzrOD/nH85jqyc74D6SshFgujOIA7osm2Rz7dYH77agkx7H4FBNxDq7Cjf+IjaX/8zwFW+ZQ==} engines: {node: '>=18.12'} peerDependencies: typescript: '>=4.8.4' + tsconfig-paths@3.15.0: + resolution: {integrity: sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==} + + tslib@2.3.1: + resolution: {integrity: sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==} + tslib@2.8.1: resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} @@ -1619,11 +2372,41 @@ packages: resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} engines: {node: '>= 0.8.0'} - typescript-eslint@8.46.4: - resolution: {integrity: sha512-KALyxkpYV5Ix7UhvjTwJXZv76VWsHG+NjNlt/z+a17SOQSiOcBdUXdbJdyXi7RPxrBFECtFOiPwUJQusJuCqrg==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - peerDependencies: - eslint: ^8.57.0 || ^9.0.0 + type-fest@0.20.2: + resolution: {integrity: sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==} + engines: {node: '>=10'} + + typed-array-buffer@1.0.3: + resolution: {integrity: sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==} + engines: {node: '>= 0.4'} + + typed-array-byte-length@1.0.3: + resolution: {integrity: sha512-BaXgOuIxz8n8pIq3e7Atg/7s+DpiYrxn4vdot3w9KbnBhcRQq6o3xemQdIfynqSeXeDrF32x+WvfzmOjPiY9lg==} + engines: {node: '>= 0.4'} + + typed-array-byte-offset@1.0.4: + resolution: {integrity: sha512-bTlAFB/FBYMcuX81gbL4OcpH5PmlFHqlCCpAl8AlEzMz5k53oNDvN8p1PNOWLEmI2x4orp3raOFB51tv9X+MFQ==} + engines: {node: '>= 0.4'} + + typed-array-length@1.0.7: + resolution: {integrity: sha512-3KS2b+kL7fsuk/eJZ7EQdnEmQoaho/r6KUef7hxvltNA5DR8NAUM+8wJMbJyZ4G9/7i3v5zPBIMN5aybAh2/Jg==} + engines: {node: '>= 0.4'} + + typescript-eslint@7.18.0: + resolution: {integrity: sha512-PonBkP603E3tt05lDkbOMyaxJjvKqQrXsnow72sVeOFINDE/qNmnnd+f9b4N+U7W6MXnnYyrhtmF2t08QWwUbA==} + engines: {node: ^18.18.0 || >=20.0.0} + peerDependencies: + eslint: ^8.56.0 + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + + typescript-eslint@8.46.4: + resolution: {integrity: sha512-KALyxkpYV5Ix7UhvjTwJXZv76VWsHG+NjNlt/z+a17SOQSiOcBdUXdbJdyXi7RPxrBFECtFOiPwUJQusJuCqrg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 typescript: '>=4.8.4 <6.0.0' typescript@5.9.3: @@ -1635,6 +2418,13 @@ packages: resolution: {integrity: sha512-LbBDqdIC5s8iROCUjMbW1f5dJQTEFB1+KO9ogbvlb3nm9n4YHa5p4KTvFPWvh2Hs8gZMBuiB1/8+pdfe/tDPug==} hasBin: true + unbox-primitive@1.1.0: + resolution: {integrity: sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw==} + engines: {node: '>= 0.4'} + + undici-types@7.16.0: + resolution: {integrity: sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==} + universalify@2.0.1: resolution: {integrity: sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==} engines: {node: '>= 10.0.0'} @@ -1648,6 +2438,13 @@ packages: uri-js@4.4.1: resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} + util-deprecate@1.0.2: + resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} + + validator@13.15.23: + resolution: {integrity: sha512-4yoz1kEWqUjzi5zsPbAS/903QXSYp0UOtHsPpp7p9rHAw/W+dkInskAE386Fat3oKRROwO98d9ZB0G4cObgUyw==} + engines: {node: '>= 0.10'} + vite-plugin-babel@1.3.2: resolution: {integrity: sha512-mEld4OVyuNs5+ISN+U5XyTnNcDwln/s2oER2m0PQ32YYPqPR25E3mfnhAA/RkZJxPuwFkprKWV405aZArE6kzA==} peerDependencies: @@ -1696,9 +2493,31 @@ packages: jsdom: optional: true + vue-eslint-parser@9.4.3: + resolution: {integrity: sha512-2rYRLWlIpaiN8xbPiDyXZXRgLGOtWxERV7ND5fFAv5qo1D2N9Fu9MNajBNc6o13lZ+24DAWCkQCvj4klgmcITg==} + engines: {node: ^14.17.0 || >=16.0.0} + peerDependencies: + eslint: '>=6.0.0' + w3c-keyname@2.2.8: resolution: {integrity: sha512-dpojBhNsCNN7T82Tm7k26A6G9ML3NkhDsnw9n/eoxSRlVBB4CEtIQ/KTCLI2Fwf3ataSXRhYFkQi3SlnFwPvPQ==} + which-boxed-primitive@1.1.1: + resolution: {integrity: sha512-TbX3mj8n0odCBFVlY8AxkqcHASw3L60jIuF8jFP78az3C2YhmGvqbHBpAjTRH2/xqYunrJ9g1jSyjCjpoWzIAA==} + engines: {node: '>= 0.4'} + + which-builtin-type@1.2.1: + resolution: {integrity: sha512-6iBczoX+kDQ7a3+YJBnh3T+KZRxM/iYNPXicqk66/Qfm1b93iu+yOImkg0zHbj5LNOcNv1TEADiZ0xa34B4q6Q==} + engines: {node: '>= 0.4'} + + which-collection@1.0.2: + resolution: {integrity: sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw==} + engines: {node: '>= 0.4'} + + which-typed-array@1.1.19: + resolution: {integrity: sha512-rEvr90Bck4WZt9HHFC4DJMsjvu7x+r6bImz0/BrbWb7A2djJ8hnZMrWnHo9F8ssv0OMErasDhftrfROTyqSDrw==} + engines: {node: '>= 0.4'} + which@2.0.2: resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} engines: {node: '>= 8'} @@ -1713,6 +2532,10 @@ packages: resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==} engines: {node: '>=0.10.0'} + xml-name-validator@4.0.0: + resolution: {integrity: sha512-ICP2e+jsHvAj2E2lIHxa5tjXRlKDJo4IdvPvCXbXQGdzSfmSpNVyIKMvoZHjDY9DP0zV17iI85o90vRFXNccRw==} + engines: {node: '>=12'} + yallist@3.1.1: resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==} @@ -1769,6 +2592,14 @@ snapshots: transitivePeerDependencies: - supports-color + '@babel/eslint-parser@7.28.5(@babel/core@7.28.5)(eslint@9.39.1)': + dependencies: + '@babel/core': 7.28.5 + '@nicolo-ribaudo/eslint-scope-5-internals': 5.1.1-v1 + eslint: 9.39.1 + eslint-visitor-keys: 2.1.0 + semver: 6.3.1 + '@babel/generator@7.28.5': dependencies: '@babel/parser': 7.28.5 @@ -1830,6 +2661,10 @@ snapshots: '@babel/core': 7.28.5 '@babel/helper-plugin-utils': 7.27.1 + '@babel/runtime@7.26.10': + dependencies: + regenerator-runtime: 0.14.1 + '@babel/runtime@7.28.4': {} '@babel/template@7.27.2': @@ -2040,6 +2875,8 @@ snapshots: transitivePeerDependencies: - supports-color + '@eslint/js@8.57.1': {} + '@eslint/js@9.39.1': {} '@eslint/object-schema@2.1.7': {} @@ -2121,6 +2958,10 @@ snapshots: '@tybys/wasm-util': 0.10.1 optional: true + '@nicolo-ribaudo/eslint-scope-5-internals@5.1.1-v1': + dependencies: + eslint-scope: 5.1.1 + '@nodelib/fs.scandir@2.1.5': dependencies: '@nodelib/fs.stat': 2.0.5 @@ -2137,6 +2978,8 @@ snapshots: '@oxc-project/types@0.96.0': {} + '@popperjs/core@2.11.8': {} + '@react-spring/animated@10.0.3(react@19.2.0)': dependencies: '@react-spring/shared': 10.0.3(react@19.2.0) @@ -2215,6 +3058,8 @@ snapshots: '@rolldown/pluginutils@1.0.0-beta.47': {} + '@rtsao/scc@1.1.0': {} + '@standard-schema/spec@1.0.0': {} '@tybys/wasm-util@0.10.1': @@ -2258,8 +3103,15 @@ snapshots: '@types/json-schema@7.0.15': {} + '@types/json5@0.0.29': {} + '@types/lodash@4.17.20': {} + '@types/node@24.10.1': + dependencies: + undici-types: 7.16.0 + optional: true + '@types/react-dom@19.2.3(@types/react@19.2.4)': dependencies: '@types/react': 19.2.4 @@ -2279,9 +3131,31 @@ snapshots: dependencies: csstype: 3.1.3 + '@types/sortablejs@1.15.9': {} + '@types/trusted-types@2.0.7': optional: true + '@types/validator@13.15.8': {} + + '@typescript-eslint/eslint-plugin@7.18.0(@typescript-eslint/parser@7.18.0(eslint@9.39.1)(typescript@5.9.3))(eslint@9.39.1)(typescript@5.9.3)': + dependencies: + '@eslint-community/regexpp': 4.12.2 + '@typescript-eslint/parser': 7.18.0(eslint@9.39.1)(typescript@5.9.3) + '@typescript-eslint/scope-manager': 7.18.0 + '@typescript-eslint/type-utils': 7.18.0(eslint@9.39.1)(typescript@5.9.3) + '@typescript-eslint/utils': 7.18.0(eslint@9.39.1)(typescript@5.9.3) + '@typescript-eslint/visitor-keys': 7.18.0 + eslint: 9.39.1 + graphemer: 1.4.0 + ignore: 5.3.2 + natural-compare: 1.4.0 + ts-api-utils: 1.4.3(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color + '@typescript-eslint/eslint-plugin@8.46.4(@typescript-eslint/parser@8.46.4(eslint@9.39.1)(typescript@5.9.3))(eslint@9.39.1)(typescript@5.9.3)': dependencies: '@eslint-community/regexpp': 4.12.2 @@ -2299,6 +3173,19 @@ snapshots: transitivePeerDependencies: - supports-color + '@typescript-eslint/parser@7.18.0(eslint@9.39.1)(typescript@5.9.3)': + dependencies: + '@typescript-eslint/scope-manager': 7.18.0 + '@typescript-eslint/types': 7.18.0 + '@typescript-eslint/typescript-estree': 7.18.0(typescript@5.9.3) + '@typescript-eslint/visitor-keys': 7.18.0 + debug: 4.4.3 + eslint: 9.39.1 + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color + '@typescript-eslint/parser@8.46.4(eslint@9.39.1)(typescript@5.9.3)': dependencies: '@typescript-eslint/scope-manager': 8.46.4 @@ -2320,6 +3207,11 @@ snapshots: transitivePeerDependencies: - supports-color + '@typescript-eslint/scope-manager@7.18.0': + dependencies: + '@typescript-eslint/types': 7.18.0 + '@typescript-eslint/visitor-keys': 7.18.0 + '@typescript-eslint/scope-manager@8.46.4': dependencies: '@typescript-eslint/types': 8.46.4 @@ -2329,6 +3221,18 @@ snapshots: dependencies: typescript: 5.9.3 + '@typescript-eslint/type-utils@7.18.0(eslint@9.39.1)(typescript@5.9.3)': + dependencies: + '@typescript-eslint/typescript-estree': 7.18.0(typescript@5.9.3) + '@typescript-eslint/utils': 7.18.0(eslint@9.39.1)(typescript@5.9.3) + debug: 4.4.3 + eslint: 9.39.1 + ts-api-utils: 1.4.3(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color + '@typescript-eslint/type-utils@8.46.4(eslint@9.39.1)(typescript@5.9.3)': dependencies: '@typescript-eslint/types': 8.46.4 @@ -2341,8 +3245,25 @@ snapshots: transitivePeerDependencies: - supports-color + '@typescript-eslint/types@7.18.0': {} + '@typescript-eslint/types@8.46.4': {} + '@typescript-eslint/typescript-estree@7.18.0(typescript@5.9.3)': + dependencies: + '@typescript-eslint/types': 7.18.0 + '@typescript-eslint/visitor-keys': 7.18.0 + debug: 4.4.3 + globby: 11.1.0 + is-glob: 4.0.3 + minimatch: 9.0.5 + semver: 7.7.3 + ts-api-utils: 1.4.3(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color + '@typescript-eslint/typescript-estree@8.46.4(typescript@5.9.3)': dependencies: '@typescript-eslint/project-service': 8.46.4(typescript@5.9.3) @@ -2359,6 +3280,17 @@ snapshots: transitivePeerDependencies: - supports-color + '@typescript-eslint/utils@7.18.0(eslint@9.39.1)(typescript@5.9.3)': + dependencies: + '@eslint-community/eslint-utils': 4.9.0(eslint@9.39.1) + '@typescript-eslint/scope-manager': 7.18.0 + '@typescript-eslint/types': 7.18.0 + '@typescript-eslint/typescript-estree': 7.18.0(typescript@5.9.3) + eslint: 9.39.1 + transitivePeerDependencies: + - supports-color + - typescript + '@typescript-eslint/utils@8.46.4(eslint@9.39.1)(typescript@5.9.3)': dependencies: '@eslint-community/eslint-utils': 4.9.0(eslint@9.39.1) @@ -2370,6 +3302,11 @@ snapshots: transitivePeerDependencies: - supports-color + '@typescript-eslint/visitor-keys@7.18.0': + dependencies: + '@typescript-eslint/types': 7.18.0 + eslint-visitor-keys: 3.4.3 + '@typescript-eslint/visitor-keys@8.46.4': dependencies: '@typescript-eslint/types': 8.46.4 @@ -2413,7 +3350,7 @@ snapshots: '@use-gesture/core': 10.3.1 react: 19.2.0 - '@vitejs/plugin-react@5.1.1(rolldown-vite@7.2.2(esbuild@0.25.12))': + '@vitejs/plugin-react@5.1.1(rolldown-vite@7.2.2(@types/node@24.10.1)(esbuild@0.25.12))': dependencies: '@babel/core': 7.28.5 '@babel/plugin-transform-react-jsx-self': 7.27.1(@babel/core@7.28.5) @@ -2421,7 +3358,7 @@ snapshots: '@rolldown/pluginutils': 1.0.0-beta.47 '@types/babel__core': 7.20.5 react-refresh: 0.18.0 - vite: rolldown-vite@7.2.2(esbuild@0.25.12) + vite: rolldown-vite@7.2.2(@types/node@24.10.1)(esbuild@0.25.12) transitivePeerDependencies: - supports-color @@ -2434,13 +3371,13 @@ snapshots: chai: 6.2.1 tinyrainbow: 3.0.3 - '@vitest/mocker@4.0.8(rolldown-vite@7.2.2(esbuild@0.25.12))': + '@vitest/mocker@4.0.8(rolldown-vite@7.2.2(@types/node@24.10.1)(esbuild@0.25.12))': dependencies: '@vitest/spy': 4.0.8 estree-walker: 3.0.3 magic-string: 0.30.21 optionalDependencies: - vite: rolldown-vite@7.2.2(esbuild@0.25.12) + vite: rolldown-vite@7.2.2(@types/node@24.10.1)(esbuild@0.25.12) '@vitest/pretty-format@4.0.8': dependencies: @@ -2498,8 +3435,83 @@ snapshots: argparse@2.0.1: {} + array-buffer-byte-length@1.0.2: + dependencies: + call-bound: 1.0.4 + is-array-buffer: 3.0.5 + + array-includes@3.1.9: + dependencies: + call-bind: 1.0.8 + call-bound: 1.0.4 + define-properties: 1.2.1 + es-abstract: 1.24.0 + es-object-atoms: 1.1.1 + get-intrinsic: 1.3.0 + is-string: 1.1.1 + math-intrinsics: 1.1.0 + + array-union@2.1.0: {} + + array.prototype.findlast@1.2.5: + dependencies: + call-bind: 1.0.8 + define-properties: 1.2.1 + es-abstract: 1.24.0 + es-errors: 1.3.0 + es-object-atoms: 1.1.1 + es-shim-unscopables: 1.1.0 + + array.prototype.findlastindex@1.2.6: + dependencies: + call-bind: 1.0.8 + call-bound: 1.0.4 + define-properties: 1.2.1 + es-abstract: 1.24.0 + es-errors: 1.3.0 + es-object-atoms: 1.1.1 + es-shim-unscopables: 1.1.0 + + array.prototype.flat@1.3.3: + dependencies: + call-bind: 1.0.8 + define-properties: 1.2.1 + es-abstract: 1.24.0 + es-shim-unscopables: 1.1.0 + + array.prototype.flatmap@1.3.3: + dependencies: + call-bind: 1.0.8 + define-properties: 1.2.1 + es-abstract: 1.24.0 + es-shim-unscopables: 1.1.0 + + array.prototype.tosorted@1.1.4: + dependencies: + call-bind: 1.0.8 + define-properties: 1.2.1 + es-abstract: 1.24.0 + es-errors: 1.3.0 + es-shim-unscopables: 1.1.0 + + arraybuffer.prototype.slice@1.0.4: + dependencies: + array-buffer-byte-length: 1.0.2 + call-bind: 1.0.8 + define-properties: 1.2.1 + es-abstract: 1.24.0 + es-errors: 1.3.0 + get-intrinsic: 1.3.0 + is-array-buffer: 3.0.5 + assertion-error@2.0.1: {} + async-function@1.0.0: {} + + available-typed-arrays@1.0.7: + dependencies: + possible-typed-array-names: 1.1.0 + babel-plugin-react-compiler@1.0.0: dependencies: '@babel/types': 7.28.5 @@ -2508,6 +3520,8 @@ snapshots: baseline-browser-mapping@2.8.28: {} + boolbase@1.0.0: {} + brace-expansion@1.1.12: dependencies: balanced-match: 1.0.2 @@ -2529,6 +3543,23 @@ snapshots: node-releases: 2.0.27 update-browserslist-db: 1.1.4(browserslist@4.28.0) + call-bind-apply-helpers@1.0.2: + dependencies: + es-errors: 1.3.0 + function-bind: 1.1.2 + + call-bind@1.0.8: + dependencies: + call-bind-apply-helpers: 1.0.2 + es-define-property: 1.0.1 + get-intrinsic: 1.3.0 + set-function-length: 1.2.2 + + call-bound@1.0.4: + dependencies: + call-bind-apply-helpers: 1.0.2 + get-intrinsic: 1.3.0 + callsites@3.1.0: {} caniuse-lite@1.0.30001754: {} @@ -2540,6 +3571,8 @@ snapshots: ansi-styles: 4.3.0 supports-color: 7.2.0 + classnames@2.5.1: {} + codemirror@6.0.2: dependencies: '@codemirror/autocomplete': 6.19.1 @@ -2572,10 +3605,36 @@ snapshots: shebang-command: 2.0.0 which: 2.0.2 + cssesc@3.0.0: {} + csstype@3.1.3: {} + data-view-buffer@1.0.2: + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + is-data-view: 1.0.2 + + data-view-byte-length@1.0.2: + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + is-data-view: 1.0.2 + + data-view-byte-offset@1.0.1: + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + is-data-view: 1.0.2 + + dayjs@1.11.10: {} + dayjs@1.11.19: {} + debug@3.2.7: + dependencies: + ms: 2.1.3 + debug@4.4.3: dependencies: ms: 2.1.3 @@ -2584,18 +3643,150 @@ snapshots: deep-is@0.1.4: {} + define-data-property@1.1.4: + dependencies: + es-define-property: 1.0.1 + es-errors: 1.3.0 + gopd: 1.2.0 + + define-properties@1.2.1: + dependencies: + define-data-property: 1.1.4 + has-property-descriptors: 1.0.2 + object-keys: 1.1.1 + detect-libc@2.1.2: {} dexie@4.2.1: {} + dir-glob@3.0.1: + dependencies: + path-type: 4.0.0 + + doctrine@2.1.0: + dependencies: + esutils: 2.0.3 + + dom-helpers@5.2.1: + dependencies: + '@babel/runtime': 7.28.4 + csstype: 3.1.3 + dompurify@3.3.0: optionalDependencies: '@types/trusted-types': 2.0.7 + dunder-proto@1.0.1: + dependencies: + call-bind-apply-helpers: 1.0.2 + es-errors: 1.3.0 + gopd: 1.2.0 + electron-to-chromium@1.5.250: {} + es-abstract@1.24.0: + dependencies: + array-buffer-byte-length: 1.0.2 + arraybuffer.prototype.slice: 1.0.4 + available-typed-arrays: 1.0.7 + call-bind: 1.0.8 + call-bound: 1.0.4 + data-view-buffer: 1.0.2 + data-view-byte-length: 1.0.2 + data-view-byte-offset: 1.0.1 + es-define-property: 1.0.1 + es-errors: 1.3.0 + es-object-atoms: 1.1.1 + es-set-tostringtag: 2.1.0 + es-to-primitive: 1.3.0 + function.prototype.name: 1.1.8 + get-intrinsic: 1.3.0 + get-proto: 1.0.1 + get-symbol-description: 1.1.0 + globalthis: 1.0.4 + gopd: 1.2.0 + has-property-descriptors: 1.0.2 + has-proto: 1.2.0 + has-symbols: 1.1.0 + hasown: 2.0.2 + internal-slot: 1.1.0 + is-array-buffer: 3.0.5 + is-callable: 1.2.7 + is-data-view: 1.0.2 + is-negative-zero: 2.0.3 + is-regex: 1.2.1 + is-set: 2.0.3 + is-shared-array-buffer: 1.0.4 + is-string: 1.1.1 + is-typed-array: 1.1.15 + is-weakref: 1.1.1 + math-intrinsics: 1.1.0 + object-inspect: 1.13.4 + object-keys: 1.1.1 + object.assign: 4.1.7 + own-keys: 1.0.1 + regexp.prototype.flags: 1.5.4 + safe-array-concat: 1.1.3 + safe-push-apply: 1.0.0 + safe-regex-test: 1.1.0 + set-proto: 1.0.0 + stop-iteration-iterator: 1.1.0 + string.prototype.trim: 1.2.10 + string.prototype.trimend: 1.0.9 + string.prototype.trimstart: 1.0.8 + typed-array-buffer: 1.0.3 + typed-array-byte-length: 1.0.3 + typed-array-byte-offset: 1.0.4 + typed-array-length: 1.0.7 + unbox-primitive: 1.1.0 + which-typed-array: 1.1.19 + + es-define-property@1.0.1: {} + + es-errors@1.3.0: {} + + es-iterator-helpers@1.2.1: + dependencies: + call-bind: 1.0.8 + call-bound: 1.0.4 + define-properties: 1.2.1 + es-abstract: 1.24.0 + es-errors: 1.3.0 + es-set-tostringtag: 2.1.0 + function-bind: 1.1.2 + get-intrinsic: 1.3.0 + globalthis: 1.0.4 + gopd: 1.2.0 + has-property-descriptors: 1.0.2 + has-proto: 1.2.0 + has-symbols: 1.1.0 + internal-slot: 1.1.0 + iterator.prototype: 1.1.5 + safe-array-concat: 1.1.3 + es-module-lexer@1.7.0: {} + es-object-atoms@1.1.1: + dependencies: + es-errors: 1.3.0 + + es-set-tostringtag@2.1.0: + dependencies: + es-errors: 1.3.0 + get-intrinsic: 1.3.0 + has-tostringtag: 1.0.2 + hasown: 2.0.2 + + es-shim-unscopables@1.1.0: + dependencies: + hasown: 2.0.2 + + es-to-primitive@1.3.0: + dependencies: + is-callable: 1.2.7 + is-date-object: 1.1.0 + is-symbol: 1.1.1 + esbuild@0.25.12: optionalDependencies: '@esbuild/aix-ppc64': 0.25.12 @@ -2630,6 +3821,85 @@ snapshots: escape-string-regexp@4.0.0: {} + eslint-config-tencent@1.1.3(@babel/core@7.28.5)(@typescript-eslint/parser@8.46.4(eslint@9.39.1)(typescript@5.9.3))(eslint@9.39.1)(prettier@3.6.2)(typescript@5.9.3): + dependencies: + '@babel/core': 7.28.5 + '@babel/eslint-parser': 7.28.5(@babel/core@7.28.5)(eslint@9.39.1) + '@eslint/js': 8.57.1 + eslint: 9.39.1 + eslint-plugin-chalk: 1.0.0(eslint@9.39.1) + eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.46.4(eslint@9.39.1)(typescript@5.9.3))(eslint@9.39.1) + eslint-plugin-prettier: 3.4.1(eslint@9.39.1)(prettier@3.6.2) + eslint-plugin-react: 7.37.5(eslint@9.39.1) + eslint-plugin-vue: 9.33.0(eslint@9.39.1) + typescript-eslint: 7.18.0(eslint@9.39.1)(typescript@5.9.3) + transitivePeerDependencies: + - '@typescript-eslint/parser' + - eslint-config-prettier + - eslint-import-resolver-typescript + - eslint-import-resolver-webpack + - prettier + - supports-color + - typescript + + eslint-import-resolver-node@0.3.9: + dependencies: + debug: 3.2.7 + is-core-module: 2.16.1 + resolve: 1.22.11 + transitivePeerDependencies: + - supports-color + + eslint-module-utils@2.12.1(@typescript-eslint/parser@8.46.4(eslint@9.39.1)(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint@9.39.1): + dependencies: + debug: 3.2.7 + optionalDependencies: + '@typescript-eslint/parser': 8.46.4(eslint@9.39.1)(typescript@5.9.3) + eslint: 9.39.1 + eslint-import-resolver-node: 0.3.9 + transitivePeerDependencies: + - supports-color + + eslint-plugin-chalk@1.0.0(eslint@9.39.1): + dependencies: + chalk: 4.1.2 + eslint: 9.39.1 + + eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.46.4(eslint@9.39.1)(typescript@5.9.3))(eslint@9.39.1): + dependencies: + '@rtsao/scc': 1.1.0 + array-includes: 3.1.9 + array.prototype.findlastindex: 1.2.6 + array.prototype.flat: 1.3.3 + array.prototype.flatmap: 1.3.3 + debug: 3.2.7 + doctrine: 2.1.0 + eslint: 9.39.1 + eslint-import-resolver-node: 0.3.9 + eslint-module-utils: 2.12.1(@typescript-eslint/parser@8.46.4(eslint@9.39.1)(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint@9.39.1) + hasown: 2.0.2 + is-core-module: 2.16.1 + is-glob: 4.0.3 + minimatch: 3.1.2 + object.fromentries: 2.0.8 + object.groupby: 1.0.3 + object.values: 1.2.1 + semver: 6.3.1 + string.prototype.trimend: 1.0.9 + tsconfig-paths: 3.15.0 + optionalDependencies: + '@typescript-eslint/parser': 8.46.4(eslint@9.39.1)(typescript@5.9.3) + transitivePeerDependencies: + - eslint-import-resolver-typescript + - eslint-import-resolver-webpack + - supports-color + + eslint-plugin-prettier@3.4.1(eslint@9.39.1)(prettier@3.6.2): + dependencies: + eslint: 9.39.1 + prettier: 3.6.2 + prettier-linter-helpers: 1.0.0 + eslint-plugin-react-hooks@7.0.1(eslint@9.39.1): dependencies: '@babel/core': 7.28.5 @@ -2645,11 +3915,59 @@ snapshots: dependencies: eslint: 9.39.1 + eslint-plugin-react@7.37.5(eslint@9.39.1): + dependencies: + array-includes: 3.1.9 + array.prototype.findlast: 1.2.5 + array.prototype.flatmap: 1.3.3 + array.prototype.tosorted: 1.1.4 + doctrine: 2.1.0 + es-iterator-helpers: 1.2.1 + eslint: 9.39.1 + estraverse: 5.3.0 + hasown: 2.0.2 + jsx-ast-utils: 3.3.5 + minimatch: 3.1.2 + object.entries: 1.1.9 + object.fromentries: 2.0.8 + object.values: 1.2.1 + prop-types: 15.8.1 + resolve: 2.0.0-next.5 + semver: 6.3.1 + string.prototype.matchall: 4.0.12 + string.prototype.repeat: 1.0.0 + + eslint-plugin-vue@9.33.0(eslint@9.39.1): + dependencies: + '@eslint-community/eslint-utils': 4.9.0(eslint@9.39.1) + eslint: 9.39.1 + globals: 13.24.0 + natural-compare: 1.4.0 + nth-check: 2.1.1 + postcss-selector-parser: 6.1.2 + semver: 7.7.3 + vue-eslint-parser: 9.4.3(eslint@9.39.1) + xml-name-validator: 4.0.0 + transitivePeerDependencies: + - supports-color + + eslint-scope@5.1.1: + dependencies: + esrecurse: 4.3.0 + estraverse: 4.3.0 + + eslint-scope@7.2.2: + dependencies: + esrecurse: 4.3.0 + estraverse: 5.3.0 + eslint-scope@8.4.0: dependencies: esrecurse: 4.3.0 estraverse: 5.3.0 + eslint-visitor-keys@2.1.0: {} + eslint-visitor-keys@3.4.3: {} eslint-visitor-keys@4.2.1: {} @@ -2699,6 +4017,12 @@ snapshots: acorn-jsx: 5.3.2(acorn@8.15.0) eslint-visitor-keys: 4.2.1 + espree@9.6.1: + dependencies: + acorn: 8.15.0 + acorn-jsx: 5.3.2(acorn@8.15.0) + eslint-visitor-keys: 3.4.3 + esquery@1.6.0: dependencies: estraverse: 5.3.0 @@ -2707,6 +4031,8 @@ snapshots: dependencies: estraverse: 5.3.0 + estraverse@4.3.0: {} + estraverse@5.3.0: {} estree-walker@3.0.3: @@ -2719,6 +4045,8 @@ snapshots: fast-deep-equal@3.1.3: {} + fast-diff@1.3.0: {} + fast-glob@3.3.3: dependencies: '@nodelib/fs.stat': 2.0.5 @@ -2761,6 +4089,10 @@ snapshots: flatted@3.3.3: {} + for-each@0.3.5: + dependencies: + is-callable: 1.2.7 + fs-extra@10.1.0: dependencies: graceful-fs: 4.2.11 @@ -2770,8 +4102,47 @@ snapshots: fsevents@2.3.3: optional: true + function-bind@1.1.2: {} + + function.prototype.name@1.1.8: + dependencies: + call-bind: 1.0.8 + call-bound: 1.0.4 + define-properties: 1.2.1 + functions-have-names: 1.2.3 + hasown: 2.0.2 + is-callable: 1.2.7 + + functions-have-names@1.2.3: {} + + generator-function@2.0.1: {} + gensync@1.0.0-beta.2: {} + get-intrinsic@1.3.0: + dependencies: + call-bind-apply-helpers: 1.0.2 + es-define-property: 1.0.1 + es-errors: 1.3.0 + es-object-atoms: 1.1.1 + function-bind: 1.1.2 + get-proto: 1.0.1 + gopd: 1.2.0 + has-symbols: 1.1.0 + hasown: 2.0.2 + math-intrinsics: 1.1.0 + + get-proto@1.0.1: + dependencies: + dunder-proto: 1.0.1 + es-object-atoms: 1.1.1 + + get-symbol-description@1.1.0: + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + get-intrinsic: 1.3.0 + glob-parent@5.1.2: dependencies: is-glob: 4.0.3 @@ -2780,22 +4151,68 @@ snapshots: dependencies: is-glob: 4.0.3 + globals@13.24.0: + dependencies: + type-fest: 0.20.2 + globals@14.0.0: {} globals@16.5.0: {} + globalthis@1.0.4: + dependencies: + define-properties: 1.2.1 + gopd: 1.2.0 + + globby@11.1.0: + dependencies: + array-union: 2.1.0 + dir-glob: 3.0.1 + fast-glob: 3.3.3 + ignore: 5.3.2 + merge2: 1.4.1 + slash: 3.0.0 + + gopd@1.2.0: {} + graceful-fs@4.2.11: {} graphemer@1.4.0: {} + has-bigints@1.1.0: {} + has-flag@4.0.0: {} + has-property-descriptors@1.0.2: + dependencies: + es-define-property: 1.0.1 + + has-proto@1.2.0: + dependencies: + dunder-proto: 1.0.1 + + has-symbols@1.1.0: {} + + has-tostringtag@1.0.2: + dependencies: + has-symbols: 1.1.0 + + hasown@2.0.2: + dependencies: + function-bind: 1.1.2 + hermes-estree@0.25.1: {} hermes-parser@0.25.1: dependencies: hermes-estree: 0.25.1 + hoist-non-react-statics@3.3.2: + dependencies: + react-is: 16.13.1 + + husky@9.1.7: {} + ignore@5.3.2: {} ignore@7.0.5: {} @@ -2807,18 +4224,135 @@ snapshots: imurmurhash@0.1.4: {} + internal-slot@1.1.0: + dependencies: + es-errors: 1.3.0 + hasown: 2.0.2 + side-channel: 1.1.0 + intersection-observer@0.12.2: {} + is-array-buffer@3.0.5: + dependencies: + call-bind: 1.0.8 + call-bound: 1.0.4 + get-intrinsic: 1.3.0 + + is-async-function@2.1.1: + dependencies: + async-function: 1.0.0 + call-bound: 1.0.4 + get-proto: 1.0.1 + has-tostringtag: 1.0.2 + safe-regex-test: 1.1.0 + + is-bigint@1.1.0: + dependencies: + has-bigints: 1.1.0 + + is-boolean-object@1.2.2: + dependencies: + call-bound: 1.0.4 + has-tostringtag: 1.0.2 + + is-callable@1.2.7: {} + + is-core-module@2.16.1: + dependencies: + hasown: 2.0.2 + + is-data-view@1.0.2: + dependencies: + call-bound: 1.0.4 + get-intrinsic: 1.3.0 + is-typed-array: 1.1.15 + + is-date-object@1.1.0: + dependencies: + call-bound: 1.0.4 + has-tostringtag: 1.0.2 + is-extglob@2.1.1: {} + is-finalizationregistry@1.1.1: + dependencies: + call-bound: 1.0.4 + + is-generator-function@1.1.2: + dependencies: + call-bound: 1.0.4 + generator-function: 2.0.1 + get-proto: 1.0.1 + has-tostringtag: 1.0.2 + safe-regex-test: 1.1.0 + is-glob@4.0.3: dependencies: is-extglob: 2.1.1 + is-map@2.0.3: {} + + is-negative-zero@2.0.3: {} + + is-number-object@1.1.1: + dependencies: + call-bound: 1.0.4 + has-tostringtag: 1.0.2 + is-number@7.0.0: {} + is-regex@1.2.1: + dependencies: + call-bound: 1.0.4 + gopd: 1.2.0 + has-tostringtag: 1.0.2 + hasown: 2.0.2 + + is-set@2.0.3: {} + + is-shared-array-buffer@1.0.4: + dependencies: + call-bound: 1.0.4 + + is-string@1.1.1: + dependencies: + call-bound: 1.0.4 + has-tostringtag: 1.0.2 + + is-symbol@1.1.1: + dependencies: + call-bound: 1.0.4 + has-symbols: 1.1.0 + safe-regex-test: 1.1.0 + + is-typed-array@1.1.15: + dependencies: + which-typed-array: 1.1.19 + + is-weakmap@2.0.2: {} + + is-weakref@1.1.1: + dependencies: + call-bound: 1.0.4 + + is-weakset@2.0.4: + dependencies: + call-bound: 1.0.4 + get-intrinsic: 1.3.0 + + isarray@2.0.5: {} + isexe@2.0.0: {} + iterator.prototype@1.1.5: + dependencies: + define-data-property: 1.1.4 + es-object-atoms: 1.1.1 + get-intrinsic: 1.3.0 + get-proto: 1.0.1 + has-symbols: 1.1.0 + set-function-name: 2.0.2 + js-cookie@3.0.5: {} js-tokens@4.0.0: {} @@ -2835,6 +4369,10 @@ snapshots: json-stable-stringify-without-jsonify@1.0.1: {} + json5@1.0.2: + dependencies: + minimist: 1.2.8 + json5@2.2.3: {} jsonfile@6.2.0: @@ -2843,6 +4381,13 @@ snapshots: optionalDependencies: graceful-fs: 4.2.11 + jsx-ast-utils@3.3.5: + dependencies: + array-includes: 3.1.9 + array.prototype.flat: 1.3.3 + object.assign: 4.1.7 + object.values: 1.2.1 + katex@0.16.25: dependencies: commander: 8.3.0 @@ -2909,10 +4454,16 @@ snapshots: dependencies: p-locate: 5.0.0 + lodash-es@4.17.21: {} + lodash.merge@4.6.2: {} lodash@4.17.21: {} + loose-envify@1.4.0: + dependencies: + js-tokens: 4.0.0 + lru-cache@5.1.1: dependencies: yallist: 3.1.1 @@ -2921,6 +4472,8 @@ snapshots: dependencies: '@jridgewell/sourcemap-codec': 1.5.5 + math-intrinsics@1.1.0: {} + merge2@1.4.1: {} micromatch@4.0.8: @@ -2936,6 +4489,10 @@ snapshots: dependencies: brace-expansion: 2.0.2 + minimist@1.2.8: {} + + mitt@3.0.1: {} + ms@2.1.3: {} nanoid@3.3.11: {} @@ -2944,6 +4501,52 @@ snapshots: node-releases@2.0.27: {} + nth-check@2.1.1: + dependencies: + boolbase: 1.0.0 + + object-assign@4.1.1: {} + + object-inspect@1.13.4: {} + + object-keys@1.1.1: {} + + object.assign@4.1.7: + dependencies: + call-bind: 1.0.8 + call-bound: 1.0.4 + define-properties: 1.2.1 + es-object-atoms: 1.1.1 + has-symbols: 1.1.0 + object-keys: 1.1.1 + + object.entries@1.1.9: + dependencies: + call-bind: 1.0.8 + call-bound: 1.0.4 + define-properties: 1.2.1 + es-object-atoms: 1.1.1 + + object.fromentries@2.0.8: + dependencies: + call-bind: 1.0.8 + define-properties: 1.2.1 + es-abstract: 1.24.0 + es-object-atoms: 1.1.1 + + object.groupby@1.0.3: + dependencies: + call-bind: 1.0.8 + define-properties: 1.2.1 + es-abstract: 1.24.0 + + object.values@1.2.1: + dependencies: + call-bind: 1.0.8 + call-bound: 1.0.4 + define-properties: 1.2.1 + es-object-atoms: 1.1.1 + optionator@0.9.4: dependencies: deep-is: 0.1.4 @@ -2953,6 +4556,12 @@ snapshots: type-check: 0.4.0 word-wrap: 1.2.5 + own-keys@1.0.1: + dependencies: + get-intrinsic: 1.3.0 + object-keys: 1.1.1 + safe-push-apply: 1.0.0 + p-limit@3.1.0: dependencies: yocto-queue: 0.1.0 @@ -2969,14 +4578,27 @@ snapshots: path-key@3.1.1: {} + path-parse@1.0.7: {} + + path-type@4.0.0: {} + pathe@2.0.3: {} + performance-now@2.1.0: {} + picocolors@1.1.1: {} picomatch@2.3.1: {} picomatch@4.0.3: {} + possible-typed-array-names@1.1.0: {} + + postcss-selector-parser@6.1.2: + dependencies: + cssesc: 3.0.0 + util-deprecate: 1.0.2 + postcss@8.5.6: dependencies: nanoid: 3.3.11 @@ -2985,8 +4607,20 @@ snapshots: prelude-ls@1.2.1: {} + prettier-linter-helpers@1.0.0: + dependencies: + fast-diff: 1.3.0 + + prettier@3.6.2: {} + prismjs@1.30.0: {} + prop-types@15.8.1: + dependencies: + loose-envify: 1.4.0 + object-assign: 4.1.1 + react-is: 16.13.1 + punycode@2.3.1: {} query-string@6.14.1: @@ -2998,6 +4632,10 @@ snapshots: queue-microtask@1.2.3: {} + raf@3.4.1: + dependencies: + performance-now: 2.1.0 + react-device-detect@2.2.3(react-dom@19.2.0(react@19.2.0))(react@19.2.0): dependencies: react: 19.2.0 @@ -3011,6 +4649,10 @@ snapshots: react-fast-compare@3.2.2: {} + react-is@16.13.1: {} + + react-is@18.3.1: {} + react-refresh@0.18.0: {} react-router-dom@7.9.5(react-dom@19.2.0(react@19.2.0))(react@19.2.0): @@ -3027,15 +4669,58 @@ snapshots: optionalDependencies: react-dom: 19.2.0(react@19.2.0) + react-transition-group@4.4.5(react-dom@19.2.0(react@19.2.0))(react@19.2.0): + dependencies: + '@babel/runtime': 7.28.4 + dom-helpers: 5.2.1 + loose-envify: 1.4.0 + prop-types: 15.8.1 + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + react@19.2.0: {} + reflect.getprototypeof@1.0.10: + dependencies: + call-bind: 1.0.8 + define-properties: 1.2.1 + es-abstract: 1.24.0 + es-errors: 1.3.0 + es-object-atoms: 1.1.1 + get-intrinsic: 1.3.0 + get-proto: 1.0.1 + which-builtin-type: 1.2.1 + + regenerator-runtime@0.14.1: {} + + regexp.prototype.flags@1.5.4: + dependencies: + call-bind: 1.0.8 + define-properties: 1.2.1 + es-errors: 1.3.0 + get-proto: 1.0.1 + gopd: 1.2.0 + set-function-name: 2.0.2 + resize-observer-polyfill@1.5.1: {} resolve-from@4.0.0: {} + resolve@1.22.11: + dependencies: + is-core-module: 2.16.1 + path-parse: 1.0.7 + supports-preserve-symlinks-flag: 1.0.0 + + resolve@2.0.0-next.5: + dependencies: + is-core-module: 2.16.1 + path-parse: 1.0.7 + supports-preserve-symlinks-flag: 1.0.0 + reusify@1.1.0: {} - rolldown-vite@7.2.2(esbuild@0.25.12): + rolldown-vite@7.2.2(@types/node@24.10.1)(esbuild@0.25.12): dependencies: '@oxc-project/runtime': 0.96.0 fdir: 6.5.0(picomatch@4.0.3) @@ -3045,6 +4730,7 @@ snapshots: rolldown: 1.0.0-beta.47 tinyglobby: 0.2.15 optionalDependencies: + '@types/node': 24.10.1 esbuild: 0.25.12 fsevents: 2.3.3 @@ -3072,6 +4758,25 @@ snapshots: dependencies: queue-microtask: 1.2.3 + safe-array-concat@1.1.3: + dependencies: + call-bind: 1.0.8 + call-bound: 1.0.4 + get-intrinsic: 1.3.0 + has-symbols: 1.1.0 + isarray: 2.0.5 + + safe-push-apply@1.0.0: + dependencies: + es-errors: 1.3.0 + isarray: 2.0.5 + + safe-regex-test@1.1.0: + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + is-regex: 1.2.1 + scheduler@0.27.0: {} screenfull@5.2.0: {} @@ -3082,6 +4787,28 @@ snapshots: set-cookie-parser@2.7.2: {} + set-function-length@1.2.2: + dependencies: + define-data-property: 1.1.4 + es-errors: 1.3.0 + function-bind: 1.1.2 + get-intrinsic: 1.3.0 + gopd: 1.2.0 + has-property-descriptors: 1.0.2 + + set-function-name@2.0.2: + dependencies: + define-data-property: 1.1.4 + es-errors: 1.3.0 + functions-have-names: 1.2.3 + has-property-descriptors: 1.0.2 + + set-proto@1.0.0: + dependencies: + dunder-proto: 1.0.1 + es-errors: 1.3.0 + es-object-atoms: 1.1.1 + shade-blend-color@1.0.0: {} shebang-command@2.0.0: @@ -3090,8 +4817,40 @@ snapshots: shebang-regex@3.0.0: {} + side-channel-list@1.0.0: + dependencies: + es-errors: 1.3.0 + object-inspect: 1.13.4 + + side-channel-map@1.0.1: + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + get-intrinsic: 1.3.0 + object-inspect: 1.13.4 + + side-channel-weakmap@1.0.2: + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + get-intrinsic: 1.3.0 + object-inspect: 1.13.4 + side-channel-map: 1.0.1 + + side-channel@1.1.0: + dependencies: + es-errors: 1.3.0 + object-inspect: 1.13.4 + side-channel-list: 1.0.0 + side-channel-map: 1.0.1 + side-channel-weakmap: 1.0.2 + siginfo@2.0.0: {} + slash@3.0.0: {} + + sortablejs@1.15.6: {} + source-map-js@1.2.1: {} split-on-first@1.1.0: {} @@ -3100,8 +4859,59 @@ snapshots: std-env@3.10.0: {} + stop-iteration-iterator@1.1.0: + dependencies: + es-errors: 1.3.0 + internal-slot: 1.1.0 + strict-uri-encode@2.0.0: {} + string.prototype.matchall@4.0.12: + dependencies: + call-bind: 1.0.8 + call-bound: 1.0.4 + define-properties: 1.2.1 + es-abstract: 1.24.0 + es-errors: 1.3.0 + es-object-atoms: 1.1.1 + get-intrinsic: 1.3.0 + gopd: 1.2.0 + has-symbols: 1.1.0 + internal-slot: 1.1.0 + regexp.prototype.flags: 1.5.4 + set-function-name: 2.0.2 + side-channel: 1.1.0 + + string.prototype.repeat@1.0.0: + dependencies: + define-properties: 1.2.1 + es-abstract: 1.24.0 + + string.prototype.trim@1.2.10: + dependencies: + call-bind: 1.0.8 + call-bound: 1.0.4 + define-data-property: 1.1.4 + define-properties: 1.2.1 + es-abstract: 1.24.0 + es-object-atoms: 1.1.1 + has-property-descriptors: 1.0.2 + + string.prototype.trimend@1.0.9: + dependencies: + call-bind: 1.0.8 + call-bound: 1.0.4 + define-properties: 1.2.1 + es-object-atoms: 1.1.1 + + string.prototype.trimstart@1.0.8: + dependencies: + call-bind: 1.0.8 + define-properties: 1.2.1 + es-object-atoms: 1.1.1 + + strip-bom@3.0.0: {} + strip-json-comments@3.1.1: {} style-mod@4.1.3: {} @@ -3110,8 +4920,39 @@ snapshots: dependencies: has-flag: 4.0.0 + supports-preserve-symlinks-flag@1.0.0: {} + swiper@12.0.3: {} + tdesign-icons-react@0.6.1(react-dom@19.2.0(react@19.2.0))(react@19.2.0): + dependencies: + '@babel/runtime': 7.28.4 + classnames: 2.5.1 + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + + tdesign-react@1.15.8(react-dom@19.2.0(react@19.2.0))(react@19.2.0): + dependencies: + '@babel/runtime': 7.26.10 + '@popperjs/core': 2.11.8 + '@types/sortablejs': 1.15.9 + '@types/validator': 13.15.8 + classnames: 2.5.1 + dayjs: 1.11.10 + hoist-non-react-statics: 3.3.2 + lodash-es: 4.17.21 + mitt: 3.0.1 + raf: 3.4.1 + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + react-fast-compare: 3.2.2 + react-is: 18.3.1 + react-transition-group: 4.4.5(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + sortablejs: 1.15.6 + tdesign-icons-react: 0.6.1(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + tslib: 2.3.1 + validator: 13.15.23 + tinybench@2.9.0: {} tinyexec@0.3.2: {} @@ -3127,16 +4968,75 @@ snapshots: dependencies: is-number: 7.0.0 + ts-api-utils@1.4.3(typescript@5.9.3): + dependencies: + typescript: 5.9.3 + ts-api-utils@2.1.0(typescript@5.9.3): dependencies: typescript: 5.9.3 + tsconfig-paths@3.15.0: + dependencies: + '@types/json5': 0.0.29 + json5: 1.0.2 + minimist: 1.2.8 + strip-bom: 3.0.0 + + tslib@2.3.1: {} + tslib@2.8.1: {} type-check@0.4.0: dependencies: prelude-ls: 1.2.1 + type-fest@0.20.2: {} + + typed-array-buffer@1.0.3: + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + is-typed-array: 1.1.15 + + typed-array-byte-length@1.0.3: + dependencies: + call-bind: 1.0.8 + for-each: 0.3.5 + gopd: 1.2.0 + has-proto: 1.2.0 + is-typed-array: 1.1.15 + + typed-array-byte-offset@1.0.4: + dependencies: + available-typed-arrays: 1.0.7 + call-bind: 1.0.8 + for-each: 0.3.5 + gopd: 1.2.0 + has-proto: 1.2.0 + is-typed-array: 1.1.15 + reflect.getprototypeof: 1.0.10 + + typed-array-length@1.0.7: + dependencies: + call-bind: 1.0.8 + for-each: 0.3.5 + gopd: 1.2.0 + is-typed-array: 1.1.15 + possible-typed-array-names: 1.1.0 + reflect.getprototypeof: 1.0.10 + + typescript-eslint@7.18.0(eslint@9.39.1)(typescript@5.9.3): + dependencies: + '@typescript-eslint/eslint-plugin': 7.18.0(@typescript-eslint/parser@7.18.0(eslint@9.39.1)(typescript@5.9.3))(eslint@9.39.1)(typescript@5.9.3) + '@typescript-eslint/parser': 7.18.0(eslint@9.39.1)(typescript@5.9.3) + '@typescript-eslint/utils': 7.18.0(eslint@9.39.1)(typescript@5.9.3) + eslint: 9.39.1 + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color + typescript-eslint@8.46.4(eslint@9.39.1)(typescript@5.9.3): dependencies: '@typescript-eslint/eslint-plugin': 8.46.4(@typescript-eslint/parser@8.46.4(eslint@9.39.1)(typescript@5.9.3))(eslint@9.39.1)(typescript@5.9.3) @@ -3152,6 +5052,16 @@ snapshots: ua-parser-js@1.0.41: {} + unbox-primitive@1.1.0: + dependencies: + call-bound: 1.0.4 + has-bigints: 1.1.0 + has-symbols: 1.1.0 + which-boxed-primitive: 1.1.1 + + undici-types@7.16.0: + optional: true + universalify@2.0.1: {} update-browserslist-db@1.1.4(browserslist@4.28.0): @@ -3164,26 +5074,30 @@ snapshots: dependencies: punycode: 2.3.1 - vite-plugin-babel@1.3.2(@babel/core@7.28.5)(rolldown-vite@7.2.2(esbuild@0.25.12)): + util-deprecate@1.0.2: {} + + validator@13.15.23: {} + + vite-plugin-babel@1.3.2(@babel/core@7.28.5)(rolldown-vite@7.2.2(@types/node@24.10.1)(esbuild@0.25.12)): dependencies: '@babel/core': 7.28.5 - vite: rolldown-vite@7.2.2(esbuild@0.25.12) + vite: rolldown-vite@7.2.2(@types/node@24.10.1)(esbuild@0.25.12) - vite-plugin-compression@0.5.1(rolldown-vite@7.2.2(esbuild@0.25.12)): + vite-plugin-compression@0.5.1(rolldown-vite@7.2.2(@types/node@24.10.1)(esbuild@0.25.12)): dependencies: chalk: 4.1.2 debug: 4.4.3 fs-extra: 10.1.0 - vite: rolldown-vite@7.2.2(esbuild@0.25.12) + vite: rolldown-vite@7.2.2(@types/node@24.10.1)(esbuild@0.25.12) transitivePeerDependencies: - supports-color vite-plugin-remove-console@2.2.0: {} - vitest@4.0.8(esbuild@0.25.12): + vitest@4.0.8(@types/node@24.10.1)(esbuild@0.25.12): dependencies: '@vitest/expect': 4.0.8 - '@vitest/mocker': 4.0.8(rolldown-vite@7.2.2(esbuild@0.25.12)) + '@vitest/mocker': 4.0.8(rolldown-vite@7.2.2(@types/node@24.10.1)(esbuild@0.25.12)) '@vitest/pretty-format': 4.0.8 '@vitest/runner': 4.0.8 '@vitest/snapshot': 4.0.8 @@ -3200,8 +5114,10 @@ snapshots: tinyexec: 0.3.2 tinyglobby: 0.2.15 tinyrainbow: 3.0.3 - vite: rolldown-vite@7.2.2(esbuild@0.25.12) + vite: rolldown-vite@7.2.2(@types/node@24.10.1)(esbuild@0.25.12) why-is-node-running: 2.3.0 + optionalDependencies: + '@types/node': 24.10.1 transitivePeerDependencies: - esbuild - jiti @@ -3216,8 +5132,62 @@ snapshots: - tsx - yaml + vue-eslint-parser@9.4.3(eslint@9.39.1): + dependencies: + debug: 4.4.3 + eslint: 9.39.1 + eslint-scope: 7.2.2 + eslint-visitor-keys: 3.4.3 + espree: 9.6.1 + esquery: 1.6.0 + lodash: 4.17.21 + semver: 7.7.3 + transitivePeerDependencies: + - supports-color + w3c-keyname@2.2.8: {} + which-boxed-primitive@1.1.1: + dependencies: + is-bigint: 1.1.0 + is-boolean-object: 1.2.2 + is-number-object: 1.1.1 + is-string: 1.1.1 + is-symbol: 1.1.1 + + which-builtin-type@1.2.1: + dependencies: + call-bound: 1.0.4 + function.prototype.name: 1.1.8 + has-tostringtag: 1.0.2 + is-async-function: 2.1.1 + is-date-object: 1.1.0 + is-finalizationregistry: 1.1.1 + is-generator-function: 1.1.2 + is-regex: 1.2.1 + is-weakref: 1.1.1 + isarray: 2.0.5 + which-boxed-primitive: 1.1.1 + which-collection: 1.0.2 + which-typed-array: 1.1.19 + + which-collection@1.0.2: + dependencies: + is-map: 2.0.3 + is-set: 2.0.3 + is-weakmap: 2.0.2 + is-weakset: 2.0.4 + + which-typed-array@1.1.19: + dependencies: + available-typed-arrays: 1.0.7 + call-bind: 1.0.8 + call-bound: 1.0.4 + for-each: 0.3.5 + get-proto: 1.0.1 + gopd: 1.2.0 + has-tostringtag: 1.0.2 + which@2.0.2: dependencies: isexe: 2.0.0 @@ -3229,6 +5199,8 @@ snapshots: word-wrap@1.2.5: {} + xml-name-validator@4.0.0: {} + yallist@3.1.1: {} yocto-queue@0.1.0: {} diff --git a/public/blogroll.json b/public/blogroll.json index 511db24..a90da54 100644 --- a/public/blogroll.json +++ b/public/blogroll.json @@ -7,4 +7,4 @@ "alt": "HairlessVillager's Blog", "url": "https://hlsvillager.icu/" } -] \ No newline at end of file +] diff --git a/src/actions/blogger.e2e.test.ts b/src/actions/blogger.e2e.test.ts index 15f7e3d..bfe6970 100644 --- a/src/actions/blogger.e2e.test.ts +++ b/src/actions/blogger.e2e.test.ts @@ -10,125 +10,145 @@ import { const E2E_TEST_TIMEOUT = 15000; // 15 seconds // A simple separator for cleaner console output between tests -const logSeparator = () => console.log('\n' + '='.repeat(50) + '\n'); +const logSeparator = () => console.log(`\n${'='.repeat(50)}\n`); describe('Blogger API Service - E2E Live Tests with Output', () => { - // This hook will run once after all tests in this file have completed. afterAll(() => { logSeparator(); - console.log("E2E tests for blogger.service.ts completed."); + console.log('E2E tests for blogger.service.ts completed.'); }); describe('getPostList', () => { - it('should fetch a real list of posts and print the result', { timeout: E2E_TEST_TIMEOUT }, async () => { - logSeparator(); - console.log("🚀 Testing: getPostList({ 'start-index': 1, 'max-results': 2 })"); - - const params = { 'start-index': 1, 'max-results': 2 }; - const result = await getPostList(params); - - // Print the Zod-parsed result to the console - console.log("✅ Response received and parsed successfully:"); - console.log(JSON.stringify(result, null, 2)); - - // Assertions to ensure the test is still valid - expect(result.feed).toBeDefined(); - expect(typeof result.feed['openSearch$totalResults']).toBe('number'); - expect(result.feed.entry).toBeInstanceOf(Array); - expect(result.feed.entry.length).toBeLessThanOrEqual(params['max-results']); - }); - - it('should fetch posts within a date range and print the result', { timeout: E2E_TEST_TIMEOUT }, async () => { - logSeparator(); - const params = { - 'start-index': 1, - 'max-results': 3, - 'published-min': '2024-03-16T00:00:00', - 'published-max': '2024-09-24T23:59:59', - }; - console.log(`🚀 Testing: getPostList with date range`, params); - - const result = await getPostList(params); - - console.log("✅ Response received and parsed successfully:"); - console.log(JSON.stringify(result, null, 2)); - - expect(result.feed.entry.length).toBeGreaterThan(0); - result.feed.entry.forEach(post => { - expect(post.published.getTime()).toBeGreaterThanOrEqual(new Date(params['published-min']).getTime()); - expect(post.published.getTime()).toBeLessThanOrEqual(new Date(params['published-max']).getTime()); - }); - }); + it( + 'should fetch a real list of posts and print the result', + { timeout: E2E_TEST_TIMEOUT }, + async () => { + logSeparator(); + console.log('🚀 Testing: getPostList({ \'start-index\': 1, \'max-results\': 2 })'); + + const params = { 'start-index': 1, 'max-results': 2 }; + const result = await getPostList(params); + + // Print the Zod-parsed result to the console + console.log('✅ Response received and parsed successfully:'); + console.log(JSON.stringify(result, null, 2)); + + // Assertions to ensure the test is still valid + expect(result.feed).toBeDefined(); + expect(typeof result.feed.openSearch$totalResults).toBe('number'); + expect(result.feed.entry).toBeInstanceOf(Array); + expect(result.feed.entry.length).toBeLessThanOrEqual(params['max-results']); + }, + ); + + it( + 'should fetch posts within a date range and print the result', + { timeout: E2E_TEST_TIMEOUT }, + async () => { + logSeparator(); + const params = { + 'start-index': 1, + 'max-results': 3, + 'published-min': '2024-03-16T00:00:00', + 'published-max': '2024-09-24T23:59:59', + }; + console.log('🚀 Testing: getPostList with date range', params); + + const result = await getPostList(params); + + console.log('✅ Response received and parsed successfully:'); + console.log(JSON.stringify(result, null, 2)); + + expect(result.feed.entry.length).toBeGreaterThan(0); + result.feed.entry.forEach((post) => { + expect(post.published.getTime()).toBeGreaterThanOrEqual(new Date(params['published-min']).getTime()); + expect(post.published.getTime()).toBeLessThanOrEqual(new Date(params['published-max']).getTime()); + }); + }, + ); }); describe('getPostContent', () => { - it('should fetch the real content for a specific post and print the result', { timeout: E2E_TEST_TIMEOUT }, async () => { - const path = '/2025/06/stackedit.html'; - logSeparator(); - console.log(`🚀 Testing: getPostContent({ path: "${path}" })`); - - const result = await getPostContent({ path }); - - console.log("✅ Response received and parsed successfully:"); - console.log(JSON.stringify(result, null, 2)); - - expect(result.feed.entry).toHaveLength(1); - const post = result.feed.entry[0]; - expect(post.title.$t).toContain('StackEdit'); - }); + it( + 'should fetch the real content for a specific post and print the result', + { timeout: E2E_TEST_TIMEOUT }, + async () => { + const path = '/2025/06/stackedit.html'; + logSeparator(); + console.log(`🚀 Testing: getPostContent({ path: "${path}" })`); + + const result = await getPostContent({ path }); + + console.log('✅ Response received and parsed successfully:'); + console.log(JSON.stringify(result, null, 2)); + + expect(result.feed.entry).toHaveLength(1); + const post = result.feed.entry[0]; + expect(post.title.$t).toContain('StackEdit'); + }, + ); }); describe('getPageList', () => { - it('should fetch a real list of pages and print the result', { timeout: E2E_TEST_TIMEOUT }, async () => { - const params = { 'start-index': 1, 'max-results': 2 }; - logSeparator(); - console.log(`🚀 Testing: getPageList(${JSON.stringify(params)})`); - - const result = await getPageList(params); - - console.log("✅ Response received and parsed successfully:"); - console.log(JSON.stringify(result, null, 2)); - - expect(result.feed).toBeDefined(); - expect(result.feed.entry.length).toBeLessThanOrEqual(params['max-results']); - }); + it( + 'should fetch a real list of pages and print the result', + { timeout: E2E_TEST_TIMEOUT }, + async () => { + const params = { 'start-index': 1, 'max-results': 2 }; + logSeparator(); + console.log(`🚀 Testing: getPageList(${JSON.stringify(params)})`); + + const result = await getPageList(params); + + console.log('✅ Response received and parsed successfully:'); + console.log(JSON.stringify(result, null, 2)); + + expect(result.feed).toBeDefined(); + expect(result.feed.entry.length).toBeLessThanOrEqual(params['max-results']); + }, + ); }); describe('getPostListByCategories', () => { - it('should fetch posts by category and print the result', { timeout: E2E_TEST_TIMEOUT }, async () => { - const category = '学习笔记-rust'; - logSeparator(); - console.log(`🚀 Testing: getPostListByCategories(["${category}"])`); - - const result = await getPostListByCategories([category]); - - console.log("✅ Response received and parsed successfully:"); - console.log(JSON.stringify(result, null, 2)); - - expect(result.feed.entry.length).toBeGreaterThan(0); - const hasCategory = result.feed.entry.some(post => - post.category?.some(cat => cat.term === category) - ); - expect(hasCategory).toBe(true); - }); + it( + 'should fetch posts by category and print the result', + { timeout: E2E_TEST_TIMEOUT }, + async () => { + const category = '学习笔记-rust'; + logSeparator(); + console.log(`🚀 Testing: getPostListByCategories(["${category}"])`); + + const result = await getPostListByCategories([category]); + + console.log('✅ Response received and parsed successfully:'); + console.log(JSON.stringify(result, null, 2)); + + expect(result.feed.entry.length).toBeGreaterThan(0); + const hasCategory = result.feed.entry.some(post => post.category?.some(cat => cat.term === category)); + expect(hasCategory).toBe(true); + }, + ); }); describe('getAllTags', () => { - it('should efficiently fetch all blog tags and print the result', { timeout: E2E_TEST_TIMEOUT }, async () => { - logSeparator(); - console.log(`🚀 Testing: getAllTags()`); - - const result = await getAllTags(); - - console.log("✅ Response received and parsed successfully (tags array):"); - console.log(JSON.stringify(result, null, 2)); - - expect(result).toBeInstanceOf(Array); - expect(result.length).toBeGreaterThan(10); - const terms = result.map(cat => cat.term); - expect(terms).toContain('杂谈'); - }); + it( + 'should efficiently fetch all blog tags and print the result', + { timeout: E2E_TEST_TIMEOUT }, + async () => { + logSeparator(); + console.log('🚀 Testing: getAllTags()'); + + const result = await getAllTags(); + + console.log('✅ Response received and parsed successfully (tags array):'); + console.log(JSON.stringify(result, null, 2)); + + expect(result).toBeInstanceOf(Array); + expect(result.length).toBeGreaterThan(10); + const terms = result.map(cat => cat.term); + expect(terms).toContain('杂谈'); + }, + ); }); - -}); \ No newline at end of file +}); diff --git a/src/actions/blogger.service.ts b/src/actions/blogger.service.ts index c657a5b..195fd6e 100644 --- a/src/actions/blogger.service.ts +++ b/src/actions/blogger.service.ts @@ -1,5 +1,5 @@ import { z } from 'zod'; -import { BLOG_URL, API_TIMEOUT } from '../constants/feedapi'; +import { BLOG_BASE, API_TIMEOUT } from '../constants/feedapi'; import { PostListResponseSchema, PageListResponseSchema, @@ -59,7 +59,7 @@ async function fetchBloggerApi(url: string): Promise { */ function createFeedApiMethod< TParams extends object, // <-- BUG FIX: Changed constraint to `object` - TSchema extends z.ZodTypeAny + TSchema extends z.ZodTypeAny, >(requestPath: string, schema: TSchema) { /** * The generated async function. @@ -75,14 +75,17 @@ function createFeedApiMethod< } } - const url = `${BLOG_URL}${requestPath}?alt=json&${searchParams.toString()}`; + const url = `${BLOG_BASE}${requestPath}?alt=json&${searchParams.toString()}`; const rawJson = await fetchBloggerApi(url); const validationResult = schema.safeParse(rawJson); if (!validationResult.success) { - console.error(`Zod validation failed for path: ${requestPath}`, validationResult.error.issues); + console.error( + `Zod validation failed for path: ${requestPath}`, + validationResult.error.issues, + ); throw new Error(`API response validation failed for path: ${requestPath}`); } @@ -95,7 +98,6 @@ function createFeedApiMethod< // The implementation now works without lint errors. // ================================================================================= - /** * Parameter interface for the `getPostList` function. * This interface now includes all supported query parameters for fetching post lists. @@ -124,10 +126,10 @@ export interface GetPostListParams { * Fetches a paginated list of post summaries. * The response is validated against `PostListResponseSchema`. */ -export const getPostList = createFeedApiMethod( - '/feeds/posts/summary', - PostListResponseSchema -); +export const getPostList = createFeedApiMethod< +GetPostListParams, + typeof PostListResponseSchema +>('/feeds/posts/summary', PostListResponseSchema); /** * Fetches a list of post summaries filtered by one or more categories (tags). @@ -137,10 +139,10 @@ export const getPostList = createFeedApiMethod { if (categories.length === 0) { - throw new Error("getPostListByCategories requires at least one category."); + throw new Error('getPostListByCategories requires at least one category.'); } // Blogger API uses slash-separated values in the path for category filtering. @@ -148,10 +150,10 @@ export async function getPostListByCategories( const requestPath = `/feeds/posts/summary/-/${categoryPath}`; // Use the existing factory to create a one-off request function. - const fetcher = createFeedApiMethod( - requestPath, - PostListResponseSchema - ); + const fetcher = createFeedApiMethod< + typeof options, + typeof PostListResponseSchema + >(requestPath, PostListResponseSchema); return fetcher(options); } @@ -168,10 +170,10 @@ export interface GetPageListParams { * Fetches a paginated list of page summaries. * The response is validated against `PageListResponseSchema`. */ -export const getPageList = createFeedApiMethod( - '/feeds/pages/summary', - PageListResponseSchema -); +export const getPageList = createFeedApiMethod< +GetPageListParams, + typeof PageListResponseSchema +>('/feeds/pages/summary', PageListResponseSchema); /** * Parameter interface for content-fetching functions. @@ -184,20 +186,19 @@ export interface GetContentByPathParams { * Fetches the full content of a single blog post by its URL path. * The response is validated against `PostContentResponseSchema`. */ -export const getPostContent = createFeedApiMethod( - '/feeds/posts/default', - PostContentResponseSchema -); +export const getPostContent = createFeedApiMethod< +GetContentByPathParams, + typeof PostContentResponseSchema +>('/feeds/posts/default', PostContentResponseSchema); /** * Fetches the full content of a single page by its URL path. * The response is validated against `PageContentResponseSchema`. */ -export const getPageContent = createFeedApiMethod( - '/feeds/pages/default', - PageContentResponseSchema -); - +export const getPageContent = createFeedApiMethod< +GetContentByPathParams, + typeof PageContentResponseSchema +>('/feeds/pages/default', PageContentResponseSchema); /** * Fetches all unique tags/labels used in the blog. @@ -222,4 +223,4 @@ export async function getAllTags(): Promise { // The Zod schema for PostListResponse now validates `feed.category`, // so we can safely access and return it. return response.feed.category; -} \ No newline at end of file +} diff --git a/src/actions/blogger.test.ts b/src/actions/blogger.test.ts index 106c538..25cbc46 100644 --- a/src/actions/blogger.test.ts +++ b/src/actions/blogger.test.ts @@ -12,7 +12,7 @@ import { PostContentResponseSchema, PageListResponseSchema, } from './blogger.types'; -import { BLOG_URL } from '../constants/feedapi'; +import { BLOG_BASE } from '../constants/feedapi'; // We still mock the global `fetch` function. const fetchSpy = vi.spyOn(globalThis, 'fetch'); @@ -34,7 +34,6 @@ const createMockApiResponse = (data: any): Response => { }); }; - describe('Blogger API Service - Structural Tests', () => { beforeEach(() => { // Reset mocks before each test to ensure isolation. @@ -46,7 +45,7 @@ describe('Blogger API Service - Structural Tests', () => { // Setup: Create a minimal mock structure that satisfies the schema. const mockResponse = { feed: { - 'openSearch$totalResults': { $t: '123' }, + openSearch$totalResults: { $t: '123' }, entry: [ { id: { $t: 'post-id-1' }, @@ -54,7 +53,13 @@ describe('Blogger API Service - Structural Tests', () => { updated: { $t: new Date().toISOString() }, title: { $t: 'Test Post' }, summary: { $t: 'This is a summary.' }, - link: [{ rel: 'alternate', type: 'text/html', href: 'http://example.com/post' }], + link: [ + { + rel: 'alternate', + type: 'text/html', + href: 'http://example.com/post', + }, + ], author: [{ name: { $t: 'Test Author' } }], category: [{ term: 'Test Tag' }], }, @@ -68,7 +73,7 @@ describe('Blogger API Service - Structural Tests', () => { const result = await getPostList({ 'start-index': 1, 'max-results': 1 }); // Assert: Verify the fetch call and the structure of the result. - const expectedUrl = `${BLOG_URL}/feeds/posts/summary?alt=json&start-index=1&max-results=1`; + const expectedUrl = `${BLOG_BASE}/feeds/posts/summary?alt=json&start-index=1&max-results=1`; expect(fetchSpy).toHaveBeenCalledWith(expectedUrl, expect.anything()); // Use Zod's `safeParse` to verify the structure. `success` should be true. @@ -76,7 +81,7 @@ describe('Blogger API Service - Structural Tests', () => { // Assert on the parsed result from our function. expect(result.feed).toBeDefined(); - expect(typeof result.feed['openSearch$totalResults']).toBe('number'); + expect(typeof result.feed.openSearch$totalResults).toBe('number'); expect(Array.isArray(result.feed.entry)).toBe(true); expect(result.feed.entry.length).toBeGreaterThanOrEqual(0); expect(result.feed.entry[0]?.title.$t).toBe('Test Post'); @@ -97,7 +102,13 @@ describe('Blogger API Service - Structural Tests', () => { updated: { $t: new Date().toISOString() }, title: { $t: 'Test Post Full Content' }, content: { $t: '

This is the full content.

' }, - link: [{ rel: 'alternate', type: 'text/html', href: 'http://example.com/post' }], + link: [ + { + rel: 'alternate', + type: 'text/html', + href: 'http://example.com/post', + }, + ], author: [{ name: { $t: 'Test Author' } }], category: [{ term: 'Test Tag' }], }, @@ -110,7 +121,7 @@ describe('Blogger API Service - Structural Tests', () => { const result = await getPostContent({ path: '/test-post.html' }); // Assert - const expectedUrl = `${BLOG_URL}/feeds/posts/default?alt=json&path=%2Ftest-post.html`; + const expectedUrl = `${BLOG_BASE}/feeds/posts/default?alt=json&path=%2Ftest-post.html`; expect(fetchSpy).toHaveBeenCalledWith(expectedUrl, expect.anything()); expect(PostContentResponseSchema.safeParse(mockResponse).success).toBe(true); @@ -128,7 +139,7 @@ describe('Blogger API Service - Structural Tests', () => { // Setup const mockResponse = { feed: { - 'openSearch$totalResults': { $t: '5' }, + openSearch$totalResults: { $t: '5' }, entry: [ { id: { $t: 'page-id-1' }, @@ -136,7 +147,13 @@ describe('Blogger API Service - Structural Tests', () => { updated: { $t: new Date().toISOString() }, title: { $t: 'Test Page' }, summary: { $t: 'This is a page summary.' }, - link: [{ rel: 'alternate', type: 'text/html', href: 'http://example.com/page' }], + link: [ + { + rel: 'alternate', + type: 'text/html', + href: 'http://example.com/page', + }, + ], author: [{ name: { $t: 'Test Author' } }], }, ], @@ -149,7 +166,7 @@ describe('Blogger API Service - Structural Tests', () => { const result = await getPageList({ 'start-index': 1, 'max-results': 5 }); // Assert - const expectedUrl = `${BLOG_URL}/feeds/pages/summary?alt=json&start-index=1&max-results=5`; + const expectedUrl = `${BLOG_BASE}/feeds/pages/summary?alt=json&start-index=1&max-results=5`; expect(fetchSpy).toHaveBeenCalledWith(expectedUrl, expect.anything()); expect(PageListResponseSchema.safeParse(mockResponse).success).toBe(true); @@ -164,15 +181,17 @@ describe('Blogger API Service - Structural Tests', () => { describe('getPostListByCategories', () => { it('should call fetch with a correctly formatted category path', async () => { // Setup: The response structure is the same as getPostList. - const mockResponse = { feed: { 'openSearch$totalResults': { $t: '1' }, entry: [], category: [] } }; + const mockResponse = { + feed: { openSearch$totalResults: { $t: '1' }, entry: [], category: [] }, + }; fetchSpy.mockResolvedValue(createMockApiResponse(mockResponse)); // Act await getPostListByCategories(['Tag One', 'Tag Two']); // Assert - const expectedPath = encodeURIComponent('Tag One') + '/' + encodeURIComponent('Tag Two'); - const expectedUrl = `${BLOG_URL}/feeds/posts/summary/-/${expectedPath}?alt=json&`; + const expectedPath = `${encodeURIComponent('Tag One')}/${encodeURIComponent('Tag Two')}`; + const expectedUrl = `${BLOG_BASE}/feeds/posts/summary/-/${expectedPath}?alt=json&`; expect(fetchSpy).toHaveBeenCalledWith(expectedUrl, expect.anything()); }); }); @@ -182,7 +201,7 @@ describe('Blogger API Service - Structural Tests', () => { // Setup const mockResponse = { feed: { - 'openSearch$totalResults': { $t: '123' }, + openSearch$totalResults: { $t: '123' }, entry: [], // The important part: entry is empty. category: [{ term: 'Global Tag 1' }, { term: 'Global Tag 2' }], }, @@ -193,7 +212,7 @@ describe('Blogger API Service - Structural Tests', () => { const result = await getAllTags(); // Assert - const expectedUrl = `${BLOG_URL}/feeds/posts/summary?alt=json&start-index=1&max-results=0`; + const expectedUrl = `${BLOG_BASE}/feeds/posts/summary?alt=json&start-index=1&max-results=0`; expect(fetchSpy).toHaveBeenCalledWith(expectedUrl, expect.anything()); // The result should be the category array itself, not the whole response. @@ -202,4 +221,4 @@ describe('Blogger API Service - Structural Tests', () => { expect(result[1].term).toBe('Global Tag 2'); }); }); -}); \ No newline at end of file +}); diff --git a/src/actions/blogger.types.ts b/src/actions/blogger.types.ts index f0c82c3..1093683 100644 --- a/src/actions/blogger.types.ts +++ b/src/actions/blogger.types.ts @@ -38,7 +38,6 @@ const CategorySchema = z.object({ term: z.string(), }); - // ================================================================================= // 2. ENTRY SCHEMAS (Schemas for individual posts or pages) // ================================================================================= @@ -49,8 +48,8 @@ const CategorySchema = z.object({ */ const BaseEntrySchema = z.object({ id: TValueSchema, - published: TValueSchema.transform((val) => new Date(val.$t)), - updated: TValueSchema.transform((val) => new Date(val.$t)), + published: TValueSchema.transform(val => new Date(val.$t)), + updated: TValueSchema.transform(val => new Date(val.$t)), title: TValueSchema, link: z.array(LinkSchema), author: z.array(AuthorSchema), @@ -90,7 +89,6 @@ export const PageContentEntrySchema = BaseEntrySchema.extend({ content: TValueSchema, }); - // ================================================================================= // 3. TOP-LEVEL RESPONSE SCHEMAS (Schemas for the entire API response object) // ================================================================================= @@ -100,25 +98,26 @@ export const PageContentEntrySchema = BaseEntrySchema.extend({ * It expects a `feed` object containing an array of entries and total result count. * @param entrySchema The Zod schema for the individual entries in the list. */ -const createListFeedSchema = (entrySchema: T) => - z.object({ - feed: z.object({ - entry: z.array(entrySchema).optional().default([]), // Use .default([]) to handle cases with 0 entries gracefully - 'openSearch$totalResults': TValueSchema.transform((val) => parseInt(val.$t, 10)), - }), - }); +const createListFeedSchema = (entrySchema: T) => z.object({ + feed: z.object({ + entry: z.array(entrySchema).optional() + .default([]), // Use .default([]) to handle cases with 0 entries gracefully + openSearch$totalResults: TValueSchema.transform(val => parseInt(val.$t, 10)), + }), +}); /** * A generic factory function to create a Zod schema for detail-based API responses (e.g., single post/page content). * It expects the `entry` array to contain exactly one item. * @param entrySchema The Zod schema for the single entry. */ -const createDetailFeedSchema = (entrySchema: T) => - z.object({ - feed: z.object({ - entry: z.array(entrySchema).length(1, { message: "Expected exactly one entry in the feed." }), - }), - }); +const createDetailFeedSchema = (entrySchema: T) => z.object({ + feed: z.object({ + entry: z + .array(entrySchema) + .length(1, { message: 'Expected exactly one entry in the feed.' }), + }), +}); /** * Zod schema for the response of the "get post list" API endpoint. @@ -127,10 +126,12 @@ const createDetailFeedSchema = (entrySchema: T) => */ export const PostListResponseSchema = z.object({ feed: z.object({ - entry: z.array(PostSummaryEntrySchema).optional().default([]), - 'openSearch$totalResults': TValueSchema.transform((val) => parseInt(val.$t, 10)), + entry: z.array(PostSummaryEntrySchema).optional() + .default([]), + openSearch$totalResults: TValueSchema.transform(val => parseInt(val.$t, 10)), // Add the blog-wide category list here - category: z.array(CategorySchema).optional().default([]), + category: z.array(CategorySchema).optional() + .default([]), }), }); @@ -155,11 +156,11 @@ export const PageContentResponseSchema = createDetailFeedSchema(PageContentEntry */ export const AllTagsResponseSchema = z.object({ feed: z.object({ - category: z.array(CategorySchema).optional().default([]), + category: z.array(CategorySchema).optional() + .default([]), }), }); - // ================================================================================= // 4. INFERRED TYPESCRIPT TYPES // These types are automatically generated from the Zod schemas above, ensuring @@ -186,4 +187,4 @@ export type PageContentResponse = z.infer; * This type now represents the full response from which we extract tags. * The actual result of our `getAllTags` function will be `Category[]`. */ -export type AllTagsResponse = z.infer; \ No newline at end of file +export type AllTagsResponse = z.infer; diff --git a/src/components/ThemeToggle.tsx b/src/components/ThemeToggle.tsx index 750ee4d..49b41a9 100644 --- a/src/components/ThemeToggle.tsx +++ b/src/components/ThemeToggle.tsx @@ -1,52 +1,50 @@ -import React from "react"; -import useTheme from "../hooks/useTheme"; +import React from 'react'; +import useTheme from '../hooks/useTheme'; const ThemeToggle: React.FC = () => { const { theme, themeMode, toggleTheme } = useTheme({ - localStorageKey: "theme", + localStorageKey: 'theme', }); // 获取滑块位置 - 使用calc确保不超出边界 - const getSliderPosition = () => { - return themeMode === "light" ? "2px" : "calc(100% - 26px)"; - }; + const getSliderPosition = () => (themeMode === 'light' ? '2px' : 'calc(100% - 26px)'); const containerStyles: React.CSSProperties = { - position: "relative", - width: "50px", - height: "28px", - backgroundColor: theme === "dark" ? "#333" : "#ddd", - borderRadius: "14px", - cursor: "pointer", - transition: "background-color 0.3s ease", - border: "1px solid var(--border-color)", + position: 'relative', + width: '50px', + height: '28px', + backgroundColor: theme === 'dark' ? '#333' : '#ddd', + borderRadius: '14px', + cursor: 'pointer', + transition: 'background-color 0.3s ease', + border: '1px solid var(--border-color)', }; const sliderStyles: React.CSSProperties = { - position: "absolute", - top: "2px", + position: 'absolute', + top: '2px', left: getSliderPosition(), - width: "24px", - height: "24px", - backgroundColor: theme === "dark" ? "#222" : "#fff", - borderRadius: "50%", - transition: "all 0.3s ease", - display: "flex", - alignItems: "center", - justifyContent: "center", - boxShadow: "0 2px 4px rgba(0, 0, 0, 0.2)", + width: '24px', + height: '24px', + backgroundColor: theme === 'dark' ? '#222' : '#fff', + borderRadius: '50%', + transition: 'all 0.3s ease', + display: 'flex', + alignItems: 'center', + justifyContent: 'center', + boxShadow: '0 2px 4px rgba(0, 0, 0, 0.2)', }; const iconStyles: React.CSSProperties = { - width: "14px", - height: "14px", - fill: theme === "dark" ? "#fff" : "#666", - transition: "fill 0.3s ease", + width: '14px', + height: '14px', + fill: theme === 'dark' ? '#fff' : '#666', + transition: 'fill 0.3s ease', }; // 根据当前主题显示不同的图标 const renderContent = () => { - if (theme === "dark") { + if (theme === 'dark') { // 月亮图标 return ( { ); - } else { - // 太阳图标 - return ( + } + // 太阳图标 + return ( { > - ); - } + ); }; - const getTooltipText = () => { - return themeMode === "dark" ? "Dark Mode" : "Light Mode"; - }; + const getTooltipText = () => (themeMode === 'dark' ? 'Dark Mode' : 'Light Mode'); return (
{ role="button" tabIndex={0} onKeyDown={(e) => { - if (e.key === "Enter" || e.key === " ") { + if (e.key === 'Enter' || e.key === ' ') { e.preventDefault(); toggleTheme(); } diff --git a/src/components/archives/DateFilter.tsx b/src/components/archives/DateFilter.tsx index cb61e86..623744b 100644 --- a/src/components/archives/DateFilter.tsx +++ b/src/components/archives/DateFilter.tsx @@ -3,7 +3,6 @@ import { isMobile } from 'react-device-detect'; import { useSetState, useMemoizedFn } from 'ahooks'; import { getCurrentTheme } from '../../constants/colors'; import PostCacheManager from '../../utils/postCache'; -import type { PostItem } from '../../models/PostItem'; interface DateFilterProps { onDateSearch: (year: number, month: number) => void; @@ -17,24 +16,25 @@ export interface DateFilterRef { updateCacheDisplay: () => Promise; } -// 暴露给外部的缓存操作方法 -export const saveCacheForDate = async (year: number, month: number, posts: PostItem[]) => { - await PostCacheManager.saveCache(year, month, posts); -}; -const DateFilter = forwardRef(({ - onDateSearch, - onRefreshRequest, - showRefreshButton = false, - initialYear, - initialMonth -}, ref) => { +const DateFilter = forwardRef(( + { + onDateSearch, + onRefreshRequest, + showRefreshButton = false, + initialYear, + initialMonth, + }, + ref, +) => { const colors = getCurrentTheme(); const [dateState, setDateState] = useSetState({ selectedYear: initialYear || new Date().getFullYear(), - selectedMonth: initialMonth || new Date().getMonth() + 1 + selectedMonth: initialMonth || new Date().getMonth() + 1, }); - const [cachedCounts, setCachedCounts] = useSetState>>({}); + const [cachedCounts, setCachedCounts] = useSetState< + Record> + >({}); // 初始化缓存管理器和加载缓存统计 useEffect(() => { @@ -61,12 +61,16 @@ const DateFilter = forwardRef(({ }, [initialYear, initialMonth, dateState, onDateSearch]); // 暴露方法给父组件 - useImperativeHandle(ref, () => ({ - updateCacheDisplay: async () => { - const counts = await PostCacheManager.getCachedDateCounts(); - setCachedCounts(counts); - } - }), []); + useImperativeHandle( + ref, + () => ({ + updateCacheDisplay: async () => { + const counts = await PostCacheManager.getCachedDateCounts(); + setCachedCounts(counts); + }, + }), + [], + ); const handleSearch = useMemoizedFn(() => { const { selectedYear, selectedMonth } = dateState; @@ -102,7 +106,10 @@ const DateFilter = forwardRef(({ return { value: month, - label: cachedCount !== undefined ? `${month}月 (${cachedCount})` : `${month}月` + label: + cachedCount !== undefined + ? `${month}月 (${cachedCount})` + : `${month}月`, }; }); @@ -234,11 +241,11 @@ const DateFilter = forwardRef(({ {showRefreshButton && (
diff --git a/src/components/archives/ResultsDisplay.tsx b/src/components/archives/ResultsDisplay.tsx index 79ae57d..26d493b 100644 --- a/src/components/archives/ResultsDisplay.tsx +++ b/src/components/archives/ResultsDisplay.tsx @@ -2,15 +2,17 @@ import React, { useRef } from 'react'; import { isMobile } from 'react-device-detect'; import { useMemoizedFn } from 'ahooks'; import { getCurrentTheme } from '../../constants/colors'; - +import type { JSX } from 'react/jsx-runtime'; import { type PostItem } from '../../models/PostItem'; import { useNavigate } from 'react-router-dom'; interface ResultsDisplayProps { - data: { + data: + | { list: PostItem[]; nextId?: string; - } | undefined; + } + | undefined; loading: boolean; loadingMore: boolean; noMore: boolean; @@ -23,9 +25,9 @@ export default function ResultsDisplay({ loading, loadingMore, noMore, - emptyMessage = "暂无文章", - scrollContainerRef -}: ResultsDisplayProps) { + emptyMessage = '暂无文章', + scrollContainerRef, +}: ResultsDisplayProps): JSX.Element { const colors = getCurrentTheme(); const ref = useRef(null); const navigate = useNavigate(); @@ -56,9 +58,7 @@ export default function ResultsDisplay({ ))} {tags.length > 3 && ( - - +{tags.length - 3} - + +{tags.length - 3} )} ); @@ -149,8 +149,16 @@ export default function ResultsDisplay({ const tagStyles = (index: number): React.CSSProperties => { const tagColors = [ - '#007bff', '#28a745', '#dc3545', '#ffc107', '#17a2b8', - '#6f42c1', '#e83e8c', '#fd7e14', '#20c997', '#6c757d' + '#007bff', + '#28a745', + '#dc3545', + '#ffc107', + '#17a2b8', + '#6f42c1', + '#e83e8c', + '#fd7e14', + '#20c997', + '#6c757d', ]; return { fontSize: isMobile ? '10px' : '11px', @@ -216,7 +224,7 @@ export default function ResultsDisplay({

📄 搜索结果

- {!data || !data.list || data.list.length === 0 ? ( + {!data?.list || data.list.length === 0 ? (
{emptyMessage}
) : ( <> @@ -227,7 +235,7 @@ export default function ResultsDisplay({ onMouseEnter={(e) => { if (!isMobile) { e.currentTarget.style.transform = 'translateY(-2px)'; - e.currentTarget.style.boxShadow = '0 6px 12px rgba(0, 0, 0, 0.15)'; + e.currentTarget.style.boxShadow = '0 6px 12px rgba(0, 0, 0, 0.15)'; } }} onMouseLeave={(e) => { @@ -250,15 +258,11 @@ export default function ResultsDisplay({ ))} {loadingMore && ( -
- 正在加载更多文章... -
+
正在加载更多文章...
)} {noMore && data.list.length > 0 && ( -
- 已显示全部文章 -
+
已显示全部文章
)} )} diff --git a/src/components/archives/TagsFilter.tsx b/src/components/archives/TagsFilter.tsx index ad2efc6..9deebb6 100644 --- a/src/components/archives/TagsFilter.tsx +++ b/src/components/archives/TagsFilter.tsx @@ -3,7 +3,7 @@ import { isMobile } from 'react-device-detect'; import { useRequest, useMemoizedFn } from 'ahooks'; import { getAllTags } from '../../actions/blogger.service'; import { getCurrentTheme } from '../../constants/colors'; - +import type { JSX } from 'react/jsx-runtime'; interface TagsFilterProps { onTagSelect: (tag: string) => void; onTagSearch: (tag: string) => void; @@ -11,13 +11,18 @@ interface TagsFilterProps { initialTag?: string; } -export default function TagsFilter({ onTagSelect, onTagSearch, selectedTag, initialTag }: TagsFilterProps) { +export default function TagsFilter({ + onTagSelect, + onTagSearch, + selectedTag, + initialTag, +}: TagsFilterProps): JSX.Element { const colors = getCurrentTheme(); const { data: tags = [], loading } = useRequest(getAllTags, { onError: (err) => { console.error('Failed to fetch tags:', err); - } + }, }); // 处理初始标签自动选择 @@ -39,8 +44,16 @@ export default function TagsFilter({ onTagSelect, onTagSearch, selectedTag, init const getTagColor = (index: number): string => { const tagColors = [ - '#007bff', '#28a745', '#dc3545', '#ffc107', '#17a2b8', - '#6f42c1', '#e83e8c', '#fd7e14', '#20c997', '#6c757d' + '#007bff', + '#28a745', + '#dc3545', + '#ffc107', + '#17a2b8', + '#6f42c1', + '#e83e8c', + '#fd7e14', + '#20c997', + '#6c757d', ]; return tagColors[index % tagColors.length]; }; @@ -97,17 +110,25 @@ export default function TagsFilter({ onTagSelect, onTagSearch, selectedTag, init WebkitTextFillColor: 'transparent', }; - const pcTagStyles = (index: number, isSelected: boolean): React.CSSProperties => ({ + const pcTagStyles = ( + index: number, + isSelected: boolean, + ): React.CSSProperties => ({ padding: '10px 16px', - backgroundColor: isSelected ? getTagColor(index) : `${getTagColor(index)}30`, + backgroundColor: isSelected + ? getTagColor(index) + : `${getTagColor(index)}30`, color: isSelected ? '#ffffff' : colors.text, borderRadius: '20px', fontSize: '13px', fontWeight: '500', cursor: 'pointer', - transition: 'background-color 0.3s cubic-bezier(0.4, 0, 0.2, 1), color 0.3s cubic-bezier(0.4, 0, 0.2, 1)', + transition: + 'background-color 0.3s cubic-bezier(0.4, 0, 0.2, 1), color 0.3s cubic-bezier(0.4, 0, 0.2, 1)', textAlign: 'center', - boxShadow: isSelected ? `0 4px 12px ${getTagColor(index)}40` : '0 2px 6px rgba(0, 0, 0, 0.1)', + boxShadow: isSelected + ? `0 4px 12px ${getTagColor(index)}40` + : '0 2px 6px rgba(0, 0, 0, 0.1)', border: `1px solid ${colors.border}`, outline: 'none', position: 'relative', @@ -118,9 +139,14 @@ export default function TagsFilter({ onTagSelect, onTagSearch, selectedTag, init minWidth: '0', }); - const mobileTagStyles = (index: number, isSelected: boolean): React.CSSProperties => ({ + const mobileTagStyles = ( + index: number, + isSelected: boolean, + ): React.CSSProperties => ({ padding: '8px 14px', - backgroundColor: isSelected ? getTagColor(index) : `${getTagColor(index)}30`, + backgroundColor: isSelected + ? getTagColor(index) + : `${getTagColor(index)}30`, color: isSelected ? '#ffffff' : colors.text, borderRadius: '16px', fontSize: '12px', @@ -152,9 +178,7 @@ export default function TagsFilter({ onTagSelect, onTagSearch, selectedTag, init return (
-

- 🏷️ 文章标签 -

+

🏷️ 文章标签

{tags.map((tag, index) => { @@ -162,19 +186,23 @@ export default function TagsFilter({ onTagSelect, onTagSearch, selectedTag, init return ( -
- 第 {current} 页 -
+
第 {current} 页
); } -export default function PostListMobile({ }: PostListMobileProps) { +export default function PostListMobile(): JSX.Element { const colors = getCurrentTheme(); const postListRef = useRef(null); // 使用URL参数同步分页状态 - 必须在组件顶层调用 - const { startIndex: urlStartIndex, pageSize: urlPageSize, updateUrl } = usePaginationUrl({ + const { + startIndex: urlStartIndex, + pageSize: urlPageSize, + updateUrl, + } = usePaginationUrl({ defaultStartIndex: 0, defaultPageSize: 10, }); @@ -292,20 +310,23 @@ export default function PostListMobile({ }: PostListMobileProps) { const prevDate = new Date(prevPost.published); return ( - currentDate.getFullYear() !== prevDate.getFullYear() || - currentDate.getMonth() !== prevDate.getMonth() + currentDate.getFullYear() !== prevDate.getFullYear() + || currentDate.getMonth() !== prevDate.getMonth() ); }; // 处理分页变化的回调函数 - const handlePageChange = useCallback((newCurrent: number, newPageSize: number) => { - // 计算新的startIndex - const newStartIndex = (newCurrent - 1) * newPageSize; - // 更新URL参数 - updateUrl(newStartIndex, newPageSize); - // 更新分页状态 - pagination.onChange(newCurrent, newPageSize); - }, [updateUrl, pagination]); + const handlePageChange = useCallback( + (newCurrent: number, newPageSize: number) => { + // 计算新的startIndex + const newStartIndex = (newCurrent - 1) * newPageSize; + // 更新URL参数 + updateUrl(newStartIndex, newPageSize); + // 更新分页状态 + pagination.onChange(newCurrent, newPageSize); + }, + [updateUrl, pagination], + ); const containerStyles: React.CSSProperties = { maxWidth: '100%', @@ -352,12 +373,16 @@ export default function PostListMobile({ }: PostListMobileProps) { return (

最新文章

-
正在加载文章...
blogger api可能抽风,偶发加载时间超过10秒
+
+ 正在加载文章... +
+ blogger api可能抽风,偶发加载时间超过10秒 +
); } - if (!data || !data.list || data.list.length === 0) { + if (!data?.list || data.list.length === 0) { return (

最新文章

@@ -395,8 +420,10 @@ export default function PostListMobile({ }: PostListMobileProps) { total={data.total} pageSize={pagination.pageSize} displayedItemsCount={data.list.length} - onPrevious={() => handlePageChange(pagination.current - 1, pagination.pageSize)} - onNext={() => handlePageChange(pagination.current + 1, pagination.pageSize)} + onPrevious={() => handlePageChange(pagination.current - 1, pagination.pageSize) + } + onNext={() => handlePageChange(pagination.current + 1, pagination.pageSize) + } />
); diff --git a/src/components/home/PostList.tsx b/src/components/home/PostList.tsx deleted file mode 100644 index c579f8b..0000000 --- a/src/components/home/PostList.tsx +++ /dev/null @@ -1,139 +0,0 @@ -import React, { useRef, useCallback } from 'react'; -import { usePagination, useUpdateEffect } from 'ahooks'; -import GetPostList from '../../services/PostList'; -import PostListItem from './PostListItem'; -import PostListPageToggle from './PostListPageToggle'; -import { getCurrentTheme } from '../../constants/colors'; -import { usePaginationUrl } from '../../hooks'; - -interface PostListProps { } - -export default function PostList({ }: PostListProps) { - const colors = getCurrentTheme(); - const postListRef = useRef(null); - - // 使用URL参数同步分页状态 - 必须在组件顶层调用 - const { startIndex: urlStartIndex, pageSize: urlPageSize, updateUrl } = usePaginationUrl({ - defaultStartIndex: 0, - defaultPageSize: 10, - }); - - // 计算初始页码 - const initialCurrent = Math.floor(urlStartIndex / urlPageSize) + 1; - - const { data, loading, pagination } = usePagination( - ({ current, pageSize }) => { - // 使用URL中的startIndex或根据当前页计算 - const startIndex = current === initialCurrent ? urlStartIndex : (current - 1) * pageSize; - - return GetPostList({ - current, - pageSize, - startIndex, - }); - }, - { - cacheKey: 'postList', - defaultCurrent: initialCurrent, - defaultPageSize: urlPageSize, - }, - ); - - // 处理分页变化的回调函数 - const handlePageChange = useCallback((newCurrent: number, newPageSize: number) => { - // 计算新的startIndex - const newStartIndex = (newCurrent - 1) * newPageSize; - // 更新URL参数 - updateUrl(newStartIndex, newPageSize); - // 更新分页状态 - pagination.onChange(newCurrent, newPageSize); - }, [updateUrl, pagination]); - - // 监听分页变化,滚动到组件顶部 - useUpdateEffect(() => { - if (postListRef.current) { - postListRef.current.scrollIntoView({ - behavior: 'smooth', - block: 'start', - }); - } - }, [pagination.current]); - - const containerStyles: React.CSSProperties = { - maxWidth: '800px', - margin: '0 auto', - padding: '20px', - }; - - const titleStyles: React.CSSProperties = { - fontSize: '24px', - fontWeight: '700', - marginBottom: '24px', - color: colors.text, - textAlign: 'center', - }; - - const loadingStyles: React.CSSProperties = { - textAlign: 'center', - padding: '40px', - color: colors.textSecondary, - fontSize: '16px', - }; - - const emptyStyles: React.CSSProperties = { - textAlign: 'center', - padding: '40px', - color: colors.textSecondary, - fontSize: '16px', - }; - - const listStyles: React.CSSProperties = { - marginBottom: '20px', - }; - - if (loading && !data) { - return ( -
-

最新文章

-
正在加载文章...
blogger api可能抽风,偶发加载时间超过10秒
-
- ); - } - - if (!data || !data.list || data.list.length === 0) { - return ( -
-

最新文章

-
暂无文章
-
- ); - } - - return ( -
-

最新文章

- -
- {data.list.map((post, index) => ( - - ))} -
- - handlePageChange(pagination.current - 1, pagination.pageSize)} - onNext={() => handlePageChange(pagination.current + 1, pagination.pageSize)} - /> -
- ); -} \ No newline at end of file diff --git a/src/components/home/PostListItem.tsx b/src/components/home/PostListItem.tsx index e32167e..69363df 100644 --- a/src/components/home/PostListItem.tsx +++ b/src/components/home/PostListItem.tsx @@ -16,7 +16,7 @@ const PostListItem: React.FC = ({ title, tags, summary, - published + published, }) => { const colors = getCurrentTheme(); @@ -113,9 +113,7 @@ const PostListItem: React.FC = ({

{summary}

-
- 发布于 {formatDate(published)} -
+
发布于 {formatDate(published)}
); }; diff --git a/src/components/home/PostListPageToggle.tsx b/src/components/home/PostListPageToggle.tsx index 011e1b9..0cdbe85 100644 --- a/src/components/home/PostListPageToggle.tsx +++ b/src/components/home/PostListPageToggle.tsx @@ -59,7 +59,7 @@ const PostListPageToggle: React.FC = ({ const buttonDisabledStyles: React.CSSProperties = { backgroundColor: colors.border, - color: "#627077", + color: '#627077', cursor: 'not-allowed', transform: 'none', }; @@ -72,9 +72,14 @@ const PostListPageToggle: React.FC = ({ textAlign: 'center', }; - const [hoveredButton, setHoveredButton] = React.useState<'prev' | 'next' | null>(null); + const [hoveredButton, setHoveredButton] = React.useState< + 'prev' | 'next' | null + >(null); - const getButtonStyles = (buttonType: 'prev' | 'next', isDisabled: boolean) => { + const getButtonStyles = ( + buttonType: 'prev' | 'next', + isDisabled: boolean, + ) => { if (isDisabled) { return { ...buttonStyles, ...buttonDisabledStyles }; } @@ -96,9 +101,7 @@ const PostListPageToggle: React.FC = ({ ← 上一页 -
- 第 {current} 页 -
+
第 {current} 页
); } diff --git a/src/components/home/SiteTitle.tsx b/src/components/home/SiteTitle.tsx index 3419cd4..eed28b9 100644 --- a/src/components/home/SiteTitle.tsx +++ b/src/components/home/SiteTitle.tsx @@ -1,9 +1,9 @@ -import React, { useRef, useEffect } from "react"; -import { useSpring, animated, useTrail } from "@react-spring/web"; -import { useGesture } from "@use-gesture/react"; -import { getCurrentTheme } from "../../constants/colors"; -import { useUpdateEffect } from "ahooks"; -import { useTheme } from "../../hooks"; +import React, { useRef, useEffect, useCallback } from 'react'; +import { useSpring, animated, useTrail } from '@react-spring/web'; +import { useGesture } from '@use-gesture/react'; +import { getCurrentTheme } from '../../constants/colors'; +import { useUpdateEffect } from 'ahooks'; +import { useTheme } from '../../hooks'; interface Particle { id: number; @@ -18,24 +18,20 @@ interface Particle { opacity: number; } -// 辅助函数:从CSS变量获取实际的颜色值 const getComputedCSSColor = (cssVar: string): string => { - if (typeof window === "undefined") return "#007bff"; // 默认颜色 + if (typeof window === 'undefined') return '#007bff'; - // 如果已经是具体的颜色值,直接返回 - if (!cssVar.startsWith("var(")) { + if (!cssVar.startsWith('var(')) { return cssVar; } - // 从CSS变量中提取变量名 - const varName = cssVar.replace(/var\((--[^)]+)\)/, "$1"); + const varName = cssVar.replace(/var\((--[^)]+)\)/, '$1'); - // 获取计算后的样式值 const computedValue = getComputedStyle(document.documentElement) .getPropertyValue(varName) .trim(); - return computedValue || "#007bff"; // 如果获取失败,返回默认颜色 + return computedValue || '#007bff'; }; const SiteTitle: React.FC = () => { @@ -43,296 +39,178 @@ const SiteTitle: React.FC = () => { const containerRef = useRef(null); const canvasRef = useRef(null); const particlesRef = useRef([]); - const animationFrameRef = useRef(0); const mousePos = useRef({ x: 0, y: 0 }); const isHovering = useRef(false); - // 主标题动画 const [titleSpring, titleApi] = useSpring(() => ({ - from: { - scale: 0.8, - opacity: 0, - rotateY: -20, - y: 20, - }, - to: { - scale: 1, - opacity: 1, - rotateY: 0, - y: 0, - }, - config: { - tension: 120, - friction: 14, - mass: 1, - }, + from: { scale: 0.8, opacity: 0, rotateY: -20, y: 20 }, + to: { scale: 1, opacity: 1, rotateY: 0, y: 0 }, + config: { tension: 120, friction: 14, mass: 1 }, })); - // 副标题动画 const [subtitleSpring, subtitleApi] = useSpring(() => ({ - from: { - opacity: 0, - x: -30, - scale: 0.9, - }, - to: { - opacity: 1, - x: 0, - scale: 1, - }, + from: { opacity: 0, x: -30, scale: 0.9 }, + to: { opacity: 1, x: 0, scale: 1 }, delay: 300, - config: { - tension: 100, - friction: 12, - }, + config: { tension: 100, friction: 12 }, })); - // 修复:使用更稳定的光晕动画配置,避免无限循环 const [glowSpring, glowApi] = useSpring(() => ({ opacity: 0.3, config: { tension: 120, friction: 60 }, })); - // 字符逐个显示动画 - const mainTitle = "绯境之外"; - const subTitle = "Outside of Scarlet"; + const mainTitle = '绯境之外'; + const subTitle = 'Outside of Scarlet'; const [mainTitleTrail, mainTitleApi] = useTrail(mainTitle.length, () => ({ - from: { opacity: 0, transform: "translateY(20px) rotateX(90deg)" }, - to: { opacity: 1, transform: "translateY(0px) rotateX(0deg)" }, + from: { opacity: 0, transform: 'translateY(20px) rotateX(90deg)' }, + to: { opacity: 1, transform: 'translateY(0px) rotateX(0deg)' }, delay: 100, config: { tension: 120, friction: 14 }, })); const [subTitleTrail, subTitleApi] = useTrail(subTitle.length, () => ({ - from: { opacity: 0, transform: "translateY(10px)" }, - to: { opacity: 1, transform: "translateY(0px)" }, + from: { opacity: 0, transform: 'translateY(10px)' }, + to: { opacity: 1, transform: 'translateY(0px)' }, delay: 800, config: { tension: 100, friction: 12 }, })); - // 主题变化时清除所有粒子并优雅地重置动画 useUpdateEffect(() => { - console.log("theme changed:", theme); - // 清除粒子 particlesRef.current = []; - - // 温和地停止所有动画,避免突兀的中断 titleApi.stop(); subtitleApi.stop(); glowApi.stop(); mainTitleApi.stop(); subTitleApi.stop(); - // 使用较短的延迟重新启动动画,确保平滑过渡 setTimeout(() => { titleApi.start({ - scale: 1, - opacity: 1, - rotateY: 0, - y: 0, + scale: 1, opacity: 1, rotateY: 0, y: 0, config: { tension: 120, friction: 14, mass: 1 }, }); - subtitleApi.start({ - opacity: 1, - x: 0, - scale: 1, + opacity: 1, x: 0, scale: 1, config: { tension: 100, friction: 12 }, }); - glowApi.start({ - opacity: 0.3, - config: { tension: 120, friction: 60 }, + opacity: 0.3, config: { tension: 120, friction: 60 }, }); - - // 重置字符动画 mainTitleApi.start({ - opacity: 1, - transform: "translateY(0px) rotateX(0deg)", + opacity: 1, transform: 'translateY(0px) rotateX(0deg)', config: { tension: 120, friction: 14 }, }); - subTitleApi.start({ - opacity: 1, - transform: "translateY(0px)", + opacity: 1, transform: 'translateY(0px)', config: { tension: 100, friction: 12 }, }); - }, 50); // 短暂延迟确保主题变化完成 + }, 50); }, [theme, titleApi, subtitleApi, glowApi, mainTitleApi, subTitleApi]); - // 手势处理 const bind = useGesture({ onMove: ({ xy: [x, y] }) => { if (containerRef.current) { const rect = containerRef.current.getBoundingClientRect(); - mousePos.current = { - x: x - rect.left, - y: y - rect.top, - }; + mousePos.current = { x: x - rect.left, y: y - rect.top }; } }, onHover: ({ hovering }) => { isHovering.current = hovering || false; - if (hovering) { - titleApi.start({ - scale: 1.05, - rotateY: 2, - config: { tension: 300, friction: 20 }, - }); - subtitleApi.start({ - scale: 1.02, - x: 5, - config: { tension: 300, friction: 20 }, - }); + titleApi.start({ scale: 1.05, rotateY: 2, config: { tension: 300, friction: 20 } }); + subtitleApi.start({ scale: 1.02, x: 5, config: { tension: 300, friction: 20 } }); } else { - titleApi.start({ - scale: 1, - rotateY: 0, - config: { tension: 200, friction: 15 }, - }); - subtitleApi.start({ - scale: 1, - x: 0, - config: { tension: 200, friction: 15 }, - }); + titleApi.start({ scale: 1, rotateY: 0, config: { tension: 200, friction: 15 } }); + subtitleApi.start({ scale: 1, x: 0, config: { tension: 200, friction: 15 } }); } }, }); - // 修复:创建粒子时获取实际的颜色值,使用缓存避免频繁计算 - const createParticle = (x: number, y: number): Particle => { + const createParticle = useCallback((x: number, y: number): Particle => { const currentColors = getCurrentTheme(); - // 使用try-catch确保颜色获取不会导致错误 - let primaryColor = "#007bff"; - let primaryHoverColor = "#0056b3"; - + let primaryColor = '#007bff'; + let primaryHoverColor = '#0056b3'; try { primaryColor = getComputedCSSColor(currentColors.primary); primaryHoverColor = getComputedCSSColor(currentColors.primaryHover); } catch (error) { - console.warn("Failed to get computed colors, using fallback", error); + console.warn('Failed to get computed colors, using fallback', error); } - return { - id: Math.random(), - x, - y, + id: Math.random(), x, y, vx: (Math.random() - 0.5) * 3, vy: (Math.random() - 0.5) * 3 - 1, - life: 0, - maxLife: 80 + Math.random() * 100, + life: 0, maxLife: 80 + Math.random() * 100, size: 2 + Math.random() * 4, color: Math.random() > 0.5 ? primaryColor : primaryHoverColor, opacity: 0.8, }; - }; + }, []); - // 粒子更新与绘制 - 添加错误处理确保稳定性 - const updateParticles = () => { + const renderFrame = useCallback(() => { const canvas = canvasRef.current; if (!canvas) return; - - const ctx = canvas.getContext("2d"); + const ctx = canvas.getContext('2d'); if (!ctx) return; - try { ctx.clearRect(0, 0, canvas.width, canvas.height); - - const livingParticles: Particle[] = []; - + const nextParticles: Particle[] = []; for (const particle of particlesRef.current) { - particle.life++; - - particle.x += particle.vx; - particle.y += particle.vy; - particle.vx *= 0.98; - particle.vy *= 0.98; - - const lifeRatio = particle.life / particle.maxLife; - particle.opacity = 0.8 * Math.pow(1 - lifeRatio, 2); - - if (particle.opacity > 0.01) { - ctx.save(); - ctx.globalAlpha = particle.opacity; - ctx.fillStyle = particle.color; - ctx.shadowBlur = 8; - ctx.shadowColor = particle.color; - - ctx.beginPath(); - ctx.arc(particle.x, particle.y, particle.size, 0, Math.PI * 2); - ctx.fill(); - ctx.restore(); - } - - if (particle.life < particle.maxLife) { - livingParticles.push(particle); + const nextLife = particle.life + 1; + if (nextLife < particle.maxLife) { + const lifeRatio = nextLife / particle.maxLife; + const nextOpacity = 0.8 * (1 - lifeRatio) ** 2; + if (nextOpacity > 0.01) { + const newParticle = { ...particle, life: nextLife, x: particle.x + particle.vx, y: particle.y + particle.vy, vx: particle.vx * 0.98, vy: particle.vy * 0.98, opacity: nextOpacity }; + ctx.save(); + ctx.globalAlpha = newParticle.opacity; + ctx.fillStyle = newParticle.color; + ctx.shadowBlur = 8; + ctx.shadowColor = newParticle.color; + ctx.beginPath(); + ctx.arc(newParticle.x, newParticle.y, newParticle.size, 0, Math.PI * 2); + ctx.fill(); + ctx.restore(); + nextParticles.push(newParticle); + } } } - - // 只在鼠标悬停且粒子数量不过多时创建新粒子 - if ( - isHovering.current && - Math.random() < 0.4 && - livingParticles.length < 50 - ) { + if (isHovering.current && Math.random() < 0.4 && nextParticles.length < 50) { const offsetX = (Math.random() - 0.5) * 120; const offsetY = (Math.random() - 0.5) * 80; - livingParticles.push( - createParticle( - mousePos.current.x + offsetX, - mousePos.current.y + offsetY - ) - ); + nextParticles.push(createParticle(mousePos.current.x + offsetX, mousePos.current.y + offsetY)); } - - particlesRef.current = livingParticles; + particlesRef.current = nextParticles; } catch (error) { - console.warn("Particle rendering error:", error); - // 清除粒子避免继续出错 + console.warn('Particle rendering error:', error); particlesRef.current = []; } + }, [createParticle]); - animationFrameRef.current = requestAnimationFrame(updateParticles); - }; - - // 安全的光晕脉动动画 - 使用更稳定的实现 useEffect(() => { let glowTimer: number; - let isActive = true; // 标记动画是否应该继续 - - const startGlowAnimation = () => { - const animateGlow = () => { - if (!isActive) return; // 如果组件已卸载,停止动画 - - glowApi.start({ - opacity: 0.6, - config: { duration: 2000 }, - onRest: () => { - if (!isActive) return; - glowApi.start({ - opacity: 0.2, - config: { duration: 2000 }, - onRest: () => { - if (isActive) { - glowTimer = setTimeout(animateGlow, 100); - } - }, - }); - }, - }); - }; - - if (isActive) { - glowTimer = setTimeout(animateGlow, 1000); - } + let isActive = true; + const animateGlow = () => { + if (!isActive) return; + glowApi.start({ + opacity: 0.6, config: { duration: 2000 }, + onRest: () => { + if (!isActive) return; + glowApi.start({ + opacity: 0.2, config: { duration: 2000 }, + onRest: () => { + if (isActive) { + glowTimer = setTimeout(animateGlow, 100); + } + }, + }); + }, + }); }; - - startGlowAnimation(); - + glowTimer = setTimeout(animateGlow, 1000); return () => { - isActive = false; // 标记为非活跃状态 + isActive = false; if (glowTimer) { clearTimeout(glowTimer); } @@ -343,138 +221,55 @@ const SiteTitle: React.FC = () => { useEffect(() => { const canvas = canvasRef.current; const container = containerRef.current; - if (canvas && container) { const resizeCanvas = () => { const rect = container.getBoundingClientRect(); canvas.width = rect.width; canvas.height = rect.height; }; - resizeCanvas(); - window.addEventListener("resize", resizeCanvas); + window.addEventListener('resize', resizeCanvas); - updateParticles(); + let animationFrameId: number; + const animationLoop = () => { + renderFrame(); + animationFrameId = requestAnimationFrame(animationLoop); + }; + animationLoop(); return () => { - window.removeEventListener("resize", resizeCanvas); - if (animationFrameRef.current) { - cancelAnimationFrame(animationFrameRef.current); - } + window.removeEventListener('resize', resizeCanvas); + cancelAnimationFrame(animationFrameId); }; } - }, []); + }, [renderFrame]); - // 获取用于显示的颜色(CSS变量) const colors = getCurrentTheme(); - - // 获取用于Canvas的实际颜色值 const computedPrimaryColor = getComputedCSSColor(colors.primary); - const containerStyles: React.CSSProperties = { - position: "relative", - display: "flex", - flexDirection: "column", - alignItems: "center", - justifyContent: "center", - padding: "40px 20px", - minHeight: "200px", - maxHeight: "25vh", - overflow: "hidden", - cursor: "pointer", - userSelect: "none", - }; - - const canvasStyles: React.CSSProperties = { - position: "absolute", - top: 0, - left: 0, - width: "100%", - height: "100%", - pointerEvents: "none", - zIndex: 1, - }; - - const titleContainerStyles: React.CSSProperties = { - position: "relative", - zIndex: 2, - textAlign: "center", - }; + const containerStyles: React.CSSProperties = { position: 'relative', display: 'flex', flexDirection: 'column', alignItems: 'center', justifyContent: 'center', padding: '40px 20px', minHeight: '200px', maxHeight: '25vh', overflow: 'hidden', cursor: 'pointer', userSelect: 'none' }; + const canvasStyles: React.CSSProperties = { position: 'absolute', top: 0, left: 0, width: '100%', height: '100%', pointerEvents: 'none', zIndex: 1 }; + const titleContainerStyles: React.CSSProperties = { position: 'relative', zIndex: 2, textAlign: 'center' }; return (
- {/* 粒子画布 */} - - {/* 背景光晕 - 使用实际颜色值 */} - - +
- {/* 主标题 */} -
+
{mainTitleTrail.map((style, index) => ( - + {mainTitle[index]} ))}
- - {/* 副标题 */} -
+
{subTitleTrail.map((style, index) => ( - - {subTitle[index] === " " ? "\u00A0" : subTitle[index]} + + {subTitle[index] === ' ' ? '\u00A0' : subTitle[index]} ))}
diff --git a/src/components/home/WelcomeSection.tsx b/src/components/home/WelcomeSection.tsx index 69b594d..481d3e9 100644 --- a/src/components/home/WelcomeSection.tsx +++ b/src/components/home/WelcomeSection.tsx @@ -1,5 +1,6 @@ -import React from "react"; -import { getCurrentTheme } from "../../constants/colors"; +import React from 'react'; +import { getCurrentTheme } from '../../constants/colors'; +import type { JSX } from 'react/jsx-runtime'; interface WelcomeSectionProps { isMobile?: boolean; @@ -7,27 +8,27 @@ interface WelcomeSectionProps { export default function WelcomeSection({ isMobile = false, -}: WelcomeSectionProps) { +}: WelcomeSectionProps): JSX.Element { const colors = getCurrentTheme(); const containerStyles: React.CSSProperties = { - padding: isMobile ? "10px 0" : "5px 0", // 进一步减少padding - marginBottom: isMobile ? "10px" : "3px", // 进一步减少margin + padding: isMobile ? '10px 0' : '5px 0', // 进一步减少padding + marginBottom: isMobile ? '10px' : '3px', // 进一步减少margin }; const titleStyles: React.CSSProperties = { - fontSize: isMobile ? "24px" : "20px", - fontWeight: "bold", + fontSize: isMobile ? '24px' : '20px', + fontWeight: 'bold', color: colors.text, - marginBottom: "10px", - margin: "0 0 10px 0", + marginBottom: '10px', + margin: '0 0 10px 0', }; const descriptionStyles: React.CSSProperties = { - fontSize: isMobile ? "16px" : "14px", + fontSize: isMobile ? '16px' : '14px', color: colors.textSecondary, - lineHeight: "1.6", - margin: "0", + lineHeight: '1.6', + margin: '0', }; return ( diff --git a/src/components/home/slider.tsx b/src/components/home/slider.tsx index 76d41ea..75317bd 100644 --- a/src/components/home/slider.tsx +++ b/src/components/home/slider.tsx @@ -5,12 +5,13 @@ import { useNavigate } from 'react-router-dom'; import { getCurrentTheme } from '../../constants/colors'; import { useTheme } from '../../hooks'; import sliders from '../../constants/sliders'; +import type { JSX } from 'react/jsx-runtime'; interface SliderProps { isMobile?: boolean; } -export default function Slider({ isMobile = false }: SliderProps) { +export default function Slider({ isMobile = false }: SliderProps): JSX.Element { const colors = getCurrentTheme(); const { theme } = useTheme(); const navigate = useNavigate(); @@ -69,13 +70,13 @@ export default function Slider({ isMobile = false }: SliderProps) { fontSize: isMobile ? '16px' : '20px', fontWeight: 'bold', marginBottom: '8px', - textShadow: textShadow, + textShadow, }; const descStyles: React.CSSProperties = { fontSize: isMobile ? '12px' : '14px', opacity: 0.9, - textShadow: textShadow, + textShadow, lineHeight: '1.4', display: '-webkit-box', WebkitLineClamp: isMobile ? 2 : 3, diff --git a/src/components/pages/ToolsList.tsx b/src/components/pages/ToolsList.tsx index 57f1346..8cbddcf 100644 --- a/src/components/pages/ToolsList.tsx +++ b/src/components/pages/ToolsList.tsx @@ -7,17 +7,19 @@ interface ToolsListProps { onItemClick: (path: string) => void; } -const ToolsList: React.FC = ({ list, onItemClick }) => { - return ( +const ToolsList: React.FC = ({ list, onItemClick }) => (
- {list.map((item) => ( -
onItemClick(item.path)}> + {list.map(item => ( +
onItemClick(item.path)} + >

{item.title}

{item.summary}

))}
- ); -}; +); export default ToolsList; diff --git a/src/components/pages/ToolsPagination.tsx b/src/components/pages/ToolsPagination.tsx index 7531191..049378f 100644 --- a/src/components/pages/ToolsPagination.tsx +++ b/src/components/pages/ToolsPagination.tsx @@ -8,16 +8,29 @@ interface ToolsPaginationProps { onChange: (page: number, pageSize: number) => void; } -const Pagination: React.FC = ({ current, total, pageSize, onChange }) => { +const Pagination: React.FC = ({ + current, + total, + pageSize, + onChange, +}) => { const totalPages = Math.ceil(total / pageSize); return (
- - {current} / {totalPages} -
diff --git a/src/components/pages/styles.css b/src/components/pages/styles.css index 5f24bab..91df995 100644 --- a/src/components/pages/styles.css +++ b/src/components/pages/styles.css @@ -47,4 +47,4 @@ .tools-pagination button:disabled { opacity: 0.5; cursor: not-allowed; -} \ No newline at end of file +} diff --git a/src/components/post/ContentView.tsx b/src/components/post/ContentView.tsx index 3ac978c..4c92659 100644 --- a/src/components/post/ContentView.tsx +++ b/src/components/post/ContentView.tsx @@ -1,20 +1,20 @@ -import React, { useEffect, useState } from "react"; -import DOMPurify from "dompurify"; -import useTheme from "../../hooks/useTheme"; +import React, { useEffect, useState } from 'react'; +import DOMPurify from 'dompurify'; +import useTheme from '../../hooks/useTheme'; // 导入拆分后的模块 -import { loadThemeStyles } from "./codeBlocks/cssLoader"; -import { generateContentStyles, generateInlineStyles } from "./contentStyles"; -import { cleanCodeMirrorContent } from "./codeBlocks/codeMirrorCleaner"; +import { loadThemeStyles } from './codeBlocks/cssLoader'; +import { generateContentStyles, generateInlineStyles } from './contentStyles'; +import { cleanCodeMirrorContent } from './codeBlocks/codeMirrorCleaner'; import { performCompleteHighlight, highlightAfterCSSLoad, highlightOnMount, -} from "./codeBlocks/prismHighlighter"; +} from './codeBlocks/prismHighlighter'; import { removeCodeBlockEnhancements, createCodeBlockObserver, -} from "./codeBlocks/codeBlockEnhancer"; +} from './codeBlocks/codeBlockEnhancer'; interface ContentViewProps { content: string; @@ -47,7 +47,7 @@ const ContentView: React.FC = ({ content }) => { await highlightAfterCSSLoad(sanitizedContent); }, 50); } catch (error) { - console.warn("Failed to load some CSS files:", error); + console.warn('Failed to load some CSS files:', error); setCssLoaded(true); // 即使失败也标记为已完成,避免卡住 } }; @@ -130,8 +130,9 @@ const ContentView: React.FC = ({ content }) => { <>
diff --git a/src/components/post/HeaderView.tsx b/src/components/post/HeaderView.tsx index 3bb8874..f76c483 100644 --- a/src/components/post/HeaderView.tsx +++ b/src/components/post/HeaderView.tsx @@ -12,7 +12,12 @@ interface HeaderViewProps { /** * 文章头部组件 - 显示标题、发布时间、更新时间和标签 */ -const HeaderView: React.FC = ({ title, published, updated, tags }) => { +const HeaderView: React.FC = ({ + title, + published, + updated, + tags, +}) => { const navigate = useNavigate(); const formatDate = (dateString: string) => { @@ -27,7 +32,7 @@ const HeaderView: React.FC = ({ title, published, updated, tags const headerStyles: React.CSSProperties = { marginBottom: isMobile ? '20px' : '32px', paddingBottom: isMobile ? '16px' : '24px', - borderBottom: `2px solid var(--border-color)`, + borderBottom: '2px solid var(--border-color)', }; const titleStyles: React.CSSProperties = { diff --git a/src/components/post/TableOfContents.tsx b/src/components/post/TableOfContents.tsx index 8f9c014..3fb6f85 100644 --- a/src/components/post/TableOfContents.tsx +++ b/src/components/post/TableOfContents.tsx @@ -195,8 +195,10 @@ const TableOfContents: React.FC = ({ content }) => { position: 'fixed', left: isOpen ? `${tocWidth}px` : '0px', top: '50%', - transform: isOpen ? 'translateY(-50%) translateX(-100%)' : 'translateY(-50%)', - width: '1%', // 变更: 宽度变窄 + transform: isOpen + ? 'translateY(-50%) translateX(-100%)' + : 'translateY(-50%)', + width: '1%', // 变更: 宽度变窄 height: '100px', // 变更: 高度变高 backgroundColor: 'var(--surface-color)', border: '1px solid var(--border-color)', @@ -212,8 +214,8 @@ const TableOfContents: React.FC = ({ content }) => { zIndex: 101, transition: 'all 0.3s ease-in-out', // 变更: 调整 clip-path 使斜边更陡峭 - clipPath: isOpen - ? 'polygon(100% 0, 0 10%, 0 90%, 100% 100%)' + clipPath: isOpen + ? 'polygon(100% 0, 0 10%, 0 90%, 100% 100%)' : 'polygon(0 0, 100% 10%, 100% 90%, 0 100%)', }; @@ -227,11 +229,11 @@ const TableOfContents: React.FC = ({ content }) => { color: var(--surface-color) !important; } `; - + return ( <> - + {!isMobile && ( <>
- +