Files
ClaudeDo/docs/superpowers/plans/2026-06-04-myday-icons-terminal-reuse.md
2026-06-04 09:11:40 +02:00

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/Settings icon-btn StackPanel) gets two more icon-btn, both IsVisible="{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 via PrepRequested).
  • SessionTerminalView becomes reusable via StyledProperties so it renders both the task Log and the prep PrepLog with the same terminal look. The prep panel in DetailsIslandView embeds it instead of the copied ItemsControl.
  • Sort icon bug: PathIcon fills geometry; Icon.Sort is 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 + add Icon.Broom, Icon.List as filled geometries in IslandStyles.axaml (in the Styles.Resources icon block). Replace the existing Icon.Sort line 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-behind SessionTerminalView.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.axaml internal bindings to the control's own properties. Give the root UserControl x:Name="Root". Change:

    • the ItemsControl ItemsSource="{Binding Log}"ItemsSource="{Binding #Root.Entries}"
    • the label TextBlock Text="{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 the LogLineViewModel item template as-is (it binds the item, not the VM). The x:DataType can stay DetailsIslandViewModel (element-name bindings to #Root don't depend on it) or be removed if it causes compile issues — verify the build.
  • Step 4: Update both embeds in DetailsIslandView.axaml.

    • Task embed (currently <islands:SessionTerminalView MaxHeight="420"/>):
      <islands:SessionTerminalView MaxHeight="420"
          Entries="{Binding Log}"
          Label="{Binding BranchLine, StringFormat='claude-session · {0}'}"
          IsRunning="{Binding IsRunning}" IsDone="{Binding IsDone}" IsFailed="{Binding IsFailed}"/>
      
      (Use the exact label binding the old internal header used — match the prior StringFormat text precisely so the task view is visually unchanged.)
    • Prep panel: replace the whole copied ItemsControl (and its surrounding ScrollViewer/title) with:
      <islands:SessionTerminalView
          Entries="{Binding PrepLog}" Label="daily-prep"
          IsRunning="{Binding IsPrepRunning}"/>
      
      Keep the panel wrapper <Panel IsVisible="{Binding IsPrepMode}">. Drop the now-redundant details.prepTitle title TextBlock (the terminal header shows the daily-prep label). Leave the details.prepTitle locale key in place (harmless) OR remove it from both en/de if you prefer — if removing, run the localization test.
  • 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-btn to 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") and tasks.prepLogTip (en "Prep log", de "Vorbereitungs-Log") to both json files. Remove the now-unused tasks.clearDay and tasks.prepLog keys 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 the UserControl to have x:Name="Root"; verify compiled bindings accept them (they do in Avalonia).
  • The auto-scroll hook must re-subscribe when Entries changes; without it the prep log won't auto-scroll.
  • ClearDayCommand / ShowPrepLogCommand already exist on TasksIslandViewModel — no VM changes; existing VM tests remain valid.