Rebuild printable roast plans and remove machine-based adjustments
Test and deploy / test-and-deploy (push) Successful in 2m28s

This commit is contained in:
snowspeeder committed 2026-09-05 14:56:11 -04:00
1 parent e9f2393c96
commit 824a964f9d
30 files changed
+1721 -908

No files matched your search

+63 -29
View File
@@ -1,32 +1,66 @@
// Bakes live input values into their sibling .pv span before printing (so text doesn't clip
// at a fixed .f width the way a raw <input> would), then clears them after. One DOM, one
// rendering — see app.css's @media print block for the corresponding display swap.
//
// Operates on #print-sheet (not the passed-in screen `form`): the print worksheet lives
// outside #plan-form on purpose, so its inputs are addressed by container id instead.
export function initPrint({ beforePrint }) {
document.getElementById("btn-print").addEventListener("click", () => window.print());
import {
renderReportBody,
renderReportHtml,
REPORT_CSS,
} from "/shared/report.js?v=__ASSET_VERSION__";
export function initPrint({ getPlan, getName }) {
const style = document.createElement("style");
style.textContent =
REPORT_CSS +
"\n#report-print{display:none}@media print{body>*:not(#report-print){display:none!important}#report-print{display:block!important}}";
document.head.append(style);
const mount = document.createElement("div");
mount.id = "report-print";
document.body.append(mount);
window.addEventListener("beforeprint", () => {
beforePrint?.(); // re-sync the print worksheet's inputs from state.plan before baking
bakeValues();
mount.innerHTML = renderReportBody(getPlan(), getName());
});
window.addEventListener("afterprint", () => mount.replaceChildren());
const print = document.getElementById("btn-print");
print.addEventListener("click", () => window.print());
const download = document.createElement("button");
download.type = "button";
download.className = "ghost-btn";
download.textContent = "Download HTML";
download.addEventListener("click", () => {
const url = URL.createObjectURL(
new Blob([renderReportHtml(getPlan(), getName())], {
type: "text/html;charset=utf-8",
}),
);
const a = document.createElement("a");
a.href = url;
a.download =
(getName() || getPlan().fields?.["0.1"] || "roast-plan").replace(
/[^a-z0-9_-]+/gi,
"-",
) + ".html";
document.body.append(a);
a.click();
a.remove();
setTimeout(() => URL.revokeObjectURL(url), 1000);
});
print.after(download);
const preview = document.createElement("button");
preview.type = "button";
preview.className = "ghost-btn";
preview.textContent = "Preview report";
download.after(preview);
const dialog = document.createElement("dialog");
dialog.style.cssText =
"width: min(1000px,96vw);height:90vh;padding:12px;border:1px solid #ccc;border-radius:12px";
const close = document.createElement("button");
close.type = "button";
close.textContent = "Close preview";
close.addEventListener("click", () => dialog.close());
const frame = document.createElement("iframe");
frame.title = "Printable roast report";
frame.setAttribute("sandbox", "");
frame.style.cssText = "width:100%;height:calc(100% - 40px);border:0";
dialog.append(close, frame);
document.body.append(dialog);
preview.addEventListener("click", () => {
frame.srcdoc = renderReportHtml(getPlan(), getName());
dialog.showModal();
});
window.addEventListener("afterprint", () => clearBaked());
}
function printSheet() {
return document.getElementById("print-sheet");
}
function bakeValues() {
for (const el of printSheet().querySelectorAll("input.ws-input, textarea.ws-input")) {
if (el.type === "radio" || el.type === "checkbox") continue;
const pv = el.nextElementSibling;
if (pv && pv.classList.contains("pv")) pv.textContent = el.value || "";
}
}
function clearBaked() {
for (const pv of printSheet().querySelectorAll(".pv")) pv.textContent = "";
}