From 8909119d1ba5c6ad5a3bf0347ab86c679b855944 Mon Sep 17 00:00:00 2001 From: mika kuns Date: Mon, 20 Apr 2026 10:15:05 +0200 Subject: [PATCH] feat(ui): scaffold islands shell and child VMs --- src/ClaudeDo.App/Program.cs | 7 ++++ .../Islands/DetailsIslandViewModel.cs | 9 +++++ .../Islands/ListNavItemViewModel.cs | 12 +++++++ .../Islands/ListsIslandViewModel.cs | 11 +++++++ .../ViewModels/Islands/TaskRowViewModel.cs | 10 ++++++ .../Islands/TasksIslandViewModel.cs | 12 +++++++ .../ViewModels/IslandsShellViewModel.cs | 33 +++++++++++++++++++ 7 files changed, 94 insertions(+) create mode 100644 src/ClaudeDo.Ui/ViewModels/Islands/DetailsIslandViewModel.cs create mode 100644 src/ClaudeDo.Ui/ViewModels/Islands/ListNavItemViewModel.cs create mode 100644 src/ClaudeDo.Ui/ViewModels/Islands/ListsIslandViewModel.cs create mode 100644 src/ClaudeDo.Ui/ViewModels/Islands/TaskRowViewModel.cs create mode 100644 src/ClaudeDo.Ui/ViewModels/Islands/TasksIslandViewModel.cs create mode 100644 src/ClaudeDo.Ui/ViewModels/IslandsShellViewModel.cs diff --git a/src/ClaudeDo.App/Program.cs b/src/ClaudeDo.App/Program.cs index a3437fd..3fb6fb5 100644 --- a/src/ClaudeDo.App/Program.cs +++ b/src/ClaudeDo.App/Program.cs @@ -5,6 +5,7 @@ using ClaudeDo.Data.Repositories; using ClaudeDo.Ui; using ClaudeDo.Ui.Services; using ClaudeDo.Ui.ViewModels; +using ClaudeDo.Ui.ViewModels.Islands; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.DependencyInjection; using System; @@ -100,6 +101,12 @@ sealed class Program () => sp.GetRequiredService()); }); + // Islands shell VMs + sc.AddSingleton(); + sc.AddSingleton(); + sc.AddSingleton(); + sc.AddSingleton(); + return sc.BuildServiceProvider(); } } diff --git a/src/ClaudeDo.Ui/ViewModels/Islands/DetailsIslandViewModel.cs b/src/ClaudeDo.Ui/ViewModels/Islands/DetailsIslandViewModel.cs new file mode 100644 index 0000000..54134ed --- /dev/null +++ b/src/ClaudeDo.Ui/ViewModels/Islands/DetailsIslandViewModel.cs @@ -0,0 +1,9 @@ +using CommunityToolkit.Mvvm.ComponentModel; + +namespace ClaudeDo.Ui.ViewModels.Islands; + +public sealed partial class DetailsIslandViewModel : ViewModelBase +{ + [ObservableProperty] private TaskRowViewModel? _task; + public void Bind(TaskRowViewModel? task) => Task = task; +} diff --git a/src/ClaudeDo.Ui/ViewModels/Islands/ListNavItemViewModel.cs b/src/ClaudeDo.Ui/ViewModels/Islands/ListNavItemViewModel.cs new file mode 100644 index 0000000..851eab3 --- /dev/null +++ b/src/ClaudeDo.Ui/ViewModels/Islands/ListNavItemViewModel.cs @@ -0,0 +1,12 @@ +using CommunityToolkit.Mvvm.ComponentModel; + +namespace ClaudeDo.Ui.ViewModels.Islands; + +public sealed partial class ListNavItemViewModel : ViewModelBase +{ + public required string Id { get; init; } + public required string Name { get; init; } + [ObservableProperty] private int _count; + [ObservableProperty] private bool _isActive; + public string? IconKey { get; init; } +} diff --git a/src/ClaudeDo.Ui/ViewModels/Islands/ListsIslandViewModel.cs b/src/ClaudeDo.Ui/ViewModels/Islands/ListsIslandViewModel.cs new file mode 100644 index 0000000..29379c3 --- /dev/null +++ b/src/ClaudeDo.Ui/ViewModels/Islands/ListsIslandViewModel.cs @@ -0,0 +1,11 @@ +using CommunityToolkit.Mvvm.ComponentModel; + +namespace ClaudeDo.Ui.ViewModels.Islands; + +public sealed partial class ListsIslandViewModel : ViewModelBase +{ + public event EventHandler? SelectionChanged; + [ObservableProperty] private ListNavItemViewModel? _selectedList; + partial void OnSelectedListChanged(ListNavItemViewModel? value) => + SelectionChanged?.Invoke(this, EventArgs.Empty); +} diff --git a/src/ClaudeDo.Ui/ViewModels/Islands/TaskRowViewModel.cs b/src/ClaudeDo.Ui/ViewModels/Islands/TaskRowViewModel.cs new file mode 100644 index 0000000..4c07520 --- /dev/null +++ b/src/ClaudeDo.Ui/ViewModels/Islands/TaskRowViewModel.cs @@ -0,0 +1,10 @@ +using CommunityToolkit.Mvvm.ComponentModel; + +namespace ClaudeDo.Ui.ViewModels.Islands; + +public sealed partial class TaskRowViewModel : ViewModelBase +{ + public required string Id { get; init; } + [ObservableProperty] private string _title = ""; + [ObservableProperty] private bool _done; +} diff --git a/src/ClaudeDo.Ui/ViewModels/Islands/TasksIslandViewModel.cs b/src/ClaudeDo.Ui/ViewModels/Islands/TasksIslandViewModel.cs new file mode 100644 index 0000000..84c6ce5 --- /dev/null +++ b/src/ClaudeDo.Ui/ViewModels/Islands/TasksIslandViewModel.cs @@ -0,0 +1,12 @@ +using CommunityToolkit.Mvvm.ComponentModel; + +namespace ClaudeDo.Ui.ViewModels.Islands; + +public sealed partial class TasksIslandViewModel : ViewModelBase +{ + public event EventHandler? SelectionChanged; + [ObservableProperty] private TaskRowViewModel? _selectedTask; + public void LoadForList(ListNavItemViewModel? list) { /* Phase 5 */ } + partial void OnSelectedTaskChanged(TaskRowViewModel? value) => + SelectionChanged?.Invoke(this, EventArgs.Empty); +} diff --git a/src/ClaudeDo.Ui/ViewModels/IslandsShellViewModel.cs b/src/ClaudeDo.Ui/ViewModels/IslandsShellViewModel.cs new file mode 100644 index 0000000..1cd9d46 --- /dev/null +++ b/src/ClaudeDo.Ui/ViewModels/IslandsShellViewModel.cs @@ -0,0 +1,33 @@ +using CommunityToolkit.Mvvm.ComponentModel; +using ClaudeDo.Ui.ViewModels.Islands; + +namespace ClaudeDo.Ui.ViewModels; + +public sealed partial class IslandsShellViewModel : ViewModelBase +{ + public ListsIslandViewModel Lists { get; } + public TasksIslandViewModel Tasks { get; } + public DetailsIslandViewModel Details { get; } + + [ObservableProperty] + private double _windowWidth = 1280; + + public bool ShowDetails => WindowWidth >= 1100; + public bool ShowLists => WindowWidth >= 780; + + partial void OnWindowWidthChanged(double value) + { + OnPropertyChanged(nameof(ShowDetails)); + OnPropertyChanged(nameof(ShowLists)); + } + + public IslandsShellViewModel( + ListsIslandViewModel lists, + TasksIslandViewModel tasks, + DetailsIslandViewModel details) + { + Lists = lists; Tasks = tasks; Details = details; + Lists.SelectionChanged += (_, _) => Tasks.LoadForList(Lists.SelectedList); + Tasks.SelectionChanged += (_, _) => Details.Bind(Tasks.SelectedTask); + } +}