From f1342b8a4102d9573fe1c2db75c3ca1fafa56f43 Mon Sep 17 00:00:00 2001 From: Archibold Date: Sat, 7 Nov 2026 19:21:58 +1100 Subject: [PATCH] Tint sidebar widget chips by origin; fix widgetSub host --- README.md | 3 ++- src/uwudash_mk3/static/app.js | 27 ++++++++++++++++++++++++--- src/uwudash_mk3/static/styles.css | 5 ++++- 3 files changed, 30 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 2ab336e..5d23813 100644 --- a/README.md +++ b/README.md @@ -276,7 +276,8 @@ in three kinds: next upcoming release that carries artwork also gets a full-width hero tile above the groups (its relayed thumb plus title and date), ringed in the same origin hue. Each widget gets its own sidebar button for a - single-widget view. + single-widget view, its left edge tinted with the same origin hue once the + widget has returned rows (an errored or empty widget stays accent-blue). - Writes are admin-only when OIDC is on, reads any session - same gate as services. diff --git a/src/uwudash_mk3/static/app.js b/src/uwudash_mk3/static/app.js index b3d4a8b..05c92ca 100644 --- a/src/uwudash_mk3/static/app.js +++ b/src/uwudash_mk3/static/app.js @@ -131,7 +131,8 @@ function renderSidebar() { } for (const widget of state.widgets) { const button = document.createElement("button"); - button.className = "widget-btn" + (state.selected === widget.id ? " active" : ""); + button.className = + "widget-btn" + widgetOriginClass(widget) + (state.selected === widget.id ? " active" : ""); button.title = widget.name; button.innerHTML = `${widgetIcon(widget)}` + @@ -161,8 +162,18 @@ function widgetSub(widget) { if (widget.kind === "notice") return (widget.body || "").slice(0, 60); const data = widget.data || {}; if (data.error) return `⚠ ${data.error.error}`; - const host = (widget.base_url || "").split("://", 1)[1]; - return `${(data.items || []).length} items · ${host}`; + // `split("://", 1)[1]` looked like Python but JS returns a one-element array, + // so the old code printed "undefined". URL() also keeps the port (`host`). + let host = ""; + if (widget.base_url) { + try { + host = new URL(widget.base_url).host; + } catch (TypeError) { + host = widget.base_url; + } + } + const count = (data.items || []).length; + return host ? `${count} item${count === 1 ? "" : "s"} · ${host}` : `${count} item${count === 1 ? "" : "s"}`; } function renderTable() { @@ -241,6 +252,16 @@ function originClass(item) { return ORIGIN_LABEL[item ? item.origin : null] ? ` origin-${item.origin}` : ""; } +// A widget's app is only knowable from the rows it returned (`calendar` covers +// both Sonarr and Radarr), so the first recognised origin wins; an errored or +// empty widget stays neutral. +function widgetOriginClass(widget) { + for (const row of (widget.data || {}).items || []) { + if (ORIGIN_LABEL[row.origin]) return ` origin-${row.origin}`; + } + return ""; +} + function releaseCard(item) { const thumb = item.thumb ? `${esc(item.label)}` diff --git a/src/uwudash_mk3/static/styles.css b/src/uwudash_mk3/static/styles.css index b216383..f51279a 100644 --- a/src/uwudash_mk3/static/styles.css +++ b/src/uwudash_mk3/static/styles.css @@ -373,7 +373,10 @@ body { /* origin tints: Sonarr teal, Radarr violet, Plex orange. The merged timeline mixes apps, so the card edge, the source chip and a legend chip in the group - header all carry the same hue. */ + header all carry the same hue; sidebar chips get it on their left edge too. */ +.widget-btn.origin-sonarr { border-left: 3px solid var(--origin-sonarr); } +.widget-btn.origin-radarr { border-left: 3px solid var(--origin-radarr); } +.widget-btn.origin-plex { border-left: 3px solid var(--origin-plex); } .release-card.origin-sonarr { border-left: 3px solid var(--origin-sonarr); } .release-card.origin-radarr { border-left: 3px solid var(--origin-radarr); } .release-card.origin-plex { border-left: 3px solid var(--origin-plex); }