300 lines
18 KiB
Plaintext
300 lines
18 KiB
Plaintext
|
|
<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>
|