diff options
| author | Joseph Campuzano <[email protected]> | 2026-01-24 12:16:53 -0600 |
|---|---|---|
| committer | GitHub <[email protected]> | 2026-01-24 12:16:53 -0600 |
| commit | 15801a01ba6b5d8957a546df6832894b7e92be6a (patch) | |
| tree | d320899a4703594182c1d3161eb3de775520a9bc | |
| parent | 32e6bcae3ba50d0c453c0de7d2e103830dd69a3f (diff) | |
| download | opencode-15801a01ba6b5d8957a546df6832894b7e92be6a.tar.gz opencode-15801a01ba6b5d8957a546df6832894b7e92be6a.zip | |
fix: add state to pause existing audio for demo menus, add support fo… (#10428)
| -rw-r--r-- | packages/app/src/components/settings-general.tsx | 32 | ||||
| -rw-r--r-- | packages/app/src/utils/sound.ts | 9 | ||||
| -rw-r--r-- | packages/ui/src/components/select.tsx | 1 |
3 files changed, 35 insertions, 7 deletions
diff --git a/packages/app/src/components/settings-general.tsx b/packages/app/src/components/settings-general.tsx index 75acf4f74..272aeb314 100644 --- a/packages/app/src/components/settings-general.tsx +++ b/packages/app/src/components/settings-general.tsx @@ -7,6 +7,26 @@ import { useSettings, monoFontFamily } from "@/context/settings" import { playSound, SOUND_OPTIONS } from "@/utils/sound" import { Link } from "./link" + +let demoSoundState = { + cleanup: undefined as (() => void) | undefined, + timeout: undefined as NodeJS.Timeout | undefined, +} + +// To prevent audio from overlapping/playing very quickly when navigating the settings menus, +// delay the playback by 100ms during quick selection changes and pause existing sounds. +const playDemoSound = (src: string) => { + if (demoSoundState.cleanup) { + demoSoundState.cleanup(); + } + + clearTimeout(demoSoundState.timeout) + + demoSoundState.timeout = setTimeout(() => { + demoSoundState.cleanup = playSound(src) + }, 100) +} + export const SettingsGeneral: Component = () => { const theme = useTheme() const language = useLanguage() @@ -211,12 +231,12 @@ export const SettingsGeneral: Component = () => { label={(o) => language.t(o.label)} onHighlight={(option) => { if (!option) return - playSound(option.src) + playDemoSound(option.src) }} onSelect={(option) => { if (!option) return settings.sounds.setAgent(option.id) - playSound(option.src) + playDemoSound(option.src) }} variant="secondary" size="small" @@ -235,12 +255,12 @@ export const SettingsGeneral: Component = () => { label={(o) => language.t(o.label)} onHighlight={(option) => { if (!option) return - playSound(option.src) + playDemoSound(option.src) }} onSelect={(option) => { if (!option) return settings.sounds.setPermissions(option.id) - playSound(option.src) + playDemoSound(option.src) }} variant="secondary" size="small" @@ -259,12 +279,12 @@ export const SettingsGeneral: Component = () => { label={(o) => language.t(o.label)} onHighlight={(option) => { if (!option) return - playSound(option.src) + playDemoSound(option.src) }} onSelect={(option) => { if (!option) return settings.sounds.setErrors(option.id) - playSound(option.src) + playDemoSound(option.src) }} variant="secondary" size="small" diff --git a/packages/app/src/utils/sound.ts b/packages/app/src/utils/sound.ts index d5e606c67..6dea812ec 100644 --- a/packages/app/src/utils/sound.ts +++ b/packages/app/src/utils/sound.ts @@ -106,5 +106,12 @@ export function soundSrc(id: string | undefined) { export function playSound(src: string | undefined) { if (typeof Audio === "undefined") return if (!src) return - void new Audio(src).play().catch(() => undefined) + const audio = new Audio(src) + audio.play().catch(() => undefined) + + // Return a cleanup function to pause the sound. + return () => { + audio.pause() + audio.currentTime = 0 + } } diff --git a/packages/ui/src/components/select.tsx b/packages/ui/src/components/select.tsx index b83f5f463..0386c329e 100644 --- a/packages/ui/src/components/select.tsx +++ b/packages/ui/src/components/select.tsx @@ -105,6 +105,7 @@ export function Select<T>(props: SelectProps<T> & Omit<ButtonProps, "children">) }} onPointerEnter={() => move(itemProps.item.rawValue)} onPointerMove={() => move(itemProps.item.rawValue)} + onFocus={() => move(itemProps.item.rawValue)} > <Kobalte.ItemLabel data-slot="select-select-item-label"> {local.children |
