ci: update CI/CD configuration
This commit is contained in:
parent
411cc17c3c
commit
2e2f3c25ca
0
.windsurf/workflows/comi.md
Normal file
0
.windsurf/workflows/comi.md
Normal file
102
web/scripts/fix-colors.cjs
Normal file
102
web/scripts/fix-colors.cjs
Normal file
@ -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`);
|
||||
@ -18,7 +18,7 @@ export default function FocusPage() {
|
||||
<header
|
||||
className="sticky top-0 z-40 border-b backdrop-blur-md"
|
||||
style={{
|
||||
backgroundColor: 'rgba(6, 7, 10, 0.85)',
|
||||
backgroundColor: 'var(--cm-bg-canvas-85)',
|
||||
borderColor: 'var(--cm-border)',
|
||||
}}
|
||||
>
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -301,8 +301,8 @@ export default function HistoryPage() {
|
||||
<div
|
||||
className="rounded-xl border p-4 text-sm"
|
||||
style={{
|
||||
backgroundColor: 'rgba(245, 158, 11, 0.1)',
|
||||
borderColor: 'rgba(245, 158, 11, 0.3)',
|
||||
backgroundColor: 'var(--cm-warning-10)',
|
||||
borderColor: 'var(--cm-warning-30)',
|
||||
color: 'var(--cm-warning)',
|
||||
}}
|
||||
>
|
||||
@ -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)' }}
|
||||
>
|
||||
<Download size={14} /> Export JSON
|
||||
</button>
|
||||
@ -396,14 +396,14 @@ export default function HistoryPage() {
|
||||
<button
|
||||
onClick={confirmIcsImport}
|
||||
className="flex items-center gap-1 px-3 py-1.5 rounded-lg text-xs font-medium cursor-pointer"
|
||||
style={{ backgroundColor: 'rgba(52,211,153,0.15)', color: 'var(--cm-success)' }}
|
||||
style={{ backgroundColor: 'var(--cm-success-15)', color: 'var(--cm-success)' }}
|
||||
>
|
||||
<Check size={14} /> Import All
|
||||
</button>
|
||||
<button
|
||||
onClick={() => setIcsPreview(null)}
|
||||
className="flex items-center gap-1 px-3 py-1.5 rounded-lg text-xs font-medium cursor-pointer"
|
||||
style={{ backgroundColor: 'rgba(255,71,87,0.15)', color: 'var(--cm-danger)' }}
|
||||
style={{ backgroundColor: 'var(--cm-critical-15)', color: 'var(--cm-danger)' }}
|
||||
>
|
||||
<X size={14} /> Cancel
|
||||
</button>
|
||||
@ -423,7 +423,7 @@ export default function HistoryPage() {
|
||||
</span>
|
||||
</div>
|
||||
{evt.conflicts.length > 0 && (
|
||||
<span className="text-xs px-1.5 py-0.5 rounded" style={{ backgroundColor: 'rgba(245,158,11,0.15)', color: 'var(--cm-warning)' }}>
|
||||
<span className="text-xs px-1.5 py-0.5 rounded" style={{ backgroundColor: 'var(--cm-warning-15)', color: 'var(--cm-warning)' }}>
|
||||
Conflict
|
||||
</span>
|
||||
)}
|
||||
|
||||
@ -48,7 +48,7 @@ export default function LandingPage() {
|
||||
<Link
|
||||
href="/"
|
||||
className="flex items-center gap-2 px-4 py-2 rounded-xl text-sm font-medium"
|
||||
style={{ backgroundColor: 'var(--cm-accent)', color: '#fff' }}
|
||||
style={{ backgroundColor: 'var(--cm-accent)', color: 'var(--cm-white)' }}
|
||||
>
|
||||
Try it now <ArrowRight size={14} />
|
||||
</Link>
|
||||
@ -60,9 +60,9 @@ export default function LandingPage() {
|
||||
<div
|
||||
className="inline-flex items-center gap-2 px-4 py-1.5 rounded-full text-xs font-medium mb-6"
|
||||
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)',
|
||||
}}
|
||||
>
|
||||
<Zap size={12} /> Free · No signup · Works offline
|
||||
@ -86,7 +86,7 @@ export default function LandingPage() {
|
||||
<Link
|
||||
href="/"
|
||||
className="flex items-center gap-2 px-8 py-3.5 rounded-xl text-base font-semibold"
|
||||
style={{ backgroundColor: 'var(--cm-accent)', color: '#fff' }}
|
||||
style={{ backgroundColor: 'var(--cm-accent)', color: 'var(--cm-white)' }}
|
||||
>
|
||||
Try it now — free <ArrowRight size={16} />
|
||||
</Link>
|
||||
@ -154,7 +154,7 @@ export default function LandingPage() {
|
||||
<Link
|
||||
href="/"
|
||||
className="inline-flex items-center gap-2 px-8 py-3.5 rounded-xl text-base font-semibold"
|
||||
style={{ backgroundColor: 'var(--cm-accent)', color: '#fff' }}
|
||||
style={{ backgroundColor: 'var(--cm-accent)', color: 'var(--cm-white)' }}
|
||||
>
|
||||
Launch ChronoMind <ArrowRight size={16} />
|
||||
</Link>
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -74,7 +74,7 @@ function ResetPasswordForm() {
|
||||
{error && <p className="text-xs" style={{ color: 'var(--cm-danger)' }}>{error}</p>}
|
||||
{successMessage && (
|
||||
<div>
|
||||
<p className="text-xs" style={{ color: 'var(--cm-success, #34d399)' }}>{successMessage}</p>
|
||||
<p className="text-xs" style={{ color: 'var(--cm-success, var(--cm-success))' }}>{successMessage}</p>
|
||||
<Link href="/settings" className="text-xs mt-2 inline-block" style={{ color: 'var(--cm-accent)' }}>
|
||||
Go to Sign In
|
||||
</Link>
|
||||
@ -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'}
|
||||
</button>
|
||||
|
||||
@ -52,7 +52,7 @@ export default function RoutinesPage() {
|
||||
<button
|
||||
onClick={() => setShowEditor(true)}
|
||||
className="flex items-center gap-2 px-4 py-2 rounded-xl text-sm font-medium cursor-pointer"
|
||||
style={{ backgroundColor: 'var(--cm-accent)', color: '#fff' }}
|
||||
style={{ backgroundColor: 'var(--cm-accent)', color: 'var(--cm-white)' }}
|
||||
>
|
||||
<Plus size={16} /> New Routine
|
||||
</button>
|
||||
@ -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)' }}
|
||||
>
|
||||
<Play size={14} /> Start
|
||||
</button>
|
||||
@ -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)' }}
|
||||
>
|
||||
<Play size={14} /> Start
|
||||
</button>
|
||||
|
||||
@ -142,13 +142,13 @@ export default function SettingsPage() {
|
||||
<button
|
||||
onClick={logout}
|
||||
className="flex items-center gap-1.5 px-3 py-2 rounded-lg text-sm font-medium cursor-pointer"
|
||||
style={{ backgroundColor: 'rgba(255,71,87,0.15)', color: 'var(--cm-danger)' }}
|
||||
style={{ backgroundColor: 'var(--cm-critical-15)', color: 'var(--cm-danger)' }}
|
||||
>
|
||||
<LogOut size={14} /> Sign Out
|
||||
</button>
|
||||
</div>
|
||||
{authError && <p className="text-xs mt-2" style={{ color: 'var(--cm-danger)' }}>{authError}</p>}
|
||||
{successMessage && <p className="text-xs mt-2" style={{ color: 'var(--cm-success, #34d399)' }}>{successMessage}</p>}
|
||||
{successMessage && <p className="text-xs mt-2" style={{ color: 'var(--cm-success, var(--cm-success))' }}>{successMessage}</p>}
|
||||
|
||||
{/* Change Password */}
|
||||
<div className="mt-4 pt-4" style={{ borderTop: '1px solid var(--cm-border)' }}>
|
||||
@ -182,7 +182,7 @@ export default function SettingsPage() {
|
||||
<button onClick={handleChangePassword}
|
||||
disabled={authSubmitting || !changePwCurrent || changePwNew.length < 8 || changePwNew !== changePwConfirm}
|
||||
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)' }}
|
||||
>
|
||||
{authSubmitting ? 'Updating…' : 'Update Password'}
|
||||
</button>
|
||||
@ -212,7 +212,7 @@ export default function SettingsPage() {
|
||||
<button onClick={handleDeleteAccount}
|
||||
disabled={authSubmitting || !deleteConfirmPw}
|
||||
className="w-full px-4 py-2 rounded-lg text-sm font-medium cursor-pointer disabled:opacity-40"
|
||||
style={{ backgroundColor: 'var(--cm-danger)', color: '#fff' }}
|
||||
style={{ backgroundColor: 'var(--cm-danger)', color: 'var(--cm-white)' }}
|
||||
>
|
||||
{authSubmitting ? 'Deleting…' : 'Permanently Delete Account'}
|
||||
</button>
|
||||
@ -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() {
|
||||
<p className="text-xs" style={{ color: 'var(--cm-danger)' }}>{authError}</p>
|
||||
)}
|
||||
{successMessage && (
|
||||
<p className="text-xs" style={{ color: 'var(--cm-success, #34d399)' }}>{successMessage}</p>
|
||||
<p className="text-xs" style={{ color: 'var(--cm-success, var(--cm-success))' }}>{successMessage}</p>
|
||||
)}
|
||||
<button
|
||||
onClick={handleAuthSubmit}
|
||||
disabled={authSubmitting || !authEmail || (authMode !== 'forgot' && !authPassword) || (authMode === 'register' && !authName)}
|
||||
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)' }}
|
||||
>
|
||||
{authSubmitting ? 'Please wait…' : authMode === 'login' ? 'Sign In' : authMode === 'register' ? 'Create Account' : 'Send Reset Link'}
|
||||
</button>
|
||||
@ -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
|
||||
</button>
|
||||
@ -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
|
||||
</button>
|
||||
|
||||
@ -36,8 +36,8 @@ function VerifyEmailForm() {
|
||||
)}
|
||||
{status === 'success' && (
|
||||
<>
|
||||
<CheckCircle size={48} style={{ color: 'var(--cm-success, #34d399)', margin: '0 auto' }} />
|
||||
<p className="text-sm font-medium" style={{ color: 'var(--cm-success, #34d399)' }}>{message}</p>
|
||||
<CheckCircle size={48} style={{ color: 'var(--cm-success, var(--cm-success))', margin: '0 auto' }} />
|
||||
<p className="text-sm font-medium" style={{ color: 'var(--cm-success, var(--cm-success))' }}>{message}</p>
|
||||
<Link href="/settings" className="text-sm inline-block" style={{ color: 'var(--cm-accent)' }}>
|
||||
Go to Settings
|
||||
</Link>
|
||||
|
||||
@ -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() {
|
||||
<button
|
||||
onClick={() => advancePom(timer.id)}
|
||||
className="w-full py-3 rounded-xl text-base font-semibold transition-colors cursor-pointer"
|
||||
style={{ backgroundColor: 'var(--cm-accent)', color: '#fff' }}
|
||||
style={{ backgroundColor: 'var(--cm-accent)', color: 'var(--cm-white)' }}
|
||||
>
|
||||
{timer.pomodoroState?.isBreak ? 'Start Next Round' : 'Start Break'}
|
||||
</button>
|
||||
@ -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'}
|
||||
|
||||
@ -259,7 +259,7 @@ export function CreateTimerModal({ isOpen, onClose }: CreateTimerModalProps) {
|
||||
<button
|
||||
onClick={handleNlCreate}
|
||||
className="px-4 py-2 rounded-lg text-xs font-medium transition-colors cursor-pointer"
|
||||
style={{ backgroundColor: 'var(--cm-accent-secondary)', color: '#000' }}
|
||||
style={{ backgroundColor: 'var(--cm-accent-secondary)', color: 'var(--cm-black)' }}
|
||||
>
|
||||
Create
|
||||
</button>
|
||||
@ -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'}
|
||||
|
||||
@ -124,7 +124,7 @@ export function Dashboard() {
|
||||
<a
|
||||
href="#main-content"
|
||||
className="sr-only focus:not-sr-only focus:fixed focus:top-2 focus:left-2 focus:z-[60] focus:px-4 focus:py-2 focus:rounded-lg focus:text-sm focus:font-semibold"
|
||||
style={{ backgroundColor: 'var(--cm-accent)', color: '#fff' }}
|
||||
style={{ backgroundColor: 'var(--cm-accent)', color: 'var(--cm-white)' }}
|
||||
>
|
||||
Skip to content
|
||||
</a>
|
||||
@ -139,7 +139,7 @@ export function Dashboard() {
|
||||
<header
|
||||
className="sticky top-0 z-40 border-b backdrop-blur-md"
|
||||
style={{
|
||||
backgroundColor: 'rgba(6, 7, 10, 0.85)',
|
||||
backgroundColor: 'var(--cm-bg-canvas-85)',
|
||||
borderColor: 'var(--cm-border)',
|
||||
}}
|
||||
>
|
||||
@ -221,7 +221,7 @@ export function Dashboard() {
|
||||
<button
|
||||
onClick={() => setIsCreateOpen(true)}
|
||||
className="flex items-center gap-2 px-4 py-2 rounded-xl text-sm font-medium transition-all cursor-pointer"
|
||||
style={{ backgroundColor: 'var(--cm-accent)', color: '#fff' }}
|
||||
style={{ backgroundColor: 'var(--cm-accent)', color: 'var(--cm-white)' }}
|
||||
>
|
||||
<Plus size={16} /> New Timer
|
||||
</button>
|
||||
@ -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)',
|
||||
}}
|
||||
>
|
||||
<div className="flex-1 min-w-0">
|
||||
@ -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
|
||||
</button>
|
||||
@ -385,7 +385,7 @@ export function Dashboard() {
|
||||
<button
|
||||
onClick={() => setIsCreateOpen(true)}
|
||||
className="inline-flex items-center gap-2 px-6 py-3 rounded-xl text-sm font-semibold transition-all cursor-pointer"
|
||||
style={{ backgroundColor: 'var(--cm-accent)', color: '#fff' }}
|
||||
style={{ backgroundColor: 'var(--cm-accent)', color: 'var(--cm-white)' }}
|
||||
>
|
||||
<Plus size={18} /> Create Timer
|
||||
</button>
|
||||
|
||||
@ -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)',
|
||||
}}
|
||||
>
|
||||
|
||||
@ -138,7 +138,7 @@ export function FocusView({ onExit }: FocusViewProps) {
|
||||
<div className="text-center max-w-md w-full">
|
||||
<div
|
||||
className="w-20 h-20 rounded-full flex items-center justify-center mx-auto mb-6"
|
||||
style={{ backgroundColor: 'rgba(90, 140, 255, 0.12)' }}
|
||||
style={{ backgroundColor: 'var(--cm-accent-12)' }}
|
||||
>
|
||||
<Eye size={40} style={{ color: 'var(--cm-accent)' }} />
|
||||
</div>
|
||||
@ -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)',
|
||||
}}
|
||||
>
|
||||
<div className="flex items-center justify-center gap-2">
|
||||
@ -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)',
|
||||
}}
|
||||
>
|
||||
<div className="flex items-center justify-center gap-2">
|
||||
@ -226,7 +226,7 @@ export function FocusView({ onExit }: FocusViewProps) {
|
||||
<div className="text-center max-w-md w-full">
|
||||
<div
|
||||
className="w-20 h-20 rounded-full flex items-center justify-center mx-auto mb-6"
|
||||
style={{ backgroundColor: 'rgba(52, 211, 153, 0.12)' }}
|
||||
style={{ backgroundColor: 'var(--cm-success-12)' }}
|
||||
>
|
||||
<Trophy size={40} style={{ color: 'var(--cm-success)' }} />
|
||||
</div>
|
||||
@ -279,7 +279,7 @@ export function FocusView({ onExit }: FocusViewProps) {
|
||||
<button
|
||||
onClick={() => setSession(null)}
|
||||
className="px-6 py-3 rounded-xl text-sm font-medium cursor-pointer"
|
||||
style={{ backgroundColor: 'var(--cm-accent)', color: '#fff' }}
|
||||
style={{ backgroundColor: 'var(--cm-accent)', color: 'var(--cm-white)' }}
|
||||
>
|
||||
Start Another
|
||||
</button>
|
||||
@ -319,7 +319,7 @@ export function FocusView({ onExit }: FocusViewProps) {
|
||||
>
|
||||
{/* Shield badge */}
|
||||
<div className="absolute top-6 left-1/2 -translate-x-1/2 flex items-center gap-2 px-4 py-2 rounded-full"
|
||||
style={{ backgroundColor: 'rgba(90, 140, 255, 0.08)', border: '1px solid rgba(90, 140, 255, 0.2)' }}
|
||||
style={{ backgroundColor: 'var(--cm-accent-08)', border: '1px solid var(--cm-accent-20)' }}
|
||||
>
|
||||
<Shield size={14} style={{ color: 'var(--cm-accent)' }} />
|
||||
<span className="text-xs font-medium" style={{ color: 'var(--cm-accent)' }}>
|
||||
@ -354,7 +354,7 @@ export function FocusView({ onExit }: FocusViewProps) {
|
||||
<button
|
||||
onClick={resumeFocus}
|
||||
className="flex items-center gap-2 px-6 py-3 rounded-xl text-sm font-medium cursor-pointer"
|
||||
style={{ backgroundColor: 'var(--cm-accent)', color: '#fff' }}
|
||||
style={{ backgroundColor: 'var(--cm-accent)', color: 'var(--cm-white)' }}
|
||||
>
|
||||
<Play size={16} /> Resume
|
||||
</button>
|
||||
@ -371,7 +371,7 @@ export function FocusView({ onExit }: FocusViewProps) {
|
||||
<button
|
||||
onClick={endFocus}
|
||||
className="flex items-center gap-2 px-6 py-3 rounded-xl text-sm font-medium cursor-pointer"
|
||||
style={{ backgroundColor: 'rgba(255,71,87,0.15)', color: 'var(--cm-danger)' }}
|
||||
style={{ backgroundColor: 'var(--cm-critical-15)', color: 'var(--cm-danger)' }}
|
||||
>
|
||||
<X size={16} /> End Session
|
||||
</button>
|
||||
@ -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}
|
||||
>
|
||||
|
||||
@ -88,7 +88,7 @@ export function InstallPrompt() {
|
||||
<button
|
||||
onClick={handleInstall}
|
||||
className="px-3 py-1.5 rounded-lg text-xs font-semibold transition-colors cursor-pointer whitespace-nowrap"
|
||||
style={{ backgroundColor: 'var(--cm-accent)', color: '#fff' }}
|
||||
style={{ backgroundColor: 'var(--cm-accent)', color: 'var(--cm-white)' }}
|
||||
>
|
||||
Install
|
||||
</button>
|
||||
|
||||
@ -100,7 +100,7 @@ export function OnboardingOverlay() {
|
||||
<div className="px-6 pt-6 pb-4 text-center">
|
||||
<div
|
||||
className="w-16 h-16 rounded-2xl flex items-center justify-center mx-auto mb-4"
|
||||
style={{ backgroundColor: 'rgba(90,140,255,0.12)', color: 'var(--cm-accent)' }}
|
||||
style={{ backgroundColor: 'var(--cm-accent-12)', color: 'var(--cm-accent)' }}
|
||||
>
|
||||
{current.icon}
|
||||
</div>
|
||||
@ -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'}
|
||||
|
||||
@ -49,7 +49,7 @@ export function PomodoroView({ timer }: PomodoroViewProps) {
|
||||
<div className="flex justify-center mb-4">
|
||||
<div
|
||||
className="w-16 h-16 rounded-full flex items-center justify-center"
|
||||
style={{ backgroundColor: 'rgba(52,211,153,0.15)' }}
|
||||
style={{ backgroundColor: 'var(--cm-success-15)' }}
|
||||
>
|
||||
<Trophy size={32} style={{ color: 'var(--cm-success)' }} />
|
||||
</div>
|
||||
@ -162,7 +162,7 @@ export function PomodoroView({ timer }: PomodoroViewProps) {
|
||||
<button
|
||||
onClick={() => resume(timer.id)}
|
||||
className="flex items-center gap-2 px-5 py-2.5 rounded-xl text-sm font-medium transition-colors cursor-pointer"
|
||||
style={{ backgroundColor: 'var(--cm-accent)', color: '#fff' }}
|
||||
style={{ backgroundColor: 'var(--cm-accent)', color: 'var(--cm-white)' }}
|
||||
>
|
||||
<Play size={16} /> Resume
|
||||
</button>
|
||||
@ -172,7 +172,7 @@ export function PomodoroView({ timer }: PomodoroViewProps) {
|
||||
<button
|
||||
onClick={() => advancePom(timer.id)}
|
||||
className="flex items-center gap-2 px-5 py-2.5 rounded-xl text-sm font-medium transition-colors cursor-pointer"
|
||||
style={{ backgroundColor: 'var(--cm-accent)', color: '#fff' }}
|
||||
style={{ backgroundColor: 'var(--cm-accent)', color: 'var(--cm-white)' }}
|
||||
>
|
||||
<SkipForward size={16} /> {isBreak ? 'Start Work' : 'Start Break'}
|
||||
</button>
|
||||
@ -181,7 +181,7 @@ export function PomodoroView({ timer }: PomodoroViewProps) {
|
||||
<button
|
||||
onClick={() => dismiss(timer.id)}
|
||||
className="flex items-center gap-2 px-5 py-2.5 rounded-xl text-sm font-medium transition-colors cursor-pointer"
|
||||
style={{ backgroundColor: 'rgba(255,71,87,0.15)', color: 'var(--cm-danger)' }}
|
||||
style={{ backgroundColor: 'var(--cm-critical-15)', color: 'var(--cm-danger)' }}
|
||||
>
|
||||
<X size={16} /> End
|
||||
</button>
|
||||
|
||||
@ -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)',
|
||||
}}
|
||||
>
|
||||
<Coffee size={14} /> Pomodoro
|
||||
|
||||
@ -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'}
|
||||
</button>
|
||||
|
||||
@ -59,7 +59,7 @@ export function RoutineRunner({ routine }: RoutineRunnerProps) {
|
||||
<div className="flex justify-center mb-4">
|
||||
<div
|
||||
className="w-16 h-16 rounded-full flex items-center justify-center"
|
||||
style={{ backgroundColor: isCompleted ? 'rgba(52,211,153,0.15)' : 'rgba(255,107,107,0.15)' }}
|
||||
style={{ backgroundColor: isCompleted ? 'var(--cm-success-15)' : 'rgba(255,107,107,0.15)' }}
|
||||
>
|
||||
{isCompleted ? (
|
||||
<Trophy size={32} style={{ color: 'var(--cm-success)' }} />
|
||||
@ -204,7 +204,7 @@ export function RoutineRunner({ routine }: RoutineRunnerProps) {
|
||||
<button
|
||||
onClick={() => resume(routine.id)}
|
||||
className="flex items-center gap-2 px-5 py-2.5 rounded-xl text-sm font-medium cursor-pointer"
|
||||
style={{ backgroundColor: 'var(--cm-accent)', color: '#fff' }}
|
||||
style={{ backgroundColor: 'var(--cm-accent)', color: 'var(--cm-white)' }}
|
||||
>
|
||||
<Play size={16} /> Resume
|
||||
</button>
|
||||
@ -213,7 +213,7 @@ export function RoutineRunner({ routine }: RoutineRunnerProps) {
|
||||
<button
|
||||
onClick={() => completeStep(routine.id)}
|
||||
className="flex items-center gap-2 px-5 py-2.5 rounded-xl text-sm font-medium cursor-pointer"
|
||||
style={{ backgroundColor: 'rgba(52,211,153,0.15)', color: 'var(--cm-success)' }}
|
||||
style={{ backgroundColor: 'var(--cm-success-15)', color: 'var(--cm-success)' }}
|
||||
>
|
||||
<CheckCircle2 size={16} /> Done
|
||||
</button>
|
||||
@ -229,7 +229,7 @@ export function RoutineRunner({ routine }: RoutineRunnerProps) {
|
||||
<button
|
||||
onClick={() => cancel(routine.id)}
|
||||
className="flex items-center gap-2 px-5 py-2.5 rounded-xl text-sm font-medium cursor-pointer"
|
||||
style={{ backgroundColor: 'rgba(255,71,87,0.15)', color: 'var(--cm-danger)' }}
|
||||
style={{ backgroundColor: 'var(--cm-critical-15)', color: 'var(--cm-danger)' }}
|
||||
>
|
||||
<X size={16} /> End
|
||||
</button>
|
||||
|
||||
@ -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]}
|
||||
|
||||
@ -23,7 +23,7 @@ export function StreakCard({ streak }: StreakCardProps) {
|
||||
{streakFreezeUsed && (
|
||||
<span
|
||||
className="flex items-center gap-1 text-xs px-2 py-0.5 rounded-full"
|
||||
style={{ backgroundColor: 'rgba(90, 140, 255, 0.15)', color: 'var(--cm-accent)' }}
|
||||
style={{ backgroundColor: 'var(--cm-accent-15)', color: 'var(--cm-accent)' }}
|
||||
>
|
||||
<Shield size={12} /> Freeze used
|
||||
</span>
|
||||
@ -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)',
|
||||
}}
|
||||
>
|
||||
|
||||
@ -106,7 +106,7 @@ export function TimerCard({ timer }: TimerCardProps) {
|
||||
{timer.recurringTimerId && (
|
||||
<span
|
||||
className="text-xs px-1.5 py-0.5 rounded-full flex items-center gap-0.5"
|
||||
style={{ backgroundColor: 'rgba(46,230,214,0.15)', color: 'var(--cm-accent-secondary)' }}
|
||||
style={{ backgroundColor: 'var(--cm-accent-secondary-15)', color: 'var(--cm-accent-secondary)' }}
|
||||
title="Recurring timer"
|
||||
>
|
||||
<Repeat size={10} />
|
||||
@ -115,7 +115,7 @@ export function TimerCard({ timer }: TimerCardProps) {
|
||||
{timer.linkedTimerId && (
|
||||
<span
|
||||
className="text-xs px-1.5 py-0.5 rounded-full"
|
||||
style={{ backgroundColor: 'rgba(90,140,255,0.15)', color: 'var(--cm-accent)' }}
|
||||
style={{ backgroundColor: 'var(--cm-accent-15)', color: 'var(--cm-accent)' }}
|
||||
title="Part of a chain"
|
||||
>
|
||||
<Link2 size={12} />
|
||||
@ -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)',
|
||||
}}
|
||||
>
|
||||
<Play size={14} /> Resume
|
||||
@ -306,7 +306,7 @@ export function TimerCard({ timer }: TimerCardProps) {
|
||||
<button
|
||||
onClick={() => advancePom(timer.id)}
|
||||
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-secondary)', color: '#000' }}
|
||||
style={{ backgroundColor: 'var(--cm-accent-secondary)', color: 'var(--cm-black)' }}
|
||||
>
|
||||
Next
|
||||
</button>
|
||||
@ -318,7 +318,7 @@ export function TimerCard({ timer }: TimerCardProps) {
|
||||
<button
|
||||
onClick={() => dismiss(timer.id)}
|
||||
className="flex items-center gap-1 px-3 py-1.5 rounded-lg text-sm font-medium transition-colors cursor-pointer ml-auto"
|
||||
style={{ backgroundColor: 'rgba(255,71,87,0.15)', color: 'var(--cm-danger)' }}
|
||||
style={{ backgroundColor: 'var(--cm-critical-15)', color: 'var(--cm-danger)' }}
|
||||
>
|
||||
<X size={14} /> Dismiss
|
||||
</button>
|
||||
|
||||
@ -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() {
|
||||
|
||||
@ -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', () => {
|
||||
|
||||
@ -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',
|
||||
|
||||
@ -22,9 +22,9 @@ export const URGENCY_CONFIGS: Record<UrgencyLevel, UrgencyConfig> = {
|
||||
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<UrgencyLevel, UrgencyConfig> = {
|
||||
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<UrgencyLevel, UrgencyConfig> = {
|
||||
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<UrgencyLevel, UrgencyConfig> = {
|
||||
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<UrgencyLevel, UrgencyConfig> = {
|
||||
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: [],
|
||||
|
||||
Loading…
Reference in New Issue
Block a user