Improve styling.

This commit is contained in:
Greyson Parrelli
2026-08-12 21:15:07 -04:00
parent 4e0e400372
commit e16b147e16
13 changed files with 1104 additions and 119 deletions
+201 -65
View File
@@ -1,41 +1,114 @@
/* Zen-style vertical tabs: a dark sidebar column with the terminal inset
to its right. */
/* Zen-style vertical tabs: a sidebar column with the terminal inset to its
right.
Every colour here is a name defined in `palette-dark.css` or
`palette-light.css`; `appearance.zig` prepends one of them and loads the
pair as a single provider. Nothing below may hardcode a colour — a literal
hex would be a rule that looks right in one scheme and wrong in the other,
and it would look right in whichever one you happened to be testing in.
`alpha()` is used for every wash rather than a second named colour, so a
state's tint is always derived from the state's own colour and the two
can't drift apart. */
.playpen-window {
background-color: #0f0d14;
background-color: @pp_bg;
}
/* The sidebar is a card, not a column: rounded on every corner and inset from
the window edge, so it sits on the backdrop the same way a pane does. It
used to run edge to edge and meet the content at a hairline, which left the
top-left corner reading as three unrelated things sharing one point — the
window edge, the header buttons and the first tab row all at once. */
.playpen-sidebar {
background-color: #1b1823;
border-right: 1px solid #2a2536;
background-color: @pp_sidebar;
border: 1px solid @pp_border;
border-radius: 12px;
margin: 6px 0 6px 6px;
}
/* Room above the buttons so they clear the card's rounded top edge rather than
sitting in it.
The rule underneath is stated explicitly rather than left to the one Adwaita
draws for every header bar: that one is a shadow in the desktop theme's
colour, which on this palette read as a stray line rather than as the pair
it now makes with the footer's. */
.playpen-sidebar headerbar {
background: none;
box-shadow: none;
min-height: 38px;
min-height: 44px;
padding: 6px 8px 2px 8px;
border-bottom: 1px solid @pp_border;
}
/* The two header actions. Styled explicitly rather than left to Adwaita, whose
default button is a grey that belongs to a different window than this one.
Scoped by class instead of by `headerbar button` so the window controls
beside them keep their own appearance — those belong to the desktop, not to
the app, and making them match would be the wrong kind of consistent.
Two selectors because a MenuButton wraps its button in a `menubutton` node,
so the class lands one level above the thing that draws. */
button.playpen-header-button,
.playpen-header-button > button {
min-width: 30px;
min-height: 30px;
padding: 0;
margin: 0 1px;
border-radius: 8px;
color: @pp_text_dim;
background-color: @pp_surface_raised;
background-image: none;
border: 1px solid @pp_border;
box-shadow: none;
}
button.playpen-header-button:hover,
.playpen-header-button > button:hover {
background-color: @pp_row_hover;
background-image: none;
color: @pp_text;
}
/* The strip below the tab list, holding the settings button. Separated by a
rule so the button doesn't read as a row of the list it sits under. */
.playpen-sidebar-footer {
padding: 6px 8px;
border-top: 1px solid @pp_border;
}
.playpen-settings-button {
min-width: 26px;
min-height: 26px;
padding: 0;
color: @pp_text_faint;
}
.playpen-settings-button:hover {
color: @pp_text;
}
.playpen-list {
background: none;
padding: 4px 6px;
padding: 4px 8px;
}
.playpen-list > row {
border-radius: 8px;
margin: 1px 0;
padding: 5px 8px;
color: #b6afc7;
margin: 2px 0;
padding: 7px 8px;
color: @pp_text_dim;
transition: background-color 120ms ease;
}
.playpen-list > row:hover {
background-color: #262133;
background-color: @pp_row_hover;
}
.playpen-list > row:selected {
background-color: #342c4a;
color: #f0ecf8;
background-color: @pp_row_selected;
color: @pp_text;
}
/* The kind icon picks up the accent on the current row. The status dot is
@@ -43,7 +116,7 @@
specific enough to beat the state classes, which used to leave the selected
row's dot accent-coloured whatever it was trying to say. */
.playpen-list > row:selected image:not(.playpen-status-dot) {
color: #b29df5;
color: @pp_accent_strong;
}
/* State on the row itself, not just on its dot.
@@ -60,24 +133,24 @@
These come after the :selected rules deliberately. Equal specificity means
source order decides, and a state outranks "this is the tab you are on". */
.playpen-list > row.playpen-attn-busy {
box-shadow: inset 3px 0 0 #b29df5;
box-shadow: inset 3px 0 0 @pp_accent_strong;
}
/* No wash for working. It is the most common state by far, and a sidebar where
half the rows are tinted all afternoon teaches you to stop looking. */
.playpen-list > row.playpen-attn-done {
box-shadow: inset 3px 0 0 #7ddc9a;
background-color: rgba(125, 220, 154, 0.13);
box-shadow: inset 3px 0 0 @pp_ok;
background-color: alpha(@pp_ok, 0.14);
}
.playpen-list > row.playpen-attn-input {
box-shadow: inset 3px 0 0 #f0c069;
background-color: rgba(240, 192, 105, 0.13);
box-shadow: inset 3px 0 0 @pp_warn;
background-color: alpha(@pp_warn, 0.14);
}
.playpen-list > row.playpen-attn-failed {
box-shadow: inset 3px 0 0 #f2a0a0;
background-color: rgba(242, 160, 160, 0.13);
box-shadow: inset 3px 0 0 @pp_err;
background-color: alpha(@pp_err, 0.14);
}
/* The current row keeps its own background: the wash and the selection would
@@ -86,7 +159,7 @@
.playpen-list > row:selected.playpen-attn-done,
.playpen-list > row:selected.playpen-attn-input,
.playpen-list > row:selected.playpen-attn-failed {
background-color: #342c4a;
background-color: @pp_row_selected;
}
/* Keep the close button unobtrusive until the row is hovered or current. */
@@ -107,12 +180,15 @@
}
.playpen-content {
background-color: #0f0d14;
background-color: @pp_bg;
}
/* A view is the container for one tab's terminals. */
/* A view is the container for one tab's terminals. Even padding now that the
sidebar is inset too — the left edge used to be flush against the sidebar's
border, so the gutter around the content was open on three sides and closed
on the fourth. */
.playpen-view {
padding: 6px 6px 6px 0;
padding: 6px;
}
/* Paned itself draws nothing; the panes inside it carry the styling. */
@@ -123,32 +199,32 @@
/* Each terminal sits in its own rounded frame so multiple panes in a view
read as distinct surfaces. */
.playpen-pane {
background-color: #16141c;
background-color: @pp_surface;
border-radius: 10px;
border: 1px solid #2a2536;
border: 1px solid @pp_border;
}
.playpen-pane.active {
border-color: #5b4d80;
border-color: @pp_accent_muted;
}
.playpen-pane-header {
padding: 2px 4px 2px 10px;
background-color: #1c1926;
border-bottom: 1px solid #262133;
background-color: @pp_surface_raised;
border-bottom: 1px solid @pp_border;
}
.playpen-pane.active .playpen-pane-header {
background-color: #241f33;
background-color: @pp_surface_raised_active;
}
.playpen-pane-title {
font-size: 0.82em;
color: #8f87a3;
color: @pp_text_faint;
}
.playpen-pane.active .playpen-pane-title {
color: #ded7ef;
color: @pp_text;
}
.playpen-pane-button {
@@ -168,12 +244,12 @@
}
.playpen-pane-icon {
color: #6f6784;
color: @pp_text_faint;
-gtk-icon-size: 14px;
}
.playpen-pane.active .playpen-pane-icon {
color: #b29df5;
color: @pp_accent_strong;
}
/* Status dots. One shared appearance for the sidebar row and the pane header,
@@ -198,7 +274,7 @@
/* Working: the same accent as an active pane's border, so "busy" reads as
ordinary activity rather than something gone wrong. */
.playpen-status-busy {
color: #b29df5;
color: @pp_accent_strong;
animation: playpen-pulse 1.6s ease-in-out infinite;
}
@@ -206,17 +282,17 @@
distinct from still-working at a glance, which is the one distinction this
whole indicator exists to make. */
.playpen-status-done {
color: #7ddc9a;
color: @pp_ok;
}
/* Blocked on you. Amber, and not animated — a pulsing dot reads as progress,
and this is the opposite of progress. */
.playpen-status-input {
color: #f0c069;
color: @pp_warn;
}
.playpen-status-failed {
color: #f2a0a0;
color: @pp_err;
}
@keyframes playpen-pulse {
@@ -235,15 +311,15 @@
than the header so the two rows don't compete. */
.playpen-nav {
padding: 4px 6px;
background-color: #16141c;
border-bottom: 1px solid #262133;
background-color: @pp_surface;
border-bottom: 1px solid @pp_border;
}
.playpen-nav-button {
min-width: 24px;
min-height: 24px;
padding: 0;
color: #b6afc7;
color: @pp_text_dim;
}
.playpen-nav-button:disabled {
@@ -256,21 +332,21 @@
padding: 2px 8px;
border-radius: 6px;
font-size: 0.85em;
background-color: #0f0d14;
color: #ded7ef;
border: 1px solid #2a2536;
background-color: @pp_bg;
color: @pp_text;
border: 1px solid @pp_border;
box-shadow: none;
}
.playpen-nav-entry:focus-within {
border-color: #5b4d80;
border-color: @pp_accent;
}
/* The pane currently filling its tab. The other panes are still open and still
running, just not drawn, so this is marked quietly — a lit border rather than
anything alarming. The header's toggle icon carries the rest of the message. */
.playpen-pane.zoomed {
border-color: #7a68a8;
border-color: @pp_accent;
}
.playpen-pane.zoomed .playpen-pane-button {
@@ -290,15 +366,15 @@
you don't. `.dragging` still wins over all of it, further down: while you are
moving a pane, feedback about the move is the only thing that matters. */
.playpen-pane.playpen-attn-done {
border-color: #7ddc9a;
border-color: @pp_ok;
}
.playpen-pane.playpen-attn-input {
border-color: #f0c069;
border-color: @pp_warn;
}
.playpen-pane.playpen-attn-failed {
border-color: #f2a0a0;
border-color: @pp_err;
}
/* The header carries a wash of the same colour. The border alone is a hairline
@@ -306,22 +382,22 @@
the title, which is what makes a pane readable at a glance in a four-way
split. */
.playpen-pane.playpen-attn-done .playpen-pane-header {
background-color: rgba(125, 220, 154, 0.12);
background-color: alpha(@pp_ok, 0.13);
}
.playpen-pane.playpen-attn-input .playpen-pane-header {
background-color: rgba(240, 192, 105, 0.12);
background-color: alpha(@pp_warn, 0.13);
}
.playpen-pane.playpen-attn-failed .playpen-pane-header {
background-color: rgba(242, 160, 160, 0.12);
background-color: alpha(@pp_err, 0.13);
}
/* The pane being dragged. There is no separate drop indicator: the layout
rearranges live during the drag, so the view itself is the preview. */
.playpen-pane.dragging {
opacity: 0.65;
border-color: #b29df5;
border-color: @pp_accent_strong;
}
/* Saved-layout menu, hanging off the sidebar header. */
@@ -336,13 +412,13 @@
.playpen-layout-empty {
padding: 8px;
color: #8f87a3;
color: @pp_text_faint;
font-size: 0.9em;
}
/* Layout dialogs: opening one, and saving the current tab as one. */
.playpen-dialog {
background-color: #16141c;
background-color: @pp_surface;
}
.playpen-dialog-content {
@@ -351,47 +427,107 @@
.playpen-dialog-actions {
padding: 12px 16px;
border-top: 1px solid #262133;
border-top: 1px solid @pp_border;
}
.playpen-dialog-heading {
margin-top: 8px;
font-weight: bold;
color: #ded7ef;
color: @pp_text;
}
.playpen-dialog-label {
color: #b6afc7;
color: @pp_text_dim;
}
.playpen-dialog-sublabel {
font-size: 0.88em;
color: #8f87a3;
color: @pp_text_faint;
}
.playpen-dialog-hint {
font-size: 0.85em;
color: #8f87a3;
color: @pp_text_faint;
}
.playpen-dialog-error {
color: #f2a0a0;
color: @pp_err;
}
/* Each captured pane in the save dialog, so the sections read apart. */
.playpen-dialog-pane {
padding: 8px;
border: 1px solid #2a2536;
border: 1px solid @pp_border;
border-radius: 8px;
}
/* -------------------------------------------------------------------------
Settings
One section per group of preferences, each a titled card on the dialog's
surface. There is a single group today; the card is what stops the second
one from needing a redesign. */
.playpen-settings-group {
padding: 12px 14px;
border: 1px solid @pp_border;
border-radius: 10px;
background-color: @pp_surface_raised;
}
.playpen-settings-title {
font-weight: bold;
color: @pp_text;
}
/* The scheme picker: three linked buttons rather than a dropdown, so the whole
choice is visible without opening anything, and so the one you are on is
readable at a glance rather than by reading a word. */
/* `background-image: none` on every rule below is load-bearing. Adwaita paints
button states with a gradient *over* the background colour, so setting the
colour alone leaves a washed-out version of it — most visibly on the checked
button, where the accent came out as a pale grey-blue. `:backdrop` is
spelled out for the same reason: Adwaita dims unfocused windows, and the
selected scheme is exactly the thing that has to stay readable while you are
looking at the window behind this one to see what it did. */
.playpen-settings-choice > button {
padding: 5px 14px;
color: @pp_text_dim;
background-color: @pp_surface;
background-image: none;
border: 1px solid @pp_border;
box-shadow: none;
}
.playpen-settings-choice > button:hover {
background-color: @pp_row_hover;
background-image: none;
color: @pp_text;
}
.playpen-settings-choice > button:checked,
.playpen-settings-choice > button:checked:backdrop {
background-color: @pp_accent;
background-image: none;
border-color: @pp_accent;
/* Against a filled accent in either scheme — the light palette's accent is
dark enough that white text is the readable choice there too. */
color: #ffffff;
}
.playpen-settings-choice > button:checked:hover {
background-color: @pp_accent_strong;
background-image: none;
border-color: @pp_accent_strong;
}
/* Divider between panes. Wide enough to grab without hunting for it. */
.playpen-view paned > separator {
background-color: #0f0d14;
background-color: @pp_bg;
min-width: 6px;
min-height: 6px;
}
.playpen-view paned > separator:hover {
background-color: #4a3f6b;
background-color: @pp_accent_muted;
}