refactor(ui): Icon-Faerbung zentral im ICON-PAINTING-Block
Inline Foreground/Stroke an Icons entfernt — ein lokaler Wert schlaegt jeden Style, dadurch erreichten Hover/Checked/Disabled das Icon nicht. Farbe wird jetzt per Klasse gewaehlt (.danger, .star-btn.on, .active), alle Zustaende liegen in einem geordneten Block in IslandStyles.axaml. - Path.plan-icon -> Path.icon-stroke (gilt jetzt fuer Button und ToggleButton) - Icon.Activity als gefuellte Kontur (PathIcon fuellt, Stroke-Polyline gab Blobs) - BloodBrightBrush als Hover-Ton fuer destruktive Icons - icon-btn:disabled bleibt transparent statt Fluent-Grau
This commit is contained in:
@@ -76,7 +76,7 @@ dotnet test tests/ClaudeDo.Worker.Tests/ClaudeDo.Worker.Tests.csproj -c Release
|
|||||||
|
|
||||||
### Gotchas
|
### Gotchas
|
||||||
- **Subagents:** use the `sonnet` model; stage files explicitly by path — never `git add -A` (parallel sessions often leave unrelated WIP in the tree).
|
- **Subagents:** use the `sonnet` model; stage files explicitly by path — never `git add -A` (parallel sessions often leave unrelated WIP in the tree).
|
||||||
- **Icons:** `PathIcon` *fills* its geometry. Line-art/stroke icons must be authored as filled geometry, or rendered with a stroked `Path` — otherwise they render invisible.
|
- **Icons:** `PathIcon` *fills* its geometry — line-art icons must be filled geometry or a `Path Classes="icon-stroke"`, else they render invisible. Colour comes from the `ICON PAINTING` block in `IslandStyles.axaml` (class + state); setting `Foreground`/`Stroke` inline kills the hover state.
|
||||||
- **Localization:** `locales/en.json` and `locales/de.json` keys must stay in parity (Localization.Tests enforces it).
|
- **Localization:** `locales/en.json` and `locales/de.json` keys must stay in parity (Localization.Tests enforces it).
|
||||||
- **Test fakes:** changing `IWorkerClient` / `WorkerHub` / ViewModel constructors breaks hand-rolled fakes in both test projects — update them.
|
- **Test fakes:** changing `IWorkerClient` / `WorkerHub` / ViewModel constructors breaks hand-rolled fakes in both test projects — update them.
|
||||||
|
|
||||||
|
|||||||
@@ -113,7 +113,8 @@ snaps `CanResize="True"` windows, which is the opt-in), and it insets itself by
|
|||||||
|
|
||||||
## Gotchas
|
## Gotchas
|
||||||
|
|
||||||
- **`PathIcon` *fills* its geometry.** Line-art/stroke icons must be authored as filled geometry or rendered with a stroked `Path` (e.g. `Icon.PlanDay` via the `Path.plan-icon` style). A pure stroke path in a `PathIcon` is **invisible**.
|
- **Never set `Foreground`/`Stroke` on an icon inline.** A local value outranks every style, so the button's hover/checked/disabled states can't reach the icon and it looks dead on hover — this is what broke the icons that were "fixed" to the right colour inline. Colour is picked with a class; the single `ICON PAINTING` block in `IslandStyles.axaml` owns all states (`.danger`, `.star-btn.on`, `.active`, `:checked`, `:disabled`). Avalonia has no specificity — that block's **declaration order** is the mechanism, so add new variants in the right section, not at the end.
|
||||||
|
- **`PathIcon` *fills* its geometry.** Line-art/stroke icons must be authored as filled geometry or rendered as `<Path Classes="icon-stroke">` inside a `Viewbox` (e.g. `Icon.PlanDay`, `Icon.GitBranch`). A pure stroke path in a `PathIcon` is **invisible**. `Path.icon-stroke` takes the same colour classes/states as `PathIcon`.
|
||||||
- **`NumericUpDown.Value` is `decimal?` and goes null while the box is empty** — i.e. every time the user clears a value to type a new one. Bound TwoWay to a non-nullable `int`/`decimal`, that null throws `InvalidCastException`. Either bind a `decimal?` property (as `AgentConfigEditorViewModel.MaxTurns` does) or add `Converter={StaticResource KeepLastNumber}`, which drops the null via `BindingOperations.DoNothing`.
|
- **`NumericUpDown.Value` is `decimal?` and goes null while the box is empty** — i.e. every time the user clears a value to type a new one. Bound TwoWay to a non-nullable `int`/`decimal`, that null throws `InvalidCastException`. Either bind a `decimal?` property (as `AgentConfigEditorViewModel.MaxTurns` does) or add `Converter={StaticResource KeepLastNumber}`, which drops the null via `BindingOperations.DoNothing`.
|
||||||
- **`ScrollViewer.Padding` is excluded from the Extent (Avalonia 12).** At max scroll the content still sticks out below the viewport by the padding height, so the last line(s) are clipped and unreachable — even after `ScrollToEnd()`. Put the inset on the *content* (`Margin` on the inner `ItemsControl`/`StackPanel`) instead. Verified headlessly: 12,8,12,4 on the viewer → last item 20px below the viewport; same inset as content margin → fully visible. **`ListBox` does *not* have this trap** — its Fluent control-theme template forwards `Padding` onto `PART_ItemsPresenter`'s margin (content side), not the raw `ScrollViewer.Padding`; verified headlessly that `ListBox.Padding="10,4"` and a `Margin="10,4"` on the `ItemsPanelTemplate` panel produce an *identical* Extent and leave the last row fully visible at max scroll. Still fine to put the inset on the panel for consistency with the other scrollables above, just don't assume it's fixing a real bug there.
|
- **`ScrollViewer.Padding` is excluded from the Extent (Avalonia 12).** At max scroll the content still sticks out below the viewport by the padding height, so the last line(s) are clipped and unreachable — even after `ScrollToEnd()`. Put the inset on the *content* (`Margin` on the inner `ItemsControl`/`StackPanel`) instead. Verified headlessly: 12,8,12,4 on the viewer → last item 20px below the viewport; same inset as content margin → fully visible. **`ListBox` does *not* have this trap** — its Fluent control-theme template forwards `Padding` onto `PART_ItemsPresenter`'s margin (content side), not the raw `ScrollViewer.Padding`; verified headlessly that `ListBox.Padding="10,4"` and a `Margin="10,4"` on the `ItemsPanelTemplate` panel produce an *identical* Extent and leave the last row fully visible at max scroll. Still fine to put the inset on the panel for consistency with the other scrollables above, just don't assume it's fixing a real bug there.
|
||||||
- **Re-templating a `TabControl` must keep `PART_ItemsPresenter`.** `TabControl.SelectedContent` is resolved via `ContainerFromIndex`, and containers are only realized by the `ItemsPresenter`. A template that renders just `PART_SelectedContentHost` (to hide the tab strip) leaves `SelectedContent` permanently `null` → an empty body. Keep the presenter with `IsVisible="False"`; that still realizes containers (verified headlessly, Avalonia 12.0.4). This broke the whole Settings modal body in 56c3719e.
|
- **Re-templating a `TabControl` must keep `PART_ItemsPresenter`.** `TabControl.SelectedContent` is resolved via `ContainerFromIndex`, and containers are only realized by the `ItemsPresenter`. A template that renders just `PART_SelectedContentHost` (to hide the tab strip) leaves `SelectedContent` permanently `null` → an empty body. Keep the presenter with `IsVisible="False"`; that still realizes containers (verified headlessly, Avalonia 12.0.4). This broke the whole Settings modal body in 56c3719e.
|
||||||
|
|||||||
@@ -5,7 +5,8 @@
|
|||||||
How to use each style:
|
How to use each style:
|
||||||
<Border Classes="island"> — floating island container
|
<Border Classes="island"> — floating island container
|
||||||
<Border Classes="chip running"> — status chip
|
<Border Classes="chip running"> — status chip
|
||||||
<Button Classes="icon-btn"> — 24×24 icon button
|
<Button Classes="icon-btn"> — 24×24 icon button (icon colour: never inline,
|
||||||
|
see "ICON PAINTING" below)
|
||||||
<Button Classes="btn primary"> — rounded-rect button
|
<Button Classes="btn primary"> — rounded-rect button
|
||||||
<TextBlock Classes="eyebrow"> — uppercase mono label
|
<TextBlock Classes="eyebrow"> — uppercase mono label
|
||||||
<Border Classes="terminal"> — terminal/log window
|
<Border Classes="terminal"> — terminal/log window
|
||||||
@@ -35,8 +36,8 @@
|
|||||||
<!-- Icon.Sun -->
|
<!-- Icon.Sun -->
|
||||||
<StreamGeometry x:Key="Icon.Sun">M12 8a4 4 0 1 0 0 8 4 4 0 0 0 0-8z M12 3v2M12 19v2M3 12h2M19 12h2M5.5 5.5l1.4 1.4M17.1 17.1l1.4 1.4M5.5 18.5l1.4-1.4M17.1 6.9l1.4-1.4</StreamGeometry>
|
<StreamGeometry x:Key="Icon.Sun">M12 8a4 4 0 1 0 0 8 4 4 0 0 0 0-8z M12 3v2M12 19v2M3 12h2M19 12h2M5.5 5.5l1.4 1.4M17.1 17.1l1.4 1.4M5.5 18.5l1.4-1.4M17.1 6.9l1.4-1.4</StreamGeometry>
|
||||||
|
|
||||||
<!-- Icon.Activity (pulse waveform) -->
|
<!-- Icon.Activity (pulse waveform) — filled outline of the polyline; PathIcon fills, a stroke-only pulse renders as blobs -->
|
||||||
<StreamGeometry x:Key="Icon.Activity">M3 12h4l2-6 4 12 2-8 2 2h4</StreamGeometry>
|
<StreamGeometry x:Key="Icon.Activity">M3,11 L6.28,11 L9,2.84 L12.86,14.43 L14.46,8.04 L17.41,11 L21,11 L21,13 L16.59,13 L15.54,11.96 L13.14,21.57 L9,9.16 L7.72,13 L3,13 Z</StreamGeometry>
|
||||||
|
|
||||||
<!-- Icon.Star -->
|
<!-- Icon.Star -->
|
||||||
<StreamGeometry x:Key="Icon.Star">M12 3.5l2.6 5.3 5.8.8-4.2 4.1 1 5.8-5.2-2.7-5.2 2.7 1-5.8-4.2-4.1 5.8-.8z</StreamGeometry>
|
<StreamGeometry x:Key="Icon.Star">M12 3.5l2.6 5.3 5.8.8-4.2 4.1 1 5.8-5.2-2.7-5.2 2.7 1-5.8-4.2-4.1 5.8-.8z</StreamGeometry>
|
||||||
@@ -74,10 +75,10 @@
|
|||||||
<!-- Icon.Broom (filled: handle + binding band + flared bristles) -->
|
<!-- 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>
|
<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.PlanDay (stroke-rendered via Path.plan-icon — sun over horizon) -->
|
<!-- Icon.PlanDay (stroke-rendered via Path.icon-stroke — sun over horizon) -->
|
||||||
<StreamGeometry x:Key="Icon.PlanDay">M3,20 L21,20 M8.4,11 a3.6,3.6 0 1,0 7.2,0 a3.6,3.6 0 1,0 -7.2,0 M12,4.5 L12,3 M6,11 L4.5,11 M18,11 L19.5,11 M7.5,6.5 L6.4,5.4 M16.5,6.5 L17.6,5.4</StreamGeometry>
|
<StreamGeometry x:Key="Icon.PlanDay">M3,20 L21,20 M8.4,11 a3.6,3.6 0 1,0 7.2,0 a3.6,3.6 0 1,0 -7.2,0 M12,4.5 L12,3 M6,11 L4.5,11 M18,11 L19.5,11 M7.5,6.5 L6.4,5.4 M16.5,6.5 L17.6,5.4</StreamGeometry>
|
||||||
|
|
||||||
<!-- Icon.Refine (stroke-rendered via Path.plan-icon — list lines + two sparkles) -->
|
<!-- Icon.Refine (stroke-rendered via Path.icon-stroke — list lines + two sparkles) -->
|
||||||
<StreamGeometry x:Key="Icon.Refine">M3,6 L13,6 M3,11 L11,11 M3,16 L9,16 M18.5,3 L19.28,5.22 L21.5,6 L19.28,6.78 L18.5,9 L17.72,6.78 L15.5,6 L17.72,5.22 Z M19.5,14.9 L19.85,16.15 L21.1,16.5 L19.85,16.85 L19.5,18.1 L19.15,16.85 L17.9,16.5 L19.15,16.15 Z</StreamGeometry>
|
<StreamGeometry x:Key="Icon.Refine">M3,6 L13,6 M3,11 L11,11 M3,16 L9,16 M18.5,3 L19.28,5.22 L21.5,6 L19.28,6.78 L18.5,9 L17.72,6.78 L15.5,6 L17.72,5.22 Z M19.5,14.9 L19.85,16.15 L21.1,16.5 L19.85,16.85 L19.5,18.1 L19.15,16.85 L17.9,16.5 L19.15,16.15 Z</StreamGeometry>
|
||||||
|
|
||||||
<!-- Icon.X — filled X outline (PathIcon fills, so a stroke-only X renders invisible) -->
|
<!-- Icon.X — filled X outline (PathIcon fills, so a stroke-only X renders invisible) -->
|
||||||
@@ -339,6 +340,12 @@
|
|||||||
<Setter Property="HorizontalContentAlignment" Value="Center" />
|
<Setter Property="HorizontalContentAlignment" Value="Center" />
|
||||||
<Setter Property="VerticalContentAlignment" Value="Center" />
|
<Setter Property="VerticalContentAlignment" Value="Center" />
|
||||||
</Style>
|
</Style>
|
||||||
|
<!-- Fluent paints disabled buttons with its own gray background — keep icon buttons transparent.
|
||||||
|
Declared *before* :pointerover so a disabled button still gets the hover surface: it's the
|
||||||
|
only feedback that the button exists at all, and its tooltip explains why it won't act. -->
|
||||||
|
<Style Selector="Button.icon-btn:disabled /template/ ContentPresenter, ToggleButton.icon-btn:disabled /template/ ContentPresenter">
|
||||||
|
<Setter Property="Background" Value="Transparent" />
|
||||||
|
</Style>
|
||||||
<Style Selector="Button.icon-btn:pointerover /template/ ContentPresenter, ToggleButton.icon-btn:pointerover /template/ ContentPresenter">
|
<Style Selector="Button.icon-btn:pointerover /template/ ContentPresenter, ToggleButton.icon-btn:pointerover /template/ ContentPresenter">
|
||||||
<Setter Property="Background" Value="{StaticResource Surface2Brush}" />
|
<Setter Property="Background" Value="{StaticResource Surface2Brush}" />
|
||||||
<Setter Property="TextElement.Foreground" Value="{StaticResource TextBrush}" />
|
<Setter Property="TextElement.Foreground" Value="{StaticResource TextBrush}" />
|
||||||
@@ -347,17 +354,85 @@
|
|||||||
<Setter Property="Background" Value="{StaticResource Surface3Brush}" />
|
<Setter Property="Background" Value="{StaticResource Surface3Brush}" />
|
||||||
<Setter Property="TextElement.Foreground" Value="{StaticResource AccentBrush}" />
|
<Setter Property="TextElement.Foreground" Value="{StaticResource AccentBrush}" />
|
||||||
</Style>
|
</Style>
|
||||||
<!-- PathIcon fills with its own Foreground and does not pick up TextElement.Foreground,
|
|
||||||
so the icon's three states are set on the icon itself. -->
|
<!-- Line-art icon geometry (PathIcon would fill the lines away). Declared before the
|
||||||
<Style Selector="ToggleButton.icon-btn PathIcon">
|
icon-painting block below because Avalonia resolves ties by declaration order,
|
||||||
|
not specificity — a later rule always wins. -->
|
||||||
|
<Style Selector="Path.icon-stroke">
|
||||||
|
<Setter Property="Stroke" Value="{StaticResource TextDimBrush}" />
|
||||||
|
<Setter Property="StrokeThickness" Value="1.7" />
|
||||||
|
<Setter Property="StrokeLineCap" Value="Round" />
|
||||||
|
<Setter Property="StrokeJoin" Value="Round" />
|
||||||
|
</Style>
|
||||||
|
|
||||||
|
<!-- ══ ICON PAINTING — the one place icon colour is decided ══════════════════
|
||||||
|
NEVER set Foreground/Stroke on an icon inline. A local value outranks every
|
||||||
|
style, so the button's hover/checked/disabled states can't reach the icon and
|
||||||
|
it stays dead on hover. Pick the colour with a class instead:
|
||||||
|
|
||||||
|
<PathIcon Data="{StaticResource Icon.X}"/> neutral (mute → text)
|
||||||
|
<PathIcon Classes="danger" .../> destructive (blood → bright)
|
||||||
|
<Viewbox><Path Classes="icon-stroke" .../></Viewbox> line-art geometry
|
||||||
|
|
||||||
|
PathIcon *fills* its geometry — line-art icons must use Path.icon-stroke or
|
||||||
|
they render as blobs/invisible. Both forms take the same classes and states.
|
||||||
|
Selectors are class-only (".icon-btn"), so Button and ToggleButton share them.
|
||||||
|
Order is the whole mechanism (Avalonia has no specificity — the last matching
|
||||||
|
rule wins), so the sequence below is: rest → hover → lit (.on/.active/:checked
|
||||||
|
stay lit under the pointer) → :disabled → .danger (red in every state). -->
|
||||||
|
|
||||||
|
<!-- rest -->
|
||||||
|
<Style Selector=".icon-btn PathIcon, .new-list-btn PathIcon">
|
||||||
<Setter Property="Foreground" Value="{StaticResource TextMuteBrush}" />
|
<Setter Property="Foreground" Value="{StaticResource TextMuteBrush}" />
|
||||||
</Style>
|
</Style>
|
||||||
<Style Selector="ToggleButton.icon-btn:pointerover PathIcon">
|
<Style Selector=".icon-btn Path.icon-stroke">
|
||||||
|
<Setter Property="Stroke" Value="{StaticResource TextMuteBrush}" />
|
||||||
|
</Style>
|
||||||
|
<!-- an unset star is barely there until you hover the row -->
|
||||||
|
<Style Selector=".icon-btn.star-btn PathIcon">
|
||||||
|
<Setter Property="Foreground" Value="{StaticResource TextFaintBrush}" />
|
||||||
|
</Style>
|
||||||
|
|
||||||
|
<!-- hover -->
|
||||||
|
<Style Selector=".icon-btn:pointerover PathIcon, .new-list-btn:pointerover PathIcon">
|
||||||
<Setter Property="Foreground" Value="{StaticResource TextBrush}" />
|
<Setter Property="Foreground" Value="{StaticResource TextBrush}" />
|
||||||
</Style>
|
</Style>
|
||||||
<Style Selector="ToggleButton.icon-btn:checked PathIcon">
|
<Style Selector=".icon-btn:pointerover Path.icon-stroke">
|
||||||
|
<Setter Property="Stroke" Value="{StaticResource TextBrush}" />
|
||||||
|
</Style>
|
||||||
|
<!-- lit: on/active/checked keep their colour under the pointer -->
|
||||||
|
<Style Selector=".icon-btn.star-btn.on PathIcon">
|
||||||
|
<Setter Property="Foreground" Value="{StaticResource PeatBrush}" />
|
||||||
|
</Style>
|
||||||
|
<Style Selector=".icon-btn.active PathIcon, .icon-btn:checked PathIcon">
|
||||||
<Setter Property="Foreground" Value="{StaticResource AccentBrush}" />
|
<Setter Property="Foreground" Value="{StaticResource AccentBrush}" />
|
||||||
</Style>
|
</Style>
|
||||||
|
<Style Selector=".icon-btn.active Path.icon-stroke, .icon-btn:checked Path.icon-stroke">
|
||||||
|
<Setter Property="Stroke" Value="{StaticResource AccentBrush}" />
|
||||||
|
</Style>
|
||||||
|
|
||||||
|
<!-- disabled greys out every neutral variant -->
|
||||||
|
<Style Selector=".icon-btn:disabled PathIcon">
|
||||||
|
<Setter Property="Foreground" Value="{StaticResource TextFaintBrush}" />
|
||||||
|
</Style>
|
||||||
|
<Style Selector=".icon-btn:disabled Path.icon-stroke">
|
||||||
|
<Setter Property="Stroke" Value="{StaticResource TextFaintBrush}" />
|
||||||
|
</Style>
|
||||||
|
|
||||||
|
<!-- …except danger, which is last on purpose: a destructive action stays red in every state,
|
||||||
|
including disabled. Greying it out makes the button read as broken rather than blocked. -->
|
||||||
|
<Style Selector=".icon-btn PathIcon.danger">
|
||||||
|
<Setter Property="Foreground" Value="{StaticResource BloodBrush}" />
|
||||||
|
</Style>
|
||||||
|
<Style Selector=".icon-btn Path.icon-stroke.danger">
|
||||||
|
<Setter Property="Stroke" Value="{StaticResource BloodBrush}" />
|
||||||
|
</Style>
|
||||||
|
<Style Selector=".icon-btn:pointerover PathIcon.danger">
|
||||||
|
<Setter Property="Foreground" Value="{StaticResource BloodBrightBrush}" />
|
||||||
|
</Style>
|
||||||
|
<Style Selector=".icon-btn:pointerover Path.icon-stroke.danger">
|
||||||
|
<Setter Property="Stroke" Value="{StaticResource BloodBrightBrush}" />
|
||||||
|
</Style>
|
||||||
|
|
||||||
<!-- Segmented switch: one control, mutually exclusive segments, active one highlighted.
|
<!-- Segmented switch: one control, mutually exclusive segments, active one highlighted.
|
||||||
Use for picking a mode (not for independent on/off flags — those are icon toggles). -->
|
Use for picking a mode (not for independent on/off flags — those are icon toggles). -->
|
||||||
@@ -387,17 +462,6 @@
|
|||||||
<Setter Property="TextElement.Foreground" Value="{StaticResource AccentBrush}" />
|
<Setter Property="TextElement.Foreground" Value="{StaticResource AccentBrush}" />
|
||||||
</Style>
|
</Style>
|
||||||
|
|
||||||
<!-- Stroke-rendered icon (for line-art geometries that PathIcon would fill away) -->
|
|
||||||
<Style Selector="Button.icon-btn Path.plan-icon">
|
|
||||||
<Setter Property="Stroke" Value="{StaticResource TextBrush}" />
|
|
||||||
<Setter Property="StrokeThickness" Value="1.7" />
|
|
||||||
<Setter Property="StrokeLineCap" Value="Round" />
|
|
||||||
<Setter Property="StrokeJoin" Value="Round" />
|
|
||||||
</Style>
|
|
||||||
<Style Selector="Button.icon-btn:pointerover Path.plan-icon">
|
|
||||||
<Setter Property="Stroke" Value="{StaticResource AccentBrush}" />
|
|
||||||
</Style>
|
|
||||||
|
|
||||||
<!-- ============================================================ -->
|
<!-- ============================================================ -->
|
||||||
<!-- INPUTS -->
|
<!-- INPUTS -->
|
||||||
<!-- ============================================================ -->
|
<!-- ============================================================ -->
|
||||||
@@ -946,17 +1010,13 @@
|
|||||||
<!-- ============================================================ -->
|
<!-- ============================================================ -->
|
||||||
<!-- STAR BUTTON -->
|
<!-- STAR BUTTON -->
|
||||||
<!-- ============================================================ -->
|
<!-- ============================================================ -->
|
||||||
|
<!-- Icon colour comes from the icon-painting block; only the opacity differs here. -->
|
||||||
<Style Selector="Button.star-btn">
|
<Style Selector="Button.star-btn">
|
||||||
<Setter Property="Foreground" Value="{StaticResource TextFaintBrush}" />
|
|
||||||
<Setter Property="Opacity" Value="0.6" />
|
<Setter Property="Opacity" Value="0.6" />
|
||||||
</Style>
|
</Style>
|
||||||
<Style Selector="Button.star-btn.on">
|
<Style Selector="Button.star-btn.on">
|
||||||
<Setter Property="Foreground" Value="{StaticResource PeatBrush}" />
|
|
||||||
<Setter Property="Opacity" Value="1.0" />
|
<Setter Property="Opacity" Value="1.0" />
|
||||||
</Style>
|
</Style>
|
||||||
<Style Selector="Button.star-btn.on /template/ ContentPresenter">
|
|
||||||
<Setter Property="TextElement.Foreground" Value="{StaticResource PeatBrush}" />
|
|
||||||
</Style>
|
|
||||||
|
|
||||||
<!-- ============================================================ -->
|
<!-- ============================================================ -->
|
||||||
<!-- LIVE-TAIL PREVIEW ROW -->
|
<!-- LIVE-TAIL PREVIEW ROW -->
|
||||||
|
|||||||
@@ -33,6 +33,7 @@
|
|||||||
<Color x:Key="PeatColor">#FFD4A574</Color>
|
<Color x:Key="PeatColor">#FFD4A574</Color>
|
||||||
<Color x:Key="PeatSoftColor">#FFB88D5E</Color>
|
<Color x:Key="PeatSoftColor">#FFB88D5E</Color>
|
||||||
<Color x:Key="BloodColor">#FFC87060</Color>
|
<Color x:Key="BloodColor">#FFC87060</Color>
|
||||||
|
<Color x:Key="BloodBrightColor">#FFE08D7C</Color> <!-- hover state for destructive icons -->
|
||||||
|
|
||||||
<!-- Primary accent — equivalent to oklch(58% 0.08 88) -->
|
<!-- Primary accent — equivalent to oklch(58% 0.08 88) -->
|
||||||
<Color x:Key="AccentColor">#FF7C9166</Color>
|
<Color x:Key="AccentColor">#FF7C9166</Color>
|
||||||
@@ -72,6 +73,7 @@
|
|||||||
<SolidColorBrush x:Key="PeatBrush" Color="{StaticResource PeatColor}" />
|
<SolidColorBrush x:Key="PeatBrush" Color="{StaticResource PeatColor}" />
|
||||||
<SolidColorBrush x:Key="PeatSoftBrush" Color="{StaticResource PeatSoftColor}" />
|
<SolidColorBrush x:Key="PeatSoftBrush" Color="{StaticResource PeatSoftColor}" />
|
||||||
<SolidColorBrush x:Key="BloodBrush" Color="{StaticResource BloodColor}" />
|
<SolidColorBrush x:Key="BloodBrush" Color="{StaticResource BloodColor}" />
|
||||||
|
<SolidColorBrush x:Key="BloodBrightBrush" Color="{StaticResource BloodBrightColor}" />
|
||||||
|
|
||||||
<SolidColorBrush x:Key="AccentBrush" Color="{StaticResource AccentColor}" />
|
<SolidColorBrush x:Key="AccentBrush" Color="{StaticResource AccentColor}" />
|
||||||
<SolidColorBrush x:Key="AccentDimBrush" Color="{StaticResource AccentDimColor}" />
|
<SolidColorBrush x:Key="AccentDimBrush" Color="{StaticResource AccentDimColor}" />
|
||||||
|
|||||||
@@ -33,10 +33,8 @@
|
|||||||
IsVisible="{Binding Task.HasBranch, FallbackValue=False}">
|
IsVisible="{Binding Task.HasBranch, FallbackValue=False}">
|
||||||
<!-- Icon.GitBranch is line-art: stroke-rendered, PathIcon would fill the lines away -->
|
<!-- Icon.GitBranch is line-art: stroke-rendered, PathIcon would fill the lines away -->
|
||||||
<Viewbox Width="10" Height="10">
|
<Viewbox Width="10" Height="10">
|
||||||
<Path Data="{StaticResource Icon.GitBranch}"
|
<Path Classes="icon-stroke" Data="{StaticResource Icon.GitBranch}"
|
||||||
Stroke="{DynamicResource TextDimBrush}"
|
StrokeThickness="2.4"/>
|
||||||
StrokeThickness="2.4"
|
|
||||||
StrokeLineCap="Round" StrokeJoin="Round"/>
|
|
||||||
</Viewbox>
|
</Viewbox>
|
||||||
<TextBlock Classes="meta" Text="{Binding Task.Branch}"/>
|
<TextBlock Classes="meta" Text="{Binding Task.Branch}"/>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
@@ -46,11 +44,11 @@
|
|||||||
<Button Grid.Column="1" Classes="icon-btn"
|
<Button Grid.Column="1" Classes="icon-btn"
|
||||||
Command="{Binding DeleteTaskCommand}"
|
Command="{Binding DeleteTaskCommand}"
|
||||||
ToolTip.Tip="{loc:Tr details.deleteTaskTip}"
|
ToolTip.Tip="{loc:Tr details.deleteTaskTip}"
|
||||||
|
ToolTip.ShowOnDisabled="True"
|
||||||
IsVisible="{Binding !IsRunning}"
|
IsVisible="{Binding !IsRunning}"
|
||||||
VerticalAlignment="Top"
|
VerticalAlignment="Top"
|
||||||
Margin="6,0,0,0">
|
Margin="6,0,0,0">
|
||||||
<PathIcon Data="{StaticResource Icon.Trash}" Width="14" Height="14"
|
<PathIcon Classes="danger" Data="{StaticResource Icon.Trash}" Width="14" Height="14"/>
|
||||||
Foreground="{DynamicResource BloodBrush}"/>
|
|
||||||
</Button>
|
</Button>
|
||||||
|
|
||||||
<!-- Column 1: skull button (running) -->
|
<!-- Column 1: skull button (running) -->
|
||||||
@@ -60,8 +58,7 @@
|
|||||||
IsVisible="{Binding IsRunning}"
|
IsVisible="{Binding IsRunning}"
|
||||||
VerticalAlignment="Top"
|
VerticalAlignment="Top"
|
||||||
Margin="6,0,0,0">
|
Margin="6,0,0,0">
|
||||||
<PathIcon Data="{StaticResource Icon.Skull}" Width="14" Height="14"
|
<PathIcon Classes="danger" Data="{StaticResource Icon.Skull}" Width="14" Height="14"/>
|
||||||
Foreground="{DynamicResource BloodBrush}"/>
|
|
||||||
</Button>
|
</Button>
|
||||||
|
|
||||||
<!-- Column 2: gear button with agent settings flyout -->
|
<!-- Column 2: gear button with agent settings flyout -->
|
||||||
|
|||||||
@@ -71,9 +71,7 @@
|
|||||||
<Button Grid.Column="2" Classes="icon-btn" VerticalAlignment="Center"
|
<Button Grid.Column="2" Classes="icon-btn" VerticalAlignment="Center"
|
||||||
Command="{Binding OpenSettingsCommand}"
|
Command="{Binding OpenSettingsCommand}"
|
||||||
ToolTip.Tip="{loc:Tr lists.settingsTip}">
|
ToolTip.Tip="{loc:Tr lists.settingsTip}">
|
||||||
<PathIcon Data="{StaticResource Icon.Settings}"
|
<PathIcon Data="{StaticResource Icon.Settings}" Width="15" Height="15"/>
|
||||||
Width="15" Height="15"
|
|
||||||
Foreground="{DynamicResource TextMuteBrush}"/>
|
|
||||||
</Button>
|
</Button>
|
||||||
</Grid>
|
</Grid>
|
||||||
</Border>
|
</Border>
|
||||||
@@ -207,20 +205,16 @@
|
|||||||
<StackPanel Orientation="Horizontal" Spacing="6">
|
<StackPanel Orientation="Horizontal" Spacing="6">
|
||||||
<PathIcon Data="{StaticResource Icon.Plus}"
|
<PathIcon Data="{StaticResource Icon.Plus}"
|
||||||
Width="13" Height="13"
|
Width="13" Height="13"
|
||||||
Foreground="{DynamicResource TextMuteBrush}"
|
|
||||||
VerticalAlignment="Center"/>
|
VerticalAlignment="Center"/>
|
||||||
<TextBlock Classes="body"
|
<TextBlock Classes="body"
|
||||||
Text="{loc:Tr lists.newList}"
|
Text="{loc:Tr lists.newList}"
|
||||||
Foreground="{DynamicResource TextMuteBrush}"
|
|
||||||
VerticalAlignment="Center"/>
|
VerticalAlignment="Center"/>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
</Button>
|
</Button>
|
||||||
<Button Grid.Column="1" Classes="icon-btn" Margin="6,0,0,0"
|
<Button Grid.Column="1" Classes="icon-btn" Margin="6,0,0,0"
|
||||||
Command="{Binding OpenRepoImportCommand}"
|
Command="{Binding OpenRepoImportCommand}"
|
||||||
ToolTip.Tip="{loc:Tr lists.addReposTip}">
|
ToolTip.Tip="{loc:Tr lists.addReposTip}">
|
||||||
<PathIcon Data="{StaticResource Icon.Folder}"
|
<PathIcon Data="{StaticResource Icon.Folder}" Width="14" Height="14"/>
|
||||||
Width="14" Height="14"
|
|
||||||
Foreground="{DynamicResource TextMuteBrush}"/>
|
|
||||||
</Button>
|
</Button>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
|
||||||
|
|||||||
@@ -58,9 +58,9 @@
|
|||||||
ToolTip.Tip="{loc:Tr tasks.toggleSubtasksTip}">
|
ToolTip.Tip="{loc:Tr tasks.toggleSubtasksTip}">
|
||||||
<Panel>
|
<Panel>
|
||||||
<PathIcon Width="12" Height="12" Data="{StaticResource Icon.ChevronDown}"
|
<PathIcon Width="12" Height="12" Data="{StaticResource Icon.ChevronDown}"
|
||||||
Foreground="{DynamicResource TextDimBrush}" IsVisible="{Binding IsExpanded}"/>
|
IsVisible="{Binding IsExpanded}"/>
|
||||||
<PathIcon Width="12" Height="12" Data="{StaticResource Icon.ChevronRight}"
|
<PathIcon Width="12" Height="12" Data="{StaticResource Icon.ChevronRight}"
|
||||||
Foreground="{DynamicResource TextDimBrush}" IsVisible="{Binding !IsExpanded}"/>
|
IsVisible="{Binding !IsExpanded}"/>
|
||||||
</Panel>
|
</Panel>
|
||||||
</Button>
|
</Button>
|
||||||
|
|
||||||
@@ -213,7 +213,7 @@
|
|||||||
</MultiBinding>
|
</MultiBinding>
|
||||||
</Button.IsVisible>
|
</Button.IsVisible>
|
||||||
<Viewbox Width="16" Height="16">
|
<Viewbox Width="16" Height="16">
|
||||||
<Path Classes="plan-icon" Data="{StaticResource Icon.Refine}"/>
|
<Path Classes="icon-stroke" Data="{StaticResource Icon.Refine}"/>
|
||||||
</Viewbox>
|
</Viewbox>
|
||||||
</Button>
|
</Button>
|
||||||
<Ellipse Classes="spinner"
|
<Ellipse Classes="spinner"
|
||||||
|
|||||||
@@ -43,7 +43,7 @@
|
|||||||
Command="{Binding MergeReviewsCommand}" ToolTip.Tip="{loc:Tr tasks.mergeReviewsTip}">
|
Command="{Binding MergeReviewsCommand}" ToolTip.Tip="{loc:Tr tasks.mergeReviewsTip}">
|
||||||
<!-- Icon.GitBranch is line-art: stroke-rendered, PathIcon would fill the lines away -->
|
<!-- Icon.GitBranch is line-art: stroke-rendered, PathIcon would fill the lines away -->
|
||||||
<Viewbox Width="16" Height="16">
|
<Viewbox Width="16" Height="16">
|
||||||
<Path Classes="plan-icon" Data="{StaticResource Icon.GitBranch}"/>
|
<Path Classes="icon-stroke" Data="{StaticResource Icon.GitBranch}"/>
|
||||||
</Viewbox>
|
</Viewbox>
|
||||||
</Button>
|
</Button>
|
||||||
<Button Classes="icon-btn" IsVisible="{Binding IsQuickClaudeVisible}"
|
<Button Classes="icon-btn" IsVisible="{Binding IsQuickClaudeVisible}"
|
||||||
@@ -57,7 +57,7 @@
|
|||||||
<Button Classes="icon-btn" IsVisible="{Binding IsMyDayList}"
|
<Button Classes="icon-btn" IsVisible="{Binding IsMyDayList}"
|
||||||
Command="{Binding ShowPrepLogCommand}" ToolTip.Tip="{loc:Tr tasks.planMyDayTip}">
|
Command="{Binding ShowPrepLogCommand}" ToolTip.Tip="{loc:Tr tasks.planMyDayTip}">
|
||||||
<Viewbox Width="18" Height="18">
|
<Viewbox Width="18" Height="18">
|
||||||
<Path Classes="plan-icon" Data="{StaticResource Icon.PlanDay}"/>
|
<Path Classes="icon-stroke" Data="{StaticResource Icon.PlanDay}"/>
|
||||||
</Viewbox>
|
</Viewbox>
|
||||||
</Button>
|
</Button>
|
||||||
<Button Classes="icon-btn" Command="{Binding OpenListSettingsCommand}" ToolTip.Tip="{loc:Tr tasks.listSettingsTip}">
|
<Button Classes="icon-btn" Command="{Binding OpenListSettingsCommand}" ToolTip.Tip="{loc:Tr tasks.listSettingsTip}">
|
||||||
@@ -144,8 +144,7 @@
|
|||||||
Command="{Binding ActionCommand}"
|
Command="{Binding ActionCommand}"
|
||||||
ToolTip.Tip="{loc:Tr tasks.clearCompletedTip}"
|
ToolTip.Tip="{loc:Tr tasks.clearCompletedTip}"
|
||||||
VerticalAlignment="Center">
|
VerticalAlignment="Center">
|
||||||
<PathIcon Data="{StaticResource Icon.Trash}" Width="13" Height="13"
|
<PathIcon Classes="danger" Data="{StaticResource Icon.Trash}" Width="13" Height="13"/>
|
||||||
Foreground="{DynamicResource BloodBrush}"/>
|
|
||||||
</Button>
|
</Button>
|
||||||
</Grid>
|
</Grid>
|
||||||
</DataTemplate>
|
</DataTemplate>
|
||||||
|
|||||||
@@ -35,20 +35,17 @@
|
|||||||
<Button Classes="icon-btn"
|
<Button Classes="icon-btn"
|
||||||
Click="OnNewSessionClicked"
|
Click="OnNewSessionClicked"
|
||||||
ToolTip.Tip="{loc:Tr missionControl.newSession}">
|
ToolTip.Tip="{loc:Tr missionControl.newSession}">
|
||||||
<PathIcon Data="{StaticResource Icon.Plus}" Width="15" Height="15"
|
<PathIcon Data="{StaticResource Icon.Plus}" Width="15" Height="15"/>
|
||||||
Foreground="{DynamicResource TextMuteBrush}"/>
|
|
||||||
</Button>
|
</Button>
|
||||||
<Button Classes="icon-btn"
|
<Button Classes="icon-btn"
|
||||||
Command="{Binding ToggleLayoutCommand}"
|
Command="{Binding ToggleLayoutCommand}"
|
||||||
ToolTip.Tip="{Binding LayoutToggleLabel}">
|
ToolTip.Tip="{Binding LayoutToggleLabel}">
|
||||||
<PathIcon Data="{StaticResource Icon.Grid}" Width="15" Height="15"
|
<PathIcon Data="{StaticResource Icon.Grid}" Width="15" Height="15"/>
|
||||||
Foreground="{DynamicResource TextMuteBrush}"/>
|
|
||||||
</Button>
|
</Button>
|
||||||
<Button Classes="icon-btn"
|
<Button Classes="icon-btn"
|
||||||
Command="{Binding OpenSettingsCommand}"
|
Command="{Binding OpenSettingsCommand}"
|
||||||
ToolTip.Tip="{loc:Tr missionControl.settings}">
|
ToolTip.Tip="{loc:Tr missionControl.settings}">
|
||||||
<PathIcon Data="{StaticResource Icon.Settings}" Width="15" Height="15"
|
<PathIcon Data="{StaticResource Icon.Settings}" Width="15" Height="15"/>
|
||||||
Foreground="{DynamicResource TextMuteBrush}"/>
|
|
||||||
</Button>
|
</Button>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
|||||||
Reference in New Issue
Block a user