@@ -7,6 +7,7 @@ import { TakeListPanel } from "./TakeListPanel";
|
||||
import { TakeEditorPanel, type FullTake } from "./TakeEditorPanel";
|
||||
import { NewShootDayDialog } from "./NewShootDayDialog";
|
||||
import { NewSetupDialog } from "./NewSetupDialog";
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
// ─── Types ────────────────────────────────────────────────────────────────────
|
||||
|
||||
@@ -28,6 +29,8 @@ export function ShootLogClient({ projects }: Props) {
|
||||
const [projectId, setProjectId] = useState<string>(projects[0]?.id ?? "");
|
||||
const [selectedTakeId, setSelectedTakeId] = useState<string | null>(null);
|
||||
const [selectedSetupId, setSelectedSetupId] = useState<string | null>(null);
|
||||
// Controls which panel is visible on mobile (< md)
|
||||
const [mobileView, setMobileView] = useState<"list" | "editor">("list");
|
||||
|
||||
// Which day to auto-expand in the left panel after creation
|
||||
const [expandDayId, setExpandDayId] = useState<string | null>(null);
|
||||
@@ -92,6 +95,7 @@ export function ShootLogClient({ projects }: Props) {
|
||||
invalidateDays();
|
||||
setSelectedTakeId(newTake.id);
|
||||
setSelectedSetupId(setupId);
|
||||
setMobileView("editor");
|
||||
},
|
||||
[invalidateDays]
|
||||
);
|
||||
@@ -122,6 +126,7 @@ export function ShootLogClient({ projects }: Props) {
|
||||
setExpandDayId(day.id);
|
||||
setSelectedTakeId(newTake.id);
|
||||
setSelectedSetupId(setup.id);
|
||||
setMobileView("editor");
|
||||
} catch {
|
||||
// Day was created but setup/take failed — still refresh
|
||||
invalidateDays();
|
||||
@@ -158,6 +163,7 @@ export function ShootLogClient({ projects }: Props) {
|
||||
if (!confirm("Delete this take? This cannot be undone.")) return;
|
||||
await fetch(`/api/shoot-log/takes/${selectedTakeId}`, { method: "DELETE" });
|
||||
setSelectedTakeId(null);
|
||||
setMobileView("list");
|
||||
invalidateDays();
|
||||
}, [selectedTakeId, invalidateDays]);
|
||||
|
||||
@@ -186,6 +192,7 @@ export function ShootLogClient({ projects }: Props) {
|
||||
setSelectedTakeId(null);
|
||||
setSelectedSetupId(null);
|
||||
setExpandDayId(null);
|
||||
setMobileView("list");
|
||||
}}
|
||||
className="bg-zinc-800 border border-zinc-700 rounded-lg text-sm text-white px-3 py-1.5 focus:outline-none focus:border-amber-600"
|
||||
>
|
||||
@@ -207,8 +214,12 @@ export function ShootLogClient({ projects }: Props) {
|
||||
|
||||
{/* Split layout */}
|
||||
<div className="flex flex-1 overflow-hidden min-h-0">
|
||||
{/* Left panel */}
|
||||
<div className="w-72 xl:w-80 shrink-0 border-r border-zinc-800 overflow-hidden flex flex-col">
|
||||
{/* Left panel — full width on mobile, fixed sidebar on md+ */}
|
||||
<div className={cn(
|
||||
"shrink-0 border-r border-zinc-800 overflow-hidden flex-col",
|
||||
"w-full md:w-72 xl:w-80",
|
||||
mobileView === "editor" ? "hidden md:flex" : "flex"
|
||||
)}>
|
||||
<TakeListPanel
|
||||
projectId={projectId}
|
||||
selectedTakeId={selectedTakeId}
|
||||
@@ -216,6 +227,7 @@ export function ShootLogClient({ projects }: Props) {
|
||||
onSelectTake={(takeId, setupId) => {
|
||||
setSelectedTakeId(takeId);
|
||||
setSelectedSetupId(setupId);
|
||||
setMobileView("editor");
|
||||
}}
|
||||
onNewDay={() => setNewDayOpen(true)}
|
||||
onNewSetup={(dayId) => setNewSetupDayId(dayId)}
|
||||
@@ -223,8 +235,11 @@ export function ShootLogClient({ projects }: Props) {
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* Right panel */}
|
||||
<div className="flex-1 overflow-hidden flex flex-col">
|
||||
{/* Right panel — hidden on mobile when list is showing */}
|
||||
<div className={cn(
|
||||
"flex-1 overflow-hidden flex-col",
|
||||
mobileView === "list" ? "hidden md:flex" : "flex"
|
||||
)}>
|
||||
{takeLoading ? (
|
||||
<div className="flex items-center justify-center h-full">
|
||||
<Loader2 className="h-6 w-6 animate-spin text-zinc-500" />
|
||||
@@ -240,6 +255,7 @@ export function ShootLogClient({ projects }: Props) {
|
||||
onNewTake={() => createTake(take.setupId)}
|
||||
onDelete={handleDelete}
|
||||
onAttachmentsChange={invalidateDays}
|
||||
onBack={() => setMobileView("list")}
|
||||
/>
|
||||
) : (
|
||||
<div className="flex flex-col items-center justify-center h-full gap-3 text-zinc-600">
|
||||
|
||||
@@ -498,6 +498,7 @@ interface Props {
|
||||
onNewTake: () => void;
|
||||
onDelete: () => void;
|
||||
onAttachmentsChange: () => void;
|
||||
onBack?: (() => void) | null;
|
||||
}
|
||||
|
||||
export function TakeEditorPanel({
|
||||
@@ -509,6 +510,7 @@ export function TakeEditorPanel({
|
||||
onNewTake,
|
||||
onDelete,
|
||||
onAttachmentsChange,
|
||||
onBack,
|
||||
}: Props) {
|
||||
const { status, queue } = useAutosave(take.id);
|
||||
|
||||
@@ -550,6 +552,13 @@ export function TakeEditorPanel({
|
||||
<div className="flex flex-col h-full overflow-hidden">
|
||||
{/* ── Nav bar ── */}
|
||||
<div className="flex items-center gap-2 px-4 py-3 border-b border-zinc-800 shrink-0 flex-wrap">
|
||||
{/* Back to list — mobile only */}
|
||||
{onBack && (
|
||||
<Button size="sm" variant="ghost" className="md:hidden -ml-2 text-zinc-400 shrink-0" onClick={onBack}>
|
||||
<ChevronLeft className="h-4 w-4" />
|
||||
List
|
||||
</Button>
|
||||
)}
|
||||
<div className="flex items-center gap-1">
|
||||
<Button size="icon-sm" variant="ghost" disabled={!onPrev} onClick={onPrev ?? undefined} title="Previous take (←)">
|
||||
<ChevronLeft className="h-4 w-4" />
|
||||
|
||||
Reference in New Issue
Block a user