From 7e610f6c452a146f7e2dbffc3bc046c6594a67d3 Mon Sep 17 00:00:00 2001 From: danielededo <37807398+danielededo@users.noreply.github.com> Date: Thu, 22 Oct 2026 22:06:19 +0000 Subject: [PATCH] feat(report): two columns on a wide screen On a screen at least 1000 px wide the month takes two columns: the net pay, its summary and what changed beside where the gross pay went and what is set aside. The glossary takes two columns too. The sections over time and accrued stay one column, at most 860 px wide, so that their charts keep text of a size that reads well. The web app widens to 1120 px with the report. --- CHANGELOG.md | 6 ++++++ internal/report/report.html.tmpl | 20 ++++++++++++++++++-- web/style.css | 2 ++ web/test/e2e.test.mjs | 4 +++- 4 files changed, 29 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d8b3928..094f2c8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -25,6 +25,12 @@ How to use this file: months, charts and totals, and keeps the tab shown. A month is still compared with the one before it in the year before. +### Changed + +- On a wide screen the month takes two columns, what it is beside where the + gross pay went, and the glossary two; the charts over time keep a size at + which their text reads well, and the web app widens with the report. + ## [0.9.0] - 2026-10-22 ### Added diff --git a/internal/report/report.html.tmpl b/internal/report/report.html.tmpl index 9f2ec51..7660899 100644 --- a/internal/report/report.html.tmpl +++ b/internal/report/report.html.tmpl @@ -215,8 +215,8 @@ td.num, th.num { text-align: right; font-variant-numeric: tabular-nums; white-sp .status.inconsistent::before { content: "!"; } .changes { margin: 0; padding-left: 20px; } .changes > li { padding: 4px 0; } -.changes .why, .month > .why { color: var(--ink-2); font-size: 14px; } -.month > .why { margin: 4px 0 0; max-width: 40em; } +.changes .why, .m-head > .why { color: var(--ink-2); font-size: 14px; } +.m-head > .why { margin: 4px 0 0; max-width: 40em; } .more-changes { margin-top: 4px; } .more-changes > summary { font-size: 14px; color: var(--series-1); } .contract-note { margin-top: 12px; } @@ -228,6 +228,18 @@ footer { margin-top: 32px; font-size: 13px; color: var(--muted); } .embedded .who .sub, .embedded .who .person { margin-top: 0; } .embedded main { padding-top: 8px; padding-bottom: 8px; } .chart.narrow { display: none; } +/* A wide screen holds the month in two columns, what it is beside where + it went, and the glossary in two. */ +@media (min-width: 1000px) { + main { max-width: 1120px; } + section.month:not([hidden]) { display: grid; grid-template-columns: minmax(0, 5fr) minmax(0, 6fr); column-gap: 56px; align-items: start; } + .m-body > h2:first-child { margin-top: 8px; } + /* Charts keep a size where their text reads as on paper. */ + #panel-time > section, #panel-accrued > section { max-width: 860px; } + .glossary { columns: 2; column-gap: 56px; } + .glossary dt { break-after: avoid; } + .glossary dd { break-inside: avoid; } +} @media (max-width: 520px) { .chart.wide { display: none; } .chart.narrow { display: block; } @@ -637,6 +649,7 @@ footer { margin-top: 32px; font-size: 13px; color: var(--muted); } {{range $i, $m := .Months}}
+

{{$m.Label}} {{$m.StatusText}}{{if gt (len $.Months) 1}}{{end}}

{{index $.T "report.net"}}{{$m.Net}}

{{if $m.Gross}}

{{$m.Gross}}

{{end}} @@ -656,7 +669,9 @@ footer { margin-top: 32px; font-size: 13px; color: var(--muted); } {{end}} {{end}} {{end}} +
+
{{if $m.Parts}}

{{index $.T "report.where"}}

{{if $m.Earnings}}
@@ -700,6 +715,7 @@ footer { margin-top: 32px; font-size: 13px; color: var(--muted); }
{{end}}
{{end}} +
{{end}} diff --git a/web/style.css b/web/style.css index a40ad57..d05e03b 100644 --- a/web/style.css +++ b/web/style.css @@ -45,6 +45,8 @@ body { font: 16px/1.5 system-ui, -apple-system, "Segoe UI", Roboto, sans-serif; } .wrap { max-width: 760px; margin: 0 auto; padding: 0 16px; } +/* The report takes two columns on a wide screen: the page widens with it. */ +@media (min-width: 1000px) { .wrap { max-width: 1120px; } } svg { flex: none; } :focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; } .bar { position: sticky; top: 0; z-index: 2; border-bottom: 1px solid var(--line); background: color-mix(in srgb, var(--surface) 88%, transparent); backdrop-filter: saturate(1.4) blur(8px); -webkit-backdrop-filter: saturate(1.4) blur(8px); } diff --git a/web/test/e2e.test.mjs b/web/test/e2e.test.mjs index bee5f71..369b4d6 100644 --- a/web/test/e2e.test.mjs +++ b/web/test/e2e.test.mjs @@ -113,7 +113,9 @@ test('reads payslips in every style and rotation and shows the report', async () ]); const frame = page.frames().find((f) => f !== page.mainFrame()); await frame.waitForSelector('section.month:not([hidden]) .bar'); - await page.waitForFunction(() => parseInt(document.getElementById('report').style.height, 10) > 600); + // The frame grows to its content: shorter on this wide window, where + // the month takes two columns. + await page.waitForFunction(() => parseInt(document.getElementById('report').style.height, 10) > 400); // One payslip at a time: the picker switches, and a segment of the bar // opens its explanation. const shown = () => frame.$$eval('section.month', (ms) => ms.filter((m) => !m.hidden).map((m) => m.dataset.month));