Files
writer-work-flow/apps/web/components/review/ReviewSectionPanel.tsx
2026-06-29 12:06:04 +02:00

66 lines
1.8 KiB
TypeScript

"use client";
import { useEffect, useRef, useState, type ReactNode } from "react";
import { ChevronDown } from "lucide-react";
import { Badge } from "@/components/ui/Badge";
import { cn, type BadgeVariant } from "@/lib/ui/variants";
interface ReviewSectionPanelProps {
title: string;
subtitle?: string;
statusLabel: string;
statusVariant: BadgeVariant;
children: ReactNode;
defaultOpen?: boolean;
}
export function ReviewSectionPanel({
title,
subtitle,
statusLabel,
statusVariant,
children,
defaultOpen = false,
}: ReviewSectionPanelProps) {
const [open, setOpen] = useState(defaultOpen);
const previousDefaultOpen = useRef(defaultOpen);
useEffect(() => {
if (defaultOpen && !previousDefaultOpen.current) {
setOpen(true);
}
previousDefaultOpen.current = defaultOpen;
}, [defaultOpen]);
return (
<details
className="group rounded border border-line bg-bg/45"
open={open}
onToggle={(event) => setOpen(event.currentTarget.open)}
>
<summary className="flex cursor-pointer list-none items-center justify-between gap-3 px-3 py-2">
<span className="min-w-0">
<span className="block font-serif text-sm text-ink">{title}</span>
{subtitle ? (
<span className="block truncate text-xs text-ink-soft">
{subtitle}
</span>
) : null}
</span>
<span className="flex shrink-0 items-center gap-2">
<Badge variant={statusVariant}>{statusLabel}</Badge>
<ChevronDown
className={cn(
"h-4 w-4 text-ink-soft transition-transform",
"group-open:rotate-180",
)}
aria-hidden="true"
/>
</span>
</summary>
<div className="border-t border-line px-3 py-3">{children}</div>
</details>
);
}