bar: implement glass-workbench's three module variants (Phase 5)
Wires modules.workspaces.style/modules.clock.style into the bar for real (Phase 3 shipped the schema but only ever consumed trail/flip), and adds cpu/ram as bar modules, so glass-workbench (bread-theme) renders correctly while liquid-motion's default path is untouched: - workspaces: "pill" never calls WorkspaceTrail::place/stretch (the trail overlay stays invisible) and honours modules.workspaces.show_empty for real, rendering unoccupied non-active workspaces dimmed via CSS instead of filtering them out of the row. "trail" keeps the exact pre-existing filter/place/stretch behaviour regardless of show_empty. - clock: "plain" registers a plain date+time label (date_lbl, built but never parented until now, plus a new clock_plain_lbl) instead of the per-digit flip box. "flip" is untouched. - cpu/ram: two new bar chips (bar_cpu_pair/bar_ram_pair, bar_cpu_lbl/ bar_ram_lbl) fed by the same AppInput::StatsUpdate data as the control panel's cpu_pair/mem_pair. Separate instances rather than reparenting the panel's own pair — a GTK widget can only have one parent, and reparenting would pull them out of the control panel's sys-grid, which no theme asked to change. theme.rs::load_css() now branches on tokens.bar_border() (full-border island vs. flush bar's bottom-only hairline) and modules.workspaces.style (dimmed/translucent trail-fill buttons vs. solid-accent-fill pills), and unconditionally gains .clock-plain/.clock-plain-time rules. The trail/flip branches reproduce today's CSS byte-for-byte. Verification (bread-capture, isolated headless-Sway harness): - Noise floor: same baseline binary against itself varies from AE=0 (same capture minute) up to ~1900px (an in-flight digit-flip/clock-tick or a live Wi-Fi scan straddling two captures) and ~39000px on control-panel (live hardware sensors) — all pre-existing, not introduced by this change. - Regression: this binary vs. the pre-Phase-5 baseline, captured in the same clock-minute to remove the dominant noise source, is AE=0 (bit-for- bit identical) on the bar view under the default liquid-motion theme. - glass-workbench (BREAD_SHELL_THEME=glass-workbench): bar view is 1920x36 (flush, no margin) vs. liquid-motion's 1920x56 (12px margin + 44px island), square corners vs. liquid-motion's rounded island, plain "Mon 24/08 23:24" clock, and cpu/ram/wifi/battery/control chips with no media widget — matches demo 02. The isolated Sway capture harness has no live Hyprland IPC, so it reports zero workspaces under both themes (pre-existing, unrelated to this change) — the pill fill/dim CSS itself is exercised by code review and the trail-untouched regression result, not by a captured pixel with visible buttons. cargo test: 18/18 passing (breadbar), no new clippy/cargo-check warnings beyond the two pre-existing ones this task named up front.
This commit is contained in:
parent
8d80a05d9b
commit
df6b568cc1
3 changed files with 213 additions and 28 deletions
85
src/theme.rs
85
src/theme.rs
|
|
@ -69,6 +69,66 @@ fn load_css() -> String {
|
|||
let spring = tokens.spring();
|
||||
let spring_settle = tokens.spring_settle();
|
||||
|
||||
// `tokens.bar_border()` (plan §11 Phase 5): "full" (default, liquid-
|
||||
// motion's floating island) draws a border on all four edges; "bottom"
|
||||
// (glass-workbench's flush edge-to-edge bar) draws only the hairline
|
||||
// the demo's `.bar { border-bottom: 1px solid #ffffff12 }` calls for —
|
||||
// a full border on a bar flush against the screen's top/left/right
|
||||
// edges would otherwise show as a stray line along those edges an
|
||||
// island never has to worry about. Reused below for the centerbox's
|
||||
// horizontal padding too: the flush bar's demo padding (`0 12px`,
|
||||
// symmetric) differs from the island's own asymmetric `0 8px 0 6px`.
|
||||
let flush = tokens.bar_border() == "bottom";
|
||||
let window_border = if flush {
|
||||
"border: none; border-bottom: 1px solid alpha(@on-bg, 0.07);".to_string()
|
||||
} else {
|
||||
"border: 1px solid alpha(@on-bg, 0.08);".to_string()
|
||||
};
|
||||
let centerbox_padding = if flush { "0 12px" } else { "0 8px 0 6px" };
|
||||
|
||||
// `modules.workspaces.style` (plan §11 Phase 5): "trail" (default,
|
||||
// liquid-motion) is exactly today's CSS, unchanged byte-for-byte —
|
||||
// dimmed/translucent buttons with the gradient trail overlay supplying
|
||||
// the active fill. "pill"/"dots" (glass-workbench, Phase 6+) render the
|
||||
// active state as a solid accent fill on the button itself instead,
|
||||
// since neither style ever calls `WorkspaceTrail::place`/`stretch`
|
||||
// (see `App::rebuild_buttons`) — the trail's own `.workspace-trail`
|
||||
// pill CSS is therefore irrelevant for them (it's never made visible).
|
||||
let workspace_css = match theme.modules().workspaces.style {
|
||||
bread_theme::shell::WorkspaceStyle::Trail => format!(
|
||||
".workspace-trail {{ background-image: linear-gradient(90deg, @accent, @teal);\
|
||||
background-color: @accent; border-radius: 12px; }}\
|
||||
.workspace-btn {{ background: transparent; opacity: 0.36; color: @on-bg;\
|
||||
border-radius: 12px; border: none; outline: none; box-shadow: none;\
|
||||
min-width: 28px; min-height: 28px; margin: 0; padding: 0 7px;\
|
||||
font-size: 22px; font-weight: bold;\
|
||||
transition: opacity 0.22s {spring_settle},\
|
||||
background-color 0.22s {spring_settle}; }}\
|
||||
.workspace-btn:hover {{ opacity: 0.85; background: alpha(@on-bg, 0.08); }}\
|
||||
.workspace-btn.occupied {{ opacity: 0.78; }}\
|
||||
.workspace-btn.active {{ background: transparent; color: @on-accent; opacity: 1; }}\
|
||||
.workspace-btn.active:hover {{ background: transparent; }}\
|
||||
.workspace-btn.ws-in {{ animation: row-in 0.32s {spring_settle} both; }}",
|
||||
),
|
||||
_ => {
|
||||
let accent = theme.tokens().accent_from();
|
||||
format!(
|
||||
".workspace-btn {{ background: transparent; opacity: 1; color: alpha(@on-bg, 0.4);\
|
||||
border-radius: {radius_sm}; border: none; outline: none; box-shadow: none;\
|
||||
min-width: 22px; min-height: 20px; margin: 0; padding: 0 6px;\
|
||||
font-size: 12px; font-weight: 600;\
|
||||
transition: background-color 0.22s {spring_settle},\
|
||||
color 0.22s {spring_settle}, opacity 0.22s {spring_settle}; }}\
|
||||
.workspace-btn:hover {{ background: alpha(@on-bg, 0.08); }}\
|
||||
.workspace-btn.occupied {{ color: alpha(@on-bg, 0.8); }}\
|
||||
.workspace-btn:not(.occupied):not(.active) {{ opacity: 0.35; }}\
|
||||
.workspace-btn.active {{ background: @{accent}; color: @on-accent; opacity: 1; }}\
|
||||
.workspace-btn.active:hover {{ background: @{accent}; }}\
|
||||
.workspace-btn.ws-in {{ animation: row-in 0.32s {spring_settle} both; }}",
|
||||
)
|
||||
}
|
||||
};
|
||||
|
||||
format!(
|
||||
"@keyframes notif-in {{ from {{ opacity: 0; margin-right: -16px; }} }}\
|
||||
@keyframes osd-in {{ from {{ opacity: 0; margin-bottom: -8px; }} }}\
|
||||
|
|
@ -79,22 +139,10 @@ fn load_css() -> String {
|
|||
@keyframes digit-flip {{ from {{ opacity: 0; margin-top: 7px; }} to {{ opacity: 1; margin-top: 0; }} }}\
|
||||
@keyframes caret-draw {{ from {{ margin-right: 200px; opacity: 0.2; }} to {{ margin-right: 4px; opacity: 1; }} }}\
|
||||
window.breadbar {{ background-color: alpha(@bg, 0.72); color: @on-bg;\
|
||||
border-radius: {radius_bar}; border: 1px solid alpha(@on-bg, 0.08); }}\
|
||||
window.breadbar > centerbox {{ padding: 0 8px 0 6px; }}\
|
||||
border-radius: {radius_bar}; {window_border} }}\
|
||||
window.breadbar > centerbox {{ padding: {centerbox_padding}; }}\
|
||||
window.breadbar button {{ min-height: 0; min-width: 0; }}\
|
||||
.workspace-trail {{ background-image: linear-gradient(90deg, @accent, @teal);\
|
||||
background-color: @accent; border-radius: 12px; }}\
|
||||
.workspace-btn {{ background: transparent; opacity: 0.36; color: @on-bg;\
|
||||
border-radius: 12px; border: none; outline: none; box-shadow: none;\
|
||||
min-width: 28px; min-height: 28px; margin: 0; padding: 0 7px;\
|
||||
font-size: 22px; font-weight: bold;\
|
||||
transition: opacity 0.22s {spring_settle},\
|
||||
background-color 0.22s {spring_settle}; }}\
|
||||
.workspace-btn:hover {{ opacity: 0.85; background: alpha(@on-bg, 0.08); }}\
|
||||
.workspace-btn.occupied {{ opacity: 0.78; }}\
|
||||
.workspace-btn.active {{ background: transparent; color: @on-accent; opacity: 1; }}\
|
||||
.workspace-btn.active:hover {{ background: transparent; }}\
|
||||
.workspace-btn.ws-in {{ animation: row-in 0.32s {spring_settle} both; }}\
|
||||
{workspace_css}\
|
||||
.clock-box {{ padding: 0 4px; }}\
|
||||
.clock-label {{ font-size: 24px; font-weight: bold; letter-spacing: 0.04em;\
|
||||
min-height: 0; padding: 0; margin-top: 3px; }}\
|
||||
|
|
@ -102,7 +150,9 @@ fn load_css() -> String {
|
|||
min-width: 15px; min-height: 0; padding: 0; margin: 0; }}\
|
||||
.clock-colon {{ min-width: 10px; opacity: 0.7; }}\
|
||||
.clock-digit.flip {{ animation: digit-flip 0.45s {spring} both; }}\
|
||||
.date-label {{ font-size: 14px; opacity: 0.52; letter-spacing: 0.04em; }}\
|
||||
.clock-plain {{ padding: 0 4px; }}\
|
||||
.clock-plain-time {{ font-size: 15px; font-weight: 600; letter-spacing: 0.04em; }}\
|
||||
.date-label {{ font-size: 12px; opacity: 0.48; letter-spacing: 0.04em; }}\
|
||||
.stat-label {{ font-size: 14px; letter-spacing: 0.02em; opacity: 0.92; }}\
|
||||
.stat-label.tick {{ animation: digit-flip 0.35s {spring} both; }}\
|
||||
.stats-box {{ margin-right: 0; }}\
|
||||
|
|
@ -321,6 +371,9 @@ fn load_css() -> String {
|
|||
pad = pad,
|
||||
spring = spring,
|
||||
spring_settle = spring_settle,
|
||||
window_border = window_border,
|
||||
centerbox_padding = centerbox_padding,
|
||||
workspace_css = workspace_css,
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue