diff --git a/entrypoints/popup/App.tsx b/entrypoints/popup/App.tsx index 3a6f405..ea6dcc2 100644 --- a/entrypoints/popup/App.tsx +++ b/entrypoints/popup/App.tsx @@ -1,5 +1,8 @@ // App.js import { HashRouter as Router, Routes, Route } from 'react-router-dom'; +import { ThemeProvider, createTheme } from '@mui/material/styles'; +import CssBaseline from '@mui/material/CssBaseline'; +import { SnackbarProvider } from 'notistack'; import TimestampPage from './pages/TimestampPage'; import RecordeReplayPage from './pages/RecordeReplayPage'; import Navbar from './components/Navbar'; @@ -13,19 +16,23 @@ const navItems = [ { path: '/recorde-replay', label: '录制与回放', element: }, ]; +const theme = createTheme(); + function App() { return ( -
- - - - {navItems.map((item) => ( - - ))} - -
+ + + + + + {navItems.map((item) => ( + + ))} + + +
); } diff --git a/entrypoints/popup/components/CopyButton.tsx b/entrypoints/popup/components/CopyButton.tsx deleted file mode 100644 index fd196bf..0000000 --- a/entrypoints/popup/components/CopyButton.tsx +++ /dev/null @@ -1,134 +0,0 @@ -import { useState, useCallback, FC, ReactNode, useEffect } from 'react'; -import Button, { ButtonProps } from '@mui/material/Button'; -import Snackbar from '@mui/material/Snackbar'; -import Alert, { AlertColor } from '@mui/material/Alert'; -import ContentCopyIcon from '@mui/icons-material/ContentCopy'; -import CheckIcon from '@mui/icons-material/Check'; - -type CopyStatus = 'idle' | 'copying' | 'success' | 'error'; - -interface CopyButtonProps extends Omit { - textToCopy: string | number; - buttonText?: ReactNode; - successMessage?: string; - errorMessage?: string; - variant?: ButtonProps['variant']; -} - -const CopyButton: FC = ({ - textToCopy, - buttonText = '复制', - successMessage = '复制成功!', - errorMessage = '复制失败,请手动复制。', - variant = 'contained', - ...buttonProps -}) => { - const [status, setStatus] = useState('idle'); - const [openSnackbar, setOpenSnackbar] = useState(false); - const [snackbarContent, setSnackbarContent] = useState<{ - message: string; - severity: AlertColor; - } | null>(null); - - useEffect(() => { - if (status === 'success' || status === 'error') { - const timer = setTimeout(() => setStatus('idle'), 2000); - return () => clearTimeout(timer); - } - return undefined; - }, [status]); - - const performCopy = useCallback(async () => { - if (!textToCopy) { - console.warn('没有提供要复制的文本'); - return false; - } - const safeText = String(textToCopy); - try { - await navigator.clipboard.writeText(safeText); - return true; - } catch (err) { - console.error('使用 Clipboard API 复制失败:', err); - return false; - } - }, [textToCopy]); - - const handleClick = useCallback(async () => { - if (status !== 'idle') return; - - setStatus('copying'); - let isSuccess = false; - try { - [isSuccess] = await Promise.all([ - performCopy(), - new Promise((resolve) => setTimeout(resolve, 300)), - ]); - } catch (error) { - console.error('复制时出错:', error); - isSuccess = false; - } finally { - const newStatus = isSuccess ? 'success' : 'error'; - setStatus(newStatus); - setSnackbarContent({ - message: isSuccess ? successMessage : errorMessage, - severity: newStatus, - }); - setOpenSnackbar(true); - } - }, [performCopy, status, successMessage, errorMessage]); - - const handleCloseSnackbar = (_event?: Event | React.SyntheticEvent, reason?: string) => { - if (reason === 'clickaway') return; - setOpenSnackbar(false); - }; - - const renderButtonIcon = () => { - if (status === 'success') { - return ; - } - return ; - }; - - return ( - <> - - - {snackbarContent ? ( - - {snackbarContent.message} - - ) : undefined} - - - ); -}; - -export default CopyButton; diff --git a/entrypoints/popup/components/TimestampExecution.tsx b/entrypoints/popup/components/TimestampExecution.tsx index 279562a..72cf8cd 100644 --- a/entrypoints/popup/components/TimestampExecution.tsx +++ b/entrypoints/popup/components/TimestampExecution.tsx @@ -1,6 +1,8 @@ import { useEffect, useState, useCallback } from 'react'; -import CopyButton from './CopyButton'; import { Button, Paper, Typography, Stack, Box } from '@mui/material'; +import ContentCopyIcon from '@mui/icons-material/ContentCopy'; +import CheckIcon from '@mui/icons-material/Check'; +import { useCopy } from './useCopy'; /** * 时间戳显示和执行组件 @@ -14,9 +16,7 @@ import { Button, Paper, Typography, Stack, Box } from '@mui/material'; * @returns {JSX.Element} 时间戳组件 */ export function TimestampExecution() { - const [currentTimestamp, setCurrentTimestamp] = useState(() => - Math.floor(Date.now()), - ); + const [currentTimestamp, setCurrentTimestamp] = useState(() => Math.floor(Date.now())); const [showMilliseconds, setShowMilliseconds] = useState(true); const [isRunningTimestamp, setIsRunningTimestamp] = useState(true); @@ -45,19 +45,14 @@ export function TimestampExecution() { setIsRunningTimestamp((prev) => !prev); }, []); - const unitButtonLabel = showMilliseconds - ? '切换为秒显示' - : '切换为毫秒显示'; - const toggleButtonLabel = isRunningTimestamp - ? '停止时间戳自动更新' - : '开始时间戳自动更新'; + const unitButtonLabel = showMilliseconds ? '切换为秒显示' : '切换为毫秒显示'; + const toggleButtonLabel = isRunningTimestamp ? '停止时间戳自动更新' : '开始时间戳自动更新'; const toggleButtonText = isRunningTimestamp ? '停止' : '开始'; + const { isCopied, copy } = useCopy(); + return ( - + - + /> */} + +