diff --git a/src/App.vue b/src/App.vue
index 070ab5c..7ae72d6 100644
--- a/src/App.vue
+++ b/src/App.vue
@@ -1,5 +1,5 @@
diff --git a/src/styles/main.css b/src/styles/main.css
index 58141c0..7b08f65 100644
--- a/src/styles/main.css
+++ b/src/styles/main.css
@@ -34,6 +34,63 @@
--font-mono: 'JetBrains Mono', 'IBM Plex Mono', monospace;
}
+/* Accent color overrides */
+[data-accent="amber"] {
+ --color-accent: #D97706;
+ --color-accent-hover: #B45309;
+ --color-accent-muted: rgba(217, 119, 6, 0.12);
+ --color-accent-text: #FBBF24;
+}
+[data-accent="blue"] {
+ --color-accent: #3B82F6;
+ --color-accent-hover: #2563EB;
+ --color-accent-muted: rgba(59, 130, 246, 0.12);
+ --color-accent-text: #60A5FA;
+}
+[data-accent="purple"] {
+ --color-accent: #8B5CF6;
+ --color-accent-hover: #7C3AED;
+ --color-accent-muted: rgba(139, 92, 246, 0.12);
+ --color-accent-text: #A78BFA;
+}
+[data-accent="green"] {
+ --color-accent: #10B981;
+ --color-accent-hover: #059669;
+ --color-accent-muted: rgba(16, 185, 129, 0.12);
+ --color-accent-text: #34D399;
+}
+[data-accent="red"] {
+ --color-accent: #EF4444;
+ --color-accent-hover: #DC2626;
+ --color-accent-muted: rgba(239, 68, 68, 0.12);
+ --color-accent-text: #F87171;
+}
+[data-accent="pink"] {
+ --color-accent: #EC4899;
+ --color-accent-hover: #DB2777;
+ --color-accent-muted: rgba(236, 72, 153, 0.12);
+ --color-accent-text: #F472B6;
+}
+[data-accent="cyan"] {
+ --color-accent: #06B6D4;
+ --color-accent-hover: #0891B2;
+ --color-accent-muted: rgba(6, 182, 212, 0.12);
+ --color-accent-text: #22D3EE;
+}
+
+/* Light mode */
+[data-theme="light"] {
+ --color-bg-base: #FAFAF9;
+ --color-bg-surface: #FFFFFF;
+ --color-bg-elevated: #F5F5F4;
+ --color-bg-inset: #E7E5E4;
+ --color-text-primary: #1C1917;
+ --color-text-secondary: #57534E;
+ --color-text-tertiary: #A8A29E;
+ --color-border-subtle: #E7E5E4;
+ --color-border-visible: #D6D3D1;
+}
+
@layer base {
* {
margin: 0;
@@ -173,3 +230,18 @@
.animate-pulse-colon {
animation: pulse-colon 1s ease-in-out infinite;
}
+
+/* Markdown inline styles */
+.markdown-inline strong { font-weight: 600; }
+.markdown-inline em { font-style: italic; }
+.markdown-inline code {
+ padding: 0.1em 0.3em;
+ background: var(--color-bg-elevated);
+ border-radius: 3px;
+ font-family: var(--font-mono);
+ font-size: 0.85em;
+}
+.markdown-inline a {
+ color: var(--color-accent-text);
+ text-decoration: underline;
+}
diff --git a/src/views/Settings.vue b/src/views/Settings.vue
index d4fa3ba..779d706 100644
--- a/src/views/Settings.vue
+++ b/src/views/Settings.vue
@@ -91,6 +91,44 @@
/>
+
+
+
+
+
Theme
+
Light or dark appearance
+
+
+
+
+
+
+
Accent Color
+
Primary interface color
+
+
+
+
+
+
@@ -120,22 +158,76 @@
-
-
-
-
Reminder Interval
-
Minutes between reminders while running
+
+
+
+
+
Idle Timeout
+
Minutes before idle pause triggers
+
+
-
+
+
Reminder Interval
+
Minutes between reminders while running
+
+
+
+
+
+
+
+
+
+
+
+
App Tracking Mode
+
What happens when a tracked app leaves focus
+
+
+
+
+
+
+
+
Check Interval
+
How often to check idle & app visibility
+
+
@@ -259,11 +351,38 @@ const activeTab = ref('general')
// Settings state
const hourlyRate = ref(0)
const idleDetection = ref(true)
+const idleTimeout = ref(5)
const reminderInterval = ref(15)
+const appTrackingMode = ref('auto')
+const appCheckInterval = ref(5)
const zoomLevel = ref(100)
const locale = ref('system')
const currency = ref('USD')
const currencyOptions = getCurrencies()
+const themeMode = ref('dark')
+const accentColor = ref('amber')
+
+const themeModes = [
+ { value: 'dark', label: 'Dark' },
+ { value: 'light', label: 'Light' },
+ { value: 'system', label: 'System' },
+]
+
+const accentColors = [
+ { value: 'amber', label: 'Amber', color: '#D97706' },
+ { value: 'blue', label: 'Blue', color: '#3B82F6' },
+ { value: 'purple', label: 'Purple', color: '#8B5CF6' },
+ { value: 'green', label: 'Green', color: '#10B981' },
+ { value: 'red', label: 'Red', color: '#EF4444' },
+ { value: 'pink', label: 'Pink', color: '#EC4899' },
+ { value: 'cyan', label: 'Cyan', color: '#06B6D4' },
+]
+
+const appTrackingModes = [
+ { value: 'auto', label: 'Auto-pause/resume' },
+ { value: 'notify', label: 'Notify + auto-resume' },
+ { value: 'prompt', label: 'Prompt user' },
+]
// Dialog state
const showClearDataDialog = ref(false)
@@ -312,7 +431,10 @@ async function saveSettings() {
try {
await settingsStore.updateSetting('hourly_rate', hourlyRate.value.toString())
await settingsStore.updateSetting('idle_detection', idleDetection.value.toString())
+ await settingsStore.updateSetting('idle_timeout', idleTimeout.value.toString())
await settingsStore.updateSetting('reminder_interval', reminderInterval.value.toString())
+ await settingsStore.updateSetting('app_tracking_mode', appTrackingMode.value)
+ await settingsStore.updateSetting('app_check_interval', appCheckInterval.value.toString())
} catch (error) {
console.error('Failed to save settings:', error)
toastStore.error('Failed to save settings')
@@ -325,6 +447,12 @@ async function saveLocaleSettings() {
await settingsStore.updateSetting('currency', currency.value)
}
+// Save theme settings
+async function saveThemeSettings() {
+ await settingsStore.updateSetting('theme_mode', themeMode.value)
+ await settingsStore.updateSetting('accent_color', accentColor.value)
+}
+
// Export all data
async function exportData() {
try {
@@ -362,9 +490,14 @@ onMounted(async () => {
hourlyRate.value = parseFloat(settingsStore.settings.hourly_rate) || 0
idleDetection.value = settingsStore.settings.idle_detection !== 'false'
+ idleTimeout.value = parseInt(settingsStore.settings.idle_timeout) || 5
reminderInterval.value = parseInt(settingsStore.settings.reminder_interval) || 15
+ appTrackingMode.value = settingsStore.settings.app_tracking_mode || 'auto'
+ appCheckInterval.value = parseInt(settingsStore.settings.app_check_interval) || 5
zoomLevel.value = parseInt(settingsStore.settings.ui_zoom) || 100
locale.value = settingsStore.settings.locale || 'system'
currency.value = settingsStore.settings.currency || 'USD'
+ themeMode.value = settingsStore.settings.theme_mode || 'dark'
+ accentColor.value = settingsStore.settings.accent_color || 'amber'
})