diff --git a/.claude/CLAUDE.md b/.claude/CLAUDE.md index b0ce666c..0d47c31d 100644 --- a/.claude/CLAUDE.md +++ b/.claude/CLAUDE.md @@ -1425,6 +1425,24 @@ Three rules about it: vocabulary is app-wide across the secondary windows and dialogs; the main window's command bar deliberately keeps its flat minimalist `toolbar` buttons (rule 1) and is the one surface exempt. + **A status line is `TextBlock.statusMessage`** (`Styles/Theme.axaml`, + 2026-10, 1.0.1 release pass): one line (`MaxLines=1`: Npgsql puts a server + error's `DETAIL` after a newline, which grew the bar a line), cut with an + ellipsis, and its whole text in a tooltip only while it is cut + (`Converters/CutTextTip`, which reads the block's `TextLayout` for a + collapsed line or lines left out). The main window's message and + cap warning, and the Activity, Database Overview and Security windows' status + lines use it; Slow Queries keeps its wrapping line, a paragraph of caveats + meant to be read. Found because a failed safe-mode commit read "Commit + failed…" in a narrow window with no way to see why: the main message had + carried a `ToolTip.Tip` since the bar was built, and it never once opened. + **Landmine: a `TextBlock` or panel with no `Background` is not hit-testable** + (not even over its glyphs: 0 of 4,536 points over the status text reached + it), so a tooltip on it is dead and the pointer lands on whatever has a + background behind it. The style sets `Background="Transparent"`, and so does + `Border.statusBar StackPanel`, whose segment tooltips (read-only reason, In + transaction, staged changes) had opened only over an icon's ink. + `StatusLineTests` hovers each with real pointer input. **Surfaces and dialogs have a vocabulary too** (2026-09, DESIGN.md rules 15 and 16). Every secondary window sits on the shell tone — a `Window` style in `Styles/Theme.axaml` sets it, and the Inter font, so no window sets either — diff --git a/src/PgNimbus.App/Converters/CutTextTip.cs b/src/PgNimbus.App/Converters/CutTextTip.cs new file mode 100644 index 00000000..edfb27f7 --- /dev/null +++ b/src/PgNimbus.App/Converters/CutTextTip.cs @@ -0,0 +1,31 @@ +using System.Globalization; +using Avalonia.Controls; +using Avalonia.Data.Converters; + +namespace PgNimbus.App.Converters; + +/// +/// The tooltip of a TextBlock.statusMessage: its whole text while the +/// line is cut with an ellipsis, and nothing while it fits (a tooltip repeating +/// what is already on screen is noise). Bound as a multi-binding over the text +/// block itself, its text and its width, so it is asked again whenever either +/// changes; by then the block's layout reflects the new width. +/// +public sealed class CutTextTip : IMultiValueConverter +{ + public static readonly CutTextTip Instance = new(); + + public object? Convert(IList values, Type targetType, object? parameter, CultureInfo culture) => + values is [TextBlock { Text: { Length: > 0 } text } block, ..] && IsCut(block) ? text : null; + + /// + /// Whether is showing less than its text: a line + /// ended in an ellipsis, or lines left out by MaxLines. + /// + public static bool IsCut(TextBlock block) + { + var lines = block.TextLayout.TextLines; + return lines.Any(line => line.HasCollapsed) + || lines.Sum(line => line.Length) < (block.Text?.Length ?? 0); + } +} diff --git a/src/PgNimbus.App/Styles/Theme.axaml b/src/PgNimbus.App/Styles/Theme.axaml index e64941cd..5c5292c7 100644 --- a/src/PgNimbus.App/Styles/Theme.axaml +++ b/src/PgNimbus.App/Styles/Theme.axaml @@ -3,7 +3,8 @@ xmlns:cc="clr-namespace:AvaloniaEdit.CodeCompletion;assembly=AvaloniaEdit" xmlns:search="clr-namespace:AvaloniaEdit.Search;assembly=AvaloniaEdit" xmlns:completion="using:PgNimbus.App.Completion" - xmlns:cmd="using:PgNimbus.App"> + xmlns:cmd="using:PgNimbus.App" + xmlns:conv="using:PgNimbus.App.Converters"> + + + + + diff --git a/src/PgNimbus.App/Views/ActivityWindow.axaml b/src/PgNimbus.App/Views/ActivityWindow.axaml index 523be1b3..7748aa19 100644 --- a/src/PgNimbus.App/Views/ActivityWindow.axaml +++ b/src/PgNimbus.App/Views/ActivityWindow.axaml @@ -166,7 +166,7 @@ - + diff --git a/src/PgNimbus.App/Views/DatabaseOverviewWindow.axaml b/src/PgNimbus.App/Views/DatabaseOverviewWindow.axaml index 1dfd2323..a958cad5 100644 --- a/src/PgNimbus.App/Views/DatabaseOverviewWindow.axaml +++ b/src/PgNimbus.App/Views/DatabaseOverviewWindow.axaml @@ -109,7 +109,7 @@ - + diff --git a/src/PgNimbus.App/Views/MainWindow.axaml b/src/PgNimbus.App/Views/MainWindow.axaml index 75baed20..016c0622 100644 --- a/src/PgNimbus.App/Views/MainWindow.axaml +++ b/src/PgNimbus.App/Views/MainWindow.axaml @@ -522,15 +522,14 @@ + (statusMessage: full text on hover while it is cut), while every + other segment is compact and keeps its width. Long cap text + truncates the same way. --> + Classes="statusText statusMessage" Classes.error="{Binding ActiveTab.HasError}" + VerticalAlignment="Center" HorizontalAlignment="Left" /> - +