@@ -55,9 +55,10 @@ pub struct RootView {
5555 selected : Option < usize > ,
5656 schema_mode : bool ,
5757 sidebar_open : bool ,
58+ show_preferences : bool ,
5859 /// `Some(true)` = force dark, `Some(false)` = light, `None` = follow OS.
5960 dark_override : Option < bool > ,
60- /// Label typeface + size for canvas labels (sidebar preferences ).
61+ /// Label typeface + size for canvas labels (Preferences window ).
6162 label_font : String ,
6263 label_font_size : f32 ,
6364 /// Effective dark state from the last render — the theme toggle flips
@@ -86,7 +87,9 @@ impl RootView {
8687 /// the scanned directory, positional files are appended (first valid one
8788 /// is selected), plus `--limit` / `--schema` overrides.
8889 pub fn with_cli ( opts : & CliOptions , cx : & mut Context < Self > ) -> Self {
90+ // Canonicalize so the sidebar shows a real path, never a bare ".".
8991 let db_dir = opts. db_dir . clone ( ) . unwrap_or_else ( backend:: default_db_dir) ;
92+ let db_dir = db_dir. canonicalize ( ) . unwrap_or ( db_dir) ;
9093 let mut databases = backend:: scan_for_databases ( & db_dir) ;
9194 for file in & opts. files {
9295 if !file. is_file ( ) {
@@ -128,6 +131,7 @@ impl RootView {
128131 selected : None ,
129132 schema_mode : opts. schema_mode ,
130133 sidebar_open : false ,
134+ show_preferences : false ,
131135 dark_override : None ,
132136 label_font : ".SystemUIFont" . to_string ( ) ,
133137 label_font_size : 11.0 ,
@@ -270,6 +274,21 @@ impl RootView {
270274 cx. notify ( ) ;
271275 }
272276
277+ pub fn toggle_preferences ( & mut self , cx : & mut Context < Self > ) {
278+ self . show_preferences = !self . show_preferences ;
279+ cx. notify ( ) ;
280+ }
281+
282+ /// Friendly display name: the default family starts with a literal
283+ /// dot, which reads as a stray glyph in UI text.
284+ pub fn label_font_display ( & self ) -> & str {
285+ self . label_font
286+ . trim_start_matches ( '.' )
287+ . split ( ' ' )
288+ . next ( )
289+ . unwrap_or ( & self . label_font )
290+ }
291+
273292 pub fn set_label_font ( & mut self , name : & str , cx : & mut Context < Self > ) {
274293 self . label_font = name. to_string ( ) ;
275294 cx. notify ( ) ;
@@ -655,78 +674,6 @@ impl RootView {
655674 . child ( d. name . clone ( ) ) ,
656675 ) ;
657676 }
658- col = col
659- . child ( div ( ) . pt_2 ( ) . font_weight ( FontWeight :: BOLD ) . child ( "Labels" ) )
660- . child ( div ( ) . text_xs ( ) . child ( format ! (
661- "{} · {:.0}pt" ,
662- self . label_font, self . label_font_size
663- ) ) ) ;
664- {
665- let mut row = div ( ) . flex ( ) . flex_row ( ) . flex_wrap ( ) . gap_1 ( ) ;
666- for name in [ ".SystemUIFont" , "Helvetica Neue" , "Menlo" , "Georgia" ] {
667- let active = self . label_font == name;
668- let short = name
669- . trim_start_matches ( '.' )
670- . split ( ' ' )
671- . next ( )
672- . unwrap_or ( name) ;
673- let name_owned = name. to_string ( ) ;
674- row = row. child (
675- div ( )
676- . px_2 ( )
677- . py ( px ( 2. ) )
678- . rounded_md ( )
679- . cursor_pointer ( )
680- . text_xs ( )
681- . bg ( if active { theme. accent } else { theme. surface } )
682- . hover ( |s| s. bg ( theme. selection ) )
683- . on_mouse_down (
684- MouseButton :: Left ,
685- cx. listener ( move |view, _, _, cx| {
686- view. set_label_font ( & name_owned. clone ( ) , cx) ;
687- } ) ,
688- )
689- . child ( short. to_string ( ) ) ,
690- ) ;
691- }
692- col = col. child ( row) ;
693- }
694- {
695- let size_row = div ( )
696- . flex ( )
697- . flex_row ( )
698- . items_center ( )
699- . gap_1 ( )
700- . child (
701- div ( )
702- . px_2 ( )
703- . py ( px ( 2. ) )
704- . rounded_md ( )
705- . cursor_pointer ( )
706- . bg ( theme. surface )
707- . hover ( |s| s. bg ( theme. selection ) )
708- . on_mouse_down (
709- MouseButton :: Left ,
710- cx. listener ( |view, _, _, cx| view. bump_label_font_size ( -1.0 , cx) ) ,
711- )
712- . child ( "A−" ) ,
713- )
714- . child (
715- div ( )
716- . px_2 ( )
717- . py ( px ( 2. ) )
718- . rounded_md ( )
719- . cursor_pointer ( )
720- . bg ( theme. surface )
721- . hover ( |s| s. bg ( theme. selection ) )
722- . on_mouse_down (
723- MouseButton :: Left ,
724- cx. listener ( |view, _, _, cx| view. bump_label_font_size ( 1.0 , cx) ) ,
725- )
726- . child ( "A+" ) ,
727- ) ;
728- col = col. child ( size_row) ;
729- }
730677 col = col
731678 . child ( div ( ) . pt_2 ( ) . font_weight ( FontWeight :: BOLD ) . child ( "Matches" ) )
732679 . child ( div ( ) . text_xs ( ) . child ( format ! (
@@ -965,6 +912,7 @@ impl Render for RootView {
965912 . flex ( )
966913 . flex_col ( )
967914 . size_full ( )
915+ . relative ( )
968916 . bg ( theme. background )
969917 . text_color ( theme. foreground )
970918 . child ( self . render_header ( theme, cx) )
@@ -1089,6 +1037,133 @@ impl Render for RootView {
10891037 . child ( query_content) ,
10901038 ) ,
10911039 )
1040+ . children ( self . render_preferences_modal ( theme, cx) )
1041+ }
1042+ }
1043+
1044+ impl RootView {
1045+ /// Native-style Preferences panel (app menu → Preferences…, ⌘,): a
1046+ /// centered modal with the label typeface + size controls. Rendered on
1047+ /// every platform from the same menu entry.
1048+ fn render_preferences_modal ( & mut self , theme : Theme , cx : & mut Context < Self > ) -> Option < Div > {
1049+ if !self . show_preferences {
1050+ return None ;
1051+ }
1052+ let mut chips = div ( ) . flex ( ) . flex_row ( ) . flex_wrap ( ) . gap_1 ( ) ;
1053+ for name in [ ".SystemUIFont" , "Helvetica Neue" , "Menlo" , "Georgia" ] {
1054+ let active = self . label_font == name;
1055+ let short = name
1056+ . trim_start_matches ( '.' )
1057+ . split ( ' ' )
1058+ . next ( )
1059+ . unwrap_or ( name) ;
1060+ let name_owned = name. to_string ( ) ;
1061+ chips = chips. child (
1062+ div ( )
1063+ . px_2 ( )
1064+ . py ( px ( 2. ) )
1065+ . rounded_md ( )
1066+ . cursor_pointer ( )
1067+ . text_xs ( )
1068+ . bg ( if active { theme. accent } else { theme. surface } )
1069+ . hover ( |s| s. bg ( theme. selection ) )
1070+ . on_mouse_down (
1071+ MouseButton :: Left ,
1072+ cx. listener ( move |view, _, _, cx| {
1073+ view. set_label_font ( & name_owned. clone ( ) , cx) ;
1074+ } ) ,
1075+ )
1076+ . child ( short. to_string ( ) ) ,
1077+ ) ;
1078+ }
1079+ let panel = div ( )
1080+ . w ( px ( 360. ) )
1081+ . rounded_lg ( )
1082+ . bg ( theme. surface )
1083+ . border_1 ( )
1084+ . border_color ( theme. border )
1085+ . text_color ( theme. foreground )
1086+ . p_4 ( )
1087+ . flex ( )
1088+ . flex_col ( )
1089+ . gap_2 ( )
1090+ . child (
1091+ div ( )
1092+ . text_lg ( )
1093+ . font_weight ( FontWeight :: BOLD )
1094+ . child ( "Preferences" ) ,
1095+ )
1096+ . child ( div ( ) . font_weight ( FontWeight :: BOLD ) . child ( "Label font" ) )
1097+ . child ( div ( ) . text_xs ( ) . text_color ( theme. secondary ) . child ( format ! (
1098+ "{} · {:.0}pt" ,
1099+ self . label_font_display( ) ,
1100+ self . label_font_size
1101+ ) ) )
1102+ . child ( chips)
1103+ . child (
1104+ div ( )
1105+ . flex ( )
1106+ . flex_row ( )
1107+ . items_center ( )
1108+ . gap_1 ( )
1109+ . child (
1110+ div ( )
1111+ . px_2 ( )
1112+ . py ( px ( 2. ) )
1113+ . rounded_md ( )
1114+ . cursor_pointer ( )
1115+ . bg ( theme. inset )
1116+ . hover ( |s| s. bg ( theme. selection ) )
1117+ . on_mouse_down (
1118+ MouseButton :: Left ,
1119+ cx. listener ( |view, _, _, cx| view. bump_label_font_size ( -1.0 , cx) ) ,
1120+ )
1121+ . child ( "A−" ) ,
1122+ )
1123+ . child ( format ! ( "{:.0}pt" , self . label_font_size) )
1124+ . child (
1125+ div ( )
1126+ . px_2 ( )
1127+ . py ( px ( 2. ) )
1128+ . rounded_md ( )
1129+ . cursor_pointer ( )
1130+ . bg ( theme. inset )
1131+ . hover ( |s| s. bg ( theme. selection ) )
1132+ . on_mouse_down (
1133+ MouseButton :: Left ,
1134+ cx. listener ( |view, _, _, cx| view. bump_label_font_size ( 1.0 , cx) ) ,
1135+ )
1136+ . child ( "A+" ) ,
1137+ ) ,
1138+ )
1139+ . child (
1140+ div ( ) . flex ( ) . flex_row ( ) . justify_end ( ) . child (
1141+ div ( )
1142+ . px_3 ( )
1143+ . py_1 ( )
1144+ . rounded_md ( )
1145+ . cursor_pointer ( )
1146+ . bg ( theme. accent )
1147+ . hover ( |s| s. bg ( theme. selection ) )
1148+ . on_mouse_down (
1149+ MouseButton :: Left ,
1150+ cx. listener ( |view, _, _, cx| view. toggle_preferences ( cx) ) ,
1151+ )
1152+ . child ( "Close" ) ,
1153+ ) ,
1154+ ) ;
1155+ Some (
1156+ div ( )
1157+ . absolute ( )
1158+ . top ( px ( 0. ) )
1159+ . left ( px ( 0. ) )
1160+ . size_full ( )
1161+ . flex ( )
1162+ . items_center ( )
1163+ . justify_center ( )
1164+ . bg ( black ( ) . opacity ( 0.45 ) )
1165+ . child ( panel) ,
1166+ )
10921167 }
10931168}
10941169
0 commit comments