diff --git a/implementation-plans/_index.md b/implementation-plans/_index.md index 450a838..7345620 100644 --- a/implementation-plans/_index.md +++ b/implementation-plans/_index.md @@ -19,3 +19,4 @@ | #15 | Agent lineage visualization | COMPLETED | [issue-015.md](issue-015.md) | | #16 | Memory candidates viewer | COMPLETED | [issue-016.md](issue-016.md) | | #17 | Audit/activity log view | COMPLETED | [issue-017.md](issue-017.md) | +| #18 | Dark/light theme toggle | COMPLETED | [issue-018.md](issue-018.md) | diff --git a/implementation-plans/issue-018.md b/implementation-plans/issue-018.md new file mode 100644 index 0000000..081a7e0 --- /dev/null +++ b/implementation-plans/issue-018.md @@ -0,0 +1,68 @@ +# Issue #18: Dark/Light Theme Toggle + +## Status: COMPLETED + +## Overview +Add a dark/light theme toggle to the UI with three modes (system, light, dark), persisted in localStorage, defaulting to system preference. + +## Implementation Details + +### 1. Tailwind v4 Dark Mode Configuration +- Updated `src/app.css` with `@variant dark (&:where(.dark, .dark *));` for class-based dark mode + +### 2. Theme Store (`src/lib/stores/theme.svelte.ts`) +- Svelte 5 runes-based store with three modes: 'light', 'dark', 'system' +- Loads preference from localStorage on init, defaults to 'system' +- Listens to `prefers-color-scheme` media query when in 'system' mode +- Applies/removes `dark` class on `document.documentElement` +- Adds temporary `theme-transition` class for smooth CSS transitions + +### 3. ThemeToggle Component (`src/lib/components/ThemeToggle.svelte`) +- Compact button that cycles: system -> light -> dark -> system +- SVG icons: monitor (system), sun (light), moon (dark) +- Text label showing current mode +- Dark mode aware styling + +### 4. Layout Integration +- Theme store initialized via `$effect` in `+layout.svelte` +- Global CSS transition styles for smooth theme switching +- ThemeToggle added to all page headers (chat, lineage, memory, audit, home) + +### 5. Dark Mode Classes Applied To +- `src/routes/+page.svelte` (home page) +- `src/routes/chat/+page.svelte` (chat page) +- `src/routes/lineage/+page.svelte` (lineage page) +- `src/routes/memory/+page.svelte` (memory page) +- `src/routes/audit/+page.svelte` (audit page) +- `src/lib/components/SessionSidebar.svelte` +- `src/lib/components/ConfigSidebar.svelte` +- `src/lib/components/MessageBubble.svelte` +- `src/lib/components/MessageList.svelte` +- `src/lib/components/MessageInput.svelte` +- `src/lib/components/OrchestrationProgress.svelte` +- `src/lib/components/ThinkingSection.svelte` +- `src/lib/components/FinalResult.svelte` +- `src/lib/components/LineageTree.svelte` +- `src/lib/components/MemoryCandidateCard.svelte` +- `src/lib/components/AuditTimeline.svelte` + +### Color Mapping Applied +- `bg-white` -> `dark:bg-gray-900` +- `bg-gray-50` -> `dark:bg-gray-800` +- `bg-gray-100` -> `dark:bg-gray-700` +- `bg-gray-200` -> `dark:bg-gray-600`/`dark:bg-gray-700` +- `text-gray-900` -> `dark:text-gray-100` +- `text-gray-700` -> `dark:text-gray-300` +- `text-gray-500` -> `dark:text-gray-400` +- `text-gray-400` -> `dark:text-gray-500` +- `border-gray-200` -> `dark:border-gray-700` +- `border-gray-300` -> `dark:border-gray-600` +- Colored backgrounds (blue, green, amber, red, purple) use opacity-based dark variants (e.g., `dark:bg-blue-900/40`) +- SVG elements in LineageTree use reactive color values based on `themeStore.isDark` + +## Files Changed +- `src/app.css` - Added dark mode variant configuration +- `src/lib/stores/theme.svelte.ts` - New theme store +- `src/lib/components/ThemeToggle.svelte` - New toggle component +- `src/routes/+layout.svelte` - Theme init and transition styles +- All page and component files listed above - Added dark: variants diff --git a/src/app.css b/src/app.css index d4b5078..062569c 100644 --- a/src/app.css +++ b/src/app.css @@ -1 +1,3 @@ @import 'tailwindcss'; + +@variant dark (&:where(.dark, .dark *)); diff --git a/src/lib/components/AuditTimeline.svelte b/src/lib/components/AuditTimeline.svelte index 176473f..c782f7c 100644 --- a/src/lib/components/AuditTimeline.svelte +++ b/src/lib/components/AuditTimeline.svelte @@ -14,15 +14,15 @@ function typeBadgeClasses(eventType: string): string { switch (eventType) { case 'state_change': - return 'bg-blue-100 text-blue-700'; + return 'bg-blue-100 dark:bg-blue-900/40 text-blue-700 dark:text-blue-300'; case 'tool_invocation': - return 'bg-green-100 text-green-700'; + return 'bg-green-100 dark:bg-green-900/40 text-green-700 dark:text-green-300'; case 'error': - return 'bg-red-100 text-red-700'; + return 'bg-red-100 dark:bg-red-900/40 text-red-700 dark:text-red-300'; case 'message': - return 'bg-gray-100 text-gray-600'; + return 'bg-gray-100 dark:bg-gray-800 text-gray-600 dark:text-gray-400'; default: - return 'bg-gray-100 text-gray-600'; + return 'bg-gray-100 dark:bg-gray-800 text-gray-600 dark:text-gray-400'; } } @@ -59,14 +59,14 @@ {#if events.length === 0}
No events for this session
-Events will appear here as orchestration runs.
+No events for this session
+Events will appear here as orchestration runs.
{event.details}
+{event.details}