fix: resolve background fill and text colors on both business card sides
This commit is contained in:
19593
lib/TruckBlueprint.tsx
19593
lib/TruckBlueprint.tsx
File diff suppressed because one or more lines are too long
@@ -46,6 +46,7 @@ export interface PDFBusinessCardProps {
|
||||
person: PersonData;
|
||||
qrCodeDataUrl: string;
|
||||
variant?: 'blue' | 'white' | 'black';
|
||||
isViaprinto?: boolean;
|
||||
}
|
||||
|
||||
// Die Buchstaben K, L, Z im SVG (inklusive dem kleinen Stück vom Z oben links)
|
||||
@@ -178,7 +179,7 @@ const styles = StyleSheet.create({
|
||||
accentLineHorizontal: {
|
||||
flex: 1,
|
||||
height: 1.5,
|
||||
backgroundColor: COLORS.primary, // Brand blue line
|
||||
backgroundColor: '#011dff', // Brand blue line
|
||||
marginLeft: 15,
|
||||
marginRight: 0,
|
||||
},
|
||||
@@ -223,7 +224,7 @@ const styles = StyleSheet.create({
|
||||
roleText: {
|
||||
fontSize: 7.5,
|
||||
fontWeight: 'bold',
|
||||
color: COLORS.primary,
|
||||
color: '#011dff',
|
||||
letterSpacing: 0.5,
|
||||
textTransform: 'uppercase',
|
||||
},
|
||||
@@ -258,15 +259,15 @@ const styles = StyleSheet.create({
|
||||
gap: 3,
|
||||
},
|
||||
qrCodeWrapper: {
|
||||
width: '13mm',
|
||||
height: '13mm',
|
||||
width: '11mm',
|
||||
height: '11mm',
|
||||
},
|
||||
qrCode: {
|
||||
width: '100%',
|
||||
height: '100%',
|
||||
},
|
||||
qrLabel: {
|
||||
fontSize: 4.5,
|
||||
fontSize: 4,
|
||||
color: COLORS.neutralDark, // Subtle grey instead of loud blue
|
||||
fontWeight: 'bold',
|
||||
letterSpacing: 1.2,
|
||||
@@ -367,6 +368,7 @@ const VectorLogo = ({
|
||||
overrideWhiteColor,
|
||||
pathOverrides,
|
||||
solidPaths,
|
||||
solidBackgroundColor = '#000a66',
|
||||
}: {
|
||||
paths: { d: string; fill: string }[];
|
||||
style: any;
|
||||
@@ -374,20 +376,25 @@ const VectorLogo = ({
|
||||
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)}>
|
||||
{paths.map((p, i) => {
|
||||
let fill = overrideColor || p.fill;
|
||||
let d = p.d;
|
||||
|
||||
if (solidPaths && solidPaths.includes(i)) {
|
||||
// Keep only the first subpath to make the shape solid (remove holes)
|
||||
{/* 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];
|
||||
@@ -688,6 +695,7 @@ export const PDFBusinessCard: React.FC<PDFBusinessCardProps> = ({
|
||||
person,
|
||||
qrCodeDataUrl,
|
||||
variant = 'blue',
|
||||
isViaprinto = false,
|
||||
}) => {
|
||||
const isWhiteVariant = variant === 'white' || variant === 'black';
|
||||
|
||||
@@ -737,11 +745,9 @@ export const PDFBusinessCard: React.FC<PDFBusinessCardProps> = ({
|
||||
>
|
||||
<View style={styles.truckWrapper}>
|
||||
<TruckBlueprint
|
||||
style={[
|
||||
styles.frontBackgroundImage,
|
||||
isWhiteVariant && { opacity: 0.2 },
|
||||
!isWhiteVariant && { opacity: 0.25 },
|
||||
]}
|
||||
style={styles.frontBackgroundImage}
|
||||
opacity={isWhiteVariant ? 0.2 : 0.25}
|
||||
backgroundColor={isWhiteVariant ? '#ffffff' : '#011dff'}
|
||||
/>
|
||||
</View>
|
||||
<View
|
||||
@@ -781,6 +787,7 @@ export const PDFBusinessCard: React.FC<PDFBusinessCardProps> = ({
|
||||
Hochspannung
|
||||
</Text>
|
||||
</View>
|
||||
|
||||
<View style={styles.frontBrandIconWrapper}>
|
||||
<IconSolar
|
||||
style={styles.frontBrandIcon}
|
||||
@@ -793,33 +800,35 @@ export const PDFBusinessCard: React.FC<PDFBusinessCardProps> = ({
|
||||
</View>
|
||||
</View>
|
||||
<View style={styles.frontContainer}>
|
||||
{/* Base Logo: text is white, truck is green. Make KLZ letters blend into background */}
|
||||
{/* Base Logo: text is white, truck is green. Fill KLZ background to hide truck, keep outline white */}
|
||||
<VectorLogo
|
||||
paths={getFrontLogoPaths()}
|
||||
style={styles.frontLogo}
|
||||
pathOverrides={KLZ_PATHS.reduce((acc, idx) => ({ ...acc, [idx]: COLORS.blue }), {})}
|
||||
solidPaths={KLZ_PATHS}
|
||||
solidBackgroundColor={isWhiteVariant ? '#ffffff' : '#011dff'}
|
||||
/>
|
||||
|
||||
{/* Letterpress Mask Layer: We use #ff00fe as a marker color. Only the "KLZ" letters! */}
|
||||
<VectorLogo
|
||||
paths={getFrontLogoPaths().filter((_, i) => KLZ_PATHS.includes(i))}
|
||||
style={[styles.frontLogo, { position: 'absolute' }]}
|
||||
overrideColor="#ff00fe"
|
||||
solidPaths={KLZ_PATHS.map((_, i) => i)}
|
||||
/>
|
||||
{isViaprinto && (
|
||||
<VectorLogo
|
||||
paths={getFrontLogoPaths().filter((_, i) => KLZ_PATHS.includes(i))}
|
||||
style={[styles.frontLogo, { position: 'absolute' }]}
|
||||
overrideColor="#ff00fe"
|
||||
solidPaths={KLZ_PATHS.map((_, i) => i)}
|
||||
/>
|
||||
)}
|
||||
</View>
|
||||
</Page>
|
||||
|
||||
{/* RÜCKSEITE (White page with contact info) */}
|
||||
{/* VORDERSEITE (White page with contact info) */}
|
||||
<Page size={[258, 173]} style={styles.pageBleedBack}>
|
||||
<View style={styles.backContainer}>
|
||||
<View style={styles.backHeader}>
|
||||
<VectorLogo
|
||||
paths={getBackLogoPaths()}
|
||||
style={styles.backLogo}
|
||||
overrideWhiteColor={COLORS.primary}
|
||||
solidPaths={KLZ_PATHS}
|
||||
overrideWhiteColor={'#011dff'}
|
||||
pathOverrides={KLZ_PATHS.reduce((acc, idx) => ({ ...acc, [idx]: 'none' }), {})}
|
||||
/>
|
||||
<View style={styles.accentLineHorizontal} />
|
||||
</View>
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -19,6 +19,8 @@ const CONFIG = {
|
||||
truckImage: path.join(process.cwd(), 'public/truck.png'),
|
||||
fontRegular: path.join(process.cwd(), 'public/fonts/Inter-Regular.ttf'),
|
||||
fontBold: path.join(process.cwd(), 'public/fonts/Inter-Bold.ttf'),
|
||||
ghostscriptScript:
|
||||
'/Users/marcmintel/.gemini/config/plugins/mintel-ui-standards-plugin/skills/mintel-print-workflow/scripts/convert-cmyk.sh',
|
||||
};
|
||||
|
||||
const PEOPLE: PersonData[] = [
|
||||
@@ -71,39 +73,52 @@ END:VCARD`;
|
||||
});
|
||||
|
||||
const safeName = person.name.replace(/\s+/g, '_');
|
||||
const finalFileName = `KLZ_Visitenkarte_${safeName}.pdf`;
|
||||
const rgbPath = path.join(CONFIG.outputDir, `RGB_${finalFileName}`);
|
||||
const finalPath = path.join(CONFIG.outputDir, finalFileName);
|
||||
|
||||
console.log(`- Rendering React-PDF layout (RGB ONLY, Blue Variant)...`);
|
||||
const buffer = await renderToBuffer(
|
||||
// 1. STANDARD DIGITAL PDF (RGB, no letterpress mask)
|
||||
console.log(`- Rendering standard digital PDF (RGB ONLY, Blue Variant)...`);
|
||||
const finalFileName = `KLZ_Visitenkarte_${safeName}.pdf`;
|
||||
const tempFileName = `temp_${finalFileName}`;
|
||||
const finalPath = path.join(CONFIG.outputDir, finalFileName);
|
||||
const tempPath = path.join(CONFIG.outputDir, tempFileName);
|
||||
|
||||
let buffer = await renderToBuffer(
|
||||
React.createElement(PDFBusinessCard, {
|
||||
person,
|
||||
qrCodeDataUrl,
|
||||
variant: 'blue', // Explicitly use blue now
|
||||
variant: 'blue',
|
||||
isViaprinto: false,
|
||||
}),
|
||||
);
|
||||
fs.writeFileSync(tempPath, buffer);
|
||||
|
||||
fs.writeFileSync(rgbPath, buffer);
|
||||
|
||||
console.log(`- Outlining fonts via Ghostscript (Keeping RGB)...`);
|
||||
const gsCommand = `gs -dNoOutputFonts -sDEVICE=pdfwrite -o "${finalPath}" "${rgbPath}"`;
|
||||
execSync(gsCommand, { stdio: 'ignore' });
|
||||
|
||||
fs.unlinkSync(rgbPath);
|
||||
|
||||
// Convert fonts to outlines via ghostscript
|
||||
const gsCommand = `gs -dNoOutputFonts -sDEVICE=pdfwrite -o "${finalPath}" "${tempPath}"`;
|
||||
execSync(gsCommand, { stdio: 'inherit' });
|
||||
fs.unlinkSync(tempPath);
|
||||
console.log(`✓ Final Print File generated (Fonts to Paths, RGB preserved): ${finalFileName}`);
|
||||
|
||||
// 2. VIAPRINTO PDF (Letterpress mask, CMYK)
|
||||
console.log(`- Rendering Viaprinto PDF (Letterpress mask)...`);
|
||||
const tempViaprintoPath = path.join(CONFIG.outputDir, `temp_viaprinto_${safeName}.pdf`);
|
||||
buffer = await renderToBuffer(
|
||||
React.createElement(PDFBusinessCard, {
|
||||
person,
|
||||
qrCodeDataUrl,
|
||||
variant: 'blue',
|
||||
isViaprinto: true,
|
||||
}),
|
||||
);
|
||||
fs.writeFileSync(tempViaprintoPath, buffer);
|
||||
|
||||
// Convert to CMYK for Viaprinto
|
||||
const finalFileNameCMYK = `KLZ_Visitenkarte_${safeName}_Viaprinto_CMYK_91x61mm_3mmBleed.pdf`;
|
||||
const finalPathCMYK = path.join(CONFIG.outputDir, finalFileNameCMYK);
|
||||
|
||||
console.log(`- Converting to CMYK for Viaprinto...`);
|
||||
const cmykScript =
|
||||
'/Users/marcmintel/.gemini/config/plugins/mintel-ui-standards-plugin/skills/mintel-print-workflow/scripts/convert-cmyk.sh';
|
||||
const cmykCommand = `bash "${cmykScript}" "${finalPath}" "${finalPathCMYK}"`;
|
||||
const cmykCommand = `bash "${CONFIG.ghostscriptScript}" "${tempViaprintoPath}" "${finalPathCMYK}"`;
|
||||
try {
|
||||
execSync(cmykCommand, { stdio: 'ignore' });
|
||||
execSync(cmykCommand, { stdio: 'inherit' });
|
||||
fs.unlinkSync(tempViaprintoPath);
|
||||
console.log(`✓ CMYK Print File generated: ${finalFileNameCMYK}`);
|
||||
} catch (e) {
|
||||
console.error(`❌ CMYK conversion failed! Is Ghostscript installed?`);
|
||||
|
||||
Reference in New Issue
Block a user