feat(observation): add dynamic camera sources

This commit is contained in:
DCCONSTRUCTIONS
2026-07-16 20:56:41 +03:00
parent 05bdab24a5
commit a281faf923
15 changed files with 1592 additions and 52 deletions
@@ -0,0 +1,52 @@
import { Button, Icon } from "@nodedc/ui-react";
import type { ObservationTimelineMode } from "../core/runtime/contracts";
export function ObservationTimeline({
active,
sourceCount,
mode = "live-only",
seekable = false,
synchronization = "host-arrival-best-effort",
className = "",
}: {
active: boolean;
sourceCount: number;
mode?: ObservationTimelineMode;
seekable?: boolean;
synchronization?: "host-arrival-best-effort" | "shared-clock" | "frame-accurate";
className?: string;
}) {
const buffered = seekable && (mode === "buffered" || mode === "recorded");
const synchronizationLabel = {
"host-arrival-best-effort": "Синхронизация по приходу",
"shared-clock": "Общие часы",
"frame-accurate": "Покадровая синхронизация",
}[synchronization];
return (
<div
className={`observation-timeline ${className}`.trim()}
data-active={active ? "true" : undefined}
data-mode={mode}
>
<Button size="compact" variant="ghost" disabled aria-label="Перейти к началу">
<Icon name="chevron-left" />
</Button>
<Button size="compact" variant="secondary" disabled>
{buffered ? "Воспроизвести" : "Только эфир"}
</Button>
<div className="observation-timeline__track" data-disabled={!buffered ? "true" : undefined}>
<span style={{ width: active ? "100%" : "0%" }} />
</div>
<div className="observation-timeline__meta">
<code>{active ? "LIVE" : "—:—:—.———"}</code>
<small>
{buffered ? `${sourceCount} каналов` : `${synchronizationLabel} · буфер не включён`}
</small>
</div>
<span className="observation-timeline__follow" data-active={active ? "true" : undefined}>
ЭФИР
</span>
</div>
);
}