style(orion): align report header footer and page layout

This commit is contained in:
Schubert Ferenc 2026-07-11 12:19:10 +02:00
parent 302e542fda
commit 503b343070
40 changed files with 2010 additions and 148 deletions

View file

@ -1,33 +1,14 @@
@page {
size: A4;
margin: 24mm 16mm 22mm 16mm;
@top-left {
content: "Validation Suite";
color: #4F6A74;
font-size: 9pt;
font-weight: 700;
}
@top-right {
content: string(report-number);
color: #6B7C85;
font-size: 9pt;
}
@bottom-left {
content: "Schubamed";
color: #6B7C85;
font-size: 8pt;
}
@bottom-right {
content: "Seite " counter(page) " von " counter(pages);
color: #6B7C85;
font-size: 8pt;
}
margin: 34mm 18mm 24mm 18mm;
@top-left { content: element(report-header); }
@bottom-left { content: element(report-footer); }
}
@page:first {
margin: 20mm 16mm 18mm 16mm;
margin: 20mm 18mm 20mm 18mm;
@top-left { content: ""; }
@top-right { content: ""; }
@bottom-left { content: ""; }
}
* {
@ -46,17 +27,137 @@ body {
}
.report-meta {
string-set: report-number attr(data-report-number);
string-set: report-number attr(data-report-number), report-version attr(data-report-version), report-date attr(data-report-date);
}
.report-header {
align-items: center;
border-bottom: .25mm solid #DCE3E3;
display: grid;
grid-template-columns: 1fr 54mm;
height: 24mm;
left: 0;
padding-bottom: 3mm;
position: running(report-header);
top: 0;
width: 174mm;
}
.report-header-brand {
align-items: center;
display: flex;
gap: 4mm;
min-width: 0;
}
.report-header-brand img {
display: block;
height: 20mm;
width: auto;
}
.report-header-brand strong {
color: #2E3B40;
display: block;
font-size: 15pt;
letter-spacing: 0;
line-height: 1.05;
}
.report-header-brand span {
color: #6B7C85;
display: block;
font-size: 9pt;
line-height: 1.35;
margin-top: 1mm;
}
.report-header-meta {
color: #4F5E63;
display: grid;
gap: 1.2mm;
margin: 0;
text-align: right;
}
.report-header-meta div,
.report-footer {
display: grid;
grid-template-columns: 1fr;
}
.report-header-meta dt {
display: none;
}
.report-header-meta dd {
font-size: 9pt;
margin: 0;
}
.report-header-meta div:first-child dd {
color: #2E3B40;
font-size: 10pt;
font-weight: 700;
}
.report-footer {
align-items: center;
border-top: .25mm solid #DCE3E3;
color: #6B7C85;
font-size: 8pt;
grid-template-columns: 1fr 1fr 1fr;
height: 10mm;
padding-top: 2.5mm;
position: running(report-footer);
width: 174mm;
}
.report-footer span:nth-child(2) {
text-align: center;
}
.report-footer span:nth-child(3) {
text-align: right;
}
.page-number::before {
content: counter(page);
}
.page-count::before {
content: counter(pages);
}
.cover-page {
min-height: 245mm;
display: flex;
flex-direction: column;
justify-content: center;
justify-content: flex-start;
page-break-after: always;
}
.cover-top {
align-items: flex-start;
display: grid;
gap: 18mm;
grid-template-columns: 1fr 55mm;
margin-bottom: 32mm;
}
.cover-logo {
height: 16mm;
justify-self: end;
width: auto;
}
.company-address {
color: #6B7C85;
font-size: 9pt;
line-height: 1.5;
text-align: right;
}
.cover-kicker {
color: #6C8A96;
font-size: 11pt;
@ -93,17 +194,29 @@ h1 {
}
.chapter {
break-before: page;
break-before: auto;
margin-top: 9mm;
}
h2 {
border-bottom: 1px solid #E6EAEA;
border-bottom: .25mm solid #DCE3E3;
color: #2E3B40;
font-size: 18pt;
margin: 0 0 8mm 0;
font-size: 22pt;
font-weight: 700;
letter-spacing: 0;
line-height: 1.15;
margin: 0 0 7mm 0;
padding-bottom: 4mm;
}
.chapter + .chapter {
margin-top: 12mm;
}
.chapter > p:only-child {
margin-bottom: 0;
}
h3 {
color: #4F6A74;
font-size: 12pt;
@ -176,6 +289,32 @@ dd {
text-decoration: none;
}
.figure-grid {
display: grid;
gap: 8mm;
grid-template-columns: 1fr 1fr;
margin-top: 8mm;
}
.report-figure {
break-inside: avoid;
margin: 0;
}
.report-image {
border: 1px solid #E6EAEA;
display: block;
max-height: 90mm;
object-fit: contain;
width: 100%;
}
figcaption {
color: #6B7C85;
font-size: 8.5pt;
margin-top: 2mm;
}
@media screen {
body {
background: #F7F8F8;
@ -190,6 +329,14 @@ dd {
padding: 48px;
}
.report-header,
.report-footer {
left: auto;
margin: 0 auto 32px auto;
position: static;
width: 100%;
}
.cover-page {
min-height: auto;
}
@ -198,4 +345,12 @@ dd {
break-before: auto;
margin-top: 48px;
}
.report-footer {
margin: 48px auto 0 auto;
}
.figure-grid {
gap: 24px;
}
}

View file

@ -2,12 +2,41 @@ from __future__ import annotations
from pathlib import Path
from app.modules.orion.assets import schubamed_logo_uri
from app.modules.orion.context import ReportContext
from app.modules.orion.html import text
def render_report_chrome(context: ReportContext, logo_uri: str) -> str:
report_number = text(context.validation.report_number)
version = text(context.validation.version)
report_date = text(context.validation.updated_at)
return f"""
<header class="report-header" aria-label="Berichtskopf">
<div class="report-header-brand">
<img src="{logo_uri}" alt="SCHUBAMED">
<div>
<strong>SCHUBAMED®</strong>
<span>Aufbereitung mit System</span>
</div>
</div>
<dl class="report-header-meta">
<div><dt>Berichtsnummer</dt><dd>{report_number}</dd></div>
<div><dt>Version</dt><dd>{version}</dd></div>
<div><dt>Datum</dt><dd>{report_date}</dd></div>
</dl>
</header>
<footer class="report-footer" aria-label="Berichtsfuß">
<span>Validation Suite</span>
<span>Seite <span class="page-number"></span> von <span class="page-count"></span></span>
<span>Version {version}</span>
</footer>
"""
def render_document(context: ReportContext, chapters: list[str]) -> str:
css = (Path(__file__).resolve().parent / "report.css").read_text(encoding="utf-8")
logo_uri = schubamed_logo_uri()
title = f"Validierungsbericht {context.validation.report_number}"
chapter_markup = "\n".join(chapters)
return f"""<!doctype html>
@ -20,9 +49,9 @@ def render_document(context: ReportContext, chapters: list[str]) -> str:
</head>
<body>
<article class="report-document">
<div class="report-meta" data-report-number="{text(context.validation.report_number)}"></div>
<div class="report-meta" data-report-number="{text(context.validation.report_number)}" data-report-version="{text(context.validation.version)}" data-report-date="{text(context.validation.updated_at)}"></div>
{render_report_chrome(context, logo_uri)}
{chapter_markup}
</article>
</body>
</html>"""