panel-redesign: vendor Bulma 1.0.4 and the Tabler icon subset

Stage 0, step 1. Nothing links the new files yet; the old panel is unchanged.

  - static/bulma.min.css: css/bulma.min.css of npm bulma@1.0.4, byte for
    byte (tarball integrity checked against the registry;
    sha256 67fa26df1ca9e95d8f2adc7c04fa1b15fa3d24257470ebc10cc68b9aab914bee).
  - static/tabler-icons.css + tabler-icons.woff2: @tabler/icons-webfont
    3.49.0 subset with fontTools pyftsubset to the 57 icons the mockups use
    (the plan said 58; the count is 57).
  - NOTICE and development.md § Vendored front-end list both, MIT.
  - Roadmap: panel-redesign is agreed (owner, 2026-10-09), 6/27; the entry no
    longer says 29 screens or that Health is undecided.

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
This commit is contained in:
mix
2026-10-09 17:19:23 +03:00
co-authored by Claude Haiku 5.5
parent 049d8c781c
commit 2fa0bef6c2
9 changed files with 294 additions and 11 deletions
+11
View File
@@ -5,6 +5,17 @@ Format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/); version
## [Unreleased] ## [Unreleased]
### Added
- panel-redesign (stage 0): Bulma 1.0.4 and a 57-icon subset of Tabler Icons
3.49.0 are vendored under `/static` (MIT, listed in NOTICE). Nothing links
them yet; the old panel is unchanged.
### Changed
- panel-redesign is `agreed` (owner, 2026-10-09); work starts with stage 0,
the component kit.
## [1.9.5] - 2026-10-09 ## [1.9.5] - 2026-10-09
CI-only cut: the release workflow no longer breaks the multi-arch image it CI-only cut: the release workflow no longer breaks the multi-arch image it
+16
View File
@@ -21,6 +21,22 @@ htmx 2.0.4 (internal/web/view/static/htmx.min.js)
Licence: Zero-Clause BSD (0BSD) Licence: Zero-Clause BSD (0BSD)
https://github.com/bigskysoftware/htmx https://github.com/bigskysoftware/htmx
Bulma 1.0.4 (internal/web/view/static/bulma.min.css)
Copyright (c) 2023 Jeremy Thomas
Licence: MIT
https://github.com/jgthms/bulma
Distributed unmodified.
Tabler Icons 3.49.0
Copyright (c) 2020-2026 Paweł Kuna
Licence: MIT
https://github.com/tabler/tabler-icons
Distributed as two files:
internal/web/view/static/tabler-icons.css
internal/web/view/static/tabler-icons.woff2
Webfont subset to the 57 icons the panel uses, made with fontTools
pyftsubset.
IBM Plex Sans / IBM Plex Mono IBM Plex Sans / IBM Plex Mono
Copyright © 2017 IBM Corp., with Reserved Font Name "Plex" Copyright © 2017 IBM Corp., with Reserved Font Name "Plex"
Licence: SIL Open Font License 1.1 Licence: SIL Open Font License 1.1
+3
View File
@@ -180,6 +180,9 @@ the tree are AGPL-3.0-compatible.
|---|---|---|---| |---|---|---|---|
| `internal/web/view/static/htmx.min.js` | 2.0.4 | <https://github.com/bigskysoftware/htmx> | 0BSD | | `internal/web/view/static/htmx.min.js` | 2.0.4 | <https://github.com/bigskysoftware/htmx> | 0BSD |
| `internal/web/view/static/ibm-plex-*.woff2` | latin subset | <https://github.com/IBM/plex> | SIL OFL 1.1 (`OFL.txt` beside the files) | | `internal/web/view/static/ibm-plex-*.woff2` | latin subset | <https://github.com/IBM/plex> | SIL OFL 1.1 (`OFL.txt` beside the files) |
| `internal/web/view/static/bulma.min.css` | 1.0.4 | <https://github.com/jgthms/bulma> | MIT |
| `internal/web/view/static/tabler-icons.css` | 3.49.0 (57-icon subset) | <https://github.com/tabler/tabler-icons> | MIT |
| `internal/web/view/static/tabler-icons.woff2` | 3.49.0 (57-icon subset) | <https://github.com/tabler/tabler-icons> | MIT |
### E2e module (`test/e2e/go.mod`) ### E2e module (`test/e2e/go.mod`)
+4 -4
View File
@@ -1,6 +1,6 @@
# Plan: panel-redesign # Plan: panel-redesign
**Status:** candidate **Status:** agreed (owner, 2026-10-09)
**Date:** 2026-09-21 (replaces the 2026-09-08 givens) **Date:** 2026-09-21 (replaces the 2026-09-08 givens)
**Version:** `2.0.0` MAJOR — a breaking release by the owner's decision (§ No compatibility). **Version:** `2.0.0` MAJOR — a breaking release by the owner's decision (§ No compatibility).
@@ -300,7 +300,7 @@ The kit is, in `internal/web/view`:
| `components.go` | the typed input of every partial — `Head{Kicker, Title, Lead, Postmark, Actions}`, `Box{No, Title, End, Help, Variant}`, `Record{Name, Status, Host, Type, Value, InDNS}`, `Fact{Label, Value, Big}`, `SideMenu{Groups}`, `Tag{Status, Label}`, … — so a page passes a struct, not a `dict` it composes itself. A partial's input is part of its definition: components.html documents the look, `components.go` the data | | `components.go` | the typed input of every partial — `Head{Kicker, Title, Lead, Postmark, Actions}`, `Box{No, Title, End, Help, Variant}`, `Record{Name, Status, Host, Type, Value, InDNS}`, `Fact{Label, Value, Big}`, `SideMenu{Groups}`, `Tag{Status, Label}`, … — so a page passes a struct, not a `dict` it composes itself. A partial's input is part of its definition: components.html documents the look, `components.go` the data |
| template functions | `status_tag` (status → `tag is-… is-light`), `copy_field`, `wbr_at` (`<wbr>` after `@` in table cells) | | template functions | `status_tag` (status → `tag is-… is-light`), `copy_field`, `wbr_at` (`<wbr>` after `@` in table cells) |
| `static/panel.css` | `panel/theme.css` + `shared/brand.css`, no rule the mockups do not have; the old stylesheet is deleted at the end, not merged | | `static/panel.css` | `panel/theme.css` + `shared/brand.css`, no rule the mockups do not have; the old stylesheet is deleted at the end, not merged |
| `static/bulma.min.css`, icons | vendored, pinned by checksum; the icon font subset to the icons the mockups use (58 today), not the whole Tabler set | | `static/bulma.min.css`, icons | vendored, pinned by checksum; the icon font subset to the icons the mockups use (57 today), not the whole Tabler set |
| `layout.html` | the shell: navbar with the wordmark, perforated edge, sibling strip, user menu, footer; the signed-out variant | | `layout.html` | the shell: navbar with the wordmark, perforated edge, sibling strip, user menu, footer; the signed-out variant |
| `GET /server/components` | the kit page, global role only: every partial in every state rendered from fixtures — the mockup `components.html` rebuilt by the real templates | | `GET /server/components` | the kit page, global role only: every partial in every state rendered from fixtures — the mockup `components.html` rebuilt by the real templates |
@@ -461,7 +461,7 @@ reviewed.
- Weakening CSP; a JS bundler; a front-end framework. - Weakening CSP; a JS bundler; a front-end framework.
## Implementation checklist ## Implementation checklist
No code until the roadmap status is **agreed**. Stages are ordered for Roadmap status: **agreed** (owner, 2026-10-09). Stages are ordered for
development, not by feature priority (owner, 2026-10-09). Stage 1 touches no development, not by feature priority (owner, 2026-10-09). Stage 1 touches no
file under `internal/web/view` and may run alongside stage 0; stage 2 starts file under `internal/web/view` and may run alongside stage 0; stage 2 starts
only when both are done. Every stage-2 step ends with the evidence of only when both are done. Every stage-2 step ends with the evidence of
@@ -477,7 +477,7 @@ only when both are done. Every stage-2 step ends with the evidence of
**Stage 0 — foundation and component kit** (§ Component kit) **Stage 0 — foundation and component kit** (§ Component kit)
- [ ] Vendor Bulma 1.0.4 and the icon subset (MIT) under `/static`, NOTICE and development.md rows, pinned checksum — **Haiku** - [x] Vendor Bulma 1.0.4 and the icon subset (MIT) under `/static`, NOTICE and development.md rows, pinned checksum — **Haiku**
- [ ] Guard tests from § Enforcement and `TestRoutesFollowNavigation`, red against today's panel where expected, with the `legacyPages` ratchet listing every page; `design-first` CI step including the ratchet and the history-blob check (§ Against resurrected pages) — **Opus** - [ ] Guard tests from § Enforcement and `TestRoutesFollowNavigation`, red against today's panel where expected, with the `legacyPages` ratchet listing every page; `design-first` CI step including the ratchet and the history-blob check (§ Against resurrected pages) — **Opus**
- [ ] `panel.css` from `panel/theme.css` + `shared/brand.css`; `components.html` partials with typed inputs in `components.go`; `status_tag`, `copy_field`, `wbr_at` — **Sonnet** - [ ] `panel.css` from `panel/theme.css` + `shared/brand.css`; `components.html` partials with typed inputs in `components.go`; `status_tag`, `copy_field`, `wbr_at` — **Sonnet**
- [ ] `layout.html`: navbar, perforated edge, sibling strip, user menu, footer, visibility flags; the signed-out shell — **Sonnet** - [ ] `layout.html`: navbar, perforated edge, sibling strip, user menu, footer, visibility flags; the signed-out shell — **Sonnet**
+9 -7
View File
@@ -39,7 +39,7 @@ in `git log` and [CHANGELOG.md](../CHANGELOG.md).
| panel-notifications | E-mail notifications about important events | candidate | — | — | | panel-notifications | E-mail notifications about important events | candidate | — | — |
| delivery-log-storage | Keep a message's `mail.log` lines with its send-log row | candidate | — | — | | delivery-log-storage | Keep a message's `mail.log` lines with its send-log row | candidate | — | — |
| password-reset | Password reset by e-mail | candidate | — | — | | password-reset | Password reset by e-mail | candidate | — | — |
| panel-redesign | Panel redesign (accepted mockups, design contract) | candidate | 5/27 | [plans/panel-redesign.md](plans/panel-redesign.md) | | panel-redesign | Panel redesign (accepted mockups, design contract) | agreed | 6/27 | [plans/panel-redesign.md](plans/panel-redesign.md) |
| schema-squash | Squash SQLite migrations into a 2.x baseline | **2.x** | — | — | | schema-squash | Squash SQLite migrations into a 2.x baseline | **2.x** | — | — |
**Recommended order** (not binding; owner, 2026-10-09: feature order follows **Recommended order** (not binding; owner, 2026-10-09: feature order follows
@@ -408,7 +408,7 @@ Not drawn yet.
**Goal:** a panel an operator opens a few times a year and still finds their **Goal:** a panel an operator opens a few times a year and still finds their
way in — the important things in view, details one or two clicks away, one way in — the important things in view, details one or two clicks away, one
visual language, no page tuning its own width. The design is drawn and visual language, no page tuning its own width. The design is drawn and
accepted: 29 screens and a components page under accepted: 33 screens and a components page under
[docs/assets/panel-redesign/](assets/panel-redesign/index.html) (Bulma base, [docs/assets/panel-redesign/](assets/panel-redesign/index.html) (Bulma base,
postmark / numbered heads / perforated edge, icons). Contract and checklist: postmark / numbered heads / perforated edge, icons). Contract and checklist:
[plans/panel-redesign.md](plans/panel-redesign.md). [plans/panel-redesign.md](plans/panel-redesign.md).
@@ -419,10 +419,12 @@ Server) and paths are renamed to match. **No compatibility is kept** (owner,
2026-09-21): no redirects, the migration chain is replaced by one baseline 2026-09-21): no redirects, the migration chain is replaced by one baseline
and 2.0 starts from an empty data directory — the only live installation is and 2.0 starts from an empty data directory — the only live installation is
the owner's. Inbound domains become delegable to a the owner's. Inbound domains become delegable to a
domain administrator, separately from outbound. Four things the mockups show need their own decision and are not domain administrator, separately from outbound. Server › Health is built
smuggled in with the restyle: queue as a table (`postqueue -j`), inbound with the restyle (decided 2026-10-09). Three things the mockups show keep
queue, inbound log (rides on inbound-antispam-panel), Server › Health. No CSP their own decision and are not smuggled in: queue as a table
change, no JavaScript widgets, no second framework. (`postqueue -j`), inbound queue, inbound log (rides on
inbound-antispam-panel) — until then both queues ship the old content in the
new shell. No CSP change, no JavaScript widgets, no second framework.
**Done when:** every page renders with the component skeleton recorded in **Done when:** every page renders with the component skeleton recorded in
`panel/outlines.json`, the guard tests in the plan are green with no `panel/outlines.json`, the guard tests in the plan are green with no
@@ -434,7 +436,7 @@ of their own — answered by guard tests that land before the templates, a
`design-first` CI step and evidence-based acceptance (plan § Enforcement). `design-first` CI step and evidence-based acceptance (plan § Enforcement).
Competes with feature work; Bulma is ~680 kB minified, embedded once. Competes with feature work; Bulma is ~680 kB minified, embedded once.
**Version:** `2.0.0` MAJOR; `candidate` until agreed. **Version:** `2.0.0` MAJOR; `agreed` (owner, 2026-10-09).
--- ---
File diff suppressed because one or more lines are too long
+247
View File
@@ -0,0 +1,247 @@
/* Tabler Icons 3.49.0 — MIT, https://github.com/tabler/tabler-icons — subset to the 57 icons the panel uses; regenerate, do not hand-edit */
@font-face {
font-family: "tabler-icons";
font-style: normal;
font-weight: 400;
src: url("tabler-icons.woff2") format("woff2");
}
.ti {
font-family: "tabler-icons" !important;
speak: none;
font-style: normal;
font-weight: normal;
font-variant: normal;
text-transform: none;
line-height: 1;
/* Better Font Rendering */
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
.ti-activity-heartbeat:before {
content: "\f0db";
}
.ti-address-book:before {
content: "\f021";
}
.ti-alert-circle:before {
content: "\ea05";
}
.ti-alert-triangle:before {
content: "\ea06";
}
.ti-apps:before {
content: "\ebb6";
}
.ti-archive:before {
content: "\ea0b";
}
.ti-arrow-forward-up:before {
content: "\eb78";
}
.ti-arrow-left:before {
content: "\ea19";
}
.ti-arrow-right:before {
content: "\ea1f";
}
.ti-arrows-exchange:before {
content: "\f1f4";
}
.ti-certificate:before {
content: "\ed76";
}
.ti-checklist:before {
content: "\f074";
}
.ti-circle-check:before {
content: "\ea67";
}
.ti-copy:before {
content: "\ea7a";
}
.ti-cpu:before {
content: "\ef8e";
}
.ti-download:before {
content: "\ea96";
}
.ti-eye:before {
content: "\ea9a";
}
.ti-file-export:before {
content: "\ede9";
}
.ti-file-import:before {
content: "\edea";
}
.ti-file-text:before {
content: "\eaa2";
}
.ti-filter:before {
content: "\eaa5";
}
.ti-gauge:before {
content: "\eab1";
}
.ti-heartbeat:before {
content: "\ef92";
}
.ti-help:before {
content: "\eabf";
}
.ti-help-circle:before {
content: "\f91d";
}
.ti-inbox:before {
content: "\eac4";
}
.ti-key:before {
content: "\eac7";
}
.ti-list-details:before {
content: "\ef40";
}
.ti-lock:before {
content: "\eae2";
}
.ti-logout:before {
content: "\eba8";
}
.ti-mail:before {
content: "\eae5";
}
.ti-mail-forward:before {
content: "\eeac";
}
.ti-mail-pause:before {
content: "\f941";
}
.ti-plug:before {
content: "\ebd9";
}
.ti-plug-connected:before {
content: "\f00a";
}
.ti-plug-connected-x:before {
content: "\f0a0";
}
.ti-plus:before {
content: "\eb0b";
}
.ti-refresh:before {
content: "\eb13";
}
.ti-reload:before {
content: "\f3ae";
}
.ti-report-analytics:before {
content: "\eecb";
}
.ti-send:before {
content: "\eb1e";
}
.ti-server-2:before {
content: "\f07c";
}
.ti-server-cog:before {
content: "\f321";
}
.ti-settings:before {
content: "\eb20";
}
.ti-shield-check:before {
content: "\eb22";
}
.ti-stack-2:before {
content: "\eef7";
}
.ti-trash:before {
content: "\eb41";
}
.ti-upload:before {
content: "\eb47";
}
.ti-user:before {
content: "\eb4d";
}
.ti-user-circle:before {
content: "\ef68";
}
.ti-user-plus:before {
content: "\eb4b";
}
.ti-users:before {
content: "\ebf2";
}
.ti-world:before {
content: "\eb54";
}
.ti-world-check:before {
content: "\f9db";
}
.ti-world-download:before {
content: "\ef8a";
}
.ti-world-upload:before {
content: "\ef8b";
}
.ti-x:before {
content: "\eb55";
}
Binary file not shown.
+1
View File
@@ -29,6 +29,7 @@ func TestStaticAssetsCarryETag(t *testing.T) {
// thing the panel serves and the ones a browser is most willing to keep. // thing the panel serves and the ones a browser is most willing to keep.
"ibm-plex-sans.woff2", "ibm-plex-mono-400.woff2", "ibm-plex-mono-600.woff2", "ibm-plex-sans.woff2", "ibm-plex-mono-400.woff2", "ibm-plex-mono-600.woff2",
"OFL.txt", "OFL.txt",
"bulma.min.css", "tabler-icons.css", "tabler-icons.woff2",
} { } {
rec := serveStatic("/static/"+name, nil) rec := serveStatic("/static/"+name, nil)
if rec.Code != http.StatusOK { if rec.Code != http.StatusOK {