Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion ROADMAP.md
Original file line number Diff line number Diff line change
Expand Up @@ -230,7 +230,7 @@ Each release's notes say what it brought, and the decisions above say why. The c
An audit on 2026-10-10 went through the UI tests' screenshots, the themes and the views. These are what it found.

- [x] Screen readers and the keyboard: the rating takes the keyboard and reads out as "Usefulness, Solid", toasts and Quick save's error are announced, a heart says whether its prompt is a favorite, Show details says when it's open, and the workflow's Previous and Next buttons point left and right like its step strip.
- [ ] Contrast and focus: danger buttons on hover, the focused list row against a picked one, the picked option in segmented controls, control edges and empty rating pips at 3:1, counts on the active sidebar row and tags on their tinted fill, and focus outlines that follow each control's corners. `ThemeTests` holds every theme to the new pairs.
- [x] Contrast and focus: danger buttons on hover, the focused list row against a picked one, the picked option in segmented controls, control edges at 3:1 (the editor's empty rating pips too), counts on the active sidebar row and tags on their tinted fill, and focus outlines that follow each control's corners. `ThemeTests` holds every theme to the new pairs.
- [ ] Layout: long dialog titles wrap, the library and Settings fit the 960-pixel minimum width with a screenshot test at that size, toasts stay clear of the buttons beneath them, the Render tab scrolls once, the data folder's path shows in full on hover, and Settings sections share one spacing.
- [ ] Copy and polish: Quick save's button says Save, the list view shows the rating's word, and small icon buttons use one icon size.
- [ ] Publish v1.1.1.
Expand Down
61 changes: 44 additions & 17 deletions src/Prompuff.App/Themes/Controls.axaml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@

<!-- Buttons: secondary by default; classes primary, ghost, danger, sm, icon, nav, card, row, bare -->
<ControlTheme x:Key="{x:Type Button}" TargetType="Button">
<Setter Property="FocusAdorner" Value="{x:Null}" />
<Setter Property="Background" Value="{DynamicResource Bg3Brush}" />
<Setter Property="Foreground" Value="{DynamicResource Text1Brush}" />
<Setter Property="BorderBrush" Value="{DynamicResource Border2Brush}" />
Expand Down Expand Up @@ -58,6 +59,10 @@
<Style Selector="^:focus-visible">
<Setter Property="BorderBrush" Value="{DynamicResource AccentBrush}" />
</Style>
<!-- Focus is a ring inside the edge, so it follows the corners and shows on buttons without a border -->
<Style Selector="^:focus-visible /template/ ContentPresenter#PART_ContentPresenter">
<Setter Property="BoxShadow" Value="{DynamicResource FocusOutline}" />
</Style>

<Style Selector="^.primary">
<Setter Property="Background" Value="{DynamicResource AccentBrush}" />
Expand Down Expand Up @@ -94,8 +99,7 @@
<Setter Property="BorderBrush" Value="{DynamicResource CriticalBorderBrush}" />
</Style>
<Style Selector="^.danger:pointerover">
<Setter Property="Background" Value="{DynamicResource CriticalBrush}" />
<Setter Property="Foreground" Value="White" />
<Setter Property="BorderBrush" Value="{DynamicResource CriticalBrush}" />
</Style>

<Style Selector="^.sm">
Expand Down Expand Up @@ -204,10 +208,11 @@
<Style Selector="^.row.selected">
<Setter Property="Background" Value="{DynamicResource AccentSubtleBrush}" />
</Style>
<!-- Avalonia draws no box shadow on a border that differs by side, so the focused row's border goes all round -->
<Style Selector="^.row:focus-visible">
<Setter Property="FocusAdorner" Value="{x:Null}" />
<Setter Property="Background" Value="{DynamicResource AccentSubtleBrush}" />
<Setter Property="BorderBrush" Value="{DynamicResource AccentBorderBrush}" />
<Setter Property="Background" Value="{DynamicResource Bg3Brush}" />
<Setter Property="BorderBrush" Value="{DynamicResource Border1Brush}" />
<Setter Property="BorderThickness" Value="1" />
</Style>

<!-- Version cards in the history timeline -->
Expand Down Expand Up @@ -267,14 +272,17 @@
<Setter Property="FontWeight" Value="SemiBold" />
<Setter Property="FontSize" Value="13" />
<Setter Property="Cursor" Value="Hand" />
<Setter Property="FocusAdorner" Value="{x:Null}" />
<Setter Property="Template">
<ControlTemplate>
<Border Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="0,0,0,2"
Padding="10,8"
Margin="0,0,0,-1">
<ContentPresenter Content="{TemplateBinding Content}" ContentTemplate="{TemplateBinding ContentTemplate}" />
<!-- The focus ring sits on an outer border, since Avalonia draws no box shadow on the underline's one-sided border -->
<Border x:Name="PART_Focus" CornerRadius="4" Margin="0,0,0,-1">
<Border Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="0,0,0,2"
Padding="10,8">
<ContentPresenter Content="{TemplateBinding Content}" ContentTemplate="{TemplateBinding ContentTemplate}" />
</Border>
</Border>
</ControlTemplate>
</Setter>
Expand All @@ -285,6 +293,9 @@
<Setter Property="Foreground" Value="{DynamicResource Text1Brush}" />
<Setter Property="BorderBrush" Value="{DynamicResource AccentBrush}" />
</Style>
<Style Selector="^:focus-visible /template/ Border#PART_Focus">
<Setter Property="BoxShadow" Value="{DynamicResource FocusOutline}" />
</Style>
</ControlTheme>

<!-- Segmented control options (Cards / List, theme, history mode) -->
Expand All @@ -295,10 +306,14 @@
<Setter Property="FontSize" Value="12" />
<Setter Property="Padding" Value="9,0" />
<Setter Property="Cursor" Value="Hand" />
<Setter Property="BorderBrush" Value="Transparent" />
<Setter Property="FocusAdorner" Value="{x:Null}" />
<Setter Property="Template">
<ControlTemplate>
<Border x:Name="PART_Border"
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="1"
CornerRadius="3"
Padding="{TemplateBinding Padding}">
<ContentPresenter VerticalAlignment="Center"
Expand All @@ -312,11 +327,12 @@
<Setter Property="Foreground" Value="{DynamicResource Text1Brush}" />
</Style>
<Style Selector="^:checked">
<Setter Property="Background" Value="{DynamicResource Bg3Brush}" />
<Setter Property="Background" Value="{DynamicResource AccentSubtleBrush}" />
<Setter Property="BorderBrush" Value="{DynamicResource AccentBrush}" />
<Setter Property="Foreground" Value="{DynamicResource Text1Brush}" />
</Style>
<Style Selector="^:checked /template/ Border#PART_Border">
<Setter Property="BoxShadow" Value="{DynamicResource Shadow1}" />
<Style Selector="^:focus-visible /template/ Border#PART_Border">
<Setter Property="BoxShadow" Value="{DynamicResource FocusOutline}" />
</Style>
<Style Selector="^:disabled">
<Setter Property="Opacity" Value="0.45" />
Expand All @@ -331,6 +347,7 @@
<Setter Property="FontWeight" Value="SemiBold" />
<Setter Property="Cursor" Value="Hand" />
<Setter Property="HorizontalAlignment" Value="Stretch" />
<Setter Property="FocusAdorner" Value="{x:Null}" />
<Setter Property="Template">
<ControlTemplate>
<Border Height="34"
Expand All @@ -354,11 +371,15 @@
<Setter Property="BorderBrush" Value="{DynamicResource AccentBorderBrush}" />
<Setter Property="Foreground" Value="{DynamicResource AccentTextBrush}" />
</Style>
<Style Selector="^:focus-visible /template/ Border">
<Setter Property="BoxShadow" Value="{DynamicResource FocusOutline}" />
</Style>
</ControlTheme>

<!-- Switch -->
<ControlTheme x:Key="Switch" TargetType="ToggleButton">
<Setter Property="Cursor" Value="Hand" />
<Setter Property="FocusAdorner" Value="{x:Null}" />
<Setter Property="Background" Value="{DynamicResource Bg4Brush}" />
<Setter Property="BorderBrush" Value="{DynamicResource Border3Brush}" />
<Setter Property="Template">
Expand Down Expand Up @@ -397,7 +418,7 @@
<Setter Property="Background" Value="{DynamicResource TextInverseBrush}" />
</Style>
<Style Selector="^:focus-visible">
<Setter Property="BorderBrush" Value="{DynamicResource AccentHoverBrush}" />
<Setter Property="BorderBrush" Value="{DynamicResource Text1Brush}" />
</Style>
</ControlTheme>

Expand Down Expand Up @@ -536,6 +557,9 @@
<Style Selector="TextBlock.faint">
<Setter Property="Foreground" Value="{DynamicResource Text3Brush}" />
</Style>
<Style Selector="Button.nav.active TextBlock.faint">
<Setter Property="Foreground" Value="{DynamicResource Text2Brush}" />
</Style>
<Style Selector="TextBlock.variable">
<Setter Property="FontFamily" Value="{StaticResource MonoFont}" />
<Setter Property="FontSize" Value="12" />
Expand Down Expand Up @@ -632,10 +656,13 @@
<!-- Rating pips and Puff -->
<Style Selector="c|RatingPips">
<Setter Property="FilledBrush" Value="{DynamicResource LavenderBrush}" />
<Setter Property="EmptyBrush" Value="{DynamicResource Bg4Brush}" />
<Setter Property="EmptyBrush" Value="{DynamicResource Border3Brush}" />
<Setter Property="VerticalAlignment" Value="Center" />
<Setter Property="FocusAdorner" Value="{x:Null}" />
</Style>
<Style Selector="c|RatingPips[IsInteractive=True]">
<Setter Property="EmptyBrush" Value="{DynamicResource ControlBorderBrush}" />
</Style>
<Style Selector="c|RatingPips:focus-visible">
<Setter Property="FocusBrush" Value="{DynamicResource AccentBrush}" />
</Style>
Expand Down Expand Up @@ -727,7 +754,7 @@
</Style>
<Style Selector="TextBox.plain:focus /template/ Border#PART_BorderElement">
<Setter Property="Background" Value="{DynamicResource Bg2Brush}" />
<Setter Property="BoxShadow" Value="none" />
<Setter Property="BoxShadow" Value="{DynamicResource FocusOutline}" />
</Style>
<Style Selector="TextBox.title">
<Setter Property="FontSize" Value="20" />
Expand Down
12 changes: 7 additions & 5 deletions src/Prompuff.App/Themes/ThemeBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,8 @@ public static ResourceDictionary Tokens(ThemePalette p)
resources["Shadow3"] = Shadow(0, 8, 24, WithAlpha(shadow, dark ? (byte)0x80 : (byte)0x1F));
resources["Shadow4"] = Shadow(0, 24, 64, WithAlpha(shadow, dark ? (byte)0x99 : (byte)0x2E));
resources["FocusRing"] = new BoxShadows(new BoxShadow { Spread = 3, Color = WithAlpha(p.AccentColor, 0x1A) });
resources["FocusOutline"] = new BoxShadows(new BoxShadow { Spread = 2, IsInset = true, Color = p.AccentColor });
Brush("ControlBorderBrush", p.ControlBorder);

Brush("AccentBrush", p.AccentColor);
Brush("AccentHoverBrush", p.AccentHover);
Expand All @@ -94,8 +96,8 @@ public static ResourceDictionary Tokens(ThemePalette p)
Brush("TextControlBackground", dark ? p.Inset : p.Bg(2));
Brush("TextControlBackgroundPointerOver", dark ? p.Inset : p.Bg(2));
Brush("TextControlBackgroundFocused", dark ? p.Inset : p.Bg(2));
Brush("TextControlBorderBrush", p.Border(2));
Brush("TextControlBorderBrushPointerOver", p.Border(3));
Brush("TextControlBorderBrush", p.ControlBorder);
Brush("TextControlBorderBrushPointerOver", p.Text(3));
Brush("TextControlBorderBrushFocused", p.AccentColor);
Brush("TextControlForeground", p.Text(1));
Brush("TextControlForegroundPointerOver", p.Text(1));
Expand All @@ -108,9 +110,9 @@ public static ResourceDictionary Tokens(ThemePalette p)
Brush("ComboBoxBackgroundPointerOver", dark ? p.Bg(4) : p.Bg(3));
Brush("ComboBoxBackgroundPressed", p.Bg(4));
Brush("ComboBoxBackgroundFocused", raised);
Brush("ComboBoxBorderBrush", p.Border(2));
Brush("ComboBoxBorderBrushPointerOver", p.Border(3));
Brush("ComboBoxBorderBrushPressed", p.Border(3));
Brush("ComboBoxBorderBrush", p.ControlBorder);
Brush("ComboBoxBorderBrushPointerOver", p.Text(3));
Brush("ComboBoxBorderBrushPressed", p.Text(3));
Brush("ComboBoxForeground", p.Text(1));
Brush("ComboBoxDropDownBackground", raised);
Brush("ComboBoxDropDownBorderBrush", p.Border(2));
Expand Down
Loading
Loading