98 lines
3.3 KiB
TypeScript
98 lines
3.3 KiB
TypeScript
import { ChevronLeft, ChevronRight, Radio } from "lucide-react";
|
|
import { Button } from "@/shared/ui/button";
|
|
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/shared/ui/select";
|
|
import type { PresentationHistoryControls } from "../utils/presentation-view-history";
|
|
|
|
const statusLabels = { running: "进行中", completed: "完成", error: "未完成", cancelled: "已取消" };
|
|
|
|
export function PresentationHistorySwitcher({
|
|
entries,
|
|
currentEntryId,
|
|
selectedId,
|
|
onSelect
|
|
}: PresentationHistoryControls) {
|
|
const currentEntry = entries.find((entry) => entry.id === currentEntryId);
|
|
const available = entries.filter(
|
|
(entry) => entry.status !== "running" && entry.id !== currentEntryId
|
|
);
|
|
const index =
|
|
selectedId === null
|
|
? available.length
|
|
: available.findIndex((entry) => entry.id === selectedId);
|
|
return (
|
|
<div className="mt-2 flex min-w-0 items-center gap-1" role="group" aria-label="展示动作历史">
|
|
<Button
|
|
type="button"
|
|
variant="ghost"
|
|
size="icon-sm"
|
|
className="size-8 shrink-0"
|
|
aria-label="上一个动作"
|
|
disabled={index <= 0}
|
|
onClick={() => onSelect(available[index - 1].id)}
|
|
>
|
|
<ChevronLeft size={14} aria-hidden />
|
|
</Button>
|
|
<Select
|
|
value={selectedId === null ? "current" : String(selectedId)}
|
|
onValueChange={(value) => onSelect(value === "current" ? null : Number(value))}
|
|
>
|
|
<SelectTrigger
|
|
aria-label="切换展示动作"
|
|
className="h-8 min-w-0 flex-1 px-2 text-xs [&>span]:truncate"
|
|
>
|
|
<SelectValue />
|
|
</SelectTrigger>
|
|
<SelectContent
|
|
position="popper"
|
|
sideOffset={4}
|
|
className="workbench-shadcn-surface z-[90] max-w-[calc(100vw-24px)]"
|
|
>
|
|
<SelectItem value="current" className="text-xs">
|
|
当前(最新)
|
|
{currentEntry ? ` · ${entries.indexOf(currentEntry) + 1}. ${currentEntry.label}` : ""} ·{" "}
|
|
{entries.length} 个动作
|
|
</SelectItem>
|
|
{entries
|
|
.slice()
|
|
.reverse()
|
|
.map((entry, position) =>
|
|
entry.id === currentEntryId ? null : (
|
|
<SelectItem
|
|
key={entry.id}
|
|
value={String(entry.id)}
|
|
disabled={entry.status === "running"}
|
|
className="whitespace-normal text-xs [&>span:last-child]:break-words"
|
|
>
|
|
{entries.length - position}. {entry.label} · {statusLabels[entry.status]}
|
|
</SelectItem>
|
|
)
|
|
)}
|
|
</SelectContent>
|
|
</Select>
|
|
<Button
|
|
type="button"
|
|
variant="ghost"
|
|
size="icon-sm"
|
|
className="size-8 shrink-0"
|
|
aria-label="下一个动作"
|
|
disabled={selectedId === null}
|
|
onClick={() => onSelect(index + 1 < available.length ? available[index + 1].id : null)}
|
|
>
|
|
<ChevronRight size={14} aria-hidden />
|
|
</Button>
|
|
{selectedId !== null ? (
|
|
<Button
|
|
type="button"
|
|
variant="secondary"
|
|
size="sm"
|
|
className="h-8 shrink-0 gap-1 px-2 text-[11px]"
|
|
onClick={() => onSelect(null)}
|
|
>
|
|
<Radio size={12} aria-hidden />
|
|
回到当前
|
|
</Button>
|
|
) : null}
|
|
</div>
|
|
);
|
|
}
|