import { createStore, reconcile } from "solid-js/store" import { createEffect, createMemo } from "solid-js" import { createSimpleContext } from "@opencode-ai/ui/context" import { persisted } from "@/utils/persist" export interface NotificationSettings { agent: boolean permissions: boolean errors: boolean } export interface SoundSettings { agent: string permissions: string errors: string } export interface Settings { general: { autoSave: boolean releaseNotes: boolean } updates: { startup: boolean } appearance: { fontSize: number font: string } keybinds: Record permissions: { autoApprove: boolean } notifications: NotificationSettings sounds: SoundSettings } const defaultSettings: Settings = { general: { autoSave: true, releaseNotes: true, }, updates: { startup: true, }, appearance: { fontSize: 14, font: "ibm-plex-mono", }, keybinds: {}, permissions: { autoApprove: false, }, notifications: { agent: true, permissions: true, errors: false, }, sounds: { agent: "staplebops-01", permissions: "staplebops-02", errors: "nope-03", }, } const monoFallback = 'ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace' const monoFonts: Record = { "ibm-plex-mono": `"IBM Plex Mono", "IBM Plex Mono Fallback", ${monoFallback}`, "cascadia-code": `"Cascadia Code Nerd Font", "Cascadia Code NF", "Cascadia Mono NF", "IBM Plex Mono", "IBM Plex Mono Fallback", ${monoFallback}`, "fira-code": `"Fira Code Nerd Font", "FiraMono Nerd Font", "FiraMono Nerd Font Mono", "IBM Plex Mono", "IBM Plex Mono Fallback", ${monoFallback}`, hack: `"Hack Nerd Font", "Hack Nerd Font Mono", "IBM Plex Mono", "IBM Plex Mono Fallback", ${monoFallback}`, inconsolata: `"Inconsolata Nerd Font", "Inconsolata Nerd Font Mono","IBM Plex Mono", "IBM Plex Mono Fallback", ${monoFallback}`, "intel-one-mono": `"Intel One Mono Nerd Font", "IntoneMono Nerd Font", "IntoneMono Nerd Font Mono", "IBM Plex Mono", "IBM Plex Mono Fallback", ${monoFallback}`, iosevka: `"Iosevka Nerd Font", "Iosevka Nerd Font Mono", "IBM Plex Mono", "IBM Plex Mono Fallback", ${monoFallback}`, "jetbrains-mono": `"JetBrains Mono Nerd Font", "JetBrainsMono Nerd Font Mono", "JetBrainsMonoNL Nerd Font", "JetBrainsMonoNL Nerd Font Mono", "IBM Plex Mono", "IBM Plex Mono Fallback", ${monoFallback}`, "meslo-lgs": `"Meslo LGS Nerd Font", "MesloLGS Nerd Font", "MesloLGM Nerd Font", "IBM Plex Mono", "IBM Plex Mono Fallback", ${monoFallback}`, "roboto-mono": `"Roboto Mono Nerd Font", "RobotoMono Nerd Font", "RobotoMono Nerd Font Mono", "IBM Plex Mono", "IBM Plex Mono Fallback", ${monoFallback}`, "source-code-pro": `"Source Code Pro Nerd Font", "SauceCodePro Nerd Font", "SauceCodePro Nerd Font Mono", "IBM Plex Mono", "IBM Plex Mono Fallback", ${monoFallback}`, "ubuntu-mono": `"Ubuntu Mono Nerd Font", "UbuntuMono Nerd Font", "UbuntuMono Nerd Font Mono", "IBM Plex Mono", "IBM Plex Mono Fallback", ${monoFallback}`, } export function monoFontFamily(font: string | undefined) { return monoFonts[font ?? defaultSettings.appearance.font] ?? monoFonts[defaultSettings.appearance.font] } export const { use: useSettings, provider: SettingsProvider } = createSimpleContext({ name: "Settings", init: () => { const [store, setStore, _, ready] = persisted("settings.v3", createStore(defaultSettings)) createEffect(() => { if (typeof document === "undefined") return document.documentElement.style.setProperty("--font-family-mono", monoFontFamily(store.appearance?.font)) }) return { ready, get current() { return store }, general: { autoSave: createMemo(() => store.general?.autoSave ?? defaultSettings.general.autoSave), setAutoSave(value: boolean) { setStore("general", "autoSave", value) }, releaseNotes: createMemo(() => store.general?.releaseNotes ?? defaultSettings.general.releaseNotes), setReleaseNotes(value: boolean) { setStore("general", "releaseNotes", value) }, }, updates: { startup: createMemo(() => store.updates?.startup ?? defaultSettings.updates.startup), setStartup(value: boolean) { setStore("updates", "startup", value) }, }, appearance: { fontSize: createMemo(() => store.appearance?.fontSize ?? defaultSettings.appearance.fontSize), setFontSize(value: number) { setStore("appearance", "fontSize", value) }, font: createMemo(() => store.appearance?.font ?? defaultSettings.appearance.font), setFont(value: string) { setStore("appearance", "font", value) }, }, keybinds: { get: (action: string) => store.keybinds?.[action], set(action: string, keybind: string) { setStore("keybinds", action, keybind) }, reset(action: string) { setStore("keybinds", action, undefined!) }, resetAll() { setStore("keybinds", reconcile({})) }, }, permissions: { autoApprove: createMemo(() => store.permissions?.autoApprove ?? defaultSettings.permissions.autoApprove), setAutoApprove(value: boolean) { setStore("permissions", "autoApprove", value) }, }, notifications: { agent: createMemo(() => store.notifications?.agent ?? defaultSettings.notifications.agent), setAgent(value: boolean) { setStore("notifications", "agent", value) }, permissions: createMemo(() => store.notifications?.permissions ?? defaultSettings.notifications.permissions), setPermissions(value: boolean) { setStore("notifications", "permissions", value) }, errors: createMemo(() => store.notifications?.errors ?? defaultSettings.notifications.errors), setErrors(value: boolean) { setStore("notifications", "errors", value) }, }, sounds: { agent: createMemo(() => store.sounds?.agent ?? defaultSettings.sounds.agent), setAgent(value: string) { setStore("sounds", "agent", value) }, permissions: createMemo(() => store.sounds?.permissions ?? defaultSettings.sounds.permissions), setPermissions(value: string) { setStore("sounds", "permissions", value) }, errors: createMemo(() => store.sounds?.errors ?? defaultSettings.sounds.errors), setErrors(value: string) { setStore("sounds", "errors", value) }, }, } }, })