Files
claude-code-usage-bubble/ui/bubble.css
T
tiennm99 094b6bdcb0 feat: draw the bubble from the payload in HTML, CSS and SVG
The stadium pill holds SVG usage and time rings, pill-shaped tail bars and
the payload's texts, laid out in physical px from canvasW, canvasH and dpi
with the GDI bubble's formulas (ui/layout.js, unit-tested). The palette is
CSS custom properties per theme; fills come from Rust. The ring arc, weekly
fill and weekly percent pulse at 95% and above on an 80 ms step, and the
time progress advances every minute.

Only the pill takes pointer input, so the corners are dead. A press that
moves 3 physical px starts an OS drag after arming the move end; an earlier
release is a click. Right-click opens the native menu and Ctrl+wheel resizes.
2026-10-21 14:40:18 +07:00

145 lines
2.0 KiB
CSS

/* Bubble palette. Accent and fill colours come from the payload. */
:root[data-theme='dark'] {
--bg: #1f1f1f;
--track: #2c2c2c;
--time-track: #404040;
--time-fill: #b0b0b0;
--text: #eaeaea;
--muted: #a8a8a8;
}
:root[data-theme='light'] {
--bg: #f3f3f3;
--track: #e2e2e2;
--time-track: #e0e0e0;
--time-fill: #666666;
--text: #1f1f1f;
--muted: #5e5e5e;
}
html,
body {
width: 100%;
height: 100%;
margin: 0;
overflow: hidden;
background: transparent;
user-select: none;
-webkit-user-select: none;
/* Only the pill takes input: the transparent stadium corners are dead. */
pointer-events: none;
}
.pill {
position: absolute;
inset: 0;
overflow: hidden;
border-radius: 9999px;
background: var(--bg);
font-family: 'Segoe UI', system-ui, sans-serif;
cursor: move;
pointer-events: auto;
}
/* Every pointer event targets the pill itself, whose hit area follows its
rounded outline. */
.pill * {
pointer-events: none;
}
.rings {
position: absolute;
inset: 0;
width: 100%;
height: 100%;
}
.rings circle {
fill: none;
}
.ring-track {
stroke: var(--track);
}
.time-ring-track {
stroke: var(--time-track);
}
.time-ring-arc {
stroke: var(--time-fill);
}
.ring-arc,
.time-ring-arc {
stroke-linecap: round;
}
.text {
position: absolute;
margin: 0;
white-space: nowrap;
color: var(--text);
}
.head-label {
font-weight: 600;
color: var(--muted);
text-align: center;
}
.head-pct {
font-weight: 700;
text-align: center;
}
.tail-pct,
.tail-time {
overflow: hidden;
text-align: right;
text-overflow: ellipsis;
}
.tail-pct {
font-weight: 600;
}
.tail-time {
font-weight: 400;
color: var(--muted);
}
.bar {
position: absolute;
overflow: hidden;
border-radius: 9999px;
}
.usage-bar {
background: var(--track);
}
.time-bar {
background: var(--time-track);
}
.fill {
position: absolute;
top: 0;
height: 100%;
border-radius: 9999px;
}
.usage-fill {
left: 0;
}
.time-fill {
right: 0;
background: var(--time-fill);
}
[hidden] {
display: none !important;
}