From a6eb406052b09757a37f7e4ed12e159a628ffe04 Mon Sep 17 00:00:00 2001 From: dtoro Date: Tue, 14 Apr 2026 22:31:10 +0200 Subject: [PATCH] ui: tidy sidebar tree indent and consolidate sidebar toggles into filter bar Folder tree now indents 20px per level (chevron width + gap) so a child's chevron column lines up under its parent's label, and depth-1 rows nest under the section eyebrow instead of starting flush with it. Spacer for leaf rows matches the chevron button footprint so rows align regardless of expandability. Sidebar open/close buttons (previously split between TopBar and each panel header) collapse into two toggles at the ends of the FilterBar. Co-Authored-By: Claude Opus 4.6 (1M context) --- frontend/src/App.tsx | 22 +++---- frontend/src/components/filter/FilterBar.tsx | 58 ++++++++++++++++++- frontend/src/components/filter/FilterPill.tsx | 6 +- .../src/components/layout/LeftSidebar.tsx | 15 +---- .../src/components/layout/RightSidebar.tsx | 16 +---- frontend/src/components/layout/TopBar.tsx | 45 +------------- 6 files changed, 74 insertions(+), 88 deletions(-) diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index e3f9427..1fe3bed 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -56,12 +56,7 @@ function MainApp() { return (
- setLeftSidebarOpen(true)} - onExpandRight={() => setRightSidebarOpen(true)} - /> +
{/* Left Sidebar */} @@ -70,9 +65,7 @@ function MainApp() { leftSidebarOpen ? 'w-60' : 'w-0' } overflow-hidden border-r border-border bg-surface`} > - setLeftSidebarOpen(false)} - /> +
{/* Main column — filter bar, discard bar, timeline. Lives to the @@ -80,7 +73,14 @@ function MainApp() { * across the sidebar. relative so the KeyboardHints overlay * centers against this column, not the viewport. */}
- {!isSettings && } + {!isSettings && ( + setLeftSidebarOpen(!leftSidebarOpen)} + onToggleRightSidebar={() => setRightSidebarOpen(!rightSidebarOpen)} + /> + )} {!isSettings && }
{currentSection === 'settings' ? ( @@ -110,7 +110,7 @@ function MainApp() { showRightSidebar ? 'w-72' : 'w-0' } overflow-hidden border-l border-border bg-surface`} > - setRightSidebarOpen(false)} /> +
diff --git a/frontend/src/components/filter/FilterBar.tsx b/frontend/src/components/filter/FilterBar.tsx index b153aaa..9c713db 100644 --- a/frontend/src/components/filter/FilterBar.tsx +++ b/frontend/src/components/filter/FilterBar.tsx @@ -1,5 +1,17 @@ import { useEffect, useMemo, useRef, useState } from 'react' -import { Star, X, ArrowDown, ArrowUp, Search, AlertTriangle, Check } from 'lucide-react' +import { + Star, + X, + ArrowDown, + ArrowUp, + Search, + AlertTriangle, + Check, + PanelLeftOpen, + PanelLeftClose, + PanelRightOpen, + PanelRightClose, +} from 'lucide-react' import clsx from 'clsx' import { useFilterStore, @@ -35,7 +47,19 @@ const SORT_OPTIONS: { value: SortField; label: string }[] = [ * underlying control, and shows a short value summary inline when active. * Replaces the old expandable FilterBar + ActiveFilterChips combo. */ -export function FilterBar() { +interface FilterBarProps { + leftSidebarOpen: boolean + rightSidebarOpen: boolean + onToggleLeftSidebar: () => void + onToggleRightSidebar: () => void +} + +export function FilterBar({ + leftSidebarOpen, + rightSidebarOpen, + onToggleLeftSidebar, + onToggleRightSidebar, +}: FilterBarProps) { const filterState = useFilterStore() const dateFrom = useFilterStore((s) => s.dateFrom) const dateTo = useFilterStore((s) => s.dateTo) @@ -132,6 +156,22 @@ export function FilterBar() { return (
+ {/* Left sidebar toggle — pinned to the far-left edge of the bar so it + * sits flush against the panel it controls (or the viewport edge + * when collapsed). */} + + {/* Pills — left side, scroll horizontally if they overflow. */}
{/* Date */} @@ -423,6 +463,20 @@ export function FilterBar() { )}
+ + {/* Right sidebar toggle — pinned to the far-right edge. */} +
) } diff --git a/frontend/src/components/filter/FilterPill.tsx b/frontend/src/components/filter/FilterPill.tsx index ae80291..7748450 100644 --- a/frontend/src/components/filter/FilterPill.tsx +++ b/frontend/src/components/filter/FilterPill.tsx @@ -125,16 +125,14 @@ export function FilterPill({ onClear() } }} - // Same h-4 w-4 as the chevron slot below so swapping the - // two doesn't change the pill's footprint. - className="ml-0.5 inline-flex h-4 w-4 cursor-pointer items-center justify-center rounded-full hover:bg-primary/30" + className="ml-0.5 inline-flex h-3.5 w-4 cursor-pointer items-center justify-center rounded-full hover:bg-primary/30" title={`Clear ${label}`} aria-label={`Clear ${label}`} > ) : ( - + )} diff --git a/frontend/src/components/layout/LeftSidebar.tsx b/frontend/src/components/layout/LeftSidebar.tsx index 0a882d8..6c812c7 100644 --- a/frontend/src/components/layout/LeftSidebar.tsx +++ b/frontend/src/components/layout/LeftSidebar.tsx @@ -15,7 +15,6 @@ import { Layers2, MoreHorizontal, Pencil, - PanelLeftClose, Settings, Users, Eye, @@ -64,11 +63,7 @@ interface TreeItem { isHidden?: boolean } -interface LeftSidebarProps { - onCollapse: () => void -} - -export function LeftSidebar({ onCollapse }: LeftSidebarProps) { +export function LeftSidebar() { const { user, isAdmin, logout } = useAuth() const [expandedItems, setExpandedItems] = useState>(new Set(['library', 'folders', 'heaps'])) // Inline rename state for source-root rows. Stores the id being edited @@ -839,14 +834,6 @@ export function LeftSidebar({ onCollapse }: LeftSidebarProps) { > -
{/* Active heap card — pinned just below the Library header so diff --git a/frontend/src/components/layout/RightSidebar.tsx b/frontend/src/components/layout/RightSidebar.tsx index de5d0b5..8930d36 100644 --- a/frontend/src/components/layout/RightSidebar.tsx +++ b/frontend/src/components/layout/RightSidebar.tsx @@ -1,5 +1,5 @@ import { useState } from 'react' -import { X, Star, ShoppingBasket, Trash2, Plus, PanelRightClose } from 'lucide-react' +import { X, Star, ShoppingBasket, Trash2, Plus } from 'lucide-react' import clsx from 'clsx' import { useMutation, useQueryClient } from '@tanstack/react-query' import { format } from 'date-fns' @@ -29,11 +29,7 @@ import { COLOR_LABEL_OPTIONS } from '../../constants/colorLabels' * - 2+ photos selected → renders a slim bulk-action panel that fans out * rating / color / discard / pick across the entire selection. */ -interface RightSidebarProps { - onCollapse: () => void -} - -export function RightSidebar({ onCollapse }: RightSidebarProps) { +export function RightSidebar() { const { selectedPhotos, activePhotoId, clearSelection } = usePhotoStore() const queryClient = useQueryClient() @@ -221,14 +217,6 @@ export function RightSidebar({ onCollapse }: RightSidebarProps) { )} - ) diff --git a/frontend/src/components/layout/TopBar.tsx b/frontend/src/components/layout/TopBar.tsx index 38b036c..b09605d 100644 --- a/frontend/src/components/layout/TopBar.tsx +++ b/frontend/src/components/layout/TopBar.tsx @@ -1,14 +1,6 @@ -import { PanelLeftOpen, PanelRightOpen } from 'lucide-react' import desertBg from '../../assets/desert.png' import muleSprites from '../../assets/mule-sprites.png' -interface TopBarProps { - leftSidebarOpen: boolean - rightSidebarOpen: boolean - onExpandLeft: () => void - onExpandRight: () => void -} - // Block-character ASCII rendering of "Mulimago" — sits on a black plate // in place of the old text title. const MULIMAGO_ASCII = `▖ ▖ ▜ ▘ @@ -34,22 +26,9 @@ function toRoman(n: number): string { /** * Slim top bar — animated walking mule on the left over a tiled desert - * backdrop, settings gear on the right. The active heap badge moved into - * the Heaps panel in the left sidebar (where it actually relates to the - * heap rows the user navigates to). - * - * Also hosts the "expand sidebar" affordances: when a side panel is - * collapsed, a small panel-open icon appears on the corresponding edge - * so the user has a way to bring it back without hunting for the - * keyboard shortcut. When the panel is open, the button hides — its - * collapse twin lives in the panel's own header. + * backdrop. Sidebar toggle buttons live on the FilterBar. */ -export function TopBar({ - leftSidebarOpen, - rightSidebarOpen, - onExpandLeft, - onExpandRight, -}: TopBarProps) { +export function TopBar() { return (
- {!leftSidebarOpen && ( - - )}
Built with hubris • {toRoman(new Date().getFullYear())} - {!rightSidebarOpen && ( - - )}
)