From bca6c31df706d76e02599350eae4b82497fb17b4 Mon Sep 17 00:00:00 2001 From: folinhilo Date: Mon, 4 May 2026 00:04:03 +0800 Subject: [PATCH] =?UTF-8?q?=E9=87=8D=E6=9E=84=EF=BC=9A=E6=8F=90=E4=BA=A4?= =?UTF-8?q?=E5=85=A8=E6=96=B0=E9=A1=B9=E7=9B=AE=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 24 + .npmrc | 1 + package.json | 20 + packages/bookmark-sync/manifest.json | 19 + packages/bookmark-sync/package.json | 15 + packages/bookmark-sync/src/controller.ts | 79 + .../src/custom-bookmark-bar/newtab.html | 47 + .../src/custom-bookmark-bar/popup.ts | 76 + packages/bookmark-sync/src/types.ts | 5 + packages/bookmark-sync/src/utils.ts | 20 + packages/bookmark-sync/tsconfig.json | 118 + packages/manga-grabber/tsconfig.json | 118 + packages/movie-grabber/tsconfig.json | 118 + packages/music-grabber/tsconfig.json | 118 + packages/note-maker/package.json | 12 + .../note-maker/src/content-block/dg-ls.ts | 0 .../note-maker/src/content-block/dg-text.ts | 8 + .../note-maker/src/content-block/dg-ul.ts | 0 packages/note-maker/tsconfig.json | 118 + packages/ui-web/.vscode/settings.json | 8 + packages/ui-web/package.json | 50 + .../vite-plugin-gen-index-css.ts | 137 ++ .../vite-plugin-gen-index-ts.ts | 129 ++ packages/ui-web/src/assets/svg/BoldSvg.tsx | 12 + .../src/assets/svg/CheckIndicatorSvg.tsx | 8 + .../ui-web/src/assets/svg/ChevronRightSvg.tsx | 12 + packages/ui-web/src/assets/svg/CutSvg.tsx | 8 + .../ui-web/src/assets/svg/DownloadSvg.tsx | 8 + packages/ui-web/src/assets/svg/FileSvg.tsx | 14 + packages/ui-web/src/assets/svg/KeySvg.tsx | 8 + packages/ui-web/src/assets/svg/MeshSvg.tsx | 14 + packages/ui-web/src/assets/svg/MoonSvg.tsx | 12 + packages/ui-web/src/assets/svg/PasteSvg.tsx | 8 + packages/ui-web/src/assets/svg/Ruler.tsx | 12 + packages/ui-web/src/assets/svg/SearchSvg.tsx | 8 + packages/ui-web/src/assets/svg/SettingSvg.tsx | 9 + packages/ui-web/src/assets/svg/SpinnerSvg.tsx | 23 + packages/ui-web/src/assets/svg/SunSvg.tsx | 12 + packages/ui-web/src/assets/svg/UserSvg.tsx | 14 + .../ui-web/src/assets/svg/VolumeHighSvg.tsx | 12 + .../ui-web/src/assets/svg/VolumeLowSvg.tsx | 12 + .../ui-web/src/assets/svg/VolumeMuteSvg.tsx | 12 + packages/ui-web/src/common/Box.tsx | 41 + packages/ui-web/src/common/CommonProps.ts | 9 + packages/ui-web/src/common/Slot.tsx | 33 + .../src/component/accordion/Accordion.css | 9 + .../src/component/accordion/Accordion.tsx | 20 + .../src/component/accordion/AccordionItem.tsx | 1 + .../component/accordion/AccordionPanel.tsx | 1 + .../component/accordion/AccordionTrigger.tsx | 1 + .../ui-web/src/component/avatar/Avatar.css | 19 + .../ui-web/src/component/avatar/Avatar.tsx | 25 + .../ui-web/src/component/button/Button.tsx | 60 + .../src/component/checkbox/Checkbox.css | 19 + .../src/component/checkbox/Checkbox.tsx | 76 + packages/ui-web/src/component/icon/Icon.tsx | 21 + packages/ui-web/src/component/theme/Theme.tsx | 18 + .../src/component/theme/ThemeContext.tsx | 5 + .../ui-web/src/component/theme/useTheme.ts | 6 + .../ui-web/src/component/tooltip/Tooltip.css | 50 + .../ui-web/src/component/tooltip/Tooltip.tsx | 14 + .../src/component/tooltip/TooltipPopup.tsx | 53 + .../src/component/tooltip/TooltipTrigger.tsx | 13 + .../username-field/UsernameField.tsx | 1 + packages/ui-web/src/index.css | 16 + packages/ui-web/src/index.ts | 45 + .../src/styles/recipe/IinlineSize.recipe.ts | 91 + .../src/styles/recipe/ItemSize.recipe.ts | 88 + .../ui-web/src/styles/recipe/brand.recipe.ts | 13 + .../src/styles/recipe/variant.recipe.ts | 38 + packages/ui-web/src/styles/theme/global.css | 44 + packages/ui-web/src/styles/utility/brand.css | 40 + packages/ui-web/src/styles/utility/font.css | 4 + packages/ui-web/src/styles/utility/gap.css | 18 + packages/ui-web/src/styles/utility/height.css | 40 + .../ui-web/src/styles/utility/loading.css | 16 + packages/ui-web/src/styles/utility/margin.css | 21 + .../ui-web/src/styles/utility/padding.css | 40 + packages/ui-web/src/styles/utility/skin.css | 9 + .../ui-web/src/styles/utility/variant.css | 200 ++ packages/ui-web/src/styles/utility/width.css | 41 + packages/ui-web/src/types/css.d.ts | 4 + packages/ui-web/tsconfig.base.json | 40 + packages/ui-web/tsconfig.build.json | 122 + packages/ui-web/tsconfig.json | 16 + packages/ui-web/vite.config.ts | 45 + pnpm-lock.yaml | 1974 +++++++++++++++++ pnpm-workspace.yaml | 6 + templates/vite-react-template/.npmrc | 1 + .../vite-react-template/.vscode/settings.json | 8 + templates/vite-react-template/package.json | 34 + .../vite-plugin-gen-index-css.ts | 137 ++ .../vite-plugin-gen-index-ts.ts | 129 ++ .../vite-react-template/src/types/css.d.ts | 4 + .../vite-react-template/src/types/env.d.ts | 51 + .../vite-react-template/tsconfig.base.json | 40 + .../vite-react-template/tsconfig.build.json | 122 + templates/vite-react-template/tsconfig.json | 16 + templates/vite-react-template/vite.config.ts | 43 + turbo.json | 15 + 100 files changed, 5524 insertions(+) create mode 100644 .gitignore create mode 100644 .npmrc create mode 100644 package.json create mode 100644 packages/bookmark-sync/manifest.json create mode 100644 packages/bookmark-sync/package.json create mode 100644 packages/bookmark-sync/src/controller.ts create mode 100644 packages/bookmark-sync/src/custom-bookmark-bar/newtab.html create mode 100644 packages/bookmark-sync/src/custom-bookmark-bar/popup.ts create mode 100644 packages/bookmark-sync/src/types.ts create mode 100644 packages/bookmark-sync/src/utils.ts create mode 100644 packages/bookmark-sync/tsconfig.json create mode 100644 packages/manga-grabber/tsconfig.json create mode 100644 packages/movie-grabber/tsconfig.json create mode 100644 packages/music-grabber/tsconfig.json create mode 100644 packages/note-maker/package.json create mode 100644 packages/note-maker/src/content-block/dg-ls.ts create mode 100644 packages/note-maker/src/content-block/dg-text.ts create mode 100644 packages/note-maker/src/content-block/dg-ul.ts create mode 100644 packages/note-maker/tsconfig.json create mode 100644 packages/ui-web/.vscode/settings.json create mode 100644 packages/ui-web/package.json create mode 100644 packages/ui-web/scripts-plugin/vite-plugin-gen-index-css.ts create mode 100644 packages/ui-web/scripts-plugin/vite-plugin-gen-index-ts.ts create mode 100644 packages/ui-web/src/assets/svg/BoldSvg.tsx create mode 100644 packages/ui-web/src/assets/svg/CheckIndicatorSvg.tsx create mode 100644 packages/ui-web/src/assets/svg/ChevronRightSvg.tsx create mode 100644 packages/ui-web/src/assets/svg/CutSvg.tsx create mode 100644 packages/ui-web/src/assets/svg/DownloadSvg.tsx create mode 100644 packages/ui-web/src/assets/svg/FileSvg.tsx create mode 100644 packages/ui-web/src/assets/svg/KeySvg.tsx create mode 100644 packages/ui-web/src/assets/svg/MeshSvg.tsx create mode 100644 packages/ui-web/src/assets/svg/MoonSvg.tsx create mode 100644 packages/ui-web/src/assets/svg/PasteSvg.tsx create mode 100644 packages/ui-web/src/assets/svg/Ruler.tsx create mode 100644 packages/ui-web/src/assets/svg/SearchSvg.tsx create mode 100644 packages/ui-web/src/assets/svg/SettingSvg.tsx create mode 100644 packages/ui-web/src/assets/svg/SpinnerSvg.tsx create mode 100644 packages/ui-web/src/assets/svg/SunSvg.tsx create mode 100644 packages/ui-web/src/assets/svg/UserSvg.tsx create mode 100644 packages/ui-web/src/assets/svg/VolumeHighSvg.tsx create mode 100644 packages/ui-web/src/assets/svg/VolumeLowSvg.tsx create mode 100644 packages/ui-web/src/assets/svg/VolumeMuteSvg.tsx create mode 100644 packages/ui-web/src/common/Box.tsx create mode 100644 packages/ui-web/src/common/CommonProps.ts create mode 100644 packages/ui-web/src/common/Slot.tsx create mode 100644 packages/ui-web/src/component/accordion/Accordion.css create mode 100644 packages/ui-web/src/component/accordion/Accordion.tsx create mode 100644 packages/ui-web/src/component/accordion/AccordionItem.tsx create mode 100644 packages/ui-web/src/component/accordion/AccordionPanel.tsx create mode 100644 packages/ui-web/src/component/accordion/AccordionTrigger.tsx create mode 100644 packages/ui-web/src/component/avatar/Avatar.css create mode 100644 packages/ui-web/src/component/avatar/Avatar.tsx create mode 100644 packages/ui-web/src/component/button/Button.tsx create mode 100644 packages/ui-web/src/component/checkbox/Checkbox.css create mode 100644 packages/ui-web/src/component/checkbox/Checkbox.tsx create mode 100644 packages/ui-web/src/component/icon/Icon.tsx create mode 100644 packages/ui-web/src/component/theme/Theme.tsx create mode 100644 packages/ui-web/src/component/theme/ThemeContext.tsx create mode 100644 packages/ui-web/src/component/theme/useTheme.ts create mode 100644 packages/ui-web/src/component/tooltip/Tooltip.css create mode 100644 packages/ui-web/src/component/tooltip/Tooltip.tsx create mode 100644 packages/ui-web/src/component/tooltip/TooltipPopup.tsx create mode 100644 packages/ui-web/src/component/tooltip/TooltipTrigger.tsx create mode 100644 packages/ui-web/src/component/username-field/UsernameField.tsx create mode 100644 packages/ui-web/src/index.css create mode 100644 packages/ui-web/src/index.ts create mode 100644 packages/ui-web/src/styles/recipe/IinlineSize.recipe.ts create mode 100644 packages/ui-web/src/styles/recipe/ItemSize.recipe.ts create mode 100644 packages/ui-web/src/styles/recipe/brand.recipe.ts create mode 100644 packages/ui-web/src/styles/recipe/variant.recipe.ts create mode 100644 packages/ui-web/src/styles/theme/global.css create mode 100644 packages/ui-web/src/styles/utility/brand.css create mode 100644 packages/ui-web/src/styles/utility/font.css create mode 100644 packages/ui-web/src/styles/utility/gap.css create mode 100644 packages/ui-web/src/styles/utility/height.css create mode 100644 packages/ui-web/src/styles/utility/loading.css create mode 100644 packages/ui-web/src/styles/utility/margin.css create mode 100644 packages/ui-web/src/styles/utility/padding.css create mode 100644 packages/ui-web/src/styles/utility/skin.css create mode 100644 packages/ui-web/src/styles/utility/variant.css create mode 100644 packages/ui-web/src/styles/utility/width.css create mode 100644 packages/ui-web/src/types/css.d.ts create mode 100644 packages/ui-web/tsconfig.base.json create mode 100644 packages/ui-web/tsconfig.build.json create mode 100644 packages/ui-web/tsconfig.json create mode 100644 packages/ui-web/vite.config.ts create mode 100644 pnpm-lock.yaml create mode 100644 pnpm-workspace.yaml create mode 100644 templates/vite-react-template/.npmrc create mode 100644 templates/vite-react-template/.vscode/settings.json create mode 100644 templates/vite-react-template/package.json create mode 100644 templates/vite-react-template/scripts-plugin/vite-plugin-gen-index-css.ts create mode 100644 templates/vite-react-template/scripts-plugin/vite-plugin-gen-index-ts.ts create mode 100644 templates/vite-react-template/src/types/css.d.ts create mode 100644 templates/vite-react-template/src/types/env.d.ts create mode 100644 templates/vite-react-template/tsconfig.base.json create mode 100644 templates/vite-react-template/tsconfig.build.json create mode 100644 templates/vite-react-template/tsconfig.json create mode 100644 templates/vite-react-template/vite.config.ts create mode 100644 turbo.json diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..757502d --- /dev/null +++ b/.gitignore @@ -0,0 +1,24 @@ +# 基础忽略规则 +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* +*.swp +*.swo + +# 根目录依赖/构建产物 +node_modules/ +dist/ +build/ +coverage/ + +# Monorepo 子包专属忽略(核心) +packages/**/dist/ +packages/**/node_modules/ +packages/**/build/ +packages/**/coverage/ +packages/**/.env* +packages/**/npm-debug.log* +packages/**/yarn-debug.log* +packages/**/yarn-error.log* +packages/**/pnpm-debug.log* \ No newline at end of file diff --git a/.npmrc b/.npmrc new file mode 100644 index 0000000..8b02f75 --- /dev/null +++ b/.npmrc @@ -0,0 +1 @@ +registry = https://registry.npmmirror.com/ \ No newline at end of file diff --git a/package.json b/package.json new file mode 100644 index 0000000..a5e3eb6 --- /dev/null +++ b/package.json @@ -0,0 +1,20 @@ +{ + "name": "defgov", + "private": true, + "type": "module", + "scripts": { + "build": "turbo run build", + "dev": "turbo run dev" + }, + "devDependencies": { + "turbo": "^2.8.0" + }, + "engines": { + "node": ">=20" + }, + "workspaces": [ + "packages/*", + "app/*" + ], + "packageManager": "pnpm@11.0.0-rc.5+sha512.c469fb6aa13a99e57aec935cd7b86ff422701f4602ecac2231d3dc20910586ebfb6b50a7b455d0778ec22ae56912d8d8e88e9f9e0a03c0875a6a41783a94a1bd" +} diff --git a/packages/bookmark-sync/manifest.json b/packages/bookmark-sync/manifest.json new file mode 100644 index 0000000..d913202 --- /dev/null +++ b/packages/bookmark-sync/manifest.json @@ -0,0 +1,19 @@ +{ + "name": "defgov-bookmark-sync", + "version": "1.0", + "manifest_version": 3, + "permissions": ["bookmarks", "storage"], + "chrome_url_overrides": { + "newtab": "newtab.html" + }, + "host_permissions": [""], + "background": { + "service_worker": "controller.js" + }, + "browser_specific_settings": { + "gecko": { + "id": "bookmark-sync@example.com", + "strict_min_version": "109.0" + } + } +} diff --git a/packages/bookmark-sync/package.json b/packages/bookmark-sync/package.json new file mode 100644 index 0000000..63310ae --- /dev/null +++ b/packages/bookmark-sync/package.json @@ -0,0 +1,15 @@ +{ + "name": "defgov-bookmark-sync", + "version": "0.0.0", + "private": true, + "dependencies": { + "typescript": "^6.0.3" + }, + "devDependencies": { + "@types/chrome": "^0.1.40", + "@types/firefox-webext-browser": "^143.0.0", + "@types/node": "^25.6.0", + "@types/webextension-polyfill": "^0.12.5", + "webextension-polyfill": "^0.12.0" + } +} diff --git a/packages/bookmark-sync/src/controller.ts b/packages/bookmark-sync/src/controller.ts new file mode 100644 index 0000000..4e22eee --- /dev/null +++ b/packages/bookmark-sync/src/controller.ts @@ -0,0 +1,79 @@ +import browser from "webextension-polyfill"; + +export class Controller { + /** + * 书签栏 (Bookmarks Bar) 固定ID为 "1" + * + * 其他书签 (Other Bookmarks) 固定ID为 "2" + * + * 移动设备书签 (Mobile Bookmarks) 固定ID为 "3" + */ + rootFolder: string; + + constructor(rootFolder: string = "1") { + this.rootFolder = rootFolder; + } + + init() {} + + setRootFolder(rootFolder: string) { + this.rootFolder = rootFolder; + } + + async createBookmark(parentId: string, title: string, url?: string) { + try { + await browser.bookmarks.create({ + parentId: parentId, + title: title, + url: url, + type: "bookmark", + }); + } catch (error) { + console.error("❌ 创建书签失败:", error); + } + } + + async createFolder(parentId: string, title: string, url?: string) { + try { + await browser.bookmarks.create({ + parentId: parentId, + title: title, + url: url, + type: "folder", + }); + } catch (error) { + console.error(error); + } + } + + async createSeparator(parentId: string) { + try { + await browser.bookmarks.create({ + parentId: parentId, + type: "separator", + }); + } catch (error) { + console.error(error); + } + } + + async deleteNode(id: string) { + const results = await browser.bookmarks.get(id); + if (results[0].type === "bookmark" || results[0].type === "separator") { + deleteBookmarkOrSeparator(id); + } else if (results[0].type === "folder") { + deleteFolder(id); + } + } + + async moveNode(id: string, destinationId: string, index: number) { + try { + await browser.bookmarks.move(id, { + parentId: destinationId, + index: index, + }); + } catch (error) { + console.error(error); + } + } +} diff --git a/packages/bookmark-sync/src/custom-bookmark-bar/newtab.html b/packages/bookmark-sync/src/custom-bookmark-bar/newtab.html new file mode 100644 index 0000000..5c4e904 --- /dev/null +++ b/packages/bookmark-sync/src/custom-bookmark-bar/newtab.html @@ -0,0 +1,47 @@ + + + + + 我的自定义书签 + + + +

我的书签管理器

+ + + + +
+ + + + diff --git a/packages/bookmark-sync/src/custom-bookmark-bar/popup.ts b/packages/bookmark-sync/src/custom-bookmark-bar/popup.ts new file mode 100644 index 0000000..9db016f --- /dev/null +++ b/packages/bookmark-sync/src/custom-bookmark-bar/popup.ts @@ -0,0 +1,76 @@ +// 递归提取某个节点下的所有书签 URL(防止文件夹嵌套) +function extractUrls( + bookmarkNode: chrome.bookmarks.BookmarkTreeNode[], +): string[] { + let urls: string[] = []; + for (const node of bookmarkNode) { + if (node.url) { + urls.push(node.url); + } else if (node.children) { + urls = urls.concat(extractUrls(node.children)); + } + } + return urls; +} + +// 渲染指定 ID 文件夹下的书签 +async function renderBookmarksByFolderId(folderId: string) { + try { + const results = await chrome.bookmarks.getSubTree(folderId); + const folderNode = results[0]; + + if (!folderNode || !folderNode.children) return; + + const container = document.getElementById("bookmark-container"); + if (container) container.innerHTML = ""; + + // 遍历直接子节点 + folderNode.children.forEach((bookmark) => { + if (bookmark.url) { + const link = document.createElement("a"); + link.className = "bookmark-item"; + link.href = bookmark.url; + link.textContent = bookmark.title || bookmark.url; + // 自动获取网站 favicon 图标 + const faviconUrl = `https://www.google.com/s2/favicons?domain=${new URL(bookmark.url).hostname}&sz=32`; + link.innerHTML = `${bookmark.title}`; + container?.appendChild(link); + } + }); + } catch (error) { + console.error("获取书签失败:", error); + } +} + +// 初始化:自动获取所有一级文件夹并填充到下拉框 +async function initFolderSelector() { + const results = await chrome.bookmarks.getTree(); + const bookmarkBar = results[0].children?.[0]; // ID为1的书签栏 + const selector = document.getElementById( + "folder-selector", + ) as HTMLSelectElement; + + if (bookmarkBar && bookmarkBar.children) { + bookmarkBar.children.forEach((folder) => { + // 只把文件夹加到下拉框里 + if (!folder.url && folder.id !== "1") { + const option = document.createElement("option"); + option.value = folder.id || ""; + option.textContent = folder.title || "未命名文件夹"; + selector.appendChild(option); + } + }); + } + + // 绑定切换事件 + selector.addEventListener("change", (e) => { + const targetId = (e.target as HTMLSelectElement).value; + renderBookmarksByFolderId(targetId); + }); + + // 默认渲染书签栏 + renderBookmarksByFolderId("1"); +} + +// 页面加载完成后启动 +document.addEventListener("DOMContentLoaded", initFolderSelector); diff --git a/packages/bookmark-sync/src/types.ts b/packages/bookmark-sync/src/types.ts new file mode 100644 index 0000000..d9aa602 --- /dev/null +++ b/packages/bookmark-sync/src/types.ts @@ -0,0 +1,5 @@ +import browser from "webextension-polyfill"; + +export type Account = { id: string; email: string; password: string }; + +export type BookmarkTreeNode = browser.Bookmarks.BookmarkTreeNode; diff --git a/packages/bookmark-sync/src/utils.ts b/packages/bookmark-sync/src/utils.ts new file mode 100644 index 0000000..bf369ae --- /dev/null +++ b/packages/bookmark-sync/src/utils.ts @@ -0,0 +1,20 @@ +async function getLastIndex(parentId: string) { + const children = await browser.bookmarks.getChildren(parentId); + return children.length > 0 ? children[children.length - 1].index : 0; +} + +async function deleteBookmarkOrSeparator(id: string) { + try { + await browser.bookmarks.remove(id); + } catch (error) { + console.error(error); + } +} + +async function deleteFolder(id: string) { + try { + await browser.bookmarks.removeTree(id); + } catch (error) { + console.error(error); + } +} diff --git a/packages/bookmark-sync/tsconfig.json b/packages/bookmark-sync/tsconfig.json new file mode 100644 index 0000000..d5ec425 --- /dev/null +++ b/packages/bookmark-sync/tsconfig.json @@ -0,0 +1,118 @@ +{ + // tsconfig.lib.json + // 直接复制本文件内容到子项目的 tsconfig.json 即可,不要用 entends 继承本文件 + "extends": "../../tsconfig.base.json", + "compilerOptions": { + /** + * Browser api,需要加 "DOM","DOM.Iterable" + * Node api,需要加 "ES2025",始终使用带版本号的最新版本 + * NextJs api,属于同构,server 端会预处理 DOM,计算url,三个都需要 "ES2025", "DOM", "DOM.Iterable" + */ + "lib": ["ES2025", "DOM", "DOM.Iterable"], + + /** + * React JSX 编译模式 + * - 使用 React 17+ 新 JSX Transform + * - 不需要手动 import React + */ + "jsx": "react-jsx", + + /** + * 编译输出目录 + * - tsc / tsc -b 都会用到 + */ + "outDir": "./dist", + + /** + * 源码根目录 + * - 确保 dist 结构与 src 一致 + * - 对 declaration 路径至关重要 + */ + "rootDir": "./src", + + /** + * 生成 .d.ts 类型声明文件 + * - 组件库 / npm 包发布必需 + * - 对应用项目无害,仅影响类型输出 + */ + "declaration": true, + + /** + * 只做类型检查,不生成 JS 输出 + * - 适用于 Vite / Next / Nuxt 等 bundler 场景 + * - 防止 tsc 与构建工具重复 emit + */ + "noEmit": true, + + /** + * 强制单文件可独立编译 + * - 适配 esbuild / SWC / bundler 编译模型 + * - 禁止依赖跨文件类型推断(enum / namespace 等) + */ + "isolatedModules": true, + + /** + * 允许在 import 中显式使用 .ts / .tsx 后缀 + * - 兼容 Node ESM / bundler 对文件扩展名的严格要求 + * - 避免 `import './foo'` 在 TS + ESM 下歧义 + */ + "allowImportingTsExtensions": true + }, + /** + * 参与类型检查和编译的文件 + * - 只扫描 src + * - 其它目录通过 exclude 排除 + */ + "include": ["src", "scripts"], + + /** + * 明确排除非源码内容 + * - 避免污染类型系统 + * - 防止误入 dist / test / config + * - 保证发布包干净 + */ + "exclude": [ + "scripts", + "node_modules", + "dist", + + // ---------- build / cache ---------- + ".turbo/**/*", + ".cache/**/*", + ".vite/**/*", + + // ---------- 配置文件 ---------- + "vite.config.ts", + "*.config.ts", + "*.config.js", + "tsconfig.*.json", + + // ---------- 测试相关 ---------- + "__tests__/**/*", + "test/**/*", + "tests/**/*", + "**/*.test.ts", + "**/*.test.tsx", + "**/*.spec.ts", + "**/*.spec.tsx", + + // ---------- Storybook ---------- + ".storybook/**/*", + "stories/**/*", + + // ---------- 示例 / 脚本 ---------- + "example/**/*", + "examples/**/*", + "scripts/**/*", + + // ---------- 环境与静态资源 ---------- + ".env", + ".env.*", + "public/**/*", + + // ---------- 文档 ---------- + "docs/**/*", + "README.md", + "LICENSE" + ] +} diff --git a/packages/manga-grabber/tsconfig.json b/packages/manga-grabber/tsconfig.json new file mode 100644 index 0000000..d5ec425 --- /dev/null +++ b/packages/manga-grabber/tsconfig.json @@ -0,0 +1,118 @@ +{ + // tsconfig.lib.json + // 直接复制本文件内容到子项目的 tsconfig.json 即可,不要用 entends 继承本文件 + "extends": "../../tsconfig.base.json", + "compilerOptions": { + /** + * Browser api,需要加 "DOM","DOM.Iterable" + * Node api,需要加 "ES2025",始终使用带版本号的最新版本 + * NextJs api,属于同构,server 端会预处理 DOM,计算url,三个都需要 "ES2025", "DOM", "DOM.Iterable" + */ + "lib": ["ES2025", "DOM", "DOM.Iterable"], + + /** + * React JSX 编译模式 + * - 使用 React 17+ 新 JSX Transform + * - 不需要手动 import React + */ + "jsx": "react-jsx", + + /** + * 编译输出目录 + * - tsc / tsc -b 都会用到 + */ + "outDir": "./dist", + + /** + * 源码根目录 + * - 确保 dist 结构与 src 一致 + * - 对 declaration 路径至关重要 + */ + "rootDir": "./src", + + /** + * 生成 .d.ts 类型声明文件 + * - 组件库 / npm 包发布必需 + * - 对应用项目无害,仅影响类型输出 + */ + "declaration": true, + + /** + * 只做类型检查,不生成 JS 输出 + * - 适用于 Vite / Next / Nuxt 等 bundler 场景 + * - 防止 tsc 与构建工具重复 emit + */ + "noEmit": true, + + /** + * 强制单文件可独立编译 + * - 适配 esbuild / SWC / bundler 编译模型 + * - 禁止依赖跨文件类型推断(enum / namespace 等) + */ + "isolatedModules": true, + + /** + * 允许在 import 中显式使用 .ts / .tsx 后缀 + * - 兼容 Node ESM / bundler 对文件扩展名的严格要求 + * - 避免 `import './foo'` 在 TS + ESM 下歧义 + */ + "allowImportingTsExtensions": true + }, + /** + * 参与类型检查和编译的文件 + * - 只扫描 src + * - 其它目录通过 exclude 排除 + */ + "include": ["src", "scripts"], + + /** + * 明确排除非源码内容 + * - 避免污染类型系统 + * - 防止误入 dist / test / config + * - 保证发布包干净 + */ + "exclude": [ + "scripts", + "node_modules", + "dist", + + // ---------- build / cache ---------- + ".turbo/**/*", + ".cache/**/*", + ".vite/**/*", + + // ---------- 配置文件 ---------- + "vite.config.ts", + "*.config.ts", + "*.config.js", + "tsconfig.*.json", + + // ---------- 测试相关 ---------- + "__tests__/**/*", + "test/**/*", + "tests/**/*", + "**/*.test.ts", + "**/*.test.tsx", + "**/*.spec.ts", + "**/*.spec.tsx", + + // ---------- Storybook ---------- + ".storybook/**/*", + "stories/**/*", + + // ---------- 示例 / 脚本 ---------- + "example/**/*", + "examples/**/*", + "scripts/**/*", + + // ---------- 环境与静态资源 ---------- + ".env", + ".env.*", + "public/**/*", + + // ---------- 文档 ---------- + "docs/**/*", + "README.md", + "LICENSE" + ] +} diff --git a/packages/movie-grabber/tsconfig.json b/packages/movie-grabber/tsconfig.json new file mode 100644 index 0000000..d5ec425 --- /dev/null +++ b/packages/movie-grabber/tsconfig.json @@ -0,0 +1,118 @@ +{ + // tsconfig.lib.json + // 直接复制本文件内容到子项目的 tsconfig.json 即可,不要用 entends 继承本文件 + "extends": "../../tsconfig.base.json", + "compilerOptions": { + /** + * Browser api,需要加 "DOM","DOM.Iterable" + * Node api,需要加 "ES2025",始终使用带版本号的最新版本 + * NextJs api,属于同构,server 端会预处理 DOM,计算url,三个都需要 "ES2025", "DOM", "DOM.Iterable" + */ + "lib": ["ES2025", "DOM", "DOM.Iterable"], + + /** + * React JSX 编译模式 + * - 使用 React 17+ 新 JSX Transform + * - 不需要手动 import React + */ + "jsx": "react-jsx", + + /** + * 编译输出目录 + * - tsc / tsc -b 都会用到 + */ + "outDir": "./dist", + + /** + * 源码根目录 + * - 确保 dist 结构与 src 一致 + * - 对 declaration 路径至关重要 + */ + "rootDir": "./src", + + /** + * 生成 .d.ts 类型声明文件 + * - 组件库 / npm 包发布必需 + * - 对应用项目无害,仅影响类型输出 + */ + "declaration": true, + + /** + * 只做类型检查,不生成 JS 输出 + * - 适用于 Vite / Next / Nuxt 等 bundler 场景 + * - 防止 tsc 与构建工具重复 emit + */ + "noEmit": true, + + /** + * 强制单文件可独立编译 + * - 适配 esbuild / SWC / bundler 编译模型 + * - 禁止依赖跨文件类型推断(enum / namespace 等) + */ + "isolatedModules": true, + + /** + * 允许在 import 中显式使用 .ts / .tsx 后缀 + * - 兼容 Node ESM / bundler 对文件扩展名的严格要求 + * - 避免 `import './foo'` 在 TS + ESM 下歧义 + */ + "allowImportingTsExtensions": true + }, + /** + * 参与类型检查和编译的文件 + * - 只扫描 src + * - 其它目录通过 exclude 排除 + */ + "include": ["src", "scripts"], + + /** + * 明确排除非源码内容 + * - 避免污染类型系统 + * - 防止误入 dist / test / config + * - 保证发布包干净 + */ + "exclude": [ + "scripts", + "node_modules", + "dist", + + // ---------- build / cache ---------- + ".turbo/**/*", + ".cache/**/*", + ".vite/**/*", + + // ---------- 配置文件 ---------- + "vite.config.ts", + "*.config.ts", + "*.config.js", + "tsconfig.*.json", + + // ---------- 测试相关 ---------- + "__tests__/**/*", + "test/**/*", + "tests/**/*", + "**/*.test.ts", + "**/*.test.tsx", + "**/*.spec.ts", + "**/*.spec.tsx", + + // ---------- Storybook ---------- + ".storybook/**/*", + "stories/**/*", + + // ---------- 示例 / 脚本 ---------- + "example/**/*", + "examples/**/*", + "scripts/**/*", + + // ---------- 环境与静态资源 ---------- + ".env", + ".env.*", + "public/**/*", + + // ---------- 文档 ---------- + "docs/**/*", + "README.md", + "LICENSE" + ] +} diff --git a/packages/music-grabber/tsconfig.json b/packages/music-grabber/tsconfig.json new file mode 100644 index 0000000..d5ec425 --- /dev/null +++ b/packages/music-grabber/tsconfig.json @@ -0,0 +1,118 @@ +{ + // tsconfig.lib.json + // 直接复制本文件内容到子项目的 tsconfig.json 即可,不要用 entends 继承本文件 + "extends": "../../tsconfig.base.json", + "compilerOptions": { + /** + * Browser api,需要加 "DOM","DOM.Iterable" + * Node api,需要加 "ES2025",始终使用带版本号的最新版本 + * NextJs api,属于同构,server 端会预处理 DOM,计算url,三个都需要 "ES2025", "DOM", "DOM.Iterable" + */ + "lib": ["ES2025", "DOM", "DOM.Iterable"], + + /** + * React JSX 编译模式 + * - 使用 React 17+ 新 JSX Transform + * - 不需要手动 import React + */ + "jsx": "react-jsx", + + /** + * 编译输出目录 + * - tsc / tsc -b 都会用到 + */ + "outDir": "./dist", + + /** + * 源码根目录 + * - 确保 dist 结构与 src 一致 + * - 对 declaration 路径至关重要 + */ + "rootDir": "./src", + + /** + * 生成 .d.ts 类型声明文件 + * - 组件库 / npm 包发布必需 + * - 对应用项目无害,仅影响类型输出 + */ + "declaration": true, + + /** + * 只做类型检查,不生成 JS 输出 + * - 适用于 Vite / Next / Nuxt 等 bundler 场景 + * - 防止 tsc 与构建工具重复 emit + */ + "noEmit": true, + + /** + * 强制单文件可独立编译 + * - 适配 esbuild / SWC / bundler 编译模型 + * - 禁止依赖跨文件类型推断(enum / namespace 等) + */ + "isolatedModules": true, + + /** + * 允许在 import 中显式使用 .ts / .tsx 后缀 + * - 兼容 Node ESM / bundler 对文件扩展名的严格要求 + * - 避免 `import './foo'` 在 TS + ESM 下歧义 + */ + "allowImportingTsExtensions": true + }, + /** + * 参与类型检查和编译的文件 + * - 只扫描 src + * - 其它目录通过 exclude 排除 + */ + "include": ["src", "scripts"], + + /** + * 明确排除非源码内容 + * - 避免污染类型系统 + * - 防止误入 dist / test / config + * - 保证发布包干净 + */ + "exclude": [ + "scripts", + "node_modules", + "dist", + + // ---------- build / cache ---------- + ".turbo/**/*", + ".cache/**/*", + ".vite/**/*", + + // ---------- 配置文件 ---------- + "vite.config.ts", + "*.config.ts", + "*.config.js", + "tsconfig.*.json", + + // ---------- 测试相关 ---------- + "__tests__/**/*", + "test/**/*", + "tests/**/*", + "**/*.test.ts", + "**/*.test.tsx", + "**/*.spec.ts", + "**/*.spec.tsx", + + // ---------- Storybook ---------- + ".storybook/**/*", + "stories/**/*", + + // ---------- 示例 / 脚本 ---------- + "example/**/*", + "examples/**/*", + "scripts/**/*", + + // ---------- 环境与静态资源 ---------- + ".env", + ".env.*", + "public/**/*", + + // ---------- 文档 ---------- + "docs/**/*", + "README.md", + "LICENSE" + ] +} diff --git a/packages/note-maker/package.json b/packages/note-maker/package.json new file mode 100644 index 0000000..f6ccb88 --- /dev/null +++ b/packages/note-maker/package.json @@ -0,0 +1,12 @@ +{ + "name": "defgov-note-maker", + "version": "0.0.0", + "private": true, + "peerDependencies": { + "parse5": "^8.0.1" + }, + "devDependencies": { + "@types/node": "^25.6.0", + "typescript": "^6.0.3" + } +} diff --git a/packages/note-maker/src/content-block/dg-ls.ts b/packages/note-maker/src/content-block/dg-ls.ts new file mode 100644 index 0000000..e69de29 diff --git a/packages/note-maker/src/content-block/dg-text.ts b/packages/note-maker/src/content-block/dg-text.ts new file mode 100644 index 0000000..67f7ff1 --- /dev/null +++ b/packages/note-maker/src/content-block/dg-text.ts @@ -0,0 +1,8 @@ +class DgText extends HTMLParagraphElement { + constructor() { + super(); + const shadow = this.attachShadow({ mode: "open" }); + + shadow.innerHTML + } +} diff --git a/packages/note-maker/src/content-block/dg-ul.ts b/packages/note-maker/src/content-block/dg-ul.ts new file mode 100644 index 0000000..e69de29 diff --git a/packages/note-maker/tsconfig.json b/packages/note-maker/tsconfig.json new file mode 100644 index 0000000..d5ec425 --- /dev/null +++ b/packages/note-maker/tsconfig.json @@ -0,0 +1,118 @@ +{ + // tsconfig.lib.json + // 直接复制本文件内容到子项目的 tsconfig.json 即可,不要用 entends 继承本文件 + "extends": "../../tsconfig.base.json", + "compilerOptions": { + /** + * Browser api,需要加 "DOM","DOM.Iterable" + * Node api,需要加 "ES2025",始终使用带版本号的最新版本 + * NextJs api,属于同构,server 端会预处理 DOM,计算url,三个都需要 "ES2025", "DOM", "DOM.Iterable" + */ + "lib": ["ES2025", "DOM", "DOM.Iterable"], + + /** + * React JSX 编译模式 + * - 使用 React 17+ 新 JSX Transform + * - 不需要手动 import React + */ + "jsx": "react-jsx", + + /** + * 编译输出目录 + * - tsc / tsc -b 都会用到 + */ + "outDir": "./dist", + + /** + * 源码根目录 + * - 确保 dist 结构与 src 一致 + * - 对 declaration 路径至关重要 + */ + "rootDir": "./src", + + /** + * 生成 .d.ts 类型声明文件 + * - 组件库 / npm 包发布必需 + * - 对应用项目无害,仅影响类型输出 + */ + "declaration": true, + + /** + * 只做类型检查,不生成 JS 输出 + * - 适用于 Vite / Next / Nuxt 等 bundler 场景 + * - 防止 tsc 与构建工具重复 emit + */ + "noEmit": true, + + /** + * 强制单文件可独立编译 + * - 适配 esbuild / SWC / bundler 编译模型 + * - 禁止依赖跨文件类型推断(enum / namespace 等) + */ + "isolatedModules": true, + + /** + * 允许在 import 中显式使用 .ts / .tsx 后缀 + * - 兼容 Node ESM / bundler 对文件扩展名的严格要求 + * - 避免 `import './foo'` 在 TS + ESM 下歧义 + */ + "allowImportingTsExtensions": true + }, + /** + * 参与类型检查和编译的文件 + * - 只扫描 src + * - 其它目录通过 exclude 排除 + */ + "include": ["src", "scripts"], + + /** + * 明确排除非源码内容 + * - 避免污染类型系统 + * - 防止误入 dist / test / config + * - 保证发布包干净 + */ + "exclude": [ + "scripts", + "node_modules", + "dist", + + // ---------- build / cache ---------- + ".turbo/**/*", + ".cache/**/*", + ".vite/**/*", + + // ---------- 配置文件 ---------- + "vite.config.ts", + "*.config.ts", + "*.config.js", + "tsconfig.*.json", + + // ---------- 测试相关 ---------- + "__tests__/**/*", + "test/**/*", + "tests/**/*", + "**/*.test.ts", + "**/*.test.tsx", + "**/*.spec.ts", + "**/*.spec.tsx", + + // ---------- Storybook ---------- + ".storybook/**/*", + "stories/**/*", + + // ---------- 示例 / 脚本 ---------- + "example/**/*", + "examples/**/*", + "scripts/**/*", + + // ---------- 环境与静态资源 ---------- + ".env", + ".env.*", + "public/**/*", + + // ---------- 文档 ---------- + "docs/**/*", + "README.md", + "LICENSE" + ] +} diff --git a/packages/ui-web/.vscode/settings.json b/packages/ui-web/.vscode/settings.json new file mode 100644 index 0000000..772343c --- /dev/null +++ b/packages/ui-web/.vscode/settings.json @@ -0,0 +1,8 @@ +{ + "json.schemas": [ + { + "fileMatch": ["/tsconfig.build.json", "/tsconfig.base.json"], + "schema": {} + } + ] +} diff --git a/packages/ui-web/package.json b/packages/ui-web/package.json new file mode 100644 index 0000000..0a188d7 --- /dev/null +++ b/packages/ui-web/package.json @@ -0,0 +1,50 @@ +{ + "name": "@defgov/ui-web", + "version": "0.0.0", + "private": true, + "type": "module", + "sideEffects": [ + "*.css" + ], + "module": "./dist/index.es.js", + "main": "./dist/index.cjs.js", + "types": "./dist/index.d.ts", + "style": "./dist/index.css", + "exports": { + ".": { + "import": "./dist/index.es.js", + "require": "./dist/index.cjs.js", + "types": "./dist/index.d.ts" + }, + "./index.css": "./dist/index.css" + }, + "files": [ + "dist" + ], + "scripts": { + "dev": "vite", + "build": "vite build --tsconfig tsconfig.build.json" + }, + "devDependencies": { + "@tailwindcss/vite": "^4.2.4", + "@types/node": "^25.6.0", + "@types/react": "^19.2.14", + "@types/react-dom": "^19.2.3", + "@vitejs/plugin-react": "^6.0.1", + "glob": "^13.0.6", + "ts-node": "^10.9.2", + "typescript": "^6.0.3", + "vite": "^8.0.9", + "vite-plugin-dts": "^4.5.4" + }, + "dependencies": { + "@base-ui/react": "^1.4.1", + "tailwind-merge": "^3.5.0", + "tailwind-variants": "^3.2.2", + "tailwindcss": "^4.2.4" + }, + "peerDependencies": { + "react": "^19", + "react-dom": "^19" + } +} diff --git a/packages/ui-web/scripts-plugin/vite-plugin-gen-index-css.ts b/packages/ui-web/scripts-plugin/vite-plugin-gen-index-css.ts new file mode 100644 index 0000000..47af09c --- /dev/null +++ b/packages/ui-web/scripts-plugin/vite-plugin-gen-index-css.ts @@ -0,0 +1,137 @@ +// plugins/vite-plugin-gen-index-css.ts +import type { Plugin } from "vite"; +import fs from "fs"; +import path from "path"; +import { globSync } from "glob"; + +interface Config { + targetDirs: string[]; + includeExtensions: string[]; + importSyntax: "@import"; + importSyntaxTail?: string; + excludeFilePattern: RegExp[]; + excludeDirs: string[]; + warnDuplicateTailwindImport: boolean; + indexFileName: string; +} + +const CONFIG: Config = { + targetDirs: ["src"], + includeExtensions: [".css"], + importSyntax: "@import", + excludeFilePattern: [/index\.css/, /index\.scss/, /\.(test|spec)\./], + excludeDirs: [ + "__tests__", + "tests", + "story", + "stories", + "types", + "node_modules", + "dist", + "build", + ], + warnDuplicateTailwindImport: true, + indexFileName: "index.css", +}; + +const normalizePath = (p: string) => p.replace(/\\/g, "/"); + +function isValidFile(filePath: string, config: Config): boolean { + const filenameWithExt = filePath.split(/[\\/]/).pop()!; + const shouldExcludeFile = config.excludeFilePattern.some((p) => + p.test(filenameWithExt), + ); + if (shouldExcludeFile) return false; + + const normalized = normalizePath(filePath); + const shouldExcludeDir = config.excludeDirs.some((dir) => + normalized.includes(`/${dir}/`), + ); + if (shouldExcludeDir) return false; + + const ext = path.extname(filePath); + if (!config.includeExtensions.includes(ext)) return false; + + if (config.warnDuplicateTailwindImport) { + try { + const content = fs.readFileSync(filePath, "utf-8"); + if ( + content.includes('@import "tailwindcss"') || + content.includes("@import 'tailwindcss'") + ) { + console.warn( + `[gen-index-css] ${filePath} 含有重复的 @import "tailwindcss",建议删除`, + ); + } + } catch { + // ignore + } + } + + return true; +} + +function generateIndexFile(config: Config) { + const [targetDir] = config.targetDirs; + const dirPath = path.resolve(process.cwd(), targetDir); + + const searchPattern = path.resolve(dirPath, "**", "*.*"); + + const allFiles = globSync(searchPattern, { + nodir: true, + absolute: true, + windowsPathsNoEscape: true, + dot: false, + follow: true, + }); + + const validFiles = allFiles.filter((f) => isValidFile(f, config)); + + console.log(`✅ 有效 CSS 文件数量: ${validFiles.length}`); + validFiles.sort(); + + const importStatements = validFiles.map((file) => { + const relPath = path.relative(dirPath, file); + const importPath = "./" + relPath.replace(/\\/g, "/"); + return `${config.importSyntax} '${importPath}';`; + }); + + const indexContent = ` +@import "tailwindcss"; +${importStatements.join("\n")} +`.trim(); + + const indexFilePath = path.resolve(dirPath, config.indexFileName); + + // ✅ 内容比对,防止无限 rebuild + if (fs.existsSync(indexFilePath)) { + const old = fs.readFileSync(indexFilePath, "utf8"); + if (old === indexContent) return; + } + + fs.writeFileSync(indexFilePath, indexContent, "utf8"); + console.log(`✅ 成功生成 ${config.indexFileName}: ${indexFilePath}`); +} + +export function genIndexCssPlugin(): Plugin { + return { + name: "vite-plugin-gen-index-css", + apply: "build", + + buildStart() { + try { + generateIndexFile(CONFIG); + } catch (err) { + const msg = err instanceof Error ? err.message : String(err); + this.error(`[gen-index-css] failed: ${msg}`); + throw err; + } + }, + + handleHotUpdate({ file }) { + if (normalizePath(file).endsWith(`/src/${CONFIG.indexFileName}`)) { + return []; + } + }, + }; +} diff --git a/packages/ui-web/scripts-plugin/vite-plugin-gen-index-ts.ts b/packages/ui-web/scripts-plugin/vite-plugin-gen-index-ts.ts new file mode 100644 index 0000000..17c5d84 --- /dev/null +++ b/packages/ui-web/scripts-plugin/vite-plugin-gen-index-ts.ts @@ -0,0 +1,129 @@ +// plugins/vite-plugin-gen-index-ts.ts +import type { Plugin } from "vite"; +import fs from "fs"; +import path from "path"; +import { globSync } from "glob"; + +interface Config { + targetDirs: string[]; + includeExtensions: string[]; + excludeKeywords: { + dirs: string[]; + fileSuffixes: string[]; + filePatterns: RegExp[]; + }; +} + +const CONFIG: Config = { + targetDirs: ["src"], + includeExtensions: [".ts", ".tsx", ".vue"], + excludeKeywords: { + dirs: ["__tests__", "tests", "story", "stories", "types"], + fileSuffixes: [".d.ts"], + filePatterns: [ + /^index\.(ts|tsx|js|jsx)$/, + /\.(test|spec)\./, + /\.(story|stories)\./, + ], + }, +}; + +const normalizePath = (p: string) => p.replace(/\\/g, "/"); + +const isInExcludeDir = (filePath: string) => { + const normalized = normalizePath(filePath); + return CONFIG.excludeKeywords.dirs.some((dir) => + normalized.includes(`/${dir}/`), + ); +}; + +const isExcludeSuffix = (filePath: string) => + CONFIG.excludeKeywords.fileSuffixes.some((suffix) => + filePath.endsWith(suffix), + ); + +const isMatchExcludePattern = (fileName: string) => + CONFIG.excludeKeywords.filePatterns.some((pattern) => pattern.test(fileName)); + +function isValidFile(filePath: string): boolean { + const fileName = filePath.split(/[\\/]/).pop()!; + + if (isInExcludeDir(filePath)) return false; + if (isExcludeSuffix(filePath)) return false; + if (isMatchExcludePattern(fileName)) return false; + + const ext = path.extname(filePath); + return CONFIG.includeExtensions.includes(ext); +} + +function generateIndexFile(dirPath: string) { + const searchPattern = path.resolve(dirPath, "**", "*.*"); + + const allFiles = globSync(searchPattern, { + nodir: true, + absolute: true, + windowsPathsNoEscape: true, + dot: false, + follow: true, + }); + + const validFiles = allFiles.filter(isValidFile); + if (validFiles.length === 0) return; + + validFiles.sort(); + + const exportStatements = validFiles.map((file) => { + const relPath = path.relative(dirPath, file); + const importPath = `./${relPath + .replace(/\.[^.]+$/, "") + .replace(/\\/g, "/")}`; + return `export * from '${importPath}';`; + }); + + const indexContent = ` +import './index.css'; + +${exportStatements.join("\n")} +`.trim(); + + const indexFilePath = path.resolve(dirPath, "index.ts"); + + // ✅ 内容比对,避免无限 rebuild + if (fs.existsSync(indexFilePath)) { + const old = fs.readFileSync(indexFilePath, "utf8"); + if (old === indexContent) return; + } + + fs.writeFileSync(indexFilePath, indexContent, "utf8"); +} + +export function genIndexTsPlugin(): Plugin { + return { + name: "vite-plugin-gen-index-ts", + apply: "build", + + buildStart() { + const [targetDir] = CONFIG.targetDirs; + if (!targetDir) { + this.error("CONFIG.targetDirs is empty"); + return; + } + + const absTargetDir = path.resolve(process.cwd(), targetDir); + + try { + generateIndexFile(absTargetDir); + } catch (err) { + const msg = err instanceof Error ? err.message : String(err); + this.error(`[gen-index-ts] failed: ${msg}`); + throw err; + } + }, + + handleHotUpdate({ file }) { + if (file.replace(/\\/g, "/").endsWith("/src/index.ts")) { + return []; + } + }, + }; +} diff --git a/packages/ui-web/src/assets/svg/BoldSvg.tsx b/packages/ui-web/src/assets/svg/BoldSvg.tsx new file mode 100644 index 0000000..3f61f26 --- /dev/null +++ b/packages/ui-web/src/assets/svg/BoldSvg.tsx @@ -0,0 +1,12 @@ +export const BoldSvg = (props: React.SVGProps) => ( + + + +); diff --git a/packages/ui-web/src/assets/svg/CheckIndicatorSvg.tsx b/packages/ui-web/src/assets/svg/CheckIndicatorSvg.tsx new file mode 100644 index 0000000..6b63f79 --- /dev/null +++ b/packages/ui-web/src/assets/svg/CheckIndicatorSvg.tsx @@ -0,0 +1,8 @@ +export const CheckIndicatorSvg = (props: React.SVGProps) => ( + + + +); diff --git a/packages/ui-web/src/assets/svg/ChevronRightSvg.tsx b/packages/ui-web/src/assets/svg/ChevronRightSvg.tsx new file mode 100644 index 0000000..612809c --- /dev/null +++ b/packages/ui-web/src/assets/svg/ChevronRightSvg.tsx @@ -0,0 +1,12 @@ +export const ChevronRightSvg = (props: React.SVGProps) => ( + + + +); diff --git a/packages/ui-web/src/assets/svg/CutSvg.tsx b/packages/ui-web/src/assets/svg/CutSvg.tsx new file mode 100644 index 0000000..3b953fc --- /dev/null +++ b/packages/ui-web/src/assets/svg/CutSvg.tsx @@ -0,0 +1,8 @@ +export const CutSvg = (props: React.SVGProps) => ( + + + +); diff --git a/packages/ui-web/src/assets/svg/DownloadSvg.tsx b/packages/ui-web/src/assets/svg/DownloadSvg.tsx new file mode 100644 index 0000000..ce6a0ca --- /dev/null +++ b/packages/ui-web/src/assets/svg/DownloadSvg.tsx @@ -0,0 +1,8 @@ +export const DownloadSvg = (props: React.SVGProps) => ( + + + +); diff --git a/packages/ui-web/src/assets/svg/FileSvg.tsx b/packages/ui-web/src/assets/svg/FileSvg.tsx new file mode 100644 index 0000000..1edb89f --- /dev/null +++ b/packages/ui-web/src/assets/svg/FileSvg.tsx @@ -0,0 +1,14 @@ +export const FileSvg = (props: React.SVGProps) => ( + + + + + + +); diff --git a/packages/ui-web/src/assets/svg/KeySvg.tsx b/packages/ui-web/src/assets/svg/KeySvg.tsx new file mode 100644 index 0000000..8136e7e --- /dev/null +++ b/packages/ui-web/src/assets/svg/KeySvg.tsx @@ -0,0 +1,8 @@ +export const KeySvg = (props: React.SVGProps) => ( + + + +); diff --git a/packages/ui-web/src/assets/svg/MeshSvg.tsx b/packages/ui-web/src/assets/svg/MeshSvg.tsx new file mode 100644 index 0000000..3ecb96b --- /dev/null +++ b/packages/ui-web/src/assets/svg/MeshSvg.tsx @@ -0,0 +1,14 @@ +export const MeshSvg = (props: React.SVGProps) => ( + + + + + + +); diff --git a/packages/ui-web/src/assets/svg/MoonSvg.tsx b/packages/ui-web/src/assets/svg/MoonSvg.tsx new file mode 100644 index 0000000..5304a65 --- /dev/null +++ b/packages/ui-web/src/assets/svg/MoonSvg.tsx @@ -0,0 +1,12 @@ +export const MoonSvg = (props: React.SVGProps) => ( + + + +); diff --git a/packages/ui-web/src/assets/svg/PasteSvg.tsx b/packages/ui-web/src/assets/svg/PasteSvg.tsx new file mode 100644 index 0000000..244848e --- /dev/null +++ b/packages/ui-web/src/assets/svg/PasteSvg.tsx @@ -0,0 +1,8 @@ +export const PasteSvg = (props: React.SVGProps) => ( + + + +); diff --git a/packages/ui-web/src/assets/svg/Ruler.tsx b/packages/ui-web/src/assets/svg/Ruler.tsx new file mode 100644 index 0000000..7f59fdc --- /dev/null +++ b/packages/ui-web/src/assets/svg/Ruler.tsx @@ -0,0 +1,12 @@ +export const RulerSvg = (props: React.SVGProps) => ( + + + +); diff --git a/packages/ui-web/src/assets/svg/SearchSvg.tsx b/packages/ui-web/src/assets/svg/SearchSvg.tsx new file mode 100644 index 0000000..fc05409 --- /dev/null +++ b/packages/ui-web/src/assets/svg/SearchSvg.tsx @@ -0,0 +1,8 @@ +export const SearchSvg = (props: React.SVGProps) => ( + + + +); diff --git a/packages/ui-web/src/assets/svg/SettingSvg.tsx b/packages/ui-web/src/assets/svg/SettingSvg.tsx new file mode 100644 index 0000000..c4baf2e --- /dev/null +++ b/packages/ui-web/src/assets/svg/SettingSvg.tsx @@ -0,0 +1,9 @@ +export const SettingSvg = (props: React.SVGProps) => ( + + + +); diff --git a/packages/ui-web/src/assets/svg/SpinnerSvg.tsx b/packages/ui-web/src/assets/svg/SpinnerSvg.tsx new file mode 100644 index 0000000..61cc1f6 --- /dev/null +++ b/packages/ui-web/src/assets/svg/SpinnerSvg.tsx @@ -0,0 +1,23 @@ +export const SpinnerSvg = (props: React.SVGProps) => { + return ( + + + + + + + ); +}; diff --git a/packages/ui-web/src/assets/svg/SunSvg.tsx b/packages/ui-web/src/assets/svg/SunSvg.tsx new file mode 100644 index 0000000..e977265 --- /dev/null +++ b/packages/ui-web/src/assets/svg/SunSvg.tsx @@ -0,0 +1,12 @@ +export const SunSvg = (props: React.SVGProps) => ( + + + +); diff --git a/packages/ui-web/src/assets/svg/UserSvg.tsx b/packages/ui-web/src/assets/svg/UserSvg.tsx new file mode 100644 index 0000000..ec51b40 --- /dev/null +++ b/packages/ui-web/src/assets/svg/UserSvg.tsx @@ -0,0 +1,14 @@ +export const UserSvg = (props: React.SVGProps) => { + return ( + + + + ); +}; diff --git a/packages/ui-web/src/assets/svg/VolumeHighSvg.tsx b/packages/ui-web/src/assets/svg/VolumeHighSvg.tsx new file mode 100644 index 0000000..5920a0c --- /dev/null +++ b/packages/ui-web/src/assets/svg/VolumeHighSvg.tsx @@ -0,0 +1,12 @@ +export const VolumeHighSvg = (props: React.SVGProps) => ( + + + +); diff --git a/packages/ui-web/src/assets/svg/VolumeLowSvg.tsx b/packages/ui-web/src/assets/svg/VolumeLowSvg.tsx new file mode 100644 index 0000000..818b4c2 --- /dev/null +++ b/packages/ui-web/src/assets/svg/VolumeLowSvg.tsx @@ -0,0 +1,12 @@ +export const VolumeLowSvg = (props: React.SVGProps) => ( + + + +); diff --git a/packages/ui-web/src/assets/svg/VolumeMuteSvg.tsx b/packages/ui-web/src/assets/svg/VolumeMuteSvg.tsx new file mode 100644 index 0000000..abaff84 --- /dev/null +++ b/packages/ui-web/src/assets/svg/VolumeMuteSvg.tsx @@ -0,0 +1,12 @@ +export const VolumeMuteSvg = (props: React.SVGProps) => ( + + + +); diff --git a/packages/ui-web/src/common/Box.tsx b/packages/ui-web/src/common/Box.tsx new file mode 100644 index 0000000..553d81e --- /dev/null +++ b/packages/ui-web/src/common/Box.tsx @@ -0,0 +1,41 @@ +import React from "react"; +import { cn } from "tailwind-variants"; +import { CommonProps } from "./CommonProps"; + +// 别名<约束>=值 +// 千万不要 C = As extend React.ElementType,这样子连等号,会切断推导 +type AsProp = { as?: C }; + +type PropsToOmit = keyof (AsProp & P); + +export type PolymorphicProps = (P & + AsProp) & + Omit, PropsToOmit>; + +interface BoxProps extends CommonProps { + as?: C; +} + +const Box = ( + props: PolymorphicProps>, + ref?: React.ComponentPropsWithRef["ref"], +) => { + const { as: Component = "div", children, className, ...rest } = props; + + + const boxRootClass = cn( className); + + return ( + + {children} + + ); +}; + +export type BoxComponent = ( + props: PolymorphicProps> & { + ref?: React.ComponentPropsWithRef["ref"]; + }, +) => React.ReactElement | null; + +export default Box as BoxComponent; diff --git a/packages/ui-web/src/common/CommonProps.ts b/packages/ui-web/src/common/CommonProps.ts new file mode 100644 index 0000000..395df95 --- /dev/null +++ b/packages/ui-web/src/common/CommonProps.ts @@ -0,0 +1,9 @@ +import { CSSProperties, ReactNode } from "react"; + +export type CommonProps = { + className?: string; + style?: CSSProperties; + children?: ReactNode; + disabled?: boolean; + key?: string; +}; diff --git a/packages/ui-web/src/common/Slot.tsx b/packages/ui-web/src/common/Slot.tsx new file mode 100644 index 0000000..4bee4a7 --- /dev/null +++ b/packages/ui-web/src/common/Slot.tsx @@ -0,0 +1,33 @@ +import { mergeProps } from "@base-ui/react"; +import * as React from "react"; +import { cn } from "tailwind-variants"; + +export interface SlotProps extends React.HTMLAttributes { + children: React.ReactNode; +} + +export const Slot = React.forwardRef( + ({ children, className: externalClassName, ...restProps }, ref) => { + if (!React.isValidElement(children)) { + return null; + } + + const child = children as React.ReactElement>; + const childProps = child.props || {}; + + const mergedClassName = cn( + childProps.className as string | undefined, + externalClassName, + ); + + const otherMergedProps = mergeProps(childProps, restProps); + + return React.cloneElement(child, { + ...otherMergedProps, + className: mergedClassName, + ref, + }); + }, +); + +Slot.displayName = "Slot"; diff --git a/packages/ui-web/src/component/accordion/Accordion.css b/packages/ui-web/src/component/accordion/Accordion.css new file mode 100644 index 0000000..0992683 --- /dev/null +++ b/packages/ui-web/src/component/accordion/Accordion.css @@ -0,0 +1,9 @@ +.accordion-root { + box-sizing: border-box; + display: flex; + width: 24rem; + max-width: calc(100vw - 8rem); + flex-direction: column; + justify-content: center; + color: var(--color-gray-900); +} diff --git a/packages/ui-web/src/component/accordion/Accordion.tsx b/packages/ui-web/src/component/accordion/Accordion.tsx new file mode 100644 index 0000000..9121f97 --- /dev/null +++ b/packages/ui-web/src/component/accordion/Accordion.tsx @@ -0,0 +1,20 @@ +import * as BUI from "@base-ui/react"; +import type { ComponentProps } from "react"; +import { CommonProps } from "../../common/CommonProps"; +import { itemSizeRecipe } from "../../styles/recipe/ItemSize.recipe"; + +type AccordionProps = CommonProps & + ComponentProps & { + size?: "xs" | "sm" | "md" | "lg"; + chevronPosition?: "left" | "right"; + }; + +export const Accordion = (props: AccordionProps) => { + const { children, size, ...rest } = props; + const accordionRootCls = itemSizeRecipe({ size }); + return ( + + {children} + + ); +}; diff --git a/packages/ui-web/src/component/accordion/AccordionItem.tsx b/packages/ui-web/src/component/accordion/AccordionItem.tsx new file mode 100644 index 0000000..1124c9b --- /dev/null +++ b/packages/ui-web/src/component/accordion/AccordionItem.tsx @@ -0,0 +1 @@ +export const AccordionItem = () => {}; diff --git a/packages/ui-web/src/component/accordion/AccordionPanel.tsx b/packages/ui-web/src/component/accordion/AccordionPanel.tsx new file mode 100644 index 0000000..dfeb857 --- /dev/null +++ b/packages/ui-web/src/component/accordion/AccordionPanel.tsx @@ -0,0 +1 @@ +export const AccordionPanel = () => {}; diff --git a/packages/ui-web/src/component/accordion/AccordionTrigger.tsx b/packages/ui-web/src/component/accordion/AccordionTrigger.tsx new file mode 100644 index 0000000..f1b7c16 --- /dev/null +++ b/packages/ui-web/src/component/accordion/AccordionTrigger.tsx @@ -0,0 +1 @@ +export const AccordionTrigger = () => {}; diff --git a/packages/ui-web/src/component/avatar/Avatar.css b/packages/ui-web/src/component/avatar/Avatar.css new file mode 100644 index 0000000..29bf0c4 --- /dev/null +++ b/packages/ui-web/src/component/avatar/Avatar.css @@ -0,0 +1,19 @@ +@layer components { + .avatar-root { + background-color: var(--default-bg); + } + .avatar-image { + object-fit: cover; + height: 100%; + width: 100%; + } + + .avatar-fallback { + align-items: center; + display: flex; + justify-content: center; + height: 100%; + width: 100%; + background-color: var(--default-bg); + } +} diff --git a/packages/ui-web/src/component/avatar/Avatar.tsx b/packages/ui-web/src/component/avatar/Avatar.tsx new file mode 100644 index 0000000..2153dc6 --- /dev/null +++ b/packages/ui-web/src/component/avatar/Avatar.tsx @@ -0,0 +1,25 @@ +import * as BUI from "@base-ui/react"; +import { itemSizeRecipe } from "../../styles/recipe/ItemSize.recipe"; +import { UserSvg } from "../../assets/svg/UserSvg"; +import { Icon } from "../icon/Icon"; + +type AvatarPorps = { + size?: "sm" | "md" | "lg"; + src?: string; + name?: string; +}; + +export const Avatar = (props: AvatarPorps) => { + const { size = "md", src, name } = props; + + const avatarCls = itemSizeRecipe({ size, iconOnly: true }); + + return ( + + + + } /> + + + ); +}; diff --git a/packages/ui-web/src/component/button/Button.tsx b/packages/ui-web/src/component/button/Button.tsx new file mode 100644 index 0000000..9244fa7 --- /dev/null +++ b/packages/ui-web/src/component/button/Button.tsx @@ -0,0 +1,60 @@ +"use client"; +import type { ReactNode } from "react"; +import * as BUI from "@base-ui/react"; +import { cn } from "tailwind-variants"; +import { brandRecipe } from "../../styles/recipe/brand.recipe"; +import { itemSizeRecipe } from "../../styles/recipe/ItemSize.recipe"; +import { variantRecipe } from "../../styles/recipe/variant.recipe"; +import { Icon } from "../icon/Icon"; + +type ButtonProps = { + size?: "xs" | "sm" | "md" | "lg"; + variant?: "filled" | "outline" | "subtle" | "ghost"; + shape?: "rounded" | "square" | "circle"; + brand?: "success" | "danger" | "info" | "warning" | "default"; + loading?: boolean; + iconSvg?: ReactNode; + iconOnly?: boolean; + hideIcon?: boolean; +} & BUI.Button.Props; + +export const Button = (props: ButtonProps) => { + const { + className, + children, + size = "md", + variant = "filled", + shape = "rounded", + brand, + loading, + disabled, + iconSvg, + iconOnly, + hideIcon = false, + } = props; + + const currentBrand = + brand == undefined ? (variant == "filled" ? "info" : "default") : brand; + + const buttonCls = cn( + itemSizeRecipe({ size, shape, iconOnly }), + variantRecipe({ variant, disabled: loading || disabled }), + brandRecipe({ brand: currentBrand }), + className, + ); + + return ( + + {iconSvg ? ( + hideIcon ? ( + iconOnly ? ( + + ) : null + ) : ( + + ) + ) : null} + {!iconOnly && children} + + ); +}; diff --git a/packages/ui-web/src/component/checkbox/Checkbox.css b/packages/ui-web/src/component/checkbox/Checkbox.css new file mode 100644 index 0000000..a3da84f --- /dev/null +++ b/packages/ui-web/src/component/checkbox/Checkbox.css @@ -0,0 +1,19 @@ +@layer components { + .checkbox-root { + &[data-unchecked] { + border: 1px solid var(--color-gray-300); + background-color: transparent; + } + &[data-checked] { + background-color: var(--brand-bg); + } + } + .checkbox-indicator { + display: flex; + color: var(--color-gray-50); + + &[data-unchecked] { + display: none; + } + } +} diff --git a/packages/ui-web/src/component/checkbox/Checkbox.tsx b/packages/ui-web/src/component/checkbox/Checkbox.tsx new file mode 100644 index 0000000..f9aa052 --- /dev/null +++ b/packages/ui-web/src/component/checkbox/Checkbox.tsx @@ -0,0 +1,76 @@ +"use client"; +import * as BUI from "@base-ui/react"; +import { cn } from "tailwind-variants"; +import type { ReactNode } from "react"; +import { itemSizeRecipe } from "../../styles/recipe/ItemSize.recipe"; +import { variantRecipe } from "../../styles/recipe/variant.recipe"; +import { CommonProps } from "../../common/CommonProps"; +import { inlineSizeRecipe } from "../../styles/recipe/IinlineSize.recipe"; +import { CheckIndicatorSvg } from "../../assets/svg/CheckIndicatorSvg"; +import { Slot } from "../../common/Slot"; + +type CheckboxProps = CommonProps & { + size?: "xs" | "sm" | "md"; + shape?: "square" | "rounded"; + icon?: ReactNode; + hideIcon?: boolean; + iconPlaceholder?: boolean; +}; + +export const Checkbox = (props: CheckboxProps) => { + const { + className, + children, + size = "sm", + shape = "square", + icon, + hideIcon = false, + iconPlaceholder = false, + disabled, + } = props; + + const checkboxCls = cn( + itemSizeRecipe({ size, shape }), + variantRecipe({ variant: "ghost", disabled }), + "brand-default", + className, + ); + const checkboxRootCls = cn( + inlineSizeRecipe({ + size, + shape: "rounded", + iconOnly: true, + }), + "checkbox-root", + "brand-info", + ); + const checkIndicatorCls = cn( + inlineSizeRecipe({ + size, + shape: "rounded", + iconOnly: true, + }), + "checkbox-indicator", + ); + const checkIndicatorSvgCls = inlineSizeRecipe({ + size, + iconOnly: true, + }); + + const iconCls = cn(inlineSizeRecipe({ size, iconOnly: true })); + + return ( + + + + + + + + {icon && !hideIcon && {icon}} + {hideIcon && iconPlaceholder && } + {children} + + + ); +}; diff --git a/packages/ui-web/src/component/icon/Icon.tsx b/packages/ui-web/src/component/icon/Icon.tsx new file mode 100644 index 0000000..6379dbe --- /dev/null +++ b/packages/ui-web/src/component/icon/Icon.tsx @@ -0,0 +1,21 @@ +import { ReactNode } from "react"; +import { cn } from "tailwind-variants"; +import { inlineSizeRecipe } from "../../styles/recipe/IinlineSize.recipe"; +import { Slot } from "../../common/Slot"; + +type IconProps = { + size?: "xs" | "sm" | "md" | "lg"; + svg?: ReactNode; +}; + +export const Icon = (props: IconProps) => { + const { size, svg } = props; + + const iconCls = cn(inlineSizeRecipe({ size, iconOnly: true })); + + return ( + + {svg ? {svg} : null} + + ); +}; diff --git a/packages/ui-web/src/component/theme/Theme.tsx b/packages/ui-web/src/component/theme/Theme.tsx new file mode 100644 index 0000000..0556f30 --- /dev/null +++ b/packages/ui-web/src/component/theme/Theme.tsx @@ -0,0 +1,18 @@ +import { cn } from "tailwind-variants"; +import { ThemeContext } from "./ThemeContext"; +import { ReactNode } from "react"; + +type ThemeProps = { + theme?: "light" | "dark"; + children?: ReactNode; +}; + +export const Theme = (props: ThemeProps) => { + const { theme = "light", children } = props; + const themeCls = cn(theme, "brand-default") as string; + return ( + +
{children}
+
+ ); +}; diff --git a/packages/ui-web/src/component/theme/ThemeContext.tsx b/packages/ui-web/src/component/theme/ThemeContext.tsx new file mode 100644 index 0000000..d11f7b1 --- /dev/null +++ b/packages/ui-web/src/component/theme/ThemeContext.tsx @@ -0,0 +1,5 @@ +import React from "react"; + +type ThemeContextValue = { themeCls?: string }; + +export const ThemeContext = React.createContext({}); diff --git a/packages/ui-web/src/component/theme/useTheme.ts b/packages/ui-web/src/component/theme/useTheme.ts new file mode 100644 index 0000000..e9305c2 --- /dev/null +++ b/packages/ui-web/src/component/theme/useTheme.ts @@ -0,0 +1,6 @@ +import { useContext } from "react"; +import { ThemeContext } from "./ThemeContext"; + +export const useTheme = () => { + return useContext(ThemeContext); +}; diff --git a/packages/ui-web/src/component/tooltip/Tooltip.css b/packages/ui-web/src/component/tooltip/Tooltip.css new file mode 100644 index 0000000..ac9757c --- /dev/null +++ b/packages/ui-web/src/component/tooltip/Tooltip.css @@ -0,0 +1,50 @@ +@layer components { + .tooltip-arrow { + display: flex; + fill: aquamarine; + + &[data-side="top"] { + bottom: -6px; + rotate: 180deg; + } + + &[data-side="bottom"] { + top: -6px; + rotate: 0deg; + } + + &[data-side="left"] { + right: -8px; + rotate: 90deg; + } + + &[data-side="right"] { + left: -8px; + rotate: -90deg; + } + } + + .tooltip-popup { + display: flex; + background-color: var(--base-bg); + border: 1px solid color-mix(in srgb, var(--brand-bg) 40%, white); + filter: drop-shadow(var(--drop-shadow-sm)); + transform-origin: var(--transform-origin); + transition: + transform 50ms, + opacity 50ms; + &[data-starting-style], + &[data-ending-style] { + opacity: 0; + transform: scale(0.9); + } + + &[data-instant] { + transition: none; + } + } + + .tooltip-arrow-border { + fill: color-mix(in srgb, var(--brand-bg) 40%, white); + } +} diff --git a/packages/ui-web/src/component/tooltip/Tooltip.tsx b/packages/ui-web/src/component/tooltip/Tooltip.tsx new file mode 100644 index 0000000..381ee4e --- /dev/null +++ b/packages/ui-web/src/component/tooltip/Tooltip.tsx @@ -0,0 +1,14 @@ +"use client"; +import * as BUI from "@base-ui/react"; + +type TooltipProps = BUI.Tooltip.Root.Props; + +export const Tooltip = (props: TooltipProps) => { + const { children, open } = props; + + return ( + + {children} + + ); +}; diff --git a/packages/ui-web/src/component/tooltip/TooltipPopup.tsx b/packages/ui-web/src/component/tooltip/TooltipPopup.tsx new file mode 100644 index 0000000..6ce9da1 --- /dev/null +++ b/packages/ui-web/src/component/tooltip/TooltipPopup.tsx @@ -0,0 +1,53 @@ +"use client"; +import * as BUI from "@base-ui/react"; +import { cn } from "tailwind-variants"; +import { useTheme } from "../theme/useTheme"; +import { itemSizeRecipe } from "../../styles/recipe/ItemSize.recipe"; +import { ReactNode } from "react"; + +type TooltipPopupProps = { + hideArrow?: boolean; + side?: "top" | "bottom" | "left" | "right"; + children?: ReactNode; +}; + +export const TooltipPopup = (props: TooltipPopupProps) => { + const { children, hideArrow = false, side } = props; + const { themeCls } = useTheme(); + + const tooltipPopupCls = cn( + themeCls, + itemSizeRecipe({ size: "xs", shape: "rounded" }), + "tooltip-popup", + ); + + return ( + + + + {!hideArrow && ( + + + + )} + {children} + + + + ); +}; + +const PopupArrowUpSvg = (props: React.SVGProps) => ( + + + + + +); diff --git a/packages/ui-web/src/component/tooltip/TooltipTrigger.tsx b/packages/ui-web/src/component/tooltip/TooltipTrigger.tsx new file mode 100644 index 0000000..11d0b1e --- /dev/null +++ b/packages/ui-web/src/component/tooltip/TooltipTrigger.tsx @@ -0,0 +1,13 @@ +"use client"; +import * as BUI from "@base-ui/react"; + +type TooltipTrigerProps = BUI.Tooltip.Trigger.Props; + +export const TooltipTriger = (props: TooltipTrigerProps) => { + const { children, delay = 100 } = props; + return ( + } delay={delay}> + {children} + + ); +}; diff --git a/packages/ui-web/src/component/username-field/UsernameField.tsx b/packages/ui-web/src/component/username-field/UsernameField.tsx new file mode 100644 index 0000000..34f1eda --- /dev/null +++ b/packages/ui-web/src/component/username-field/UsernameField.tsx @@ -0,0 +1 @@ +export const UsernameField = () => {}; diff --git a/packages/ui-web/src/index.css b/packages/ui-web/src/index.css new file mode 100644 index 0000000..6416da1 --- /dev/null +++ b/packages/ui-web/src/index.css @@ -0,0 +1,16 @@ +@import "tailwindcss"; +@import './component/accordion/Accordion.css'; +@import './component/avatar/Avatar.css'; +@import './component/checkbox/Checkbox.css'; +@import './component/tooltip/Tooltip.css'; +@import './styles/theme/global.css'; +@import './styles/utility/brand.css'; +@import './styles/utility/font.css'; +@import './styles/utility/gap.css'; +@import './styles/utility/height.css'; +@import './styles/utility/loading.css'; +@import './styles/utility/margin.css'; +@import './styles/utility/padding.css'; +@import './styles/utility/skin.css'; +@import './styles/utility/variant.css'; +@import './styles/utility/width.css'; \ No newline at end of file diff --git a/packages/ui-web/src/index.ts b/packages/ui-web/src/index.ts new file mode 100644 index 0000000..74b0046 --- /dev/null +++ b/packages/ui-web/src/index.ts @@ -0,0 +1,45 @@ + + +import './index.css'; + +export * from './assets/svg/BoldSvg'; +export * from './assets/svg/CheckIndicatorSvg'; +export * from './assets/svg/ChevronRightSvg'; +export * from './assets/svg/CutSvg'; +export * from './assets/svg/DownloadSvg'; +export * from './assets/svg/FileSvg'; +export * from './assets/svg/KeySvg'; +export * from './assets/svg/MeshSvg'; +export * from './assets/svg/MoonSvg'; +export * from './assets/svg/PasteSvg'; +export * from './assets/svg/Ruler'; +export * from './assets/svg/SearchSvg'; +export * from './assets/svg/SettingSvg'; +export * from './assets/svg/SpinnerSvg'; +export * from './assets/svg/SunSvg'; +export * from './assets/svg/UserSvg'; +export * from './assets/svg/VolumeHighSvg'; +export * from './assets/svg/VolumeLowSvg'; +export * from './assets/svg/VolumeMuteSvg'; +export * from './common/Box'; +export * from './common/CommonProps'; +export * from './common/Slot'; +export * from './component/accordion/Accordion'; +export * from './component/accordion/AccordionItem'; +export * from './component/accordion/AccordionPanel'; +export * from './component/accordion/AccordionTrigger'; +export * from './component/avatar/Avatar'; +export * from './component/button/Button'; +export * from './component/checkbox/Checkbox'; +export * from './component/icon/Icon'; +export * from './component/theme/Theme'; +export * from './component/theme/ThemeContext'; +export * from './component/theme/useTheme'; +export * from './component/tooltip/Tooltip'; +export * from './component/tooltip/TooltipPopup'; +export * from './component/tooltip/TooltipTrigger'; +export * from './component/username-field/UsernameField'; +export * from './styles/recipe/IinlineSize.recipe'; +export * from './styles/recipe/ItemSize.recipe'; +export * from './styles/recipe/brand.recipe'; +export * from './styles/recipe/variant.recipe'; diff --git a/packages/ui-web/src/styles/recipe/IinlineSize.recipe.ts b/packages/ui-web/src/styles/recipe/IinlineSize.recipe.ts new file mode 100644 index 0000000..f6c999e --- /dev/null +++ b/packages/ui-web/src/styles/recipe/IinlineSize.recipe.ts @@ -0,0 +1,91 @@ +import { tv } from "tailwind-variants"; + +export const inlineSizeRecipe = tv({ + base: "relative overflow-hidden flex flex-nowrap justify-center items-center box-border", + variants: { + size: { + xs: "text-xs h-inline-xs", + sm: "text-sm h-inline-sm", + md: "text-md h-inline-md", + lg: "text-lg h-inline-lg", + xl: "text-xl h-inline-xl", + "2xl": "text-2xl h-inline-2xl", + }, + shape: { + square: "rounded-none", + rounded: "", + circle: "rounded-full", + }, + iconOnly: { + true: "", + false: "", + }, + disabled: { + true: "", + false: "", + }, + }, + compoundVariants: [ + { + shape: "rounded", + size: "xs", + class: "rounded-xs", + }, + { + shape: "rounded", + size: "sm", + class: "rounded-sm", + }, + { + shape: "rounded", + size: "md", + class: "rounded-md", + }, + { + shape: "rounded", + size: "lg", + class: "rounded-lg", + }, + { + shape: "rounded", + size: "xl", + class: "rounded-xl", + }, + { + shape: "rounded", + size: "2xl", + class: "rounded-2xl", + }, + // -------------------------------------------------- + { + iconOnly: true, + size: "xs", + class: "w-inline-xs", + }, + { + iconOnly: true, + size: "sm", + class: "w-inline-sm", + }, + { + iconOnly: true, + size: "md", + class: "w-inline-md", + }, + { + iconOnly: true, + size: "lg", + class: "w-inline-lg", + }, + { + iconOnly: true, + size: "xl", + class: "w-inline-xl", + }, + { + iconOnly: true, + size: "2xl", + class: "w-inline-2xl", + }, + ], +}); diff --git a/packages/ui-web/src/styles/recipe/ItemSize.recipe.ts b/packages/ui-web/src/styles/recipe/ItemSize.recipe.ts new file mode 100644 index 0000000..4829f8d --- /dev/null +++ b/packages/ui-web/src/styles/recipe/ItemSize.recipe.ts @@ -0,0 +1,88 @@ +import { tv } from "tailwind-variants"; + +export const itemSizeRecipe = tv({ + base: "relative select-none flex flex-nowrap justify-center items-center", + variants: { + size: { + xs: "text-xs h-item-xs px-xs gap-xs", + sm: "text-sm h-item-sm px-sm gap-sm", + md: "text-md h-item-md px-md gap-md", + lg: "text-lg h-item-lg px-lg gap-lg", + xl: "text-xl h-item-xl px-xl gap-xl", + "2xl": "text-2xl h-item-2xl px-2xl gap-2xl", + }, + shape: { + square: "rounded-none", + rounded: "", + circle: "rounded-full", + }, + + iconOnly: { + true: "px-none", + false: "", + }, + disabled: { + true: "", + false: "", + }, + }, + compoundVariants: [ + { shape: "rounded", size: "xs", class: "rounded-sm" }, + { + shape: "rounded", + size: "sm", + class: "rounded-md", + }, + { + shape: "rounded", + size: "md", + class: "rounded-lg", + }, + { + shape: "rounded", + size: "lg", + class: "rounded-xl", + }, + { + shape: "rounded", + size: "xl", + class: "rounded-2xl", + }, + { + shape: "rounded", + size: "2xl", + class: "rounded-3xl", + }, + // -------------------------------------------------- + { + iconOnly: true, + size: "xs", + class: "w-item-xs", + }, + { + iconOnly: true, + size: "sm", + class: "w-item-sm", + }, + { + iconOnly: true, + size: "md", + class: "w-item-md", + }, + { + iconOnly: true, + size: "lg", + class: "w-item-lg", + }, + { + iconOnly: true, + size: "xl", + class: "w-item-xl", + }, + { + iconOnly: true, + size: "2xl", + class: "w-item-2xl", + }, + ], +}); diff --git a/packages/ui-web/src/styles/recipe/brand.recipe.ts b/packages/ui-web/src/styles/recipe/brand.recipe.ts new file mode 100644 index 0000000..72ad1b6 --- /dev/null +++ b/packages/ui-web/src/styles/recipe/brand.recipe.ts @@ -0,0 +1,13 @@ +import { tv } from "tailwind-variants"; + +export const brandRecipe = tv({ + variants: { + brand: { + success: "brand-success", + danger: "brand-danger", + info: "brand-info", + warning: "brand-warning", + default: "brand-default", + }, + }, +}); diff --git a/packages/ui-web/src/styles/recipe/variant.recipe.ts b/packages/ui-web/src/styles/recipe/variant.recipe.ts new file mode 100644 index 0000000..534bfd9 --- /dev/null +++ b/packages/ui-web/src/styles/recipe/variant.recipe.ts @@ -0,0 +1,38 @@ +import { tv } from "tailwind-variants"; + +export const variantRecipe = tv({ + variants: { + variant: { + filled: "variant-filled", + outline: "variant-outline", + subtle: "variant-subtle", + ghost: "variant-ghost", + }, + disabled: { + true: "", + false: "", + }, + }, + compoundVariants: [ + { + disabled: true, + variant: "filled", + class: "variant-filled-disabled", + }, + { + disabled: true, + variant: "outline", + class: "variant-outline-disabled", + }, + { + disabled: true, + variant: "subtle", + class: "variant-subtle-disabled", + }, + { + disabled: true, + variant: "ghost", + class: "variant-ghost-disabled", + }, + ], +}); diff --git a/packages/ui-web/src/styles/theme/global.css b/packages/ui-web/src/styles/theme/global.css new file mode 100644 index 0000000..ce9877a --- /dev/null +++ b/packages/ui-web/src/styles/theme/global.css @@ -0,0 +1,44 @@ +@theme { + --text-md: 1rem; + --text-md--line-height: calc(1.5 / 1); + --color-transparent: transparent; + + --danger-bg: var(--color-red-600); + --danger-bg-hover: var(--color-red-500); + --danger-bg-active: var(--color-red-400); + --danger-bg-low: var(--color-red-100); + --danger-bg-low-hover: var(--color-red-200); + --danger-bg-low-active: var(--color-red-300); + + --success-bg: var(--color-emerald-600); + --success-bg-hover: var(--color-emerald-500); + --success-bg-active: var(--color-emerald-400); + --success-bg-low: var(--color-emerald-100); + --success-bg-low-hover: var(--color-emerald-100); + --success-bg-low-active: var(--color-emerald-200); + + --info-bg: var(--color-sky-600); + --info-bg-hover: var(--color-sky-500); + --info-bg-active: var(--color-sky-400); + --info-bg-low: var(--color-sky-100); + --info-bg-low-hover: var(--color-sky-200); + --info-bg-low-active: var(--color-sky-300); + + --warning-bg: var(--color-yellow-600); + --warning-bg-hover: var(--color-yellow-500); + --warning-bg-active: var(--color-yellow-400); + --warning-bg-low: var(--color-yellow-100); + --warning-bg-low-hover: var(--color-yellow-200); + --warning-bg-low-active: var(--color-yellow-300); + + --default-bg: var(--color-neutral-700); + --default-bg-hover: var(--color-neutral-600); + --default-bg-active: var(--color-neutral-500); + --default-bg-low: var(--color-neutral-100); + --default-bg-low-hover: var(--color-neutral-200); + --default-bg-low-active: var(--color-neutral-300); + + --disabled-fg: var(--color-gray-500); + --disabled-bg: var(--color-gray-200); + --disabled-border-color: var(--color-gray-500); +} diff --git a/packages/ui-web/src/styles/utility/brand.css b/packages/ui-web/src/styles/utility/brand.css new file mode 100644 index 0000000..fc31a3d --- /dev/null +++ b/packages/ui-web/src/styles/utility/brand.css @@ -0,0 +1,40 @@ +@utility brand-info { + --brand-bg: var(--info-bg); + --brand-bg-hover: var(--info-bg-hover); + --brand-bg-active: var(--info-bg-active); + --brand-bg-low: var(--info-bg-low); + --brand-bg-low-hover: var(--info-bg-low-hover); + --brand-bg-low-active: var(--info-bg-low-active); +} +@utility brand-danger { + --brand-bg: var(--danger-bg); + --brand-bg-hover: var(--danger-bg-hover); + --brand-bg-active: var(--danger-bg-active); + --brand-bg-low: var(--danger-bg-low); + --brand-bg-low-hover: var(--danger-bg-low-hover); + --brand-bg-low-active: var(--danger-bg-low-active); +} +@utility brand-success { + --brand-bg: var(--success-bg); + --brand-bg-hover: var(--success-bg-hover); + --brand-bg-active: var(--success-bg-active); + --brand-bg-low: var(--success-bg-low); + --brand-bg-low-hover: var(--success-bg-low-hover); + --brand-bg-low-active: var(--success-bg-low-active); +} +@utility brand-warning { + --brand-bg: var(--warning-bg); + --brand-bg-hover: var(--warning-bg-hover); + --brand-bg-active: var(--warning-bg-active); + --brand-bg-low: var(--warning-bg-low); + --brand-bg-low-hover: var(--warning-bg-low-hover); + --brand-bg-low-active: var(--warning-bg-low-active); +} +@utility brand-default { + --brand-bg: var(--default-bg); + --brand-bg-hover: var(--default-bg-hover); + --brand-bg-active: var(--default-bg-active); + --brand-bg-low: var(--default-bg-low); + --brand-bg-low-hover: var(--default-bg-low-hover); + --brand-bg-low-active: var(--default-bg-low-active); +} diff --git a/packages/ui-web/src/styles/utility/font.css b/packages/ui-web/src/styles/utility/font.css new file mode 100644 index 0000000..ed1ad0d --- /dev/null +++ b/packages/ui-web/src/styles/utility/font.css @@ -0,0 +1,4 @@ +@utility text-md { + font-size: var(--text-md); /* 1rem (16px) */ + line-height: var(--text-md--line-height); /* calc(1.5 / 1) */ +} diff --git a/packages/ui-web/src/styles/utility/gap.css b/packages/ui-web/src/styles/utility/gap.css new file mode 100644 index 0000000..0163dec --- /dev/null +++ b/packages/ui-web/src/styles/utility/gap.css @@ -0,0 +1,18 @@ +@utility gap-xs { + gap: calc(var(--spacing) * 0.5); +} +@utility gap-sm { + gap: calc(var(--spacing) * 1); +} +@utility gap-md { + gap: calc(var(--spacing) * 1.5); +} +@utility gap-lg { + gap: calc(var(--spacing) * 2); +} +@utility gap-xl { + gap: calc(var(--spacing) * 2.5); +} +@utility gap-2xl { + gap: calc(var(--spacing) * 3); +} diff --git a/packages/ui-web/src/styles/utility/height.css b/packages/ui-web/src/styles/utility/height.css new file mode 100644 index 0000000..d5b712b --- /dev/null +++ b/packages/ui-web/src/styles/utility/height.css @@ -0,0 +1,40 @@ +@utility h-item-xs { + /* 24px minimum touch size for text line */ + height: 24px; +} +@utility h-item-sm { + /* 28px save space for most used size */ + height: 28px; +} +@utility h-item-md { + /* 34px most used size */ + height: 34px; +} +@utility h-item-lg { + /* 44px maximum touch size without waste */ + height: 44px; +} +@utility h-item-xl { + height: calc(var(--spacing) * 16); +} +@utility h-item-2xl { + height: calc(var(--spacing) * 16); +} +@utility h-inline-xs { + height: calc(var(--text-xs--line-height) * var(--text-xs)); +} +@utility h-inline-sm { + height: calc(var(--text-sm--line-height) * var(--text-sm)); +} +@utility h-inline-md { + height: calc(var(--text-md--line-height) * var(--text-md)); +} +@utility h-inline-lg { + height: calc(var(--text-lg--line-height) * var(--text-lg)); +} +@utility h-inline-xl { + height: calc(var(--text-xl--line-height) * var(--text-xl)); +} +@utility h-inline-2xl { + height: calc(var(--text-2xl--line-height) * var(--text-2xl)); +} diff --git a/packages/ui-web/src/styles/utility/loading.css b/packages/ui-web/src/styles/utility/loading.css new file mode 100644 index 0000000..a046d34 --- /dev/null +++ b/packages/ui-web/src/styles/utility/loading.css @@ -0,0 +1,16 @@ +@utility loading-true { + position: "absolute"; + top: "50%"; + left: "50%"; + transform: "translate(-50%, -50%)"; + opacity: 1; + transition: "top 0.15s ease-in, opacity 0.1s ease-in"; +} +@utility loading-false { + position: "absolute"; + top: "-50%"; + left: "50%"; + transform: "translate(-50%, -50%)"; + opacity: 0; + transition: "top 0.15s ease-out, opacity 0.1s ease-out"; +} diff --git a/packages/ui-web/src/styles/utility/margin.css b/packages/ui-web/src/styles/utility/margin.css new file mode 100644 index 0000000..1f6f0fd --- /dev/null +++ b/packages/ui-web/src/styles/utility/margin.css @@ -0,0 +1,21 @@ +@utility mr-none { + margin-right: 0; +} +@utility mr-sm { + margin-right: calc(var(--spacing) * 1); +} +@utility mr-sm { + margin-right: calc(var(--spacing) * 2); +} +@utility mr-md { + margin-right: calc(var(--spacing) * 3); +} +@utility mr-lg { + margin-right: calc(var(--spacing) * 4); +} +@utility mr-xl { + margin-right: calc(var(--spacing) * 2); +} +@utility mr-2xl { + margin-right: calc(var(--spacing) * 2); +} diff --git a/packages/ui-web/src/styles/utility/padding.css b/packages/ui-web/src/styles/utility/padding.css new file mode 100644 index 0000000..3e5e0ba --- /dev/null +++ b/packages/ui-web/src/styles/utility/padding.css @@ -0,0 +1,40 @@ +@utility px-none { + padding-inline: 0px; +} +@utility px-xs { + padding-inline: 6px; +} +@utility px-sm { + padding-inline: 8px; +} +@utility px-md { + padding-inline: 10px; +} +@utility px-lg { + padding-inline: 12px; +} +@utility px-xl { + padding-inline: var(--radius-xl); +} +@utility px-2xl { + padding-inline: var(--radius-2xl); +} +@utility py-xs { + /* 2px correspond to rounded-xs */ + padding-block: var(--radius-xs); +} +@utility py-sm { + padding-block: var(--radius-sm); +} +@utility py-md { + padding-block: var(--radius-md); +} +@utility py-lg { + padding-block: var(--radius-lg); +} +@utility py-xl { + padding-block: var(--radius-xl); +} +@utility py-2xl { + padding-block: var(--radius-2xl); +} diff --git a/packages/ui-web/src/styles/utility/skin.css b/packages/ui-web/src/styles/utility/skin.css new file mode 100644 index 0000000..e52a634 --- /dev/null +++ b/packages/ui-web/src/styles/utility/skin.css @@ -0,0 +1,9 @@ +@utility light { + --base-fg: var(--color-gray-950); + --base-bg: var(--color-white); +} + +@utility dark { + --base-fg: var(--color-gray-50); + --base-bg: var(--color-black); +} diff --git a/packages/ui-web/src/styles/utility/variant.css b/packages/ui-web/src/styles/utility/variant.css new file mode 100644 index 0000000..904ae20 --- /dev/null +++ b/packages/ui-web/src/styles/utility/variant.css @@ -0,0 +1,200 @@ +@utility variant-filled { + --filled-fg: var(--color-white); + --filled-fg-hover: var(--color-white); + --filled-fg-active: var(--color-white); + --filled-bg: var(--brand-bg); + --filled-bg-hover: var(--brand-bg-hover); + --filled-bg-active: var(--brand-bg-active); + --filled-border-color: var(--color-transparent); + + color: var(--filled-fg); + background-color: var(--filled-bg); + border-color: var(--filled-border-color); + + &:hover { + background-color: var(--filled-bg-hover); + color: var(--filled-fg-hover); + } + + &:active { + background-color: var(--filled-bg-active); + color: var(--filled-fg-active); + } + + &:focus-visible { + background-color: var(--filled-bg-hover); + color: var(--filled-fg-hover); + } +} + +@utility variant-outline { + --outline-fg: var(--brand-bg); + --outline-fg-hover: var(--brand-bg); + --outline-fg-active: var(--brand-bg); + --outline-bg: var(--color-transparent); + --outline-bg-hover: var(--brand-bg-low-hover); + --outline-bg-active: var(--brand-bg-low-active); + --outline-border-color: var(--brand-bg); + + color: var(--outline-fg); + background-color: var(--outline-bg); + border: solid 1px; + border-color: var(--outline-border-color); + + &:hover { + background-color: var(--outline-bg-hover); + color: var(--outline-fg-hover); + } + + &:active { + background-color: var(--outline-bg-active); + color: var(--outline-fg-active); + } + + &:focus-visible { + background-color: var(--outline-bg-hover); + color: var(--outline-fg-hover); + } +} + +@utility variant-subtle { + --subtle-fg: var(--brand-bg); + --subtle-fg-hover: var(--brand-bg); + --subtle-fg-active: var(--brand-bg); + --subtle-bg: var(--brand-bg-low); + --subtle-bg-hover: var(--brand-bg-low-hover); + --subtle-bg-active: var(--brand-bg-low-active); + --subtle-border-color: var(--color-transparent); + + color: var(--subtle-fg); + background-color: var(--subtle-bg); + border-color: var(--subtle-border-color); + + &:hover { + background-color: var(--subtle-bg-hover); + color: var(--subtle-fg-hover); + } + + &:active { + background-color: var(--subtle-bg-active); + color: var(--subtle-fg-active); + } + + &:focus-visible { + background-color: var(--subtle-bg-hover); + color: var(--subtle-fg-hover); + } +} + +@utility variant-ghost { + --ghost-fg: var(--brand-bg); + --ghost-fg-hover: var(--brand-bg); + --ghost-fg-active: var(--brand-bg); + --ghost-bg: var(--color-transparent); + --ghost-bg-hover: var(--brand-bg-low); + --ghost-bg-active: var(--brand-bg-low-hover); + --ghost-border-color: var(--color-transparent); + + color: var(--ghost-fg); + background-color: var(--ghost-bg); + border-color: var(--ghost-border-color); + + &:hover { + background-color: var(--ghost-bg-hover); + color: var(--ghost-fg-hover); + } + + &:active { + background-color: var(--ghost-bg-active); + color: var(--ghost-fg-active); + } + + &:focus-visible { + background-color: var(--ghost-bg-hover); + color: var(--ghost-fg-hover); + } +} + +@utility variant-filled-disabled { + color: var(--disabled-fg); + background-color: var(--disabled-bg); + border-color: var(--disabled-border-color); + filter: grayscale(100%); + + &:hover { + color: var(--disabled-fg); + background-color: var(--disabled-bg); + border-color: var(--disabled-border-color); + filter: grayscale(100%); + } + + &:active { + color: var(--disabled-fg); + background-color: var(--disabled-bg); + border-color: var(--disabled-border-color); + filter: grayscale(100%); + } + + &:focus-visible { + color: var(--filled-fg); + background-color: var(--filled-bg); + border-color: var(--filled-border-color); + filter: grayscale(100%); + } +} + +@utility variant-outline-disabled { + color: var(--outline-fg); + background-color: var(--outline-bg); + border-color: var(--outline-border-color); + filter: grayscale(50%); + + &:hover { + color: var(--outline-fg); + background-color: var(--outline-bg); + border-color: var(--outline-border-color); + filter: grayscale(50%); + } + + &:active { + color: var(--outline-fg); + background-color: var(--outline-bg); + border-color: var(--outline-border-color); + filter: grayscale(50%); + } + + &:focus-visible { + color: var(--outline-fg); + background-color: var(--outline-bg); + border-color: var(--outline-border-color); + filter: grayscale(50%); + } +} + +@utility variant-ghost-disabled { + color: var(--ghost-fg); + background-color: var(--ghost-bg); + border-color: var(--ghost-border-color); + filter: grayscale(50%); + + &:hover { + color: var(--ghost-fg); + background-color: var(--ghost-bg); + border-color: var(--ghost-border-color); + filter: grayscale(50%); + } + + &:active { + color: var(--ghost-fg); + background-color: var(--ghost-bg); + border-color: var(--ghost-border-color); + filter: grayscale(50%); + } + + &:focus-visible { + color: var(--ghost-fg); + background-color: var(--ghost-bg); + border-color: var(--ghost-border-color); + filter: grayscale(50%); + } +} diff --git a/packages/ui-web/src/styles/utility/width.css b/packages/ui-web/src/styles/utility/width.css new file mode 100644 index 0000000..daee86d --- /dev/null +++ b/packages/ui-web/src/styles/utility/width.css @@ -0,0 +1,41 @@ +@utility w-item-xs { + /* 24px minimum touch size for text line */ + width: calc(var(--spacing) * 6); +} +@utility w-item-sm { + /* 30px save space for most used size */ + width: calc(var(--spacing) * 7.5); +} +@utility w-item-md { + /* 34px most used size */ + width: calc(var(--spacing) * 8.5); +} +@utility w-item-lg { + /* 46px maximum touch size without waste */ + width: calc(var(--spacing) * 11.5); +} +@utility w-item-xl { + width: calc(var(--spacing) * 16); +} +@utility w-item-2xl { + width: calc(var(--spacing) * 16); +} +/* ---------------------------------------------------- */ +@utility w-inline-xs { + width: calc(var(--text-xs--line-height) * var(--text-xs)); +} +@utility w-inline-sm { + width: calc(var(--text-sm--line-height) * var(--text-sm)); +} +@utility w-inline-md { + width: calc(var(--text-md--line-height) * var(--text-md)); +} +@utility w-inline-lg { + width: calc(var(--text-lg--line-height) * var(--text-lg)); +} +@utility w-inline-xl { + width: calc(var(--text-xl--line-height) * var(--text-xl)); +} +@utility w-inline-2xl { + width: calc(var(--text-2xl--line-height) * var(--text-2xl)); +} diff --git a/packages/ui-web/src/types/css.d.ts b/packages/ui-web/src/types/css.d.ts new file mode 100644 index 0000000..d535de2 --- /dev/null +++ b/packages/ui-web/src/types/css.d.ts @@ -0,0 +1,4 @@ +declare module '*.css' { + const content: { [className: string]: string }; + export default content; +} \ No newline at end of file diff --git a/packages/ui-web/tsconfig.base.json b/packages/ui-web/tsconfig.base.json new file mode 100644 index 0000000..b134137 --- /dev/null +++ b/packages/ui-web/tsconfig.base.json @@ -0,0 +1,40 @@ +{ + // tsconfig.base.json,用于被 tesconfig.json 和 tesconfig.build.json 继承 + "compilerOptions": { + // 输出模块语法,使用版本号最新的那个,而不是实验性语法 ESNext + "module": "es2022", + + // 模块解析策略,模拟 Vite / Rollup / webpack,支持 exports / imports,不强制 Node ESM 的严格规则 + "moduleResolution": "bundler", + + // 显式声明使用的类型包 + "types": ["node", "react", "vite/client"], + + // 开启所有严格类型检查,防止 any / 隐式 any 扩散 + "strict": true, + + // 允许 ESM 导入 CJS + "esModuleInterop": true, + + // 跳过 node_modules 类型检查,加快构建,避免第三方类型污染 + "skipLibCheck": true, + + // 模块检测策略,不会影响 node_modules 中的第三方 CommonJS 依赖,Vite 会在预构建阶段自动将其转换为 ESM。 + "moduleDetection": "force", + + // 保留源码中的 import / export 语句原样输出,不进行自动转换(如 import → require),通常与 moduleDetection: "force" 搭配使用 + "verbatimModuleSyntax": true, + + // 是否检查“未使用的局部变量” + "noUnusedLocals": true, + + // 是否检查“未使用的函数参数” + "noUnusedParameters": true, + + // 是否只允许“可擦除的语法(Erasable Syntax),确保 TypeScript 语法在编译后可完全移除 + "erasableSyntaxOnly": true, + + // 是否禁止 switch 语句中的 case 贯穿(fallthrough),如果 case 没有 break / return,会报错 + "noFallthroughCasesInSwitch": true + } +} diff --git a/packages/ui-web/tsconfig.build.json b/packages/ui-web/tsconfig.build.json new file mode 100644 index 0000000..f3b4b99 --- /dev/null +++ b/packages/ui-web/tsconfig.build.json @@ -0,0 +1,122 @@ +{ + // 此文件仅用于类型检查,不用于类型检查,构建时会指定使用 tsconfig.build.json + "extends": "./tsconfig.base.json", + "compilerOptions": { + // Browser api,需要加 "DOM","DOM.Iterable" + // Node api,需要加 "ES2025",始终使用带版本号的最新版本 + // NextJs api,属于同构,server 端会预处理 DOM,计算url,三个都需要 "ES2025", "DOM", "DOM.Iterable" + "lib": ["ES2025", "DOM", "DOM.Iterable"], + + /** + * 显式声明使用的类型包 + * - node:Node.js API + * - react:JSX / React 类型 + * - vite/client:import.meta / env + */ + "types": ["node", "react", "vite/client"], + + /** + * React JSX 编译模式 + * - 使用 React 17+ 新 JSX Transform + * - 不需要手动 import React + */ + "jsx": "react-jsx", + + /** + * 编译输出目录 + * - tsc / tsc -b 都会用到 + */ + "outDir": "./dist", + + /** + * 源码根目录 + * - 确保 dist 结构与 src 一致 + * - 对 declaration 路径至关重要 + */ + "rootDir": "./src", + + /** + * 生成 .d.ts 类型声明文件 + * - 组件库 / npm 包发布必需 + * - 对应用项目无害,仅影响类型输出 + */ + "declaration": true, + + /** + * 只做类型检查,不生成 JS 输出 + * - 适用于 Vite / Next / Nuxt 等 bundler 场景 + * - 防止 tsc 与构建工具重复 emit + */ + "noEmit": true, + + /** + * 强制单文件可独立编译 + * - 适配 esbuild / SWC / bundler 编译模型 + * - 禁止依赖跨文件类型推断(enum / namespace 等) + */ + "isolatedModules": true, + + /** + * 允许在 import 中显式使用 .ts / .tsx 后缀 + * - 兼容 Node ESM / bundler 对文件扩展名的严格要求 + * - 避免 `import './foo'` 在 TS + ESM 下歧义 + */ + "allowImportingTsExtensions": true + }, + /** + * 参与类型检查和编译的文件 + * - 只扫描 src + * - 其它目录通过 exclude 排除 + */ + "include": ["src", "scripts"], + + /** + * 明确排除非源码内容 + * - 避免污染类型系统 + * - 防止误入 dist / test / config + * - 保证发布包干净 + */ + "exclude": [ + "node_modules", + "dist", + + // ---------- build / cache ---------- + ".turbo/**/*", + ".cache/**/*", + ".vite/**/*", + + // ---------- 配置文件 ---------- + "vite.config.ts", + "*.config.ts", + "*.config.js", + "tsconfig.*.json", + + // ---------- 测试相关 ---------- + "__tests__/**/*", + "test/**/*", + "tests/**/*", + "**/*.test.ts", + "**/*.test.tsx", + "**/*.spec.ts", + "**/*.spec.tsx", + + // ---------- Storybook ---------- + ".storybook/**/*", + "stories/**/*", + + // ---------- 示例 / 脚本 ---------- + "example/**/*", + "examples/**/*", + "scripts/**/*", + + // ---------- 环境与静态资源 ---------- + ".env", + ".env.*", + "public/**/*", + + // ---------- 文档 ---------- + "docs/**/*", + "README.md", + "LICENSE" + ] +} diff --git a/packages/ui-web/tsconfig.json b/packages/ui-web/tsconfig.json new file mode 100644 index 0000000..a28554e --- /dev/null +++ b/packages/ui-web/tsconfig.json @@ -0,0 +1,16 @@ +{ + // 此文件仅用于类型检查,不用于构建,构建时会指定使用 tsconfig.build.json + "extends": "./tsconfig.base.json", + "compilerOptions": { + // node api 使用最新版本号的 "ESxxxx",browser api 使用 "DOM" 和 "DOM.Iterable" + "lib": ["ES2025", "DOM", "DOM.Iterable"], + + //显式声明使用的类型包,避免找不到模块 + "types": ["node", "react", "vite/client"], + + // React JSX 编译模式 + "jsx": "react-jsx" + }, + // 将类型检查范围扩大至整个子项目,而不只是 src 文件夹, + "include": ["**/*"] +} diff --git a/packages/ui-web/vite.config.ts b/packages/ui-web/vite.config.ts new file mode 100644 index 0000000..12b8568 --- /dev/null +++ b/packages/ui-web/vite.config.ts @@ -0,0 +1,45 @@ +import { defineConfig } from "vite"; +import react from "@vitejs/plugin-react"; +import dts from "vite-plugin-dts"; +import path from "path"; +import tailwindcss from "@tailwindcss/vite"; +import { genIndexTsPlugin } from "./scripts-plugin/vite-plugin-gen-index-ts"; +import { genIndexCssPlugin } from "./scripts-plugin/vite-plugin-gen-index-css"; + +export default defineConfig({ + plugins: [ + genIndexTsPlugin(), + genIndexCssPlugin(), + react(), + tailwindcss(), + dts({ + insertTypesEntry: true, + }), + ], + + build: { + lib: { + entry: path.resolve(__dirname, "src/index.ts"), + name: "DefgovUIWeb", + formats: ["es", "cjs"], + fileName: (format) => `index.${format}.js`, + }, + + rollupOptions: { + external: ["react", "react-dom", "react/jsx-runtime"], + output: { + globals: { + react: "React", + "react-dom": "ReactDOM", + }, + }, + }, + + sourcemap: true, + cssCodeSplit: true, + + watch: { + exclude: ["node_modules", "dist", ".git"], + }, + }, +}); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml new file mode 100644 index 0000000..12cd7df --- /dev/null +++ b/pnpm-lock.yaml @@ -0,0 +1,1974 @@ +lockfileVersion: '9.0' + +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false + +importers: + + .: + devDependencies: + turbo: + specifier: ^2.8.0 + version: 2.9.7 + + packages/bookmark-sync: + dependencies: + typescript: + specifier: ^6.0.3 + version: 6.0.3 + devDependencies: + '@types/chrome': + specifier: ^0.1.40 + version: 0.1.40 + '@types/firefox-webext-browser': + specifier: ^143.0.0 + version: 143.0.0 + '@types/node': + specifier: ^25.6.0 + version: 25.6.0 + '@types/webextension-polyfill': + specifier: ^0.12.5 + version: 0.12.5 + webextension-polyfill: + specifier: ^0.12.0 + version: 0.12.0 + + packages/note-maker: + dependencies: + parse5: + specifier: ^8.0.1 + version: 8.0.1 + devDependencies: + '@types/node': + specifier: ^25.6.0 + version: 25.6.0 + typescript: + specifier: ^6.0.3 + version: 6.0.3 + + packages/ui-web: + dependencies: + '@base-ui/react': + specifier: ^1.4.1 + version: 1.4.1(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + react: + specifier: ^19 + version: 19.2.5 + react-dom: + specifier: ^19 + version: 19.2.5(react@19.2.5) + tailwind-merge: + specifier: ^3.5.0 + version: 3.5.0 + tailwind-variants: + specifier: ^3.2.2 + version: 3.2.2(tailwind-merge@3.5.0)(tailwindcss@4.2.4) + tailwindcss: + specifier: ^4.2.4 + version: 4.2.4 + devDependencies: + '@tailwindcss/vite': + specifier: ^4.2.4 + version: 4.2.4(vite@8.0.10(@types/node@25.6.0)(jiti@2.6.1)) + '@types/node': + specifier: ^25.6.0 + version: 25.6.0 + '@types/react': + specifier: ^19.2.14 + version: 19.2.14 + '@types/react-dom': + specifier: ^19.2.3 + version: 19.2.3(@types/react@19.2.14) + '@vitejs/plugin-react': + specifier: ^6.0.1 + version: 6.0.1(vite@8.0.10(@types/node@25.6.0)(jiti@2.6.1)) + glob: + specifier: ^13.0.6 + version: 13.0.6 + ts-node: + specifier: ^10.9.2 + version: 10.9.2(@types/node@25.6.0)(typescript@6.0.3) + typescript: + specifier: ^6.0.3 + version: 6.0.3 + vite: + specifier: ^8.0.9 + version: 8.0.10(@types/node@25.6.0)(jiti@2.6.1) + vite-plugin-dts: + specifier: ^4.5.4 + version: 4.5.4(@types/node@25.6.0)(typescript@6.0.3)(vite@8.0.10(@types/node@25.6.0)(jiti@2.6.1)) + + templates/vite-react-template: + devDependencies: + '@types/node': + specifier: ^25.6.0 + version: 25.6.0 + '@types/react': + specifier: ^19.2.14 + version: 19.2.14 + '@types/react-dom': + specifier: ^19.2.3 + version: 19.2.3(@types/react@19.2.14) + '@vitejs/plugin-react': + specifier: ^6.0.1 + version: 6.0.1(vite@8.0.10(@types/node@25.6.0)(jiti@2.6.1)) + glob: + specifier: ^13.0.6 + version: 13.0.6 + typescript: + specifier: ^6.0.3 + version: 6.0.3 + vite: + specifier: ^8.0.9 + version: 8.0.10(@types/node@25.6.0)(jiti@2.6.1) + vite-plugin-dts: + specifier: ^4.5.4 + version: 4.5.4(@types/node@25.6.0)(typescript@6.0.3)(vite@8.0.10(@types/node@25.6.0)(jiti@2.6.1)) + +packages: + + '@babel/helper-string-parser@7.27.1': + resolution: {integrity: sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==} + engines: {node: '>=6.9.0'} + + '@babel/helper-validator-identifier@7.28.5': + resolution: {integrity: sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==} + engines: {node: '>=6.9.0'} + + '@babel/parser@7.29.3': + resolution: {integrity: sha512-b3ctpQwp+PROvU/cttc4OYl4MzfJUWy6FZg+PMXfzmt/+39iHVF0sDfqay8TQM3JA2EUOyKcFZt75jWriQijsA==} + engines: {node: '>=6.0.0'} + hasBin: true + + '@babel/runtime@7.29.2': + resolution: {integrity: sha512-JiDShH45zKHWyGe4ZNVRrCjBz8Nh9TMmZG1kh4QTK8hCBTWBi8Da+i7s1fJw7/lYpM4ccepSNfqzZ/QvABBi5g==} + engines: {node: '>=6.9.0'} + + '@babel/types@7.29.0': + resolution: {integrity: sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==} + engines: {node: '>=6.9.0'} + + '@base-ui/react@1.4.1': + resolution: {integrity: sha512-Ab5/LIhcmL8BQcsBUYiOfkSDRdLpvgUBzMK30cu684JPcLclYlztharvCZyNNgzJtbAiREzI9q0pI5erHCMgCw==} + engines: {node: '>=14.0.0'} + peerDependencies: + '@date-fns/tz': ^1.2.0 + '@types/react': ^17 || ^18 || ^19 + date-fns: ^4.0.0 + react: ^17 || ^18 || ^19 + react-dom: ^17 || ^18 || ^19 + peerDependenciesMeta: + '@date-fns/tz': + optional: true + '@types/react': + optional: true + date-fns: + optional: true + + '@base-ui/utils@0.2.8': + resolution: {integrity: sha512-jvOi+c+ftGlGotNcKnzPVg2IhCaDTB6/6R3JeqdjdXktuAJi3wKH9T7+svuaKh1mmfVU11UWzUZVH74JDfi/wQ==} + peerDependencies: + '@types/react': ^17 || ^18 || ^19 + react: ^17 || ^18 || ^19 + react-dom: ^17 || ^18 || ^19 + peerDependenciesMeta: + '@types/react': + optional: true + + '@cspotcode/source-map-support@0.8.1': + resolution: {integrity: sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==} + engines: {node: '>=12'} + + '@emnapi/core@1.10.0': + resolution: {integrity: sha512-yq6OkJ4p82CAfPl0u9mQebQHKPJkY7WrIuk205cTYnYe+k2Z8YBh11FrbRG/H6ihirqcacOgl2BIO8oyMQLeXw==} + + '@emnapi/runtime@1.10.0': + resolution: {integrity: sha512-ewvYlk86xUoGI0zQRNq/mC+16R1QeDlKQy21Ki3oSYXNgLb45GV1P6A0M+/s6nyCuNDqe5VpaY84BzXGwVbwFA==} + + '@emnapi/wasi-threads@1.2.1': + resolution: {integrity: sha512-uTII7OYF+/Mes/MrcIOYp5yOtSMLBWSIoLPpcgwipoiKbli6k322tcoFsxoIIxPDqW01SQGAgko4EzZi2BNv2w==} + + '@floating-ui/core@1.7.5': + resolution: {integrity: sha512-1Ih4WTWyw0+lKyFMcBHGbb5U5FtuHJuujoyyr5zTaWS5EYMeT6Jb2AuDeftsCsEuchO+mM2ij5+q9crhydzLhQ==} + + '@floating-ui/dom@1.7.6': + resolution: {integrity: sha512-9gZSAI5XM36880PPMm//9dfiEngYoC6Am2izES1FF406YFsjvyBMmeJ2g4SAju3xWwtuynNRFL2s9hgxpLI5SQ==} + + '@floating-ui/react-dom@2.1.8': + resolution: {integrity: sha512-cC52bHwM/n/CxS87FH0yWdngEZrjdtLW/qVruo68qg+prK7ZQ4YGdut2GyDVpoGeAYe/h899rVeOVm6Oi40k2A==} + peerDependencies: + react: '>=16.8.0' + react-dom: '>=16.8.0' + + '@floating-ui/utils@0.2.11': + resolution: {integrity: sha512-RiB/yIh78pcIxl6lLMG0CgBXAZ2Y0eVHqMPYugu+9U0AeT6YBeiJpf7lbdJNIugFP5SIjwNRgo4DhR1Qxi26Gg==} + + '@jridgewell/gen-mapping@0.3.13': + resolution: {integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==} + + '@jridgewell/remapping@2.3.5': + resolution: {integrity: sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==} + + '@jridgewell/resolve-uri@3.1.2': + resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} + engines: {node: '>=6.0.0'} + + '@jridgewell/sourcemap-codec@1.5.5': + resolution: {integrity: sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==} + + '@jridgewell/trace-mapping@0.3.31': + resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==} + + '@jridgewell/trace-mapping@0.3.9': + resolution: {integrity: sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==} + + '@microsoft/api-extractor-model@7.33.8': + resolution: {integrity: sha512-aIcoQggPyer3B6Ze3usz0YWC/oBwUHfRH5ETUsr+oT2BRA6SfTJl7IKPcPZkX4UR+PohowzW4uMxsvjrn8vm+w==} + + '@microsoft/api-extractor@7.58.7': + resolution: {integrity: sha512-yK6OycD46gIzLRpj6ueVUWPk1ACSpkN1LBo05gY1qPTylbWyUCanXfH7+VgkI5LJrJoRSQR5F04XuCffCXLOBw==} + hasBin: true + + '@microsoft/tsdoc-config@0.18.1': + resolution: {integrity: sha512-9brPoVdfN9k9g0dcWkFeA7IH9bbcttzDJlXvkf8b2OBzd5MueR1V2wkKBL0abn0otvmkHJC6aapBOTJDDeMCZg==} + + '@microsoft/tsdoc@0.16.0': + resolution: {integrity: sha512-xgAyonlVVS+q7Vc7qLW0UrJU7rSFcETRWsqdXZtjzRU8dF+6CkozTK4V4y1LwOX7j8r/vHphjDeMeGI4tNGeGA==} + + '@napi-rs/wasm-runtime@1.1.4': + resolution: {integrity: sha512-3NQNNgA1YSlJb/kMH1ildASP9HW7/7kYnRI2szWJaofaS1hWmbGI4H+d3+22aGzXXN9IJ+n+GiFVcGipJP18ow==} + peerDependencies: + '@emnapi/core': ^1.7.1 + '@emnapi/runtime': ^1.7.1 + + '@oxc-project/types@0.127.0': + resolution: {integrity: sha512-aIYXQBo4lCbO4z0R3FHeucQHpF46l2LbMdxRvqvuRuW2OxdnSkcng5B8+K12spgLDj93rtN3+J2Vac/TIO+ciQ==} + + '@rolldown/binding-android-arm64@1.0.0-rc.17': + resolution: {integrity: sha512-s70pVGhw4zqGeFnXWvAzJDlvxhlRollagdCCKRgOsgUOH3N1l0LIxf83AtGzmb5SiVM4Hjl5HyarMRfdfj3DaQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [android] + + '@rolldown/binding-darwin-arm64@1.0.0-rc.17': + resolution: {integrity: sha512-4ksWc9n0mhlZpZ9PMZgTGjeOPRu8MB1Z3Tz0Mo02eWfWCHMW1zN82Qz/pL/rC+yQa+8ZnutMF0JjJe7PjwasYw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [darwin] + + '@rolldown/binding-darwin-x64@1.0.0-rc.17': + resolution: {integrity: sha512-SUSDOI6WwUVNcWxd02QEBjLdY1VPHvlEkw6T/8nYG322iYWCTxRb1vzk4E+mWWYehTp7ERibq54LSJGjmouOsw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [darwin] + + '@rolldown/binding-freebsd-x64@1.0.0-rc.17': + resolution: {integrity: sha512-hwnz3nw9dbJ05EDO/PvcjaaewqqDy7Y1rn1UO81l8iIK1GjenME75dl16ajbvSSMfv66WXSRCYKIqfgq2KCfxw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [freebsd] + + '@rolldown/binding-linux-arm-gnueabihf@1.0.0-rc.17': + resolution: {integrity: sha512-IS+W7epTcwANmFSQFrS1SivEXHtl1JtuQA9wlxrZTcNi6mx+FDOYrakGevvvTwgj2JvWiK8B29/qD9BELZPyXQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm] + os: [linux] + + '@rolldown/binding-linux-arm64-gnu@1.0.0-rc.17': + resolution: {integrity: sha512-e6usGaHKW5BMNZOymS1UcEYGowQMWcgZ71Z17Sl/h2+ZziNJ1a9n3Zvcz6LdRyIW5572wBCTH/Z+bKuZouGk9Q==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [linux] + libc: [glibc] + + '@rolldown/binding-linux-arm64-musl@1.0.0-rc.17': + resolution: {integrity: sha512-b/CgbwAJpmrRLp02RPfhbudf5tZnN9nsPWK82znefso832etkem8H7FSZwxrOI9djcdTP7U6YfNhbRnh7djErg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [linux] + libc: [musl] + + '@rolldown/binding-linux-ppc64-gnu@1.0.0-rc.17': + resolution: {integrity: sha512-4EII1iNGRUN5WwGbF/kOh/EIkoDN9HsupgLQoXfY+D1oyJm7/F4t5PYU5n8SWZgG0FEwakyM8pGgwcBYruGTlA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [ppc64] + os: [linux] + libc: [glibc] + + '@rolldown/binding-linux-s390x-gnu@1.0.0-rc.17': + resolution: {integrity: sha512-AH8oq3XqQo4IibpVXvPeLDI5pzkpYn0WiZAfT05kFzoJ6tQNzwRdDYQ45M8I/gslbodRZwW8uxLhbSBbkv96rA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [s390x] + os: [linux] + libc: [glibc] + + '@rolldown/binding-linux-x64-gnu@1.0.0-rc.17': + resolution: {integrity: sha512-cLnjV3xfo7KslbU41Z7z8BH/E1y5mzUYzAqih1d1MDaIGZRCMqTijqLv76/P7fyHuvUcfGsIpqCdddbxLLK9rA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [linux] + libc: [glibc] + + '@rolldown/binding-linux-x64-musl@1.0.0-rc.17': + resolution: {integrity: sha512-0phclDw1spsL7dUB37sIARuis2tAgomCJXAHZlpt8PXZ4Ba0dRP1e+66lsRqrfhISeN9bEGNjQs+T/Fbd7oYGw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [linux] + libc: [musl] + + '@rolldown/binding-openharmony-arm64@1.0.0-rc.17': + resolution: {integrity: sha512-0ag/hEgXOwgw4t8QyQvUCxvEg+V0KBcA6YuOx9g0r02MprutRF5dyljgm3EmR02O292UX7UeS6HzWHAl6KgyhA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [openharmony] + + '@rolldown/binding-wasm32-wasi@1.0.0-rc.17': + resolution: {integrity: sha512-LEXei6vo0E5wTGwpkJ4KoT3OZJRnglwldt5ziLzOlc6qqb55z4tWNq2A+PFqCJuvWWdP53CVhG1Z9NtToDPJrA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [wasm32] + + '@rolldown/binding-win32-arm64-msvc@1.0.0-rc.17': + resolution: {integrity: sha512-gUmyzBl3SPMa6hrqFUth9sVfcLBlYsbMzBx5PlexMroZStgzGqlZ26pYG89rBb45Mnia+oil6YAIFeEWGWhoZA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [win32] + + '@rolldown/binding-win32-x64-msvc@1.0.0-rc.17': + resolution: {integrity: sha512-3hkiolcUAvPB9FLb3UZdfjVVNWherN1f/skkGWJP/fgSQhYUZpSIRr0/I8ZK9TkF3F7kxvJAk0+IcKvPHk9qQg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [win32] + + '@rolldown/pluginutils@1.0.0-rc.17': + resolution: {integrity: sha512-n8iosDOt6Ig1UhJ2AYqoIhHWh/isz0xpicHTzpKBeotdVsTEcxsSA/i3EVM7gQAj0rU27OLAxCjzlj15IWY7bg==} + + '@rolldown/pluginutils@1.0.0-rc.7': + resolution: {integrity: sha512-qujRfC8sFVInYSPPMLQByRh7zhwkGFS4+tyMQ83srV1qrxL4g8E2tyxVVyxd0+8QeBM1mIk9KbWxkegRr76XzA==} + + '@rollup/pluginutils@5.3.0': + resolution: {integrity: sha512-5EdhGZtnu3V88ces7s53hhfK5KSASnJZv8Lulpc04cWO3REESroJXg73DFsOmgbU2BhwV0E20bu2IDZb3VKW4Q==} + engines: {node: '>=14.0.0'} + peerDependencies: + rollup: ^1.20.0||^2.0.0||^3.0.0||^4.0.0 + peerDependenciesMeta: + rollup: + optional: true + + '@rushstack/node-core-library@5.23.1': + resolution: {integrity: sha512-wlKmIKIYCKuCASbITvOxLZXepPbwXvrv7S6ig6XNWFchSyhL/E2txmVXspHY49Wu2dzf7nI27a2k/yV5BA3EiA==} + peerDependencies: + '@types/node': '*' + peerDependenciesMeta: + '@types/node': + optional: true + + '@rushstack/problem-matcher@0.2.1': + resolution: {integrity: sha512-gulfhBs6n+I5b7DvjKRfhMGyUejtSgOHTclF/eONr8hcgF1APEDjhxIsfdUYYMzC3rvLwGluqLjbwCFZ8nxrog==} + peerDependencies: + '@types/node': '*' + peerDependenciesMeta: + '@types/node': + optional: true + + '@rushstack/rig-package@0.7.3': + resolution: {integrity: sha512-aAA518n6wxxjCfnTAOjQnm7ngNE0FVHxHAw2pxKlIhxrMn0XQjGcXKF0oKWpjBgJOmsaJpVob/v+zr3zxgPWuA==} + + '@rushstack/terminal@0.24.0': + resolution: {integrity: sha512-8ZQS4MMaGsv27EXCBiH7WMPkRZrffeDoIevs6z9TM5dzqiY6+Hn4evfK/G+gvgBTjfvfkHIZPQQmalmI2sM4TQ==} + peerDependencies: + '@types/node': '*' + peerDependenciesMeta: + '@types/node': + optional: true + + '@rushstack/ts-command-line@5.3.9': + resolution: {integrity: sha512-GIHqU+sRGQ3LGWAZu1O+9Yh++qwtyNIIGuNbcWHJjBTm2qRez0cwINUHZ+pQLR8UuzZDcMajrDaNbUYoaL/XtQ==} + + '@tailwindcss/node@4.2.4': + resolution: {integrity: sha512-Ai7+yQPxz3ddrDQzFfBKdHEVBg0w3Zl83jnjuwxnZOsnH9pGn93QHQtpU0p/8rYWxvbFZHneni6p1BSLK4DkGA==} + + '@tailwindcss/oxide-android-arm64@4.2.4': + resolution: {integrity: sha512-e7MOr1SAn9U8KlZzPi1ZXGZHeC5anY36qjNwmZv9pOJ8E4Q6jmD1vyEHkQFmNOIN7twGPEMXRHmitN4zCMN03g==} + engines: {node: '>= 20'} + cpu: [arm64] + os: [android] + + '@tailwindcss/oxide-darwin-arm64@4.2.4': + resolution: {integrity: sha512-tSC/Kbqpz/5/o/C2sG7QvOxAKqyd10bq+ypZNf+9Fi2TvbVbv1zNpcEptcsU7DPROaSbVgUXmrzKhurFvo5eDg==} + engines: {node: '>= 20'} + cpu: [arm64] + os: [darwin] + + '@tailwindcss/oxide-darwin-x64@4.2.4': + resolution: {integrity: sha512-yPyUXn3yO/ufR6+Kzv0t4fCg2qNr90jxXc5QqBpjlPNd0NqyDXcmQb/6weunH/MEDXW5dhyEi+agTDiqa3WsGg==} + engines: {node: '>= 20'} + cpu: [x64] + os: [darwin] + + '@tailwindcss/oxide-freebsd-x64@4.2.4': + resolution: {integrity: sha512-BoMIB4vMQtZsXdGLVc2z+P9DbETkiopogfWZKbWwM8b/1Vinbs4YcUwo+kM/KeLkX3Ygrf4/PsRndKaYhS8Eiw==} + engines: {node: '>= 20'} + cpu: [x64] + os: [freebsd] + + '@tailwindcss/oxide-linux-arm-gnueabihf@4.2.4': + resolution: {integrity: sha512-7pIHBLTHYRAlS7V22JNuTh33yLH4VElwKtB3bwchK/UaKUPpQ0lPQiOWcbm4V3WP2I6fNIJ23vABIvoy2izdwA==} + engines: {node: '>= 20'} + cpu: [arm] + os: [linux] + + '@tailwindcss/oxide-linux-arm64-gnu@4.2.4': + resolution: {integrity: sha512-+E4wxJ0ZGOzSH325reXTWB48l42i93kQqMvDyz5gqfRzRZ7faNhnmvlV4EPGJU3QJM/3Ab5jhJ5pCRUsKn6OQw==} + engines: {node: '>= 20'} + cpu: [arm64] + os: [linux] + libc: [glibc] + + '@tailwindcss/oxide-linux-arm64-musl@4.2.4': + resolution: {integrity: sha512-bBADEGAbo4ASnppIziaQJelekCxdMaxisrk+fB7Thit72IBnALp9K6ffA2G4ruj90G9XRS2VQ6q2bCKbfFV82g==} + engines: {node: '>= 20'} + cpu: [arm64] + os: [linux] + libc: [musl] + + '@tailwindcss/oxide-linux-x64-gnu@4.2.4': + resolution: {integrity: sha512-7Mx25E4WTfnht0TVRTyC00j3i0M+EeFe7wguMDTlX4mRxafznw0CA8WJkFjWYH5BlgELd1kSjuU2JiPnNZbJDA==} + engines: {node: '>= 20'} + cpu: [x64] + os: [linux] + libc: [glibc] + + '@tailwindcss/oxide-linux-x64-musl@4.2.4': + resolution: {integrity: sha512-2wwJRF7nyhOR0hhHoChc04xngV3iS+akccHTGtz965FwF0up4b2lOdo6kI1EbDaEXKgvcrFBYcYQQ/rrnWFVfA==} + engines: {node: '>= 20'} + cpu: [x64] + os: [linux] + libc: [musl] + + '@tailwindcss/oxide-wasm32-wasi@4.2.4': + resolution: {integrity: sha512-FQsqApeor8Fo6gUEklzmaa9994orJZZDBAlQpK2Mq+DslRKFJeD6AjHpBQ0kZFQohVr8o85PPh8eOy86VlSCmw==} + engines: {node: '>=14.0.0'} + cpu: [wasm32] + bundledDependencies: + - '@napi-rs/wasm-runtime' + - '@emnapi/core' + - '@emnapi/runtime' + - '@tybys/wasm-util' + - '@emnapi/wasi-threads' + - tslib + + '@tailwindcss/oxide-win32-arm64-msvc@4.2.4': + resolution: {integrity: sha512-L9BXqxC4ToVgwMFqj3pmZRqyHEztulpUJzCxUtLjobMCzTPsGt1Fa9enKbOpY2iIyVtaHNeNvAK8ERP/64sqGQ==} + engines: {node: '>= 20'} + cpu: [arm64] + os: [win32] + + '@tailwindcss/oxide-win32-x64-msvc@4.2.4': + resolution: {integrity: sha512-ESlKG0EpVJQwRjXDDa9rLvhEAh0mhP1sF7sap9dNZT0yyl9SAG6T7gdP09EH0vIv0UNTlo6jPWyujD6559fZvw==} + engines: {node: '>= 20'} + cpu: [x64] + os: [win32] + + '@tailwindcss/oxide@4.2.4': + resolution: {integrity: sha512-9El/iI069DKDSXwTvB9J4BwdO5JhRrOweGaK25taBAvBXyXqJAX+Jqdvs8r8gKpsI/1m0LeJLyQYTf/WLrBT1Q==} + engines: {node: '>= 20'} + + '@tailwindcss/vite@4.2.4': + resolution: {integrity: sha512-pCvohwOCspk3ZFn6eJzrrX3g4n2JY73H6MmYC87XfGPyTty4YsCjYTMArRZm/zOI8dIt3+EcrLHAFPe5A4bgtw==} + peerDependencies: + vite: ^5.2.0 || ^6 || ^7 || ^8 + + '@tsconfig/node10@1.0.12': + resolution: {integrity: sha512-UCYBaeFvM11aU2y3YPZ//O5Rhj+xKyzy7mvcIoAjASbigy8mHMryP5cK7dgjlz2hWxh1g5pLw084E0a/wlUSFQ==} + + '@tsconfig/node12@1.0.11': + resolution: {integrity: sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==} + + '@tsconfig/node14@1.0.3': + resolution: {integrity: sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==} + + '@tsconfig/node16@1.0.4': + resolution: {integrity: sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==} + + '@turbo/darwin-64@2.9.7': + resolution: {integrity: sha512-wnvOWuVWJ5EUHNKxExEWiGlTeVpLG1L0PCu5MUozyC1P2SHGiWsmpW6/yAuShH91Fa2TAHOvdCRBzriZh4j4Eg==} + cpu: [x64] + os: [darwin] + + '@turbo/darwin-arm64@2.9.7': + resolution: {integrity: sha512-mA0FIPMwwN3lodDkQYaGxj6PeT7ZaN5aCEbkKn/WB+ZB9yJdVWA4J83GH7t43jqDc5dcnVluVN5UFx3plRiXhA==} + cpu: [arm64] + os: [darwin] + + '@turbo/linux-64@2.9.7': + resolution: {integrity: sha512-fEbUYpgb5l7P+q+5tsWF2gw+/GSjUsuUTcnfm+f0lozUjgcjLKyOat6PgtAChmIFcTPchCL/8rJ3TvkBy01gfA==} + cpu: [x64] + os: [linux] + + '@turbo/linux-arm64@2.9.7': + resolution: {integrity: sha512-VkUjulo9ytfHKUHOS5gy0XPoh4CTKPXWCL8nLdrlHVi9fSut31ECeUqnm/dAbETP5D4xo9mH9XkJ+qMzGe/zmg==} + cpu: [arm64] + os: [linux] + + '@turbo/windows-64@2.9.7': + resolution: {integrity: sha512-/GWdY6/x4aIHqkYJq596Rpdk1x0MkpRPkJcLAoB3yGRwyUms0+u2F1GnV54IbyAZTeKLRWSJKzNC+QwVGdYchA==} + cpu: [x64] + os: [win32] + + '@turbo/windows-arm64@2.9.7': + resolution: {integrity: sha512-xBBgxCC5PK2+WZ1PPRZdp+aJ0bMBcEbweXWux3RUHJvX9ZodcoQySkrW6qt+ahb+uk8ZjyQodLfDwtVSoYds1w==} + cpu: [arm64] + os: [win32] + + '@tybys/wasm-util@0.10.1': + resolution: {integrity: sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg==} + + '@types/argparse@1.0.38': + resolution: {integrity: sha512-ebDJ9b0e702Yr7pWgB0jzm+CX4Srzz8RcXtLJDJB+BSccqMa36uyH/zUsSYao5+BD1ytv3k3rPYCq4mAE1hsXA==} + + '@types/chrome@0.1.40': + resolution: {integrity: sha512-UnfyRAe8ORu9HSuTH0EqyOEUin3JrWW9Nl/gDXezNfTUrfIoxw+WRZgKOxGz0t5BnjbfXBnS2eCYfW2PxH1wcA==} + + '@types/estree@1.0.8': + resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==} + + '@types/filesystem@0.0.36': + resolution: {integrity: sha512-vPDXOZuannb9FZdxgHnqSwAG/jvdGM8Wq+6N4D/d80z+D4HWH+bItqsZaVRQykAn6WEVeEkLm2oQigyHtgb0RA==} + + '@types/filewriter@0.0.33': + resolution: {integrity: sha512-xFU8ZXTw4gd358lb2jw25nxY9QAgqn2+bKKjKOYfNCzN4DKCFetK7sPtrlpg66Ywe3vWY9FNxprZawAh9wfJ3g==} + + '@types/firefox-webext-browser@143.0.0': + resolution: {integrity: sha512-865dYKMOP0CllFyHmgXV4IQgVL51OSQQCwSoihQ17EwugePKFSAZRc0EI+y7Ly4q7j5KyURlA7LgRpFieO4JOw==} + + '@types/har-format@1.2.16': + resolution: {integrity: sha512-fluxdy7ryD3MV6h8pTfTYpy/xQzCFC7m89nOH9y94cNqJ1mDIDPut7MnRHI3F6qRmh/cT2fUjG1MLdCNb4hE9A==} + + '@types/node@25.6.0': + resolution: {integrity: sha512-+qIYRKdNYJwY3vRCZMdJbPLJAtGjQBudzZzdzwQYkEPQd+PJGixUL5QfvCLDaULoLv+RhT3LDkwEfKaAkgSmNQ==} + + '@types/react-dom@19.2.3': + resolution: {integrity: sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==} + peerDependencies: + '@types/react': ^19.2.0 + + '@types/react@19.2.14': + resolution: {integrity: sha512-ilcTH/UniCkMdtexkoCN0bI7pMcJDvmQFPvuPvmEaYA/NSfFTAgdUSLAoVjaRJm7+6PvcM+q1zYOwS4wTYMF9w==} + + '@types/webextension-polyfill@0.12.5': + resolution: {integrity: sha512-uKSAv6LgcVdINmxXMKBuVIcg/2m5JZugoZO8x20g7j2bXJkPIl/lVGQcDlbV+aXAiTyXT2RA5U5mI4IGCDMQeg==} + + '@vitejs/plugin-react@6.0.1': + resolution: {integrity: sha512-l9X/E3cDb+xY3SWzlG1MOGt2usfEHGMNIaegaUGFsLkb3RCn/k8/TOXBcab+OndDI4TBtktT8/9BwwW8Vi9KUQ==} + engines: {node: ^20.19.0 || >=22.12.0} + peerDependencies: + '@rolldown/plugin-babel': ^0.1.7 || ^0.2.0 + babel-plugin-react-compiler: ^1.0.0 + vite: ^8.0.0 + peerDependenciesMeta: + '@rolldown/plugin-babel': + optional: true + babel-plugin-react-compiler: + optional: true + + '@volar/language-core@2.4.28': + resolution: {integrity: sha512-w4qhIJ8ZSitgLAkVay6AbcnC7gP3glYM3fYwKV3srj8m494E3xtrCv6E+bWviiK/8hs6e6t1ij1s2Endql7vzQ==} + + '@volar/source-map@2.4.28': + resolution: {integrity: sha512-yX2BDBqJkRXfKw8my8VarTyjv48QwxdJtvRgUpNE5erCsgEUdI2DsLbpa+rOQVAJYshY99szEcRDmyHbF10ggQ==} + + '@volar/typescript@2.4.28': + resolution: {integrity: sha512-Ja6yvWrbis2QtN4ClAKreeUZPVYMARDYZl9LMEv1iQ1QdepB6wn0jTRxA9MftYmYa4DQ4k/DaSZpFPUfxl8giw==} + + '@vue/compiler-core@3.5.33': + resolution: {integrity: sha512-3PZLQwFw4Za3TC8t0FvTy3wI16Kt+pmwcgNZca4Pj9iWL2E72a/gZlpBtAJvEdDMdCxdG/qq0C7PN0bsJuv0Rw==} + + '@vue/compiler-dom@3.5.33': + resolution: {integrity: sha512-PXq0yrfCLzzL07rbXO4awtXY1Z06LG2eu6Adg3RJFa/j3Cii217XxxLXG22N330gw7GmALCY0Z8RgXEviwgpjA==} + + '@vue/compiler-vue2@2.7.16': + resolution: {integrity: sha512-qYC3Psj9S/mfu9uVi5WvNZIzq+xnXMhOwbTFKKDD7b1lhpnn71jXSFdTQ+WsIEk0ONCd7VV2IMm7ONl6tbQ86A==} + + '@vue/language-core@2.2.0': + resolution: {integrity: sha512-O1ZZFaaBGkKbsRfnVH1ifOK1/1BUkyK+3SQsfnh6PmMmD4qJcTU8godCeA96jjDRTL6zgnK7YzCHfaUlH2r0Mw==} + peerDependencies: + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + + '@vue/shared@3.5.33': + resolution: {integrity: sha512-5vR2QIlmaLG77Ygd4pMP6+SGQ5yox9VhtnbDWTy9DzMzdmeLxZ1QqxrywEZ9sa1AVubfIJyaCG3ytyWU81ufcQ==} + + acorn-walk@8.3.5: + resolution: {integrity: sha512-HEHNfbars9v4pgpW6SO1KSPkfoS0xVOM/9UzkJltjlsHZmJasxg8aXkuZa7SMf8vKGIBhpUsPluQSqhJFCqebw==} + engines: {node: '>=0.4.0'} + + acorn@8.16.0: + resolution: {integrity: sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==} + engines: {node: '>=0.4.0'} + hasBin: true + + ajv-draft-04@1.0.0: + resolution: {integrity: sha512-mv00Te6nmYbRp5DCwclxtt7yV/joXJPGS7nM+97GdxvuttCOfgI3K4U25zboyeX0O+myI8ERluxQe5wljMmVIw==} + peerDependencies: + ajv: ^8.5.0 + peerDependenciesMeta: + ajv: + optional: true + + ajv-formats@3.0.1: + resolution: {integrity: sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ==} + peerDependencies: + ajv: ^8.0.0 + peerDependenciesMeta: + ajv: + optional: true + + ajv@8.18.0: + resolution: {integrity: sha512-PlXPeEWMXMZ7sPYOHqmDyCJzcfNrUr3fGNKtezX14ykXOEIvyK81d+qydx89KY5O71FKMPaQ2vBfBFI5NHR63A==} + + alien-signals@0.4.9: + resolution: {integrity: sha512-piRGlMgQ65uRiY06mGU7I432AwPwAGf64TK1RXtM1Px4pPfLMTGI9TmsHTfioW1GukZRsNzkVQ/uHjhhd231Ow==} + + arg@4.1.3: + resolution: {integrity: sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==} + + argparse@1.0.10: + resolution: {integrity: sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==} + + balanced-match@1.0.0: + resolution: {integrity: sha512-9Y0g0Q8rmSt+H33DfKv7FOc3v+iRI+o1lbzt8jGcIosYW37IIW/2XVYq5NPdmaD5NQ59Nk26Kl/vZbwW9Fr8vg==} + + balanced-match@4.0.4: + resolution: {integrity: sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==} + engines: {node: 18 || 20 || >=22} + + brace-expansion@2.1.0: + resolution: {integrity: sha512-TN1kCZAgdgweJhWWpgKYrQaMNHcDULHkWwQIspdtjV4Y5aurRdZpjAqn6yX3FPqTA9ngHCc4hJxMAMgGfve85w==} + + brace-expansion@5.0.5: + resolution: {integrity: sha512-VZznLgtwhn+Mact9tfiwx64fA9erHH/MCXEUfB/0bX/6Fz6ny5EGTXYltMocqg4xFAQZtnO3DHWWXi8RiuN7cQ==} + engines: {node: 18 || 20 || >=22} + + compare-versions@6.1.1: + resolution: {integrity: sha512-4hm4VPpIecmlg59CHXnRDnqGplJFrbLG4aFEl5vl6cK1u76ws3LLvX7ikFnTDl5vo39sjWD6AaDPYodJp/NNHg==} + + confbox@0.1.8: + resolution: {integrity: sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w==} + + confbox@0.2.4: + resolution: {integrity: sha512-ysOGlgTFbN2/Y6Cg3Iye8YKulHw+R2fNXHrgSmXISQdMnomY6eNDprVdW9R5xBguEqI954+S6709UyiO7B+6OQ==} + + create-require@1.1.1: + resolution: {integrity: sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==} + + csstype@3.2.3: + resolution: {integrity: sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==} + + de-indent@1.0.2: + resolution: {integrity: sha512-e/1zu3xH5MQryN2zdVaF0OrdNLUbvWxzMbi+iNA6Bky7l1RoP8a2fIbRocyHclXt/arDrrR6lL3TqFD9pMQTsg==} + + debug@4.4.3: + resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==} + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + + detect-libc@2.1.2: + resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==} + engines: {node: '>=8'} + + diff@4.0.4: + resolution: {integrity: sha512-X07nttJQkwkfKfvTPG/KSnE2OMdcUCao6+eXF3wmnIQRn2aPAHH3VxDbDOdegkd6JbPsXqShpvEOHfAT+nCNwQ==} + engines: {node: '>=0.3.1'} + + diff@8.0.4: + resolution: {integrity: sha512-DPi0FmjiSU5EvQV0++GFDOJ9ASQUVFh5kD+OzOnYdi7n3Wpm9hWWGfB/O2blfHcMVTL5WkQXSnRiK9makhrcnw==} + engines: {node: '>=0.3.1'} + + enhanced-resolve@5.21.0: + resolution: {integrity: sha512-otxSQPw4lkOZWkHpB3zaEQs6gWYEsmX4xQF68ElXC/TWvGxGMSGOvoNbaLXm6/cS/fSfHtsEdw90y20PCd+sCA==} + engines: {node: '>=10.13.0'} + + entities@7.0.1: + resolution: {integrity: sha512-TWrgLOFUQTH994YUyl1yT4uyavY5nNB5muff+RtWaqNVCAK408b5ZnnbNAUEWLTCpum9w6arT70i1XdQ4UeOPA==} + engines: {node: '>=0.12'} + + entities@8.0.0: + resolution: {integrity: sha512-zwfzJecQ/Uej6tusMqwAqU/6KL2XaB2VZ2Jg54Je6ahNBGNH6Ek6g3jjNCF0fG9EWQKGZNddNjU5F1ZQn/sBnA==} + engines: {node: '>=20.19.0'} + + es-errors@1.3.0: + resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==} + engines: {node: '>= 0.4'} + + estree-walker@2.0.2: + resolution: {integrity: sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==} + + exsolve@1.0.8: + resolution: {integrity: sha512-LmDxfWXwcTArk8fUEnOfSZpHOJ6zOMUJKOtFLFqJLoKJetuQG874Uc7/Kki7zFLzYybmZhp1M7+98pfMqeX8yA==} + + fast-deep-equal@3.1.3: + resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} + + fast-uri@3.1.0: + resolution: {integrity: sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA==} + + fdir@6.5.0: + resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==} + engines: {node: '>=12.0.0'} + peerDependencies: + picomatch: ^3 || ^4 + peerDependenciesMeta: + picomatch: + optional: true + + fs-extra@11.3.4: + resolution: {integrity: sha512-CTXd6rk/M3/ULNQj8FBqBWHYBVYybQ3VPBw0xGKFe3tuH7ytT6ACnvzpIQ3UZtB8yvUKC2cXn1a+x+5EVQLovA==} + engines: {node: '>=14.14'} + + fsevents@2.3.3: + resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} + engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} + os: [darwin] + + function-bind@1.1.2: + resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} + + glob@13.0.6: + resolution: {integrity: sha512-Wjlyrolmm8uDpm/ogGyXZXb1Z+Ca2B8NbJwqBVg0axK9GbBeoS7yGV6vjXnYdGm6X53iehEuxxbyiKp8QmN4Vw==} + engines: {node: 18 || 20 || >=22} + + graceful-fs@4.2.11: + resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} + + has-flag@4.0.0: + resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} + engines: {node: '>=8'} + + hasown@2.0.3: + resolution: {integrity: sha512-ej4AhfhfL2Q2zpMmLo7U1Uv9+PyhIZpgQLGT1F9miIGmiCJIoCgSmczFdrc97mWT4kVY72KA+WnnhJ5pghSvSg==} + engines: {node: '>= 0.4'} + + he@1.2.0: + resolution: {integrity: sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==} + hasBin: true + + import-lazy@4.0.0: + resolution: {integrity: sha512-rKtvo6a868b5Hu3heneU+L4yEQ4jYKLtjpnPeUdK7h0yzXGmyBTypknlkCvHFBqfX9YlorEiMM6Dnq/5atfHkw==} + engines: {node: '>=8'} + + is-core-module@2.16.1: + resolution: {integrity: sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==} + engines: {node: '>= 0.4'} + + jiti@2.6.1: + resolution: {integrity: sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==} + hasBin: true + + jju@1.4.0: + resolution: {integrity: sha512-8wb9Yw966OSxApiCt0K3yNJL8pnNeIv+OEq2YMidz4FKP6nonSRoOXc80iXY4JaN2FC11B9qsNmDsm+ZOfMROA==} + + json-schema-traverse@1.0.0: + resolution: {integrity: sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==} + + jsonfile@6.2.1: + resolution: {integrity: sha512-zwOTdL3rFQ/lRdBnntKVOX6k5cKJwEc1HdilT71BWEu7J41gXIB2MRp+vxduPSwZJPWBxEzv4yH1wYLJGUHX4Q==} + + kolorist@1.8.0: + resolution: {integrity: sha512-Y+60/zizpJ3HRH8DCss+q95yr6145JXZo46OTpFvDZWLfRCE4qChOyk1b26nMaNpfHHgxagk9dXT5OP0Tfe+dQ==} + + lightningcss-android-arm64@1.32.0: + resolution: {integrity: sha512-YK7/ClTt4kAK0vo6w3X+Pnm0D2cf2vPHbhOXdoNti1Ga0al1P4TBZhwjATvjNwLEBCnKvjJc2jQgHXH0NEwlAg==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [android] + + lightningcss-darwin-arm64@1.32.0: + resolution: {integrity: sha512-RzeG9Ju5bag2Bv1/lwlVJvBE3q6TtXskdZLLCyfg5pt+HLz9BqlICO7LZM7VHNTTn/5PRhHFBSjk5lc4cmscPQ==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [darwin] + + lightningcss-darwin-x64@1.32.0: + resolution: {integrity: sha512-U+QsBp2m/s2wqpUYT/6wnlagdZbtZdndSmut/NJqlCcMLTWp5muCrID+K5UJ6jqD2BFshejCYXniPDbNh73V8w==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [darwin] + + lightningcss-freebsd-x64@1.32.0: + resolution: {integrity: sha512-JCTigedEksZk3tHTTthnMdVfGf61Fky8Ji2E4YjUTEQX14xiy/lTzXnu1vwiZe3bYe0q+SpsSH/CTeDXK6WHig==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [freebsd] + + lightningcss-linux-arm-gnueabihf@1.32.0: + resolution: {integrity: sha512-x6rnnpRa2GL0zQOkt6rts3YDPzduLpWvwAF6EMhXFVZXD4tPrBkEFqzGowzCsIWsPjqSK+tyNEODUBXeeVHSkw==} + engines: {node: '>= 12.0.0'} + cpu: [arm] + os: [linux] + + lightningcss-linux-arm64-gnu@1.32.0: + resolution: {integrity: sha512-0nnMyoyOLRJXfbMOilaSRcLH3Jw5z9HDNGfT/gwCPgaDjnx0i8w7vBzFLFR1f6CMLKF8gVbebmkUN3fa/kQJpQ==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [linux] + libc: [glibc] + + lightningcss-linux-arm64-musl@1.32.0: + resolution: {integrity: sha512-UpQkoenr4UJEzgVIYpI80lDFvRmPVg6oqboNHfoH4CQIfNA+HOrZ7Mo7KZP02dC6LjghPQJeBsvXhJod/wnIBg==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [linux] + libc: [musl] + + lightningcss-linux-x64-gnu@1.32.0: + resolution: {integrity: sha512-V7Qr52IhZmdKPVr+Vtw8o+WLsQJYCTd8loIfpDaMRWGUZfBOYEJeyJIkqGIDMZPwPx24pUMfwSxxI8phr/MbOA==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [linux] + libc: [glibc] + + lightningcss-linux-x64-musl@1.32.0: + resolution: {integrity: sha512-bYcLp+Vb0awsiXg/80uCRezCYHNg1/l3mt0gzHnWV9XP1W5sKa5/TCdGWaR/zBM2PeF/HbsQv/j2URNOiVuxWg==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [linux] + libc: [musl] + + lightningcss-win32-arm64-msvc@1.32.0: + resolution: {integrity: sha512-8SbC8BR40pS6baCM8sbtYDSwEVQd4JlFTOlaD3gWGHfThTcABnNDBda6eTZeqbofalIJhFx0qKzgHJmcPTnGdw==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [win32] + + lightningcss-win32-x64-msvc@1.32.0: + resolution: {integrity: sha512-Amq9B/SoZYdDi1kFrojnoqPLxYhQ4Wo5XiL8EVJrVsB8ARoC1PWW6VGtT0WKCemjy8aC+louJnjS7U18x3b06Q==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [win32] + + lightningcss@1.32.0: + resolution: {integrity: sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ==} + engines: {node: '>= 12.0.0'} + + local-pkg@1.1.2: + resolution: {integrity: sha512-arhlxbFRmoQHl33a0Zkle/YWlmNwoyt6QNZEIJcqNbdrsix5Lvc4HyyI3EnwxTYlZYc32EbYrQ8SzEZ7dqgg9A==} + engines: {node: '>=14'} + + lru-cache@11.3.5: + resolution: {integrity: sha512-NxVFwLAnrd9i7KUBxC4DrUhmgjzOs+1Qm50D3oF1/oL+r1NpZ4gA7xvG0/zJ8evR7zIKn4vLf7qTNduWFtCrRw==} + engines: {node: 20 || >=22} + + magic-string@0.30.21: + resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==} + + make-error@1.3.6: + resolution: {integrity: sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==} + + minimatch@10.2.3: + resolution: {integrity: sha512-Rwi3pnapEqirPSbWbrZaa6N3nmqq4Xer/2XooiOKyV3q12ML06f7MOuc5DVH8ONZIFhwIYQ3yzPH4nt7iWHaTg==} + engines: {node: 18 || 20 || >=22} + + minimatch@10.2.5: + resolution: {integrity: sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==} + engines: {node: 18 || 20 || >=22} + + minimatch@9.0.9: + resolution: {integrity: sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==} + engines: {node: '>=16 || 14 >=14.17'} + + minipass@7.1.3: + resolution: {integrity: sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A==} + engines: {node: '>=16 || 14 >=14.17'} + + mlly@1.8.2: + resolution: {integrity: sha512-d+ObxMQFmbt10sretNDytwt85VrbkhhUA/JBGm1MPaWJ65Cl4wOgLaB1NYvJSZ0Ef03MMEU/0xpPMXUIQ29UfA==} + + ms@2.1.3: + resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} + + muggle-string@0.4.1: + resolution: {integrity: sha512-VNTrAak/KhO2i8dqqnqnAHOa3cYBwXEZe9h+D5h/1ZqFSTEFHdM65lR7RoIqq3tBBYavsOXV84NoHXZ0AkPyqQ==} + + nanoid@3.3.12: + resolution: {integrity: sha512-ZB9RH/39qpq5Vu6Y+NmUaFhQR6pp+M2Xt76XBnEwDaGcVAqhlvxrl3B2bKS5D3NH3QR76v3aSrKaF/Kiy7lEtQ==} + engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} + hasBin: true + + parse5@8.0.1: + resolution: {integrity: sha512-z1e/HMG90obSGeidlli3hj7cbocou0/wa5HacvI3ASx34PecNjNQeaHNo5WIZpWofN9kgkqV1q5YvXe3F0FoPw==} + + path-browserify@1.0.1: + resolution: {integrity: sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==} + + path-parse@1.0.7: + resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} + + path-scurry@2.0.2: + resolution: {integrity: sha512-3O/iVVsJAPsOnpwWIeD+d6z/7PmqApyQePUtCndjatj/9I5LylHvt5qluFaBT3I5h3r1ejfR056c+FCv+NnNXg==} + engines: {node: 18 || 20 || >=22} + + pathe@2.0.3: + resolution: {integrity: sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==} + + picocolors@1.1.1: + resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} + + picomatch@4.0.4: + resolution: {integrity: sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==} + engines: {node: '>=12'} + + pkg-types@1.3.1: + resolution: {integrity: sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ==} + + pkg-types@2.3.1: + resolution: {integrity: sha512-y+ichcgc2LrADuhLNAx8DFjVfgz91pRxfZdI3UDhxHvcVEZsenLO+7XaU5vOp0u/7V/wZ+plyuQxtrDlZJ+yeg==} + + postcss@8.5.13: + resolution: {integrity: sha512-qif0+jGGZoLWdHey3UFHHWP0H7Gbmsk8T5VEqyYFbWqPr1XqvLGBbk/sl8V5exGmcYJklJOhOQq1pV9IcsiFag==} + engines: {node: ^10 || ^12 || >=14} + + quansync@0.2.11: + resolution: {integrity: sha512-AifT7QEbW9Nri4tAwR5M/uzpBuqfZf+zwaEM/QkzEjj7NBuFD2rBuy0K3dE+8wltbezDV7JMA0WfnCPYRSYbXA==} + + react-dom@19.2.5: + resolution: {integrity: sha512-J5bAZz+DXMMwW/wV3xzKke59Af6CHY7G4uYLN1OvBcKEsWOs4pQExj86BBKamxl/Ik5bx9whOrvBlSDfWzgSag==} + peerDependencies: + react: ^19.2.5 + + react@19.2.5: + resolution: {integrity: sha512-llUJLzz1zTUBrskt2pwZgLq59AemifIftw4aB7JxOqf1HY2FDaGDxgwpAPVzHU1kdWabH7FauP4i1oEeer2WCA==} + engines: {node: '>=0.10.0'} + + require-from-string@2.0.2: + resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==} + engines: {node: '>=0.10.0'} + + reselect@5.1.1: + resolution: {integrity: sha512-K/BG6eIky/SBpzfHZv/dd+9JBFiS4SWV7FIujVyJRux6e45+73RaUHXLmIR1f7WOMaQ0U1km6qwklRQxpJJY0w==} + + resolve@1.22.12: + resolution: {integrity: sha512-TyeJ1zif53BPfHootBGwPRYT1RUt6oGWsaQr8UyZW/eAm9bKoijtvruSDEmZHm92CwS9nj7/fWttqPCgzep8CA==} + engines: {node: '>= 0.4'} + hasBin: true + + rolldown@1.0.0-rc.17: + resolution: {integrity: sha512-ZrT53oAKrtA4+YtBWPQbtPOxIbVDbxT0orcYERKd63VJTF13zPcgXTvD4843L8pcsI7M6MErt8QtON6lrB9tyA==} + engines: {node: ^20.19.0 || >=22.12.0} + hasBin: true + + scheduler@0.27.0: + resolution: {integrity: sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==} + + semver@7.7.4: + resolution: {integrity: sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==} + engines: {node: '>=10'} + hasBin: true + + source-map-js@1.2.1: + resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} + engines: {node: '>=0.10.0'} + + source-map@0.6.1: + resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==} + engines: {node: '>=0.10.0'} + + sprintf-js@1.0.3: + resolution: {integrity: sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==} + + string-argv@0.3.2: + resolution: {integrity: sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q==} + engines: {node: '>=0.6.19'} + + supports-color@8.1.1: + resolution: {integrity: sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==} + engines: {node: '>=10'} + + supports-preserve-symlinks-flag@1.0.0: + resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} + engines: {node: '>= 0.4'} + + tailwind-merge@3.5.0: + resolution: {integrity: sha512-I8K9wewnVDkL1NTGoqWmVEIlUcB9gFriAEkXkfCjX5ib8ezGxtR3xD7iZIxrfArjEsH7F1CHD4RFUtxefdqV/A==} + + tailwind-variants@3.2.2: + resolution: {integrity: sha512-Mi4kHeMTLvKlM98XPnK+7HoBPmf4gygdFmqQPaDivc3DpYS6aIY6KiG/PgThrGvii5YZJqRsPz0aPyhoFzmZgg==} + engines: {node: '>=16.x', pnpm: '>=7.x'} + peerDependencies: + tailwind-merge: '>=3.0.0' + tailwindcss: '*' + peerDependenciesMeta: + tailwind-merge: + optional: true + + tailwindcss@4.2.4: + resolution: {integrity: sha512-HhKppgO81FQof5m6TEnuBWCZGgfRAWbaeOaGT00KOy/Pf/j6oUihdvBpA7ltCeAvZpFhW3j0PTclkxsd4IXYDA==} + + tapable@2.3.3: + resolution: {integrity: sha512-uxc/zpqFg6x7C8vOE7lh6Lbda8eEL9zmVm/PLeTPBRhh1xCgdWaQ+J1CUieGpIfm2HdtsUpRv+HshiasBMcc6A==} + engines: {node: '>=6'} + + tinyglobby@0.2.16: + resolution: {integrity: sha512-pn99VhoACYR8nFHhxqix+uvsbXineAasWm5ojXoN8xEwK5Kd3/TrhNn1wByuD52UxWRLy8pu+kRMniEi6Eq9Zg==} + engines: {node: '>=12.0.0'} + + ts-node@10.9.2: + resolution: {integrity: sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==} + hasBin: true + peerDependencies: + '@swc/core': '>=1.2.50' + '@swc/wasm': '>=1.2.50' + '@types/node': '*' + typescript: '>=2.7' + peerDependenciesMeta: + '@swc/core': + optional: true + '@swc/wasm': + optional: true + + tslib@2.8.1: + resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} + + turbo@2.9.7: + resolution: {integrity: sha512-epxzqVO2s0IxcSWcgb+qKrtco8isfe7g3VtiS6hkYnEK4A9XQDZbrtavQ6MtWR1KoQn+1fUomaQth2rfRHlUlg==} + hasBin: true + + typescript@5.9.3: + resolution: {integrity: sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==} + engines: {node: '>=14.17'} + hasBin: true + + typescript@6.0.3: + resolution: {integrity: sha512-y2TvuxSZPDyQakkFRPZHKFm+KKVqIisdg9/CZwm9ftvKXLP8NRWj38/ODjNbr43SsoXqNuAisEf1GdCxqWcdBw==} + engines: {node: '>=14.17'} + hasBin: true + + ufo@1.6.4: + resolution: {integrity: sha512-JFNbkD1Svwe0KvGi8GOeLcP4kAWQ609twvCdcHxq1oSL8svv39ZuSvajcD8B+5D0eL4+s1Is2D/O6KN3qcTeRA==} + + undici-types@7.19.2: + resolution: {integrity: sha512-qYVnV5OEm2AW8cJMCpdV20CDyaN3g0AjDlOGf1OW4iaDEx8MwdtChUp4zu4H0VP3nDRF/8RKWH+IPp9uW0YGZg==} + + universalify@2.0.1: + resolution: {integrity: sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==} + engines: {node: '>= 10.0.0'} + + use-sync-external-store@1.6.0: + resolution: {integrity: sha512-Pp6GSwGP/NrPIrxVFAIkOQeyw8lFenOHijQWkUTrDvrF4ALqylP2C/KCkeS9dpUM3KvYRQhna5vt7IL95+ZQ9w==} + peerDependencies: + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + + v8-compile-cache-lib@3.0.1: + resolution: {integrity: sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==} + + vite-plugin-dts@4.5.4: + resolution: {integrity: sha512-d4sOM8M/8z7vRXHHq/ebbblfaxENjogAAekcfcDCCwAyvGqnPrc7f4NZbvItS+g4WTgerW0xDwSz5qz11JT3vg==} + peerDependencies: + typescript: '*' + vite: '*' + peerDependenciesMeta: + vite: + optional: true + + vite@8.0.10: + resolution: {integrity: sha512-rZuUu9j6J5uotLDs+cAA4O5H4K1SfPliUlQwqa6YEwSrWDZzP4rhm00oJR5snMewjxF5V/K3D4kctsUTsIU9Mw==} + engines: {node: ^20.19.0 || >=22.12.0} + hasBin: true + peerDependencies: + '@types/node': ^20.19.0 || >=22.12.0 + '@vitejs/devtools': ^0.1.0 + 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 + peerDependenciesMeta: + '@types/node': + optional: true + '@vitejs/devtools': + optional: true + esbuild: + optional: true + jiti: + optional: true + less: + optional: true + sass: + optional: true + sass-embedded: + optional: true + stylus: + optional: true + sugarss: + optional: true + terser: + optional: true + tsx: + optional: true + yaml: + optional: true + + vscode-uri@3.1.0: + resolution: {integrity: sha512-/BpdSx+yCQGnCvecbyXdxHDkuk55/G3xwnC0GqY4gmQ3j+A+g8kzzgB4Nk/SINjqn6+waqw3EgbVF2QKExkRxQ==} + + webextension-polyfill@0.12.0: + resolution: {integrity: sha512-97TBmpoWJEE+3nFBQ4VocyCdLKfw54rFaJ6EVQYLBCXqCIpLSZkwGgASpv4oPt9gdKCJ80RJlcmNzNn008Ag6Q==} + + yn@3.1.1: + resolution: {integrity: sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==} + engines: {node: '>=6'} + +snapshots: + + '@babel/helper-string-parser@7.27.1': {} + + '@babel/helper-validator-identifier@7.28.5': {} + + '@babel/parser@7.29.3': + dependencies: + '@babel/types': 7.29.0 + + '@babel/runtime@7.29.2': {} + + '@babel/types@7.29.0': + dependencies: + '@babel/helper-string-parser': 7.27.1 + '@babel/helper-validator-identifier': 7.28.5 + + '@base-ui/react@1.4.1(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)': + dependencies: + '@babel/runtime': 7.29.2 + '@base-ui/utils': 0.2.8(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + '@floating-ui/react-dom': 2.1.8(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + '@floating-ui/utils': 0.2.11 + react: 19.2.5 + react-dom: 19.2.5(react@19.2.5) + use-sync-external-store: 1.6.0(react@19.2.5) + optionalDependencies: + '@types/react': 19.2.14 + + '@base-ui/utils@0.2.8(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)': + dependencies: + '@babel/runtime': 7.29.2 + '@floating-ui/utils': 0.2.11 + react: 19.2.5 + react-dom: 19.2.5(react@19.2.5) + reselect: 5.1.1 + use-sync-external-store: 1.6.0(react@19.2.5) + optionalDependencies: + '@types/react': 19.2.14 + + '@cspotcode/source-map-support@0.8.1': + dependencies: + '@jridgewell/trace-mapping': 0.3.9 + + '@emnapi/core@1.10.0': + dependencies: + '@emnapi/wasi-threads': 1.2.1 + tslib: 2.8.1 + optional: true + + '@emnapi/runtime@1.10.0': + dependencies: + tslib: 2.8.1 + optional: true + + '@emnapi/wasi-threads@1.2.1': + dependencies: + tslib: 2.8.1 + optional: true + + '@floating-ui/core@1.7.5': + dependencies: + '@floating-ui/utils': 0.2.11 + + '@floating-ui/dom@1.7.6': + dependencies: + '@floating-ui/core': 1.7.5 + '@floating-ui/utils': 0.2.11 + + '@floating-ui/react-dom@2.1.8(react-dom@19.2.5(react@19.2.5))(react@19.2.5)': + dependencies: + '@floating-ui/dom': 1.7.6 + react: 19.2.5 + react-dom: 19.2.5(react@19.2.5) + + '@floating-ui/utils@0.2.11': {} + + '@jridgewell/gen-mapping@0.3.13': + dependencies: + '@jridgewell/sourcemap-codec': 1.5.5 + '@jridgewell/trace-mapping': 0.3.31 + + '@jridgewell/remapping@2.3.5': + dependencies: + '@jridgewell/gen-mapping': 0.3.13 + '@jridgewell/trace-mapping': 0.3.31 + + '@jridgewell/resolve-uri@3.1.2': {} + + '@jridgewell/sourcemap-codec@1.5.5': {} + + '@jridgewell/trace-mapping@0.3.31': + dependencies: + '@jridgewell/resolve-uri': 3.1.2 + '@jridgewell/sourcemap-codec': 1.5.5 + + '@jridgewell/trace-mapping@0.3.9': + dependencies: + '@jridgewell/resolve-uri': 3.1.2 + '@jridgewell/sourcemap-codec': 1.5.5 + + '@microsoft/api-extractor-model@7.33.8(@types/node@25.6.0)': + dependencies: + '@microsoft/tsdoc': 0.16.0 + '@microsoft/tsdoc-config': 0.18.1 + '@rushstack/node-core-library': 5.23.1(@types/node@25.6.0) + transitivePeerDependencies: + - '@types/node' + + '@microsoft/api-extractor@7.58.7(@types/node@25.6.0)': + dependencies: + '@microsoft/api-extractor-model': 7.33.8(@types/node@25.6.0) + '@microsoft/tsdoc': 0.16.0 + '@microsoft/tsdoc-config': 0.18.1 + '@rushstack/node-core-library': 5.23.1(@types/node@25.6.0) + '@rushstack/rig-package': 0.7.3 + '@rushstack/terminal': 0.24.0(@types/node@25.6.0) + '@rushstack/ts-command-line': 5.3.9(@types/node@25.6.0) + diff: 8.0.4 + minimatch: 10.2.3 + resolve: 1.22.12 + semver: 7.7.4 + source-map: 0.6.1 + typescript: 5.9.3 + transitivePeerDependencies: + - '@types/node' + + '@microsoft/tsdoc-config@0.18.1': + dependencies: + '@microsoft/tsdoc': 0.16.0 + ajv: 8.18.0 + jju: 1.4.0 + resolve: 1.22.12 + + '@microsoft/tsdoc@0.16.0': {} + + '@napi-rs/wasm-runtime@1.1.4(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)': + dependencies: + '@emnapi/core': 1.10.0 + '@emnapi/runtime': 1.10.0 + '@tybys/wasm-util': 0.10.1 + optional: true + + '@oxc-project/types@0.127.0': {} + + '@rolldown/binding-android-arm64@1.0.0-rc.17': + optional: true + + '@rolldown/binding-darwin-arm64@1.0.0-rc.17': + optional: true + + '@rolldown/binding-darwin-x64@1.0.0-rc.17': + optional: true + + '@rolldown/binding-freebsd-x64@1.0.0-rc.17': + optional: true + + '@rolldown/binding-linux-arm-gnueabihf@1.0.0-rc.17': + optional: true + + '@rolldown/binding-linux-arm64-gnu@1.0.0-rc.17': + optional: true + + '@rolldown/binding-linux-arm64-musl@1.0.0-rc.17': + optional: true + + '@rolldown/binding-linux-ppc64-gnu@1.0.0-rc.17': + optional: true + + '@rolldown/binding-linux-s390x-gnu@1.0.0-rc.17': + optional: true + + '@rolldown/binding-linux-x64-gnu@1.0.0-rc.17': + optional: true + + '@rolldown/binding-linux-x64-musl@1.0.0-rc.17': + optional: true + + '@rolldown/binding-openharmony-arm64@1.0.0-rc.17': + optional: true + + '@rolldown/binding-wasm32-wasi@1.0.0-rc.17': + dependencies: + '@emnapi/core': 1.10.0 + '@emnapi/runtime': 1.10.0 + '@napi-rs/wasm-runtime': 1.1.4(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0) + optional: true + + '@rolldown/binding-win32-arm64-msvc@1.0.0-rc.17': + optional: true + + '@rolldown/binding-win32-x64-msvc@1.0.0-rc.17': + optional: true + + '@rolldown/pluginutils@1.0.0-rc.17': {} + + '@rolldown/pluginutils@1.0.0-rc.7': {} + + '@rollup/pluginutils@5.3.0': + dependencies: + '@types/estree': 1.0.8 + estree-walker: 2.0.2 + picomatch: 4.0.4 + + '@rushstack/node-core-library@5.23.1(@types/node@25.6.0)': + dependencies: + ajv: 8.18.0 + ajv-draft-04: 1.0.0(ajv@8.18.0) + ajv-formats: 3.0.1(ajv@8.18.0) + fs-extra: 11.3.4 + import-lazy: 4.0.0 + jju: 1.4.0 + resolve: 1.22.12 + semver: 7.7.4 + optionalDependencies: + '@types/node': 25.6.0 + + '@rushstack/problem-matcher@0.2.1(@types/node@25.6.0)': + optionalDependencies: + '@types/node': 25.6.0 + + '@rushstack/rig-package@0.7.3': + dependencies: + jju: 1.4.0 + resolve: 1.22.12 + + '@rushstack/terminal@0.24.0(@types/node@25.6.0)': + dependencies: + '@rushstack/node-core-library': 5.23.1(@types/node@25.6.0) + '@rushstack/problem-matcher': 0.2.1(@types/node@25.6.0) + supports-color: 8.1.1 + optionalDependencies: + '@types/node': 25.6.0 + + '@rushstack/ts-command-line@5.3.9(@types/node@25.6.0)': + dependencies: + '@rushstack/terminal': 0.24.0(@types/node@25.6.0) + '@types/argparse': 1.0.38 + argparse: 1.0.10 + string-argv: 0.3.2 + transitivePeerDependencies: + - '@types/node' + + '@tailwindcss/node@4.2.4': + dependencies: + '@jridgewell/remapping': 2.3.5 + enhanced-resolve: 5.21.0 + jiti: 2.6.1 + lightningcss: 1.32.0 + magic-string: 0.30.21 + source-map-js: 1.2.1 + tailwindcss: 4.2.4 + + '@tailwindcss/oxide-android-arm64@4.2.4': + optional: true + + '@tailwindcss/oxide-darwin-arm64@4.2.4': + optional: true + + '@tailwindcss/oxide-darwin-x64@4.2.4': + optional: true + + '@tailwindcss/oxide-freebsd-x64@4.2.4': + optional: true + + '@tailwindcss/oxide-linux-arm-gnueabihf@4.2.4': + optional: true + + '@tailwindcss/oxide-linux-arm64-gnu@4.2.4': + optional: true + + '@tailwindcss/oxide-linux-arm64-musl@4.2.4': + optional: true + + '@tailwindcss/oxide-linux-x64-gnu@4.2.4': + optional: true + + '@tailwindcss/oxide-linux-x64-musl@4.2.4': + optional: true + + '@tailwindcss/oxide-wasm32-wasi@4.2.4': + optional: true + + '@tailwindcss/oxide-win32-arm64-msvc@4.2.4': + optional: true + + '@tailwindcss/oxide-win32-x64-msvc@4.2.4': + optional: true + + '@tailwindcss/oxide@4.2.4': + optionalDependencies: + '@tailwindcss/oxide-android-arm64': 4.2.4 + '@tailwindcss/oxide-darwin-arm64': 4.2.4 + '@tailwindcss/oxide-darwin-x64': 4.2.4 + '@tailwindcss/oxide-freebsd-x64': 4.2.4 + '@tailwindcss/oxide-linux-arm-gnueabihf': 4.2.4 + '@tailwindcss/oxide-linux-arm64-gnu': 4.2.4 + '@tailwindcss/oxide-linux-arm64-musl': 4.2.4 + '@tailwindcss/oxide-linux-x64-gnu': 4.2.4 + '@tailwindcss/oxide-linux-x64-musl': 4.2.4 + '@tailwindcss/oxide-wasm32-wasi': 4.2.4 + '@tailwindcss/oxide-win32-arm64-msvc': 4.2.4 + '@tailwindcss/oxide-win32-x64-msvc': 4.2.4 + + '@tailwindcss/vite@4.2.4(vite@8.0.10(@types/node@25.6.0)(jiti@2.6.1))': + dependencies: + '@tailwindcss/node': 4.2.4 + '@tailwindcss/oxide': 4.2.4 + tailwindcss: 4.2.4 + vite: 8.0.10(@types/node@25.6.0)(jiti@2.6.1) + + '@tsconfig/node10@1.0.12': {} + + '@tsconfig/node12@1.0.11': {} + + '@tsconfig/node14@1.0.3': {} + + '@tsconfig/node16@1.0.4': {} + + '@turbo/darwin-64@2.9.7': + optional: true + + '@turbo/darwin-arm64@2.9.7': + optional: true + + '@turbo/linux-64@2.9.7': + optional: true + + '@turbo/linux-arm64@2.9.7': + optional: true + + '@turbo/windows-64@2.9.7': + optional: true + + '@turbo/windows-arm64@2.9.7': + optional: true + + '@tybys/wasm-util@0.10.1': + dependencies: + tslib: 2.8.1 + optional: true + + '@types/argparse@1.0.38': {} + + '@types/chrome@0.1.40': + dependencies: + '@types/filesystem': 0.0.36 + '@types/har-format': 1.2.16 + + '@types/estree@1.0.8': {} + + '@types/filesystem@0.0.36': + dependencies: + '@types/filewriter': 0.0.33 + + '@types/filewriter@0.0.33': {} + + '@types/firefox-webext-browser@143.0.0': {} + + '@types/har-format@1.2.16': {} + + '@types/node@25.6.0': + dependencies: + undici-types: 7.19.2 + + '@types/react-dom@19.2.3(@types/react@19.2.14)': + dependencies: + '@types/react': 19.2.14 + + '@types/react@19.2.14': + dependencies: + csstype: 3.2.3 + + '@types/webextension-polyfill@0.12.5': {} + + '@vitejs/plugin-react@6.0.1(vite@8.0.10(@types/node@25.6.0)(jiti@2.6.1))': + dependencies: + '@rolldown/pluginutils': 1.0.0-rc.7 + vite: 8.0.10(@types/node@25.6.0)(jiti@2.6.1) + + '@volar/language-core@2.4.28': + dependencies: + '@volar/source-map': 2.4.28 + + '@volar/source-map@2.4.28': {} + + '@volar/typescript@2.4.28': + dependencies: + '@volar/language-core': 2.4.28 + path-browserify: 1.0.1 + vscode-uri: 3.1.0 + + '@vue/compiler-core@3.5.33': + dependencies: + '@babel/parser': 7.29.3 + '@vue/shared': 3.5.33 + entities: 7.0.1 + estree-walker: 2.0.2 + source-map-js: 1.2.1 + + '@vue/compiler-dom@3.5.33': + dependencies: + '@vue/compiler-core': 3.5.33 + '@vue/shared': 3.5.33 + + '@vue/compiler-vue2@2.7.16': + dependencies: + de-indent: 1.0.2 + he: 1.2.0 + + '@vue/language-core@2.2.0(typescript@6.0.3)': + dependencies: + '@volar/language-core': 2.4.28 + '@vue/compiler-dom': 3.5.33 + '@vue/compiler-vue2': 2.7.16 + '@vue/shared': 3.5.33 + alien-signals: 0.4.9 + minimatch: 9.0.9 + muggle-string: 0.4.1 + path-browserify: 1.0.1 + optionalDependencies: + typescript: 6.0.3 + + '@vue/shared@3.5.33': {} + + acorn-walk@8.3.5: + dependencies: + acorn: 8.16.0 + + acorn@8.16.0: {} + + ajv-draft-04@1.0.0(ajv@8.18.0): + optionalDependencies: + ajv: 8.18.0 + + ajv-formats@3.0.1(ajv@8.18.0): + optionalDependencies: + ajv: 8.18.0 + + ajv@8.18.0: + dependencies: + fast-deep-equal: 3.1.3 + fast-uri: 3.1.0 + json-schema-traverse: 1.0.0 + require-from-string: 2.0.2 + + alien-signals@0.4.9: {} + + arg@4.1.3: {} + + argparse@1.0.10: + dependencies: + sprintf-js: 1.0.3 + + balanced-match@1.0.0: {} + + balanced-match@4.0.4: {} + + brace-expansion@2.1.0: + dependencies: + balanced-match: 1.0.0 + + brace-expansion@5.0.5: + dependencies: + balanced-match: 4.0.4 + + compare-versions@6.1.1: {} + + confbox@0.1.8: {} + + confbox@0.2.4: {} + + create-require@1.1.1: {} + + csstype@3.2.3: {} + + de-indent@1.0.2: {} + + debug@4.4.3: + dependencies: + ms: 2.1.3 + + detect-libc@2.1.2: {} + + diff@4.0.4: {} + + diff@8.0.4: {} + + enhanced-resolve@5.21.0: + dependencies: + graceful-fs: 4.2.11 + tapable: 2.3.3 + + entities@7.0.1: {} + + entities@8.0.0: {} + + es-errors@1.3.0: {} + + estree-walker@2.0.2: {} + + exsolve@1.0.8: {} + + fast-deep-equal@3.1.3: {} + + fast-uri@3.1.0: {} + + fdir@6.5.0(picomatch@4.0.4): + optionalDependencies: + picomatch: 4.0.4 + + fs-extra@11.3.4: + dependencies: + graceful-fs: 4.2.11 + jsonfile: 6.2.1 + universalify: 2.0.1 + + fsevents@2.3.3: + optional: true + + function-bind@1.1.2: {} + + glob@13.0.6: + dependencies: + minimatch: 10.2.5 + minipass: 7.1.3 + path-scurry: 2.0.2 + + graceful-fs@4.2.11: {} + + has-flag@4.0.0: {} + + hasown@2.0.3: + dependencies: + function-bind: 1.1.2 + + he@1.2.0: {} + + import-lazy@4.0.0: {} + + is-core-module@2.16.1: + dependencies: + hasown: 2.0.3 + + jiti@2.6.1: {} + + jju@1.4.0: {} + + json-schema-traverse@1.0.0: {} + + jsonfile@6.2.1: + dependencies: + universalify: 2.0.1 + optionalDependencies: + graceful-fs: 4.2.11 + + kolorist@1.8.0: {} + + lightningcss-android-arm64@1.32.0: + optional: true + + lightningcss-darwin-arm64@1.32.0: + optional: true + + lightningcss-darwin-x64@1.32.0: + optional: true + + lightningcss-freebsd-x64@1.32.0: + optional: true + + lightningcss-linux-arm-gnueabihf@1.32.0: + optional: true + + lightningcss-linux-arm64-gnu@1.32.0: + optional: true + + lightningcss-linux-arm64-musl@1.32.0: + optional: true + + lightningcss-linux-x64-gnu@1.32.0: + optional: true + + lightningcss-linux-x64-musl@1.32.0: + optional: true + + lightningcss-win32-arm64-msvc@1.32.0: + optional: true + + lightningcss-win32-x64-msvc@1.32.0: + optional: true + + lightningcss@1.32.0: + dependencies: + detect-libc: 2.1.2 + optionalDependencies: + lightningcss-android-arm64: 1.32.0 + lightningcss-darwin-arm64: 1.32.0 + lightningcss-darwin-x64: 1.32.0 + lightningcss-freebsd-x64: 1.32.0 + lightningcss-linux-arm-gnueabihf: 1.32.0 + lightningcss-linux-arm64-gnu: 1.32.0 + lightningcss-linux-arm64-musl: 1.32.0 + lightningcss-linux-x64-gnu: 1.32.0 + lightningcss-linux-x64-musl: 1.32.0 + lightningcss-win32-arm64-msvc: 1.32.0 + lightningcss-win32-x64-msvc: 1.32.0 + + local-pkg@1.1.2: + dependencies: + mlly: 1.8.2 + pkg-types: 2.3.1 + quansync: 0.2.11 + + lru-cache@11.3.5: {} + + magic-string@0.30.21: + dependencies: + '@jridgewell/sourcemap-codec': 1.5.5 + + make-error@1.3.6: {} + + minimatch@10.2.3: + dependencies: + brace-expansion: 5.0.5 + + minimatch@10.2.5: + dependencies: + brace-expansion: 5.0.5 + + minimatch@9.0.9: + dependencies: + brace-expansion: 2.1.0 + + minipass@7.1.3: {} + + mlly@1.8.2: + dependencies: + acorn: 8.16.0 + pathe: 2.0.3 + pkg-types: 1.3.1 + ufo: 1.6.4 + + ms@2.1.3: {} + + muggle-string@0.4.1: {} + + nanoid@3.3.12: {} + + parse5@8.0.1: + dependencies: + entities: 8.0.0 + + path-browserify@1.0.1: {} + + path-parse@1.0.7: {} + + path-scurry@2.0.2: + dependencies: + lru-cache: 11.3.5 + minipass: 7.1.3 + + pathe@2.0.3: {} + + picocolors@1.1.1: {} + + picomatch@4.0.4: {} + + pkg-types@1.3.1: + dependencies: + confbox: 0.1.8 + mlly: 1.8.2 + pathe: 2.0.3 + + pkg-types@2.3.1: + dependencies: + confbox: 0.2.4 + exsolve: 1.0.8 + pathe: 2.0.3 + + postcss@8.5.13: + dependencies: + nanoid: 3.3.12 + picocolors: 1.1.1 + source-map-js: 1.2.1 + + quansync@0.2.11: {} + + react-dom@19.2.5(react@19.2.5): + dependencies: + react: 19.2.5 + scheduler: 0.27.0 + + react@19.2.5: {} + + require-from-string@2.0.2: {} + + reselect@5.1.1: {} + + resolve@1.22.12: + dependencies: + es-errors: 1.3.0 + is-core-module: 2.16.1 + path-parse: 1.0.7 + supports-preserve-symlinks-flag: 1.0.0 + + rolldown@1.0.0-rc.17: + dependencies: + '@oxc-project/types': 0.127.0 + '@rolldown/pluginutils': 1.0.0-rc.17 + optionalDependencies: + '@rolldown/binding-android-arm64': 1.0.0-rc.17 + '@rolldown/binding-darwin-arm64': 1.0.0-rc.17 + '@rolldown/binding-darwin-x64': 1.0.0-rc.17 + '@rolldown/binding-freebsd-x64': 1.0.0-rc.17 + '@rolldown/binding-linux-arm-gnueabihf': 1.0.0-rc.17 + '@rolldown/binding-linux-arm64-gnu': 1.0.0-rc.17 + '@rolldown/binding-linux-arm64-musl': 1.0.0-rc.17 + '@rolldown/binding-linux-ppc64-gnu': 1.0.0-rc.17 + '@rolldown/binding-linux-s390x-gnu': 1.0.0-rc.17 + '@rolldown/binding-linux-x64-gnu': 1.0.0-rc.17 + '@rolldown/binding-linux-x64-musl': 1.0.0-rc.17 + '@rolldown/binding-openharmony-arm64': 1.0.0-rc.17 + '@rolldown/binding-wasm32-wasi': 1.0.0-rc.17 + '@rolldown/binding-win32-arm64-msvc': 1.0.0-rc.17 + '@rolldown/binding-win32-x64-msvc': 1.0.0-rc.17 + + scheduler@0.27.0: {} + + semver@7.7.4: {} + + source-map-js@1.2.1: {} + + source-map@0.6.1: {} + + sprintf-js@1.0.3: {} + + string-argv@0.3.2: {} + + supports-color@8.1.1: + dependencies: + has-flag: 4.0.0 + + supports-preserve-symlinks-flag@1.0.0: {} + + tailwind-merge@3.5.0: {} + + tailwind-variants@3.2.2(tailwind-merge@3.5.0)(tailwindcss@4.2.4): + dependencies: + tailwindcss: 4.2.4 + optionalDependencies: + tailwind-merge: 3.5.0 + + tailwindcss@4.2.4: {} + + tapable@2.3.3: {} + + tinyglobby@0.2.16: + dependencies: + fdir: 6.5.0(picomatch@4.0.4) + picomatch: 4.0.4 + + ts-node@10.9.2(@types/node@25.6.0)(typescript@6.0.3): + dependencies: + '@cspotcode/source-map-support': 0.8.1 + '@tsconfig/node10': 1.0.12 + '@tsconfig/node12': 1.0.11 + '@tsconfig/node14': 1.0.3 + '@tsconfig/node16': 1.0.4 + '@types/node': 25.6.0 + acorn: 8.16.0 + acorn-walk: 8.3.5 + arg: 4.1.3 + create-require: 1.1.1 + diff: 4.0.4 + make-error: 1.3.6 + typescript: 6.0.3 + v8-compile-cache-lib: 3.0.1 + yn: 3.1.1 + + tslib@2.8.1: + optional: true + + turbo@2.9.7: + optionalDependencies: + '@turbo/darwin-64': 2.9.7 + '@turbo/darwin-arm64': 2.9.7 + '@turbo/linux-64': 2.9.7 + '@turbo/linux-arm64': 2.9.7 + '@turbo/windows-64': 2.9.7 + '@turbo/windows-arm64': 2.9.7 + + typescript@5.9.3: {} + + typescript@6.0.3: {} + + ufo@1.6.4: {} + + undici-types@7.19.2: {} + + universalify@2.0.1: {} + + use-sync-external-store@1.6.0(react@19.2.5): + dependencies: + react: 19.2.5 + + v8-compile-cache-lib@3.0.1: {} + + vite-plugin-dts@4.5.4(@types/node@25.6.0)(typescript@6.0.3)(vite@8.0.10(@types/node@25.6.0)(jiti@2.6.1)): + dependencies: + '@microsoft/api-extractor': 7.58.7(@types/node@25.6.0) + '@rollup/pluginutils': 5.3.0 + '@volar/typescript': 2.4.28 + '@vue/language-core': 2.2.0(typescript@6.0.3) + compare-versions: 6.1.1 + debug: 4.4.3 + kolorist: 1.8.0 + local-pkg: 1.1.2 + magic-string: 0.30.21 + typescript: 6.0.3 + optionalDependencies: + vite: 8.0.10(@types/node@25.6.0)(jiti@2.6.1) + transitivePeerDependencies: + - '@types/node' + - rollup + - supports-color + + vite@8.0.10(@types/node@25.6.0)(jiti@2.6.1): + dependencies: + lightningcss: 1.32.0 + picomatch: 4.0.4 + postcss: 8.5.13 + rolldown: 1.0.0-rc.17 + tinyglobby: 0.2.16 + optionalDependencies: + '@types/node': 25.6.0 + fsevents: 2.3.3 + jiti: 2.6.1 + + vscode-uri@3.1.0: {} + + webextension-polyfill@0.12.0: {} + + yn@3.1.1: {} diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml new file mode 100644 index 0000000..4cc172b --- /dev/null +++ b/pnpm-workspace.yaml @@ -0,0 +1,6 @@ +packages: + - "packages/*" + - "apps/*" + - "templates/*" +allowBuilds: + sharp: false diff --git a/templates/vite-react-template/.npmrc b/templates/vite-react-template/.npmrc new file mode 100644 index 0000000..8b02f75 --- /dev/null +++ b/templates/vite-react-template/.npmrc @@ -0,0 +1 @@ +registry = https://registry.npmmirror.com/ \ No newline at end of file diff --git a/templates/vite-react-template/.vscode/settings.json b/templates/vite-react-template/.vscode/settings.json new file mode 100644 index 0000000..772343c --- /dev/null +++ b/templates/vite-react-template/.vscode/settings.json @@ -0,0 +1,8 @@ +{ + "json.schemas": [ + { + "fileMatch": ["/tsconfig.build.json", "/tsconfig.base.json"], + "schema": {} + } + ] +} diff --git a/templates/vite-react-template/package.json b/templates/vite-react-template/package.json new file mode 100644 index 0000000..2e61490 --- /dev/null +++ b/templates/vite-react-template/package.json @@ -0,0 +1,34 @@ +{ + "name": "vite-react-template", + "version": "0.0.0", + "private": true, + "type": "module", + "sideEffects": ["*.css"], + "module": "./dist/index.es.js", + "main": "./dist/index.cjs.js", + "types": "./dist/index.d.ts", + "style": "./dist/index.css", + "exports": { + ".": { + "import": "./dist/index.es.js", + "require": "./dist/index.cjs.js", + "types": "./dist/index.d.ts" + }, + "./index.css": "./dist/index.css" + }, + "files": ["dist"], + "scripts": { + "dev": "vite", + "build": "vite build --tsconfig tsconfig.build.json" + }, + "devDependencies": { + "@types/node": "^25.6.0", + "@types/react": "^19.2.14", + "@types/react-dom": "^19.2.3", + "@vitejs/plugin-react": "^6.0.1", + "glob": "^13.0.6", + "typescript": "^6.0.3", + "vite": "^8.0.9", + "vite-plugin-dts": "^4.5.4" + } +} diff --git a/templates/vite-react-template/scripts-plugin/vite-plugin-gen-index-css.ts b/templates/vite-react-template/scripts-plugin/vite-plugin-gen-index-css.ts new file mode 100644 index 0000000..47af09c --- /dev/null +++ b/templates/vite-react-template/scripts-plugin/vite-plugin-gen-index-css.ts @@ -0,0 +1,137 @@ +// plugins/vite-plugin-gen-index-css.ts +import type { Plugin } from "vite"; +import fs from "fs"; +import path from "path"; +import { globSync } from "glob"; + +interface Config { + targetDirs: string[]; + includeExtensions: string[]; + importSyntax: "@import"; + importSyntaxTail?: string; + excludeFilePattern: RegExp[]; + excludeDirs: string[]; + warnDuplicateTailwindImport: boolean; + indexFileName: string; +} + +const CONFIG: Config = { + targetDirs: ["src"], + includeExtensions: [".css"], + importSyntax: "@import", + excludeFilePattern: [/index\.css/, /index\.scss/, /\.(test|spec)\./], + excludeDirs: [ + "__tests__", + "tests", + "story", + "stories", + "types", + "node_modules", + "dist", + "build", + ], + warnDuplicateTailwindImport: true, + indexFileName: "index.css", +}; + +const normalizePath = (p: string) => p.replace(/\\/g, "/"); + +function isValidFile(filePath: string, config: Config): boolean { + const filenameWithExt = filePath.split(/[\\/]/).pop()!; + const shouldExcludeFile = config.excludeFilePattern.some((p) => + p.test(filenameWithExt), + ); + if (shouldExcludeFile) return false; + + const normalized = normalizePath(filePath); + const shouldExcludeDir = config.excludeDirs.some((dir) => + normalized.includes(`/${dir}/`), + ); + if (shouldExcludeDir) return false; + + const ext = path.extname(filePath); + if (!config.includeExtensions.includes(ext)) return false; + + if (config.warnDuplicateTailwindImport) { + try { + const content = fs.readFileSync(filePath, "utf-8"); + if ( + content.includes('@import "tailwindcss"') || + content.includes("@import 'tailwindcss'") + ) { + console.warn( + `[gen-index-css] ${filePath} 含有重复的 @import "tailwindcss",建议删除`, + ); + } + } catch { + // ignore + } + } + + return true; +} + +function generateIndexFile(config: Config) { + const [targetDir] = config.targetDirs; + const dirPath = path.resolve(process.cwd(), targetDir); + + const searchPattern = path.resolve(dirPath, "**", "*.*"); + + const allFiles = globSync(searchPattern, { + nodir: true, + absolute: true, + windowsPathsNoEscape: true, + dot: false, + follow: true, + }); + + const validFiles = allFiles.filter((f) => isValidFile(f, config)); + + console.log(`✅ 有效 CSS 文件数量: ${validFiles.length}`); + validFiles.sort(); + + const importStatements = validFiles.map((file) => { + const relPath = path.relative(dirPath, file); + const importPath = "./" + relPath.replace(/\\/g, "/"); + return `${config.importSyntax} '${importPath}';`; + }); + + const indexContent = ` +@import "tailwindcss"; +${importStatements.join("\n")} +`.trim(); + + const indexFilePath = path.resolve(dirPath, config.indexFileName); + + // ✅ 内容比对,防止无限 rebuild + if (fs.existsSync(indexFilePath)) { + const old = fs.readFileSync(indexFilePath, "utf8"); + if (old === indexContent) return; + } + + fs.writeFileSync(indexFilePath, indexContent, "utf8"); + console.log(`✅ 成功生成 ${config.indexFileName}: ${indexFilePath}`); +} + +export function genIndexCssPlugin(): Plugin { + return { + name: "vite-plugin-gen-index-css", + apply: "build", + + buildStart() { + try { + generateIndexFile(CONFIG); + } catch (err) { + const msg = err instanceof Error ? err.message : String(err); + this.error(`[gen-index-css] failed: ${msg}`); + throw err; + } + }, + + handleHotUpdate({ file }) { + if (normalizePath(file).endsWith(`/src/${CONFIG.indexFileName}`)) { + return []; + } + }, + }; +} diff --git a/templates/vite-react-template/scripts-plugin/vite-plugin-gen-index-ts.ts b/templates/vite-react-template/scripts-plugin/vite-plugin-gen-index-ts.ts new file mode 100644 index 0000000..17c5d84 --- /dev/null +++ b/templates/vite-react-template/scripts-plugin/vite-plugin-gen-index-ts.ts @@ -0,0 +1,129 @@ +// plugins/vite-plugin-gen-index-ts.ts +import type { Plugin } from "vite"; +import fs from "fs"; +import path from "path"; +import { globSync } from "glob"; + +interface Config { + targetDirs: string[]; + includeExtensions: string[]; + excludeKeywords: { + dirs: string[]; + fileSuffixes: string[]; + filePatterns: RegExp[]; + }; +} + +const CONFIG: Config = { + targetDirs: ["src"], + includeExtensions: [".ts", ".tsx", ".vue"], + excludeKeywords: { + dirs: ["__tests__", "tests", "story", "stories", "types"], + fileSuffixes: [".d.ts"], + filePatterns: [ + /^index\.(ts|tsx|js|jsx)$/, + /\.(test|spec)\./, + /\.(story|stories)\./, + ], + }, +}; + +const normalizePath = (p: string) => p.replace(/\\/g, "/"); + +const isInExcludeDir = (filePath: string) => { + const normalized = normalizePath(filePath); + return CONFIG.excludeKeywords.dirs.some((dir) => + normalized.includes(`/${dir}/`), + ); +}; + +const isExcludeSuffix = (filePath: string) => + CONFIG.excludeKeywords.fileSuffixes.some((suffix) => + filePath.endsWith(suffix), + ); + +const isMatchExcludePattern = (fileName: string) => + CONFIG.excludeKeywords.filePatterns.some((pattern) => pattern.test(fileName)); + +function isValidFile(filePath: string): boolean { + const fileName = filePath.split(/[\\/]/).pop()!; + + if (isInExcludeDir(filePath)) return false; + if (isExcludeSuffix(filePath)) return false; + if (isMatchExcludePattern(fileName)) return false; + + const ext = path.extname(filePath); + return CONFIG.includeExtensions.includes(ext); +} + +function generateIndexFile(dirPath: string) { + const searchPattern = path.resolve(dirPath, "**", "*.*"); + + const allFiles = globSync(searchPattern, { + nodir: true, + absolute: true, + windowsPathsNoEscape: true, + dot: false, + follow: true, + }); + + const validFiles = allFiles.filter(isValidFile); + if (validFiles.length === 0) return; + + validFiles.sort(); + + const exportStatements = validFiles.map((file) => { + const relPath = path.relative(dirPath, file); + const importPath = `./${relPath + .replace(/\.[^.]+$/, "") + .replace(/\\/g, "/")}`; + return `export * from '${importPath}';`; + }); + + const indexContent = ` +import './index.css'; + +${exportStatements.join("\n")} +`.trim(); + + const indexFilePath = path.resolve(dirPath, "index.ts"); + + // ✅ 内容比对,避免无限 rebuild + if (fs.existsSync(indexFilePath)) { + const old = fs.readFileSync(indexFilePath, "utf8"); + if (old === indexContent) return; + } + + fs.writeFileSync(indexFilePath, indexContent, "utf8"); +} + +export function genIndexTsPlugin(): Plugin { + return { + name: "vite-plugin-gen-index-ts", + apply: "build", + + buildStart() { + const [targetDir] = CONFIG.targetDirs; + if (!targetDir) { + this.error("CONFIG.targetDirs is empty"); + return; + } + + const absTargetDir = path.resolve(process.cwd(), targetDir); + + try { + generateIndexFile(absTargetDir); + } catch (err) { + const msg = err instanceof Error ? err.message : String(err); + this.error(`[gen-index-ts] failed: ${msg}`); + throw err; + } + }, + + handleHotUpdate({ file }) { + if (file.replace(/\\/g, "/").endsWith("/src/index.ts")) { + return []; + } + }, + }; +} diff --git a/templates/vite-react-template/src/types/css.d.ts b/templates/vite-react-template/src/types/css.d.ts new file mode 100644 index 0000000..d535de2 --- /dev/null +++ b/templates/vite-react-template/src/types/css.d.ts @@ -0,0 +1,4 @@ +declare module '*.css' { + const content: { [className: string]: string }; + export default content; +} \ No newline at end of file diff --git a/templates/vite-react-template/src/types/env.d.ts b/templates/vite-react-template/src/types/env.d.ts new file mode 100644 index 0000000..7ba6254 --- /dev/null +++ b/templates/vite-react-template/src/types/env.d.ts @@ -0,0 +1,51 @@ +/// + +declare module "*.svg" { + import * as React from "react"; + export const ReactComponent: React.FC>; + const src: string; + export default src; +} + +declare module "*.png" { + const src: string; + export default src; +} + +declare module "*.jpg" { + const src: string; + export default src; +} + +declare module "*.jpeg" { + const src: string; + export default src; +} + +declare module "*.gif" { + const src: string; + export default src; +} + +declare module "*.webp" { + const src: string; + export default src; +} + +interface ImportMetaEnv { + readonly MODE: "development" | "production" | "test"; + readonly BASE_URL: string; + readonly PROD: boolean; + readonly DEV: boolean; + readonly SSR: boolean; + + // ===== 业务环境变量 ===== + readonly VITE_API_BASE: string; + readonly VITE_UPLOAD_URL?: string; + readonly VITE_ENABLE_MOCK?: "true" | "false"; + readonly VITE_SENTRY_DSN?: string; +} + +interface ImportMeta { + readonly env: ImportMetaEnv; +} diff --git a/templates/vite-react-template/tsconfig.base.json b/templates/vite-react-template/tsconfig.base.json new file mode 100644 index 0000000..b134137 --- /dev/null +++ b/templates/vite-react-template/tsconfig.base.json @@ -0,0 +1,40 @@ +{ + // tsconfig.base.json,用于被 tesconfig.json 和 tesconfig.build.json 继承 + "compilerOptions": { + // 输出模块语法,使用版本号最新的那个,而不是实验性语法 ESNext + "module": "es2022", + + // 模块解析策略,模拟 Vite / Rollup / webpack,支持 exports / imports,不强制 Node ESM 的严格规则 + "moduleResolution": "bundler", + + // 显式声明使用的类型包 + "types": ["node", "react", "vite/client"], + + // 开启所有严格类型检查,防止 any / 隐式 any 扩散 + "strict": true, + + // 允许 ESM 导入 CJS + "esModuleInterop": true, + + // 跳过 node_modules 类型检查,加快构建,避免第三方类型污染 + "skipLibCheck": true, + + // 模块检测策略,不会影响 node_modules 中的第三方 CommonJS 依赖,Vite 会在预构建阶段自动将其转换为 ESM。 + "moduleDetection": "force", + + // 保留源码中的 import / export 语句原样输出,不进行自动转换(如 import → require),通常与 moduleDetection: "force" 搭配使用 + "verbatimModuleSyntax": true, + + // 是否检查“未使用的局部变量” + "noUnusedLocals": true, + + // 是否检查“未使用的函数参数” + "noUnusedParameters": true, + + // 是否只允许“可擦除的语法(Erasable Syntax),确保 TypeScript 语法在编译后可完全移除 + "erasableSyntaxOnly": true, + + // 是否禁止 switch 语句中的 case 贯穿(fallthrough),如果 case 没有 break / return,会报错 + "noFallthroughCasesInSwitch": true + } +} diff --git a/templates/vite-react-template/tsconfig.build.json b/templates/vite-react-template/tsconfig.build.json new file mode 100644 index 0000000..f3b4b99 --- /dev/null +++ b/templates/vite-react-template/tsconfig.build.json @@ -0,0 +1,122 @@ +{ + // 此文件仅用于类型检查,不用于类型检查,构建时会指定使用 tsconfig.build.json + "extends": "./tsconfig.base.json", + "compilerOptions": { + // Browser api,需要加 "DOM","DOM.Iterable" + // Node api,需要加 "ES2025",始终使用带版本号的最新版本 + // NextJs api,属于同构,server 端会预处理 DOM,计算url,三个都需要 "ES2025", "DOM", "DOM.Iterable" + "lib": ["ES2025", "DOM", "DOM.Iterable"], + + /** + * 显式声明使用的类型包 + * - node:Node.js API + * - react:JSX / React 类型 + * - vite/client:import.meta / env + */ + "types": ["node", "react", "vite/client"], + + /** + * React JSX 编译模式 + * - 使用 React 17+ 新 JSX Transform + * - 不需要手动 import React + */ + "jsx": "react-jsx", + + /** + * 编译输出目录 + * - tsc / tsc -b 都会用到 + */ + "outDir": "./dist", + + /** + * 源码根目录 + * - 确保 dist 结构与 src 一致 + * - 对 declaration 路径至关重要 + */ + "rootDir": "./src", + + /** + * 生成 .d.ts 类型声明文件 + * - 组件库 / npm 包发布必需 + * - 对应用项目无害,仅影响类型输出 + */ + "declaration": true, + + /** + * 只做类型检查,不生成 JS 输出 + * - 适用于 Vite / Next / Nuxt 等 bundler 场景 + * - 防止 tsc 与构建工具重复 emit + */ + "noEmit": true, + + /** + * 强制单文件可独立编译 + * - 适配 esbuild / SWC / bundler 编译模型 + * - 禁止依赖跨文件类型推断(enum / namespace 等) + */ + "isolatedModules": true, + + /** + * 允许在 import 中显式使用 .ts / .tsx 后缀 + * - 兼容 Node ESM / bundler 对文件扩展名的严格要求 + * - 避免 `import './foo'` 在 TS + ESM 下歧义 + */ + "allowImportingTsExtensions": true + }, + /** + * 参与类型检查和编译的文件 + * - 只扫描 src + * - 其它目录通过 exclude 排除 + */ + "include": ["src", "scripts"], + + /** + * 明确排除非源码内容 + * - 避免污染类型系统 + * - 防止误入 dist / test / config + * - 保证发布包干净 + */ + "exclude": [ + "node_modules", + "dist", + + // ---------- build / cache ---------- + ".turbo/**/*", + ".cache/**/*", + ".vite/**/*", + + // ---------- 配置文件 ---------- + "vite.config.ts", + "*.config.ts", + "*.config.js", + "tsconfig.*.json", + + // ---------- 测试相关 ---------- + "__tests__/**/*", + "test/**/*", + "tests/**/*", + "**/*.test.ts", + "**/*.test.tsx", + "**/*.spec.ts", + "**/*.spec.tsx", + + // ---------- Storybook ---------- + ".storybook/**/*", + "stories/**/*", + + // ---------- 示例 / 脚本 ---------- + "example/**/*", + "examples/**/*", + "scripts/**/*", + + // ---------- 环境与静态资源 ---------- + ".env", + ".env.*", + "public/**/*", + + // ---------- 文档 ---------- + "docs/**/*", + "README.md", + "LICENSE" + ] +} diff --git a/templates/vite-react-template/tsconfig.json b/templates/vite-react-template/tsconfig.json new file mode 100644 index 0000000..a28554e --- /dev/null +++ b/templates/vite-react-template/tsconfig.json @@ -0,0 +1,16 @@ +{ + // 此文件仅用于类型检查,不用于构建,构建时会指定使用 tsconfig.build.json + "extends": "./tsconfig.base.json", + "compilerOptions": { + // node api 使用最新版本号的 "ESxxxx",browser api 使用 "DOM" 和 "DOM.Iterable" + "lib": ["ES2025", "DOM", "DOM.Iterable"], + + //显式声明使用的类型包,避免找不到模块 + "types": ["node", "react", "vite/client"], + + // React JSX 编译模式 + "jsx": "react-jsx" + }, + // 将类型检查范围扩大至整个子项目,而不只是 src 文件夹, + "include": ["**/*"] +} diff --git a/templates/vite-react-template/vite.config.ts b/templates/vite-react-template/vite.config.ts new file mode 100644 index 0000000..a7b245d --- /dev/null +++ b/templates/vite-react-template/vite.config.ts @@ -0,0 +1,43 @@ +import { defineConfig } from "vite"; +import react from "@vitejs/plugin-react"; +import dts from "vite-plugin-dts"; +import path from "path"; +import { genIndexTsPlugin } from "./scripts-plugin/vite-plugin-gen-index-ts"; +import { genIndexCssPlugin } from "./scripts-plugin/vite-plugin-gen-index-css"; + +export default defineConfig({ + plugins: [ + genIndexTsPlugin(), + genIndexCssPlugin(), + react(), + dts({ + insertTypesEntry: true, + }), + ], + + build: { + lib: { + entry: path.resolve(__dirname, "src/index.ts"), + name: "DefgovUIWeb", + formats: ["es", "cjs"], + fileName: (format) => `index.${format}.js`, + }, + + rollupOptions: { + external: ["react", "react-dom", "react/jsx-runtime"], + output: { + globals: { + react: "React", + "react-dom": "ReactDOM", + }, + }, + }, + + sourcemap: true, + cssCodeSplit: true, + + watch: { + exclude: ["node_modules", "dist", ".git"], + }, + }, +}); diff --git a/turbo.json b/turbo.json new file mode 100644 index 0000000..f6f4952 --- /dev/null +++ b/turbo.json @@ -0,0 +1,15 @@ +{ + "$schema": "https://turborepo.dev/schema.json", + "ui": "tui", + "tasks": { + "build": { + "dependsOn": ["^build"], + "inputs": ["$TURBO_DEFAULT$", ".env*"], + "outputs": [".next/**", "!.next/cache/**"] + }, + "dev": { + "cache": false, + "persistent": true + } + } +}