diff --git a/src/app/globals.css b/src/app/globals.css index b3f526a..4a0adc8 100644 --- a/src/app/globals.css +++ b/src/app/globals.css @@ -1965,14 +1965,23 @@ button.structure-entry-main:focus-visible { display: none; } +/* Druck im kbp-CD der Seitenansicht (src/frontend/print/print-document.css): + gleiche Farben, Schrift, Titelblock und Fußzeile. Die Fußzeile mit + Seitenzahlen setzt EstimatePrintHeader als @page-Regel mit Projektdaten. */ +.estimate-print-titleblock { + display: none; +} + @page estimate-balance { size: A4 landscape; - margin: 10mm; + margin: 10mm 10mm 13mm; } @media print { body:has(.estimate-print-root) .sidebar, .estimate-print-root .estimate-no-print, + .estimate-print-root .estimate-page-header, + .estimate-print-root .estimate-header-fields, .estimate-print-root .alert, .estimate-print-root input, .estimate-print-root select, @@ -1989,28 +1998,122 @@ button.structure-entry-main:focus-visible { } .estimate-print-root { + --ep-blue: #476088; + --ep-lilac: #9198c4; + --ep-line: #d6dae5; + --ep-tint: #f5f6fa; + --ep-text: #2b2b2b; + --ep-muted: #6b7280; + --ep-accent: #c9782a; page: estimate-balance; padding: 0 !important; max-width: none; - color: #000; + color: var(--ep-text); + font-family: Arial, "Helvetica Neue", Helvetica, sans-serif; + color-scheme: light; + } + + .estimate-print-root * { + -webkit-print-color-adjust: exact; + print-color-adjust: exact; } .estimate-print-root .estimate-print-value { display: inline; } - .estimate-print-root .page-header { + /* Titelblock wie der Plankopf der Seitenansicht */ + .estimate-print-titleblock { + display: grid; + grid-template-columns: 30mm 1fr auto auto; margin-bottom: 4mm; + border: 1.5px solid var(--ep-blue); + background: #fff; + font-size: 8.5pt; + break-inside: avoid; } - .estimate-print-root .page-header h1 { - font-size: 14pt; - color: #000; + .estimate-print-titleblock > * { + padding: 2.5mm 3.5mm; + border-left: 1px solid var(--ep-line); } + .estimate-print-titleblock > :first-child { + border-left: none; + } + + .estimate-print-logo { + display: flex; + align-items: center; + justify-content: center; + min-height: 16mm; + color: var(--ep-blue); + font-weight: bold; + text-align: center; + } + + .estimate-print-logo img { + max-width: 100%; + max-height: 10mm; + } + + .estimate-print-kicker { + color: var(--ep-muted); + font-size: 7pt; + letter-spacing: 0.05em; + text-transform: uppercase; + } + + .estimate-print-heading { + display: flex; + align-items: baseline; + flex-wrap: wrap; + gap: 1mm 4mm; + margin-top: 1mm; + } + + .estimate-print-stand { + color: var(--ep-blue); + font-size: 16pt; + font-weight: bold; + } + + .estimate-print-project { + font-size: 12pt; + font-weight: bold; + } + + .estimate-print-meta { + display: grid; + grid-template-columns: auto auto; + gap: 0.8mm 4mm; + align-content: center; + margin: 0; + font-size: 7.5pt; + } + + .estimate-print-meta div { + display: contents; + } + + .estimate-print-meta dt { + color: var(--ep-muted); + font-weight: normal; + } + + .estimate-print-meta dd { + margin: 0; + font-weight: bold; + } + + .estimate-print-meta.is-tinted { + background: var(--ep-tint); + } + + /* Karten und Ränder der Bildschirmansicht entfallen */ .estimate-print-root .card { border: 0; - box-shadow: none; + box-shadow: none !important; background: transparent; } @@ -2026,54 +2129,117 @@ button.structure-entry-main:focus-visible { break-inside: avoid; } + .estimate-print-root .estimate-comparison-card .card-header { + margin-bottom: 2mm; + color: var(--ep-blue); + font-size: 10pt; + font-weight: bold; + } + .estimate-sheet-wrap { overflow: visible; } + /* Tabelle */ .estimate-sheet { min-width: 0; table-layout: auto; - font-size: 7.5pt; + font-size: 7.4pt; + line-height: 1.2; background: #fff; - color: #000; + color: var(--ep-text); } .estimate-sheet th, .estimate-sheet td { - border-color: #999; - padding: 1px 3px; + border: 1px solid var(--ep-line) !important; + padding: 0.7mm 1.5mm; + background: #fff; + color: var(--ep-text); } .estimate-sheet thead { display: table-header-group; } - .estimate-sheet thead th, - .estimate-total-row td { - background: #e8e8e8 !important; + .estimate-sheet thead th { + background: var(--ep-blue) !important; + border-color: var(--ep-blue) !important; + color: #fff !important; + font-weight: bold; + vertical-align: bottom; + } + + .estimate-sheet thead .estimate-th-hint { + color: #dfe3f0 !important; } .estimate-group-title-row td { - background: #d9d9d9 !important; + background: var(--ep-tint) !important; + border-top: 1.5px solid var(--ep-lilac) !important; + font-weight: bold; + } + + .estimate-group-title-row .estimate-cost-group-cell { + color: var(--ep-blue) !important; + } + + .estimate-group-title-row .estimate-group-editor { + color: var(--ep-muted); + font-weight: normal; } .estimate-subtotal-row td { - background: #f2f2f2 !important; + border-bottom: 1.5px solid var(--ep-line) !important; + font-weight: bold; + } + + .estimate-subtotal-row .estimate-total-label { + color: var(--ep-muted); + } + + .estimate-total-row td { + background: var(--ep-tint) !important; + font-weight: bold; + } + + .estimate-total-row.is-strong td { + background: var(--ep-blue) !important; + border-color: var(--ep-blue) !important; + color: #fff !important; + } + + .estimate-total-row .estimate-total-hint { + color: var(--ep-muted); + font-weight: normal; + } + + .estimate-total-row.is-strong .estimate-total-hint { + color: #dfe3f0; + } + + .estimate-comparison .is-over { + color: var(--ep-accent) !important; + font-weight: bold; + } + + .estimate-comparison .is-under { + color: var(--ep-blue) !important; + font-weight: bold; } .estimate-group-title-row, .estimate-subtotal-row, - .estimate-total-row { + .estimate-total-row, + .estimate-row { break-inside: avoid; - -webkit-print-color-adjust: exact; - print-color-adjust: exact; } .estimate-group-title-row { break-after: avoid; } - /* Totals print once at the end, not repeated on every page. */ + /* Summen einmal am Ende, nicht auf jeder Seite */ .estimate-sheet tfoot { display: table-row-group; break-inside: avoid; @@ -2087,8 +2253,4 @@ button.structure-entry-main:focus-visible { .estimate-gzf-input { justify-content: flex-end; } - - .estimate-header-fields { - margin-bottom: 3mm; - } } diff --git a/src/app/projects/[projectId]/grobbilanz/[balanceId]/page.tsx b/src/app/projects/[projectId]/grobbilanz/[balanceId]/page.tsx index 2aa7f5e..584f5cf 100644 --- a/src/app/projects/[projectId]/grobbilanz/[balanceId]/page.tsx +++ b/src/app/projects/[projectId]/grobbilanz/[balanceId]/page.tsx @@ -48,6 +48,7 @@ import { } from "../../../../../frontend/estimate-balance/estimate-balance-sheet"; import { EstimateComparisonTable } from "../../../../../frontend/estimate-balance/estimate-comparison-table"; import { DraftInput } from "../../../../../frontend/estimate-balance/estimate-draft-input"; +import { EstimatePrintHeader } from "../../../../../frontend/estimate-balance/estimate-print-header"; import { EstimateGroupModal, type EstimateGroupFormValues, @@ -461,6 +462,7 @@ export default function EstimateBalanceEditorPage() { return (
+ {project && draft ? : null}
\r\n]/g, " ")); +} + +/** + * Print-only title block and page footer of the rough power balance in the + * kbp corporate design of the print view (Seitenansicht): logo, blue title, + * meta data, "Seite x von y". Hidden on screen. + */ +export function EstimatePrintHeader({ project, balance }: EstimatePrintHeaderProps) { + const [office, setOffice] = useState(null); + const [hasLogo, setHasLogo] = useState(false); + const [logoVersion, setLogoVersion] = useState(""); + + useEffect(() => { + getDocumentBranding() + .then((branding) => { + setOffice(branding.office); + setHasLogo(Boolean(branding.logo)); + setLogoVersion(branding.logo ? branding.logo.updatedAtIso : ""); + }) + .catch(() => { + setOffice(null); + setHasLogo(false); + }); + }, []); + + const stand = [balance.name, balance.workStage].filter(Boolean).join(" · "); + const date = balance.dateIso ? formatIsoDateGerman(balance.dateIso) : null; + const footer = ` + @page estimate-balance { + size: A4 landscape; + margin: 10mm 10mm 13mm; + @bottom-left { content: ${cssString(`${project.name} · Grobe Leistungsbilanz`)}; font: 7.5pt Arial, sans-serif; color: #6b7280; } + @bottom-center { content: ${cssString(`Stand ${stand}${date ? ` · ${date}` : ""}`)}; font: 7.5pt Arial, sans-serif; color: #6b7280; } + @bottom-right { content: "Seite " counter(page) " von " counter(pages); font: 7.5pt Arial, sans-serif; color: #6b7280; } + }`; + + return ( + <> + + + + ); +}