Public Access
1093 lines
60 KiB
XML
1093 lines
60 KiB
XML
<Application xmlns="https://github.com/avaloniaui"
|
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
|
x:Class="DodoSSH.Client.App.DodoSshApp"
|
|
RequestedThemeVariant="Dark">
|
|
|
|
<!--
|
|
Dark by default rather than following the system. A terminal is a dark surface either way, and
|
|
a light chrome around a dark terminal is the worst of both: the eye adapts to the bright frame
|
|
and then cannot read the text.
|
|
-->
|
|
|
|
<Application.Resources>
|
|
|
|
<!--
|
|
The palette and the font stack, shared with the Android head. They moved into DodoSSH.Client.Shell
|
|
when there were two heads that had to agree on them; Theme/Palette.axaml carries the reasoning behind
|
|
the names, the five near-black surfaces and the font substitution.
|
|
-->
|
|
<ResourceDictionary>
|
|
<ResourceDictionary.MergedDictionaries>
|
|
<ResourceInclude Source="avares://DodoSSH.Client.Shell/Theme/Palette.axaml" />
|
|
</ResourceDictionary.MergedDictionaries>
|
|
</ResourceDictionary>
|
|
|
|
</Application.Resources>
|
|
|
|
<Application.Styles>
|
|
<FluentTheme />
|
|
|
|
<!--
|
|
Application-wide rather than on MainWindow, which is where the first three lived until the vault column
|
|
became its own control. A Window's styles reach its whole tree, so the move changes nothing about how
|
|
the application renders — but a control laid out on its own, as the layout harness lays the column out,
|
|
would otherwise lose them. That matters more than it looks: "hint" carries TextWrapping, and text that
|
|
wraps in the application and does not wrap in the harness makes every measured height too small, which
|
|
is the one way this kind of test lies quietly.
|
|
-->
|
|
<!--
|
|
◆ THE BASE SIZE, and it is set here rather than on the window.
|
|
|
|
Every explicit FontSize below is a step off a base nothing was stating: a bare TextBlock took
|
|
TextElement's own default of 12, which meant the one number the whole scale is measured from lived in
|
|
Avalonia rather than in this file. Raising the scale meant naming it.
|
|
|
|
Declared on Window *and* on UserControl, which is not redundancy. FontSize inherits, so the window
|
|
alone would reach everything the application draws — but the layout harness hosts a UserControl in a
|
|
plain `new Window()` it constructs itself, and that window has no style of this application's on it.
|
|
Without the second selector the harness would measure every screen a point smaller than it ships,
|
|
which is the failure mode App.axaml's own note at the top of this block was written about: a test that
|
|
lays out text smaller than the application does reports heights that are all slightly too small, and
|
|
it does it silently.
|
|
|
|
A selector on TextBlock would have been the obvious way and is wrong. Style setters beat inherited
|
|
values in Avalonia, so `Selector="TextBlock"` would win over the size a Button sets on itself and
|
|
reach the TextBlock inside that button's template — collapsing every deliberate step below back to one
|
|
number.
|
|
-->
|
|
<Style Selector="Window">
|
|
<Setter Property="FontSize" Value="13" />
|
|
</Style>
|
|
<Style Selector="UserControl">
|
|
<Setter Property="FontSize" Value="13" />
|
|
</Style>
|
|
|
|
<Style Selector="TextBlock.hint">
|
|
<Setter Property="Foreground" Value="{StaticResource TextDim}" />
|
|
<Setter Property="TextWrapping" Value="Wrap" />
|
|
</Style>
|
|
<Style Selector="TextBlock.heading">
|
|
<Setter Property="Foreground" Value="{StaticResource Text}" />
|
|
<Setter Property="FontSize" Value="19" />
|
|
<Setter Property="FontWeight" Value="SemiBold" />
|
|
</Style>
|
|
<Style Selector="Border.card">
|
|
<Setter Property="Background" Value="{StaticResource Chrome}" />
|
|
<Setter Property="BorderBrush" Value="{StaticResource Border}" />
|
|
<Setter Property="BorderThickness" Value="1" />
|
|
<Setter Property="CornerRadius" Value="12" />
|
|
<Setter Property="Padding" Value="24" />
|
|
<Setter Property="MaxWidth" Value="520" />
|
|
<Setter Property="VerticalAlignment" Value="Center" />
|
|
<Setter Property="HorizontalAlignment" Value="Center" />
|
|
</Style>
|
|
|
|
<!--
|
|
Monospace, which in this design is not a decoration for code. Host names, fingerprints, addresses and
|
|
counts are all things people compare character by character, and a proportional font is what makes two
|
|
similar fingerprints look alike.
|
|
-->
|
|
<Style Selector="TextBlock.mono">
|
|
<Setter Property="FontFamily" Value="{StaticResource MonoFont}" />
|
|
</Style>
|
|
<Style Selector="SelectableTextBlock.mono">
|
|
<Setter Property="FontFamily" Value="{StaticResource MonoFont}" />
|
|
</Style>
|
|
|
|
<!--
|
|
The small tracked-out capitals the design uses for every section heading. Letter spacing rather than
|
|
bold: at this size weight closes the counters up and the word turns into a smudge, whereas spacing is
|
|
what makes six characters read as a label instead of as an abbreviation.
|
|
-->
|
|
<Style Selector="TextBlock.label">
|
|
<Setter Property="FontFamily" Value="{StaticResource MonoFont}" />
|
|
<Setter Property="FontSize" Value="11" />
|
|
<Setter Property="FontWeight" Value="SemiBold" />
|
|
<Setter Property="LetterSpacing" Value="1.2" />
|
|
<Setter Property="Foreground" Value="{StaticResource TextFaint}" />
|
|
</Style>
|
|
|
|
<!--
|
|
A chip: a bordered scrap of text stating one fact. The design uses them for tags, roles, scopes and
|
|
shortcut hints, which have nothing in common except that each is a noun the eye should be able to skip.
|
|
|
|
CornerRadius 6 rather than v2's 4: v3 draws every small chip — a tag, a pin badge — at 5-6, distinct
|
|
from the 10-12 the cards and fields moved to, so a chip keeps reading as a chip beside either.
|
|
-->
|
|
<Style Selector="Border.chip">
|
|
<Setter Property="BorderBrush" Value="{StaticResource BorderMid}" />
|
|
<Setter Property="BorderThickness" Value="1" />
|
|
<Setter Property="CornerRadius" Value="6" />
|
|
<Setter Property="Padding" Value="6,2" />
|
|
<Setter Property="VerticalAlignment" Value="Center" />
|
|
</Style>
|
|
<Style Selector="Border.chip > TextBlock">
|
|
<Setter Property="FontFamily" Value="{StaticResource MonoFont}" />
|
|
<Setter Property="FontSize" Value="11" />
|
|
<Setter Property="FontWeight" Value="Medium" />
|
|
<Setter Property="LetterSpacing" Value="0.5" />
|
|
<Setter Property="Foreground" Value="{StaticResource TextDim}" />
|
|
</Style>
|
|
<Style Selector="Border.chip.accent">
|
|
<Setter Property="BorderBrush" Value="{StaticResource AccentSoft}" />
|
|
</Style>
|
|
<!--
|
|
AccentText rather than Accent, which is the v2 split: the fill colour is too saturated to read as
|
|
small text on a dark surface, and a chip is small text. See the remark on the pair in Palette.axaml.
|
|
-->
|
|
<Style Selector="Border.chip.accent > TextBlock">
|
|
<Setter Property="Foreground" Value="{StaticResource AccentText}" />
|
|
</Style>
|
|
<!--
|
|
A chip that is also a button: the tag picker in the host editor. It borrows Border.chip's geometry
|
|
rather than inheriting it, because a Button is not a Border and Avalonia's selectors are structural —
|
|
the numbers are repeated here and the two have to move together, which is why they sit adjacent.
|
|
|
|
Worn is filled, unworn is outlined, and the difference is the accent rather than a tick: a row of
|
|
these has to read as "the tags this host has" at a glance, and a checkbox column reads as a form.
|
|
-->
|
|
<Style Selector="Button.chiptoggle">
|
|
<Setter Property="Background" Value="Transparent" />
|
|
<Setter Property="BorderBrush" Value="{StaticResource BorderMid}" />
|
|
<Setter Property="BorderThickness" Value="1" />
|
|
<Setter Property="CornerRadius" Value="6" />
|
|
<Setter Property="Padding" Value="6,2" />
|
|
<Setter Property="MinHeight" Value="0" />
|
|
<Setter Property="Foreground" Value="{StaticResource TextDim}" />
|
|
<Setter Property="FontFamily" Value="{StaticResource MonoFont}" />
|
|
<Setter Property="FontWeight" Value="Medium" />
|
|
</Style>
|
|
<Style Selector="Button.chiptoggle.worn">
|
|
<Setter Property="BorderBrush" Value="{StaticResource AccentSoft}" />
|
|
<Setter Property="Foreground" Value="{StaticResource AccentText}" />
|
|
</Style>
|
|
<Style Selector="Button.chiptoggle.worn /template/ ContentPresenter">
|
|
<Setter Property="Background" Value="{StaticResource AccentWash}" />
|
|
</Style>
|
|
<Style Selector="Button.chiptoggle:pointerover /template/ ContentPresenter">
|
|
<Setter Property="Background" Value="{StaticResource Hover}" />
|
|
</Style>
|
|
|
|
<Style Selector="Border.chip.warn">
|
|
<Setter Property="BorderBrush" Value="{StaticResource WarnSoft}" />
|
|
</Style>
|
|
<Style Selector="Border.chip.warn > TextBlock">
|
|
<Setter Property="Foreground" Value="{StaticResource Warn}" />
|
|
</Style>
|
|
|
|
<!--
|
|
The buttons. Fluent's own chrome is a rounded grey slab, and one of those beside a hairline-bordered
|
|
chip reads as belonging to a different application — so the three shapes this design uses are declared
|
|
here rather than restyled per view.
|
|
|
|
Each sets its brushes on the content presenter, not on the button. That is where the Fluent theme puts
|
|
its own, so a Background set on the button is a TemplateBinding the theme's :pointerover rule overrides
|
|
— which shows up as a button that is styled until the pointer arrives and then is not.
|
|
-->
|
|
<Style Selector="Button.ghost /template/ ContentPresenter#PART_ContentPresenter">
|
|
<Setter Property="Background" Value="Transparent" />
|
|
<Setter Property="BorderBrush" Value="{StaticResource BorderMid}" />
|
|
<Setter Property="BorderThickness" Value="1" />
|
|
<Setter Property="CornerRadius" Value="10" />
|
|
<Setter Property="Foreground" Value="{StaticResource TextDim}" />
|
|
</Style>
|
|
<Style Selector="Button.ghost:pointerover /template/ ContentPresenter#PART_ContentPresenter">
|
|
<Setter Property="Background" Value="{StaticResource ChromeHover}" />
|
|
<Setter Property="BorderBrush" Value="{StaticResource BorderHover}" />
|
|
<Setter Property="Foreground" Value="{StaticResource Text}" />
|
|
</Style>
|
|
<Style Selector="Button.ghost:disabled /template/ ContentPresenter#PART_ContentPresenter">
|
|
<Setter Property="Background" Value="Transparent" />
|
|
<Setter Property="BorderBrush" Value="{StaticResource BorderFaint}" />
|
|
<Setter Property="Foreground" Value="{StaticResource TextFaint}" />
|
|
</Style>
|
|
|
|
<!--
|
|
The primary action, and since v3 filled with a gradient rather than a flat colour: the design draws
|
|
every accent button top-to-bottom from a lighter violet into the accent proper, and lifts it off the
|
|
surface with a soft violet glow instead of a border. Both live in Palette.axaml as AccentGradient and
|
|
AccentGlow, named there rather than here for the reason every other accent value is — see the remark
|
|
on the pair in that file.
|
|
|
|
BoxShadow is set here rather than on the Button itself: this rule already targets the template's
|
|
ContentPresenter for Background for the Fluent-override reason explained above, and ContentPresenter
|
|
carries its own BoxShadow property in Avalonia 11, so the glow and the fill live on the same element
|
|
and move together.
|
|
-->
|
|
<Style Selector="Button.accent /template/ ContentPresenter#PART_ContentPresenter">
|
|
<Setter Property="Background" Value="{StaticResource AccentGradient}" />
|
|
<Setter Property="BoxShadow" Value="{StaticResource AccentGlow}" />
|
|
<Setter Property="BorderThickness" Value="0" />
|
|
<Setter Property="CornerRadius" Value="10" />
|
|
<Setter Property="Foreground" Value="{StaticResource AccentInk}" />
|
|
</Style>
|
|
<Style Selector="Button.accent:pointerover /template/ ContentPresenter#PART_ContentPresenter">
|
|
<Setter Property="Background" Value="{StaticResource AccentGradient}" />
|
|
<Setter Property="Opacity" Value="0.85" />
|
|
<Setter Property="Foreground" Value="{StaticResource AccentInk}" />
|
|
</Style>
|
|
<!--
|
|
A disabled accent button keeps its shape and loses its fill. Fluent's disabled state greys the
|
|
foreground and leaves the background, which on a purple slab is unreadable rather than merely dim.
|
|
|
|
BoxShadow is cleared here too, and that is new alongside the gradient: the base rule now sets a glow
|
|
that reads as "this is lit and wants pressing", which is the opposite of what a disabled control
|
|
should say. Left unset it would still apply — the base rule's Setter is still in effect wherever a
|
|
more specific one does not override it — so the glow has to be named here, as "none", to go away.
|
|
|
|
◆ "none" RATHER THAN THE EMPTY STRING. The remark this replaced claimed an empty string parses to "no
|
|
shadows", and it does not on the Avalonia this project builds against — BoxShadowsTypeConverter throws
|
|
an InvalidCastException on it instead, which failed silently at style-sheet load time in nothing that
|
|
exercises this rule's own screen and loudly in every headless layout test that lays out any window at
|
|
all, because Application.Styles is global. "none" is the literal this converter does accept for an
|
|
empty BoxShadows.
|
|
-->
|
|
<Style Selector="Button.accent:disabled /template/ ContentPresenter#PART_ContentPresenter">
|
|
<Setter Property="Background" Value="Transparent" />
|
|
<Setter Property="BorderBrush" Value="{StaticResource BorderFaint}" />
|
|
<Setter Property="BorderThickness" Value="1" />
|
|
<Setter Property="BoxShadow" Value="none" />
|
|
<Setter Property="Foreground" Value="{StaticResource TextFaint}" />
|
|
</Style>
|
|
|
|
<Style Selector="Button.danger /template/ ContentPresenter#PART_ContentPresenter">
|
|
<Setter Property="Background" Value="Transparent" />
|
|
<Setter Property="BorderBrush" Value="{StaticResource DangerSoft}" />
|
|
<Setter Property="BorderThickness" Value="1" />
|
|
<Setter Property="CornerRadius" Value="10" />
|
|
<Setter Property="Foreground" Value="{StaticResource Danger}" />
|
|
</Style>
|
|
<Style Selector="Button.danger:pointerover /template/ ContentPresenter#PART_ContentPresenter">
|
|
<Setter Property="Background" Value="{StaticResource DangerWash}" />
|
|
<Setter Property="BorderBrush" Value="{StaticResource Danger}" />
|
|
<Setter Property="Foreground" Value="{StaticResource Danger}" />
|
|
</Style>
|
|
<Style Selector="Button.danger:disabled /template/ ContentPresenter#PART_ContentPresenter">
|
|
<Setter Property="Background" Value="Transparent" />
|
|
<Setter Property="BorderBrush" Value="{StaticResource BorderFaint}" />
|
|
<Setter Property="Foreground" Value="{StaticResource TextFaint}" />
|
|
</Style>
|
|
|
|
<!-- Every button in this window is small, mono and tracked out; only the colours differ. -->
|
|
<Style Selector="Button.ghost, Button.accent, Button.danger">
|
|
<Setter Property="FontFamily" Value="{StaticResource MonoFont}" />
|
|
<Setter Property="FontSize" Value="11.5" />
|
|
<Setter Property="FontWeight" Value="SemiBold" />
|
|
<Setter Property="LetterSpacing" Value="0.8" />
|
|
<Setter Property="Padding" Value="10,5" />
|
|
<Setter Property="MinHeight" Value="0" />
|
|
<Setter Property="VerticalAlignment" Value="Center" />
|
|
</Style>
|
|
|
|
<!--
|
|
Buttons that are not shaped like buttons: a group heading, a nav-rail destination, a terminal tab, a
|
|
window control. All four are clickable regions that read as part of the chrome, so they carry no
|
|
border and no fill until the pointer is over them — and all four are buttons rather than borders with
|
|
a gesture, because a button is focusable, keyboard-activatable and announced as a control.
|
|
-->
|
|
<Style Selector="Button.flat">
|
|
<Setter Property="MinHeight" Value="0" />
|
|
<Setter Property="MinWidth" Value="0" />
|
|
<Setter Property="Padding" Value="0" />
|
|
<Setter Property="CornerRadius" Value="0" />
|
|
<Setter Property="Background" Value="Transparent" />
|
|
<Setter Property="BorderThickness" Value="0" />
|
|
</Style>
|
|
<Style Selector="Button.flat /template/ ContentPresenter#PART_ContentPresenter">
|
|
<Setter Property="Background" Value="Transparent" />
|
|
<Setter Property="BorderThickness" Value="0" />
|
|
<Setter Property="CornerRadius" Value="0" />
|
|
</Style>
|
|
<Style Selector="Button.flat:pointerover /template/ ContentPresenter#PART_ContentPresenter">
|
|
<Setter Property="Background" Value="{StaticResource ChromeHover}" />
|
|
</Style>
|
|
<Style Selector="Button.flat:pressed /template/ ContentPresenter#PART_ContentPresenter">
|
|
<Setter Property="Background" Value="{StaticResource ChromeHover}" />
|
|
</Style>
|
|
|
|
<!--
|
|
Button.grouphead was here: the padding on the fold-away group heading that used to sit between the host
|
|
cards. The headings went when the grid became cards and the group cards above it became the thing that
|
|
names a group — see HostsScreen.axaml — and a style with nothing wearing it is a shape somebody will
|
|
later reintroduce by reaching for it.
|
|
-->
|
|
|
|
<!-- A category in the vault's rail: the same accent strip a selected row carries, at full row height. -->
|
|
<Style Selector="Button.cat">
|
|
<Setter Property="Padding" Value="0,6,14,6" />
|
|
<Setter Property="HorizontalAlignment" Value="Stretch" />
|
|
<Setter Property="HorizontalContentAlignment" Value="Stretch" />
|
|
<Setter Property="FontFamily" Value="{StaticResource MonoFont}" />
|
|
<Setter Property="FontSize" Value="11" />
|
|
<Setter Property="FontWeight" Value="Medium" />
|
|
<Setter Property="LetterSpacing" Value="0.5" />
|
|
<Setter Property="Foreground" Value="{StaticResource TextDim}" />
|
|
</Style>
|
|
<Style Selector="Button.cat /template/ ContentPresenter#PART_ContentPresenter">
|
|
<Setter Property="Foreground" Value="{StaticResource TextDim}" />
|
|
</Style>
|
|
<Style Selector="Button.cat.active /template/ ContentPresenter#PART_ContentPresenter">
|
|
<Setter Property="Background" Value="{StaticResource AccentWash}" />
|
|
<Setter Property="Foreground" Value="{StaticResource Text}" />
|
|
</Style>
|
|
<!--
|
|
The nav rail. The active destination is marked with an accent bar down its left edge and a wash
|
|
behind it, which is the design's whole idiom for "you are here" — the same two marks a selected list
|
|
row carries, so the window has one vocabulary for selection rather than one per control.
|
|
-->
|
|
<!--
|
|
A destination in the sidebar. v2 turns these from 54-pixel stacked labels into 32-pixel rows with a
|
|
glyph, a word and a count, and the active one becomes a filled rounded row rather than a label with an
|
|
accent bar down its left edge. The bar is gone because a filled row at this width already reads as
|
|
chosen, and the bar was carrying that on its own when there was no room for a fill.
|
|
-->
|
|
<Style Selector="Button.nav">
|
|
<Setter Property="Height" Value="32" />
|
|
<Setter Property="Padding" Value="10,0" />
|
|
<Setter Property="HorizontalAlignment" Value="Stretch" />
|
|
<Setter Property="HorizontalContentAlignment" Value="Stretch" />
|
|
<Setter Property="VerticalContentAlignment" Value="Center" />
|
|
<Setter Property="CornerRadius" Value="8" />
|
|
<Setter Property="FontSize" Value="13" />
|
|
<Setter Property="FontWeight" Value="Medium" />
|
|
<Setter Property="Foreground" Value="{StaticResource TextDim}" />
|
|
</Style>
|
|
<Style Selector="Button.nav /template/ ContentPresenter#PART_ContentPresenter">
|
|
<Setter Property="Foreground" Value="{StaticResource TextDim}" />
|
|
<Setter Property="BorderThickness" Value="0" />
|
|
<Setter Property="CornerRadius" Value="8" />
|
|
</Style>
|
|
<Style Selector="Button.nav:pointerover /template/ ContentPresenter#PART_ContentPresenter">
|
|
<Setter Property="Foreground" Value="{StaticResource Text}" />
|
|
<Setter Property="Background" Value="{StaticResource Hover}" />
|
|
</Style>
|
|
<Style Selector="Button.nav.active /template/ ContentPresenter#PART_ContentPresenter">
|
|
<Setter Property="Foreground" Value="{StaticResource AccentText}" />
|
|
<Setter Property="Background" Value="{StaticResource Active}" />
|
|
</Style>
|
|
|
|
<!--
|
|
The three parts of a sidebar row. Separate classes rather than inline setters because nine rows draw
|
|
them and the day one of the three moves is the day eight of them would not have.
|
|
|
|
The glyph and the label inherit the row's own foreground, so they light with it; the count does not,
|
|
because a number that lit with its row would compete with the word beside it for the same emphasis.
|
|
-->
|
|
<Style Selector="TextBlock.navicon">
|
|
<Setter Property="FontSize" Value="14" />
|
|
<Setter Property="Width" Value="20" />
|
|
<Setter Property="VerticalAlignment" Value="Center" />
|
|
</Style>
|
|
<Style Selector="TextBlock.navlabel">
|
|
<Setter Property="VerticalAlignment" Value="Center" />
|
|
<Setter Property="TextTrimming" Value="CharacterEllipsis" />
|
|
</Style>
|
|
<Style Selector="TextBlock.navcount">
|
|
<Setter Property="FontFamily" Value="{StaticResource MonoFont}" />
|
|
<Setter Property="FontSize" Value="11" />
|
|
<Setter Property="Foreground" Value="{StaticResource TextFaint}" />
|
|
<Setter Property="VerticalAlignment" Value="Center" />
|
|
</Style>
|
|
|
|
<!--
|
|
A terminal tab, and since v2 a pill rather than a filing-cabinet tab: 30 tall inside a 42 strip, its
|
|
own rounded outline, and the active one filled instead of marked along an edge. The edge mark is gone
|
|
because a pill has no edge to share with its neighbour — the gap between two of them is the divider
|
|
the old top-and-right border was standing in for.
|
|
-->
|
|
<Style Selector="Button.tab">
|
|
<!-- Less on the right than the left: the close box lives inside the tab and brings its own margin. -->
|
|
<Setter Property="Padding" Value="12,0,8,0" />
|
|
<Setter Property="Height" Value="30" />
|
|
<Setter Property="Margin" Value="0,0,6,0" />
|
|
<Setter Property="VerticalAlignment" Value="Center" />
|
|
<Setter Property="CornerRadius" Value="8" />
|
|
<Setter Property="FontSize" Value="13" />
|
|
<Setter Property="FontWeight" Value="Medium" />
|
|
<Setter Property="Foreground" Value="{StaticResource TextDim}" />
|
|
</Style>
|
|
|
|
<!--
|
|
◆ ORDER IS THE BEHAVIOUR HERE. The base pill comes first, then its hover, then the exceptions — and
|
|
that ordering is the fix for a bug this arrangement had when v2 first drew it.
|
|
|
|
A pill paints its own Background, which the flat tab it replaced did not. That one detail moves where
|
|
the hover has to live: `Button.flat:pointerover` is declared far above and used to supply it, and the
|
|
moment `.tab`'s template rule set a Background of its own, the later declaration won and every tab in
|
|
the strip lost its pointer feedback silently. The `+` lost more than that — it sits below as an
|
|
exception, so a `.tab` rule declared after it was overriding the very thing that made it an exception,
|
|
and it drew as a filled outlined pill contradicting the comment above it.
|
|
|
|
Avalonia has no specificity; the later declaration wins. The same trap is recorded further down this
|
|
file for Border.rowmark. Anything added below must be an exception to what is above it, never a
|
|
restatement of the base.
|
|
-->
|
|
<Style Selector="Button.tab /template/ ContentPresenter#PART_ContentPresenter">
|
|
<Setter Property="Foreground" Value="{StaticResource TextDim}" />
|
|
<Setter Property="Background" Value="{StaticResource Panel}" />
|
|
<Setter Property="BorderBrush" Value="{StaticResource Border}" />
|
|
<Setter Property="BorderThickness" Value="1" />
|
|
<Setter Property="CornerRadius" Value="8" />
|
|
</Style>
|
|
<Style Selector="Button.tab:pointerover /template/ ContentPresenter#PART_ContentPresenter">
|
|
<Setter Property="Background" Value="{StaticResource Hover}" />
|
|
<Setter Property="Foreground" Value="{StaticResource Text}" />
|
|
</Style>
|
|
|
|
<!--
|
|
One of the strip's three fixed tabs — Vaults, SFTP, S3. A pill in every respect except that it has no
|
|
close box, so it takes its padding back on the right: the base rule is short there to leave room for
|
|
the cross a terminal tab carries inside itself, and a fixed tab with the same asymmetry sits visibly
|
|
off-centre beside one that has a reason for it.
|
|
|
|
Nothing else differs, deliberately. These are tabs and have to read as tabs — the whole point of the
|
|
strip is that "where the window is" is one row of one kind of control.
|
|
-->
|
|
<Style Selector="Button.tab.fixed">
|
|
<Setter Property="Padding" Value="12,0" />
|
|
</Style>
|
|
|
|
<!--
|
|
The button that opens a connection. A tab in every respect but the marks a tab carries: no active
|
|
state, because it is never the thing showing, and no outline, because it is not one of the things
|
|
being chosen between. Both of those are cleared rather than merely omitted — the base rule above sets
|
|
a fill and a border, so an exception has to say so.
|
|
-->
|
|
<Style Selector="Button.tab.plus">
|
|
<Setter Property="Padding" Value="0" />
|
|
<Setter Property="Width" Value="28" />
|
|
<Setter Property="Height" Value="28" />
|
|
<Setter Property="Foreground" Value="{StaticResource TextFaint}" />
|
|
</Style>
|
|
<Style Selector="Button.tab.plus /template/ ContentPresenter#PART_ContentPresenter">
|
|
<Setter Property="Background" Value="Transparent" />
|
|
<Setter Property="BorderThickness" Value="0" />
|
|
<Setter Property="CornerRadius" Value="8" />
|
|
</Style>
|
|
<Style Selector="Button.tab.plus:pointerover /template/ ContentPresenter#PART_ContentPresenter">
|
|
<Setter Property="Foreground" Value="{StaticResource Text}" />
|
|
<Setter Property="Background" Value="{StaticResource Hover}" />
|
|
</Style>
|
|
|
|
<Style Selector="Button.tab.active /template/ ContentPresenter#PART_ContentPresenter">
|
|
<Setter Property="Background" Value="{StaticResource Active}" />
|
|
<Setter Property="Foreground" Value="{StaticResource Text}" />
|
|
<Setter Property="BorderBrush" Value="{StaticResource BorderMid}" />
|
|
</Style>
|
|
|
|
<!--
|
|
The two halves of the Vaults tab: the tab itself, and the caret that opens its menu. Two buttons
|
|
because they do two things, drawn as one pill because they are one destination — so the pair meets in
|
|
the middle with no gap, no doubled border down the join, and the outer corners rounded as any tab's
|
|
are.
|
|
|
|
Both the Button and its ContentPresenter carry a CornerRadius above, so both have to be squared here:
|
|
setting only one leaves a rounded outline inside a square hit area, which shows as a hairline of the
|
|
strip's background cutting through the join.
|
|
|
|
After Button.tab.fixed rather than beside it, because .caret takes that rule's padding back to zero
|
|
and Avalonia has no specificity — the later declaration is the one that wins. See the ordering note
|
|
above.
|
|
-->
|
|
<Style Selector="Button.tab.split">
|
|
<Setter Property="Margin" Value="0" />
|
|
<Setter Property="CornerRadius" Value="8,0,0,8" />
|
|
</Style>
|
|
<Style Selector="Button.tab.split /template/ ContentPresenter#PART_ContentPresenter">
|
|
<Setter Property="CornerRadius" Value="8,0,0,8" />
|
|
<Setter Property="BorderThickness" Value="1,1,0,1" />
|
|
</Style>
|
|
<Style Selector="Button.tab.caret">
|
|
<Setter Property="Padding" Value="0" />
|
|
<Setter Property="CornerRadius" Value="0,8,8,0" />
|
|
</Style>
|
|
<Style Selector="Button.tab.caret /template/ ContentPresenter#PART_ContentPresenter">
|
|
<Setter Property="CornerRadius" Value="0,8,8,0" />
|
|
</Style>
|
|
|
|
<!--
|
|
A pair of buttons standing in for a two-way choice, inside a pane rather than down a rail. Not the
|
|
.cat style, which stretches to fill a 176-pixel rail row and would be wrong at this width — and which
|
|
the category rail's own test counts, so borrowing it would have made this a fourth category.
|
|
-->
|
|
<Style Selector="Button.choice">
|
|
<Setter Property="Padding" Value="10,5" />
|
|
<Setter Property="FontFamily" Value="{StaticResource MonoFont}" />
|
|
<Setter Property="FontSize" Value="10.5" />
|
|
<Setter Property="LetterSpacing" Value="0.5" />
|
|
<Setter Property="Foreground" Value="{StaticResource TextFaint}" />
|
|
</Style>
|
|
<Style Selector="Button.choice /template/ ContentPresenter#PART_ContentPresenter">
|
|
<Setter Property="CornerRadius" Value="4" />
|
|
<Setter Property="Background" Value="{StaticResource Raised}" />
|
|
<Setter Property="BorderBrush" Value="{StaticResource Border}" />
|
|
<Setter Property="BorderThickness" Value="1" />
|
|
<Setter Property="Foreground" Value="{StaticResource TextDim}" />
|
|
</Style>
|
|
<Style Selector="Button.choice:pointerover /template/ ContentPresenter#PART_ContentPresenter">
|
|
<Setter Property="Foreground" Value="{StaticResource Text}" />
|
|
</Style>
|
|
<Style Selector="Button.choice.active /template/ ContentPresenter#PART_ContentPresenter">
|
|
<Setter Property="Background" Value="{StaticResource AccentWash}" />
|
|
<Setter Property="BorderBrush" Value="{StaticResource Accent}" />
|
|
<Setter Property="Foreground" Value="{StaticResource Text}" />
|
|
</Style>
|
|
|
|
<!-- The close box on a tab, and the window controls. Square, quiet, and red only where it means it. -->
|
|
<Style Selector="Button.close /template/ ContentPresenter#PART_ContentPresenter">
|
|
<Setter Property="Foreground" Value="{StaticResource TextFaint}" />
|
|
</Style>
|
|
<Style Selector="Button.close:pointerover /template/ ContentPresenter#PART_ContentPresenter">
|
|
<Setter Property="Background" Value="{StaticResource DangerWash}" />
|
|
<Setter Property="Foreground" Value="{StaticResource Danger}" />
|
|
</Style>
|
|
|
|
<!--
|
|
The one inside a tab, as opposed to the ones in the titlebar. Rounded and small, because a square
|
|
full-height red panel inside a tab reads as a divider between two tabs rather than as part of one —
|
|
which is what it looked like while it was a sibling of the tab instead of a child.
|
|
-->
|
|
<Style Selector="Button.close.inline /template/ ContentPresenter#PART_ContentPresenter">
|
|
<Setter Property="CornerRadius" Value="3" />
|
|
</Style>
|
|
|
|
<!--
|
|
Text input. Fluent draws a filled box with a thick focus underline; this design draws a hairline field
|
|
that changes border colour, and the two do not sit together in one row.
|
|
-->
|
|
<Style Selector="TextBox">
|
|
<Setter Property="Background" Value="{StaticResource Field}" />
|
|
<Setter Property="BorderBrush" Value="{StaticResource Border}" />
|
|
<Setter Property="BorderThickness" Value="1" />
|
|
<Setter Property="CornerRadius" Value="10" />
|
|
<Setter Property="Foreground" Value="{StaticResource Text}" />
|
|
<Setter Property="SelectionBrush" Value="{StaticResource AccentSoft}" />
|
|
<Setter Property="CaretBrush" Value="{StaticResource Accent}" />
|
|
<Setter Property="MinHeight" Value="30" />
|
|
<Setter Property="Padding" Value="8,4" />
|
|
<Setter Property="FontSize" Value="13" />
|
|
</Style>
|
|
<Style Selector="TextBox /template/ Border#PART_BorderElement">
|
|
<Setter Property="Background" Value="{StaticResource Field}" />
|
|
<Setter Property="BorderBrush" Value="{StaticResource Border}" />
|
|
<Setter Property="BorderThickness" Value="1" />
|
|
</Style>
|
|
<Style Selector="TextBox:pointerover /template/ Border#PART_BorderElement">
|
|
<Setter Property="Background" Value="{StaticResource Field}" />
|
|
<Setter Property="BorderBrush" Value="{StaticResource BorderMid}" />
|
|
</Style>
|
|
<Style Selector="TextBox:focus /template/ Border#PART_BorderElement">
|
|
<Setter Property="Background" Value="{StaticResource Field}" />
|
|
<Setter Property="BorderBrush" Value="{StaticResource AccentSoft}" />
|
|
<Setter Property="BorderThickness" Value="1" />
|
|
</Style>
|
|
<Style Selector="TextBox /template/ TextBlock#PART_Watermark">
|
|
<Setter Property="Foreground" Value="{StaticResource TextFaint}" />
|
|
</Style>
|
|
|
|
<!--
|
|
◆ THE ADDRESS FIELD, the one input the host drawer draws with an accent border rather than the
|
|
ordinary grey hairline — the mock's own choice, kept, because it is the one field a session cannot be
|
|
opened without. Taller than the drawer's other fields too, at 42 rather than the TextBox default.
|
|
|
|
No drawn caret: the mock blinks one inside the field's own text, but this is a real TextBox with a real
|
|
one already, so painting a second would either fight the true caret for the same pixel or lie about
|
|
where typing lands. See HostDrawer.axaml's ADDRESS section, on both the pane and the editor.
|
|
|
|
Declared after the base TextBox rules — including :pointerover and :focus — for the reason this file
|
|
states three times already for Button.tab, Border.rowmark and the tiles list: Avalonia has no
|
|
specificity, and a rule declared before an exception it overrides does nothing at all. Placed here
|
|
rather than beside them so both still read as one un-interrupted block of "what every TextBox looks
|
|
like" with the one exception after it, not threaded through the middle.
|
|
-->
|
|
<Style Selector="TextBox.address">
|
|
<Setter Property="Height" Value="42" />
|
|
<Setter Property="FontFamily" Value="{StaticResource MonoFont}" />
|
|
</Style>
|
|
<Style Selector="TextBox.address /template/ Border#PART_BorderElement">
|
|
<Setter Property="BorderBrush" Value="{StaticResource Accent}" />
|
|
<Setter Property="BorderThickness" Value="1.5" />
|
|
</Style>
|
|
|
|
<!--
|
|
Lists. The rows in this design are drawn by their own templates and marked as selected with an accent
|
|
strip down the left edge, so the theme's rounded blue selection block has to go — it would sit behind
|
|
every row as a second, disagreeing highlight.
|
|
-->
|
|
<Style Selector="ListBox">
|
|
<Setter Property="Background" Value="Transparent" />
|
|
<Setter Property="Padding" Value="0" />
|
|
</Style>
|
|
<Style Selector="ListBoxItem">
|
|
<Setter Property="Padding" Value="0" />
|
|
<Setter Property="MinHeight" Value="0" />
|
|
<Setter Property="CornerRadius" Value="0" />
|
|
</Style>
|
|
<Style Selector="ListBoxItem /template/ ContentPresenter#PART_ContentPresenter">
|
|
<Setter Property="Background" Value="Transparent" />
|
|
<Setter Property="CornerRadius" Value="0" />
|
|
<Setter Property="Padding" Value="0" />
|
|
</Style>
|
|
<Style Selector="ListBoxItem:pointerover /template/ ContentPresenter#PART_ContentPresenter">
|
|
<Setter Property="Background" Value="{StaticResource Hover}" />
|
|
</Style>
|
|
<Style Selector="ListBoxItem:selected /template/ ContentPresenter#PART_ContentPresenter">
|
|
<Setter Property="Background" Value="{StaticResource AccentWash}" />
|
|
</Style>
|
|
<Style Selector="ListBoxItem:selected:pointerover /template/ ContentPresenter#PART_ContentPresenter">
|
|
<Setter Property="Background" Value="{StaticResource AccentWash}" />
|
|
</Style>
|
|
|
|
<!--
|
|
◆ A LIST OF TILES, which is the hosts screen's grid of group and host cards.
|
|
|
|
The three rules above paint the *item* — a full-bleed rectangle behind whatever the template draws —
|
|
and that is right for a row and wrong for a card: a square wash behind a 10-pixel-rounded tile shows
|
|
as four grey corners, and it does it on hover as well as on selection, which is most of the time the
|
|
pointer is anywhere near the grid. So a tiles list clears all three and the tile paints its own
|
|
states.
|
|
|
|
Declared after them and not before. Avalonia has no specificity: two rules matching one element are
|
|
settled by declaration order, so an exception stated above the rule it excepts does nothing at all.
|
|
That trap is recorded twice more in this file, for Button.tab and for Border.rowmark.
|
|
-->
|
|
<Style Selector="ListBox.tiles > ListBoxItem:pointerover /template/ ContentPresenter#PART_ContentPresenter">
|
|
<Setter Property="Background" Value="Transparent" />
|
|
</Style>
|
|
<Style Selector="ListBox.tiles > ListBoxItem:selected /template/ ContentPresenter#PART_ContentPresenter">
|
|
<Setter Property="Background" Value="Transparent" />
|
|
</Style>
|
|
<Style Selector="ListBox.tiles > ListBoxItem:selected:pointerover /template/ ContentPresenter#PART_ContentPresenter">
|
|
<Setter Property="Background" Value="Transparent" />
|
|
</Style>
|
|
|
|
<!--
|
|
The card itself. A fixed width and a free height, which is the pair that makes a WrapPanel of these
|
|
into a grid: equal columns, and a card that grew a third line of tags is taller than its neighbours
|
|
rather than narrower.
|
|
|
|
◆ 224 IS DERIVED, and the arithmetic is written out because getting it wrong is invisible. The grid's
|
|
column at the window's minimum is 1016 less the rail's 190 and the drawer's 320, which is 506. The
|
|
scrolling stack inside it takes 16 of margin on each side, and the vertical scrollbar takes its own —
|
|
call the usable width 474. A WrapPanel fits floor(474 / (Width + 10)) per row, so two columns needs
|
|
Width no more than 227.
|
|
|
|
The first number here was 248, from the same reasoning with the two margins left out. It laid out
|
|
cleanly and the layout harness passed it, because the harness asks whether a control is inside the
|
|
window and not how many of them fit on a line — so the grid quietly became one column wide at exactly
|
|
the size this application guarantees, which is the shape the cards exist to avoid. The second was 232,
|
|
derived the same way against the drawer's own 304; v5 widened the drawer to 320 for the ADDRESS field's
|
|
breathing room, which narrowed the budget this number is drawn from and had to move it down in step.
|
|
-->
|
|
<Style Selector="Border.tile">
|
|
<Setter Property="Background" Value="{StaticResource Raised}" />
|
|
<Setter Property="BorderBrush" Value="{StaticResource Border}" />
|
|
<Setter Property="BorderThickness" Value="1" />
|
|
<Setter Property="CornerRadius" Value="12" />
|
|
<Setter Property="Padding" Value="12,10" />
|
|
<Setter Property="Width" Value="224" />
|
|
<Setter Property="Margin" Value="0,0,10,10" />
|
|
</Style>
|
|
<Style Selector="ListBoxItem:pointerover Border.tile">
|
|
<Setter Property="BorderBrush" Value="{StaticResource BorderHover}" />
|
|
</Style>
|
|
<!--
|
|
Selected is the accent outline *and* the filled surface, which is the same pair the nav rail and the
|
|
tab strip use for "you are here". A tile marked by its border alone is legible on a card you are
|
|
looking at and invisible in peripheral vision, which is where a selected card usually is once the
|
|
drawer beside it has opened.
|
|
-->
|
|
<Style Selector="ListBoxItem:selected Border.tile">
|
|
<Setter Property="Background" Value="{StaticResource Active}" />
|
|
<Setter Property="BorderBrush" Value="{StaticResource Accent}" />
|
|
</Style>
|
|
|
|
<!--
|
|
◆ A CARD IN THE CHOSEN SET, which is not the same thing as the selected one.
|
|
|
|
The list holds one selection — the card the drawer and CONNECT are about — and the set is what Ctrl,
|
|
Shift and a band dragged across the grid build on top of it. Six ticked cards with one of them also
|
|
selected is the ordinary shape, so the two marks have to be legible together and legible apart.
|
|
|
|
The fill and the tick on the card are the mark; the border is deliberately left to the rule above. A
|
|
chosen card that also drew an accent outline would be indistinguishable from the selected one, and the
|
|
question "which of these is the drawer showing" would have no answer. Declared after that rule anyway,
|
|
because it sets the same Background and Avalonia settles two matching rules by declaration order —
|
|
the trap this file records for Button.tab, Border.rowmark and the drop target below.
|
|
-->
|
|
<Style Selector="Border.tile.chosen">
|
|
<Setter Property="Background" Value="{StaticResource Active}" />
|
|
</Style>
|
|
|
|
<!-- The square a tile carries on its left: a group's mark, or a host's prompt. -->
|
|
<Style Selector="Border.tileicon">
|
|
<Setter Property="Width" Value="32" />
|
|
<Setter Property="Height" Value="32" />
|
|
<Setter Property="CornerRadius" Value="8" />
|
|
<Setter Property="VerticalAlignment" Value="Center" />
|
|
</Style>
|
|
|
|
<!--
|
|
◆ THE PENCIL ON A HOST CARD, which is the only way the drawer opens from the grid.
|
|
|
|
It exists because selecting a host stopped opening it. A card that took 304 pixels off the grid the
|
|
moment it was touched charged the price of the pane for the act of choosing — most of which is arrowing
|
|
past machines you did not want — so opening is now a thing you ask for and this is the asking. See
|
|
VaultViewModel.IsHostPaneOpen.
|
|
|
|
Hidden until the pointer is on the card, and shown on the selected one whether or not the pointer is
|
|
there, because the selected card is the one whose pane you are most likely to want and a control that
|
|
vanished from under the card you just clicked would have to be hunted for. Both are declared after the
|
|
base rule: Avalonia has no specificity and settles two matching rules by declaration order, which this
|
|
file records three times over.
|
|
|
|
IsVisible rather than Opacity. A button at zero opacity is still a button — it takes the click, and the
|
|
card underneath does not — so half the grid would swallow presses aimed at selecting a host. The space
|
|
is held open by the Panel around it in the item template rather than by this, so the card does not
|
|
reflow as the pointer crosses it; see HostsScreen.axaml.
|
|
-->
|
|
<Style Selector="Button.rowedit">
|
|
<Setter Property="Width" Value="24" />
|
|
<Setter Property="Height" Value="24" />
|
|
<Setter Property="CornerRadius" Value="6" />
|
|
<Setter Property="FontSize" Value="12" />
|
|
<Setter Property="Foreground" Value="{StaticResource TextFaint}" />
|
|
<Setter Property="HorizontalContentAlignment" Value="Center" />
|
|
<Setter Property="VerticalContentAlignment" Value="Center" />
|
|
<Setter Property="IsVisible" Value="False" />
|
|
</Style>
|
|
<Style Selector="Button.rowedit /template/ ContentPresenter#PART_ContentPresenter">
|
|
<Setter Property="CornerRadius" Value="6" />
|
|
</Style>
|
|
<Style Selector="Button.rowedit:pointerover /template/ ContentPresenter#PART_ContentPresenter">
|
|
<Setter Property="Background" Value="{StaticResource ChromeHover}" />
|
|
<Setter Property="Foreground" Value="{StaticResource AccentText}" />
|
|
</Style>
|
|
<Style Selector="ListBoxItem:pointerover Button.rowedit">
|
|
<Setter Property="IsVisible" Value="True" />
|
|
</Style>
|
|
<Style Selector="ListBoxItem:selected Button.rowedit">
|
|
<Setter Property="IsVisible" Value="True" />
|
|
</Style>
|
|
|
|
<!--
|
|
◆ THE DRAWER'S FURNITURE: a card, its heading, and the rows inside it.
|
|
|
|
The hosts drawer is a column of grouped fields rather than a run of labelled controls — address here,
|
|
the general facts here, the connection and its credentials here — which is what the design draws and
|
|
what a 320-pixel column needs to stay readable: three cards is three things to find, where fourteen
|
|
stacked controls is fourteen. v5 widened the column from 304 to 320 for the ADDRESS field's own
|
|
breathing room, and moved every affected number in this file and its neighbours with it.
|
|
|
|
Raised on Sidebar, which is the one pairing that works in this column. Panel and Chrome are the same
|
|
value as each other and near enough Sidebar to vanish against it. Field no longer reads as a well
|
|
beneath either: v3 gives a field and a card the same fill, where a field used to sit visibly below
|
|
one — see the remark on Field in Palette.axaml. What still marks a field as a field here is its
|
|
border and its focus state, not a darker surface underneath it.
|
|
-->
|
|
<Style Selector="Border.section">
|
|
<Setter Property="Background" Value="{StaticResource Raised}" />
|
|
<Setter Property="BorderBrush" Value="{StaticResource Border}" />
|
|
<Setter Property="BorderThickness" Value="1" />
|
|
<Setter Property="CornerRadius" Value="12" />
|
|
<Setter Property="Padding" Value="12" />
|
|
</Style>
|
|
|
|
<!--
|
|
A card's heading, and deliberately not TextBlock.label. That style is the small tracked-out capitals
|
|
this design uses for a *section of a screen* — GROUPS, HOSTS, the vault's categories — and three of
|
|
them inside a 320-pixel column would claim the same weight as the screen headings beside it. These are
|
|
captions on a card, so they are sentence case at the body size.
|
|
|
|
Still what the group editor's two cards use — GROUP, and what its hosts inherit — because that editor
|
|
is not the mock this file's ADDRESS/GENERAL/CONNECTION/QUICK ACCESS labels were drawn from and nothing
|
|
asked it to match a screen it is not on.
|
|
-->
|
|
<Style Selector="TextBlock.sectionhead">
|
|
<Setter Property="FontSize" Value="13" />
|
|
<Setter Property="FontWeight" Value="SemiBold" />
|
|
<Setter Property="Foreground" Value="{StaticResource Text}" />
|
|
</Style>
|
|
|
|
<!--
|
|
◆ THE OTHER CARD HEADING, v5's own, and the two are not interchangeable.
|
|
|
|
TextBlock.sectionhead above is sentence case at the body size — a caption on a card, the same weight
|
|
the design's own prose is drawn at. This is the v5 mock's own idiom for the same job, on the one screen
|
|
it was drawn for: ADDRESS, GENERAL, CONNECTION and QUICK ACCESS in the host drawer, tracked-out capitals
|
|
at a third the size. Both exist because the group editor's cards were not restyled to the v5 mock — see
|
|
the remark above — so the drawer now carries a heading in each of the two idioms depending on which
|
|
panel is showing, and a single class could not have been both.
|
|
-->
|
|
<Style Selector="TextBlock.sectionlabel">
|
|
<Setter Property="FontFamily" Value="{StaticResource MonoFont}" />
|
|
<Setter Property="FontSize" Value="10" />
|
|
<Setter Property="FontWeight" Value="SemiBold" />
|
|
<Setter Property="LetterSpacing" Value="1.2" />
|
|
<Setter Property="Foreground" Value="{StaticResource TextGhost}" />
|
|
</Style>
|
|
|
|
<!--
|
|
◆ A ROW IN THE DETAIL PANE, AND IT IS A BUTTON THAT LOOKS LIKE A FIELD.
|
|
|
|
The design draws every fact about a host as a filled box, which is the shape of an input — so a reader
|
|
arrives expecting to type in one. They cannot: saving here is a whole-host operation that validates the
|
|
key-or-credential exclusion and writes one encrypted payload, so a box that committed on every
|
|
keystroke would be a save per character and a half-typed hostname on the wire.
|
|
|
|
Rather than draw an input that refuses the pointer, each row *is* the door to the editor. Pressing any
|
|
of them opens the host editor, which is the same three cards with real boxes in them — so the thing
|
|
that looked editable turns out to be editable, one step further along, and nothing on screen is a
|
|
control that does nothing. The alternative was a flat read-only pane with one EDIT button, which is
|
|
what this replaced.
|
|
|
|
It borrows the TextBox's own geometry rather than sharing it, for the reason Button.chiptoggle borrows
|
|
Border.chip's: a Button is not a TextBox and Avalonia's selectors are structural. The numbers are
|
|
repeated and the two have to move together, which is why they are adjacent in this file.
|
|
-->
|
|
<Style Selector="Button.fieldrow">
|
|
<Setter Property="HorizontalAlignment" Value="Stretch" />
|
|
<Setter Property="HorizontalContentAlignment" Value="Stretch" />
|
|
<Setter Property="VerticalContentAlignment" Value="Center" />
|
|
<Setter Property="MinHeight" Value="32" />
|
|
<Setter Property="Padding" Value="8,5" />
|
|
<Setter Property="FontSize" Value="13" />
|
|
<Setter Property="Foreground" Value="{StaticResource Text}" />
|
|
</Style>
|
|
<Style Selector="Button.fieldrow /template/ ContentPresenter#PART_ContentPresenter">
|
|
<Setter Property="Background" Value="{StaticResource Field}" />
|
|
<Setter Property="BorderBrush" Value="{StaticResource Border}" />
|
|
<Setter Property="BorderThickness" Value="1" />
|
|
<Setter Property="CornerRadius" Value="4" />
|
|
<Setter Property="Foreground" Value="{StaticResource Text}" />
|
|
</Style>
|
|
<Style Selector="Button.fieldrow:pointerover /template/ ContentPresenter#PART_ContentPresenter">
|
|
<Setter Property="Background" Value="{StaticResource Hover}" />
|
|
<Setter Property="BorderBrush" Value="{StaticResource BorderHover}" />
|
|
</Style>
|
|
|
|
<!--
|
|
The detail pane's own ADDRESS row, matched to TextBox.address above: taller, and bordered in accent
|
|
rather than the ordinary hairline even under the pointer — declared after the :pointerover rule for the
|
|
reason that class's own remark gives, so it wins in both states rather than only the resting one.
|
|
-->
|
|
<Style Selector="Button.fieldrow.address">
|
|
<Setter Property="MinHeight" Value="42" />
|
|
</Style>
|
|
<Style Selector="Button.fieldrow.address /template/ ContentPresenter#PART_ContentPresenter">
|
|
<Setter Property="BorderBrush" Value="{StaticResource Accent}" />
|
|
<Setter Property="BorderThickness" Value="1.5" />
|
|
</Style>
|
|
|
|
<!--
|
|
The glyph at the head of such a row. A fixed width so that four rows in a card line their text up, and
|
|
the faintest step in the ramp because it is a mark to skip rather than a fact to read: what the row
|
|
says is to its right.
|
|
-->
|
|
<Style Selector="TextBlock.fieldglyph">
|
|
<Setter Property="FontFamily" Value="{StaticResource MonoFont}" />
|
|
<Setter Property="FontSize" Value="11" />
|
|
<Setter Property="Width" Value="16" />
|
|
<Setter Property="Foreground" Value="{StaticResource TextFaint}" />
|
|
<Setter Property="VerticalAlignment" Value="Center" />
|
|
</Style>
|
|
|
|
<!--
|
|
The two buttons in the drawer's header: the overflow menu and the arrow that puts the drawer away.
|
|
Chrome rather than controls — they are the frame around whichever panel is showing, which is why they
|
|
are flat and quiet until the pointer finds them.
|
|
-->
|
|
<Style Selector="Button.paneicon">
|
|
<Setter Property="Width" Value="26" />
|
|
<Setter Property="Height" Value="26" />
|
|
<Setter Property="CornerRadius" Value="6" />
|
|
<Setter Property="FontSize" Value="13" />
|
|
<Setter Property="Foreground" Value="{StaticResource TextFaint}" />
|
|
<Setter Property="HorizontalContentAlignment" Value="Center" />
|
|
<Setter Property="VerticalContentAlignment" Value="Center" />
|
|
</Style>
|
|
<Style Selector="Button.paneicon /template/ ContentPresenter#PART_ContentPresenter">
|
|
<Setter Property="CornerRadius" Value="6" />
|
|
</Style>
|
|
<Style Selector="Button.paneicon:pointerover /template/ ContentPresenter#PART_ContentPresenter">
|
|
<Setter Property="Background" Value="{StaticResource ChromeHover}" />
|
|
<Setter Property="Foreground" Value="{StaticResource Text}" />
|
|
</Style>
|
|
|
|
<!--
|
|
The status dot, in one place rather than as a converter in code.
|
|
|
|
Two states and not the design's three. Green means connected — a terminal is open on this host, or a
|
|
connection to the server is held with nothing waiting to be sent. Grey means it is not. The design also
|
|
has an amber dot, which would have to mean "reachable but not connected", and nothing in this
|
|
application ever checks whether a host is reachable; a colour for a state nobody computes would be
|
|
decoration that reads as information.
|
|
|
|
A style rather than a value converter so that the two colours are the palette's, once. A converter
|
|
would have had to name the hex value in C#, which is how a green ends up one shade off in the fourth
|
|
place it appears — and it has already moved once, from v2's #3DDC97 to this design's #34D399, without
|
|
touching this file.
|
|
|
|
Live rather than Accent, and that is a v2 change with meaning rather than a recolour, one that survives
|
|
the accent moving again from blue to purple in v3: the green is the colour of a fact regardless of what
|
|
hue the accent currently is — see the remark on Live in Palette.axaml. Filling this with Accent would
|
|
say a connected host is a thing to press.
|
|
-->
|
|
<Style Selector="Ellipse.dot">
|
|
<Setter Property="Width" Value="6" />
|
|
<Setter Property="Height" Value="6" />
|
|
<Setter Property="Fill" Value="{StaticResource TextFaint}" />
|
|
</Style>
|
|
<Style Selector="Ellipse.dot.live">
|
|
<Setter Property="Fill" Value="{StaticResource Live}" />
|
|
</Style>
|
|
|
|
<!--
|
|
The accent strip a selected row carries, drawn by the row template rather than by the item, because the
|
|
item's presenter is the thing the theme keeps repainting.
|
|
-->
|
|
<Style Selector="Border.rowmark">
|
|
<Setter Property="Width" Value="2" />
|
|
<Setter Property="Background" Value="Transparent" />
|
|
</Style>
|
|
<Style Selector="ListBoxItem:selected Border.rowmark">
|
|
<Setter Property="Background" Value="{StaticResource Accent}" />
|
|
</Style>
|
|
|
|
<!--
|
|
Quick connect's own rows. In this file rather than QuickConnect.axaml, the same reason every other
|
|
list style is here: that view is the one caller, but what a selected row looks like is a palette
|
|
answer and belongs beside every other one.
|
|
|
|
Classes="tiles" on that ListBox clears the theme's own full-bleed selection wash first — see the
|
|
remark above "A LIST OF TILES" — for the same reason: a wash behind a 9-pixel-rounded row shows as
|
|
square corners peeking out from behind it. This is the one list in the application whose selected row
|
|
fills solid rather than tinting or carrying a strip, which is the mock's own choice and reads as
|
|
right here specifically: this palette is choosing a machine to connect to *now*, not one it is idly
|
|
browsing, and nothing else in the window asks to look this insistent.
|
|
-->
|
|
<Style Selector="Border.qcrow">
|
|
<Setter Property="Background" Value="Transparent" />
|
|
</Style>
|
|
<Style Selector="ListBoxItem:pointerover Border.qcrow">
|
|
<Setter Property="Background" Value="{StaticResource Hover}" />
|
|
</Style>
|
|
<Style Selector="ListBoxItem:selected Border.qcrow, ListBoxItem:selected:pointerover Border.qcrow">
|
|
<Setter Property="Background" Value="{StaticResource Accent}" />
|
|
</Style>
|
|
<Style Selector="TextBlock.qcrow-text">
|
|
<Setter Property="Foreground" Value="{StaticResource Text}" />
|
|
</Style>
|
|
<Style Selector="TextBlock.qcrow-subtext">
|
|
<Setter Property="Foreground" Value="{StaticResource TextFaint}" />
|
|
</Style>
|
|
<Style Selector="ListBoxItem:selected TextBlock.qcrow-text, ListBoxItem:selected TextBlock.qcrow-subtext">
|
|
<!--
|
|
AccentInk rather than a literal white: it is v5's name for "the colour text sits in on top of the
|
|
accent", which is what a filled row is. Naming it that way rather than #FFFFFF is what keeps this
|
|
rule true if the accent itself ever moves to a hue where white stops being the readable choice.
|
|
-->
|
|
<Setter Property="Foreground" Value="{StaticResource AccentInk}" />
|
|
</Style>
|
|
|
|
<!--
|
|
The group card a host is about to be dropped on. A wash rather than the accent strip a selection
|
|
carries, because it is not a selection: it says "let go here", it lasts as long as the pointer is over
|
|
the card, and it has to be legible on top of whatever that card already looks like — including the
|
|
selected one, which is the group the grid is currently narrowed to and so often the one being dragged
|
|
onto.
|
|
|
|
Painted on the tile rather than on the item's own presenter, which is where this used to go when the
|
|
target was a full-width heading. A wash behind a 10-pixel-rounded tile is a square of colour with the
|
|
card floating on it — the same four grey corners the tiles list clears the theme's own hover and
|
|
selection brushes to avoid. Declared after that rule and after the selected-tile rule, because
|
|
Avalonia has no specificity and settles two matching rules by declaration order.
|
|
|
|
◆ THE DOUBLED BORDER IS THE MARK, not the fill, and that is what the move to the tile forced. The fill
|
|
a selected tile already carries is the strongest one this palette has, so a target that only filled
|
|
would be invisible on the card the grid is narrowed to — which is the card a host most often has to be
|
|
dragged off, into another group. Two pixels of accent is legible on both.
|
|
|
|
Set from the code-behind rather than by a binding, for the reason the whole gesture is code: the rows
|
|
are rebuilt from scratch on every filter keystroke and every sync pass, so a flag on the view model
|
|
would be state the list throws away halfway through the drag. See HostsScreen.axaml.cs.
|
|
-->
|
|
<Style Selector="ListBoxItem.droptarget Border.tile">
|
|
<Setter Property="Background" Value="{StaticResource Active}" />
|
|
<Setter Property="BorderBrush" Value="{StaticResource Accent}" />
|
|
<Setter Property="BorderThickness" Value="2" />
|
|
</Style>
|
|
|
|
<!--
|
|
A context menu, in this window's palette rather than the theme's. The Fluent default is a lighter grey
|
|
than anything else here, which on a near-black chrome reads as a dialog from another application.
|
|
|
|
FlyoutPresenter is in the same rule rather than one of its own: the vault menu on the tab strip is a
|
|
plain Flyout, and a popup that came out of this window in a different grey from the context menu two
|
|
screens away would read as two applications rather than one.
|
|
-->
|
|
<Style Selector="MenuFlyoutPresenter, ContextMenu, FlyoutPresenter">
|
|
<Setter Property="Background" Value="{StaticResource Chrome}" />
|
|
<Setter Property="BorderBrush" Value="{StaticResource BorderMid}" />
|
|
<Setter Property="BorderThickness" Value="1" />
|
|
<Setter Property="CornerRadius" Value="4" />
|
|
</Style>
|
|
<Style Selector="MenuItem">
|
|
<Setter Property="FontSize" Value="13" />
|
|
<Setter Property="Foreground" Value="{StaticResource Text}" />
|
|
</Style>
|
|
|
|
<!--
|
|
The same strip on the vault's category rail, which is buttons rather than list items — so the class
|
|
the rail sets stands in for the :selected pseudo-class.
|
|
|
|
It has to come after Border.rowmark, and that is not tidiness. Avalonia has no CSS specificity: two
|
|
class selectors matching one element carry the same priority, and the later declaration wins. Declared
|
|
above, "Background: Transparent" from Border.rowmark overrode this and the active category had no
|
|
strip at all — which looks exactly like a rail that was never given one.
|
|
-->
|
|
<Style Selector="Button.cat Border.catmark">
|
|
<Setter Property="Background" Value="Transparent" />
|
|
</Style>
|
|
<Style Selector="Button.cat.active Border.catmark">
|
|
<Setter Property="Background" Value="{StaticResource Accent}" />
|
|
</Style>
|
|
|
|
<Style Selector="ComboBox">
|
|
<Setter Property="Background" Value="{StaticResource Field}" />
|
|
<Setter Property="BorderBrush" Value="{StaticResource Border}" />
|
|
<Setter Property="CornerRadius" Value="10" />
|
|
<Setter Property="Foreground" Value="{StaticResource Text}" />
|
|
<Setter Property="MinHeight" Value="30" />
|
|
<Setter Property="FontSize" Value="13" />
|
|
</Style>
|
|
<Style Selector="NumericUpDown">
|
|
<Setter Property="Background" Value="{StaticResource Field}" />
|
|
<Setter Property="BorderBrush" Value="{StaticResource Border}" />
|
|
<Setter Property="CornerRadius" Value="10" />
|
|
<Setter Property="Foreground" Value="{StaticResource Text}" />
|
|
<Setter Property="MinHeight" Value="30" />
|
|
<Setter Property="FontSize" Value="13" />
|
|
</Style>
|
|
<!--
|
|
The foreground goes on the content presenter as well as on the control, for the same reason the
|
|
buttons' brushes do: the Fluent theme sets its own there, and a Foreground set only on the CheckBox is
|
|
a TemplateBinding the theme's own value wins over — which showed up as a label in the theme's blue-grey
|
|
beside a hint in this palette's.
|
|
-->
|
|
<Style Selector="CheckBox">
|
|
<Setter Property="Foreground" Value="{StaticResource TextDim}" />
|
|
<Setter Property="FontSize" Value="13" />
|
|
<Setter Property="MinHeight" Value="0" />
|
|
</Style>
|
|
<Style Selector="CheckBox /template/ ContentPresenter#PART_ContentPresenter">
|
|
<Setter Property="Foreground" Value="{StaticResource TextDim}" />
|
|
</Style>
|
|
<Style Selector="CheckBox:pointerover /template/ ContentPresenter#PART_ContentPresenter">
|
|
<Setter Property="Foreground" Value="{StaticResource Text}" />
|
|
</Style>
|
|
|
|
</Application.Styles>
|
|
|
|
</Application>
|