Files
claude-local-overview-display/MainWindow.xaml
2026-06-25 09:59:54 +02:00

300 lines
18 KiB
XML

<Window x:Class="ClaudeOverview.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Claude Overview"
WindowStyle="None"
AllowsTransparency="True"
Background="Transparent"
ShowInTaskbar="False"
Topmost="True"
ResizeMode="NoResize"
SizeToContent="Manual"
TextOptions.TextFormattingMode="Display"
UseLayoutRounding="True"
FontFamily="Segoe UI">
<Grid>
<!-- ===== STATE 1: minimized arrow button (bottom-right) ===== -->
<Border x:Name="MinimizedState"
Width="44" Height="44"
HorizontalAlignment="Right" VerticalAlignment="Bottom"
Background="{StaticResource PanelBg}"
BorderBrush="{StaticResource BorderBrush}" BorderThickness="1"
CornerRadius="10">
<Border.ContextMenu>
<ContextMenu>
<MenuItem Header="Quit" Click="Quit_Click"/>
</ContextMenu>
</Border.ContextMenu>
<Border.Effect>
<DropShadowEffect BlurRadius="14" ShadowDepth="0" Opacity="0.5" Color="#000000"/>
</Border.Effect>
<Button Style="{StaticResource IconButton}" Click="Expand_Click"
ToolTip="Show active Claude chats">
<!-- up-left pointing arrow toward the corner widget; recolored when a chat waits -->
<TextBlock x:Name="MinArrow" Text="◤" FontSize="18"
Foreground="{StaticResource TextMuted}"/>
</Button>
</Border>
<!-- ===== STATE 2: the panel (bottom-right) ===== -->
<Border x:Name="ExpandedState"
Width="370" Height="520"
HorizontalAlignment="Right" VerticalAlignment="Bottom"
Background="{StaticResource PanelBg}"
BorderBrush="{StaticResource BorderBrush}" BorderThickness="1"
CornerRadius="12"
Visibility="Collapsed">
<Border.Effect>
<DropShadowEffect BlurRadius="18" ShadowDepth="0" Opacity="0.55" Color="#000000"/>
</Border.Effect>
<Grid Margin="14,12,14,12">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<!-- Header (also draggable to move the window) -->
<Grid Grid.Row="0" Background="Transparent" MouseLeftButtonDown="Header_DragMove">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<StackPanel Grid.Column="0">
<TextBlock Text="Active Claude chats" FontSize="14" FontWeight="SemiBold"
Foreground="{StaticResource TextPrimary}"/>
<TextBlock x:Name="SubtitleText" Text="VS Code · scanning…" FontSize="11"
Foreground="{StaticResource TextMuted}" Margin="0,1,0,0"/>
</StackPanel>
<StackPanel Grid.Column="1" Orientation="Horizontal">
<Button Style="{StaticResource IconButton}"
Width="28" Height="28" Click="Settings_Click" ToolTip="Settings">
<TextBlock Text="⚙" FontSize="15" Foreground="{StaticResource TextMuted}"/>
</Button>
<Button Style="{StaticResource IconButton}"
Width="28" Height="28" Click="Collapse_Click" ToolTip="Minimize">
<TextBlock Text="▾" FontSize="16" Foreground="{StaticResource TextMuted}"/>
</Button>
<Button Style="{StaticResource IconButton}"
Width="28" Height="28" Click="Quit_Click" ToolTip="Quit">
<TextBlock Text="✕" FontSize="13" Foreground="{StaticResource TextMuted}"/>
</Button>
</StackPanel>
</Grid>
<!-- Subscription usage meter -->
<Border x:Name="UsagePanel" Grid.Row="1" Margin="0,10,0,0"
Background="{StaticResource CardBg}" CornerRadius="9" Padding="11,9">
<StackPanel>
<Grid>
<TextBlock Text="Session limit" FontSize="11"
Foreground="{StaticResource TextMuted}" HorizontalAlignment="Left"/>
<TextBlock x:Name="SessionPctText" FontSize="11" FontWeight="SemiBold"
Foreground="{StaticResource TextPrimary}" HorizontalAlignment="Right"/>
</Grid>
<ProgressBar x:Name="SessionBar" Height="6" Minimum="0" Maximum="100"
Margin="0,5,0,0" BorderThickness="0"
Background="#33000000"
Foreground="{StaticResource AccentBrush}"/>
<Grid Margin="0,5,0,0">
<TextBlock x:Name="WeeklyText" FontSize="10"
Foreground="{StaticResource TextMuted}" HorizontalAlignment="Left"/>
<TextBlock x:Name="SessionResetText" FontSize="10"
Foreground="{StaticResource TextMuted}" HorizontalAlignment="Right"/>
</Grid>
</StackPanel>
</Border>
<!-- Session list -->
<ScrollViewer Grid.Row="2" Margin="0,10,0,0"
VerticalScrollBarVisibility="Auto"
HorizontalScrollBarVisibility="Disabled">
<Grid>
<ItemsControl x:Name="SessionsList">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Border x:Name="CardRoot" Background="{StaticResource CardBg}" CornerRadius="9"
Padding="11,9" Margin="0,0,0,8">
<StackPanel>
<!-- project + status -->
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<StackPanel Orientation="Horizontal" Grid.Column="0">
<Ellipse x:Name="StatusDot" Width="7" Height="7"
Fill="{StaticResource WorkingBrush}"
VerticalAlignment="Center" Margin="0,0,7,0"/>
<TextBlock Text="{Binding ProjectName}" FontSize="13"
FontWeight="SemiBold"
Foreground="{StaticResource TextPrimary}"
TextTrimming="CharacterEllipsis"/>
</StackPanel>
<TextBlock x:Name="StatusLabel" Grid.Column="1"
Text="{Binding StatusText}"
FontSize="10" FontWeight="SemiBold"
Foreground="{StaticResource WorkingBrush}"
VerticalAlignment="Center"/>
</Grid>
<!-- chat name (VS Code's generated title, else first prompt) -->
<TextBlock Text="{Binding DisplayTitle}" FontSize="11"
Foreground="{StaticResource TextMuted}"
TextTrimming="CharacterEllipsis"
Margin="14,2,0,0"/>
<!-- usage + last activity -->
<StackPanel Orientation="Horizontal" Margin="14,6,0,0">
<TextBlock Text="{Binding ModelShort}" FontSize="11"
Foreground="{StaticResource TextMuted}"/>
<TextBlock Text=" · " FontSize="11"
Foreground="{StaticResource TextMuted}"/>
<TextBlock Text="{Binding LastActivityLocal}" FontSize="11"
Foreground="{StaticResource TextMuted}"/>
</StackPanel>
<!-- share of this session-limit window's total tokens -->
<Grid Margin="14,6,0,0"
ToolTip="Share of all tokens used this session-limit window">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<ProgressBar Grid.Column="0" Height="4" Minimum="0" Maximum="100"
Value="{Binding SessionSharePercent}"
BorderThickness="0" Background="#33000000"
Foreground="{StaticResource AccentBrush}"
VerticalAlignment="Center"/>
<TextBlock Grid.Column="1" Text="{Binding SessionShareText}"
FontSize="10" Foreground="{StaticResource TextMuted}"
Margin="8,0,0,0" VerticalAlignment="Center"/>
</Grid>
</StackPanel>
</Border>
<DataTemplate.Triggers>
<DataTrigger Binding="{Binding IsWaiting}" Value="True">
<Setter TargetName="StatusDot" Property="Fill"
Value="{StaticResource WaitingBrush}"/>
<Setter TargetName="StatusLabel" Property="Foreground"
Value="{StaticResource WaitingBrush}"/>
</DataTrigger>
<DataTrigger Binding="{Binding NeedsPermission}" Value="True">
<Setter TargetName="StatusDot" Property="Fill"
Value="{StaticResource PermissionBrush}"/>
<Setter TargetName="StatusLabel" Property="Foreground"
Value="{StaticResource PermissionBrush}"/>
</DataTrigger>
<!-- Cold (inactive) chats: dimmed, no status colors. Last so it
overrides the waiting/permission colors above. -->
<DataTrigger Binding="{Binding IsCold}" Value="True">
<Setter TargetName="CardRoot" Property="Opacity" Value="0.45"/>
<Setter TargetName="StatusDot" Property="Fill"
Value="{StaticResource TextMuted}"/>
<Setter TargetName="StatusLabel" Property="Visibility"
Value="Collapsed"/>
</DataTrigger>
</DataTemplate.Triggers>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
<!-- Empty / error state -->
<TextBlock x:Name="EmptyText"
Text="No active VS Code chats right now."
FontSize="12" Foreground="{StaticResource TextMuted}"
TextWrapping="Wrap" Margin="2,8,2,0"
Visibility="Collapsed"/>
</Grid>
</ScrollViewer>
<!-- Footer totals -->
<Border Grid.Row="3" Margin="0,8,0,0" Padding="0,8,0,0"
BorderBrush="{StaticResource BorderBrush}" BorderThickness="0,1,0,0">
<TextBlock x:Name="FooterText" FontSize="11"
Foreground="{StaticResource TextMuted}"/>
</Border>
<!-- ===== Settings overlay (covers usage + list + footer) ===== -->
<Border x:Name="SettingsPanel" Grid.Row="1" Grid.RowSpan="3"
Background="{StaticResource PanelSolid}" Panel.ZIndex="10"
Margin="0,10,0,0" Visibility="Collapsed">
<StackPanel>
<TextBlock Text="Settings" FontSize="13" FontWeight="SemiBold"
Foreground="{StaticResource TextPrimary}" Margin="0,0,0,12"/>
<!-- Monitor -->
<TextBlock Text="Monitor" FontSize="11"
Foreground="{StaticResource TextMuted}" Margin="0,0,0,4"/>
<ComboBox x:Name="MonitorCombo" Height="30"
DisplayMemberPath="Label" SelectedValuePath="Index"
Foreground="#202020" FontSize="12" Margin="0,0,0,16"/>
<!-- Active threshold -->
<Grid Margin="0,0,0,4">
<TextBlock Text="Active threshold" FontSize="11"
Foreground="{StaticResource TextMuted}"
HorizontalAlignment="Left"/>
<TextBlock x:Name="ThresholdLabel" FontSize="11" FontWeight="SemiBold"
Foreground="{StaticResource TextPrimary}"
HorizontalAlignment="Right"/>
</Grid>
<Slider x:Name="ThresholdSlider" Minimum="1" Maximum="60"
IsSnapToTickEnabled="True" TickFrequency="1"
ValueChanged="ThresholdSlider_ValueChanged" Margin="0,0,0,6"/>
<TextBlock Text="A chat counts as active if its transcript changed within this window."
FontSize="10" Foreground="{StaticResource TextMuted}"
TextWrapping="Wrap" Margin="0,0,0,16"/>
<!-- Refresh interval -->
<Grid Margin="0,0,0,4">
<TextBlock Text="Refresh interval" FontSize="11"
Foreground="{StaticResource TextMuted}"
HorizontalAlignment="Left"/>
<TextBlock x:Name="RefreshLabel" FontSize="11" FontWeight="SemiBold"
Foreground="{StaticResource TextPrimary}"
HorizontalAlignment="Right"/>
</Grid>
<Slider x:Name="RefreshSlider" Minimum="1" Maximum="30"
IsSnapToTickEnabled="True" TickFrequency="1"
ValueChanged="RefreshSlider_ValueChanged" Margin="0,0,0,18"/>
<!-- Notifications -->
<CheckBox x:Name="FlashCheck" Content="Flash when a chat needs input"
Foreground="{StaticResource TextPrimary}" FontSize="12"
Margin="0,0,0,8"/>
<CheckBox x:Name="SoundCheck" Content="Play a sound too"
Foreground="{StaticResource TextPrimary}" FontSize="12"
Margin="0,0,0,18"/>
<!-- Actions -->
<StackPanel Orientation="Horizontal" HorizontalAlignment="Right">
<Button Content="Cancel" Style="{StaticResource PillButton}"
Click="SettingsCancel_Click" Margin="0,0,8,0"/>
<Button Content="Save" Style="{StaticResource PillButtonAccent}"
Click="SettingsSave_Click"/>
</StackPanel>
</StackPanel>
</Border>
</Grid>
</Border>
<!-- ===== Attention flash (pulses when a chat starts waiting) ===== -->
<Border x:Name="FlashOverlay" IsHitTestVisible="False"
CornerRadius="12" Opacity="0"
BorderBrush="{StaticResource WaitingBrush}" BorderThickness="3"
Background="#33E8A33D">
<Border.Effect>
<DropShadowEffect BlurRadius="22" ShadowDepth="0"
Color="#E8A33D" Opacity="0.9"/>
</Border.Effect>
</Border>
</Grid>
</Window>