summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorJoseph Campuzano <[email protected]>2026-01-24 12:16:53 -0600
committerGitHub <[email protected]>2026-01-24 12:16:53 -0600
commit15801a01ba6b5d8957a546df6832894b7e92be6a (patch)
treed320899a4703594182c1d3161eb3de775520a9bc
parent32e6bcae3ba50d0c453c0de7d2e103830dd69a3f (diff)
downloadopencode-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.tsx32
-rw-r--r--packages/app/src/utils/sound.ts9
-rw-r--r--packages/ui/src/components/select.tsx1
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