import { useState } from 'react' import { Timeline } from './components/timeline/Timeline' import { DuplicatesView } from './components/duplicates/DuplicatesView' import { MapView } from './components/map/MapView' import { MemoriesView } from './components/memories/MemoriesView' import { TagsView } from './components/tags/TagsView' import { ColorsView } from './components/colors/ColorsView' import { RatedView } from './components/rated/RatedView' import { LeftSidebar } from './components/layout/LeftSidebar' import { RightSidebar } from './components/layout/RightSidebar' import { TopBar } from './components/layout/TopBar' import { ScanProgress } from './components/ScanProgress' import { ToastContainer } from './components/ToastContainer' import { KeyboardHints } from './components/KeyboardHints' import { PreviewView } from './components/preview/PreviewView' import { FilterBar } from './components/filter/FilterBar' import { DiscardActionBar } from './components/discard/DiscardActionBar' import { SettingsPage } from './components/dialogs/SettingsDialog' import { usePhotoStore } from './store/photoStore' import { useFilterStore } from './store/filterStore' import { useKeyboardShortcuts } from './hooks/useKeyboardShortcuts' import { useFilterUrlSync } from './hooks/useFilterUrlSync' import { usePhotosQuery } from './hooks/usePhotosQuery' import { AuthProvider, useAuth } from './contexts/AuthContext' import { LoginPage } from './components/auth/LoginPage' import { SetupPage } from './components/auth/SetupPage' function MainApp() { const [leftSidebarOpen, setLeftSidebarOpen] = useState(true) const [rightSidebarOpen, setRightSidebarOpen] = useState(true) const viewMode = usePhotoStore((state) => state.viewMode) const currentSection = useFilterStore((s) => s.currentSection) // Bidirectional sync of filter store with URL query params. useFilterUrlSync() // Subscribe to the same photos query the Timeline uses, so the keyboard // "open preview on first photo" path can read from the live cache regardless // of what filter key it's stored under. const { data: allPhotos } = usePhotosQuery() // Set up global keyboard shortcuts useKeyboardShortcuts({ onToggleLeftSidebar: () => setLeftSidebarOpen(!leftSidebarOpen), onToggleRightSidebar: () => setRightSidebarOpen(!rightSidebarOpen), getFirstPhotoId: () => allPhotos?.[0]?.id ?? null, }) // Settings page is a full-page section — hide filter bar, right sidebar, // and keyboard hints when it's active. const isSettings = currentSection === 'settings' // Right sidebar stays open by default and shows whatever's selected // (or an empty state if nothing is). User can still toggle it manually. const showRightSidebar = rightSidebarOpen && !isSettings return (
{/* Left Sidebar */}
{/* Main column — filter bar, discard bar, timeline. Lives to the * right of the left sidebar so the filter row doesn't bleed * across the sidebar. relative so the KeyboardHints overlay * centers against this column, not the viewport. */}
{!isSettings && ( setLeftSidebarOpen(!leftSidebarOpen)} onToggleRightSidebar={() => setRightSidebarOpen(!rightSidebarOpen)} /> )} {!isSettings && }
{currentSection === 'settings' ? ( ) : currentSection === 'map' ? ( ) : currentSection === 'memories' ? ( ) : currentSection === 'duplicates' ? ( ) : currentSection === 'tags' ? ( ) : currentSection === 'colors' ? ( ) : currentSection === 'rated' ? ( ) : ( )}
{!isSettings && }
{/* Right Sidebar */}
{/* Scan Progress Indicator */} {/* Toast Notifications */} {/* Preview overlay — covers TopBar when active */} {viewMode === 'preview' && }
) } /** Auth-gated shell: shows setup, login, or the main app. */ function App() { return ( ) } function AuthGate() { const { user, isLoading, needsSetup } = useAuth() if (isLoading) { return (
Loading…
) } if (needsSetup) return if (!user) return return } export default App