From 359bb3a43926d37aa0bde996e336e13b8f610abb Mon Sep 17 00:00:00 2001 From: mika kuns Date: Mon, 10 Aug 2026 13:58:40 +0200 Subject: [PATCH] refactor(ui): clean up task-row drag visuals Collapse the grabbed row out of layout instead of overlapping neighbors with scale/opacity/shadow (the ghost window already shows the moving snapshot). Replace the thin moss drop-hint lines with a dashed placeholder gap sized like a collapsed row. Suppress the ordinary hover highlight and transitions on whatever row is currently the drop target so it doesn't read as "clickable" while dragging. --- src/ClaudeDo.Ui/Design/IslandStyles.axaml | 19 +++++++++++----- .../ViewModels/Islands/TaskRowViewModel.cs | 6 +++++ .../Views/Islands/TaskRowView.axaml | 18 ++++++++------- .../UiVm/TaskRowViewModelTests.cs | 22 +++++++++++++++++++ 4 files changed, 52 insertions(+), 13 deletions(-) diff --git a/src/ClaudeDo.Ui/Design/IslandStyles.axaml b/src/ClaudeDo.Ui/Design/IslandStyles.axaml index c6870765..9b7d5994 100644 --- a/src/ClaudeDo.Ui/Design/IslandStyles.axaml +++ b/src/ClaudeDo.Ui/Design/IslandStyles.axaml @@ -484,12 +484,21 @@ - + + + + + diff --git a/src/ClaudeDo.Ui/ViewModels/Islands/TaskRowViewModel.cs b/src/ClaudeDo.Ui/ViewModels/Islands/TaskRowViewModel.cs index 3e3f0e66..c0649ebe 100644 --- a/src/ClaudeDo.Ui/ViewModels/Islands/TaskRowViewModel.cs +++ b/src/ClaudeDo.Ui/ViewModels/Islands/TaskRowViewModel.cs @@ -45,6 +45,10 @@ public sealed partial class TaskRowViewModel : ViewModelBase // Set by the custom drag while this row is being dragged — drives the "grabbed" row style. [ObservableProperty] private bool _isDragging; + // True while a drag is hovering this row (i.e. it would show a drop-hint gap). Used to + // suppress the ordinary hover highlight/transitions so they don't fight the hint. + public bool IsDropTarget => DropHintAbove || DropHintBelow; + public bool CanRefine => Status == TaskStatus.Idle && PlanningPhase == PlanningPhase.None && !IsRefining && !IsManual; @@ -289,6 +293,8 @@ public sealed partial class TaskRowViewModel : ViewModelBase partial void OnDiffAdditionsChanged(int value) { OnPropertyChanged(nameof(HasDiff)); OnPropertyChanged(nameof(DiffAdditionsText)); } partial void OnDiffDeletionsChanged(int value) { OnPropertyChanged(nameof(HasDiff)); OnPropertyChanged(nameof(DiffDeletionsText)); } partial void OnRoadblockCountChanged(int value) { OnPropertyChanged(nameof(HasRoadblock)); OnPropertyChanged(nameof(RoadblockTooltip)); } + partial void OnDropHintAboveChanged(bool value) => OnPropertyChanged(nameof(IsDropTarget)); + partial void OnDropHintBelowChanged(bool value) => OnPropertyChanged(nameof(IsDropTarget)); public void RefreshLocalized() { diff --git a/src/ClaudeDo.Ui/Views/Islands/TaskRowView.axaml b/src/ClaudeDo.Ui/Views/Islands/TaskRowView.axaml index dd3f4ee9..cf4bc51e 100644 --- a/src/ClaudeDo.Ui/Views/Islands/TaskRowView.axaml +++ b/src/ClaudeDo.Ui/Views/Islands/TaskRowView.axaml @@ -7,15 +7,16 @@ x:DataType="vm:TaskRowViewModel"> - + - - + + + + @@ -31,6 +32,7 @@ Margin="0" Classes.selected="{Binding IsSelected}" Classes.dragging="{Binding IsDragging}" + Classes.drop-target="{Binding IsDropTarget}" Classes.done="{Binding Done}" ContextRequested="OnRowContextRequested"> @@ -202,9 +204,9 @@ - - + + diff --git a/tests/ClaudeDo.Worker.Tests/UiVm/TaskRowViewModelTests.cs b/tests/ClaudeDo.Worker.Tests/UiVm/TaskRowViewModelTests.cs index 9044eb88..a8a2166d 100644 --- a/tests/ClaudeDo.Worker.Tests/UiVm/TaskRowViewModelTests.cs +++ b/tests/ClaudeDo.Worker.Tests/UiVm/TaskRowViewModelTests.cs @@ -1,3 +1,4 @@ +using System.Collections.Generic; using ClaudeDo.Data.Models; using ClaudeDo.Ui.ViewModels.Islands; using Xunit; @@ -20,4 +21,25 @@ public class TaskRowViewModelTests vm.Status = s; Assert.Equal(expected, vm.StatusChipClass); } + + [Fact] + public void IsDropTarget_Follows_Either_DropHint_And_Raises_PropertyChanged() + { + var vm = new TaskRowViewModel { Id = "t" }; + var raised = new List(); + vm.PropertyChanged += (_, e) => raised.Add(e.PropertyName); + + Assert.False(vm.IsDropTarget); + + vm.DropHintAbove = true; + Assert.True(vm.IsDropTarget); + Assert.Contains(nameof(TaskRowViewModel.IsDropTarget), raised); + + vm.DropHintAbove = false; + vm.DropHintBelow = true; + Assert.True(vm.IsDropTarget); + + vm.DropHintBelow = false; + Assert.False(vm.IsDropTarget); + } }