panel: give the monitoring pages a width that fits their data
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 <main> 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 <noreply@anthropic.com>
This commit is contained in:
@@ -5,6 +5,13 @@ Format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/); version
|
|||||||
|
|
||||||
## [Unreleased]
|
## [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
|
### Fixed
|
||||||
|
|
||||||
- panel: Deliveries now shows the subject as text rather than as its MIME
|
- 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,
|
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.
|
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
|
## [0.3.0] - 2026-08-03
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
|
|||||||
@@ -50,21 +50,38 @@ button:hover, a.btn:hover { background: #1d4ed8; }
|
|||||||
form's block layout; its button is styled like any other. */
|
form's block layout; its button is styled like any other. */
|
||||||
form.inline { display: inline; margin: 0; }
|
form.inline { display: inline; margin: 0; }
|
||||||
main { max-width: 48rem; }
|
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>. */
|
||||||
|
main.page-deliveries, main.page-mail_queue, main.page-system_log { max-width: 64rem; }
|
||||||
.card + .card { margin-top: 1.2rem; }
|
.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; }
|
.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; } }
|
@media (prefers-color-scheme: dark) { .flash { background: #0d2818 !important; border-color: #1a5336 !important; color: #75d99b !important; } }
|
||||||
table { width: 100%; border-collapse: collapse; }
|
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; } }
|
@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; }
|
th { font-size: 0.8rem; text-transform: uppercase; letter-spacing: 0.03em; color: #6b7280; }
|
||||||
td.actions { text-align: right; }
|
td.actions { text-align: right; }
|
||||||
/* Subject is the one cell whose text we do not control, and a table sizes a
|
/* Subject is the one cell whose text we do not control. Breaking mid word (the
|
||||||
column to its longest unbreakable run — a long subject widens the row until
|
rule above) keeps it inside the card, but a long subject would do it by
|
||||||
Status hangs past the card's edge. The clamp sits on an inner block box
|
growing the row several lines tall, which buries the rows around it. So the
|
||||||
rather than the cell because max-width on a <td> is only advisory in the
|
subject is clipped to one line instead, with the whole of it in the tooltip.
|
||||||
automatic table layout; the full subject stays in the tooltip. */
|
The clamp sits on an inner block box rather than the cell because max-width
|
||||||
|
on a <td> is only advisory in the automatic table layout. */
|
||||||
td.subject span {
|
td.subject span {
|
||||||
display: block; max-width: 16rem;
|
display: block; max-width: 18rem;
|
||||||
overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
|
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;
|
.code { display: block; white-space: pre-wrap; word-break: break-all; font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
<tbody>
|
<tbody>
|
||||||
{{range .Rows}}
|
{{range .Rows}}
|
||||||
<tr>
|
<tr>
|
||||||
<td class="muted">{{.CreatedAt.Format "2006-01-02 15:04:05"}}</td>
|
<td class="time muted">{{.CreatedAt.Format "2006-01-02 15:04:05"}}</td>
|
||||||
<td>{{.Domain}}</td>
|
<td>{{.Domain}}</td>
|
||||||
<td>{{.AppLogin}}</td>
|
<td>{{.AppLogin}}</td>
|
||||||
<td>{{.From}}</td>
|
<td>{{.From}}</td>
|
||||||
|
|||||||
@@ -16,7 +16,12 @@
|
|||||||
<script src="/static/panel.js" defer></script>
|
<script src="/static/panel.js" defer></script>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<main>
|
{{/* The page name travels onto <main> 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. */}}
|
||||||
|
<main class="page-{{.Active}}">
|
||||||
{{if .User}}{{template "nav" .}}{{end}}
|
{{if .User}}{{template "nav" .}}{{end}}
|
||||||
{{template "content" .}}
|
{{template "content" .}}
|
||||||
{{/* The running version, on every authenticated page: it is what a backup
|
{{/* The running version, on every authenticated page: it is what a backup
|
||||||
|
|||||||
Reference in New Issue
Block a user