Skip to content

Appearance (light & dark)

What this is

Built-in light and dark themes (Raspberry Pi red / green accents), shared ops-hero layout chrome, and theme-aware brand marks. Light and dark stay a browser choice. On this train an admin can set an instance name and one accent, and can hide Catalog in the nav. The official mark and the primary red stay. There is no logo upload and no per-user skin. Production v1.6.0 does not have those Settings cards yet.

Why it exists

Operators work in bright workshops and dark server rooms. Theme is a local browser preference, not a fleet setting, so one instance can look right for everyone without admin policy.


How to switch

Where Action
Header / avatar menu Toggle theme
First visit Follows system preference when possible

Your choice is stored in the browser (local preference). It does not change other operators’ views.

Light vs dark structure

Both themes use the same layout; contrast is token-driven. Stylesheets (loaded from base.html, query-busted):

File Role
app/static/css/themes.css Colour tokens, header/nav, cards, buttons, shared chrome
app/static/css/fabric.css Network mesh SVG, focus, map fullscreen, dashboard hero
app/static/css/fabric-stack.css Runtime stack drawer + reorder chrome
app/static/css/dns-hub.css DNS records modal rows
app/static/css/ops.css Ops heroes, compact filters, catalog tab bar, ph-only-* responsive utilities
app/static/css/ops-auth.css Login / register / force-password / 2FA stage
app/static/css/ops-pages.css Feature pages, Docker/Services heroes, dense lists (ph-dense-*)
Role Light Dark
Page canvas (--color-bg) Cool grey so white cards separate Deep navy
Cards / panels (--color-surface) White + border + light elevation Elevated grey + border
borders / chrome (--color-border) Medium grey (readable on white) Mid-grey on dark panels
Secondary buttons Canvas-tinted fill + border (not ghost-white) Recessed panel + border

If light mode ever looks like “one flat white screen”, borders or canvas grey have slipped too close to pure white — fix tokens, not per-page CSS.

Brand logos (light & dark)

The product mark and About art use theme-aware PNGs. Those files stay the official mark. An instance name does not replace the image:

Asset Light UI Dark UI
Header / login mark Full-colour herder mark (piherder-mark*.png) Black body/circuits recolored light (piherder-mark-dark*.png); red/green/brown kept
About / docs hero Same mark (piherder-about.png) Dark-theme ink treatment (piherder-about-dark.png)
Favicon / PWA favicon.png + icons/icon-*.png from the same master —

Toggle theme swaps the image src in the browser. Asset inventory: app/static/images/README.md (mirrored under wiki/assets/ for this site).

Instance name, accent, and Catalog in the nav

Settings → General → Instance (admin). The public demo ignores this card and keeps official PiHerder chrome, including Catalog in the nav. PIHERDER_INSTANCE_NAME and PIHERDER_ACCENT do not apply there either.

Knob What it does
Instance name Max 40 characters. Empty keeps the Pi / Herder wordmark. A name is the header, the footer, the sign-in wordmark, apple-mobile-web-app-title, and /manifest.webmanifest name (short name is the first 12 characters). Sentences in the app still say PiHerder.
Accent Recolours --color-accent and the subtle accent background only. Official green is #00a651. Saving that green stores “use the built-in accent”. Primary red stays #e60012. The mark and the browser theme-color stay red.
Show Catalog in the navigation On by default. Uncheck to drop Catalog from the desktop nav and the phone menu. /catalog still opens, including its tabs. Every account on the instance sees the same nav. There is no env lock for this checkbox.

When PIHERDER_INSTANCE_NAME or PIHERDER_ACCENT is set and non-blank, that field is locked. Recreate web after changing either variable. The Catalog checkbox can still be saved while a name or accent is locked. Demo mode disables the whole card.

Instance name, accent, and Catalog

Settings → General → Instance — a name, one accent, and Show Catalog in the navigation. There is no logo upload.

Header with an instance name

A short instance name in the header. The official mark stays, and the red buttons stay red.

Catalog hidden on a phone

With Catalog hidden, the phone menu no longer lists it. Opening /catalog directly still loads the page.

Live docs URL (custom domain only): piherder-docs.hacknow.info. Example hostnames in guides use *.example.com.

About & updates

Avatar menu → About shows the project story, wordmark (theme-aware), running version, a short scheduled-jobs count, and links to GitHub / docs / releases. View schedule uses the same dialog chrome as the other modals. The type control sits above the list. Pick a type, then each host with its status, last run, and next fire. Last run is the latest matching job. A restart does not clear it.

Scheduled jobs by type

View schedule, with the type control above the list. Status is a short pill. Host names are masked.

If a newer GitHub release is available, a dismissible banner appears under the header (per browser). Check for updates on the About page forces a refresh (wait modal). Disable checks with PIHERDER_UPDATE_CHECK=false (air-gapped).

Ops-hero UI (v0.5.0)

Fleet ops pages share a compact ops-hero: primary orb + dual-line stats + optional type chips. Used on:

Area Pages
Fleet Servers, Jobs, Audit, Notifications (bell), fleet Services
Catalog Integrations / Certificates / Templates / Network
Host Server detail, host Docker, Backups, host Services
Access Settings, Account, Users

Dashboard keeps a distinct showcase hero plus a Network maps entry panel (constellation mesh). Login / register use a related mesh treatment (not the ops pulse).

Layout contract (all ops-heroes + dashboard hero):

Viewport Layout
< 768px Title / actions first · compact pulse strip under it
≥ 768px Title left · pulse / viz right (fixed grid column)

Heroes and body cards use the full main content width (Account is not clamped narrower than Servers/Jobs). Catalog always draws the viz shell (placeholder if a detail page has no stats) so switching Integrations → Certificates → Templates → Network does not jump chrome height.

Supporting chrome: compact filters (ph-subhead), branded detail modals (ph-detail-modal), mobile service rows that stack actions instead of squashing.

Mobile navigation

  • Desktop and mobile menus share one nav_items / secondary_items source in base.html (no drift).
  • The hamburger slide-out is portaled to body so fixed positioning is not trapped by page overflow (especially Network maps).
  • Z-index contract: map fullscreen 100000 · menu backdrop 100090 · menu panel 100100. Opening ☰ exits map fullscreen cleanly (label, aria, and viewport listeners).
  • Portrait ↔ landscape: the app recomputes --app-vh / --app-vw, closes the drawer if open, and forces a short reflow so pages rescale without navigating away. Network maps also call PiHerderFabric.refreshLayout (reset map zoom, clear sticky sizes).

Theme CSS not updating after a deploy

PiHerder registers a service worker (PWA / push). Older builds cache-first’d CSS, so the browser could keep serving stale tokens until the SW cache was replaced.

Current behaviour: CSS/JS is network-first; shell cache is versioned (piherder-shell-v3+). Stylesheet links are query-busted (themes.css?v=…, fabric.css?v=…, ops.css?v=…).

If a tab still looks unchanged after a theme fix:

  1. Hard reload once (or close all PiHerder tabs and reopen).
  2. Or DevTools → Application → Service Workers → Unregister, then reload.
  3. Or Application → Cache Storage → delete piherder-shell-*.

What theme does not affect

  • Server data, jobs, or audits
  • Self-backup / restore
  • API tokens or REST behaviour

Dashboard dark theme

Dashboard in dark theme.
  • Settings — Instance card and the other General hub cards
  • PWA & Web Push — install to home screen (theme still toggles in-app; the home-screen title follows the instance name when one is set)
  • Network maps — map chrome and mobile list-first
  • Theme sandbox (developers): /static/theme-test.html on a running instance