taffybar CSS: extract per-widget colors to nth-child rotation

Replace individual .outer-pad.audio, .outer-pad.network, etc. color
rules with a 5-color palette in end-widget-colors.css that cycles via
:nth-child(5n+N). Add workspace pill reset to prevent the rotation
from bleeding into workspace widgets. Move per-widget color variables
from theme.css into end-widget-colors.css (keep tray colors in theme
since the SNI tray is a center widget outside the rotation).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-02-09 16:41:33 -08:00
committed by Kat Huang
parent a258af58d6
commit ba952b4b57
3 changed files with 129 additions and 123 deletions

View File

@@ -0,0 +1,106 @@
/* End-widget color rotation.
*
* Defines a 5-color palette and cycles through it using :nth-child().
* End widgets are children of their own container box in taffybar's layout,
* so nth-child counts only among siblings in that box.
*
* NOTE: These rules also match workspace .outer-pad elements.
* taffybar.css resets workspace pills via `.workspaces .outer-pad` which
* has equal specificity but comes later in the cascade, so it wins.
*
* To change the palette, edit the @define-color values below.
* To add more colors to the rotation, add end-color-6-* etc. and a
* corresponding :nth-child(Nn+6) rule block (updating N in all selectors).
*/
/* --- Rotation palette (5 colors) --- */
/* 1 — indigo */
@define-color end-color-1-bg rgba(50, 60, 160, 0.92);
@define-color end-color-1-fg #d5d8f8;
@define-color end-color-1-border rgba(90, 100, 210, 0.60);
/* 2 — purple */
@define-color end-color-2-bg rgba(110, 45, 160, 0.92);
@define-color end-color-2-fg #e8d5f8;
@define-color end-color-2-border rgba(155, 85, 210, 0.60);
/* 3 — emerald */
@define-color end-color-3-bg rgba(25, 130, 75, 0.92);
@define-color end-color-3-fg #c8f5e0;
@define-color end-color-3-border rgba(55, 190, 115, 0.60);
/* 4 — teal */
@define-color end-color-4-bg rgba(20, 120, 140, 0.92);
@define-color end-color-4-fg #d0f2f8;
@define-color end-color-4-border rgba(50, 175, 200, 0.60);
/* 5 — rose */
@define-color end-color-5-bg rgba(160, 40, 70, 0.92);
@define-color end-color-5-fg #f8d5e0;
@define-color end-color-5-border rgba(210, 80, 115, 0.60);
/* --- Color rotation rules --- */
/* Slot 1: indigo (child 1, 6, 11, ...) */
.outer-pad:nth-child(5n+1) {
background-color: @end-color-1-bg;
border-color: @end-color-1-border;
box-shadow: 0 1px 0 rgba(255, 255, 255, 0.06), 0 10px 24px rgba(0, 0, 0, 0.30);
}
.outer-pad:nth-child(5n+1) :not(menu):not(menuitem):not(popover):not(window),
.outer-pad:nth-child(5n+1) :not(menu):not(menuitem):not(popover):not(window) * {
color: @end-color-1-fg;
}
/* Slot 2: purple (child 2, 7, 12, ...) */
.outer-pad:nth-child(5n+2) {
background-color: @end-color-2-bg;
border-color: @end-color-2-border;
box-shadow: 0 1px 0 rgba(255, 255, 255, 0.06), 0 10px 24px rgba(0, 0, 0, 0.30);
}
.outer-pad:nth-child(5n+2) :not(menu):not(menuitem):not(popover):not(window),
.outer-pad:nth-child(5n+2) :not(menu):not(menuitem):not(popover):not(window) * {
color: @end-color-2-fg;
}
/* Slot 3: emerald (child 3, 8, 13, ...) */
.outer-pad:nth-child(5n+3) {
background-color: @end-color-3-bg;
border-color: @end-color-3-border;
box-shadow: 0 1px 0 rgba(255, 255, 255, 0.06), 0 10px 24px rgba(0, 0, 0, 0.30);
}
.outer-pad:nth-child(5n+3) :not(menu):not(menuitem):not(popover):not(window),
.outer-pad:nth-child(5n+3) :not(menu):not(menuitem):not(popover):not(window) * {
color: @end-color-3-fg;
}
/* Slot 4: teal (child 4, 9, 14, ...) */
.outer-pad:nth-child(5n+4) {
background-color: @end-color-4-bg;
border-color: @end-color-4-border;
box-shadow: 0 1px 0 rgba(255, 255, 255, 0.06), 0 10px 24px rgba(0, 0, 0, 0.30);
}
.outer-pad:nth-child(5n+4) :not(menu):not(menuitem):not(popover):not(window),
.outer-pad:nth-child(5n+4) :not(menu):not(menuitem):not(popover):not(window) * {
color: @end-color-4-fg;
}
/* Slot 5: rose (child 5, 10, 15, ...) */
.outer-pad:nth-child(5n+5) {
background-color: @end-color-5-bg;
border-color: @end-color-5-border;
box-shadow: 0 1px 0 rgba(255, 255, 255, 0.06), 0 10px 24px rgba(0, 0, 0, 0.30);
}
.outer-pad:nth-child(5n+5) :not(menu):not(menuitem):not(popover):not(window),
.outer-pad:nth-child(5n+5) :not(menu):not(menuitem):not(popover):not(window) * {
color: @end-color-5-fg;
}
/* --- SNI tray (center widget, not part of the rotation) --- */
.outer-pad.sni-tray {
background-color: @widget-tray-bg;
border-color: @widget-tray-border;
box-shadow: 0 1px 0 rgba(255, 255, 255, 0.06), 0 10px 24px rgba(0, 0, 0, 0.30);
}

View File

@@ -5,6 +5,7 @@
* by GTK's CSS parser. * by GTK's CSS parser.
*/ */
@import url("theme.css"); @import url("theme.css");
@import url("end-widget-colors.css");
/* Base typography + foreground color for the bar itself. /* Base typography + foreground color for the bar itself.
* *
@@ -84,95 +85,32 @@
background-color: transparent; background-color: transparent;
} }
/* Per-widget colored squircle overrides. /* Per-widget color overrides now live in end-widget-colors.css,
decorateWithClassAndBox "name" (in taffybar.hs) adds the widget class to which rotates through a 5-color palette via :nth-child(). */
the same element that has .outer-pad, so `.outer-pad.audio` etc. target
each widget's pill. Colors come from @widget-*-bg/fg/border in theme.css. */
.outer-pad.audio {
background-color: @widget-audio-bg;
border-color: @widget-audio-border;
box-shadow: 0 1px 0 rgba(255, 255, 255, 0.06), 0 10px 24px rgba(0, 0, 0, 0.30);
}
.outer-pad.audio :not(menu):not(menuitem):not(popover):not(window),
.outer-pad.audio :not(menu):not(menuitem):not(popover):not(window) * {
color: @widget-audio-fg;
}
.outer-pad.network {
background-color: @widget-network-bg;
border-color: @widget-network-border;
box-shadow: 0 1px 0 rgba(255, 255, 255, 0.06), 0 10px 24px rgba(0, 0, 0, 0.30);
}
.outer-pad.network :not(menu):not(menuitem):not(popover):not(window),
.outer-pad.network :not(menu):not(menuitem):not(popover):not(window) * {
color: @widget-network-fg;
}
.outer-pad.mpris {
background-color: @widget-mpris-bg;
border-color: @widget-mpris-border;
box-shadow: 0 1px 0 rgba(255, 255, 255, 0.06), 0 10px 24px rgba(0, 0, 0, 0.30);
}
.outer-pad.mpris :not(menu):not(menuitem):not(popover):not(window),
.outer-pad.mpris :not(menu):not(menuitem):not(popover):not(window) * {
color: @widget-mpris-fg;
}
.outer-pad.mpris .icon { .outer-pad.mpris .icon {
font-family: "Iosevka Nerd Font"; font-family: "Iosevka Nerd Font";
} }
.outer-pad.clock {
background-color: @widget-clock-bg;
border-color: @widget-clock-border;
box-shadow: 0 1px 0 rgba(255, 255, 255, 0.06), 0 10px 24px rgba(0, 0, 0, 0.30);
}
.outer-pad.clock :not(menu):not(menuitem):not(popover):not(window),
.outer-pad.clock :not(menu):not(menuitem):not(popover):not(window) * {
color: @widget-clock-fg;
}
.outer-pad.disk-usage {
background-color: @widget-disk-bg;
border-color: @widget-disk-border;
box-shadow: 0 1px 0 rgba(255, 255, 255, 0.06), 0 10px 24px rgba(0, 0, 0, 0.30);
}
.outer-pad.disk-usage :not(menu):not(menuitem):not(popover):not(window),
.outer-pad.disk-usage :not(menu):not(menuitem):not(popover):not(window) * {
color: @widget-disk-fg;
}
.outer-pad.sni-tray {
background-color: @widget-tray-bg;
border-color: @widget-tray-border;
box-shadow: 0 1px 0 rgba(255, 255, 255, 0.06), 0 10px 24px rgba(0, 0, 0, 0.30);
}
.outer-pad.sni-tray :not(menu):not(menuitem):not(popover):not(window),
.outer-pad.sni-tray :not(menu):not(menuitem):not(popover):not(window) * {
color: @widget-tray-fg;
}
.outer-pad.battery {
background-color: @widget-battery-bg;
border-color: @widget-battery-border;
box-shadow: 0 1px 0 rgba(255, 255, 255, 0.06), 0 10px 24px rgba(0, 0, 0, 0.30);
}
.outer-pad.battery :not(menu):not(menuitem):not(popover):not(window),
.outer-pad.battery :not(menu):not(menuitem):not(popover):not(window) * {
color: @widget-battery-fg;
}
.outer-pad.backlight {
background-color: @widget-backlight-bg;
border-color: @widget-backlight-border;
box-shadow: 0 1px 0 rgba(255, 255, 255, 0.06), 0 10px 24px rgba(0, 0, 0, 0.30);
}
.outer-pad.backlight :not(menu):not(menuitem):not(popover):not(window),
.outer-pad.backlight :not(menu):not(menuitem):not(popover):not(window) * {
color: @widget-backlight-fg;
}
/* Workspaces styling */ /* Workspaces styling */
/* Reset workspace .outer-pad pills to default styling so the nth-child color
rotation from end-widget-colors.css doesn't bleed into workspace pills.
This has specificity 0,2,0 (same as the nth-child rules) but comes later
in the cascade, so it wins. */
.workspaces .outer-pad {
background-color: @pill-background;
box-shadow:
inset 0 1px 0 @pill-highlight,
inset 0 0 0 1px @pill-border,
0 10px 24px @pill-shadow;
}
.workspaces .outer-pad :not(menu):not(menuitem):not(popover):not(window),
.workspaces .outer-pad :not(menu):not(menuitem):not(popover):not(window) * {
color: @font-color;
}
/* Asymmetric padding: 10px left leaves room for the overlaid workspace number /* Asymmetric padding: 10px left leaves room for the overlaid workspace number
label; 3px right keeps the pill tight against the trailing icon edge. */ label; 3px right keeps the pill tight against the trailing icon edge. */
.workspaces .inner-pad { .workspaces .inner-pad {

View File

@@ -21,52 +21,14 @@
@define-color pill-highlight rgba(255, 255, 255, 0.10); @define-color pill-highlight rgba(255, 255, 255, 0.10);
@define-color pill-shadow rgba(0, 0, 0, 0.28); @define-color pill-shadow rgba(0, 0, 0, 0.28);
/* Per-widget backgrounds — each widget gets a distinct tinted squircle so they /* Per-widget end-widget colors now live in end-widget-colors.css
are visually distinguishable at a glance. Each group defines: (5-color rotation palette applied via :nth-child). */
*-bg : pill background color (semi-transparent, dark-tinted)
*-fg : text/icon color (light, tinted to complement the background)
*-border : subtle border stroke color */
/* PulseAudio volume widget — purple */ /* StatusNotifierItem system tray — neutral dark slate (center widget, not rotated) */
@define-color widget-audio-bg rgba(110, 45, 160, 0.92);
@define-color widget-audio-fg #e8d5f8;
@define-color widget-audio-border rgba(155, 85, 210, 0.60);
/* NetworkManager wifi/ethernet widget — teal */
@define-color widget-network-bg rgba(20, 120, 140, 0.92);
@define-color widget-network-fg #d0f2f8;
@define-color widget-network-border rgba(50, 175, 200, 0.60);
/* MPRIS2 now-playing widget — rose/crimson */
@define-color widget-mpris-bg rgba(160, 40, 70, 0.92);
@define-color widget-mpris-fg #f8d5e0;
@define-color widget-mpris-border rgba(210, 80, 115, 0.60);
/* Clock widget — indigo/royal blue */
@define-color widget-clock-bg rgba(50, 60, 160, 0.92);
@define-color widget-clock-fg #d5d8f8;
@define-color widget-clock-border rgba(90, 100, 210, 0.60);
/* Disk-usage widget — emerald green */
@define-color widget-disk-bg rgba(25, 130, 75, 0.92);
@define-color widget-disk-fg #c8f5e0;
@define-color widget-disk-border rgba(55, 190, 115, 0.60);
/* StatusNotifierItem system tray — neutral dark slate */
@define-color widget-tray-bg rgba(65, 70, 100, 0.92); @define-color widget-tray-bg rgba(65, 70, 100, 0.92);
@define-color widget-tray-fg #d8dae8; @define-color widget-tray-fg #d8dae8;
@define-color widget-tray-border rgba(110, 115, 160, 0.60); @define-color widget-tray-border rgba(110, 115, 160, 0.60);
/* Battery (icon and text) — amber/gold */
@define-color widget-battery-bg rgba(160, 115, 20, 0.92);
@define-color widget-battery-fg #f8ecc5;
@define-color widget-battery-border rgba(210, 165, 50, 0.60);
/* Backlight/brightness widget — warm golden */
@define-color widget-backlight-bg rgba(170, 120, 15, 0.92);
@define-color widget-backlight-fg #f8efc5;
@define-color widget-backlight-border rgba(220, 170, 45, 0.60);
/* Text */ /* Text */
@define-color font-color #e7e4ee; @define-color font-color #e7e4ee;
@define-color font-muted #b8b1c6; @define-color font-muted #b8b1c6;