Tint sidebar widget chips by origin; fix widgetSub host

This commit is contained in:
Archibold committed 2026-11-07 19:21:58 +11:00
1 parent 4737891997
commit f1342b8a41
3 files changed
+30 -5

No files matched your search

+2 -1
View File
@@ -276,7 +276,8 @@ in three kinds:
next upcoming release that carries artwork also gets a full-width hero tile 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 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 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 - Writes are admin-only when OIDC is on, reads any session - same gate as
services. services.
+24 -3
View File
@@ -131,7 +131,8 @@ function renderSidebar() {
} }
for (const widget of state.widgets) { for (const widget of state.widgets) {
const button = document.createElement("button"); 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.title = widget.name;
button.innerHTML = button.innerHTML =
`<span class="icon">${widgetIcon(widget)}</span>` + `<span class="icon">${widgetIcon(widget)}</span>` +
@@ -161,8 +162,18 @@ function widgetSub(widget) {
if (widget.kind === "notice") return (widget.body || "").slice(0, 60); if (widget.kind === "notice") return (widget.body || "").slice(0, 60);
const data = widget.data || {}; const data = widget.data || {};
if (data.error) return `⚠ ${data.error.error}`; if (data.error) return `⚠ ${data.error.error}`;
const host = (widget.base_url || "").split("://", 1)[1]; // `split("://", 1)[1]` looked like Python but JS returns a one-element array,
return `${(data.items || []).length} items · ${host}`; // 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() { function renderTable() {
@@ -241,6 +252,16 @@ function originClass(item) {
return ORIGIN_LABEL[item ? item.origin : null] ? ` origin-${item.origin}` : ""; 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) { function releaseCard(item) {
const thumb = item.thumb const thumb = item.thumb
? `<img class="widget-thumb" src="${esc(item.thumb)}" alt="${esc(item.label)}" loading="lazy" />` ? `<img class="widget-thumb" src="${esc(item.thumb)}" alt="${esc(item.label)}" loading="lazy" />`
+4 -1
View File
@@ -373,7 +373,10 @@ body {
/* origin tints: Sonarr teal, Radarr violet, Plex orange. The merged timeline /* 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 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-sonarr { border-left: 3px solid var(--origin-sonarr); }
.release-card.origin-radarr { border-left: 3px solid var(--origin-radarr); } .release-card.origin-radarr { border-left: 3px solid var(--origin-radarr); }
.release-card.origin-plex { border-left: 3px solid var(--origin-plex); } .release-card.origin-plex { border-left: 3px solid var(--origin-plex); }