From 53993aa3c690f336ad5b5150f76949f355f20d9b Mon Sep 17 00:00:00 2001 From: Richard R Date: Wed, 27 May 2026 20:11:43 -0600 Subject: [PATCH] feat(doclist): improve sidebar responsiveness and toolbar interaction in document list Enhance mobile and desktop sidebar behavior by introducing a separate state for mobile sidebar visibility and ensuring it does not persist from desktop state. Update FinderToolbar to visually indicate sidebar open state and make the toolbar sticky for better accessibility. Refine FinderSidebar width handling for improved responsiveness. Remove redundant border in mobile sidebar dialog for a cleaner appearance. These changes provide a more consistent and intuitive sidebar experience across viewports. --- src/components/doclist/DocumentList.tsx | 22 +- .../doclist/window/FinderSidebar.tsx | 7 +- .../doclist/window/FinderToolbar.tsx | 228 +++++++++--------- .../doclist/window/FinderWindow.tsx | 2 +- 4 files changed, 140 insertions(+), 119 deletions(-) diff --git a/src/components/doclist/DocumentList.tsx b/src/components/doclist/DocumentList.tsx index 663120e..344ccaa 100644 --- a/src/components/doclist/DocumentList.tsx +++ b/src/components/doclist/DocumentList.tsx @@ -124,6 +124,7 @@ function DocumentListInner({ brand, appActions }: DocumentListInnerProps) { const [sidebarWidth, setSidebarWidth] = useState(DEFAULT_STATE.sidebarWidth); const [sidebarFilter, setSidebarFilter] = useState('all'); const [sidebarOpen, setSidebarOpen] = useState(true); + const [mobileSidebarOpen, setMobileSidebarOpen] = useState(false); const [query, setQuery] = useState(''); const [isInitialized, setIsInitialized] = useState(false); @@ -206,6 +207,12 @@ function DocumentListInner({ brand, appActions }: DocumentListInnerProps) { isInitialized, ]); + // Mobile drawer should never auto-open from persisted desktop state. + useEffect(() => { + if (!isNarrow) return; + setMobileSidebarOpen(false); + }, [isNarrow]); + // Build the union document list. const allDocuments: DocumentListDocument[] = useMemo( () => [ @@ -413,6 +420,7 @@ function DocumentListInner({ brand, appActions }: DocumentListInnerProps) { const fallbackViewMode: ViewMode = viewMode === 'columns' && isNarrow ? 'list' : viewMode; + const effectiveSidebarOpen = isNarrow ? mobileSidebarOpen : sidebarOpen; return ( setSidebarOpen((p) => !p)} + onToggleSidebar={() => + isNarrow + ? setMobileSidebarOpen((p) => !p) + : setSidebarOpen((p) => !p) + } + isSidebarOpen={effectiveSidebarOpen} isNarrow={isNarrow} leftSlot={brand} rightSlot={appActions} @@ -460,8 +473,11 @@ function DocumentListInner({ brand, appActions }: DocumentListInnerProps) { summary={summary} /> } - sidebarOpen={sidebarOpen} - onSidebarOpenChange={setSidebarOpen} + sidebarOpen={effectiveSidebarOpen} + onSidebarOpenChange={(open) => { + if (isNarrow) setMobileSidebarOpen(open); + else setSidebarOpen(open); + }} > {!isLoading && showHint && allDocuments.length > 1 && (
diff --git a/src/components/doclist/window/FinderSidebar.tsx b/src/components/doclist/window/FinderSidebar.tsx index 7de467b..7d5b4a9 100644 --- a/src/components/doclist/window/FinderSidebar.tsx +++ b/src/components/doclist/window/FinderSidebar.tsx @@ -1,6 +1,6 @@ 'use client'; -import { useRef, type ReactNode } from 'react'; +import { useRef, type CSSProperties, type ReactNode } from 'react'; import { useDrop } from 'react-dnd'; import type { Folder, SidebarFilter } from '@/types/documents'; import { PDFIcon, EPUBIcon, FileIcon } from '@/components/icons/Icons'; @@ -158,8 +158,8 @@ export function FinderSidebar({ return ( ); } - diff --git a/src/components/doclist/window/FinderToolbar.tsx b/src/components/doclist/window/FinderToolbar.tsx index e40761f..e98284c 100644 --- a/src/components/doclist/window/FinderToolbar.tsx +++ b/src/components/doclist/window/FinderToolbar.tsx @@ -27,6 +27,7 @@ interface FinderToolbarProps { onQueryChange: (q: string) => void; onNewFolder: () => void; onToggleSidebar: () => void; + isSidebarOpen: boolean; /** True when the columns view should be disabled (mobile viewport). */ isNarrow: boolean; /** App-level content rendered at the far left (brand/logo). */ @@ -61,6 +62,7 @@ const TOOLBAR_BTN = 'inline-flex items-center py-1 px-2 rounded-md border bg-base text-xs transition-all duration-200 ease-out hover:scale-[1.01]'; const TOOLBAR_BTN_INACTIVE = 'border-offbase text-foreground hover:text-accent hover:border-accent hover:bg-offbase'; +const TOOLBAR_BTN_ACTIVE = 'border-accent bg-offbase text-accent'; // Pill-grouped segmented control. Outer pill carries the border; inner segments are // borderless and rely on bg/text color to show active/hover. Sized so the whole pill @@ -84,6 +86,7 @@ export function FinderToolbar({ onQueryChange, onNewFolder, onToggleSidebar, + isSidebarOpen, isNarrow, leftSlot, rightSlot, @@ -92,138 +95,141 @@ export function FinderToolbar({ const directionLabel = sortDirection === 'asc' ? currentSort.asc : currentSort.desc; return ( -
- {leftSlot && ( -
- {leftSlot} -
- )} +
+
+ {leftSlot && ( +
+ {leftSlot} +
+ )} - + -
- {VIEW_BUTTONS.map(({ value, label, Icon }) => { - const disabled = value === 'columns' && isNarrow; - const active = viewMode === value; - return ( - - ); - })} -
- - {viewMode === 'icons' && ( -