From b664f6aaee4938b56f3ac2b82850a91a845932a4 Mon Sep 17 00:00:00 2001 From: Alexander Mills Date: Sat, 1 Aug 2026 21:33:10 -0500 Subject: [PATCH 1/5] feat(DEN-1343): harden accessible and printable report structure --- scripts/render-release-plan-html.mjs | 39 +++++++++++++++++++++++++--- 1 file changed, 36 insertions(+), 3 deletions(-) diff --git a/scripts/render-release-plan-html.mjs b/scripts/render-release-plan-html.mjs index 15e996e1..00f06a6d 100644 --- a/scripts/render-release-plan-html.mjs +++ b/scripts/render-release-plan-html.mjs @@ -9,6 +9,10 @@ const STYLE = ` :root{color-scheme:light dark;font-family:ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,"Segoe UI",sans-serif;line-height:1.5} *{box-sizing:border-box} body{margin:0;background:Canvas;color:CanvasText} +.skip-link{position:absolute;left:.75rem;top:.75rem;z-index:10;padding:.6rem .8rem;background:Canvas;color:CanvasText;border:2px solid CanvasText;border-radius:.4rem;transform:translateY(-200%)} +.skip-link:focus{transform:translateY(0)} +.visually-hidden{position:absolute!important;width:1px!important;height:1px!important;padding:0!important;margin:-1px!important;overflow:hidden!important;clip:rect(0,0,0,0)!important;white-space:nowrap!important;border:0!important} +.no-js .filter-controls{display:none} main{width:min(88rem,100%);margin:0 auto;padding:clamp(1rem,4vw,3rem)} header,.panel{border:1px solid color-mix(in srgb,CanvasText 22%,transparent);border-radius:.9rem;padding:clamp(1rem,3vw,1.5rem);margin-block:1rem} .eyebrow{margin:0;font-size:.78rem;font-weight:750;letter-spacing:.09em;text-transform:uppercase} @@ -19,10 +23,12 @@ h1,h2{line-height:1.2;overflow-wrap:anywhere} .metrics{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:.8rem} .metric span{font-size:clamp(1.6rem,5vw,2.5rem);font-weight:800} label{display:block;font-weight:700;margin-bottom:.4rem} +.filter-help{margin:.35rem 0 .65rem} input{width:100%;min-height:2.75rem;padding:.65rem .75rem;border:1px solid color-mix(in srgb,CanvasText 28%,transparent);border-radius:.55rem;background:Canvas;color:CanvasText;font:inherit} input:focus-visible,a:focus-visible{outline:.2rem solid Highlight;outline-offset:.15rem} .table-wrap{overflow-x:auto;border:1px solid color-mix(in srgb,CanvasText 20%,transparent);border-radius:.65rem} table{width:100%;border-collapse:collapse;min-width:44rem} +caption{text-align:left;font-weight:700;padding:.7rem} th,td{text-align:left;vertical-align:top;padding:.7rem;border-bottom:1px solid color-mix(in srgb,CanvasText 14%,transparent)} th{font-size:.78rem;letter-spacing:.05em;text-transform:uppercase;background:color-mix(in srgb,Canvas 92%,CanvasText 8%)} tbody tr:last-child td{border-bottom:0} @@ -31,14 +37,35 @@ code{overflow-wrap:anywhere;word-break:break-word} .empty{text-align:center;font-style:italic} footer{padding:1rem 0;font-size:.9rem} @media(max-width:42rem){.metrics{grid-template-columns:1fr}.panel,header{border-radius:.65rem}table{min-width:36rem}} +@media(forced-colors:active){header,.panel,.provenance li,.metric,.table-wrap,input{border-color:CanvasText}.provenance li,.metric,th{background:Canvas}} +@page{margin:12mm} +@media print{ + :root{color-scheme:light} + body{background:#fff;color:#000;font-size:10pt} + main{width:100%;padding:0} + .skip-link,.filter-controls,noscript{display:none!important} + header,.panel{border:0;border-radius:0;padding:0;margin:0 0 1rem} + .provenance{grid-template-columns:repeat(2,minmax(0,1fr))} + .provenance li,.metric{background:#fff;border:1px solid #000} + .table-wrap{overflow:visible;border:0} + table{min-width:0;font-size:8.5pt} + caption{padding:.3rem 0} + thead{display:table-header-group} + tr,.provenance li,.metric{break-inside:avoid} + [hidden]{display:table-row!important} + th{background:#fff;color:#000} + footer{border-top:1px solid #000;margin-top:1rem} +} `; const SCRIPT = ` (() => { "use strict"; + document.documentElement.classList.remove("no-js"); const input = document.querySelector("#artifact-filter"); const status = document.querySelector("#filter-status"); const rows = [...document.querySelectorAll("tbody tr[data-search]")]; + input.disabled = false; const apply = () => { const query = input.value.trim().toLocaleLowerCase(); let visible = 0; @@ -167,6 +194,7 @@ function tableSection({ id, title, description, headers, rows, empty }) {

${escapeHtml(title)}

${escapeHtml(description)}

+${headers.map((header) => ``).join("")}${body}
${escapeHtml(title)}. ${escapeHtml(description)}
${escapeHtml(header)}
@@ -228,7 +256,7 @@ export function renderReleasePlan(input) { ].join("; "); return ` - + @@ -237,7 +265,8 @@ export function renderReleasePlan(input) { -
+ +

Credential-free release review

${escapeHtml(plan.release_set)}

@@ -257,10 +286,14 @@ export function renderReleasePlan(input) {
Forge mirrors${counts.forge}

${total} total planned artifacts and mirrors.

+
- +

Search target, registry, package, tag, or directory. Press Escape to clear.

+

Showing all ${total} artifacts.

+
+ ${tableSection({ id: "zed", title: "Zed artifacts", From 5b13accfc36af1e5bece1378a10bcf3829e5fd23 Mon Sep 17 00:00:00 2001 From: Alexander Mills Date: Sat, 1 Aug 2026 21:33:32 -0500 Subject: [PATCH 2/5] test(DEN-1343): lock accessibility and print structure --- tests/release_plan_accessibility_test.mjs | 67 +++++++++++++++++++++++ 1 file changed, 67 insertions(+) create mode 100644 tests/release_plan_accessibility_test.mjs diff --git a/tests/release_plan_accessibility_test.mjs b/tests/release_plan_accessibility_test.mjs new file mode 100644 index 00000000..a1ed2151 --- /dev/null +++ b/tests/release_plan_accessibility_test.mjs @@ -0,0 +1,67 @@ +import assert from "node:assert/strict"; +import test from "node:test"; + +import { renderReleasePlan } from "../scripts/render-release-plan-html.mjs"; + +const fixture = { + release_set: "acme/browser-report@1.2.3#v1.2.3", + source: { + package: "acme/browser-report", + version: "1.2.3", + vcs_tag: "v1.2.3", + repository: "https://github.com/acme/browser-report", + }, + zed: [ + { target: "nodejs", package: "acme/browser-report-node", version: "1.2.3", dir: "node" }, + ], + native: [ + { + target: "nodejs", + registry: "npm", + package: "@acme/browser-report", + version: "1.2.3", + vcs_tag: "v1.2.3", + dir: "node", + }, + ], + forge: [], +}; + +test("report includes progressive-enhancement accessibility structure", () => { + const html = renderReleasePlan(fixture); + assert.match(html, //); + assert.match(html, /