From 940b72f8dd643724ce56b701169dbfd8ef129241 Mon Sep 17 00:00:00 2001 From: mika kuns Date: Mon, 20 Apr 2026 11:30:32 +0200 Subject: [PATCH] style(ui): tasks header toolbar and add-task row MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Reformat subtitle to "{Weekday}, {Month} {Day} · {open} open". - Add right-aligned running/review status pill (kbd style). - Add header icon toolbar: Sort, Eye (toggle completed), MoreHorizontal. - Wire Eye to IsShowingCompleted [ObservableProperty] on the VM. - Style add-task row as rounded Surface2 border with dashed Plus circle, borderless TextBox, and ENTER kbd chip visible on focus. Co-Authored-By: Claude Opus 4.7 (1M context) --- src/ClaudeDo.Ui/Design/IslandStyles.axaml | 178 ++++++++++++++++++ .../Islands/TasksIslandViewModel.cs | 72 ++++++- .../Views/Islands/TasksIslandView.axaml | 143 +++++++++++--- 3 files changed, 364 insertions(+), 29 deletions(-) diff --git a/src/ClaudeDo.Ui/Design/IslandStyles.axaml b/src/ClaudeDo.Ui/Design/IslandStyles.axaml index cc83799..c6d7b97 100644 --- a/src/ClaudeDo.Ui/Design/IslandStyles.axaml +++ b/src/ClaudeDo.Ui/Design/IslandStyles.axaml @@ -499,4 +499,182 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/ClaudeDo.Ui/ViewModels/Islands/TasksIslandViewModel.cs b/src/ClaudeDo.Ui/ViewModels/Islands/TasksIslandViewModel.cs index b750701..b096970 100644 --- a/src/ClaudeDo.Ui/ViewModels/Islands/TasksIslandViewModel.cs +++ b/src/ClaudeDo.Ui/ViewModels/Islands/TasksIslandViewModel.cs @@ -1,4 +1,5 @@ using System.Collections.ObjectModel; +using System.Globalization; using CommunityToolkit.Mvvm.ComponentModel; using CommunityToolkit.Mvvm.Input; using ClaudeDo.Data; @@ -19,12 +20,21 @@ public sealed partial class TasksIslandViewModel : ViewModelBase public void RequestFocusAddTask() => FocusAddTaskRequested?.Invoke(this, EventArgs.Empty); public ObservableCollection Items { get; } = new(); + public ObservableCollection OverdueItems { get; } = new(); + public ObservableCollection OpenItems { get; } = new(); + public ObservableCollection CompletedItems { get; } = new(); [ObservableProperty] private string _newTaskTitle = ""; [ObservableProperty] private TaskRowViewModel? _selectedTask; [ObservableProperty] private string _headerTitle = ""; [ObservableProperty] private string _headerEyebrow = ""; [ObservableProperty] private string _subtitle = ""; + [ObservableProperty] private string _statusPill = ""; + [ObservableProperty] private bool _hasStatusPill; + [ObservableProperty] private bool _isShowingCompleted = true; + [ObservableProperty] private bool _hasOverdue; + [ObservableProperty] private bool _hasCompleted; + [ObservableProperty] private string _completedHeader = "COMPLETED"; public TasksIslandViewModel(IDbContextFactory dbFactory) { @@ -40,10 +50,15 @@ public sealed partial class TasksIslandViewModel : ViewModelBase _currentList = list; Items.Clear(); + OverdueItems.Clear(); + OpenItems.Clear(); + CompletedItems.Clear(); + HasOverdue = false; + HasCompleted = false; if (list is null) return; HeaderTitle = list.Name; - HeaderEyebrow = DateTime.Now.ToString("dddd · MMM dd").ToUpperInvariant(); + HeaderEyebrow = DateTime.Now.ToString("dddd · MMM dd", CultureInfo.InvariantCulture).ToUpperInvariant(); _ = LoadForListAsync(list, ct); } @@ -74,17 +89,56 @@ public sealed partial class TasksIslandViewModel : ViewModelBase foreach (var t in filtered) Items.Add(TaskRowViewModel.FromEntity(t)); + Regroup(); UpdateSubtitle(); } catch (OperationCanceledException) { } } + private void Regroup() + { + OverdueItems.Clear(); + OpenItems.Clear(); + CompletedItems.Clear(); + + var today = DateTime.Today; + foreach (var r in Items) + { + if (r.Done) + CompletedItems.Add(r); + else if (r.ScheduledFor is { } d && d.Date < today) + OverdueItems.Add(r); + else + OpenItems.Add(r); + } + + HasOverdue = OverdueItems.Count > 0; + HasCompleted = CompletedItems.Count > 0; + CompletedHeader = $"COMPLETED · {CompletedItems.Count}"; + } + private void UpdateSubtitle() { + var now = DateTime.Now; var open = Items.Count(i => !i.Done); var running = Items.Count(i => i.Status == TaskStatus.Running); var review = Items.Count(i => i.Status == TaskStatus.Done && i.Branch != null); - Subtitle = $"{open} open · {running} running · {review} in review"; + + var weekday = now.ToString("dddd", CultureInfo.CurrentCulture); + var month = now.ToString("MMM", CultureInfo.CurrentCulture); + var day = now.Day; + Subtitle = $"{weekday}, {month} {day} · {open} open"; + + if (running > 0 || review > 0) + { + StatusPill = $"{running} running · {review} review"; + HasStatusPill = true; + } + else + { + StatusPill = ""; + HasStatusPill = false; + } } [RelayCommand] @@ -102,7 +156,9 @@ public sealed partial class TasksIslandViewModel : ViewModelBase await using var db = await _dbFactory.CreateDbContextAsync(); db.Tasks.Add(entity); await db.SaveChangesAsync(); - Items.Insert(0, TaskRowViewModel.FromEntity(entity)); + var row = TaskRowViewModel.FromEntity(entity); + Items.Insert(0, row); + Regroup(); NewTaskTitle = ""; UpdateSubtitle(); } @@ -119,6 +175,7 @@ public sealed partial class TasksIslandViewModel : ViewModelBase row.Status = entity.Status; await db.SaveChangesAsync(); } + Regroup(); UpdateSubtitle(); } @@ -138,6 +195,15 @@ public sealed partial class TasksIslandViewModel : ViewModelBase [RelayCommand] private void Select(TaskRowViewModel row) => SelectedTask = row; + [RelayCommand] + private void ToggleShowCompleted() => IsShowingCompleted = !IsShowingCompleted; + + [RelayCommand] + private void Sort() { /* placeholder — UI-only */ } + + [RelayCommand] + private void More() { /* placeholder — UI-only */ } + partial void OnSelectedTaskChanged(TaskRowViewModel? value) { foreach (var i in Items) i.IsSelected = ReferenceEquals(i, value); diff --git a/src/ClaudeDo.Ui/Views/Islands/TasksIslandView.axaml b/src/ClaudeDo.Ui/Views/Islands/TasksIslandView.axaml index c1a95e1..a60afbd 100644 --- a/src/ClaudeDo.Ui/Views/Islands/TasksIslandView.axaml +++ b/src/ClaudeDo.Ui/Views/Islands/TasksIslandView.axaml @@ -2,45 +2,136 @@ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:vm="using:ClaudeDo.Ui.ViewModels.Islands" xmlns:islands="using:ClaudeDo.Ui.Views.Islands" + xmlns:converters="using:Avalonia.Data.Converters" x:Class="ClaudeDo.Ui.Views.Islands.TasksIslandView" x:DataType="vm:TasksIslandViewModel"> - - - - - + + + + + + + + + + + + + + + + - - - - - - + + + + + + + + + + + + + + - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +