Develop fastapi (#6)
* feat: add side panel with navigation and storage cleaner functionality * feat: add OpenUrlPage and integrate into app navigation * feat: 添加 GlobalSnackbar 组件并在多个页面中集成,替换原有 Snackbar 实现 * feat: fix OpenUrl sidebar issue with architecture refactor - 修复原问题:不再直接替换侧边栏 URL,保持插件导航可见 - 采用配置页 + 查看页分离架构:OpenUrlPage (配置) + OpenUrlViewerPage (查看) - 支持多个 URL 快捷方式管理(添加/删除) - 每个 URL 提供两种打开方式:在侧边栏打开 / 在新标签页打开 - 侧边栏查看页使用 iframe 占满全部剩余空间 - 更新 TypeScript 类型定义 - 保留原有混合内容警告检查 - 数据持久化到 Chrome Storage * refactor: centralized route management - consolidate routing config into single source * feat: 更换logo * refactor: code review fixes - security and race condition improvements Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> Changes: - wxt.config.ts: Remove unused `debugger` permission (no code uses it) - OpenUrlPage.tsx: Fix unreachable showMessage after window.close() - OpenUrlPage.tsx: Replace unnecessary div wrapper with Fragment to reduce DOM nesting - OpenUrlViewerPage.tsx: Add URL validation to prevent XSS via javascript:/data: URLs - OpenUrlViewerPage.tsx: Add sandbox attribute to iframe for security isolation - OpenUrlViewerPage.tsx: Add error handling for invalid URLs - StorageCleanerPage.tsx: Fix race condition in handleOptionChange preference saving - StorageCleanerPage.tsx: Remove unnecessary storage reads when saving preferences (use state directly) - StorageCleanerPage.tsx: Add timeout cleanup for setTimeout to follow React best practices * feat: implement drill-down navigation with master-detail dashboard * feat: enhance dashboard dynamism and refine options UI * feat: overhaul storage cleaner UI with real-time size estimation and modern aesthetics * feat: overhaul TimestampPage UI/UX and fix GlobalSnackbar positioning * fix: decouple popup routing from storage sync and enhance OpenUrlPage UI * fix: avoid closing sidepanel when opening URL preview from within sidepanel
This commit is contained in:
@@ -0,0 +1,91 @@
|
||||
/* 极简滚动条变量 */
|
||||
:root {
|
||||
/* 统一圆角变量 */
|
||||
--radius: 8px;
|
||||
/* 统一背景颜色变量 */
|
||||
--bg-color: #fafafa;
|
||||
/* 统一文字颜色变量 */
|
||||
--text-color: #333333;
|
||||
/* 统一按钮颜色变量 */
|
||||
--btn-bg: #e0e0e0;
|
||||
/* 统一按钮文字颜色变量 */
|
||||
--btn-text: #333333;
|
||||
--border: 1px solid #e0e0e0;
|
||||
|
||||
/* 滚动条变量 */
|
||||
--sb-width: 6px;
|
||||
--sb-thumb-color: rgba(0, 0, 0, 0.1);
|
||||
--sb-thumb-hover: rgba(0, 0, 0, 0.2);
|
||||
--sb-track-color: transparent;
|
||||
}
|
||||
|
||||
/* 适配侧边栏 - 使用百分比而非固定尺寸 */
|
||||
html,
|
||||
body,
|
||||
#root {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
width: 100%;
|
||||
height: 100vh;
|
||||
overflow: hidden; /* 禁用外层滚动 */
|
||||
}
|
||||
|
||||
/* 全局极简滚动条定制 */
|
||||
*::-webkit-scrollbar {
|
||||
width: var(--sb-width);
|
||||
}
|
||||
|
||||
*::-webkit-scrollbar-track {
|
||||
background: var(--sb-track-color);
|
||||
}
|
||||
|
||||
*::-webkit-scrollbar-thumb {
|
||||
background: var(--sb-thumb-color);
|
||||
border-radius: 10px;
|
||||
background-clip: content-box;
|
||||
border: 1px solid transparent;
|
||||
}
|
||||
|
||||
*::-webkit-scrollbar-thumb:hover {
|
||||
background: var(--sb-thumb-hover);
|
||||
}
|
||||
|
||||
.app {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
box-sizing: border-box;
|
||||
font-family:
|
||||
-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
|
||||
overflow: hidden; /* 内部由 flex 子项控制滚动 */
|
||||
}
|
||||
|
||||
/* Animations */
|
||||
@keyframes slideInRight {
|
||||
from {
|
||||
transform: translateX(30px);
|
||||
opacity: 0;
|
||||
}
|
||||
to {
|
||||
transform: translateX(0);
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes fadeIn {
|
||||
from {
|
||||
opacity: 0;
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.page-transition-enter {
|
||||
animation: slideInRight 0.3s cubic-bezier(0.25, 0.8, 0.25, 1) forwards;
|
||||
}
|
||||
|
||||
.page-transition-dashboard {
|
||||
animation: fadeIn 0.3s ease-out forwards;
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
import './App.css';
|
||||
import RouterProvider from '@/providers/RouterProvider';
|
||||
import TopBar from '@/components/TopBar';
|
||||
import RouterContainer from '@/components/RouterContainer';
|
||||
|
||||
function App() {
|
||||
const handleOpenOptions = () => {
|
||||
chrome.runtime.openOptionsPage();
|
||||
};
|
||||
|
||||
return (
|
||||
<RouterProvider defaultRoute="dashboard">
|
||||
<div className="app" style={{ display: 'flex', flexDirection: 'column', height: '100vh', overflow: 'hidden' }}>
|
||||
<TopBar onOpenOptions={handleOpenOptions} />
|
||||
<RouterContainer />
|
||||
</div>
|
||||
</RouterProvider>
|
||||
);
|
||||
}
|
||||
|
||||
export default App;
|
||||
@@ -0,0 +1,12 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Testing Tools - Side Panel</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="root"></div>
|
||||
<script type="module" src="./main.tsx"></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,10 @@
|
||||
import React from 'react';
|
||||
import ReactDOM from 'react-dom/client';
|
||||
import App from './App.tsx';
|
||||
import './style.css';
|
||||
|
||||
ReactDOM.createRoot(document.getElementById('root')!).render(
|
||||
<React.StrictMode>
|
||||
<App />
|
||||
</React.StrictMode>,
|
||||
);
|
||||
@@ -0,0 +1,22 @@
|
||||
body {
|
||||
margin: 0;
|
||||
font-family:
|
||||
-apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Ubuntu', 'Cantarell', 'Fira Sans',
|
||||
'Droid Sans', 'Helvetica Neue', sans-serif;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
}
|
||||
|
||||
code {
|
||||
font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', monospace;
|
||||
}
|
||||
|
||||
h1,
|
||||
h2,
|
||||
h3,
|
||||
h4,
|
||||
h5,
|
||||
h6 {
|
||||
font-size: inherit; /* 先全部重置为继承大小 */
|
||||
font-weight: inherit;
|
||||
}
|
||||
Reference in New Issue
Block a user