From b79fe7dd497a7bb6d54c13ab21ea3749a0106abd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=9B=A8=E9=9C=96=E9=93=83?= Date: Thu, 28 May 2026 20:20:45 +0800 Subject: [PATCH] refactor: reorganize directory structure into src/ MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Move all source code directories into src/ for cleaner project structure: - pages/, components/, utils/, config/, providers/, types/, lib/, assets/, entrypoints/ → src/ - Use WXT srcDir config to resolve @/ alias to src/ - Update tsconfig, vitest, eslint, tailwind configs - Remove scattered README.md files from subdirectories - Update documentation (AGENTS.md, CODING_STANDARDS.md, README.md) - Fix pre-existing lint error in RouterProvider.tsx Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .github/CODING_STANDARDS.md | 67 +++++---- AGENTS.md | 42 +++--- README.md | 38 ++--- components/README.md | 27 ---- components/ui/README.md | 40 ----- config/README.md | 44 ------ entrypoints/README.md | 51 ------- eslint.config.ts | 9 +- lib/README.md | 26 ---- pages/README.md | 140 ------------------ providers/README.md | 63 -------- public/README.md | 20 --- src/README.md | 24 --- {assets => src/assets}/react.svg | 0 {components => src/components}/CopyButton.tsx | 0 .../components}/DecodeResultPaper.tsx | 0 .../components}/ErrorBoundary.tsx | 0 .../components}/GlobalSnackbar.tsx | 0 .../components}/ImageUploader.tsx | 0 .../components}/PageErrorBoundary.tsx | 0 .../components}/PageSkeleton.tsx | 0 .../components}/QrCodePreview.tsx | 0 .../components}/RouterContainer.tsx | 0 .../components}/SwitchButtonGroup.tsx | 0 .../components}/TextInputArea.tsx | 0 {components => src/components}/TopBar.tsx | 0 .../__tests__/DecodeResultPaper.test.tsx | 0 .../__tests__/ErrorBoundary.test.tsx | 0 .../__tests__/GlobalSnackbar.test.tsx | 0 .../__tests__/ImageUploader.test.tsx | 0 .../__tests__/PageErrorBoundary.test.tsx | 0 .../__tests__/PageSkeleton.test.tsx | 0 .../__tests__/QrCodePreview.test.tsx | 0 .../__tests__/RouterContainer.test.tsx | 0 .../__tests__/StorageCleanerConfirm.test.tsx | 0 .../__tests__/SwitchButtonGroup.test.tsx | 0 .../__tests__/TextInputArea.test.tsx | 0 .../components}/__tests__/ToolCard.test.tsx | 0 .../components}/__tests__/TopBar.test.tsx | 0 {components => src/components}/ui/badge.tsx | 0 {components => src/components}/ui/button.tsx | 0 .../components}/ui/checkbox.tsx | 0 {components => src/components}/ui/dialog.tsx | 0 {components => src/components}/ui/input.tsx | 0 {components => src/components}/ui/label.tsx | 0 {components => src/components}/ui/select.tsx | 0 {components => src/components}/ui/switch.tsx | 0 .../config}/__tests__/features.test.ts | 0 {config => src/config}/features.tsx | 0 .../entrypoints}/__tests__/background.test.ts | 0 .../entrypoints}/background.ts | 2 +- {entrypoints => src/entrypoints}/content.ts | 2 +- .../content/contextMenuHandler.ts | 0 .../entrypoints}/content/messageHandler.ts | 0 .../entrypoints}/content/uiPopover.ts | 0 .../entrypoints}/options/App.tsx | 0 .../options/__tests__/App.test.tsx | 0 .../entrypoints}/options/index.html | 0 .../entrypoints}/options/main.tsx | 2 +- .../entrypoints}/popup/App.tsx | 0 .../entrypoints}/popup/index.html | 0 .../entrypoints}/popup/main.tsx | 2 +- .../rightClickRestorer.content.ts | 0 .../entrypoints}/sidepanel/App.tsx | 0 .../entrypoints}/sidepanel/index.html | 0 .../entrypoints}/sidepanel/main.tsx | 2 +- {lib => src/lib}/utils.ts | 0 .../Base64ConverterSection.tsx | 0 .../pages}/Base64Converter/TextMode.tsx | 0 .../__tests__/TextMode.test.tsx | 0 .../Base64Converter/__tests__/index.test.tsx | 0 .../pages}/Base64Converter/index.tsx | 0 .../Base64Converter/useBase64Converter.ts | 0 {pages => src/pages}/Dashboard/ToolCard.tsx | 0 {pages => src/pages}/Dashboard/index.tsx | 0 {pages => src/pages}/HtmlToMarkdown/index.tsx | 0 .../pages}/JsonTools/DiffNavigator.tsx | 0 {pages => src/pages}/JsonTools/DiffResult.tsx | 0 .../pages}/JsonTools/JsonConvertSection.tsx | 0 .../pages}/JsonTools/JsonDiffInput.tsx | 0 .../pages}/JsonTools/JsonFormatSection.tsx | 0 {pages => src/pages}/JsonTools/JsonTree.tsx | 0 {pages => src/pages}/JsonTools/diffEngine.ts | 0 {pages => src/pages}/JsonTools/index.tsx | 0 {pages => src/pages}/JsonTools/types.ts | 0 {pages => src/pages}/Jwt/index.tsx | 0 {pages => src/pages}/MarkdownToHtml/index.tsx | 0 .../pages}/QrCode/__tests__/index.test.tsx | 0 .../QrCode/components/GeneratePanel.tsx | 0 .../pages}/QrCode/components/ParsePanel.tsx | 0 .../pages}/QrCode/contexts/QrCodeContext.ts | 0 .../pages}/QrCode/hooks/useQrCode.ts | 0 {pages => src/pages}/QrCode/index.tsx | 0 {pages => src/pages}/QrCode/types.ts | 0 .../__tests__/index.test.tsx | 0 .../__tests__/useRightClickRestorer.test.ts | 0 .../pages}/RightClickRestorer/index.tsx | 0 .../useRightClickRestorer.ts | 0 .../StorageCleaner/AutoRefreshToggle.tsx | 0 .../pages}/StorageCleaner/CleaningResult.tsx | 0 .../pages}/StorageCleaner/ErrorDisplay.tsx | 0 .../pages}/StorageCleaner/OptionItem.tsx | 0 .../StorageCleaner/StorageCleanerConfirm.tsx | 0 .../StorageCleaner/StorageOptionsGrid.tsx | 0 {pages => src/pages}/StorageCleaner/index.tsx | 0 .../StorageCleaner/useStorageCleaner.ts | 0 {pages => src/pages}/TextStatistics/index.tsx | 0 {pages => src/pages}/Timestamp/LiveClock.tsx | 0 {pages => src/pages}/Timestamp/ResultView.tsx | 0 {pages => src/pages}/Timestamp/constants.ts | 0 {pages => src/pages}/Timestamp/index.tsx | 0 .../pages}/Timestamp/useTimestampConverter.ts | 0 {providers => src/providers}/AppRoot.tsx | 0 .../providers}/RouterProvider.tsx | 3 +- .../providers}/ThemeModeProvider.tsx | 0 .../__tests__/RouterProvider.test.tsx | 0 {types => src/types}/qrious.d.ts | 0 {types => src/types}/storage.d.ts | 0 .../utils}/__tests__/base64Converter.test.ts | 0 .../utils}/__tests__/chromeStorage.test.ts | 0 .../utils}/__tests__/chromeTabs.test.ts | 0 .../utils}/__tests__/clipboard.test.ts | 0 .../utils}/__tests__/contextMenu.test.ts | 0 {utils => src/utils}/__tests__/dayjs.test.ts | 0 .../utils}/__tests__/diffEngine.test.ts | 0 {utils => src/utils}/__tests__/format.test.ts | 0 .../utils}/__tests__/htmlToMarkdown.test.ts | 0 .../utils}/__tests__/jsonFormatter.test.ts | 0 .../utils}/__tests__/jsonMinify.test.ts | 0 .../utils}/__tests__/jsonToToml.test.ts | 0 .../utils}/__tests__/jsonToYaml.test.ts | 0 {utils => src/utils}/__tests__/jwt.test.ts | 0 .../utils}/__tests__/markdownToHtml.test.ts | 0 .../utils}/__tests__/messages.test.ts | 0 .../utils}/__tests__/qrCodeParser.test.ts | 0 .../utils}/__tests__/storageCleaner.test.ts | 0 .../utils}/__tests__/textStatistics.test.ts | 0 .../__tests__/useContextMenuData.test.ts | 0 .../utils}/__tests__/useStorageState.test.ts | 0 {utils => src/utils}/base64Converter.ts | 0 {utils => src/utils}/chromeI18n.ts | 0 {utils => src/utils}/chromeStorage.ts | 0 {utils => src/utils}/chromeTabs.ts | 0 {utils => src/utils}/clipboard.ts | 0 {utils => src/utils}/contextMenu.ts | 0 {utils => src/utils}/dayjs.ts | 0 {utils => src/utils}/format.ts | 0 {utils => src/utils}/htmlToMarkdown.ts | 0 {utils => src/utils}/jsonFormatter.ts | 0 {utils => src/utils}/jsonToToml.ts | 0 {utils => src/utils}/jsonToYaml.ts | 0 {utils => src/utils}/jwt.ts | 0 {utils => src/utils}/markdownToHtml.ts | 0 {utils => src/utils}/messages.ts | 0 {utils => src/utils}/qrCodeParser.ts | 0 {utils => src/utils}/storageCleaner.ts | 0 {utils => src/utils}/textStatistics.ts | 0 {utils => src/utils}/useContextMenuData.ts | 0 {utils => src/utils}/useDebounce.ts | 0 {utils => src/utils}/useStorageState.ts | 0 tailwind.config.js | 9 +- tsconfig.json | 17 +-- types/README.md | 42 ------ utils/README.md | 42 ------ vitest.config.ts | 2 +- wxt.config.ts | 1 + 166 files changed, 86 insertions(+), 631 deletions(-) delete mode 100644 components/README.md delete mode 100644 components/ui/README.md delete mode 100644 config/README.md delete mode 100644 entrypoints/README.md delete mode 100644 lib/README.md delete mode 100644 pages/README.md delete mode 100644 providers/README.md delete mode 100644 public/README.md delete mode 100644 src/README.md rename {assets => src/assets}/react.svg (100%) rename {components => src/components}/CopyButton.tsx (100%) rename {components => src/components}/DecodeResultPaper.tsx (100%) rename {components => src/components}/ErrorBoundary.tsx (100%) rename {components => src/components}/GlobalSnackbar.tsx (100%) rename {components => src/components}/ImageUploader.tsx (100%) rename {components => src/components}/PageErrorBoundary.tsx (100%) rename {components => src/components}/PageSkeleton.tsx (100%) rename {components => src/components}/QrCodePreview.tsx (100%) rename {components => src/components}/RouterContainer.tsx (100%) rename {components => src/components}/SwitchButtonGroup.tsx (100%) rename {components => src/components}/TextInputArea.tsx (100%) rename {components => src/components}/TopBar.tsx (100%) rename {components => src/components}/__tests__/DecodeResultPaper.test.tsx (100%) rename {components => src/components}/__tests__/ErrorBoundary.test.tsx (100%) rename {components => src/components}/__tests__/GlobalSnackbar.test.tsx (100%) rename {components => src/components}/__tests__/ImageUploader.test.tsx (100%) rename {components => src/components}/__tests__/PageErrorBoundary.test.tsx (100%) rename {components => src/components}/__tests__/PageSkeleton.test.tsx (100%) rename {components => src/components}/__tests__/QrCodePreview.test.tsx (100%) rename {components => src/components}/__tests__/RouterContainer.test.tsx (100%) rename {components => src/components}/__tests__/StorageCleanerConfirm.test.tsx (100%) rename {components => src/components}/__tests__/SwitchButtonGroup.test.tsx (100%) rename {components => src/components}/__tests__/TextInputArea.test.tsx (100%) rename {components => src/components}/__tests__/ToolCard.test.tsx (100%) rename {components => src/components}/__tests__/TopBar.test.tsx (100%) rename {components => src/components}/ui/badge.tsx (100%) rename {components => src/components}/ui/button.tsx (100%) rename {components => src/components}/ui/checkbox.tsx (100%) rename {components => src/components}/ui/dialog.tsx (100%) rename {components => src/components}/ui/input.tsx (100%) rename {components => src/components}/ui/label.tsx (100%) rename {components => src/components}/ui/select.tsx (100%) rename {components => src/components}/ui/switch.tsx (100%) rename {config => src/config}/__tests__/features.test.ts (100%) rename {config => src/config}/features.tsx (100%) rename {entrypoints => src/entrypoints}/__tests__/background.test.ts (100%) rename {entrypoints => src/entrypoints}/background.ts (99%) rename {entrypoints => src/entrypoints}/content.ts (83%) rename {entrypoints => src/entrypoints}/content/contextMenuHandler.ts (100%) rename {entrypoints => src/entrypoints}/content/messageHandler.ts (100%) rename {entrypoints => src/entrypoints}/content/uiPopover.ts (100%) rename {entrypoints => src/entrypoints}/options/App.tsx (100%) rename {entrypoints => src/entrypoints}/options/__tests__/App.test.tsx (100%) rename {entrypoints => src/entrypoints}/options/index.html (100%) rename {entrypoints => src/entrypoints}/options/main.tsx (89%) rename {entrypoints => src/entrypoints}/popup/App.tsx (100%) rename {entrypoints => src/entrypoints}/popup/index.html (100%) rename {entrypoints => src/entrypoints}/popup/main.tsx (89%) rename {entrypoints => src/entrypoints}/rightClickRestorer.content.ts (100%) rename {entrypoints => src/entrypoints}/sidepanel/App.tsx (100%) rename {entrypoints => src/entrypoints}/sidepanel/index.html (100%) rename {entrypoints => src/entrypoints}/sidepanel/main.tsx (89%) rename {lib => src/lib}/utils.ts (100%) rename {pages => src/pages}/Base64Converter/Base64ConverterSection.tsx (100%) rename {pages => src/pages}/Base64Converter/TextMode.tsx (100%) rename {pages => src/pages}/Base64Converter/__tests__/TextMode.test.tsx (100%) rename {pages => src/pages}/Base64Converter/__tests__/index.test.tsx (100%) rename {pages => src/pages}/Base64Converter/index.tsx (100%) rename {pages => src/pages}/Base64Converter/useBase64Converter.ts (100%) rename {pages => src/pages}/Dashboard/ToolCard.tsx (100%) rename {pages => src/pages}/Dashboard/index.tsx (100%) rename {pages => src/pages}/HtmlToMarkdown/index.tsx (100%) rename {pages => src/pages}/JsonTools/DiffNavigator.tsx (100%) rename {pages => src/pages}/JsonTools/DiffResult.tsx (100%) rename {pages => src/pages}/JsonTools/JsonConvertSection.tsx (100%) rename {pages => src/pages}/JsonTools/JsonDiffInput.tsx (100%) rename {pages => src/pages}/JsonTools/JsonFormatSection.tsx (100%) rename {pages => src/pages}/JsonTools/JsonTree.tsx (100%) rename {pages => src/pages}/JsonTools/diffEngine.ts (100%) rename {pages => src/pages}/JsonTools/index.tsx (100%) rename {pages => src/pages}/JsonTools/types.ts (100%) rename {pages => src/pages}/Jwt/index.tsx (100%) rename {pages => src/pages}/MarkdownToHtml/index.tsx (100%) rename {pages => src/pages}/QrCode/__tests__/index.test.tsx (100%) rename {pages => src/pages}/QrCode/components/GeneratePanel.tsx (100%) rename {pages => src/pages}/QrCode/components/ParsePanel.tsx (100%) rename {pages => src/pages}/QrCode/contexts/QrCodeContext.ts (100%) rename {pages => src/pages}/QrCode/hooks/useQrCode.ts (100%) rename {pages => src/pages}/QrCode/index.tsx (100%) rename {pages => src/pages}/QrCode/types.ts (100%) rename {pages => src/pages}/RightClickRestorer/__tests__/index.test.tsx (100%) rename {pages => src/pages}/RightClickRestorer/__tests__/useRightClickRestorer.test.ts (100%) rename {pages => src/pages}/RightClickRestorer/index.tsx (100%) rename {pages => src/pages}/RightClickRestorer/useRightClickRestorer.ts (100%) rename {pages => src/pages}/StorageCleaner/AutoRefreshToggle.tsx (100%) rename {pages => src/pages}/StorageCleaner/CleaningResult.tsx (100%) rename {pages => src/pages}/StorageCleaner/ErrorDisplay.tsx (100%) rename {pages => src/pages}/StorageCleaner/OptionItem.tsx (100%) rename {pages => src/pages}/StorageCleaner/StorageCleanerConfirm.tsx (100%) rename {pages => src/pages}/StorageCleaner/StorageOptionsGrid.tsx (100%) rename {pages => src/pages}/StorageCleaner/index.tsx (100%) rename {pages => src/pages}/StorageCleaner/useStorageCleaner.ts (100%) rename {pages => src/pages}/TextStatistics/index.tsx (100%) rename {pages => src/pages}/Timestamp/LiveClock.tsx (100%) rename {pages => src/pages}/Timestamp/ResultView.tsx (100%) rename {pages => src/pages}/Timestamp/constants.ts (100%) rename {pages => src/pages}/Timestamp/index.tsx (100%) rename {pages => src/pages}/Timestamp/useTimestampConverter.ts (100%) rename {providers => src/providers}/AppRoot.tsx (100%) rename {providers => src/providers}/RouterProvider.tsx (98%) rename {providers => src/providers}/ThemeModeProvider.tsx (100%) rename {providers => src/providers}/__tests__/RouterProvider.test.tsx (100%) rename {types => src/types}/qrious.d.ts (100%) rename {types => src/types}/storage.d.ts (100%) rename {utils => src/utils}/__tests__/base64Converter.test.ts (100%) rename {utils => src/utils}/__tests__/chromeStorage.test.ts (100%) rename {utils => src/utils}/__tests__/chromeTabs.test.ts (100%) rename {utils => src/utils}/__tests__/clipboard.test.ts (100%) rename {utils => src/utils}/__tests__/contextMenu.test.ts (100%) rename {utils => src/utils}/__tests__/dayjs.test.ts (100%) rename {utils => src/utils}/__tests__/diffEngine.test.ts (100%) rename {utils => src/utils}/__tests__/format.test.ts (100%) rename {utils => src/utils}/__tests__/htmlToMarkdown.test.ts (100%) rename {utils => src/utils}/__tests__/jsonFormatter.test.ts (100%) rename {utils => src/utils}/__tests__/jsonMinify.test.ts (100%) rename {utils => src/utils}/__tests__/jsonToToml.test.ts (100%) rename {utils => src/utils}/__tests__/jsonToYaml.test.ts (100%) rename {utils => src/utils}/__tests__/jwt.test.ts (100%) rename {utils => src/utils}/__tests__/markdownToHtml.test.ts (100%) rename {utils => src/utils}/__tests__/messages.test.ts (100%) rename {utils => src/utils}/__tests__/qrCodeParser.test.ts (100%) rename {utils => src/utils}/__tests__/storageCleaner.test.ts (100%) rename {utils => src/utils}/__tests__/textStatistics.test.ts (100%) rename {utils => src/utils}/__tests__/useContextMenuData.test.ts (100%) rename {utils => src/utils}/__tests__/useStorageState.test.ts (100%) rename {utils => src/utils}/base64Converter.ts (100%) rename {utils => src/utils}/chromeI18n.ts (100%) rename {utils => src/utils}/chromeStorage.ts (100%) rename {utils => src/utils}/chromeTabs.ts (100%) rename {utils => src/utils}/clipboard.ts (100%) rename {utils => src/utils}/contextMenu.ts (100%) rename {utils => src/utils}/dayjs.ts (100%) rename {utils => src/utils}/format.ts (100%) rename {utils => src/utils}/htmlToMarkdown.ts (100%) rename {utils => src/utils}/jsonFormatter.ts (100%) rename {utils => src/utils}/jsonToToml.ts (100%) rename {utils => src/utils}/jsonToYaml.ts (100%) rename {utils => src/utils}/jwt.ts (100%) rename {utils => src/utils}/markdownToHtml.ts (100%) rename {utils => src/utils}/messages.ts (100%) rename {utils => src/utils}/qrCodeParser.ts (100%) rename {utils => src/utils}/storageCleaner.ts (100%) rename {utils => src/utils}/textStatistics.ts (100%) rename {utils => src/utils}/useContextMenuData.ts (100%) rename {utils => src/utils}/useDebounce.ts (100%) rename {utils => src/utils}/useStorageState.ts (100%) delete mode 100644 types/README.md delete mode 100644 utils/README.md diff --git a/.github/CODING_STANDARDS.md b/.github/CODING_STANDARDS.md index 8e36816..46c6bee 100644 --- a/.github/CODING_STANDARDS.md +++ b/.github/CODING_STANDARDS.md @@ -79,12 +79,12 @@ export function isSupportedImageType(mimeType: string): boolean { | 场景 | 导出方式 | 示例 | | ----------- | ------------------------------------------------ | --------------------------------- | -| 页面组件 | `export default function ComponentName()` | `pages/Timestamp/index.tsx` | +| 页面组件 | `export default function ComponentName()` | `src/pages/Timestamp/index.tsx` | | 业务组件 | `const X = React.memo(...)` + `export default X` | `LiveClock.tsx`, `ResultView.tsx` | -| UI 原子组件 | `React.forwardRef(...)` + `export { X }` | `components/ui/button.tsx` | -| 工具函数 | `export function xxx()` | `utils/clipboard.ts` | -| 自定义 Hook | `export function useXxx()` | `utils/useStorageState.ts` | -| 类型/接口 | `export interface` / `export type` | `types/storage.d.ts` | +| UI 原子组件 | `React.forwardRef(...)` + `export { X }` | `src/components/ui/button.tsx` | +| 工具函数 | `export function xxx()` | `src/utils/clipboard.ts` | +| 自定义 Hook | `export function useXxx()` | `src/utils/useStorageState.ts` | +| 类型/接口 | `export interface` / `export type` | `src/types/storage.d.ts` | ```typescript // ✅ 页面组件 — default export @@ -473,7 +473,7 @@ import ErrorBoundary from '@/components/ErrorBoundary'; | 类型 | 命名模式 | 示例 | | ----------- | -------------------------- | -------------------------------------------------------- | | 页面目录 | PascalCase | `Timestamp/`, `Base64Converter/`, `StorageCleaner/` | -| 页面入口 | `index.tsx` | `pages/Timestamp/index.tsx` | +| 页面入口 | `index.tsx` | `src/pages/Timestamp/index.tsx` | | 组件文件 | PascalCase `.tsx` | `TopBar.tsx`, `LiveClock.tsx`, `ResultView.tsx` | | 自定义 Hook | camelCase `.ts` | `useTimestampConverter.ts`, `useStorageCleaner.ts` | | 工具函数 | camelCase `.ts` | `chromeStorage.ts`, `base64Converter.ts`, `clipboard.ts` | @@ -527,12 +527,12 @@ const handleClean = useCallback(async () => { ... }, []); 测试文件放在源代码同级的 `__tests__/` 目录下: ``` -utils/__tests__/jwt.test.ts -utils/__tests__/base64Converter.test.ts -utils/__tests__/useStorageState.test.ts -components/__tests__/SwitchButtonGroup.test.tsx -components/__tests__/ErrorBoundary.test.tsx -pages/Timestamp/__tests__/index.test.tsx +src/utils/__tests__/jwt.test.ts +src/utils/__tests__/base64Converter.test.ts +src/utils/__tests__/useStorageState.test.ts +src/components/__tests__/SwitchButtonGroup.test.tsx +src/components/__tests__/ErrorBoundary.test.tsx +src/pages/Timestamp/__tests__/index.test.tsx ``` ### 7.2 describe / it 命名 @@ -653,16 +653,16 @@ export function useTimestampConverter(): UseTimestampConverterReturn { ... } ### 8.2 Hook 存放位置 -- **全局通用 Hook**:放在 `utils/` 目录下 +- **全局通用 Hook**:放在 `src/utils/` 目录下 - **页面专属 Hook**:与页面组件同目录 ``` -utils/useStorageState.ts — Chrome Storage 状态持久化 -utils/useLazyTranslation.ts — i18n 懒加载 -utils/useContextMenuData.ts — 右键菜单数据 -utils/useDebounce.ts — 防抖 -pages/Timestamp/useTimestampConverter.ts — 页面级 Hook -pages/StorageCleaner/useStorageCleaner.ts — 页面级 Hook +src/utils/useStorageState.ts — Chrome Storage 状态持久化 +src/utils/useLazyTranslation.ts — i18n 懒加载 +src/utils/useContextMenuData.ts — 右键菜单数据 +src/utils/useDebounce.ts — 防抖 +src/pages/Timestamp/useTimestampConverter.ts — 页面级 Hook +src/pages/StorageCleaner/useStorageCleaner.ts — 页面级 Hook ``` --- @@ -767,7 +767,7 @@ const [themeMode, setThemeMode, isInitialized] = useStorageState( ### 11.1 页面组件结构 ``` -pages/FeatureName/ +src/pages/FeatureName/ ├── index.tsx # 页面 UI(纯展示,使用 shadcn/ui 组件) ├── useFeatureName.ts # 业务逻辑 Hook(状态管理 + 转换逻辑) ├── constants.ts # 常量定义(可选) @@ -779,20 +779,19 @@ pages/FeatureName/ ### 11.2 目录职责 -| 目录 | 职责 | -| ---------------- | ------------------------------------------------------------ | -| `config/` | 应用配置(功能定义、路由映射) | -| `entrypoints/` | 扩展入口点(popup、options、sidepanel、background、content) | -| `pages/` | 功能页面组件(懒加载) | -| `components/` | 可复用 UI 组件 | -| `components/ui/` | shadcn/ui 基础组件(button、dialog、select 等) | -| `providers/` | React Context(Router、Theme 等) | -| `hooks/` | 自定义 React Hooks | -| `utils/` | 工具函数与服务抽象 | -| `types/` | TypeScript 类型声明 | -| `lib/` | 通用工具函数(cn、utils) | -| `i18n/` | 国际化资源 | -| `public/` | 静态资源 | +| 目录 | 职责 | +| -------------------- | ------------------------------------------------------------ | +| `src/config/` | 应用配置(功能定义、路由映射) | +| `src/entrypoints/` | 扩展入口点(popup、options、sidepanel、background、content) | +| `src/pages/` | 功能页面组件(懒加载) | +| `src/components/` | 可复用 UI 组件 | +| `src/components/ui/` | shadcn/ui 基础组件(button、dialog、select 等) | +| `src/providers/` | React Context(Router、Theme 等) | +| `src/hooks/` | 自定义 React Hooks | +| `src/utils/` | 工具函数与服务抽象 | +| `src/types/` | TypeScript 类型声明 | +| `src/lib/` | 通用工具函数(cn、utils) | +| `public/` | 静态资源 | --- diff --git a/AGENTS.md b/AGENTS.md index bdf1672..568c80b 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -43,16 +43,18 @@ Pre-commit hook(`.husky/pre-commit` 调用 `lint-staged`,任一步骤返回 ## 项目结构 ``` -config/features.tsx # 功能定义(路由 + 元数据的单一事实来源) -entrypoints/ # 扩展入口点 (popup/, options/, sidepanel/, background.ts, content.ts) -pages/ # 功能页面组件 (懒加载) -components/ # 可复用 UI 组件 -components/ui/ # shadcn/ui 基础组件 (button, dialog, select 等) -providers/ # React Context (Router, Theme 等) -hooks/ # 自定义 React Hooks -utils/ # 工具函数与服务抽象 -types/ # TypeScript 类型声明 -i18n/locales/{zh,en}/ # 国际化资源 (common.json, features.json 及各功能独立 JSON) +src/ # 源代码根目录 + config/features.tsx # 功能定义(路由 + 元数据的单一事实来源) + entrypoints/ # 扩展入口点 (popup/, options/, sidepanel/, background.ts, content.ts) + pages/ # 功能页面组件 (懒加载) + components/ # 可复用 UI 组件 + components/ui/ # shadcn/ui 基础组件 (button, dialog, select 等) + providers/ # React Context (Router, Theme 等) + hooks/ # 自定义 React Hooks + utils/ # 工具函数与服务抽象 + types/ # TypeScript 类型声明 + lib/ # 通用工具函数(cn、utils) +public/ # 静态资源(图标、_locales 等) ``` ### 页面组件模式 @@ -60,7 +62,7 @@ i18n/locales/{zh,en}/ # 国际化资源 (common.json, features.json 及各功 典型功能页面遵循 **UI + Hook 分离** 模式: ``` -pages/FeatureName/ +src/pages/FeatureName/ ├── index.tsx # 页面 UI(纯展示,使用 shadcn/ui 组件) ├── useFeatureName.ts # 业务逻辑 Hook(状态管理 + 转换逻辑) └── constants.ts # 常量定义 @@ -72,15 +74,15 @@ pages/FeatureName/ ## 关键架构决策 -**路由**: 不使用 React Router。通过 `config/features.tsx` 的 `FEATURES` 数组管理,`RouterProvider` 根据 `PageType` +**路由**: 不使用 React Router。通过 `src/config/features.tsx` 的 `FEATURES` 数组管理,`RouterProvider` 根据 `PageType` 渲染对应组件。支持三种渲染模式:popup(弹窗)、sidepanel(侧边栏)和 browser-tab(浏览器新标签页,通过 `open_in_tab` 打开)。 每种模式有独立的路由和可见页面配置(`app/popupRoute`、`app/sidepanelRoute`、`app/tabRoute` 等)。 -**存储**: 所有 Chrome Storage 键必须在 `types/storage.d.ts` 的 `StorageSchema` 中定义,键名使用 kebab-case 格式(如 `app/currentRoute`)。 -使用 `utils/chromeStorage.ts` 及其 Hook。Router 同时使用 `chrome.storage.local` 和 `localStorage` 做快照以消除首屏闪烁。 -修改 StorageSchema 时,必须在 `utils/chromeStorage.ts` 添加版本迁移函数,并在测试中覆盖迁移场景。 +**存储**: 所有 Chrome Storage 键必须在 `src/types/storage.d.ts` 的 `StorageSchema` 中定义,键名使用 kebab-case 格式(如 `app/currentRoute`)。 +使用 `src/utils/chromeStorage.ts` 及其 Hook。Router 同时使用 `chrome.storage.local` 和 `localStorage` 做快照以消除首屏闪烁。 +修改 StorageSchema 时,必须在 `src/utils/chromeStorage.ts` 添加版本迁移函数,并在测试中覆盖迁移场景。 -**通信**: 使用 `@webext-core/messaging`,协议定义在 `utils/messages.ts`。 +**通信**: 使用 `@webext-core/messaging`,协议定义在 `src/utils/messages.ts`。 **路径别名**: `@/` 映射到项目根目录 (已在 tsconfig 和 vitest.config 中配置)。 @@ -116,9 +118,9 @@ pages/FeatureName/ ## 新功能开发清单 -1. 在 `types/storage.d.ts` 添加 `PageType` 联合类型 -2. 在 `config/features.tsx` 的 `FEATURES` 数组添加配置(指定 key、翻译键、图标、三种渲染模式的组件) -3. 在 `pages/` 创建页面组件 (懒加载): +1. 在 `src/types/storage.d.ts` 添加 `PageType` 联合类型 +2. 在 `src/config/features.tsx` 的 `FEATURES` 数组添加配置(指定 key、翻译键、图标、三种渲染模式的组件) +3. 在 `src/pages/` 创建页面组件 (懒加载): - `index.tsx` — UI 组件,使用 `useLazyTranslation` 获取翻译 - `useFeatureName.ts` — 业务逻辑 Hook - `constants.ts` — 常量(可选) @@ -131,7 +133,7 @@ pages/FeatureName/ - 禁止使用 `any` (测试文件除外) - 未使用变量/参数: 使用 `_` 前缀 (如 `_unused`) - 样式: 使用 Tailwind CSS + shadcn/ui (通过 `className` 和 `cn()` 工具) -- UI 组件: 优先使用 `components/ui/` 下的 shadcn/ui 组件 (button, dialog, select 等) +- UI 组件: 优先使用 `src/components/ui/` 下的 shadcn/ui 组件 (button, dialog, select 等) - 图标: 使用 `lucide-react` 图标库 - 格式: Prettier (`.prettierrc`: 100 字符宽, 单引号, 尾逗号 all, LF 换行) - ESLint 使用 `typescript-eslint` 的 `projectService: true`(无需手动维护 project 路径) diff --git a/README.md b/README.md index 4c56054..8ec821e 100644 --- a/README.md +++ b/README.md @@ -84,25 +84,25 @@ ## 项目结构 ```text -├── components/ # 可复用 React 组件 -├── config/ # 应用配置 -│ └── features.tsx # 功能定义与路由映射 -├── entrypoints/ # 扩展程序入口点 -│ ├── popup/ # 点击图标弹出的主界面 -│ ├── options/ # 扩展程序设置页面 -│ ├── sidepanel/ # 浏览器侧边栏集成 -│ ├── background.ts # 后台 Service Worker -│ └── content.ts # 网页注入脚本 -├── pages/ # 各功能模块的页面组件 -├── providers/ # 全局状态提供者 (Router, Theme 等) -├── hooks/ # 自定义 React Hooks -├── utils/ # 工具函数与服务抽象 -├── types/ # TypeScript 类型声明 -├── lib/ # 通用工具函数 (cn, utils 等) -├── i18n/ # 国际化资源 -├── public/ # 静态资源 (图标、manifest 资源等) -├── wxt.config.ts # WXT 框架核心配置 -└── package.json # 项目元数据与依赖管理 +├── src/ # 源代码根目录 +│ ├── components/ # 可复用 React 组件 +│ ├── config/ # 应用配置 +│ │ └── features.tsx # 功能定义与路由映射 +│ ├── entrypoints/ # 扩展程序入口点 +│ │ ├── popup/ # 点击图标弹出的主界面 +│ │ ├── options/ # 扩展程序设置页面 +│ │ ├── sidepanel/ # 浏览器侧边栏集成 +│ │ ├── background.ts # 后台 Service Worker +│ │ └── content.ts # 网页注入脚本 +│ ├── pages/ # 各功能模块的页面组件 +│ ├── providers/ # 全局状态提供者 (Router, Theme 等) +│ ├── hooks/ # 自定义 React Hooks +│ ├── utils/ # 工具函数与服务抽象 +│ ├── types/ # TypeScript 类型声明 +│ └── lib/ # 通用工具函数 (cn, utils 等) +├── public/ # 静态资源 (图标、manifest 资源等) +├── wxt.config.ts # WXT 框架核心配置 +└── package.json # 项目元数据与依赖管理 ``` ## 开发与部署 diff --git a/components/README.md b/components/README.md deleted file mode 100644 index abd1286..0000000 --- a/components/README.md +++ /dev/null @@ -1,27 +0,0 @@ -# components/ - -通用业务组件目录,存放跨页面复用的 UI 组件,与具体工具页面解耦。 - -## 组件列表 - -| 组件 | 用途 | -| ----------------------- | ------------------------------------------------------------------------------ | -| `TopBar.tsx` | 顶部导航栏,集成搜索(含历史记录)、主题切换、语言切换、返回导航 | -| `RouterContainer.tsx` | 路由容器,根据当前路由动态渲染对应页面组件,集成错误边界和骨架屏 | -| `SwitchButtonGroup.tsx` | 通用切换按钮组,支持 `small/medium/large` 三种尺寸,用于页面子模式切换 | -| `TextInputArea.tsx` | 增强文本输入区域,支持校验规则、工具栏操作、字符计数、清空 | -| `CopyButton.tsx` | 一键复制按钮,支持复制成功状态动画,封装 `copyTextToClipboard` 和 `toast` 反馈 | -| `ImageUploader.tsx` | 图片上传组件,支持拖拽上传、文件选择和预览 | -| `QrCodePreview.tsx` | 二维码预览组件,展示生成的二维码图片,提供复制和下载操作 | -| `DecodeResultPaper.tsx` | Base64 解码结果展示面板,显示 MIME 类型、文件大小、文件名输入和下载按钮 | -| `GlobalSnackbar.tsx` | 全局消息提示组件 + Context Provider,支持受控/Hook/全局单例三种使用方式 | -| `ErrorBoundary.tsx` | 全局错误边界(类组件),捕获子组件树 JS 错误并展示友好错误页面 | -| `PageErrorBoundary.tsx` | 页面级错误边界,适配 shadcn 暗黑模式,支持 `resetKey` 自动恢复 | -| `PageSkeleton.tsx` | 页面骨架屏,提供 `dashboard` 和 `tool` 两种变体,用于 Suspense fallback | - -## 使用约定 - -- 优先使用 `components/ui/` 下的 shadcn/ui 基础组件 -- 组件使用 `cn()` 合并 Tailwind 类名,支持 `className` 透传 -- 需要 memo 优化的组件使用 `React.memo` + `displayName` -- 需要 ref 转发的组件使用 `React.forwardRef` + `displayName` diff --git a/components/ui/README.md b/components/ui/README.md deleted file mode 100644 index 72420ba..0000000 --- a/components/ui/README.md +++ /dev/null @@ -1,40 +0,0 @@ -# components/ui/ - -shadcn/ui 基础原子组件目录,基于 Radix UI 原语 + Tailwind CSS 实现。 - -## 组件列表 - -| 组件 | 用途 | -| -------------- | -------------------------------------------------------------------------------------------------- | -| `button.tsx` | 按钮组件,支持 `default/destructive/outline/secondary/ghost/link` 变体和 `default/sm/lg/icon` 尺寸 | -| `input.tsx` | 标准输入框,统一的 ring/focus 样式 | -| `select.tsx` | 下拉选择组件,包含 Trigger、Content、Item 等子组件 | -| `dialog.tsx` | 对话框组件,包含 Overlay、Content、Header、Footer、Title、Description | -| `checkbox.tsx` | 复选框组件 | -| `label.tsx` | 标签组件 | -| `switch.tsx` | 开关组件 | -| `badge.tsx` | 徽章组件,支持 `default/secondary/destructive/outline` 变体 | - -## 使用方式 - -```tsx -import { Button } from '@/components/ui/button'; -import { Input } from '@/components/ui/input'; -import { - Select, - SelectContent, - SelectItem, - SelectTrigger, - SelectValue, -} from '@/components/ui/select'; -``` - -## 添加新组件 - -使用 shadcn/ui CLI 添加新组件: - -```bash -npx shadcn-ui@latest add -``` - -组件配置在项目根目录的 `components.json` 中定义。 diff --git a/config/README.md b/config/README.md deleted file mode 100644 index ced4dcb..0000000 --- a/config/README.md +++ /dev/null @@ -1,44 +0,0 @@ -# config/ - -应用级配置目录,存放功能特性的注册中心。 - -## 文件说明 - -| 文件 | 用途 | -| -------------- | ---------------------------------------- | -| `features.tsx` | 核心配置文件,定义所有工具功能的注册信息 | - -## features.tsx - -`FEATURES` 数组是路由和功能元数据的**单一事实来源**,每个功能定义包含: - -- `key`:页面类型标识(`PageType`) -- `labelKey` / `descriptionKey`:i18n 翻译键 -- `themeColorKey`:主题色(`primary/success/warning/error/secondary/info`) -- `icon`:lucide-react 图标组件 -- `defaultVisible`:默认是否可见 -- `components`:三种渲染模式的懒加载组件(`popup`、`sidepanel`、`tab`) - -## 已注册功能(11 个) - -| key | 图标 | 说明 | -| -------------------- | ----------------- | ----------------- | -| `dashboard` | — | 仪表盘首页 | -| `timestamp` | Clock | 时间戳转换工具 | -| `storageCleaner` | Database | 存储清理工具 | -| `qrCode` | QrCode | 二维码工具 | -| `textStatistics` | FileText | 文本统计工具 | -| `jwt` | Key | JWT 解析工具 | -| `jsonDiff` | GitCompareArrows | JSON 差异比较工具 | -| `base64Converter` | ArrowLeftRight | Base64 转换器 | -| `markdownToHtml` | Code | Markdown 转 HTML | -| `htmlToMarkdown` | File | HTML 转 Markdown | -| `rightClickRestorer` | MousePointerClick | 右键菜单恢复工具 | - -## 导出函数 - -- `getFeatureByKey(key)` — 根据 key 获取功能配置 -- `getDefaultVisibleFeatureKeys()` — 获取默认可见的功能 key 列表 -- `getAllFeatureKeys()` — 获取所有功能 key 列表 -- `getDefaultPageOrder()` — 获取默认页面排序(不含 dashboard) -- `getEntryPointType()` — 判断当前入口类型(popup/sidepanel/tab) diff --git a/entrypoints/README.md b/entrypoints/README.md deleted file mode 100644 index 47982f0..0000000 --- a/entrypoints/README.md +++ /dev/null @@ -1,51 +0,0 @@ -# entrypoints/ - -WXT 框架要求的扩展生命周期入口点,对应 Chrome Extension 的各个上下文。 - -## 入口文件 - -| 文件 | 用途 | -| ------------------------------- | --------------------------------------------------------------------------------------------- | -| `background.ts` | Service Worker 入口:注册右键菜单、监听菜单点击、处理消息通信、管理侧边栏状态、注入主环境脚本 | -| `content.ts` | Content Script 入口:注入所有页面(``),在 `document_end` 时初始化消息处理器 | -| `rightClickRestorer.content.ts` | 专用 Content Script:处理右键菜单恢复功能,注入浮动状态徽章 | - -## 子目录 - -### popup/ - -Popup 弹窗页面(点击扩展图标弹出)。 - -| 文件 | 用途 | -| ------------ | ------------------------------------------------------------------------------ | -| `index.html` | HTML 入口 | -| `main.tsx` | React 挂载点 | -| `App.tsx` | 根组件,组装 `RouterProvider` + `TopBar` + `ErrorBoundary` + `RouterContainer` | - -### sidepanel/ - -侧边栏页面,结构与 popup 类似,额外通知 background 侧边栏开启/关闭状态。 - -### options/ - -设置页面,支持: - -- 拖拽排序功能顺序(`@dnd-kit`) -- 功能可见性管理(显示/隐藏) -- Popup/Sidepanel/Tab 三种模式独立配置 - -### content/ - -Content Script 内部分模块: - -| 文件 | 用途 | -| ----------------------- | ------------------------------------------------------------------- | -| `messageHandler.ts` | 消息处理器初始化入口 | -| `contextMenuHandler.ts` | 右键菜单点击事件处理,执行时间戳转换/文本统计并通过 UI Popover 展示 | -| `uiPopover.ts` | 在页面中注入浮层 Popover UI,展示右键菜单操作结果 | - -## 架构说明 - -- `background.ts` 是扩展的核心协调者,处理跨上下文通信 -- `content.ts` 注入到所有页面,负责接收和处理来自 background 的消息 -- `popup/`、`sidepanel/`、`options/` 共享同一套页面组件(来自 `pages/`),通过 `RouterProvider` 的不同配置实现独立路由 diff --git a/eslint.config.ts b/eslint.config.ts index db7eb21..fd0db65 100644 --- a/eslint.config.ts +++ b/eslint.config.ts @@ -28,14 +28,7 @@ export default tseslint.config( // 4. 核心业务全受控大管线(Hooks, Entrypoints, Components 统一护航) { - files: [ - 'hooks/**/*.{ts,tsx}', - 'entrypoints/**/*.{ts,tsx}', - 'pages/**/*.{ts,tsx}', - 'utils/**/*.{ts,tsx}', - 'components/**/*.{ts,tsx}', - 'services/**/*.{ts,tsx}', - ], + files: ['src/**/*.{ts,tsx}'], ignores: ['**/__tests__/**', '**/*.test.{ts,tsx}', '**/*.spec.{ts,tsx}'], languageOptions: { diff --git a/lib/README.md b/lib/README.md deleted file mode 100644 index 4616805..0000000 --- a/lib/README.md +++ /dev/null @@ -1,26 +0,0 @@ -# lib/ - -通用库工具目录,存放与业务无关的底层工具函数。 - -## 文件说明 - -| 文件 | 用途 | -| ---------- | ------------------------------------ | -| `utils.ts` | `cn()` 函数 — shadcn/ui 标准工具函数 | - -## cn() - -组合 `clsx` + `tailwind-merge`,用于合并和去重 Tailwind CSS 类名: - -```typescript -import { cn } from '@/lib/utils'; - -// 条件类名 + 合并外部 className -
-``` - -所有需要动态合并 Tailwind 类名的场景都应使用 `cn()`,而非手动拼接字符串。 diff --git a/pages/README.md b/pages/README.md deleted file mode 100644 index c3a15a2..0000000 --- a/pages/README.md +++ /dev/null @@ -1,140 +0,0 @@ -# pages/ - -功能页面组件目录,每个子目录对应一个工具页面。 - -## 目录结构约定 - -典型页面遵循 **UI + Hook 分离** 模式: - -``` -pages/FeatureName/ -├── index.tsx # 页面 UI(纯展示,使用 shadcn/ui 组件) -├── useFeatureName.ts # 业务逻辑 Hook(状态管理 + 转换逻辑) -├── constants.ts # 常量定义(可选) -├── SubComponent.tsx # 子组件(可选) -└── __tests__/ # 测试文件 - └── index.test.tsx -``` - -## 页面列表 - -### Dashboard/ - -仪表盘首页,以卡片网格展示所有可见工具,支持点击导航。 - -| 文件 | 用途 | -| -------------- | -------------------------------------------- | -| `index.tsx` | 页面组件,渲染工具卡片网格 | -| `ToolCard.tsx` | 工具卡片组件,展示图标、标题、描述和实时数据 | - -### Timestamp/ - -时间戳转换工具,支持秒/毫秒级互转、多时区选择、实时时钟。 - -| 文件 | 用途 | -| -------------------------- | ----------------------------------------------------------------- | -| `index.tsx` | 页面 UI | -| `useTimestampConverter.ts` | 业务逻辑 Hook,包含转换模式、输入、单位、时区状态和响应式计算管线 | -| `LiveClock.tsx` | 实时时钟子组件,`React.memo` 优化 | -| `ResultView.tsx` | 转换结果展示子组件 | -| `constants.ts` | 时区列表等常量 | - -### StorageCleaner/ - -浏览器存储清理工具,支持 Cookie/LocalStorage/SessionStorage/IndexedDB/Cache/SW 清理。 - -| 文件 | 用途 | -| --------------------------- | -------------- | -| `index.tsx` | 页面 UI | -| `useStorageCleaner.ts` | 业务逻辑 Hook | -| `StorageOptionsGrid.tsx` | 清理选项网格 | -| `StorageCleanerConfirm.tsx` | 清理确认对话框 | -| `AutoRefreshToggle.tsx` | 自动刷新开关 | -| `ErrorDisplay.tsx` | 错误展示组件 | -| `CleaningResult.tsx` | 清理结果展示 | -| `OptionItem.tsx` | 单个选项组件 | - -### QrCode/ - -二维码工具,支持生成(URL→QR)和解析(QR→URL)。 - -| 文件/目录 | 用途 | -| ------------- | ---------------- | -| `index.tsx` | 页面 UI | -| `types.ts` | 类型定义 | -| `contexts/` | Context Provider | -| `hooks/` | 业务逻辑 Hooks | -| `components/` | 子组件 | - -### TextStatistics/ - -文本统计工具,实时计算字符数、单词数、行数、字节大小。 - -| 文件 | 用途 | -| ----------- | --------------------------------------------- | -| `index.tsx` | 页面组件,集成 `TextInputArea` 和统计结果展示 | - -### Jwt/ - -JWT 解析工具,解码 Header/Payload/Signature。 - -| 文件/目录 | 用途 | -| ------------- | ---------------- | -| `index.tsx` | 页面 UI | -| `types.ts` | 类型定义 | -| `contexts/` | Context Provider | -| `hooks/` | 业务逻辑 Hooks | -| `components/` | 子组件 | - -### JsonTools/ - -JSON 工具集:差异比较、格式化、YAML/TOML/Minify 转换。 - -| 文件 | 用途 | -| ------------------------ | ---------------------------- | -| `index.tsx` | 页面入口,子模式切换 | -| `types.ts` | 类型定义 | -| `diffEngine.ts` | 差异比较引擎 | -| `JsonDiffInput.tsx` | JSON 输入组件 | -| `DiffResult.tsx` | 差异结果展示 | -| `DiffNavigator.tsx` | 差异导航器 | -| `JsonFormatSection.tsx` | 格式化区域 | -| `JsonConvertSection.tsx` | 转换区域(YAML/TOML/Minify) | -| `JsonTree.tsx` | JSON 树形展示 | - -### Base64Converter/ - -Base64 编解码工具,支持文本/文件/图片三种模式。 - -| 文件 | 用途 | -| ---------------------------- | --------------------- | -| `index.tsx` | 页面入口,子模式切换 | -| `useBase64Converter.ts` | 业务逻辑 Hook | -| `TextMode.tsx` | 文本模式 | -| `Base64ConverterSection.tsx` | 文件/图片通用转换区域 | - -### MarkdownToHtml/ - -Markdown 转 HTML 工具,支持分栏/预览/源码三种视图模式。 - -### HtmlToMarkdown/ - -HTML 转 Markdown 工具,支持分栏/预览/Markdown 三种视图模式。 - -### RightClickRestorer/ - -右键菜单恢复工具,解除网站对右键的限制。 - -| 文件 | 用途 | -| -------------------------- | ------------- | -| `index.tsx` | 页面 UI | -| `useRightClickRestorer.ts` | 业务逻辑 Hook | - -## 新增页面 - -1. 在 `types/storage.d.ts` 添加 `PageType` 联合类型成员 -2. 在 `config/features.tsx` 的 `FEATURES` 数组添加配置 -3. 在 `pages/` 创建页面目录(遵循上述结构) -4. 在 `i18n/locales/{zh,en}/features.json` 添加翻译 -5. 如需新权限,更新 `wxt.config.ts` -6. 添加对应的单元测试 diff --git a/providers/README.md b/providers/README.md deleted file mode 100644 index 22d2209..0000000 --- a/providers/README.md +++ /dev/null @@ -1,63 +0,0 @@ -# providers/ - -React Context Provider 目录,为整个应用提供全局共享状态。 - -## 文件说明 - -| 文件 | 用途 | -| ----------------------- | ---------------------- | -| `AppRoot.tsx` | 应用根 Provider 组合器 | -| `RouterProvider.tsx` | 路由 Context Provider | -| `ThemeModeProvider.tsx` | 主题模式 Provider | - -## AppRoot.tsx - -应用根 Provider 组合器,按顺序包裹: - -``` -React.StrictMode - └── ThemeModeProvider - └── RouterProvider - └── children -``` - -## RouterProvider.tsx - -路由 Context Provider,管理: - -- **当前页面**:`currentPage`(`PageType`) -- **可见页面列表**:`visiblePages` -- **页面排序**:`pageOrder` -- **加载状态**:`isLoaded` - -核心特性: - -- 通过 `chrome.storage` 持久化路由状态 -- 使用 `localStorage` 快照实现首屏 0 闪烁 -- 支持 popup/sidepanel/tab 三种入口的独立路由同步(通过 `syncKey`、`visiblePagesKey`、`pageOrderKey` 配置) -- 处理右键菜单待处理数据的路由跳转 -- 监听 `chrome.storage.onChanged` 实现跨端同步 - -导出: - -- `RouterProvider` 组件 -- `useRouter()` Hook — 获取 `currentPage`、`visiblePages`、`pageOrder`、`navigateTo`、`goBack` 等 - -## ThemeModeProvider.tsx - -主题模式 Provider,管理: - -- **主题模式**:`light` / `dark` / `system` -- **解析后的主题**:`resolvedTheme`(`light` / `dark`) - -核心特性: - -- 使用 `localStorage` 快照实现首屏 0 闪烁 -- 监听系统级暗色模式变化(`matchMedia`) -- 通过 `chrome.storage` 跨端同步主题偏好 -- 自动在 `document.documentElement` 上切换 `dark` class - -导出: - -- `ThemeModeProvider` 组件 -- `useThemeMode()` Hook — 获取 `themeMode`、`resolvedTheme`、`setThemeMode` diff --git a/public/README.md b/public/README.md deleted file mode 100644 index b7b3f2f..0000000 --- a/public/README.md +++ /dev/null @@ -1,20 +0,0 @@ -# public/ - -静态资源目录,存放无需构建处理的文件,会被直接复制到输出目录。 - -## 文件说明 - -| 文件/目录 | 用途 | -| -------------- | -------------------------------- | -| `icon/` | 扩展图标,提供多种尺寸 | -| `icon/16.png` | 16×16 图标(工具栏) | -| `icon/32.png` | 32×32 图标 | -| `icon/48.png` | 48×48 图标(扩展管理页) | -| `icon/96.png` | 96×96 图标 | -| `icon/128.png` | 128×128 图标(Chrome Web Store) | -| `wxt.svg` | WXT 框架标志 SVG 图标 | - -## 注意事项 - -- 修改图标后需同步更新 `wxt.config.ts` 中的 manifest 配置 -- 图标格式推荐使用 PNG,确保透明背景 diff --git a/src/README.md b/src/README.md deleted file mode 100644 index 5bb0402..0000000 --- a/src/README.md +++ /dev/null @@ -1,24 +0,0 @@ -# src/ - -源码目录,存放全局样式定义。 - -## 文件说明 - -| 文件 | 用途 | -| ----------- | ----------------- | -| `index.css` | 全局 CSS 入口文件 | - -## index.css - -全局样式入口,包含: - -- **Tailwind 指令**:`@tailwind base/components/utilities` -- **shadcn/ui CSS 变量**:定义 `--background`、`--primary`、`--destructive`、`--card`、`--muted`、`--accent`、`--border`、`--ring` 等语义化颜色变量 -- **主题色值**:`:root`(亮色)和 `.dark`(暗色)两套完整的颜色定义 -- **圆角变量**:`--radius` 定义全局圆角大小 - -## 修改注意事项 - -- 修改 CSS 变量会影响所有使用 shadcn/ui 语义化 token 的组件 -- 新增颜色变量需同时在 `:root` 和 `.dark` 中定义 -- 避免在组件中硬编码颜色值,应使用 CSS 变量或 Tailwind 的语义化类名 diff --git a/assets/react.svg b/src/assets/react.svg similarity index 100% rename from assets/react.svg rename to src/assets/react.svg diff --git a/components/CopyButton.tsx b/src/components/CopyButton.tsx similarity index 100% rename from components/CopyButton.tsx rename to src/components/CopyButton.tsx diff --git a/components/DecodeResultPaper.tsx b/src/components/DecodeResultPaper.tsx similarity index 100% rename from components/DecodeResultPaper.tsx rename to src/components/DecodeResultPaper.tsx diff --git a/components/ErrorBoundary.tsx b/src/components/ErrorBoundary.tsx similarity index 100% rename from components/ErrorBoundary.tsx rename to src/components/ErrorBoundary.tsx diff --git a/components/GlobalSnackbar.tsx b/src/components/GlobalSnackbar.tsx similarity index 100% rename from components/GlobalSnackbar.tsx rename to src/components/GlobalSnackbar.tsx diff --git a/components/ImageUploader.tsx b/src/components/ImageUploader.tsx similarity index 100% rename from components/ImageUploader.tsx rename to src/components/ImageUploader.tsx diff --git a/components/PageErrorBoundary.tsx b/src/components/PageErrorBoundary.tsx similarity index 100% rename from components/PageErrorBoundary.tsx rename to src/components/PageErrorBoundary.tsx diff --git a/components/PageSkeleton.tsx b/src/components/PageSkeleton.tsx similarity index 100% rename from components/PageSkeleton.tsx rename to src/components/PageSkeleton.tsx diff --git a/components/QrCodePreview.tsx b/src/components/QrCodePreview.tsx similarity index 100% rename from components/QrCodePreview.tsx rename to src/components/QrCodePreview.tsx diff --git a/components/RouterContainer.tsx b/src/components/RouterContainer.tsx similarity index 100% rename from components/RouterContainer.tsx rename to src/components/RouterContainer.tsx diff --git a/components/SwitchButtonGroup.tsx b/src/components/SwitchButtonGroup.tsx similarity index 100% rename from components/SwitchButtonGroup.tsx rename to src/components/SwitchButtonGroup.tsx diff --git a/components/TextInputArea.tsx b/src/components/TextInputArea.tsx similarity index 100% rename from components/TextInputArea.tsx rename to src/components/TextInputArea.tsx diff --git a/components/TopBar.tsx b/src/components/TopBar.tsx similarity index 100% rename from components/TopBar.tsx rename to src/components/TopBar.tsx diff --git a/components/__tests__/DecodeResultPaper.test.tsx b/src/components/__tests__/DecodeResultPaper.test.tsx similarity index 100% rename from components/__tests__/DecodeResultPaper.test.tsx rename to src/components/__tests__/DecodeResultPaper.test.tsx diff --git a/components/__tests__/ErrorBoundary.test.tsx b/src/components/__tests__/ErrorBoundary.test.tsx similarity index 100% rename from components/__tests__/ErrorBoundary.test.tsx rename to src/components/__tests__/ErrorBoundary.test.tsx diff --git a/components/__tests__/GlobalSnackbar.test.tsx b/src/components/__tests__/GlobalSnackbar.test.tsx similarity index 100% rename from components/__tests__/GlobalSnackbar.test.tsx rename to src/components/__tests__/GlobalSnackbar.test.tsx diff --git a/components/__tests__/ImageUploader.test.tsx b/src/components/__tests__/ImageUploader.test.tsx similarity index 100% rename from components/__tests__/ImageUploader.test.tsx rename to src/components/__tests__/ImageUploader.test.tsx diff --git a/components/__tests__/PageErrorBoundary.test.tsx b/src/components/__tests__/PageErrorBoundary.test.tsx similarity index 100% rename from components/__tests__/PageErrorBoundary.test.tsx rename to src/components/__tests__/PageErrorBoundary.test.tsx diff --git a/components/__tests__/PageSkeleton.test.tsx b/src/components/__tests__/PageSkeleton.test.tsx similarity index 100% rename from components/__tests__/PageSkeleton.test.tsx rename to src/components/__tests__/PageSkeleton.test.tsx diff --git a/components/__tests__/QrCodePreview.test.tsx b/src/components/__tests__/QrCodePreview.test.tsx similarity index 100% rename from components/__tests__/QrCodePreview.test.tsx rename to src/components/__tests__/QrCodePreview.test.tsx diff --git a/components/__tests__/RouterContainer.test.tsx b/src/components/__tests__/RouterContainer.test.tsx similarity index 100% rename from components/__tests__/RouterContainer.test.tsx rename to src/components/__tests__/RouterContainer.test.tsx diff --git a/components/__tests__/StorageCleanerConfirm.test.tsx b/src/components/__tests__/StorageCleanerConfirm.test.tsx similarity index 100% rename from components/__tests__/StorageCleanerConfirm.test.tsx rename to src/components/__tests__/StorageCleanerConfirm.test.tsx diff --git a/components/__tests__/SwitchButtonGroup.test.tsx b/src/components/__tests__/SwitchButtonGroup.test.tsx similarity index 100% rename from components/__tests__/SwitchButtonGroup.test.tsx rename to src/components/__tests__/SwitchButtonGroup.test.tsx diff --git a/components/__tests__/TextInputArea.test.tsx b/src/components/__tests__/TextInputArea.test.tsx similarity index 100% rename from components/__tests__/TextInputArea.test.tsx rename to src/components/__tests__/TextInputArea.test.tsx diff --git a/components/__tests__/ToolCard.test.tsx b/src/components/__tests__/ToolCard.test.tsx similarity index 100% rename from components/__tests__/ToolCard.test.tsx rename to src/components/__tests__/ToolCard.test.tsx diff --git a/components/__tests__/TopBar.test.tsx b/src/components/__tests__/TopBar.test.tsx similarity index 100% rename from components/__tests__/TopBar.test.tsx rename to src/components/__tests__/TopBar.test.tsx diff --git a/components/ui/badge.tsx b/src/components/ui/badge.tsx similarity index 100% rename from components/ui/badge.tsx rename to src/components/ui/badge.tsx diff --git a/components/ui/button.tsx b/src/components/ui/button.tsx similarity index 100% rename from components/ui/button.tsx rename to src/components/ui/button.tsx diff --git a/components/ui/checkbox.tsx b/src/components/ui/checkbox.tsx similarity index 100% rename from components/ui/checkbox.tsx rename to src/components/ui/checkbox.tsx diff --git a/components/ui/dialog.tsx b/src/components/ui/dialog.tsx similarity index 100% rename from components/ui/dialog.tsx rename to src/components/ui/dialog.tsx diff --git a/components/ui/input.tsx b/src/components/ui/input.tsx similarity index 100% rename from components/ui/input.tsx rename to src/components/ui/input.tsx diff --git a/components/ui/label.tsx b/src/components/ui/label.tsx similarity index 100% rename from components/ui/label.tsx rename to src/components/ui/label.tsx diff --git a/components/ui/select.tsx b/src/components/ui/select.tsx similarity index 100% rename from components/ui/select.tsx rename to src/components/ui/select.tsx diff --git a/components/ui/switch.tsx b/src/components/ui/switch.tsx similarity index 100% rename from components/ui/switch.tsx rename to src/components/ui/switch.tsx diff --git a/config/__tests__/features.test.ts b/src/config/__tests__/features.test.ts similarity index 100% rename from config/__tests__/features.test.ts rename to src/config/__tests__/features.test.ts diff --git a/config/features.tsx b/src/config/features.tsx similarity index 100% rename from config/features.tsx rename to src/config/features.tsx diff --git a/entrypoints/__tests__/background.test.ts b/src/entrypoints/__tests__/background.test.ts similarity index 100% rename from entrypoints/__tests__/background.test.ts rename to src/entrypoints/__tests__/background.test.ts diff --git a/entrypoints/background.ts b/src/entrypoints/background.ts similarity index 99% rename from entrypoints/background.ts rename to src/entrypoints/background.ts index fcfe6eb..e2b5e63 100644 --- a/entrypoints/background.ts +++ b/src/entrypoints/background.ts @@ -1,4 +1,4 @@ -import '../.wxt/types/imports.d.ts'; +import '../../.wxt/types/imports.d.ts'; import { browser } from 'wxt/browser'; import { MessageAction, onMessage, sendMessage } from '@/utils/messages'; import { createAllContextMenus, parseContextMenuClick } from '@/utils/contextMenu'; diff --git a/entrypoints/content.ts b/src/entrypoints/content.ts similarity index 83% rename from entrypoints/content.ts rename to src/entrypoints/content.ts index c6e8255..de742e7 100644 --- a/entrypoints/content.ts +++ b/src/entrypoints/content.ts @@ -1,4 +1,4 @@ -import '../.wxt/types/imports.d.ts'; +import '../../.wxt/types/imports.d.ts'; import { initMessageHandler } from './content/messageHandler'; export default defineContentScript({ diff --git a/entrypoints/content/contextMenuHandler.ts b/src/entrypoints/content/contextMenuHandler.ts similarity index 100% rename from entrypoints/content/contextMenuHandler.ts rename to src/entrypoints/content/contextMenuHandler.ts diff --git a/entrypoints/content/messageHandler.ts b/src/entrypoints/content/messageHandler.ts similarity index 100% rename from entrypoints/content/messageHandler.ts rename to src/entrypoints/content/messageHandler.ts diff --git a/entrypoints/content/uiPopover.ts b/src/entrypoints/content/uiPopover.ts similarity index 100% rename from entrypoints/content/uiPopover.ts rename to src/entrypoints/content/uiPopover.ts diff --git a/entrypoints/options/App.tsx b/src/entrypoints/options/App.tsx similarity index 100% rename from entrypoints/options/App.tsx rename to src/entrypoints/options/App.tsx diff --git a/entrypoints/options/__tests__/App.test.tsx b/src/entrypoints/options/__tests__/App.test.tsx similarity index 100% rename from entrypoints/options/__tests__/App.test.tsx rename to src/entrypoints/options/__tests__/App.test.tsx diff --git a/entrypoints/options/index.html b/src/entrypoints/options/index.html similarity index 100% rename from entrypoints/options/index.html rename to src/entrypoints/options/index.html diff --git a/entrypoints/options/main.tsx b/src/entrypoints/options/main.tsx similarity index 89% rename from entrypoints/options/main.tsx rename to src/entrypoints/options/main.tsx index 1571624..ea46171 100644 --- a/entrypoints/options/main.tsx +++ b/src/entrypoints/options/main.tsx @@ -1,6 +1,6 @@ import ReactDOM from 'react-dom/client'; import AppRoot from '@/providers/AppRoot'; -import '@/src/index.css'; +import '@/index.css'; import App from './App'; ReactDOM.createRoot(document.getElementById('root')!).render( diff --git a/entrypoints/popup/App.tsx b/src/entrypoints/popup/App.tsx similarity index 100% rename from entrypoints/popup/App.tsx rename to src/entrypoints/popup/App.tsx diff --git a/entrypoints/popup/index.html b/src/entrypoints/popup/index.html similarity index 100% rename from entrypoints/popup/index.html rename to src/entrypoints/popup/index.html diff --git a/entrypoints/popup/main.tsx b/src/entrypoints/popup/main.tsx similarity index 89% rename from entrypoints/popup/main.tsx rename to src/entrypoints/popup/main.tsx index 67f30b7..6f602b5 100644 --- a/entrypoints/popup/main.tsx +++ b/src/entrypoints/popup/main.tsx @@ -1,6 +1,6 @@ import ReactDOM from 'react-dom/client'; import AppRoot from '@/providers/AppRoot'; -import '@/src/index.css'; +import '@/index.css'; import App from './App.tsx'; ReactDOM.createRoot(document.getElementById('root')!).render( diff --git a/entrypoints/rightClickRestorer.content.ts b/src/entrypoints/rightClickRestorer.content.ts similarity index 100% rename from entrypoints/rightClickRestorer.content.ts rename to src/entrypoints/rightClickRestorer.content.ts diff --git a/entrypoints/sidepanel/App.tsx b/src/entrypoints/sidepanel/App.tsx similarity index 100% rename from entrypoints/sidepanel/App.tsx rename to src/entrypoints/sidepanel/App.tsx diff --git a/entrypoints/sidepanel/index.html b/src/entrypoints/sidepanel/index.html similarity index 100% rename from entrypoints/sidepanel/index.html rename to src/entrypoints/sidepanel/index.html diff --git a/entrypoints/sidepanel/main.tsx b/src/entrypoints/sidepanel/main.tsx similarity index 89% rename from entrypoints/sidepanel/main.tsx rename to src/entrypoints/sidepanel/main.tsx index 67f30b7..6f602b5 100644 --- a/entrypoints/sidepanel/main.tsx +++ b/src/entrypoints/sidepanel/main.tsx @@ -1,6 +1,6 @@ import ReactDOM from 'react-dom/client'; import AppRoot from '@/providers/AppRoot'; -import '@/src/index.css'; +import '@/index.css'; import App from './App.tsx'; ReactDOM.createRoot(document.getElementById('root')!).render( diff --git a/lib/utils.ts b/src/lib/utils.ts similarity index 100% rename from lib/utils.ts rename to src/lib/utils.ts diff --git a/pages/Base64Converter/Base64ConverterSection.tsx b/src/pages/Base64Converter/Base64ConverterSection.tsx similarity index 100% rename from pages/Base64Converter/Base64ConverterSection.tsx rename to src/pages/Base64Converter/Base64ConverterSection.tsx diff --git a/pages/Base64Converter/TextMode.tsx b/src/pages/Base64Converter/TextMode.tsx similarity index 100% rename from pages/Base64Converter/TextMode.tsx rename to src/pages/Base64Converter/TextMode.tsx diff --git a/pages/Base64Converter/__tests__/TextMode.test.tsx b/src/pages/Base64Converter/__tests__/TextMode.test.tsx similarity index 100% rename from pages/Base64Converter/__tests__/TextMode.test.tsx rename to src/pages/Base64Converter/__tests__/TextMode.test.tsx diff --git a/pages/Base64Converter/__tests__/index.test.tsx b/src/pages/Base64Converter/__tests__/index.test.tsx similarity index 100% rename from pages/Base64Converter/__tests__/index.test.tsx rename to src/pages/Base64Converter/__tests__/index.test.tsx diff --git a/pages/Base64Converter/index.tsx b/src/pages/Base64Converter/index.tsx similarity index 100% rename from pages/Base64Converter/index.tsx rename to src/pages/Base64Converter/index.tsx diff --git a/pages/Base64Converter/useBase64Converter.ts b/src/pages/Base64Converter/useBase64Converter.ts similarity index 100% rename from pages/Base64Converter/useBase64Converter.ts rename to src/pages/Base64Converter/useBase64Converter.ts diff --git a/pages/Dashboard/ToolCard.tsx b/src/pages/Dashboard/ToolCard.tsx similarity index 100% rename from pages/Dashboard/ToolCard.tsx rename to src/pages/Dashboard/ToolCard.tsx diff --git a/pages/Dashboard/index.tsx b/src/pages/Dashboard/index.tsx similarity index 100% rename from pages/Dashboard/index.tsx rename to src/pages/Dashboard/index.tsx diff --git a/pages/HtmlToMarkdown/index.tsx b/src/pages/HtmlToMarkdown/index.tsx similarity index 100% rename from pages/HtmlToMarkdown/index.tsx rename to src/pages/HtmlToMarkdown/index.tsx diff --git a/pages/JsonTools/DiffNavigator.tsx b/src/pages/JsonTools/DiffNavigator.tsx similarity index 100% rename from pages/JsonTools/DiffNavigator.tsx rename to src/pages/JsonTools/DiffNavigator.tsx diff --git a/pages/JsonTools/DiffResult.tsx b/src/pages/JsonTools/DiffResult.tsx similarity index 100% rename from pages/JsonTools/DiffResult.tsx rename to src/pages/JsonTools/DiffResult.tsx diff --git a/pages/JsonTools/JsonConvertSection.tsx b/src/pages/JsonTools/JsonConvertSection.tsx similarity index 100% rename from pages/JsonTools/JsonConvertSection.tsx rename to src/pages/JsonTools/JsonConvertSection.tsx diff --git a/pages/JsonTools/JsonDiffInput.tsx b/src/pages/JsonTools/JsonDiffInput.tsx similarity index 100% rename from pages/JsonTools/JsonDiffInput.tsx rename to src/pages/JsonTools/JsonDiffInput.tsx diff --git a/pages/JsonTools/JsonFormatSection.tsx b/src/pages/JsonTools/JsonFormatSection.tsx similarity index 100% rename from pages/JsonTools/JsonFormatSection.tsx rename to src/pages/JsonTools/JsonFormatSection.tsx diff --git a/pages/JsonTools/JsonTree.tsx b/src/pages/JsonTools/JsonTree.tsx similarity index 100% rename from pages/JsonTools/JsonTree.tsx rename to src/pages/JsonTools/JsonTree.tsx diff --git a/pages/JsonTools/diffEngine.ts b/src/pages/JsonTools/diffEngine.ts similarity index 100% rename from pages/JsonTools/diffEngine.ts rename to src/pages/JsonTools/diffEngine.ts diff --git a/pages/JsonTools/index.tsx b/src/pages/JsonTools/index.tsx similarity index 100% rename from pages/JsonTools/index.tsx rename to src/pages/JsonTools/index.tsx diff --git a/pages/JsonTools/types.ts b/src/pages/JsonTools/types.ts similarity index 100% rename from pages/JsonTools/types.ts rename to src/pages/JsonTools/types.ts diff --git a/pages/Jwt/index.tsx b/src/pages/Jwt/index.tsx similarity index 100% rename from pages/Jwt/index.tsx rename to src/pages/Jwt/index.tsx diff --git a/pages/MarkdownToHtml/index.tsx b/src/pages/MarkdownToHtml/index.tsx similarity index 100% rename from pages/MarkdownToHtml/index.tsx rename to src/pages/MarkdownToHtml/index.tsx diff --git a/pages/QrCode/__tests__/index.test.tsx b/src/pages/QrCode/__tests__/index.test.tsx similarity index 100% rename from pages/QrCode/__tests__/index.test.tsx rename to src/pages/QrCode/__tests__/index.test.tsx diff --git a/pages/QrCode/components/GeneratePanel.tsx b/src/pages/QrCode/components/GeneratePanel.tsx similarity index 100% rename from pages/QrCode/components/GeneratePanel.tsx rename to src/pages/QrCode/components/GeneratePanel.tsx diff --git a/pages/QrCode/components/ParsePanel.tsx b/src/pages/QrCode/components/ParsePanel.tsx similarity index 100% rename from pages/QrCode/components/ParsePanel.tsx rename to src/pages/QrCode/components/ParsePanel.tsx diff --git a/pages/QrCode/contexts/QrCodeContext.ts b/src/pages/QrCode/contexts/QrCodeContext.ts similarity index 100% rename from pages/QrCode/contexts/QrCodeContext.ts rename to src/pages/QrCode/contexts/QrCodeContext.ts diff --git a/pages/QrCode/hooks/useQrCode.ts b/src/pages/QrCode/hooks/useQrCode.ts similarity index 100% rename from pages/QrCode/hooks/useQrCode.ts rename to src/pages/QrCode/hooks/useQrCode.ts diff --git a/pages/QrCode/index.tsx b/src/pages/QrCode/index.tsx similarity index 100% rename from pages/QrCode/index.tsx rename to src/pages/QrCode/index.tsx diff --git a/pages/QrCode/types.ts b/src/pages/QrCode/types.ts similarity index 100% rename from pages/QrCode/types.ts rename to src/pages/QrCode/types.ts diff --git a/pages/RightClickRestorer/__tests__/index.test.tsx b/src/pages/RightClickRestorer/__tests__/index.test.tsx similarity index 100% rename from pages/RightClickRestorer/__tests__/index.test.tsx rename to src/pages/RightClickRestorer/__tests__/index.test.tsx diff --git a/pages/RightClickRestorer/__tests__/useRightClickRestorer.test.ts b/src/pages/RightClickRestorer/__tests__/useRightClickRestorer.test.ts similarity index 100% rename from pages/RightClickRestorer/__tests__/useRightClickRestorer.test.ts rename to src/pages/RightClickRestorer/__tests__/useRightClickRestorer.test.ts diff --git a/pages/RightClickRestorer/index.tsx b/src/pages/RightClickRestorer/index.tsx similarity index 100% rename from pages/RightClickRestorer/index.tsx rename to src/pages/RightClickRestorer/index.tsx diff --git a/pages/RightClickRestorer/useRightClickRestorer.ts b/src/pages/RightClickRestorer/useRightClickRestorer.ts similarity index 100% rename from pages/RightClickRestorer/useRightClickRestorer.ts rename to src/pages/RightClickRestorer/useRightClickRestorer.ts diff --git a/pages/StorageCleaner/AutoRefreshToggle.tsx b/src/pages/StorageCleaner/AutoRefreshToggle.tsx similarity index 100% rename from pages/StorageCleaner/AutoRefreshToggle.tsx rename to src/pages/StorageCleaner/AutoRefreshToggle.tsx diff --git a/pages/StorageCleaner/CleaningResult.tsx b/src/pages/StorageCleaner/CleaningResult.tsx similarity index 100% rename from pages/StorageCleaner/CleaningResult.tsx rename to src/pages/StorageCleaner/CleaningResult.tsx diff --git a/pages/StorageCleaner/ErrorDisplay.tsx b/src/pages/StorageCleaner/ErrorDisplay.tsx similarity index 100% rename from pages/StorageCleaner/ErrorDisplay.tsx rename to src/pages/StorageCleaner/ErrorDisplay.tsx diff --git a/pages/StorageCleaner/OptionItem.tsx b/src/pages/StorageCleaner/OptionItem.tsx similarity index 100% rename from pages/StorageCleaner/OptionItem.tsx rename to src/pages/StorageCleaner/OptionItem.tsx diff --git a/pages/StorageCleaner/StorageCleanerConfirm.tsx b/src/pages/StorageCleaner/StorageCleanerConfirm.tsx similarity index 100% rename from pages/StorageCleaner/StorageCleanerConfirm.tsx rename to src/pages/StorageCleaner/StorageCleanerConfirm.tsx diff --git a/pages/StorageCleaner/StorageOptionsGrid.tsx b/src/pages/StorageCleaner/StorageOptionsGrid.tsx similarity index 100% rename from pages/StorageCleaner/StorageOptionsGrid.tsx rename to src/pages/StorageCleaner/StorageOptionsGrid.tsx diff --git a/pages/StorageCleaner/index.tsx b/src/pages/StorageCleaner/index.tsx similarity index 100% rename from pages/StorageCleaner/index.tsx rename to src/pages/StorageCleaner/index.tsx diff --git a/pages/StorageCleaner/useStorageCleaner.ts b/src/pages/StorageCleaner/useStorageCleaner.ts similarity index 100% rename from pages/StorageCleaner/useStorageCleaner.ts rename to src/pages/StorageCleaner/useStorageCleaner.ts diff --git a/pages/TextStatistics/index.tsx b/src/pages/TextStatistics/index.tsx similarity index 100% rename from pages/TextStatistics/index.tsx rename to src/pages/TextStatistics/index.tsx diff --git a/pages/Timestamp/LiveClock.tsx b/src/pages/Timestamp/LiveClock.tsx similarity index 100% rename from pages/Timestamp/LiveClock.tsx rename to src/pages/Timestamp/LiveClock.tsx diff --git a/pages/Timestamp/ResultView.tsx b/src/pages/Timestamp/ResultView.tsx similarity index 100% rename from pages/Timestamp/ResultView.tsx rename to src/pages/Timestamp/ResultView.tsx diff --git a/pages/Timestamp/constants.ts b/src/pages/Timestamp/constants.ts similarity index 100% rename from pages/Timestamp/constants.ts rename to src/pages/Timestamp/constants.ts diff --git a/pages/Timestamp/index.tsx b/src/pages/Timestamp/index.tsx similarity index 100% rename from pages/Timestamp/index.tsx rename to src/pages/Timestamp/index.tsx diff --git a/pages/Timestamp/useTimestampConverter.ts b/src/pages/Timestamp/useTimestampConverter.ts similarity index 100% rename from pages/Timestamp/useTimestampConverter.ts rename to src/pages/Timestamp/useTimestampConverter.ts diff --git a/providers/AppRoot.tsx b/src/providers/AppRoot.tsx similarity index 100% rename from providers/AppRoot.tsx rename to src/providers/AppRoot.tsx diff --git a/providers/RouterProvider.tsx b/src/providers/RouterProvider.tsx similarity index 98% rename from providers/RouterProvider.tsx rename to src/providers/RouterProvider.tsx index 9285a40..5f04c43 100644 --- a/providers/RouterProvider.tsx +++ b/src/providers/RouterProvider.tsx @@ -147,6 +147,7 @@ export function RouterProvider({ if (isValidPageList(savedPageOrder) && savedPageOrder.length > 0) { setPageOrder(mergeWithDefaults(savedPageOrder, getDefaultPageOrder())); } + setIsLoaded(true); } catch (error) { console.error('[Router Init Error] Core data fetch failed:', error); } @@ -156,10 +157,10 @@ export function RouterProvider({ useEffect(() => { let cancelled = false; + // eslint-disable-next-line react-hooks/set-state-in-effect -- Valid async data loading pattern on mount loadInitialData() .then(() => { if (cancelled) return; - setIsLoaded(true); // 检查 URL 参数中的右键菜单高阶中转数据 if (typeof window !== 'undefined') { diff --git a/providers/ThemeModeProvider.tsx b/src/providers/ThemeModeProvider.tsx similarity index 100% rename from providers/ThemeModeProvider.tsx rename to src/providers/ThemeModeProvider.tsx diff --git a/providers/__tests__/RouterProvider.test.tsx b/src/providers/__tests__/RouterProvider.test.tsx similarity index 100% rename from providers/__tests__/RouterProvider.test.tsx rename to src/providers/__tests__/RouterProvider.test.tsx diff --git a/types/qrious.d.ts b/src/types/qrious.d.ts similarity index 100% rename from types/qrious.d.ts rename to src/types/qrious.d.ts diff --git a/types/storage.d.ts b/src/types/storage.d.ts similarity index 100% rename from types/storage.d.ts rename to src/types/storage.d.ts diff --git a/utils/__tests__/base64Converter.test.ts b/src/utils/__tests__/base64Converter.test.ts similarity index 100% rename from utils/__tests__/base64Converter.test.ts rename to src/utils/__tests__/base64Converter.test.ts diff --git a/utils/__tests__/chromeStorage.test.ts b/src/utils/__tests__/chromeStorage.test.ts similarity index 100% rename from utils/__tests__/chromeStorage.test.ts rename to src/utils/__tests__/chromeStorage.test.ts diff --git a/utils/__tests__/chromeTabs.test.ts b/src/utils/__tests__/chromeTabs.test.ts similarity index 100% rename from utils/__tests__/chromeTabs.test.ts rename to src/utils/__tests__/chromeTabs.test.ts diff --git a/utils/__tests__/clipboard.test.ts b/src/utils/__tests__/clipboard.test.ts similarity index 100% rename from utils/__tests__/clipboard.test.ts rename to src/utils/__tests__/clipboard.test.ts diff --git a/utils/__tests__/contextMenu.test.ts b/src/utils/__tests__/contextMenu.test.ts similarity index 100% rename from utils/__tests__/contextMenu.test.ts rename to src/utils/__tests__/contextMenu.test.ts diff --git a/utils/__tests__/dayjs.test.ts b/src/utils/__tests__/dayjs.test.ts similarity index 100% rename from utils/__tests__/dayjs.test.ts rename to src/utils/__tests__/dayjs.test.ts diff --git a/utils/__tests__/diffEngine.test.ts b/src/utils/__tests__/diffEngine.test.ts similarity index 100% rename from utils/__tests__/diffEngine.test.ts rename to src/utils/__tests__/diffEngine.test.ts diff --git a/utils/__tests__/format.test.ts b/src/utils/__tests__/format.test.ts similarity index 100% rename from utils/__tests__/format.test.ts rename to src/utils/__tests__/format.test.ts diff --git a/utils/__tests__/htmlToMarkdown.test.ts b/src/utils/__tests__/htmlToMarkdown.test.ts similarity index 100% rename from utils/__tests__/htmlToMarkdown.test.ts rename to src/utils/__tests__/htmlToMarkdown.test.ts diff --git a/utils/__tests__/jsonFormatter.test.ts b/src/utils/__tests__/jsonFormatter.test.ts similarity index 100% rename from utils/__tests__/jsonFormatter.test.ts rename to src/utils/__tests__/jsonFormatter.test.ts diff --git a/utils/__tests__/jsonMinify.test.ts b/src/utils/__tests__/jsonMinify.test.ts similarity index 100% rename from utils/__tests__/jsonMinify.test.ts rename to src/utils/__tests__/jsonMinify.test.ts diff --git a/utils/__tests__/jsonToToml.test.ts b/src/utils/__tests__/jsonToToml.test.ts similarity index 100% rename from utils/__tests__/jsonToToml.test.ts rename to src/utils/__tests__/jsonToToml.test.ts diff --git a/utils/__tests__/jsonToYaml.test.ts b/src/utils/__tests__/jsonToYaml.test.ts similarity index 100% rename from utils/__tests__/jsonToYaml.test.ts rename to src/utils/__tests__/jsonToYaml.test.ts diff --git a/utils/__tests__/jwt.test.ts b/src/utils/__tests__/jwt.test.ts similarity index 100% rename from utils/__tests__/jwt.test.ts rename to src/utils/__tests__/jwt.test.ts diff --git a/utils/__tests__/markdownToHtml.test.ts b/src/utils/__tests__/markdownToHtml.test.ts similarity index 100% rename from utils/__tests__/markdownToHtml.test.ts rename to src/utils/__tests__/markdownToHtml.test.ts diff --git a/utils/__tests__/messages.test.ts b/src/utils/__tests__/messages.test.ts similarity index 100% rename from utils/__tests__/messages.test.ts rename to src/utils/__tests__/messages.test.ts diff --git a/utils/__tests__/qrCodeParser.test.ts b/src/utils/__tests__/qrCodeParser.test.ts similarity index 100% rename from utils/__tests__/qrCodeParser.test.ts rename to src/utils/__tests__/qrCodeParser.test.ts diff --git a/utils/__tests__/storageCleaner.test.ts b/src/utils/__tests__/storageCleaner.test.ts similarity index 100% rename from utils/__tests__/storageCleaner.test.ts rename to src/utils/__tests__/storageCleaner.test.ts diff --git a/utils/__tests__/textStatistics.test.ts b/src/utils/__tests__/textStatistics.test.ts similarity index 100% rename from utils/__tests__/textStatistics.test.ts rename to src/utils/__tests__/textStatistics.test.ts diff --git a/utils/__tests__/useContextMenuData.test.ts b/src/utils/__tests__/useContextMenuData.test.ts similarity index 100% rename from utils/__tests__/useContextMenuData.test.ts rename to src/utils/__tests__/useContextMenuData.test.ts diff --git a/utils/__tests__/useStorageState.test.ts b/src/utils/__tests__/useStorageState.test.ts similarity index 100% rename from utils/__tests__/useStorageState.test.ts rename to src/utils/__tests__/useStorageState.test.ts diff --git a/utils/base64Converter.ts b/src/utils/base64Converter.ts similarity index 100% rename from utils/base64Converter.ts rename to src/utils/base64Converter.ts diff --git a/utils/chromeI18n.ts b/src/utils/chromeI18n.ts similarity index 100% rename from utils/chromeI18n.ts rename to src/utils/chromeI18n.ts diff --git a/utils/chromeStorage.ts b/src/utils/chromeStorage.ts similarity index 100% rename from utils/chromeStorage.ts rename to src/utils/chromeStorage.ts diff --git a/utils/chromeTabs.ts b/src/utils/chromeTabs.ts similarity index 100% rename from utils/chromeTabs.ts rename to src/utils/chromeTabs.ts diff --git a/utils/clipboard.ts b/src/utils/clipboard.ts similarity index 100% rename from utils/clipboard.ts rename to src/utils/clipboard.ts diff --git a/utils/contextMenu.ts b/src/utils/contextMenu.ts similarity index 100% rename from utils/contextMenu.ts rename to src/utils/contextMenu.ts diff --git a/utils/dayjs.ts b/src/utils/dayjs.ts similarity index 100% rename from utils/dayjs.ts rename to src/utils/dayjs.ts diff --git a/utils/format.ts b/src/utils/format.ts similarity index 100% rename from utils/format.ts rename to src/utils/format.ts diff --git a/utils/htmlToMarkdown.ts b/src/utils/htmlToMarkdown.ts similarity index 100% rename from utils/htmlToMarkdown.ts rename to src/utils/htmlToMarkdown.ts diff --git a/utils/jsonFormatter.ts b/src/utils/jsonFormatter.ts similarity index 100% rename from utils/jsonFormatter.ts rename to src/utils/jsonFormatter.ts diff --git a/utils/jsonToToml.ts b/src/utils/jsonToToml.ts similarity index 100% rename from utils/jsonToToml.ts rename to src/utils/jsonToToml.ts diff --git a/utils/jsonToYaml.ts b/src/utils/jsonToYaml.ts similarity index 100% rename from utils/jsonToYaml.ts rename to src/utils/jsonToYaml.ts diff --git a/utils/jwt.ts b/src/utils/jwt.ts similarity index 100% rename from utils/jwt.ts rename to src/utils/jwt.ts diff --git a/utils/markdownToHtml.ts b/src/utils/markdownToHtml.ts similarity index 100% rename from utils/markdownToHtml.ts rename to src/utils/markdownToHtml.ts diff --git a/utils/messages.ts b/src/utils/messages.ts similarity index 100% rename from utils/messages.ts rename to src/utils/messages.ts diff --git a/utils/qrCodeParser.ts b/src/utils/qrCodeParser.ts similarity index 100% rename from utils/qrCodeParser.ts rename to src/utils/qrCodeParser.ts diff --git a/utils/storageCleaner.ts b/src/utils/storageCleaner.ts similarity index 100% rename from utils/storageCleaner.ts rename to src/utils/storageCleaner.ts diff --git a/utils/textStatistics.ts b/src/utils/textStatistics.ts similarity index 100% rename from utils/textStatistics.ts rename to src/utils/textStatistics.ts diff --git a/utils/useContextMenuData.ts b/src/utils/useContextMenuData.ts similarity index 100% rename from utils/useContextMenuData.ts rename to src/utils/useContextMenuData.ts diff --git a/utils/useDebounce.ts b/src/utils/useDebounce.ts similarity index 100% rename from utils/useDebounce.ts rename to src/utils/useDebounce.ts diff --git a/utils/useStorageState.ts b/src/utils/useStorageState.ts similarity index 100% rename from utils/useStorageState.ts rename to src/utils/useStorageState.ts diff --git a/tailwind.config.js b/tailwind.config.js index 7710cb5..ed91354 100644 --- a/tailwind.config.js +++ b/tailwind.config.js @@ -1,14 +1,7 @@ /** @type {import('tailwindcss').Config} */ export default { darkMode: 'class', - content: [ - './entrypoints/**/*.{js,ts,jsx,tsx}', - './components/**/*.{js,ts,jsx,tsx}', - './pages/**/*.{js,ts,jsx,tsx}', - './providers/**/*.{js,ts,jsx,tsx}', - './utils/**/*.{js,ts,jsx,tsx}', - './config/**/*.{js,ts,jsx,tsx}', - ], + content: ['./entrypoints/**/*.{js,ts,jsx,tsx}', './src/**/*.{js,ts,jsx,tsx}'], theme: { extend: { colors: { diff --git a/tsconfig.json b/tsconfig.json index 82e1037..987cf9b 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -29,21 +29,6 @@ "noImplicitAny": true }, // 确保包含你的源代码目录 - "include": [ - "entrypoints/**/*", - "pages/**/*", - "components/**/*", - "providers/**/*", - "utils/**/*", - "config/**/*", - "types/**/*", - "assets/**/*", - "hooks/**/*", - "lib/**/*", - "src/**/*", - ".wxt/types/**/*.ts", - ".wxt/types/*.d.ts", - "eslint.config.ts" - ], + "include": ["src/**/*", ".wxt/types/**/*.ts", ".wxt/types/*.d.ts", "eslint.config.ts"], "exclude": ["node_modules", ".wxt", "dist"] } diff --git a/types/README.md b/types/README.md deleted file mode 100644 index 67fbff4..0000000 --- a/types/README.md +++ /dev/null @@ -1,42 +0,0 @@ -# types/ - -全局共享的 TypeScript 类型声明文件目录。 - -## 文件说明 - -### storage.d.ts - -核心类型定义文件,包含: - -**页面类型:** - -- `PageType` — 所有页面类型的联合类型(`dashboard` | `timestamp` | `storageCleaner` | ...) -- `JsonToolsPageMode` — JSON 工具子模式(`diff` | `format` | `yaml` | `toml` | `minify`) -- `Base64ConverterPageMode` — Base64 子模式(`text` | `file` | `image`) -- `Base64ConvertDirection` — 编解码方向(`encode` | `decode`) -- `MarkdownToHtmlPreviewMode` — Markdown 预览模式(`split` | `preview` | `html`) -- `HtmlToMarkdownPreviewMode` — HTML 预览模式(`split` | `preview` | `markdown`) - -**存储 Schema:** - -- `StorageSchema` — Chrome Storage 完整数据结构定义,所有存储键必须在此声明 - - 键名使用 kebab-case 格式(如 `app/currentRoute`) - - 包含路由、主题、工具偏好、搜索历史等所有持久化数据 - -**其他类型:** - -- `FormMapEntry` — 表单映射条目定义 -- `ContextMenuPendingData` — 右键菜单待处理数据 -- `StorageCleanerPreferences` / `StorageCleanerOptions` — 存储清理偏好 -- `CleaningResult` / `StorageCleanResult` — 清理结果类型 - -### qrious.d.ts - -`qrious` 库的类型声明,定义 QR 码生成选项和 `QRious` 类。 - -## 修改 StorageSchema 的注意事项 - -修改 `StorageSchema` 时,必须: - -1. 在 `utils/chromeStorage.ts` 添加版本迁移函数 -2. 在测试中覆盖迁移场景 diff --git a/utils/README.md b/utils/README.md deleted file mode 100644 index a3f8d04..0000000 --- a/utils/README.md +++ /dev/null @@ -1,42 +0,0 @@ -# utils/ - -通用工具函数和 React 自定义 Hooks 目录,与具体页面解耦。 - -## 工具函数 - -| 文件 | 用途 | -| -------------------- | --------------------------------------------------------------------------------------------------- | -| `chromeStorage.ts` | Chrome Storage API 封装:类型安全的 `StorageUtils` 类,提供 `get/set/remove` 方法 | -| `chromeTabs.ts` | Chrome Tabs API 封装:获取活动标签页、获取域名、在新标签页打开扩展页面 | -| `clipboard.ts` | 剪贴板操作:`copyTextToClipboard`(文本)、`copyImageToClipboard`(图片) | -| `messages.ts` | 扩展消息通信:基于 `@webext-core/messaging`,定义 `MessageAction` 枚举和 `ProtocolMap` 类型安全映射 | -| `contextMenu.ts` | 右键菜单配置与操作:定义菜单项、创建菜单、解析点击事件、ID→PageType 映射 | -| `base64Converter.ts` | Base64 编解码:文本↔Base64、文件↔Base64、图片预览,定义文件大小限制和图像 MIME 类型 | -| `jwt.ts` | JWT 解析:Base64URL 解码、解析 Header/Payload/Signature、JSON 格式化输出 | -| `jsonFormatter.ts` | JSON 格式化/压缩:支持缩进、按键排序、minify | -| `jsonToYaml.ts` | JSON→YAML 转换 | -| `jsonToToml.ts` | JSON→TOML 转换 | -| `markdownToHtml.ts` | Markdown→HTML 转换:基于 `marked` 库,支持 GFM 和换行转换 | -| `htmlToMarkdown.ts` | HTML→Markdown 转换:基于 DOMParser 解析 | -| `qrCodeParser.ts` | 二维码解析:基于 `qr-scanner` 库从文件中解析二维码 | -| `storageCleaner.ts` | 存储清理:获取当前标签页、检测受限 URL、计算 Cookie/Storage 大小、清理操作 | -| `textStatistics.ts` | 文本统计:使用 `Intl.Segmenter` 计算字符数/单词数/行数/字节大小 | -| `format.ts` | 通用格式化:`formatBytes` 将字节转为可读字符串(B/KB/MB/GB/TB) | -| `dayjs.ts` | Day.js 初始化:扩展 UTC、Timezone、RelativeTime 插件,加载中文本地化 | - -## 自定义 Hooks - -| 文件 | 用途 | -| ----------------------- | -------------------------------------------------------------------------------------------------------------- | -| `useStorageState.ts` | Chrome Storage 状态 Hook:类似 `useState`,值自动同步到 `chrome.storage`,使用 `localStorage` 快照消除首屏闪烁 | -| `useLazyTranslation.ts` | 懒加载翻译 Hook:按需动态导入 i18n 命名空间,支持预加载和缓存 | -| `useContextMenuData.ts` | 右键菜单数据 Hook:从 storage 读取待处理数据,匹配 featureKey 后消费并触发回调 | -| `useDebounce.ts` | 防抖 Hook:对值进行延迟更新,避免频繁触发 | - -## 使用约定 - -- 工具函数使用**命名导出**(`export function xxx()`) -- 工具函数**不抛异常**,返回包含 `hasError` 和 `error` 字段的结果对象 -- Hook 使用 `use` 前缀命名,定义返回值接口类型 -- 存储操作使用 `chromeStorage.ts` 的 `storageUtil` 封装,不要直接调用 `chrome.storage` -- 消息通信使用 `messages.ts` 的 `sendMessage`/`onMessage`,不要使用原生 `chrome.runtime.sendMessage` diff --git a/vitest.config.ts b/vitest.config.ts index dd54924..ad42e97 100644 --- a/vitest.config.ts +++ b/vitest.config.ts @@ -24,7 +24,7 @@ export default defineConfig({ ], }, alias: { - '@': resolve(__dirname, './'), + '@': resolve(__dirname, './src'), }, }, }); diff --git a/wxt.config.ts b/wxt.config.ts index a3bf45f..27e02cb 100644 --- a/wxt.config.ts +++ b/wxt.config.ts @@ -44,6 +44,7 @@ function manualChunksForHtmlOnly(): Plugin { export default defineConfig({ modules: ['@wxt-dev/module-react'], + srcDir: 'src', manifest: { name: 'Testing Tool', description: 'A tool for testing web applications.',