design: preview pane to tokens (surface 4), and one palette list instead of two

110 hardcoded colours gone from the preview — the biggest surface in the app. Nicknames:
- the webcam selection ring is the interactive accent (was the retired brand red)
- the mute chips are `attention` (a muted mic is a caution, not a live state) with a white play
  glyph; the live badge is `primary`
- YPP progress bars/track, TRAX level zones, the error line, the dim strips and the poster veil
  all resolve from tokens (`positive`, `secondary-container`, `error-container`, `scrim-dark`,
  `scrim-dark-strong`)

Plus the duplication this sweep exposed: the webcam's right-click "Border Color" submenu carried
**seven hand-written colours**, a second source of truth beside the properties drop-down that
TASK 63 had already unified onto `Models/BorderColorPalette.cs` — and the two lists disagreed
(7 vs 14). The submenu is now built from the palette when it opens, so every offered colour is
the same colour everywhere, with the palette's name beside it. The click handler is unchanged;
generated rows inherit the menu's SceneElement DataContext.

Guard list extended: Controls/PreviewPane.xaml.
This commit is contained in:
2026-10-30 08:28:21 -07:00
parent 66b85d3fcc
commit 8415bb5f37
3 changed files with 126 additions and 115 deletions
+28
View File
@@ -365,6 +365,34 @@ public partial class PreviewPane : UserControl
sb.Children.Add(anim);
}
/// <summary>The border-colour submenu is BUILT from the palette on open: the list of
/// offered colours lives once, in <see cref="BorderColorPalette"/> (TASK 63's rule —
/// a picker never carries its own copy). The generated rows inherit this menu's
/// DataContext (the <see cref="SceneElement"/>), so the click handler is unchanged.</summary>
private void WebcamBorderColorMenu_SubmenuOpened(object sender, RoutedEventArgs e)
{
if (sender is not MenuItem { DataContext: SceneElement element } menu) return;
menu.Items.Clear();
var none = new MenuItem { Header = "None", Tag = string.Empty, IsCheckable = true,
IsChecked = string.IsNullOrEmpty(element.BorderColor) };
none.Click += WebcamMenu_SetBorderColor;
menu.Items.Add(none);
foreach (var colour in BorderColorPalette.All)
{
var row = new MenuItem
{
Header = colour.ToString(),
Tag = colour.Hex,
IsCheckable = true,
IsChecked = string.Equals(element.BorderColor, colour.Hex, StringComparison.OrdinalIgnoreCase),
};
row.Click += WebcamMenu_SetBorderColor;
menu.Items.Add(row);
}
}
private void WebcamMenu_SetBorderColor(object sender, RoutedEventArgs e)
{
if (sender is MenuItem { DataContext: SceneElement element, Tag: string color })