feat: content engine usw

This commit is contained in:
2026-02-25 12:43:57 +01:00
parent a55a5bb834
commit 960914ebb8
21 changed files with 722 additions and 203 deletions

View File

@@ -13,6 +13,8 @@ import {
Footer,
FoldingMarks,
DocumentTitle,
COLORS,
FONT_SIZES,
} from "./pdf/SharedUI.js";
import { SimpleLayout } from "./pdf/SimpleLayout.js";
@@ -29,23 +31,23 @@ const localStyles = PDFStyleSheet.create({
marginBottom: 6,
},
monoNumber: {
fontSize: 7,
fontSize: FONT_SIZES.TINY,
fontWeight: "bold",
color: "#94a3b8",
color: COLORS.TEXT_LIGHT,
letterSpacing: 2,
width: 25,
},
sectionTitle: {
fontSize: 9,
fontSize: FONT_SIZES.LABEL,
fontWeight: "bold",
color: "#000000",
color: COLORS.CHARCOAL,
textTransform: "uppercase",
letterSpacing: 0.5,
},
officialText: {
fontSize: 8,
fontSize: FONT_SIZES.BODY,
lineHeight: 1.5,
color: "#334155",
color: COLORS.TEXT_MAIN,
textAlign: "justify",
paddingLeft: 25,
},
@@ -100,7 +102,7 @@ export const AgbsPDF = ({
};
const content = (
<>
<PDFView>
<DocumentTitle
title="Allgemeine Geschäftsbedingungen"
subLines={[`Stand: ${date}`]}
@@ -142,7 +144,7 @@ export const AgbsPDF = ({
<AGBSection index="05" title="Abnahme">
Die Leistung gilt als abgenommen, wenn der Auftraggeber sie produktiv
nutzt oder innerhalb von 7 Tagen nach Bereitstellung keine
nutzt oder innerhalb von 30 Tagen nach Bereitstellung keine
wesentlichen Mängel angezeigt werden. Optische Abweichungen,
Geschmacksfragen oder subjektive Einschätzungen stellen keine Mängel
dar.
@@ -206,7 +208,7 @@ export const AgbsPDF = ({
bleibt die Wirksamkeit der übrigen Regelungen unberührt.
</AGBSection>
</PDFView>
</>
</PDFView>
);
if (mode === "full") {
@@ -214,9 +216,8 @@ export const AgbsPDF = ({
<SimpleLayout
companyData={companyData}
bankData={bankData}
headerIcon={headerIcon}
footerLogo={footerLogo}
icon={headerIcon}
pageNumber="10"
showPageNumber={false}
>
{content}
@@ -232,7 +233,7 @@ export const AgbsPDF = ({
<Footer
logo={footerLogo}
companyData={companyData}
bankData={bankData}
_bankData={bankData}
showDetails={false}
showPageNumber={false}
/>

View File

@@ -46,7 +46,7 @@ export const CombinedQuotePDF = ({
const layoutProps = {
date,
icon: estimationProps.headerIcon,
headerIcon: estimationProps.headerIcon,
footerLogo: estimationProps.footerLogo,
companyData,
bankData,
@@ -71,7 +71,7 @@ export const CombinedQuotePDF = ({
footerLogo={estimationProps.footerLogo}
/>
)}
<SimpleLayout {...layoutProps} pageNumber="END" showPageNumber={false}>
<SimpleLayout {...layoutProps} showPageNumber={false}>
<ClosingModule />
</SimpleLayout>
</PDFDocument>

View File

@@ -50,7 +50,7 @@ export const EstimationPDF = ({
const commonProps = {
state,
date,
icon: headerIcon,
headerIcon,
footerLogo,
companyData,
};
@@ -64,17 +64,17 @@ export const EstimationPDF = ({
<FrontPageModule state={state} headerIcon={headerIcon} date={date} />
</PDFPage>
<SimpleLayout {...commonProps} pageNumber={getPageNum()}>
<SimpleLayout {...commonProps}>
<BriefingModule state={state} />
</SimpleLayout>
{state.sitemap && state.sitemap.length > 0 && (
<SimpleLayout {...commonProps} pageNumber={getPageNum()}>
<SimpleLayout {...commonProps}>
<SitemapModule state={state} />
</SimpleLayout>
)}
<SimpleLayout {...commonProps} pageNumber={getPageNum()}>
<SimpleLayout {...commonProps}>
<EstimationModule
state={state}
positions={positions}
@@ -83,11 +83,11 @@ export const EstimationPDF = ({
/>
</SimpleLayout>
<SimpleLayout {...commonProps} pageNumber={getPageNum()}>
<SimpleLayout {...commonProps}>
<TransparenzModule pricing={pricing} />
</SimpleLayout>
<SimpleLayout {...commonProps} pageNumber={getPageNum()}>
<SimpleLayout {...commonProps}>
<ClosingModule />
</SimpleLayout>
</PDFDocument>

View File

@@ -8,58 +8,48 @@ const simpleStyles = StyleSheet.create({
industrialPage: {
padding: 30,
paddingTop: 20,
backgroundColor: '#ffffff',
flexDirection: 'column',
backgroundColor: '#FFFFFF',
fontFamily: 'Outfit',
},
industrialNumber: {
fontSize: 60,
fontWeight: 'bold',
color: '#f1f5f9',
position: 'absolute',
top: -10,
right: 0,
zIndex: -1,
},
industrialSection: {
marginTop: 16,
paddingTop: 12,
flexDirection: 'row',
position: 'relative',
contentView: {
flex: 1,
marginTop: 20,
},
});
interface SimpleLayoutProps {
children: React.ReactNode;
pageNumber?: string;
icon?: string;
headerIcon?: string;
footerLogo?: string;
companyData: any;
bankData?: any;
showDetails?: boolean;
showPageNumber?: boolean;
children: React.ReactNode;
}
export const SimpleLayout = ({
children,
pageNumber,
icon,
export const SimpleLayout: React.FC<SimpleLayoutProps> = ({
headerIcon,
footerLogo,
companyData,
bankData,
showPageNumber = true
}: SimpleLayoutProps) => {
showDetails = false,
showPageNumber = true,
children,
}) => {
return (
<PDFPage size="A4" style={[pdfStyles.page, simpleStyles.industrialPage]}>
<Header icon={icon} showAddress={false} />
{pageNumber && <PDFText style={simpleStyles.industrialNumber}>{pageNumber}</PDFText>}
<PDFView style={simpleStyles.industrialSection}>
<PDFView style={{ width: '100%' }}>
{children}
</PDFView>
<PDFPage size="A4" style={simpleStyles.industrialPage}>
<Header icon={headerIcon} sender={companyData.name} showAddress={false} />
<PDFView style={simpleStyles.contentView}>
{children}
</PDFView>
<Footer
logo={footerLogo}
companyData={companyData}
bankData={bankData}
showDetails={false}
_bankData={bankData}
showDetails={showDetails}
showPageNumber={showPageNumber}
/>
</PDFPage>

View File

@@ -0,0 +1,53 @@
import { renderToFile, Document as PDFDocument, Font } from "@react-pdf/renderer";
import { createElement } from "react";
import { AgbsPDF } from "./components/AgbsPDF.js";
import path from "path";
import fs from "fs";
import { fileURLToPath } from "url";
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
// Standard Font Registration
Font.register({
family: 'Outfit',
fonts: [
{ src: 'Helvetica' },
{ src: 'Helvetica-Bold', fontWeight: 'bold' },
],
});
Font.register({
family: 'Helvetica',
fonts: [
{ src: 'Helvetica' },
{ src: 'Helvetica-Bold', fontWeight: 'bold' },
],
});
async function generate() {
const outDir = path.join(__dirname, "../../../out");
if (!fs.existsSync(outDir)) {
fs.mkdirSync(outDir, { recursive: true });
}
const outputPath = path.resolve(outDir, "AGB_Mintel.pdf");
console.log("Generating High-Fidelity AGB PDF...");
const headerIcon = "/Users/marcmintel/Projects/mintel.me/apps/web/src/assets/logo/Icon-White-Transparent.png";
const footerLogo = "/Users/marcmintel/Projects/mintel.me/apps/web/src/assets/logo/Logo-Black-Transparent.png";
// WRAP IN DOCUMENT - MANDATORY FOR standalone rendering
const document = createElement(PDFDocument, {
title: "Allgemeine Geschäftsbedingungen - Marc Mintel",
author: "Marc Mintel",
},
createElement(AgbsPDF, { mode: "full", headerIcon, footerLogo })
);
await renderToFile(document, outputPath);
console.log(`Generated: ${outputPath}`);
}
generate().catch(console.error);