107 lines
3.9 KiB
Markdown
107 lines
3.9 KiB
Markdown
# Dark Mode Implementation Plan
|
|
|
|
## Context
|
|
The Synculous client already has a bare `@media (prefers-color-scheme: dark)` in `globals.css` that only flips `body` background/foreground. Every component uses hardcoded Tailwind classes (`bg-white`, `bg-gray-50`, `text-gray-900`, etc.) with no `dark:` variants, so manually switching modes via a button has no effect. The goal is a user-controlled toggle that persists preference, respects the OS default, and applies comprehensive dark styles across all pages.
|
|
|
|
---
|
|
|
|
## Steps
|
|
|
|
### 1. Configure Tailwind v4 for class-based dark mode
|
|
**File:** `src/app/globals.css`
|
|
|
|
Add the Tailwind v4 CSS directive that maps `dark:` utilities to an ancestor `.dark` class:
|
|
```css
|
|
@variant dark (&:where(.dark, .dark *));
|
|
```
|
|
Replace the `@media (prefers-color-scheme: dark)` block with a `.dark` selector:
|
|
```css
|
|
.dark {
|
|
--background: #0a0a0a;
|
|
--foreground: #ededed;
|
|
}
|
|
```
|
|
|
|
### 2. Create ThemeProvider
|
|
**New file:** `src/components/theme/ThemeProvider.tsx`
|
|
|
|
A minimal React context provider:
|
|
- State: `isDark: boolean`
|
|
- On mount: reads `localStorage.getItem('theme')`, falls back to `window.matchMedia('(prefers-color-scheme: dark)').matches`
|
|
- Applies/removes `dark` class on `document.documentElement`
|
|
- `toggleDark()` function that flips state and saves to `localStorage`
|
|
- Exports `useTheme()` hook
|
|
|
|
### 3. Anti-flash script + wrap in layout
|
|
**File:** `src/app/layout.tsx`
|
|
|
|
- Add ThemeProvider wrapping `AuthProvider`
|
|
- Add inline `<script>` before `<body>` content to set `.dark` class before hydration (prevents white flash)
|
|
|
|
### 4. Dark mode toggle button in dashboard header
|
|
**File:** `src/app/dashboard/layout.tsx`
|
|
|
|
- Import `useTheme` from the ThemeProvider
|
|
- Add a sun/moon icon button in the existing right-side icon row (between Settings and Logout)
|
|
- `SunIcon` and `MoonIcon` already exist in `src/components/ui/Icons.tsx` — no new icons needed
|
|
|
|
### 5. Add `dark:` variants to all components
|
|
|
|
Color mapping:
|
|
|
|
| Light class | Dark variant |
|
|
|---|---|
|
|
| `bg-white` | `dark:bg-gray-800` |
|
|
| `bg-gray-50` | `dark:bg-gray-900` |
|
|
| `bg-gray-100` | `dark:bg-gray-700` |
|
|
| `bg-gray-200` | `dark:bg-gray-600` |
|
|
| `text-gray-900` | `dark:text-gray-100` |
|
|
| `text-gray-700` | `dark:text-gray-300` |
|
|
| `text-gray-600` | `dark:text-gray-400` |
|
|
| `text-gray-500` | `dark:text-gray-400` |
|
|
| `border-gray-200` | `dark:border-gray-700` |
|
|
| `border-gray-100` | `dark:border-gray-800` |
|
|
| `border-gray-300` | `dark:border-gray-600` |
|
|
| `bg-indigo-50` | `dark:bg-indigo-900/30` |
|
|
| `bg-green-50` | `dark:bg-green-900/30` |
|
|
| `bg-amber-50` | `dark:bg-amber-900/30` |
|
|
| `bg-blue-50` | `dark:bg-blue-900/30` |
|
|
| `bg-red-50` | `dark:bg-red-900/30` |
|
|
|
|
**Files to update (in order):**
|
|
1. `src/app/dashboard/layout.tsx` — shell, header, nav
|
|
2. `src/app/dashboard/page.tsx` — Today view
|
|
3. `src/app/dashboard/routines/page.tsx`
|
|
4. `src/app/dashboard/routines/new/page.tsx`
|
|
5. `src/app/dashboard/routines/[id]/page.tsx`
|
|
6. `src/app/dashboard/routines/[id]/launch/page.tsx`
|
|
7. `src/app/dashboard/routines/[id]/run/page.tsx`
|
|
8. `src/app/dashboard/templates/page.tsx`
|
|
9. `src/app/dashboard/history/page.tsx`
|
|
10. `src/app/dashboard/stats/page.tsx`
|
|
11. `src/app/dashboard/medications/page.tsx`
|
|
12. `src/app/dashboard/medications/new/page.tsx`
|
|
13. `src/app/dashboard/settings/page.tsx`
|
|
14. `src/app/login/page.tsx`
|
|
15. `src/components/session/VisualTimeline.tsx`
|
|
16. `src/components/notifications/PushNotificationToggle.tsx`
|
|
|
|
---
|
|
|
|
## Files to create
|
|
- `src/components/theme/ThemeProvider.tsx` (new)
|
|
|
|
## Files to modify
|
|
- `src/app/globals.css`
|
|
- `src/app/layout.tsx`
|
|
- All pages listed in step 5
|
|
|
|
---
|
|
|
|
## Verification
|
|
1. Run `npm run dev` in `synculous-client/`
|
|
2. Navigate to `/dashboard` — should default to OS preference
|
|
3. Click the sun/moon toggle in the header — UI should switch immediately
|
|
4. Refresh the page — theme should persist (no flash)
|
|
5. Switch OS theme — manual override takes priority; no override follows OS
|