diff --git a/apps/ui/src/components/layout/project-switcher/project-switcher.tsx b/apps/ui/src/components/layout/project-switcher/project-switcher.tsx index 9fa772da..541fa83c 100644 --- a/apps/ui/src/components/layout/project-switcher/project-switcher.tsx +++ b/apps/ui/src/components/layout/project-switcher/project-switcher.tsx @@ -2,7 +2,7 @@ import { useState, useCallback, useEffect } from 'react'; import { Plus, Bug, FolderOpen, BookOpen } from 'lucide-react'; import { useNavigate, useLocation } from '@tanstack/react-router'; import { cn } from '@/lib/utils'; -import { useAppStore, type ThemeMode } from '@/store/app-store'; +import { useAppStore } from '@/store/app-store'; import { useOSDetection } from '@/hooks/use-os-detection'; import { ProjectSwitcherItem } from './components/project-switcher-item'; import { ProjectContextMenu } from './components/project-context-menu'; @@ -10,7 +10,7 @@ import { EditProjectDialog } from './components/edit-project-dialog'; import { NotificationBell } from './components/notification-bell'; import { NewProjectModal } from '@/components/dialogs/new-project-modal'; import { OnboardingDialog } from '@/components/layout/sidebar/dialogs'; -import { useProjectCreation, useProjectTheme } from '@/components/layout/sidebar/hooks'; +import { useProjectCreation } from '@/components/layout/sidebar/hooks'; import { SIDEBAR_FEATURE_FLAGS } from '@/components/layout/sidebar/constants'; import type { Project } from '@/lib/electron'; import { getElectronAPI } from '@/lib/electron'; @@ -41,7 +41,6 @@ export function ProjectSwitcher() { projects, currentProject, setCurrentProject, - trashedProjects, upsertAndSetCurrentProject, specCreatingForProject, setSpecCreatingForProject, @@ -69,9 +68,6 @@ export function ProjectSwitcher() { const appMode = import.meta.env.VITE_APP_MODE || '?'; const versionSuffix = `${getOSAbbreviation(os)}${appMode}`; - // Get global theme for project creation - const { globalTheme } = useProjectTheme(); - // Project creation state and handlers const { showNewProjectModal, @@ -84,9 +80,6 @@ export function ProjectSwitcher() { handleCreateFromTemplate, handleCreateFromCustomUrl, } = useProjectCreation({ - trashedProjects, - currentProject, - globalTheme, upsertAndSetCurrentProject, }); @@ -161,13 +154,8 @@ export function ProjectSwitcher() { } // Upsert project and set as current (handles both create and update cases) - // Theme preservation is handled by the store action - const trashedProject = trashedProjects.find((p) => p.path === path); - const effectiveTheme = - (trashedProject?.theme as ThemeMode | undefined) || - (currentProject?.theme as ThemeMode | undefined) || - globalTheme; - upsertAndSetCurrentProject(path, name, effectiveTheme); + // Theme handling (trashed project recovery or undefined for global) is done by the store + upsertAndSetCurrentProject(path, name); // Check if app_spec.txt exists const specExists = await hasAppSpec(path); @@ -198,7 +186,7 @@ export function ProjectSwitcher() { }); } } - }, [trashedProjects, upsertAndSetCurrentProject, currentProject, globalTheme, navigate]); + }, [upsertAndSetCurrentProject, navigate]); // Handler for creating initial spec from the setup dialog const handleCreateInitialSpec = useCallback(async () => { diff --git a/apps/ui/src/components/layout/sidebar.tsx b/apps/ui/src/components/layout/sidebar.tsx index 0baa81cf..05ff1328 100644 --- a/apps/ui/src/components/layout/sidebar.tsx +++ b/apps/ui/src/components/layout/sidebar.tsx @@ -4,7 +4,7 @@ import { useNavigate, useLocation } from '@tanstack/react-router'; const logger = createLogger('Sidebar'); import { cn } from '@/lib/utils'; -import { useAppStore, type ThemeMode } from '@/store/app-store'; +import { useAppStore } from '@/store/app-store'; import { useNotificationsStore } from '@/store/notifications-store'; import { useKeyboardShortcuts, useKeyboardShortcutsConfig } from '@/hooks/use-keyboard-shortcuts'; import { getElectronAPI } from '@/lib/electron'; @@ -34,7 +34,6 @@ import { useProjectCreation, useSetupDialog, useTrashOperations, - useProjectTheme, useUnviewedValidations, } from './sidebar/hooks'; @@ -79,9 +78,6 @@ export function Sidebar() { // State for trash dialog const [showTrashDialog, setShowTrashDialog] = useState(false); - // Project theme management (must come before useProjectCreation which uses globalTheme) - const { globalTheme } = useProjectTheme(); - // Project creation state and handlers const { showNewProjectModal, @@ -97,9 +93,6 @@ export function Sidebar() { handleCreateFromTemplate, handleCreateFromCustomUrl, } = useProjectCreation({ - trashedProjects, - currentProject, - globalTheme, upsertAndSetCurrentProject, }); @@ -198,13 +191,8 @@ export function Sidebar() { } // Upsert project and set as current (handles both create and update cases) - // Theme preservation is handled by the store action - const trashedProject = trashedProjects.find((p) => p.path === path); - const effectiveTheme = - (trashedProject?.theme as ThemeMode | undefined) || - (currentProject?.theme as ThemeMode | undefined) || - globalTheme; - upsertAndSetCurrentProject(path, name, effectiveTheme); + // Theme handling (trashed project recovery or undefined for global) is done by the store + upsertAndSetCurrentProject(path, name); // Check if app_spec.txt exists const specExists = await hasAppSpec(path); @@ -232,7 +220,7 @@ export function Sidebar() { }); } } - }, [trashedProjects, upsertAndSetCurrentProject, currentProject, globalTheme]); + }, [upsertAndSetCurrentProject]); // Navigation sections and keyboard shortcuts (defined after handlers) const { navSections, navigationShortcuts } = useNavigation({ diff --git a/apps/ui/src/components/layout/sidebar/hooks/use-project-creation.ts b/apps/ui/src/components/layout/sidebar/hooks/use-project-creation.ts index 2720bb98..45cd816a 100644 --- a/apps/ui/src/components/layout/sidebar/hooks/use-project-creation.ts +++ b/apps/ui/src/components/layout/sidebar/hooks/use-project-creation.ts @@ -6,20 +6,13 @@ const logger = createLogger('ProjectCreation'); import { initializeProject } from '@/lib/project-init'; import { toast } from 'sonner'; import type { StarterTemplate } from '@/lib/templates'; -import type { ThemeMode } from '@/store/app-store'; -import type { TrashedProject, Project } from '@/lib/electron'; +import type { Project } from '@/lib/electron'; interface UseProjectCreationProps { - trashedProjects: TrashedProject[]; - currentProject: Project | null; - globalTheme: ThemeMode; - upsertAndSetCurrentProject: (path: string, name: string, theme: ThemeMode) => Project; + upsertAndSetCurrentProject: (path: string, name: string) => Project; } export function useProjectCreation({ - trashedProjects, - currentProject, - globalTheme, upsertAndSetCurrentProject, }: UseProjectCreationProps) { // Modal state @@ -67,14 +60,8 @@ export function useProjectCreation({ ` ); - // Determine theme: try trashed project theme, then current project theme, then global - const trashedProject = trashedProjects.find((p) => p.path === projectPath); - const effectiveTheme = - (trashedProject?.theme as ThemeMode | undefined) || - (currentProject?.theme as ThemeMode | undefined) || - globalTheme; - - upsertAndSetCurrentProject(projectPath, projectName, effectiveTheme); + // Let the store handle theme (trashed project recovery or undefined for global) + upsertAndSetCurrentProject(projectPath, projectName); setShowNewProjectModal(false); @@ -92,7 +79,7 @@ export function useProjectCreation({ throw error; } }, - [trashedProjects, currentProject, globalTheme, upsertAndSetCurrentProject] + [upsertAndSetCurrentProject] ); /** @@ -169,14 +156,8 @@ export function useProjectCreation({ ` ); - // Determine theme - const trashedProject = trashedProjects.find((p) => p.path === projectPath); - const effectiveTheme = - (trashedProject?.theme as ThemeMode | undefined) || - (currentProject?.theme as ThemeMode | undefined) || - globalTheme; - - upsertAndSetCurrentProject(projectPath, projectName, effectiveTheme); + // Let the store handle theme (trashed project recovery or undefined for global) + upsertAndSetCurrentProject(projectPath, projectName); setShowNewProjectModal(false); setNewProjectName(projectName); setNewProjectPath(projectPath); @@ -194,7 +175,7 @@ export function useProjectCreation({ setIsCreatingProject(false); } }, - [trashedProjects, currentProject, globalTheme, upsertAndSetCurrentProject] + [upsertAndSetCurrentProject] ); /** @@ -244,14 +225,8 @@ export function useProjectCreation({ ` ); - // Determine theme - const trashedProject = trashedProjects.find((p) => p.path === projectPath); - const effectiveTheme = - (trashedProject?.theme as ThemeMode | undefined) || - (currentProject?.theme as ThemeMode | undefined) || - globalTheme; - - upsertAndSetCurrentProject(projectPath, projectName, effectiveTheme); + // Let the store handle theme (trashed project recovery or undefined for global) + upsertAndSetCurrentProject(projectPath, projectName); setShowNewProjectModal(false); setNewProjectName(projectName); setNewProjectPath(projectPath); @@ -269,7 +244,7 @@ export function useProjectCreation({ setIsCreatingProject(false); } }, - [trashedProjects, currentProject, globalTheme, upsertAndSetCurrentProject] + [upsertAndSetCurrentProject] ); return { diff --git a/apps/ui/src/components/views/dashboard-view.tsx b/apps/ui/src/components/views/dashboard-view.tsx index 80f9624b..872b97a8 100644 --- a/apps/ui/src/components/views/dashboard-view.tsx +++ b/apps/ui/src/components/views/dashboard-view.tsx @@ -1,7 +1,7 @@ import { useState, useCallback } from 'react'; import { createLogger } from '@automaker/utils/logger'; import { useNavigate } from '@tanstack/react-router'; -import { useAppStore, type ThemeMode } from '@/store/app-store'; +import { useAppStore } from '@/store/app-store'; import { useOSDetection } from '@/hooks/use-os-detection'; import { getElectronAPI, isElectron } from '@/lib/electron'; import { initializeProject } from '@/lib/project-init'; @@ -76,14 +76,11 @@ export function DashboardView() { const { projects, - trashedProjects, - currentProject, upsertAndSetCurrentProject, addProject, setCurrentProject, toggleProjectFavorite, moveProjectToTrash, - theme: globalTheme, } = useAppStore(); const [showNewProjectModal, setShowNewProjectModal] = useState(false); @@ -143,12 +140,8 @@ export function DashboardView() { return; } - const trashedProject = trashedProjects.find((p) => p.path === path); - const effectiveTheme = - (trashedProject?.theme as ThemeMode | undefined) || - (currentProject?.theme as ThemeMode | undefined) || - globalTheme; - upsertAndSetCurrentProject(path, name, effectiveTheme); + // Theme handling (trashed project recovery or undefined for global) is done by the store + upsertAndSetCurrentProject(path, name); toast.success('Project opened', { description: `Opened ${name}`, @@ -164,15 +157,7 @@ export function DashboardView() { setIsOpening(false); } }, - [ - projects, - trashedProjects, - currentProject, - globalTheme, - upsertAndSetCurrentProject, - navigate, - moveProjectToTrash, - ] + [projects, upsertAndSetCurrentProject, navigate, moveProjectToTrash] ); const handleOpenProject = useCallback(async () => { diff --git a/apps/ui/src/components/views/setup-view/steps/theme-step.tsx b/apps/ui/src/components/views/setup-view/steps/theme-step.tsx index 2698ca7c..36d999f5 100644 --- a/apps/ui/src/components/views/setup-view/steps/theme-step.tsx +++ b/apps/ui/src/components/views/setup-view/steps/theme-step.tsx @@ -24,10 +24,10 @@ export function ThemeStep({ onNext, onBack }: ThemeStepProps) { const handleThemeClick = (themeValue: string) => { setTheme(themeValue as typeof theme); - // Also update the current project's theme if one exists - // This ensures the selected theme is visible since getEffectiveTheme() prioritizes project theme - if (currentProject) { - setProjectTheme(currentProject.id, themeValue as typeof theme); + // Clear the current project's theme so it uses the global theme + // This ensures "Use Global Theme" is checked and the project inherits the global theme + if (currentProject && currentProject.theme !== undefined) { + setProjectTheme(currentProject.id, null); } setPreviewTheme(null); }; diff --git a/apps/ui/src/components/views/welcome-view.tsx b/apps/ui/src/components/views/welcome-view.tsx index 46e4d88c..bfe0d92a 100644 --- a/apps/ui/src/components/views/welcome-view.tsx +++ b/apps/ui/src/components/views/welcome-view.tsx @@ -9,7 +9,7 @@ import { DialogHeader, DialogTitle, } from '@/components/ui/dialog'; -import { useAppStore, type ThemeMode } from '@/store/app-store'; +import { useAppStore } from '@/store/app-store'; import { getElectronAPI } from '@/lib/electron'; import { initializeProject } from '@/lib/project-init'; import { @@ -38,15 +38,7 @@ import { useNavigate } from '@tanstack/react-router'; const logger = createLogger('WelcomeView'); export function WelcomeView() { - const { - projects, - trashedProjects, - currentProject, - upsertAndSetCurrentProject, - addProject, - setCurrentProject, - theme: globalTheme, - } = useAppStore(); + const { projects, upsertAndSetCurrentProject, addProject, setCurrentProject } = useAppStore(); const navigate = useNavigate(); const [showNewProjectModal, setShowNewProjectModal] = useState(false); const [isCreating, setIsCreating] = useState(false); @@ -109,13 +101,8 @@ export function WelcomeView() { } // Upsert project and set as current (handles both create and update cases) - // Theme preservation is handled by the store action - const trashedProject = trashedProjects.find((p) => p.path === path); - const effectiveTheme = - (trashedProject?.theme as ThemeMode | undefined) || - (currentProject?.theme as ThemeMode | undefined) || - globalTheme; - upsertAndSetCurrentProject(path, name, effectiveTheme); + // Theme handling (trashed project recovery or undefined for global) is done by the store + upsertAndSetCurrentProject(path, name); // Show initialization dialog if files were created if (initResult.createdFiles && initResult.createdFiles.length > 0) { @@ -150,14 +137,7 @@ export function WelcomeView() { setIsOpening(false); } }, - [ - trashedProjects, - currentProject, - globalTheme, - upsertAndSetCurrentProject, - analyzeProject, - navigate, - ] + [upsertAndSetCurrentProject, analyzeProject, navigate] ); const handleOpenProject = useCallback(async () => { diff --git a/apps/ui/src/store/app-store.ts b/apps/ui/src/store/app-store.ts index ee8ca98a..c1fde9bb 100644 --- a/apps/ui/src/store/app-store.ts +++ b/apps/ui/src/store/app-store.ts @@ -1627,16 +1627,18 @@ export const useAppStore = create()((set, get) => ({ const updatedProjects = projects.map((p) => (p.id === existingProject.id ? project : p)); set({ projects: updatedProjects }); } else { - // Create new project - check for trashed project with same path first (preserves theme if deleted/recreated) - // Then fall back to provided theme, then current project theme, then global theme + // Create new project - only set theme if explicitly provided or recovering from trash + // Otherwise leave undefined so project uses global theme ("Use Global Theme" checked) const trashedProject = trashedProjects.find((p) => p.path === path); - const effectiveTheme = theme || trashedProject?.theme || currentProject?.theme || globalTheme; + const projectTheme = + theme !== undefined ? theme : (trashedProject?.theme as ThemeMode | undefined); + project = { id: `project-${Date.now()}`, name, path, lastOpened: new Date().toISOString(), - theme: effectiveTheme, + theme: projectTheme, // May be undefined - intentional! }; // Add the new project to the store set({