diff options
| author | Danilo M. <danix@danix.xyz> | 2026-11-10 10:33:13 +0100 |
|---|---|---|
| committer | Danilo M. <danix@danix.xyz> | 2026-11-10 10:33:13 +0100 |
| commit | 6933aa3220ff420beeb883d25fc68b9c79aa7df1 (patch) | |
| tree | 0ca54434b4b8c8d0768d1d5165c2e00e33fde6ac /static/deck.css | |
| parent | 213a82118a7f5db58759edffe8d1776475e4e4e4 (diff) | |
| download | deck-it-6933aa3220ff420beeb883d25fc68b9c79aa7df1.tar.gz deck-it-6933aa3220ff420beeb883d25fc68b9c79aa7df1.zip | |
feat: K1C printer tab and proper cards for switched-off sources
A K1C tab follows a Klipper printer through Moonraker ([k1c] url):
state, file, progress with elapsed, left and finish time, layer, the
slicer's model thumbnail, nozzle and bed with target and power, fan,
speed, position, filament, and the camera snapshot. It is read-only bar
one action, the emergency stop (M112), behind a press-and-hold button so
a stray touch on an always-on tablet cannot kill a print. Klipper being
down (after a stop) shows its message in a red banner.
The printer is often off, so a failed poll backs off 10s instead of
costing every tick a timeout. File metadata is fetched once per job; the
slicer's estimate covers the start of a print until the file-position
estimate settles. The tablet loads the camera and the thumbnail straight
from the printer, so both need it on the printer's LAN.
OBS, the build VM and LLM usage showed raw text when their source was
off ("OBS offline: [Errno 111] ..."). They now share static/offline.js:
a greyed app icon, what is off, what brings it back, and a pulsing
"checking" note, with the raw error in the tooltip. OBS hides its empty
blocks while off. The card is not rebuilt on every poll.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Diffstat (limited to 'static/deck.css')
| -rw-r--r-- | static/deck.css | 119 |
1 files changed, 115 insertions, 4 deletions
diff --git a/static/deck.css b/static/deck.css index 2484e1b..f0a9fdc 100644 --- a/static/deck.css +++ b/static/deck.css @@ -447,11 +447,122 @@ select { .chan input[type=range] { flex: 1; min-width: 60px; accent-color: var(--udt-accent); } .chan-pct { flex: none; min-width: 40px; text-align: right; font-size: 0.857rem; } -.deck-offline { - flex: 1; +/* What a panel shows while the thing it watches is off (static/offline.js). */ +.offline { + height: 100%; + min-height: 140px; display: flex; + flex-direction: column; align-items: center; justify-content: center; - min-height: 120px; - color: var(--udt-subtext0); + gap: 4px; + padding: 16px; + text-align: center; +} +.off-icon { + width: 48px; + height: 48px; + margin-bottom: 6px; + filter: grayscale(1); + opacity: .45; +} +.off-title { font-size: 1.143rem; font-weight: 600; color: var(--udt-subtext1, var(--udt-text)); } +.off-detail { max-width: 32ch; font-size: 0.857rem; color: var(--udt-overlay0); } +.off-poll { + display: flex; + align-items: center; + gap: 6px; + margin-top: 8px; + font-size: 0.714rem; + text-transform: uppercase; + letter-spacing: .08em; + color: var(--udt-overlay0); +} +.off-poll i { + width: 6px; + height: 6px; + border-radius: 50%; + background: var(--udt-overlay0); + animation: off-pulse 2s ease-in-out infinite; +} +@keyframes off-pulse { 50% { opacity: .2; } } +@media (prefers-reduced-motion: reduce) { .off-poll i { animation: none; } } + +/* The K1C tab. */ +.k1c { display: flex; flex-direction: column; gap: 14px; padding: 4px 2px; } +.k1c-on { display: flex; flex-direction: column; gap: 14px; } +.k1c-on[hidden], .k1c-off[hidden] { display: none; } +.k1c-head { display: flex; align-items: center; gap: 12px; } +.k1c-state { + flex: none; + padding: 4px 12px; + border-radius: 999px; + background: var(--udt-surface1); + font-weight: 600; +} +.k1c-state.good { background: var(--udt-green); color: var(--udt-crust); } +.k1c-state.warn { background: var(--udt-yellow); color: var(--udt-crust); } +.k1c-state.bad { background: var(--udt-red); color: var(--udt-crust); } +.k1c-file { flex: 1; min-width: 0; font-size: 1.143rem; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } +.k1c-alert { + padding: 10px 14px; + border-radius: 12px; + border: 1px solid var(--udt-red); + color: var(--udt-red); } +.k1c-job { display: flex; align-items: center; gap: 16px; } +.k1c-thumb { + flex: none; + width: 120px; + height: 120px; + object-fit: contain; + padding: 6px; + border-radius: 14px; + background: var(--udt-surface0); + border: 1px solid var(--udt-surface1); +} +.k1c-thumb[hidden] { display: none; } +.k1c-progress { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 6px; } +.k1c-progress[hidden] { display: none; } +.k1c-pct { font-size: 2.571rem; font-weight: 600; line-height: 1; } +.k1c-progress .gbar { height: 10px; border-radius: 5px; } +.k1c-times { font-size: 0.857rem; color: var(--udt-subtext0); } +.k1c-body { display: grid; grid-template-columns: 1fr 1fr; gap: 14px; align-items: start; } +@media (max-width: 900px) { .k1c-body { grid-template-columns: 1fr; } } +.k1c-tiles { grid-template-columns: 1fr 1fr; } +.k1c-cam { width: 100%; border-radius: 12px; background: var(--udt-crust); } + +/* Press and hold: the fill grows across the button over --hold. */ +.estop { + flex: none; + position: relative; + overflow: hidden; + min-width: 150px; + min-height: 64px; + padding: 0 18px; + border: 2px solid var(--udt-red); + border-radius: 16px; + background: color-mix(in srgb, var(--udt-red) 22%, transparent); + color: var(--udt-text); + font: inherit; + font-weight: 700; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + touch-action: none; + cursor: pointer; +} +.estop::before { + content: ""; + position: absolute; + inset: 0; + background: var(--udt-red); + transform: scaleX(0); + transform-origin: left; +} +.estop.holding::before { transform: scaleX(1); transition: transform var(--hold, 800ms) linear; } +.estop.sent { background: var(--udt-red); color: var(--udt-crust); } +.estop > span { position: relative; } +.estop-label { font-size: 1.071rem; text-transform: uppercase; letter-spacing: .04em; } +.estop-hint { font-size: 0.714rem; font-weight: 400; opacity: .7; } |
