dragon-iso/src/TeamsISO.App/Views/CommandPaletteWindow.xaml
Zac Gaetano d282e1b0f8
Some checks failed
CI / build-and-test (push) Failing after 30s
feat(wpf): v2 task 39+40 - studio table redesign + Ctrl+K command palette
Task 39: 5-column participants table - state LED, name+codec caption, 5-bar audio meter, mono output name, ISO pill. Row height 52, full-row active-speaker tint (no left stripe). New converter LevelThresholdConverter, OutputName property on ParticipantViewModel.

Task 40: Ctrl+K / Ctrl+P command palette - chromeless centered floating window, fuzzy Contains match across Label/Category/Keywords, arrow nav, Enter invoke, Esc close. Quick/Teams/Network/App categories cover top operator verbs and theme switching.

Also: log startup exceptions to Serilog before the modal MessageBox fires - much better triage signal than user-pasted dialog text.
2026-05-15 11:15:00 -04:00

198 lines
11 KiB
XML

<Window x:Class="TeamsISO.App.Views.CommandPaletteWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:vm="clr-namespace:TeamsISO.App.ViewModels"
xmlns:conv="clr-namespace:TeamsISO.App.Converters"
Width="560" Height="360"
WindowStartupLocation="CenterOwner"
WindowStyle="None"
AllowsTransparency="True"
ShowInTaskbar="False"
Background="Transparent"
ResizeMode="NoResize"
Topmost="True"
d:DataContext="{d:DesignInstance Type=vm:CommandPaletteViewModel}"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">
<Window.Resources>
<conv:NullToCollapsedConverter x:Key="NullToCollapsed"/>
</Window.Resources>
<!--
v2 command palette — Ctrl+K / Ctrl+P. The navigation surface for the
Studio Terminal redesign: operators with attention budgets in the
low single digits type two letters, press Enter, action fires.
Chromeless window so the palette feels like a popover, not another
OS-level top-level. The single rounded card inside is the entire
affordance; the host window background is Transparent and the card
sits centered. Esc closes the window from code-behind.
-->
<Border CornerRadius="{StaticResource Radius.L}"
Background="{DynamicResource Wd.SurfaceElevated}"
BorderBrush="{DynamicResource Wd.BorderStrong}"
BorderThickness="1"
SnapsToDevicePixels="True">
<Border.Effect>
<DropShadowEffect BlurRadius="32" ShadowDepth="0" Opacity="0.35" Color="Black"/>
</Border.Effect>
<DockPanel LastChildFill="True">
<!-- Search input — autofocused on open. The placeholder doubles
as a help hint until the operator types. -->
<Border DockPanel.Dock="Top"
BorderBrush="{DynamicResource Wd.Border}"
BorderThickness="0,0,0,1"
Padding="16,12">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0"
Text="⌘"
FontFamily="{StaticResource Wd.Font.Mono}"
FontSize="14"
Foreground="{DynamicResource Wd.Text.Tertiary}"
VerticalAlignment="Center"
Margin="0,0,12,0"/>
<TextBox Grid.Column="1"
x:Name="FilterBox"
Text="{Binding Filter, UpdateSourceTrigger=PropertyChanged, Delay=20}"
FontFamily="{StaticResource Wd.Font.Sans}"
FontSize="14"
Background="Transparent"
BorderThickness="0"
Foreground="{DynamicResource Wd.Text.Primary}"
CaretBrush="{DynamicResource Wd.Accent.Cyan}"
VerticalAlignment="Center"
Padding="0">
<TextBox.Style>
<Style TargetType="TextBox">
<Style.Resources>
<VisualBrush x:Key="PlaceholderBrush" TileMode="None" Stretch="None" AlignmentX="Left" AlignmentY="Center">
<VisualBrush.Visual>
<TextBlock Text="Type a command…"
FontFamily="{StaticResource Wd.Font.Sans}"
FontSize="14"
Foreground="{DynamicResource Wd.Text.Tertiary}"/>
</VisualBrush.Visual>
</VisualBrush>
</Style.Resources>
<Style.Triggers>
<Trigger Property="Text" Value="">
<Setter Property="Background" Value="{StaticResource PlaceholderBrush}"/>
</Trigger>
</Style.Triggers>
</Style>
</TextBox.Style>
</TextBox>
<TextBlock Grid.Column="2"
Text="esc to close"
FontFamily="{StaticResource Wd.Font.Mono}"
FontSize="10"
Foreground="{DynamicResource Wd.Text.Disabled}"
VerticalAlignment="Center"
Margin="12,0,0,0"/>
</Grid>
</Border>
<!-- Footer hint -->
<Border DockPanel.Dock="Bottom"
BorderBrush="{DynamicResource Wd.Border}"
BorderThickness="0,1,0,0"
Padding="16,8">
<TextBlock FontFamily="{StaticResource Wd.Font.Mono}"
FontSize="10"
Foreground="{DynamicResource Wd.Text.Tertiary}">
<Run Text="↑ ↓ navigate"/>
<Run Text="·" Foreground="{DynamicResource Wd.Text.Disabled}"/>
<Run Text="enter invoke"/>
<Run Text="·" Foreground="{DynamicResource Wd.Text.Disabled}"/>
<Run Text="esc close"/>
</TextBlock>
</Border>
<!-- Results list — bound to CommandPaletteViewModel.Visible -->
<ListBox x:Name="ResultsList"
ItemsSource="{Binding Visible}"
SelectedItem="{Binding Selected}"
Background="Transparent"
BorderThickness="0"
Padding="6,6,6,6"
Focusable="False"
ScrollViewer.HorizontalScrollBarVisibility="Disabled"
ScrollViewer.VerticalScrollBarVisibility="Auto"
HorizontalContentAlignment="Stretch">
<ListBox.ItemContainerStyle>
<Style TargetType="ListBoxItem">
<Setter Property="Background" Value="Transparent"/>
<Setter Property="Padding" Value="10,8"/>
<Setter Property="Margin" Value="0,1"/>
<Setter Property="Focusable" Value="False"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ListBoxItem">
<Border x:Name="Bd"
Background="{TemplateBinding Background}"
CornerRadius="{StaticResource Radius.S}"
Padding="{TemplateBinding Padding}">
<ContentPresenter/>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsSelected" Value="True">
<Setter TargetName="Bd" Property="Background" Value="{DynamicResource Wd.Accent.CyanMuted}"/>
</Trigger>
<Trigger Property="IsMouseOver" Value="True">
<Setter TargetName="Bd" Property="Background" Value="{DynamicResource Wd.SurfaceHover}"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ListBox.ItemContainerStyle>
<ListBox.ItemTemplate>
<DataTemplate DataType="{x:Type vm:PaletteCommand}">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="80"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0"
Text="{Binding Category}"
FontFamily="{StaticResource Wd.Font.Sans}"
FontSize="10"
FontWeight="SemiBold"
Foreground="{DynamicResource Wd.Text.Tertiary}"
VerticalAlignment="Center"/>
<TextBlock Grid.Column="1"
Text="{Binding Label}"
FontFamily="{StaticResource Wd.Font.Sans}"
FontSize="13"
Foreground="{DynamicResource Wd.Text.Primary}"
VerticalAlignment="Center"
TextTrimming="CharacterEllipsis"/>
<Border Grid.Column="2"
Background="{DynamicResource Wd.Surface}"
BorderBrush="{DynamicResource Wd.Border}"
BorderThickness="1"
CornerRadius="{StaticResource Radius.S}"
Padding="6,1"
VerticalAlignment="Center"
Margin="12,0,0,0"
Visibility="{Binding Shortcut, Converter={StaticResource NullToCollapsed}}">
<TextBlock Text="{Binding Shortcut}"
FontFamily="{StaticResource Wd.Font.Mono}"
FontSize="10"
Foreground="{DynamicResource Wd.Text.Secondary}"/>
</Border>
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</DockPanel>
</Border>
</Window>