import { type ReactNode } from "react"; import { useTranslation } from "react-i18next"; import { Check, Pencil, Pin, PinOff, RotateCcw } from "lucide-react"; import { useScrollFade } from "../lib/useScrollFade"; import { useHoverFocusWithin } from "../lib/useHoverFocusWithin"; // The shared floating side panel — one shell for the Feed / Plex / Playlists rails so they read as // one system, and the same peek-open model as the nav rail: unpinned it sits as a small tab docked // against the rail's right edge (this panel is the flex sibling right after it) and expands into a // rounded glass card on hover/focus WITHOUT pushing content; pinned it stays expanded in-flow. // `collapsed` (persisted per-account) therefore means "unpinned". export default function SidePanel({ title, icon, count = 0, collapsed, onToggleCollapse, editing = false, onToggleEditing, onReset, editHint, actions, iconExpanded, onTitleClick, titleActionLabel, children, }: { title: string; icon: ReactNode; count?: number; collapsed: boolean; onToggleCollapse: () => void; // Customize (reorder/hide) mode — omit onToggleEditing to hide the pencil entirely. editing?: boolean; onToggleEditing?: () => void; onReset?: () => void; editHint?: string; // Extra header controls shown when NOT editing (e.g. the feed's Clear all + Share view). actions?: ReactNode; // Optional override for the icon in the EXPANDED header only (the collapsed tab keeps the plain // `icon`) — the feed passes its saved-views popover trigger here so the header icon opens the picker. iconExpanded?: ReactNode; // When set, the expanded-header title becomes a button (the feed opens its Personal Views modal). onTitleClick?: () => void; // Accessible name / tooltip describing what onTitleClick does (the plain title text alone doesn't). titleActionLabel?: string; children: ReactNode; }) { const { t } = useTranslation(); const fade = useScrollFade(); const peek = useHoverFocusWithin(); const pinned = !collapsed; const expanded = pinned || peek.active; return ( // Layout slot: reserves only the tab's gutter when unpinned, so the expanded card overlays // content instead of pushing it. Pinned reserves --rail-pinned-w: 16.75rem (in-flow, pushes) on a // full-width page or a narrow window, but 2.25rem (overlay, doesn't push) when the centred content // leaves room for the rail to sit in its left margin — see PageShell. Default 16.75rem = old w-67.
{/* The tab: a small handle flush against the nav rail, flat on the docked edge. It stays mounted while the card is open — swapping it out from under the pointer would drop the very hover that opened the card, and unmounting it while focused would throw keyboard focus to nowhere. It only goes transparent: the card's rounded corner cuts away its own pixels, and this square-cornered tab sits right under that arc, so it would otherwise bleed through. `opacity-0` (not `invisible`/`hidden`) keeps it hoverable and focusable. */} {expanded && ( )}
); }