feat(pdf): implement premium industrial layout and integrate brand logo
Some checks failed
Build & Deploy / 🔍 Prepare (push) Successful in 6s
Build & Deploy / 🧪 QA (push) Failing after 1m18s
Build & Deploy / 🚀 Deploy (push) Has been skipped
Build & Deploy / 🏗️ Build (push) Has been skipped
Build & Deploy / 🧪 Post-Deploy Verification (push) Has been skipped
Build & Deploy / 🔔 Notify (push) Successful in 2s
Some checks failed
Build & Deploy / 🔍 Prepare (push) Successful in 6s
Build & Deploy / 🧪 QA (push) Failing after 1m18s
Build & Deploy / 🚀 Deploy (push) Has been skipped
Build & Deploy / 🏗️ Build (push) Has been skipped
Build & Deploy / 🧪 Post-Deploy Verification (push) Has been skipped
Build & Deploy / 🔔 Notify (push) Successful in 2s
This commit is contained in:
172
lib/pdf-page.tsx
172
lib/pdf-page.tsx
@@ -1,5 +1,5 @@
|
|||||||
import * as React from 'react';
|
import { Document, Page, View, Text, StyleSheet, Font, Link, Image } from '@react-pdf/renderer';
|
||||||
import { Document, Page, View, Text, StyleSheet, Font, Link } from '@react-pdf/renderer';
|
import path from 'path';
|
||||||
|
|
||||||
// Standard fonts like Helvetica are built-in to PDF and don't require registration
|
// Standard fonts like Helvetica are built-in to PDF and don't require registration
|
||||||
// unless we want to use specific TTF files. Using built-in Helvetica for maximum stability.
|
// unless we want to use specific TTF files. Using built-in Helvetica for maximum stability.
|
||||||
@@ -24,67 +24,65 @@ const MARGIN = 72;
|
|||||||
const styles = StyleSheet.create({
|
const styles = StyleSheet.create({
|
||||||
page: {
|
page: {
|
||||||
color: C.gray900,
|
color: C.gray900,
|
||||||
lineHeight: 1.5,
|
lineHeight: 1.6,
|
||||||
backgroundColor: C.white,
|
backgroundColor: C.white,
|
||||||
paddingTop: 0,
|
paddingTop: 0,
|
||||||
paddingBottom: 100,
|
paddingBottom: 80,
|
||||||
fontFamily: 'Helvetica',
|
fontFamily: 'Helvetica',
|
||||||
},
|
},
|
||||||
|
|
||||||
// Hero-style header
|
// Premium Header Layout
|
||||||
hero: {
|
hero: {
|
||||||
backgroundColor: C.white,
|
backgroundColor: C.offWhite,
|
||||||
paddingTop: 24,
|
paddingTop: 40,
|
||||||
paddingBottom: 20,
|
paddingBottom: 32,
|
||||||
paddingHorizontal: MARGIN,
|
paddingHorizontal: MARGIN,
|
||||||
marginBottom: 20,
|
marginBottom: 40,
|
||||||
position: 'relative',
|
|
||||||
borderBottomWidth: 1,
|
borderBottomWidth: 1,
|
||||||
borderBottomColor: C.gray200,
|
borderBottomColor: C.gray200,
|
||||||
|
position: 'relative',
|
||||||
},
|
},
|
||||||
|
|
||||||
header: {
|
headerTop: {
|
||||||
flexDirection: 'row',
|
flexDirection: 'row',
|
||||||
justifyContent: 'space-between',
|
justifyContent: 'space-between',
|
||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
marginBottom: 16,
|
marginBottom: 32,
|
||||||
},
|
},
|
||||||
|
|
||||||
logoText: {
|
logo: {
|
||||||
fontSize: 24,
|
width: 60,
|
||||||
fontWeight: 700,
|
height: 'auto',
|
||||||
color: C.navyDeep,
|
|
||||||
letterSpacing: 1,
|
|
||||||
textTransform: 'uppercase',
|
|
||||||
},
|
},
|
||||||
|
|
||||||
docTitle: {
|
docType: {
|
||||||
fontSize: 10,
|
fontSize: 9,
|
||||||
fontWeight: 700,
|
fontWeight: 700,
|
||||||
color: C.navy,
|
color: C.navy,
|
||||||
letterSpacing: 2,
|
letterSpacing: 2,
|
||||||
textTransform: 'uppercase',
|
textTransform: 'uppercase',
|
||||||
|
opacity: 0.6,
|
||||||
},
|
},
|
||||||
|
|
||||||
productHero: {
|
headerTitleArea: {
|
||||||
marginTop: 0,
|
marginTop: 0,
|
||||||
},
|
},
|
||||||
|
|
||||||
pageTitle: {
|
pageTitle: {
|
||||||
fontSize: 24,
|
fontSize: 28,
|
||||||
fontWeight: 700,
|
fontWeight: 700,
|
||||||
color: C.navyDeep,
|
color: C.navyDeep,
|
||||||
marginBottom: 0,
|
marginBottom: 4,
|
||||||
textTransform: 'uppercase',
|
textTransform: 'uppercase',
|
||||||
letterSpacing: -0.5,
|
letterSpacing: -0.5,
|
||||||
},
|
},
|
||||||
|
|
||||||
accentBar: {
|
accentBar: {
|
||||||
width: 30,
|
width: 40,
|
||||||
height: 3,
|
height: 4,
|
||||||
backgroundColor: C.accent,
|
backgroundColor: C.accent,
|
||||||
marginTop: 8,
|
marginTop: 12,
|
||||||
borderRadius: 1.5,
|
borderRadius: 2,
|
||||||
},
|
},
|
||||||
|
|
||||||
// Content Area
|
// Content Area
|
||||||
@@ -92,89 +90,103 @@ const styles = StyleSheet.create({
|
|||||||
paddingHorizontal: MARGIN,
|
paddingHorizontal: MARGIN,
|
||||||
},
|
},
|
||||||
|
|
||||||
// Lexical Elements
|
// Lexical Elements with high-fidelity formatting
|
||||||
paragraph: {
|
paragraph: {
|
||||||
fontSize: 10,
|
fontSize: 10,
|
||||||
color: C.gray600,
|
color: C.gray600,
|
||||||
lineHeight: 1.7,
|
lineHeight: 1.7,
|
||||||
marginBottom: 12,
|
marginBottom: 14,
|
||||||
|
textAlign: 'justify',
|
||||||
},
|
},
|
||||||
|
|
||||||
heading1: {
|
heading1: {
|
||||||
fontSize: 16,
|
fontSize: 14,
|
||||||
fontWeight: 700,
|
fontWeight: 700,
|
||||||
color: C.navyDeep,
|
color: C.navyDeep,
|
||||||
marginTop: 20,
|
marginTop: 24,
|
||||||
|
marginBottom: 12,
|
||||||
|
textTransform: 'uppercase',
|
||||||
|
letterSpacing: 0.8,
|
||||||
|
borderLeftWidth: 3,
|
||||||
|
borderLeftColor: C.accent,
|
||||||
|
paddingLeft: 12,
|
||||||
|
},
|
||||||
|
|
||||||
|
heading2: {
|
||||||
|
fontSize: 11,
|
||||||
|
fontWeight: 700,
|
||||||
|
color: C.navyDeep,
|
||||||
|
marginTop: 18,
|
||||||
marginBottom: 10,
|
marginBottom: 10,
|
||||||
textTransform: 'uppercase',
|
textTransform: 'uppercase',
|
||||||
letterSpacing: 0.5,
|
letterSpacing: 0.5,
|
||||||
},
|
},
|
||||||
heading2: {
|
|
||||||
fontSize: 12,
|
|
||||||
fontWeight: 700,
|
|
||||||
color: C.navyDeep,
|
|
||||||
marginTop: 16,
|
|
||||||
marginBottom: 8,
|
|
||||||
},
|
|
||||||
heading3: {
|
heading3: {
|
||||||
fontSize: 10,
|
fontSize: 10,
|
||||||
fontWeight: 700,
|
fontWeight: 700,
|
||||||
color: C.navyDeep,
|
color: C.navyDeep,
|
||||||
marginTop: 12,
|
marginTop: 14,
|
||||||
marginBottom: 6,
|
marginBottom: 8,
|
||||||
},
|
},
|
||||||
|
|
||||||
list: {
|
list: {
|
||||||
marginBottom: 12,
|
marginBottom: 16,
|
||||||
marginLeft: 8,
|
marginLeft: 4,
|
||||||
},
|
},
|
||||||
|
|
||||||
listItem: {
|
listItem: {
|
||||||
flexDirection: 'row',
|
flexDirection: 'row',
|
||||||
marginBottom: 4,
|
marginBottom: 6,
|
||||||
},
|
},
|
||||||
|
|
||||||
listItemBullet: {
|
listItemBullet: {
|
||||||
width: 12,
|
width: 20,
|
||||||
fontSize: 10,
|
fontSize: 10,
|
||||||
color: C.accent,
|
color: C.gray400,
|
||||||
fontWeight: 700,
|
fontWeight: 700,
|
||||||
},
|
},
|
||||||
|
|
||||||
listItemContent: {
|
listItemContent: {
|
||||||
flex: 1,
|
flex: 1,
|
||||||
fontSize: 10,
|
fontSize: 10,
|
||||||
color: C.gray600,
|
color: C.gray600,
|
||||||
lineHeight: 1.7,
|
lineHeight: 1.7,
|
||||||
|
textAlign: 'justify',
|
||||||
},
|
},
|
||||||
|
|
||||||
link: {
|
link: {
|
||||||
color: C.accent,
|
color: C.navy,
|
||||||
textDecoration: 'none',
|
textDecoration: 'underline',
|
||||||
},
|
},
|
||||||
|
|
||||||
textBold: {
|
textBold: {
|
||||||
fontWeight: 700,
|
fontWeight: 700,
|
||||||
fontFamily: 'Helvetica-Bold',
|
fontFamily: 'Helvetica-Bold',
|
||||||
color: C.navyDeep,
|
color: C.navyDeep,
|
||||||
},
|
},
|
||||||
|
|
||||||
textItalic: {
|
textItalic: {
|
||||||
fontStyle: 'italic',
|
fontStyle: 'italic',
|
||||||
},
|
},
|
||||||
|
|
||||||
// Footer — matches brochure style
|
// Industrial Footer
|
||||||
footer: {
|
footer: {
|
||||||
position: 'absolute',
|
position: 'absolute',
|
||||||
bottom: 40,
|
bottom: 30,
|
||||||
left: MARGIN,
|
left: MARGIN,
|
||||||
right: MARGIN,
|
right: MARGIN,
|
||||||
flexDirection: 'row',
|
flexDirection: 'row',
|
||||||
justifyContent: 'space-between',
|
justifyContent: 'space-between',
|
||||||
alignItems: 'center',
|
alignItems: 'flex-end',
|
||||||
paddingTop: 24,
|
paddingTop: 16,
|
||||||
borderTopWidth: 1,
|
borderTopWidth: 0.5,
|
||||||
borderTopColor: C.gray200,
|
borderTopColor: C.gray200,
|
||||||
},
|
},
|
||||||
|
|
||||||
footerText: {
|
footerInfo: {
|
||||||
fontSize: 8,
|
flexDirection: 'column',
|
||||||
color: C.gray400,
|
gap: 2,
|
||||||
fontWeight: 500,
|
|
||||||
textTransform: 'uppercase',
|
|
||||||
letterSpacing: 1,
|
|
||||||
},
|
},
|
||||||
|
|
||||||
footerBrand: {
|
footerBrand: {
|
||||||
@@ -183,6 +195,20 @@ const styles = StyleSheet.create({
|
|||||||
color: C.navyDeep,
|
color: C.navyDeep,
|
||||||
textTransform: 'uppercase',
|
textTransform: 'uppercase',
|
||||||
letterSpacing: 1,
|
letterSpacing: 1,
|
||||||
|
marginBottom: 2,
|
||||||
|
},
|
||||||
|
|
||||||
|
footerText: {
|
||||||
|
fontSize: 7,
|
||||||
|
color: C.gray400,
|
||||||
|
fontWeight: 500,
|
||||||
|
textTransform: 'uppercase',
|
||||||
|
letterSpacing: 0.5,
|
||||||
|
},
|
||||||
|
|
||||||
|
pageNum: {
|
||||||
|
fontSize: 8,
|
||||||
|
color: C.gray400,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -291,19 +317,21 @@ export const PDFPage: React.FC<PDFPageProps> = ({ page, locale = 'de' }) => {
|
|||||||
day: 'numeric',
|
day: 'numeric',
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const logoPath = path.join(process.cwd(), 'public/logo.png');
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Document>
|
<Document>
|
||||||
<Page size="A4" style={styles.page}>
|
<Page size="A4" style={styles.page}>
|
||||||
{/* Hero Header */}
|
{/* Improved Hero Header */}
|
||||||
<View style={styles.hero} fixed>
|
<View style={styles.hero} fixed>
|
||||||
<View style={styles.header}>
|
<View style={styles.headerTop}>
|
||||||
<View>
|
<Image src={logoPath} style={styles.logo} />
|
||||||
<Text style={styles.logoText}>KLZ</Text>
|
<Text style={styles.docType}>
|
||||||
</View>
|
{locale === 'en' ? 'Official Document' : 'Offizielles Dokument'}
|
||||||
<Text style={styles.docTitle}>{locale === 'en' ? 'Document' : 'Dokument'}</Text>
|
</Text>
|
||||||
</View>
|
</View>
|
||||||
|
|
||||||
<View style={styles.productHero}>
|
<View style={styles.headerTitleArea}>
|
||||||
<Text style={styles.pageTitle}>{page.title}</Text>
|
<Text style={styles.pageTitle}>{page.title}</Text>
|
||||||
<View style={styles.accentBar} />
|
<View style={styles.accentBar} />
|
||||||
</View>
|
</View>
|
||||||
@@ -317,10 +345,18 @@ export const PDFPage: React.FC<PDFPageProps> = ({ page, locale = 'de' }) => {
|
|||||||
</View>
|
</View>
|
||||||
</View>
|
</View>
|
||||||
|
|
||||||
{/* Minimal footer */}
|
{/* Industrial footer with page numbers */}
|
||||||
<View style={styles.footer} fixed>
|
<View style={styles.footer} fixed>
|
||||||
<Text style={styles.footerBrand}>KLZ CABLES</Text>
|
<View style={styles.footerInfo}>
|
||||||
<Text style={styles.footerText}>{dateStr}</Text>
|
<Text style={styles.footerBrand}>KLZ VERTRIEBS GMBH</Text>
|
||||||
|
<Text style={styles.footerText}>
|
||||||
|
RAIFFEISENSTRASSE 22 • 73630 REMSHALDEN • {dateStr}
|
||||||
|
</Text>
|
||||||
|
</View>
|
||||||
|
<Text
|
||||||
|
style={styles.pageNum}
|
||||||
|
render={({ pageNumber, totalPages }) => `${pageNumber} / ${totalPages}`}
|
||||||
|
/>
|
||||||
</View>
|
</View>
|
||||||
</Page>
|
</Page>
|
||||||
</Document>
|
</Document>
|
||||||
|
|||||||
@@ -139,7 +139,7 @@
|
|||||||
"prepare": "husky",
|
"prepare": "husky",
|
||||||
"preinstall": "npx only-allow pnpm"
|
"preinstall": "npx only-allow pnpm"
|
||||||
},
|
},
|
||||||
"version": "2.3.18-rc.1",
|
"version": "2.3.18-rc.2",
|
||||||
"pnpm": {
|
"pnpm": {
|
||||||
"onlyBuiltDependencies": [
|
"onlyBuiltDependencies": [
|
||||||
"@parcel/watcher",
|
"@parcel/watcher",
|
||||||
|
|||||||
Reference in New Issue
Block a user