71 lines
2.7 KiB
React
71 lines
2.7 KiB
React
import React from 'react';
|
||
import Box from '@mui/material/Box';
|
||
import Typography from '@mui/material/Typography';
|
||
import Button from '@mui/material/Button';
|
||
|
||
/* ============================================================
|
||
* SidebarPane:VSCode 风格侧边栏容器(一侧一个)
|
||
*
|
||
* - 该侧全部 sidebar 模式视图**常驻挂载**(display 显隐切换),
|
||
* 切换视图/切标签页不丢编辑状态(记事本草稿、密码箱解锁态)
|
||
* - 每个视图由 ToolWindow 提供标题栏;内容按 activeView 显示
|
||
* - 视图处于 tab 模式时该视图不在侧栏 → 显示占位 + 「移回侧边栏」
|
||
* - 无障碍:容器 id=wb-sidebar-{side} 供活动栏 aria-controls;
|
||
* aria-live 播报当前视图,配合活动栏焦点提示
|
||
* ============================================================ */
|
||
|
||
export default function SidebarPane({ side, views, activeId, renderView, renderPlaceholder }) {
|
||
const right = side === 'right';
|
||
const activeView = views.find((v) => v.id === activeId);
|
||
return (
|
||
<Box
|
||
component="aside"
|
||
id={`wb-sidebar-${side}`}
|
||
aria-label={right ? '右侧侧边栏' : '左侧侧边栏'}
|
||
sx={{
|
||
height: '100%', minWidth: 0, overflow: 'hidden', position: 'relative',
|
||
display: 'flex', flexDirection: 'column',
|
||
bgcolor: 'background.paper',
|
||
}}
|
||
>
|
||
{/* 活动栏激活后的屏幕阅读器播报(视觉隐藏) */}
|
||
<Box
|
||
aria-live="polite"
|
||
sx={{
|
||
position: 'absolute', width: 1, height: 1, overflow: 'hidden',
|
||
clip: 'rect(0 0 0 0)', whiteSpace: 'nowrap', m: -1, p: 0, border: 0,
|
||
}}
|
||
>
|
||
{activeView ? `当前视图:${activeView.label}` : '侧边栏为空'}
|
||
</Box>
|
||
|
||
{views.map((v) => {
|
||
const active = activeId === v.id;
|
||
return (
|
||
<Box
|
||
key={v.id}
|
||
sx={{
|
||
flex: 1, minHeight: 0, display: active ? 'flex' : 'none',
|
||
flexDirection: 'column',
|
||
}}
|
||
>
|
||
{renderView(v.id)}
|
||
</Box>
|
||
);
|
||
})}
|
||
{views.length === 0 && (
|
||
<Box sx={{ flex: 1, display: 'flex', alignItems: 'center', justifyContent: 'center', px: 3, textAlign: 'center' }}>
|
||
<Typography variant="caption" sx={{ color: 'text.disabled' }}>
|
||
从另一侧活动栏拖一个功能标签到这里
|
||
</Typography>
|
||
</Box>
|
||
)}
|
||
{views.length > 0 && !views.some((v) => v.id === activeId) && renderPlaceholder && (
|
||
<Box sx={{ flex: 1, minHeight: 0, display: 'flex', flexDirection: 'column', alignItems: 'center', justifyContent: 'center', gap: 1, px: 3, textAlign: 'center' }}>
|
||
{renderPlaceholder()}
|
||
</Box>
|
||
)}
|
||
</Box>
|
||
);
|
||
}
|