feat(ui): pulse, hover, modal, and row-add animations
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -162,6 +162,11 @@
|
|||||||
<Setter Property="CornerRadius" Value="8" />
|
<Setter Property="CornerRadius" Value="8" />
|
||||||
<Setter Property="Background" Value="Transparent" />
|
<Setter Property="Background" Value="Transparent" />
|
||||||
<Setter Property="Cursor" Value="Hand" />
|
<Setter Property="Cursor" Value="Hand" />
|
||||||
|
<Setter Property="Transitions">
|
||||||
|
<Transitions>
|
||||||
|
<BrushTransition Property="Background" Duration="0:0:0.10"/>
|
||||||
|
</Transitions>
|
||||||
|
</Setter>
|
||||||
</Style>
|
</Style>
|
||||||
<Style Selector="Border.task-row:pointerover">
|
<Style Selector="Border.task-row:pointerover">
|
||||||
<Setter Property="Background" Value="{StaticResource Surface2Brush}" />
|
<Setter Property="Background" Value="{StaticResource Surface2Brush}" />
|
||||||
@@ -186,6 +191,17 @@
|
|||||||
<Setter Property="Fill" Value="{StaticResource AccentBrush}" />
|
<Setter Property="Fill" Value="{StaticResource AccentBrush}" />
|
||||||
</Style>
|
</Style>
|
||||||
|
|
||||||
|
<!-- Status dot pulse (applied when running) -->
|
||||||
|
<Style Selector="Ellipse.status-pulse">
|
||||||
|
<Style.Animations>
|
||||||
|
<Animation Duration="0:0:1.2" IterationCount="INFINITE" Easing="CubicEaseInOut">
|
||||||
|
<KeyFrame Cue="0%"><Setter Property="Opacity" Value="0.4"/></KeyFrame>
|
||||||
|
<KeyFrame Cue="50%"><Setter Property="Opacity" Value="1.0"/></KeyFrame>
|
||||||
|
<KeyFrame Cue="100%"><Setter Property="Opacity" Value="0.4"/></KeyFrame>
|
||||||
|
</Animation>
|
||||||
|
</Style.Animations>
|
||||||
|
</Style>
|
||||||
|
|
||||||
<!-- ============================================================ -->
|
<!-- ============================================================ -->
|
||||||
<!-- AGENT STRIP -->
|
<!-- AGENT STRIP -->
|
||||||
<!-- ============================================================ -->
|
<!-- ============================================================ -->
|
||||||
|
|||||||
@@ -26,6 +26,9 @@ public sealed partial class DetailsIslandViewModel : ViewModelBase
|
|||||||
|
|
||||||
// Agent strip fields
|
// Agent strip fields
|
||||||
[ObservableProperty] private string _agentStatusLabel = "Idle";
|
[ObservableProperty] private string _agentStatusLabel = "Idle";
|
||||||
|
public bool IsRunning => AgentStatusLabel == "Running";
|
||||||
|
|
||||||
|
partial void OnAgentStatusLabelChanged(string value) => OnPropertyChanged(nameof(IsRunning));
|
||||||
[ObservableProperty] private string? _model;
|
[ObservableProperty] private string? _model;
|
||||||
[ObservableProperty] private string? _worktreePath;
|
[ObservableProperty] private string? _worktreePath;
|
||||||
[ObservableProperty] private string? _branchLine;
|
[ObservableProperty] private string? _branchLine;
|
||||||
|
|||||||
@@ -7,7 +7,8 @@
|
|||||||
<StackPanel Margin="14,12" Spacing="6">
|
<StackPanel Margin="14,12" Spacing="6">
|
||||||
<!-- Row 1: status dot · status label · model · turns · tokens -->
|
<!-- Row 1: status dot · status label · model · turns · tokens -->
|
||||||
<StackPanel Orientation="Horizontal" Spacing="10">
|
<StackPanel Orientation="Horizontal" Spacing="10">
|
||||||
<Ellipse Width="8" Height="8" Fill="{DynamicResource MossBrush}" VerticalAlignment="Center"/>
|
<Ellipse Width="8" Height="8" Fill="{DynamicResource MossBrush}" VerticalAlignment="Center"
|
||||||
|
Classes.status-pulse="{Binding IsRunning}"/>
|
||||||
<TextBlock Text="{Binding AgentStatusLabel}" FontSize="12"
|
<TextBlock Text="{Binding AgentStatusLabel}" FontSize="12"
|
||||||
Foreground="{DynamicResource TextBrush}" VerticalAlignment="Center"/>
|
Foreground="{DynamicResource TextBrush}" VerticalAlignment="Center"/>
|
||||||
<TextBlock Text="{Binding Model}" FontFamily="{DynamicResource MonoFamily}"
|
<TextBlock Text="{Binding Model}" FontFamily="{DynamicResource MonoFamily}"
|
||||||
|
|||||||
@@ -1,8 +1,33 @@
|
|||||||
|
using Avalonia;
|
||||||
|
using Avalonia.Animation;
|
||||||
|
using Avalonia.Animation.Easings;
|
||||||
using Avalonia.Controls;
|
using Avalonia.Controls;
|
||||||
|
using Avalonia.Media;
|
||||||
|
using Avalonia.Styling;
|
||||||
|
|
||||||
namespace ClaudeDo.Ui.Views.Islands;
|
namespace ClaudeDo.Ui.Views.Islands;
|
||||||
|
|
||||||
public partial class TaskRowView : UserControl
|
public partial class TaskRowView : UserControl
|
||||||
{
|
{
|
||||||
public TaskRowView() { InitializeComponent(); }
|
public TaskRowView() { InitializeComponent(); }
|
||||||
|
|
||||||
|
protected override async void OnAttachedToVisualTree(VisualTreeAttachmentEventArgs e)
|
||||||
|
{
|
||||||
|
base.OnAttachedToVisualTree(e);
|
||||||
|
RenderTransform = new TranslateTransform(0, 8);
|
||||||
|
Opacity = 0;
|
||||||
|
var anim = new Avalonia.Animation.Animation
|
||||||
|
{
|
||||||
|
Duration = TimeSpan.FromMilliseconds(300),
|
||||||
|
Easing = new CubicEaseOut(),
|
||||||
|
Children =
|
||||||
|
{
|
||||||
|
new KeyFrame { Cue = new Cue(0), Setters = { new Setter(OpacityProperty, 0d) } },
|
||||||
|
new KeyFrame { Cue = new Cue(1), Setters = { new Setter(OpacityProperty, 1d) } },
|
||||||
|
}
|
||||||
|
};
|
||||||
|
await anim.RunAsync(this);
|
||||||
|
Opacity = 1;
|
||||||
|
RenderTransform = null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,10 @@
|
|||||||
|
using Avalonia;
|
||||||
|
using Avalonia.Animation;
|
||||||
|
using Avalonia.Animation.Easings;
|
||||||
using Avalonia.Controls;
|
using Avalonia.Controls;
|
||||||
using Avalonia.Input;
|
using Avalonia.Input;
|
||||||
|
using Avalonia.Media;
|
||||||
|
using Avalonia.Styling;
|
||||||
using ClaudeDo.Ui.ViewModels.Modals;
|
using ClaudeDo.Ui.ViewModels.Modals;
|
||||||
|
|
||||||
namespace ClaudeDo.Ui.Views.Modals;
|
namespace ClaudeDo.Ui.Views.Modals;
|
||||||
@@ -18,6 +23,27 @@ public partial class DiffModalView : Window
|
|||||||
vm.CloseAction = Close;
|
vm.CloseAction = Close;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected override async void OnOpened(EventArgs e)
|
||||||
|
{
|
||||||
|
base.OnOpened(e);
|
||||||
|
Opacity = 0;
|
||||||
|
RenderTransform = new ScaleTransform(0.98, 0.98);
|
||||||
|
var anim = new Avalonia.Animation.Animation
|
||||||
|
{
|
||||||
|
Duration = TimeSpan.FromMilliseconds(180),
|
||||||
|
Easing = new CubicEaseOut(),
|
||||||
|
FillMode = FillMode.Forward,
|
||||||
|
Children =
|
||||||
|
{
|
||||||
|
new KeyFrame { Cue = new Cue(0), Setters = { new Setter(OpacityProperty, 0d) } },
|
||||||
|
new KeyFrame { Cue = new Cue(1), Setters = { new Setter(OpacityProperty, 1d) } },
|
||||||
|
}
|
||||||
|
};
|
||||||
|
await anim.RunAsync(this);
|
||||||
|
Opacity = 1;
|
||||||
|
RenderTransform = new ScaleTransform(1.0, 1.0);
|
||||||
|
}
|
||||||
|
|
||||||
private void TitleBar_PointerPressed(object? sender, PointerPressedEventArgs e)
|
private void TitleBar_PointerPressed(object? sender, PointerPressedEventArgs e)
|
||||||
{
|
{
|
||||||
if (e.GetCurrentPoint(this).Properties.IsLeftButtonPressed)
|
if (e.GetCurrentPoint(this).Properties.IsLeftButtonPressed)
|
||||||
|
|||||||
@@ -1,5 +1,10 @@
|
|||||||
|
using Avalonia;
|
||||||
|
using Avalonia.Animation;
|
||||||
|
using Avalonia.Animation.Easings;
|
||||||
using Avalonia.Controls;
|
using Avalonia.Controls;
|
||||||
using Avalonia.Input;
|
using Avalonia.Input;
|
||||||
|
using Avalonia.Media;
|
||||||
|
using Avalonia.Styling;
|
||||||
using ClaudeDo.Ui.ViewModels.Modals;
|
using ClaudeDo.Ui.ViewModels.Modals;
|
||||||
|
|
||||||
namespace ClaudeDo.Ui.Views.Modals;
|
namespace ClaudeDo.Ui.Views.Modals;
|
||||||
@@ -18,6 +23,27 @@ public partial class WorktreeModalView : Window
|
|||||||
vm.CloseAction = Close;
|
vm.CloseAction = Close;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected override async void OnOpened(EventArgs e)
|
||||||
|
{
|
||||||
|
base.OnOpened(e);
|
||||||
|
Opacity = 0;
|
||||||
|
RenderTransform = new ScaleTransform(0.98, 0.98);
|
||||||
|
var anim = new Avalonia.Animation.Animation
|
||||||
|
{
|
||||||
|
Duration = TimeSpan.FromMilliseconds(180),
|
||||||
|
Easing = new CubicEaseOut(),
|
||||||
|
FillMode = FillMode.Forward,
|
||||||
|
Children =
|
||||||
|
{
|
||||||
|
new KeyFrame { Cue = new Cue(0), Setters = { new Setter(OpacityProperty, 0d) } },
|
||||||
|
new KeyFrame { Cue = new Cue(1), Setters = { new Setter(OpacityProperty, 1d) } },
|
||||||
|
}
|
||||||
|
};
|
||||||
|
await anim.RunAsync(this);
|
||||||
|
Opacity = 1;
|
||||||
|
RenderTransform = new ScaleTransform(1.0, 1.0);
|
||||||
|
}
|
||||||
|
|
||||||
private void OnTitleBarPressed(object? sender, PointerPressedEventArgs e)
|
private void OnTitleBarPressed(object? sender, PointerPressedEventArgs e)
|
||||||
{
|
{
|
||||||
if (e.GetCurrentPoint(this).Properties.IsLeftButtonPressed)
|
if (e.GetCurrentPoint(this).Properties.IsLeftButtonPressed)
|
||||||
|
|||||||
Reference in New Issue
Block a user