style(ui): Material Design icons for the tasks island header bar
This commit is contained in:
@@ -130,7 +130,7 @@ snaps `CanResize="True"` windows, which is the opt-in), and it insets itself by
|
||||
## Gotchas
|
||||
|
||||
- **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`.
|
||||
- **`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.Refine`, `Icon.GitBranch`). For new icons prefer Material Design Icons (`mdi:Name` via the `IconKey` converter) — they are filled and work in a plain `PathIcon`. 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`.
|
||||
- **`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.
|
||||
|
||||
@@ -82,9 +82,6 @@
|
||||
<!-- 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.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>
|
||||
|
||||
<!-- 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>
|
||||
|
||||
|
||||
@@ -36,36 +36,31 @@
|
||||
IsVisible="{Binding !IsNotesList}"
|
||||
Command="{Binding ToggleShowCompletedCommand}"
|
||||
ToolTip.Tip="{loc:Tr tasks.showCompletedTip}">
|
||||
<PathIcon Width="15" Height="15" Data="{StaticResource Icon.Eye}"/>
|
||||
<PathIcon Width="16" Height="16" Data="{Binding Source='mdi:CheckAll', Converter={StaticResource IconKey}}"/>
|
||||
</Button>
|
||||
<Button Classes="icon-btn" IsVisible="{Binding IsLetClaudeVisible}"
|
||||
Command="{Binding LetClaudeHandleCommand}" ToolTip.Tip="{loc:Tr tasks.letClaudeTip}">
|
||||
<PathIcon Width="15" Height="15" Data="{StaticResource Icon.AgentSuggested}"/>
|
||||
<PathIcon Width="16" Height="16" Data="{Binding Source='mdi:RobotOutline', Converter={StaticResource IconKey}}"/>
|
||||
</Button>
|
||||
<Button Classes="icon-btn" IsVisible="{Binding IsMergeReviewsVisible}"
|
||||
Command="{Binding MergeReviewsCommand}" ToolTip.Tip="{loc:Tr tasks.mergeReviewsTip}">
|
||||
<!-- Icon.GitBranch is line-art: stroke-rendered, PathIcon would fill the lines away -->
|
||||
<Viewbox Width="16" Height="16">
|
||||
<Path Classes="icon-stroke" Data="{StaticResource Icon.GitBranch}"/>
|
||||
</Viewbox>
|
||||
<PathIcon Width="16" Height="16" Data="{Binding Source='mdi:SourceMerge', Converter={StaticResource IconKey}}"/>
|
||||
</Button>
|
||||
<Button Classes="icon-btn" IsVisible="{Binding IsQuickClaudeVisible}"
|
||||
Command="{Binding OpenQuickClaudeSessionCommand}" ToolTip.Tip="{loc:Tr tasks.quickClaudeTip}">
|
||||
<PathIcon Width="15" Height="15" Data="{StaticResource Icon.ArrowOut}"/>
|
||||
<PathIcon Width="16" Height="16" Data="{Binding Source='mdi:ConsoleLine', Converter={StaticResource IconKey}}"/>
|
||||
</Button>
|
||||
<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}"/>
|
||||
<PathIcon Width="16" Height="16" Data="{Binding Source='mdi:Broom', Converter={StaticResource IconKey}}"/>
|
||||
</Button>
|
||||
<Button Classes="icon-btn" IsVisible="{Binding IsMyDayList}"
|
||||
Command="{Binding ShowPrepLogCommand}" ToolTip.Tip="{loc:Tr tasks.planMyDayTip}">
|
||||
<Viewbox Width="18" Height="18">
|
||||
<Path Classes="icon-stroke" Data="{StaticResource Icon.PlanDay}"/>
|
||||
</Viewbox>
|
||||
<PathIcon Width="16" Height="16" Data="{Binding Source='mdi:WeatherSunsetUp', Converter={StaticResource IconKey}}"/>
|
||||
</Button>
|
||||
<Button Classes="icon-btn" IsVisible="{Binding !IsNotesList}"
|
||||
Command="{Binding OpenListSettingsCommand}" ToolTip.Tip="{loc:Tr tasks.listSettingsTip}">
|
||||
<PathIcon Width="15" Height="15" Data="{StaticResource Icon.Settings}"/>
|
||||
<PathIcon Width="16" Height="16" Data="{Binding Source='mdi:CogOutline', Converter={StaticResource IconKey}}"/>
|
||||
</Button>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
|
||||
Reference in New Issue
Block a user