docs: Add comprehensive implementation plans for all todo items

Created detailed markdown plans for all items in todo.md:

1. 01-playwright-scaffolding.md - Base Playwright infrastructure
2. 02-magnitude-tests-comprehensive.md - Complete test coverage
3. 03-stream-ai-to-deepgram-tts.md - TTS latency optimization
4. 04-fix-galaxy-node-clicking.md - Galaxy navigation bugs
5. 05-dark-light-mode-theme.md - Dark/light mode with dynamic favicons
6. 06-fix-double-border-desktop.md - UI polish
7. 07-delete-backup-files.md - Code cleanup
8. 08-ai-transition-to-edit.md - Intelligent node creation flow
9. 09-umap-minimum-nodes-analysis.md - Technical analysis

Each plan includes:
- Detailed problem analysis
- Proposed solutions with code examples
- Manual Playwright MCP testing strategy
- Magnitude test specifications
- Implementation steps
- Success criteria

Ready to implement in sequence.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2025-11-09 21:07:42 +00:00
parent 346326e31f
commit b96159ec02
9 changed files with 2994 additions and 0 deletions

View File

@@ -0,0 +1,463 @@
# Plan: Add Dark/Light Mode with Dynamic Favicons
**Priority:** MEDIUM
**Dependencies:** None
**Affects:** User experience, accessibility, branding
## Overview
Add full dark mode / light mode support throughout the app, including:
- Dynamic theme switching
- Persistent user preference
- System preference detection
- Mode-specific favicons
- Smooth transitions
## Current State
- App uses a minimal grayscale theme
- No dark mode support
- Single favicon for all modes
- No theme toggle UI
## Proposed Implementation
### 1. Mantine Color Scheme Support
Mantine has built-in dark mode support. We'll leverage `@mantine/core` ColorSchemeScript and hooks.
#### Update `app/layout.tsx`
```typescript
import {
ColorSchemeScript,
MantineProvider,
} from '@mantine/core';
export default function RootLayout({
children,
}: {
children: React.ReactNode;
}) {
return (
<html lang="en">
<head>
<ColorSchemeScript defaultColorScheme="auto" />
{/* Dynamic favicon based on theme */}
<link
rel="icon"
href="/favicon-light.svg"
media="(prefers-color-scheme: light)"
/>
<link
rel="icon"
href="/favicon-dark.svg"
media="(prefers-color-scheme: dark)"
/>
</head>
<body>
<MantineProvider defaultColorScheme="auto">
{children}
</MantineProvider>
</body>
</html>
);
}
```
### 2. Update Theme Configuration
#### `app/theme.ts`
```typescript
import { createTheme, MantineColorsTuple } from '@mantine/core';
const gray: MantineColorsTuple = [
'#f8f9fa',
'#f1f3f5',
'#e9ecef',
'#dee2e6',
'#ced4da',
'#adb5bd',
'#868e96',
'#495057',
'#343a40',
'#212529',
];
export const theme = createTheme({
fontFamily: 'Inter, system-ui, sans-serif',
primaryColor: 'gray',
colors: {
gray,
},
// Dark mode specific colors
black: '#0a0a0a',
white: '#ffffff',
// Component-specific dark mode overrides
components: {
AppShell: {
styles: (theme) => ({
main: {
backgroundColor: theme.colorScheme === 'dark'
? theme.colors.dark[8]
: theme.white,
},
}),
},
Paper: {
styles: (theme) => ({
root: {
backgroundColor: theme.colorScheme === 'dark'
? theme.colors.dark[7]
: theme.white,
borderColor: theme.colorScheme === 'dark'
? theme.colors.dark[5]
: theme.colors.gray[3],
},
}),
},
Modal: {
styles: (theme) => ({
content: {
backgroundColor: theme.colorScheme === 'dark'
? theme.colors.dark[7]
: theme.white,
},
header: {
backgroundColor: theme.colorScheme === 'dark'
? theme.colors.dark[6]
: theme.colors.gray[0],
},
}),
},
},
});
```
### 3. Theme Toggle Component
#### `components/ThemeToggle.tsx`
```typescript
'use client';
import { ActionIcon, useMantineColorScheme, useComputedColorScheme } from '@mantine/core';
import { IconSun, IconMoon } from '@tabler/icons-react';
export function ThemeToggle() {
const { setColorScheme } = useMantineColorScheme();
const computedColorScheme = useComputedColorScheme('light');
return (
<ActionIcon
onClick={() => setColorScheme(computedColorScheme === 'dark' ? 'light' : 'dark')}
variant="subtle"
size="lg"
aria-label="Toggle color scheme"
>
{computedColorScheme === 'dark' ? (
<IconSun size={20} />
) : (
<IconMoon size={20} />
)}
</ActionIcon>
);
}
```
### 4. Add Toggle to Desktop Navigation
#### `components/DesktopNav.tsx`
```typescript
import { ThemeToggle } from './ThemeToggle';
export function DesktopNav() {
return (
<AppShell.Navbar p="md">
<Stack justify="space-between" h="100%">
<Stack>
{/* Navigation items */}
</Stack>
<Stack>
<ThemeToggle />
{/* Profile menu */}
</Stack>
</Stack>
</AppShell.Navbar>
);
}
```
### 5. Create Mode-Specific Favicons
#### Design Requirements
- **Light mode favicon:** Dark icon on transparent background
- **Dark mode favicon:** Light icon on transparent background
- Both should be SVG for scalability
- Simple, recognizable icon representing "thoughts" or "ponderants"
#### `public/favicon-light.svg`
```svg
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100">
<!-- Dark icon for light mode -->
<circle cx="50" cy="50" r="40" fill="#212529" />
<circle cx="35" cy="45" r="5" fill="#ffffff" />
<circle cx="65" cy="45" r="5" fill="#ffffff" />
<path d="M 30 65 Q 50 75 70 65" stroke="#ffffff" stroke-width="3" fill="none" />
</svg>
```
#### `public/favicon-dark.svg`
```svg
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100">
<!-- Light icon for dark mode -->
<circle cx="50" cy="50" r="40" fill="#f8f9fa" />
<circle cx="35" cy="45" r="5" fill="#212529" />
<circle cx="65" cy="45" r="5" fill="#212529" />
<path d="M 30 65 Q 50 75 70 65" stroke="#212529" stroke-width="3" fill="none" />
</svg>
```
### 6. Update Galaxy Visualization for Dark Mode
The 3D galaxy needs to look good in both modes:
#### `components/galaxy/ThoughtGalaxy.tsx`
```typescript
'use client';
import { useComputedColorScheme } from '@mantine/core';
export function ThoughtGalaxy() {
const colorScheme = useComputedColorScheme('light');
const isDark = colorScheme === 'dark';
return (
<Canvas
style={{
background: isDark
? 'linear-gradient(to bottom, #0a0a0a, #1a1a1a)'
: 'linear-gradient(to bottom, #f8f9fa, #e9ecef)',
}}
>
<ambientLight intensity={isDark ? 0.3 : 0.5} />
<pointLight position={[10, 10, 10]} intensity={isDark ? 0.8 : 1} />
{/* Node spheres - adjust color based on theme */}
<NodeSphere color={isDark ? '#f8f9fa' : '#212529'} />
{/* Link lines */}
<LinkLine color={isDark ? 'rgba(248, 249, 250, 0.3)' : 'rgba(33, 37, 41, 0.3)'} />
</Canvas>
);
}
```
### 7. Persist User Preference
Mantine automatically stores the preference in localStorage with the key `mantine-color-scheme-value`.
For server-side rendering, we can add a cookie fallback:
#### `middleware.ts`
```typescript
import { NextResponse } from 'next/server';
import type { NextRequest } from 'next/server';
export function middleware(request: NextRequest) {
const response = NextResponse.next();
// Set color scheme cookie if not present
if (!request.cookies.has('mantine-color-scheme')) {
response.cookies.set('mantine-color-scheme', 'auto');
}
return response;
}
```
## Testing Strategy
### Manual Playwright MCP Testing
#### Test 1: Theme Toggle
```typescript
test('User can toggle between light and dark mode', async ({ page }) => {
await page.goto('/');
// Check initial theme
const initialTheme = await page.evaluate(() => {
return document.documentElement.getAttribute('data-mantine-color-scheme');
});
// Click theme toggle
await page.click('[aria-label="Toggle color scheme"]');
// Check theme changed
const newTheme = await page.evaluate(() => {
return document.documentElement.getAttribute('data-mantine-color-scheme');
});
expect(newTheme).not.toBe(initialTheme);
});
```
#### Test 2: Theme Persistence
```typescript
test('Theme preference persists across page refreshes', async ({ page }) => {
await page.goto('/');
// Set to dark mode
await page.click('[aria-label="Toggle color scheme"]');
await page.waitForTimeout(100);
const darkTheme = await page.evaluate(() => {
return document.documentElement.getAttribute('data-mantine-color-scheme');
});
// Refresh page
await page.reload();
// Check theme persisted
const persistedTheme = await page.evaluate(() => {
return document.documentElement.getAttribute('data-mantine-color-scheme');
});
expect(persistedTheme).toBe(darkTheme);
});
```
#### Test 3: Favicon Changes
```typescript
test('Favicon changes with theme', async ({ page }) => {
await page.goto('/');
// Get favicon in light mode
const lightFavicon = await page.evaluate(() => {
const link = document.querySelector('link[rel="icon"]');
return link?.getAttribute('href');
});
// Switch to dark mode
await page.click('[aria-label="Toggle color scheme"]');
await page.waitForTimeout(100);
// Get favicon in dark mode
const darkFavicon = await page.evaluate(() => {
const link = document.querySelector('link[rel="icon"]');
return link?.getAttribute('href');
});
expect(lightFavicon).toContain('light');
expect(darkFavicon).toContain('dark');
});
```
### Magnitude Tests
```typescript
import { test } from 'magnitude-test';
test('User can switch between light and dark mode', async (agent) => {
await agent.open('http://localhost:3000');
await agent.check('Page loads in default theme');
await agent.act('Click theme toggle button');
await agent.check('Theme switches to opposite mode');
await agent.check('All UI elements are visible in new theme');
});
test('Dark mode looks good throughout app', async (agent) => {
await agent.open('http://localhost:3000');
await agent.act('Switch to dark mode');
await agent.act('Navigate to /chat');
await agent.check('Chat interface is readable in dark mode');
await agent.act('Navigate to /galaxy');
await agent.check('Galaxy visualization looks good in dark mode');
await agent.act('Navigate to /edit');
await agent.check('Editor is readable in dark mode');
});
test('Theme preference persists', async (agent) => {
await agent.open('http://localhost:3000');
await agent.act('Switch to dark mode');
await agent.check('App is in dark mode');
await agent.act('Refresh page');
await agent.check('App remains in dark mode');
});
```
## Implementation Steps
1. **Update Mantine provider and layout**
- Add ColorSchemeScript to head
- Add dynamic favicon links
- Update MantineProvider with defaultColorScheme
2. **Update theme configuration**
- Add dark mode color overrides
- Update component styles for both modes
3. **Create ThemeToggle component**
- Add sun/moon icon toggle
- Wire up to Mantine color scheme hooks
4. **Add toggle to navigation**
- Add to DesktopNav
- Add to mobile nav if applicable
5. **Create favicons**
- Design light mode favicon (dark icon)
- Design dark mode favicon (light icon)
- Export as SVG
- Add to public folder
6. **Update galaxy visualization**
- Add theme-aware colors
- Test in both modes
7. **Test with Playwright MCP**
- Test toggle functionality
- Test persistence
- Test favicon changes
- Test all pages in both modes
8. **Add Magnitude tests**
- Write comprehensive theme tests
- Ensure all pass
9. **Commit and push (NO DEPLOY)**
## Success Criteria
- ✅ User can toggle between light and dark mode
- ✅ Theme preference persists across sessions
- ✅ Favicon changes based on active theme
- ✅ All UI elements are readable in both modes
- ✅ Galaxy visualization looks good in both modes
- ✅ System preference is detected and respected
- ✅ Smooth transitions between modes
- ✅ All Playwright MCP tests pass
- ✅ All Magnitude tests pass
## Files to Create
1. `components/ThemeToggle.tsx` - Toggle component
2. `public/favicon-light.svg` - Light mode favicon
3. `public/favicon-dark.svg` - Dark mode favicon
4. `tests/playwright/theme.spec.ts` - Manual tests
5. `tests/magnitude/theme.mag.ts` - Magnitude tests
## Files to Update
1. `app/layout.tsx` - Add ColorSchemeScript and dynamic favicons
2. `app/theme.ts` - Add dark mode color overrides
3. `components/DesktopNav.tsx` - Add ThemeToggle
4. `components/galaxy/ThoughtGalaxy.tsx` - Add theme-aware colors