@@ -18,6 +18,8 @@ import { Toggle } from "~/components/Toggle";
1818import { defaultCaptionSettings } from "~/store/captions" ;
1919import type { CaptionSettings } from "~/utils/tauri" ;
2020import { commands , events } from "~/utils/tauri" ;
21+ import IconCapChevronDown from "~icons/cap/chevron-down" ;
22+ import IconCapCircleCheck from "~icons/cap/circle-check" ;
2123import IconLucideCheck from "~icons/lucide/check" ;
2224import IconLucideDownload from "~icons/lucide/download" ;
2325import { useEditorContext } from "./context" ;
@@ -31,6 +33,7 @@ import {
3133 Slider ,
3234 Subfield ,
3335 topLeftAnimateClasses ,
36+ topSlideAnimateClasses ,
3437} from "./ui" ;
3538
3639interface ModelOption {
@@ -273,16 +276,24 @@ export function CaptionsTab() {
273276 ) ;
274277
275278 createEffect (
276- on ( selectedModel , ( model ) => {
277- if ( model ) localStorage . setItem ( "selectedTranscriptionModel" , model ) ;
278- } ) ,
279+ on (
280+ selectedModel ,
281+ ( model ) => {
282+ if ( model ) localStorage . setItem ( "selectedTranscriptionModel" , model ) ;
283+ } ,
284+ { defer : true } ,
285+ ) ,
279286 ) ;
280287
281288 createEffect (
282- on ( selectedLanguage , ( language ) => {
283- if ( language )
284- localStorage . setItem ( "selectedTranscriptionLanguage" , language ) ;
285- } ) ,
289+ on (
290+ selectedLanguage ,
291+ ( language ) => {
292+ if ( language )
293+ localStorage . setItem ( "selectedTranscriptionLanguage" , language ) ;
294+ } ,
295+ { defer : true } ,
296+ ) ,
286297 ) ;
287298
288299 const checkModelExists = async ( modelName : string ) => {
@@ -778,32 +789,71 @@ export function CaptionsTab() {
778789 </ div >
779790 </ Field >
780791
781- < Field name = "Style Options" icon = { < IconCapMessageBubble /> } >
782- < div class = "space-y-3" >
783- < div class = "flex flex-col gap-4" >
784- < Subfield name = "Outline" >
785- < Toggle
786- checked = { getSetting ( "outline" ) }
787- onChange = { ( checked ) =>
788- updateCaptionSetting ( "outline" , checked )
789- }
790- disabled = { ! hasCaptions ( ) }
791- />
792- </ Subfield >
793- </ div >
794-
795- < Show when = { getSetting ( "outline" ) } >
796- < div class = "flex flex-col gap-2" >
797- < span class = "text-gray-11 text-sm" > Outline Color</ span >
798- < RgbInput
799- value = { getSetting ( "outlineColor" ) }
800- onChange = { ( value ) =>
801- updateCaptionSetting ( "outlineColor" , value )
802- }
792+ < Field name = "Font Weight" icon = { < IconCapMessageBubble /> } >
793+ < KSelect
794+ options = { [
795+ { label : "Normal" , value : 400 } ,
796+ { label : "Medium" , value : 500 } ,
797+ { label : "Bold" , value : 700 } ,
798+ ] }
799+ optionValue = "value"
800+ optionTextValue = "label"
801+ value = { {
802+ label : "Custom" ,
803+ value : getSetting ( "fontWeight" ) ,
804+ } }
805+ onChange = { ( value ) => {
806+ if ( ! value ) return ;
807+ updateCaptionSetting ( "fontWeight" , value . value ) ;
808+ } }
809+ disabled = { ! hasCaptions ( ) }
810+ itemComponent = { ( selectItemProps ) => (
811+ < MenuItem < typeof KSelect . Item >
812+ as = { KSelect . Item }
813+ item = { selectItemProps . item }
814+ >
815+ < KSelect . ItemLabel class = "flex-1" >
816+ { selectItemProps . item . rawValue . label }
817+ </ KSelect . ItemLabel >
818+ < KSelect . ItemIndicator class = "ml-auto text-blue-9" >
819+ < IconCapCircleCheck />
820+ </ KSelect . ItemIndicator >
821+ </ MenuItem >
822+ ) }
823+ >
824+ < KSelect . Trigger class = "flex w-full items-center justify-between rounded-md border border-gray-3 bg-gray-2 px-3 py-2 text-sm text-gray-12 transition-colors hover:border-gray-4 hover:bg-gray-3 focus:border-blue-9 focus:outline-none focus:ring-1 focus:ring-blue-9" >
825+ < KSelect . Value < {
826+ label : string ;
827+ value : number ;
828+ } > class = "truncate" >
829+ { ( state ) => {
830+ const selected = state . selectedOption ( ) ;
831+ if ( selected ) return selected . label ;
832+ const weight = getSetting ( "fontWeight" ) ;
833+ const option = [
834+ { label : "Normal" , value : 400 } ,
835+ { label : "Medium" , value : 500 } ,
836+ { label : "Bold" , value : 700 } ,
837+ ] . find ( ( o ) => o . value === weight ) ;
838+ return option ? option . label : "Bold" ;
839+ } }
840+ </ KSelect . Value >
841+ < KSelect . Icon >
842+ < IconCapChevronDown class = "size-4 shrink-0 transform transition-transform ui-expanded:rotate-180 text-[--gray-500]" />
843+ </ KSelect . Icon >
844+ </ KSelect . Trigger >
845+ < KSelect . Portal >
846+ < PopperContent < typeof KSelect . Content >
847+ as = { KSelect . Content }
848+ class = { cx ( topSlideAnimateClasses , "z-50" ) }
849+ >
850+ < MenuItemList < typeof KSelect . Listbox >
851+ class = "overflow-y-auto max-h-40"
852+ as = { KSelect . Listbox }
803853 />
804- </ div >
805- </ Show >
806- </ div >
854+ </ PopperContent >
855+ </ KSelect . Portal >
856+ </ KSelect >
807857 </ Field >
808858
809859 < Field name = "Export Options" icon = { < IconCapMessageBubble /> } >
0 commit comments