ui(properties): one typography hierarchy, pill switches, and tokens instead of hex

Creator directive 2026-11-01: the properties panels had 14 hand-rolled heading styles, 37
hand-rolled labels, four literal grey hex values, and 14 square checkboxes.

- PropertyHeader / PropertySubHeader / PropertyFieldLabel / PropertyHint in Themes/Controls.xaml
  now carry the whole hierarchy: category bright and 11px, labels and hints dim, size and weight
  doing the level. Colour groups the panel — bright for what you edit, dim for its labels and
  help — and no new palette entry was needed; DESIGN.md stays the only colour source.
- Every checkbox in the panel is a pill switch (PropertyPillCheck, 32x16 animated thumb).
  IsChecked semantics unchanged, so no binding moved.
- Literal #888/#666/#555 became OnSurfaceVariant / OnSurfaceDisabled.
- 13 headings, 2 sub-headers and 31 in-row labels now reference a style instead of repeating
  colour + size + alignment inline.

Controls audited for backing: every Button/Slider/ComboBox/CheckBox/ToggleButton/TextBox in the
panel has a Command or Click, a Value binding, an ItemsSource or Selected*, IsChecked, or Text —
no dead controls. Release 0 warnings; typography and token tests pass.
This commit is contained in:
2026-11-01 15:51:33 -08:00
parent 82960d0ca3
commit 8221bd6478
3 changed files with 174 additions and 69 deletions
+99
View File
@@ -145,6 +145,105 @@
<!-- Dark check box. The default WPF template is the light system one — it
sticks out of the dark panels, so every check box carries this style
(the guard test in ytLive.Tests/PropertiesStyleTests.cs enforces it). -->
<!-- ═══ Property-panel typography (2026-11-01) ═══
One hierarchy for every properties section, so no panel invents its own:
PropertyHeader — the category (bright, 11px, semibold)
PropertySubHeader — a field label inside it (dim, 10px, indented)
PropertyHint — the explanatory sentence under a control (dim, 10px, wrapped)
Colour does the grouping: bright for the thing you are editing, dim for its labels and
help. No new palette entries; these are the existing OnSurface / OnSurfaceVariant tokens. -->
<Style x:Key="PropertyHeader" TargetType="TextBlock">
<Setter Property="Foreground" Value="{StaticResource Brush.OnSurface}"/>
<Setter Property="FontSize" Value="11"/>
<Setter Property="FontWeight" Value="SemiBold"/>
<Setter Property="Margin" Value="0,0,0,6"/>
</Style>
<Style x:Key="PropertySubHeader" TargetType="TextBlock">
<Setter Property="Foreground" Value="{StaticResource Brush.OnSurfaceVariant}"/>
<Setter Property="FontSize" Value="10"/>
<Setter Property="FontWeight" Value="SemiBold"/>
<Setter Property="Margin" Value="10,6,0,3"/>
</Style>
<!-- A field label that sits in a row with its control (DockPanel.Dock="Left", fixed Width).
Same typography as PropertySubHeader, but vertically centred and marginless so the rows
stay on a grid. -->
<Style x:Key="PropertyFieldLabel" TargetType="TextBlock">
<Setter Property="Foreground" Value="{StaticResource Brush.OnSurfaceVariant}"/>
<Setter Property="FontSize" Value="10"/>
<Setter Property="FontWeight" Value="SemiBold"/>
<Setter Property="VerticalAlignment" Value="Center"/>
</Style>
<Style x:Key="PropertyHint" TargetType="TextBlock">
<Setter Property="Foreground" Value="{StaticResource Brush.OnSurfaceVariant}"/>
<Setter Property="FontSize" Value="10"/>
<Setter Property="TextWrapping" Value="Wrap"/>
<Setter Property="Margin" Value="10,0,0,6"/>
</Style>
<!-- Checkboxes are pill switches (creator ruling 2026-11-01): a 14px box in a properties panel
reads as a form, and a switch reads as a setting. IsChecked semantics are untouched, so
every existing binding still works. -->
<Style x:Key="PropertyPillCheck" TargetType="CheckBox">
<Setter Property="Foreground" Value="{StaticResource Brush.OnSurface}"/>
<Setter Property="FontSize" Value="11"/>
<Setter Property="Cursor" Value="Hand"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="CheckBox">
<Grid Background="Transparent">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Border x:Name="Track" Grid.Column="0" Width="32" Height="16" CornerRadius="8"
Background="{StaticResource Brush.SurfaceContainerHighest}"
BorderBrush="{StaticResource Brush.Outline}" BorderThickness="1"
VerticalAlignment="Center">
<Ellipse x:Name="Thumb" Width="10" Height="10" Fill="{StaticResource Brush.OnSurfaceVariant}"
HorizontalAlignment="Left" Margin="2,0,0,0">
<Ellipse.RenderTransform>
<TranslateTransform x:Name="ThumbShift" X="0"/>
</Ellipse.RenderTransform>
</Ellipse>
</Border>
<ContentPresenter Grid.Column="1" Margin="8,0,0,0" VerticalAlignment="Center"
RecognizesAccessKey="True"/>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsChecked" Value="True">
<Setter TargetName="Track" Property="Background" Value="{StaticResource Brush.Tertiary}"/>
<Setter TargetName="Track" Property="BorderBrush" Value="{StaticResource Brush.Tertiary}"/>
<Setter TargetName="Thumb" Property="Fill" Value="{StaticResource Brush.OnAccent}"/>
<Trigger.EnterActions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Storyboard.TargetName="ThumbShift" Storyboard.TargetProperty="X"
To="16" Duration="0:0:0.12"/>
</Storyboard>
</BeginStoryboard>
</Trigger.EnterActions>
<Trigger.ExitActions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Storyboard.TargetName="ThumbShift" Storyboard.TargetProperty="X"
To="0" Duration="0:0:0.12"/>
</Storyboard>
</BeginStoryboard>
</Trigger.ExitActions>
</Trigger>
<Trigger Property="IsEnabled" Value="False">
<Setter Property="Foreground" Value="{StaticResource Brush.OnSurfaceDisabled}"/>
<Setter TargetName="Track" Property="Opacity" Value="0.5"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style x:Key="YtCheckBox" TargetType="CheckBox">
<Setter Property="Foreground" Value="{StaticResource Brush.OnSurface}"/>
<Setter Property="FontSize" Value="11"/>