Files
twotalesanimation e24fd8eda0
Deploy / deploy (push) Successful in 3m5s
Supervisor feature
2026-07-11 15:06:12 +02:00

105 lines
3.9 KiB
TypeScript

"use client";
import { cn } from "@/lib/utils";
import type { FullTake } from "./TakeEditorPanel";
// Fields to compare (label → key)
const COMPARE_FIELDS: { label: string; key: keyof FullTake; format?: (v: unknown) => string }[] = [
{ label: "Scene", key: "scene" },
{ label: "Shot", key: "shotLabel" },
{ label: "Camera", key: "cameraLetter" },
{ label: "Clip Name", key: "clipName" },
{ label: "Camera Model", key: "cameraModel" },
{ label: "Resolution", key: "resolution" },
{ label: "Codec", key: "codec" },
{ label: "FPS", key: "fps" },
{ label: "Shutter", key: "shutter" },
{ label: "ISO", key: "iso" },
{ label: "White Balance", key: "whiteBalance" },
{ label: "Colour Space", key: "colourSpace" },
{ label: "Lens Set", key: "lensSet" },
{ label: "Lens", key: "lens" },
{ label: "T Stop", key: "tStop" },
{ label: "Filters", key: "filters" },
{ label: "Anamorphic", key: "isAnamorphic", format: (v) => (v ? "Yes" : "No") },
{ label: "Weather", key: "weather" },
{ label: "Sun Direction", key: "sunDirection" },
];
function display(value: unknown, format?: (v: unknown) => string): string {
if (value === null || value === undefined || value === "") return "—";
if (format) return format(value);
return String(value);
}
function isChanged(a: unknown, b: unknown): boolean {
if (a === null || a === undefined) a = "";
if (b === null || b === undefined) b = "";
return String(a) !== String(b);
}
interface Props {
current: FullTake;
previous: FullTake;
}
export function PreviousTakePanel({ current, previous }: Props) {
const changedFields = COMPARE_FIELDS.filter(({ key, format }) =>
isChanged(display(current[key], format), display(previous[key], format))
);
const unchangedFields = COMPARE_FIELDS.filter(({ key, format }) =>
!isChanged(display(current[key], format), display(previous[key], format))
);
return (
<div className="rounded-lg border border-zinc-800 bg-zinc-900/40 overflow-hidden text-xs">
<div className="grid grid-cols-[1fr_1fr_1fr] border-b border-zinc-800">
<div className="px-3 py-2 text-zinc-600 font-semibold uppercase tracking-wider text-[10px]">Field</div>
<div className="px-3 py-2 text-zinc-600 font-semibold uppercase tracking-wider text-[10px]">
T{previous.takeNumber} (prev)
</div>
<div className="px-3 py-2 text-zinc-600 font-semibold uppercase tracking-wider text-[10px]">
T{current.takeNumber} (current)
</div>
</div>
{/* Changed fields — highlighted */}
{changedFields.map(({ label, key, format }) => (
<div
key={String(key)}
className="grid grid-cols-[1fr_1fr_1fr] border-b border-zinc-800 bg-amber-500/5"
>
<div className="px-3 py-2 text-amber-400/70 font-medium">{label}</div>
<div className="px-3 py-2 text-zinc-400 line-through">
{display(previous[key], format)}
</div>
<div className="px-3 py-2 text-amber-300 font-semibold">
{display(current[key], format)}
</div>
</div>
))}
{/* Unchanged fields */}
{unchangedFields.map(({ label, key, format }) => {
const val = display(current[key], format);
if (val === "—") return null;
return (
<div
key={String(key)}
className="grid grid-cols-[1fr_1fr_1fr] border-b border-zinc-800/50 opacity-50"
>
<div className="px-3 py-1.5 text-zinc-500">{label}</div>
<div className="px-3 py-1.5 text-zinc-400">{val}</div>
<div className="px-3 py-1.5 text-zinc-400">{val}</div>
</div>
);
})}
{changedFields.length === 0 && (
<div className="px-3 py-3 text-zinc-600 italic">No changes from previous take.</div>
)}
</div>
);
}