mirror of
https://github.com/kiddin9/op-packages.git
synced 2026-09-12 03:14:48 +08:00
🤞 Sync 2026-08-12 09:27:55
This commit is contained in:
@@ -17,7 +17,7 @@ LUCI_NAME:=luci-theme-footstrap
|
||||
FOOTSTRAP_VERSION?=
|
||||
ifneq ($(FOOTSTRAP_VERSION),)
|
||||
PKG_VERSION:=$(FOOTSTRAP_VERSION)
|
||||
PKG_RELEASE:=12
|
||||
PKG_RELEASE:=13
|
||||
endif
|
||||
|
||||
LUCI_TITLE:=Footstrap Theme
|
||||
|
||||
@@ -412,9 +412,13 @@ function navigate(pathname, push, kbd) {
|
||||
* decided by how the user got there.
|
||||
*
|
||||
* So decline, exactly as the poisoned-document bail above does: speed is traded for correctness,
|
||||
* never the other way. It costs ONE full load per such page — after it the <link> is in the
|
||||
* document, this test passes, and every later visit is a swap again (fs-sheets.js owns the sheet
|
||||
* from then on and re-lights it per page).
|
||||
* never the other way. The cost is one full load per ENTRY INTO A DOCUMENT that lacks the sheet,
|
||||
* not one per page ever: head.ut emits the link for the DISPATCHED node only, so each full load
|
||||
* starts a document carrying exactly one such sheet and discards what the previous one had
|
||||
* gathered. Within that document the page is a swap from then on (fs-sheets.js owns the sheet and
|
||||
* re-lights it per page) — but two `css`-bearing pages alternating are a full load every time, in
|
||||
* both directions. That is the trade taken knowingly: an unstyled page is worse than a reload, and
|
||||
* no in-tree node sets `css` today.
|
||||
*
|
||||
* Injecting the <link> here instead would work and is deliberately not done: it would put the theme
|
||||
* in charge of fetching and ordering a foreign stylesheet, which is the job fs-sheets.js exists to
|
||||
|
||||
@@ -325,14 +325,29 @@ function outlivesPage(el) {
|
||||
* this module's because the answer is: a link inside #view is about to be deleted with the rest of
|
||||
* the view, and counting it would hand the router a sheet the next dom.content() throws away —
|
||||
* `luci-app-nlbwmon` returns E('link', …, L.resource('view/nlbw.css')) from render(), so that shape
|
||||
* is real. Compared by PATH and by suffix: head.ut prints `{{ resource }}/{{ dispatched.css }}?v=…`,
|
||||
* so neither the resource base nor the cache key is anyone's to assume. */
|
||||
* is real.
|
||||
*
|
||||
* WHOLE PATH, NOT A SUFFIX. head.ut prints `{{ resource }}/{{ dispatched.css }}?v=…`, and the base in
|
||||
* that line is the SAME value the runtime holds: header.ut hands `resource` to `new LuCI({…})`, and
|
||||
* `L.resource()` joins it back exactly, so the server's href is reconstructable rather than guessable
|
||||
* — only the cache key has to come off. A suffix match is what a guess costs: anchored at nothing but
|
||||
* a `/`, `custom.css` matches any sheet ending in that filename, and two in-tree apps append exactly
|
||||
* that to <head> at module eval — `luci-app-adblock` and `luci-app-banip` both add
|
||||
* `L.resource('view/<app>/custom.css')`, outside #view, so outlivesPage() keeps them and this module
|
||||
* disables rather than removes them: they stay for the life of the document. A third-party node
|
||||
* declaring `"css": "custom.css"` would then read as already-carried the moment the user had passed
|
||||
* through Adblock → Feeds, and the router would swap into a page whose stylesheet was never linked —
|
||||
* the one outcome the guard exists to prevent.
|
||||
*
|
||||
* Equality also keeps the failure safe: L.path() drops a part that leaves its charset, so a malformed
|
||||
* `css` yields the bare base and matches no href at all — a full load, which is the correct answer for
|
||||
* a value nobody can serve. */
|
||||
function documentCarries(path) {
|
||||
const want = '/' + String(path).replace(/^\/+/, '');
|
||||
const want = L.resource(String(path));
|
||||
for (const link of document.querySelectorAll('link[rel~="stylesheet"][href]')) {
|
||||
if (!outlivesPage(link))
|
||||
continue;
|
||||
if ((link.getAttribute('href') || '').split('?')[0].endsWith(want))
|
||||
if ((link.getAttribute('href') || '').split('?')[0] === want)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
||||
@@ -469,14 +469,22 @@
|
||||
--background-color-medium: color-mix(in srgb, var(--fs-panel) 55%, var(--fs-panel2));
|
||||
--background-color-low: var(--fs-panel2);
|
||||
|
||||
/* --text-color-low cannot move: --fs-dim IS the muted text colour and already
|
||||
* sits ON the AA floor (4.56:1 on --fs-panel2 in dark), so a fainter step would
|
||||
* be an illegible grey. It stays equal to -medium — the ramp is still wide, -high
|
||||
* being --fs-text — and a duplicate beats a value nobody can read. */
|
||||
/* -low used to be a DUPLICATE of -medium, both --fs-dim, on the grounds that a fainter
|
||||
* step would be illegible: --fs-dim sits on the AA floor in dark (4.56:1 on --fs-panel2)
|
||||
* and --fs-faint is the fainter one. That held while the two were a hair apart. Light's
|
||||
* secondary tier has since moved to 11.8:1 (see 03-palettes.css), so the duplicate stopped
|
||||
* being a rounding decision and started flattening the export: `spread(high, low)` fell to
|
||||
* 0.082 in the default palette and 0.094 in hicontrast, under the 0.10 the ramp promises —
|
||||
* an app asking for a gradation would have got one colour twice.
|
||||
*
|
||||
* So -low is --fs-faint, the theme's own third ink, and the illegibility that argument
|
||||
* feared is what the gate below measures rather than assumes: every level is held to AA as
|
||||
* text on all three surfaces AND as a fill under its --on-* ink, in both modes, across the
|
||||
* whole palette x tint matrix. --fs-faint clears it everywhere. */
|
||||
--text-color-highest: var(--fs-text);
|
||||
--text-color-high: var(--fs-text);
|
||||
--text-color-medium: var(--fs-dim);
|
||||
--text-color-low: var(--fs-dim);
|
||||
--text-color-low: var(--fs-faint);
|
||||
|
||||
/* borders carry no text, so here -low MAY fade toward the surface: a hairline
|
||||
* is supposed to disappear into it. */
|
||||
|
||||
@@ -257,9 +257,15 @@
|
||||
--fs-panel2-base: #f6f8fa;
|
||||
--fs-border-base: #d0d7de;
|
||||
--fs-text: #1f2328;
|
||||
--fs-dim: #656d76;
|
||||
--fs-faint: #68727e;
|
||||
--fs-select-chevron: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="%23656d76" stroke-width="2.4" stroke-linecap="round" stroke-linejoin="round"><path d="m6 9 6 6 6-6"/></svg>');
|
||||
/* The SECONDARY tier carries LuCI's page descriptions and every field title, and at the
|
||||
* GitHub-light greys it started from (#656d76/#68727e, 5.2:1 and 4.9:1 on the card) that is
|
||||
* help text a reader has to lean into — reported on the upstream PR by someone reading the
|
||||
* light theme on a real router. LuCI's pages are technical and their descriptions are the
|
||||
* part you read once and act on, so this tier is now 11.8:1 and 10.0:1: still a tier below
|
||||
* the 15.8:1 body ink, which is what keeps a label a label, but no longer a whisper. */
|
||||
--fs-dim: #33383d;
|
||||
--fs-faint: #3d4348;
|
||||
--fs-select-chevron: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="%2333383d" stroke-width="2.4" stroke-linecap="round" stroke-linejoin="round"><path d="m6 9 6 6 6-6"/></svg>');
|
||||
--fs-accent-base: #0969da;
|
||||
/* a tint OF --fs-accent, so mixed FROM it. It used to restate the accent's RGB as a
|
||||
* literal, which goes stale silently the moment the accent is recoloured (or the
|
||||
@@ -315,9 +321,13 @@
|
||||
--fs-panel2-base: #f6f8fb;
|
||||
--fs-border-base: #e4e9f1;
|
||||
--fs-text: #101725;
|
||||
--fs-dim: #5b6675;
|
||||
--fs-faint: #69727f;
|
||||
--fs-select-chevron: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="%235b6675" stroke-width="2.4" stroke-linecap="round" stroke-linejoin="round"><path d="m6 9 6 6 6-6"/></svg>');
|
||||
/* …and this palette's secondary tier moves with it, because the promise in the comment above
|
||||
* is RELATIVE: 5.8:1 and 4.9:1 were above the default when the default was 5.2:1 and 4.9:1,
|
||||
* and below it the moment that changed. 13.5:1 and 12.0:1 against the default's 11.8 and
|
||||
* 10.0. */
|
||||
--fs-dim: #272f3d;
|
||||
--fs-faint: #2e3745;
|
||||
--fs-select-chevron: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="%23272f3d" stroke-width="2.4" stroke-linecap="round" stroke-linejoin="round"><path d="m6 9 6 6 6-6"/></svg>');
|
||||
--fs-accent-base: #0b6fbd;
|
||||
--fs-accent-soft: color-mix(in srgb, var(--fs-accent) 10%, transparent);
|
||||
--fs-track: #eaeef4;
|
||||
@@ -388,10 +398,17 @@
|
||||
--fs-panel-base: #ffffff;
|
||||
--fs-panel2-base: #f5f5f5;
|
||||
--fs-border-base: #cccccc;
|
||||
--fs-text: #404040;
|
||||
--fs-dim: #6a6a6a;
|
||||
--fs-faint: #6e6e6e;
|
||||
--fs-select-chevron: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="%236a6a6a" stroke-width="2.4" stroke-linecap="round" stroke-linejoin="round"><path d="m6 9 6 6 6-6"/></svg>');
|
||||
/* THE INK IS THE ONE PLACE THIS COLOURWAY LEAVES BOOTSTRAP'S OWN VALUES BEHIND, and it is
|
||||
* the same decision the default palette made: bootstrap's #404040 body and #6a6a6a muted
|
||||
* tier measure 10.4:1 and 5.0:1 on white, and the muted one carries LuCI's page
|
||||
* descriptions and every field title — help text you have to lean into. Matched to the
|
||||
* default palette's light ramp instead, ratio for ratio: 15.7 / 11.7 / 10.0 against its
|
||||
* 15.8 / 11.8 / 10.0. Neutral greys, so the colourway still reads as bootstrap's — what is
|
||||
* copied is its hue, not its readability. */
|
||||
--fs-text: #232323;
|
||||
--fs-dim: #383838;
|
||||
--fs-faint: #424242;
|
||||
--fs-select-chevron: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="%23383838" stroke-width="2.4" stroke-linecap="round" stroke-linejoin="round"><path d="m6 9 6 6 6-6"/></svg>');
|
||||
/* --primary-color-medium; -high (#1976d2) measured 4.22:1 on --fs-panel2 */
|
||||
--fs-accent-base: #1564c0;
|
||||
--fs-accent-soft: color-mix(in srgb, var(--fs-accent) 10%, transparent);
|
||||
@@ -417,8 +434,13 @@
|
||||
--fs-panel2-base: #303030;
|
||||
--fs-border-base: #444444;
|
||||
--fs-text: #bfbfbf;
|
||||
/* faint == dim here, and that is the deviation this palette allows itself: bootstrap's dark
|
||||
* has no third ink, and the export tier's -low now follows --fs-faint (02-tokens.css), so
|
||||
* the #969696 this used to carry landed at 4.46:1 on a tinted --fs-panel2 — under AA for a
|
||||
* name apps print text in. The step above it is bootstrap's own, so the fainter one gives
|
||||
* way rather than the ramp. */
|
||||
--fs-dim: #9a9a9a;
|
||||
--fs-faint: #969696;
|
||||
--fs-faint: #9a9a9a;
|
||||
--fs-select-chevron: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="%239a9a9a" stroke-width="2.4" stroke-linecap="round" stroke-linejoin="round"><path d="m6 9 6 6 6-6"/></svg>');
|
||||
--fs-accent-base: #53a4c2;
|
||||
--fs-accent-soft: color-mix(in srgb, var(--fs-accent) 15%, transparent);
|
||||
|
||||
Reference in New Issue
Block a user