|
@@ -1,6 +1,6 @@
|
|
|
import { useState, useEffect, useCallback, useRef, useMemo } from 'react';
|
|
import { useState, useEffect, useCallback, useRef, useMemo } from 'react';
|
|
|
import { NavLink, Outlet, useNavigate, useLocation } from 'react-router-dom';
|
|
import { NavLink, Outlet, useNavigate, useLocation } from 'react-router-dom';
|
|
|
-import { Printer, Archive, ListOrdered, BarChart3, Cloud, Settings, Sun, Moon, ChevronLeft, ChevronRight, Keyboard, Github, GripVertical, ArrowUpCircle, Wrench, FolderKanban, FolderOpen, X, Menu, Info, Plug, Bug, LogOut, Key, Loader2, Disc3, ShieldAlert, Bell, Globe, type LucideIcon } from 'lucide-react';
|
|
|
|
|
|
|
+import { Printer, Archive, ListOrdered, BarChart3, Cloud, Settings, Sun, Moon, Monitor, ChevronLeft, ChevronRight, Keyboard, Github, GripVertical, ArrowUpCircle, Wrench, FolderKanban, FolderOpen, X, Menu, Info, Plug, Bug, LogOut, Key, Loader2, Disc3, ShieldAlert, Bell, Globe, type LucideIcon } from 'lucide-react';
|
|
|
import { useTranslation } from 'react-i18next';
|
|
import { useTranslation } from 'react-i18next';
|
|
|
import { useTheme } from '../contexts/ThemeContext';
|
|
import { useTheme } from '../contexts/ThemeContext';
|
|
|
import { KeyboardShortcutsModal } from './KeyboardShortcutsModal';
|
|
import { KeyboardShortcutsModal } from './KeyboardShortcutsModal';
|
|
@@ -78,9 +78,14 @@ export function setDefaultView(path: string) {
|
|
|
export function Layout() {
|
|
export function Layout() {
|
|
|
const navigate = useNavigate();
|
|
const navigate = useNavigate();
|
|
|
const location = useLocation();
|
|
const location = useLocation();
|
|
|
- const { mode, toggleMode } = useTheme();
|
|
|
|
|
|
|
+ const { mode, resolvedMode, toggleMode } = useTheme();
|
|
|
const { t } = useTranslation();
|
|
const { t } = useTranslation();
|
|
|
const isSidebarCompact = useIsSidebarCompact();
|
|
const isSidebarCompact = useIsSidebarCompact();
|
|
|
|
|
+
|
|
|
|
|
+ // Theme toggle: mode → icon and tooltip
|
|
|
|
|
+ const ThemeIcon = { dark: Sun, light: Monitor, system: Moon }[mode];
|
|
|
|
|
+ const themeSwitchTitle = t({ dark: 'nav.switchToLight', light: 'nav.switchToSystem', system: 'nav.switchToDark' }[mode]);
|
|
|
|
|
+
|
|
|
// Re-render Layout (and the page rendered inside <Outlet />) whenever the
|
|
// Re-render Layout (and the page rendered inside <Outlet />) whenever the
|
|
|
// backend color catalog is (re)populated, so pages that mounted before the
|
|
// backend color catalog is (re)populated, so pages that mounted before the
|
|
|
// catalog fetched — and cached HSL-fallback color names during their first
|
|
// catalog fetched — and cached HSL-fallback color names during their first
|
|
@@ -499,7 +504,7 @@ export function Layout() {
|
|
|
<Menu className="w-6 h-6 text-white" />
|
|
<Menu className="w-6 h-6 text-white" />
|
|
|
</button>
|
|
</button>
|
|
|
<img
|
|
<img
|
|
|
- src={mode === 'dark' ? '/img/bambuddy_logo_dark_transparent.png' : '/img/bambuddy_logo_light.png'}
|
|
|
|
|
|
|
+ src={resolvedMode === 'dark' ? '/img/bambuddy_logo_dark_transparent.png' : '/img/bambuddy_logo_light.png'}
|
|
|
alt="Bambuddy"
|
|
alt="Bambuddy"
|
|
|
className="h-8 ml-3"
|
|
className="h-8 ml-3"
|
|
|
/>
|
|
/>
|
|
@@ -525,7 +530,7 @@ export function Layout() {
|
|
|
{/* Logo */}
|
|
{/* Logo */}
|
|
|
<div className={`border-b border-bambu-dark-tertiary flex items-center justify-center ${isSidebarCompact || sidebarExpanded ? 'p-4' : 'p-2'}`}>
|
|
<div className={`border-b border-bambu-dark-tertiary flex items-center justify-center ${isSidebarCompact || sidebarExpanded ? 'p-4' : 'p-2'}`}>
|
|
|
<img
|
|
<img
|
|
|
- src={mode === 'dark' ? '/img/bambuddy_logo_dark_transparent.png' : '/img/bambuddy_logo_light.png'}
|
|
|
|
|
|
|
+ src={resolvedMode === 'dark' ? '/img/bambuddy_logo_dark_transparent.png' : '/img/bambuddy_logo_light.png'}
|
|
|
alt="Bambuddy"
|
|
alt="Bambuddy"
|
|
|
className={isSidebarCompact || sidebarExpanded ? 'h-16 w-auto' : 'h-8 w-8 object-cover object-left'}
|
|
className={isSidebarCompact || sidebarExpanded ? 'h-16 w-auto' : 'h-8 w-8 object-cover object-left'}
|
|
|
/>
|
|
/>
|
|
@@ -753,9 +758,9 @@ export function Layout() {
|
|
|
<button
|
|
<button
|
|
|
onClick={toggleMode}
|
|
onClick={toggleMode}
|
|
|
className="p-2 rounded-lg hover:bg-bambu-dark-tertiary transition-colors text-bambu-gray-light hover:text-white"
|
|
className="p-2 rounded-lg hover:bg-bambu-dark-tertiary transition-colors text-bambu-gray-light hover:text-white"
|
|
|
- title={mode === 'dark' ? t('nav.switchToLight') : t('nav.switchToDark')}
|
|
|
|
|
|
|
+ title={themeSwitchTitle}
|
|
|
>
|
|
>
|
|
|
- {mode === 'dark' ? <Sun className="w-5 h-5" /> : <Moon className="w-5 h-5" />}
|
|
|
|
|
|
|
+ <ThemeIcon className="w-5 h-5" />
|
|
|
</button>
|
|
</button>
|
|
|
{authEnabled && user && (
|
|
{authEnabled && user && (
|
|
|
<>
|
|
<>
|
|
@@ -858,9 +863,9 @@ export function Layout() {
|
|
|
<button
|
|
<button
|
|
|
onClick={toggleMode}
|
|
onClick={toggleMode}
|
|
|
className="p-2 rounded-lg hover:bg-bambu-dark-tertiary transition-colors text-bambu-gray-light hover:text-white"
|
|
className="p-2 rounded-lg hover:bg-bambu-dark-tertiary transition-colors text-bambu-gray-light hover:text-white"
|
|
|
- title={mode === 'dark' ? t('nav.switchToLight') : t('nav.switchToDark')}
|
|
|
|
|
|
|
+ title={themeSwitchTitle}
|
|
|
>
|
|
>
|
|
|
- {mode === 'dark' ? <Sun className="w-5 h-5" /> : <Moon className="w-5 h-5" />}
|
|
|
|
|
|
|
+ <ThemeIcon className="w-5 h-5" />
|
|
|
</button>
|
|
</button>
|
|
|
{authEnabled && user && (
|
|
{authEnabled && user && (
|
|
|
<>
|
|
<>
|