Files
DodoSSH/src/DodoSSH.Client.Shell/Theme/Palette.axaml
T

236 lines
16 KiB
XML

<ResourceDictionary xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<!--
The palette, named for what a colour is for rather than for what it looks like. Every one of these is
from the design; the names are this codebase's, because "#0E1220" appearing in nine files is how a
surface ends up two shades off in the tenth.
It lives here, in the shared project, because there are now two heads drawing the same product. Two
copies of a palette is the same failure one file up: the phone's "connected" green drifting from the
desktop's is not a thing anybody would notice until a screenshot sat beside another screenshot.
Five near-black surfaces rather than one, and the difference between them is real work: the window is
the darkest so the terminal reads as the lit thing, chrome sits one step up so the header and status
bar frame it, and the lists sit between the two so a list does not look like part of either.
── v2 ──────────────────────────────────────────────────────────────────────────────────────────────
This is the second design's palette: blue-black surfaces and a blue accent, replacing the green-black
ones the first import shipped. Both heads move together, which is the whole reason the file is here —
the Android v2 design and the desktop v2 design specify the same seventeen tokens, so a phone that went
blue while the desktop stayed green would be the drift this file exists to prevent.
Where the design names a colour, the value below is that colour exactly. The design has seventeen
tokens and this palette has rather more, so the rest are interpolated along the same ramp and are
marked. That is deliberate rather than lazy: the finer distinctions here — three border weights, four
text steps — are ones the design draws without naming, and collapsing them to match the token count
would lose the rule each one encodes.
── v3 ──────────────────────────────────────────────────────────────────────────────────────────────
The third design moves again, and further in the same direction v2 moved in: v1 was green-black, v2
blue-black, and this one near-black — the surfaces are lower-contrast against true black than either
predecessor, and the accent turns purple, sitting where the blue used to. Both heads still move
together for the reason given above. Where a name below still carries a v2-era comment explaining a v2
fact in v2's numbers, that comment is a record of what v2 changed and why, not a claim about the
current values — it is left as history except where it stated something the current palette makes
false outright, which is called out where it happens.
-->
<!--
The surfaces, darkest first. Two things changed shape rather than merely colour, in v2, and the second
of the two has since changed back.
A field became *inset* in v2 — darker than the canvas it sat on — where it had been raised before that.
That followed the v2 design, which drew the search box as a well rather than as a tile. It does not
follow this one: the v3 design gives a card and a field the same fill, rgb(16,16,25), and marks a field
as editable with a 1.5px accent-coloured inset border instead of a darker well. Raised and Field are
kept as separate keys anyway, for the same reason Chrome and Panel are — the day one of the two needs
to move again, having merged them would have to be undone everywhere that used the wrong one.
Chrome and Panel remain the same value for that reason: the design uses one surface for both the header
and a card. They are kept as two names anyway: they answer different questions, and the day one of the
two moves is the day having merged them would have to be undone across every file that used the wrong
one.
-->
<Color x:Key="CanvasColor">#05050A</Color>
<SolidColorBrush x:Key="Canvas" Color="{StaticResource CanvasColor}" />
<SolidColorBrush x:Key="Chrome" Color="#10111E" />
<SolidColorBrush x:Key="Sidebar" Color="#0D0D16" />
<SolidColorBrush x:Key="Panel" Color="#10111E" />
<SolidColorBrush x:Key="Raised" Color="#101019" />
<SolidColorBrush x:Key="Field" Color="#101019" />
<!--
The surface a terminal, a log and a snippet's command are drawn on, and it is not one of the five
above. The design gives every block of monospaced output this one value, warmer than the chrome around
it, and that is what makes the lit thing read as lit. Named here rather than repeated in the renderer's
stylesheet and in two screens, which is how the three of them would drift.
Not one of the design's named tokens in v3 either — the mock this palette was drawn from is a Hosts
screen with no terminal on it — so the value is interpolated the same way it was for v2: warmer and a
touch lighter than the new Chrome, on the same ramp as Raised and Field rather than the old blue-black
one.
-->
<SolidColorBrush x:Key="TerminalSurface" Color="#18161F" />
<!-- Row hover, and the heavier one the chrome's own buttons use. On the phone these are press states. -->
<SolidColorBrush x:Key="Hover" Color="#14151E" />
<SolidColorBrush x:Key="ChromeHover" Color="#1E1E2C" />
<!--
Selection, and it is a surface rather than a highlight: the design fills a chosen host row, the current
segment of a toggle and the current chip with this and adds no border. Distinct from Hover, which is
what the finger is on rather than what is chosen.
-->
<SolidColorBrush x:Key="Active" Color="#1E1E2C" />
<!-- The fill behind a small monospaced tag — a group name, a storage class, a bucket. -->
<SolidColorBrush x:Key="Chip" Color="#1A1A28" />
<!--
Three border weights, and they are not interchangeable. Strong separates one region from another,
subtle separates rows inside one region, and mid is what a control draws around itself.
BorderFaint changes relationship in v3: in v2 it sat above Border, lighter than it — a fact this
comment did not previously state because nothing here described it. In this design BorderSubtle and
BorderFaint are both a step darker than Border rather than one of them being a step lighter, so the
weight now runs, faintest to strongest: BorderFaint, BorderSubtle, Border, BorderMid, BorderHover — a
single ramp rather than Border sitting in the middle of two that disagree about which side it is on.
-->
<SolidColorBrush x:Key="Border" Color="#1E1E2C" />
<SolidColorBrush x:Key="BorderSubtle" Color="#17172A" />
<SolidColorBrush x:Key="BorderMid" Color="#24243A" />
<SolidColorBrush x:Key="BorderHover" Color="#2C2C3E" />
<SolidColorBrush x:Key="BorderFaint" Color="#141420" />
<!--
The text ramp. Three steps, used consistently: what you read, what you glance at, and what is there
only so its absence would be noticed. A fourth step would be one nobody could tell from its neighbours.
── The ramp is white-topped, and every step below it moved with the top. ─────────────────────────────
This was v2's reasoning, told in v2's numbers, and is left as a record of that change rather than
updated in place: the design's #E3E7F4 was a blue-tinted white, and against v2's blue-black surfaces
the tint cost contrast twice — once because it was darker than white, and once because it shared a hue
with what it was drawn on. Pure white against v2's canvas, #0E1220, was 18.6:1, where #E3E7F4 had been
15.5:1.
Raising only the top would have been the wrong half of that change. The three steps are a ramp rather
than three colours, and their job is that a glance can tell them apart — so lifting Text and leaving
TextDim where it was would have widened the first gap and left the second two crowded at the bottom.
Every step was raised by roughly what the top gained, which kept the intervals the design chose and
brought the lower steps up to where a secondary label was comfortably readable rather than merely
present. TextDim cleared 9.8:1 at that point, against 6.4:1 before it.
── v3 ──────────────────────────────────────────────────────────────────────────────────────────────
The canvas darkens again, past v2's blue-black to near-black, which raises every one of these ratios
again without any of them moving: pure white against the new #05050A canvas is 20.3:1. TextDim,
TextFaint and TextGhost are repicked to the design's own neutral-grey values rather than re-derived
from v2's blue-tinted ones, because the design supplies its own steps this time — #EDEDF5, #9C9EB4 and
#7C7F98 read against the new canvas at roughly 17.5:1, 7.7:1 and 5.2:1, in the same descending order the
three names promise. The design also uses two deeper steps, #6D6F84 and #5D5F74, for distinctions this
ramp does not yet draw; they are not added as keys until a screen needs them, on the same reasoning as
the paragraph above the border ramp — a resource nothing reads is not free, because the next person to
touch this file has to work out whether it is dead or merely not yet wired up.
-->
<SolidColorBrush x:Key="Text" Color="#FFFFFF" />
<SolidColorBrush x:Key="TextDim" Color="#EDEDF5" />
<SolidColorBrush x:Key="TextFaint" Color="#9C9EB4" />
<SolidColorBrush x:Key="TextGhost" Color="#7C7F98" />
<!--
The accent, and it is two colours rather than one. The design fills with #5D42DE — the button, the
floating action button, a progress bar, a toggle that is on — and writes with #A78BFA: the current
destination in the bottom bar, a link, the text inside a chip. They are not interchangeable in either
direction. The fill is too saturated to read as small text on a dark surface, and the text colour is
too pale to carry a button.
AccentInk is what goes *on* the fill, and it no longer equals Canvas the way it did through v1 and v2:
the new accent is dark enough on its own that white carries better on it than the near-black the app
otherwise writes on. "The darkest surface" and "the colour of text on the accent" were two facts that
happened to coincide before; this design is the light theme the old comment predicted would separate
them, arriving by a different route.
AccentGradient and the glow beneath it are new in v3 — the design draws its primary buttons with a
top-to-bottom gradient rather than a flat fill, lighter violet into the accent proper, and lifts them
off the surface with a soft violet-tinted shadow rather than a border. Both are named here rather than
inlined in App.axaml for the same reason every other accent value is: one button styled from the wrong
purple is how a screenshot next to another screenshot finds the seam.
-->
<Color x:Key="AccentColor">#5D42DE</Color>
<SolidColorBrush x:Key="Accent" Color="{StaticResource AccentColor}" />
<SolidColorBrush x:Key="AccentText" Color="#A78BFA" />
<SolidColorBrush x:Key="AccentInk" Color="#FFFFFF" />
<SolidColorBrush x:Key="AccentSoft" Color="#5D42DE" Opacity="0.35" />
<SolidColorBrush x:Key="AccentWash" Color="#5D42DE" Opacity="0.06" />
<LinearGradientBrush x:Key="AccentGradient" StartPoint="0%,0%" EndPoint="0%,100%">
<GradientStop Color="#8D51E7" Offset="0" />
<GradientStop Color="#5D42DE" Offset="1" />
</LinearGradientBrush>
<BoxShadows x:Key="AccentGlow">0 0 22 0 #598D51E7</BoxShadows>
<!--
◆ Green is still not the accent, and purple replacing blue in v3 does not reopen that question.
Blue was the accent through v1 and v2; purple is the accent now. Either way, Ellipse.dot.live keeps its
own colour rather than borrowing the accent's, which is the separation this comment originally recorded
when the accent first stopped being green: "a shell is open on this host" and "this is the thing the
screen wants you to press" read as two different colours by construction, not by coincidence of which
two hues the current design happens to pick.
Live is #34D399 in this design — the design's own green, a shade cooler than v2's #3DDC97 — for the
live dot, the sync light and the follow indicator. Nothing that is merely interactive may use it.
Read the pair as: purple is what you can do, green is what is true.
-->
<SolidColorBrush x:Key="Live" Color="#34D399" />
<SolidColorBrush x:Key="LiveWash" Color="#34D399" Opacity="0.12" />
<!--
The three colours that are allowed to disagree with the accent. Amber means a caveat worth reading, red
means refused or destructive, and blue-light is for the one thing that is neither — an informational log
line, a directory, a distinct scope.
Info is left at its v2 value, #7FB0FF, rather than moved: it was already meant to read as distinct from
the accent, and now that the accent has moved to purple a blue that used to sit close to it on the wheel
sits further from it instead — the separation this colour exists for gets stronger for free.
WarnText and DangerText are the prose weights: a wash is a very dark tint, and the signal colour that
works as a 6-pixel dot or a one-word label is not the one that reads as a sentence on top of it. Danger
keeps its v2 values outright — the design does not revisit red — so DangerSoft, DangerWash and
DangerText stay derived from the same #E86A6A they always were. Warn's fill and wash move to the
design's own #F59E0B, and WarnText to the design's own #F5B942 rather than the interpolated value v2
carried, because this design supplies a prose weight where v2's did not name one.
-->
<SolidColorBrush x:Key="Warn" Color="#F59E0B" />
<SolidColorBrush x:Key="WarnSoft" Color="#F59E0B" Opacity="0.35" />
<SolidColorBrush x:Key="WarnWash" Color="#F59E0B" Opacity="0.12" />
<SolidColorBrush x:Key="WarnText" Color="#F5B942" />
<SolidColorBrush x:Key="Danger" Color="#E86A6A" />
<SolidColorBrush x:Key="DangerSoft" Color="#E86A6A" Opacity="0.3" />
<SolidColorBrush x:Key="DangerWash" Color="#E86A6A" Opacity="0.12" />
<SolidColorBrush x:Key="DangerText" Color="#FF8F8F" />
<SolidColorBrush x:Key="Info" Color="#7FB0FF" />
<!--
Montserrat, JetBrains Mono and Material Icons are embedded font files rather than names handed to the
font fallback system, and that is a change from every design before this one. v1 asked for IBM Plex,
v2 for Instrument Sans and Fira Code, and neither shipped with the application nor came stock on a
Windows or an Android install, so requesting either by name would have rendered as whatever fallback
the platform chose that day — worse than substituting deliberately. Inter stood in for both heads' sans
and the generic `monospace` stood in for the mono stack, and that substitution was the reversible
stand-in this comment used to describe.
It no longer needs to be: the three faces this design names ship as TTFs under Assets/Fonts in this
project, embedded the same way WebAssets is, and resolved by the same avares:// URI scheme Inter
already used. MonoFont below is JetBrains Mono first, with the old system-mono stack kept after it as a
fallback for whatever glyph JetBrains Mono does not cover. IconFont is new: the design's icons are drawn
from Material Icons by codepoint rather than by name, and screens adopt that per glyph as they are
touched rather than all at once — this resource only makes the face available. Program.cs makes the
equivalent change for the sans stack, with Montserrat first and Inter kept as its fallback; see the
remarks on BuildAvaloniaApp.
-->
<FontFamily x:Key="MonoFont">avares://DodoSSH.Client.Shell/Assets/Fonts#JetBrains Mono,ui-monospace,Cascadia Mono,Consolas,monospace</FontFamily>
<FontFamily x:Key="IconFont">avares://DodoSSH.Client.Shell/Assets/Fonts#Material Icons</FontFamily>
</ResourceDictionary>