feat: unified bar styling

- semantic tokens (accent/surface/hairline/text-muted) derived from the
  palette so they follow stylix in light and dark mode
- every bar module is a uniform 28px rounded chip; one accent for active
  state, tints for attention, solid fill only for mail-debt alarm
- workspaces as dots with a stretching accent pill
- mic/cpu-ram/tray/battery grouped into one chip; cpu/ram as concentric
  rings with tooltip; clock split into bold time + muted date
- stylix provider only sets palette + font; scope its font-size so the
  bar's own CSS sizes are no longer flattened
- drop inline widget styles, 16px tray icons, fix broken menu.css selector
This commit is contained in:
2026-11-09 23:29:01 +01:00
parent a890604001
commit 377889db8c
12 changed files with 326 additions and 484 deletions
+1 -1
View File
@@ -48,7 +48,7 @@ from gi.repository import GLib, Gtk
from fabric.notifications import Notifications from fabric.notifications import Notifications
tray = SystemTray(name="system-tray", spacing=4) tray = SystemTray(name="system-tray", spacing=2, icon_size=16)
get_i3_connection() get_i3_connection()
# Subscribe before the main loop runs so fenster's replayed capture state # Subscribe before the main loop runs so fenster's replayed capture state
# (sent right after SUBSCRIBE) is not missed. # (sent right after SUBSCRIBE) is not missed.
+48 -23
View File
@@ -1,8 +1,10 @@
import time
from fabric.widgets.box import Box from fabric.widgets.box import Box
from fabric.widgets.label import Label from fabric.widgets.label import Label
from fabric.widgets.overlay import Overlay from fabric.widgets.overlay import Overlay
from fabric.widgets.datetime import DateTime
from fabric.widgets.centerbox import CenterBox from fabric.widgets.centerbox import CenterBox
from fabric.utils import invoke_repeater
from sims.modules.player import Player, PlayerSmall from sims.modules.player import Player, PlayerSmall
from sims.modules.battery import Battery from sims.modules.battery import Battery
from sims.modules.control_center import ControlCenter from sims.modules.control_center import ControlCenter
@@ -55,12 +57,10 @@ class StatusBar(Window):
spacing=4, spacing=4,
) )
datetime_widget = DateTime(name="date-time", formatters="%d %b - %H:%M")
self.date_time = Button( self.date_time = Button(
name="date-time-button", name="date-time-button",
child=datetime_widget, child=Clock(),
on_clicked=self._on_date_time_clicked, on_clicked=self._on_date_time_clicked,
style="background: transparent; border: none; padding: 0; margin: 0; box-shadow: none;",
) )
self.control_center = control_center self.control_center = control_center
@@ -69,22 +69,21 @@ class StatusBar(Window):
self.active_window = FensterActiveWindow( self.active_window = FensterActiveWindow(
name="active-window", name="active-window",
max_length=50, max_length=50,
style="font-size: 14px; font-weight: bold;",
) )
# CPU/RAM as concentric "activity rings": outer = RAM, inner = CPU.
ring = dict(line_width=3, start_angle=-90, end_angle=270,
h_align="center", v_align="center")
self.ram_progress_bar = CircularProgressBar( self.ram_progress_bar = CircularProgressBar(
name="ram-progress-bar", pie=True, size=24 name="ram-progress-bar", size=18, **ring
) )
self.cpu_progress_bar = CircularProgressBar( self.cpu_progress_bar = CircularProgressBar(
name="cpu-progress-bar", pie=True, size=24 name="cpu-progress-bar", size=8, **ring
)
self.progress_label = Label(
"", style="margin: 0px 6px 0px 0px; font-size: 12px"
) )
self.progress_bars_overlay = Overlay( self.progress_bars_overlay = Overlay(
name="system-stats",
child=self.ram_progress_bar, child=self.ram_progress_bar,
overlays=[self.cpu_progress_bar, self.progress_label], overlays=[self.cpu_progress_bar],
) )
self.player = Player() self.player = Player()
self.player_small = PlayerSmall(monitor=monitor) self.player_small = PlayerSmall(monitor=monitor)
@@ -110,11 +109,18 @@ class StatusBar(Window):
self.microphone = MicrophoneWidget() self.microphone = MicrophoneWidget()
# One chip for the ambient system state; attention items (org,
# mail, screen share) stay separate so they can light up.
status_children = [self.microphone, self.progress_bars_overlay]
if self.system_tray:
status_children.append(self.system_tray)
if self.battery:
status_children.append(self.battery)
self.status_container = Box( self.status_container = Box(
name="widgets-container", name="widgets-container",
spacing=4, spacing=6,
orientation="h", orientation="h",
children=[self.microphone, self.progress_bars_overlay], children=status_children,
) )
end_container_children = [] end_container_children = []
@@ -122,17 +128,11 @@ class StatusBar(Window):
if self.org is not None: if self.org is not None:
end_container_children.append(self.org) end_container_children.append(self.org)
end_container_children.append(self.status_container)
if self.system_tray:
end_container_children.append(self.system_tray)
if self.battery:
end_container_children.append(self.battery)
if self.notmuch: if self.notmuch:
end_container_children.append(self.notmuch) end_container_children.append(self.notmuch)
end_container_children.append(self.capture) end_container_children.append(self.capture)
end_container_children.append(self.status_container)
end_container_children.append(self.date_time) end_container_children.append(self.date_time)
@@ -155,7 +155,7 @@ class StatusBar(Window):
name="sims-inner", name="sims-inner",
start_children=Box( start_children=Box(
name="start-container", name="start-container",
spacing=6, spacing=8,
orientation="h", orientation="h",
children=start_container_children, children=start_container_children,
), ),
@@ -167,7 +167,7 @@ class StatusBar(Window):
), ),
end_children=Box( end_children=Box(
name="end-container", name="end-container",
spacing=4, spacing=6,
orientation="h", orientation="h",
children=end_container_children, children=end_container_children,
), ),
@@ -218,7 +218,32 @@ class StatusBar(Window):
def update_progress_bars(self, service, cpu_percent, memory_percent): def update_progress_bars(self, service, cpu_percent, memory_percent):
self.cpu_progress_bar.value = cpu_percent self.cpu_progress_bar.value = cpu_percent
self.ram_progress_bar.value = memory_percent self.ram_progress_bar.value = memory_percent
self.progress_bars_overlay.set_tooltip_text(
f"CPU {cpu_percent * 100:.0f}% · RAM {memory_percent * 100:.0f}%"
)
def _on_date_time_clicked(self, _button=None): def _on_date_time_clicked(self, _button=None):
if self.control_center is not None: if self.control_center is not None:
self.control_center.toggle() self.control_center.toggle()
class Clock(Box):
"""Bold time + muted date, e.g. `20:26 Mon 22 Jul`."""
def __init__(self, **kwargs):
self._time = Label(name="clock-time")
self._date = Label(name="clock-date")
super().__init__(
name="date-time",
orientation="h",
spacing=8,
children=[self._time, self._date],
**kwargs,
)
invoke_repeater(1000, self._update)
def _update(self) -> bool:
now = time.localtime()
self._time.set_label(time.strftime("%H:%M", now))
self._date.set_label(time.strftime("%a %d %b", now))
return True
-1
View File
@@ -27,7 +27,6 @@ class MicrophoneWidget(Box):
name="microphone-button", name="microphone-button",
child=self.icon_label, child=self.icon_label,
on_clicked=self.on_clicked, on_clicked=self.on_clicked,
style="background: transparent; border: none; margin: 0; box-shadow: none;",
) )
self.add(self.button) self.add(self.button)
+13 -253
View File
@@ -60,58 +60,6 @@ def resolve_colors(mode: str | None = None) -> dict[str, str]:
return colors return colors
def is_light(colors: dict[str, str]) -> bool:
"""Whether the palette is a light one, judged by base00's relative
luminance (so light base schemes work without `variants` too)."""
def channel(c: int) -> float:
c = c / 255
return c / 12.92 if c <= 0.04045 else ((c + 0.055) / 1.055) ** 2.4
hex_bg = colors["base00"].lstrip("#")
r, g, b = (channel(int(hex_bg[i : i + 2], 16)) for i in (0, 2, 4))
return 0.2126 * r + 0.7152 * g + 0.0722 * b > 0.5
# Accent "status pills": (widget selector, child selectors, base16 slot). Later
# entries win over earlier ones at equal specificity, mirroring org.css and
# notmuch.css (debt state overrides unread, in-progress+next overrides both).
ACCENT_PILLS = [
("#org-widget.has-in-progress", ("#org-icon", "#org-count"), "base0E"),
("#org-widget.has-next", ("#org-icon", "#org-count"), "base0D"),
("#org-widget.has-in-progress.has-next", ("#org-icon", "#org-count"), "base0C"),
("#notmuch-widget.has-unread", ("#notmuch-icon", "#unread-count"), "base0D"),
("#notmuch-widget.debt-warn", ("#notmuch-icon", "#unread-count"), "base09"),
("#notmuch-widget.debt-alarm", ("#notmuch-icon", "#unread-count"), "base08"),
]
def accent_pill_css(colors: dict[str, str]) -> str:
"""Org/notmuch alert pills. Dark palettes get a solid accent fill with
background-colored text (pastel accents carry that well); light palettes
get a pale accent tint with accent-colored text, since a solid fill of a
light scheme's saturated accents is far louder than the rest of the bar."""
light = is_light(colors)
rules = []
for widget, children, slot in ACCENT_PILLS:
accent = f"#{colors[slot]}"
if light:
bg, hover_bg, fg = (
f"alpha({accent}, 0.18)",
f"alpha({accent}, 0.30)",
accent,
)
else:
bg, hover_bg, fg = accent, f"shade({accent}, 1.12)", f"#{colors['base00']}"
child_sel = ",\n".join(f"{widget} {c}" for c in children)
rules.append(
f"{widget} {{\n background-color: {bg};\n}}\n\n"
f"{widget}:hover {{\n background-color: {hover_bg};\n}}\n\n"
f"{child_sel} {{\n color: {fg};\n}}\n"
)
return "\n".join(rules)
def generate_stylix_css(mode: str | None = None) -> str | None: def generate_stylix_css(mode: str | None = None) -> str | None:
"""Generate CSS using Stylix colors (for `mode`, if variants are set)""" """Generate CSS using Stylix colors (for `mode`, if variants are set)"""
if not STYLIX.get("enable", False): if not STYLIX.get("enable", False):
@@ -144,129 +92,27 @@ def generate_stylix_css(mode: str | None = None) -> str | None:
{palette} {palette}
/* Apply Stylix font */ /* Apply Stylix font. This provider sits in front of main.css and GTK lets
the first provider that sets a property win regardless of selector
specificity, so a blanket `* {{ font-size }}` here would flatten every
size in the bar's own CSS. The bar (window#sims) therefore only gets the
size on its toplevel and inherits it; other windows keep the blanket
rule they were designed against. */
* {{ * {{
font-family: "{font_family}", sans-serif; font-family: "{font_family}", sans-serif;
}}
window,
tooltip {{
font-size: {font_size}px; font-size: {font_size}px;
}} }}
/* Bar styling */ window:not(#sims) * {{
#sims-inner {{
padding: 4px;
border-bottom: solid 2px;
border-color: #{colors["base02"]};
background-color: #{colors["base00"]};
border-radius: 0;
transition: border-radius 200ms ease;
}}
#sims-inner.rounded-bottom {{
border-radius: 0 0 28px 28px;
}}
#center-container {{
color: #{colors["base05"]};
}}
.active-window {{
color: #{colors["base05"]};
font-weight: bold;
}}
/* Battery */
#battery-widget {{
background-color: #{colors["base01"]};
padding: 4px 8px;
border-radius: 12px;
}}
#bat-icon {{
color: #{colors["base0D"]};
margin-right: 2px;
}}
#bat-label {{
color: #{colors["base05"]};
font-size: {font_size}px; font-size: {font_size}px;
}} }}
#bat-label.battery-low {{ /* Bar widgets are styled purely in the static styles/ css through the palette
color: #{colors["base08"]}; above (see styles/colors.css for the semantic tokens). */
font-weight: bold;
}}
/* Progress bars */
#cpu-progress-bar,
#ram-progress-bar,
#volume-progress-bar {{
color: transparent;
background-color: transparent;
}}
#cpu-progress-bar {{
border: solid 0px alpha(#{colors["base0E"]}, 0.8);
}}
#ram-progress-bar,
#volume-progress-bar {{
border: solid 0px #{colors["base0D"]};
}}
/* Widgets container */
#widgets-container {{
background-color: #{colors["base01"]};
padding: 2px;
border-radius: 16px;
}}
/* NixOS label */
#nixos-label {{
color: #{colors["base0D"]};
font-size: 20px;
}}
/* CPU/RAM pies: the RAM pie (underneath) draws a faint full-circle track in
`color` so the usage wedge reads as a pie instead of a stray triangle; the
CPU pie on top keeps a transparent track. */
#ram-progress-bar {{
color: alpha(#{colors["base03"]}, 0.4);
}}
/* System tray: match the other bar pills */
#system-tray {{
background-color: #{colors["base01"]};
padding: 2px 6px;
border-radius: 12px;
}}
/* Org / notmuch pills */
#org-widget,
#notmuch-widget {{
background-color: #{colors["base01"]};
}}
#org-widget:hover,
#notmuch-widget:hover {{
background-color: #{colors["base02"]};
}}
{accent_pill_css(colors)}
/* Date time */
#date-time {{
color: #{colors["base05"]};
background-color: #{colors["base01"]};
padding: 4px 8px;
border-radius: 12px;
}}
#date-time-button {{
background: transparent;
border: none;
padding: 0;
margin: 0;
box-shadow: none;
}}
/* Generic popup styling */ /* Generic popup styling */
.popup-window, .popup-window,
@@ -370,92 +216,6 @@ def generate_stylix_css(mode: str | None = None) -> str | None:
opacity: 0.8; opacity: 0.8;
}} }}
/* Tooltips */
tooltip {{
border: solid 2px;
border-color: #{colors["base02"]};
background-color: #{colors["base00"]};
color: #{colors["base05"]};
border-radius: 16px;
}}
tooltip>* {{
padding: 2px 4px;
}}
/* Workspaces */
#workspaces {{
background-color: #{colors["base01"]};
padding: 6px 6px;
border-radius: 16px;
}}
#workspaces>button {{
background-color: #{colors["base05"]};
}}
#workspaces>button.empty:not(.active):not(.visible) {{
background-color: #{colors["base03"]};
}}
#workspaces>button.visible:not(.active) {{
background-color: #{colors["base0E"]};
}}
#workspaces>button.active {{
background-color: #{colors["base0D"]};
}}
#workspaces>button.urgent {{
background-color: #{colors["base08"]};
}}
/* Workspace shown on a different monitor than this bar — dim it. */
#workspaces>button.foreign {{
opacity: 0.45;
}}
#workspaces>button>label {{
font-size: 0px;
}}
/* Compact MPRIS player */
#player-small {{
background-color: #{colors["base01"]};
padding: 6px;
border-radius: 100px;
}}
#compact-mpris-icon,
#compact-mpris-button {{
background: transparent;
border: none;
padding: 0 4px;
margin: 0;
box-shadow: none;
min-height: 0;
min-width: 0;
}}
#compact-mpris-button-icon,
#compact-mpris-fallback {{
color: #{colors["base05"]};
}}
#compact-mpris-button:hover #compact-mpris-button-icon {{
color: #{colors["base0D"]};
}}
#compact-mpris-fallback {{
opacity: 0.7;
}}
#compact-mpris-label {{
color: #{colors["base05"]};
font-size: {font_size}px;
margin: 0 6px;
}}
/* Quick Menu styling */ /* Quick Menu styling */
#quick-menu-container {{ #quick-menu-container {{
background-color: #{colors["base00"]}; background-color: #{colors["base00"]};
+150 -81
View File
@@ -1,8 +1,18 @@
/* ------------------------------------------------------------------------
Bar shell
One visual language for every module:
- "chips": --surface fill, same height (bar height minus the 6px
vertical padding below), fully rounded, 10px side padding.
- a single accent color for "this is active" (workspace, play state),
tinted chips for "needs attention", solid fill only for alarms.
- text is foreground / --text-muted, icons are 16px.
------------------------------------------------------------------------ */
#sims-inner { #sims-inner {
padding: 4px; padding: 6px 12px;
border-bottom: solid 2px;
border-color: var(--border-color);
background-color: var(--window-bg); background-color: var(--window-bg);
border-bottom: solid 1px var(--hairline);
border-radius: 0; border-radius: 0;
transition: border-radius 200ms ease; transition: border-radius 200ms ease;
} }
@@ -11,19 +21,31 @@
border-radius: 0 0 28px 28px; border-radius: 0 0 28px 28px;
} }
#center-container { /* Shared chip look (workspaces.css applies the same to #workspaces) */
color: var(--foreground); #player-small,
#widgets-container,
#org-widget,
#notmuch-widget,
#date-time {
min-height: 28px;
padding: 0 10px;
border-radius: 14px;
background-color: var(--surface);
transition: background-color 150ms ease;
} }
.active-window { #org-widget:hover,
color: var(--foreground); #notmuch-widget:hover,
font-weight: bold; #date-time-button:hover #date-time {
background-color: var(--surface-hover);
} }
#battery-widget { /* ---- left ------------------------------------------------------------- */
background-color: var(--module-bg);
padding: 4px 8px; #nixos-label {
border-radius: 4px; color: var(--accent);
font-size: 18px;
padding: 0 6px 0 2px;
} }
#buddy-container, #buddy-container,
@@ -34,125 +56,172 @@
#buddy-button { #buddy-button {
padding: 0; padding: 0;
margin: 0 2px; margin: 0 2px;
background: transparent;
border: none;
} }
#bat-icon { /* Compact player chip: circular cover hugging the left edge */
color: var(--blue); #player-small {
margin-right: 2px; padding: 0 6px 0 3px;
} }
#bat-label { #compact-mpris-icon,
#compact-mpris-button {
padding: 0;
margin: 0;
min-height: 0;
min-width: 0;
}
#compact-mpris-label {
color: var(--foreground); color: var(--foreground);
font-size: 14px; font-weight: 500;
margin: 0 8px;
} }
#bat-label.battery-low { #compact-mpris-fallback {
color: var(--red); color: var(--text-muted);
font-weight: bold; margin: 0 3px;
} }
#microphone-icon { #compact-mpris-button-icon {
color: var(--foreground); color: var(--text-muted);
font-size: 20px; transition: color 150ms ease;
}
#compact-mpris-button:hover #compact-mpris-button-icon {
color: var(--accent);
}
/* ---- center ----------------------------------------------------------- */
#active-window,
.active-window {
color: var(--text-muted);
font-weight: 500;
}
/* ---- right ------------------------------------------------------------ */
/* System cluster: mic, cpu/ram rings, tray, battery in one chip */
#widgets-container {
padding: 0 8px;
} }
#microphone-button { #microphone-button {
min-width: 28px; padding: 0 4px;
padding: 0 6px; border-radius: 10px;
}
#microphone-icon {
color: var(--text-muted);
font-size: 16px;
}
#microphone-button:hover #microphone-icon {
color: var(--foreground);
} }
#microphone-icon.muted { #microphone-icon.muted {
color: var(--red); color: var(--red);
} }
#cpu-progress-bar, /* CPU / RAM "activity rings": outer ring = RAM, inner ring = CPU.
CircularProgressBar draws its track with `color` and progress with
`border-color`; the border *width* must stay 0 or it inflates the line. */
#system-stats {
padding: 0 4px;
}
#ram-progress-bar, #ram-progress-bar,
#volume-progress-bar { #cpu-progress-bar {
color: transparent; background-color: transparent;
background-color: transparent color: alpha(var(--foreground), 0.12);
border: solid 0 transparent;
}
#ram-progress-bar {
border-color: var(--accent);
} }
#cpu-progress-bar { #cpu-progress-bar {
border: solid 0px alpha(var(--violet), 0.8); border-color: var(--violet);
} }
#ram-progress-bar, #system-tray {
#volume-progress-bar { padding: 0 2px;
border: solid 0px var(--blue);
} }
#widgets-container { #system-tray > button {
background-color: var(--module-bg); padding: 0 3px;
padding: 2px; border-radius: 8px;
} }
#player-small { #system-tray > button:hover {
background-color: var(--module-bg); background-color: var(--surface-hover);
padding: 6px;
border-radius: 100px;
} }
#compact-mpris-icon, #battery-widget {
#compact-mpris-button { padding: 0 2px 0 4px;
background: transparent;
border: none;
padding: 0 4px;
margin: 0;
box-shadow: none;
min-height: 0;
min-width: 0;
} }
#compact-mpris-button-icon { #bat-icon {
color: var(--text-muted);
}
#bat-label {
color: var(--foreground); color: var(--foreground);
font-feature-settings: "tnum";
} }
#compact-mpris-button:hover #compact-mpris-button-icon { #bat-icon.battery-low,
color: var(--blue); #bat-label.battery-low {
} color: var(--red);
font-weight: bold;
#compact-mpris-fallback {
color: var(--foreground);
opacity: 0.7;
}
#compact-mpris-label {
color: var(--foreground);
font-size: 13px;
}
#nixos-label {
color: var(--blue);
font-size: 20px;
margin: 0 2px 0 4px;
} }
/* Screen-share indicator: a bare red dot, only visible while sharing */
#capture-widget { #capture-widget {
background: transparent;
border: none;
padding: 0 6px; padding: 0 6px;
margin: 0; margin: 0;
box-shadow: none;
} }
#capture-dot { #capture-dot {
color: var(--red); color: var(--red);
font-size: 14px; font-size: 12px;
} }
#capture-summary { #capture-summary {
font-size: 12px; color: var(--text-muted);
margin-right: 6px; margin-right: 6px;
} }
tooltip { /* Clock: bold time, muted date */
border: solid 2px; #date-time-button {
border-color: var(--border-color); padding: 0;
background-color: var(--window-bg); margin: 0;
} }
tooltip>* { #date-time {
padding: 2px 4px padding: 0 12px;
}
#clock-time {
font-weight: bold;
font-feature-settings: "tnum";
}
#clock-date {
color: var(--text-muted);
font-feature-settings: "tnum";
}
/* ---- tooltips --------------------------------------------------------- */
tooltip {
background-color: var(--window-bg);
border: solid 1px var(--hairline);
border-radius: 10px;
}
tooltip > * {
padding: 4px 8px;
} }
-16
View File
@@ -1,21 +1,5 @@
/* Calendar widget styling */ /* Calendar widget styling */
/* Date time button */
#date-time-button {
background: transparent;
border: none;
padding: 0;
margin: 0;
box-shadow: none;
}
#date-time {
color: var(--foreground);
background-color: var(--module-bg);
padding: 4px 8px;
border-radius: 12px;
}
/* Calendar event items */ /* Calendar event items */
.event-item { .event-item {
border-radius: 8px; border-radius: 8px;
+17 -6
View File
@@ -17,13 +17,24 @@
--violet: #AD60FF; --violet: #AD60FF;
--red: #FC3F2C; --red: #FC3F2C;
--window-bg: alpha(var(--background), 0.9); /* Semantic tokens. Surfaces/text are derived from --foreground so they
work on both dark and light palettes (stylix redefines the base
colors at runtime and these follow). */
--accent: var(--blue);
--surface: alpha(var(--foreground), 0.06);
--surface-hover: alpha(var(--foreground), 0.11);
--surface-active: alpha(var(--foreground), 0.16);
--hairline: alpha(var(--foreground), 0.08);
--text-muted: alpha(var(--foreground), 0.62);
--text-faint: alpha(var(--foreground), 0.38);
--window-bg: alpha(var(--background), 0.94);
--module-bg: alpha(var(--mid-bg), 0.8); --module-bg: alpha(var(--mid-bg), 0.8);
--border-color: var(--light-bg); --border-color: var(--light-bg);
--ws-active: var(--blue); --ws-active: var(--accent);
--ws-visible: var(--violet); --ws-visible: alpha(var(--accent), 0.5);
--ws-inactive: var(--light-grey); --ws-inactive: alpha(var(--foreground), 0.55);
--ws-empty: var(--dark-grey); --ws-empty: alpha(var(--foreground), 0.18);
--ws-hover: var(--turquoise); --ws-hover: alpha(var(--foreground), 0.85);
--ws-urgent: var(--red); --ws-urgent: var(--red);
} }
+7 -1
View File
@@ -11,10 +11,16 @@
@import url("./media.css"); @import url("./media.css");
/* unset so we can style everything from the ground up. */ /* unset so we can style everything from the ground up. `all: unset`
makes font-size/font-family inherit, so the base font is set once on the
toplevels and any widget rule (e.g. icon sizes) can still override it. */
* { * {
all: unset; all: unset;
color: var(--foreground); color: var(--foreground);
}
window,
tooltip {
font-size: 16px; font-size: 16px;
font-family: "Jost*", sans-serif; font-family: "Jost*", sans-serif;
} }
+19 -27
View File
@@ -1,38 +1,30 @@
#date-time, /* Context menus (system tray) */
menu>menuitem>label,
#date-time>label,
/* system tray */
#system-tray {
padding: 2px 4px;
background-color: var(--module-bg);
}
/* menu and menu items (written for the system tray) */
menu { menu {
border: solid 2px; padding: 4px;
border-radius: 10px; border: solid 1px var(--hairline);
border-color: var(--border-color); border-radius: 12px;
background-color: var(--window-bg); background-color: var(--window-bg);
} }
menu>menuitem { menu > menuitem {
border-radius: 0px; padding: 6px 10px;
background-color: var(--module-bg); border-radius: 8px;
padding: 6px;
margin-left: 2px;
margin-right: 2px;
} }
menu>menuitem:first-child { menu > menuitem:hover {
margin-top: 1px; background-color: alpha(var(--accent), 0.18);
border-radius: 8px 8px 0px 0px;
} }
menu>menuitem:last-child { menu > menuitem:hover > label {
margin-bottom: 1px; color: var(--accent);
border-radius: 0px 0px 8px 8px;
} }
menu>menuitem:hover { menu > menuitem:disabled > label {
background-color: var(--pink); color: var(--text-faint);
}
menu > separator {
min-height: 1px;
margin: 4px 6px;
background-color: var(--hairline);
} }
+24 -27
View File
@@ -1,34 +1,42 @@
/* Notmuch email widget styling */ /* Notmuch unread badge. Base chip look lives in bar.css.
Calm by default; tinted when there is unread mail, solid red only when
the email debt timer is in alarm. */
#notmuch-widget { #notmuch-icon {
background-color: var(--module-bg); color: var(--text-muted);
padding: 4px 8px;
border-radius: 12px;
transition: background-color 0.2s ease;
} }
#notmuch-widget:hover { #unread-count {
background-color: var(--light-bg); color: var(--foreground);
font-weight: bold;
font-feature-settings: "tnum";
min-width: 16px;
} }
#notmuch-widget.has-unread { #notmuch-widget.has-unread {
background-color: var(--blue); background-color: alpha(var(--accent), 0.18);
} }
#notmuch-widget.has-unread:hover { #notmuch-widget.has-unread:hover {
background-color: var(--turquoise); background-color: alpha(var(--accent), 0.28);
} }
#notmuch-widget.no-unread { #notmuch-widget.has-unread #notmuch-icon,
background-color: var(--module-bg); #notmuch-widget.has-unread #unread-count {
color: var(--accent);
} }
#notmuch-widget.debt-warn { #notmuch-widget.debt-warn {
background-color: var(--orange); background-color: alpha(var(--orange), 0.2);
} }
#notmuch-widget.debt-warn:hover { #notmuch-widget.debt-warn:hover {
background-color: var(--gold); background-color: alpha(var(--orange), 0.3);
}
#notmuch-widget.debt-warn #notmuch-icon,
#notmuch-widget.debt-warn #unread-count {
color: var(--orange);
} }
#notmuch-widget.debt-alarm { #notmuch-widget.debt-alarm {
@@ -36,21 +44,10 @@
} }
#notmuch-widget.debt-alarm:hover { #notmuch-widget.debt-alarm:hover {
background-color: var(--pink); background-color: shade(var(--red), 1.1);
} }
#unread-count {
color: var(--foreground);
font-size: 14px;
font-weight: bold;
min-width: 16px;
}
#notmuch-widget.has-unread #notmuch-icon,
#notmuch-widget.has-unread #unread-count,
#notmuch-widget.debt-warn #notmuch-icon,
#notmuch-widget.debt-warn #unread-count,
#notmuch-widget.debt-alarm #notmuch-icon, #notmuch-widget.debt-alarm #notmuch-icon,
#notmuch-widget.debt-alarm #unread-count { #notmuch-widget.debt-alarm #unread-count {
color: var(--background); color: var(--background);
} }
+22 -27
View File
@@ -1,48 +1,43 @@
/* Org-agenda bar widget + dropdown */ /* Org-agenda bar widget + dropdown. Base chip look lives in bar.css. */
#org-widget { #org-icon {
background-color: var(--module-bg); color: var(--text-muted);
padding: 4px 8px;
border-radius: 12px;
transition: background-color 0.2s ease;
} }
#org-widget:hover { #org-count {
background-color: var(--light-bg); font-weight: bold;
font-feature-settings: "tnum";
min-width: 16px;
} }
#org-widget.empty { #org-widget.empty {
background-color: var(--module-bg);
opacity: 0.6; opacity: 0.6;
} }
#org-widget.has-next { #org-widget.has-next {
background-color: var(--blue); background-color: alpha(var(--accent), 0.18);
} }
#org-widget.has-next:hover { #org-widget.has-next:hover {
background-color: var(--turquoise); background-color: alpha(var(--accent), 0.28);
}
#org-widget.has-in-progress {
background-color: var(--violet);
}
#org-widget.has-in-progress.has-next {
background-color: var(--turquoise);
}
#org-count {
font-size: 14px;
font-weight: bold;
min-width: 16px;
} }
#org-widget.has-next #org-icon, #org-widget.has-next #org-icon,
#org-widget.has-next #org-count, #org-widget.has-next #org-count {
color: var(--accent);
}
#org-widget.has-in-progress {
background-color: alpha(var(--violet), 0.2);
}
#org-widget.has-in-progress:hover {
background-color: alpha(var(--violet), 0.3);
}
#org-widget.has-in-progress #org-icon, #org-widget.has-in-progress #org-icon,
#org-widget.has-in-progress #org-count { #org-widget.has-in-progress #org-count {
color: var(--background); color: var(--violet);
} }
/* Dropdown */ /* Dropdown */
+25 -21
View File
@@ -1,50 +1,54 @@
/* Workspace rail: small dots, the focused one stretches into an accent pill.
The chip is 28px tall; 10px vertical padding leaves 8px dots. */
#workspaces { #workspaces {
padding: 6px; min-height: 8px;
min-width: 0px; padding: 10px 12px;
background-color: var(--module-bg); border-radius: 14px;
background-color: var(--surface);
} }
#workspaces>button { #workspaces > button {
padding: 8px; min-width: 8px;
transition: padding 0.05s steps(8), background-color 0.15s ease; min-height: 8px;
border-radius: 99px;
background-color: var(--ws-inactive); background-color: var(--ws-inactive);
border-radius: 100px; transition: min-width 200ms cubic-bezier(0.4, 0, 0.2, 1),
background-color 150ms ease;
} }
#workspaces>button>label { #workspaces > button > label {
font-size: 0px; font-size: 0px;
} }
#workspaces>button:hover { #workspaces > button.empty {
background-color: var(--ws-hover);
}
#workspaces>button.empty {
background-color: var(--ws-empty); background-color: var(--ws-empty);
} }
#workspaces>button.visible { #workspaces > button.visible {
background-color: var(--ws-visible); background-color: var(--ws-visible);
} }
#workspaces>button.active { #workspaces > button:hover {
padding: 8px 32px; background-color: var(--ws-hover);
}
#workspaces > button.active {
min-width: 24px;
background-color: var(--ws-active); background-color: var(--ws-active);
} }
#workspaces>button.urgent { #workspaces > button.urgent {
background-color: var(--ws-urgent); background-color: var(--ws-urgent);
color: var(--foreground);
font-weight: bold;
animation: urgent-blink 1s infinite; animation: urgent-blink 1s infinite;
} }
#workspaces>button.foreign { /* Workspace shown on a different monitor than this bar */
#workspaces > button.foreign {
opacity: 0.45; opacity: 0.45;
} }
@keyframes urgent-blink { @keyframes urgent-blink {
0% { opacity: 1.0; } 0% { opacity: 1.0; }
50% { opacity: 0.5; } 50% { opacity: 0.4; }
100% { opacity: 1.0; } 100% { opacity: 1.0; }
} }