diff options
| author | Adam <[email protected]> | 2026-01-06 16:03:39 -0600 |
|---|---|---|
| committer | Adam <[email protected]> | 2026-01-20 07:33:44 -0600 |
| commit | de3641e8ebfd6d6d0262289136e970b1ddea54b2 (patch) | |
| tree | b351a43a08e24c57bec5ddcdc2e851853759a761 /packages/app/src/context | |
| parent | 8bcbfd63960120efa3cb770f8e07de1bb57e93b0 (diff) | |
| download | opencode-de3641e8ebfd6d6d0262289136e970b1ddea54b2.tar.gz opencode-de3641e8ebfd6d6d0262289136e970b1ddea54b2.zip | |
wip(app): settings
Diffstat (limited to 'packages/app/src/context')
| -rw-r--r-- | packages/app/src/context/notification.tsx | 40 | ||||
| -rw-r--r-- | packages/app/src/context/settings.tsx | 60 |
2 files changed, 75 insertions, 25 deletions
diff --git a/packages/app/src/context/notification.tsx b/packages/app/src/context/notification.tsx index 16b3d306c..8b1088519 100644 --- a/packages/app/src/context/notification.tsx +++ b/packages/app/src/context/notification.tsx @@ -4,13 +4,12 @@ import { createSimpleContext } from "@opencode-ai/ui/context" import { useGlobalSDK } from "./global-sdk" import { useGlobalSync } from "./global-sync" import { usePlatform } from "@/context/platform" +import { useSettings } from "@/context/settings" import { Binary } from "@opencode-ai/util/binary" import { base64Encode } from "@opencode-ai/util/encode" import { EventSessionError } from "@opencode-ai/sdk/v2" -import { makeAudioPlayer } from "@solid-primitives/audio" -import idleSound from "@opencode-ai/ui/audio/staplebops-01.aac" -import errorSound from "@opencode-ai/ui/audio/nope-03.aac" import { Persist, persisted } from "@/utils/persist" +import { playSound, soundSrc } from "@/utils/sound" type NotificationBase = { directory?: string @@ -44,19 +43,10 @@ function pruneNotifications(list: Notification[]) { export const { use: useNotification, provider: NotificationProvider } = createSimpleContext({ name: "Notification", init: () => { - let idlePlayer: ReturnType<typeof makeAudioPlayer> | undefined - let errorPlayer: ReturnType<typeof makeAudioPlayer> | undefined - - try { - idlePlayer = makeAudioPlayer(idleSound) - errorPlayer = makeAudioPlayer(errorSound) - } catch (err) { - console.log("Failed to load audio", err) - } - const globalSDK = useGlobalSDK() const globalSync = useGlobalSync() const platform = usePlatform() + const settings = useSettings() const [store, setStore, _, ready] = persisted( Persist.global("notification", ["notification.v1"]), @@ -93,16 +83,20 @@ export const { use: useNotification, provider: NotificationProvider } = createSi const match = Binary.search(syncStore.session, sessionID, (s) => s.id) const session = match.found ? syncStore.session[match.index] : undefined if (session?.parentID) break - try { - idlePlayer?.play() - } catch {} + + playSound(soundSrc(settings.sounds.agent())) + append({ ...base, type: "turn-complete", session: sessionID, }) + const href = `/${base64Encode(directory)}/session/${sessionID}` - void platform.notify("Response ready", session?.title ?? sessionID, href) + if (settings.notifications.agent()) { + void platform.notify("Response ready", session?.title ?? sessionID, href) + } + break } case "session.error": { @@ -111,9 +105,9 @@ export const { use: useNotification, provider: NotificationProvider } = createSi const match = sessionID ? Binary.search(syncStore.session, sessionID, (s) => s.id) : undefined const session = sessionID && match?.found ? syncStore.session[match.index] : undefined if (session?.parentID) break - try { - errorPlayer?.play() - } catch {} + + playSound(soundSrc(settings.sounds.errors())) + const error = "error" in event.properties ? event.properties.error : undefined append({ ...base, @@ -121,9 +115,13 @@ export const { use: useNotification, provider: NotificationProvider } = createSi session: sessionID ?? "global", error, }) + const description = session?.title ?? (typeof error === "string" ? error : "An error occurred") const href = sessionID ? `/${base64Encode(directory)}/session/${sessionID}` : `/${base64Encode(directory)}` - void platform.notify("Session error", description, href) + if (settings.notifications.errors()) { + void platform.notify("Session error", description, href) + } + break } } diff --git a/packages/app/src/context/settings.tsx b/packages/app/src/context/settings.tsx index 6aca57ae2..4160d1b70 100644 --- a/packages/app/src/context/settings.tsx +++ b/packages/app/src/context/settings.tsx @@ -1,5 +1,5 @@ import { createStore } from "solid-js/store" -import { createMemo } from "solid-js" +import { createEffect, createMemo } from "solid-js" import { createSimpleContext } from "@opencode-ai/ui/context" import { persisted } from "@/utils/persist" @@ -9,6 +9,12 @@ export interface NotificationSettings { errors: boolean } +export interface SoundSettings { + agent: string + permissions: string + errors: string +} + export interface Settings { general: { autoSave: boolean @@ -22,6 +28,7 @@ export interface Settings { autoApprove: boolean } notifications: NotificationSettings + sounds: SoundSettings } const defaultSettings: Settings = { @@ -37,16 +44,47 @@ const defaultSettings: Settings = { autoApprove: false, }, notifications: { - agent: false, - permissions: false, + 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<string, string> = { + "ibm-plex-mono": `"IBM Plex Mono", "IBM Plex Mono Fallback", ${monoFallback}`, + "cascadia-code": `"Cascadia Code Nerd Font", "IBM Plex Mono", "IBM Plex Mono Fallback", ${monoFallback}`, + "fira-code": `"Fira Code Nerd Font", "IBM Plex Mono", "IBM Plex Mono Fallback", ${monoFallback}`, + hack: `"Hack Nerd Font", "IBM Plex Mono", "IBM Plex Mono Fallback", ${monoFallback}`, + inconsolata: `"Inconsolata Nerd Font", "IBM Plex Mono", "IBM Plex Mono Fallback", ${monoFallback}`, + "intel-one-mono": `"Intel One Mono Nerd Font", "IBM Plex Mono", "IBM Plex Mono Fallback", ${monoFallback}`, + "jetbrains-mono": `"JetBrains Mono Nerd Font", "IBM Plex Mono", "IBM Plex Mono Fallback", ${monoFallback}`, + "meslo-lgs": `"Meslo LGS Nerd Font", "IBM Plex Mono", "IBM Plex Mono Fallback", ${monoFallback}`, + "roboto-mono": `"Roboto Mono Nerd Font", "IBM Plex Mono", "IBM Plex Mono Fallback", ${monoFallback}`, + "source-code-pro": `"Source Code Pro Nerd Font", "IBM Plex Mono", "IBM Plex Mono Fallback", ${monoFallback}`, + "ubuntu-mono": `"Ubuntu Mono Nerd Font", "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.v1", createStore<Settings>(defaultSettings)) + const [store, setStore, _, ready] = persisted("settings.v3", createStore<Settings>(defaultSettings)) + + createEffect(() => { + if (typeof document === "undefined") return + document.documentElement.style.setProperty("--font-family-mono", monoFontFamily(store.appearance?.font)) + }) return { ready, @@ -98,6 +136,20 @@ export const { use: useSettings, provider: SettingsProvider } = createSimpleCont 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) + }, + }, } }, }) |
