feat(web-platform): release V0.8.3 常规界面优化
web-platform-release / Build and publish release (push) Has been cancelled
web-platform-ci / TypeScript, lint, unit, build (push) Has been cancelled
web-platform-ci / Playwright E2E (push) Has been cancelled
web-platform-ci / TypeScript, lint, unit, build (pull_request) Has been cancelled
web-platform-ci / Playwright E2E (pull_request) Has been cancelled
web-platform-release / Build and publish release (push) Has been cancelled
web-platform-ci / TypeScript, lint, unit, build (push) Has been cancelled
web-platform-ci / Playwright E2E (push) Has been cancelled
web-platform-ci / TypeScript, lint, unit, build (pull_request) Has been cancelled
web-platform-ci / Playwright E2E (pull_request) Has been cancelled
This commit is contained in:
@@ -0,0 +1,65 @@
|
||||
import { Database, PanelRight, SlidersHorizontal, type LucideIcon } from 'lucide-react';
|
||||
|
||||
export type RightSidebarView = 'inspector' | 'controls' | 'data';
|
||||
|
||||
const VIEWS: ReadonlyArray<{
|
||||
value: RightSidebarView;
|
||||
label: string;
|
||||
icon: LucideIcon;
|
||||
}> = [
|
||||
{ value: 'inspector', label: '检查器', icon: PanelRight },
|
||||
{ value: 'controls', label: '控制台', icon: SlidersHorizontal },
|
||||
{ value: 'data', label: '数据录制', icon: Database },
|
||||
];
|
||||
|
||||
export function RightSidebarTabs({
|
||||
value,
|
||||
onChange,
|
||||
}: {
|
||||
value: RightSidebarView;
|
||||
onChange: (value: RightSidebarView) => void;
|
||||
}) {
|
||||
return (
|
||||
<div
|
||||
role="tablist"
|
||||
aria-label="右侧工作区视图"
|
||||
className="grid shrink-0 grid-cols-3 gap-1 border-b border-border bg-panel-muted/40 p-2"
|
||||
>
|
||||
{VIEWS.map((view, index) => {
|
||||
const Icon = view.icon;
|
||||
const selected = value === view.value;
|
||||
return (
|
||||
<button
|
||||
key={view.value}
|
||||
type="button"
|
||||
role="tab"
|
||||
aria-selected={selected}
|
||||
tabIndex={selected ? 0 : -1}
|
||||
className={`flex min-w-0 items-center justify-center gap-1.5 rounded-md px-1 py-2 text-[11px] font-medium transition-colors ${
|
||||
selected
|
||||
? 'bg-panel text-accent shadow-sm'
|
||||
: 'text-text-tertiary hover:bg-element-hover hover:text-text-primary'
|
||||
}`}
|
||||
onClick={() => onChange(view.value)}
|
||||
onKeyDown={(event) => {
|
||||
let nextIndex: number | undefined;
|
||||
if (event.key === 'ArrowLeft') nextIndex = (index + VIEWS.length - 1) % VIEWS.length;
|
||||
else if (event.key === 'ArrowRight') nextIndex = (index + 1) % VIEWS.length;
|
||||
else if (event.key === 'Home') nextIndex = 0;
|
||||
else if (event.key === 'End') nextIndex = VIEWS.length - 1;
|
||||
if (nextIndex === undefined) return;
|
||||
event.preventDefault();
|
||||
onChange(VIEWS[nextIndex].value);
|
||||
const tabs =
|
||||
event.currentTarget.parentElement?.querySelectorAll<HTMLElement>('[role="tab"]');
|
||||
tabs?.[nextIndex]?.focus();
|
||||
}}
|
||||
>
|
||||
<Icon className="h-3.5 w-3.5 shrink-0" aria-hidden="true" />
|
||||
<span className="truncate">{view.label}</span>
|
||||
</button>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user