Dashboard Studio 1.14.0: new cards, kiosk announcements, guest mode, templates, sharing and phone app

- Seven new cards: parcels, air quality, water and gas usage, solar forecast, garage and gate, sports, Formula One
- Kiosk: announcements from automations, tab rotation, guest mode, click sound
- Editor: templates, widget presets, undo history, alignment guides, Lovelace import, share link and QR code, theme variants, suggestions, touch and hold actions
- Phones: installable app with shortcuts, offline states, tab swipe, pull to refresh, bottom sheets, haptics, phone/large visibility, landscape layout, editing on the phone, away tab
- Fixed: the weather forecast and to-do list could stay on Loading…

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-26 21:08:42 +01:00
parent 93bb42dcbb
commit 79d4a0f011
17 changed files with 2256 additions and 58 deletions
+31
View File
@@ -0,0 +1,31 @@
/* Dashboard Studio service worker: always the network first, so updates show straight away.
* When the network fails (or Home Assistant's ingress session has run out), it answers with
* the last good copy, so the app can start, show the last known states and reconnect. */
const CACHE = "ds-__VERSION__";
const SKIP = /\/(ws|api\/camera|api\/immich|api\/history)/;
self.addEventListener("install", () => self.skipWaiting());
self.addEventListener("activate", (e) => {
e.waitUntil(caches.keys().then((keys) => Promise.all(keys.filter((k) => k.startsWith("ds-") && k !== CACHE).map((k) => caches.delete(k)))).then(() => self.clients.claim()));
});
self.addEventListener("fetch", (e) => {
const req = e.request, url = new URL(req.url);
if (req.method !== "GET" || url.origin !== location.origin || SKIP.test(url.pathname)) return;
const page = req.mode === "navigate";
e.respondWith((async () => {
const cache = await caches.open(CACHE);
try {
const res = await fetch(req);
if (res.ok) {
cache.put(page ? new Request(new URL("./", self.registration.scope)) : req, res.clone());
return res;
}
if (!page) return res;
throw new Error(String(res.status));
} catch (err) {
const hit = page ? await cache.match(new URL("./", self.registration.scope).href) : await cache.match(req);
if (hit) return hit;
throw err;
}
})());
});