// PaneDrawer — collapsible group inside a list pane. Used to group rows by // review state without losing screen real estate when a group is empty or // the user doesn't want to see it. // // Stack layout: Kept list (always-on, fills) → [Pending drawer] → [Discarded // drawer]. Drawers always render their header (so the count is visible at a // glance); their body collapses on toggle. // // Tone is one of: // "default" — neutral, used for kept-only views // "pending" — accent strip + count chip in accent // "muted" — dim styling, used for the Discarded drawer // // The drawer is non-sticky on purpose: the user can scroll past kept items // to reach pending, and the kept count never gets crushed by an over-tall // drawer. CSS lives in styles/base.css under .pane-drawer. "use client"; import { useState, type ReactNode } from "react"; interface PaneDrawerProps { title: string; /** Optional count rendered as a pip in the header. */ count?: number; /** Visual tone. */ tone?: "default" | "pending" | "muted"; /** Initial expanded state. */ defaultOpen?: boolean; /** When the drawer would be empty AND `hideWhenEmpty` is true, the entire * drawer (header included) is omitted. Useful for the Discarded drawer * where 0 items means "nothing dismissed yet, don't even show me the * header." */ hideWhenEmpty?: boolean; /** Override action shown to the right of the title (e.g. "Restore all"). */ rightAction?: ReactNode; children: ReactNode; } export function PaneDrawer({ title, count, tone = "default", defaultOpen = false, hideWhenEmpty = false, rightAction, children, }: PaneDrawerProps) { const [open, setOpen] = useState(defaultOpen); const isEmpty = typeof count === "number" && count === 0; if (hideWhenEmpty && isEmpty) return null; return (
{rightAction ?
{rightAction}
: null}
{open ?
{children}
: null}
); }