feat: migrate npm registry from Verdaccio to Gitea Packages
Some checks failed
Monorepo Pipeline / ⚡ Prioritize Release (push) Successful in 1s
Monorepo Pipeline / 🧹 Lint (push) Failing after 35s
Monorepo Pipeline / 🧪 Test (push) Failing after 35s
Monorepo Pipeline / 🏗️ Build (push) Failing after 12s
Monorepo Pipeline / 🚀 Release (push) Has been skipped
Monorepo Pipeline / 🐳 Build Image Processor (push) Has been skipped
Monorepo Pipeline / 🐳 Build Directus (Base) (push) Has been skipped
Monorepo Pipeline / 🐳 Build Gatekeeper (Product) (push) Has been skipped
Monorepo Pipeline / 🐳 Build Build-Base (push) Has been skipped
Monorepo Pipeline / 🐳 Build Production Runtime (push) Has been skipped
Some checks failed
Monorepo Pipeline / ⚡ Prioritize Release (push) Successful in 1s
Monorepo Pipeline / 🧹 Lint (push) Failing after 35s
Monorepo Pipeline / 🧪 Test (push) Failing after 35s
Monorepo Pipeline / 🏗️ Build (push) Failing after 12s
Monorepo Pipeline / 🚀 Release (push) Has been skipped
Monorepo Pipeline / 🐳 Build Image Processor (push) Has been skipped
Monorepo Pipeline / 🐳 Build Directus (Base) (push) Has been skipped
Monorepo Pipeline / 🐳 Build Gatekeeper (Product) (push) Has been skipped
Monorepo Pipeline / 🐳 Build Build-Base (push) Has been skipped
Monorepo Pipeline / 🐳 Build Production Runtime (push) Has been skipped
This commit is contained in:
70
packages/pdf-library/src/components/ConceptPDF.tsx
Normal file
70
packages/pdf-library/src/components/ConceptPDF.tsx
Normal file
@@ -0,0 +1,70 @@
|
||||
"use client";
|
||||
|
||||
import * as React from "react";
|
||||
import { Page as PDFPage, Document as PDFDocument } from "@react-pdf/renderer";
|
||||
import { pdfStyles } from "./pdf/SharedUI.js";
|
||||
import { SimpleLayout } from "./pdf/SimpleLayout.js";
|
||||
|
||||
// Modules
|
||||
import { FrontPageModule } from "./pdf/modules/FrontPageModule.js";
|
||||
import { BriefingModule } from "./pdf/modules/BriefingModule.js";
|
||||
import { SitemapModule } from "./pdf/modules/SitemapModule.js";
|
||||
import { ClosingModule } from "./pdf/modules/CommonModules.js";
|
||||
|
||||
export const ConceptPDF = ({
|
||||
concept,
|
||||
headerIcon,
|
||||
footerLogo,
|
||||
}: any) => {
|
||||
const date = new Date().toLocaleDateString("de-DE", {
|
||||
year: "numeric",
|
||||
month: "long",
|
||||
day: "numeric",
|
||||
});
|
||||
|
||||
// Flatten the ProjectConcept to match what the legacy modules expect
|
||||
const flatState = {
|
||||
...concept.auditedFacts,
|
||||
briefingSummary: concept.strategy?.briefingSummary || "",
|
||||
designVision: concept.strategy?.designVision || "",
|
||||
sitemap: concept.architecture?.sitemap || [],
|
||||
websiteTopic: concept.architecture?.websiteTopic || concept.auditedFacts?.websiteTopic || "",
|
||||
};
|
||||
|
||||
const companyData = {
|
||||
name: "Marc Mintel",
|
||||
address1: "Georg-Meistermann-Straße 7",
|
||||
address2: "54586 Schüller",
|
||||
ustId: "DE367588065",
|
||||
};
|
||||
|
||||
const commonProps = {
|
||||
state: flatState,
|
||||
date,
|
||||
headerIcon,
|
||||
footerLogo,
|
||||
companyData,
|
||||
};
|
||||
|
||||
return (
|
||||
<PDFDocument title={`Projektkonzept - ${flatState.companyName || "Projekt"}`}>
|
||||
<PDFPage size="A4" style={pdfStyles.titlePage}>
|
||||
<FrontPageModule state={flatState} headerIcon={headerIcon} date={date} />
|
||||
</PDFPage>
|
||||
|
||||
<SimpleLayout {...commonProps}>
|
||||
<BriefingModule state={flatState} />
|
||||
</SimpleLayout>
|
||||
|
||||
{flatState.sitemap && flatState.sitemap.length > 0 && (
|
||||
<SimpleLayout {...commonProps}>
|
||||
<SitemapModule state={flatState} />
|
||||
</SimpleLayout>
|
||||
)}
|
||||
|
||||
<SimpleLayout {...commonProps}>
|
||||
<ClosingModule />
|
||||
</SimpleLayout>
|
||||
</PDFDocument>
|
||||
);
|
||||
};
|
||||
@@ -7,8 +7,6 @@ import { SimpleLayout } from "./pdf/SimpleLayout.js";
|
||||
|
||||
// Modules
|
||||
import { FrontPageModule } from "./pdf/modules/FrontPageModule.js";
|
||||
import { BriefingModule } from "./pdf/modules/BriefingModule.js";
|
||||
import { SitemapModule } from "./pdf/modules/SitemapModule.js";
|
||||
import { EstimationModule } from "./pdf/modules/EstimationModule.js";
|
||||
import { TransparenzModule } from "./pdf/modules/TransparenzModule.js";
|
||||
import { ClosingModule } from "./pdf/modules/CommonModules.js";
|
||||
@@ -64,16 +62,6 @@ export const EstimationPDF = ({
|
||||
<FrontPageModule state={state} headerIcon={headerIcon} date={date} />
|
||||
</PDFPage>
|
||||
|
||||
<SimpleLayout {...commonProps}>
|
||||
<BriefingModule state={state} />
|
||||
</SimpleLayout>
|
||||
|
||||
{state.sitemap && state.sitemap.length > 0 && (
|
||||
<SimpleLayout {...commonProps}>
|
||||
<SitemapModule state={state} />
|
||||
</SimpleLayout>
|
||||
)}
|
||||
|
||||
<SimpleLayout {...commonProps}>
|
||||
<EstimationModule
|
||||
state={state}
|
||||
|
||||
172
packages/pdf-library/src/components/InfoPDF.tsx
Normal file
172
packages/pdf-library/src/components/InfoPDF.tsx
Normal file
@@ -0,0 +1,172 @@
|
||||
"use client";
|
||||
|
||||
import * as React from "react";
|
||||
import {
|
||||
Page as PDFPage,
|
||||
Text as PDFText,
|
||||
View as PDFView,
|
||||
StyleSheet as PDFStyleSheet,
|
||||
Document as PDFDocument,
|
||||
} from "@react-pdf/renderer";
|
||||
import {
|
||||
pdfStyles,
|
||||
DocumentTitle,
|
||||
COLORS,
|
||||
FONT_SIZES,
|
||||
Divider,
|
||||
} from "./pdf/SharedUI.js";
|
||||
import { SimpleLayout } from "./pdf/SimpleLayout.js";
|
||||
|
||||
const styles = PDFStyleSheet.create({
|
||||
section: {
|
||||
marginBottom: 24,
|
||||
},
|
||||
textLead: {
|
||||
fontSize: FONT_SIZES.BODY,
|
||||
color: COLORS.TEXT_MAIN,
|
||||
lineHeight: 1.6,
|
||||
marginBottom: 16,
|
||||
},
|
||||
textRegular: {
|
||||
fontSize: FONT_SIZES.BODY,
|
||||
color: COLORS.TEXT_DIM,
|
||||
lineHeight: 1.6,
|
||||
marginBottom: 12,
|
||||
},
|
||||
bulletPoint: {
|
||||
flexDirection: "row",
|
||||
marginBottom: 6,
|
||||
paddingLeft: 10,
|
||||
},
|
||||
bullet: {
|
||||
width: 15,
|
||||
fontSize: FONT_SIZES.BODY,
|
||||
color: COLORS.TEXT_LIGHT,
|
||||
},
|
||||
bulletText: {
|
||||
flex: 1,
|
||||
fontSize: FONT_SIZES.BODY,
|
||||
color: COLORS.TEXT_DIM,
|
||||
lineHeight: 1.6,
|
||||
},
|
||||
quoteBox: {
|
||||
marginTop: 20,
|
||||
marginBottom: 20,
|
||||
padding: 20,
|
||||
backgroundColor: COLORS.GRID,
|
||||
borderLeftWidth: 3,
|
||||
borderLeftColor: COLORS.CHARCOAL,
|
||||
},
|
||||
quoteText: {
|
||||
fontSize: FONT_SIZES.LABEL,
|
||||
fontWeight: "bold",
|
||||
color: COLORS.CHARCOAL,
|
||||
lineHeight: 1.4,
|
||||
},
|
||||
headingSmall: {
|
||||
fontSize: FONT_SIZES.LABEL,
|
||||
fontWeight: "bold",
|
||||
color: COLORS.CHARCOAL,
|
||||
textTransform: "uppercase",
|
||||
letterSpacing: 1,
|
||||
marginBottom: 12,
|
||||
marginTop: 8,
|
||||
},
|
||||
});
|
||||
|
||||
export const InfoPDF = ({ headerIcon, footerLogo }: { headerIcon?: string; footerLogo?: string }) => {
|
||||
const companyData = {
|
||||
name: "Marc Mintel",
|
||||
address1: "Georg-Meistermann-Straße 7",
|
||||
address2: "54586 Schüller",
|
||||
ustId: "DE367588065",
|
||||
};
|
||||
|
||||
const bankData = {
|
||||
name: "N26",
|
||||
bic: "NTSBDEB1XXX",
|
||||
iban: "DE50 1001 1001 2620 4328 65",
|
||||
};
|
||||
|
||||
const content = (
|
||||
<PDFView>
|
||||
<DocumentTitle
|
||||
title="Arbeitsweise & Philosophie"
|
||||
subLines={["Digital Architect — Marc Mintel"]}
|
||||
isHero={true}
|
||||
/>
|
||||
|
||||
<PDFView style={styles.section}>
|
||||
<PDFText style={styles.headingSmall}>Hintergrund & Motivation</PDFText>
|
||||
<PDFText style={styles.textLead}>
|
||||
Ich baue Websites und Systeme seit über 15 Jahren. Nicht weil ich Websites so liebe – sondern weil ich es hasse, wenn Dinge nicht funktionieren.
|
||||
</PDFText>
|
||||
<PDFText style={styles.textRegular}>
|
||||
In diesen 15 Jahren habe ich Agenturen von innen gesehen, Konzerne erlebt, Startups aufgebaut und gelernt, wie man Dinge baut, die einfach laufen. Heute mache ich das ohne Agentur-Zwischenschichten: Direkt. Sauber. Verantwortlich.
|
||||
</PDFText>
|
||||
</PDFView>
|
||||
|
||||
<PDFView style={styles.quoteBox}>
|
||||
<PDFText style={styles.quoteText}>
|
||||
"Das Problem ist selten Technik. Es ist immer Zuständigkeit. Wenn keiner verantwortlich ist, passiert nichts."
|
||||
</PDFText>
|
||||
</PDFView>
|
||||
|
||||
<PDFView style={styles.section}>
|
||||
<PDFText style={styles.headingSmall}>System-Architektur statt Baukasten</PDFText>
|
||||
<PDFText style={styles.textRegular}>
|
||||
Als Senior Developer in Umgebungen mit Millionenumsätzen habe ich gelernt: Performance ist nicht optional, Sicherheit kein Nice-to-Have. Deshalb sind meine Lösungen:
|
||||
</PDFText>
|
||||
<PDFView style={styles.bulletPoint}>
|
||||
<PDFText style={styles.bullet}>•</PDFText>
|
||||
<PDFText style={styles.bulletText}>Schnell, stabil und "boring" (im besten Sinne).</PDFText>
|
||||
</PDFView>
|
||||
<PDFView style={styles.bulletPoint}>
|
||||
<PDFText style={styles.bullet}>•</PDFText>
|
||||
<PDFText style={styles.bulletText}>Wartungsarm und unabhängig von Plugins oder Agenturen.</PDFText>
|
||||
</PDFView>
|
||||
<PDFView style={styles.bulletPoint}>
|
||||
<PDFText style={styles.bullet}>•</PDFText>
|
||||
<PDFText style={styles.bulletText}>Technologisch auf Augenhöhe mit Konzern-Standards, ohne bürokratischen Overhead.</PDFText>
|
||||
</PDFView>
|
||||
</PDFView>
|
||||
|
||||
<PDFView style={styles.section}>
|
||||
<PDFText style={styles.headingSmall}>Ihre Vorteile</PDFText>
|
||||
<PDFText style={styles.textRegular}>
|
||||
Sie bekommen keinen Projektmanager, keinen starren Prozess und kein CMS-Drama.
|
||||
</PDFText>
|
||||
<PDFView style={{ flexDirection: 'row', marginTop: 10 }}>
|
||||
<PDFView style={{ flex: 1, paddingRight: 20 }}>
|
||||
<PDFText style={{ fontSize: FONT_SIZES.TINY, color: COLORS.TEXT_LIGHT, marginBottom: 4 }}>KOMMUNIKATION</PDFText>
|
||||
<PDFText style={styles.textRegular}>Ein Ansprechpartner. Eine kurze Mail reicht oft aus. Keine endlosen Meetings.</PDFText>
|
||||
</PDFView>
|
||||
<PDFView style={{ flex: 1 }}>
|
||||
<PDFText style={{ fontSize: FONT_SIZES.TINY, color: COLORS.TEXT_LIGHT, marginBottom: 4 }}>VERANTWORTUNG</PDFText>
|
||||
<PDFText style={styles.textRegular}>Ich übernehme das Thema komplett, damit es für Sie kein Thema mehr ist.</PDFText>
|
||||
</PDFView>
|
||||
</PDFView>
|
||||
</PDFView>
|
||||
|
||||
<Divider style={{ marginTop: 20, marginBottom: 20, backgroundColor: COLORS.GRID }} />
|
||||
|
||||
<PDFText style={[styles.textRegular, { fontSize: FONT_SIZES.SMALL, textAlign: 'center', color: COLORS.TEXT_LIGHT }]}>
|
||||
Marc Mintel — Digital Architect & Senior Software Developer
|
||||
</PDFText>
|
||||
</PDFView>
|
||||
);
|
||||
|
||||
return (
|
||||
<PDFDocument title="Marc Mintel - Arbeitsweise">
|
||||
<SimpleLayout
|
||||
companyData={companyData}
|
||||
bankData={bankData}
|
||||
headerIcon={headerIcon}
|
||||
footerLogo={footerLogo}
|
||||
showPageNumber={false}
|
||||
>
|
||||
{content}
|
||||
</SimpleLayout>
|
||||
</PDFDocument>
|
||||
);
|
||||
};
|
||||
@@ -24,9 +24,10 @@ const styles = StyleSheet.create({
|
||||
borderBottomColor: COLORS.GRID,
|
||||
alignItems: "flex-start",
|
||||
},
|
||||
colPos: { width: "8%" },
|
||||
colDesc: { width: "62%" },
|
||||
colQty: { width: "10%", textAlign: "center" },
|
||||
colPos: { width: "6%" },
|
||||
colDesc: { width: "46%", paddingRight: 10 },
|
||||
colQty: { width: "8%", textAlign: "center" },
|
||||
colUnitPrice: { width: "20%", textAlign: "right", paddingRight: 10 },
|
||||
colPrice: { width: "20%", textAlign: "right" },
|
||||
headerText: {
|
||||
fontSize: FONT_SIZES.TINY,
|
||||
@@ -111,7 +112,8 @@ export const EstimationModule = ({
|
||||
Beschreibung
|
||||
</PDFText>
|
||||
<PDFText style={[styles.headerText, styles.colQty]}>Menge</PDFText>
|
||||
<PDFText style={[styles.headerText, styles.colPrice]}>Betrag</PDFText>
|
||||
<PDFText style={[styles.headerText, styles.colUnitPrice]}>E-Preis</PDFText>
|
||||
<PDFText style={[styles.headerText, styles.colPrice]}>Gesamt</PDFText>
|
||||
</PDFView>
|
||||
{positions.map((item: any, i: number) => (
|
||||
<PDFView key={i} style={styles.tableRow} wrap={false}>
|
||||
@@ -125,6 +127,11 @@ export const EstimationModule = ({
|
||||
</PDFText>
|
||||
</PDFView>
|
||||
<PDFText style={[styles.posText, styles.colQty]}>{item.qty}</PDFText>
|
||||
<PDFText style={[styles.priceText, styles.colUnitPrice, { fontSize: FONT_SIZES.SMALL, color: COLORS.TEXT_MAIN, fontWeight: "normal" }]}>
|
||||
{item.price > 0 && item.qty > 0
|
||||
? `${(item.price / item.qty).toLocaleString("de-DE")} €`
|
||||
: "n. A."}
|
||||
</PDFText>
|
||||
<PDFText style={[styles.priceText, styles.colPrice]}>
|
||||
{item.price > 0
|
||||
? `${item.price.toLocaleString("de-DE")} €`
|
||||
|
||||
@@ -17,64 +17,61 @@ const styles = StyleSheet.create({
|
||||
marginBottom: 24,
|
||||
textAlign: "justify",
|
||||
},
|
||||
sitemapTree: { marginTop: 8 },
|
||||
rootNode: {
|
||||
padding: 12,
|
||||
backgroundColor: COLORS.GRID,
|
||||
marginBottom: 20,
|
||||
borderLeftWidth: 2,
|
||||
borderLeftColor: COLORS.CHARCOAL,
|
||||
sitemapTree: {
|
||||
marginTop: 8,
|
||||
borderLeftWidth: 1,
|
||||
borderLeftColor: COLORS.GRID,
|
||||
marginLeft: 4,
|
||||
paddingLeft: 16,
|
||||
},
|
||||
rootTitle: {
|
||||
fontSize: FONT_SIZES.HEADING,
|
||||
fontSize: FONT_SIZES.LABEL,
|
||||
fontWeight: "bold",
|
||||
color: COLORS.CHARCOAL,
|
||||
letterSpacing: 0.5,
|
||||
textTransform: "uppercase",
|
||||
letterSpacing: 1,
|
||||
marginBottom: 16,
|
||||
marginLeft: -16, // offset the padding
|
||||
},
|
||||
categorySection: { marginBottom: 20 },
|
||||
categorySection: { marginBottom: 16 },
|
||||
categoryHeader: {
|
||||
flexDirection: "row",
|
||||
alignItems: "center",
|
||||
paddingBottom: 6,
|
||||
borderBottomWidth: 1,
|
||||
borderBottomColor: COLORS.BLUEPRINT,
|
||||
marginBottom: 10,
|
||||
marginBottom: 8,
|
||||
},
|
||||
categoryIcon: {
|
||||
width: 8,
|
||||
height: 8,
|
||||
backgroundColor: COLORS.GRID,
|
||||
borderInlineWidth: 1,
|
||||
borderColor: COLORS.DIVIDER,
|
||||
marginRight: 10,
|
||||
width: 6,
|
||||
height: 6,
|
||||
backgroundColor: COLORS.CHARCOAL,
|
||||
marginRight: 8,
|
||||
},
|
||||
categoryTitle: {
|
||||
fontSize: FONT_SIZES.BODY,
|
||||
fontWeight: "bold",
|
||||
color: COLORS.CHARCOAL,
|
||||
textTransform: "uppercase",
|
||||
letterSpacing: 1,
|
||||
},
|
||||
pagesGrid: { flexDirection: "row", flexWrap: "wrap" },
|
||||
pageCard: {
|
||||
width: "48%",
|
||||
marginRight: "2%",
|
||||
marginBottom: 12,
|
||||
padding: 10,
|
||||
borderWidth: 1,
|
||||
borderColor: COLORS.GRID,
|
||||
backgroundColor: "#fafafa",
|
||||
pageRow: {
|
||||
flexDirection: "row",
|
||||
alignItems: "flex-start",
|
||||
marginBottom: 6,
|
||||
paddingLeft: 14,
|
||||
},
|
||||
pageBullet: {
|
||||
fontSize: FONT_SIZES.BODY,
|
||||
color: COLORS.TEXT_LIGHT,
|
||||
marginRight: 8,
|
||||
width: 10,
|
||||
},
|
||||
pageTitle: {
|
||||
fontSize: FONT_SIZES.BODY,
|
||||
fontWeight: "bold",
|
||||
color: COLORS.TEXT_MAIN,
|
||||
marginBottom: 4,
|
||||
fontWeight: "bold",
|
||||
},
|
||||
pageDesc: {
|
||||
fontSize: FONT_SIZES.TINY,
|
||||
fontSize: FONT_SIZES.SMALL,
|
||||
color: COLORS.TEXT_DIM,
|
||||
lineHeight: 1.3,
|
||||
marginLeft: 6,
|
||||
marginTop: 1,
|
||||
},
|
||||
});
|
||||
|
||||
@@ -83,16 +80,13 @@ export const SitemapModule = ({ state }: any) => (
|
||||
<DocumentTitle title="Informationsarchitektur" isHero={true} />
|
||||
<PDFView style={styles.section}>
|
||||
<PDFText style={styles.intro}>
|
||||
Die folgende Struktur definiert die logische Hierarchie und
|
||||
Benutzerführung. Sie dient als Bauplan für die technische Umsetzung und
|
||||
stellt sicher, dass alle relevanten Geschäftsbereiche intuitiv
|
||||
auffindbar sind.
|
||||
Die folgende Baumstruktur definiert die logische Hierarchie und
|
||||
Benutzerführung. Sie dient als kompakter Bauplan für die technische
|
||||
Umsetzung aller relevanten Geschäftsbereiche.
|
||||
</PDFText>
|
||||
|
||||
<PDFView style={styles.sitemapTree}>
|
||||
<PDFView style={styles.rootNode}>
|
||||
<PDFText style={styles.rootTitle}>Seitenstruktur</PDFText>
|
||||
</PDFView>
|
||||
<PDFText style={styles.rootTitle}>/ Root (Startseite)</PDFText>
|
||||
|
||||
{state.sitemap?.map((cat: any, i: number) => (
|
||||
<PDFView key={i} style={styles.categorySection} wrap={false}>
|
||||
@@ -101,18 +95,13 @@ export const SitemapModule = ({ state }: any) => (
|
||||
<PDFText style={styles.categoryTitle}>{cat.category}</PDFText>
|
||||
</PDFView>
|
||||
|
||||
<PDFView style={styles.pagesGrid}>
|
||||
<PDFView>
|
||||
{cat.pages.map((p: any, j: number) => (
|
||||
<PDFView
|
||||
key={j}
|
||||
style={[
|
||||
styles.pageCard,
|
||||
j % 2 === 1 ? { marginRight: 0 } : {},
|
||||
]}
|
||||
>
|
||||
<PDFView key={j} style={styles.pageRow}>
|
||||
<PDFText style={styles.pageBullet}>↳</PDFText>
|
||||
<PDFText style={styles.pageTitle}>{p.title}</PDFText>
|
||||
{p.desc && (
|
||||
<PDFText style={styles.pageDesc}>{p.desc}</PDFText>
|
||||
<PDFText style={styles.pageDesc}> – {p.desc}</PDFText>
|
||||
)}
|
||||
</PDFView>
|
||||
))}
|
||||
|
||||
@@ -81,7 +81,7 @@ export const TransparenzModule = ({ pricing }: any) => {
|
||||
},
|
||||
{
|
||||
l: "Sprachversionen",
|
||||
d: "Skalierung der System-Architektur auf Zweit-Sprachen.",
|
||||
d: "Skalierung der Architektur für weitere Sprachen (+20% Aufschlag auf die Zwischensumme aller vorherigen Positionen).",
|
||||
p: "+20%",
|
||||
},
|
||||
{
|
||||
|
||||
@@ -2,6 +2,8 @@ export * from "./logic/pricing/types.js";
|
||||
export * from "./logic/pricing/constants.js";
|
||||
export * from "./logic/pricing/calculator.js";
|
||||
export * from "./components/EstimationPDF.js";
|
||||
export * from "./components/ConceptPDF.js";
|
||||
export * from "./components/InfoPDF.js";
|
||||
export * from "./components/pdf/SimpleLayout.js";
|
||||
export * from "./components/pdf/SharedUI.js";
|
||||
export * from "./components/pdf/modules/FrontPageModule.js";
|
||||
@@ -12,4 +14,5 @@ export * from "./components/pdf/modules/CommonModules.js";
|
||||
export * from "./components/pdf/modules/BrandingModules.js";
|
||||
export * from "./components/pdf/modules/TransparenzModule.js";
|
||||
export * from "./components/AgbsPDF.js";
|
||||
export * from "./components/InfoPDF.js";
|
||||
export * from "./components/CombinedQuotePDF.js";
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { FormState } from "./types.js";
|
||||
|
||||
export const PRICING = {
|
||||
BASE_WEBSITE: 5440, // Updated to match AI prompt requirement in Pass 1
|
||||
BASE_WEBSITE: 4000, // Foundation server infrastructure setup
|
||||
PAGE: 600,
|
||||
FEATURE: 1500,
|
||||
FUNCTION: 800,
|
||||
|
||||
@@ -1,3 +1,2 @@
|
||||
export * from "./index.js";
|
||||
export * from "./services/AcquisitionService.js";
|
||||
export * from "./services/PdfEngine.js";
|
||||
|
||||
@@ -1,6 +1,27 @@
|
||||
import { renderToFile } from "@react-pdf/renderer";
|
||||
import { renderToFile, Font } from "@react-pdf/renderer";
|
||||
import { createElement } from "react";
|
||||
|
||||
// Standard Font Registrations to prevent crashes when PDFs use custom web fonts
|
||||
Font.register({
|
||||
family: 'Outfit',
|
||||
fonts: [
|
||||
{ src: 'Helvetica' },
|
||||
{ src: 'Helvetica-Bold', fontWeight: 'bold' },
|
||||
],
|
||||
});
|
||||
|
||||
Font.register({
|
||||
family: 'Inter',
|
||||
fonts: [
|
||||
{ src: 'Helvetica' },
|
||||
{ src: 'Helvetica-Bold', fontWeight: 'bold' },
|
||||
],
|
||||
});
|
||||
|
||||
import { EstimationPDF } from "../components/EstimationPDF.js";
|
||||
import { ConceptPDF } from "../components/ConceptPDF.js";
|
||||
import { InfoPDF } from "../components/InfoPDF.js";
|
||||
import { AgbsPDF } from "../components/AgbsPDF.js";
|
||||
import { PRICING } from "../logic/pricing/constants.js";
|
||||
import { calculateTotals } from "../logic/pricing/calculator.js";
|
||||
|
||||
@@ -21,4 +42,33 @@ export class PdfEngine {
|
||||
|
||||
return outputPath;
|
||||
}
|
||||
|
||||
async generateConceptPdf(concept: any, outputPath: string): Promise<string> {
|
||||
await renderToFile(
|
||||
createElement(ConceptPDF as any, {
|
||||
concept,
|
||||
} as any) as any,
|
||||
outputPath
|
||||
);
|
||||
|
||||
return outputPath;
|
||||
}
|
||||
|
||||
async generateInfoPdf(outputPath: string, options: { headerIcon?: string; footerLogo?: string } = {}): Promise<string> {
|
||||
await renderToFile(
|
||||
createElement(InfoPDF as any, options as any) as any,
|
||||
outputPath
|
||||
);
|
||||
|
||||
return outputPath;
|
||||
}
|
||||
|
||||
async generateAgbsPdf(outputPath: string, options: { headerIcon?: string; footerLogo?: string; mode?: "estimation" | "full" } = {}): Promise<string> {
|
||||
await renderToFile(
|
||||
createElement(AgbsPDF as any, options as any) as any,
|
||||
outputPath
|
||||
);
|
||||
|
||||
return outputPath;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user