feat(ui): maximize work console via green traffic-light dot
This commit is contained in:
@@ -186,6 +186,9 @@
|
|||||||
"chipDone": "FERTIG",
|
"chipDone": "FERTIG",
|
||||||
"chipFailed": "FEHLGESCHLAGEN"
|
"chipFailed": "FEHLGESCHLAGEN"
|
||||||
},
|
},
|
||||||
|
"console": {
|
||||||
|
"maximizeTip": "Terminal maximieren / wiederherstellen"
|
||||||
|
},
|
||||||
"modals": {
|
"modals": {
|
||||||
"about": {
|
"about": {
|
||||||
"title": "ÜBER",
|
"title": "ÜBER",
|
||||||
|
|||||||
@@ -186,6 +186,9 @@
|
|||||||
"chipDone": "DONE",
|
"chipDone": "DONE",
|
||||||
"chipFailed": "FAILED"
|
"chipFailed": "FAILED"
|
||||||
},
|
},
|
||||||
|
"console": {
|
||||||
|
"maximizeTip": "Maximize / restore the terminal"
|
||||||
|
},
|
||||||
"modals": {
|
"modals": {
|
||||||
"about": {
|
"about": {
|
||||||
"title": "ABOUT",
|
"title": "ABOUT",
|
||||||
|
|||||||
@@ -62,6 +62,14 @@ public sealed partial class DetailsIslandViewModel : ViewModelBase
|
|||||||
partial void OnIsNotesModeChanged(bool value) => OnPropertyChanged(nameof(IsTaskDetailVisible));
|
partial void OnIsNotesModeChanged(bool value) => OnPropertyChanged(nameof(IsTaskDetailVisible));
|
||||||
partial void OnIsPrepModeChanged(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!;
|
public NotesEditorViewModel Notes { get; private set; } = null!;
|
||||||
|
|
||||||
// Current task row (set by IslandsShellViewModel via Bind)
|
// Current task row (set by IslandsShellViewModel via Bind)
|
||||||
|
|||||||
@@ -24,6 +24,18 @@
|
|||||||
<Setter Property="TextElement.Foreground" Value="{StaticResource AccentBrush}" />
|
<Setter Property="TextElement.Foreground" Value="{StaticResource AccentBrush}" />
|
||||||
</Style>
|
</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 -->
|
<!-- Terminal prompt action: bracketed text, no button chrome -->
|
||||||
<Style Selector="Button.prompt-action">
|
<Style Selector="Button.prompt-action">
|
||||||
<Setter Property="Background" Value="Transparent" />
|
<Setter Property="Background" Value="Transparent" />
|
||||||
@@ -60,12 +72,22 @@
|
|||||||
<Grid DockPanel.Dock="Top" ColumnDefinitions="Auto,*,Auto"
|
<Grid DockPanel.Dock="Top" ColumnDefinitions="Auto,*,Auto"
|
||||||
Background="{DynamicResource Surface2Brush}" Height="28">
|
Background="{DynamicResource Surface2Brush}" Height="28">
|
||||||
|
|
||||||
<!-- Traffic-light dots -->
|
<!-- Traffic-light dots; green toggles console maximize -->
|
||||||
<StackPanel Grid.Column="0" Orientation="Horizontal" Spacing="6"
|
<StackPanel Grid.Column="0" Orientation="Horizontal" Spacing="6"
|
||||||
Margin="12,0" VerticalAlignment="Center">
|
Margin="12,0" VerticalAlignment="Center">
|
||||||
<Ellipse Classes="dot-red" />
|
<Ellipse Classes="dot-red" />
|
||||||
<Ellipse Classes="dot-yellow" />
|
<Ellipse Classes="dot-yellow" />
|
||||||
<Ellipse Classes="dot-green" />
|
<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>
|
</StackPanel>
|
||||||
|
|
||||||
<!-- Right cluster: info header (model · turns · diff) + status chip -->
|
<!-- Right cluster: info header (model · turns · diff) + status chip -->
|
||||||
|
|||||||
@@ -39,15 +39,22 @@
|
|||||||
<Grid>
|
<Grid>
|
||||||
|
|
||||||
<!-- Task detail: description/steps card (upper) + pinned work console (lower) -->
|
<!-- Task detail: description/steps card (upper) + pinned work console (lower) -->
|
||||||
<Grid IsVisible="{Binding IsTaskDetailVisible}"
|
<Grid x:Name="DetailBodyGrid"
|
||||||
Margin="14,12,14,12"
|
IsVisible="{Binding IsTaskDetailVisible}"
|
||||||
RowDefinitions="2*,*">
|
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">
|
<ScrollViewer Grid.Row="0" VerticalScrollBarVisibility="Auto">
|
||||||
<detail:DescriptionStepsCard VerticalAlignment="Top"/>
|
<detail:DescriptionStepsCard VerticalAlignment="Top"/>
|
||||||
</ScrollViewer>
|
</ScrollViewer>
|
||||||
<detail:WorkConsole Grid.Row="1" Margin="0,10,0,0"/>
|
<detail:WorkConsole Grid.Row="1" Margin="0,10,0,0"/>
|
||||||
<!-- Resize by dragging the console's top edge — a transparent splitter
|
<!-- 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"
|
<GridSplitter Grid.Row="1"
|
||||||
VerticalAlignment="Top"
|
VerticalAlignment="Top"
|
||||||
Height="10"
|
Height="10"
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
using System.ComponentModel;
|
||||||
using Avalonia;
|
using Avalonia;
|
||||||
using Avalonia.Controls;
|
using Avalonia.Controls;
|
||||||
using Avalonia.Layout;
|
using Avalonia.Layout;
|
||||||
@@ -10,6 +11,8 @@ namespace ClaudeDo.Ui.Views.Islands;
|
|||||||
|
|
||||||
public partial class DetailsIslandView : UserControl
|
public partial class DetailsIslandView : UserControl
|
||||||
{
|
{
|
||||||
|
private DetailsIslandViewModel? _subscribedVm;
|
||||||
|
|
||||||
public DetailsIslandView()
|
public DetailsIslandView()
|
||||||
{
|
{
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
@@ -18,6 +21,15 @@ public partial class DetailsIslandView : UserControl
|
|||||||
|
|
||||||
private void OnDataContextChanged(object? sender, EventArgs e)
|
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)
|
if (DataContext is DetailsIslandViewModel vm)
|
||||||
{
|
{
|
||||||
vm.ShowDiffModal = async (diffVm) =>
|
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)
|
private async System.Threading.Tasks.Task ShowErrorDialogAsync(string message)
|
||||||
{
|
{
|
||||||
var owner = TopLevel.GetTopLevel(this) as Window;
|
var owner = TopLevel.GetTopLevel(this) as Window;
|
||||||
|
|||||||
Reference in New Issue
Block a user