Files
klz-cables.com/lib/pdf-business-card.tsx
Marc Mintel b78a848ec2
Some checks failed
Build & Deploy / 🔍 Prepare (push) Successful in 18s
Build & Deploy / 🧪 QA (push) Successful in 1m59s
Build & Deploy / 🚀 Deploy (push) Has been cancelled
Build & Deploy / 🧪 Post-Deploy Verification (push) Has been cancelled
Build & Deploy / 🔔 Notify (push) Has been cancelled
Build & Deploy / 🏗️ Build (push) Has been cancelled
fix: ensure email addresses are strictly lowercase
2026-06-12 12:01:00 +02:00

979 lines
39 KiB
TypeScript

import React from 'react';
import * as fs from 'fs';
import {
Document,
Page,
Text,
View,
StyleSheet,
Font,
Image,
Svg,
Path,
G,
Rect,
ClipPath,
Circle,
} from '@react-pdf/renderer';
import * as path from 'path';
import { TruckBlueprint } from './TruckBlueprint';
// Register embedded fonts so Ghostscript -dNoOutputFonts can convert them to
// outlines (curves). Built-in PDF fonts like Helvetica are NEVER embedded and
// therefore cannot be outlined — always use a physical font file here.
Font.register({
family: 'Inter',
fonts: [
{
src: path.join(process.cwd(), 'public', 'fonts', 'Inter-Regular.woff'),
fontWeight: 'normal',
},
{
src: path.join(process.cwd(), 'public', 'fonts', 'Inter-Bold.woff'),
fontWeight: 'bold',
},
],
});
export interface PersonData {
name: string;
role: string;
phone: string;
email: string;
}
export interface PDFBusinessCardProps {
person: PersonData;
qrCodeDataUrl: string;
variant?: 'blue' | 'white' | 'black';
isViaprinto?: boolean;
withTruck?: boolean;
withCropMarks?: boolean;
}
// Die Buchstaben K, L, Z im SVG (inklusive dem kleinen Stück vom Z oben links)
export const KLZ_PATHS = [25, 26, 27, 28, 29];
const COLORS = {
primary: '#000a66', // Brand Dark Blue (from website)
blue: '#000a66',
green: '#82ed20', // Brand Accent Green
darkGreen: '#4A9E00', // Darker green for white background visibility
white: '#ffffff',
grayText: '#6c757d',
black: '#0a0a0a',
neutralDark: '#263336',
lightGray: '#f8f9fa',
};
const CropMarks = () => (
<View style={{ position: 'absolute', top: 0, left: 0, right: 0, bottom: 0, zIndex: 9999 }}>
{/* Top Left */}
<View
style={{
position: 'absolute',
left: '13mm',
top: '0mm',
width: '0.25pt',
height: '10mm',
backgroundColor: '#000',
}}
/>
<View
style={{
position: 'absolute',
left: '0mm',
top: '13mm',
width: '10mm',
height: '0.25pt',
backgroundColor: '#000',
}}
/>
{/* Top Right */}
<View
style={{
position: 'absolute',
right: '13mm',
top: '0mm',
width: '0.25pt',
height: '10mm',
backgroundColor: '#000',
}}
/>
<View
style={{
position: 'absolute',
right: '0mm',
top: '13mm',
width: '10mm',
height: '0.25pt',
backgroundColor: '#000',
}}
/>
{/* Bottom Left */}
<View
style={{
position: 'absolute',
left: '13mm',
bottom: '0mm',
width: '0.25pt',
height: '10mm',
backgroundColor: '#000',
}}
/>
<View
style={{
position: 'absolute',
left: '0mm',
bottom: '13mm',
width: '10mm',
height: '0.25pt',
backgroundColor: '#000',
}}
/>
{/* Bottom Right */}
<View
style={{
position: 'absolute',
right: '13mm',
bottom: '0mm',
width: '0.25pt',
height: '10mm',
backgroundColor: '#000',
}}
/>
<View
style={{
position: 'absolute',
right: '0mm',
bottom: '13mm',
width: '10mm',
height: '0.25pt',
backgroundColor: '#000',
}}
/>
</View>
);
const styles = StyleSheet.create({
pageBleed: {
width: '91mm',
height: '61mm',
backgroundColor: COLORS.primary,
position: 'relative',
fontFamily: 'Inter',
overflow: 'hidden',
},
pageBleedBack: {
width: '91mm',
height: '61mm',
backgroundColor: COLORS.white,
position: 'relative',
fontFamily: 'Inter',
overflow: 'hidden',
},
// -- BLUE PAGE (Rückseite) --
truckWrapper: {
position: 'absolute',
top: 0,
left: 0,
right: 0,
bottom: '20mm', // Truck stops above the footer area to avoid text conflict
zIndex: 1,
},
frontBackgroundImage: {
width: '100%',
height: '100%',
opacity: 0.4, // Less transparent, more contrast
},
frontContainer: {
flex: 1,
paddingTop: '3mm', // Compensate for top bleed for perfect optical centering
paddingBottom: '20mm', // Leave space for the footer area
justifyContent: 'center',
alignItems: 'center',
},
frontLogo: {
width: 145, // Reduced for a more elegant, premium look with more negative space
zIndex: 100,
},
frontTagline: {
color: COLORS.white,
fontSize: 5.5,
marginTop: 8,
letterSpacing: 2,
fontWeight: 'bold',
textTransform: 'uppercase',
zIndex: 100,
},
frontFooterArea: {
position: 'absolute',
bottom: 0,
left: 0,
right: 0,
height: '20mm', // Generous area for the footer
paddingBottom: '7mm', // 3mm bleed + 4mm safe margin
zIndex: 50,
flexDirection: 'column',
justifyContent: 'center',
alignItems: 'center',
gap: 6, // Harmonious spacing to icons
},
frontIconsGroup: {
flexDirection: 'row',
gap: 14, // Wider gaps between icon groups for visual clarity at small size
},
frontBrandIconWrapper: {
alignItems: 'center',
gap: 1.5,
},
frontBrandIcon: {
width: 12, // Smaller for compact bar
height: 12,
opacity: 0.85,
},
frontBrandText: {
fontSize: 4, // Tiny but readable at 300dpi print
color: COLORS.white,
textTransform: 'uppercase',
letterSpacing: 0.6,
// Full opacity — white on blue needs to pop cleanly
},
frontTaglineBar: {
color: COLORS.green,
fontSize: 7, // Larger — as requested
letterSpacing: 0.5, // Harmonious tracking for mixed case
fontWeight: 'bold',
},
// -- WHITE PAGE (Vorderseite) --
backContainer: {
flex: 1,
paddingTop: '4mm', // Reduced significantly to pull content up
paddingLeft: '6mm',
paddingRight: '6mm',
flexDirection: 'column',
},
backHeader: {
flexDirection: 'row',
alignItems: 'center',
marginBottom: '8mm', // Generous breathing room
width: '100%',
},
backLogo: {
width: 60,
},
accentLineHorizontal: {
flex: 1,
height: 1.5,
backgroundColor: COLORS.primary, // Brand blue line
marginLeft: 12,
marginRight: 12,
},
accentDot: {
width: 4,
height: 4,
borderRadius: 2,
backgroundColor: COLORS.green,
marginRight: 20, // Keep away from the edge!
},
accentBoxEdge: {
width: 3,
height: 25, // Sleek vertical bar on the edge
backgroundColor: COLORS.green,
position: 'absolute',
right: '-8mm', // Bleed edge
top: -5,
},
backBody: {
flex: 1,
flexDirection: 'column',
justifyContent: 'flex-start',
alignItems: 'flex-start',
width: '100%',
},
leftColumn: {
width: '100%', // Take full width since right column is removed
flexDirection: 'column',
},
nameSection: {
marginBottom: '2.5mm', // Clear separation between name block and contact block
},
nameText: {
fontSize: 13,
fontWeight: 'bold',
color: COLORS.neutralDark,
marginBottom: 1.5,
letterSpacing: -0.15,
},
roleText: {
fontSize: 6.5,
fontWeight: 'bold',
color: COLORS.darkGreen,
letterSpacing: 1.2,
textTransform: 'uppercase',
},
contactSection: {
flexDirection: 'column',
gap: 0,
},
contactRow: {
flexDirection: 'row',
alignItems: 'center',
marginBottom: 5, // Even rhythm between contact lines
},
iconWrapper: {
width: 12,
justifyContent: 'center',
alignItems: 'flex-start',
},
contactText: {
fontSize: 7.5,
color: COLORS.neutralDark,
fontWeight: 'normal',
paddingTop: 0.5,
letterSpacing: 0.1,
},
rightColumn: {
flexDirection: 'column',
alignItems: 'flex-end',
justifyContent: 'flex-start',
},
// Ultra Minimalist QR Area
qrContainer: {
flexDirection: 'column',
alignItems: 'center',
gap: 3,
},
qrCodeWrapper: {
width: '12mm',
height: '12mm',
border: `0.75pt solid ${COLORS.darkGreen}`,
padding: 2.5,
backgroundColor: '#ffffff',
},
qrCode: {
width: '100%',
height: '100%',
},
addressFooter: {
width: '100%',
flexDirection: 'row',
justifyContent: 'flex-start',
alignItems: 'center',
position: 'absolute',
bottom: '7mm', // 3mm bleed + 4mm safe margin
left: '6mm', // Match backContainer paddingLeft for flush alignment
},
addressFooterText: {
fontSize: 6.5,
color: COLORS.grayText,
letterSpacing: 0.4,
fontWeight: 'normal',
},
});
// SVG Icons
const PhoneIcon = () => (
<Svg viewBox="0 0 24 24" width={9} height={9}>
<Path
d="M6.62 10.79c1.44 2.83 3.76 5.14 6.59 6.59l2.2-2.2c.27-.27.67-.36 1.02-.24 1.12.37 2.33.57 3.57.57.55 0 1 .45 1 1V20c0 .55-.45 1-1 1-9.39 0-17-7.61-17-17 0-.55.45-1 1-1h3.5c.55 0 1 .45 1 1 0 1.25.2 2.45.57 3.57.11.35.03.74-.25 1.02l-2.2 2.2z"
fill="#000000"
/>
</Svg>
);
const EmailIcon = () => (
<Svg viewBox="0 0 24 24" width={9} height={9}>
<Path
d="M20 4H4c-1.1 0-1.99.9-1.99 2L2 18c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V6c0-1.1-.9-2-2-2zm0 4l-8 5-8-5V6l8 5 8-5v2z"
fill="#000000"
/>
</Svg>
);
const GlobeIcon = () => (
<Svg viewBox="0 0 24 24" width={9} height={9}>
<Path
d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm-1 17.93c-3.95-.49-7-3.85-7-7.93 0-.62.08-1.21.21-1.79L9 15v1c0 1.1.9 2 2 2v1.93zm6.9-2.54c-.26-.81-1-1.39-1.9-1.39h-1v-3c0-.55-.45-1-1-1H8v-2h2c.55 0 1-.45 1-1V7h2c1.1 0 2-.9 2-2v-.41c2.93 1.19 5 4.06 5 7.41 0 2.08-.8 3.97-2.1 5.39z"
fill="#000000"
/>
</Svg>
);
const LocationIcon = () => (
<Svg viewBox="0 0 24 24" width={9} height={9}>
<Path
d="M12 2C8.13 2 5 5.13 5 9c0 5.25 7 13 7 13s7-7.75 7-13c0-3.87-3.13-7-7-7zm0 9.5c-1.38 0-2.5-1.12-2.5-2.5s1.12-2.5 2.5-2.5 2.5 1.12 2.5 2.5-1.12 2.5-2.5 2.5z"
fill="#000000"
/>
</Svg>
);
const ScanIcon = () => (
<Svg viewBox="0 0 24 24" width={9} height={9}>
<Path
d="M3 3h6v2H5v4H3V3zm18 0h-6v2h4v4h2V3zM3 21h6v-2H5v-4H3v6zm18 0h-6v-2h4v-4h2v6zM7 7h10v10H7V7z"
fill="#000000"
/>
</Svg>
);
const parseSvgPaths = (filePath: string) => {
try {
const raw = fs.readFileSync(filePath, 'utf8');
const paths = [];
const pathRegex = /<path([^>]+)>/g;
let match;
while ((match = pathRegex.exec(raw)) !== null) {
const attrs = match[1];
const dMatch = attrs.match(/d="([^"]+)"/);
if (!dMatch) continue;
let fill = 'white';
const fillMatch = attrs.match(/fill(?:[:=])"?([^;"\s>]+)/);
if (fillMatch) {
fill = fillMatch[1].replace(/"$/, '');
if (fill === 'none') continue;
}
paths.push({ d: dMatch[1], fill });
}
return paths;
} catch (e) {
console.error('Could not parse SVG:', filePath);
return [];
}
};
const VectorLogo = ({
paths,
style,
overrideColor,
overrideWhiteColor,
pathOverrides,
solidPaths,
solidBackgroundColor = '#000a66',
}: {
paths: { d: string; fill: string }[];
style: any;
overrideColor?: string;
overrideWhiteColor?: string;
pathOverrides?: Record<number, string>;
solidPaths?: number[];
solidBackgroundColor?: string;
}) => (
<Svg viewBox="0 0 295 99" style={style}>
<G {...({ fillRule: 'evenodd', clipRule: 'evenodd' } as any)}>
{/* Background layer: solid fills to prevent see-through */}
{solidPaths &&
solidBackgroundColor &&
paths.map((p, i) => {
if (!solidPaths.includes(i)) return null;
let d = p.d;
const zIndex = d.toUpperCase().indexOf('Z');
if (zIndex !== -1) {
d = d.substring(0, zIndex + 1);
}
return <Path key={`bg-${i}`} d={d} fill={solidBackgroundColor} />;
})}
{paths.map((p, i) => {
let fill = overrideColor || p.fill;
const d = p.d;
if (pathOverrides && pathOverrides[i]) {
fill = pathOverrides[i];
} else if (
overrideWhiteColor &&
(p.fill === 'white' || p.fill === '#ffffff' || p.fill === '#fff')
) {
fill = overrideWhiteColor;
}
return <Path key={i} d={d} fill={fill} />;
})}
</G>
</Svg>
);
export const IconSolar = ({ style, color = 'white' }: { style: any; color?: string }) => (
<Svg viewBox="0 0 46 45" width={18} height={18} style={style}>
<G>
<Path
d="M44.798,22.471c-0,-11.988 -9.733,-21.721 -21.722,-21.721c-11.988,0 -21.721,9.733 -21.721,21.721c-0,11.989 9.733,21.722 21.721,21.722c11.989,0 21.722,-9.733 21.722,-21.722Z"
style={{ fill: 'none', stroke: color, strokeWidth: '0.75px' }}
/>
<Path
d="M39.801,22.472c-0,-9.231 -7.494,-16.726 -16.725,-16.726c-9.23,0 -16.724,7.495 -16.724,16.725c-0,9.231 7.494,16.725 16.724,16.725c9.231,0 16.725,-7.494 16.725,-16.725Z"
style={{ fill: 'none', stroke: color, strokeWidth: '0.75px' }}
/>
<Path
d="M25.685,22.471c0,-1.504 -1.221,-2.725 -2.725,-2.725c-1.504,0 -2.726,1.221 -2.726,2.725c0,1.505 1.222,2.726 2.726,2.726c1.504,-0 2.725,-1.221 2.725,-2.726Z"
style={{ fill: 'none', stroke: color, strokeWidth: '0.48px' }}
/>
<Path
d="M31.488,22.471c-0,-1.504 -1.222,-2.725 -2.726,-2.725c-1.504,0 -2.725,1.221 -2.725,2.725c-0,1.505 1.221,2.726 2.725,2.726c1.504,-0 2.726,-1.221 2.726,-2.726Z"
style={{ fill: 'none', stroke: color, strokeWidth: '0.48px' }}
/>
<Path
d="M37.29,22.471c-0,-1.504 -1.221,-2.725 -2.726,-2.725c-1.504,0 -2.725,1.221 -2.725,2.725c-0,1.505 1.221,2.726 2.725,2.726c1.505,-0 2.726,-1.221 2.726,-2.726Z"
style={{ fill: 'none', stroke: color, strokeWidth: '0.48px' }}
/>
<Path
d="M19.883,22.471c0,-1.504 -1.221,-2.725 -2.725,-2.725c-1.505,0 -2.726,1.221 -2.726,2.725c0,1.505 1.221,2.726 2.726,2.726c1.504,-0 2.725,-1.221 2.725,-2.726Z"
style={{ fill: 'none', stroke: color, strokeWidth: '0.48px' }}
/>
<Path
d="M14.081,22.471c-0,-1.504 -1.221,-2.725 -2.726,-2.725c-1.504,0 -2.725,1.221 -2.725,2.725c-0,1.505 1.221,2.726 2.725,2.726c1.505,-0 2.726,-1.221 2.726,-2.726Z"
style={{ fill: 'none', stroke: color, strokeWidth: '0.48px' }}
/>
<Path
d="M28.439,17.676c-0,-1.504 -1.222,-2.725 -2.726,-2.725c-1.504,0 -2.725,1.221 -2.725,2.725c-0,1.505 1.221,2.726 2.725,2.726c1.504,-0 2.726,-1.221 2.726,-2.726Z"
style={{ fill: 'none', stroke: color, strokeWidth: '0.48px' }}
/>
<Path
d="M34.023,17.676c-0,-1.504 -1.221,-2.725 -2.726,-2.725c-1.504,0 -2.725,1.221 -2.725,2.725c-0,1.505 1.221,2.726 2.725,2.726c1.505,-0 2.726,-1.221 2.726,-2.726Z"
style={{ fill: 'none', stroke: color, strokeWidth: '0.48px' }}
/>
<Path
d="M22.855,17.676c-0,-1.504 -1.222,-2.725 -2.726,-2.725c-1.504,0 -2.725,1.221 -2.725,2.725c-0,1.505 1.221,2.726 2.725,2.726c1.504,-0 2.726,-1.221 2.726,-2.726Z"
style={{ fill: 'none', stroke: color, strokeWidth: '0.48px' }}
/>
<Path
d="M17.271,17.676c-0,-1.504 -1.222,-2.725 -2.726,-2.725c-1.504,0 -2.725,1.221 -2.725,2.725c-0,1.505 1.221,2.726 2.725,2.726c1.504,-0 2.726,-1.221 2.726,-2.726Z"
style={{ fill: 'none', stroke: color, strokeWidth: '0.48px' }}
/>
<Path
d="M31.458,12.955c-0,-1.504 -1.222,-2.726 -2.726,-2.726c-1.504,0 -2.725,1.222 -2.725,2.726c-0,1.504 1.221,2.725 2.725,2.725c1.504,-0 2.726,-1.221 2.726,-2.725Z"
style={{ fill: 'none', stroke: color, strokeWidth: '0.48px' }}
/>
<Path
d="M25.874,12.955c-0,-1.504 -1.222,-2.726 -2.726,-2.726c-1.504,0 -2.725,1.222 -2.725,2.726c-0,1.504 1.221,2.725 2.725,2.725c1.504,-0 2.726,-1.221 2.726,-2.725Z"
style={{ fill: 'none', stroke: color, strokeWidth: '0.48px' }}
/>
<Path
d="M20.29,12.955c-0,-1.504 -1.222,-2.726 -2.726,-2.726c-1.504,0 -2.725,1.222 -2.725,2.726c-0,1.504 1.221,2.725 2.725,2.725c1.504,-0 2.726,-1.221 2.726,-2.725Z"
style={{ fill: 'none', stroke: color, strokeWidth: '0.48px' }}
/>
<Path
d="M31.52,32.09c-0,-1.504 -1.222,-2.726 -2.726,-2.726c-1.504,0 -2.725,1.222 -2.725,2.726c-0,1.504 1.221,2.725 2.725,2.725c1.504,-0 2.726,-1.221 2.726,-2.725Z"
style={{ fill: 'none', stroke: color, strokeWidth: '0.48px' }}
/>
<Path
d="M25.935,32.09c0,-1.504 -1.221,-2.726 -2.725,-2.726c-1.504,0 -2.725,1.222 -2.725,2.726c-0,1.504 1.221,2.725 2.725,2.725c1.504,-0 2.725,-1.221 2.725,-2.725Z"
style={{ fill: 'none', stroke: color, strokeWidth: '0.48px' }}
/>
<Path
d="M20.351,32.09c0,-1.504 -1.221,-2.726 -2.725,-2.726c-1.504,0 -2.725,1.222 -2.725,2.726c-0,1.504 1.221,2.725 2.725,2.725c1.504,-0 2.725,-1.221 2.725,-2.725Z"
style={{ fill: 'none', stroke: color, strokeWidth: '0.48px' }}
/>
<Path
d="M28.748,27.267c0,-1.505 -1.221,-2.726 -2.725,-2.726c-1.504,0 -2.726,1.221 -2.726,2.726c0,1.504 1.222,2.725 2.726,2.725c1.504,-0 2.725,-1.221 2.725,-2.725Z"
style={{ fill: 'none', stroke: color, strokeWidth: '0.48px' }}
/>
<Path
d="M34.642,27.267c-0,-1.505 -1.221,-2.726 -2.725,-2.726c-1.505,0 -2.726,1.221 -2.726,2.726c0,1.504 1.221,2.725 2.726,2.725c1.504,-0 2.725,-1.221 2.725,-2.725Z"
style={{ fill: 'none', stroke: color, strokeWidth: '0.48px' }}
/>
<Path
d="M22.855,27.267c-0,-1.505 -1.222,-2.726 -2.726,-2.726c-1.504,0 -2.725,1.221 -2.725,2.726c-0,1.504 1.221,2.725 2.725,2.725c1.504,-0 2.726,-1.221 2.726,-2.725Z"
style={{ fill: 'none', stroke: color, strokeWidth: '0.48px' }}
/>
<Path
d="M16.961,27.267c0,-1.505 -1.221,-2.726 -2.725,-2.726c-1.505,0 -2.726,1.221 -2.726,2.726c0,1.504 1.221,2.725 2.726,2.725c1.504,-0 2.725,-1.221 2.725,-2.725Z"
style={{ fill: 'none', stroke: color, strokeWidth: '0.48px' }}
/>
</G>
</Svg>
);
export const AbstractCable = ({
size = 10,
color = COLORS.green,
}: {
size?: number;
color?: string;
}) => (
<Svg viewBox="0 0 16 10" width={size * 1.6} height={size}>
<Path d="M0,5 L6,5" fill="none" stroke={color} strokeWidth="1.5" strokeLinecap="square" />
<Path
d="M10,1 L16,1 M10,5 L16,5 M10,9 L16,9"
fill="none"
stroke={color}
strokeWidth="1.5"
strokeLinecap="square"
/>
</Svg>
);
export const IconLowVoltage = ({ style, color = 'white' }: { style: any; color?: string }) => (
<Svg viewBox="0 0 45 45" width={18} height={18} style={style}>
<G>
<Path
d="M44.193,22.471c0,-11.988 -9.733,-21.721 -21.722,-21.721c-11.988,0 -21.721,9.733 -21.721,21.721c0,11.989 9.733,21.722 21.722,21.722c11.988,0 21.721,-9.733 21.721,-21.722Z"
style={{ fill: 'none', stroke: color, strokeWidth: '0.75px' }}
/>
<Path
d="M39.196,22.472c0,-9.231 -7.494,-16.726 -16.725,-16.726c-9.23,0 -16.724,7.495 -16.724,16.725c-0,9.231 7.494,16.725 16.725,16.725c9.23,0 16.724,-7.494 16.724,-16.725Z"
style={{ fill: 'none', stroke: color, strokeWidth: '0.75px' }}
/>
<Path
d="M26.713,18.74c0,-2.341 -1.9,-4.241 -4.241,-4.241c-2.342,-0 -4.242,1.9 -4.242,4.241c-0,2.341 1.9,4.241 4.242,4.241c2.341,0 4.241,-1.9 4.241,-4.241Z"
style={{ fill: 'none', stroke: color, strokeWidth: '0.75px' }}
/>
<Path
d="M30.955,26.203c-0,-2.341 -1.901,-4.242 -4.242,-4.242c-2.341,0 -4.242,1.901 -4.242,4.242c0,2.341 1.901,4.241 4.242,4.241c2.341,-0 4.242,-1.9 4.242,-4.241Z"
style={{ fill: 'none', stroke: color, strokeWidth: '0.75px' }}
/>
<Path
d="M22.472,26.203c-0,-2.341 -1.901,-4.242 -4.242,-4.242c-2.341,0 -4.242,1.901 -4.242,4.242c0,2.341 1.901,4.241 4.242,4.241c2.341,-0 4.242,-1.9 4.242,-4.241Z"
style={{ fill: 'none', stroke: color, strokeWidth: '0.75px' }}
/>
</G>
</Svg>
);
export const IconMediumVoltage = ({ style, color = 'white' }: { style: any; color?: string }) => (
<Svg viewBox="0 0 46 45" width={18} height={18} style={style}>
<G>
<Path
d="M44.475,22.471c0,-11.988 -9.733,-21.721 -21.721,-21.721c-11.988,0 -21.722,9.733 -21.722,21.721c0,11.989 9.734,21.722 21.722,21.722c11.988,0 21.721,-9.733 21.721,-21.722Z"
style={{ fill: 'none', stroke: color, strokeWidth: '0.75px' }}
/>
<Path
d="M39.479,22.472c-0,-9.231 -7.494,-16.726 -16.725,-16.726c-9.231,0 -16.725,7.495 -16.725,16.725c0,9.231 7.494,16.725 16.725,16.725c9.231,0 16.725,-7.494 16.725,-16.725Z"
style={{ fill: 'none', stroke: color, strokeWidth: '0.75px' }}
/>
<Path
d="M26.995,22.471c0,-2.34 -1.9,-4.241 -4.241,-4.241c-2.341,0 -4.242,1.901 -4.242,4.241c0,2.341 1.901,4.242 4.242,4.242c2.341,-0 4.241,-1.901 4.241,-4.242Z"
style={{ fill: 'none', stroke: color, strokeWidth: '0.75px' }}
/>
<Path
d="M35.478,22.471c0,-2.34 -1.9,-4.241 -4.241,-4.241c-2.341,0 -4.242,1.901 -4.242,4.241c0,2.341 1.901,4.242 4.242,4.242c2.341,-0 4.241,-1.901 4.241,-4.242Z"
style={{ fill: 'none', stroke: color, strokeWidth: '0.75px' }}
/>
<Path
d="M18.512,22.471c0,-2.34 -1.9,-4.241 -4.241,-4.241c-2.341,0 -4.242,1.901 -4.242,4.241c0,2.341 1.901,4.242 4.242,4.242c2.341,-0 4.241,-1.901 4.241,-4.242Z"
style={{ fill: 'none', stroke: color, strokeWidth: '0.75px' }}
/>
<Path
d="M31.237,15.009c-0,-2.341 -1.901,-4.241 -4.242,-4.241c-2.341,-0 -4.241,1.9 -4.241,4.241c-0,2.341 1.9,4.241 4.241,4.241c2.341,0 4.242,-1.9 4.242,-4.241Z"
style={{ fill: 'none', stroke: color, strokeWidth: '0.75px' }}
/>
<Path
d="M22.754,15.009c-0,-2.341 -1.901,-4.241 -4.242,-4.241c-2.341,-0 -4.241,1.9 -4.241,4.241c-0,2.341 1.9,4.241 4.241,4.241c2.341,0 4.242,-1.9 4.242,-4.241Z"
style={{ fill: 'none', stroke: color, strokeWidth: '0.75px' }}
/>
<Path
d="M31.237,29.934c-0,-2.341 -1.901,-4.241 -4.242,-4.241c-2.341,-0 -4.241,1.9 -4.241,4.241c-0,2.341 1.9,4.241 4.241,4.241c2.341,0 4.242,-1.9 4.242,-4.241Z"
style={{ fill: 'none', stroke: color, strokeWidth: '0.75px' }}
/>
<Path
d="M22.754,29.934c-0,-2.341 -1.901,-4.241 -4.242,-4.241c-2.341,-0 -4.241,1.9 -4.241,4.241c-0,2.341 1.9,4.241 4.241,4.241c2.341,0 4.242,-1.9 4.242,-4.241Z"
style={{ fill: 'none', stroke: color, strokeWidth: '0.75px' }}
/>
</G>
</Svg>
);
export const IconHighVoltage = ({ style, color = 'white' }: { style: any; color?: string }) => (
<Svg viewBox="0 0 46 46" width={18} height={18} style={style}>
<G>
<Path
d="M44.612,22.931c0,-11.988 -9.733,-21.722 -21.721,-21.722c-11.988,0 -21.722,9.734 -21.722,21.722c0,11.988 9.734,21.721 21.722,21.721c11.988,0 21.721,-9.733 21.721,-21.721Z"
style={{ fill: 'none', stroke: color, strokeWidth: '0.75px' }}
/>
<G>
<Path
d="M24.642,22.947c-0,-1.031 -0.837,-1.867 -1.867,-1.867c-1.031,-0 -1.868,0.836 -1.868,1.867c0,1.03 0.837,1.867 1.868,1.867c1.03,0 1.867,-0.837 1.867,-1.867Z"
style={{ fill: 'none', stroke: color, strokeWidth: '0.33px' }}
/>
<Path
d="M28.617,22.947c0,-1.031 -0.836,-1.867 -1.867,-1.867c-1.031,-0 -1.867,0.836 -1.867,1.867c-0,1.03 0.836,1.867 1.867,1.867c1.031,0 1.867,-0.837 1.867,-1.867Z"
style={{ fill: 'none', stroke: color, strokeWidth: '0.33px' }}
/>
<Path
d="M32.593,22.947c-0,-1.031 -0.837,-1.867 -1.867,-1.867c-1.031,-0 -1.868,0.836 -1.868,1.867c0,1.03 0.837,1.867 1.868,1.867c1.03,0 1.867,-0.837 1.867,-1.867Z"
style={{ fill: 'none', stroke: color, strokeWidth: '0.33px' }}
/>
<Path
d="M20.666,22.947c0,-1.031 -0.836,-1.867 -1.867,-1.867c-1.03,-0 -1.867,0.836 -1.867,1.867c-0,1.03 0.837,1.867 1.867,1.867c1.031,0 1.867,-0.837 1.867,-1.867Z"
style={{ fill: 'none', stroke: color, strokeWidth: '0.33px' }}
/>
<Path
d="M16.691,22.947c0,-1.031 -0.837,-1.867 -1.867,-1.867c-1.031,-0 -1.868,0.836 -1.868,1.867c0,1.03 0.837,1.867 1.868,1.867c1.03,0 1.867,-0.837 1.867,-1.867Z"
style={{ fill: 'none', stroke: color, strokeWidth: '0.33px' }}
/>
<Path
d="M26.528,19.662c0,-1.031 -0.836,-1.868 -1.867,-1.868c-1.031,0 -1.867,0.837 -1.867,1.868c-0,1.03 0.836,1.867 1.867,1.867c1.031,-0 1.867,-0.837 1.867,-1.867Z"
style={{ fill: 'none', stroke: color, strokeWidth: '0.33px' }}
/>
<Path
d="M30.354,19.662c0,-1.031 -0.836,-1.868 -1.867,-1.868c-1.031,0 -1.867,0.837 -1.867,1.868c-0,1.03 0.836,1.867 1.867,1.867c1.031,-0 1.867,-0.837 1.867,-1.867Z"
style={{ fill: 'none', stroke: color, strokeWidth: '0.33px' }}
/>
<Path
d="M22.702,19.662c0,-1.031 -0.836,-1.868 -1.867,-1.868c-1.031,0 -1.867,0.837 -1.867,1.868c-0,1.03 0.836,1.867 1.867,1.867c1.031,-0 1.867,-0.837 1.867,-1.867Z"
style={{ fill: 'none', stroke: color, strokeWidth: '0.33px' }}
/>
<Path
d="M18.877,19.662c-0,-1.031 -0.837,-1.868 -1.868,-1.868c-1.03,0 -1.867,0.837 -1.867,1.868c-0,1.03 0.837,1.867 1.867,1.867c1.031,-0 1.868,-0.837 1.868,-1.867Z"
style={{ fill: 'none', stroke: color, strokeWidth: '0.33px' }}
/>
<Path
d="M28.597,16.426c-0,-1.03 -0.837,-1.868 -1.868,-1.867c-1.03,0 -1.867,0.837 -1.867,1.867c0,1.031 0.837,1.868 1.867,1.868c1.031,-0 1.868,-0.837 1.868,-1.868Z"
style={{ fill: 'none', stroke: color, strokeWidth: '0.33px' }}
/>
<Path
d="M24.771,16.426c-0,-1.03 -0.837,-1.867 -1.867,-1.867c-1.031,0 -1.868,0.837 -1.868,1.867c0,1.031 0.837,1.868 1.868,1.868c1.03,-0 1.867,-0.837 1.867,-1.868Z"
style={{ fill: 'none', stroke: color, strokeWidth: '0.33px' }}
/>
<Path
d="M20.945,16.426c-0,-1.03 -0.837,-1.867 -1.867,-1.867c-1.031,0 -1.868,0.837 -1.868,1.867c0,1.031 0.837,1.868 1.868,1.868c1.03,-0 1.867,-0.837 1.867,-1.868Z"
style={{ fill: 'none', stroke: color, strokeWidth: '0.33px' }}
/>
<Path
d="M28.639,29.537c0,-1.031 -0.836,-1.867 -1.867,-1.867c-1.031,-0 -1.867,0.836 -1.867,1.867c-0,1.03 0.836,1.867 1.867,1.867c1.031,0 1.867,-0.837 1.867,-1.867Z"
style={{ fill: 'none', stroke: color, strokeWidth: '0.33px' }}
/>
<Path
d="M24.813,29.537c0,-1.031 -0.836,-1.867 -1.867,-1.867c-1.031,-0 -1.867,0.836 -1.867,1.867c-0,1.03 0.836,1.867 1.867,1.867c1.031,0 1.867,-0.837 1.867,-1.867Z"
style={{ fill: 'none', stroke: color, strokeWidth: '0.33px' }}
/>
<Path
d="M20.987,29.537c0,-1.031 -0.836,-1.867 -1.867,-1.867c-1.031,-0 -1.867,0.836 -1.867,1.867c-0,1.03 0.836,1.867 1.867,1.867c1.031,0 1.867,-0.837 1.867,-1.867Z"
style={{ fill: 'none', stroke: color, strokeWidth: '0.33px' }}
/>
<Path
d="M26.741,26.232c-0,-1.03 -0.837,-1.867 -1.868,-1.867c-1.03,0 -1.867,0.837 -1.867,1.867c-0,1.031 0.837,1.867 1.867,1.867c1.031,0 1.868,-0.836 1.868,-1.867Z"
style={{ fill: 'none', stroke: color, strokeWidth: '0.33px' }}
/>
<Path
d="M30.779,26.232c-0,-1.03 -0.837,-1.867 -1.868,-1.867c-1.03,0 -1.867,0.837 -1.867,1.867c-0,1.031 0.837,1.867 1.867,1.867c1.031,0 1.868,-0.836 1.868,-1.867Z"
style={{ fill: 'none', stroke: color, strokeWidth: '0.33px' }}
/>
<Path
d="M22.702,26.232c0,-1.03 -0.836,-1.867 -1.867,-1.867c-1.031,0 -1.867,0.837 -1.867,1.867c-0,1.031 0.836,1.867 1.867,1.867c1.031,0 1.867,-0.836 1.867,-1.867Z"
style={{ fill: 'none', stroke: color, strokeWidth: '0.33px' }}
/>
<Path
d="M18.664,26.232c0,-1.03 -0.836,-1.867 -1.867,-1.867c-1.031,0 -1.867,0.837 -1.867,1.867c-0,1.031 0.836,1.867 1.867,1.867c1.031,0 1.867,-0.836 1.867,-1.867Z"
style={{ fill: 'none', stroke: color, strokeWidth: '0.33px' }}
/>
</G>
<Path
d="M35.253,22.931c-0,-6.823 -5.539,-12.362 -12.362,-12.362c-6.823,-0 -12.362,5.539 -12.362,12.362c0,6.823 5.539,12.362 12.362,12.362c6.823,0 12.362,-5.539 12.362,-12.362Z"
style={{ fill: 'none', stroke: color, strokeWidth: '0.75px' }}
/>
<Path
d="M7.792,21.245c0.931,0 1.686,0.756 1.686,1.686c-0,0.93 -0.755,1.686 -1.686,1.686c-0.93,-0 -1.685,-0.756 -1.685,-1.686c-0,-0.93 0.755,-1.686 1.685,-1.686Zm0.078,3.965c0.899,-0.24 1.824,0.294 2.065,1.193c0.241,0.898 -0.293,1.823 -1.192,2.064c-0.899,0.241 -1.824,-0.293 -2.064,-1.192c-0.241,-0.899 0.293,-1.824 1.191,-2.065Zm1.102,3.81c0.806,-0.465 1.838,-0.188 2.303,0.618c0.465,0.805 0.189,1.837 -0.617,2.302c-0.806,0.465 -1.838,0.189 -2.303,-0.617c-0.465,-0.806 -0.189,-1.837 0.617,-2.303Zm2.051,3.395c0.657,-0.657 1.726,-0.657 2.383,0c0.658,0.658 0.658,1.727 0.001,2.384c-0.658,0.658 -1.726,0.658 -2.384,0c-0.658,-0.658 -0.658,-1.726 -0,-2.384Zm2.859,2.749c0.465,-0.806 1.497,-1.082 2.302,-0.617c0.806,0.465 1.083,1.497 0.618,2.303c-0.466,0.805 -1.497,1.082 -2.303,0.617c-0.806,-0.466 -1.083,-1.497 -0.617,-2.303Zm3.473,1.915c0.241,-0.899 1.166,-1.433 2.064,-1.192c0.899,0.241 1.433,1.166 1.192,2.065c-0.24,0.898 -1.165,1.432 -2.064,1.191c-0.899,-0.24 -1.433,-1.165 -1.192,-2.064Zm3.85,0.951c0,-0.931 0.756,-1.686 1.686,-1.686c0.93,0 1.686,0.755 1.686,1.686c-0,0.93 -0.756,1.685 -1.686,1.685c-0.93,0 -1.686,-0.755 -1.686,-1.685Zm3.965,-0.078c-0.24,-0.899 0.294,-1.824 1.193,-2.065c0.898,-0.241 1.823,0.293 2.064,1.192c0.241,0.899 -0.293,1.824 -1.192,2.064c-0.899,0.241 -1.824,-0.293 -2.065,-1.191Zm3.81,-1.102c-0.465,-0.806 -0.188,-1.838 0.618,-2.303c0.805,-0.465 1.837,-0.189 2.302,0.617c0.465,0.806 0.189,1.837 -0.617,2.303c-0.806,0.465 -1.837,0.188 -2.303,-0.617Zm3.395,-2.051c-0.657,-0.657 -0.657,-1.726 0,-2.384c0.658,-0.657 1.727,-0.657 2.384,0c0.658,0.658 0.658,1.726 0,2.384c-0.658,0.658 -1.726,0.658 -2.384,0Zm2.749,-2.859c-0.806,-0.465 -1.082,-1.497 -0.617,-2.302c0.465,-0.806 1.497,-1.083 2.303,-0.618c0.805,0.466 1.082,1.497 0.617,2.303c-0.466,0.806 -1.497,1.082 -2.303,0.617Zm1.915,-3.473c-0.899,-0.241 -1.433,-1.166 -1.192,-2.064c0.241,-0.899 1.166,-1.433 2.065,-1.193c0.898,0.241 1.432,1.166 1.191,2.065c-0.24,0.899 -1.165,1.433 -2.064,1.192Zm0.951,-3.85c-0.931,-0 -1.686,-0.756 -1.686,-1.686c0,-0.93 0.755,-1.686 1.686,-1.686c0.93,0 1.685,0.756 1.685,1.686c0,0.93 -0.755,1.686 -1.685,1.686Zm-0.078,-3.966c-0.899,0.241 -1.824,-0.293 -2.065,-1.192c-0.241,-0.898 0.293,-1.823 1.192,-2.064c0.899,-0.241 1.824,0.293 2.064,1.192c0.241,0.899 -0.293,1.824 -1.191,2.064Zm-1.102,-3.809c-0.806,0.465 -1.838,0.188 -2.303,-0.618c-0.465,-0.805 -0.189,-1.837 0.617,-2.302c0.806,-0.465 1.837,-0.189 2.303,0.617c0.465,0.806 0.188,1.837 -0.617,2.303Zm-2.051,-3.395c-0.657,0.657 -1.726,0.657 -2.384,-0.001c-0.657,-0.657 -0.657,-1.726 0,-2.383c0.658,-0.658 1.726,-0.658 2.384,-0c0.658,0.658 0.658,1.726 0,2.384Zm-2.859,-2.749c-0.465,0.806 -1.497,1.082 -2.302,0.617c-0.806,-0.465 -1.083,-1.497 -0.618,-2.303c0.466,-0.805 1.497,-1.082 2.303,-0.617c0.806,0.465 1.082,1.497 0.617,2.303Zm-3.473,-1.915c-0.241,0.899 -1.166,1.433 -2.064,1.192c-0.899,-0.241 -1.433,-1.166 -1.193,-2.065c0.241,-0.898 1.166,-1.432 2.065,-1.191c0.899,0.24 1.433,1.165 1.192,2.064Zm-3.85,-0.951c-0,0.931 -0.756,1.686 -1.686,1.686c-0.93,-0 -1.686,-0.755 -1.686,-1.686c0,-0.93 0.756,-1.685 1.686,-1.685c0.93,-0 1.686,0.755 1.686,1.685Zm-3.966,0.078c0.241,0.899 -0.293,1.824 -1.192,2.065c-0.898,0.241 -1.823,-0.293 -2.064,-1.192c-0.241,-0.899 0.293,-1.824 1.192,-2.064c0.899,-0.241 1.824,0.293 2.064,1.191Zm-3.809,1.102c0.465,0.806 0.188,1.838 -0.618,2.303c-0.805,0.465 -1.837,0.189 -2.302,-0.617c-0.466,-0.806 -0.189,-1.838 0.617,-2.303c0.806,-0.465 1.837,-0.188 2.303,0.617Zm-3.395,2.051c0.657,0.657 0.657,1.726 -0.001,2.383c-0.657,0.658 -1.726,0.658 -2.383,0.001c-0.658,-0.658 -0.658,-1.726 -0,-2.384c0.658,-0.658 1.726,-0.658 2.384,-0Zm-2.749,2.859c0.806,0.465 1.082,1.497 0.617,2.302c-0.465,0.806 -1.497,1.083 -2.303,0.618c-0.806,-0.466 -1.082,-1.497 -0.617,-2.303c0.465,-0.806 1.497,-1.082 2.303,-0.617Zm-1.915,3.473c0.899,0.241 1.433,1.166 1.192,2.064c-0.241,0.899 -1.166,1.433 -2.065,1.192c-0.898,-0.24 -1.432,-1.165 -1.191,-2.064c0.24,-0.899 1.165,-1.433 2.064,-1.192Z"
style={{ fill: 'none', stroke: color, strokeWidth: '0.27px' }}
/>
<Path
d="M41.098,22.931c0,-9.799 -8.158,-17.755 -18.207,-17.755c-10.049,0 -18.208,7.956 -18.208,17.755c0,9.799 8.159,17.755 18.208,17.755c10.049,-0 18.207,-7.956 18.207,-17.755Z"
style={{ fill: 'none', stroke: color, strokeWidth: '0.75px' }}
/>
</G>
</Svg>
);
export const PDFBusinessCard: React.FC<PDFBusinessCardProps> = ({
person,
qrCodeDataUrl,
variant = 'blue',
isViaprinto = false,
withTruck = true,
withCropMarks = false,
}) => {
const isWhiteVariant = variant === 'white' || variant === 'black';
const logoWhitePath = path.join(process.cwd(), 'public', 'logo-green-text.svg');
const logoBluePath = path.join(process.cwd(), 'public', 'logo-green-text-blue.svg');
const logoBlueWithTaglinePath = path.join(
process.cwd(),
'public',
'logo-green-text-blue-with-tagline.svg',
);
const logoBlackWithTaglinePath = path.join(
process.cwd(),
'public',
'logo-green-text-black-with-tagline.svg',
);
const logoWhitePaths = parseSvgPaths(logoWhitePath);
const logoBluePaths = parseSvgPaths(logoBluePath);
const logoBlueWithTaglinePaths = parseSvgPaths(logoBlueWithTaglinePath);
const logoBlackWithTaglinePaths = parseSvgPaths(logoBlackWithTaglinePath);
const getFrontLogoPaths = () => {
if (variant === 'black') return logoBlackWithTaglinePaths;
if (variant === 'white') return logoBlueWithTaglinePaths;
return logoWhitePaths;
};
const getBackLogoPaths = () => {
return logoBlackWithTaglinePaths;
};
const bgImagePath = isWhiteVariant
? path.join(process.cwd(), 'public', 'media', 'cable_drums_truck.png')
: path.join(process.cwd(), 'public', 'cable_drums_bg.png');
const renderPageWrapper = (children: React.ReactNode, bleedStyle: any) => {
if (withCropMarks) {
return (
<Page size={[315, 230]} style={{ backgroundColor: '#ffffff' }}>
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
<CropMarks />
<View style={[bleedStyle, { overflow: 'hidden', position: 'relative' }]}>
{children}
</View>
</View>
</Page>
);
}
return (
<Page size={[258, 173]} style={bleedStyle}>
{children}
</Page>
);
};
return (
<Document
title={`Business Card - ${person.name}`}
author="KLZ Cables"
creator="KLZ Print Engine"
>
{/* VORDERSEITE (Blue page with logo, truck and tagline) */}
{renderPageWrapper(
<>
<View style={styles.frontFooterArea}>
<Text style={[styles.frontTaglineBar, isWhiteVariant && { color: COLORS.black }]}>
Von 0,6/1,0 kV bis 64/110 kV
</Text>
<View style={styles.frontIconsGroup}>
<View style={styles.frontBrandIconWrapper}>
<IconLowVoltage
style={styles.frontBrandIcon}
color={isWhiteVariant ? COLORS.black : 'white'}
/>
<Text style={[styles.frontBrandText, isWhiteVariant && { color: COLORS.black }]}>
Niederspannung
</Text>
</View>
<View style={styles.frontBrandIconWrapper}>
<IconMediumVoltage
style={styles.frontBrandIcon}
color={isWhiteVariant ? COLORS.black : 'white'}
/>
<Text style={[styles.frontBrandText, isWhiteVariant && { color: COLORS.black }]}>
Mittelspannung
</Text>
</View>
<View style={styles.frontBrandIconWrapper}>
<IconHighVoltage
style={styles.frontBrandIcon}
color={isWhiteVariant ? COLORS.black : 'white'}
/>
<Text style={[styles.frontBrandText, isWhiteVariant && { color: COLORS.black }]}>
Hochspannung
</Text>
</View>
<View style={styles.frontBrandIconWrapper}>
<IconSolar
style={styles.frontBrandIcon}
color={isWhiteVariant ? COLORS.black : 'white'}
/>
<Text style={[styles.frontBrandText, isWhiteVariant && { color: COLORS.black }]}>
Solar
</Text>
</View>
</View>
</View>
<View style={styles.frontContainer}>
{/* Base Logo: text is white, truck is green. Fill KLZ background to hide truck, keep outline white */}
<VectorLogo
paths={getFrontLogoPaths()}
style={styles.frontLogo}
solidPaths={KLZ_PATHS}
solidBackgroundColor={isWhiteVariant ? '#ffffff' : COLORS.primary}
/>
{/* Letterpress Mask Layer: We use #ff00fe as a marker color. Only the "KLZ" letters! */}
{isViaprinto && (
<VectorLogo
paths={getFrontLogoPaths().filter((_, i) => KLZ_PATHS.includes(i))}
style={[styles.frontLogo, { position: 'absolute' }]}
overrideColor="#ff00fe"
solidPaths={KLZ_PATHS.map((_, i) => i)}
/>
)}
</View>
</>,
[styles.pageBleed, isWhiteVariant && { backgroundColor: '#ffffff' }],
)}
{renderPageWrapper(
<View style={styles.backContainer}>
<View style={styles.backHeader}>
<VectorLogo
paths={getBackLogoPaths()}
style={styles.backLogo}
overrideWhiteColor={COLORS.black}
pathOverrides={KLZ_PATHS.reduce((acc, idx) => ({ ...acc, [idx]: 'none' }), {})}
/>
<View style={styles.accentLineHorizontal} />
<View style={styles.qrContainer}>
<View style={[styles.qrCodeWrapper, { borderColor: COLORS.darkGreen }]}>
<Image src={qrCodeDataUrl} style={styles.qrCode} />
</View>
</View>
</View>
<View style={styles.backBody}>
<View style={styles.leftColumn}>
<View style={styles.nameSection}>
<Text style={styles.nameText}>{person.name}</Text>
<Text style={styles.roleText}>{person.role}</Text>
</View>
<View style={styles.contactSection}>
<View style={styles.contactRow}>
<View style={styles.iconWrapper}>
<PhoneIcon />
</View>
<Text style={styles.contactText}>{person.phone}</Text>
</View>
<View style={styles.contactRow}>
<View style={styles.iconWrapper}>
<EmailIcon />
</View>
<Text style={styles.contactText}>{person.email.toLowerCase()}</Text>
</View>
<View style={styles.contactRow}>
<View style={styles.iconWrapper}>
<GlobeIcon />
</View>
<Text style={styles.contactText}>klz-cables.com</Text>
</View>
</View>
</View>
</View>
<View style={styles.addressFooter}>
<Text style={styles.addressFooterText}>
KLZ Vertriebs GmbH · Raiffeisenstraße 22 · 73630 Remshalden
</Text>
</View>
</View>,
styles.pageBleedBack,
)}
</Document>
);
};