diff --git a/CHANGELOG.md b/CHANGELOG.md index d1ed379..10b3f38 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 remove icons (the picker reflects the change the next time it opens), and your edits survive app updates. Delete it to restore the default set. +### Fixed +- **Window caption buttons invisible in Light theme.** The minimise, maximise and + close glyphs were always white, leaving them barely visible against the light + title bar. They now take a theme-appropriate colour, update when you switch + theme, and follow the OS when the theme is set to System. + ### Changed - **Home, navigation and shared-parameters polish.** The Home page leads with a full-bleed hero banner (drop `Assets/HomeHero.png` to supply the image), the diff --git a/src/Snipdeck.App/MainWindow.xaml.cs b/src/Snipdeck.App/MainWindow.xaml.cs index a49e386..ad59330 100644 --- a/src/Snipdeck.App/MainWindow.xaml.cs +++ b/src/Snipdeck.App/MainWindow.xaml.cs @@ -35,6 +35,14 @@ public MainWindow(AppConfig config, ShellPage shellPage) ShellHost.Content = shellPage; ApplyTheme(config.Theme); + + // While on System theme, the caption buttons must follow an OS + // light/dark flip too — RequestedTheme stays Default, so only + // ActualTheme changes. + if (Content is FrameworkElement themedRoot) + { + themedRoot.ActualThemeChanged += (sender, _) => UpdateCaptionButtonColours(sender.ActualTheme); + } } // The title-bar switcher and snip search bind to the shell view model. @@ -129,18 +137,61 @@ private void OnSearchQuerySubmitted(AutoSuggestBox sender, AutoSuggestBoxQuerySu } } - private void ApplyTheme(ThemePreference theme) + /// + /// Applies the chosen theme to the app content and the system caption + /// buttons. Public so the runtime theme applier routes through here, + /// keeping the window content and the min/max/close glyphs in step. + /// + public void ApplyTheme(ThemePreference theme) { - if (Content is FrameworkElement root) + if (Content is not FrameworkElement root) { - root.RequestedTheme = theme switch - { - ThemePreference.Light => ElementTheme.Light, - ThemePreference.Dark => ElementTheme.Dark, - ThemePreference.System => ElementTheme.Default, - _ => ElementTheme.Default, - }; + return; } + + root.RequestedTheme = theme switch + { + ThemePreference.Light => ElementTheme.Light, + ThemePreference.Dark => ElementTheme.Dark, + ThemePreference.System => ElementTheme.Default, + _ => ElementTheme.Default, + }; + + // ActualTheme resolves Default to the OS light/dark choice, so the + // caption glyphs get a concrete theme to contrast against. + UpdateCaptionButtonColours(root.ActualTheme); + } + + // The caption buttons are system-drawn chrome, not styled by the app's + // theme resources — so without this they keep their default (white) + // glyphs and vanish on a light background. Backgrounds stay transparent + // so the Mica backdrop shows through; only the glyph colours change. + private void UpdateCaptionButtonColours(ElementTheme actualTheme) + { + var dark = actualTheme == ElementTheme.Dark; + + var foreground = dark + ? Microsoft.UI.Colors.White + : Windows.UI.Color.FromArgb(0xFF, 0x1A, 0x1A, 0x1A); + var inactive = dark + ? Windows.UI.Color.FromArgb(0xFF, 0x80, 0x80, 0x80) + : Windows.UI.Color.FromArgb(0xFF, 0x8A, 0x8A, 0x8A); + var hoverBackground = dark + ? Windows.UI.Color.FromArgb(0x1F, 0xFF, 0xFF, 0xFF) + : Windows.UI.Color.FromArgb(0x14, 0x00, 0x00, 0x00); + var pressedBackground = dark + ? Windows.UI.Color.FromArgb(0x12, 0xFF, 0xFF, 0xFF) + : Windows.UI.Color.FromArgb(0x0A, 0x00, 0x00, 0x00); + + var titleBar = AppWindow.TitleBar; + titleBar.ButtonBackgroundColor = Microsoft.UI.Colors.Transparent; + titleBar.ButtonInactiveBackgroundColor = Microsoft.UI.Colors.Transparent; + titleBar.ButtonForegroundColor = foreground; + titleBar.ButtonHoverForegroundColor = foreground; + titleBar.ButtonHoverBackgroundColor = hoverBackground; + titleBar.ButtonPressedForegroundColor = foreground; + titleBar.ButtonPressedBackgroundColor = pressedBackground; + titleBar.ButtonInactiveForegroundColor = inactive; } } } diff --git a/src/Snipdeck.App/Services/WindowsThemeApplier.cs b/src/Snipdeck.App/Services/WindowsThemeApplier.cs index f91346f..3051734 100644 --- a/src/Snipdeck.App/Services/WindowsThemeApplier.cs +++ b/src/Snipdeck.App/Services/WindowsThemeApplier.cs @@ -1,5 +1,3 @@ -using Microsoft.UI.Xaml; - using Snipdeck.Core.Abstractions; using Snipdeck.Core.Models; @@ -17,17 +15,10 @@ public WindowsThemeApplier(IServiceProvider services) public void Apply(ThemePreference theme) { + // Route through the window so the content and the system caption + // buttons are themed together (see MainWindow.ApplyTheme). var mainWindow = (MainWindow?)_services.GetService(typeof(MainWindow)); - if (mainWindow?.Content is FrameworkElement root) - { - root.RequestedTheme = theme switch - { - ThemePreference.Light => ElementTheme.Light, - ThemePreference.Dark => ElementTheme.Dark, - ThemePreference.System => ElementTheme.Default, - _ => ElementTheme.Default, - }; - } + mainWindow?.ApplyTheme(theme); } } }