feat(observation): add dynamic camera sources
This commit is contained in:
@@ -0,0 +1,78 @@
|
||||
import type { RefObject } from "react";
|
||||
import { WorkspaceWindow } from "@nodedc/ui-react";
|
||||
|
||||
import type { ObservationWindowRect } from "../core/observation/useObservationLayout";
|
||||
import type { ObservationSourceDescriptor } from "../core/runtime/contracts";
|
||||
import { ObservationMedia, observationSourceStatusLabel } from "./ObservationSources";
|
||||
|
||||
export function initialObservationWindowRect(index: number): ObservationWindowRect {
|
||||
return {
|
||||
x: 18 + (index % 3) * 354,
|
||||
y: 78 + Math.floor(index / 3) * 226,
|
||||
width: 336,
|
||||
height: 210,
|
||||
};
|
||||
}
|
||||
|
||||
export function FloatingObservationWindow({
|
||||
source,
|
||||
index,
|
||||
boundsRef,
|
||||
rect,
|
||||
maximized,
|
||||
active,
|
||||
onRectChange,
|
||||
onMaximizedChange,
|
||||
onActivate,
|
||||
onClose,
|
||||
}: {
|
||||
source: ObservationSourceDescriptor;
|
||||
index: number;
|
||||
boundsRef: RefObject<HTMLElement | null>;
|
||||
rect?: ObservationWindowRect;
|
||||
maximized: boolean;
|
||||
active: boolean;
|
||||
onRectChange: (rect: ObservationWindowRect) => void;
|
||||
onMaximizedChange: (maximized: boolean) => void;
|
||||
onActivate: () => void;
|
||||
onClose: () => void;
|
||||
}) {
|
||||
return (
|
||||
<WorkspaceWindow
|
||||
boundsRef={boundsRef}
|
||||
rect={rect ?? initialObservationWindowRect(index)}
|
||||
onRectChange={onRectChange}
|
||||
maximized={maximized}
|
||||
onMaximizedChange={onMaximizedChange}
|
||||
onActivate={onActivate}
|
||||
onClose={onClose}
|
||||
title={source.label}
|
||||
subtitle={source.description}
|
||||
status={(
|
||||
<span className="floating-observation-window__status">
|
||||
<i data-availability={source.availability} aria-hidden="true" />
|
||||
{observationSourceStatusLabel(source)}
|
||||
</span>
|
||||
)}
|
||||
footer={(
|
||||
<span className="floating-observation-window__footer">
|
||||
<span>{source.endpointLabel || source.transport}</span>
|
||||
<span>{source.capabilities.timelineMode === "live-only" ? "Эфир без буфера" : "Временная шкала"}</span>
|
||||
</span>
|
||||
)}
|
||||
minWidth={280}
|
||||
minHeight={190}
|
||||
resizable={source.capabilities.resizable}
|
||||
active={active}
|
||||
zIndex={maximized ? 15 : active ? 9 : 7}
|
||||
className="floating-observation-window"
|
||||
closeLabel={`Закрыть ${source.label}`}
|
||||
maximizeLabel={`Развернуть ${source.label}`}
|
||||
restoreLabel={`Восстановить ${source.label}`}
|
||||
moveLabel={`Переместить ${source.label}`}
|
||||
resizeLabel={`Изменить размер ${source.label}`}
|
||||
>
|
||||
<ObservationMedia source={source} />
|
||||
</WorkspaceWindow>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user