Files
ClaudeDo/src/ClaudeDo.Ui/Views/MainWindow.axaml
Mika Kuns 4847c5c0a4 feat(ui): My Day actions, orphan-aware grouping, menu restructure
Pending UI work:
- My Day add/remove context actions on task rows (parent removal cascades to children)
- orphan-aware grouping: a child whose parent isn't in view renders as a top-level row, not an indented draft
- shell menu restructure (Worker / Repositories submenus); 'Finalize plan' action, drop 'Queue subtasks sequentially'
- notes editor refinements
- subtask-row hover tweak (Surface3, no transition)
- bump Avalonia 12.0.0 -> 12.0.4
2026-06-18 16:22:29 +02:00

242 lines
11 KiB
XML

<Window xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:vm="using:ClaudeDo.Ui.ViewModels"
xmlns:islands="using:ClaudeDo.Ui.Views.Islands"
xmlns:converters="using:ClaudeDo.Ui.Converters"
xmlns:loc="using:ClaudeDo.Ui.Localization"
x:Class="ClaudeDo.Ui.Views.MainWindow"
x:DataType="vm:IslandsShellViewModel"
Title="ClaudeDo"
Width="1280" Height="820" MinWidth="780" MinHeight="600"
Background="{DynamicResource VoidBrush}"
Icon="avares://ClaudeDo.Ui/Assets/ClaudeTask.ico"
CanResize="True"
WindowDecorations="BorderOnly"
ExtendClientAreaToDecorationsHint="True"
ExtendClientAreaTitleBarHeightHint="-1">
<Window.Resources>
<converters:WorkerLogLevelToBrushConverter x:Key="WorkerLogLevelToBrush"/>
</Window.Resources>
<Window.KeyBindings>
<KeyBinding Gesture="OemQuestion" Command="{Binding FocusSearchCommand}"/>
<KeyBinding Gesture="Shift+OemQuestion" Command="{Binding FocusSearchCommand}"/>
<KeyBinding Gesture="Ctrl+N" Command="{Binding FocusAddTaskCommand}"/>
</Window.KeyBindings>
<Grid x:Name="RootGrid" RowDefinitions="36,Auto,*,22">
<!-- Custom title bar -->
<Border Grid.Row="0"
Background="{DynamicResource DeepBrush}"
BorderBrush="{DynamicResource LineBrush}"
BorderThickness="0,0,0,1">
<Grid ColumnDefinitions="Auto,*,Auto">
<!-- Left: brand block -->
<StackPanel Grid.Column="0" Orientation="Horizontal" Spacing="8"
VerticalAlignment="Center" Margin="14,0,0,0">
<!-- App icon (matches taskbar) -->
<Image Source="avares://ClaudeDo.Ui/Assets/ClaudeTask.ico"
Width="16" Height="16"
VerticalAlignment="Center"
RenderOptions.BitmapInterpolationMode="HighQuality"/>
<!-- CLAUDEDO label -->
<TextBlock Classes="title-brand-name eyebrow"
Text="CLAUDEDO"
Foreground="{DynamicResource TextBrush}"
LetterSpacing="1.4"
VerticalAlignment="Center"/>
<!-- separator dot -->
<TextBlock Classes="meta"
Text="·"
VerticalAlignment="Center"/>
<!-- current list name -->
<TextBlock Classes="meta"
Text="{Binding Lists.SelectedList.Name, Converter={StaticResource UpperCase}}"
LetterSpacing="1.4"
VerticalAlignment="Center"/>
<!-- Help menu -->
<Menu Margin="12,0,0,0"
Background="Transparent"
VerticalAlignment="Center">
<MenuItem Header="{loc:Tr shell.menu.worker}"
FontSize="{StaticResource FontSizeMono}"
Foreground="{DynamicResource TextDimBrush}">
<MenuItem Header="{loc:Tr shell.menu.restartWorker}"
Command="{Binding RestartWorkerCommand}"/>
<MenuItem Header="{loc:Tr shell.menu.checkForUpdates}"
Command="{Binding CheckForUpdatesCommand}"/>
</MenuItem>
<MenuItem Header="{loc:Tr shell.menu.repositories}"
FontSize="{StaticResource FontSizeMono}"
Foreground="{DynamicResource TextDimBrush}">
<MenuItem Header="{loc:Tr shell.menu.addRepos}" Command="{Binding OpenRepoImportCommand}"/>
<MenuItem Header="{loc:Tr shell.menu.worktrees}"
Command="{Binding OpenWorktreesOverviewGlobalCommand}"/>
</MenuItem>
<MenuItem Header="{loc:Tr shell.menu.help}"
FontSize="{StaticResource FontSizeMono}"
Foreground="{DynamicResource TextDimBrush}">
<MenuItem Header="{loc:Tr shell.menu.weeklyReport}" Command="{Binding OpenWeeklyReportCommand}"/>
<MenuItem Header="{loc:Tr shell.menu.about}" Command="{Binding OpenAboutCommand}"/>
</MenuItem>
</Menu>
</StackPanel>
<!-- Middle: draggable strip -->
<Border Grid.Column="1" Background="Transparent"
PointerPressed="OnTitleBarPressed" />
<!-- Right: window controls -->
<StackPanel Grid.Column="2" Orientation="Horizontal" Spacing="0"
VerticalAlignment="Center" Margin="0,0,4,0">
<Button Classes="title-ctrl" Click="OnMinimize">
<PathIcon Data="{StaticResource Icon.WinMin}" Width="10" Height="10"/>
</Button>
<Button Classes="title-ctrl" Click="OnToggleMax">
<PathIcon x:Name="MaxIcon" Data="{StaticResource Icon.WinMax}" Width="10" Height="10"/>
</Button>
<Button Classes="title-ctrl close" Click="OnClose">
<PathIcon Data="{StaticResource Icon.WinClose}" Width="10" Height="10"/>
</Button>
</StackPanel>
</Grid>
</Border>
<!-- Update banner -->
<Border Grid.Row="1"
Background="{DynamicResource DeepBrush}"
BorderBrush="{DynamicResource LineBrush}"
BorderThickness="0,0,0,1"
Padding="14,6"
IsVisible="{Binding IsUpdateBannerVisible}">
<Grid ColumnDefinitions="*,Auto,Auto">
<TextBlock Grid.Column="0"
Classes="body"
VerticalAlignment="Center">
<Run Text="{loc:Tr shell.update.available}"/>
<Run Text="{Binding UpdateCheck.CurrentVersion}"/>
<Run Text=" → v"/>
<Run Text="{Binding UpdateBannerLatestVersion}"/>
</TextBlock>
<Button Grid.Column="1"
Classes="btn"
Margin="0,0,8,0"
Content="{loc:Tr shell.update.updateNow}"
Command="{Binding UpdateNowCommand}"/>
<Button Grid.Column="2"
Classes="btn"
Content="{loc:Tr shell.update.dismiss}"
Command="{Binding DismissBannerCommand}"/>
</Grid>
</Border>
<!-- Inline update status (appears at right of banner row when no banner) -->
<TextBlock Grid.Row="1"
Classes="meta"
HorizontalAlignment="Right"
VerticalAlignment="Center"
Margin="0,0,14,0"
Text="{Binding InlineUpdateStatus}"
IsVisible="{Binding InlineUpdateStatus, Converter={x:Static ObjectConverters.IsNotNull}}"/>
<!-- Background gradient layer -->
<Border Grid.Row="2">
<Border.Background>
<RadialGradientBrush Center="50%,50%" GradientOrigin="50%,50%" RadiusX="70%" RadiusY="70%">
<GradientStop Offset="0" Color="{StaticResource DeepColor}" />
<GradientStop Offset="1" Color="{StaticResource VoidColor}" />
</RadialGradientBrush>
</Border.Background>
</Border>
<!-- Three islands (user-resizable) -->
<Grid Grid.Row="2" Margin="7">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="260" MinWidth="200"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*" MinWidth="320"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="460" MinWidth="280"/>
</Grid.ColumnDefinitions>
<Border Grid.Column="0" Classes="island" Margin="3">
<islands:ListsIslandView DataContext="{Binding Lists}"/>
</Border>
<GridSplitter Grid.Column="1"
Width="3"
Background="Transparent"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
ResizeDirection="Columns"
ResizeBehavior="PreviousAndNext"/>
<Border Grid.Column="2" Classes="island" Margin="3">
<islands:TasksIslandView DataContext="{Binding Tasks}"/>
</Border>
<GridSplitter Grid.Column="3"
Width="3"
Background="Transparent"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
ResizeDirection="Columns"
ResizeBehavior="PreviousAndNext"
IsVisible="{Binding ShowDetails}"/>
<Border Grid.Column="4" Classes="island" Margin="3"
IsVisible="{Binding ShowDetails}">
<islands:DetailsIslandView DataContext="{Binding Details}"/>
</Border>
</Grid>
<!-- Footer: connection status -->
<Border Grid.Row="3"
Background="{DynamicResource DeepBrush}"
BorderBrush="{DynamicResource LineBrush}"
BorderThickness="0,1,0,0">
<DockPanel LastChildFill="True" Margin="14,0">
<!-- Left: connection pill (click to open worker help) -->
<Button DockPanel.Dock="Left"
Command="{Binding OpenWorkerConnectionHelpCommand}"
Background="Transparent" BorderThickness="0" Padding="0"
Cursor="Hand" VerticalAlignment="Center">
<StackPanel Orientation="Horizontal" Spacing="7" VerticalAlignment="Center">
<Ellipse Width="7" Height="7" Fill="{DynamicResource StatusRunningBrush}"
IsVisible="{Binding Worker.IsConnected}"/>
<Ellipse Width="7" Height="7" Fill="{DynamicResource StatusReviewBrush}"
IsVisible="{Binding Worker.IsReconnecting}"/>
<Ellipse Width="7" Height="7" Fill="{DynamicResource StatusErrorBrush}"
IsVisible="{Binding IsOffline}"/>
<TextBlock Classes="eyebrow"
Text="{Binding ConnectionText, Converter={StaticResource UpperCase}}"
LetterSpacing="1.4"
VerticalAlignment="Center"/>
</StackPanel>
</Button>
<!-- Right: worker log line -->
<TextBlock DockPanel.Dock="Right"
Classes="meta"
Text="{Binding WorkerLogText}"
IsVisible="{Binding IsWorkerLogVisible}"
Foreground="{Binding WorkerLogLevel, Converter={StaticResource WorkerLogLevelToBrush}}"
LetterSpacing="1.4"
TextTrimming="CharacterEllipsis"
VerticalAlignment="Center"/>
<!-- Right: prime status notification -->
<TextBlock DockPanel.Dock="Right"
Classes="meta"
Text="{Binding PrimeStatus}"
VerticalAlignment="Center"
Margin="12,0,0,0"
IsVisible="{Binding PrimeStatus, Converter={x:Static StringConverters.IsNotNullOrEmpty}}"/>
<!-- Spacer between pill and log -->
<Panel/>
</DockPanel>
</Border>
</Grid>
</Window>