feat(deps): react-resizable-panels for docs hub desktop split
Docs hub's desktop sidebar is now drag-resizable. Mobile path is unchanged — still uses the FolderTreeSidebar Sheet drawer. - Extracted `FolderTreeBody` from `folder-tree-sidebar.tsx` so the same tree renders inside the mobile Sheet AND the desktop panel without forking the component. - `FolderTreeSidebar` is now mobile-only (just the Sheet trigger); documents-hub composes the desktop layout itself. - `<ResizablePanelGroup autoSaveId="documents-hub-split">` persists the user's chosen split width via localStorage automatically. Min 14% / max 40% defends against starvation. - shadcn-style `<Resizable*>` primitives in `src/components/ui/` match the rest of the UI kit; uses react-resizable-panels v3 (the v4 release renamed exports to `Group`/`Separator` and broke the shadcn convention — pinned v3 for now). Verified: tsc clean, vitest 1315/1315, next build green. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -18,17 +18,11 @@ interface FolderTreeSidebarProps {
|
||||
}
|
||||
|
||||
/**
|
||||
* Collapsed-by-default tree. Each row shows a chevron that toggles its
|
||||
* children; clicking the row label selects the folder. The "All
|
||||
* documents" + "Root" pseudo-rows at the top let reps filter to the
|
||||
* full set or to docs without a folder.
|
||||
* Mobile-only Sheet trigger that opens the folder tree in a drawer.
|
||||
*
|
||||
* Designed for unlimited depth — only the top level renders by default
|
||||
* so deep trees don't blow out the page; reps drill in by expanding.
|
||||
*
|
||||
* On mobile (< sm) the sidebar collapses into a Sheet drawer triggered by
|
||||
* a "Show folders" button so the main listing isn't pushed below a
|
||||
* full-width folder stack.
|
||||
* Desktop rendering lives in `documents-hub.tsx` as one panel of a
|
||||
* `<ResizablePanelGroup>` so power users on wide monitors can drag the
|
||||
* split. Both surfaces render the same `<FolderTreeBody>` underneath.
|
||||
*/
|
||||
export function FolderTreeSidebar({ selectedFolderId, onSelect, footer }: FolderTreeSidebarProps) {
|
||||
const [mobileOpen, setMobileOpen] = useState(false);
|
||||
@@ -39,43 +33,32 @@ export function FolderTreeSidebar({ selectedFolderId, onSelect, footer }: Folder
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
{/* Mobile-only trigger that opens the drawer; hidden at sm+. */}
|
||||
<div className="sm:hidden px-3 pt-3">
|
||||
<Sheet open={mobileOpen} onOpenChange={setMobileOpen}>
|
||||
<SheetTrigger asChild>
|
||||
<Button variant="outline" size="sm" className="min-h-[44px]">
|
||||
<FolderTree className="mr-2 h-4 w-4" />
|
||||
Show folders
|
||||
</Button>
|
||||
</SheetTrigger>
|
||||
<SheetContent side="left" className="w-3/4 max-w-xs p-0">
|
||||
<SheetHeader className="border-b px-3 py-3">
|
||||
<SheetTitle className="text-sm">Folders</SheetTitle>
|
||||
</SheetHeader>
|
||||
<div className="p-2 overflow-y-auto">
|
||||
<TreeBody
|
||||
selectedFolderId={selectedFolderId}
|
||||
onSelect={handleMobileSelect}
|
||||
footer={footer}
|
||||
/>
|
||||
</div>
|
||||
</SheetContent>
|
||||
</Sheet>
|
||||
</div>
|
||||
|
||||
{/* Desktop sidebar: hidden on mobile (the Sheet trigger replaces it). */}
|
||||
<aside className="hidden sm:block w-60 shrink-0 border-b sm:border-b-0 sm:border-r bg-muted/40 p-2">
|
||||
<div className="mb-2 px-2 text-xs font-medium uppercase tracking-wide text-muted-foreground">
|
||||
Folders
|
||||
</div>
|
||||
<TreeBody selectedFolderId={selectedFolderId} onSelect={onSelect} footer={footer} />
|
||||
</aside>
|
||||
</>
|
||||
<div className="sm:hidden px-3 pt-3">
|
||||
<Sheet open={mobileOpen} onOpenChange={setMobileOpen}>
|
||||
<SheetTrigger asChild>
|
||||
<Button variant="outline" size="sm" className="min-h-[44px]">
|
||||
<FolderTree className="mr-2 h-4 w-4" />
|
||||
Show folders
|
||||
</Button>
|
||||
</SheetTrigger>
|
||||
<SheetContent side="left" className="w-3/4 max-w-xs p-0">
|
||||
<SheetHeader className="border-b px-3 py-3">
|
||||
<SheetTitle className="text-sm">Folders</SheetTitle>
|
||||
</SheetHeader>
|
||||
<div className="p-2 overflow-y-auto">
|
||||
<FolderTreeBody
|
||||
selectedFolderId={selectedFolderId}
|
||||
onSelect={handleMobileSelect}
|
||||
footer={footer}
|
||||
/>
|
||||
</div>
|
||||
</SheetContent>
|
||||
</Sheet>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function TreeBody({
|
||||
export function FolderTreeBody({
|
||||
selectedFolderId,
|
||||
onSelect,
|
||||
footer,
|
||||
|
||||
Reference in New Issue
Block a user