Skip to content

feat(theme): Fluent foundation — system Light/Dark + brand palette across all windows - #33

Merged
aksOps merged 16 commits into
mainfrom
worktree-fluent-foundation
Aug 14, 2026
Merged

feat(theme): Fluent foundation — system Light/Dark + brand palette across all windows#33
aksOps merged 16 commits into
mainfrom
worktree-fluent-foundation

Conversation

@aksOps

@aksOps aksOps commented Aug 13, 2026

Copy link
Copy Markdown
Contributor

Summary

Fluent Foundation — Plan 1 of the SnipIT Fluent Suite redesign. Every existing window now renders in the .NET 9 WPF Fluent theme, following system Light/Dark, with the locked 5-color brand palette. Zero new dependencies; single-file distribution unchanged in shape.

  • Get-SnipFluentPalette (pure, -CoreOnly-safe): locked palette contract — accent #035BA3, neutral #909496, positive #043D19/#2E6B42, destructive #A60707 — plus the 28-key Fluent resource override map
  • Get-SnipSystemThemeMode: registry-backed Light/Dark detection with a test seam; hardened against corrupted values
  • Initialize-SnipWindowTheme: app+window ThemeMode via reflection (absent-type safe), palette overrides at window scope, background grounding skipped on AllowsTransparency glass surfaces
  • Wired into Settings, About, FloatingWidget, and Preview windows
  • Preview More-menu popup lifecycle now survives Fluent's MenuItem template swap (capture-exclusion HWND registration held correct through rebinds, stale registrations released)
  • Palette-swap audit test pins the brand accent over the system accent
  • Distribution regenerated deterministically via Build-SnipIT.ps1

Test plan

  • Build contract suite 30/30 (release mode, byte-identical rebuild)
  • Pure suite 337/337 (Linux-safe -CoreOnly load verified)
  • Interactive WPF suite 236/236 (incl. 12 new theme tests: glass-background guard, popup rebind regression, palette audit tripwire)
  • Release-file smoke: Settings/About/Widget driven through TestAction seams on the regenerated SnipIT.ps1, accent #FF035BA3 asserted; rendered screenshots reviewed
  • Human visual pass on a Light-mode machine (author machine runs Dark)

aksOps and others added 16 commits August 13, 2026 16:08
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…s template swap

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- Initialize-SnipWindowTheme now builds the Dark ground brush from
  $palette.Ground via ColorConverter instead of a hardcoded Colors::Black
  literal, closing the contract gap between the palette and the applied
  brush (behavior unchanged: Ground is #000000 in dark mode).
- Get-SnipSystemThemeMode hardens the registry-value cast with `-as [int]`
  so a corrupted non-numeric value falls back to 'Light' instead of
  throwing; adds a regression test pinning that fallback.
- Regenerate SnipIT.ps1 from src/ and xaml/ via Build-SnipIT.ps1.
The preview toolbar wrote fixed Win32 SystemColors brushes as local values
for its active-tool and More-button chrome. Those brushes never follow the
.NET Fluent theme this branch applies, so under Dark the theme's white button
ink landed on ControlLight #E3E3E3 (1.28:1) or Control #F0F0F0 (1.14:1) and
the glyph and the More label disappeared. The status indicator had the same
problem through SystemColors.ControlTextBrushKey, which is always black.

Replace all three with DynamicResource references to the palette keys
Initialize-SnipWindowTheme injects: the brand accent plate with on-accent ink
when active (6.93:1 in both modes), and cleared local values otherwise so the
theme style supplies its own subtle fill and ink.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The tray menu is a WinForms ContextMenuStrip, so it never inherits the WPF
Fluent theme the windows get. It painted the same owner-drawn champagne-on
black chrome no matter what the system app theme was.

Add a -ThemeMode seam defaulting to Get-SnipSystemThemeMode, re-read on every
construction because the tray rebuilds its menu per open. Dark now paints the
Fluent dark flyout surface (#202020 with #FFFFFF ink) and selects rows with
the brand accent #035BA3 under on-accent ink, propagated to every nested
dropdown and to the owner-drawn check margin. High contrast still overrides
both modes, and Light keeps the existing rendering unchanged.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@aksOps
aksOps enabled auto-merge (squash) August 14, 2026 02:19
@aksOps
aksOps disabled auto-merge August 14, 2026 02:20
@aksOps
aksOps enabled auto-merge (squash) August 14, 2026 02:20
@aksOps aksOps closed this Aug 14, 2026
auto-merge was automatically disabled August 14, 2026 02:21

Pull request was closed

@aksOps aksOps reopened this Aug 14, 2026
@aksOps
aksOps enabled auto-merge (squash) August 14, 2026 02:22
@aksOps
aksOps merged commit 052d935 into main Aug 14, 2026
12 checks passed
@aksOps
aksOps deleted the worktree-fluent-foundation branch August 14, 2026 02:23
aksOps added a commit that referenced this pull request Aug 14, 2026
…ross all windows (#33)

* docs(plan): Fluent Foundation implementation plan


* feat(theme): add Get-SnipFluentPalette pure palette contract

* feat(theme): detect system Light/Dark app theme


* feat(theme): window-level Fluent theme wiring with palette overrides


* feat(theme): Fluent-theme the Settings and About windows


* fix(theme): preserve transparent backgrounds on glass windows


* feat(theme): Fluent-theme the widget and preview windows


* fix(preview): resolve More-menu popup at open time so theming survives template swap


* fix(preview): reset nested-popup registration state on template swap


* style(preview): drop duplicated comment block


* test(theme): palette-swap audit pins brand accent over system accent


* build: regenerate distribution with Fluent theme foundation


* docs(plan): record execution amendments for theme grounding and window wiring

* fix(theme): palette-ground contract + registry cast hardening

- Initialize-SnipWindowTheme now builds the Dark ground brush from
 $palette.Ground via ColorConverter instead of a hardcoded Colors::Black
 literal, closing the contract gap between the palette and the applied
 brush (behavior unchanged: Ground is #000000 in dark mode).
- Get-SnipSystemThemeMode hardens the registry-value cast with `-as [int]`
 so a corrupted non-numeric value falls back to 'Light' instead of
 throwing; adds a regression test pinning that fallback.
- Regenerate SnipIT.ps1 from src/ and xaml/ via Build-SnipIT.ps1.

* fix(theme): readable preview toolbar in dark mode

The preview toolbar wrote fixed Win32 SystemColors brushes as local values
for its active-tool and More-button chrome. Those brushes never follow the
.NET Fluent theme this branch applies, so under Dark the theme's white button
ink landed on ControlLight #E3E3E3 (1.28:1) or Control #F0F0F0 (1.14:1) and
the glyph and the More label disappeared. The status indicator had the same
problem through SystemColors.ControlTextBrushKey, which is always black.

Replace all three with DynamicResource references to the palette keys
Initialize-SnipWindowTheme injects: the brand accent plate with on-accent ink
when active (6.93:1 in both modes), and cleared local values otherwise so the
theme style supplies its own subtle fill and ink.


* fix(tray): dark context-menu rendering follows system theme

The tray menu is a WinForms ContextMenuStrip, so it never inherits the WPF
Fluent theme the windows get. It painted the same owner-drawn champagne-on
black chrome no matter what the system app theme was.

Add a -ThemeMode seam defaulting to Get-SnipSystemThemeMode, re-read on every
construction because the tray rebuilds its menu per open. Dark now paints the
Fluent dark flyout surface (#202020 with #FFFFFF ink) and selects rows with
the brand accent #035BA3 under on-accent ink, propagated to every nested
dropdown and to the owner-drawn check margin. High contrast still overrides
both modes, and Light keeps the existing rendering unchanged.


---------
aksOps added a commit that referenced this pull request Aug 14, 2026
…ross all windows (#33)

* docs(plan): Fluent Foundation implementation plan


* feat(theme): add Get-SnipFluentPalette pure palette contract

* feat(theme): detect system Light/Dark app theme


* feat(theme): window-level Fluent theme wiring with palette overrides


* feat(theme): Fluent-theme the Settings and About windows


* fix(theme): preserve transparent backgrounds on glass windows


* feat(theme): Fluent-theme the widget and preview windows


* fix(preview): resolve More-menu popup at open time so theming survives template swap


* fix(preview): reset nested-popup registration state on template swap


* style(preview): drop duplicated comment block


* test(theme): palette-swap audit pins brand accent over system accent


* build: regenerate distribution with Fluent theme foundation


* docs(plan): record execution amendments for theme grounding and window wiring

* fix(theme): palette-ground contract + registry cast hardening

- Initialize-SnipWindowTheme now builds the Dark ground brush from
 $palette.Ground via ColorConverter instead of a hardcoded Colors::Black
 literal, closing the contract gap between the palette and the applied
 brush (behavior unchanged: Ground is #000000 in dark mode).
- Get-SnipSystemThemeMode hardens the registry-value cast with `-as [int]`
 so a corrupted non-numeric value falls back to 'Light' instead of
 throwing; adds a regression test pinning that fallback.
- Regenerate SnipIT.ps1 from src/ and xaml/ via Build-SnipIT.ps1.

* fix(theme): readable preview toolbar in dark mode

The preview toolbar wrote fixed Win32 SystemColors brushes as local values
for its active-tool and More-button chrome. Those brushes never follow the
.NET Fluent theme this branch applies, so under Dark the theme's white button
ink landed on ControlLight #E3E3E3 (1.28:1) or Control #F0F0F0 (1.14:1) and
the glyph and the More label disappeared. The status indicator had the same
problem through SystemColors.ControlTextBrushKey, which is always black.

Replace all three with DynamicResource references to the palette keys
Initialize-SnipWindowTheme injects: the brand accent plate with on-accent ink
when active (6.93:1 in both modes), and cleared local values otherwise so the
theme style supplies its own subtle fill and ink.


* fix(tray): dark context-menu rendering follows system theme

The tray menu is a WinForms ContextMenuStrip, so it never inherits the WPF
Fluent theme the windows get. It painted the same owner-drawn champagne-on
black chrome no matter what the system app theme was.

Add a -ThemeMode seam defaulting to Get-SnipSystemThemeMode, re-read on every
construction because the tray rebuilds its menu per open. Dark now paints the
Fluent dark flyout surface (#202020 with #FFFFFF ink) and selects rows with
the brand accent #035BA3 under on-accent ink, propagated to every nested
dropdown and to the owner-drawn check margin. High contrast still overrides
both modes, and Light keeps the existing rendering unchanged.


---------
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant