fix(client-handover): PDF render bugs — marked CLI, white cover, PNG logo
Three bugs surfaced on the LIVRAISON.pdf test render: 1. **MD→HTML conversion** — host had no pandoc, no python-markdown, fell back to `npx marked < "$src"`. marked CLI 16.x ignores stdin and dumps its own cli.js source. Resulting PDF body = marked's binary source (`#!/usr/bin/env node`, `Marked CLI`, copyright). Fix: `npx --yes marked --gfm -i "$src"` (file path via -i, not stdin). 2. **Cover background** — original cream `#F5F0EB` + 8mm green stripe was washed out. Iterated to white-pure bg with subtle radial sage/forest tints, black-deep title, green-forest accents (eyebrow, meta labels, footer, border). Solid green-dark tried first then rejected (too heavy for long client-facing doc). 3. **Default logo** — SVG `logo-horizontal.svg` rendered cream-toned, blended into bg. Switched LOGO_URL default to `https://zenquality.fr/assets/logo-horizontal-1024.png`. Also added test-artifact gitignore rules for LIVRAISON.* / HANDOVER.* project-local renders. Verified: regenerated LIVRAISON.pdf → 164 KB, 19 pages, full content rendered, white cover with black title + green-forest accents + visible PNG logo. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
591a035ec6
commit
b447a892b1
8
.gitignore
vendored
8
.gitignore
vendored
@ -86,6 +86,14 @@ hooks/node_modules/
|
|||||||
graphify-out/
|
graphify-out/
|
||||||
.ctx7-cache/
|
.ctx7-cache/
|
||||||
|
|
||||||
|
# /client-handover test artifacts (project-local renders)
|
||||||
|
LIVRAISON.md
|
||||||
|
LIVRAISON.html
|
||||||
|
LIVRAISON.pdf
|
||||||
|
HANDOVER.md
|
||||||
|
HANDOVER.html
|
||||||
|
HANDOVER.pdf
|
||||||
|
|
||||||
# Install logs
|
# Install logs
|
||||||
install-*.log
|
install-*.log
|
||||||
|
|
||||||
|
|||||||
@ -1216,9 +1216,12 @@ The renderer:
|
|||||||
(pandoc > python-markdown > `npx marked`).
|
(pandoc > python-markdown > `npx marked`).
|
||||||
2. Wraps the body in the ZenQuality template (cover page + branded
|
2. Wraps the body in the ZenQuality template (cover page + branded
|
||||||
typography Inter + Playfair Display, ZenQuality green palette
|
typography Inter + Playfair Display, ZenQuality green palette
|
||||||
`#1A3A25 / #2D5A3D / #4A7C59 / #87A878`, cream page background
|
`#1A3A25 / #2D5A3D / #4A7C59 / #87A878`, **white cover**
|
||||||
`#F5F0EB`).
|
(`--white-pure`) with black-deep title and green-forest accents
|
||||||
3. Embeds the ZenQuality logo (default: `https://zenquality.fr/logo-horizontal.svg`;
|
(eyebrow, meta labels, footer); subtle radial sage + forest tints
|
||||||
|
add depth. Cream `#F5F0EB` reserved for body code/blockquote
|
||||||
|
accents — not page bg).
|
||||||
|
3. Embeds the ZenQuality logo (default: `https://zenquality.fr/assets/logo-horizontal-1024.png`;
|
||||||
override with `LOGO_URL` env var to use a local file).
|
override with `LOGO_URL` env var to use a local file).
|
||||||
4. Emits `LIVRAISON.html` (or `HANDOVER.html`) next to the `.md`.
|
4. Emits `LIVRAISON.html` (or `HANDOVER.html`) next to the `.md`.
|
||||||
5. Tries PDF engines in order: weasyprint > wkhtmltopdf > chromium >
|
5. Tries PDF engines in order: weasyprint > wkhtmltopdf > chromium >
|
||||||
|
|||||||
@ -75,8 +75,9 @@ html, body {
|
|||||||
padding: 35mm 22mm 22mm 22mm;
|
padding: 35mm 22mm 22mm 22mm;
|
||||||
background:
|
background:
|
||||||
radial-gradient(ellipse at top right, rgba(135, 168, 120, 0.18) 0%, transparent 55%),
|
radial-gradient(ellipse at top right, rgba(135, 168, 120, 0.18) 0%, transparent 55%),
|
||||||
radial-gradient(ellipse at bottom left, rgba(74, 124, 89, 0.10) 0%, transparent 55%),
|
radial-gradient(ellipse at bottom left, rgba(45, 90, 61, 0.06) 0%, transparent 55%),
|
||||||
var(--white-cream);
|
var(--white-pure);
|
||||||
|
color: var(--black-deep);
|
||||||
position: relative;
|
position: relative;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
@ -84,16 +85,6 @@ html, body {
|
|||||||
page: cover;
|
page: cover;
|
||||||
}
|
}
|
||||||
|
|
||||||
.cover::before {
|
|
||||||
content: "";
|
|
||||||
position: absolute;
|
|
||||||
top: 0;
|
|
||||||
left: 0;
|
|
||||||
right: 0;
|
|
||||||
height: 8mm;
|
|
||||||
background: linear-gradient(90deg, var(--green-dark), var(--green-forest), var(--green-moss));
|
|
||||||
}
|
|
||||||
|
|
||||||
.cover-header {
|
.cover-header {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: flex-start;
|
align-items: flex-start;
|
||||||
@ -131,7 +122,7 @@ html, body {
|
|||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
text-transform: uppercase;
|
text-transform: uppercase;
|
||||||
letter-spacing: 0.18em;
|
letter-spacing: 0.18em;
|
||||||
color: var(--green-moss);
|
color: var(--green-forest);
|
||||||
margin-bottom: 6mm;
|
margin-bottom: 6mm;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -139,7 +130,7 @@ html, body {
|
|||||||
font-family: 'Playfair Display', Georgia, serif;
|
font-family: 'Playfair Display', Georgia, serif;
|
||||||
font-size: 34pt;
|
font-size: 34pt;
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
color: var(--green-dark);
|
color: var(--black-deep);
|
||||||
line-height: 1.1;
|
line-height: 1.1;
|
||||||
margin: 0 0 6mm 0;
|
margin: 0 0 6mm 0;
|
||||||
letter-spacing: -0.015em;
|
letter-spacing: -0.015em;
|
||||||
@ -158,36 +149,42 @@ html, body {
|
|||||||
.cover-meta {
|
.cover-meta {
|
||||||
font-family: 'Inter', sans-serif;
|
font-family: 'Inter', sans-serif;
|
||||||
font-size: 10.5pt;
|
font-size: 10.5pt;
|
||||||
color: var(--black-soft);
|
color: var(--black-deep);
|
||||||
line-height: 1.9;
|
line-height: 1.9;
|
||||||
border-left: 2px solid var(--green-moss);
|
border-left: 2px solid var(--green-forest);
|
||||||
padding-left: 5mm;
|
padding-left: 5mm;
|
||||||
}
|
}
|
||||||
|
|
||||||
.cover-meta strong {
|
.cover-meta strong {
|
||||||
color: var(--green-dark);
|
color: var(--green-forest);
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
min-width: 25mm;
|
min-width: 25mm;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.cover-meta a {
|
||||||
|
color: var(--black-deep);
|
||||||
|
text-decoration: underline;
|
||||||
|
text-decoration-color: rgba(45, 90, 61, 0.6);
|
||||||
|
}
|
||||||
|
|
||||||
.cover-footer {
|
.cover-footer {
|
||||||
font-family: 'Inter', sans-serif;
|
font-family: 'Inter', sans-serif;
|
||||||
font-size: 9pt;
|
font-size: 9pt;
|
||||||
color: var(--gray-mid);
|
color: var(--green-forest);
|
||||||
border-top: 1px solid var(--green-sage);
|
border-top: 1px solid rgba(45, 90, 61, 0.4);
|
||||||
padding-top: 5mm;
|
padding-top: 5mm;
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
}
|
}
|
||||||
|
|
||||||
.cover-footer a {
|
.cover-footer a {
|
||||||
color: var(--green-forest);
|
color: var(--black-deep);
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
}
|
}
|
||||||
|
|
||||||
.cover-footer a:hover { color: var(--green-dark); }
|
.cover-footer a:hover { color: var(--green-forest); }
|
||||||
|
|
||||||
/* ============ DOCUMENT BODY ============ */
|
/* ============ DOCUMENT BODY ============ */
|
||||||
.content {
|
.content {
|
||||||
|
|||||||
@ -104,7 +104,7 @@ PROJECT_PERIOD_RESOLVED="${PROJECT_PERIOD:-—}"
|
|||||||
PROJECT_URL_RESOLVED="${PROJECT_URL:-—}"
|
PROJECT_URL_RESOLVED="${PROJECT_URL:-—}"
|
||||||
COVER_TITLE_RESOLVED="${COVER_TITLE:-$PROJECT_NAME_RESOLVED}"
|
COVER_TITLE_RESOLVED="${COVER_TITLE:-$PROJECT_NAME_RESOLVED}"
|
||||||
COVER_SUBTITLE_RESOLVED="${COVER_SUBTITLE:-$DEFAULT_SUBTITLE}"
|
COVER_SUBTITLE_RESOLVED="${COVER_SUBTITLE:-$DEFAULT_SUBTITLE}"
|
||||||
LOGO_URL_RESOLVED="${LOGO_URL:-https://zenquality.fr/logo-horizontal.svg}"
|
LOGO_URL_RESOLVED="${LOGO_URL:-https://zenquality.fr/assets/logo-horizontal-1024.png}"
|
||||||
|
|
||||||
if command -v date >/dev/null 2>&1; then
|
if command -v date >/dev/null 2>&1; then
|
||||||
if [ "$LANG_CODE" = "fr" ]; then
|
if [ "$LANG_CODE" = "fr" ]; then
|
||||||
@ -135,7 +135,9 @@ print(markdown.markdown(
|
|||||||
return
|
return
|
||||||
fi
|
fi
|
||||||
if command -v npx >/dev/null 2>&1; then
|
if command -v npx >/dev/null 2>&1; then
|
||||||
npx --yes marked < "$src"
|
# marked CLI 16.x ignores stdin and dumps its own cli.js source —
|
||||||
|
# always pass the file via -i to get correct output.
|
||||||
|
npx --yes marked --gfm -i "$src"
|
||||||
return
|
return
|
||||||
fi
|
fi
|
||||||
echo "error: no Markdown converter available (need pandoc, python3+markdown, or npx)" >&2
|
echo "error: no Markdown converter available (need pandoc, python3+markdown, or npx)" >&2
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user