feat(ui): maximize work console via green traffic-light dot
This commit is contained in:
@@ -186,6 +186,9 @@
|
||||
"chipDone": "FERTIG",
|
||||
"chipFailed": "FEHLGESCHLAGEN"
|
||||
},
|
||||
"console": {
|
||||
"maximizeTip": "Terminal maximieren / wiederherstellen"
|
||||
},
|
||||
"modals": {
|
||||
"about": {
|
||||
"title": "ÜBER",
|
||||
|
||||
@@ -186,6 +186,9 @@
|
||||
"chipDone": "DONE",
|
||||
"chipFailed": "FAILED"
|
||||
},
|
||||
"console": {
|
||||
"maximizeTip": "Maximize / restore the terminal"
|
||||
},
|
||||
"modals": {
|
||||
"about": {
|
||||
"title": "ABOUT",
|
||||
|
||||
@@ -62,6 +62,14 @@ public sealed partial class DetailsIslandViewModel : ViewModelBase
|
||||
partial void OnIsNotesModeChanged(bool value) => OnPropertyChanged(nameof(IsTaskDetailVisible));
|
||||
partial void OnIsPrepModeChanged(bool value) => OnPropertyChanged(nameof(IsTaskDetailVisible));
|
||||
|
||||
// Console maximize: green dot shrinks the description row to its MinHeight so
|
||||
// the WorkConsole fills the rest. The row stays draggable and never overlaps.
|
||||
// Applied in DetailsIslandView code-behind (RowDefinitions can't bind).
|
||||
[ObservableProperty] private bool _isConsoleMaximized;
|
||||
|
||||
[RelayCommand]
|
||||
private void ToggleConsoleMaximized() => IsConsoleMaximized = !IsConsoleMaximized;
|
||||
|
||||
public NotesEditorViewModel Notes { get; private set; } = null!;
|
||||
|
||||
// Current task row (set by IslandsShellViewModel via Bind)
|
||||
|
||||
@@ -24,6 +24,18 @@
|
||||
<Setter Property="TextElement.Foreground" Value="{StaticResource AccentBrush}" />
|
||||
</Style>
|
||||
|
||||
<!-- Traffic-light dot button: no chrome, just the ellipse -->
|
||||
<Style Selector="Button.dot-btn">
|
||||
<Setter Property="Background" Value="Transparent" />
|
||||
<Setter Property="BorderThickness" Value="0" />
|
||||
<Setter Property="Padding" Value="0" />
|
||||
<Setter Property="CornerRadius" Value="0" />
|
||||
<Setter Property="Cursor" Value="Hand" />
|
||||
</Style>
|
||||
<Style Selector="Button.dot-btn /template/ ContentPresenter">
|
||||
<Setter Property="Background" Value="Transparent" />
|
||||
</Style>
|
||||
|
||||
<!-- Terminal prompt action: bracketed text, no button chrome -->
|
||||
<Style Selector="Button.prompt-action">
|
||||
<Setter Property="Background" Value="Transparent" />
|
||||
@@ -60,12 +72,22 @@
|
||||
<Grid DockPanel.Dock="Top" ColumnDefinitions="Auto,*,Auto"
|
||||
Background="{DynamicResource Surface2Brush}" Height="28">
|
||||
|
||||
<!-- Traffic-light dots -->
|
||||
<!-- Traffic-light dots; green toggles console maximize -->
|
||||
<StackPanel Grid.Column="0" Orientation="Horizontal" Spacing="6"
|
||||
Margin="12,0" VerticalAlignment="Center">
|
||||
<Ellipse Classes="dot-red" />
|
||||
<Ellipse Classes="dot-yellow" />
|
||||
<Button Classes="dot-btn"
|
||||
Command="{Binding ToggleConsoleMaximizedCommand}"
|
||||
ToolTip.Tip="{loc:Tr console.maximizeTip}">
|
||||
<Panel>
|
||||
<Ellipse Classes="dot-green" />
|
||||
<PathIcon Data="{StaticResource Icon.ArrowOut}"
|
||||
Width="6" Height="6"
|
||||
Foreground="{DynamicResource MossBrightBrush}"
|
||||
HorizontalAlignment="Center" VerticalAlignment="Center" />
|
||||
</Panel>
|
||||
</Button>
|
||||
</StackPanel>
|
||||
|
||||
<!-- Right cluster: info header (model · turns · diff) + status chip -->
|
||||
|
||||
@@ -39,15 +39,22 @@
|
||||
<Grid>
|
||||
|
||||
<!-- Task detail: description/steps card (upper) + pinned work console (lower) -->
|
||||
<Grid IsVisible="{Binding IsTaskDetailVisible}"
|
||||
Margin="14,12,14,12"
|
||||
RowDefinitions="2*,*">
|
||||
<Grid x:Name="DetailBodyGrid"
|
||||
IsVisible="{Binding IsTaskDetailVisible}"
|
||||
Margin="14,12,14,12">
|
||||
<Grid.RowDefinitions>
|
||||
<!-- MinHeight keeps the description visible: the console can never
|
||||
overlap it, whether maximized (code-behind) or dragged. -->
|
||||
<RowDefinition Height="2*" MinHeight="90"/>
|
||||
<RowDefinition Height="*"/>
|
||||
</Grid.RowDefinitions>
|
||||
<ScrollViewer Grid.Row="0" VerticalScrollBarVisibility="Auto">
|
||||
<detail:DescriptionStepsCard VerticalAlignment="Top"/>
|
||||
</ScrollViewer>
|
||||
<detail:WorkConsole Grid.Row="1" Margin="0,10,0,0"/>
|
||||
<!-- Resize by dragging the console's top edge — a transparent splitter
|
||||
over the gap above the console; no standalone separator bar. -->
|
||||
over the gap above the console; no standalone separator bar.
|
||||
Stays draggable while maximized. -->
|
||||
<GridSplitter Grid.Row="1"
|
||||
VerticalAlignment="Top"
|
||||
Height="10"
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
using System.ComponentModel;
|
||||
using Avalonia;
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Layout;
|
||||
@@ -10,6 +11,8 @@ namespace ClaudeDo.Ui.Views.Islands;
|
||||
|
||||
public partial class DetailsIslandView : UserControl
|
||||
{
|
||||
private DetailsIslandViewModel? _subscribedVm;
|
||||
|
||||
public DetailsIslandView()
|
||||
{
|
||||
InitializeComponent();
|
||||
@@ -18,6 +21,15 @@ public partial class DetailsIslandView : UserControl
|
||||
|
||||
private void OnDataContextChanged(object? sender, EventArgs e)
|
||||
{
|
||||
if (_subscribedVm is not null)
|
||||
_subscribedVm.PropertyChanged -= OnVmPropertyChanged;
|
||||
_subscribedVm = DataContext as DetailsIslandViewModel;
|
||||
if (_subscribedVm is not null)
|
||||
{
|
||||
_subscribedVm.PropertyChanged += OnVmPropertyChanged;
|
||||
ApplyConsoleMaximized(_subscribedVm.IsConsoleMaximized);
|
||||
}
|
||||
|
||||
if (DataContext is DetailsIslandViewModel vm)
|
||||
{
|
||||
vm.ShowDiffModal = async (diffVm) =>
|
||||
@@ -49,6 +61,24 @@ public partial class DetailsIslandView : UserControl
|
||||
}
|
||||
}
|
||||
|
||||
private void OnVmPropertyChanged(object? sender, PropertyChangedEventArgs e)
|
||||
{
|
||||
if (e.PropertyName == nameof(DetailsIslandViewModel.IsConsoleMaximized)
|
||||
&& sender is DetailsIslandViewModel vm)
|
||||
ApplyConsoleMaximized(vm.IsConsoleMaximized);
|
||||
}
|
||||
|
||||
// Maximized: shrink the description row to its MinHeight (the console fills
|
||||
// the rest). Restored: back to the 2:1 default. The GridSplitter keeps both
|
||||
// states draggable; MinHeight stops the console from ever covering it.
|
||||
private void ApplyConsoleMaximized(bool maximized)
|
||||
{
|
||||
var descRow = DetailBodyGrid.RowDefinitions[0];
|
||||
descRow.Height = maximized
|
||||
? new GridLength(descRow.MinHeight, GridUnitType.Pixel)
|
||||
: new GridLength(2, GridUnitType.Star);
|
||||
}
|
||||
|
||||
private async System.Threading.Tasks.Task ShowErrorDialogAsync(string message)
|
||||
{
|
||||
var owner = TopLevel.GetTopLevel(this) as Window;
|
||||
|
||||
Reference in New Issue
Block a user