1- import { Component , Show , createMemo , createResource , type JSX } from "solid-js"
1+ import { Component , Show , createMemo , createResource , onMount , type JSX } from "solid-js"
22import { createStore } from "solid-js/store"
33import { Button } from "@opencode-ai/ui/button"
44import { Icon } from "@opencode-ai/ui/icon"
55import { Select } from "@opencode-ai/ui/select"
66import { Switch } from "@opencode-ai/ui/switch"
77import { Tooltip } from "@opencode-ai/ui/tooltip"
8- import { useTheme , type ColorScheme } from "@opencode-ai/ui/theme"
8+ import { useTheme , type ColorScheme } from "@opencode-ai/ui/theme/context "
99import { showToast } from "@opencode-ai/ui/toast"
1010import { useLanguage } from "@/context/language"
1111import { usePlatform } from "@/context/platform"
1212import { useSettings , monoFontFamily } from "@/context/settings"
13- import { playSound , SOUND_OPTIONS } from "@/utils/sound"
13+ import { playSoundById , SOUND_OPTIONS } from "@/utils/sound"
1414import { Link } from "./link"
1515import { SettingsList } from "./settings-list"
1616
1717let demoSoundState = {
1818 cleanup : undefined as ( ( ) => void ) | undefined ,
1919 timeout : undefined as NodeJS . Timeout | undefined ,
20+ run : 0 ,
21+ }
22+
23+ type ThemeOption = {
24+ id : string
25+ name : string
26+ }
27+
28+ let font : Promise < typeof import ( "@opencode-ai/ui/font-loader" ) > | undefined
29+
30+ function loadFont ( ) {
31+ font ??= import ( "@opencode-ai/ui/font-loader" )
32+ return font
2033}
2134
2235// To prevent audio from overlapping/playing very quickly when navigating the settings menus,
2336// delay the playback by 100ms during quick selection changes and pause existing sounds.
2437const stopDemoSound = ( ) => {
38+ demoSoundState . run += 1
2539 if ( demoSoundState . cleanup ) {
2640 demoSoundState . cleanup ( )
2741 }
2842 clearTimeout ( demoSoundState . timeout )
2943 demoSoundState . cleanup = undefined
3044}
3145
32- const playDemoSound = ( src : string | undefined ) => {
46+ const playDemoSound = ( id : string | undefined ) => {
3347 stopDemoSound ( )
34- if ( ! src ) return
48+ if ( ! id ) return
3549
50+ const run = ++ demoSoundState . run
3651 demoSoundState . timeout = setTimeout ( ( ) => {
37- demoSoundState . cleanup = playSound ( src )
52+ void playSoundById ( id ) . then ( ( cleanup ) => {
53+ if ( demoSoundState . run !== run ) {
54+ cleanup ?.( )
55+ return
56+ }
57+ demoSoundState . cleanup = cleanup
58+ } )
3859 } , 100 )
3960}
4061
@@ -44,6 +65,10 @@ export const SettingsGeneral: Component = () => {
4465 const platform = usePlatform ( )
4566 const settings = useSettings ( )
4667
68+ onMount ( ( ) => {
69+ void theme . loadThemes ( )
70+ } )
71+
4772 const [ store , setStore ] = createStore ( {
4873 checking : false ,
4974 } )
@@ -104,9 +129,7 @@ export const SettingsGeneral: Component = () => {
104129 . finally ( ( ) => setStore ( "checking" , false ) )
105130 }
106131
107- const themeOptions = createMemo ( ( ) =>
108- Object . entries ( theme . themes ( ) ) . map ( ( [ id , def ] ) => ( { id, name : def . name ?? id } ) ) ,
109- )
132+ const themeOptions = createMemo < ThemeOption [ ] > ( ( ) => theme . ids ( ) . map ( ( id ) => ( { id, name : theme . name ( id ) } ) ) )
110133
111134 const colorSchemeOptions = createMemo ( ( ) : { value : ColorScheme ; label : string } [ ] => [
112135 { value : "system" , label : language . t ( "theme.scheme.system" ) } ,
@@ -143,7 +166,7 @@ export const SettingsGeneral: Component = () => {
143166 ] as const
144167 const fontOptionsList = [ ...fontOptions ]
145168
146- const noneSound = { id : "none" , label : "sound.option.none" , src : undefined } as const
169+ const noneSound = { id : "none" , label : "sound.option.none" } as const
147170 const soundOptions = [ noneSound , ...SOUND_OPTIONS ]
148171
149172 const soundSelectProps = (
@@ -158,7 +181,7 @@ export const SettingsGeneral: Component = () => {
158181 label : ( o : ( typeof soundOptions ) [ number ] ) => language . t ( o . label ) ,
159182 onHighlight : ( option : ( typeof soundOptions ) [ number ] | undefined ) => {
160183 if ( ! option ) return
161- playDemoSound ( option . src )
184+ playDemoSound ( option . id === "none" ? undefined : option . id )
162185 } ,
163186 onSelect : ( option : ( typeof soundOptions ) [ number ] | undefined ) => {
164187 if ( ! option ) return
@@ -169,7 +192,7 @@ export const SettingsGeneral: Component = () => {
169192 }
170193 setEnabled ( true )
171194 set ( option . id )
172- playDemoSound ( option . src )
195+ playDemoSound ( option . id )
173196 } ,
174197 variant : "secondary" as const ,
175198 size : "small" as const ,
@@ -321,6 +344,9 @@ export const SettingsGeneral: Component = () => {
321344 current = { fontOptionsList . find ( ( o ) => o . value === settings . appearance . font ( ) ) }
322345 value = { ( o ) => o . value }
323346 label = { ( o ) => language . t ( o . label ) }
347+ onHighlight = { ( option ) => {
348+ void loadFont ( ) . then ( ( x ) => x . ensureMonoFont ( option ?. value ) )
349+ } }
324350 onSelect = { ( option ) => option && settings . appearance . setFont ( option . value ) }
325351 variant = "secondary"
326352 size = "small"
0 commit comments