57ea4d9858
- **docs**: 完善组件注释、README 目录结构及 AGENTS.md 文档。 - **refactor**: - 提取通用 `PageHeader`、`Button`、`DashboardCard` 及 `ErrorBoundary` 组件。 - 重构消息通信机制,采用 `@webext-core/messaging` 实现类型安全。 - 将全局通知系统重构为 `SnackbarProvider` (后合并至 `GlobalSnackbar`)。 - 迁移样式系统至 MUI 主题,移除冗余 CSS。 - 优化路由配置,支持独立标签页模式及页面懒加载。 - 移除未使用文件、URL 工具及表单映射相关功能。 - **feat**: - 新增配置导出功能(JSON)及状态提示。 - 新增侧边栏状态变化通知机制。 - 新增文本统计及 JWT 解析工具。 - 优化二维码生成与解析逻辑,换用更轻量的 `qrious` 和 `qr-scanner`。 - 增强高亮器功能,支持闪烁效果及 Shadow DOM 穿透。 - **style**: 优化仪表盘响应式网格布局及 UI 细节。 - **fix**: 修复 `useStorageState` 依赖缺失及路由初始化性能问题。 - **test**: 更新单元测试以覆盖新增的工具函数及功能特性。
153 lines
4.3 KiB
TypeScript
153 lines
4.3 KiB
TypeScript
import React, { ReactNode, lazy } from 'react';
|
|
import type { PageType } from '@/types/storage';
|
|
import AccessTimeIcon from '@mui/icons-material/AccessTime';
|
|
import StorageIcon from '@mui/icons-material/Storage';
|
|
import QrCodeIcon from '@mui/icons-material/QrCode';
|
|
import DescriptionIcon from '@mui/icons-material/Description';
|
|
import VpnKeyIcon from '@mui/icons-material/VpnKey';
|
|
|
|
import { THEME_COLORS } from './pageTheme';
|
|
|
|
// 懒加载页面组件
|
|
const DashboardPage = lazy(() => import('@/pages/DashboardPage'));
|
|
const TimestampPage = lazy(() => import('@/pages/TimestampPage'));
|
|
const StorageCleanerPage = lazy(() => import('@/pages/StorageCleanerPage'));
|
|
const QrCodePage = lazy(() => import('@/pages/QrCodePage'));
|
|
const TextStatisticsPage = lazy(() => import('@/pages/TextStatisticsPage'));
|
|
const JwtPage = lazy(() => import('@/pages/JwtPage'));
|
|
|
|
/**
|
|
* 功能配置接口
|
|
*
|
|
* 整合了路由信息和仪表盘卡片元数据,作为功能的单一事实来源
|
|
*/
|
|
export interface FeatureConfig {
|
|
/** 页面类型标识 */
|
|
key: PageType;
|
|
/** 功能名称(用于路由标签和卡片标题) */
|
|
label: string;
|
|
/** 功能描述(用于仪表盘卡片) */
|
|
description: string;
|
|
/** 主题颜色(用于仪表盘卡片) */
|
|
themeColor?: string;
|
|
/** 图标组件(用于仪表盘卡片) */
|
|
icon?: ReactNode;
|
|
/** 默认是否在仪表盘显示 */
|
|
defaultVisible: boolean;
|
|
/** 不同显示模式对应的组件 */
|
|
components: {
|
|
/** 弹窗模式组件 */
|
|
popup: React.ComponentType;
|
|
/** 侧边栏模式组件 */
|
|
sidepanel: React.ComponentType;
|
|
/** 标签页模式组件 */
|
|
tab: React.ComponentType;
|
|
};
|
|
}
|
|
|
|
export const FEATURES: FeatureConfig[] = [
|
|
{
|
|
key: 'dashboard',
|
|
label: 'Dashboard',
|
|
description: '',
|
|
defaultVisible: true,
|
|
components: {
|
|
popup: DashboardPage,
|
|
sidepanel: DashboardPage,
|
|
tab: DashboardPage,
|
|
},
|
|
},
|
|
{
|
|
key: 'timestamp',
|
|
label: '时间戳',
|
|
description: 'Unix 毫秒数转换与格式化',
|
|
themeColor: THEME_COLORS.primary,
|
|
icon: <AccessTimeIcon sx={{ fontSize: 20 }} />,
|
|
defaultVisible: true,
|
|
components: {
|
|
popup: TimestampPage,
|
|
sidepanel: TimestampPage,
|
|
tab: TimestampPage,
|
|
},
|
|
},
|
|
{
|
|
key: 'storageCleaner',
|
|
label: '存储清理',
|
|
description: '清理缓存、Cookies 及本地存储',
|
|
themeColor: THEME_COLORS.warning,
|
|
icon: <StorageIcon sx={{ fontSize: 20 }} />,
|
|
defaultVisible: true,
|
|
components: {
|
|
popup: StorageCleanerPage,
|
|
sidepanel: StorageCleanerPage,
|
|
tab: StorageCleanerPage,
|
|
},
|
|
},
|
|
{
|
|
key: 'qrCode',
|
|
label: '二维码工具',
|
|
description: '生成当前选中的 URL 的二维码',
|
|
themeColor: THEME_COLORS.success,
|
|
icon: <QrCodeIcon sx={{ fontSize: 20 }} />,
|
|
defaultVisible: true,
|
|
components: {
|
|
popup: QrCodePage,
|
|
sidepanel: QrCodePage,
|
|
tab: QrCodePage,
|
|
},
|
|
},
|
|
{
|
|
key: 'textStatistics',
|
|
label: '文本统计',
|
|
description: '实时分析文本字符、单词及字节',
|
|
themeColor: THEME_COLORS.purple,
|
|
icon: <DescriptionIcon sx={{ fontSize: 20 }} />,
|
|
defaultVisible: true,
|
|
components: {
|
|
popup: TextStatisticsPage,
|
|
sidepanel: TextStatisticsPage,
|
|
tab: TextStatisticsPage,
|
|
},
|
|
},
|
|
{
|
|
key: 'jwt',
|
|
label: 'JWT 解析',
|
|
description: 'JSON Web Token 解码与查看',
|
|
themeColor: THEME_COLORS.indigo,
|
|
icon: <VpnKeyIcon sx={{ fontSize: 20 }} />,
|
|
defaultVisible: true,
|
|
components: {
|
|
popup: JwtPage,
|
|
sidepanel: JwtPage,
|
|
tab: JwtPage,
|
|
},
|
|
},
|
|
];
|
|
|
|
export function getFeatureByKey(key: PageType): FeatureConfig | undefined {
|
|
return FEATURES.find((f) => f.key === key);
|
|
}
|
|
|
|
export function getDefaultVisibleFeatureKeys(): PageType[] {
|
|
return FEATURES.filter((f) => f.defaultVisible).map((f) => f.key);
|
|
}
|
|
|
|
export function getAllFeatureKeys(): PageType[] {
|
|
return FEATURES.map((f) => f.key);
|
|
}
|
|
|
|
export function getDefaultPageOrder(): PageType[] {
|
|
return FEATURES.filter((f) => f.key !== 'dashboard').map((f) => f.key);
|
|
}
|
|
|
|
export function getEntryPointType(): 'popup' | 'sidepanel' | 'tab' {
|
|
const pathname = window.location.pathname;
|
|
if (pathname.includes('sidepanel')) {
|
|
return 'sidepanel';
|
|
}
|
|
if (new URLSearchParams(window.location.search).get('mode') === 'tab') {
|
|
return 'tab';
|
|
}
|
|
return 'popup';
|
|
}
|