@@ -82,11 +82,22 @@ struct ContentView: View {
8282 @State private var isHoveringHistoryText = false
8383 @State private var isHoveringHistoryPath = false
8484 @State private var isHoveringHistoryArrow = false
85- @State private var colorScheme : ColorScheme = . light // Add state for color scheme
8685 @State private var isHoveringThemeToggle = false // Add state for theme toggle hover
8786 let timer = Timer . publish ( every: 1 , on: . main, in: . common) . autoconnect ( )
8887 let entryHeight : CGFloat = 40
8988
89+ @AppStorage ( " colorScheme " ) private var colorSchemeString : String = " auto "
90+ @Environment ( \. colorScheme) private var systemColorScheme
91+ @State private var showingThemePopover = false
92+ @State private var refreshID = UUID ( )
93+ private var currentColorScheme : ColorScheme {
94+ switch colorSchemeString {
95+ case " light " : return . light
96+ case " dark " : return . dark
97+ default : return systemColorScheme
98+ }
99+ }
100+
90101 let availableFonts = NSFontManager . shared. availableFontFamilies
91102 let standardFonts = [ " Lato-Regular " , " Arial " , " .AppleSystemUIFont " , " Times New Roman " ]
92103 let fontSizes : [ CGFloat ] = [ 16 , 18 , 20 , 22 , 24 , 26 ]
@@ -149,13 +160,6 @@ struct ContentView: View {
149160 Here's my journal entry:
150161 """
151162
152- // Initialize with saved theme preference if available
153- init ( ) {
154- // Load saved color scheme preference
155- let savedScheme = UserDefaults . standard. string ( forKey: " colorScheme " ) ?? " light "
156- _colorScheme = State ( initialValue: savedScheme == " dark " ? . dark : . light)
157- }
158-
159163 // Modify getDocumentsDirectory to use cached value
160164 private func getDocumentsDirectory( ) -> URL {
161165 return documentsDirectory
@@ -351,9 +355,9 @@ struct ContentView: View {
351355
352356 var timerColor : Color {
353357 if timerIsRunning {
354- return isHoveringTimer ? ( colorScheme == . light ? . black : . white) : . gray. opacity ( 0.8 )
358+ return isHoveringTimer ? ( currentColorScheme == . light ? . black : . white) : . gray. opacity ( 0.8 )
355359 } else {
356- return isHoveringTimer ? ( colorScheme == . light ? . black : . white) : ( colorScheme == . light ? . gray : . gray. opacity ( 0.8 ) )
360+ return isHoveringTimer ? ( currentColorScheme == . light ? . black : . white) : ( currentColorScheme == . light ? . gray : . gray. opacity ( 0.8 ) )
357361 }
358362 }
359363
@@ -372,25 +376,24 @@ struct ContentView: View {
372376 return fontSize / 2
373377 }
374378
375- // Add a color utility computed property
376379 var popoverBackgroundColor : Color {
377- return colorScheme == . light ? Color ( NSColor . controlBackgroundColor) : Color ( NSColor . darkGray)
380+ return currentColorScheme == . light ? Color ( NSColor . controlBackgroundColor) : Color ( NSColor . darkGray)
378381 }
379382
380383 var popoverTextColor : Color {
381- return colorScheme == . light ? Color . primary : Color . white
384+ return currentColorScheme == . light ? Color . primary : Color . white
382385 }
383386
384387 var body : some View {
385- let buttonBackground = colorScheme == . light ? Color . white : Color . black
388+ let buttonBackground = currentColorScheme == . light ? Color . white : Color . black
386389 let navHeight : CGFloat = 68
387- let textColor = colorScheme == . light ? Color . gray : Color . gray. opacity ( 0.8 )
388- let textHoverColor = colorScheme == . light ? Color . black : Color . white
390+ let textColor = currentColorScheme == . light ? Color . gray : Color . gray. opacity ( 0.8 )
391+ let textHoverColor = currentColorScheme == . light ? Color . black : Color . white
389392
390393 HStack ( spacing: 0 ) {
391394 // Main content
392395 ZStack {
393- Color ( colorScheme == . light ? . white : . black)
396+ Color ( currentColorScheme == . light ? . white : . black)
394397 . ignoresSafeArea ( )
395398
396399 TextEditor ( text: Binding (
@@ -404,17 +407,17 @@ struct ContentView: View {
404407 }
405408 }
406409 ) )
407- . background ( Color ( colorScheme == . light ? . white : . black) )
410+ . background ( Color ( currentColorScheme == . light ? . white : . black) )
408411 . font ( . custom( selectedFont, size: fontSize) )
409- . foregroundColor ( colorScheme == . light ? Color ( red: 0.20 , green: 0.20 , blue: 0.20 ) : Color ( red: 0.9 , green: 0.9 , blue: 0.9 ) )
412+ . foregroundColor ( currentColorScheme == . light ? Color ( red: 0.20 , green: 0.20 , blue: 0.20 ) : Color ( red: 0.9 , green: 0.9 , blue: 0.9 ) )
410413 . scrollContentBackground ( . hidden)
411414 . scrollIndicators ( . never)
412415 . lineSpacing ( lineHeight)
413416 . frame ( maxWidth: 650 )
414- . id ( " \( selectedFont) - \( fontSize) - \( colorScheme ) " )
417+ . id ( " \( selectedFont) - \( fontSize) - \( currentColorScheme ) " )
415418 . padding ( . bottom, bottomNavOpacity > 0 ? navHeight : 0 )
416419 . ignoresSafeArea ( )
417- . colorScheme ( colorScheme )
420+ . colorScheme ( currentColorScheme )
418421 . onAppear {
419422 placeholderText = placeholderOptions. randomElement ( ) ?? " \n \n Begin writing "
420423 // Removed findSubview code which was causing errors
@@ -424,7 +427,7 @@ struct ContentView: View {
424427 if text. trimmingCharacters ( in: . whitespacesAndNewlines) . isEmpty {
425428 Text ( placeholderText)
426429 . font ( . custom( selectedFont, size: fontSize) )
427- . foregroundColor ( colorScheme == . light ? . gray. opacity ( 0.5 ) : . gray. opacity ( 0.6 ) )
430+ . foregroundColor ( currentColorScheme == . light ? . gray. opacity ( 0.5 ) : . gray. opacity ( 0.6 ) )
428431 // .padding(.top, 8)
429432 // .padding(.leading, 8)
430433 . allowsHitTesting ( false )
@@ -724,12 +727,13 @@ struct ContentView: View {
724727
725728 // Theme toggle button
726729 Button ( action: {
727- colorScheme = colorScheme == . light ? . dark : . light
728- // Save preference
729- UserDefaults . standard. set ( colorScheme == . light ? " light " : " dark " , forKey: " colorScheme " )
730+ showingThemePopover = true
730731 } ) {
731- Image ( systemName: colorScheme == . light ? " moon.fill " : " sun.max.fill " )
732+ let theme = AppColorScheme ( rawValue: colorSchemeString) ?? . auto
733+ Image ( systemName: theme. systemImage)
734+ . frame ( width: 18 ) // If you remove this, there will be flickering in the width of the bar.
732735 . foregroundColor ( isHoveringThemeToggle ? textHoverColor : textColor)
736+ . animation ( . easeInOut( duration: 0.3 ) , value: colorSchemeString)
733737 }
734738 . buttonStyle ( . plain)
735739 . onHover { hovering in
@@ -741,6 +745,39 @@ struct ContentView: View {
741745 NSCursor . pop ( )
742746 }
743747 }
748+ . popover ( isPresented: $showingThemePopover, attachmentAnchor: . point( UnitPoint ( x: 0.5 , y: 0 ) ) , arrowEdge: . top) {
749+ VStack ( spacing: 0 ) {
750+ ForEach ( [ " light " , " dark " , " auto " ] , id: \. self) { themeValue in
751+ let theme = AppColorScheme ( rawValue: themeValue) ?? . auto
752+ Button ( action: {
753+ withAnimation ( . easeInOut( duration: 0.3 ) ) {
754+ colorSchemeString = themeValue
755+ }
756+ showingThemePopover = false
757+ } ) {
758+ HStack {
759+ Image ( systemName: theme. systemImage)
760+ . frame ( width: 20 )
761+ Text ( theme. displayName)
762+ . frame ( maxWidth: . infinity, alignment: . leading)
763+ }
764+ . padding ( . horizontal, 12 )
765+ . padding ( . vertical, 8 )
766+ . background ( colorSchemeString == themeValue ? Color . gray. opacity ( 0.2 ) : Color . clear)
767+ . cornerRadius ( 4 )
768+ }
769+ . buttonStyle ( . plain)
770+ . foregroundColor ( popoverTextColor)
771+
772+ if themeValue != " auto " {
773+ Divider ( )
774+ }
775+ }
776+ }
777+ . background ( popoverBackgroundColor)
778+ . cornerRadius ( 8 )
779+ . shadow ( color: Color . black. opacity ( 0.1 ) , radius: 4 , y: 2 )
780+ }
744781
745782 Text ( " • " )
746783 . foregroundColor ( . gray)
@@ -772,7 +809,7 @@ struct ContentView: View {
772809 }
773810 }
774811 . padding ( )
775- . background ( Color ( colorScheme == . light ? . white : . black) )
812+ . background ( Color ( currentColorScheme == . light ? . white : . black) )
776813 . opacity ( bottomNavOpacity)
777814 . onHover { hovering in
778815 isHoveringBottomNav = hovering
@@ -861,8 +898,8 @@ struct ContentView: View {
861898 Image ( systemName: " arrow.down.circle " )
862899 . font ( . system( size: 11 ) )
863900 . foregroundColor ( hoveredExportId == entry. id ?
864- ( colorScheme == . light ? . black : . white) :
865- ( colorScheme == . light ? . gray : . gray. opacity ( 0.8 ) ) )
901+ ( currentColorScheme == . light ? . black : . white) :
902+ ( currentColorScheme == . light ? . gray : . gray. opacity ( 0.8 ) ) )
866903 }
867904 . buttonStyle ( . plain)
868905 . help ( " Export entry as PDF " )
@@ -934,12 +971,12 @@ struct ContentView: View {
934971 . scrollIndicators ( . never)
935972 }
936973 . frame ( width: 200 )
937- . background ( Color ( colorScheme == . light ? . white : NSColor . black) )
974+ . background ( Color ( currentColorScheme == . light ? . white : NSColor . black) )
938975 }
939976 }
940977 . frame ( minWidth: 1100 , minHeight: 600 )
941978 . animation ( . easeInOut( duration: 0.2 ) , value: showingSidebar)
942- . preferredColorScheme ( colorScheme )
979+ . preferredColorScheme ( currentColorScheme )
943980 . onAppear {
944981 showingSidebar = false // Hide sidebar by default
945982 loadExistingEntries ( )
@@ -1305,4 +1342,4 @@ extension NSView {
13051342
13061343#Preview {
13071344 ContentView ( )
1308- }
1345+ }
0 commit comments