diff --git a/ai-docs/ARCHITECTURE.md b/ai-docs/ARCHITECTURE.md index 90af1a7..403d174 100644 --- a/ai-docs/ARCHITECTURE.md +++ b/ai-docs/ARCHITECTURE.md @@ -704,7 +704,7 @@ The task dashboard uses AG-Grid Community v35.1.0 for the main data grid: | Component | Location | Purpose | |-----------|----------|---------| | `RootLayout` | `src/renderer/app/layouts/RootLayout.tsx` | Root shell: renders TitleBar at top, then `react-resizable-panels` (Group/Panel/Separator) for resizable sidebar + content layout. Sidebar panel is collapsible (syncs with layout store). Layout persists to localStorage via `useDefaultLayout`. | -| `TitleBar` | `src/renderer/app/layouts/TitleBar.tsx` | Custom frameless window title bar (32px). Drag region for window movement + minimize/maximize/close controls via `window.*` IPC channels. | +| `TitleBar` | `src/renderer/app/layouts/TitleBar.tsx` | Custom frameless window title bar (32px). Drag region for window movement, utility buttons (screenshot, health, hub status) separated by vertical divider from minimize/maximize/close window controls via `window.*` IPC channels. | | `Sidebar` | `src/renderer/app/layouts/Sidebar.tsx` | Navigation sidebar (fills its parent panel container) | | `TopBar` | `src/renderer/app/layouts/TopBar.tsx` | Top bar with CommandBar trigger | | `CommandBar` | `src/renderer/app/layouts/CommandBar.tsx` | Global command palette (Cmd+K) | diff --git a/ai-docs/FEATURES-INDEX.md b/ai-docs/FEATURES-INDEX.md index 24e61a0..8bf4b7a 100644 --- a/ai-docs/FEATURES-INDEX.md +++ b/ai-docs/FEATURES-INDEX.md @@ -27,7 +27,7 @@ Location: `src/renderer/features/` |---------|---------|----------------|--------------| | **agents** | Agent process management | AgentDashboard, AgentControls, AgentLogs | `agents.*` | | **alerts** | Reminder/alert system | AlertsPage, AlertForm, AlertList | `alerts.*` | -| **assistant** | Built-in Claude assistant | AssistantWidget (WidgetFab, WidgetPanel, WidgetInput, WidgetMessageArea), CommandBar (TopBar) | `assistant.*` | +| **assistant** | Built-in Claude assistant | AssistantWidget (WidgetFab, WidgetPanel, WidgetInput, WidgetMessageArea) | `assistant.*` | | **auth** | User authentication | LoginPage (TanStack Form + Zod), RegisterPage (TanStack Form + Zod), AuthGuard, UserMenu (in layouts); **Hooks**: useForceLogout (IPC-driven logout on token refresh failure) | `auth.*` | | **changelog** | Project changelog viewer | ChangelogPage, ChangelogEntry | `changelog.*` | | **communications** | Slack/Discord integration | SlackPanel, DiscordPanel | MCP tools | @@ -42,8 +42,8 @@ Location: `src/renderer/features/` | **productivity** | Productivity widgets | CalendarWidget, SpotifyWidget | `calendar.*`, `spotify.*` | | **projects** | Project management | ProjectListPage, ProjectSettings, WorktreeManager, ProjectEditDialog, GitStatusIndicator (branch name + clean/changed badge in project list) | `projects.*`, `git.status` | | **roadmap** | Project roadmap | RoadmapPage, MilestoneCard | `milestones.*` | -| **settings** | App settings | SettingsPage, ProfileFormModal (TanStack Form + Zod + FormSelect), HubSettings (ConnectionForm uses TanStack Form + Zod), OAuthProviderSettings, OAuthConnectionStatus, WebhookSettings (SlackForm + GitHubForm use TanStack Form + Zod), StorageManagementSection, StorageUsageBar, RetentionControl | `settings.*`, `oauth.*`, `dataManagement.*` | -| **tasks** | Task management (AG-Grid dashboard) | TaskDataGrid (AG-Grid v35 wrapped in `` from `@ui`; themed via compound `.ag-theme-quartz.ag-theme-claude` CSS class with design-system token overrides in `ag-grid-theme.css`), TaskFiltersToolbar, TaskDetailRow (subtasks use `?? []` fallback for Hub data), TaskStatusBadge, CreateTaskDialog, PlanFeedbackDialog, TaskResultView (status/duration/cost/log summary for completed tasks), CreatePrDialog (GitHub PR creation post-task-completion); **Hooks**: useTaskEvents (→ useAgentEvents + useQaEvents), useAgentMutations (useStartPlanning, useStartExecution, useReplanWithFeedback, useKillAgent, useRestartFromCheckpoint), useQaMutations, QaReportViewer | `hub.tasks.*`, `tasks.*`, `agent.*` (incl. `agent.replanWithFeedback`), `qa.*`, `git.createPr`, `event:agent.orchestrator.*`, `event:qa.*` | +| **settings** | App settings | SettingsPage, ProfileFormModal (TanStack Form + Zod + FormSelect), HubSettings (ConnectionForm uses TanStack Form + Zod), OAuthProviderSettings, OAuthConnectionStatus, WebhookSettings (SlackForm + GitHubForm use TanStack Form + Zod), StorageManagementSection, StorageUsageBar, RetentionControl, ColorThemeSection; **Theme Editor** (`components/theme-editor/`, 10 files): ThemeEditorPage, ColorControl, ColorSection, ThemePreview, SavedThemesBar, CssImportDialog, css-parser.ts, css-exporter.ts, token-sections.ts — Route: `/settings/themes` | `settings.*`, `oauth.*`, `dataManagement.*` | +| **tasks** | Task management (AG-Grid dashboard) | TaskDataGrid (AG-Grid v35 wrapped in `` from `@ui`; themed via compound `.ag-theme-quartz.ag-theme-claude` CSS class with design-system token overrides via AG-Grid Theming API in `ag-grid-modules.ts`), TaskFiltersToolbar, TaskDetailRow (subtasks use `?? []` fallback for Hub data), TaskStatusBadge, CreateTaskDialog, PlanFeedbackDialog, TaskResultView (status/duration/cost/log summary for completed tasks), CreatePrDialog (GitHub PR creation post-task-completion); **Hooks**: useTaskEvents (→ useAgentEvents + useQaEvents), useAgentMutations (useStartPlanning, useStartExecution, useReplanWithFeedback, useKillAgent, useRestartFromCheckpoint), useQaMutations, QaReportViewer | `hub.tasks.*`, `tasks.*`, `agent.*` (incl. `agent.replanWithFeedback`), `qa.*`, `git.createPr`, `event:agent.orchestrator.*`, `event:qa.*` | | **terminals** | Terminal emulator | TerminalGrid, TerminalInstance | `terminals.*` | | **briefing** | Daily briefing & suggestions | BriefingPage, SuggestionCard | `briefing.*` | | **merge** | Branch merge workflow | MergeConfirmModal, MergePreviewPanel, ConflictResolver, FileDiffViewer (`@git-diff-view/react`) | `merge.*` | @@ -388,11 +388,11 @@ Location: `src/renderer/app/layouts/` | Layout | Purpose | |--------|---------| -| `RootLayout.tsx` | Root shell: renders TitleBar at top, then `react-resizable-panels` (Group/Panel/Separator) for sidebar + content layout with localStorage persistence. Sidebar panel is collapsible (collapses to 56px, minSize 160px so labels are visible when expanded, maxSize 300px) and syncs with layout store. | -| `TitleBar.tsx` | Custom frameless window title bar (32px). Drag region for window movement + minimize/maximize/close controls. Uses `window.*` IPC channels. | +| `RootLayout.tsx` | Root shell: renders TitleBar at top, then `react-resizable-panels` (Group/Panel/Separator) for sidebar + content layout with localStorage persistence. Sidebar panel is collapsible (collapses to 56px, minSize 160px, maxSize 300px) and syncs with layout store. | +| `TitleBar.tsx` | Custom frameless window title bar (32px). Drag region for window movement, utility buttons (screenshot, health indicator, hub status) separated by vertical divider from minimize/maximize/close window controls. Uses `window.*` IPC channels. | +| `TitleBarScreenshot.tsx` | Camera icon button that captures the primary screen via `screen.listSources` + `screen.capture` IPC channels and copies PNG to clipboard. Shows checkmark feedback for 1.5s on success. | | `Sidebar.tsx` | Navigation sidebar (fills its parent panel, collapse state driven by layout store). Uses `bg-sidebar text-sidebar-foreground` theme variables. | -| `TopBar.tsx` | Top bar with assistant command input | -| `CommandBar.tsx` | Global command palette (Cmd+K) | +| `TopBar.tsx` | Top bar with project tabs + add button | | `ProjectTabBar.tsx` | Horizontal tab bar for switching between open projects | | `UserMenu.tsx` | Avatar + logout dropdown in sidebar footer | @@ -474,7 +474,6 @@ Location: `src/renderer/shared/stores/` | Store | Purpose | |-------|---------| | `assistant-widget-store.ts` | Floating assistant widget open/close state (`useAssistantWidgetStore`) | -| `command-bar-store.ts` | CommandBar processing state, input history, toast visibility | | `layout-store.ts` | Sidebar state, active project, project tabs, resizable panel layout (persisted via `react-resizable-panels` `useDefaultLayout`) | | `theme-store.ts` | Dark/light mode, color theme, UI scale | | `toast-store.ts` | Toast notification queue (max 3, auto-dismiss 5s) | @@ -541,7 +540,7 @@ ADC/ │ │ │ │ └── ui/ # 30 design system primitives (shadcn/ui pattern, barrel: @ui) │ │ │ ├── hooks/ # 6 shared hooks (+ useLooseParams) │ │ │ ├── lib/ # Utilities (cn, ipc helper) -│ │ │ └── stores/ # 5 Zustand stores + ThemeHydrator +│ │ │ └── stores/ # 4 Zustand stores + ThemeHydrator │ │ └── styles/globals.css # Theme tokens + Tailwind │ └── shared/ # Shared between main + renderer │ ├── ipc-contract.ts # Thin re-export from ipc/ barrel diff --git a/ai-docs/PATTERNS.md b/ai-docs/PATTERNS.md index 305cf04..00d4b41 100644 --- a/ai-docs/PATTERNS.md +++ b/ai-docs/PATTERNS.md @@ -470,25 +470,35 @@ Every theme block must define all tokens. Template: ### Theme Switching Flow +Custom themes inject CSS variables at runtime via `document.documentElement.style.setProperty('--token', value)`. + ``` -User selects theme → useThemeStore.setColorTheme('ocean') +User selects custom theme → useThemeStore.setColorTheme(themeId) → Zustand state updates - → applyColorTheme() sets data-theme="ocean" on - → CSS [data-theme="ocean"] variables take effect + → applyColorTheme() sets data-theme="{uuid}" on + → applyCustomTokens() calls setProperty() for all 33 CSS tokens → All Tailwind classes (bg-primary, etc.) automatically use new values → color-mix() expressions automatically use new values -``` + → AG-Grid reads the same CSS vars automatically via its Theming API -### Constants for Theme Names +User selects default theme → useThemeStore.setColorTheme('default') + → removeProperty() clears all custom CSS var overrides + → data-theme attribute is removed from + → Base :root / .dark CSS variables take effect +``` -```typescript -import { COLOR_THEMES } from '@shared/constants'; -import type { ColorTheme } from '@shared/constants'; +### Custom Theme Token Injection -// Available: 'default' | 'dusk' | 'lime' | 'ocean' | 'retro' | 'neo' | 'forest' -``` +Custom themes inject CSS variables at runtime via `document.documentElement.style.setProperty('--token', value)`. +The theme store's `applyCustomTokens()` function applies all 33 tokens when a custom theme is selected. +To clear custom tokens: `removeProperty('--token')` for each key. +AG-Grid reads the same CSS vars automatically via its Theming API configuration in `ag-grid-modules.ts`. -When adding a theme, update BOTH `globals.css` AND `src/shared/constants/themes.ts`. +The Theme Editor page (`/settings/themes`) provides: +- Color pickers organized in sections (Base, Card & Surface, Brand, Semantic, Controls, Sidebar, Utility) +- Live preview with isolated CSS scope +- CSS import/export for theme portability +- Save/load named themes to local storage ### Terminal Theme Integration (xterm.js) @@ -529,51 +539,16 @@ For branded buttons that need a dark appearance on light backgrounds and vice ve ## AG-Grid Theming Pattern -AG-Grid v35 uses the quartz theme with design-system token overrides. The theme CSS lives at `src/renderer/features/tasks/components/grid/ag-grid-theme.css` and is imported in `globals.css`. +AG-Grid v35 uses the quartz theme with design-system token overrides. Theme configuration is defined programmatically via the AG-Grid Theming API in `src/renderer/features/tasks/components/grid/ag-grid-modules.ts`, reading CSS custom properties at runtime. ### How It Works 1. **Base theme**: `ag-theme-quartz` (imported from `ag-grid-community/styles/`) 2. **Override class**: `ag-theme-claude` stacked with quartz for compound specificity -3. **CSS variables**: `--ag-*` properties mapped to design system tokens (`var(--card)`, `var(--foreground)`, etc.) -4. **Interactive states**: Use `color-mix()` for hover/selection (NEVER hardcode hex/rgb) -5. **Dark mode**: `.dark .ag-theme-quartz.ag-theme-claude` sets `color-scheme: dark` for native scrollbars/controls -6. **Explicit fallbacks**: `.ag-root-wrapper` and `.ag-body-viewport` get direct `background-color` overrides in case CSS variable inheritance doesn't cascade through AG-Grid's internal DOM - -### Variable Categories - -The theme CSS defines variables across these groups: -- **Core**: `--ag-background-color`, `--ag-foreground-color`, `--ag-data-background-color`, `--ag-border-color`, `--ag-secondary-border-color` -- **Header**: `--ag-header-background-color`, `--ag-header-foreground-color`, `--ag-header-cell-hover-background-color` -- **Rows**: `--ag-odd-row-background-color`, `--ag-row-hover-color`, `--ag-row-border-color`, `--ag-selected-row-background-color`, `--ag-range-selection-background-color` -- **Controls**: `--ag-input-focus-border-color`, `--ag-input-border-color`, `--ag-checkbox-checked-color`, `--ag-toggle-button-on-background-color` -- **Text**: `--ag-secondary-foreground-color`, `--ag-disabled-foreground-color` -- **Panels/Menus**: `--ag-control-panel-background-color`, `--ag-menu-background-color`, `--ag-panel-background-color`, `--ag-modal-overlay-background-color`, `--ag-tooltip-background-color` - -**Critical**: `--ag-data-background-color` MUST be set explicitly — it controls the data viewport area and defaults to white if omitted, breaking dark mode. - -### CSS Selector Pattern - -```css -/* Compound selector ensures overrides beat quartz defaults */ -.ag-theme-quartz.ag-theme-claude { - --ag-background-color: var(--card); - --ag-foreground-color: var(--foreground); - --ag-data-background-color: var(--card); - --ag-header-background-color: var(--muted); - --ag-row-hover-color: color-mix(in srgb, var(--accent) 50%, transparent); - /* ... */ -} - -/* Dark mode: native scrollbar + control dark rendering */ -.dark .ag-theme-quartz.ag-theme-claude { - color-scheme: dark; -} - -/* Explicit background fallbacks for AG-Grid internal DOM */ -.ag-theme-quartz.ag-theme-claude .ag-root-wrapper { background-color: var(--card); } -.ag-theme-quartz.ag-theme-claude .ag-body-viewport { background-color: var(--card); } -``` +3. **Theming API**: AG-Grid's `themeQuartz.withPart(colorSchemeDark).withParams()` maps theme params to design system CSS vars at runtime (defined in `ag-grid-theme.ts`) +4. **Custom themes**: Because AG-Grid reads CSS custom properties, custom themes applied via `setProperty()` are automatically picked up — no AG-Grid-specific reconfiguration needed +5. **Interactive states**: Use `color-mix()` for hover/selection (NEVER hardcode hex/rgb) +6. **Dark mode**: `colorSchemeDark` part handles native scrollbar/control rendering ### Component Usage diff --git a/ai-docs/user-interface-flow.md b/ai-docs/user-interface-flow.md index 0306937..a7ec0cb 100644 --- a/ai-docs/user-interface-flow.md +++ b/ai-docs/user-interface-flow.md @@ -244,7 +244,7 @@ After auth + onboarding, the user sees the main app shell: ``` ┌─────────────────────────────────────────────────────┐ -│ TopBar: [Project Tabs] [+] ─ [📷] [Health] [Hub] [⌘K] │ +│ TopBar: [Project Tabs] [+] │ ├──────────┬──────────────────────────────────────────┤ │ Sidebar │ Main Content Area () │ │ │ │ @@ -279,8 +279,7 @@ After auth + onboarding, the user sees the main app shell: |-----------|------|---------| | `RootLayout` | `src/renderer/app/layouts/RootLayout.tsx` | Shell: sidebar (collapsible, minSize 160px) + topbar + outlet + notifications | | `Sidebar` | `src/renderer/app/layouts/Sidebar.tsx` | Nav items (top-level + project-scoped), collapsible. Uses `bg-sidebar text-sidebar-foreground` theme vars. | -| `TopBar` | `src/renderer/app/layouts/TopBar.tsx` | Project tabs + add button + ScreenshotButton + Health + Hub status + command bar | -| `CommandBar` | `src/renderer/app/layouts/CommandBar.tsx` | Global assistant input (Cmd+K) | +| `TopBar` | `src/renderer/app/layouts/TopBar.tsx` | Project tabs + add button (utility buttons moved to TitleBar; AssistantWidget provides global assistant access) | | `ProjectTabBar` | `src/renderer/app/layouts/ProjectTabBar.tsx` | Horizontal tab bar for switching between open projects | | `UserMenu` | `src/renderer/app/layouts/UserMenu.tsx` | Avatar + logout dropdown in sidebar footer (above HubConnectionIndicator) | | `AssistantWidget` | `src/renderer/features/assistant/components/AssistantWidget.tsx` | Floating chat widget (Ctrl+J toggle), renders WidgetFab + WidgetPanel | @@ -570,7 +569,7 @@ Hub broadcasts WebSocket event - `src/renderer/features/tasks/store.ts` — UI state (expanded rows, filters) - `src/main/ipc/handlers/task-handlers.ts` — all task IPC handlers + transforms - `src/renderer/features/tasks/components/grid/ag-grid-modules.ts` — AG-Grid module registration -- `src/renderer/features/tasks/components/grid/ag-grid-theme.css` — custom theme +- `src/renderer/features/tasks/components/grid/ag-grid-modules.ts` — AG-Grid modules + Theming API config --- @@ -868,7 +867,7 @@ Email integration: | **Background & Startup** | `BackgroundSettings.tsx` | `settings.update`, `app.setOpenAtLogin` | Open at login, minimize to tray | | **Profiles** | `ProfileSection.tsx` | `settings.getProfiles`, `settings.createProfile`, `settings.updateProfile`, `settings.deleteProfile`, `settings.setDefaultProfile` | Claude API profiles (name, API key, model) | | **Workspaces** | `WorkspacesTab.tsx` | `workspaces.list`, `workspaces.create`, `workspaces.update`, `workspaces.delete` | Workspace CRUD | -| **Color Theme** | inline in `SettingsPage` | `settings.update` | 7 color themes (default, dusk, lime, ocean, retro, neo, forest) | +| **Color Theme** | `ColorThemeSection.tsx` | `settings.update` | Shows active theme name + "Customize Theme" button → navigates to Theme Editor (`/settings/themes`) | | **UI Scale** | inline in `SettingsPage` | `settings.update` | 75%–150% scaling slider | | **Font Family** | inline in `SettingsPage` | `settings.update` | System/Inter/JetBrains Mono/Fira Code/SF Mono | | **Font Size** | inline in `SettingsPage` | `settings.update` | 12px–20px slider | @@ -881,6 +880,60 @@ Email integration: | **Storage Management** | `StorageManagementSection.tsx` (+ `StorageUsageBar.tsx`, `RetentionControl.tsx`) | `dataManagement.getRegistry`, `dataManagement.getUsage`, `dataManagement.getRetention`, `dataManagement.updateRetention`, `dataManagement.clearStore`, `dataManagement.runCleanup`, `dataManagement.exportData`, `dataManagement.importData`, `event:dataManagement.cleanupComplete` | Storage usage bar, per-store retention policies, auto-cleanup toggle, manual cleanup, data export/import | | **About** | inline | — | Version number (v0.1.0) | +### 23.0 Theme Editor Page + +**Route**: `/settings/themes` +**Component**: `ThemeEditorPage` +**File**: `src/renderer/features/settings/components/theme-editor/ThemeEditorPage.tsx` + +**Navigation**: Settings → "Customize Theme" button → Theme Editor Page + +``` +┌──────────────────────────────────────────────────────────────┐ +│ [← Back to Settings] [Light/Dark] [Import CSS] [Export] │ +│ [Apply] [Save] │ +├────────────────────────────┬─────────────────────────────────┤ +│ Color Controls (left) │ Live Preview (right) │ +│ │ │ +│ ▸ Base │ ┌─────────────────────────┐ │ +│ - Background │ │ Isolated preview with │ │ +│ - Foreground │ │ current token values │ │ +│ - Border │ │ │ │ +│ ▸ Card & Surface │ │ Card, buttons, inputs, │ │ +│ - Card │ │ badges, sidebar mock │ │ +│ - Card Foreground │ └─────────────────────────┘ │ +│ ▸ Brand │ │ +│ - Primary │ │ +│ - Secondary │ │ +│ ▸ Semantic │ │ +│ - Success/Warning/Error │ │ +│ ▸ Controls │ │ +│ ▸ Sidebar │ │ +│ ▸ Utility │ │ +├────────────────────────────┴─────────────────────────────────┤ +│ Saved Themes: [Theme A] [Theme B] [+] │ +└──────────────────────────────────────────────────────────────┘ +``` + +**Data flow**: +- Custom themes inject CSS vars at runtime via `document.documentElement.style.setProperty('--token', value)` +- `data-theme` attribute set to UUID of the custom theme (not a name like "ocean") +- Default theme: `data-theme` is removed; base `:root`/`.dark` vars apply +- Themes saved to localStorage as JSON objects with all 33 token values +- CSS import parses `:root { --token: value; }` blocks; CSS export generates them + +**Key files**: +- `src/renderer/features/settings/components/theme-editor/ThemeEditorPage.tsx` +- `src/renderer/features/settings/components/theme-editor/ColorControl.tsx` +- `src/renderer/features/settings/components/theme-editor/ColorSection.tsx` +- `src/renderer/features/settings/components/theme-editor/ThemePreview.tsx` +- `src/renderer/features/settings/components/theme-editor/SavedThemesBar.tsx` +- `src/renderer/features/settings/components/theme-editor/CssImportDialog.tsx` +- `src/renderer/features/settings/components/theme-editor/css-parser.ts` +- `src/renderer/features/settings/components/theme-editor/css-exporter.ts` +- `src/renderer/features/settings/components/theme-editor/token-sections.ts` +- `src/renderer/features/settings/components/ColorThemeSection.tsx` (settings page entry point) + ### 23.1 Profile Save Flow (When User Clicks "Save" on a Profile) ``` @@ -1249,7 +1302,7 @@ Complete list of all registered IPC channels by domain: | G-7 | ~~Project delete confirmation~~ | Low | Projects | **RESOLVED** (2026-02-18) — `ProjectEditDialog.tsx` uses `ConfirmDialog` with `variant="destructive"`, `title="Delete Project"`, wired to `removeProject.mutate()`. | | G-8 | ~~Workspace assignment in project wizard~~ | Low | Projects | **RESOLVED** (2026-02-18) — `StepConfigure.tsx` renders workspace ` { - setInputValue(e.target.value); - }} - /> - - - - - {/* Toast notification */} - {isToastVisible && lastResponse !== null ? ( -
-
- {isError ? ( - - ) : ( - - )} -

{lastResponse.content}

-
-
- ) : null} - - ); -} diff --git a/src/renderer/app/layouts/Sidebar.tsx b/src/renderer/app/layouts/Sidebar.tsx index 62ae9dd..b02916f 100644 --- a/src/renderer/app/layouts/Sidebar.tsx +++ b/src/renderer/app/layouts/Sidebar.tsx @@ -1,7 +1,7 @@ /** * Sidebar -- Navigation sidebar * - * Shows nav items for the active project's views. + * Shows nav items grouped into collapsible "Personal" and "Development" sections. * Collapses to icon-only mode. */ @@ -12,6 +12,7 @@ import { Bot, Briefcase, CalendarDays, + ChevronDown, Dumbbell, Globe, GitBranch, @@ -23,6 +24,7 @@ import { Newspaper, PanelLeft, PanelLeftClose, + Plus, ScrollText, Settings, StickyNote, @@ -36,6 +38,8 @@ import { HubConnectionIndicator } from '@renderer/shared/components/HubConnectio import { cn } from '@renderer/shared/lib/utils'; import { useLayoutStore } from '@renderer/shared/stores'; +import { Collapsible, CollapsibleContent, CollapsibleTrigger } from '@ui'; + import { UserMenu } from './UserMenu'; interface NavItem { @@ -51,8 +55,8 @@ const INACTIVE_STYLE = 'text-muted-foreground'; const ACTIVE_STYLE = 'bg-accent text-foreground font-medium'; const COLLAPSED_STYLE = 'justify-center px-0'; -/** Top-level nav items (not project-scoped) */ -const topLevelItems: NavItem[] = [ +/** Personal nav items (not project-scoped) */ +const personalItems: NavItem[] = [ { label: 'Dashboard', icon: Home, path: ROUTES.DASHBOARD }, { label: 'Briefing', icon: Newspaper, path: ROUTES.BRIEFING }, { label: 'My Work', icon: Briefcase, path: ROUTES.MY_WORK }, @@ -64,8 +68,8 @@ const topLevelItems: NavItem[] = [ { label: 'Comms', icon: Globe, path: ROUTES.COMMUNICATIONS }, ]; -/** Project-scoped nav items */ -const projectItems: NavItem[] = [ +/** Development nav items (project-scoped) */ +const developmentItems: NavItem[] = [ { label: 'Tasks', icon: ListTodo, path: PROJECT_VIEWS.TASKS }, { label: 'Terminals', icon: Terminal, path: PROJECT_VIEWS.TERMINALS }, { label: 'Agents', icon: Bot, path: PROJECT_VIEWS.AGENTS }, @@ -96,6 +100,68 @@ export function Sidebar() { void navigate({ to: projectViewPath(activeProjectId, path) }); } + function renderPersonalItem(item: NavItem) { + const isActive = + currentPath === item.path || currentPath.startsWith(`${item.path}/`); + return ( + + ); + } + + function renderDevelopmentItem(item: NavItem) { + const isActive = + activeProjectId !== null && currentPath.endsWith(`/${item.path}`); + return ( + + ); + } + + function renderAddProjectButton() { + return ( + + ); + } + return (