Give the window its v5b chrome and each session surface its own shell

This commit is contained in:
2026-08-08 00:49:59 +02:00
parent 1b76c51fbb
commit 43c939b697
30 changed files with 4433 additions and 1772 deletions
+55 -50
View File
@@ -9,86 +9,83 @@
The window asks Windows for no chrome at all, so everything a titlebar does has to be here: dragging,
the double-click to maximise, and three buttons. That is a real cost, and the reason it is worth paying
is that a 38-pixel grey system bar above a near-black application is the one part of the window that
is that a 53-pixel grey system bar above a near-black application is the one part of the window that
would look borrowed.
It sits above the terminal rather than over it, which matters more than it looks: the terminal is a
native child window that composites above anything Avalonia draws in the same rectangle, so a titlebar
overlapping it would be painted underneath and its close button would not be clickable.
── v5b ──────────────────────────────────────────────────────────────────────────────────────────────
Redrawn against TitleBar.dc.html rather than the v3 mock this replaced, and three things left with the
redraw. The vault chip and the account name are gone from here — both now live on the rail's user chip,
which is where the design's own "who is signed in" lives too, one destination lower than the window's
own name. 44 pixels became 53, which is the design's own height and not a number this file chose; see
<c>LayoutHarness.TitleBarHeight</c> and the matching 9-pixel rise in <c>MainWindow.axaml</c>'s own
<c>MinHeight</c>, which is what keeps every screen the exact height it was designed against despite the
bar above it growing.
The design's kbd chip reads ⌘K; this one reads CTRL K, because a Windows build is not where the ⌘ key
lives — the same substitution the search box's own tooltip already made before this pass touched it.
SYNCED stays, on the right, past the window buttons' own left edge: a documented deviation from a design
whose titlebar has no home for it at all — see design-notes/v5b-fidelity-notes.md.
-->
<Border Height="44" Background="{StaticResource Chrome}"
BorderBrush="{StaticResource Border}" BorderThickness="0,0,0,1"
<Border Height="53" Background="{StaticResource DeepChrome}"
PointerPressed="OnDrag" DoubleTapped="OnToggleMaximised">
<Grid ColumnDefinitions="Auto,*,Auto" Margin="14,0,10,0">
<Grid ColumnDefinitions="Auto,*,Auto" Margin="24,0,20,0">
<StackPanel Grid.Column="0" Orientation="Horizontal" Spacing="8" VerticalAlignment="Center">
<StackPanel Grid.Column="0" Orientation="Horizontal" Spacing="10" VerticalAlignment="Center">
<!--
Filled rather than outlined since v2, and rounded. The same mark the phone's header draws and the
same one the launcher icon carries, so the three cannot drift.
24 pixels and radius 7, the design's own tile — up from v3's 20/6, which was this bar's own
approximation before there was a mock to measure against. Filled rather than outlined, and the
same mark the phone's header draws and the launcher icon carries, so the three cannot drift.
-->
<Border Width="20" Height="20" CornerRadius="6" Background="{StaticResource Accent}">
<Border Width="24" Height="24" CornerRadius="7" Background="{StaticResource Accent}">
<TextBlock Classes="mono" Text="&gt;_" FontSize="10" FontWeight="Bold"
Foreground="{StaticResource AccentInk}"
HorizontalAlignment="Center" VerticalAlignment="Center" />
</Border>
<!--
The product's name is the one string in this bar that is not machine-shaped, so v2 sets it in the
sans face while the address, the account and the fingerprint beside it stay monospaced.
19 bold at -0.2 tracking, the design's own numbers. Named, because a nightly says so here — see
the code-behind, where the release build is exactly what this markup says and nothing changes
for it.
-->
<!--
Named, because a nightly says so here. See the code-behind: the release build is what this
markup says and nothing changes for it.
-->
<TextBlock x:Name="ProductName" Text="DodoSSH" FontSize="14" FontWeight="SemiBold"
Foreground="{StaticResource Text}" VerticalAlignment="Center" />
<!--
The design puts an organisation here — "dodotech / platform". There are no organisations: the
server has team tables and no endpoint that reads them, so the only name this application can
truthfully print is the one on the vault it has open. The account is beside it because a machine
can be enrolled to one account at a time and knowing which is the point of the chip.
-->
<Border Classes="chip" IsVisible="{Binding IsUnlocked}">
<TextBlock Text="{Binding Vault.VaultName}" />
</Border>
<TextBlock Classes="mono" Text="{Binding AccountName}" FontSize="11"
Foreground="{StaticResource TextFaint}" VerticalAlignment="Center"
TextTrimming="CharacterEllipsis" MaxWidth="220" />
<TextBlock x:Name="ProductName" Text="DodoSSH" FontSize="19" FontWeight="Bold"
LetterSpacing="-0.2" Foreground="{StaticResource Text}" VerticalAlignment="Center" />
</StackPanel>
<!--
The quick-connect box. It searches hosts and nothing else — the design's box also promises "run
command", and there is no snippet or saved-command item type for it to run. Clicking it is the same
as Ctrl+K, which is what the window binds; the design says ⌘K, and this is a Windows build.
514 wide and centred, which is what the design states for this box specifically — MaxWidth rather
than Width, so the button is free to shrink at the window's minimum instead of arranging outside its
own parent when there is no room for all 514 of it.
-->
<!--
Stretch-to-a-maximum, not a fixed width. The design draws this box at exactly 380 and centred, and
stating that as a Width on the Border is what makes it wrong: the Button around it is free to
shrink when the account name or the vault chip beside it is long, and a Border that will not shrink
with it arranges outside its own parent — over the name on one side and over the window buttons on
the other. MaxWidth on the stretching button gives the same 380 whenever there is room and gives
way when there is not.
-->
<Button Grid.Column="1" Classes="flat" MaxWidth="380" Height="28" Margin="16,0"
<Button Grid.Column="1" Classes="flat search" MaxWidth="514" Height="35"
HorizontalAlignment="Stretch" HorizontalContentAlignment="Stretch"
Command="{Binding ToggleSearchCommand}" IsEnabled="{Binding IsUnlocked}">
<Border Background="{StaticResource Field}" BorderBrush="{StaticResource BorderMid}"
BorderThickness="1" CornerRadius="8" Padding="10,0">
<Border Classes="searchpill" CornerRadius="10" Padding="16,0,8,0">
<Grid ColumnDefinitions="Auto,*,Auto">
<TextBlock Grid.Column="0" Text="⌕" FontSize="13"
Foreground="{StaticResource TextFaint}" VerticalAlignment="Center" />
<TextBlock Grid.Column="0" FontFamily="{StaticResource IconFont}" Text="&#xE8B6;"
FontSize="15" Foreground="{StaticResource TextGhost}" VerticalAlignment="Center" />
<!--
"Search or connect…", which is what it does: the palette connects on Enter. Not the design's
wider promise of running a command — a snippet is inserted from its own screen, and a box that
offered to run one would be offering something this palette does not do.
-->
<TextBlock Grid.Column="1" Text="Search or connect…" FontSize="13" Margin="8,0"
Foreground="{StaticResource TextFaint}" VerticalAlignment="Center" />
<Border Grid.Column="2" BorderBrush="{StaticResource BorderMid}" BorderThickness="1"
CornerRadius="4" Padding="5,1" VerticalAlignment="Center">
<TextBlock Classes="mono" Text="CTRL K" FontSize="10"
Foreground="{StaticResource TextFaint}" />
<TextBlock Grid.Column="1" Text="Search or connect…" FontSize="13.5" Margin="10,0"
Foreground="{StaticResource TextGhost}" VerticalAlignment="Center" />
<!-- CTRL K, not the design's ⌘K — see the remark at the top of this file. -->
<Border Grid.Column="2" Width="34" Height="18" CornerRadius="5"
Background="{StaticResource KbdChip}"
HorizontalAlignment="Center" VerticalAlignment="Center">
<TextBlock Classes="mono" Text="CTRL K" FontSize="10.5" FontWeight="Medium"
Foreground="{StaticResource TextFaint}"
HorizontalAlignment="Center" VerticalAlignment="Center" />
</Border>
</Grid>
</Border>
@@ -112,20 +109,28 @@
<Border Width="1" Height="16" Background="{StaticResource Border}"
IsVisible="{Binding IsUnlocked}" />
<!--
The window controls, restyled to the design's own quiet Material glyphs: remove, crop_square,
close, rather than the dashes and box this bar drew before there was a mock to measure them
against. What each does is unchanged — see the code-behind.
-->
<StackPanel Orientation="Horizontal" Spacing="2">
<Button Classes="flat" Width="26" Height="24" Click="OnMinimise"
ToolTip.Tip="Minimise">
<TextBlock Text="" FontSize="13" Foreground="{StaticResource TextDim}"
<TextBlock FontFamily="{StaticResource IconFont}" Text="&#xE15B;" FontSize="14"
Foreground="{StaticResource TextFaint}"
HorizontalAlignment="Center" VerticalAlignment="Center" />
</Button>
<Button Classes="flat" Width="26" Height="24" Click="OnToggleMaximised"
ToolTip.Tip="Maximise">
<TextBlock Text="▢" FontSize="11" Foreground="{StaticResource TextDim}"
<TextBlock FontFamily="{StaticResource IconFont}" Text="&#xE3C6;" FontSize="13"
Foreground="{StaticResource TextFaint}"
HorizontalAlignment="Center" VerticalAlignment="Center" />
</Button>
<Button Classes="flat close" Width="26" Height="24" Click="OnClose"
ToolTip.Tip="Close DodoSSH. This ends every shell it has open.">
<TextBlock Text="✕" FontSize="12" HorizontalAlignment="Center" VerticalAlignment="Center" />
<TextBlock FontFamily="{StaticResource IconFont}" Text="&#xE5CD;" FontSize="14"
HorizontalAlignment="Center" VerticalAlignment="Center" />
</Button>
</StackPanel>