fix(pdf): render truck as vector, fix back logo coloring
Some checks failed
Build & Deploy / 🔍 Prepare (push) Successful in 11s
Build & Deploy / 🧪 QA (push) Failing after 1m21s
Build & Deploy / 🏗️ Build (push) Has been skipped
Build & Deploy / 🚀 Deploy (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 11s
Build & Deploy / 🧪 QA (push) Failing after 1m21s
Build & Deploy / 🏗️ Build (push) Has been skipped
Build & Deploy / 🚀 Deploy (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:
9898
lib/TruckBlueprint.tsx
Normal file
9898
lib/TruckBlueprint.tsx
Normal file
File diff suppressed because one or more lines are too long
@@ -16,6 +16,7 @@ import {
|
|||||||
Circle,
|
Circle,
|
||||||
} from '@react-pdf/renderer';
|
} from '@react-pdf/renderer';
|
||||||
import * as path from 'path';
|
import * as path from 'path';
|
||||||
|
import { TruckBlueprint } from './TruckBlueprint';
|
||||||
|
|
||||||
// Register embedded fonts so Ghostscript -dNoOutputFonts can convert them to
|
// Register embedded fonts so Ghostscript -dNoOutputFonts can convert them to
|
||||||
// outlines (curves). Built-in PDF fonts like Helvetica are NEVER embedded and
|
// outlines (curves). Built-in PDF fonts like Helvetica are NEVER embedded and
|
||||||
@@ -89,9 +90,6 @@ const styles = StyleSheet.create({
|
|||||||
frontBackgroundImage: {
|
frontBackgroundImage: {
|
||||||
width: '100%',
|
width: '100%',
|
||||||
height: '100%',
|
height: '100%',
|
||||||
objectFit: 'contain',
|
|
||||||
objectPositionX: 'center',
|
|
||||||
objectPositionY: 'center',
|
|
||||||
opacity: 0.4, // Less transparent, more contrast
|
opacity: 0.4, // Less transparent, more contrast
|
||||||
},
|
},
|
||||||
frontContainer: {
|
frontContainer: {
|
||||||
@@ -362,16 +360,25 @@ const VectorLogo = ({
|
|||||||
paths,
|
paths,
|
||||||
style,
|
style,
|
||||||
overrideColor,
|
overrideColor,
|
||||||
|
overrideWhiteColor,
|
||||||
}: {
|
}: {
|
||||||
paths: { d: string; fill: string }[];
|
paths: { d: string; fill: string }[];
|
||||||
style: any;
|
style: any;
|
||||||
overrideColor?: string;
|
overrideColor?: string;
|
||||||
|
overrideWhiteColor?: string;
|
||||||
}) => (
|
}) => (
|
||||||
<Svg viewBox="0 0 295 99" style={style}>
|
<Svg viewBox="0 0 295 99" style={style}>
|
||||||
<G {...({ fillRule: 'evenodd', clipRule: 'evenodd' } as any)}>
|
<G {...({ fillRule: 'evenodd', clipRule: 'evenodd' } as any)}>
|
||||||
{paths.map((p, i) => (
|
{paths.map((p, i) => {
|
||||||
<Path key={i} d={p.d} fill={overrideColor || p.fill} />
|
let fill = overrideColor || p.fill;
|
||||||
))}
|
if (
|
||||||
|
overrideWhiteColor &&
|
||||||
|
(p.fill === 'white' || p.fill === '#ffffff' || p.fill === '#fff')
|
||||||
|
) {
|
||||||
|
fill = overrideWhiteColor;
|
||||||
|
}
|
||||||
|
return <Path key={i} d={p.d} fill={fill} />;
|
||||||
|
})}
|
||||||
</G>
|
</G>
|
||||||
</Svg>
|
</Svg>
|
||||||
);
|
);
|
||||||
@@ -704,8 +711,7 @@ export const PDFBusinessCard: React.FC<PDFBusinessCardProps> = ({
|
|||||||
style={[styles.pageBleed, isWhiteVariant && { backgroundColor: '#ffffff' }]}
|
style={[styles.pageBleed, isWhiteVariant && { backgroundColor: '#ffffff' }]}
|
||||||
>
|
>
|
||||||
<View style={styles.truckWrapper}>
|
<View style={styles.truckWrapper}>
|
||||||
<Image
|
<TruckBlueprint
|
||||||
src={bgImagePath}
|
|
||||||
style={[styles.frontBackgroundImage, isWhiteVariant && { opacity: 0.2 }]}
|
style={[styles.frontBackgroundImage, isWhiteVariant && { opacity: 0.2 }]}
|
||||||
/>
|
/>
|
||||||
</View>
|
</View>
|
||||||
@@ -766,7 +772,11 @@ export const PDFBusinessCard: React.FC<PDFBusinessCardProps> = ({
|
|||||||
<Page size={[258, 173]} style={styles.pageBleedBack}>
|
<Page size={[258, 173]} style={styles.pageBleedBack}>
|
||||||
<View style={styles.backContainer}>
|
<View style={styles.backContainer}>
|
||||||
<View style={styles.backHeader}>
|
<View style={styles.backHeader}>
|
||||||
<VectorLogo paths={logoBluePaths} style={styles.backLogo} overrideColor={COLORS.blue} />
|
<VectorLogo
|
||||||
|
paths={logoWhitePaths}
|
||||||
|
style={styles.backLogo}
|
||||||
|
overrideWhiteColor={COLORS.blue}
|
||||||
|
/>
|
||||||
<View style={styles.accentLineHorizontal} />
|
<View style={styles.accentLineHorizontal} />
|
||||||
</View>
|
</View>
|
||||||
|
|
||||||
|
|||||||
64
scripts/svg-to-react-pdf.ts
Normal file
64
scripts/svg-to-react-pdf.ts
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
import fs from 'fs';
|
||||||
|
|
||||||
|
const svgFile = process.argv[2];
|
||||||
|
const outFile = process.argv[3];
|
||||||
|
|
||||||
|
let content = fs.readFileSync(svgFile, 'utf8');
|
||||||
|
|
||||||
|
content = content.replace(/<\?xml.*\?>/g, '');
|
||||||
|
content = content.replace(/<!DOCTYPE.*>/g, '');
|
||||||
|
content = content.replace(/xmlns:xlink="[^"]+"/g, '');
|
||||||
|
content = content.replace(/xmlns:serif="[^"]+"/g, '');
|
||||||
|
content = content.replace(/xml:space="preserve"/g, '');
|
||||||
|
content = content.replace(/xmlns="[^"]+"/g, '');
|
||||||
|
content = content.replace(/version="[^"]+"/g, '');
|
||||||
|
|
||||||
|
// Convert attributes to camelCase
|
||||||
|
content = content.replace(/fill-rule/g, 'fillRule');
|
||||||
|
content = content.replace(/clip-rule/g, 'clipRule');
|
||||||
|
content = content.replace(/stroke-linejoin/g, 'strokeLinejoin');
|
||||||
|
content = content.replace(/stroke-miterlimit/g, 'strokeMiterlimit');
|
||||||
|
|
||||||
|
// Convert style="fill:#xxxx;fill-rule:nonzero;" to fill="#xxxx" fillRule="nonzero"
|
||||||
|
content = content.replace(/style="([^"]+)"/g, (match, styleStr) => {
|
||||||
|
const parts = styleStr.split(';').filter(Boolean);
|
||||||
|
let attrs = [];
|
||||||
|
for (const part of parts) {
|
||||||
|
const [key, val] = part.split(':');
|
||||||
|
if (key === 'fill') attrs.push(`fill="${val}"`);
|
||||||
|
if (key === 'fillRule' || key === 'fill-rule') attrs.push(`fillRule="${val}"`);
|
||||||
|
if (key === 'clipRule' || key === 'clip-rule') attrs.push(`clipRule="${val}"`);
|
||||||
|
if (key === 'strokeLinejoin' || key === 'stroke-linejoin')
|
||||||
|
attrs.push(`strokeLinejoin="${val}"`);
|
||||||
|
if (key === 'strokeMiterlimit' || key === 'stroke-miterlimit')
|
||||||
|
attrs.push(`strokeMiterlimit="${val}"`);
|
||||||
|
}
|
||||||
|
return attrs.join(' ');
|
||||||
|
});
|
||||||
|
|
||||||
|
// React components
|
||||||
|
content = content.replace(/<svg/g, '<Svg');
|
||||||
|
content = content.replace(/<\/svg>/g, '</Svg>');
|
||||||
|
content = content.replace(/<g/g, '<G');
|
||||||
|
content = content.replace(/<\/g>/g, '</G>');
|
||||||
|
content = content.replace(/<path/g, '<Path');
|
||||||
|
content = content.replace(/<\/path>/g, '</Path>');
|
||||||
|
|
||||||
|
// In React PDF, width/height on Svg can be removed and controlled via style.
|
||||||
|
content = content.replace(/width="100%" height="100%" /, '');
|
||||||
|
|
||||||
|
const final = `
|
||||||
|
import React from 'react';
|
||||||
|
import { Svg, G, Path } from '@react-pdf/renderer';
|
||||||
|
|
||||||
|
export const TruckBlueprint = ({ style, opacity = 1 }: { style?: any, opacity?: number }) => (
|
||||||
|
<Svg viewBox="0 0 1615 974" style={[style, { opacity }]}>
|
||||||
|
<G fillRule="evenodd" clipRule="evenodd" strokeLinejoin="round" strokeMiterlimit="2">
|
||||||
|
${content.match(/<G[\s\S]*<\/G>/)?.[0] || content}
|
||||||
|
</G>
|
||||||
|
</Svg>
|
||||||
|
);
|
||||||
|
`;
|
||||||
|
|
||||||
|
fs.writeFileSync(outFile, final);
|
||||||
|
console.log('Done!');
|
||||||
Reference in New Issue
Block a user