fix: improve Claw PDF table print layout

This commit is contained in:
134 2026-06-25 21:53:19 +08:00
parent e02dff0b06
commit 934bc56202

View File

@ -45,6 +45,10 @@ function clonePrintableStyles(targetWindow: Window) {
function createPrintOverrides(targetWindow: Window) {
const style = targetWindow.document.createElement("style");
style.textContent = `
* {
box-sizing: border-box;
}
:root {
--background: #ffffff;
--foreground: #111827;
@ -142,14 +146,32 @@ function createPrintOverrides(targetWindow: Window) {
.claw-pdf-content {
font-size: 14px;
line-height: 1.7;
overflow: visible;
}
.claw-pdf-content,
.claw-pdf-content * {
max-width: 100%;
}
[data-pdf-exclude="true"] {
display: none !important;
}
.chat-card-x-scroll {
.claw-pdf-table-card {
break-inside: auto;
page-break-inside: auto;
overflow: visible !important;
width: 100% !important;
max-width: 100% !important;
border-radius: 10px !important;
}
.chat-card-x-scroll {
display: block !important;
overflow: visible !important;
width: 100% !important;
max-width: 100% !important;
padding-bottom: 0 !important;
scrollbar-width: none !important;
}
@ -159,13 +181,69 @@ function createPrintOverrides(targetWindow: Window) {
}
table {
width: 100% !important;
min-width: 0 !important;
max-width: 100% !important;
table-layout: fixed !important;
border-collapse: collapse !important;
page-break-inside: auto;
break-inside: auto;
font-size: 11px !important;
line-height: 1.45 !important;
}
.claw-pdf-wide-table {
font-size: 10px !important;
}
.claw-pdf-extra-wide-table {
font-size: 9px !important;
}
thead {
display: table-header-group;
}
tbody {
display: table-row-group;
}
tr {
page-break-inside: avoid;
break-inside: avoid;
}
th,
td {
min-width: 0 !important;
width: auto !important;
max-width: none !important;
white-space: normal !important;
overflow-wrap: anywhere !important;
word-break: break-word !important;
text-overflow: clip !important;
vertical-align: top !important;
padding: 5px 7px !important;
line-height: 1.45 !important;
}
th {
text-align: left !important;
font-weight: 700 !important;
}
.claw-pdf-wide-table th,
.claw-pdf-wide-table td,
.claw-pdf-extra-wide-table th,
.claw-pdf-extra-wide-table td {
padding-left: 5px !important;
padding-right: 5px !important;
}
tr,
svg,
img {
page-break-inside: avoid;
break-inside: avoid;
}
svg {
@ -189,6 +267,58 @@ function createPrintOverrides(targetWindow: Window) {
targetWindow.document.head.appendChild(style);
}
function getTableColumnCount(table: HTMLTableElement) {
return Array.from(table.rows).reduce(
(maxColumns, row) => Math.max(maxColumns, row.cells.length),
0
);
}
function preparePrintableTables(root: HTMLElement) {
root.querySelectorAll<HTMLTableElement>("table").forEach((table) => {
const columnCount = getTableColumnCount(table);
table.dataset.pdfColumnCount = String(columnCount);
table.classList.toggle("claw-pdf-wide-table", columnCount >= 5);
table.classList.toggle("claw-pdf-extra-wide-table", columnCount >= 7);
const scrollWrapper = table.closest(".chat-card-x-scroll");
scrollWrapper?.parentElement?.classList.add("claw-pdf-table-card");
});
}
function waitForFrame(targetWindow: Window) {
return new Promise<void>((resolve) => {
targetWindow.requestAnimationFrame(() => resolve());
});
}
async function waitForPrintableAssets(targetWindow: Window, root: HTMLElement) {
const fontReady =
"fonts" in targetWindow.document
? targetWindow.document.fonts.ready.catch(() => undefined)
: Promise.resolve();
const images = Array.from(root.querySelectorAll<HTMLImageElement>("img"));
const imageReady = Promise.all(
images.map((image) => {
if (image.complete && image.naturalWidth > 0) return Promise.resolve();
if (typeof image.decode === "function") {
return image.decode().catch(() => undefined);
}
return new Promise<void>((resolve) => {
image.addEventListener("load", () => resolve(), { once: true });
image.addEventListener("error", () => resolve(), { once: true });
});
})
);
await Promise.race([
Promise.all([fontReady, imageReady]),
new Promise((resolve) => targetWindow.setTimeout(resolve, 1800)),
]);
await waitForFrame(targetWindow);
await waitForFrame(targetWindow);
}
export function ResponsePdfDownloadButton({
contentRef,
fileName,
@ -273,15 +403,21 @@ export function ResponsePdfDownloadButton({
clonedContent
.querySelectorAll('[data-pdf-exclude="true"]')
.forEach((node) => node.remove());
preparePrintableTables(clonedContent);
content.appendChild(clonedContent);
shell.appendChild(content);
printWindow.document.body.appendChild(shell);
window.setTimeout(() => {
setIsPreparing(false);
printWindow.focus();
printWindow.print();
}, 600);
void waitForPrintableAssets(printWindow, shell)
.catch((error) => {
console.warn("[Response PDF] asset readiness check failed:", error);
})
.finally(() => {
setIsPreparing(false);
if (printWindow.closed) return;
printWindow.focus();
printWindow.print();
});
} catch (error) {
setIsPreparing(false);
printWindow.close();