mirror of
https://github.com/AutoMaker-Org/automaker.git
synced 2026-02-04 09:13:08 +00:00
fix: prevent new projects from overriding global theme setting
When creating new projects, the theme was always explicitly set even when matching the global theme. This caused "Use Global Theme" to be unchecked, preventing global theme changes from affecting the project. Now theme is only set on new projects when explicitly provided or when recovering a trashed project's theme preference.
This commit is contained in:
@@ -2,7 +2,7 @@ import { useState, useCallback, useEffect } from 'react';
|
|||||||
import { Plus, Bug, FolderOpen, BookOpen } from 'lucide-react';
|
import { Plus, Bug, FolderOpen, BookOpen } from 'lucide-react';
|
||||||
import { useNavigate, useLocation } from '@tanstack/react-router';
|
import { useNavigate, useLocation } from '@tanstack/react-router';
|
||||||
import { cn } from '@/lib/utils';
|
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 { useOSDetection } from '@/hooks/use-os-detection';
|
||||||
import { ProjectSwitcherItem } from './components/project-switcher-item';
|
import { ProjectSwitcherItem } from './components/project-switcher-item';
|
||||||
import { ProjectContextMenu } from './components/project-context-menu';
|
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 { NotificationBell } from './components/notification-bell';
|
||||||
import { NewProjectModal } from '@/components/dialogs/new-project-modal';
|
import { NewProjectModal } from '@/components/dialogs/new-project-modal';
|
||||||
import { OnboardingDialog } from '@/components/layout/sidebar/dialogs';
|
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 { SIDEBAR_FEATURE_FLAGS } from '@/components/layout/sidebar/constants';
|
||||||
import type { Project } from '@/lib/electron';
|
import type { Project } from '@/lib/electron';
|
||||||
import { getElectronAPI } from '@/lib/electron';
|
import { getElectronAPI } from '@/lib/electron';
|
||||||
@@ -41,7 +41,6 @@ export function ProjectSwitcher() {
|
|||||||
projects,
|
projects,
|
||||||
currentProject,
|
currentProject,
|
||||||
setCurrentProject,
|
setCurrentProject,
|
||||||
trashedProjects,
|
|
||||||
upsertAndSetCurrentProject,
|
upsertAndSetCurrentProject,
|
||||||
specCreatingForProject,
|
specCreatingForProject,
|
||||||
setSpecCreatingForProject,
|
setSpecCreatingForProject,
|
||||||
@@ -69,9 +68,6 @@ export function ProjectSwitcher() {
|
|||||||
const appMode = import.meta.env.VITE_APP_MODE || '?';
|
const appMode = import.meta.env.VITE_APP_MODE || '?';
|
||||||
const versionSuffix = `${getOSAbbreviation(os)}${appMode}`;
|
const versionSuffix = `${getOSAbbreviation(os)}${appMode}`;
|
||||||
|
|
||||||
// Get global theme for project creation
|
|
||||||
const { globalTheme } = useProjectTheme();
|
|
||||||
|
|
||||||
// Project creation state and handlers
|
// Project creation state and handlers
|
||||||
const {
|
const {
|
||||||
showNewProjectModal,
|
showNewProjectModal,
|
||||||
@@ -84,9 +80,6 @@ export function ProjectSwitcher() {
|
|||||||
handleCreateFromTemplate,
|
handleCreateFromTemplate,
|
||||||
handleCreateFromCustomUrl,
|
handleCreateFromCustomUrl,
|
||||||
} = useProjectCreation({
|
} = useProjectCreation({
|
||||||
trashedProjects,
|
|
||||||
currentProject,
|
|
||||||
globalTheme,
|
|
||||||
upsertAndSetCurrentProject,
|
upsertAndSetCurrentProject,
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -161,13 +154,8 @@ export function ProjectSwitcher() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Upsert project and set as current (handles both create and update cases)
|
// Upsert project and set as current (handles both create and update cases)
|
||||||
// Theme preservation is handled by the store action
|
// Theme handling (trashed project recovery or undefined for global) is done by the store
|
||||||
const trashedProject = trashedProjects.find((p) => p.path === path);
|
upsertAndSetCurrentProject(path, name);
|
||||||
const effectiveTheme =
|
|
||||||
(trashedProject?.theme as ThemeMode | undefined) ||
|
|
||||||
(currentProject?.theme as ThemeMode | undefined) ||
|
|
||||||
globalTheme;
|
|
||||||
upsertAndSetCurrentProject(path, name, effectiveTheme);
|
|
||||||
|
|
||||||
// Check if app_spec.txt exists
|
// Check if app_spec.txt exists
|
||||||
const specExists = await hasAppSpec(path);
|
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
|
// Handler for creating initial spec from the setup dialog
|
||||||
const handleCreateInitialSpec = useCallback(async () => {
|
const handleCreateInitialSpec = useCallback(async () => {
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import { useNavigate, useLocation } from '@tanstack/react-router';
|
|||||||
|
|
||||||
const logger = createLogger('Sidebar');
|
const logger = createLogger('Sidebar');
|
||||||
import { cn } from '@/lib/utils';
|
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 { useNotificationsStore } from '@/store/notifications-store';
|
||||||
import { useKeyboardShortcuts, useKeyboardShortcutsConfig } from '@/hooks/use-keyboard-shortcuts';
|
import { useKeyboardShortcuts, useKeyboardShortcutsConfig } from '@/hooks/use-keyboard-shortcuts';
|
||||||
import { getElectronAPI } from '@/lib/electron';
|
import { getElectronAPI } from '@/lib/electron';
|
||||||
@@ -34,7 +34,6 @@ import {
|
|||||||
useProjectCreation,
|
useProjectCreation,
|
||||||
useSetupDialog,
|
useSetupDialog,
|
||||||
useTrashOperations,
|
useTrashOperations,
|
||||||
useProjectTheme,
|
|
||||||
useUnviewedValidations,
|
useUnviewedValidations,
|
||||||
} from './sidebar/hooks';
|
} from './sidebar/hooks';
|
||||||
|
|
||||||
@@ -79,9 +78,6 @@ export function Sidebar() {
|
|||||||
// State for trash dialog
|
// State for trash dialog
|
||||||
const [showTrashDialog, setShowTrashDialog] = useState(false);
|
const [showTrashDialog, setShowTrashDialog] = useState(false);
|
||||||
|
|
||||||
// Project theme management (must come before useProjectCreation which uses globalTheme)
|
|
||||||
const { globalTheme } = useProjectTheme();
|
|
||||||
|
|
||||||
// Project creation state and handlers
|
// Project creation state and handlers
|
||||||
const {
|
const {
|
||||||
showNewProjectModal,
|
showNewProjectModal,
|
||||||
@@ -97,9 +93,6 @@ export function Sidebar() {
|
|||||||
handleCreateFromTemplate,
|
handleCreateFromTemplate,
|
||||||
handleCreateFromCustomUrl,
|
handleCreateFromCustomUrl,
|
||||||
} = useProjectCreation({
|
} = useProjectCreation({
|
||||||
trashedProjects,
|
|
||||||
currentProject,
|
|
||||||
globalTheme,
|
|
||||||
upsertAndSetCurrentProject,
|
upsertAndSetCurrentProject,
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -198,13 +191,8 @@ export function Sidebar() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Upsert project and set as current (handles both create and update cases)
|
// Upsert project and set as current (handles both create and update cases)
|
||||||
// Theme preservation is handled by the store action
|
// Theme handling (trashed project recovery or undefined for global) is done by the store
|
||||||
const trashedProject = trashedProjects.find((p) => p.path === path);
|
upsertAndSetCurrentProject(path, name);
|
||||||
const effectiveTheme =
|
|
||||||
(trashedProject?.theme as ThemeMode | undefined) ||
|
|
||||||
(currentProject?.theme as ThemeMode | undefined) ||
|
|
||||||
globalTheme;
|
|
||||||
upsertAndSetCurrentProject(path, name, effectiveTheme);
|
|
||||||
|
|
||||||
// Check if app_spec.txt exists
|
// Check if app_spec.txt exists
|
||||||
const specExists = await hasAppSpec(path);
|
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)
|
// Navigation sections and keyboard shortcuts (defined after handlers)
|
||||||
const { navSections, navigationShortcuts } = useNavigation({
|
const { navSections, navigationShortcuts } = useNavigation({
|
||||||
|
|||||||
@@ -6,20 +6,13 @@ const logger = createLogger('ProjectCreation');
|
|||||||
import { initializeProject } from '@/lib/project-init';
|
import { initializeProject } from '@/lib/project-init';
|
||||||
import { toast } from 'sonner';
|
import { toast } from 'sonner';
|
||||||
import type { StarterTemplate } from '@/lib/templates';
|
import type { StarterTemplate } from '@/lib/templates';
|
||||||
import type { ThemeMode } from '@/store/app-store';
|
import type { Project } from '@/lib/electron';
|
||||||
import type { TrashedProject, Project } from '@/lib/electron';
|
|
||||||
|
|
||||||
interface UseProjectCreationProps {
|
interface UseProjectCreationProps {
|
||||||
trashedProjects: TrashedProject[];
|
upsertAndSetCurrentProject: (path: string, name: string) => Project;
|
||||||
currentProject: Project | null;
|
|
||||||
globalTheme: ThemeMode;
|
|
||||||
upsertAndSetCurrentProject: (path: string, name: string, theme: ThemeMode) => Project;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export function useProjectCreation({
|
export function useProjectCreation({
|
||||||
trashedProjects,
|
|
||||||
currentProject,
|
|
||||||
globalTheme,
|
|
||||||
upsertAndSetCurrentProject,
|
upsertAndSetCurrentProject,
|
||||||
}: UseProjectCreationProps) {
|
}: UseProjectCreationProps) {
|
||||||
// Modal state
|
// Modal state
|
||||||
@@ -67,14 +60,8 @@ export function useProjectCreation({
|
|||||||
</project_specification>`
|
</project_specification>`
|
||||||
);
|
);
|
||||||
|
|
||||||
// Determine theme: try trashed project theme, then current project theme, then global
|
// Let the store handle theme (trashed project recovery or undefined for global)
|
||||||
const trashedProject = trashedProjects.find((p) => p.path === projectPath);
|
upsertAndSetCurrentProject(projectPath, projectName);
|
||||||
const effectiveTheme =
|
|
||||||
(trashedProject?.theme as ThemeMode | undefined) ||
|
|
||||||
(currentProject?.theme as ThemeMode | undefined) ||
|
|
||||||
globalTheme;
|
|
||||||
|
|
||||||
upsertAndSetCurrentProject(projectPath, projectName, effectiveTheme);
|
|
||||||
|
|
||||||
setShowNewProjectModal(false);
|
setShowNewProjectModal(false);
|
||||||
|
|
||||||
@@ -92,7 +79,7 @@ export function useProjectCreation({
|
|||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[trashedProjects, currentProject, globalTheme, upsertAndSetCurrentProject]
|
[upsertAndSetCurrentProject]
|
||||||
);
|
);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -169,14 +156,8 @@ export function useProjectCreation({
|
|||||||
</project_specification>`
|
</project_specification>`
|
||||||
);
|
);
|
||||||
|
|
||||||
// Determine theme
|
// Let the store handle theme (trashed project recovery or undefined for global)
|
||||||
const trashedProject = trashedProjects.find((p) => p.path === projectPath);
|
upsertAndSetCurrentProject(projectPath, projectName);
|
||||||
const effectiveTheme =
|
|
||||||
(trashedProject?.theme as ThemeMode | undefined) ||
|
|
||||||
(currentProject?.theme as ThemeMode | undefined) ||
|
|
||||||
globalTheme;
|
|
||||||
|
|
||||||
upsertAndSetCurrentProject(projectPath, projectName, effectiveTheme);
|
|
||||||
setShowNewProjectModal(false);
|
setShowNewProjectModal(false);
|
||||||
setNewProjectName(projectName);
|
setNewProjectName(projectName);
|
||||||
setNewProjectPath(projectPath);
|
setNewProjectPath(projectPath);
|
||||||
@@ -194,7 +175,7 @@ export function useProjectCreation({
|
|||||||
setIsCreatingProject(false);
|
setIsCreatingProject(false);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[trashedProjects, currentProject, globalTheme, upsertAndSetCurrentProject]
|
[upsertAndSetCurrentProject]
|
||||||
);
|
);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -244,14 +225,8 @@ export function useProjectCreation({
|
|||||||
</project_specification>`
|
</project_specification>`
|
||||||
);
|
);
|
||||||
|
|
||||||
// Determine theme
|
// Let the store handle theme (trashed project recovery or undefined for global)
|
||||||
const trashedProject = trashedProjects.find((p) => p.path === projectPath);
|
upsertAndSetCurrentProject(projectPath, projectName);
|
||||||
const effectiveTheme =
|
|
||||||
(trashedProject?.theme as ThemeMode | undefined) ||
|
|
||||||
(currentProject?.theme as ThemeMode | undefined) ||
|
|
||||||
globalTheme;
|
|
||||||
|
|
||||||
upsertAndSetCurrentProject(projectPath, projectName, effectiveTheme);
|
|
||||||
setShowNewProjectModal(false);
|
setShowNewProjectModal(false);
|
||||||
setNewProjectName(projectName);
|
setNewProjectName(projectName);
|
||||||
setNewProjectPath(projectPath);
|
setNewProjectPath(projectPath);
|
||||||
@@ -269,7 +244,7 @@ export function useProjectCreation({
|
|||||||
setIsCreatingProject(false);
|
setIsCreatingProject(false);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[trashedProjects, currentProject, globalTheme, upsertAndSetCurrentProject]
|
[upsertAndSetCurrentProject]
|
||||||
);
|
);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|||||||
@@ -24,10 +24,10 @@ export function ThemeStep({ onNext, onBack }: ThemeStepProps) {
|
|||||||
|
|
||||||
const handleThemeClick = (themeValue: string) => {
|
const handleThemeClick = (themeValue: string) => {
|
||||||
setTheme(themeValue as typeof theme);
|
setTheme(themeValue as typeof theme);
|
||||||
// Also update the current project's theme if one exists
|
// Clear the current project's theme so it uses the global theme
|
||||||
// This ensures the selected theme is visible since getEffectiveTheme() prioritizes project theme
|
// This ensures "Use Global Theme" is checked and the project inherits the global theme
|
||||||
if (currentProject) {
|
if (currentProject && currentProject.theme !== undefined) {
|
||||||
setProjectTheme(currentProject.id, themeValue as typeof theme);
|
setProjectTheme(currentProject.id, null);
|
||||||
}
|
}
|
||||||
setPreviewTheme(null);
|
setPreviewTheme(null);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ import {
|
|||||||
DialogHeader,
|
DialogHeader,
|
||||||
DialogTitle,
|
DialogTitle,
|
||||||
} from '@/components/ui/dialog';
|
} from '@/components/ui/dialog';
|
||||||
import { useAppStore, type ThemeMode } from '@/store/app-store';
|
import { useAppStore } from '@/store/app-store';
|
||||||
import { getElectronAPI } from '@/lib/electron';
|
import { getElectronAPI } from '@/lib/electron';
|
||||||
import { initializeProject } from '@/lib/project-init';
|
import { initializeProject } from '@/lib/project-init';
|
||||||
import {
|
import {
|
||||||
@@ -38,15 +38,7 @@ import { useNavigate } from '@tanstack/react-router';
|
|||||||
const logger = createLogger('WelcomeView');
|
const logger = createLogger('WelcomeView');
|
||||||
|
|
||||||
export function WelcomeView() {
|
export function WelcomeView() {
|
||||||
const {
|
const { projects, upsertAndSetCurrentProject, addProject, setCurrentProject } = useAppStore();
|
||||||
projects,
|
|
||||||
trashedProjects,
|
|
||||||
currentProject,
|
|
||||||
upsertAndSetCurrentProject,
|
|
||||||
addProject,
|
|
||||||
setCurrentProject,
|
|
||||||
theme: globalTheme,
|
|
||||||
} = useAppStore();
|
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const [showNewProjectModal, setShowNewProjectModal] = useState(false);
|
const [showNewProjectModal, setShowNewProjectModal] = useState(false);
|
||||||
const [isCreating, setIsCreating] = 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)
|
// Upsert project and set as current (handles both create and update cases)
|
||||||
// Theme preservation is handled by the store action
|
// Theme handling (trashed project recovery or undefined for global) is done by the store
|
||||||
const trashedProject = trashedProjects.find((p) => p.path === path);
|
upsertAndSetCurrentProject(path, name);
|
||||||
const effectiveTheme =
|
|
||||||
(trashedProject?.theme as ThemeMode | undefined) ||
|
|
||||||
(currentProject?.theme as ThemeMode | undefined) ||
|
|
||||||
globalTheme;
|
|
||||||
upsertAndSetCurrentProject(path, name, effectiveTheme);
|
|
||||||
|
|
||||||
// Show initialization dialog if files were created
|
// Show initialization dialog if files were created
|
||||||
if (initResult.createdFiles && initResult.createdFiles.length > 0) {
|
if (initResult.createdFiles && initResult.createdFiles.length > 0) {
|
||||||
@@ -150,14 +137,7 @@ export function WelcomeView() {
|
|||||||
setIsOpening(false);
|
setIsOpening(false);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[
|
[upsertAndSetCurrentProject, analyzeProject, navigate]
|
||||||
trashedProjects,
|
|
||||||
currentProject,
|
|
||||||
globalTheme,
|
|
||||||
upsertAndSetCurrentProject,
|
|
||||||
analyzeProject,
|
|
||||||
navigate,
|
|
||||||
]
|
|
||||||
);
|
);
|
||||||
|
|
||||||
const handleOpenProject = useCallback(async () => {
|
const handleOpenProject = useCallback(async () => {
|
||||||
|
|||||||
@@ -1627,16 +1627,18 @@ export const useAppStore = create<AppState & AppActions>()((set, get) => ({
|
|||||||
const updatedProjects = projects.map((p) => (p.id === existingProject.id ? project : p));
|
const updatedProjects = projects.map((p) => (p.id === existingProject.id ? project : p));
|
||||||
set({ projects: updatedProjects });
|
set({ projects: updatedProjects });
|
||||||
} else {
|
} else {
|
||||||
// Create new project - check for trashed project with same path first (preserves theme if deleted/recreated)
|
// Create new project - only set theme if explicitly provided or recovering from trash
|
||||||
// Then fall back to provided theme, then current project theme, then global theme
|
// Otherwise leave undefined so project uses global theme ("Use Global Theme" checked)
|
||||||
const trashedProject = trashedProjects.find((p) => p.path === path);
|
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 = {
|
project = {
|
||||||
id: `project-${Date.now()}`,
|
id: `project-${Date.now()}`,
|
||||||
name,
|
name,
|
||||||
path,
|
path,
|
||||||
lastOpened: new Date().toISOString(),
|
lastOpened: new Date().toISOString(),
|
||||||
theme: effectiveTheme,
|
theme: projectTheme, // May be undefined - intentional!
|
||||||
};
|
};
|
||||||
// Add the new project to the store
|
// Add the new project to the store
|
||||||
set({
|
set({
|
||||||
|
|||||||
Reference in New Issue
Block a user