Dashboard Studio 1.8.0: vacuum card, clock position and background, light groups

- Vacuum card: status, battery, start/pause, dock, locate, suction
  power and an optional live map from a camera or image entity
- Clock: 3x3 text position picker and a background image from links or
  Immich albums (shared slideshow code with the Photos card), dimmable
- Light card lists the lights of a light group with their own switches;
  picking a group grows the card to fit

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-25 23:37:23 +01:00
parent 75ab27db10
commit e73c688017
7 changed files with 211 additions and 50 deletions
+37 -1
View File
@@ -268,6 +268,7 @@ textarea.input { resize: vertical; min-height: 76px; font-family: ui-monospace,
color: var(--lit-text);
--d-text-2: var(--lit-text-2);
--d-fill: rgba(61, 44, 10, 0.12);
--d-separator: rgba(61, 44, 10, 0.14);
}
.w.lit-lamp .badge { background: rgba(255, 255, 255, 0.55); color: var(--lit-text); }
.surface-plain .w.lit-lamp, .surface-outline .w.lit-lamp { background: transparent; color: var(--w-color, var(--d-text)); --d-text-2: var(--text-2); --d-fill: var(--fill); }
@@ -367,7 +368,7 @@ body.editing .w:hover .w-resize, body.editing .w.selected .w-resize { opacity: 1
.clock-wx-text { font-size: 14px; color: var(--d-text-2); }
.clock-hl { font-size: 14px; color: var(--d-text-2); }
.clock-hl:empty { display: none; }
@container (max-height: 150px) { .clock-wx-text, .clock-hl { display: none; } .clock-wx { margin-top: 6px; } }
@container (max-height: 175px) { .clock-wx-text, .clock-hl { display: none; } .clock-wx { margin-top: 6px; } }
.cam-btn { position: absolute; inset: 0; }
.cam { width: 100%; height: 100%; object-fit: cover; display: block; background: #000; }
@@ -549,6 +550,41 @@ body.kiosk #tabnav { top: 6px; max-height: calc(100vh - 20px); }
.child-open .i { font-size: 18px; flex: none; }
.child-item .btn.icon { width: 30px; min-width: 30px; flex: none; }
/* clock: text position and background image */
.clock { position: relative; }
.clock-content { position: relative; z-index: 1; display: flex; flex-direction: column; align-items: inherit; text-align: inherit; max-width: 100%; }
.clock-content .clock-time { align-items: inherit; }
.clock.pos-top-left, .clock.pos-top, .clock.pos-top-right { justify-content: flex-start; }
.clock.pos-bottom-left, .clock.pos-bottom, .clock.pos-bottom-right { justify-content: flex-end; }
.clock.pos-top-left, .clock.pos-left, .clock.pos-bottom-left { align-items: flex-start; text-align: left; }
.clock.pos-top-right, .clock.pos-right, .clock.pos-bottom-right { align-items: flex-end; text-align: right; }
.clock-bg { position: absolute; inset: 0; margin: -16px; z-index: 0; border-radius: inherit; }
.w.transparent .clock-bg, .surface-plain .clock-bg { margin: -6px -4px; }
.clock-dim { position: absolute; inset: 0; margin: -16px; z-index: 0; background: linear-gradient(to bottom, rgba(0, 0, 0, calc(var(--dim) * 0.8)), rgba(0, 0, 0, var(--dim))); }
.clock.on-image { color: #fff; --d-text-2: rgba(255, 255, 255, 0.86); text-shadow: 0 1px 12px rgba(0, 0, 0, 0.45); }
.clock.on-image .clock-wx { background: rgba(0, 0, 0, 0.32); backdrop-filter: blur(12px); -webkit-backdrop-filter: blur(12px); }
.pos9 { display: grid; grid-template-columns: repeat(3, 34px); gap: 4px; padding: 4px; background: var(--fill); border-radius: 10px; width: max-content; }
.pos9 button { width: 34px; height: 28px; border: 0; border-radius: 7px; background: transparent; cursor: pointer; display: grid; place-items: center; }
.pos9 button i { width: 8px; height: 8px; border-radius: 50%; background: var(--text-2); opacity: .4; }
.pos9 button[aria-pressed="true"] { background: var(--surface); box-shadow: 0 1px 3px rgba(0, 0, 0, 0.12); }
.pos9 button[aria-pressed="true"] i { width: 14px; height: 10px; border-radius: 3px; background: var(--accent); opacity: 1; }
/* light groups */
.light-members { flex: 1; min-height: 0; margin: 0 -6px; }
.light:has(.light-members) { justify-content: flex-start; }
/* vacuum */
.vac { display: flex; flex-direction: column; height: 100%; gap: 10px; }
.vac-batt { margin-left: auto; display: inline-flex; align-items: center; gap: 4px; font-size: 14px; font-weight: 600; color: var(--d-text-2); }
.vac-batt .i { font-size: 18px; }
.vac-map { flex: 1; min-height: 0; width: 100%; object-fit: contain; border-radius: 12px; background: var(--d-fill); }
.vac-spacer { flex: 1; }
.vac .ctrls { display: flex; gap: 8px; align-items: center; }
.vac .round:disabled { opacity: .35; cursor: default; }
.vac-hint { margin-left: 4px; }
.vac.is-error .state { color: var(--crit); font-weight: 600; }
@container (max-height: 220px) { .vac-map { display: none; } .vac-spacer { display: none; } }
/* photos */
.photos { position: absolute; inset: 0; background: #000; overflow: hidden; }
.ph-layer { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: var(--fit, cover); opacity: 0; transition: opacity 1.2s ease; }