9.8 KiB
MyDay Icon Buttons + Terminal Reuse + Sort Icon Fix — Plan
For agentic workers: REQUIRED SUB-SKILL: superpowers:subagent-driven-development. Steps use
- [ ].
Goal: Move the "Clear day" and "Prep log" actions into the MyDay header icon row as icon buttons (broom + list), render the prep log in the real SessionTerminalView ("cool terminal") by making that control reusable, and fix the invisible Sort icon.
Approved design (chat):
- Header icon row (
TasksIslandView.axaml, the Sort/Eye/Settingsicon-btnStackPanel) gets two moreicon-btn, bothIsVisible="{Binding IsMyDayList}", inserted after the Eye button: broom (Icon.Broom) →ClearDayCommand, list (Icon.List) →ShowPrepLogCommand. The two full-width text buttons "Prep log" and "Clear day" are removed. "Tag vorbereiten" stays as the full-width button (already opens the prep view viaPrepRequested). SessionTerminalViewbecomes reusable via StyledProperties so it renders both the taskLogand the prepPrepLogwith the same terminal look. The prep panel inDetailsIslandViewembeds it instead of the copiedItemsControl.- Sort icon bug:
PathIconfills geometry;Icon.Sortis an open-line path (no enclosed area) → invisible. Replace with a filled geometry. New icons (Broom, List) are authored as filled geometries too.
Tech: Avalonia (PathIcon/StreamGeometry, StyledProperty), CommunityToolkit.Mvvm, xUnit.
Build/test
.slnx needs .NET 9 — build the csproj. Use -c Release if a Worker locks Debug.
dotnet build src/ClaudeDo.App/ClaudeDo.App.csproj -c Release
dotnet test tests/ClaudeDo.Ui.Tests/ClaudeDo.Ui.Tests.csproj -c Release
dotnet test tests/ClaudeDo.Localization.Tests/ClaudeDo.Localization.Tests.csproj -c Release
GUI cannot be smoke-tested headlessly — note it; the human verifies visuals.
Task A: Icons + reusable SessionTerminalView
Files:
-
Modify:
src/ClaudeDo.Ui/Design/IslandStyles.axaml(icon geometries) -
Modify:
src/ClaudeDo.Ui/Views/Islands/SessionTerminalView.axaml+SessionTerminalView.axaml.cs -
Modify:
src/ClaudeDo.Ui/Views/Islands/DetailsIslandView.axaml(both embeds) -
Step 1: Fix
Icon.Sort+ addIcon.Broom,Icon.Listas filled geometries inIslandStyles.axaml(in theStyles.Resourcesicon block). Replace the existingIcon.Sortline and add the two new ones:
<!-- Icon.Sort (filled bars, decreasing width) -->
<StreamGeometry x:Key="Icon.Sort">M4 6 H20 V8 H4 Z M4 11 H16 V13 H4 Z M4 16 H11 V18 H4 Z</StreamGeometry>
<!-- Icon.Broom (filled: handle + binding band + flared bristles) -->
<StreamGeometry x:Key="Icon.Broom">M11 3 H13 V10 H11 Z M8.5 10 H15.5 V12 H8.5 Z M9 12 H15 L17 21 H7 Z</StreamGeometry>
<!-- Icon.List (filled: square bullets + lines) -->
<StreamGeometry x:Key="Icon.List">M4 5 H6 V7 H4 Z M8 5 H20 V7 H8 Z M4 11 H6 V13 H4 Z M8 11 H20 V13 H8 Z M4 17 H6 V19 H4 Z M8 17 H20 V19 H8 Z</StreamGeometry>
- Step 2: Add StyledProperties to
SessionTerminalView(code-behindSessionTerminalView.axaml.cs). Add public StyledProperties and CLR wrappers:
public static readonly StyledProperty<System.Collections.IEnumerable?> EntriesProperty =
AvaloniaProperty.Register<SessionTerminalView, System.Collections.IEnumerable?>(nameof(Entries));
public static readonly StyledProperty<string?> LabelProperty =
AvaloniaProperty.Register<SessionTerminalView, string?>(nameof(Label));
public static readonly StyledProperty<bool> IsRunningProperty =
AvaloniaProperty.Register<SessionTerminalView, bool>(nameof(IsRunning));
public static readonly StyledProperty<bool> IsDoneProperty =
AvaloniaProperty.Register<SessionTerminalView, bool>(nameof(IsDone));
public static readonly StyledProperty<bool> IsFailedProperty =
AvaloniaProperty.Register<SessionTerminalView, bool>(nameof(IsFailed));
public System.Collections.IEnumerable? Entries { get => GetValue(EntriesProperty); set => SetValue(EntriesProperty, value); }
public string? Label { get => GetValue(LabelProperty); set => SetValue(LabelProperty, value); }
public bool IsRunning { get => GetValue(IsRunningProperty); set => SetValue(IsRunningProperty, value); }
public bool IsDone { get => GetValue(IsDoneProperty); set => SetValue(IsDoneProperty, value); }
public bool IsFailed { get => GetValue(IsFailedProperty); set => SetValue(IsFailedProperty, value); }
Replace the existing auto-scroll hook (which cast DataContext as DetailsIslandViewModel and watched .Log.CollectionChanged) with one that watches whichever collection Entries points at: in OnPropertyChanged, when change.Property == EntriesProperty, detach the old INotifyCollectionChanged.CollectionChanged handler and attach to the new value (if it implements INotifyCollectionChanged); the handler scrolls the existing ScrollViewer to the end (reuse the existing scroll logic / named ScrollViewer). Keep the named ScrollViewer's x:Name.
-
Step 3: Repoint
SessionTerminalView.axamlinternal bindings to the control's own properties. Give the rootUserControlx:Name="Root". Change:- the
ItemsControl ItemsSource="{Binding Log}"→ItemsSource="{Binding #Root.Entries}" - the label
TextBlockText="{Binding BranchLine, StringFormat='claude-session · {0}'}"(or whatever it is) →Text="{Binding #Root.Label}" - the LIVE chip
IsVisible="{Binding IsRunning}"→{Binding #Root.IsRunning}; DONE →#Root.IsDone; FAILED →#Root.IsFailed. Keep theLogLineViewModelitem template as-is (it binds the item, not the VM). Thex:DataTypecan stayDetailsIslandViewModel(element-name bindings to#Rootdon't depend on it) or be removed if it causes compile issues — verify the build.
- the
-
Step 4: Update both embeds in
DetailsIslandView.axaml.- Task embed (currently
<islands:SessionTerminalView MaxHeight="420"/>):(Use the exact label binding the old internal header used — match the prior<islands:SessionTerminalView MaxHeight="420" Entries="{Binding Log}" Label="{Binding BranchLine, StringFormat='claude-session · {0}'}" IsRunning="{Binding IsRunning}" IsDone="{Binding IsDone}" IsFailed="{Binding IsFailed}"/>StringFormattext precisely so the task view is visually unchanged.) - Prep panel: replace the whole copied
ItemsControl(and its surroundingScrollViewer/title) with:Keep the panel wrapper<islands:SessionTerminalView Entries="{Binding PrepLog}" Label="daily-prep" IsRunning="{Binding IsPrepRunning}"/><Panel IsVisible="{Binding IsPrepMode}">. Drop the now-redundantdetails.prepTitletitle TextBlock (the terminal header shows thedaily-preplabel). Leave thedetails.prepTitlelocale key in place (harmless) OR remove it from both en/de if you prefer — if removing, run the localization test.
- Task embed (currently
-
Step 5: Build the App; confirm no binding/compile errors.
dotnet build src/ClaudeDo.App/ClaudeDo.App.csproj -c Release
dotnet test tests/ClaudeDo.Ui.Tests/ClaudeDo.Ui.Tests.csproj -c Release
(The existing DetailsIsland prep tests must still pass — PrepLog/IsPrepMode/ShowPrep are unchanged.)
- Step 6: Commit (stage only Task A files; do NOT
git add -A):
git commit -m "feat(daily-prep): reuse SessionTerminal for prep log; fix invisible Sort icon; add Broom/List icons"
Task B: MyDay header icon buttons
Files:
- Modify:
src/ClaudeDo.Ui/Views/Islands/TasksIslandView.axaml - Modify:
src/ClaudeDo.Localization/locales/en.json,de.json
Depends on Task A (uses Icon.Broom / Icon.List).
- Step 1: Add two
icon-btnto the header icon StackPanel (the one with Sort/Eye/Settings), inserted right after the Eye button and before Settings, both MyDay-only:
<Button Classes="icon-btn" IsVisible="{Binding IsMyDayList}"
Command="{Binding ClearDayCommand}" ToolTip.Tip="{loc:Tr tasks.clearDayTip}">
<PathIcon Width="15" Height="15" Data="{StaticResource Icon.Broom}"/>
</Button>
<Button Classes="icon-btn" IsVisible="{Binding IsMyDayList}"
Command="{Binding ShowPrepLogCommand}" ToolTip.Tip="{loc:Tr tasks.prepLogTip}">
<PathIcon Width="15" Height="15" Data="{StaticResource Icon.List}"/>
</Button>
-
Step 2: Remove the two full-width buttons "Prep log" (
ShowPrepLogCommand) and "Clear day" (ClearDayCommand) from the DockPanel button stack. Keep the "Prepare day" (PrepareDayCommand) full-width button and the Notes pinned-row button. -
Step 3: Locales. Add
tasks.clearDayTip(en "Clear day", de "Tag leeren") andtasks.prepLogTip(en "Prep log", de "Vorbereitungs-Log") to both json files. Remove the now-unusedtasks.clearDayandtasks.prepLogkeys from both (keep en/de in parity). -
Step 4: Build + test.
dotnet build src/ClaudeDo.App/ClaudeDo.App.csproj -c Release
dotnet test tests/ClaudeDo.Ui.Tests/ClaudeDo.Ui.Tests.csproj -c Release
dotnet test tests/ClaudeDo.Localization.Tests/ClaudeDo.Localization.Tests.csproj -c Release
-
Step 5: Manual smoke (human): on MyDay the header shows Sort (now visible) + Eye + Broom + List + Settings; broom clears the day; list opens the prep terminal; "Tag vorbereiten" opens the prep terminal and streams; the three MyDay-only controls hide on other lists; the task session terminal still renders normally.
-
Step 6: Commit (stage only Task B files):
git commit -m "feat(daily-prep): move Clear-day and Prep-log into MyDay header icon row"
Notes / risks
- Element-name bindings (
#Root.*) require theUserControlto havex:Name="Root"; verify compiled bindings accept them (they do in Avalonia). - The auto-scroll hook must re-subscribe when
Entrieschanges; without it the prep log won't auto-scroll. ClearDayCommand/ShowPrepLogCommandalready exist onTasksIslandViewModel— no VM changes; existing VM tests remain valid.