diff --git a/.windsurf/workflows/comi.md b/.windsurf/workflows/comi.md new file mode 100644 index 0000000..e69de29 diff --git a/web/scripts/fix-colors.cjs b/web/scripts/fix-colors.cjs new file mode 100644 index 0000000..c009b34 --- /dev/null +++ b/web/scripts/fix-colors.cjs @@ -0,0 +1,102 @@ +#!/usr/bin/env node +/** + * Batch fix hardcoded colors in ChronoMind Web + */ + +const { readFileSync, writeFileSync, readdirSync, statSync } = require('fs'); +const { join, extname } = require('path'); + +const REPLACEMENTS = [ + { from: /'#fff'/g, to: "'var(--cm-white)'" }, + { from: /'#ffffff'/g, to: "'var(--cm-white)'" }, + { from: /'#FFF'/g, to: "'var(--cm-white)'" }, + { from: /'#FFFFFF'/g, to: "'var(--cm-white)'" }, + { from: /'#000'/g, to: "'var(--cm-black)'" }, + { from: /'#000000'/g, to: "'var(--cm-black)'" }, + { from: /"#fff"/g, to: '"var(--cm-white)"' }, + { from: /"#ffffff"/g, to: '"var(--cm-white)"' }, + { from: /"#000"/g, to: '"var(--cm-black)"' }, + { from: /rgba\(6,\s*7,\s*10,\s*0\.85\)/g, to: 'var(--cm-bg-canvas-85)' }, + { from: /rgba\(90,\s*140,\s*255,\s*0\.1\)/g, to: 'var(--cm-accent-10)' }, + { from: /rgba\(90,\s*140,\s*255,\s*0\.08\)/g, to: 'var(--cm-accent-08)' }, + { from: /rgba\(90,\s*140,\s*255,\s*0\.12\)/g, to: 'var(--cm-accent-12)' }, + { from: /rgba\(90,\s*140,\s*255,\s*0\.15\)/g, to: 'var(--cm-accent-15)' }, + { from: /rgba\(90,\s*140,\s*255,\s*0\.2\)/g, to: 'var(--cm-accent-20)' }, + { from: /rgba\(90,\s*140,\s*255,\s*0\.3\)/g, to: 'var(--cm-accent-30)' }, + { from: /rgba\(255,\s*71,\s*87,\s*0\.1\)/g, to: 'var(--cm-critical-10)' }, + { from: /rgba\(255,\s*71,\s*87,\s*0\.15\)/g, to: 'var(--cm-critical-15)' }, + { from: /rgba\(255,\s*71,\s*87,\s*0\.2\)/g, to: 'var(--cm-critical-20)' }, + { from: /rgba\(255,\s*71,\s*87,\s*0\.4\)/g, to: 'var(--cm-critical-40)' }, + { from: /rgba\(52,\s*211,\s*153,\s*0\.12\)/g, to: 'var(--cm-success-12)' }, + { from: /rgba\(52,\s*211,\s*153,\s*0\.15\)/g, to: 'var(--cm-success-15)' }, + { from: /rgba\(46,\s*230,\s*214,\s*0\.1\)/g, to: 'var(--cm-accent-secondary-10)' }, + { from: /rgba\(46,\s*230,\s*214,\s*0\.15\)/g, to: 'var(--cm-accent-secondary-15)' }, + { from: /rgba\(46,\s*230,\s*214,\s*0\.3\)/g, to: 'var(--cm-accent-secondary-30)' }, + { from: /rgba\(245,\s*158,\s*11,\s*0\.1\)/g, to: 'var(--cm-warning-10)' }, + { from: /rgba\(245,\s*158,\s*11,\s*0\.15\)/g, to: 'var(--cm-warning-15)' }, + { from: /rgba\(245,\s*158,\s*11,\s*0\.3\)/g, to: 'var(--cm-warning-30)' }, + { from: /rgba\(165,\s*177,\s*199,\s*0\.1\)/g, to: 'var(--cm-passive-10)' }, + { from: /rgba\(165,\s*177,\s*199,\s*0\.2\)/g, to: 'var(--cm-passive-20)' }, + { from: /rgba\(0,\s*0,\s*0,\s*0\.8\)/g, to: 'var(--cm-black-80)' }, + { from: /rgba\(255,\s*159,\s*67,\s*0\.1\)/g, to: 'var(--cm-important-10)' }, + { from: /rgba\(255,\s*159,\s*67,\s*0\.15\)/g, to: 'var(--cm-important-15)' }, + { from: /rgba\(255,\s*159,\s*67,\s*0\.4\)/g, to: 'var(--cm-important-40)' }, + { from: /rgba\(254,\s*202,\s*87,\s*0\.15\)/g, to: 'var(--cm-standard-15)' }, + { from: /rgba\(254,\s*202,\s*87,\s*0\.4\)/g, to: 'var(--cm-standard-40)' }, + { from: /rgba\(46,\s*213,\s*115,\s*0\.15\)/g, to: 'var(--cm-gentle-15)' }, + { from: /rgba\(46,\s*213,\s*115,\s*0\.4\)/g, to: 'var(--cm-gentle-40)' }, + // Hex urgency colors in lib/urgency.ts + { from: /'#FF4757'/g, to: "'var(--cm-critical)'" }, + { from: /'#FF9F43'/g, to: "'var(--cm-important)'" }, + { from: /'#FECA57'/g, to: "'var(--cm-standard)'" }, + { from: /'#2ED573'/g, to: "'var(--cm-gentle)'" }, + { from: /'#2EE6D6'/g, to: "'var(--cm-accent-secondary)'" }, + { from: /'#A5B1C7'/g, to: "'var(--cm-passive)'" }, + { from: /'#5A8CFF'/g, to: "'var(--cm-accent)'" }, + { from: /"#FF4757"/g, to: '"var(--cm-critical)"' }, + { from: /"#FF9F43"/g, to: '"var(--cm-important)"' }, + { from: /"#FECA57"/g, to: '"var(--cm-standard)"' }, + { from: /"#2ED573"/g, to: '"var(--cm-gentle)"' }, + { from: /"#2EE6D6"/g, to: '"var(--cm-accent-secondary)"' }, + { from: /"#A5B1C7"/g, to: '"var(--cm-passive)"' }, + { from: /"#5A8CFF"/g, to: '"var(--cm-accent)"' }, +]; + +function findFiles(dir, files = []) { + const items = readdirSync(dir); + for (const item of items) { + const fullPath = join(dir, item); + if (item === 'node_modules' || item === '.next' || item === 'dist') continue; + const stat = statSync(fullPath); + if (stat.isDirectory()) { + findFiles(fullPath, files); + } else if (['.tsx', '.ts', '.jsx', '.js'].includes(extname(item))) { + files.push(fullPath); + } + } + return files; +} + +const srcDir = process.argv[2] || 'src'; +const files = findFiles(srcDir); +let totalChanges = 0; + +for (const file of files) { + let content = readFileSync(file, 'utf-8'); + let changed = false; + + for (const { from, to } of REPLACEMENTS) { + if (from.test(content)) { + content = content.replace(from, to); + changed = true; + totalChanges++; + } + } + + if (changed) { + writeFileSync(file, content); + console.log(`✅ ${file.replace(srcDir + '/', '')}`); + } +} + +console.log(`\nFixed ${totalChanges} color instances across ${files.length} files`); diff --git a/web/src/app/focus/page.tsx b/web/src/app/focus/page.tsx index 1edc7d0..62ad9ae 100644 --- a/web/src/app/focus/page.tsx +++ b/web/src/app/focus/page.tsx @@ -18,7 +18,7 @@ export default function FocusPage() {
diff --git a/web/src/app/globals.css b/web/src/app/globals.css index fc61139..04bd7a0 100644 --- a/web/src/app/globals.css +++ b/web/src/app/globals.css @@ -27,6 +27,35 @@ --cm-success: #34D399; --cm-warning: #F59E0B; --cm-danger: #FF6E6E; + --cm-white: #FFFFFF; + --cm-black: #000000; + + /* Opacity variants for rgba() values */ + --cm-critical-15: rgba(255, 71, 87, 0.15); + --cm-critical-20: rgba(255, 71, 87, 0.2); + --cm-critical-40: rgba(255, 71, 87, 0.4); + --cm-important-10: rgba(255, 159, 67, 0.1); + --cm-important-15: rgba(255, 159, 67, 0.15); + --cm-important-40: rgba(255, 159, 67, 0.4); + --cm-standard-15: rgba(254, 202, 87, 0.15); + --cm-standard-40: rgba(254, 202, 87, 0.4); + --cm-gentle-15: rgba(46, 213, 115, 0.15); + --cm-gentle-40: rgba(46, 213, 115, 0.4); + --cm-passive-10: rgba(165, 177, 199, 0.1); + --cm-passive-20: rgba(165, 177, 199, 0.2); + --cm-accent-10: rgba(90, 140, 255, 0.1); + --cm-accent-12: rgba(90, 140, 255, 0.12); + --cm-accent-15: rgba(90, 140, 255, 0.15); + --cm-accent-20: rgba(90, 140, 255, 0.2); + --cm-accent-30: rgba(90, 140, 255, 0.3); + --cm-accent-secondary-10: rgba(46, 230, 214, 0.1); + --cm-accent-secondary-15: rgba(46, 230, 214, 0.15); + --cm-accent-secondary-30: rgba(46, 230, 214, 0.3); + --cm-success-12: rgba(52, 211, 153, 0.12); + --cm-success-15: rgba(52, 211, 153, 0.15); + --cm-bg-canvas-85: rgba(6, 7, 10, 0.85); + --cm-black-80: rgba(0, 0, 0, 0.8); + --cm-black-90: rgba(0, 0, 0, 0.9); --background: var(--cm-bg-canvas); --foreground: var(--cm-text-primary); diff --git a/web/src/app/history/page.tsx b/web/src/app/history/page.tsx index 8e8b6ec..c302587 100644 --- a/web/src/app/history/page.tsx +++ b/web/src/app/history/page.tsx @@ -301,8 +301,8 @@ export default function HistoryPage() {
@@ -326,7 +326,7 @@ export default function HistoryPage() { onClick={handleExport} disabled={timers.length === 0 && routines.length === 0} className="flex items-center gap-1.5 px-4 py-2 rounded-lg text-sm font-medium cursor-pointer disabled:opacity-30" - style={{ backgroundColor: 'var(--cm-accent)', color: '#fff' }} + style={{ backgroundColor: 'var(--cm-accent)', color: 'var(--cm-white)' }} > Export JSON @@ -396,14 +396,14 @@ export default function HistoryPage() { @@ -423,7 +423,7 @@ export default function HistoryPage() {
{evt.conflicts.length > 0 && ( - + Conflict )} diff --git a/web/src/app/landing/page.tsx b/web/src/app/landing/page.tsx index 75132d9..0b8b1f1 100644 --- a/web/src/app/landing/page.tsx +++ b/web/src/app/landing/page.tsx @@ -48,7 +48,7 @@ export default function LandingPage() { Try it now @@ -60,9 +60,9 @@ export default function LandingPage() {
Free · No signup · Works offline @@ -86,7 +86,7 @@ export default function LandingPage() { Try it now — free @@ -154,7 +154,7 @@ export default function LandingPage() { Launch ChronoMind diff --git a/web/src/app/layout.tsx b/web/src/app/layout.tsx index f272378..c0bcdb5 100644 --- a/web/src/app/layout.tsx +++ b/web/src/app/layout.tsx @@ -15,7 +15,7 @@ const jetbrainsMono = JetBrains_Mono({ }); export const viewport: Viewport = { - themeColor: "#5A8CFF", + themeColor: "var(--cm-accent)", width: "device-width", initialScale: 1, maximumScale: 1, diff --git a/web/src/app/reset-password/page.tsx b/web/src/app/reset-password/page.tsx index 424d17d..767fe69 100644 --- a/web/src/app/reset-password/page.tsx +++ b/web/src/app/reset-password/page.tsx @@ -74,7 +74,7 @@ function ResetPasswordForm() { {error &&

{error}

} {successMessage && (
-

{successMessage}

+

{successMessage}

Go to Sign In @@ -85,7 +85,7 @@ function ResetPasswordForm() { onClick={handleSubmit} disabled={submitting || newPassword.length < 8 || newPassword !== confirmPassword} className="w-full px-4 py-2 rounded-lg text-sm font-medium cursor-pointer disabled:opacity-40" - style={{ backgroundColor: 'var(--cm-accent)', color: '#fff' }} + style={{ backgroundColor: 'var(--cm-accent)', color: 'var(--cm-white)' }} > {submitting ? 'Resetting…' : 'Reset Password'} diff --git a/web/src/app/routines/page.tsx b/web/src/app/routines/page.tsx index 6c7619a..c0224f6 100644 --- a/web/src/app/routines/page.tsx +++ b/web/src/app/routines/page.tsx @@ -52,7 +52,7 @@ export default function RoutinesPage() { @@ -95,7 +95,7 @@ export default function RoutinesPage() { onClick={() => startFromTemplate(tmpl.id)} disabled={!!activeRoutine} className="flex items-center gap-1.5 px-3 py-2 rounded-lg text-xs font-medium cursor-pointer disabled:opacity-30" - style={{ backgroundColor: 'rgba(52,211,153,0.15)', color: 'var(--cm-success)' }} + style={{ backgroundColor: 'var(--cm-success-15)', color: 'var(--cm-success)' }} > Start @@ -140,7 +140,7 @@ export default function RoutinesPage() { onClick={() => start(r.id)} disabled={!!activeRoutine} className="flex items-center gap-1.5 px-3 py-2 rounded-lg text-xs font-medium cursor-pointer disabled:opacity-30" - style={{ backgroundColor: 'var(--cm-accent)', color: '#fff' }} + style={{ backgroundColor: 'var(--cm-accent)', color: 'var(--cm-white)' }} > Start diff --git a/web/src/app/settings/page.tsx b/web/src/app/settings/page.tsx index 15c8969..14670a5 100644 --- a/web/src/app/settings/page.tsx +++ b/web/src/app/settings/page.tsx @@ -142,13 +142,13 @@ export default function SettingsPage() {
{authError &&

{authError}

} - {successMessage &&

{successMessage}

} + {successMessage &&

{successMessage}

} {/* Change Password */}
@@ -182,7 +182,7 @@ export default function SettingsPage() { @@ -212,7 +212,7 @@ export default function SettingsPage() { @@ -231,7 +231,7 @@ export default function SettingsPage() { className="px-3 py-1.5 rounded-lg text-xs font-medium cursor-pointer" style={{ backgroundColor: authMode === 'login' ? 'var(--cm-accent)' : 'var(--cm-surface-muted)', - color: authMode === 'login' ? '#fff' : 'var(--cm-text-secondary)', + color: authMode === 'login' ? 'var(--cm-white)' : 'var(--cm-text-secondary)', }} > Sign In @@ -241,7 +241,7 @@ export default function SettingsPage() { className="px-3 py-1.5 rounded-lg text-xs font-medium cursor-pointer" style={{ backgroundColor: authMode === 'register' ? 'var(--cm-accent)' : 'var(--cm-surface-muted)', - color: authMode === 'register' ? '#fff' : 'var(--cm-text-secondary)', + color: authMode === 'register' ? 'var(--cm-white)' : 'var(--cm-text-secondary)', }} > Create Account @@ -292,13 +292,13 @@ export default function SettingsPage() {

{authError}

)} {successMessage && ( -

{successMessage}

+

{successMessage}

)} @@ -366,7 +366,7 @@ export default function SettingsPage() { className="px-4 py-2 rounded-lg text-sm font-medium cursor-pointer" style={{ backgroundColor: compactMode ? 'var(--cm-accent)' : 'var(--cm-surface-muted)', - color: compactMode ? '#fff' : 'var(--cm-text-secondary)', + color: compactMode ? 'var(--cm-white)' : 'var(--cm-text-secondary)', }} > {compactMode ? 'On' : 'Off'} @@ -400,7 +400,7 @@ export default function SettingsPage() { setNotifPerm(result); }} className="px-4 py-2 rounded-lg text-sm font-medium cursor-pointer" - style={{ backgroundColor: 'var(--cm-accent)', color: '#fff' }} + style={{ backgroundColor: 'var(--cm-accent)', color: 'var(--cm-white)' }} > Enable @@ -477,7 +477,7 @@ export default function SettingsPage() { onClick={clearHistory} disabled={completedCount === 0} className="px-4 py-2 rounded-lg text-sm font-medium cursor-pointer disabled:opacity-30" - style={{ backgroundColor: 'rgba(255,71,87,0.15)', color: 'var(--cm-danger)' }} + style={{ backgroundColor: 'var(--cm-critical-15)', color: 'var(--cm-danger)' }} > Clear diff --git a/web/src/app/verify-email/page.tsx b/web/src/app/verify-email/page.tsx index dfc0a0c..65e1201 100644 --- a/web/src/app/verify-email/page.tsx +++ b/web/src/app/verify-email/page.tsx @@ -36,8 +36,8 @@ function VerifyEmailForm() { )} {status === 'success' && ( <> - -

{message}

+ +

{message}

Go to Settings diff --git a/web/src/components/AlarmOverlay.tsx b/web/src/components/AlarmOverlay.tsx index 42ca8b0..37dc3e8 100644 --- a/web/src/components/AlarmOverlay.tsx +++ b/web/src/components/AlarmOverlay.tsx @@ -25,8 +25,8 @@ export function AlarmOverlay() { className="absolute inset-0" style={{ background: isCritical - ? `radial-gradient(ellipse at center, ${urgencyConfig.bgColor} 0%, rgba(0,0,0,0.9) 100%)` - : 'rgba(0,0,0,0.8)', + ? `radial-gradient(ellipse at center, ${urgencyConfig.bgColor} 0%, var(--cm-black-90) 100%)` + : 'var(--cm-black-80)', }} /> @@ -63,7 +63,7 @@ export function AlarmOverlay() { @@ -98,8 +98,8 @@ export function AlarmOverlay() { onClick={() => dismiss(timer.id)} className="w-full py-3 rounded-xl text-sm font-medium transition-colors cursor-pointer" style={{ - backgroundColor: isCritical ? urgencyConfig.color : 'rgba(255,71,87,0.2)', - color: isCritical ? '#fff' : 'var(--cm-danger)', + backgroundColor: isCritical ? urgencyConfig.color : 'var(--cm-critical-20)', + color: isCritical ? 'var(--cm-white)' : 'var(--cm-danger)', }} > {isCritical ? 'Confirm Dismiss' : 'Dismiss'} diff --git a/web/src/components/CreateTimerModal.tsx b/web/src/components/CreateTimerModal.tsx index 90547d7..772a2da 100644 --- a/web/src/components/CreateTimerModal.tsx +++ b/web/src/components/CreateTimerModal.tsx @@ -259,7 +259,7 @@ export function CreateTimerModal({ isOpen, onClose }: CreateTimerModalProps) { @@ -466,7 +466,7 @@ export function CreateTimerModal({ isOpen, onClose }: CreateTimerModalProps) { className="px-2.5 py-1 rounded-lg text-xs font-medium transition-all cursor-pointer" style={{ backgroundColor: !category ? 'var(--cm-accent)' : 'var(--cm-surface-muted)', - color: !category ? '#fff' : 'var(--cm-text-tertiary)', + color: !category ? 'var(--cm-white)' : 'var(--cm-text-tertiary)', border: !category ? '1px solid var(--cm-accent)' : '1px solid transparent', }} > @@ -572,7 +572,7 @@ export function CreateTimerModal({ isOpen, onClose }: CreateTimerModalProps) { className="w-full py-3 rounded-xl text-sm font-semibold transition-colors cursor-pointer" style={{ backgroundColor: 'var(--cm-accent)', - color: '#fff', + color: 'var(--cm-white)', }} > Create {tab === 'pomodoro' ? 'Pomodoro' : tab === 'alarm' ? 'Alarm' : 'Countdown'} diff --git a/web/src/components/Dashboard.tsx b/web/src/components/Dashboard.tsx index 8a56f78..ea8a822 100644 --- a/web/src/components/Dashboard.tsx +++ b/web/src/components/Dashboard.tsx @@ -124,7 +124,7 @@ export function Dashboard() { Skip to content @@ -139,7 +139,7 @@ export function Dashboard() {
@@ -221,7 +221,7 @@ export function Dashboard() { @@ -271,7 +271,7 @@ export function Dashboard() { className="px-3 py-1 rounded-full text-xs font-medium whitespace-nowrap transition-colors cursor-pointer" style={{ backgroundColor: !filterCategory ? 'var(--cm-accent)' : 'var(--cm-surface-muted)', - color: !filterCategory ? '#fff' : 'var(--cm-text-tertiary)', + color: !filterCategory ? 'var(--cm-white)' : 'var(--cm-text-tertiary)', }} > All @@ -303,8 +303,8 @@ export function Dashboard() { key={suggestion.labelPattern} className="rounded-xl border p-3 flex items-center justify-between" style={{ - backgroundColor: 'rgba(90,140,255,0.08)', - borderColor: 'rgba(90,140,255,0.2)', + backgroundColor: 'var(--cm-accent-08)', + borderColor: 'var(--cm-accent-20)', }} >
@@ -339,7 +339,7 @@ export function Dashboard() { setDismissedSuggestions((prev) => new Set([...prev, suggestion.labelPattern])); }} className="text-xs px-2 py-1 rounded-lg cursor-pointer" - style={{ backgroundColor: 'rgba(90,140,255,0.2)', color: 'var(--cm-accent)' }} + style={{ backgroundColor: 'var(--cm-accent-20)', color: 'var(--cm-accent)' }} > Accept @@ -385,7 +385,7 @@ export function Dashboard() { diff --git a/web/src/components/FeedbackButton.tsx b/web/src/components/FeedbackButton.tsx index 7d2c46d..660e63b 100644 --- a/web/src/components/FeedbackButton.tsx +++ b/web/src/components/FeedbackButton.tsx @@ -20,7 +20,7 @@ export function FeedbackButton() { className="fixed bottom-6 right-6 z-30 p-3 rounded-full shadow-lg transition-all cursor-pointer hover:scale-110" style={{ backgroundColor: 'var(--cm-accent)', - color: '#fff', + color: 'var(--cm-white)', }} title="Send feedback" > @@ -69,7 +69,7 @@ export function FeedbackButton() { rel="noopener noreferrer" className="flex items-center gap-2 w-full px-3 py-2 rounded-lg text-sm font-medium transition-colors" style={{ - backgroundColor: 'rgba(255,71,87,0.1)', + backgroundColor: 'var(--cm-critical-10)', color: 'var(--cm-danger)', }} > diff --git a/web/src/components/FocusView.tsx b/web/src/components/FocusView.tsx index ec17197..bd24b4e 100644 --- a/web/src/components/FocusView.tsx +++ b/web/src/components/FocusView.tsx @@ -138,7 +138,7 @@ export function FocusView({ onExit }: FocusViewProps) {
@@ -181,9 +181,9 @@ export function FocusView({ onExit }: FocusViewProps) { onClick={() => startFocus('until_next', untilNextMs)} className="w-full py-3 rounded-xl text-sm font-medium transition-all cursor-pointer mb-4" style={{ - backgroundColor: 'rgba(46, 230, 214, 0.1)', + backgroundColor: 'var(--cm-accent-secondary-10)', color: 'var(--cm-accent-secondary)', - border: '1px solid rgba(46, 230, 214, 0.3)', + border: '1px solid var(--cm-accent-secondary-30)', }} >
@@ -201,9 +201,9 @@ export function FocusView({ onExit }: FocusViewProps) { onClick={() => startFocus('pomodoro', 25 * 60_000)} className="w-full py-3 rounded-xl text-sm font-medium transition-all cursor-pointer" style={{ - backgroundColor: 'rgba(90, 140, 255, 0.1)', + backgroundColor: 'var(--cm-accent-10)', color: 'var(--cm-accent)', - border: '1px solid rgba(90, 140, 255, 0.3)', + border: '1px solid var(--cm-accent-30)', }} >
@@ -226,7 +226,7 @@ export function FocusView({ onExit }: FocusViewProps) {
@@ -279,7 +279,7 @@ export function FocusView({ onExit }: FocusViewProps) { @@ -319,7 +319,7 @@ export function FocusView({ onExit }: FocusViewProps) { > {/* Shield badge */}
@@ -354,7 +354,7 @@ export function FocusView({ onExit }: FocusViewProps) { @@ -371,7 +371,7 @@ export function FocusView({ onExit }: FocusViewProps) { @@ -400,9 +400,9 @@ export function FocusView({ onExit }: FocusViewProps) { }} className="px-3 py-1.5 rounded-lg text-xs font-medium transition-all cursor-pointer" style={{ - backgroundColor: ambientType === sound.type ? 'rgba(46,230,214,0.15)' : 'var(--cm-surface-muted)', + backgroundColor: ambientType === sound.type ? 'var(--cm-accent-secondary-15)' : 'var(--cm-surface-muted)', color: ambientType === sound.type ? 'var(--cm-accent-secondary)' : 'var(--cm-text-tertiary)', - border: ambientType === sound.type ? '1px solid rgba(46,230,214,0.3)' : '1px solid transparent', + border: ambientType === sound.type ? '1px solid var(--cm-accent-secondary-30)' : '1px solid transparent', }} title={sound.description} > diff --git a/web/src/components/InstallPrompt.tsx b/web/src/components/InstallPrompt.tsx index 9735c92..7fb53f5 100644 --- a/web/src/components/InstallPrompt.tsx +++ b/web/src/components/InstallPrompt.tsx @@ -88,7 +88,7 @@ export function InstallPrompt() { diff --git a/web/src/components/OnboardingOverlay.tsx b/web/src/components/OnboardingOverlay.tsx index 27ee65e..1808be1 100644 --- a/web/src/components/OnboardingOverlay.tsx +++ b/web/src/components/OnboardingOverlay.tsx @@ -100,7 +100,7 @@ export function OnboardingOverlay() {
{current.icon}
@@ -143,7 +143,7 @@ export function OnboardingOverlay() { className="flex-1 py-2.5 rounded-xl text-sm font-semibold transition-colors cursor-pointer flex items-center justify-center gap-1" style={{ backgroundColor: 'var(--cm-accent)', - color: '#fff', + color: 'var(--cm-white)', }} > {step === STEPS.length - 1 ? 'Get Started' : 'Next'} diff --git a/web/src/components/PomodoroView.tsx b/web/src/components/PomodoroView.tsx index 4c4ed4a..321a8e0 100644 --- a/web/src/components/PomodoroView.tsx +++ b/web/src/components/PomodoroView.tsx @@ -49,7 +49,7 @@ export function PomodoroView({ timer }: PomodoroViewProps) {
@@ -162,7 +162,7 @@ export function PomodoroView({ timer }: PomodoroViewProps) { @@ -172,7 +172,7 @@ export function PomodoroView({ timer }: PomodoroViewProps) { @@ -181,7 +181,7 @@ export function PomodoroView({ timer }: PomodoroViewProps) { diff --git a/web/src/components/QuickTimerBar.tsx b/web/src/components/QuickTimerBar.tsx index f344c0e..d1e14c9 100644 --- a/web/src/components/QuickTimerBar.tsx +++ b/web/src/components/QuickTimerBar.tsx @@ -41,9 +41,9 @@ export function QuickTimerBar() { onClick={() => addPomodoro({ label: 'Focus Session' })} className="flex items-center gap-1.5 px-3 py-2 rounded-lg text-sm font-medium transition-all cursor-pointer hover:scale-105" style={{ - backgroundColor: 'rgba(90, 140, 255, 0.1)', + backgroundColor: 'var(--cm-accent-10)', color: 'var(--cm-accent)', - border: '1px solid rgba(90, 140, 255, 0.2)', + border: '1px solid var(--cm-accent-20)', }} > Pomodoro diff --git a/web/src/components/RoutineEditor.tsx b/web/src/components/RoutineEditor.tsx index cfbd808..9f54af1 100644 --- a/web/src/components/RoutineEditor.tsx +++ b/web/src/components/RoutineEditor.tsx @@ -277,7 +277,7 @@ export function RoutineEditor({ style={{ width: `${Math.max(pct, 2)}%`, backgroundColor: `hsl(${hue}, 60%, 45%)`, - color: '#fff', + color: 'var(--cm-white)', borderRight: idx < steps.length - 1 ? '1px solid var(--cm-bg-elevated)' : undefined, }} title={`${step.label || `Step ${idx + 1}`}: ${step.durationMinutes}m`} @@ -360,7 +360,7 @@ export function RoutineEditor({ onClick={handleSave} disabled={!canSave} className="flex-1 py-2.5 rounded-xl text-sm font-semibold cursor-pointer disabled:opacity-40" - style={{ backgroundColor: 'var(--cm-accent)', color: '#fff' }} + style={{ backgroundColor: 'var(--cm-accent)', color: 'var(--cm-white)' }} > {saveAsTemplate ? 'Save Template' : 'Create Routine'} diff --git a/web/src/components/RoutineRunner.tsx b/web/src/components/RoutineRunner.tsx index 8a217bc..08f15cc 100644 --- a/web/src/components/RoutineRunner.tsx +++ b/web/src/components/RoutineRunner.tsx @@ -59,7 +59,7 @@ export function RoutineRunner({ routine }: RoutineRunnerProps) {
{isCompleted ? ( @@ -204,7 +204,7 @@ export function RoutineRunner({ routine }: RoutineRunnerProps) { @@ -213,7 +213,7 @@ export function RoutineRunner({ routine }: RoutineRunnerProps) { @@ -229,7 +229,7 @@ export function RoutineRunner({ routine }: RoutineRunnerProps) { diff --git a/web/src/components/StatsView.tsx b/web/src/components/StatsView.tsx index 2ef4c1f..ce21f2e 100644 --- a/web/src/components/StatsView.tsx +++ b/web/src/components/StatsView.tsx @@ -54,7 +54,7 @@ export function StatsView() { return { name: cat?.label ?? c.categoryId, value: c.count, - color: cat?.color ?? '#5A8CFF', + color: cat?.color ?? 'var(--cm-accent)', }; }); @@ -69,7 +69,7 @@ export function StatsView() { className="px-3 py-1.5 rounded-lg text-xs font-medium transition-colors cursor-pointer" style={{ backgroundColor: range === r ? 'var(--cm-accent)' : 'var(--cm-surface-muted)', - color: range === r ? '#fff' : 'var(--cm-text-tertiary)', + color: range === r ? 'var(--cm-white)' : 'var(--cm-text-tertiary)', }} > {RANGE_LABELS[r]} diff --git a/web/src/components/StreakCard.tsx b/web/src/components/StreakCard.tsx index 639a7e3..743f71f 100644 --- a/web/src/components/StreakCard.tsx +++ b/web/src/components/StreakCard.tsx @@ -23,7 +23,7 @@ export function StreakCard({ streak }: StreakCardProps) { {streakFreezeUsed && ( Freeze used @@ -79,8 +79,8 @@ export function StreakCard({ streak }: StreakCardProps) { className="mt-3 px-3 py-1.5 rounded-lg text-xs font-medium text-center" style={{ backgroundColor: currentStreak >= 30 - ? 'rgba(255, 159, 67, 0.15)' - : 'rgba(46, 213, 115, 0.15)', + ? 'var(--cm-important-15)' + : 'var(--cm-gentle-15)', color: currentStreak >= 30 ? 'var(--cm-important)' : 'var(--cm-gentle)', }} > diff --git a/web/src/components/TimerCard.tsx b/web/src/components/TimerCard.tsx index a9b9353..12e3738 100644 --- a/web/src/components/TimerCard.tsx +++ b/web/src/components/TimerCard.tsx @@ -106,7 +106,7 @@ export function TimerCard({ timer }: TimerCardProps) { {timer.recurringTimerId && ( @@ -115,7 +115,7 @@ export function TimerCard({ timer }: TimerCardProps) { {timer.linkedTimerId && ( @@ -126,7 +126,7 @@ export function TimerCard({ timer }: TimerCardProps) { className="text-xs font-mono px-2 py-0.5 rounded" style={{ backgroundColor: isFiring ? urgencyConfig.color : 'var(--cm-surface-muted)', - color: isFiring ? '#fff' : 'var(--cm-text-tertiary)', + color: isFiring ? 'var(--cm-white)' : 'var(--cm-text-tertiary)', }} > {stateLabel} @@ -279,7 +279,7 @@ export function TimerCard({ timer }: TimerCardProps) { className="flex items-center gap-1 px-3 py-1.5 rounded-lg text-sm font-medium transition-colors cursor-pointer" style={{ backgroundColor: 'var(--cm-accent)', - color: '#fff', + color: 'var(--cm-white)', }} > Resume @@ -306,7 +306,7 @@ export function TimerCard({ timer }: TimerCardProps) { @@ -318,7 +318,7 @@ export function TimerCard({ timer }: TimerCardProps) { diff --git a/web/src/components/Toast.tsx b/web/src/components/Toast.tsx index 6e59c43..3688904 100644 --- a/web/src/components/Toast.tsx +++ b/web/src/components/Toast.tsx @@ -45,10 +45,10 @@ const ICONS = { }; const COLORS = { - info: { bg: 'var(--cm-accent)', text: '#fff' }, - warning: { bg: 'var(--cm-warning)', text: '#000' }, - success: { bg: 'var(--cm-success)', text: '#000' }, - alarm: { bg: 'var(--cm-critical)', text: '#fff' }, + info: { bg: 'var(--cm-accent)', text: 'var(--cm-white)' }, + warning: { bg: 'var(--cm-warning)', text: 'var(--cm-black)' }, + success: { bg: 'var(--cm-success)', text: 'var(--cm-black)' }, + alarm: { bg: 'var(--cm-critical)', text: 'var(--cm-white)' }, }; export function ToastContainer() { diff --git a/web/src/lib/categories.test.ts b/web/src/lib/categories.test.ts index f38998e..bafa8bd 100644 --- a/web/src/lib/categories.test.ts +++ b/web/src/lib/categories.test.ts @@ -162,7 +162,7 @@ describe('Categories', () => { describe('getCategoryColor', () => { it('returns color for valid category', () => { - expect(getCategoryColor('work')).toBe('#5A8CFF'); + expect(getCategoryColor('work')).toBe('var(--cm-accent)'); }); it('returns undefined for undefined category', () => { diff --git a/web/src/lib/categories.ts b/web/src/lib/categories.ts index 94000bf..512bae8 100644 --- a/web/src/lib/categories.ts +++ b/web/src/lib/categories.ts @@ -20,7 +20,7 @@ export const BUILT_IN_CATEGORIES: Category[] = [ { id: 'work', label: 'Work', - color: '#5A8CFF', + color: 'var(--cm-accent)', icon: 'Briefcase', defaultUrgency: 'important', defaultCascade: 'standard', @@ -38,7 +38,7 @@ export const BUILT_IN_CATEGORIES: Category[] = [ { id: 'health', label: 'Health', - color: '#34D399', + color: 'var(--cm-success)', icon: 'Heart', defaultUrgency: 'important', defaultCascade: 'standard', @@ -47,7 +47,7 @@ export const BUILT_IN_CATEGORIES: Category[] = [ { id: 'cooking', label: 'Cooking', - color: '#F59E0B', + color: 'var(--cm-warning)', icon: 'ChefHat', defaultUrgency: 'standard', defaultCascade: 'light', @@ -56,7 +56,7 @@ export const BUILT_IN_CATEGORIES: Category[] = [ { id: 'exercise', label: 'Exercise', - color: '#2EE6D6', + color: 'var(--cm-accent-secondary)', icon: 'Dumbbell', defaultUrgency: 'standard', defaultCascade: 'minimal', @@ -65,7 +65,7 @@ export const BUILT_IN_CATEGORIES: Category[] = [ { id: 'study', label: 'Study', - color: '#FF9F43', + color: 'var(--cm-important)', icon: 'BookOpen', defaultUrgency: 'standard', defaultCascade: 'light', diff --git a/web/src/lib/urgency.ts b/web/src/lib/urgency.ts index 1ab1329..07b3b64 100644 --- a/web/src/lib/urgency.ts +++ b/web/src/lib/urgency.ts @@ -22,9 +22,9 @@ export const URGENCY_CONFIGS: Record = { critical: { level: 'critical', label: 'Critical', - color: '#FF4757', - bgColor: 'rgba(255, 71, 87, 0.15)', - borderColor: 'rgba(255, 71, 87, 0.4)', + color: 'var(--cm-critical)', + bgColor: 'var(--cm-critical-15)', + borderColor: 'var(--cm-critical-40)', notificationStyle: 'persistent', soundEnabled: true, vibrationPattern: [200, 100, 200, 100, 400], @@ -36,9 +36,9 @@ export const URGENCY_CONFIGS: Record = { important: { level: 'important', label: 'Important', - color: '#FF9F43', - bgColor: 'rgba(255, 159, 67, 0.15)', - borderColor: 'rgba(255, 159, 67, 0.4)', + color: 'var(--cm-important)', + bgColor: 'var(--cm-important-15)', + borderColor: 'var(--cm-important-40)', notificationStyle: 'prominent', soundEnabled: true, vibrationPattern: [200, 100, 200], @@ -50,9 +50,9 @@ export const URGENCY_CONFIGS: Record = { standard: { level: 'standard', label: 'Standard', - color: '#FECA57', - bgColor: 'rgba(254, 202, 87, 0.15)', - borderColor: 'rgba(254, 202, 87, 0.4)', + color: 'var(--cm-standard)', + bgColor: 'var(--cm-standard-15)', + borderColor: 'var(--cm-standard-40)', notificationStyle: 'default', soundEnabled: true, vibrationPattern: [200], @@ -64,9 +64,9 @@ export const URGENCY_CONFIGS: Record = { gentle: { level: 'gentle', label: 'Gentle', - color: '#2ED573', - bgColor: 'rgba(46, 213, 115, 0.15)', - borderColor: 'rgba(46, 213, 115, 0.4)', + color: 'var(--cm-gentle)', + bgColor: 'var(--cm-gentle-15)', + borderColor: 'var(--cm-gentle-40)', notificationStyle: 'subtle', soundEnabled: true, vibrationPattern: [100], @@ -78,9 +78,9 @@ export const URGENCY_CONFIGS: Record = { passive: { level: 'passive', label: 'Passive', - color: '#A5B1C7', - bgColor: 'rgba(165, 177, 199, 0.1)', - borderColor: 'rgba(165, 177, 199, 0.2)', + color: 'var(--cm-passive)', + bgColor: 'var(--cm-passive-10)', + borderColor: 'var(--cm-passive-20)', notificationStyle: 'badge', soundEnabled: false, vibrationPattern: [],