From 9b4a368b055ff4a7d85338405d69fb336f193c93 Mon Sep 17 00:00:00 2001 From: Mikhail Yenuchenko Date: Mon, 3 Aug 2026 23:21:49 +0300 Subject: [PATCH] panel: give the monitoring pages a width that fits their data MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 48rem is a reading measure, right for the panel's forms and prose and the width the nav bar's two rows were sized for. Deliveries, Mail queue and System log hold data instead: seven columns of send-log, and mail.log lines that are long by nature. They get 64rem; every other page keeps the narrow measure. The page name travels onto
as a class so the stylesheet can tell them apart without every handler having to pass a second field. Width alone does not make a table fit, though — a column is at least as wide as the longest unbreakable run in it, and one 40-character recipient still hung Status over the card's edge. Cells may now break mid word, with timestamps exempt, so a column can always be squeezed into the room available. Co-Authored-By: Claude Opus 5 --- CHANGELOG.md | 13 +++++++++ internal/web/static/panel.css | 31 ++++++++++++++++----- internal/web/templates/deliveries_rows.html | 2 +- internal/web/templates/layout.html | 7 ++++- 4 files changed, 44 insertions(+), 9 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3fac906..793fe99 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,13 @@ Format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/); version ## [Unreleased] +### Changed + +- panel: the three monitoring pages — Deliveries, Mail queue, System log — are + now laid out wider (64rem against the 48rem the rest of the panel keeps). + They carry data rather than prose: the send-log's seven columns had no room + to breathe, and the raw `mail.log` lines wrapped every second line. + ### Fixed - panel: Deliveries now shows the subject as text rather than as its MIME @@ -17,6 +24,12 @@ Format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/); version their raw string. Subjects in the legacy single-byte charsets (windows-1251, koi8-r) are still stored as sent — there is no decoder for them. +- panel: table cells may now break inside a word, so no single long value can + push a table past the edge of its card. A 40-character recipient address did + it just as readily as an undecoded subject: a column is at least as wide as + the longest unbreakable run it holds, and email addresses have nothing to + break on. Timestamps are exempt and stay on one line. + ## [0.3.0] - 2026-08-03 ### Fixed diff --git a/internal/web/static/panel.css b/internal/web/static/panel.css index 6e6fe57..b4d54ba 100644 --- a/internal/web/static/panel.css +++ b/internal/web/static/panel.css @@ -50,21 +50,38 @@ button:hover, a.btn:hover { background: #1d4ed8; } form's block layout; its button is styled like any other. */ form.inline { display: inline; margin: 0; } main { max-width: 48rem; } +/* 48rem is a reading measure: right for the forms and prose that make up most + of the panel, and the width the navigation bar's two rows were sized for. The + three monitoring pages hold data instead — seven columns of send-log, and raw + mail.log lines that are long by nature — and at that width the send-log's + Subject and Status were fighting over the last inch while the log pages wrapped + every second line. They get a wider measure; every other page keeps the narrow + one. The class comes from the layout, which stamps the page name onto
. */ +main.page-deliveries, main.page-mail_queue, main.page-system_log { max-width: 64rem; } .card + .card { margin-top: 1.2rem; } .flash { background: #ecfdf3; border: 1px solid #abefc6; color: #067647; padding: 0.7rem 1rem; border-radius: 8px; margin-bottom: 1.2rem; } @media (prefers-color-scheme: dark) { .flash { background: #0d2818 !important; border-color: #1a5336 !important; color: #75d99b !important; } } table { width: 100%; border-collapse: collapse; } -th, td { text-align: left; padding: 0.5rem 0.4rem; border-bottom: 1px solid #e2e5e9; } +/* A table column is at least as wide as the longest unbreakable run inside it, + and the panel's tables are full of runs with nothing to break on: email + addresses, domains, queue ids. One 40-character recipient was enough to widen + the send-log past its card and hang Status over the edge. Cells may break mid + word, so a column can always be squeezed to the width available. */ +th, td { text-align: left; padding: 0.5rem 0.4rem; border-bottom: 1px solid #e2e5e9; overflow-wrap: anywhere; } +/* The exception: a timestamp broken across two lines is unreadable, and it is + short enough to never be the reason a row does not fit. */ +td.time { white-space: nowrap; } @media (prefers-color-scheme: dark) { th, td { border-color: #2b3138 !important; } } th { font-size: 0.8rem; text-transform: uppercase; letter-spacing: 0.03em; color: #6b7280; } td.actions { text-align: right; } -/* Subject is the one cell whose text we do not control, and a table sizes a - column to its longest unbreakable run — a long subject widens the row until - Status hangs past the card's edge. The clamp sits on an inner block box - rather than the cell because max-width on a is only advisory in the - automatic table layout; the full subject stays in the tooltip. */ +/* Subject is the one cell whose text we do not control. Breaking mid word (the + rule above) keeps it inside the card, but a long subject would do it by + growing the row several lines tall, which buries the rows around it. So the + subject is clipped to one line instead, with the whole of it in the tooltip. + The clamp sits on an inner block box rather than the cell because max-width + on a is only advisory in the automatic table layout. */ td.subject span { - display: block; max-width: 16rem; + display: block; max-width: 18rem; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } .code { display: block; white-space: pre-wrap; word-break: break-all; font-family: ui-monospace, SFMono-Regular, Menlo, monospace; diff --git a/internal/web/templates/deliveries_rows.html b/internal/web/templates/deliveries_rows.html index 9db934f..8aa6024 100644 --- a/internal/web/templates/deliveries_rows.html +++ b/internal/web/templates/deliveries_rows.html @@ -9,7 +9,7 @@ {{range .Rows}} - {{.CreatedAt.Format "2006-01-02 15:04:05"}} + {{.CreatedAt.Format "2006-01-02 15:04:05"}} {{.Domain}} {{.AppLogin}} {{.From}} diff --git a/internal/web/templates/layout.html b/internal/web/templates/layout.html index d4ec6d2..b6ce836 100644 --- a/internal/web/templates/layout.html +++ b/internal/web/templates/layout.html @@ -16,7 +16,12 @@ -
+{{/* The page name travels onto
as a class so the stylesheet can size a + page to what it holds — the monitoring pages are wider than the panel's + form pages (see main.page-* in panel.css). It is .Active, already carried + for the navigation, rather than a second field every handler would have to + remember to set. */}} +
{{if .User}}{{template "nav" .}}{{end}} {{template "content" .}} {{/* The running version, on every authenticated page: it is what a backup