feat(homepage): add Arbo 'Raven' theme to custom.css; correct the tab-bar note
Ports Arbo's design tokens (irv-ml1:8201) into conf/custom.css — flat raven ink #021425, card surface #112333 on #1B2E3D borders, Manrope, and mint #2FFC89 reserved for signal so a green pill means the service is actually serving. Values read off Arbo's running :root custom properties rather than sampled from a screenshot. CSS rather than settings.yaml because Homepage's color: setting only accepts built-in Tailwind ramps. NOT YET DEPLOYED — live still runs the stock theme pending an A/B decision. Prototype is at 10.0.50.45:5199; shots in ~/booth-data/homepage-cleanup/. Promoting it also means dropping the background: block from settings.yaml. Also corrects the previous commit's tab-bar claim. It is not a fixed few minutes of warm-up: a fresh container was still tab-less at 4m30s twice, and recovered on its own about an hour later. Cause remains unpinned; the README now records the measured timing and the four ruled-out causes.
This commit is contained in:
+53
-20
@@ -84,21 +84,39 @@ Three fixes, all in this stack's config except where noted:
|
||||
`settings.yaml`. Check with `GET /api/services`, which prints live per-group
|
||||
counts.
|
||||
|
||||
## RESOLVED — the tab bar takes several minutes to appear after a recreate
|
||||
## The tab bar goes missing after a recreate, then comes back on its own
|
||||
|
||||
**Status: closed, and the answer is "wait".** After the 2026-08-18 recreate the
|
||||
client render came up with no tab bar, no wallpaper and no i18n (the search box
|
||||
read the raw key `search.search`); groups fell back to side-by-side columns.
|
||||
It restored itself with no further intervention. **A freshly recreated homepage
|
||||
container needs a few minutes before the client render is whole** — far longer
|
||||
than the healthcheck takes to report `healthy`, which is the trap: `docker ps`
|
||||
says the service is up while the page is still visibly wrong.
|
||||
**Status: self-healing, cause not pinned. Do not chase it.** After a recreate
|
||||
the client render comes up with no tab bar, no wallpaper and no i18n (the
|
||||
search box shows the raw key `search.search`), and groups fall back to
|
||||
side-by-side columns. It restores itself with no intervention.
|
||||
|
||||
**So: after any `docker compose up -d --force-recreate` here, do not judge the
|
||||
dashboard for at least ~5 minutes, and do not start changing config to chase
|
||||
it.** Everything below is the evidence trail from doing exactly that, kept
|
||||
because it rules out four plausible causes and will save the next session the
|
||||
same hour.
|
||||
**Timing, measured rather than assumed:** five minutes is NOT enough — a fresh
|
||||
container was still tab-less at 4m30s, twice. It was observed healthy again
|
||||
after a gap of roughly an hour. So the window is somewhere between those, and
|
||||
`docker ps` reporting `healthy` says nothing about it: the container is
|
||||
serving, the page is just wrong.
|
||||
|
||||
**Practical rule: recreate, then walk away and re-check later.** Do not start
|
||||
editing config to fix it — that is how an hour got spent ruling out four
|
||||
causes that were never the cause:
|
||||
|
||||
- **Not the config.** Restoring `settings.yaml` *and* `services.yaml` to their
|
||||
committed versions reproduces it, as does the pre-adoption backup config in
|
||||
`/opt/docker-bu/conf/homepage/`.
|
||||
- **Not the v2.0.0 release.** A throwaway container on `v1.13.2` (the last v1)
|
||||
shows identical symptoms, and the image never changed anyway — working and
|
||||
broken containers both report `v2.0.0` / rev `17456f2`.
|
||||
- **Not `PUID`/`PGID`**, and not Docker discovery — tested with both, and with
|
||||
the socket unmounted entirely.
|
||||
- **Not a server-side failure.** The server-rendered HTML still contains the
|
||||
tab markup, the background URL and `useEqualHeights` throughout, and
|
||||
`GET /api/validate` returns `[]`. Whatever is lost, is lost client-side, and
|
||||
with no page error, no failed chunk and no non-200.
|
||||
|
||||
If someone does want to pin it: the shape (recovers on a long timescale, no
|
||||
client exception) points at a cache or revalidation window rather than a
|
||||
config fault. Start there, not in this directory.
|
||||
|
||||
**What it is not** — both obvious suspects were tested and cleared:
|
||||
|
||||
@@ -119,17 +137,32 @@ widget 403s. `GET /api/validate` returns `[]`. A fresh container never
|
||||
renders tabs here regardless of image version, config version, `PUID`/`PGID`,
|
||||
or whether Docker discovery is mounted at all.
|
||||
|
||||
**What it actually was: warm-up time.** Every throwaway container in the list
|
||||
above was judged within ~30 seconds of starting, which is why they all looked
|
||||
broken — they were all in the same warm-up window, and that consistency read as
|
||||
a reproduction when it was really the same mistake five times. The live
|
||||
container recovered on its own once left alone. The lesson is a measurement
|
||||
discipline, not a config one, and it sits alongside the existing warning that
|
||||
`docker ps` health and a correct render are different questions.
|
||||
Every throwaway container in that list was judged within ~30s of starting, so
|
||||
they were all inside the same window — and that consistency read as a
|
||||
reproduction when it was really the same measurement mistake five times over.
|
||||
This sits alongside the existing warning that `docker ps` health and a correct
|
||||
render are different questions.
|
||||
|
||||
Before/after evidence: `~/booth-data/homepage-cleanup/` on nh3-dev →
|
||||
`http://10.100.10.50:8090/b/homepage-cleanup/` (24h TTL).
|
||||
|
||||
## Theme — the Arbo "Raven" palette (`conf/custom.css`)
|
||||
|
||||
`conf/custom.css` carries a port of Arbo's design tokens (irv-ml1:8201): flat
|
||||
raven ink `#021425`, card surface `#112333` on `#1B2E3D` borders, Manrope, and
|
||||
mint `#2FFC89` reserved for signal — a status pill is green only when the
|
||||
service is actually serving. Values were read off Arbo's running `:root`
|
||||
custom properties, not sampled from a screenshot, so drift checks are a diff.
|
||||
|
||||
It lives in CSS rather than `settings.yaml` because Homepage's `color:` setting
|
||||
only accepts built-in Tailwind ramps and has no separate surface/border/accent
|
||||
knobs. `color: slate` stays as the base ramp. The `!important` flags are
|
||||
load-bearing against Tailwind utility specificity.
|
||||
|
||||
Pairs with removing the `background:` block from `settings.yaml` — Arbo has no
|
||||
background image, and the wallpaper fought the card surfaces, which sit only a
|
||||
little lighter than the page.
|
||||
|
||||
## Open question
|
||||
|
||||
`ESH-FileBot` (`10.0.50.70`) is still described as "role TBC" — it responds to
|
||||
|
||||
@@ -1,2 +1,171 @@
|
||||
/* Custom styling for homepage. Empty placeholder — keep file present so
|
||||
* homepage doesn't 404 on the asset. */
|
||||
/* Homepage — Corviduo "Raven" theme, ported from Arbo (irv-ml1:8201).
|
||||
*
|
||||
* PROVENANCE: every value below is lifted verbatim from Arbo's own :root
|
||||
* custom properties, read off the running app rather than eyeballed from a
|
||||
* screenshot. Keep the --raven-* / --eye-* / --surface* names identical to
|
||||
* Arbo's so a future drift check is a diff, not an interpretation.
|
||||
*
|
||||
* WHY CSS AND NOT settings.yaml: Homepage's `color:` setting only accepts
|
||||
* built-in Tailwind ramps (slate, zinc, ...). None of them is the raven mint,
|
||||
* and there is no setting for surface/border/accent separately. `color: slate`
|
||||
* stays as the base ramp because it is the closest neutral; everything that
|
||||
* makes this look like Arbo is here.
|
||||
*
|
||||
* SPECIFICITY: Homepage is Tailwind-generated, so utility classes win on
|
||||
* equal specificity. `!important` below is deliberate and load-bearing —
|
||||
* removing it silently reverts individual rules to the stock theme.
|
||||
*/
|
||||
|
||||
@import url("https://fonts.googleapis.com/css2?family=Manrope:wght@400;500;600;700&display=swap");
|
||||
|
||||
:root {
|
||||
/* --- Arbo brand ramp (verbatim) --- */
|
||||
--raven-ink: #021425;
|
||||
--raven-black: #0f2131;
|
||||
--raven-eye: #2ffc89;
|
||||
--raven-bone: #e5f4f4;
|
||||
|
||||
--black-700: #1b2e3d;
|
||||
--black-600: #283b4a;
|
||||
--slate-400: #6a7f88;
|
||||
--slate-300: #8499a0;
|
||||
|
||||
--eye-500: #2ffc89;
|
||||
--eye-400: #77ffa3;
|
||||
--eye-600: #00cf67;
|
||||
|
||||
--info-500: #00a5fb;
|
||||
--success-500: #30ab60;
|
||||
--warning-500: #ecb230;
|
||||
--error-500: #f5686c;
|
||||
|
||||
/* --- semantic surfaces (Arbo's own mapping) --- */
|
||||
--bg: var(--raven-ink);
|
||||
--bg-sunken: #010e1b;
|
||||
--surface: #112333;
|
||||
--surface-2: #1b2e3d;
|
||||
--surface-3: #283b4a;
|
||||
--fg: #dfeeee;
|
||||
--fg-muted: var(--slate-300);
|
||||
--fg-subtle: var(--slate-400);
|
||||
--border: #1b2e3d;
|
||||
--border-strong: #283b4a;
|
||||
--accent: var(--eye-500);
|
||||
}
|
||||
|
||||
/* ---------- page ---------- */
|
||||
/* Flat ink, no photo. Arbo has no background image and the wallpaper was
|
||||
* fighting the card surfaces for contrast — the cards are only ~0x10 lighter
|
||||
* than the page, which reads as depth on flat ink and as mud over a photo. */
|
||||
body,
|
||||
#page_wrapper,
|
||||
#page_container {
|
||||
background: var(--bg) !important;
|
||||
color: var(--fg) !important;
|
||||
font-family: Manrope, ui-sans-serif, system-ui, -apple-system, "Segoe UI",
|
||||
Roboto, "Helvetica Neue", Arial, sans-serif !important;
|
||||
}
|
||||
|
||||
/* ---------- header widgets ---------- */
|
||||
#information-widgets .widget-container,
|
||||
#information-widgets .information-widget-search {
|
||||
background: var(--surface) !important;
|
||||
border: 1px solid var(--border) !important;
|
||||
border-radius: 0.5rem !important;
|
||||
}
|
||||
|
||||
#information-widgets .information-widget-search input {
|
||||
background: transparent !important;
|
||||
color: var(--fg) !important;
|
||||
}
|
||||
|
||||
/* ---------- tabs ---------- */
|
||||
/* Arbo marks the active nav item with a mint rule and a raised surface. */
|
||||
#myTab li button,
|
||||
#services + div li button {
|
||||
color: var(--fg-muted) !important;
|
||||
border-radius: 0.5rem !important;
|
||||
}
|
||||
|
||||
#myTab li button[aria-selected="true"],
|
||||
#myTab li button.active {
|
||||
background: var(--surface-2) !important;
|
||||
color: var(--fg) !important;
|
||||
box-shadow: inset 0 -2px 0 0 var(--accent) !important;
|
||||
}
|
||||
|
||||
/* ---------- group headers ---------- */
|
||||
.service-group-name,
|
||||
.bookmark-group-name {
|
||||
color: var(--fg-subtle) !important;
|
||||
font-weight: 600 !important;
|
||||
letter-spacing: 0.04em !important;
|
||||
text-transform: uppercase !important;
|
||||
font-size: 0.78rem !important;
|
||||
}
|
||||
|
||||
/* ---------- service cards ---------- */
|
||||
.service-card,
|
||||
.bookmark li > a,
|
||||
.bookmark-list li > a {
|
||||
background: var(--surface) !important;
|
||||
border: 1px solid var(--border) !important;
|
||||
border-radius: 0.5rem !important;
|
||||
transition: background 120ms ease, border-color 120ms ease !important;
|
||||
}
|
||||
|
||||
.service-card:hover,
|
||||
.bookmark li > a:hover,
|
||||
.bookmark-list li > a:hover {
|
||||
background: var(--surface-2) !important;
|
||||
border-color: var(--border-strong) !important;
|
||||
}
|
||||
|
||||
.service-name,
|
||||
.bookmark-name {
|
||||
color: var(--fg) !important;
|
||||
font-weight: 600 !important;
|
||||
}
|
||||
|
||||
.service-description,
|
||||
.bookmark-description {
|
||||
color: var(--fg-muted) !important;
|
||||
}
|
||||
|
||||
/* ---------- status pills + widget stat blocks ---------- */
|
||||
/* Stock Homepage renders every pill in the same slate; Arbo reserves colour
|
||||
* for signal. Green only means "this is actually serving". */
|
||||
.service-tag,
|
||||
.service-block,
|
||||
.service-stats {
|
||||
background: var(--surface-2) !important;
|
||||
border: 1px solid var(--border) !important;
|
||||
color: var(--fg-muted) !important;
|
||||
border-radius: 0.375rem !important;
|
||||
}
|
||||
|
||||
.status-online,
|
||||
.status-healthy,
|
||||
.status-running {
|
||||
color: var(--eye-500) !important;
|
||||
}
|
||||
|
||||
.status-offline,
|
||||
.status-unhealthy,
|
||||
.status-error {
|
||||
color: var(--error-500) !important;
|
||||
}
|
||||
|
||||
.status-unknown,
|
||||
.status-exited,
|
||||
.status-partial {
|
||||
color: var(--warning-500) !important;
|
||||
}
|
||||
|
||||
/* ---------- focus ---------- */
|
||||
a:focus-visible,
|
||||
button:focus-visible,
|
||||
input:focus-visible {
|
||||
outline: 2px solid var(--accent) !important;
|
||||
outline-offset: 2px !important;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user