refactor: 统一扩展消息机制并优化组件结构

1、统一消息系统:将 background、content 和 popup 的通信方式从原生的 chrome.runtime 迁移至 @webext-core/messaging,修复了消息回调返回 undefined 的问题。
2、优化组件结构:将通用组件从 entrypoints/popup/components 迁移至根目录 components,并使用 MUI 重构了 Navbar。
3、同步更新:调整了录制工具 (useRecorder) 和各页面组件(RecordeReplayPage, TestPage等),以适配新的消息协议和组件路径。
This commit is contained in:
雨霖铃
2026-02-13 20:38:15 +08:00
parent 22985f4c18
commit 50034331bc
16 changed files with 252 additions and 271 deletions
+117
View File
@@ -0,0 +1,117 @@
import { NavLink, useLocation } from 'react-router-dom';
import { useState, ReactNode, MouseEvent } from 'react';
import {
AppBar,
Box,
IconButton,
Menu,
MenuItem,
Tab,
Tabs,
Toolbar,
useMediaQuery,
} from '@mui/material';
import MenuIcon from '@mui/icons-material/Menu';
interface RouteItem {
path: string;
label: string;
element: ReactNode;
}
interface NavbarProps {
items?: RouteItem[];
}
function Navbar({ items = [] }: NavbarProps) {
const [anchorEl, setAnchorEl] = useState<null | HTMLElement>(null);
const isMenuOpen = Boolean(anchorEl);
const location = useLocation();
// Replicating the screen size logic from original component
const isLargeScreen = useMediaQuery('(min-width:768px)');
const isMediumScreen = useMediaQuery('(min-width:480px)');
let visibleItemsCount: number;
if (isLargeScreen) {
visibleItemsCount = items.length;
} else if (isMediumScreen) {
visibleItemsCount = Math.min(3, items.length);
} else {
// Small screen
visibleItemsCount = Math.min(2, items.length);
}
const visibleNavItems = items.slice(0, visibleItemsCount);
const collapsedNavItems = items.slice(visibleItemsCount);
const handleMenuOpen = (event: MouseEvent<HTMLElement>) => {
setAnchorEl(event.currentTarget);
};
const handleMenuClose = () => {
setAnchorEl(null);
};
// Find the current active tab index for the Tabs value
// Using startsWith to handle nested routes correctly.
const activeTabIndex = visibleNavItems.findIndex((item) =>
location.pathname.startsWith(item.path),
);
return (
<AppBar
position="static"
color="default"
elevation={0}
sx={{ backgroundColor: 'transparent', borderBottom: 1, borderColor: 'divider' }}
>
<Toolbar sx={{ justifyContent: 'center', position: 'relative' }}>
<Tabs
value={activeTabIndex === -1 ? false : activeTabIndex}
variant="scrollable"
scrollButtons="auto"
allowScrollButtonsMobile
aria-label="navigation tabs"
>
{visibleNavItems.map((item) => (
<Tab key={item.path} label={item.label} component={NavLink} to={item.path} />
))}
</Tabs>
{collapsedNavItems.length > 0 && (
<Box sx={{ position: 'absolute', right: 8 }}>
<IconButton color="inherit" aria-label="open menu" edge="end" onClick={handleMenuOpen}>
<MenuIcon />
</IconButton>
<Menu
anchorEl={anchorEl}
open={isMenuOpen}
onClose={handleMenuClose}
PaperProps={{
style: {
maxHeight: 48 * 4.5,
width: '20ch',
},
}}
>
{collapsedNavItems.map((item) => (
<MenuItem
key={item.path}
component={NavLink}
to={item.path}
onClick={handleMenuClose}
selected={location.pathname.startsWith(item.path)}
>
{item.label}
</MenuItem>
))}
</Menu>
</Box>
)}
</Toolbar>
</AppBar>
);
}
export default Navbar;