feat(ui): the capture context menu is always available (Ctrl+right-click); wordmark "ty" is YouTube red
1. The preview's right-click handler swallowed every right-click for the zoom box, so the element/backdrop context menu could not open at all. Sources and capture windows must be changeable AT ANY TIME — a creator swaps a window mid-stream without entering edit mode. Ctrl + right-click now bypasses the zoom path and lets WPF open the menu under the cursor; plain right-click keeps the zoom box. No menu markup changed. 2. The wordmark's "ty" is YouTube red (#ff0000), permanently. The token sweep had recoloured it to the interactive blue because it was a bare literal; DESIGN.md now records "never re-colour the wordmark" beside the token, and UiShellTests pins it. Guard: UiShellTests gains the wordmark rule and the Ctrl+right-click chord.
This commit is contained in:
@@ -590,6 +590,12 @@ public partial class PreviewPane : UserControl
|
|||||||
|
|
||||||
private void Preview_MouseRightButtonDown(object sender, MouseButtonEventArgs e)
|
private void Preview_MouseRightButtonDown(object sender, MouseButtonEventArgs e)
|
||||||
{
|
{
|
||||||
|
// Ctrl + right-click opens the element / backdrop context menu — sources and windows can
|
||||||
|
// be changed at ANY time, live or not (creator ruling 2026-10-30). Plain right-click stays
|
||||||
|
// with the zoom box, which is why the menu needed its own chord.
|
||||||
|
// Returning without Handled lets WPF's ContextMenuService open the menu under the cursor.
|
||||||
|
if ((Keyboard.Modifiers & ModifierKeys.Control) != 0) return;
|
||||||
|
|
||||||
var vm = DataContext as MainViewModel;
|
var vm = DataContext as MainViewModel;
|
||||||
if (vm == null) return;
|
if (vm == null) return;
|
||||||
var grid = (Grid)sender;
|
var grid = (Grid)sender;
|
||||||
|
|||||||
@@ -23,7 +23,9 @@
|
|||||||
</ControlTemplate>
|
</ControlTemplate>
|
||||||
</Button.Template>
|
</Button.Template>
|
||||||
<TextBlock FontSize="22" FontWeight="Bold" VerticalAlignment="Center">
|
<TextBlock FontSize="22" FontWeight="Bold" VerticalAlignment="Center">
|
||||||
<Run Text="LlamaCas" Foreground="{StaticResource Brush.OnSurface}"/><Run Text="ty" Foreground="{StaticResource Brush.Tertiary}"/><Run
|
<Run Text="LlamaCas" Foreground="{StaticResource Brush.OnSurface}"/><!-- Creator ruling (2026-10-30, asked repeatedly): the wordmark's "ty" is YouTube red.
|
||||||
|
It is brand, not state — do not re-tokenise it to an accent. -->
|
||||||
|
<Run Text="ty" Foreground="{StaticResource Brush.Youtube}"/><Run
|
||||||
x:Name="BuildIdStamp" Text="{x:Static helpers:BuildStamp.Label}" FontSize="9"
|
x:Name="BuildIdStamp" Text="{x:Static helpers:BuildStamp.Label}" FontSize="9"
|
||||||
BaselineAlignment="Superscript" Foreground="{StaticResource Brush.OnSurfaceVariant}"
|
BaselineAlignment="Superscript" Foreground="{StaticResource Brush.OnSurfaceVariant}"
|
||||||
ToolTipService.ToolTip="{x:Static helpers:BuildStamp.Label}"/><Run Text=" " FontSize="4"/>
|
ToolTipService.ToolTip="{x:Static helpers:BuildStamp.Label}"/><Run Text=" " FontSize="4"/>
|
||||||
|
|||||||
@@ -58,7 +58,7 @@
|
|||||||
| `success-container` | `#1d5c38` | Success notice surface (success toast) |
|
| `success-container` | `#1d5c38` | Success notice surface (success toast) |
|
||||||
| `warning-container` | `#b8860b` | Warning surface — health banner, warning toast |
|
| `warning-container` | `#b8860b` | Warning surface — health banner, warning toast |
|
||||||
| `test-container` | `#9c6f1c` | Test-stream chrome: the gold top bar and glow |
|
| `test-container` | `#9c6f1c` | Test-stream chrome: the gold top bar and glow |
|
||||||
| `youtube` | `#ff0000` | **YouTube-branded surfaces only** — the Stream Info and YPP rails, the YouTube account row. Not for state: live stays `primary` |
|
| `youtube` | `#ff0000` | **YouTube-branded surfaces only** — Stream Info / YPP rails, the YouTube account row, and the wordmark's "ty" (creator ruling: never re-colour it) | — the Stream Info and YPP rails, the YouTube account row. Not for state: live stays `primary` |
|
||||||
|
|
||||||
**The rule:** red means "live or recording" and nothing else. Never a Send button, a delete action,
|
**The rule:** red means "live or recording" and nothing else. Never a Send button, a delete action,
|
||||||
a brand flourish, or a general accent — that was the defect in the first Stitch draft.
|
a brand flourish, or a general accent — that was the defect in the first Stitch draft.
|
||||||
|
|||||||
@@ -59,6 +59,19 @@ public class UiShellTests
|
|||||||
Assert.DoesNotContain("MaxHeight", listLine);
|
Assert.DoesNotContain("MaxHeight", listLine);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void The_wordmark_ty_stays_youtube_red_and_ctrl_opens_the_context_menu()
|
||||||
|
{
|
||||||
|
var topBar = SourceAssert.Text("Controls", "TopBar.xaml");
|
||||||
|
Assert.Contains("<Run Text=\"ty\" Foreground=\"{StaticResource Brush.Youtube}\"/>", topBar);
|
||||||
|
|
||||||
|
// Plain right-click is the zoom box; the context menu moved to Ctrl+right-click so a
|
||||||
|
// creator can change capture sources mid-stream.
|
||||||
|
var preview = SourceAssert.Text("Controls", "PreviewPane.xaml.cs");
|
||||||
|
Assert.Contains("ModifierKeys.Control", preview);
|
||||||
|
Assert.Contains("return;", preview);
|
||||||
|
}
|
||||||
|
|
||||||
private static int Count(string haystack, string needle)
|
private static int Count(string haystack, string needle)
|
||||||
{
|
{
|
||||||
var hits = 0;
|
var hits = 0;
|
||||||
|
|||||||
Reference in New Issue
Block a user