feat(topbar): the output stage's three states, and keyboard entry into the bar

Build 729 (creator):

- "press <esc> to return" loses the word "press"; the label is "Record / Go-Live".
- The bar takes focus on "Build scenes" and Tab cycles between the two halves only
  (KeyboardNavigation.TabNavigation="Cycle"), never off into the window.
- Entering Record / Go-Live starts with NOTHING chosen — the output switches are a fresh decision,
  not a remembered one.
- Three states: nothing chosen [YouTube][Local MP4]; YouTube chosen [YouTube(red)][Live Stream][Private
  Stream]; Local MP4 chosen [Local MP4(red)][Start Recording] → [End Recording] while recording. Only the
  chosen output is red; the action chips never highlight. Choosing Local MP4 takes the left slot and the
  YouTube chip disappears with it, which is what "slides to the left, replacing it" describes.

"Private Stream" is the private-visibility stream — the same thing this app has always called the test
stream (creator's clarification, so the wording is deliberate, not a new broadcast type).

Output chips are one style with a Tag-driven trigger (OutputChip + OutputChipIcon), so a chip's red face
and its glyph colour can't drift apart; the one-alpha hit-area colour is a token, because
DesignTokensTests rightly refuses literals in theme files.

680 pass, 0 warnings. Scope justification: Assets/starting-background.jpg is outside this unit — the
creator's replacement art, still awaiting their visual check.
This commit is contained in:
2026-11-12 16:35:16 -08:00
parent 6b4aa99863
commit caf5d6130d
7 changed files with 205 additions and 55 deletions
+48
View File
@@ -1002,6 +1002,54 @@
<!-- REC / ON-AIR segment pills: an armed session control reads red, because red is what
"live or recording" means (DESIGN.md). Kept separate from SegmentToggle so the Rect|Circle
choice in the properties panel stays the interactive blue. -->
<!-- An output chip: muted until it is the CHOSEN output, then red with white ink (creator, build
729). Tag carries that chip's own selection flag, so one style serves every chip. -->
<Style x:Key="OutputChip" TargetType="Button">
<Setter Property="Background" Value="{StaticResource Brush.SegmentHitArea}"/>
<Setter Property="Foreground" Value="{StaticResource Brush.SegmentTextInactive}"/>
<Setter Property="BorderThickness" Value="0"/>
<Setter Property="Cursor" Value="Hand"/>
<Setter Property="Margin" Value="0,0,4,0"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Border x:Name="Face" Background="{TemplateBinding Background}"
CornerRadius="8" Padding="12,4">
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<DataTrigger Binding="{Binding Tag, RelativeSource={RelativeSource Self}}" Value="True">
<Setter Property="Background" Value="{StaticResource Brush.Primary}"/>
<Setter Property="Foreground" Value="{StaticResource Brush.OnAccent}"/>
<Setter Property="FontWeight" Value="Bold"/>
</DataTrigger>
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Binding="{Binding IsMouseOver, RelativeSource={RelativeSource Self}}" Value="True"/>
<Condition Binding="{Binding Tag, RelativeSource={RelativeSource Self}}" Value="False"/>
</MultiDataTrigger.Conditions>
<Setter Property="Background" Value="{StaticResource Brush.SegmentHover}"/>
</MultiDataTrigger>
</Style.Triggers>
</Style>
<!-- The chip glyph follows the chip: muted normally, white on the red selected face. -->
<Style x:Key="OutputChipIcon" TargetType="Path">
<Setter Property="Fill" Value="{StaticResource Brush.SegmentTextInactive}"/>
<Setter Property="Width" Value="14"/>
<Setter Property="Height" Value="14"/>
<Setter Property="Stretch" Value="Uniform"/>
<Setter Property="VerticalAlignment" Value="Center"/>
<Style.Triggers>
<DataTrigger Binding="{Binding Tag, RelativeSource={RelativeSource Self}}" Value="True">
<Setter Property="Fill" Value="{StaticResource Brush.OnAccent}"/>
</DataTrigger>
</Style.Triggers>
</Style>
<!-- The segmented mode switcher's icon: muted when its segment is inactive, coral when active.
Tag carries the segment's own flag so one style serves both halves (creator mock 2026-11-12). -->
<Style x:Key="SegmentIcon" TargetType="Path">