/** * Sidebar - Navigation with task list and session list. * * Structure: * - Tab bar: Collapse button + Tasks | Sessions * - Scrollable Body: Task list or date-grouped session list * - Resizable: Drag right edge to resize * - Collapsible: Cmd+B to toggle (Notion-style) */ import { useCallback, useEffect, useRef, useState } from 'react'; import { useStore } from '@renderer/store'; import { formatShortcut } from '@renderer/utils/stringUtils'; import { PanelLeft } from 'lucide-react'; import { useShallow } from 'zustand/react/shallow'; import { DateGroupedSessions } from '../sidebar/DateGroupedSessions'; import { GlobalTaskList } from '../sidebar/GlobalTaskList'; import { defaultTaskFiltersState } from '../sidebar/taskFiltersState'; import type { TaskFiltersState } from '../sidebar/taskFiltersState'; type SidebarTab = 'tasks' | 'sessions'; const MIN_WIDTH = 200; const MAX_WIDTH = 500; const DEFAULT_WIDTH = 280; export const Sidebar = (): React.JSX.Element => { const { sidebarCollapsed, toggleSidebar } = useStore( useShallow((s) => ({ sidebarCollapsed: s.sidebarCollapsed, toggleSidebar: s.toggleSidebar, })) ); const [width, setWidth] = useState(DEFAULT_WIDTH); const [isResizing, setIsResizing] = useState(false); const [sidebarTab, setSidebarTab] = useState('tasks'); const [taskFilters, setTaskFilters] = useState(defaultTaskFiltersState); const [taskFiltersPopoverOpen, setTaskFiltersPopoverOpen] = useState(false); const [isCollapseHovered, setIsCollapseHovered] = useState(false); const sidebarRef = useRef(null); // Handle mouse move during resize (right sidebar: width = viewport - clientX) const handleMouseMove = useCallback( (e: MouseEvent) => { if (!isResizing) return; const newWidth = window.innerWidth - e.clientX; if (newWidth >= MIN_WIDTH && newWidth <= MAX_WIDTH) { setWidth(newWidth); } }, [isResizing] ); // Handle mouse up to stop resizing const handleMouseUp = useCallback(() => { setIsResizing(false); }, []); // Add/remove event listeners for resize useEffect(() => { if (isResizing) { document.addEventListener('mousemove', handleMouseMove); document.addEventListener('mouseup', handleMouseUp); document.body.style.cursor = 'col-resize'; document.body.style.userSelect = 'none'; } return () => { document.removeEventListener('mousemove', handleMouseMove); document.removeEventListener('mouseup', handleMouseUp); document.body.style.cursor = ''; document.body.style.userSelect = ''; }; }, [isResizing, handleMouseMove, handleMouseUp]); const handleResizeStart = (e: React.MouseEvent): void => { e.preventDefault(); setIsResizing(true); }; return (
{/* Tab bar: Collapse button + Tasks | Sessions */}
{/* Collapse sidebar button */}
{/* Content: Tasks list or Sessions list */}
{/* Resize handle - only interactive when expanded */} {!sidebarCollapsed && (
); };