From bfb84eef3907dc6088fb78cb10f4b9669c95677d Mon Sep 17 00:00:00 2001 From: Hazel Granados Date: Sat, 10 Oct 2026 17:49:41 -0500 Subject: [PATCH 1/7] fix(layout): fit the library and Settings in the smallest window MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit At 960 × 600 the selection hint ran under Select all, and Import's and About's buttons ran past their panels. The hint now trims with a tooltip, those buttons wrap, and shortcut names wrap beside long key lists. LayoutTests visits the library and every Settings section at that size and fails on text that overflows untrimmed or a button pushed past its panel. --- src/Prompuff.App/Views/LibraryView.axaml | 5 +- src/Prompuff.App/Views/SettingsView.axaml | 14 ++--- tests/Prompuff.App.Tests/LayoutTests.cs | 73 +++++++++++++++++++++++ 3 files changed, 83 insertions(+), 9 deletions(-) create mode 100644 tests/Prompuff.App.Tests/LayoutTests.cs diff --git a/src/Prompuff.App/Views/LibraryView.axaml b/src/Prompuff.App/Views/LibraryView.axaml index 0c62e8d..7a9c862 100644 --- a/src/Prompuff.App/Views/LibraryView.axaml +++ b/src/Prompuff.App/Views/LibraryView.axaml @@ -99,8 +99,9 @@ - - + + - + @@ -459,9 +459,9 @@ - - - + + + @@ -483,7 +483,7 @@ - + - + diff --git a/tests/Prompuff.App.Tests/LayoutTests.cs b/tests/Prompuff.App.Tests/LayoutTests.cs new file mode 100644 index 0000000..8688c30 --- /dev/null +++ b/tests/Prompuff.App.Tests/LayoutTests.cs @@ -0,0 +1,73 @@ +using Avalonia; +using Avalonia.Controls; +using Avalonia.Headless.XUnit; +using Avalonia.Media; +using Avalonia.VisualTree; +using Prompuff.App.ViewModels; + +namespace Prompuff.App.Tests; + +public class LayoutTests +{ + /// + /// Text that runs past the space it was given, with nothing to trim or wrap it, and buttons pushed past the panel + /// they sit in. Both are what a narrow window does to a layout that only fits a wide one. + /// + private static List Overflowing(AppHarness app, string screen) + { + var failures = new List(); + foreach (var control in app.Window.GetVisualDescendants().OfType()) + { + if (!control.IsEffectivelyVisible || control.Bounds.Width < 1 || control.FindAncestorOfType() is { HorizontalScrollBarVisibility: not Avalonia.Controls.Primitives.ScrollBarVisibility.Disabled }) + { + continue; + } + + if (control is TextBlock { TextTrimming: var trimming, TextWrapping: TextWrapping.NoWrap } text && trimming == TextTrimming.None + && text.TextLayout.WidthIncludingTrailingWhitespace > text.Bounds.Width + 1 && text.FindAncestorOfType() is not { ClipToBounds: true }) + { + failures.Add($"{screen}: \"{text.Text}\" needs {text.TextLayout.WidthIncludingTrailingWhitespace:0} px but has {text.Bounds.Width:0}"); + } + + if (control is Button button && button.FindAncestorOfType() is { } panel + && button.TranslatePoint(new Point(button.Bounds.Width, 0), panel) is { } right && right.X > panel.Bounds.Width + 1) + { + failures.Add($"{screen}: the button \"{Controls.AccessibleNames.Describe(button)}\" runs {right.X - panel.Bounds.Width:0} px past its panel"); + } + } + + return failures; + } + + /// At the window's minimum size, 960 × 600, the library and every Settings section fit without clipping. + [AvaloniaFact] + public async Task The_library_and_settings_fit_the_smallest_window() + { + await using var app = await AppHarness.StartAsync(width: 960, height: 600); + var failures = new List(); + + failures.AddRange(Overflowing(app, "library cards")); + app.Screenshot("min-size-library-cards"); + app.ViewModel.Library.IsListLayout = true; + await app.SettleAsync(); + failures.AddRange(Overflowing(app, "library list")); + app.Screenshot("min-size-library-list"); + + app.ViewModel.Library.SelectAll(); + await app.SettleAsync(); + failures.AddRange(Overflowing(app, "library selecting")); + app.Screenshot("min-size-library-selecting"); + app.ViewModel.Library.ClearSelection(); + + await app.ViewModel.Sidebar.OpenSettingsCommand.ExecuteAsync(null); + foreach (var section in Enum.GetValues()) + { + app.ViewModel.Settings.Select(section); + await app.SettleAsync(); + failures.AddRange(Overflowing(app, $"settings {section}")); + app.Screenshot($"min-size-settings-{section.ToString().ToLowerInvariant()}"); + } + + Assert.True(failures.Count == 0, $"{failures.Count} things don't fit at 960 × 600:\n" + string.Join("\n", failures.Distinct())); + } +} From 4eb75242e9f759367b8db6392d91bb38487f7e36 Mon Sep 17 00:00:00 2001 From: Hazel Granados Date: Sat, 10 Oct 2026 17:49:42 -0500 Subject: [PATCH 2/7] fix(layout): wrap long dialog titles The title sat in a horizontal stack beside the warning icon, so a long one, such as Delete with a long prompt title, ran out of the dialog. --- src/Prompuff.App/Views/MainWindow.axaml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Prompuff.App/Views/MainWindow.axaml b/src/Prompuff.App/Views/MainWindow.axaml index 5a2a0ac..2ed55e6 100644 --- a/src/Prompuff.App/Views/MainWindow.axaml +++ b/src/Prompuff.App/Views/MainWindow.axaml @@ -447,10 +447,10 @@ - - - - + + + +