feat: Add Discord-like project switcher sidebar with icon support

- Add project icon field to ProjectRef and Project types
- Create vertical project switcher sidebar component
  - Project icons with hover tooltips
  - Active project highlighting
  - Plus button to create new projects
  - Right-click context menu for edit/delete
- Add IconPicker component with 35+ Lucide icons
- Add EditProjectDialog for inline project editing
- Update settings appearance section with project details editor
- Add setProjectIcon and setProjectName actions to app store
- Integrate ProjectSwitcher in root layout (shows on app pages only)

Implements #469

Co-authored-by: Web Dev Cody <webdevcody@users.noreply.github.com>
This commit is contained in:
claude[bot]
2026-01-13 17:53:15 +00:00
parent 0dc70addb6
commit 0ddd672e0e
12 changed files with 625 additions and 2 deletions

View File

@@ -873,6 +873,8 @@ export interface AppActions {
cycleNextProject: () => void; // Cycle forward through project history (E)
clearProjectHistory: () => void; // Clear history, keeping only current project
toggleProjectFavorite: (projectId: string) => void; // Toggle project favorite status
setProjectIcon: (projectId: string, icon: string | null) => void; // Set project icon (null to clear)
setProjectName: (projectId: string, name: string) => void; // Update project name
// View actions
setCurrentView: (view: ViewMode) => void;
@@ -1560,6 +1562,38 @@ export const useAppStore = create<AppState & AppActions>()((set, get) => ({
}
},
setProjectIcon: (projectId, icon) => {
const { projects, currentProject } = get();
const updatedProjects = projects.map((p) =>
p.id === projectId ? { ...p, icon: icon === null ? undefined : icon } : p
);
set({ projects: updatedProjects });
// Also update currentProject if it matches
if (currentProject?.id === projectId) {
set({
currentProject: {
...currentProject,
icon: icon === null ? undefined : icon,
},
});
}
},
setProjectName: (projectId, name) => {
const { projects, currentProject } = get();
const updatedProjects = projects.map((p) => (p.id === projectId ? { ...p, name } : p));
set({ projects: updatedProjects });
// Also update currentProject if it matches
if (currentProject?.id === projectId) {
set({
currentProject: {
...currentProject,
name,
},
});
}
},
// View actions
setCurrentView: (view) => set({ currentView: view }),
toggleSidebar: () => set({ sidebarOpen: !get().sidebarOpen }),