diff --git a/packages/app/src/components/settings/SettingsPanel.vue b/packages/app/src/components/settings/SettingsPanel.vue new file mode 100644 index 00000000..dba6282b --- /dev/null +++ b/packages/app/src/components/settings/SettingsPanel.vue @@ -0,0 +1,476 @@ + + + + + + Settings + + + + + + + + + + + {{ tab.label }} + + + + + + + + + + Accent Colour + + + + + + + + + + + + + Glass Intensity + + + {{ opt.label }} + + + + + + + Font Size + + + {{ opt.label }} + + + + + + + + + + Content Types + Hidden types still extract but don't show in the panel + + + + {{ ct.label }} + + + + + + + + + + Keyboard Shortcuts + + + {{ formatAction(action as string) }} + + {{ recordingAction === action ? 'Press key...' : binding }} + + + + + + + + + + + Notifications + + + + Generation complete + Notify when AI finishes while tab is backgrounded + + + + {{ notificationStatus }} + + + + + + + + + Auto-Archive + Archive conversations older than: + + + {{ opt.label }} + + + + + + + Data Export + + {{ isExporting ? 'Exporting...' : 'Export All Data' }} + + Exports conversations, favorites, settings, tags, and collections as JSON + + + + + Danger Zone + + Wipe All Data + + + Are you sure? + This will clear all conversations, favorites, settings, and cached data. + + + Also clear API key vault + + + + Cancel + + + Confirm Wipe + + + + + + + + + + + Default Conversation Settings + Applied to all new conversations + + + + Default Model + + + + + + Enable web search by default + + + + + Show token counts by default + + + + + + + + + + diff --git a/packages/app/src/stores/settings.ts b/packages/app/src/stores/settings.ts new file mode 100644 index 00000000..dc0fa085 --- /dev/null +++ b/packages/app/src/stores/settings.ts @@ -0,0 +1,160 @@ +import { ref, computed, watch } from 'vue' +import { defineStore } from 'pinia' +import type { ContentTab } from '@/composables/contentFiltering' + +const STORAGE_KEY = 'aiui-settings' + +export interface AppSettings { + // M15.1 — Accent colour + accentColor: string + // M15.2 — Glass intensity + glassIntensity: 'subtle' | 'default' | 'strong' + // M15.3 — Font size + fontSize: 'compact' | 'default' | 'large' + // M15.4 — Content type visibility + hiddenContentTabs: ContentTab[] + // M15.5 — Keyboard shortcuts + shortcuts: Record + // M15.6 — Push notifications + notificationsEnabled: boolean + // M15.7 — Auto-archive + autoArchiveDays: number // 0 = never, 7/30/90 + // M15.10 — Default conversation settings + defaultModel: string + defaultPersonaId: string + defaultWebSearch: boolean + defaultShowTokens: boolean +} + +const DEFAULT_SETTINGS: AppSettings = { + accentColor: '#F7931A', + glassIntensity: 'default', + fontSize: 'default', + hiddenContentTabs: [], + shortcuts: { + 'send-message': 'Enter', + 'new-line': 'Shift+Enter', + 'search': 'Cmd+F', + 'new-chat': 'Cmd+N', + 'settings': 'Cmd+,', + 'close-panel': 'Escape', + }, + notificationsEnabled: false, + autoArchiveDays: 0, + defaultModel: '', + defaultPersonaId: '', + defaultWebSearch: false, + defaultShowTokens: false, +} + +export const useSettingsStore = defineStore('settings', () => { + const settings = ref(loadSettings()) + + function loadSettings(): AppSettings { + try { + const stored = localStorage.getItem(STORAGE_KEY) + if (stored) return { ...DEFAULT_SETTINGS, ...JSON.parse(stored) } + } catch { /* ignore */ } + return { ...DEFAULT_SETTINGS } + } + + function save() { + localStorage.setItem(STORAGE_KEY, JSON.stringify(settings.value)) + } + + // Apply CSS variables when settings change + function applyCssVars() { + const root = document.documentElement + + // Accent colour + root.style.setProperty('--color-accent', settings.value.accentColor) + + // Glass intensity + const glass = { + subtle: { blur: '12px', opacity: '0.25' }, + default: { blur: '18px', opacity: '0.35' }, + strong: { blur: '28px', opacity: '0.50' }, + }[settings.value.glassIntensity] + root.style.setProperty('--glass-blur', glass.blur) + root.style.setProperty('--glass-opacity', glass.opacity) + + // Font size + const sizes = { compact: '13px', default: '15px', large: '17px' } + root.style.setProperty('--font-size-base', sizes[settings.value.fontSize]) + } + + // Watch for changes and persist + apply + watch(settings, () => { + save() + applyCssVars() + }, { deep: true }) + + // Apply on init + applyCssVars() + + const accentColor = computed({ + get: () => settings.value.accentColor, + set: (v) => { settings.value.accentColor = v }, + }) + + const glassIntensity = computed({ + get: () => settings.value.glassIntensity, + set: (v) => { settings.value.glassIntensity = v }, + }) + + const fontSize = computed({ + get: () => settings.value.fontSize, + set: (v) => { settings.value.fontSize = v }, + }) + + const hiddenContentTabs = computed({ + get: () => settings.value.hiddenContentTabs, + set: (v) => { settings.value.hiddenContentTabs = v }, + }) + + const notificationsEnabled = computed({ + get: () => settings.value.notificationsEnabled, + set: (v) => { settings.value.notificationsEnabled = v }, + }) + + const autoArchiveDays = computed({ + get: () => settings.value.autoArchiveDays, + set: (v) => { settings.value.autoArchiveDays = v }, + }) + + function isTabVisible(tab: ContentTab): boolean { + return !settings.value.hiddenContentTabs.includes(tab) + } + + function toggleTabVisibility(tab: ContentTab) { + const idx = settings.value.hiddenContentTabs.indexOf(tab) + if (idx >= 0) { + settings.value.hiddenContentTabs.splice(idx, 1) + } else { + settings.value.hiddenContentTabs.push(tab) + } + } + + function setShortcut(action: string, binding: string) { + settings.value.shortcuts[action] = binding + } + + function resetSettings() { + settings.value = { ...DEFAULT_SETTINGS } + } + + return { + settings, + accentColor, + glassIntensity, + fontSize, + hiddenContentTabs, + notificationsEnabled, + autoArchiveDays, + isTabVisible, + toggleTabVisibility, + setShortcut, + resetSettings, + applyCssVars, + } +})
Accent Colour
Glass Intensity
Font Size
Content Types
Hidden types still extract but don't show in the panel
Keyboard Shortcuts
Notifications
Generation complete
Notify when AI finishes while tab is backgrounded
+ {{ notificationStatus }} +
Auto-Archive
Archive conversations older than:
Data Export
Exports conversations, favorites, settings, tags, and collections as JSON
Danger Zone
Are you sure?
This will clear all conversations, favorites, settings, and cached data.
Default Conversation Settings
Applied to all new conversations