Compare commits
3 Commits
f442c07dbf
...
7d57c9e7ae
| Author | SHA1 | Date | |
|---|---|---|---|
| 7d57c9e7ae | |||
| 9635de56e8 | |||
| a57fdbe7c6 |
@@ -10,6 +10,7 @@ lerna-debug.log*
|
|||||||
node_modules
|
node_modules
|
||||||
dist
|
dist
|
||||||
dist-ssr
|
dist-ssr
|
||||||
|
.ssr
|
||||||
.output
|
.output
|
||||||
*.local
|
*.local
|
||||||
|
|
||||||
|
|||||||
@@ -57,7 +57,6 @@
|
|||||||
"@workspace/i18n": "workspace:*",
|
"@workspace/i18n": "workspace:*",
|
||||||
"@workspace/preferences": "workspace:*",
|
"@workspace/preferences": "workspace:*",
|
||||||
"@workspace/search": "workspace:*",
|
"@workspace/search": "workspace:*",
|
||||||
"@workspace/ui": "workspace:*",
|
|
||||||
"clsx": "^2.1.1",
|
"clsx": "^2.1.1",
|
||||||
"react": "^19.2.8",
|
"react": "^19.2.8",
|
||||||
"react-dom": "^19.2.8",
|
"react-dom": "^19.2.8",
|
||||||
@@ -74,7 +73,6 @@
|
|||||||
"@types/react-dom": "^19.2.7",
|
"@types/react-dom": "^19.2.7",
|
||||||
"@vitejs/plugin-react": "^6.1.1",
|
"@vitejs/plugin-react": "^6.1.1",
|
||||||
"babel-plugin-react-compiler": "^1.0.0",
|
"babel-plugin-react-compiler": "^1.0.0",
|
||||||
"oxlint": "^1.81.0",
|
|
||||||
"satteri": "^0.10.5",
|
"satteri": "^0.10.5",
|
||||||
"tailwindcss": "^4.3.3",
|
"tailwindcss": "^4.3.3",
|
||||||
"typescript": "~6.0.2",
|
"typescript": "~6.0.2",
|
||||||
@@ -1958,8 +1956,6 @@
|
|||||||
|
|
||||||
"data-urls/whatwg-url": ["whatwg-url@16.0.1", "", { "dependencies": { "@exodus/bytes": "^1.11.0", "tr46": "^6.0.0", "webidl-conversions": "^8.0.1" } }, "sha512-1to4zXBxmXHV3IiSSEInrreIlu02vUOvrhxJJH5vcxYTBDAx51cqZiKdyTxlecdKNSjj8EcxGBxNf6Vg+945gw=="],
|
"data-urls/whatwg-url": ["whatwg-url@16.0.1", "", { "dependencies": { "@exodus/bytes": "^1.11.0", "tr46": "^6.0.0", "webidl-conversions": "^8.0.1" } }, "sha512-1to4zXBxmXHV3IiSSEInrreIlu02vUOvrhxJJH5vcxYTBDAx51cqZiKdyTxlecdKNSjj8EcxGBxNf6Vg+945gw=="],
|
||||||
|
|
||||||
"docs/oxlint": ["oxlint@1.83.0", "", { "optionalDependencies": { "@oxlint/binding-android-arm-eabi": "1.83.0", "@oxlint/binding-android-arm64": "1.83.0", "@oxlint/binding-darwin-arm64": "1.83.0", "@oxlint/binding-darwin-x64": "1.83.0", "@oxlint/binding-freebsd-x64": "1.83.0", "@oxlint/binding-linux-arm-gnueabihf": "1.83.0", "@oxlint/binding-linux-arm-musleabihf": "1.83.0", "@oxlint/binding-linux-arm64-gnu": "1.83.0", "@oxlint/binding-linux-arm64-musl": "1.83.0", "@oxlint/binding-linux-ppc64-gnu": "1.83.0", "@oxlint/binding-linux-riscv64-gnu": "1.83.0", "@oxlint/binding-linux-riscv64-musl": "1.83.0", "@oxlint/binding-linux-s390x-gnu": "1.83.0", "@oxlint/binding-linux-x64-gnu": "1.83.0", "@oxlint/binding-linux-x64-musl": "1.83.0", "@oxlint/binding-openharmony-arm64": "1.83.0", "@oxlint/binding-win32-arm64-msvc": "1.83.0", "@oxlint/binding-win32-ia32-msvc": "1.83.0", "@oxlint/binding-win32-x64-msvc": "1.83.0" }, "peerDependencies": { "oxlint-tsgolint": ">=7.0.2001", "vite-plus": "*" }, "optionalPeers": ["oxlint-tsgolint", "vite-plus"], "bin": { "oxlint": "bin/oxlint" } }, "sha512-cyDzSzaw3uzP0TeCeq3lLRPPoaUxkbB4ZOXj+kn+5r+BX9V+4bNVGk9lxer+WrgcpebH4JxLlJ3KQjveVztOLQ=="],
|
|
||||||
|
|
||||||
"dot-prop/is-obj": ["is-obj@2.0.0", "", {}, "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w=="],
|
"dot-prop/is-obj": ["is-obj@2.0.0", "", {}, "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w=="],
|
||||||
|
|
||||||
"enquirer/strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="],
|
"enquirer/strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="],
|
||||||
@@ -2090,44 +2086,6 @@
|
|||||||
|
|
||||||
"cross-spawn/which/isexe": ["isexe@2.0.0", "", {}, "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw=="],
|
"cross-spawn/which/isexe": ["isexe@2.0.0", "", {}, "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw=="],
|
||||||
|
|
||||||
"docs/oxlint/@oxlint/binding-android-arm-eabi": ["@oxlint/binding-android-arm-eabi@1.83.0", "", { "os": "android", "cpu": "arm" }, "sha512-0yGY24EwsLk5YDe6F+VkmZyRHSwJDALa3nIrPpq7FXmp2lV2d0TzvBCGeZk+wgiULRGr5blhyr4QMp5KCXJUqA=="],
|
|
||||||
|
|
||||||
"docs/oxlint/@oxlint/binding-android-arm64": ["@oxlint/binding-android-arm64@1.83.0", "", { "os": "android", "cpu": "arm64" }, "sha512-hHfJ0vc17A4iUjH5p9BsTUPYbYRNxGpvD2lbu1aBRk54bzNIx9o5TtYF39QPZcV95DagZd+4DEAw2RH3G2ZsMg=="],
|
|
||||||
|
|
||||||
"docs/oxlint/@oxlint/binding-darwin-arm64": ["@oxlint/binding-darwin-arm64@1.83.0", "", { "os": "darwin", "cpu": "arm64" }, "sha512-hsOjYjszLb/3zym/TkzUMPAoQlTJcuzSyEPOAyA+skXJIX9M0o+4JfOtqopX/Vf4hSLrJ98j0nvFo23gzk8auQ=="],
|
|
||||||
|
|
||||||
"docs/oxlint/@oxlint/binding-darwin-x64": ["@oxlint/binding-darwin-x64@1.83.0", "", { "os": "darwin", "cpu": "x64" }, "sha512-mjh5oH2EA+wl5yRJYT9K9G61O2zFlpuv+yf2JwZOi0+dq2FnTUtm1h8i+5Ik0fXPWIu/k84I1psZR9aQsLAnyA=="],
|
|
||||||
|
|
||||||
"docs/oxlint/@oxlint/binding-freebsd-x64": ["@oxlint/binding-freebsd-x64@1.83.0", "", { "os": "freebsd", "cpu": "x64" }, "sha512-fNHr64/YaO8YssuoDVC8+F4Uk5enR86q5uxfHkQrjAPs1dbAILOrD2uaud+J7MO8Fx774g44ERLD0IGIvZE48w=="],
|
|
||||||
|
|
||||||
"docs/oxlint/@oxlint/binding-linux-arm-gnueabihf": ["@oxlint/binding-linux-arm-gnueabihf@1.83.0", "", { "os": "linux", "cpu": "arm" }, "sha512-Qpwy3zzAwMj+8/lyYItHmkSMwbkprFNWTK7jPYDOxSyxEhaSLOWYUTCMkjF334J8/WD0nznCCsoBbIH6hpsuIw=="],
|
|
||||||
|
|
||||||
"docs/oxlint/@oxlint/binding-linux-arm-musleabihf": ["@oxlint/binding-linux-arm-musleabihf@1.83.0", "", { "os": "linux", "cpu": "arm" }, "sha512-s+BirYLFq7JL2k9sP0XI3ZXJ9dYvJ8sX3jLCLoag7tt+zrSHpZxP0jqznfL+Gdgwu7ay0dYgGYJXrQvq3iWloA=="],
|
|
||||||
|
|
||||||
"docs/oxlint/@oxlint/binding-linux-arm64-gnu": ["@oxlint/binding-linux-arm64-gnu@1.83.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-7lihXt3vKr+GIyapNbHrnFHm/biiW30le6Zv/DExbAFPF6YwCQXVFlONPFehxs0CpGO4CBfYPM9rdDT+XMoIlg=="],
|
|
||||||
|
|
||||||
"docs/oxlint/@oxlint/binding-linux-arm64-musl": ["@oxlint/binding-linux-arm64-musl@1.83.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-q63JalLYVkZiZvls1z3PPUnpmQluOMXp0khqQMznCeAPLGydfNY8JhvuA4WlK57JfrvikU8wB5lPVveqpIXvew=="],
|
|
||||||
|
|
||||||
"docs/oxlint/@oxlint/binding-linux-ppc64-gnu": ["@oxlint/binding-linux-ppc64-gnu@1.83.0", "", { "os": "linux", "cpu": "ppc64" }, "sha512-krQmDF+dRbxvdqVPV88ZuOoPPu8X5BuqDA8Hd+qcS4YMRQCb+nexA57DazgGsc/rGdKBe3QmV0mnv0bdpW/p5g=="],
|
|
||||||
|
|
||||||
"docs/oxlint/@oxlint/binding-linux-riscv64-gnu": ["@oxlint/binding-linux-riscv64-gnu@1.83.0", "", { "os": "linux", "cpu": "none" }, "sha512-MmOl8Y6txEAXZU1RG8Rr264jQ6D7VPmqFsU/45x/FeWsGe32hklTqGrLE6UxHzp5Rjt0wP+20tY8YXKgSFB3mw=="],
|
|
||||||
|
|
||||||
"docs/oxlint/@oxlint/binding-linux-riscv64-musl": ["@oxlint/binding-linux-riscv64-musl@1.83.0", "", { "os": "linux", "cpu": "none" }, "sha512-u1rMymh0W3JZkq370kzQsYPULGWqhE09pZRqnZvUSoYaI9pVO5yVX+iYIslmWuEgwuzH9YAaOsScJiobWCHoOw=="],
|
|
||||||
|
|
||||||
"docs/oxlint/@oxlint/binding-linux-s390x-gnu": ["@oxlint/binding-linux-s390x-gnu@1.83.0", "", { "os": "linux", "cpu": "s390x" }, "sha512-y0zK3HNwGysu7rqtE+BQG/d0bx5gh/KwlOtghN8oWeK1KcWzeaLqtZrbm8owqdma1lFyrce/hTO5ismuNu+INQ=="],
|
|
||||||
|
|
||||||
"docs/oxlint/@oxlint/binding-linux-x64-gnu": ["@oxlint/binding-linux-x64-gnu@1.83.0", "", { "os": "linux", "cpu": "x64" }, "sha512-rS5gM0NgD7ngmuJmbIehsidtrOwKkLFwCQbKEeb9KuyQrrWNq5Zkn0uV6AYdXOMJ0grrWEiLwBuvMxt8w5vsNw=="],
|
|
||||||
|
|
||||||
"docs/oxlint/@oxlint/binding-linux-x64-musl": ["@oxlint/binding-linux-x64-musl@1.83.0", "", { "os": "linux", "cpu": "x64" }, "sha512-W2IH4EtpcPaWcvNGCA95YoDg4vxqE/ZiPCi3arrxEEpsK7+JQN9WYwrlYFx9pcdP6KPXqRqkv3zdQPHcx7b6YQ=="],
|
|
||||||
|
|
||||||
"docs/oxlint/@oxlint/binding-openharmony-arm64": ["@oxlint/binding-openharmony-arm64@1.83.0", "", { "os": "none", "cpu": "arm64" }, "sha512-6LyKkUyoajssTPLlZmDbZIbu4IZ5B4bGuRUnBgCGpEvHP3FQMaYITncHA/unPUo7q+Z+pIu2HhdkQ+8d1SG7iA=="],
|
|
||||||
|
|
||||||
"docs/oxlint/@oxlint/binding-win32-arm64-msvc": ["@oxlint/binding-win32-arm64-msvc@1.83.0", "", { "os": "win32", "cpu": "arm64" }, "sha512-Uz/fObEtF0jmNJQJ8CGRBKfefYstS0/wjD3s6IGzP8nUwsJykHQJBiN3npHwKiGRGn/vvBEgNr4B3cCzmmatvg=="],
|
|
||||||
|
|
||||||
"docs/oxlint/@oxlint/binding-win32-ia32-msvc": ["@oxlint/binding-win32-ia32-msvc@1.83.0", "", { "os": "win32", "cpu": "ia32" }, "sha512-u7XcvPW6Bk58tY5iWs2ESb0vJjoE/kuSpHxopbwp/p3ZtWVQXZ6wor5w3ssVTHOqd/v8b+QdhSFWQ4grEUNWpA=="],
|
|
||||||
|
|
||||||
"docs/oxlint/@oxlint/binding-win32-x64-msvc": ["@oxlint/binding-win32-x64-msvc@1.83.0", "", { "os": "win32", "cpu": "x64" }, "sha512-LZRubd7ph13QmAg4fFecTYVZkiYbROR2Htaxh/ufWRkDhPOm2wrwaEYR89e0YpPFD3dqBrPoxS7myBw5hmYA7Q=="],
|
|
||||||
|
|
||||||
"jest-validate/chalk/ansi-styles": ["ansi-styles@4.3.0", "", { "dependencies": { "color-convert": "^2.0.1" } }, "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg=="],
|
"jest-validate/chalk/ansi-styles": ["ansi-styles@4.3.0", "", { "dependencies": { "color-convert": "^2.0.1" } }, "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg=="],
|
||||||
|
|
||||||
"jest-validate/pretty-format/react-is": ["react-is@18.3.1", "", {}, "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg=="],
|
"jest-validate/pretty-format/react-is": ["react-is@18.3.1", "", {}, "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg=="],
|
||||||
|
|||||||
@@ -1,24 +0,0 @@
|
|||||||
# Logs
|
|
||||||
logs
|
|
||||||
*.log
|
|
||||||
npm-debug.log*
|
|
||||||
yarn-debug.log*
|
|
||||||
yarn-error.log*
|
|
||||||
pnpm-debug.log*
|
|
||||||
lerna-debug.log*
|
|
||||||
|
|
||||||
node_modules
|
|
||||||
dist
|
|
||||||
dist-ssr
|
|
||||||
*.local
|
|
||||||
|
|
||||||
# Editor directories and files
|
|
||||||
.vscode/*
|
|
||||||
!.vscode/extensions.json
|
|
||||||
.idea
|
|
||||||
.DS_Store
|
|
||||||
*.suo
|
|
||||||
*.ntvs*
|
|
||||||
*.njsproj
|
|
||||||
*.sln
|
|
||||||
*.sw?
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
{
|
|
||||||
"$schema": "./node_modules/oxlint/configuration_schema.json",
|
|
||||||
"plugins": ["react", "typescript", "oxc"],
|
|
||||||
"rules": {
|
|
||||||
"react/rules-of-hooks": "error",
|
|
||||||
"react/only-export-components": ["warn", { "allowConstantExport": true }]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
+35
-30
@@ -1,35 +1,40 @@
|
|||||||
# React + TypeScript + Vite
|
# Documentation site
|
||||||
|
|
||||||
This template provides a minimal setup to get React working in Vite with HMR and some Oxlint rules.
|
文档站使用 Vite、React、Satteri 和 MDX。默认语言为 `zh-Hans`,英文页面位于 `/en-US`。
|
||||||
|
|
||||||
Currently, two official plugins are available:
|
## Development
|
||||||
|
|
||||||
- [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react) uses [Oxc](https://oxc.rs)
|
```sh
|
||||||
- [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react-swc) uses [SWC](https://swc.rs/)
|
bun run --cwd docs dev
|
||||||
|
|
||||||
## React Compiler
|
|
||||||
|
|
||||||
The React Compiler is enabled on this template. See [this documentation](https://react.dev/learn/react-compiler) for more information.
|
|
||||||
|
|
||||||
Note: This will impact Vite dev & build performances.
|
|
||||||
You can also try [the experimental native React Compiler support in plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react/README.md#rust-react-compiler) by using `compiler: true` in the plugin options instead of using the Babel plugin.
|
|
||||||
|
|
||||||
## Expanding the Oxlint configuration
|
|
||||||
|
|
||||||
If you are developing a production application, we recommend enabling type-aware lint rules by installing `oxlint-tsgolint` and editing `.oxlintrc.json`:
|
|
||||||
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"$schema": "./node_modules/oxlint/configuration_schema.json",
|
|
||||||
"plugins": ["react", "typescript", "oxc"],
|
|
||||||
"options": {
|
|
||||||
"typeAware": true
|
|
||||||
},
|
|
||||||
"rules": {
|
|
||||||
"react/rules-of-hooks": "error",
|
|
||||||
"react/only-export-components": ["warn", { "allowConstantExport": true }]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
```
|
||||||
|
|
||||||
See the [Oxlint rules documentation](https://oxc.rs/docs/guide/usage/linter/rules) for the full list of rules and categories.
|
开发服务器直接监听 `packages/*/docs/*/**/*.mdx`。新增或修改文档后,页面注册表与开发搜索索引会随 Vite 模块图更新。
|
||||||
|
|
||||||
|
## Static generation
|
||||||
|
|
||||||
|
```sh
|
||||||
|
bun run --cwd docs build
|
||||||
|
```
|
||||||
|
|
||||||
|
构建过程依次执行:
|
||||||
|
|
||||||
|
1. 类型检查并构建浏览器资源;
|
||||||
|
2. 构建仅供预渲染使用的 SSR 入口;
|
||||||
|
3. 枚举注册表中的首页、设置页和所有双语文章路由;
|
||||||
|
4. 将每个路由预渲染到 `dist/<route>/index.html`;
|
||||||
|
5. 生成 `dist/404.html` 和按语言拆分的搜索索引;
|
||||||
|
6. 删除临时 `.ssr` 目录。
|
||||||
|
|
||||||
|
生成的 `dist` 可以直接部署到静态文件服务。页面在浏览器中使用 hydration 恢复交互,后续站内导航仍由轻量客户端路由处理。
|
||||||
|
|
||||||
|
## Search data
|
||||||
|
|
||||||
|
搜索正文不会打进入口 JavaScript:
|
||||||
|
|
||||||
|
- 生产构建从 MDX 原始文本生成 `dist/search/zh-Hans.json` 和 `dist/search/en-US.json`;
|
||||||
|
- 用户第一次执行搜索时,浏览器只请求当前语言的索引,并在当前会话中缓存;
|
||||||
|
- 切换语言后才会按需请求另一份索引;
|
||||||
|
- MDX 页面组件按文章拆分为独立 chunk;
|
||||||
|
- 开发模式使用相同的索引生成逻辑,但从 Vite 监听中的 MDX 源文件即时构建。
|
||||||
|
|
||||||
|
新增符合 `packages/<package>/docs/<locale>/**` 目录约定的文档后,无需手工维护搜索列表。
|
||||||
-255
@@ -1,255 +0,0 @@
|
|||||||
{
|
|
||||||
"lockfileVersion": 1,
|
|
||||||
"configVersion": 1,
|
|
||||||
"workspaces": {
|
|
||||||
"": {
|
|
||||||
"name": "docs",
|
|
||||||
"dependencies": {
|
|
||||||
"react": "^19.2.8",
|
|
||||||
"react-dom": "^19.2.8",
|
|
||||||
},
|
|
||||||
"devDependencies": {
|
|
||||||
"@babel/core": "^7.29.7",
|
|
||||||
"@rolldown/plugin-babel": "^0.2.3",
|
|
||||||
"@types/babel__core": "^7.20.5",
|
|
||||||
"@types/node": "^24.13.3",
|
|
||||||
"@types/react": "^19.2.18",
|
|
||||||
"@types/react-dom": "^19.2.7",
|
|
||||||
"@vitejs/plugin-react": "^6.1.1",
|
|
||||||
"babel-plugin-react-compiler": "^1.0.0",
|
|
||||||
"oxlint": "^1.81.0",
|
|
||||||
"typescript": "~6.0.2",
|
|
||||||
"vite": "^8.3.0",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
"packages": {
|
|
||||||
"@babel/code-frame": ["@babel/code-frame@7.29.7", "", { "dependencies": { "@babel/helper-validator-identifier": "^7.29.7", "js-tokens": "^4.0.0", "picocolors": "^1.1.1" } }, "sha512-Aup7aUOfpbAUg2ROOJN6Iw5f9DMBlzu0mIkm/malLQFN/YQgO48wCj0Kxa3sEHJvPVFg7siR+qRInwXd2qhQKw=="],
|
|
||||||
|
|
||||||
"@babel/compat-data": ["@babel/compat-data@7.29.7", "", {}, "sha512-locTkQyKvwIEgBzVrn8693ebc97F2U8ZHjbXwDXJ5Fn2TCpNwTlKcaKLkdHop5c/icOFE7qt7Q9JC5hnKNa6Gg=="],
|
|
||||||
|
|
||||||
"@babel/core": ["@babel/core@7.29.7", "", { "dependencies": { "@babel/code-frame": "^7.29.7", "@babel/generator": "^7.29.7", "@babel/helper-compilation-targets": "^7.29.7", "@babel/helper-module-transforms": "^7.29.7", "@babel/helpers": "^7.29.7", "@babel/parser": "^7.29.7", "@babel/template": "^7.29.7", "@babel/traverse": "^7.29.7", "@babel/types": "^7.29.7", "@jridgewell/remapping": "^2.3.5", "convert-source-map": "^2.0.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", "json5": "^2.2.3", "semver": "^6.3.1" } }, "sha512-RgHBCvtjbOK2gXSNBNIkNoEc9qoVEtau3hj8gEqKQuL3HZAibKarWFEI3Lfm6EYKkLalOh8eSrj9b+ch9H/VBA=="],
|
|
||||||
|
|
||||||
"@babel/generator": ["@babel/generator@7.29.8", "", { "dependencies": { "@babel/parser": "^7.29.8", "@babel/types": "^7.29.8", "@jridgewell/gen-mapping": "^0.3.12", "@jridgewell/trace-mapping": "^0.3.28", "jsesc": "^3.0.2" } }, "sha512-gZbepsdh3WDtgZKWL+vTPh71LSBrm/Y4/QDZBVCcYfmeTEEuoOYwlSy+G1StfJg+/Zy550u/3TATbm7qDbbMtg=="],
|
|
||||||
|
|
||||||
"@babel/helper-compilation-targets": ["@babel/helper-compilation-targets@7.29.7", "", { "dependencies": { "@babel/compat-data": "^7.29.7", "@babel/helper-validator-option": "^7.29.7", "browserslist": "^4.24.0", "lru-cache": "^5.1.1", "semver": "^6.3.1" } }, "sha512-wem6WaBj4NaVYVdNhLPPVacES6ZJ+KBBfSkTMD3YZxbP3rm3Di85tJU5ljaUNhaOynt+Aj0xruhYuzQBt8n71g=="],
|
|
||||||
|
|
||||||
"@babel/helper-globals": ["@babel/helper-globals@7.29.7", "", {}, "sha512-3nQVUAtvkKH9zahfWgw96Jc/uFOmjACE1kQz82E2lqWmHBgjzbNlsC22nuQTfahmWeQtTq5nQ/4Nnd2A1wj4zA=="],
|
|
||||||
|
|
||||||
"@babel/helper-module-imports": ["@babel/helper-module-imports@7.29.7", "", { "dependencies": { "@babel/traverse": "^7.29.7", "@babel/types": "^7.29.7" } }, "sha512-ejHwrQQYcm9xnTivShn2IDOlIzInN34AXskvq9QicvCtEzq1Vzclu/tKF8Jq1Cg8JG2GL6/EmjgsCT7lXepE3g=="],
|
|
||||||
|
|
||||||
"@babel/helper-module-transforms": ["@babel/helper-module-transforms@7.29.7", "", { "dependencies": { "@babel/helper-module-imports": "^7.29.7", "@babel/helper-validator-identifier": "^7.29.7", "@babel/traverse": "^7.29.7" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-UPUVSyXbOh627KiCIGQSgwWzGeBKLkaJ9PJEdrngIwMSzxLR4jS4+f1f1jb7VzBbg8nFLaYotvVPFCTqdrmTAg=="],
|
|
||||||
|
|
||||||
"@babel/helper-string-parser": ["@babel/helper-string-parser@7.29.7", "", {}, "sha512-Pb5ijPrZ89GDH8223L4UP8i6QApWxs04RbPQJTeWDV0/keR2E36MeKnyr6LYmUUvqRRI+Iv87SuF1W6ErINzYw=="],
|
|
||||||
|
|
||||||
"@babel/helper-validator-identifier": ["@babel/helper-validator-identifier@7.29.7", "", {}, "sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg=="],
|
|
||||||
|
|
||||||
"@babel/helper-validator-option": ["@babel/helper-validator-option@7.29.7", "", {}, "sha512-N9ZErrD+yW5geCDtBqnOoxmR8+tNKiGuxKlDpuJxfsqpa2dFcexaziGAE/qoHLiDDreVNMupxGmSoNlyvsA3gw=="],
|
|
||||||
|
|
||||||
"@babel/helpers": ["@babel/helpers@7.29.7", "", { "dependencies": { "@babel/template": "^7.29.7", "@babel/types": "^7.29.7" } }, "sha512-1k2lAGRMfHTcwuNYcCNUmaUffmQv8KWMfh2iJUUeRlwlwH4FdNG7mfPI10NPfLHJFThE4Tyr4mv7kTNZOiPuBg=="],
|
|
||||||
|
|
||||||
"@babel/parser": ["@babel/parser@7.29.8", "", { "dependencies": { "@babel/types": "^7.29.8" }, "bin": "./bin/babel-parser.js" }, "sha512-E8lTAYNB1KW+FH+VGJuZM1ioAx2E6oVlvQFRrf5P8ZZmsiJXYAD9vTFV7yyEURNzgh1dFqMZuO6tUwcARbqFCA=="],
|
|
||||||
|
|
||||||
"@babel/template": ["@babel/template@7.29.7", "", { "dependencies": { "@babel/code-frame": "^7.29.7", "@babel/parser": "^7.29.7", "@babel/types": "^7.29.7" } }, "sha512-puq+Gf35oI24FeN11LkoUQFqv9uwNeWpxXZi/Ji3rRIoKAzKnxRaZ+Gkj0vKS9ZCiTESfng1N9LyOyXvo+m+Gg=="],
|
|
||||||
|
|
||||||
"@babel/traverse": ["@babel/traverse@7.29.8", "", { "dependencies": { "@babel/code-frame": "^7.29.7", "@babel/generator": "^7.29.8", "@babel/helper-globals": "^7.29.7", "@babel/parser": "^7.29.8", "@babel/template": "^7.29.7", "@babel/types": "^7.29.8", "debug": "^4.3.1" } }, "sha512-I5z7H3bf/41ktsNVLtpN0wAa336HkqIHQ5BuPLEhTkt1jVSyZpeNKIzTgEWmlxjdg81R0IgUCcaE+Ok3NvrfZg=="],
|
|
||||||
|
|
||||||
"@babel/types": ["@babel/types@7.29.8", "", { "dependencies": { "@babel/helper-string-parser": "^7.29.7", "@babel/helper-validator-identifier": "^7.29.7" } }, "sha512-Vj1jF3cPfxg7OAfoI7QnVKLoILlm2JF9pnVHrX8qx7AHMiYWT+NDAA7jChlNgRS4WTLc/fD1lXLmPixluj+3Gg=="],
|
|
||||||
|
|
||||||
"@jridgewell/gen-mapping": ["@jridgewell/gen-mapping@0.3.13", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.0", "@jridgewell/trace-mapping": "^0.3.24" } }, "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA=="],
|
|
||||||
|
|
||||||
"@jridgewell/remapping": ["@jridgewell/remapping@2.3.5", "", { "dependencies": { "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.24" } }, "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ=="],
|
|
||||||
|
|
||||||
"@jridgewell/resolve-uri": ["@jridgewell/resolve-uri@3.1.2", "", {}, "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw=="],
|
|
||||||
|
|
||||||
"@jridgewell/sourcemap-codec": ["@jridgewell/sourcemap-codec@1.6.0", "", {}, "sha512-T7jf+5zgsZHwNJ4lvQ7/aezbyk0nNX+zJVWpmHA7VYsEx7a7qr5Rg5IbtJFqkgze5Y2sruq1RUY8Q837Od7iFw=="],
|
|
||||||
|
|
||||||
"@jridgewell/trace-mapping": ["@jridgewell/trace-mapping@0.3.31", "", { "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" } }, "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw=="],
|
|
||||||
|
|
||||||
"@oxc-project/types": ["@oxc-project/types@0.149.0", "", {}, "sha512-Efcc+iF0j3Bf67YjEqIqWXbX5XddXoK/Mw4K1/JuXwRCZ8N16VR7iT23nlCc9XrveFVh/E5Rqs2StT0V8v9LdA=="],
|
|
||||||
|
|
||||||
"@oxlint/binding-android-arm-eabi": ["@oxlint/binding-android-arm-eabi@1.83.0", "", { "os": "android", "cpu": "arm" }, "sha512-0yGY24EwsLk5YDe6F+VkmZyRHSwJDALa3nIrPpq7FXmp2lV2d0TzvBCGeZk+wgiULRGr5blhyr4QMp5KCXJUqA=="],
|
|
||||||
|
|
||||||
"@oxlint/binding-android-arm64": ["@oxlint/binding-android-arm64@1.83.0", "", { "os": "android", "cpu": "arm64" }, "sha512-hHfJ0vc17A4iUjH5p9BsTUPYbYRNxGpvD2lbu1aBRk54bzNIx9o5TtYF39QPZcV95DagZd+4DEAw2RH3G2ZsMg=="],
|
|
||||||
|
|
||||||
"@oxlint/binding-darwin-arm64": ["@oxlint/binding-darwin-arm64@1.83.0", "", { "os": "darwin", "cpu": "arm64" }, "sha512-hsOjYjszLb/3zym/TkzUMPAoQlTJcuzSyEPOAyA+skXJIX9M0o+4JfOtqopX/Vf4hSLrJ98j0nvFo23gzk8auQ=="],
|
|
||||||
|
|
||||||
"@oxlint/binding-darwin-x64": ["@oxlint/binding-darwin-x64@1.83.0", "", { "os": "darwin", "cpu": "x64" }, "sha512-mjh5oH2EA+wl5yRJYT9K9G61O2zFlpuv+yf2JwZOi0+dq2FnTUtm1h8i+5Ik0fXPWIu/k84I1psZR9aQsLAnyA=="],
|
|
||||||
|
|
||||||
"@oxlint/binding-freebsd-x64": ["@oxlint/binding-freebsd-x64@1.83.0", "", { "os": "freebsd", "cpu": "x64" }, "sha512-fNHr64/YaO8YssuoDVC8+F4Uk5enR86q5uxfHkQrjAPs1dbAILOrD2uaud+J7MO8Fx774g44ERLD0IGIvZE48w=="],
|
|
||||||
|
|
||||||
"@oxlint/binding-linux-arm-gnueabihf": ["@oxlint/binding-linux-arm-gnueabihf@1.83.0", "", { "os": "linux", "cpu": "arm" }, "sha512-Qpwy3zzAwMj+8/lyYItHmkSMwbkprFNWTK7jPYDOxSyxEhaSLOWYUTCMkjF334J8/WD0nznCCsoBbIH6hpsuIw=="],
|
|
||||||
|
|
||||||
"@oxlint/binding-linux-arm-musleabihf": ["@oxlint/binding-linux-arm-musleabihf@1.83.0", "", { "os": "linux", "cpu": "arm" }, "sha512-s+BirYLFq7JL2k9sP0XI3ZXJ9dYvJ8sX3jLCLoag7tt+zrSHpZxP0jqznfL+Gdgwu7ay0dYgGYJXrQvq3iWloA=="],
|
|
||||||
|
|
||||||
"@oxlint/binding-linux-arm64-gnu": ["@oxlint/binding-linux-arm64-gnu@1.83.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-7lihXt3vKr+GIyapNbHrnFHm/biiW30le6Zv/DExbAFPF6YwCQXVFlONPFehxs0CpGO4CBfYPM9rdDT+XMoIlg=="],
|
|
||||||
|
|
||||||
"@oxlint/binding-linux-arm64-musl": ["@oxlint/binding-linux-arm64-musl@1.83.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-q63JalLYVkZiZvls1z3PPUnpmQluOMXp0khqQMznCeAPLGydfNY8JhvuA4WlK57JfrvikU8wB5lPVveqpIXvew=="],
|
|
||||||
|
|
||||||
"@oxlint/binding-linux-ppc64-gnu": ["@oxlint/binding-linux-ppc64-gnu@1.83.0", "", { "os": "linux", "cpu": "ppc64" }, "sha512-krQmDF+dRbxvdqVPV88ZuOoPPu8X5BuqDA8Hd+qcS4YMRQCb+nexA57DazgGsc/rGdKBe3QmV0mnv0bdpW/p5g=="],
|
|
||||||
|
|
||||||
"@oxlint/binding-linux-riscv64-gnu": ["@oxlint/binding-linux-riscv64-gnu@1.83.0", "", { "os": "linux", "cpu": "none" }, "sha512-MmOl8Y6txEAXZU1RG8Rr264jQ6D7VPmqFsU/45x/FeWsGe32hklTqGrLE6UxHzp5Rjt0wP+20tY8YXKgSFB3mw=="],
|
|
||||||
|
|
||||||
"@oxlint/binding-linux-riscv64-musl": ["@oxlint/binding-linux-riscv64-musl@1.83.0", "", { "os": "linux", "cpu": "none" }, "sha512-u1rMymh0W3JZkq370kzQsYPULGWqhE09pZRqnZvUSoYaI9pVO5yVX+iYIslmWuEgwuzH9YAaOsScJiobWCHoOw=="],
|
|
||||||
|
|
||||||
"@oxlint/binding-linux-s390x-gnu": ["@oxlint/binding-linux-s390x-gnu@1.83.0", "", { "os": "linux", "cpu": "s390x" }, "sha512-y0zK3HNwGysu7rqtE+BQG/d0bx5gh/KwlOtghN8oWeK1KcWzeaLqtZrbm8owqdma1lFyrce/hTO5ismuNu+INQ=="],
|
|
||||||
|
|
||||||
"@oxlint/binding-linux-x64-gnu": ["@oxlint/binding-linux-x64-gnu@1.83.0", "", { "os": "linux", "cpu": "x64" }, "sha512-rS5gM0NgD7ngmuJmbIehsidtrOwKkLFwCQbKEeb9KuyQrrWNq5Zkn0uV6AYdXOMJ0grrWEiLwBuvMxt8w5vsNw=="],
|
|
||||||
|
|
||||||
"@oxlint/binding-linux-x64-musl": ["@oxlint/binding-linux-x64-musl@1.83.0", "", { "os": "linux", "cpu": "x64" }, "sha512-W2IH4EtpcPaWcvNGCA95YoDg4vxqE/ZiPCi3arrxEEpsK7+JQN9WYwrlYFx9pcdP6KPXqRqkv3zdQPHcx7b6YQ=="],
|
|
||||||
|
|
||||||
"@oxlint/binding-openharmony-arm64": ["@oxlint/binding-openharmony-arm64@1.83.0", "", { "os": "none", "cpu": "arm64" }, "sha512-6LyKkUyoajssTPLlZmDbZIbu4IZ5B4bGuRUnBgCGpEvHP3FQMaYITncHA/unPUo7q+Z+pIu2HhdkQ+8d1SG7iA=="],
|
|
||||||
|
|
||||||
"@oxlint/binding-win32-arm64-msvc": ["@oxlint/binding-win32-arm64-msvc@1.83.0", "", { "os": "win32", "cpu": "arm64" }, "sha512-Uz/fObEtF0jmNJQJ8CGRBKfefYstS0/wjD3s6IGzP8nUwsJykHQJBiN3npHwKiGRGn/vvBEgNr4B3cCzmmatvg=="],
|
|
||||||
|
|
||||||
"@oxlint/binding-win32-ia32-msvc": ["@oxlint/binding-win32-ia32-msvc@1.83.0", "", { "os": "win32", "cpu": "ia32" }, "sha512-u7XcvPW6Bk58tY5iWs2ESb0vJjoE/kuSpHxopbwp/p3ZtWVQXZ6wor5w3ssVTHOqd/v8b+QdhSFWQ4grEUNWpA=="],
|
|
||||||
|
|
||||||
"@oxlint/binding-win32-x64-msvc": ["@oxlint/binding-win32-x64-msvc@1.83.0", "", { "os": "win32", "cpu": "x64" }, "sha512-LZRubd7ph13QmAg4fFecTYVZkiYbROR2Htaxh/ufWRkDhPOm2wrwaEYR89e0YpPFD3dqBrPoxS7myBw5hmYA7Q=="],
|
|
||||||
|
|
||||||
"@rolldown/binding-android-arm-eabi": ["@rolldown/binding-android-arm-eabi@1.2.8", "", { "os": "android", "cpu": "arm" }, "sha512-tN5aztYkKCte4i5SIrrz5yK/HMjEuCqCSCJa418jOV8tZ1cBY3YF2otxB1ktPxzsLA1BeTqwapK0bfjxNvHJVw=="],
|
|
||||||
|
|
||||||
"@rolldown/binding-android-arm64": ["@rolldown/binding-android-arm64@1.2.8", "", { "os": "android", "cpu": "arm64" }, "sha512-dIYTWl9XprMUiQFoc55KUyk/oS8SKYH3zFl0LTR7RT0Xj4hgSVyuJcroH8JUu8RcpF8fTB6E0aOwCkZoYPcDSQ=="],
|
|
||||||
|
|
||||||
"@rolldown/binding-darwin-arm64": ["@rolldown/binding-darwin-arm64@1.2.8", "", { "os": "darwin", "cpu": "arm64" }, "sha512-PCSDQGXD2IyTEFrcgPyBM8jJuGmrbCMuoIOXdbEGVemruKACXoLQJrb+A45Z0L5t1RQkdfJprAYPkikbh7dzdA=="],
|
|
||||||
|
|
||||||
"@rolldown/binding-darwin-x64": ["@rolldown/binding-darwin-x64@1.2.8", "", { "os": "darwin", "cpu": "x64" }, "sha512-Uk7lRsGhPFHVX/sAUC6D5H9Ol30dFHd6iquokll2th3LpdJ3F5CzQB+7DHn0Ri2mG+U7k2zXiPHDrwZenXhwSA=="],
|
|
||||||
|
|
||||||
"@rolldown/binding-freebsd-x64": ["@rolldown/binding-freebsd-x64@1.2.8", "", { "os": "freebsd", "cpu": "x64" }, "sha512-DjszaTEVogPqA5bYzsEeqDCQxbcp2fexQwKcRspYji2yzR68fCf+e4fx6kBSRDwX5/brZaHw/hWS9+A/+/w9sQ=="],
|
|
||||||
|
|
||||||
"@rolldown/binding-linux-arm-gnueabihf": ["@rolldown/binding-linux-arm-gnueabihf@1.2.8", "", { "os": "linux", "cpu": "arm" }, "sha512-zmwa7FTmdzB6aaEEuuls18H6Ap5JmJPSoPTuXixeJZV6tG40SyLkApQtz1g8ptZtiEKqj9OM0oNLPh1AgvE31Q=="],
|
|
||||||
|
|
||||||
"@rolldown/binding-linux-arm64-gnu": ["@rolldown/binding-linux-arm64-gnu@1.2.8", "", { "os": "linux", "cpu": "arm64" }, "sha512-KdYQDPHwJVnbFwdTGMgxsI9SqblBlz6STGM+w1We/d5B8OWWidYH0MwkU/uA1wM5fIpO2MkOVxXrNzzuZhw9ew=="],
|
|
||||||
|
|
||||||
"@rolldown/binding-linux-arm64-musl": ["@rolldown/binding-linux-arm64-musl@1.2.8", "", { "os": "linux", "cpu": "arm64" }, "sha512-jFJTifHnNPY+yzOoNZQfSIysrVyXzEQPhPnOUjmD1bcQGHH6s7c8cViKWar8YplQImE5N9JRqMCLrM2CdxOrZA=="],
|
|
||||||
|
|
||||||
"@rolldown/binding-linux-ppc64-gnu": ["@rolldown/binding-linux-ppc64-gnu@1.2.8", "", { "os": "linux", "cpu": "ppc64" }, "sha512-FhiOziBDWPBjbcmRzfLyIJnaP7AVMFXT7YCXPjXxj7wKU3vx24RjrCNN/zjvVa+N2vVoHJwCoUBvsrN/DG3zIA=="],
|
|
||||||
|
|
||||||
"@rolldown/binding-linux-s390x-gnu": ["@rolldown/binding-linux-s390x-gnu@1.2.8", "", { "os": "linux", "cpu": "s390x" }, "sha512-WnHfADMzOV2Y55wlx1hzzQnar/wDt/VdvWSD99r18Mz9ylNieIGOkRx3UV21h7m/eJvjySYJkO26VvGNFkwsIQ=="],
|
|
||||||
|
|
||||||
"@rolldown/binding-linux-x64-gnu": ["@rolldown/binding-linux-x64-gnu@1.2.8", "", { "os": "linux", "cpu": "x64" }, "sha512-H9tRr5ibfXFVLxbPOseVewewFpl28zcEdjRDt2FTUZU7odxP0gEv1ki4/kGmcGOh78oRwZuuQllGLZ9zTJp84g=="],
|
|
||||||
|
|
||||||
"@rolldown/binding-linux-x64-musl": ["@rolldown/binding-linux-x64-musl@1.2.8", "", { "os": "linux", "cpu": "x64" }, "sha512-UefiqfM3D6IVNlZ8tSGs9+Ejjud2T+oxO0IHADU45Y+lyEjD2dVFyZHbkfX0LUb5Zugo/oIv1eCO/KVYhgYJYA=="],
|
|
||||||
|
|
||||||
"@rolldown/binding-openharmony-arm64": ["@rolldown/binding-openharmony-arm64@1.2.8", "", { "os": "none", "cpu": "arm64" }, "sha512-637Ke4kWSy6rp9cxQ9gMOXlxPgIw/c1beASV4M//3+9I4uwBVOOl74G+e3zyU3u19U7RkRl/HuewixZ/Z6+Rjg=="],
|
|
||||||
|
|
||||||
"@rolldown/binding-win32-arm64-msvc": ["@rolldown/binding-win32-arm64-msvc@1.2.8", "", { "os": "win32", "cpu": "arm64" }, "sha512-xWBkPOF1Q9k/Gv1nQXnVdLxKu74jXppuOM4Z3mnypVUJJJwLsMl7hNJGRAUJoG8A5MgOI1ACKM+wBFxSJzKy4A=="],
|
|
||||||
|
|
||||||
"@rolldown/binding-win32-x64-msvc": ["@rolldown/binding-win32-x64-msvc@1.2.8", "", { "os": "win32", "cpu": "x64" }, "sha512-uz2ZvfgXbxqNwijjjbxrnvALwpyODDcgc1T1N8N3rf/DXKQmaFwmB4LX4yyjggpwN2obdQLb2rgirX5ffCWYng=="],
|
|
||||||
|
|
||||||
"@rolldown/plugin-babel": ["@rolldown/plugin-babel@0.2.4", "", { "dependencies": { "picomatch": "^4.0.7" }, "peerDependencies": { "@babel/core": "^7.29.0 || ^8.0.0-rc.1", "@babel/plugin-transform-runtime": "^7.29.0 || ^8.0.0-rc.1", "@babel/runtime": "^7.27.0 || ^8.0.0-rc.1", "rolldown": "^1.0.0-rc.5", "vite": "^8.0.0" }, "optionalPeers": ["@babel/plugin-transform-runtime", "@babel/runtime", "vite"] }, "sha512-ygmm2j/mN+aCvstHo0x3IOu4uc6LqXT9SJ3q4kpfG/+Yhfz0B+E47FITcC0FljZADwUFARP6E2kiE+Lc26D8wg=="],
|
|
||||||
|
|
||||||
"@rolldown/pluginutils": ["@rolldown/pluginutils@1.0.1", "", {}, "sha512-2j9bGt5Jh8hj+vPtgzPtl72j0yRxHAyumoo6TNfAjsLB04UtpSvPbPcDcBMxz7n+9CYB0c1GxQFxYRg2jimqGw=="],
|
|
||||||
|
|
||||||
"@types/babel__core": ["@types/babel__core@7.20.5", "", { "dependencies": { "@babel/parser": "^7.20.7", "@babel/types": "^7.20.7", "@types/babel__generator": "*", "@types/babel__template": "*", "@types/babel__traverse": "*" } }, "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA=="],
|
|
||||||
|
|
||||||
"@types/babel__generator": ["@types/babel__generator@7.27.0", "", { "dependencies": { "@babel/types": "^7.0.0" } }, "sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg=="],
|
|
||||||
|
|
||||||
"@types/babel__template": ["@types/babel__template@7.4.4", "", { "dependencies": { "@babel/parser": "^7.1.0", "@babel/types": "^7.0.0" } }, "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A=="],
|
|
||||||
|
|
||||||
"@types/babel__traverse": ["@types/babel__traverse@7.28.0", "", { "dependencies": { "@babel/types": "^7.28.2" } }, "sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q=="],
|
|
||||||
|
|
||||||
"@types/node": ["@types/node@24.13.5", "", { "dependencies": { "undici-types": "~7.18.0" } }, "sha512-TXyindR+lBr22aJIdMQzCFHPHR6cR4js838mRDCSz5hOKWZvZwsXSSiXDmjRj4iJmgl+sR9O+1mkoVBSMadNug=="],
|
|
||||||
|
|
||||||
"@types/react": ["@types/react@19.3.0", "", { "dependencies": { "csstype": "^3.2.2" } }, "sha512-N0rFCuH9YoxG9/m61l9MfpJKfmLOVU0em7ipIz6TRgSSkvReLB9vL85GB+yr8Bs5leqpvg96JSwF4ZS1s4viQg=="],
|
|
||||||
|
|
||||||
"@types/react-dom": ["@types/react-dom@19.3.0", "", { "peerDependencies": { "@types/react": "^19.3.0" } }, "sha512-ZI7bU42mZXXKHn/qNLEw2IrbiINU7X5+vfgdixBHkCNpYWXjKgfQ/P+uyGb5CjOLB9UcnTeg3rylQtV2hym44Q=="],
|
|
||||||
|
|
||||||
"@vitejs/plugin-react": ["@vitejs/plugin-react@6.1.1", "", { "dependencies": { "@rolldown/pluginutils": "^1.0.1" }, "peerDependencies": { "@rolldown/plugin-babel": "^0.1.7 || ^0.2.0", "babel-plugin-react-compiler": "^1.0.0", "oxc-transform-react": "^0.145.0", "vite": "^8.0.0" }, "optionalPeers": ["@rolldown/plugin-babel", "babel-plugin-react-compiler", "oxc-transform-react"] }, "sha512-yxLaQV9gkhS8ezJqCM6+ndU7mDY6gqAg75NQ+0IjwEI8IYOmQCgkRwHKVSfWXW076DsqMo0Dk+0FK1U+M5RgFw=="],
|
|
||||||
|
|
||||||
"babel-plugin-react-compiler": ["babel-plugin-react-compiler@1.0.0", "", { "dependencies": { "@babel/types": "^7.26.0" } }, "sha512-Ixm8tFfoKKIPYdCCKYTsqv+Fd4IJ0DQqMyEimo+pxUOMUR9cVPlwTrFt9Avu+3cb6Zp3mAzl+t1MrG2fxxKsxw=="],
|
|
||||||
|
|
||||||
"baseline-browser-mapping": ["baseline-browser-mapping@2.11.24", "", { "bin": { "baseline-browser-mapping": "dist/cli.cjs" } }, "sha512-hYrgxie335U08WqICoGqKRzV1HFXv6zdxwJE4ekCb80CM9a0SVVsN4QPwT67RraRo+9h8IATk6uxHJw7QSkdOg=="],
|
|
||||||
|
|
||||||
"browserslist": ["browserslist@4.29.0", "", { "dependencies": { "baseline-browser-mapping": "^2.11.23", "caniuse-lite": "^1.0.30001810", "electron-to-chromium": "^1.5.427", "node-releases": "^2.0.55", "update-browserslist-db": "^1.3.3" }, "bin": { "browserslist": "cli.js" } }, "sha512-3GSvyjvDI4Dur1Meg2BekJquu5uF+9R9a1+5M1Mde192eZoXbeXjzgOsgqPS2V8D5wrrip0gR5Hf/GhWQ9ZzaA=="],
|
|
||||||
|
|
||||||
"caniuse-lite": ["caniuse-lite@1.0.30001810", "", {}, "sha512-TITQPUkaz+aVk5GL6NhOdwk1aEaNTSDPsGFWrTuhKGtjTF70jL/Oht2W4c6rXUe5fu7Ie19VIahAXHIIiWWNeg=="],
|
|
||||||
|
|
||||||
"convert-source-map": ["convert-source-map@2.0.0", "", {}, "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg=="],
|
|
||||||
|
|
||||||
"csstype": ["csstype@3.2.3", "", {}, "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ=="],
|
|
||||||
|
|
||||||
"debug": ["debug@4.4.3", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA=="],
|
|
||||||
|
|
||||||
"detect-libc": ["detect-libc@2.1.2", "", {}, "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ=="],
|
|
||||||
|
|
||||||
"electron-to-chromium": ["electron-to-chromium@1.5.430", "", {}, "sha512-e1QEj72Y4zd8RlNZVmoTg+iCOSVwpk05IOiiQwdrkwCSVlZfPthevErhE+nckGd2YbsXfp1SkisznhGVIXP2NQ=="],
|
|
||||||
|
|
||||||
"escalade": ["escalade@3.2.0", "", {}, "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA=="],
|
|
||||||
|
|
||||||
"fdir": ["fdir@6.5.0", "", { "peerDependencies": { "picomatch": "^3 || ^4" }, "optionalPeers": ["picomatch"] }, "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg=="],
|
|
||||||
|
|
||||||
"fsevents": ["fsevents@2.3.3", "", { "os": "darwin" }, "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw=="],
|
|
||||||
|
|
||||||
"gensync": ["gensync@1.0.0-beta.2", "", {}, "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg=="],
|
|
||||||
|
|
||||||
"js-tokens": ["js-tokens@4.0.0", "", {}, "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="],
|
|
||||||
|
|
||||||
"jsesc": ["jsesc@3.1.0", "", { "bin": { "jsesc": "bin/jsesc" } }, "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA=="],
|
|
||||||
|
|
||||||
"json5": ["json5@2.2.3", "", { "bin": { "json5": "lib/cli.js" } }, "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg=="],
|
|
||||||
|
|
||||||
"lightningcss": ["lightningcss@1.33.0", "", { "dependencies": { "detect-libc": "^2.0.3" }, "optionalDependencies": { "lightningcss-android-arm64": "1.33.0", "lightningcss-darwin-arm64": "1.33.0", "lightningcss-darwin-x64": "1.33.0", "lightningcss-freebsd-x64": "1.33.0", "lightningcss-linux-arm-gnueabihf": "1.33.0", "lightningcss-linux-arm64-gnu": "1.33.0", "lightningcss-linux-arm64-musl": "1.33.0", "lightningcss-linux-x64-gnu": "1.33.0", "lightningcss-linux-x64-musl": "1.33.0", "lightningcss-win32-arm64-msvc": "1.33.0", "lightningcss-win32-x64-msvc": "1.33.0" } }, "sha512-WkUDrojuJs0xkgGf2udWxa3yGBRxPtxUkB79i6aCZLRgc7PM8fZe9TosfPDcvEpQZbuFASnHYmRLBLUbmLOIIA=="],
|
|
||||||
|
|
||||||
"lightningcss-android-arm64": ["lightningcss-android-arm64@1.33.0", "", { "os": "android", "cpu": "arm64" }, "sha512-gEpRTalKdosp4Bb8qWtc2iOgE5SeIHlpS1up9bFq2wAyYhl1UdTObYiHe98zEM9SQvSoqQZ1IQD0JNpg3Ml5pg=="],
|
|
||||||
|
|
||||||
"lightningcss-darwin-arm64": ["lightningcss-darwin-arm64@1.33.0", "", { "os": "darwin", "cpu": "arm64" }, "sha512-Sciaz8eenNTKn9b3t7+xr0ipTp9YxKQY4npwQ3mrRuL0BAVHBLyZxofhaKBAVtzmtRZ/zTyo0/to4B1uWG/Djg=="],
|
|
||||||
|
|
||||||
"lightningcss-darwin-x64": ["lightningcss-darwin-x64@1.33.0", "", { "os": "darwin", "cpu": "x64" }, "sha512-Z5UPAxzrjlWNNyGy6i65cJzzvgJ5D3T6wMvs+gWpY9d7qRhANrxqAp6LhxIgZhWEw18RfJTGcRxjuLIBr+m8XQ=="],
|
|
||||||
|
|
||||||
"lightningcss-freebsd-x64": ["lightningcss-freebsd-x64@1.33.0", "", { "os": "freebsd", "cpu": "x64" }, "sha512-QQM/Ti/hQajJwCY+RiWuCZ9sdtI/XQk7nDK5vC8kkdwixezOlDgvDx7+RT+QjK6FcFT4MpsuoBnHIo/O3StRRg=="],
|
|
||||||
|
|
||||||
"lightningcss-linux-arm-gnueabihf": ["lightningcss-linux-arm-gnueabihf@1.33.0", "", { "os": "linux", "cpu": "arm" }, "sha512-N7FVBe6iS24MlM6R/4RBTxGhQheZGs7tiQ9U32UtF75NzP5Q7xWPRqLBCKxlRQRk3rY1jCIPLzx7WzOhuUIRLQ=="],
|
|
||||||
|
|
||||||
"lightningcss-linux-arm64-gnu": ["lightningcss-linux-arm64-gnu@1.33.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-j2v/itmy4HlNxlc6voKXYgBqNi0Ng2LShg4z7GufpEgs05P+2suBVyi9I6YHq5uoVFx9ETin3eCEhLVyXGQnKg=="],
|
|
||||||
|
|
||||||
"lightningcss-linux-arm64-musl": ["lightningcss-linux-arm64-musl@1.33.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-yiO5ROMuYQgXbC60yjZU5CYSFZGKXL0HFATXt9mHJn1+zW55oCtMI9NfcVhYLMFDL7gV7oBPon/EmMMGg2OvtQ=="],
|
|
||||||
|
|
||||||
"lightningcss-linux-x64-gnu": ["lightningcss-linux-x64-gnu@1.33.0", "", { "os": "linux", "cpu": "x64" }, "sha512-ar+Ju7LmcN0Jo4FpL4hpFybwNG9/3A/Br5KW2n2jyODg3MEZXaDYADdemoNS+BDNfMgKvylJLj4S5tyRActuAg=="],
|
|
||||||
|
|
||||||
"lightningcss-linux-x64-musl": ["lightningcss-linux-x64-musl@1.33.0", "", { "os": "linux", "cpu": "x64" }, "sha512-RYiYbkokw0trfKqqzfF55lginwEPrD3OJDfTuJzFs1MK6iFnDenaz1fqLLtX4ITG3OktJQXOeTaw1awrBAlZPw=="],
|
|
||||||
|
|
||||||
"lightningcss-win32-arm64-msvc": ["lightningcss-win32-arm64-msvc@1.33.0", "", { "os": "win32", "cpu": "arm64" }, "sha512-1K+MPfLSFVpphzpdbfkhlWk6wBrTObBzS2T6db10PNOZgR9GoVsAWzwNyuhUYYbTp23j+4RrncfujZ4uAzXvwA=="],
|
|
||||||
|
|
||||||
"lightningcss-win32-x64-msvc": ["lightningcss-win32-x64-msvc@1.33.0", "", { "os": "win32", "cpu": "x64" }, "sha512-OlEICDx/Xl0FqSp4bry8zFnCvGpig3Gl4gCquvYwHuqJKEC1+n9NgDniFvqHGmMv1ZkqDJrDqKKSykTDX+ehuA=="],
|
|
||||||
|
|
||||||
"lru-cache": ["lru-cache@5.1.1", "", { "dependencies": { "yallist": "^3.0.2" } }, "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w=="],
|
|
||||||
|
|
||||||
"ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="],
|
|
||||||
|
|
||||||
"nanoid": ["nanoid@3.3.19", "", { "bin": { "nanoid": "bin/nanoid.cjs" } }, "sha512-Y2tUNy4ouw6tq5oDSKeQYGOyhkUBhNOcGV/02KC+6kd9eDGqdZd++mjMiIDilrBYvjEnCYvVtsuHCuP+okSfug=="],
|
|
||||||
|
|
||||||
"node-releases": ["node-releases@2.0.55", "", {}, "sha512-mIrE/Cw9y+9Au6dS5vDKDhQza9YvG6w+ZrS6X+ZzA7yFW/soAeaups4Qzn1bL6g5FVy8WtP79+0j82oPIbqRjQ=="],
|
|
||||||
|
|
||||||
"oxlint": ["oxlint@1.83.0", "", { "optionalDependencies": { "@oxlint/binding-android-arm-eabi": "1.83.0", "@oxlint/binding-android-arm64": "1.83.0", "@oxlint/binding-darwin-arm64": "1.83.0", "@oxlint/binding-darwin-x64": "1.83.0", "@oxlint/binding-freebsd-x64": "1.83.0", "@oxlint/binding-linux-arm-gnueabihf": "1.83.0", "@oxlint/binding-linux-arm-musleabihf": "1.83.0", "@oxlint/binding-linux-arm64-gnu": "1.83.0", "@oxlint/binding-linux-arm64-musl": "1.83.0", "@oxlint/binding-linux-ppc64-gnu": "1.83.0", "@oxlint/binding-linux-riscv64-gnu": "1.83.0", "@oxlint/binding-linux-riscv64-musl": "1.83.0", "@oxlint/binding-linux-s390x-gnu": "1.83.0", "@oxlint/binding-linux-x64-gnu": "1.83.0", "@oxlint/binding-linux-x64-musl": "1.83.0", "@oxlint/binding-openharmony-arm64": "1.83.0", "@oxlint/binding-win32-arm64-msvc": "1.83.0", "@oxlint/binding-win32-ia32-msvc": "1.83.0", "@oxlint/binding-win32-x64-msvc": "1.83.0" }, "peerDependencies": { "oxlint-tsgolint": ">=7.0.2001", "vite-plus": "*" }, "optionalPeers": ["oxlint-tsgolint", "vite-plus"], "bin": { "oxlint": "bin/oxlint" } }, "sha512-cyDzSzaw3uzP0TeCeq3lLRPPoaUxkbB4ZOXj+kn+5r+BX9V+4bNVGk9lxer+WrgcpebH4JxLlJ3KQjveVztOLQ=="],
|
|
||||||
|
|
||||||
"picocolors": ["picocolors@1.1.1", "", {}, "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA=="],
|
|
||||||
|
|
||||||
"picomatch": ["picomatch@4.0.7", "", {}, "sha512-qcJu88Q2IWqJsDD529JKMdwGm/dvInW4HvQnRwiH9JtihJvzGOscDtHE3x1pBKeUOTysQ8kVmLnJ2kJu7yhcGA=="],
|
|
||||||
|
|
||||||
"postcss": ["postcss@8.5.28", "", { "dependencies": { "nanoid": "^3.3.18", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" } }, "sha512-RRuzqDtt5Y9h3quz5hWhK+TPnsmVs6WwSU6LkJMeY4HstUEDuYTG8UJSdawMRzmzAtV+KEoG8N3Qg2qLy5vM/A=="],
|
|
||||||
|
|
||||||
"react": ["react@19.3.0", "", {}, "sha512-E8LUcbtBWt20bbl2YoHfx4ZDBdxVTfOKtCZn9cDSJ4l6/nuoApcpIBcj47t2wZoVX8g2ZHuMHbiShgCR1T5Sog=="],
|
|
||||||
|
|
||||||
"react-dom": ["react-dom@19.3.0", "", { "dependencies": { "scheduler": "^0.28.0" }, "peerDependencies": { "react": "^19.3.0" } }, "sha512-JDk8dgif51OjFoDE70+OT9ICyYr+69HlmihNwp1+Nsfbna3t5sIiCa9ZJktDmQ4/1b/rn26hIAR2uYXDMr5r0Q=="],
|
|
||||||
|
|
||||||
"rolldown": ["rolldown@1.2.8", "", { "dependencies": { "@oxc-project/types": "=0.149.0", "@rolldown/pluginutils": "^1.0.0" }, "optionalDependencies": { "@rolldown/binding-android-arm-eabi": "1.2.8", "@rolldown/binding-android-arm64": "1.2.8", "@rolldown/binding-darwin-arm64": "1.2.8", "@rolldown/binding-darwin-x64": "1.2.8", "@rolldown/binding-freebsd-x64": "1.2.8", "@rolldown/binding-linux-arm-gnueabihf": "1.2.8", "@rolldown/binding-linux-arm64-gnu": "1.2.8", "@rolldown/binding-linux-arm64-musl": "1.2.8", "@rolldown/binding-linux-ppc64-gnu": "1.2.8", "@rolldown/binding-linux-s390x-gnu": "1.2.8", "@rolldown/binding-linux-x64-gnu": "1.2.8", "@rolldown/binding-linux-x64-musl": "1.2.8", "@rolldown/binding-openharmony-arm64": "1.2.8", "@rolldown/binding-win32-arm64-msvc": "1.2.8", "@rolldown/binding-win32-x64-msvc": "1.2.8" }, "bin": { "rolldown": "./bin/cli.mjs" } }, "sha512-Z67nTmhZe7anqnM/EjI392w5i/ANUinjip7QYsOyN37oayduxt3ksdX0hf5OOamkAd53BiIHfbfSzfUmzKFQqQ=="],
|
|
||||||
|
|
||||||
"scheduler": ["scheduler@0.28.0", "", {}, "sha512-juorfCmIkIw8tT+p5BXSm6PJjQF/ycEYmKyzURCIt/RaZIhL+PulbQ9Yu2z1HdOJDdqDTlxA1+xKBmHXJsczAw=="],
|
|
||||||
|
|
||||||
"semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="],
|
|
||||||
|
|
||||||
"source-map-js": ["source-map-js@1.2.1", "", {}, "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA=="],
|
|
||||||
|
|
||||||
"tinyglobby": ["tinyglobby@0.2.17", "", { "dependencies": { "fdir": "^6.5.0", "picomatch": "^4.0.4" } }, "sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g=="],
|
|
||||||
|
|
||||||
"typescript": ["typescript@6.0.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-y2TvuxSZPDyQakkFRPZHKFm+KKVqIisdg9/CZwm9ftvKXLP8NRWj38/ODjNbr43SsoXqNuAisEf1GdCxqWcdBw=="],
|
|
||||||
|
|
||||||
"undici-types": ["undici-types@7.18.2", "", {}, "sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w=="],
|
|
||||||
|
|
||||||
"update-browserslist-db": ["update-browserslist-db@1.3.3", "", { "dependencies": { "escalade": "^3.2.0", "picocolors": "^1.1.1" }, "peerDependencies": { "browserslist": ">= 4.21.0" }, "bin": { "update-browserslist-db": "cli.js" } }, "sha512-pJ2sYawQS0R/WI928Gj5GlPhTGzbMelq0+4INtSYNDV9ErKJcX6xjGWkoG/VnB3dpUm00zALaqkrUD77pO5TDQ=="],
|
|
||||||
|
|
||||||
"vite": ["vite@8.3.0", "", { "dependencies": { "lightningcss": "^1.33.0", "picomatch": "^4.0.7", "postcss": "^8.5.28", "rolldown": "~1.2.6", "tinyglobby": "^0.2.17" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "peerDependencies": { "@types/node": "^20.19.0 || >=22.12.0", "@vitejs/devtools": "^0.7.1", "esbuild": "^0.27.0 || ^0.28.0", "jiti": ">=1.21.0", "less": "^4.0.0", "sass": "^1.70.0", "sass-embedded": "^1.70.0", "stylus": ">=0.54.8", "sugarss": "^5.0.0", "terser": "^5.16.0", "tsx": "^4.8.1", "yaml": "^2.4.2" }, "optionalPeers": ["@types/node", "@vitejs/devtools", "esbuild", "jiti", "less", "sass", "sass-embedded", "stylus", "sugarss", "terser", "tsx", "yaml"], "bin": { "vite": "bin/vite.js" } }, "sha512-lhZBVvEHefgE+HQZC9O7EBJgCU/nVzFNl7vkS4RE0APtWLP02/8QVIkQtzBxPquh7lq5/78NHipTj7ODQ6XuyQ=="],
|
|
||||||
|
|
||||||
"yallist": ["yallist@3.1.1", "", {}, "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g=="],
|
|
||||||
}
|
|
||||||
}
|
|
||||||
+1
-1
@@ -4,7 +4,7 @@
|
|||||||
<meta charset="UTF-8" />
|
<meta charset="UTF-8" />
|
||||||
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
|
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
<title>docs</title>
|
<title>my-shadcn-ui Documentation</title>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div id="root"></div>
|
<div id="root"></div>
|
||||||
|
|||||||
+1
-4
@@ -5,8 +5,7 @@
|
|||||||
"type": "module",
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "vite",
|
"dev": "vite",
|
||||||
"build": "tsc -b && vite build",
|
"build": "tsc -b && vite build && vite build --ssr src/entry-server.tsx --outDir .ssr && bun scripts/prerender.ts",
|
||||||
"lint": "oxlint",
|
|
||||||
"preview": "vite preview",
|
"preview": "vite preview",
|
||||||
"typecheck": "tsc -b"
|
"typecheck": "tsc -b"
|
||||||
},
|
},
|
||||||
@@ -14,7 +13,6 @@
|
|||||||
"@icones/react": "^0.0.1",
|
"@icones/react": "^0.0.1",
|
||||||
"@workspace/i18n": "workspace:*",
|
"@workspace/i18n": "workspace:*",
|
||||||
"@workspace/preferences": "workspace:*",
|
"@workspace/preferences": "workspace:*",
|
||||||
"@workspace/ui": "workspace:*",
|
|
||||||
"@workspace/search": "workspace:*",
|
"@workspace/search": "workspace:*",
|
||||||
"clsx": "^2.1.1",
|
"clsx": "^2.1.1",
|
||||||
"react": "^19.2.8",
|
"react": "^19.2.8",
|
||||||
@@ -32,7 +30,6 @@
|
|||||||
"@types/react-dom": "^19.2.7",
|
"@types/react-dom": "^19.2.7",
|
||||||
"@vitejs/plugin-react": "^6.1.1",
|
"@vitejs/plugin-react": "^6.1.1",
|
||||||
"babel-plugin-react-compiler": "^1.0.0",
|
"babel-plugin-react-compiler": "^1.0.0",
|
||||||
"oxlint": "^1.81.0",
|
|
||||||
"satteri": "^0.10.5",
|
"satteri": "^0.10.5",
|
||||||
"tailwindcss": "^4.3.3",
|
"tailwindcss": "^4.3.3",
|
||||||
"typescript": "~6.0.2",
|
"typescript": "~6.0.2",
|
||||||
|
|||||||
@@ -1,24 +0,0 @@
|
|||||||
<svg xmlns="http://www.w3.org/2000/svg">
|
|
||||||
<symbol id="bluesky-icon" viewBox="0 0 16 17">
|
|
||||||
<g clip-path="url(#bluesky-clip)"><path fill="#08060d" d="M7.75 7.735c-.693-1.348-2.58-3.86-4.334-5.097-1.68-1.187-2.32-.981-2.74-.79C.188 2.065.1 2.812.1 3.251s.241 3.602.398 4.13c.52 1.744 2.367 2.333 4.07 2.145-2.495.37-4.71 1.278-1.805 4.512 3.196 3.309 4.38-.71 4.987-2.746.608 2.036 1.307 5.91 4.93 2.746 2.72-2.746.747-4.143-1.747-4.512 1.702.189 3.55-.4 4.07-2.145.156-.528.397-3.691.397-4.13s-.088-1.186-.575-1.406c-.42-.19-1.06-.395-2.741.79-1.755 1.24-3.64 3.752-4.334 5.099"/></g>
|
|
||||||
<defs><clipPath id="bluesky-clip"><path fill="#fff" d="M.1.85h15.3v15.3H.1z"/></clipPath></defs>
|
|
||||||
</symbol>
|
|
||||||
<symbol id="discord-icon" viewBox="0 0 20 19">
|
|
||||||
<path fill="#08060d" d="M16.224 3.768a14.5 14.5 0 0 0-3.67-1.153c-.158.286-.343.67-.47.976a13.5 13.5 0 0 0-4.067 0c-.128-.306-.317-.69-.476-.976A14.4 14.4 0 0 0 3.868 3.77C1.546 7.28.916 10.703 1.231 14.077a14.7 14.7 0 0 0 4.5 2.306q.545-.748.965-1.587a9.5 9.5 0 0 1-1.518-.74q.191-.14.372-.293c2.927 1.369 6.107 1.369 8.999 0q.183.152.372.294-.723.437-1.52.74.418.838.963 1.588a14.6 14.6 0 0 0 4.504-2.308c.37-3.911-.63-7.302-2.644-10.309m-9.13 8.234c-.878 0-1.599-.82-1.599-1.82 0-.998.705-1.82 1.6-1.82.894 0 1.614.82 1.599 1.82.001 1-.705 1.82-1.6 1.82m5.91 0c-.878 0-1.599-.82-1.599-1.82 0-.998.705-1.82 1.6-1.82.893 0 1.614.82 1.599 1.82 0 1-.706 1.82-1.6 1.82"/>
|
|
||||||
</symbol>
|
|
||||||
<symbol id="documentation-icon" viewBox="0 0 21 20">
|
|
||||||
<path fill="none" stroke="#aa3bff" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.35" d="m15.5 13.333 1.533 1.322c.645.555.967.833.967 1.178s-.322.623-.967 1.179L15.5 18.333m-3.333-5-1.534 1.322c-.644.555-.966.833-.966 1.178s.322.623.966 1.179l1.534 1.321"/>
|
|
||||||
<path fill="none" stroke="#aa3bff" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.35" d="M17.167 10.836v-4.32c0-1.41 0-2.117-.224-2.68-.359-.906-1.118-1.621-2.08-1.96-.599-.21-1.349-.21-2.848-.21-2.623 0-3.935 0-4.983.369-1.684.591-3.013 1.842-3.641 3.428C3 6.449 3 7.684 3 10.154v2.122c0 2.558 0 3.838.706 4.726q.306.383.713.671c.76.536 1.79.64 3.581.66"/>
|
|
||||||
<path fill="none" stroke="#aa3bff" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.35" d="M3 10a2.78 2.78 0 0 1 2.778-2.778c.555 0 1.209.097 1.748-.047.48-.129.854-.503.982-.982.145-.54.048-1.194.048-1.749a2.78 2.78 0 0 1 2.777-2.777"/>
|
|
||||||
</symbol>
|
|
||||||
<symbol id="github-icon" viewBox="0 0 19 19">
|
|
||||||
<path fill="#08060d" fill-rule="evenodd" d="M9.356 1.85C5.05 1.85 1.57 5.356 1.57 9.694a7.84 7.84 0 0 0 5.324 7.44c.387.079.528-.168.528-.376 0-.182-.013-.805-.013-1.454-2.165.467-2.616-.935-2.616-.935-.349-.91-.864-1.143-.864-1.143-.71-.48.051-.48.051-.48.787.051 1.2.805 1.2.805.695 1.194 1.817.857 2.268.649.064-.507.27-.857.49-1.052-1.728-.182-3.545-.857-3.545-3.87 0-.857.31-1.558.8-2.104-.078-.195-.349-1 .077-2.078 0 0 .657-.208 2.14.805a7.5 7.5 0 0 1 1.946-.26c.657 0 1.328.092 1.946.26 1.483-1.013 2.14-.805 2.14-.805.426 1.078.155 1.883.078 2.078.502.546.799 1.247.799 2.104 0 3.013-1.818 3.675-3.558 3.87.284.247.528.714.528 1.454 0 1.052-.012 1.896-.012 2.156 0 .208.142.455.528.377a7.84 7.84 0 0 0 5.324-7.441c.013-4.338-3.48-7.844-7.773-7.844" clip-rule="evenodd"/>
|
|
||||||
</symbol>
|
|
||||||
<symbol id="social-icon" viewBox="0 0 20 20">
|
|
||||||
<path fill="none" stroke="#aa3bff" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.35" d="M12.5 6.667a4.167 4.167 0 1 0-8.334 0 4.167 4.167 0 0 0 8.334 0"/>
|
|
||||||
<path fill="none" stroke="#aa3bff" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.35" d="M2.5 16.667a5.833 5.833 0 0 1 8.75-5.053m3.837.474.513 1.035c.07.144.257.282.414.309l.93.155c.596.1.736.536.307.965l-.723.73a.64.64 0 0 0-.152.531l.207.903c.164.715-.213.991-.84.618l-.872-.52a.63.63 0 0 0-.577 0l-.872.52c-.624.373-1.003.094-.84-.618l.207-.903a.64.64 0 0 0-.152-.532l-.723-.729c-.426-.43-.289-.864.306-.964l.93-.156a.64.64 0 0 0 .412-.31l.513-1.034c.28-.562.735-.562 1.012 0"/>
|
|
||||||
</symbol>
|
|
||||||
<symbol id="x-icon" viewBox="0 0 19 19">
|
|
||||||
<path fill="#08060d" fill-rule="evenodd" d="M1.893 1.98c.052.072 1.245 1.769 2.653 3.77l2.892 4.114c.183.261.333.48.333.486s-.068.089-.152.183l-.522.593-.765.867-3.597 4.087c-.375.426-.734.834-.798.905a1 1 0 0 0-.118.148c0 .01.236.017.664.017h.663l.729-.83c.4-.457.796-.906.879-.999a692 692 0 0 0 1.794-2.038c.034-.037.301-.34.594-.675l.551-.624.345-.392a7 7 0 0 1 .34-.374c.006 0 .93 1.306 2.052 2.903l2.084 2.965.045.063h2.275c1.87 0 2.273-.003 2.266-.021-.008-.02-1.098-1.572-3.894-5.547-2.013-2.862-2.28-3.246-2.273-3.266.008-.019.282-.332 2.085-2.38l2-2.274 1.567-1.782c.022-.028-.016-.03-.65-.03h-.674l-.3.342a871 871 0 0 1-1.782 2.025c-.067.075-.405.458-.75.852a100 100 0 0 1-.803.91c-.148.172-.299.344-.99 1.127-.304.343-.32.358-.345.327-.015-.019-.904-1.282-1.976-2.808L6.365 1.85H1.8zm1.782.91 8.078 11.294c.772 1.08 1.413 1.973 1.425 1.984.016.017.241.02 1.05.017l1.03-.004-2.694-3.766L7.796 5.75 5.722 2.852l-1.039-.004-1.039-.004z" clip-rule="evenodd"/>
|
|
||||||
</symbol>
|
|
||||||
</svg>
|
|
||||||
|
Before Width: | Height: | Size: 4.9 KiB |
@@ -0,0 +1,88 @@
|
|||||||
|
import { mkdir, readFile, rm, writeFile } from "node:fs/promises"
|
||||||
|
import { dirname, join } from "node:path"
|
||||||
|
import { pathToFileURL } from "node:url"
|
||||||
|
|
||||||
|
import { docLocales } from "../src/content/types.ts"
|
||||||
|
|
||||||
|
type StaticPage = {
|
||||||
|
html: string
|
||||||
|
locale: (typeof docLocales)[number]
|
||||||
|
metadata: { description: string; title: string }
|
||||||
|
}
|
||||||
|
|
||||||
|
type ServerEntry = {
|
||||||
|
getStaticDocRoutes: () => readonly string[]
|
||||||
|
getStaticSearchIndex: (locale: (typeof docLocales)[number]) => unknown
|
||||||
|
renderStaticPage: (pathname: string) => Promise<StaticPage>
|
||||||
|
}
|
||||||
|
|
||||||
|
const docsDirectory = dirname(dirname(import.meta.filename))
|
||||||
|
const outputDirectory = join(docsDirectory, "dist")
|
||||||
|
const serverDirectory = join(docsDirectory, ".ssr")
|
||||||
|
const serverEntryUrl = pathToFileURL(
|
||||||
|
join(serverDirectory, "entry-server.js")
|
||||||
|
).href
|
||||||
|
const server = (await import(serverEntryUrl)) as ServerEntry
|
||||||
|
const template = await readFile(join(outputDirectory, "index.html"), "utf8")
|
||||||
|
|
||||||
|
await Promise.all(
|
||||||
|
server.getStaticDocRoutes().map(async (route) => {
|
||||||
|
const page = await server.renderStaticPage(route)
|
||||||
|
const filename = getRouteFilename(route)
|
||||||
|
await mkdir(dirname(filename), { recursive: true })
|
||||||
|
await writeFile(filename, createHtml(template, page), "utf8")
|
||||||
|
})
|
||||||
|
)
|
||||||
|
|
||||||
|
const notFoundPage = await server.renderStaticPage("/404")
|
||||||
|
await writeFile(
|
||||||
|
join(outputDirectory, "404.html"),
|
||||||
|
createHtml(template, notFoundPage),
|
||||||
|
"utf8"
|
||||||
|
)
|
||||||
|
|
||||||
|
const searchDirectory = join(outputDirectory, "search")
|
||||||
|
await mkdir(searchDirectory, { recursive: true })
|
||||||
|
await Promise.all(
|
||||||
|
docLocales.map((locale) =>
|
||||||
|
writeFile(
|
||||||
|
join(searchDirectory, `${locale}.json`),
|
||||||
|
JSON.stringify(server.getStaticSearchIndex(locale)),
|
||||||
|
"utf8"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
await rm(serverDirectory, { recursive: true })
|
||||||
|
|
||||||
|
function getRouteFilename(route: string) {
|
||||||
|
return route === "/"
|
||||||
|
? join(outputDirectory, "index.html")
|
||||||
|
: join(outputDirectory, route.slice(1), "index.html")
|
||||||
|
}
|
||||||
|
|
||||||
|
function createHtml(
|
||||||
|
source: string,
|
||||||
|
page: Awaited<ReturnType<typeof server.renderStaticPage>>
|
||||||
|
) {
|
||||||
|
const description = `<meta name="description" content="${escapeAttribute(page.metadata.description)}" />`
|
||||||
|
|
||||||
|
return source
|
||||||
|
.replace(/<html lang="[^"]*">/, `<html lang="${page.locale}">`)
|
||||||
|
.replace(
|
||||||
|
/<title>[^<]*<\/title>/,
|
||||||
|
`<title>${escapeText(page.metadata.title)}</title>\n ${description}`
|
||||||
|
)
|
||||||
|
.replace('<div id="root"></div>', `<div id="root">${page.html}</div>`)
|
||||||
|
}
|
||||||
|
|
||||||
|
function escapeText(value: string) {
|
||||||
|
return value
|
||||||
|
.replaceAll("&", "&")
|
||||||
|
.replaceAll("<", "<")
|
||||||
|
.replaceAll(">", ">")
|
||||||
|
}
|
||||||
|
|
||||||
|
function escapeAttribute(value: string) {
|
||||||
|
return escapeText(value).replaceAll('"', """)
|
||||||
|
}
|
||||||
+36
-18
@@ -12,13 +12,15 @@ import { DocsPreferencesProvider } from "./components/preferences-provider"
|
|||||||
import { DocsSearchProvider } from "./components/docs-search-provider"
|
import { DocsSearchProvider } from "./components/docs-search-provider"
|
||||||
import { resolveDocLocale } from "./content/registry"
|
import { resolveDocLocale } from "./content/registry"
|
||||||
import { useTranslate } from "./lib/locale"
|
import { useTranslate } from "./lib/locale"
|
||||||
|
import { PathnameProvider } from "./lib/router"
|
||||||
|
import type { Preferences } from "@workspace/preferences"
|
||||||
|
|
||||||
const Index = lazy(() => import("./pages/index"))
|
const Index = lazy(() => import("./pages/index"))
|
||||||
const Article = lazy(() => import("./pages/article"))
|
const Article = lazy(() => import("./pages/article"))
|
||||||
const Settings = lazy(() => import("./pages/settings"))
|
const Settings = lazy(() => import("./pages/settings"))
|
||||||
|
|
||||||
type RouteDefinition = {
|
type RouteDefinition = {
|
||||||
Component: ComponentType
|
Component: ComponentType<{ pathname: string }>
|
||||||
matches: (pathname: string) => boolean
|
matches: (pathname: string) => boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -40,8 +42,15 @@ const routes: RouteDefinition[] = [
|
|||||||
},
|
},
|
||||||
]
|
]
|
||||||
|
|
||||||
function App() {
|
export type AppProps = {
|
||||||
const [currentUrl, setCurrentUrl] = useState(() => window.location.href)
|
initialPreferences?: Preferences
|
||||||
|
initialUrl?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
function App({ initialPreferences, initialUrl }: AppProps) {
|
||||||
|
const [currentUrl, setCurrentUrl] = useState(
|
||||||
|
() => initialUrl ?? window.location.href
|
||||||
|
)
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
function updateRoute() {
|
function updateRoute() {
|
||||||
@@ -99,26 +108,35 @@ function App() {
|
|||||||
}
|
}
|
||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
const { pathname } = new URL(currentUrl)
|
const { pathname } = new URL(currentUrl, "https://docs.local")
|
||||||
const Route = routes.find((route) => route.matches(pathname))?.Component
|
const Route = routes.find((route) => route.matches(pathname))?.Component
|
||||||
const locale = resolveDocLocale(pathname)
|
const locale = resolveDocLocale(pathname)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<DocsPreferencesProvider routeLocale={locale}>
|
<DocsPreferencesProvider
|
||||||
|
initialPreferences={initialPreferences}
|
||||||
|
routeLocale={locale}
|
||||||
|
>
|
||||||
<LocaleProvider locale={locale}>
|
<LocaleProvider locale={locale}>
|
||||||
<DocsSearchProvider>
|
<PathnameProvider pathname={pathname}>
|
||||||
<div style={rootCSSVariables}>
|
<DocsSearchProvider>
|
||||||
<Suspense
|
<div style={rootCSSVariables}>
|
||||||
fallback={
|
<Suspense
|
||||||
<p className="p-6 text-slate-500 dark:text-slate-400">
|
fallback={
|
||||||
Loading…
|
<p className="p-6 text-slate-500 dark:text-slate-400">
|
||||||
</p>
|
Loading…
|
||||||
}
|
</p>
|
||||||
>
|
}
|
||||||
{Route ? <Route key={pathname} /> : <NotFound />}
|
>
|
||||||
</Suspense>
|
{Route ? (
|
||||||
</div>
|
<Route key={pathname} pathname={pathname} />
|
||||||
</DocsSearchProvider>
|
) : (
|
||||||
|
<NotFound />
|
||||||
|
)}
|
||||||
|
</Suspense>
|
||||||
|
</div>
|
||||||
|
</DocsSearchProvider>
|
||||||
|
</PathnameProvider>
|
||||||
</LocaleProvider>
|
</LocaleProvider>
|
||||||
</DocsPreferencesProvider>
|
</DocsPreferencesProvider>
|
||||||
)
|
)
|
||||||
|
|||||||
Binary file not shown.
|
Before Width: | Height: | Size: 13 KiB |
@@ -1 +0,0 @@
|
|||||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="35.93" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 228"><path fill="#00D8FF" d="M210.483 73.824a171.49 171.49 0 0 0-8.24-2.597c.465-1.9.893-3.777 1.273-5.621c6.238-30.281 2.16-54.676-11.769-62.708c-13.355-7.7-35.196.329-57.254 19.526a171.23 171.23 0 0 0-6.375 5.848a155.866 155.866 0 0 0-4.241-3.917C100.759 3.829 77.587-4.822 63.673 3.233C50.33 10.957 46.379 33.89 51.995 62.588a170.974 170.974 0 0 0 1.892 8.48c-3.28.932-6.445 1.924-9.474 2.98C17.309 83.498 0 98.307 0 113.668c0 15.865 18.582 31.778 46.812 41.427a145.52 145.52 0 0 0 6.921 2.165a167.467 167.467 0 0 0-2.01 9.138c-5.354 28.2-1.173 50.591 12.134 58.266c13.744 7.926 36.812-.22 59.273-19.855a145.567 145.567 0 0 0 5.342-4.923a168.064 168.064 0 0 0 6.92 6.314c21.758 18.722 43.246 26.282 56.54 18.586c13.731-7.949 18.194-32.003 12.4-61.268a145.016 145.016 0 0 0-1.535-6.842c1.62-.48 3.21-.974 4.76-1.488c29.348-9.723 48.443-25.443 48.443-41.52c0-15.417-17.868-30.326-45.517-39.844Zm-6.365 70.984c-1.4.463-2.836.91-4.3 1.345c-3.24-10.257-7.612-21.163-12.963-32.432c5.106-11 9.31-21.767 12.459-31.957c2.619.758 5.16 1.557 7.61 2.4c23.69 8.156 38.14 20.213 38.14 29.504c0 9.896-15.606 22.743-40.946 31.14Zm-10.514 20.834c2.562 12.94 2.927 24.64 1.23 33.787c-1.524 8.219-4.59 13.698-8.382 15.893c-8.067 4.67-25.32-1.4-43.927-17.412a156.726 156.726 0 0 1-6.437-5.87c7.214-7.889 14.423-17.06 21.459-27.246c12.376-1.098 24.068-2.894 34.671-5.345a134.17 134.17 0 0 1 1.386 6.193ZM87.276 214.515c-7.882 2.783-14.16 2.863-17.955.675c-8.075-4.657-11.432-22.636-6.853-46.752a156.923 156.923 0 0 1 1.869-8.499c10.486 2.32 22.093 3.988 34.498 4.994c7.084 9.967 14.501 19.128 21.976 27.15a134.668 134.668 0 0 1-4.877 4.492c-9.933 8.682-19.886 14.842-28.658 17.94ZM50.35 144.747c-12.483-4.267-22.792-9.812-29.858-15.863c-6.35-5.437-9.555-10.836-9.555-15.216c0-9.322 13.897-21.212 37.076-29.293c2.813-.98 5.757-1.905 8.812-2.773c3.204 10.42 7.406 21.315 12.477 32.332c-5.137 11.18-9.399 22.249-12.634 32.792a134.718 134.718 0 0 1-6.318-1.979Zm12.378-84.26c-4.811-24.587-1.616-43.134 6.425-47.789c8.564-4.958 27.502 2.111 47.463 19.835a144.318 144.318 0 0 1 3.841 3.545c-7.438 7.987-14.787 17.08-21.808 26.988c-12.04 1.116-23.565 2.908-34.161 5.309a160.342 160.342 0 0 1-1.76-7.887Zm110.427 27.268a347.8 347.8 0 0 0-7.785-12.803c8.168 1.033 15.994 2.404 23.343 4.08c-2.206 7.072-4.956 14.465-8.193 22.045a381.151 381.151 0 0 0-7.365-13.322Zm-45.032-43.861c5.044 5.465 10.096 11.566 15.065 18.186a322.04 322.04 0 0 0-30.257-.006c4.974-6.559 10.069-12.652 15.192-18.18ZM82.802 87.83a323.167 323.167 0 0 0-7.227 13.238c-3.184-7.553-5.909-14.98-8.134-22.152c7.304-1.634 15.093-2.97 23.209-3.984a321.524 321.524 0 0 0-7.848 12.897Zm8.081 65.352c-8.385-.936-16.291-2.203-23.593-3.793c2.26-7.3 5.045-14.885 8.298-22.6a321.187 321.187 0 0 0 7.257 13.246c2.594 4.48 5.28 8.868 8.038 13.147Zm37.542 31.03c-5.184-5.592-10.354-11.779-15.403-18.433c4.902.192 9.899.29 14.978.29c5.218 0 10.376-.117 15.453-.343c-4.985 6.774-10.018 12.97-15.028 18.486Zm52.198-57.817c3.422 7.8 6.306 15.345 8.596 22.52c-7.422 1.694-15.436 3.058-23.88 4.071a382.417 382.417 0 0 0 7.859-13.026a347.403 347.403 0 0 0 7.425-13.565Zm-16.898 8.101a358.557 358.557 0 0 1-12.281 19.815a329.4 329.4 0 0 1-23.444.823c-7.967 0-15.716-.248-23.178-.732a310.202 310.202 0 0 1-12.513-19.846h.001a307.41 307.41 0 0 1-10.923-20.627a310.278 310.278 0 0 1 10.89-20.637l-.001.001a307.318 307.318 0 0 1 12.413-19.761c7.613-.576 15.42-.876 23.31-.876H128c7.926 0 15.743.303 23.354.883a329.357 329.357 0 0 1 12.335 19.695a358.489 358.489 0 0 1 11.036 20.54a329.472 329.472 0 0 1-11 20.722Zm22.56-122.124c8.572 4.944 11.906 24.881 6.52 51.026c-.344 1.668-.73 3.367-1.15 5.09c-10.622-2.452-22.155-4.275-34.23-5.408c-7.034-10.017-14.323-19.124-21.64-27.008a160.789 160.789 0 0 1 5.888-5.4c18.9-16.447 36.564-22.941 44.612-18.3ZM128 90.808c12.625 0 22.86 10.235 22.86 22.86s-10.235 22.86-22.86 22.86s-22.86-10.235-22.86-22.86s10.235-22.86 22.86-22.86Z"></path></svg>
|
|
||||||
|
Before Width: | Height: | Size: 4.0 KiB |
File diff suppressed because one or more lines are too long
|
Before Width: | Height: | Size: 8.5 KiB |
@@ -9,18 +9,8 @@ import { messages as searchMessagesEnUS } from "@workspace/search/locales/en-US"
|
|||||||
import { messages as searchMessagesZhHans } from "@workspace/search/locales/zh-Hans"
|
import { messages as searchMessagesZhHans } from "@workspace/search/locales/zh-Hans"
|
||||||
import React from "react"
|
import React from "react"
|
||||||
|
|
||||||
import {
|
import { loadDocSearchIndex } from "../content/search-index.client"
|
||||||
getDocHref,
|
import type { DocLocale, DocSearchEntry } from "../content/types"
|
||||||
getDocPackages,
|
|
||||||
getDocSearchText,
|
|
||||||
getDocSectionLabel,
|
|
||||||
} from "../content/registry"
|
|
||||||
import type {
|
|
||||||
DocLocale,
|
|
||||||
DocPackage,
|
|
||||||
DocPage,
|
|
||||||
DocTocItem,
|
|
||||||
} from "../content/types"
|
|
||||||
import { useLocale } from "../lib/locale"
|
import { useLocale } from "../lib/locale"
|
||||||
|
|
||||||
const searchCatalogs = {
|
const searchCatalogs = {
|
||||||
@@ -57,69 +47,73 @@ export function DocsSearchProvider({
|
|||||||
}
|
}
|
||||||
|
|
||||||
function createDocsSearchAdapter(locale: DocLocale): SearchAdapter {
|
function createDocsSearchAdapter(locale: DocLocale): SearchAdapter {
|
||||||
const docPackages = getDocPackages(locale)
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
async search({ query, signal }) {
|
async search({ query, signal }) {
|
||||||
const normalizedQuery = normalize(query)
|
const normalizedQuery = normalize(query)
|
||||||
if (!normalizedQuery) return { groups: [] }
|
if (!normalizedQuery) return { groups: [] }
|
||||||
|
|
||||||
|
const index = await loadDocSearchIndex(locale)
|
||||||
|
if (signal.aborted) return { groups: [] }
|
||||||
|
|
||||||
const terms = normalizedQuery.split(/\s+/).filter(Boolean)
|
const terms = normalizedQuery.split(/\s+/).filter(Boolean)
|
||||||
const groups = docPackages.flatMap((docPackage) => {
|
const groups = new Map<
|
||||||
const items = docPackage.pages
|
string,
|
||||||
.map((page) => ({
|
{
|
||||||
item: createResultItem(docPackage, page, locale),
|
id: string
|
||||||
score: getMatchScore(
|
items: Array<{ item: SearchResultItem; score: number }>
|
||||||
normalizedQuery,
|
label: string
|
||||||
terms,
|
total: number
|
||||||
docPackage.label,
|
}
|
||||||
page
|
>()
|
||||||
),
|
|
||||||
}))
|
for (const entry of index) {
|
||||||
.filter((result) => result.score >= 0)
|
const score = getMatchScore(normalizedQuery, terms, entry)
|
||||||
.sort(
|
if (score < 0) continue
|
||||||
|
|
||||||
|
const group = groups.get(entry.packageKey) ?? {
|
||||||
|
id: entry.packageKey,
|
||||||
|
items: [],
|
||||||
|
label: entry.packageLabel,
|
||||||
|
total: 0,
|
||||||
|
}
|
||||||
|
group.items.push({ item: createResultItem(entry), score })
|
||||||
|
group.total += 1
|
||||||
|
groups.set(entry.packageKey, group)
|
||||||
|
}
|
||||||
|
|
||||||
|
const results = Array.from(groups.values(), (group) => ({
|
||||||
|
id: group.id,
|
||||||
|
label: group.label,
|
||||||
|
total: group.total,
|
||||||
|
items: group.items
|
||||||
|
.toSorted(
|
||||||
(left, right) =>
|
(left, right) =>
|
||||||
right.score - left.score ||
|
right.score - left.score ||
|
||||||
left.item.title.localeCompare(right.item.title, locale)
|
left.item.title.localeCompare(right.item.title, locale)
|
||||||
)
|
)
|
||||||
.map((result) => result.item)
|
.map((result) => result.item),
|
||||||
|
}))
|
||||||
return items.length > 0
|
|
||||||
? [
|
|
||||||
{
|
|
||||||
id: docPackage.key,
|
|
||||||
label: docPackage.label,
|
|
||||||
items,
|
|
||||||
total: items.length,
|
|
||||||
},
|
|
||||||
]
|
|
||||||
: []
|
|
||||||
})
|
|
||||||
|
|
||||||
if (signal.aborted) return { groups: [] }
|
if (signal.aborted) return { groups: [] }
|
||||||
return { groups }
|
return { groups: results }
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function createResultItem(
|
function createResultItem(entry: DocSearchEntry): SearchResultItem {
|
||||||
docPackage: DocPackage,
|
|
||||||
page: DocPage,
|
|
||||||
locale: DocLocale
|
|
||||||
): SearchResultItem {
|
|
||||||
return {
|
return {
|
||||||
id: `${page.section}/${page.slug}`,
|
id: entry.id,
|
||||||
title: page.title,
|
title: entry.title,
|
||||||
description: page.description,
|
description: entry.description,
|
||||||
keywords: [
|
keywords: [
|
||||||
docPackage.label,
|
entry.packageLabel,
|
||||||
getDocSectionLabel(page.section, locale),
|
entry.sectionLabel,
|
||||||
...page.toc.flatMap(flattenTocTitles),
|
...entry.toc,
|
||||||
getDocSearchText(page),
|
entry.body,
|
||||||
],
|
],
|
||||||
meta: [getDocSectionLabel(page.section, locale)],
|
meta: [entry.sectionLabel],
|
||||||
payload: {
|
payload: {
|
||||||
href: getDocHref(docPackage, page),
|
href: entry.href,
|
||||||
} satisfies DocsSearchPayload,
|
} satisfies DocsSearchPayload,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -127,14 +121,13 @@ function createResultItem(
|
|||||||
function getMatchScore(
|
function getMatchScore(
|
||||||
query: string,
|
query: string,
|
||||||
terms: readonly string[],
|
terms: readonly string[],
|
||||||
packageLabel: string,
|
entry: DocSearchEntry
|
||||||
page: DocPage
|
|
||||||
) {
|
) {
|
||||||
const title = normalize(page.title)
|
const title = normalize(entry.title)
|
||||||
const description = normalize(page.description)
|
const description = normalize(entry.description)
|
||||||
const packageName = normalize(packageLabel)
|
const packageName = normalize(entry.packageLabel)
|
||||||
const toc = normalize(page.toc.flatMap(flattenTocTitles).join(" "))
|
const toc = normalize(entry.toc.join(" "))
|
||||||
const body = normalize(getDocSearchText(page))
|
const body = normalize(entry.body)
|
||||||
const searchableText = [packageName, title, description, toc, body].join(" ")
|
const searchableText = [packageName, title, description, toc, body].join(" ")
|
||||||
|
|
||||||
if (!terms.every((term) => searchableText.includes(term))) return -1
|
if (!terms.every((term) => searchableText.includes(term))) return -1
|
||||||
@@ -147,15 +140,11 @@ function getMatchScore(
|
|||||||
else if (packageName.includes(query)) score += 20
|
else if (packageName.includes(query)) score += 20
|
||||||
if (description.includes(query)) score += 15
|
if (description.includes(query)) score += 15
|
||||||
if (toc.includes(query)) score += 10
|
if (toc.includes(query)) score += 10
|
||||||
if (page.section === "overview") score += 2
|
if (entry.id === "overview/overview") score += 2
|
||||||
|
|
||||||
return score
|
return score
|
||||||
}
|
}
|
||||||
|
|
||||||
function flattenTocTitles(item: DocTocItem): readonly string[] {
|
|
||||||
return [item.title, ...(item.items?.flatMap(flattenTocTitles) ?? [])]
|
|
||||||
}
|
|
||||||
|
|
||||||
function normalize(value: string) {
|
function normalize(value: string) {
|
||||||
return value.normalize("NFKC").toLocaleLowerCase().trim()
|
return value.normalize("NFKC").toLocaleLowerCase().trim()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,264 +0,0 @@
|
|||||||
import { Icon } from "@icones/react"
|
|
||||||
import { usePreference } from "@workspace/preferences"
|
|
||||||
import { useEffect, useId, useRef, useState } from "react"
|
|
||||||
import { createPortal } from "react-dom"
|
|
||||||
|
|
||||||
import { LocaleFlag } from "./locale-flag"
|
|
||||||
import { getLocalizedHref } from "../content/registry"
|
|
||||||
import type { DocLocale } from "../content/types"
|
|
||||||
import { useLocale, useTranslate } from "../lib/locale"
|
|
||||||
import { useIsMobile } from "../lib/use-mobile"
|
|
||||||
|
|
||||||
type LocaleOption = {
|
|
||||||
label: string
|
|
||||||
locale: DocLocale
|
|
||||||
}
|
|
||||||
|
|
||||||
const localeOptions: readonly LocaleOption[] = [
|
|
||||||
{ label: "简体中文", locale: "zh-Hans" },
|
|
||||||
{ label: "English", locale: "en-US" },
|
|
||||||
]
|
|
||||||
|
|
||||||
export function LanguageSwitcher() {
|
|
||||||
const locale = useLocale()
|
|
||||||
const t = useTranslate()
|
|
||||||
const isMobile = useIsMobile()
|
|
||||||
const [, setLocaleMode] = usePreference("locale-mode")
|
|
||||||
const [, setPreferredLocale] = usePreference("locale")
|
|
||||||
const [open, setOpen] = useState(false)
|
|
||||||
const rootRef = useRef<HTMLDivElement>(null)
|
|
||||||
const menuRef = useRef<HTMLDivElement>(null)
|
|
||||||
const triggerRef = useRef<HTMLButtonElement>(null)
|
|
||||||
const menuId = useId()
|
|
||||||
const selectedLocale = getLocaleOption(locale)
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (!open) return
|
|
||||||
|
|
||||||
function isInsideSwitcher(target: EventTarget | null) {
|
|
||||||
return (
|
|
||||||
target instanceof Node &&
|
|
||||||
(rootRef.current?.contains(target) || menuRef.current?.contains(target))
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
function closeAndRestoreFocus() {
|
|
||||||
setOpen(false)
|
|
||||||
window.requestAnimationFrame(() => triggerRef.current?.focus())
|
|
||||||
}
|
|
||||||
|
|
||||||
function handlePointerDown(event: PointerEvent) {
|
|
||||||
if (isInsideSwitcher(event.target)) return
|
|
||||||
|
|
||||||
if (isMobile) {
|
|
||||||
closeAndRestoreFocus()
|
|
||||||
} else {
|
|
||||||
setOpen(false)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function handleFocusIn(event: FocusEvent) {
|
|
||||||
if (!isMobile && !isInsideSwitcher(event.target)) setOpen(false)
|
|
||||||
}
|
|
||||||
|
|
||||||
function handleKeyDown(event: KeyboardEvent) {
|
|
||||||
if (event.key === "Escape") {
|
|
||||||
event.preventDefault()
|
|
||||||
closeAndRestoreFocus()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!isMobile || event.key !== "Tab") return
|
|
||||||
|
|
||||||
const items = getMenuItems(menuRef.current)
|
|
||||||
const firstItem = items[0]
|
|
||||||
const lastItem = items.at(-1)
|
|
||||||
if (!firstItem || !lastItem) return
|
|
||||||
|
|
||||||
if (event.shiftKey && document.activeElement === firstItem) {
|
|
||||||
event.preventDefault()
|
|
||||||
lastItem.focus()
|
|
||||||
} else if (!event.shiftKey && document.activeElement === lastItem) {
|
|
||||||
event.preventDefault()
|
|
||||||
firstItem.focus()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const previousOverflow = document.body.style.overflow
|
|
||||||
if (isMobile) {
|
|
||||||
document.body.style.overflow = "hidden"
|
|
||||||
window.requestAnimationFrame(() => {
|
|
||||||
menuRef.current
|
|
||||||
?.querySelector<HTMLElement>('[aria-checked="true"]')
|
|
||||||
?.focus()
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
document.addEventListener("pointerdown", handlePointerDown)
|
|
||||||
document.addEventListener("focusin", handleFocusIn)
|
|
||||||
document.addEventListener("keydown", handleKeyDown)
|
|
||||||
|
|
||||||
return () => {
|
|
||||||
document.removeEventListener("pointerdown", handlePointerDown)
|
|
||||||
document.removeEventListener("focusin", handleFocusIn)
|
|
||||||
document.removeEventListener("keydown", handleKeyDown)
|
|
||||||
if (isMobile) document.body.style.overflow = previousOverflow
|
|
||||||
}
|
|
||||||
}, [isMobile, open])
|
|
||||||
|
|
||||||
function focusMenuItem(position: "first" | "last") {
|
|
||||||
setOpen(true)
|
|
||||||
window.requestAnimationFrame(() => {
|
|
||||||
const items = getMenuItems(menuRef.current)
|
|
||||||
const item = position === "first" ? items[0] : items.at(-1)
|
|
||||||
item?.focus()
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
function selectLocale(nextLocale: DocLocale) {
|
|
||||||
setPreferredLocale(nextLocale)
|
|
||||||
setLocaleMode("manual")
|
|
||||||
setOpen(false)
|
|
||||||
window.requestAnimationFrame(() => triggerRef.current?.focus())
|
|
||||||
}
|
|
||||||
|
|
||||||
const menu = (
|
|
||||||
<div
|
|
||||||
ref={menuRef}
|
|
||||||
id={menuId}
|
|
||||||
role={isMobile ? "dialog" : undefined}
|
|
||||||
aria-label={t({ zh: "语言", us: "Language" })}
|
|
||||||
aria-modal={isMobile || undefined}
|
|
||||||
className="w-[min(80vw,20rem)] rounded-xl border border-slate-200 bg-white/95 p-4 shadow-2xl backdrop-blur-md md:w-auto md:min-w-40 md:p-1 dark:border-slate-800 dark:bg-slate-950/95 dark:shadow-black/60"
|
|
||||||
>
|
|
||||||
<p className="px-2 py-2 text-sm text-slate-500 md:text-xs dark:text-slate-400">
|
|
||||||
{t({ zh: "语言", us: "Language" })}
|
|
||||||
</p>
|
|
||||||
<ul
|
|
||||||
role="menu"
|
|
||||||
aria-label={t({ zh: "语言", us: "Languages" })}
|
|
||||||
onKeyDown={(event) => {
|
|
||||||
if (
|
|
||||||
event.key !== "ArrowDown" &&
|
|
||||||
event.key !== "ArrowUp" &&
|
|
||||||
event.key !== "Home" &&
|
|
||||||
event.key !== "End"
|
|
||||||
) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
event.preventDefault()
|
|
||||||
const items = getMenuItems(event.currentTarget)
|
|
||||||
const currentIndex = items.indexOf(
|
|
||||||
document.activeElement as HTMLButtonElement
|
|
||||||
)
|
|
||||||
let nextIndex = currentIndex
|
|
||||||
|
|
||||||
if (event.key === "Home") nextIndex = 0
|
|
||||||
if (event.key === "End") nextIndex = items.length - 1
|
|
||||||
if (event.key === "ArrowDown") {
|
|
||||||
nextIndex = (currentIndex + 1) % items.length
|
|
||||||
}
|
|
||||||
if (event.key === "ArrowUp") {
|
|
||||||
nextIndex = (currentIndex - 1 + items.length) % items.length
|
|
||||||
}
|
|
||||||
|
|
||||||
items[nextIndex]?.focus()
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{localeOptions.map((option) => {
|
|
||||||
const selected = option.locale === locale
|
|
||||||
|
|
||||||
return (
|
|
||||||
<li role="none" key={option.locale}>
|
|
||||||
<a
|
|
||||||
role="menuitemradio"
|
|
||||||
aria-checked={selected}
|
|
||||||
lang={option.locale}
|
|
||||||
href={getLocalizedHref(window.location.pathname, option.locale)}
|
|
||||||
className="flex h-11 w-full cursor-pointer items-center gap-2 rounded-lg px-2 text-left whitespace-nowrap transition-colors hover:bg-slate-100 focus:bg-slate-100 focus:outline-none aria-checked:text-indigo-600 dark:hover:bg-slate-900 dark:focus:bg-slate-900 dark:aria-checked:text-indigo-400"
|
|
||||||
onClick={() => selectLocale(option.locale)}
|
|
||||||
>
|
|
||||||
<LocaleFlag
|
|
||||||
locale={option.locale}
|
|
||||||
className="size-5 shrink-0"
|
|
||||||
/>
|
|
||||||
<span>{option.label}</span>
|
|
||||||
{selected && (
|
|
||||||
<Icon
|
|
||||||
name="tabler:check"
|
|
||||||
className="ml-auto size-4 shrink-0"
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
)
|
|
||||||
})}
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div ref={rootRef} className="flex items-center md:relative">
|
|
||||||
<button
|
|
||||||
ref={triggerRef}
|
|
||||||
type="button"
|
|
||||||
aria-controls={open ? menuId : undefined}
|
|
||||||
aria-expanded={open}
|
|
||||||
aria-haspopup={isMobile ? "dialog" : "menu"}
|
|
||||||
aria-label={t({ zh: "选择语言", us: "Choose language" })}
|
|
||||||
title={t({ zh: "选择语言", us: "Choose language" })}
|
|
||||||
className="inline-flex size-8 cursor-pointer items-center justify-center rounded-full transition-colors outline-none hover:bg-slate-100 focus-visible:ring-2 focus-visible:ring-indigo-500 focus-visible:ring-offset-2 dark:hover:bg-slate-800 dark:focus-visible:ring-indigo-400 dark:focus-visible:ring-offset-slate-950"
|
|
||||||
onClick={() => setOpen((current) => !current)}
|
|
||||||
onKeyDown={(event) => {
|
|
||||||
if (event.key === "ArrowDown") {
|
|
||||||
event.preventDefault()
|
|
||||||
focusMenuItem("first")
|
|
||||||
} else if (event.key === "ArrowUp") {
|
|
||||||
event.preventDefault()
|
|
||||||
focusMenuItem("last")
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<LocaleFlag locale={selectedLocale.locale} className="size-7" />
|
|
||||||
</button>
|
|
||||||
|
|
||||||
{open &&
|
|
||||||
(isMobile ? (
|
|
||||||
createPortal(
|
|
||||||
<div className="fixed inset-0 z-100 flex items-center justify-center p-4">
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
tabIndex={-1}
|
|
||||||
aria-label={t({
|
|
||||||
zh: "关闭语言菜单",
|
|
||||||
us: "Close language menu",
|
|
||||||
})}
|
|
||||||
className="absolute inset-0 cursor-default bg-black/60 backdrop-blur-sm"
|
|
||||||
onClick={() => {
|
|
||||||
setOpen(false)
|
|
||||||
window.requestAnimationFrame(() =>
|
|
||||||
triggerRef.current?.focus()
|
|
||||||
)
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
<div className="relative">{menu}</div>
|
|
||||||
</div>,
|
|
||||||
document.body
|
|
||||||
)
|
|
||||||
) : (
|
|
||||||
<div className="absolute top-full right-0 z-100 pt-2">{menu}</div>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
function getMenuItems(root: ParentNode | null) {
|
|
||||||
return Array.from(
|
|
||||||
root?.querySelectorAll<HTMLElement>('[role="menuitemradio"]') ?? []
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
function getLocaleOption(locale: DocLocale) {
|
|
||||||
return localeOptions.find((option) => option.locale === locale)!
|
|
||||||
}
|
|
||||||
@@ -5,7 +5,6 @@ import React from "react"
|
|||||||
import { SearchTrigger } from "./search-trigger"
|
import { SearchTrigger } from "./search-trigger"
|
||||||
import { SettingsLink } from "./settings-link"
|
import { SettingsLink } from "./settings-link"
|
||||||
|
|
||||||
// oxlint-disable-next-line react/only-export-components -- Shared layout tokens are consumed by App.
|
|
||||||
export const rootCSSVariables = {
|
export const rootCSSVariables = {
|
||||||
"--cw": "60rem",
|
"--cw": "60rem",
|
||||||
"--max-lw": "18rem",
|
"--max-lw": "18rem",
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
import type { MdxComponents } from "../content/types"
|
import type { MdxComponents } from "../content/types"
|
||||||
|
|
||||||
/* oxlint-disable react/only-export-components -- This module exports an MDX component registry. */
|
|
||||||
export const mdxComponents: MdxComponents = {
|
export const mdxComponents: MdxComponents = {
|
||||||
a: MdxAnchor,
|
a: MdxAnchor,
|
||||||
blockquote: MdxBlockquote,
|
blockquote: MdxBlockquote,
|
||||||
@@ -90,4 +89,3 @@ function MdxPre({ className, ...props }: React.ComponentProps<"pre">) {
|
|||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
/* oxlint-enable react/only-export-components */
|
|
||||||
|
|||||||
@@ -36,12 +36,17 @@ type PreferencesMessage =
|
|||||||
|
|
||||||
export function DocsPreferencesProvider({
|
export function DocsPreferencesProvider({
|
||||||
children,
|
children,
|
||||||
|
initialPreferences,
|
||||||
routeLocale,
|
routeLocale,
|
||||||
}: {
|
}: {
|
||||||
children: ReactNode
|
children: ReactNode
|
||||||
|
initialPreferences?: Preferences
|
||||||
routeLocale: DocLocale
|
routeLocale: DocLocale
|
||||||
}) {
|
}) {
|
||||||
const [initialPreferences] = useState(() => readDocsPreferences(routeLocale))
|
const hydrateStoredPreferences = initialPreferences !== undefined
|
||||||
|
const [providerInitialPreferences] = useState(
|
||||||
|
() => initialPreferences ?? readDocsPreferences(routeLocale)
|
||||||
|
)
|
||||||
const channelRef = useRef<BroadcastChannel>(null)
|
const channelRef = useRef<BroadcastChannel>(null)
|
||||||
const applyingExternalUpdateRef = useRef(false)
|
const applyingExternalUpdateRef = useRef(false)
|
||||||
|
|
||||||
@@ -58,12 +63,13 @@ export function DocsPreferencesProvider({
|
|||||||
return (
|
return (
|
||||||
<PreferencesProvider
|
<PreferencesProvider
|
||||||
effects={docsPreferenceEffects}
|
effects={docsPreferenceEffects}
|
||||||
initialPreferences={initialPreferences}
|
initialPreferences={providerInitialPreferences}
|
||||||
onPreferenceChange={handlePreferenceChange}
|
onPreferenceChange={handlePreferenceChange}
|
||||||
>
|
>
|
||||||
<PreferencesRuntime
|
<PreferencesRuntime
|
||||||
applyingExternalUpdateRef={applyingExternalUpdateRef}
|
applyingExternalUpdateRef={applyingExternalUpdateRef}
|
||||||
channelRef={channelRef}
|
channelRef={channelRef}
|
||||||
|
hydrateStoredPreferences={hydrateStoredPreferences}
|
||||||
routeLocale={routeLocale}
|
routeLocale={routeLocale}
|
||||||
/>
|
/>
|
||||||
{children}
|
{children}
|
||||||
@@ -74,10 +80,12 @@ export function DocsPreferencesProvider({
|
|||||||
function PreferencesRuntime({
|
function PreferencesRuntime({
|
||||||
applyingExternalUpdateRef,
|
applyingExternalUpdateRef,
|
||||||
channelRef,
|
channelRef,
|
||||||
|
hydrateStoredPreferences,
|
||||||
routeLocale,
|
routeLocale,
|
||||||
}: {
|
}: {
|
||||||
applyingExternalUpdateRef: MutableRefObject<boolean>
|
applyingExternalUpdateRef: MutableRefObject<boolean>
|
||||||
channelRef: MutableRefObject<BroadcastChannel | null>
|
channelRef: MutableRefObject<BroadcastChannel | null>
|
||||||
|
hydrateStoredPreferences: boolean
|
||||||
routeLocale: DocLocale
|
routeLocale: DocLocale
|
||||||
}) {
|
}) {
|
||||||
const preferences = usePreferences()
|
const preferences = usePreferences()
|
||||||
@@ -89,6 +97,32 @@ function PreferencesRuntime({
|
|||||||
const [, setLocale] = usePreference("locale")
|
const [, setLocale] = usePreference("locale")
|
||||||
const [, setThemeMode] = usePreference("theme-mode")
|
const [, setThemeMode] = usePreference("theme-mode")
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!hydrateStoredPreferences) return
|
||||||
|
|
||||||
|
const storedPreferences = readDocsPreferences(routeLocale)
|
||||||
|
applyingExternalUpdateRef.current = true
|
||||||
|
try {
|
||||||
|
setAccentColor(storedPreferences["accent-color"])
|
||||||
|
setBackgroundShade(storedPreferences["background-shade"])
|
||||||
|
setForegroundShade(storedPreferences["foreground-shade"])
|
||||||
|
setLocaleMode(storedPreferences["locale-mode"])
|
||||||
|
setLocale(storedPreferences.locale)
|
||||||
|
setThemeMode(storedPreferences["theme-mode"])
|
||||||
|
} finally {
|
||||||
|
applyingExternalUpdateRef.current = false
|
||||||
|
}
|
||||||
|
}, [
|
||||||
|
applyingExternalUpdateRef,
|
||||||
|
hydrateStoredPreferences,
|
||||||
|
routeLocale,
|
||||||
|
setAccentColor,
|
||||||
|
setBackgroundShade,
|
||||||
|
setForegroundShade,
|
||||||
|
setLocale,
|
||||||
|
setLocaleMode,
|
||||||
|
setThemeMode,
|
||||||
|
])
|
||||||
useLayoutEffect(() => {
|
useLayoutEffect(() => {
|
||||||
preferencesRef.current = preferences
|
preferencesRef.current = preferences
|
||||||
}, [preferences])
|
}, [preferences])
|
||||||
@@ -148,10 +182,12 @@ function PreferencesRuntime({
|
|||||||
if (!message || typeof message !== "object") return
|
if (!message || typeof message !== "object") return
|
||||||
|
|
||||||
if (message.type === "request") {
|
if (message.type === "request") {
|
||||||
|
/* oxlint-disable unicorn/require-post-message-target-origin -- BroadcastChannel has no targetOrigin argument. */
|
||||||
channel.postMessage({
|
channel.postMessage({
|
||||||
type: "snapshot",
|
type: "snapshot",
|
||||||
preferences: preferencesRef.current,
|
preferences: preferencesRef.current,
|
||||||
} satisfies PreferencesMessage)
|
} satisfies PreferencesMessage)
|
||||||
|
/* oxlint-enable unicorn/require-post-message-target-origin */
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -175,6 +211,7 @@ function PreferencesRuntime({
|
|||||||
}
|
}
|
||||||
|
|
||||||
channel.addEventListener("message", handleMessage)
|
channel.addEventListener("message", handleMessage)
|
||||||
|
// oxlint-disable-next-line unicorn/require-post-message-target-origin -- BroadcastChannel has no targetOrigin argument.
|
||||||
channel.postMessage({ type: "request" } satisfies PreferencesMessage)
|
channel.postMessage({ type: "request" } satisfies PreferencesMessage)
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
@@ -191,7 +228,6 @@ function PreferencesRuntime({
|
|||||||
setLocaleMode,
|
setLocaleMode,
|
||||||
setThemeMode,
|
setThemeMode,
|
||||||
])
|
])
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (preferences["locale-mode"] !== "auto") return
|
if (preferences["locale-mode"] !== "auto") return
|
||||||
|
|
||||||
|
|||||||
@@ -1,55 +0,0 @@
|
|||||||
import { Icon } from "@icones/react"
|
|
||||||
import { usePreference } from "@workspace/preferences"
|
|
||||||
|
|
||||||
import { useResolvedTheme } from "../lib/appearance"
|
|
||||||
import { useTranslate } from "../lib/locale"
|
|
||||||
|
|
||||||
export function ThemeSwitch({ className }: { className?: string }) {
|
|
||||||
const t = useTranslate()
|
|
||||||
const [, setThemeMode] = usePreference("theme-mode")
|
|
||||||
const resolvedTheme = useResolvedTheme()
|
|
||||||
const dark = resolvedTheme === "dark"
|
|
||||||
const label = dark
|
|
||||||
? t({ zh: "切换到浅色主题", us: "Switch to light theme" })
|
|
||||||
: t({ zh: "切换到深色主题", us: "Switch to dark theme" })
|
|
||||||
|
|
||||||
return (
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
role="switch"
|
|
||||||
aria-checked={dark}
|
|
||||||
aria-label={label}
|
|
||||||
title={label}
|
|
||||||
className={[
|
|
||||||
"relative inline-flex h-7 w-13 shrink-0 cursor-pointer items-center rounded-full border transition-colors duration-200",
|
|
||||||
"focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-500 motion-reduce:transition-none",
|
|
||||||
dark
|
|
||||||
? "border-zinc-700 bg-zinc-900 shadow-inner hover:border-zinc-600"
|
|
||||||
: "border-slate-300 bg-slate-100 shadow-inner hover:border-slate-400",
|
|
||||||
className,
|
|
||||||
]
|
|
||||||
.filter(Boolean)
|
|
||||||
.join(" ")}
|
|
||||||
onClick={() => {
|
|
||||||
setThemeMode(dark ? "light" : "dark")
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<span
|
|
||||||
aria-hidden="true"
|
|
||||||
className={[
|
|
||||||
"absolute top-px left-px inline-flex size-6 items-center justify-center rounded-full ring-1 shadow-sm transition-transform duration-200 ease-out motion-reduce:transition-none",
|
|
||||||
dark
|
|
||||||
? "translate-x-6 bg-black text-zinc-100 ring-zinc-700"
|
|
||||||
: "translate-x-0 bg-white text-slate-500 ring-slate-200",
|
|
||||||
].join(" ")}
|
|
||||||
>
|
|
||||||
<Icon
|
|
||||||
name="tabler:sun-high"
|
|
||||||
altName="tabler:moon"
|
|
||||||
showAlt={dark}
|
|
||||||
className="z-10 size-4"
|
|
||||||
/>
|
|
||||||
</span>
|
|
||||||
</button>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
@@ -1,3 +1,5 @@
|
|||||||
|
import { lazy } from "react"
|
||||||
|
|
||||||
import {
|
import {
|
||||||
defaultDocLocale,
|
defaultDocLocale,
|
||||||
docLocales,
|
docLocales,
|
||||||
@@ -12,23 +14,17 @@ import {
|
|||||||
} from "./types"
|
} from "./types"
|
||||||
import { trans, type Translation } from "../lib/locale"
|
import { trans, type Translation } from "../lib/locale"
|
||||||
|
|
||||||
type DocModule = {
|
type DocContentModule = {
|
||||||
default: React.ComponentType<{ components?: MdxComponents }>
|
default: React.ComponentType<{ components?: MdxComponents }>
|
||||||
frontmatter: Record<string, unknown>
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type LocalizedText = Translation<string>
|
|
||||||
|
|
||||||
type PackageDefinition = {
|
type PackageDefinition = {
|
||||||
key: string
|
key: string
|
||||||
label: string
|
label: string
|
||||||
description: LocalizedText
|
description: Translation<string>
|
||||||
}
|
}
|
||||||
|
|
||||||
type ParsedDocPage = DocPage & {
|
type ParsedDocPage = DocPage & { packageKey: string }
|
||||||
packageKey: string
|
|
||||||
searchText: string
|
|
||||||
}
|
|
||||||
|
|
||||||
const packageDefinitions: readonly PackageDefinition[] = [
|
const packageDefinitions: readonly PackageDefinition[] = [
|
||||||
{
|
{
|
||||||
@@ -81,18 +77,23 @@ const packageDefinitions: readonly PackageDefinition[] = [
|
|||||||
},
|
},
|
||||||
]
|
]
|
||||||
|
|
||||||
const docModules = import.meta.glob<DocModule>(
|
const docModuleLoaders = import.meta.glob<DocContentModule>(
|
||||||
"../../../packages/*/docs/*/**/*.mdx",
|
"../../../packages/*/docs/*/**/*.mdx",
|
||||||
{ eager: true }
|
{ eager: false }
|
||||||
)
|
)
|
||||||
|
|
||||||
const docSources = import.meta.glob<string>(
|
const docFrontmatter = import.meta.glob<Record<string, unknown>>(
|
||||||
"../../../packages/*/docs/*/**/*.mdx",
|
"../../../packages/*/docs/*/**/*.mdx",
|
||||||
{ eager: true, import: "default", query: "?docs-search-raw" }
|
{ eager: true, import: "frontmatter" }
|
||||||
)
|
)
|
||||||
|
|
||||||
const parsedPages = Object.entries(docModules).map(([path, module]) =>
|
const parsedPages = Object.entries(docFrontmatter).map(
|
||||||
parseDocPage(path, module, docSources[path] ?? "")
|
([path, frontmatter]) => {
|
||||||
|
const load = docModuleLoaders[path]
|
||||||
|
if (!load) throw new Error(`Missing documentation module for "${path}".`)
|
||||||
|
|
||||||
|
return parseDocPage(path, frontmatter, lazy(load))
|
||||||
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
const packagesByLocale: Record<DocLocale, readonly DocPackage[]> = {
|
const packagesByLocale: Record<DocLocale, readonly DocPackage[]> = {
|
||||||
@@ -147,7 +148,7 @@ export function getLocalizedHref(pathname: string, locale: DocLocale) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function resolveDocLocale(pathname: string): DocLocale {
|
export function resolveDocLocale(pathname: string): DocLocale {
|
||||||
const firstSegment = pathname.split("/").filter(Boolean)[0]
|
const firstSegment = pathname.split("/").find(Boolean)
|
||||||
return isDocLocale(firstSegment) ? firstSegment : defaultDocLocale
|
return isDocLocale(firstSegment) ? firstSegment : defaultDocLocale
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -193,8 +194,17 @@ export function getDocSectionLabel(section: DocSection, locale: DocLocale) {
|
|||||||
return trans(locale, labels[section])
|
return trans(locale, labels[section])
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getDocSearchText(page: DocPage) {
|
export function getStaticDocRoutes() {
|
||||||
return (page as ParsedDocPage).searchText
|
return docLocales.flatMap((locale) => {
|
||||||
|
const home = getDocsHomeHref(locale)
|
||||||
|
return [
|
||||||
|
home,
|
||||||
|
`${home === "/" ? "" : home}/settings`,
|
||||||
|
...getDocPackages(locale).flatMap((docPackage) =>
|
||||||
|
docPackage.pages.map((page) => getDocHref(docPackage, page))
|
||||||
|
),
|
||||||
|
]
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
function createDocPackage(
|
function createDocPackage(
|
||||||
@@ -205,7 +215,7 @@ function createDocPackage(
|
|||||||
.filter(
|
.filter(
|
||||||
(page) => page.packageKey === definition.key && page.locale === locale
|
(page) => page.packageKey === definition.key && page.locale === locale
|
||||||
)
|
)
|
||||||
.sort(
|
.toSorted(
|
||||||
(left, right) =>
|
(left, right) =>
|
||||||
docSections.indexOf(left.section) -
|
docSections.indexOf(left.section) -
|
||||||
docSections.indexOf(right.section) ||
|
docSections.indexOf(right.section) ||
|
||||||
@@ -241,8 +251,8 @@ function createDocPackage(
|
|||||||
|
|
||||||
function parseDocPage(
|
function parseDocPage(
|
||||||
path: string,
|
path: string,
|
||||||
module: DocModule,
|
frontmatter: Record<string, unknown>,
|
||||||
source: string
|
Content: DocPage["Content"]
|
||||||
): ParsedDocPage {
|
): ParsedDocPage {
|
||||||
const match = path.match(
|
const match = path.match(
|
||||||
/\/packages\/([^/]+)\/docs\/([^/]+)\/(overview|guide|advanced|examples)(?:\/([^/]+))?\.mdx$/
|
/\/packages\/([^/]+)\/docs\/([^/]+)\/(overview|guide|advanced|examples)(?:\/([^/]+))?\.mdx$/
|
||||||
@@ -269,14 +279,12 @@ function parseDocPage(
|
|||||||
throw new Error(`Documentation file is in the wrong directory: "${path}".`)
|
throw new Error(`Documentation file is in the wrong directory: "${path}".`)
|
||||||
}
|
}
|
||||||
|
|
||||||
const frontmatter = module.frontmatter
|
|
||||||
return {
|
return {
|
||||||
Content: module.default,
|
Content,
|
||||||
description: readString(frontmatter, "description"),
|
description: readString(frontmatter, "description"),
|
||||||
locale: localeValue,
|
locale: localeValue,
|
||||||
order: readNumber(frontmatter, "order"),
|
order: readNumber(frontmatter, "order"),
|
||||||
packageKey,
|
packageKey,
|
||||||
searchText: source,
|
|
||||||
section: sectionValue,
|
section: sectionValue,
|
||||||
slug: nestedSlug ?? "overview",
|
slug: nestedSlug ?? "overview",
|
||||||
title: readString(frontmatter, "title"),
|
title: readString(frontmatter, "title"),
|
||||||
|
|||||||
@@ -0,0 +1,31 @@
|
|||||||
|
import type { DocLocale, DocSearchEntry } from "./types"
|
||||||
|
|
||||||
|
const indexes = new Map<DocLocale, Promise<readonly DocSearchEntry[]>>()
|
||||||
|
|
||||||
|
export function loadDocSearchIndex(locale: DocLocale) {
|
||||||
|
const existing = indexes.get(locale)
|
||||||
|
if (existing) return existing
|
||||||
|
|
||||||
|
const index = (
|
||||||
|
import.meta.env.DEV
|
||||||
|
? import("./search-index.source").then((module) =>
|
||||||
|
module.getDocSearchIndex(locale)
|
||||||
|
)
|
||||||
|
: fetch(
|
||||||
|
`${import.meta.env.BASE_URL}search/${encodeURIComponent(locale)}.json`
|
||||||
|
).then(async (response) => {
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new Error(
|
||||||
|
`Unable to load the ${locale} documentation search index.`
|
||||||
|
)
|
||||||
|
}
|
||||||
|
return (await response.json()) as readonly DocSearchEntry[]
|
||||||
|
})
|
||||||
|
).catch((error: unknown) => {
|
||||||
|
indexes.delete(locale)
|
||||||
|
throw error
|
||||||
|
})
|
||||||
|
|
||||||
|
indexes.set(locale, index)
|
||||||
|
return index
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
import { createDocSearchIndex } from "./search-index"
|
||||||
|
import type { DocLocale } from "./types"
|
||||||
|
|
||||||
|
const docSources = import.meta.glob<string>(
|
||||||
|
"../../../packages/*/docs/*/**/*.mdx",
|
||||||
|
{ eager: true, import: "default", query: "?docs-search-raw" }
|
||||||
|
)
|
||||||
|
|
||||||
|
export function getDocSearchIndex(locale: DocLocale) {
|
||||||
|
return createDocSearchIndex(locale, docSources)
|
||||||
|
}
|
||||||
@@ -0,0 +1,49 @@
|
|||||||
|
import { getDocHref, getDocPackages, getDocSectionLabel } from "./registry"
|
||||||
|
import type { DocLocale, DocSearchEntry, DocTocItem } from "./types"
|
||||||
|
|
||||||
|
export function createDocSearchIndex(
|
||||||
|
locale: DocLocale,
|
||||||
|
sources: Readonly<Record<string, string>>
|
||||||
|
): readonly DocSearchEntry[] {
|
||||||
|
const sourcesByPage = new Map(
|
||||||
|
Object.entries(sources).map(([path, source]) => [
|
||||||
|
getSourcePageKey(path),
|
||||||
|
stripFrontmatter(source),
|
||||||
|
])
|
||||||
|
)
|
||||||
|
|
||||||
|
return getDocPackages(locale).flatMap((docPackage) =>
|
||||||
|
docPackage.pages.map((page) => ({
|
||||||
|
body:
|
||||||
|
sourcesByPage.get(
|
||||||
|
`${docPackage.key}/${locale}/${page.section}/${page.slug}`
|
||||||
|
) ?? "",
|
||||||
|
description: page.description,
|
||||||
|
href: getDocHref(docPackage, page),
|
||||||
|
id: `${page.section}/${page.slug}`,
|
||||||
|
packageKey: docPackage.key,
|
||||||
|
packageLabel: docPackage.label,
|
||||||
|
sectionLabel: getDocSectionLabel(page.section, locale),
|
||||||
|
title: page.title,
|
||||||
|
toc: page.toc.flatMap(flattenTocTitles),
|
||||||
|
}))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
function getSourcePageKey(path: string) {
|
||||||
|
const match = path.match(
|
||||||
|
/\/packages\/([^/]+)\/docs\/([^/]+)\/(overview|guide|advanced|examples)(?:\/([^/]+))?\.mdx$/
|
||||||
|
)
|
||||||
|
if (!match) throw new Error(`Invalid documentation search source: "${path}".`)
|
||||||
|
|
||||||
|
const [, packageKey, locale, section, nestedSlug] = match
|
||||||
|
return `${packageKey}/${locale}/${section}/${nestedSlug ?? "overview"}`
|
||||||
|
}
|
||||||
|
|
||||||
|
function flattenTocTitles(item: DocTocItem): readonly string[] {
|
||||||
|
return [item.title, ...(item.items?.flatMap(flattenTocTitles) ?? [])]
|
||||||
|
}
|
||||||
|
|
||||||
|
function stripFrontmatter(source: string) {
|
||||||
|
return source.replace(/^---\r?\n[\s\S]*?\r?\n---(?:\r?\n|$)/, "")
|
||||||
|
}
|
||||||
@@ -30,6 +30,18 @@ export type DocPage = {
|
|||||||
toc: readonly DocTocItem[]
|
toc: readonly DocTocItem[]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type DocSearchEntry = {
|
||||||
|
body: string
|
||||||
|
description: string
|
||||||
|
href: string
|
||||||
|
id: string
|
||||||
|
packageKey: string
|
||||||
|
packageLabel: string
|
||||||
|
sectionLabel: string
|
||||||
|
title: string
|
||||||
|
toc: readonly string[]
|
||||||
|
}
|
||||||
|
|
||||||
export type DocPackage = {
|
export type DocPackage = {
|
||||||
key: string
|
key: string
|
||||||
label: string
|
label: string
|
||||||
|
|||||||
@@ -0,0 +1,68 @@
|
|||||||
|
import { StrictMode } from "react"
|
||||||
|
import { prerender } from "react-dom/static"
|
||||||
|
|
||||||
|
import App from "./App"
|
||||||
|
import {
|
||||||
|
getStaticDocRoutes,
|
||||||
|
resolveDocLocale,
|
||||||
|
resolveDocLocation,
|
||||||
|
} from "./content/registry"
|
||||||
|
import { getDocSearchIndex } from "./content/search-index.source"
|
||||||
|
import type { DocLocale } from "./content/types"
|
||||||
|
import { createDefaultDocsPreferences } from "./lib/preferences"
|
||||||
|
|
||||||
|
export { getStaticDocRoutes, getDocSearchIndex as getStaticSearchIndex }
|
||||||
|
|
||||||
|
export async function renderStaticPage(pathname: string) {
|
||||||
|
const locale = resolveDocLocale(pathname)
|
||||||
|
const { prelude } = await prerender(
|
||||||
|
<StrictMode>
|
||||||
|
<App
|
||||||
|
initialPreferences={createDefaultDocsPreferences(locale)}
|
||||||
|
initialUrl={new URL(pathname, "https://docs.local").href}
|
||||||
|
/>
|
||||||
|
</StrictMode>
|
||||||
|
)
|
||||||
|
|
||||||
|
return {
|
||||||
|
html: await new Response(prelude).text(),
|
||||||
|
locale,
|
||||||
|
metadata: getPageMetadata(pathname, locale),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function getPageMetadata(pathname: string, locale: DocLocale) {
|
||||||
|
const location = resolveDocLocation(pathname)
|
||||||
|
if (location) {
|
||||||
|
return {
|
||||||
|
description: location.page.description,
|
||||||
|
title: `${location.page.title} · ${location.package.label}`,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const english = locale === "en-US"
|
||||||
|
if (/\/settings\/?$/.test(pathname)) {
|
||||||
|
return {
|
||||||
|
description: english
|
||||||
|
? "Configure the documentation theme, colors, and language."
|
||||||
|
: "配置文档站的主题、颜色和语言。",
|
||||||
|
title: english ? "Settings · Documentation" : "设置 · 文档",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pathname === "/" || pathname === "/en-US") {
|
||||||
|
return {
|
||||||
|
description: english
|
||||||
|
? "Documentation for the my-shadcn-ui workspace packages."
|
||||||
|
: "my-shadcn-ui 工作区各个 package 的使用文档。",
|
||||||
|
title: english ? "my-shadcn-ui Documentation" : "my-shadcn-ui 文档",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
description: english
|
||||||
|
? "The requested documentation page does not exist."
|
||||||
|
: "请求的文档页面不存在。",
|
||||||
|
title: english ? "Page not found · Documentation" : "页面不存在 · 文档",
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
import { useCallback, useSyncExternalStore } from "react"
|
import { useCallback } from "react"
|
||||||
import { usePreference } from "@workspace/preferences"
|
import { usePreference } from "@workspace/preferences"
|
||||||
import colors from "tailwindcss/colors"
|
import colors from "tailwindcss/colors"
|
||||||
|
|
||||||
@@ -37,7 +37,7 @@ export type ThemeMode = (typeof themeModes)[number]
|
|||||||
export type AccentColor = (typeof accentColors)[number]
|
export type AccentColor = (typeof accentColors)[number]
|
||||||
export type BackgroundShade = (typeof backgroundShades)[number]
|
export type BackgroundShade = (typeof backgroundShades)[number]
|
||||||
export type ForegroundShade = (typeof foregroundShades)[number]
|
export type ForegroundShade = (typeof foregroundShades)[number]
|
||||||
export type ResolvedTheme = Exclude<ThemeMode, "system">
|
type ResolvedTheme = Exclude<ThemeMode, "system">
|
||||||
|
|
||||||
export type Appearance = {
|
export type Appearance = {
|
||||||
accentColor: AccentColor
|
accentColor: AccentColor
|
||||||
@@ -91,17 +91,6 @@ export function useAppearance(): AppearanceController {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function useResolvedTheme() {
|
|
||||||
const [themeMode] = usePreference("theme-mode")
|
|
||||||
const systemTheme = useSyncExternalStore(
|
|
||||||
subscribeToSystemTheme,
|
|
||||||
getSystemTheme,
|
|
||||||
() => "light" as const
|
|
||||||
)
|
|
||||||
|
|
||||||
return themeMode === "system" ? systemTheme : themeMode
|
|
||||||
}
|
|
||||||
|
|
||||||
export function getPaletteColor(
|
export function getPaletteColor(
|
||||||
color: AccentColor | BackgroundShade | ForegroundShade,
|
color: AccentColor | BackgroundShade | ForegroundShade,
|
||||||
step: ColorStep = 500
|
step: ColorStep = 500
|
||||||
@@ -146,7 +135,7 @@ export function subscribeToSystemTheme(listener: VoidFunction) {
|
|||||||
return () => mediaQuery.removeEventListener("change", listener)
|
return () => mediaQuery.removeEventListener("change", listener)
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getSystemTheme(): ResolvedTheme {
|
function getSystemTheme(): ResolvedTheme {
|
||||||
return window.matchMedia(systemThemeQuery).matches ? "dark" : "light"
|
return window.matchMedia(systemThemeQuery).matches ? "dark" : "light"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -105,6 +105,19 @@ export function readDocsPreferences(
|
|||||||
return preferences
|
return preferences
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function createDefaultDocsPreferences(
|
||||||
|
locale: DocLocale = defaultDocLocale
|
||||||
|
): Preferences {
|
||||||
|
return Object.fromEntries(
|
||||||
|
(
|
||||||
|
Object.keys(docsPreferenceDefinitions) as Array<keyof DocsPreferences>
|
||||||
|
).map((key) => [
|
||||||
|
key,
|
||||||
|
key === "locale" ? locale : docsPreferenceDefinitions[key].defaultValue,
|
||||||
|
])
|
||||||
|
) as DocsPreferences
|
||||||
|
}
|
||||||
|
|
||||||
export function persistDocsPreference(update: PreferenceUpdate) {
|
export function persistDocsPreference(update: PreferenceUpdate) {
|
||||||
const definition = docsPreferenceDefinitions[update.key]
|
const definition = docsPreferenceDefinitions[update.key]
|
||||||
const serializedValue =
|
const serializedValue =
|
||||||
|
|||||||
@@ -0,0 +1,21 @@
|
|||||||
|
import { createContext, useContext, type ReactNode } from "react"
|
||||||
|
|
||||||
|
const PathnameContext = createContext("/")
|
||||||
|
|
||||||
|
export function PathnameProvider({
|
||||||
|
children,
|
||||||
|
pathname,
|
||||||
|
}: {
|
||||||
|
children: ReactNode
|
||||||
|
pathname: string
|
||||||
|
}) {
|
||||||
|
return (
|
||||||
|
<PathnameContext.Provider value={pathname}>
|
||||||
|
{children}
|
||||||
|
</PathnameContext.Provider>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export function usePathname() {
|
||||||
|
return useContext(PathnameContext)
|
||||||
|
}
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
import * as React from "react"
|
|
||||||
|
|
||||||
const MOBILE_BREAKPOINT = 768
|
|
||||||
|
|
||||||
export function useIsMobile() {
|
|
||||||
const [isMobile, setIsMobile] = React.useState<boolean | undefined>(undefined)
|
|
||||||
|
|
||||||
React.useEffect(() => {
|
|
||||||
const mql = window.matchMedia(`(max-width: ${MOBILE_BREAKPOINT - 1}px)`)
|
|
||||||
const onChange = () => {
|
|
||||||
setIsMobile(window.innerWidth < MOBILE_BREAKPOINT)
|
|
||||||
}
|
|
||||||
mql.addEventListener("change", onChange)
|
|
||||||
setIsMobile(window.innerWidth < MOBILE_BREAKPOINT)
|
|
||||||
return () => mql.removeEventListener("change", onChange)
|
|
||||||
}, [])
|
|
||||||
|
|
||||||
return !!isMobile
|
|
||||||
}
|
|
||||||
+24
-7
@@ -1,18 +1,35 @@
|
|||||||
import { StrictMode } from "react"
|
import { StrictMode } from "react"
|
||||||
import { createRoot } from "react-dom/client"
|
import { createRoot, hydrateRoot } from "react-dom/client"
|
||||||
|
|
||||||
import App from "./App.tsx"
|
import App from "./App.tsx"
|
||||||
|
// oxlint-disable-next-line import/no-unassigned-import -- The entry point installs the global stylesheet.
|
||||||
import "./index.css"
|
import "./index.css"
|
||||||
import { initializeDocsPreferences } from "./lib/preferences"
|
import { resolveDocLocale } from "./content/registry"
|
||||||
|
import {
|
||||||
|
createDefaultDocsPreferences,
|
||||||
|
initializeDocsPreferences,
|
||||||
|
} from "./lib/preferences"
|
||||||
|
|
||||||
document.documentElement.lang = window.location.pathname.startsWith("/en-US")
|
const root = document.getElementById("root")!
|
||||||
? "en-US"
|
const prerendered = root.hasChildNodes()
|
||||||
: "zh-Hans"
|
const locale = resolveDocLocale(window.location.pathname)
|
||||||
|
document.documentElement.lang = locale
|
||||||
|
|
||||||
initializeDocsPreferences()
|
initializeDocsPreferences()
|
||||||
|
|
||||||
createRoot(document.getElementById("root")!).render(
|
const app = (
|
||||||
<StrictMode>
|
<StrictMode>
|
||||||
<App />
|
<App
|
||||||
|
initialPreferences={
|
||||||
|
prerendered ? createDefaultDocsPreferences(locale) : undefined
|
||||||
|
}
|
||||||
|
initialUrl={window.location.href}
|
||||||
|
/>
|
||||||
</StrictMode>
|
</StrictMode>
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if (prerendered) {
|
||||||
|
hydrateRoot(root, app)
|
||||||
|
} else {
|
||||||
|
createRoot(root).render(app)
|
||||||
|
}
|
||||||
|
|||||||
@@ -8,20 +8,16 @@ import {
|
|||||||
getDocsHomeHref,
|
getDocsHomeHref,
|
||||||
resolveDocLocation,
|
resolveDocLocation,
|
||||||
} from "../content/registry"
|
} from "../content/registry"
|
||||||
import type {
|
import type { DocLocation, DocPage, DocTocItem } from "../content/types"
|
||||||
DocLocation,
|
|
||||||
DocPage,
|
|
||||||
DocTocItem,
|
|
||||||
} from "../content/types"
|
|
||||||
import { Actions, Container, HomeButton, SlashLine } from "../components/layout"
|
import { Actions, Container, HomeButton, SlashLine } from "../components/layout"
|
||||||
import { mdxComponents } from "../components/mdx"
|
import { mdxComponents } from "../components/mdx"
|
||||||
import { useLocale, useTranslate } from "../lib/locale"
|
import { useLocale, useTranslate } from "../lib/locale"
|
||||||
|
|
||||||
const noTocItems: readonly DocTocItem[] = []
|
const noTocItems: readonly DocTocItem[] = []
|
||||||
|
|
||||||
export default function ArticlePage() {
|
export default function ArticlePage({ pathname }: { pathname: string }) {
|
||||||
const t = useTranslate()
|
const t = useTranslate()
|
||||||
const docLocation = resolveDocLocation(window.location.pathname)
|
const docLocation = resolveDocLocation(pathname)
|
||||||
const visibleTocIds = useVisibleTocIds(docLocation?.page.toc ?? noTocItems)
|
const visibleTocIds = useVisibleTocIds(docLocation?.page.toc ?? noTocItems)
|
||||||
const [mobilePanel, setMobilePanel] = React.useState<
|
const [mobilePanel, setMobilePanel] = React.useState<
|
||||||
"navigation" | "toc" | null
|
"navigation" | "toc" | null
|
||||||
@@ -401,8 +397,6 @@ function TableOfContents({
|
|||||||
height: number
|
height: number
|
||||||
top: number
|
top: number
|
||||||
} | null>(null)
|
} | null>(null)
|
||||||
const activeKey = activeIds.join("\n")
|
|
||||||
|
|
||||||
React.useLayoutEffect(() => {
|
React.useLayoutEffect(() => {
|
||||||
const root = rootRef.current
|
const root = rootRef.current
|
||||||
const rail = railRef.current
|
const rail = railRef.current
|
||||||
@@ -437,7 +431,7 @@ function TableOfContents({
|
|||||||
resizeObserver.disconnect()
|
resizeObserver.disconnect()
|
||||||
window.removeEventListener("resize", measureMarker)
|
window.removeEventListener("resize", measureMarker)
|
||||||
}
|
}
|
||||||
}, [activeKey, activeIds])
|
}, [activeIds])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<aside
|
<aside
|
||||||
@@ -514,7 +508,7 @@ function TocAnchor({
|
|||||||
<a
|
<a
|
||||||
href={href}
|
href={href}
|
||||||
data-active={active || undefined}
|
data-active={active || undefined}
|
||||||
className="text-slate-600 transition-colors hover:text-indigo-500 data-active:font-medium data-active:text-indigo-600 dark:text-slate-400 dark:hover:text-indigo-300 dark:data-active:text-indigo-400"
|
className="text-slate-600 transition-colors hover:text-indigo-500 dark:text-slate-400 dark:hover:text-indigo-300 data-active:font-medium data-active:text-indigo-600 dark:data-active:text-indigo-400"
|
||||||
>
|
>
|
||||||
{title}
|
{title}
|
||||||
</a>
|
</a>
|
||||||
@@ -532,10 +526,7 @@ function useVisibleTocIds(items: readonly DocTocItem[]) {
|
|||||||
const [activeIds, setActiveIds] = React.useState<readonly string[]>([])
|
const [activeIds, setActiveIds] = React.useState<readonly string[]>([])
|
||||||
|
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
if (entries.length === 0) {
|
if (entries.length === 0) return
|
||||||
setActiveIds([])
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
let animationFrame: number | undefined
|
let animationFrame: number | undefined
|
||||||
const articleElement = document.querySelector<HTMLElement>(
|
const articleElement = document.querySelector<HTMLElement>(
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ import {
|
|||||||
import { useLocale, useTranslate, type Translation } from "../lib/locale"
|
import { useLocale, useTranslate, type Translation } from "../lib/locale"
|
||||||
import { navigateToLocale } from "../lib/locale-navigation"
|
import { navigateToLocale } from "../lib/locale-navigation"
|
||||||
import { detectLocale } from "../lib/preferences"
|
import { detectLocale } from "../lib/preferences"
|
||||||
|
import { usePathname } from "../lib/router"
|
||||||
|
|
||||||
const foregroundOptions: ReadonlyArray<{
|
const foregroundOptions: ReadonlyArray<{
|
||||||
label: Translation
|
label: Translation
|
||||||
@@ -54,6 +55,7 @@ const messages = {
|
|||||||
|
|
||||||
export default function SettingsPage() {
|
export default function SettingsPage() {
|
||||||
const locale = useLocale()
|
const locale = useLocale()
|
||||||
|
const pathname = usePathname()
|
||||||
const t = useTranslate()
|
const t = useTranslate()
|
||||||
const appearance = useAppearance()
|
const appearance = useAppearance()
|
||||||
const [localeMode, setLocaleMode] = usePreference("locale-mode")
|
const [localeMode, setLocaleMode] = usePreference("locale-mode")
|
||||||
@@ -231,7 +233,7 @@ export default function SettingsPage() {
|
|||||||
<div className="w-full space-y-1 rounded-xl border p-1 sm:w-fit sm:min-w-48 dark:border-slate-700">
|
<div className="w-full space-y-1 rounded-xl border p-1 sm:w-fit sm:min-w-48 dark:border-slate-700">
|
||||||
<LocaleLink
|
<LocaleLink
|
||||||
disabled={autoDetectLocale}
|
disabled={autoDetectLocale}
|
||||||
href={getLocalizedHref(window.location.pathname, "zh-Hans")}
|
href={getLocalizedHref(pathname, "zh-Hans")}
|
||||||
label="简体中文"
|
label="简体中文"
|
||||||
locale="zh-Hans"
|
locale="zh-Hans"
|
||||||
selected={locale === "zh-Hans"}
|
selected={locale === "zh-Hans"}
|
||||||
@@ -239,7 +241,7 @@ export default function SettingsPage() {
|
|||||||
/>
|
/>
|
||||||
<LocaleLink
|
<LocaleLink
|
||||||
disabled={autoDetectLocale}
|
disabled={autoDetectLocale}
|
||||||
href={getLocalizedHref(window.location.pathname, "en-US")}
|
href={getLocalizedHref(pathname, "en-US")}
|
||||||
label="English"
|
label="English"
|
||||||
locale="en-US"
|
locale="en-US"
|
||||||
selected={locale === "en-US"}
|
selected={locale === "en-US"}
|
||||||
|
|||||||
@@ -19,5 +19,5 @@
|
|||||||
"erasableSyntaxOnly": true,
|
"erasableSyntaxOnly": true,
|
||||||
"noFallthroughCasesInSwitch": true
|
"noFallthroughCasesInSwitch": true
|
||||||
},
|
},
|
||||||
"include": ["vite.config.ts"]
|
"include": ["vite.config.ts", "scripts"]
|
||||||
}
|
}
|
||||||
+1
-1
@@ -5,7 +5,7 @@ import { icones } from "@icones/vite"
|
|||||||
import { readFile } from "node:fs/promises"
|
import { readFile } from "node:fs/promises"
|
||||||
import { fileURLToPath } from "node:url"
|
import { fileURLToPath } from "node:url"
|
||||||
import { defineConfig, type Plugin } from "vite"
|
import { defineConfig, type Plugin } from "vite"
|
||||||
import satteri from "vite-plugin-satteri"
|
import { satteri } from "vite-plugin-satteri"
|
||||||
|
|
||||||
const packagesDirectory = fileURLToPath(new URL("../packages", import.meta.url))
|
const packagesDirectory = fileURLToPath(new URL("../packages", import.meta.url))
|
||||||
|
|
||||||
|
|||||||
@@ -9,9 +9,9 @@ export function useSearchHistory({
|
|||||||
limit,
|
limit,
|
||||||
storageKey,
|
storageKey,
|
||||||
}: UseSearchHistoryOptions) {
|
}: UseSearchHistoryOptions) {
|
||||||
const [items, setItems] = React.useState<readonly string[]>(() =>
|
// Keep the server render and the client's first render identical. Persisted
|
||||||
readSearchHistory(storageKey, limit)
|
// history is restored by the effect after hydration.
|
||||||
)
|
const [items, setItems] = React.useState<readonly string[]>([])
|
||||||
|
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
const syncFromStorage = () => setItems(readSearchHistory(storageKey, limit))
|
const syncFromStorage = () => setItems(readSearchHistory(storageKey, limit))
|
||||||
|
|||||||
Reference in New Issue
Block a user