From 66d94a2d136636df03345cb452169bcd241fc495 Mon Sep 17 00:00:00 2001
From: SandObserver <260779319+SandObserver@users.noreply.github.com>
Date: Wed, 23 Sep 2026 19:00:48 -0400
Subject: [PATCH 1/2] Give widget cards the kit's glass edge and sentence-case
headings
---
ui/css/dashboard.css | 11 +++++++++++
ui/index.html | 2 +-
ui/widgets/books/i18n/de.json | 6 +++---
ui/widgets/books/i18n/en.json | 6 +++---
ui/widgets/books/i18n/es.json | 6 +++---
ui/widgets/books/i18n/fr.json | 6 +++---
ui/widgets/books/index.html | 10 +++++-----
ui/widgets/connections/connections-vpn.html | 4 ++--
ui/widgets/dns/index.html | 2 +-
9 files changed, 32 insertions(+), 21 deletions(-)
diff --git a/ui/css/dashboard.css b/ui/css/dashboard.css
index bfefeeab..ecf42a45 100644
--- a/ui/css/dashboard.css
+++ b/ui/css/dashboard.css
@@ -2,6 +2,8 @@
:root {
--glass-bg: #1C1C1E;
--glass-border: rgba(255,255,255,.09);
+ --card-edge-hi: rgba(255,255,255,.16);
+ --card-edge-lo: rgba(255,255,255,.05);
--glass-surface-bg: rgba(51,51,51,.33);
--glass-surface-blur: blur(12px) saturate(180%);
--glass-rim-light: rgba(255,255,255,.30);
@@ -149,6 +151,13 @@
border:1px solid var(--glass-border); background:var(--glass-bg);
}
.widget iframe { display:block; border:0; width:100% }
+ /* Keep it on its own layer. WebKit otherwise composites it late over a
+ moving frame, and the edge flashes in after a page change. */
+ .widget::after, .mob-widget-card::after {
+ content:''; position:absolute; inset:0; border-radius:inherit;
+ pointer-events:none; z-index:5; transform:translateZ(0);
+ box-shadow:inset 0 1px 0 var(--card-edge-hi), inset 0 -1px 0 var(--card-edge-lo);
+ }
/* The mobile home screen builds its own card element with the same glass
material. Its sizing stays inline. */
@@ -1054,6 +1063,8 @@ html[data-theme="light"] {
--bg-base: #E5E5EA;
--glass-bg: #FFFFFF;
--glass-border: rgba(0,0,0,.06);
+ --card-edge-hi: rgba(255,255,255,.9);
+ --card-edge-lo: rgba(0,0,0,.05);
--glass-surface-bg: rgba(153,153,153,.33);
--glass-surface-blur: blur(24px) saturate(180%);
--glass-rim-light: rgba(255,255,255,1);
diff --git a/ui/index.html b/ui/index.html
index 270f3d17..2be4e8db 100644
--- a/ui/index.html
+++ b/ui/index.html
@@ -26,7 +26,7 @@
Stackyard
-
+
Stackyard
diff --git a/ui/widgets/books/i18n/de.json b/ui/widgets/books/i18n/de.json
index 0ac14c51..a1e43691 100644
--- a/ui/widgets/books/i18n/de.json
+++ b/ui/widgets/books/i18n/de.json
@@ -28,9 +28,9 @@
"listId.hint": "Oben URL und Schlüssel eingeben, dann Abrufen klicken, um Sammlungen und Leselisten zu laden.",
"href.label": "Klick-URL (optional)",
"href.placeholder": "https://…",
- "ui.reading": "LESE GERADE",
- "ui.srcRecently": "ZULETZT HINZUGEFÜGT",
- "ui.srcUnread": "WEITERLESEN",
+ "ui.reading": "Lese gerade",
+ "ui.srcRecently": "Zuletzt hinzugefügt",
+ "ui.srcUnread": "Weiterlesen",
"ui.finished": "Gelesen",
"ui.unread": "Ungelesen",
"ui.percentRead": "{pct} % gelesen",
diff --git a/ui/widgets/books/i18n/en.json b/ui/widgets/books/i18n/en.json
index 9d09a039..1b537d9a 100644
--- a/ui/widgets/books/i18n/en.json
+++ b/ui/widgets/books/i18n/en.json
@@ -28,9 +28,9 @@
"listId.hint": "Enter the URL + key above, then click Fetch to load your collections / reading lists.",
"href.label": "Click URL (optional)",
"href.placeholder": "https://…",
- "ui.reading": "READING",
- "ui.srcRecently": "RECENTLY ADDED",
- "ui.srcUnread": "ON DECK",
+ "ui.reading": "Reading",
+ "ui.srcRecently": "Recently Added",
+ "ui.srcUnread": "On Deck",
"ui.finished": "Finished",
"ui.unread": "Unread",
"ui.percentRead": "{pct}% read",
diff --git a/ui/widgets/books/i18n/es.json b/ui/widgets/books/i18n/es.json
index dd47dc77..54117475 100644
--- a/ui/widgets/books/i18n/es.json
+++ b/ui/widgets/books/i18n/es.json
@@ -28,9 +28,9 @@
"listId.hint": "Introduce arriba la URL y la clave, y pulsa Obtener para cargar tus colecciones y listas de lectura.",
"href.label": "URL de clic (opcional)",
"href.placeholder": "https://…",
- "ui.reading": "LEYENDO",
- "ui.srcRecently": "AÑADIDOS RECIENTEMENTE",
- "ui.srcUnread": "EN CURSO",
+ "ui.reading": "Leyendo",
+ "ui.srcRecently": "Añadidos recientemente",
+ "ui.srcUnread": "En curso",
"ui.finished": "Terminado",
"ui.unread": "Sin leer",
"ui.percentRead": "{pct} % leído",
diff --git a/ui/widgets/books/i18n/fr.json b/ui/widgets/books/i18n/fr.json
index 3163417f..8659ec0d 100644
--- a/ui/widgets/books/i18n/fr.json
+++ b/ui/widgets/books/i18n/fr.json
@@ -28,9 +28,9 @@
"listId.hint": "Saisissez l’URL et la clé ci-dessus, puis cliquez sur Récupérer pour charger vos collections et listes de lecture.",
"href.label": "URL de clic (facultatif)",
"href.placeholder": "https://…",
- "ui.reading": "EN COURS",
- "ui.srcRecently": "AJOUTS RÉCENTS",
- "ui.srcUnread": "À POURSUIVRE",
+ "ui.reading": "En cours",
+ "ui.srcRecently": "Ajouts récents",
+ "ui.srcUnread": "À poursuivre",
"ui.finished": "Terminé",
"ui.unread": "Non lu",
"ui.percentRead": "{pct} % lu",
diff --git a/ui/widgets/books/index.html b/ui/widgets/books/index.html
index 0d461a6e..e428ca04 100644
--- a/ui/widgets/books/index.html
+++ b/ui/widgets/books/index.html
@@ -15,14 +15,14 @@
.card.clickable{cursor:pointer}
.card.clickable:focus-visible{outline:2px solid #00D2E0;outline-offset:-3px}
- .head{flex:none;font-size:11px;font-weight:500;color:#8E8E93;letter-spacing:.05em;
+ .head{flex:none;font-size:13px;font-weight:600;color:#8E8E93;
white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.shelves{flex:1;display:flex;flex-direction:column;gap:8px;min-height:0;margin-top:6px}
.size-large .shelves{margin-top:10px}
.shelf-wrap{flex:1;display:flex;flex-direction:column;min-height:0}
- .shelf-lbl{flex:none;font-size:10px;font-weight:600;color:#8E8E93;letter-spacing:.06em;margin-bottom:4px;
- text-transform:uppercase;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
+ .shelf-lbl{flex:none;font-size:11px;font-weight:600;color:#8E8E93;margin-bottom:4px;
+ white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.shelf-lbl[hidden]{display:none}
.shelf{flex:1;position:relative;min-height:0;border-bottom:1px solid rgba(235,235,245,.5)}
.shelf::after{content:"";position:absolute;left:5%;right:5%;bottom:-1px;height:10px;pointer-events:none;
@@ -101,7 +101,7 @@
Stackyard
-
+
Stackyard
diff --git a/ui/test/theme.test.mjs b/ui/test/theme.test.mjs
index 3785cf34..9a4a1aef 100644
--- a/ui/test/theme.test.mjs
+++ b/ui/test/theme.test.mjs
@@ -113,3 +113,12 @@ test('the light palette carries an increased-contrast partner for every hue', ()
assert.ok(hues.length >= 18, `expected the twelve hues and six greys, found ${hues.length}`);
for (const h of hues) assert.match(light, new RegExp(`--sy-${h}-hi:\\s*#`), `--sy-${h} has no -hi partner`);
});
+
+test('a widget held dark in the light theme keeps the dark edge light', () => {
+ const css = read('../css/dashboard.css');
+ const at = css.indexOf('html[data-theme="light"] .mob-widget-card[data-appearance="dark"] {');
+ assert.ok(at > -1, 'the forced-dark block is gone');
+ const block = css.slice(at, css.indexOf('}', at));
+ assert.match(block, /--card-edge-hi:rgba\(255,255,255,\.16\)/);
+ assert.match(block, /--card-edge-lo:rgba\(255,255,255,\.05\)/);
+});