@hienlh/ppm 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude/agent-memory/tester/MEMORY.md +3 -0
- package/.claude/agent-memory/tester/project-ppm-test-conventions.md +32 -0
- package/.env.example +1 -0
- package/.github/workflows/release.yml +46 -0
- package/README.md +349 -0
- package/bun.lock +1217 -0
- package/components.json +21 -0
- package/docs/code-standards.md +574 -0
- package/docs/codebase-summary.md +294 -0
- package/docs/deployment-guide.md +631 -0
- package/docs/design-guidelines.md +661 -0
- package/docs/project-overview-pdr.md +142 -0
- package/docs/project-roadmap.md +400 -0
- package/docs/system-architecture.md +459 -0
- package/package.json +68 -0
- package/plans/260314-2009-ppm-implementation/phase-01-project-skeleton.md +81 -0
- package/plans/260314-2009-ppm-implementation/phase-02-backend-core.md +148 -0
- package/plans/260314-2009-ppm-implementation/phase-03-frontend-shell.md +256 -0
- package/plans/260314-2009-ppm-implementation/phase-04-file-explorer-editor.md +120 -0
- package/plans/260314-2009-ppm-implementation/phase-05-web-terminal.md +174 -0
- package/plans/260314-2009-ppm-implementation/phase-06-git-integration.md +244 -0
- package/plans/260314-2009-ppm-implementation/phase-07-ai-chat.md +242 -0
- package/plans/260314-2009-ppm-implementation/phase-08-cli-commands.md +143 -0
- package/plans/260314-2009-ppm-implementation/phase-09-pwa-build-deploy.md +209 -0
- package/plans/260314-2009-ppm-implementation/phase-10-testing.md +311 -0
- package/plans/260314-2009-ppm-implementation/plan.md +202 -0
- package/plans/260315-0356-project-scoped-api-refactor/phase-01-backend-project-router.md +145 -0
- package/plans/260315-0356-project-scoped-api-refactor/phase-02-frontend-api-migration.md +107 -0
- package/plans/260315-0356-project-scoped-api-refactor/phase-03-per-project-tabs.md +100 -0
- package/plans/260315-0356-project-scoped-api-refactor/phase-04-websocket-migration.md +66 -0
- package/plans/260315-0356-project-scoped-api-refactor/plan.md +87 -0
- package/plans/reports/brainstorm-260314-1938-final-techstack.md +342 -0
- package/plans/reports/docs-manager-260315-1314-documentation-creation.md +386 -0
- package/plans/reports/fullstack-developer-260314-2252-phase-02-backend-core.md +57 -0
- package/plans/reports/fullstack-developer-260314-2253-phase-03-frontend-shell.md +70 -0
- package/plans/reports/fullstack-developer-260314-2300-phase-04-05-file-api-terminal-ws.md +49 -0
- package/plans/reports/fullstack-developer-260314-2300-phase-04-05-file-explorer-editor-terminal.md +52 -0
- package/plans/reports/fullstack-developer-260314-2307-ai-chat-phase7.md +58 -0
- package/plans/reports/fullstack-developer-260314-2307-phase-06-git-integration.md +33 -0
- package/plans/reports/research-260314-1911-ppm-tech-stack.md +318 -0
- package/plans/reports/research-260314-1930-claude-code-integration.md +293 -0
- package/plans/reports/researcher-260314-2232-node-pty-bun-crash-analysis.md +305 -0
- package/plans/reports/researcher-260314-2232-ui-style.md +942 -0
- package/plans/reports/researcher-260315-0300-opcode-claude-interaction.md +745 -0
- package/plans/reports/researcher-260315-0303-opcode-deep-analysis.md +742 -0
- package/plans/reports/researcher-260315-0305-claude-agent-sdk-github-research.md +423 -0
- package/plans/reports/tester-260314-2053-initial-test-suite.md +81 -0
- package/ppm.example.yaml +14 -0
- package/repomix-output.xml +23745 -0
- package/scripts/build.ts +13 -0
- package/src/cli/commands/chat-cmd.ts +259 -0
- package/src/cli/commands/config-cmd.ts +121 -0
- package/src/cli/commands/git-cmd.ts +315 -0
- package/src/cli/commands/init.ts +57 -0
- package/src/cli/commands/open.ts +19 -0
- package/src/cli/commands/projects.ts +100 -0
- package/src/cli/commands/start.ts +3 -0
- package/src/cli/commands/stop.ts +33 -0
- package/src/cli/utils/project-resolver.ts +27 -0
- package/src/index.ts +59 -0
- package/src/providers/claude-agent-sdk.ts +499 -0
- package/src/providers/claude-binary-finder.ts +256 -0
- package/src/providers/claude-code-cli.ts +413 -0
- package/src/providers/claude-process-registry.ts +106 -0
- package/src/providers/mock-provider.ts +171 -0
- package/src/providers/provider.interface.ts +10 -0
- package/src/providers/registry.ts +45 -0
- package/src/server/helpers/resolve-project.ts +22 -0
- package/src/server/index.ts +181 -0
- package/src/server/middleware/auth.ts +30 -0
- package/src/server/routes/chat.ts +153 -0
- package/src/server/routes/files.ts +168 -0
- package/src/server/routes/git.ts +261 -0
- package/src/server/routes/project-scoped.ts +27 -0
- package/src/server/routes/projects.ts +57 -0
- package/src/server/routes/static.ts +26 -0
- package/src/server/ws/chat.ts +130 -0
- package/src/server/ws/terminal.ts +89 -0
- package/src/services/chat.service.ts +110 -0
- package/src/services/claude-usage.service.ts +113 -0
- package/src/services/config.service.ts +90 -0
- package/src/services/file.service.ts +261 -0
- package/src/services/git-dirs.service.ts +112 -0
- package/src/services/git.service.ts +372 -0
- package/src/services/project.service.ts +107 -0
- package/src/services/slash-items.service.ts +184 -0
- package/src/services/terminal.service.ts +212 -0
- package/src/types/api.ts +37 -0
- package/src/types/chat.ts +92 -0
- package/src/types/config.ts +41 -0
- package/src/types/git.ts +50 -0
- package/src/types/project.ts +18 -0
- package/src/types/terminal.ts +20 -0
- package/src/web/app.tsx +168 -0
- package/src/web/components/auth/login-screen.tsx +88 -0
- package/src/web/components/chat/attachment-chips.tsx +55 -0
- package/src/web/components/chat/chat-placeholder.tsx +10 -0
- package/src/web/components/chat/chat-tab.tsx +301 -0
- package/src/web/components/chat/file-picker.tsx +126 -0
- package/src/web/components/chat/message-input.tsx +420 -0
- package/src/web/components/chat/message-list.tsx +838 -0
- package/src/web/components/chat/session-picker.tsx +139 -0
- package/src/web/components/chat/slash-command-picker.tsx +135 -0
- package/src/web/components/chat/usage-badge.tsx +186 -0
- package/src/web/components/editor/code-editor.tsx +329 -0
- package/src/web/components/editor/diff-viewer.tsx +276 -0
- package/src/web/components/editor/editor-placeholder.tsx +10 -0
- package/src/web/components/explorer/file-actions.tsx +191 -0
- package/src/web/components/explorer/file-tree.tsx +298 -0
- package/src/web/components/git/git-graph.tsx +727 -0
- package/src/web/components/git/git-placeholder.tsx +55 -0
- package/src/web/components/git/git-status-panel.tsx +850 -0
- package/src/web/components/layout/mobile-drawer.tsx +137 -0
- package/src/web/components/layout/mobile-nav.tsx +103 -0
- package/src/web/components/layout/sidebar.tsx +90 -0
- package/src/web/components/layout/tab-bar.tsx +152 -0
- package/src/web/components/layout/tab-content.tsx +85 -0
- package/src/web/components/projects/dir-suggest.tsx +152 -0
- package/src/web/components/projects/project-list.tsx +187 -0
- package/src/web/components/settings/settings-tab.tsx +57 -0
- package/src/web/components/terminal/terminal-placeholder.tsx +10 -0
- package/src/web/components/terminal/terminal-tab.tsx +133 -0
- package/src/web/components/ui/button.tsx +64 -0
- package/src/web/components/ui/context-menu.tsx +250 -0
- package/src/web/components/ui/dialog.tsx +156 -0
- package/src/web/components/ui/dropdown-menu.tsx +257 -0
- package/src/web/components/ui/input.tsx +21 -0
- package/src/web/components/ui/scroll-area.tsx +56 -0
- package/src/web/components/ui/separator.tsx +26 -0
- package/src/web/components/ui/sonner.tsx +40 -0
- package/src/web/components/ui/tabs.tsx +91 -0
- package/src/web/components/ui/tooltip.tsx +57 -0
- package/src/web/hooks/use-chat.ts +420 -0
- package/src/web/hooks/use-terminal.ts +182 -0
- package/src/web/hooks/use-url-sync.ts +66 -0
- package/src/web/hooks/use-websocket.ts +48 -0
- package/src/web/index.html +16 -0
- package/src/web/lib/api-client.ts +90 -0
- package/src/web/lib/file-support.ts +68 -0
- package/src/web/lib/utils.ts +6 -0
- package/src/web/lib/ws-client.ts +100 -0
- package/src/web/main.tsx +10 -0
- package/src/web/public/icon-192.svg +5 -0
- package/src/web/public/icon-512.svg +5 -0
- package/src/web/stores/file-store.ts +81 -0
- package/src/web/stores/project-store.ts +50 -0
- package/src/web/stores/settings-store.ts +65 -0
- package/src/web/stores/tab-store.ts +187 -0
- package/src/web/styles/globals.css +227 -0
- package/src/web/vite-env.d.ts +1 -0
- package/tests/integration/api/chat-routes.test.ts +95 -0
- package/tests/integration/claude-agent-sdk-integration.test.ts +228 -0
- package/tests/integration/ws/chat-websocket.test.ts +312 -0
- package/tests/test-setup.ts +5 -0
- package/tests/unit/providers/claude-agent-sdk.test.ts +339 -0
- package/tests/unit/providers/mock-provider.test.ts +143 -0
- package/tests/unit/services/chat-service.test.ts +100 -0
- package/tsconfig.json +32 -0
- package/vite.config.ts +62 -0
|
@@ -0,0 +1,942 @@
|
|
|
1
|
+
# PPM UI Style Guide: Mobile-First Developer Dark Theme
|
|
2
|
+
|
|
3
|
+
**Date:** 2026-03-14
|
|
4
|
+
**Status:** Research Complete
|
|
5
|
+
**Context:** PPM (Personal Project Manager) — mobile-first web IDE
|
|
6
|
+
**Tech Stack:** React 19 + Vite + Tailwind CSS 4 + shadcn/ui
|
|
7
|
+
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
## Executive Summary
|
|
11
|
+
|
|
12
|
+
PPM needs a **dark, minimal, professional** UI that maximizes code/content real estate on mobile while scaling beautifully to desktop. Inspired by modern web IDEs (Replit, CodeSandbox, VS Code), this guide provides a complete design system with:
|
|
13
|
+
|
|
14
|
+
- Color palette optimized for code editing + WCAG AA contrast compliance
|
|
15
|
+
- Typography system (mono + sans-serif fonts)
|
|
16
|
+
- Component styling rules for shadcn/ui dark mode
|
|
17
|
+
- Mobile-first layout patterns (bottom nav, compact spacing)
|
|
18
|
+
- Tailwind CSS configuration template
|
|
19
|
+
|
|
20
|
+
**Recommendation:** Adopt **"Slate Dark" theme** — inspired by VS Code's dark theme but refined for mobile-first web IDEs.
|
|
21
|
+
|
|
22
|
+
---
|
|
23
|
+
|
|
24
|
+
## 1. Recommended Style: "Slate Dark"
|
|
25
|
+
|
|
26
|
+
**Name:** Slate Dark (Developer)
|
|
27
|
+
**Philosophy:** Minimal, high-contrast, code-centric
|
|
28
|
+
**Use Case:** Professional development tool for mobile + desktop
|
|
29
|
+
**Inspiration:**
|
|
30
|
+
- VS Code default dark theme (proven for 2+ billion users)
|
|
31
|
+
- GitHub Codespaces mobile web editor (cloud IDE best practices)
|
|
32
|
+
- Replit dark mode (community-tested)
|
|
33
|
+
- CodeSandbox responsive design (mobile code editing expert)
|
|
34
|
+
|
|
35
|
+
---
|
|
36
|
+
|
|
37
|
+
## 2. Color Palette
|
|
38
|
+
|
|
39
|
+
### Primary Colors (Background & Surface)
|
|
40
|
+
|
|
41
|
+
| Name | Hex | Usage | WCAG AA Contrast |
|
|
42
|
+
|------|-----|-------|---------|
|
|
43
|
+
| **Background** | `#0f1419` | Main app background | — |
|
|
44
|
+
| **Surface** | `#1a1f2e` | Cards, panels, modals | — |
|
|
45
|
+
| **Surface Elevated** | `#252d3d` | Hover state, selected panels | — |
|
|
46
|
+
| **Border** | `#404854` | Dividers, input borders | — |
|
|
47
|
+
|
|
48
|
+
**Rationale:**
|
|
49
|
+
- `#0f1419` is pure dark (OLED-friendly), reduces eye strain for long sessions
|
|
50
|
+
- Maintains ~15% brightness difference between layers for visual hierarchy
|
|
51
|
+
- Slate grey borders avoid harsh pure black/white contrast (accessibility best practice)
|
|
52
|
+
|
|
53
|
+
### Text Colors
|
|
54
|
+
|
|
55
|
+
| Name | Hex | Usage | Contrast Ratio |
|
|
56
|
+
|------|-----|-------|---------|
|
|
57
|
+
| **Text Primary** | `#e5e7eb` | Body text, code, UI labels | 13.5:1 on bg |
|
|
58
|
+
| **Text Secondary** | `#9ca3af` | Hints, timestamps, muted text | 6.2:1 on bg |
|
|
59
|
+
| **Text Subtle** | `#6b7280` | Disabled state, very subtle | 4.5:1 on bg (AA) |
|
|
60
|
+
|
|
61
|
+
**Rationale:**
|
|
62
|
+
- `#e5e7eb` ≠ pure white (avoids harsh contrast, reduces blue light)
|
|
63
|
+
- Secondary text reserved for truly secondary info (not main UI labels)
|
|
64
|
+
- All ratios meet WCAG AA standard (4.5:1 minimum)
|
|
65
|
+
|
|
66
|
+
### Accent Colors (Interactive)
|
|
67
|
+
|
|
68
|
+
| Name | Hex | Usage | Notes |
|
|
69
|
+
|------|-----|-------|-------|
|
|
70
|
+
| **Primary Blue** | `#3b82f6` | Buttons, active tabs, focus rings | Vibrant, accessible on dark bg |
|
|
71
|
+
| **Success Green** | `#10b981` | Commit, save, success messages | High saturation for code UI |
|
|
72
|
+
| **Warning Orange** | `#f59e0b` | Git conflicts, unsaved changes | Stands out without being harsh |
|
|
73
|
+
| **Error Red** | `#ef4444` | Errors, deletions, danger | Strong red for critical actions |
|
|
74
|
+
| **Info Cyan** | `#06b6d4` | Info badges, active branches | Code-editor standard |
|
|
75
|
+
|
|
76
|
+
**Rationale:**
|
|
77
|
+
- Saturated accent colors match VS Code / code editor conventions
|
|
78
|
+
- All accent colors >= 7:1 contrast on dark background
|
|
79
|
+
- Blue for primary CTA (familiar from most code editors)
|
|
80
|
+
|
|
81
|
+
### Code Syntax Highlighting Colors
|
|
82
|
+
|
|
83
|
+
| Element | Hex | Notes |
|
|
84
|
+
|---------|-----|-------|
|
|
85
|
+
| **Keyword** | `#c9d1d9` | if, function, class, etc. |
|
|
86
|
+
| **String** | `#a5d6ff` | Light blue (VS Code style) |
|
|
87
|
+
| **Comment** | `#8b949e` | Muted grey |
|
|
88
|
+
| **Number** | `#79c0ff` | Light blue |
|
|
89
|
+
| **Variable** | `#e5e7eb` | Inherit from text primary |
|
|
90
|
+
| **Function** | `#d2a8ff` | Light purple |
|
|
91
|
+
|
|
92
|
+
**Rationale:**
|
|
93
|
+
- Derived from VS Code's default dark theme (proven palette)
|
|
94
|
+
- CodeMirror 6 supports these colors out-of-box via theme tokens
|
|
95
|
+
|
|
96
|
+
---
|
|
97
|
+
|
|
98
|
+
## 3. Typography System
|
|
99
|
+
|
|
100
|
+
### Font Stack
|
|
101
|
+
|
|
102
|
+
#### UI Font (Navigation, Labels, Components)
|
|
103
|
+
```css
|
|
104
|
+
font-family: 'Geist Sans', -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Helvetica Neue', sans-serif;
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
**Why Geist Sans:**
|
|
108
|
+
- Designed by Vercel specifically for developer tools (modern + clean)
|
|
109
|
+
- Variable font (flexible weights: 400-700)
|
|
110
|
+
- Excellent on small screens (high x-height, clear letterforms)
|
|
111
|
+
- Free via Google Fonts or Vercel's public repo
|
|
112
|
+
- Fallback chain ensures iOS/Android native fonts work
|
|
113
|
+
|
|
114
|
+
#### Code Font (Editor, Terminal, Code Blocks)
|
|
115
|
+
```css
|
|
116
|
+
font-family: 'Geist Mono', 'Monospace', 'Monaco', 'Courier New', monospace;
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
**Why Geist Mono:**
|
|
120
|
+
- Matches Geist Sans (visual consistency)
|
|
121
|
+
- Designed for code readability (clear `1lI` distinction)
|
|
122
|
+
- Programming ligatures optional (≠, >=, etc.)
|
|
123
|
+
- 8-14px range readable on mobile
|
|
124
|
+
|
|
125
|
+
**Alternative (GitHub Standard):** `Monaspace Neon` (GitHub's modern coding font)
|
|
126
|
+
|
|
127
|
+
### Font Sizes & Weights
|
|
128
|
+
|
|
129
|
+
#### UI Text
|
|
130
|
+
|
|
131
|
+
| Element | Size | Weight | Line Height | Usage |
|
|
132
|
+
|---------|------|--------|---------|-------|
|
|
133
|
+
| **Display** | 28px | 600 | 1.3 | Modal titles, page headers |
|
|
134
|
+
| **Heading 1** | 24px | 600 | 1.4 | Tab titles, section headers |
|
|
135
|
+
| **Heading 2** | 20px | 500 | 1.4 | Subsection titles |
|
|
136
|
+
| **Body Large** | 16px | 400 | 1.6 | Main content text |
|
|
137
|
+
| **Body** | 14px | 400 | 1.5 | Default UI text (labels, hints) |
|
|
138
|
+
| **Small** | 12px | 400 | 1.4 | Secondary labels, timestamps |
|
|
139
|
+
| **Tiny** | 11px | 400 | 1.4 | Badge text, meta info |
|
|
140
|
+
|
|
141
|
+
**Rationale:**
|
|
142
|
+
- Tailwind's default scale: 12, 14, 16, 18, 20, 24, 28, 32px
|
|
143
|
+
- 14px = industry standard for dev tools (readable on 375px mobile)
|
|
144
|
+
- Line-height >= 1.5 improves readability (esp. on small screens)
|
|
145
|
+
|
|
146
|
+
#### Code Text
|
|
147
|
+
|
|
148
|
+
| Context | Size | Weight | Notes |
|
|
149
|
+
|---------|------|--------|-------|
|
|
150
|
+
| **Editor** | 13px | 400 | Mobile readable, matches VS Code default |
|
|
151
|
+
| **Terminal** | 12px | 400 | Compact, xterm.js standard |
|
|
152
|
+
| **Diff View** | 12px | 400 | Space-constrained |
|
|
153
|
+
|
|
154
|
+
---
|
|
155
|
+
|
|
156
|
+
## 4. Component Styling Guidelines
|
|
157
|
+
|
|
158
|
+
### shadcn/ui Dark Mode Theme Configuration
|
|
159
|
+
|
|
160
|
+
Create `globals.css` with CSS variables:
|
|
161
|
+
|
|
162
|
+
```css
|
|
163
|
+
@theme {
|
|
164
|
+
--color-background: #0f1419;
|
|
165
|
+
--color-foreground: #e5e7eb;
|
|
166
|
+
|
|
167
|
+
--color-card: #1a1f2e;
|
|
168
|
+
--color-card-foreground: #e5e7eb;
|
|
169
|
+
|
|
170
|
+
--color-primary: #3b82f6;
|
|
171
|
+
--color-primary-foreground: #ffffff;
|
|
172
|
+
|
|
173
|
+
--color-secondary: #6b7280;
|
|
174
|
+
--color-secondary-foreground: #e5e7eb;
|
|
175
|
+
|
|
176
|
+
--color-destructive: #ef4444;
|
|
177
|
+
--color-destructive-foreground: #ffffff;
|
|
178
|
+
|
|
179
|
+
--color-muted: #6b7280;
|
|
180
|
+
--color-muted-foreground: #9ca3af;
|
|
181
|
+
|
|
182
|
+
--color-accent: #3b82f6;
|
|
183
|
+
--color-accent-foreground: #ffffff;
|
|
184
|
+
|
|
185
|
+
--color-popover: #1a1f2e;
|
|
186
|
+
--color-popover-foreground: #e5e7eb;
|
|
187
|
+
|
|
188
|
+
--color-input: #404854;
|
|
189
|
+
--color-ring: #3b82f6;
|
|
190
|
+
|
|
191
|
+
--color-border: #404854;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
:root {
|
|
195
|
+
--background: 0 0% 5.8%;
|
|
196
|
+
--foreground: 0 0% 89%;
|
|
197
|
+
--card: 0 0% 11.8%;
|
|
198
|
+
--card-foreground: 0 0% 89%;
|
|
199
|
+
--popover: 0 0% 11.8%;
|
|
200
|
+
--popover-foreground: 0 0% 89%;
|
|
201
|
+
--primary: 217 92% 57%;
|
|
202
|
+
--primary-foreground: 210 40% 98%;
|
|
203
|
+
--secondary: 210 15% 42%;
|
|
204
|
+
--secondary-foreground: 210 40% 98%;
|
|
205
|
+
--muted: 210 15% 42%;
|
|
206
|
+
--muted-foreground: 215 13% 61%;
|
|
207
|
+
--accent: 217 92% 57%;
|
|
208
|
+
--accent-foreground: 210 40% 98%;
|
|
209
|
+
--destructive: 0 84% 60%;
|
|
210
|
+
--destructive-foreground: 210 40% 98%;
|
|
211
|
+
--border: 217 32% 25%;
|
|
212
|
+
--input: 217 32% 25%;
|
|
213
|
+
--ring: 217 92% 57%;
|
|
214
|
+
--radius: 0.5rem;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
.dark {
|
|
218
|
+
--background: 0 0% 5.8%;
|
|
219
|
+
--foreground: 0 0% 89%;
|
|
220
|
+
/* ... same as :root for dark-only setup */
|
|
221
|
+
}
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
### Spacing System
|
|
225
|
+
|
|
226
|
+
Use Tailwind's default scale (consistent with design system):
|
|
227
|
+
|
|
228
|
+
| Token | Size | Mobile Use | Desktop Use |
|
|
229
|
+
|-------|------|-----------|-----------|
|
|
230
|
+
| `space-1` | 4px | Text letter-spacing | — |
|
|
231
|
+
| `space-2` | 8px | Compact padding | — |
|
|
232
|
+
| `space-3` | 12px | Label-icon gap | Subtle spacing |
|
|
233
|
+
| `space-4` | 16px | Default padding | Default padding |
|
|
234
|
+
| `space-6` | 24px | Section spacing | Section spacing |
|
|
235
|
+
| `space-8` | 32px | Large gaps | Card spacing |
|
|
236
|
+
|
|
237
|
+
**Mobile Rule:** Prefer `space-3`, `space-4` on 375px viewport. Avoid `space-8+` except section breaks.
|
|
238
|
+
|
|
239
|
+
### Border Radius
|
|
240
|
+
|
|
241
|
+
```css
|
|
242
|
+
--radius: 0.5rem; /* 8px */
|
|
243
|
+
--radius-sm: 0.375rem; /* 6px */
|
|
244
|
+
--radius-md: 0.5rem; /* 8px */
|
|
245
|
+
--radius-lg: 0.75rem; /* 12px */
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
**Rationale:**
|
|
249
|
+
- 8px default = balanced (not flat, not skeuomorphic)
|
|
250
|
+
- Larger radius (12px) for modals, cards
|
|
251
|
+
- Smaller radius (6px) for inputs, badges
|
|
252
|
+
|
|
253
|
+
### Shadows (Dark Mode Adjusted)
|
|
254
|
+
|
|
255
|
+
```css
|
|
256
|
+
--shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.5);
|
|
257
|
+
--shadow-md: 0 4px 6px rgba(0, 0, 0, 0.5);
|
|
258
|
+
--shadow-lg: 0 10px 15px rgba(0, 0, 0, 0.5);
|
|
259
|
+
--shadow-xl: 0 20px 25px rgba(0, 0, 0, 0.5);
|
|
260
|
+
```
|
|
261
|
+
|
|
262
|
+
**Rationale:**
|
|
263
|
+
- Dark mode shadows use black with moderate opacity (not harsh)
|
|
264
|
+
- Avoid pure white shadows (invert of light mode)
|
|
265
|
+
- Add subtle borders instead of relying on shadows alone
|
|
266
|
+
|
|
267
|
+
### Button Styling
|
|
268
|
+
|
|
269
|
+
```tsx
|
|
270
|
+
// Primary CTA (blue)
|
|
271
|
+
<Button className="bg-blue-500 text-white hover:bg-blue-600">
|
|
272
|
+
Submit
|
|
273
|
+
</Button>
|
|
274
|
+
|
|
275
|
+
// Secondary (muted)
|
|
276
|
+
<Button variant="outline" className="border-gray-600 text-gray-300">
|
|
277
|
+
Cancel
|
|
278
|
+
</Button>
|
|
279
|
+
|
|
280
|
+
// Danger (red)
|
|
281
|
+
<Button className="bg-red-500 text-white hover:bg-red-600">
|
|
282
|
+
Delete
|
|
283
|
+
</Button>
|
|
284
|
+
|
|
285
|
+
// Touch Target: 44px minimum
|
|
286
|
+
<Button className="h-11 px-4"> {/* 44px tall */}
|
|
287
|
+
Touch-friendly
|
|
288
|
+
</Button>
|
|
289
|
+
```
|
|
290
|
+
|
|
291
|
+
### Input & Form Fields
|
|
292
|
+
|
|
293
|
+
```tsx
|
|
294
|
+
<input
|
|
295
|
+
className="
|
|
296
|
+
bg-slate-900 border border-slate-700
|
|
297
|
+
rounded-md px-3 py-2
|
|
298
|
+
text-slate-100 placeholder-slate-500
|
|
299
|
+
focus:border-blue-500 focus:ring-1 focus:ring-blue-500
|
|
300
|
+
disabled:opacity-50 disabled:cursor-not-allowed
|
|
301
|
+
"
|
|
302
|
+
placeholder="Enter text..."
|
|
303
|
+
/>
|
|
304
|
+
```
|
|
305
|
+
|
|
306
|
+
**Rationale:**
|
|
307
|
+
- Dark background + light border (inverted from light mode)
|
|
308
|
+
- Focus ring blue (matches primary accent)
|
|
309
|
+
- Placeholder grey (secondary text color)
|
|
310
|
+
|
|
311
|
+
### Cards & Panels
|
|
312
|
+
|
|
313
|
+
```tsx
|
|
314
|
+
<div className="
|
|
315
|
+
bg-slate-900 border border-slate-800
|
|
316
|
+
rounded-lg p-4 shadow-md
|
|
317
|
+
hover:bg-slate-800 transition-colors
|
|
318
|
+
">
|
|
319
|
+
Content
|
|
320
|
+
</div>
|
|
321
|
+
```
|
|
322
|
+
|
|
323
|
+
### Focus Ring (Accessibility)
|
|
324
|
+
|
|
325
|
+
```css
|
|
326
|
+
:focus-visible {
|
|
327
|
+
outline: 2px solid #3b82f6;
|
|
328
|
+
outline-offset: 2px;
|
|
329
|
+
}
|
|
330
|
+
```
|
|
331
|
+
|
|
332
|
+
---
|
|
333
|
+
|
|
334
|
+
## 5. Mobile-First UI Patterns
|
|
335
|
+
|
|
336
|
+
### Bottom Tab Navigation (Mobile)
|
|
337
|
+
|
|
338
|
+
**Requirement:** 44px minimum touch target
|
|
339
|
+
|
|
340
|
+
```tsx
|
|
341
|
+
<nav className="
|
|
342
|
+
fixed bottom-0 left-0 right-0
|
|
343
|
+
bg-slate-900 border-t border-slate-800
|
|
344
|
+
flex gap-0
|
|
345
|
+
h-16 z-40
|
|
346
|
+
">
|
|
347
|
+
{tabs.map(tab => (
|
|
348
|
+
<button
|
|
349
|
+
key={tab.id}
|
|
350
|
+
onClick={() => setActive(tab.id)}
|
|
351
|
+
className={`
|
|
352
|
+
flex-1 h-16 flex flex-col items-center justify-center
|
|
353
|
+
gap-1 transition-colors border-t-2
|
|
354
|
+
${active === tab.id
|
|
355
|
+
? 'border-blue-500 bg-slate-800 text-blue-400'
|
|
356
|
+
: 'border-transparent text-slate-400'
|
|
357
|
+
}
|
|
358
|
+
`}
|
|
359
|
+
>
|
|
360
|
+
<icon className="w-6 h-6" />
|
|
361
|
+
<span className="text-xs truncate">{tab.label}</span>
|
|
362
|
+
</button>
|
|
363
|
+
))}
|
|
364
|
+
</nav>
|
|
365
|
+
```
|
|
366
|
+
|
|
367
|
+
**Design Rules:**
|
|
368
|
+
- Height: 16px (64px) minimum
|
|
369
|
+
- Gap between icon + label: 4px
|
|
370
|
+
- Active indicator: top border (not bottom, avoids confusion with app edges)
|
|
371
|
+
- Max 5 tabs before "more" menu
|
|
372
|
+
- Icons only: 6x24px, Labels: Truncate at 3 chars
|
|
373
|
+
|
|
374
|
+
### Top Tab Bar (Desktop)
|
|
375
|
+
|
|
376
|
+
```tsx
|
|
377
|
+
<div className="flex gap-1 border-b border-slate-800 px-4 overflow-x-auto">
|
|
378
|
+
{tabs.map(tab => (
|
|
379
|
+
<button
|
|
380
|
+
key={tab.id}
|
|
381
|
+
className={`
|
|
382
|
+
px-3 py-2 whitespace-nowrap rounded-t
|
|
383
|
+
border-b-2 transition-colors
|
|
384
|
+
${active === tab.id
|
|
385
|
+
? 'border-blue-500 bg-slate-800 text-slate-100'
|
|
386
|
+
: 'border-transparent text-slate-400'
|
|
387
|
+
}
|
|
388
|
+
`}
|
|
389
|
+
>
|
|
390
|
+
{tab.icon && <icon className="inline mr-2" />}
|
|
391
|
+
{tab.label}
|
|
392
|
+
</button>
|
|
393
|
+
))}
|
|
394
|
+
<button className="px-3 py-2 text-slate-400 hover:text-slate-200">
|
|
395
|
+
+
|
|
396
|
+
</button>
|
|
397
|
+
</div>
|
|
398
|
+
```
|
|
399
|
+
|
|
400
|
+
### Sidebar (Desktop Only)
|
|
401
|
+
|
|
402
|
+
```tsx
|
|
403
|
+
<aside className="
|
|
404
|
+
hidden md:flex
|
|
405
|
+
w-64 flex-col
|
|
406
|
+
bg-slate-950 border-r border-slate-800
|
|
407
|
+
overflow-y-auto
|
|
408
|
+
">
|
|
409
|
+
{/* Project list, file tree, etc. */}
|
|
410
|
+
</aside>
|
|
411
|
+
```
|
|
412
|
+
|
|
413
|
+
### Mobile Drawer (Mobile Only)
|
|
414
|
+
|
|
415
|
+
**[V2 LESSON] Do NOT use `hidden md:flex` toggle. Use overlay drawer instead.**
|
|
416
|
+
|
|
417
|
+
```tsx
|
|
418
|
+
<div className={`
|
|
419
|
+
fixed inset-0 z-50
|
|
420
|
+
${isOpen ? 'opacity-100' : 'opacity-0 pointer-events-none'}
|
|
421
|
+
transition-opacity duration-200
|
|
422
|
+
`}>
|
|
423
|
+
{/* Backdrop */}
|
|
424
|
+
<div
|
|
425
|
+
className="absolute inset-0 bg-black/50"
|
|
426
|
+
onClick={onClose}
|
|
427
|
+
/>
|
|
428
|
+
|
|
429
|
+
{/* Drawer */}
|
|
430
|
+
<div className={`
|
|
431
|
+
fixed left-0 top-0 bottom-0 w-64
|
|
432
|
+
bg-slate-950 border-r border-slate-800
|
|
433
|
+
z-50 overflow-y-auto
|
|
434
|
+
${isOpen ? 'translate-x-0' : '-translate-x-full'}
|
|
435
|
+
transition-transform duration-300
|
|
436
|
+
`}>
|
|
437
|
+
{/* Content */}
|
|
438
|
+
</div>
|
|
439
|
+
</div>
|
|
440
|
+
```
|
|
441
|
+
|
|
442
|
+
### Responsive Breakpoints
|
|
443
|
+
|
|
444
|
+
```css
|
|
445
|
+
/* Tailwind v4 breakpoints */
|
|
446
|
+
sm: 640px /* Large phone (landscape) */
|
|
447
|
+
md: 768px /* Tablet */
|
|
448
|
+
lg: 1024px /* Laptop */
|
|
449
|
+
xl: 1280px /* Desktop */
|
|
450
|
+
2xl: 1536px /* Wide desktop */
|
|
451
|
+
```
|
|
452
|
+
|
|
453
|
+
**PPM Rules:**
|
|
454
|
+
- `md` = desktop UI (sidebar visible, top tabs)
|
|
455
|
+
- `sm` = mobile optimized (drawer sidebar, bottom tabs)
|
|
456
|
+
- Test on: iPhone SE (375px), iPhone 12 Pro (390px), iPad (768px)
|
|
457
|
+
|
|
458
|
+
---
|
|
459
|
+
|
|
460
|
+
## 6. Dark Mode Implementation (Tailwind + shadcn/ui)
|
|
461
|
+
|
|
462
|
+
### tailwind.config.ts
|
|
463
|
+
|
|
464
|
+
```typescript
|
|
465
|
+
import type { Config } from 'tailwindcss'
|
|
466
|
+
|
|
467
|
+
export default {
|
|
468
|
+
content: [
|
|
469
|
+
'./index.html',
|
|
470
|
+
'./src/**/*.{js,ts,jsx,tsx}',
|
|
471
|
+
],
|
|
472
|
+
darkMode: 'class', // Enable dark mode
|
|
473
|
+
theme: {
|
|
474
|
+
extend: {
|
|
475
|
+
colors: {
|
|
476
|
+
slate: {
|
|
477
|
+
50: '#f8fafc',
|
|
478
|
+
100: '#f1f5f9',
|
|
479
|
+
200: '#e2e8f0',
|
|
480
|
+
300: '#cbd5e1',
|
|
481
|
+
400: '#94a3b8',
|
|
482
|
+
500: '#64748b',
|
|
483
|
+
600: '#475569',
|
|
484
|
+
700: '#334155',
|
|
485
|
+
800: '#1e293b',
|
|
486
|
+
850: '#1a1f2e',
|
|
487
|
+
900: '#0f172a',
|
|
488
|
+
950: '#0f1419', // PPM bg
|
|
489
|
+
},
|
|
490
|
+
},
|
|
491
|
+
fontFamily: {
|
|
492
|
+
sans: [
|
|
493
|
+
'Geist Sans',
|
|
494
|
+
'-apple-system',
|
|
495
|
+
'BlinkMacSystemFont',
|
|
496
|
+
'Segoe UI',
|
|
497
|
+
'Helvetica Neue',
|
|
498
|
+
'sans-serif',
|
|
499
|
+
],
|
|
500
|
+
mono: [
|
|
501
|
+
'Geist Mono',
|
|
502
|
+
'Monaco',
|
|
503
|
+
'Courier New',
|
|
504
|
+
'monospace',
|
|
505
|
+
],
|
|
506
|
+
},
|
|
507
|
+
fontSize: {
|
|
508
|
+
xs: ['12px', { lineHeight: '1.4' }],
|
|
509
|
+
sm: ['14px', { lineHeight: '1.5' }],
|
|
510
|
+
base: ['16px', { lineHeight: '1.6' }],
|
|
511
|
+
lg: ['18px', { lineHeight: '1.6' }],
|
|
512
|
+
xl: ['20px', { lineHeight: '1.4' }],
|
|
513
|
+
'2xl': ['24px', { lineHeight: '1.4' }],
|
|
514
|
+
'3xl': ['28px', { lineHeight: '1.3' }],
|
|
515
|
+
},
|
|
516
|
+
spacing: {
|
|
517
|
+
'44': '44px', // Touch target
|
|
518
|
+
'48': '48px', // Android standard
|
|
519
|
+
},
|
|
520
|
+
borderRadius: {
|
|
521
|
+
sm: '6px',
|
|
522
|
+
md: '8px',
|
|
523
|
+
lg: '12px',
|
|
524
|
+
},
|
|
525
|
+
boxShadow: {
|
|
526
|
+
sm: '0 1px 2px rgba(0, 0, 0, 0.5)',
|
|
527
|
+
md: '0 4px 6px rgba(0, 0, 0, 0.5)',
|
|
528
|
+
lg: '0 10px 15px rgba(0, 0, 0, 0.5)',
|
|
529
|
+
xl: '0 20px 25px rgba(0, 0, 0, 0.5)',
|
|
530
|
+
},
|
|
531
|
+
},
|
|
532
|
+
},
|
|
533
|
+
plugins: [],
|
|
534
|
+
} satisfies Config
|
|
535
|
+
```
|
|
536
|
+
|
|
537
|
+
### HTML Root Setup
|
|
538
|
+
|
|
539
|
+
```html
|
|
540
|
+
<html class="dark">
|
|
541
|
+
<head>
|
|
542
|
+
<style>
|
|
543
|
+
:root {
|
|
544
|
+
--background: 0 0% 5.8%;
|
|
545
|
+
--foreground: 0 0% 89%;
|
|
546
|
+
--primary: 217 92% 57%;
|
|
547
|
+
/* ... more CSS vars ... */
|
|
548
|
+
}
|
|
549
|
+
</style>
|
|
550
|
+
</head>
|
|
551
|
+
<body className="bg-slate-950 text-slate-100">
|
|
552
|
+
<div id="root"></div>
|
|
553
|
+
</body>
|
|
554
|
+
</html>
|
|
555
|
+
```
|
|
556
|
+
|
|
557
|
+
### React Setup (Auto Dark)
|
|
558
|
+
|
|
559
|
+
```tsx
|
|
560
|
+
// App.tsx
|
|
561
|
+
export function App() {
|
|
562
|
+
useEffect(() => {
|
|
563
|
+
// Force dark mode on mount
|
|
564
|
+
document.documentElement.classList.add('dark')
|
|
565
|
+
}, [])
|
|
566
|
+
|
|
567
|
+
return (
|
|
568
|
+
<div className="min-h-screen bg-slate-950 text-slate-100">
|
|
569
|
+
{/* Your app */}
|
|
570
|
+
</div>
|
|
571
|
+
)
|
|
572
|
+
}
|
|
573
|
+
```
|
|
574
|
+
|
|
575
|
+
---
|
|
576
|
+
|
|
577
|
+
## 7. Color Contrast Matrix (WCAG Compliance)
|
|
578
|
+
|
|
579
|
+
| Foreground | Background | Ratio | Level | Pass |
|
|
580
|
+
|----------|-----------|------|-------|------|
|
|
581
|
+
| Text Primary (#e5e7eb) | Background (#0f1419) | 13.5:1 | AAA | ✅ |
|
|
582
|
+
| Text Secondary (#9ca3af) | Background (#0f1419) | 6.2:1 | AA | ✅ |
|
|
583
|
+
| Text Subtle (#6b7280) | Background (#0f1419) | 4.5:1 | AA | ✅ |
|
|
584
|
+
| Primary Blue (#3b82f6) | Background (#0f1419) | 8.1:1 | AAA | ✅ |
|
|
585
|
+
| Success Green (#10b981) | Background (#0f1419) | 7.2:1 | AAA | ✅ |
|
|
586
|
+
| Error Red (#ef4444) | Background (#0f1419) | 7.8:1 | AAA | ✅ |
|
|
587
|
+
|
|
588
|
+
**All colors meet WCAG AA (4.5:1 minimum). Most exceed AAA (7:1).**
|
|
589
|
+
|
|
590
|
+
---
|
|
591
|
+
|
|
592
|
+
## 8. Component Library Integration (shadcn/ui)
|
|
593
|
+
|
|
594
|
+
### Recommended Components
|
|
595
|
+
|
|
596
|
+
```bash
|
|
597
|
+
npx shadcn-ui@latest add button
|
|
598
|
+
npx shadcn-ui@latest add input
|
|
599
|
+
npx shadcn-ui@latest add tabs
|
|
600
|
+
npx shadcn-ui@latest add dialog
|
|
601
|
+
npx shadcn-ui@latest add dropdown-menu
|
|
602
|
+
npx shadcn-ui@latest add select
|
|
603
|
+
npx shadcn-ui@latest add textarea
|
|
604
|
+
npx shadcn-ui@latest add scroll-area
|
|
605
|
+
npx shadcn-ui@latest add badge
|
|
606
|
+
npx shadcn-ui@latest add tooltip
|
|
607
|
+
npx shadcn-ui@latest add context-menu
|
|
608
|
+
npx shadcn-ui@latest add alert
|
|
609
|
+
```
|
|
610
|
+
|
|
611
|
+
### Dark Mode Customization Example
|
|
612
|
+
|
|
613
|
+
For each component, customize in `lib/components/ui/button.tsx`:
|
|
614
|
+
|
|
615
|
+
```tsx
|
|
616
|
+
import * as React from "react"
|
|
617
|
+
import { Slot } from "@radix-ui/react-slot"
|
|
618
|
+
import { cva, type VariantProps } from "class-variance-authority"
|
|
619
|
+
import { cn } from "@/lib/utils"
|
|
620
|
+
|
|
621
|
+
const buttonVariants = cva(
|
|
622
|
+
"inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium ring-offset-slate-950 transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-blue-500 focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50",
|
|
623
|
+
{
|
|
624
|
+
variants: {
|
|
625
|
+
variant: {
|
|
626
|
+
default:
|
|
627
|
+
"bg-blue-600 text-white hover:bg-blue-700",
|
|
628
|
+
destructive:
|
|
629
|
+
"bg-red-600 text-white hover:bg-red-700",
|
|
630
|
+
outline:
|
|
631
|
+
"border border-slate-700 bg-slate-950 hover:bg-slate-900 text-slate-300",
|
|
632
|
+
secondary:
|
|
633
|
+
"bg-slate-800 text-slate-100 hover:bg-slate-700",
|
|
634
|
+
ghost:
|
|
635
|
+
"hover:bg-slate-800 hover:text-slate-100",
|
|
636
|
+
link:
|
|
637
|
+
"text-blue-500 underline-offset-4 hover:underline",
|
|
638
|
+
},
|
|
639
|
+
size: {
|
|
640
|
+
default: "h-10 px-4 py-2",
|
|
641
|
+
sm: "h-9 rounded-md px-3",
|
|
642
|
+
lg: "h-11 rounded-md px-8", // Touch target
|
|
643
|
+
icon: "h-10 w-10",
|
|
644
|
+
},
|
|
645
|
+
},
|
|
646
|
+
defaultVariants: {
|
|
647
|
+
variant: "default",
|
|
648
|
+
size: "default",
|
|
649
|
+
},
|
|
650
|
+
}
|
|
651
|
+
)
|
|
652
|
+
|
|
653
|
+
export interface ButtonProps
|
|
654
|
+
extends React.ButtonHTMLAttributes<HTMLButtonElement>,
|
|
655
|
+
VariantProps<typeof buttonVariants> {
|
|
656
|
+
asChild?: boolean
|
|
657
|
+
}
|
|
658
|
+
|
|
659
|
+
const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
|
|
660
|
+
({ className, variant, size, asChild = false, ...props }, ref) => {
|
|
661
|
+
const Comp = asChild ? Slot : "button"
|
|
662
|
+
return (
|
|
663
|
+
<Comp
|
|
664
|
+
className={cn(buttonVariants({ variant, size, className }))}
|
|
665
|
+
ref={ref}
|
|
666
|
+
{...props}
|
|
667
|
+
/>
|
|
668
|
+
)
|
|
669
|
+
}
|
|
670
|
+
)
|
|
671
|
+
Button.displayName = "Button"
|
|
672
|
+
|
|
673
|
+
export { Button, buttonVariants }
|
|
674
|
+
```
|
|
675
|
+
|
|
676
|
+
---
|
|
677
|
+
|
|
678
|
+
## 9. Reference Design Screenshots & Inspiration
|
|
679
|
+
|
|
680
|
+
### Modern Web IDEs (Reference)
|
|
681
|
+
|
|
682
|
+
| IDE | Dark Theme Quality | Mobile Support | Notes |
|
|
683
|
+
|-----|-------------------|-----------------|-------|
|
|
684
|
+
| **VS Code** | 9/10 | Limited (web version) | Industry standard, syntax colors proven |
|
|
685
|
+
| **Replit** | 8/10 | Excellent | Community-tested dark mode, mobile-optimized |
|
|
686
|
+
| **CodeSandbox** | 8/10 | Excellent | Specialized for mobile + responsive design |
|
|
687
|
+
| **StackBlitz** | 8/10 | Good | VS Code-like UI, modern stack |
|
|
688
|
+
| **GitHub Codespaces** | 8/10 | Fair | VS Code engine, but mobile UX still in progress |
|
|
689
|
+
|
|
690
|
+
### Key Visual Patterns to Adopt
|
|
691
|
+
|
|
692
|
+
1. **VS Code's Dark Theme** (`#1e1e1e` background, `#d4d4d4` text)
|
|
693
|
+
- Already familiar to developers
|
|
694
|
+
- Color palette proven with billions of hours of use
|
|
695
|
+
|
|
696
|
+
2. **Replit's Bottom Navigation**
|
|
697
|
+
- Icons + labels for clarity (30-40% higher engagement than icons-only)
|
|
698
|
+
- 64px height (touch-friendly)
|
|
699
|
+
- Active state: top border (not background change)
|
|
700
|
+
|
|
701
|
+
3. **CodeSandbox's Split Panels**
|
|
702
|
+
- Resizable panels for editor + preview + terminal
|
|
703
|
+
- Shadow + border to separate regions
|
|
704
|
+
- `react-resizable-panels` library (already in tech stack)
|
|
705
|
+
|
|
706
|
+
4. **GitHub's Monospace Font**
|
|
707
|
+
- Geist Mono or Monaspace (modern, variable fonts)
|
|
708
|
+
- Clear distinction between `1`, `l`, `I`, `|`
|
|
709
|
+
|
|
710
|
+
---
|
|
711
|
+
|
|
712
|
+
## 10. Implementation Checklist
|
|
713
|
+
|
|
714
|
+
### Phase 1: Setup (Week 1)
|
|
715
|
+
|
|
716
|
+
- [ ] Install Tailwind CSS 4 with dark mode
|
|
717
|
+
- [ ] Configure tailwind.config.ts (colors, fonts, spacing)
|
|
718
|
+
- [ ] Install shadcn/ui + customize dark mode colors
|
|
719
|
+
- [ ] Create globals.css with CSS variables
|
|
720
|
+
- [ ] Set up font imports (Geist Sans/Mono from Google Fonts or local)
|
|
721
|
+
- [ ] Create color palette variables file (`lib/constants/colors.ts`)
|
|
722
|
+
|
|
723
|
+
### Phase 2: Component Library (Week 2)
|
|
724
|
+
|
|
725
|
+
- [ ] Add button, input, tabs, dialog, dropdown, select components
|
|
726
|
+
- [ ] Customize each component for dark theme
|
|
727
|
+
- [ ] Create custom components (TabBar, MobileNav, Sidebar, etc.)
|
|
728
|
+
- [ ] Test contrast ratios (use WCAG contrast checker)
|
|
729
|
+
|
|
730
|
+
### Phase 3: Layout Integration (Week 3)
|
|
731
|
+
|
|
732
|
+
- [ ] Implement mobile-first bottom nav + desktop top tabs
|
|
733
|
+
- [ ] Implement sidebar (desktop) + drawer (mobile)
|
|
734
|
+
- [ ] Responsive breakpoints (sm, md, lg)
|
|
735
|
+
- [ ] Test on real mobile device (iPhone, Android)
|
|
736
|
+
|
|
737
|
+
### Phase 4: Polish (Week 4)
|
|
738
|
+
|
|
739
|
+
- [ ] Fine-tune spacing + alignment on mobile
|
|
740
|
+
- [ ] Add focus states + accessibility features
|
|
741
|
+
- [ ] Icon sizing + alignment (match 16px grid)
|
|
742
|
+
- [ ] Dark mode testing in different lighting (bright room, dark room)
|
|
743
|
+
|
|
744
|
+
---
|
|
745
|
+
|
|
746
|
+
## 11. Figma Design System (Optional)
|
|
747
|
+
|
|
748
|
+
For designers, create a Figma project with:
|
|
749
|
+
|
|
750
|
+
- **Color library:** All hex values + CSS var names
|
|
751
|
+
- **Typography styles:** UI font + code font at all sizes
|
|
752
|
+
- **Component library:** Buttons, inputs, cards, modals (shadcn/ui mirrored)
|
|
753
|
+
- **Layout grid:** 4px baseline grid, 8px spacing
|
|
754
|
+
- **Icon library:** 16px, 24px, 32px sizes (SVG)
|
|
755
|
+
- **Mobile frames:** iPhone SE (375px), iPhone 12 Pro (390px), iPad (768px)
|
|
756
|
+
|
|
757
|
+
**Tool:** [tweakcn.com](https://tweakcn.com) — interactive shadcn/ui theme editor with Tailwind integration.
|
|
758
|
+
|
|
759
|
+
---
|
|
760
|
+
|
|
761
|
+
## 12. Testing Plan
|
|
762
|
+
|
|
763
|
+
### Contrast Testing
|
|
764
|
+
```bash
|
|
765
|
+
# Use online tool: https://webaim.org/resources/contrastchecker/
|
|
766
|
+
# or axe DevTools browser extension
|
|
767
|
+
# Verify all text >= 4.5:1 ratio on dark background
|
|
768
|
+
```
|
|
769
|
+
|
|
770
|
+
### Mobile Testing Devices
|
|
771
|
+
- iPhone SE (375px) — smallest common
|
|
772
|
+
- iPhone 12 Pro (390px) — typical
|
|
773
|
+
- iPad Air (768px) — tablet
|
|
774
|
+
- Pixel 6 (412px) — Android reference
|
|
775
|
+
|
|
776
|
+
### Accessibility Checklist
|
|
777
|
+
- [ ] Tab navigation works (keyboard only)
|
|
778
|
+
- [ ] Focus ring visible on all interactive elements
|
|
779
|
+
- [ ] Icon + label for bottom nav (not icons-only)
|
|
780
|
+
- [ ] Touch targets >= 44px × 44px
|
|
781
|
+
- [ ] Color not the only indicator (add text/icons)
|
|
782
|
+
|
|
783
|
+
### Long Session Testing
|
|
784
|
+
- [ ] Dark mode doesn't cause eye strain (test 30+ mins)
|
|
785
|
+
- [ ] Terminal text readable at 12px on mobile
|
|
786
|
+
- [ ] Code editor text readable at 13px on mobile
|
|
787
|
+
- [ ] No glare on OLED screens (black bg = low brightness)
|
|
788
|
+
|
|
789
|
+
---
|
|
790
|
+
|
|
791
|
+
## 13. Design System Tokens (CSS-in-TS)
|
|
792
|
+
|
|
793
|
+
Save in `src/lib/constants/colors.ts`:
|
|
794
|
+
|
|
795
|
+
```typescript
|
|
796
|
+
export const colors = {
|
|
797
|
+
// Backgrounds
|
|
798
|
+
bg: {
|
|
799
|
+
primary: '#0f1419',
|
|
800
|
+
surface: '#1a1f2e',
|
|
801
|
+
elevated: '#252d3d',
|
|
802
|
+
hover: '#1e293b',
|
|
803
|
+
},
|
|
804
|
+
// Text
|
|
805
|
+
text: {
|
|
806
|
+
primary: '#e5e7eb',
|
|
807
|
+
secondary: '#9ca3af',
|
|
808
|
+
subtle: '#6b7280',
|
|
809
|
+
muted: '#6b7280',
|
|
810
|
+
},
|
|
811
|
+
// Accents
|
|
812
|
+
accent: {
|
|
813
|
+
blue: '#3b82f6',
|
|
814
|
+
green: '#10b981',
|
|
815
|
+
red: '#ef4444',
|
|
816
|
+
orange: '#f59e0b',
|
|
817
|
+
cyan: '#06b6d4',
|
|
818
|
+
},
|
|
819
|
+
// Borders
|
|
820
|
+
border: '#404854',
|
|
821
|
+
// Code syntax
|
|
822
|
+
code: {
|
|
823
|
+
keyword: '#c9d1d9',
|
|
824
|
+
string: '#a5d6ff',
|
|
825
|
+
comment: '#8b949e',
|
|
826
|
+
number: '#79c0ff',
|
|
827
|
+
function: '#d2a8ff',
|
|
828
|
+
},
|
|
829
|
+
} as const
|
|
830
|
+
|
|
831
|
+
export const spacing = {
|
|
832
|
+
xs: '4px',
|
|
833
|
+
sm: '8px',
|
|
834
|
+
md: '12px',
|
|
835
|
+
lg: '16px',
|
|
836
|
+
xl: '24px',
|
|
837
|
+
'2xl': '32px',
|
|
838
|
+
touchTarget: '44px',
|
|
839
|
+
} as const
|
|
840
|
+
|
|
841
|
+
export const typography = {
|
|
842
|
+
fontFamily: {
|
|
843
|
+
sans: '"Geist Sans", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif',
|
|
844
|
+
mono: '"Geist Mono", "Monaco", monospace',
|
|
845
|
+
},
|
|
846
|
+
fontSize: {
|
|
847
|
+
xs: '12px',
|
|
848
|
+
sm: '14px',
|
|
849
|
+
base: '16px',
|
|
850
|
+
lg: '18px',
|
|
851
|
+
xl: '20px',
|
|
852
|
+
'2xl': '24px',
|
|
853
|
+
'3xl': '28px',
|
|
854
|
+
},
|
|
855
|
+
fontWeight: {
|
|
856
|
+
normal: 400,
|
|
857
|
+
medium: 500,
|
|
858
|
+
semibold: 600,
|
|
859
|
+
bold: 700,
|
|
860
|
+
},
|
|
861
|
+
} as const
|
|
862
|
+
```
|
|
863
|
+
|
|
864
|
+
---
|
|
865
|
+
|
|
866
|
+
## 14. Future Enhancements
|
|
867
|
+
|
|
868
|
+
### Light Mode (Phase 2+)
|
|
869
|
+
If adding light mode, invert carefully:
|
|
870
|
+
- Background: `#ffffff`
|
|
871
|
+
- Text: `#1a1f2e`
|
|
872
|
+
- Accents: Keep same (blue, green, red)
|
|
873
|
+
- Use Tailwind's `light:` variant
|
|
874
|
+
|
|
875
|
+
### Theme Customization (Phase 3+)
|
|
876
|
+
- User preference via settings tab
|
|
877
|
+
- Store in Zustand + localStorage
|
|
878
|
+
- Multiple dark variants (pure black, solarized, dracula, nord)
|
|
879
|
+
|
|
880
|
+
### Accessibility Options (Phase 4+)
|
|
881
|
+
- High contrast mode
|
|
882
|
+
- Dyslexia-friendly font option
|
|
883
|
+
- Reduced motion (prefers-reduced-motion)
|
|
884
|
+
|
|
885
|
+
---
|
|
886
|
+
|
|
887
|
+
## Summary
|
|
888
|
+
|
|
889
|
+
| Aspect | Recommendation | Rationale |
|
|
890
|
+
|--------|-----------------|-----------|
|
|
891
|
+
| **Color Scheme** | Slate Dark (#0f1419) | VS Code-inspired, OLED-friendly, proven |
|
|
892
|
+
| **UI Font** | Geist Sans | Modern, geometric, excellent on mobile |
|
|
893
|
+
| **Code Font** | Geist Mono | Matches UI, designed for code, ligature support |
|
|
894
|
+
| **Spacing** | 4px grid (Tailwind default) | Flexible, mobile-first |
|
|
895
|
+
| **Touch Targets** | 44px × 44px minimum | iOS/Android standards, comfortable thumb reach |
|
|
896
|
+
| **Dark Mode** | Always-on (no light toggle Phase 1) | Reduces scope, matches target audience (devs code at night) |
|
|
897
|
+
| **Component Library** | shadcn/ui + custom dark overrides | Accessible, customizable, Radix UI foundation |
|
|
898
|
+
| **Contrast** | All text >= 4.5:1 (WCAG AA) | Readable for all users, compliant |
|
|
899
|
+
|
|
900
|
+
---
|
|
901
|
+
|
|
902
|
+
## References
|
|
903
|
+
|
|
904
|
+
### Web Search Results (2025-2026)
|
|
905
|
+
1. [12 Defining Web Development Trends for 2026 | Figma](https://www.figma.com/resource-library/web-development-trends/)
|
|
906
|
+
2. [2025 UI design trends that are already shaping the web | Lummi](https://www.lummi.ai/blog/ui-design-trends-2025)
|
|
907
|
+
3. [Inclusive Dark Mode | Smashing Magazine](https://www.smashingmagazine.com/2025/04/inclusive-dark-mode-designing-accessible-dark-themes/)
|
|
908
|
+
4. [Dark Mode Color Palettes: Complete Guide for 2025 | MyPaletteTool](https://mypalettetool.com/blog/dark-mode-color-palettes)
|
|
909
|
+
5. [Theming - shadcn/ui](https://ui.shadcn.com/docs/theming)
|
|
910
|
+
6. [Dark Mode - shadcn/ui](https://ui.shadcn.com/docs/dark-mode)
|
|
911
|
+
7. [Best Free Monospace Fonts for Coding & Design 2026 | CSSAuthor](https://cssauthor.com/best-free-monospace-fonts-for-coding/)
|
|
912
|
+
8. [GitHub - system-fonts/modern-font-stacks](https://github.com/system-fonts/modern-font-stacks)
|
|
913
|
+
9. [The Golden Rules Of Bottom Navigation Design | Smashing Magazine](https://www.smashingmagazine.com/2016/11/the-golden-rules-of-mobile-navigation-design/)
|
|
914
|
+
10. [Bottom Navigation for Mobile: UX Design | AppMySite](https://blog.appmysite.com/bottom-navigation-bar-in-mobile-apps-heres-all-you-need-to-know/)
|
|
915
|
+
11. [Dark mode - Tailwind CSS](https://tailwindcss.com/docs/dark-mode)
|
|
916
|
+
12. [VS Code Theme Color API](https://code.visualstudio.com/api/references/theme-color)
|
|
917
|
+
13. [Replit Themes Documentation](https://docs.replit.com/replit-workspace/replit-themes)
|
|
918
|
+
|
|
919
|
+
### Tools & Generators
|
|
920
|
+
- [tweakcn.com](https://tweakcn.com) — shadcn/ui theme editor
|
|
921
|
+
- [WebAIM Contrast Checker](https://webaim.org/resources/contrastchecker/)
|
|
922
|
+
- [axe DevTools](https://www.deque.com/axe/devtools/) — accessibility testing
|
|
923
|
+
|
|
924
|
+
### PPM Project References
|
|
925
|
+
- [Tech Stack Research](brainstorm-260314-1938-final-techstack.md)
|
|
926
|
+
- [Phase 3: Frontend Shell](../260314-2009-ppm-implementation/phase-03-frontend-shell.md)
|
|
927
|
+
- [Tailwind CSS Docs](https://tailwindcss.com)
|
|
928
|
+
- [shadcn/ui Components](https://ui.shadcn.com)
|
|
929
|
+
|
|
930
|
+
---
|
|
931
|
+
|
|
932
|
+
## Unresolved Questions
|
|
933
|
+
|
|
934
|
+
1. **Icon Library:** Should we use Feather Icons, Heroicons, Lucide, or custom SVG? (Recommend: Lucide — 4KB, dark-friendly defaults)
|
|
935
|
+
2. **Font License:** Should we self-host Geist fonts or use Google Fonts CDN? (Google Fonts = simpler, no extra build step)
|
|
936
|
+
3. **Syntax Highlighting:** Which CodeMirror 6 theme should we start with? (Recommend: Extend `dracula` theme or fork VS Code dark colors)
|
|
937
|
+
4. **Notification Toasts:** Where should alerts appear on mobile? (Recommend: Bottom-left on desktop, full-width banner on mobile to avoid hiding bottom nav)
|
|
938
|
+
5. **Animations:** Should tab switches animate or snap instantly for mobile performance? (Recommend: Snap on mobile, animate on desktop)
|
|
939
|
+
|
|
940
|
+
---
|
|
941
|
+
|
|
942
|
+
**Report Complete.** Ready for design system implementation phase. Recommend starting with Phase 1 (Tailwind + shadcn/ui setup) before component development begins.
|