diff --git a/README.md b/README.md index 28d284e..c89c60a 100644 --- a/README.md +++ b/README.md @@ -87,4 +87,18 @@ npm run video:preview # Render the showcase video npm run video:render ``` -See `.agent/workflows/video-toolkit.md` for more details. \ No newline at end of file +See `.agent/workflows/video-toolkit.md` for more details. + +## 🤖 Industrial AI Estimation System +A multi-pass AI consultation engine for generating technical project estimations and professional PDFs. + +- **Context-Aware**: Crawls existing customer websites to understand company DNA. +- **Industrial Standards**: Strictly follows "Industrial Engineering" aesthetics and technical wording. +- **Transparent**: Maps scope directly to a modular pricing model. + +### Quick Start +```bash +# Generate estimation with website crawl +npm run ai-estimate -- "Project Briefing" --url https://example.com +``` +See [ESTIMATION_GUIDE.md](docs/ESTIMATION_GUIDE.md) for full documentation. \ No newline at end of file diff --git a/docs/ESTIMATION_GUIDE.md b/docs/ESTIMATION_GUIDE.md new file mode 100644 index 0000000..fc300a4 --- /dev/null +++ b/docs/ESTIMATION_GUIDE.md @@ -0,0 +1,83 @@ +# Service Estimation & AI Consultation Guide + +This guide explains how to use the automated estimation system to generate professional PDF quotes for clients using AI-driven context analysis. + +## 🛠 Basic Usage + +The primary entry point is the `ai-estimate` script. It orchestrates a 6-pass AI consultation: +1. **Fact Extraction**: Identifying company data and project scope. +2. **Feature Deep-Dive**: Generating technical justifications for items. +3. **Strategic Content**: Creating the Briefing Analysis and Strategic Vision. +4. **Information Architecture**: Designing a hierarchical sitemap. +5. **Position Synthesis**: Mapping everything to a transparent pricing model. +6. **Industrial Critic**: Final quality gate for tone and accuracy. + +### Generating an Estimation from Scratch + +#### 1. With a Website URL (Recommended) +Providing a URL allows the system to crawl the existing site to understand the "Company DNA" and services. +```bash +npm run ai-estimate -- "Relaunch der Website mit Fokus auf B2B Leads" --url https://example.com +``` + +#### 2. From a Text File +If you have a long briefing in a `.txt` file: +```bash +npm run ai-estimate -- @briefing.txt --url https://example.com +``` + +#### 3. Text-Only (No URL) +If no URL is provided, the system relies entirely on your briefing text. +```bash +npm run ai-estimate -- "Neuentwicklung eines Portals für XYZ" +``` + +--- + +## 📄 Output Modes + +The system can generate two types of documents: + +### 1. Full Quote (Default) +Includes everything: Front Page, Briefing Analysis, Vision, Sitemap, Technical Principles, Detailed Pricing, Roadmap, and Legal Terms (AGB). +```bash +npm run ai-estimate -- "Project Briefing" +``` + +### 2. Estimation Only +A condensed version excluding legal terms and deep technical principles. Focuses purely on the strategic fit and the price. +```bash +npm run ai-estimate -- "Project Briefing" --estimation +``` + +--- + +## 📦 Cache & Cache Management + +To save costs and time, all AI responses and crawl results are cached in the `.cache` directory. + +### Regenerating with Cached Data +If you run the same command again (identical briefing and URL), the system will use the cached results and won't call the AI APIs again. This is useful if you want to tweak the PDF layout without spending tokens. + +### Forcing a Refresh +To ignore the cache and get a fresh AI consultation: +```bash +npm run ai-estimate -- "Project Briefing" --clear-cache +``` + +### Manual Tweaking (JSON State) +Every run saves a detailed state to `out/estimations/json/[Company]_[Timestamp].json`. +If you want to manually edit the AI's results (e.g., fix a typo in the sitemap or description), you can edit this JSON file and then regenerate the PDF from it: + +```bash +npm run ai-estimate -- --json out/estimations/json/Your_Project.json +``` +*(Add `--estimation` if you want the condensed version).* + +--- + +## 💡 Advanced Options + +- `--comments "..."`: Add manual notes that the AI should consider (e.g., "Customer prefers a minimalist blue theme"). +- `--clear-cache`: Purges all cached data for this project before starting. +- `--url [URL]`: Explicitly sets the crawl target (auto-discovered from briefing if omitted). diff --git a/scripts/ai-estimate.ts b/scripts/ai-estimate.ts index ebc4f1f..95661e6 100644 --- a/scripts/ai-estimate.ts +++ b/scripts/ai-estimate.ts @@ -23,6 +23,8 @@ async function main() { let jsonStatePath: string | null = null; + const isEstimation = process.argv.includes('--estimation') || process.argv.includes('-E'); + const args = process.argv.slice(2); for (let i = 0; i < args.length; i++) { const arg = args[i]; @@ -34,6 +36,8 @@ async function main() { cacheKey = args[++i]; } else if (arg === '--json') { jsonStatePath = args[++i]; + } else if (arg === '--estimation' || arg === '-E') { + // Handled above } else if (!arg.startsWith('--')) { briefing = arg; } @@ -140,7 +144,8 @@ async function main() { console.log(`📦 Saved detailed state to: ${finalJsonPath}`); console.log('📄 Generating PDF estimation...'); try { - execSync(`npx tsx ./scripts/generate-quote.ts --input ${tempJsonPath}`, { stdio: 'inherit' }); + const genArgs = isEstimation ? '--estimation' : ''; + execSync(`npx tsx ./scripts/generate-quote.ts --input ${tempJsonPath} ${genArgs}`, { stdio: 'inherit' }); } finally { // await fs.unlink(tempJsonPath); } @@ -243,7 +248,17 @@ async function performCrawl(url: string): Promise { return summary + pages.map(p => `--- PAGE: ${p.url} ---\n${p.content}`).join('\n\n'); } -async function getAiEstimation(briefing: string, distilledCrawl: string, comments: string | null, apiKey: string, principles: string, techStandards: string, tone: string) { +const cleanJson = (str: string) => { + // Remove markdown code blocks if present + let cleaned = str.replace(/```json\n?|```/g, '').trim(); + // Remove potential control characters that break JSON.parse + cleaned = cleaned.replace(/[\u0000-\u001F\u007F-\u009F]/g, " "); + // Remove trailing commas before closing braces/brackets + cleaned = cleaned.replace(/,\s*([\]}])/g, '$1'); + return cleaned; +}; + +const getAiEstimation = async (briefing: string, distilledCrawl: string, comments: string | null, apiKey: string, principles: string, techStandards: string, tone: string) => { let usage = { prompt: 0, completion: 0, cost: 0 }; const addUsage = (data: any) => { if (data?.usage) { @@ -316,7 +331,7 @@ Focus 100% on the BRIEFING text provided by the user. Use the DISTILLED_CRAWL on response_format: { type: 'json_object' } }, { headers: { 'Authorization': `Bearer ${apiKey}`, 'Content-Type': 'application/json' } }); addUsage(p1Resp.data); - const facts = JSON.parse(p1Resp.data.choices[0].message.content); + const facts = JSON.parse(cleanJson(p1Resp.data.choices[0].message.content)); // 2. PASS 2: Feature Deep-Dive console.log(' ↳ Pass 2: Feature Deep-Dive...'); @@ -348,7 +363,7 @@ ${JSON.stringify(facts, null, 2)} response_format: { type: 'json_object' } }, { headers: { 'Authorization': `Bearer ${apiKey}`, 'Content-Type': 'application/json' } }); addUsage(p2Resp.data); - const details = JSON.parse(p2Resp.data.choices[0].message.content); + const details = JSON.parse(cleanJson(p2Resp.data.choices[0].message.content)); // 3. PASS 3: Strategic Content (Bespoke Strategy) console.log(' ↳ Pass 3: Strategic Content (Bespoke Strategy)...'); @@ -360,19 +375,17 @@ Analyze the BRIEFING and the EXISTING WEBSITE context. ${tone} ### OBJECTIVE: -1. **briefingSummary**: A deep, respectful summary of the status quo and the target state. - - **LENGTH**: EXACTLY TWO PARAGRAPHS. Minimum 8 sentences total. - - **MIRROR TEST**: Acknowledge the EXISTING website specifically. Why does the new project make sense NOW? - - **ABSOLUTE RULE**: DO NOT claim "keine digitale Repräsentation", "erstmals abgebildet", "Erstplatzierung" or "kommunikative Lücke" regarding existence if Pass 1 identified this as a RELAUNCH (isRelaunch=true). EXPLICITLY acknowledge the existing context and the NEED FOR EVOLUTION/MODERNIZATION. - - **RESPECT**: Explicitly incorporate the customer's expressed wishes. - - **ABSOLUTE RULE**: DO NOT INVENT DETAILS. Do not mention specific people (e.g., "Frieder Helmich"), software versions, or internal details NOT present in the briefing. - - **TONE**: Natural Ich-Form. Clear, direct, zero marketing fluff. -2. **designVision**: A high-density, professional vision of the future execution. - - **LENGTH**: EXACTLY TWO PARAGRAPHS. Minimum 6 sentences total. - - **INVESTMENT VALUE**: Plant a clear picture of a stable, high-quality system. - - **TECHNICAL PRECISION**: Focus on execution (Typografie, Visual Logic, Performance). - - **NO FLUFF**: Do NOT focus on "Full-Screen Hero Video" as the main thing. Focus on the FIRM's essence and how we translate it into a professional tool. - - **ABSOLUTE RULE**: NO HALLUCINATIONS. Stay general yet precise. No "Verzicht auf Stockmaterial" unless explicitly stated. +3. **briefingSummary**: Ein sachlicher, tiefgehender Überblick der Unternehmenslage. + - **STIL**: Keine Ich-Form. Keine Marketing-Floskeln. Nutze präzise Fachbegriffe. Sei prägnant und effizient (ca. 70% der vorherigen Länge). + - **FORM**: EXAKT ZWEI ABSÄTZE. Insgesamt ca. 6 Sätze. + - **INHALT**: Welcher technologische Sprung ist notwendig? Was ist der Status Quo? (Bezug zur URL/Briefing). + - **ABSOLUTE REGEL**: Keine Halluzinationen über fehlende Präsenzen bei Relaunches. + - **DATENSCHUTZ**: KEINERLEI namentliche Nennungen von Personen (z. B. "Danny Joseph") in diesen Texten. +4. **designVision**: Ein abstraktes, strategisches Konzept. + - **STIL**: Rein konzeptionell. Keine Umsetzungsschritte. Keinerlei "To-dos". Sei prägnant. + - **FORM**: EXAKT ZWEI ABSÄTZE. Insgesamt ca. 4 Sätze. + - **DATENSCHUTZ**: KEINERLEI namentliche Nennungen von Personen in diesen Texten. + - **FOKUS**: Welche strategische Wirkung soll erzielt werden? (Z. B. "Industrielle Souveränität"). ### OUTPUT FORMAT (Strict JSON): { @@ -389,7 +402,7 @@ ${tone} response_format: { type: 'json_object' } }, { headers: { 'Authorization': `Bearer ${apiKey}`, 'Content-Type': 'application/json' } }); addUsage(p3Resp.data); - const strategy = JSON.parse(p3Resp.data.choices[0].message.content); + const strategy = JSON.parse(cleanJson(p3Resp.data.choices[0].message.content)); // 4. PASS 4: Information Architecture (Sitemap) console.log(' ↳ Pass 4: Information Architecture...'); @@ -418,7 +431,7 @@ ${JSON.stringify({ facts, strategy }, null, 2)} response_format: { type: 'json_object' } }, { headers: { 'Authorization': `Bearer ${apiKey}`, 'Content-Type': 'application/json' } }); addUsage(p4Resp.data); - const ia = JSON.parse(p4Resp.data.choices[0].message.content); + const ia = JSON.parse(cleanJson(p4Resp.data.choices[0].message.content)); // 5. PASS 5: Position Synthesis & Pricing Transparency console.log(' ↳ Pass 5: Position Synthesis...'); @@ -443,14 +456,15 @@ Each position in the quote must be perfectly justified and detailed. ### RULES FOR positionDescriptions (STRICT): 1. **NO "ICH-FORM"**: Do NOT use "Ich" or "Mein". Lead with the action or component. 2. **CONCISE & ITEM-BASED**: Use short, technical sentences. Focus on WHAT is delivered. -3. **ZERO GENERALIZATION**: Do NOT say "Verschiedene Funktionen". +3. **ZERO GENERALIZATION**: Do NOT say "Verschiedene Funktionen" or "Optimierte Darstellung". Name the things. 4. **ITEMIZED SYNTHESIS**: Mention EVERY component selected in Pass 1. -5. **HARD SPECIFICS**: Preserve technical details from the briefing (e.g., "110 kV", "HDD-Bohrtechnik"). -6. **STYLE**: Direct, engineering-grade, 100% GERMAN. +5. **HARD SPECIFICS**: Preserve technical details from the briefing and CURRENT WEBSITE (distilledCrawl). If they mention "HDD-Bohrtechnik" or "110kV Kabelanlagen", IT MUST BE IN THE DESCRIPTION. +6. **INDUSTRIAL AMBITION**: Describe it as a high-end technical solution, not a cheap website. 7. **SPECIFIC - PAGES**: For "Individuelle Seiten", list the pages as a comma-separated list. 8. **SPECIFIC - HOSTING**: Always append: "Inkl. 20GB Speicher." 9. **SPECIFIC - LOGIC**: Describe the ACTUAL logic. NEVER use generic terms. 10. **STRICT KEYS**: Keys MUST be EXACTLY the ones defined in POSITION TITLES. +11. **AGB BAN (CRITICAL)**: NEVER mention "Allgemeine Geschäftsbedingungen" or "AGGs" in any text. They are NOT part of this offer. ### EXAMPLES (FEW-SHOT): - **BAD**: "Ich entwickle die Seiten: Startseite, Leistungen, Kontakt." @@ -481,7 +495,7 @@ ${JSON.stringify({ facts, details, strategy, ia }, null, 2)} response_format: { type: 'json_object' } }, { headers: { 'Authorization': `Bearer ${apiKey}`, 'Content-Type': 'application/json' } }); addUsage(p5Resp.data); - const positionsData = JSON.parse(p5Resp.data.choices[0].message.content); + const positionsData = JSON.parse(cleanJson(p5Resp.data.choices[0].message.content)); // 6. PASS 6: The Industrial Critic console.log(' ↳ Pass 6: The Industrial Critic (Quality Gate)...'); @@ -492,10 +506,13 @@ Analyze the CURRENT_STATE against the BRIEFING_TRUTH. ### CRITICAL ERROR CHECKLIST (FAIL IF FOUND): 1. **Hallucination Leakage**: FAIL if names of people (e.g., "Frieder Helmich"), specific software versions, or invented details are used unless they appear EXACTLY in the BRIEFING. - **CRITICAL**: Forbid "Sie", "Ansprechpartner" or "Unternehmen" for personName if a name IS in the briefing. If none is in briefing, use empty string. -2. **Logic Conflict**: FAIL if isRelaunch is true but briefingSummary claims no website exists or uses phrases like "Da aktuell keine digitale Repräsentation vorliegt", "erstmals abgebildet", "Erstplatzierung" or "Lücke schließen" (regarding existence). +2. **Logic Conflict**: FAIL if isRelaunch is true but briefingSummary claims no website exists. - FAIL if the description in positionDescriptions mentions more items than extracted in facts. -3. **Implementation Fluff**: FAIL if "React", "Next.js", "TypeScript", "Tailwind" or other tech-stack details are mentioned. Focus on Concept & Result. -4. **Length Check**: Briefing and Vision MUST be significantly long (EXACTLY 2 paragraphs each, minimum 8 sentences for briefing, 6 for vision). +3. **Implementation Fluff**: FAIL if tech-stack details are mentioned (React, etc.). Focus on Concept & Result. +4. **Genericism Check (CRITICAL)**: FAIL if any text sounds like it could apply to ANY company. It MUST mention specific industry details (e.g., "Kabeltiefbau", "Infrastruktur-Zentrum") from the Briefing or Crawl. +6. **Namen-Verbot (STRICT)**: FAIL if any personal names (e.g. "Danny Joseph", "Joseph", etc.) appear in 'briefingSummary' or 'designVision'. Use abstract terms like "Unternehmensführung" or "Management" if necessary. +7. **AGB BAN**: FAIL if "Allgemeine Geschäftsbedingungen" or "AGB" appear anywhere. +8. **Length Check**: Briefing (ca. 6 Sätze) und Vision (ca. 4 Sätze). Kürze Texte, die zu ausschweifend sind, auf das Wesentliche. ### MISSION: Return updated fields ONLY. Specifically focus on hardening 'positionDescriptions', 'sitemap', 'briefingSummary', and 'designVision'. @@ -509,7 +526,7 @@ ${JSON.stringify({ facts, strategy, ia, positionsData }, null, 2)} response_format: { type: 'json_object' } }, { headers: { 'Authorization': `Bearer ${apiKey}`, 'Content-Type': 'application/json' } }); addUsage(p6Resp.data); - const reflection = JSON.parse(p6Resp.data.choices[0].message.content); + const reflection = JSON.parse(cleanJson(p6Resp.data.choices[0].message.content)); // 6. Reflection Merge Utility const mergeReflection = (state: any, reflection: any) => { diff --git a/src/components/pdf/SharedUI.tsx b/src/components/pdf/SharedUI.tsx index 4a92094..006443f 100644 --- a/src/components/pdf/SharedUI.tsx +++ b/src/components/pdf/SharedUI.tsx @@ -16,13 +16,13 @@ export const COLORS = { }; export const FONT_SIZES = { - H1: 24, - H2: 18, - H3: 12, - BODY: 9, - TINY: 7, - SUB: 8, - BLUEPRINT: 5 + H1: 28, + H2: 20, + H3: 14, + BODY: 11, + TINY: 9, + SUB: 10, + BLUEPRINT: 8 }; // Register a more technical font if possible, or use Helvetica with varying weights @@ -94,8 +94,7 @@ export const pdfStyles = StyleSheet.create({ fontWeight: 'bold', marginBottom: 4, color: COLORS.CHARCOAL, - textTransform: 'uppercase', - letterSpacing: 1, + letterSpacing: 0.5, }, subTitle: { fontSize: FONT_SIZES.BODY, diff --git a/src/components/pdf/modules/BrandingModules.tsx b/src/components/pdf/modules/BrandingModules.tsx index 613bf13..74d4737 100644 --- a/src/components/pdf/modules/BrandingModules.tsx +++ b/src/components/pdf/modules/BrandingModules.tsx @@ -6,14 +6,11 @@ import { IndustrialListItem, IndustrialCard, Divider, COLORS, FONT_SIZES } from const styles = StyleSheet.create({ industrialTitle: { fontSize: FONT_SIZES.H1, fontWeight: 'bold', color: COLORS.CHARCOAL, marginBottom: 6, letterSpacing: -1 }, - industrialSubtitle: { fontSize: FONT_SIZES.SUB, fontWeight: 'bold', color: COLORS.TEXT_LIGHT, textTransform: 'uppercase', marginBottom: 16, letterSpacing: 2 }, - industrialTextLead: { fontSize: FONT_SIZES.H3, color: COLORS.TEXT_MAIN, lineHeight: 1.6, marginBottom: 12 }, - industrialText: { fontSize: FONT_SIZES.BODY, color: COLORS.TEXT_DIM, lineHeight: 1.6, marginBottom: 8 }, - industrialGrid2: { flexDirection: 'row', gap: 32 }, - industrialCol: { width: '48%' }, - darkBox: { marginTop: 32, padding: 24, backgroundColor: COLORS.CHARCOAL, color: COLORS.WHITE }, - darkTitle: { fontSize: FONT_SIZES.H2, fontWeight: 'bold', color: COLORS.WHITE, marginBottom: 8 }, - darkText: { fontSize: FONT_SIZES.BODY, color: COLORS.TEXT_LIGHT, lineHeight: 1.6 }, + industrialSubtitle: { fontSize: FONT_SIZES.SUB, fontWeight: 'bold', color: COLORS.TEXT_LIGHT, marginBottom: 16, letterSpacing: 0.5 }, + industrialTextLead: { fontSize: FONT_SIZES.H3, color: COLORS.TEXT_MAIN, lineHeight: 1.6, marginBottom: 16 }, + industrialText: { fontSize: FONT_SIZES.BODY, color: COLORS.TEXT_DIM, lineHeight: 1.6, marginBottom: 12 }, + industrialGrid2: { flexDirection: 'row' }, + industrialCol: { width: '46%' }, industrialBulletBox: { width: 6, height: 6, @@ -26,30 +23,41 @@ const styles = StyleSheet.create({ export const AboutModule = () => ( <> Über mich - Direkt. Sauber. Verantwortlich. + Senior Software Developer & Technischer Partner - - - Seit 15 Jahren entstehen unter meiner Leitung Websysteme für Agenturen, Konzerne und Startups. Ich arbeite bewusst alleine, um die volle Verantwortung für jedes Projekt zu tragen. - Technik scheitert selten an Bits und Bytes, sondern meist an unklaren Zuständigkeiten. Als Ihr direkter Ansprechpartner treffe ich die notwendigen Entscheidungen und löse technische Probleme ohne Umwege. - - Mein Standard: - Code-Lieferung ohne technische Altlasten. - Entwicklung von Systemen, die autark operieren. - Verzicht auf Overhead und Kommunikationsverluste. + + + + Ich begleite mittelständische Unternehmen und Agenturen bei der Realisierung anspruchsvoller Web-Projekte. Als Senior Software Developer mit über 15 Jahren Erfahrung biete ich das gesamte technische Spektrum – von der Architektur bis zum fertigen Produkt. + + + + + Erfahrung & Substanz + + Mein Weg führte mich durch alle Ebenen der Webentwicklung: vom Junior zum Teamleiter, von der kleinen Kreativagentur bis zur Softwareentwicklung für internationale Konzerne. + + + Ich kenne die Prozesse hinter großen Systemen ebenso gut wie die Agilität, die im Mittelstand gefordert wird. Dieses Wissen nutze ich heute, um Lösungen zu bauen, die technologisch auf Augenhöhe mit den Großen sind, aber ohne deren bürokratischen Overhead auskommen. + + + + + Fokus Einzelentwicklung + + Ich arbeite bewusst als Einzelentwickler. Für Sie bedeutet das: maximale Geschwindigkeit und volle Verantwortung. Es gibt keine Informationsverluste zwischen Projektmanagern, Vertrieblern und Entwicklern. + + + Sie haben einen direkten technischen Sparringspartner, der Ihren Code von der ersten bis zur letzten Zeile kennt und dafür einsteht. Diese Unmittelbarkeit garantiert Ergebnisse, die technisch sauber und wirtschaftlich sinnvoll sind. + - - - Ich bin der einzige Entwickler. - Ich antworte direkt auf technische Fragen. - Ich garantiere die Umsetzung. - - - Keine Projektmanager. - Keine Vertriebler. - Kein Ticket-Chaos. - + + + Meine Zusage + + Ich baue keine Prototypen, die beim ersten Nutzeransturm zusammenbrechen. Ich liefere produktionsreife Software, die wartbar bleibt und mit Ihrem Unternehmen mitwächst. Direkt. Sauber. Ohne Ballast. + @@ -57,34 +65,34 @@ export const AboutModule = () => ( export const CrossSellModule = ({ state }: any) => { const isWebsite = state.projectType === 'website'; - const title = isWebsite ? "Digitale Routine" : "Websites & Ökosysteme"; - const subtitle = isWebsite ? "Automatisierung statt Fleißarbeit" : "Technische Infrastruktur ohne Kompromisse"; + const title = isWebsite ? "Routine-Automatisierung" : "Websites & Ökosysteme"; + const subtitle = isWebsite ? "Maßgeschneiderte Software zur Prozessoptimierung" : "Technische Infrastruktur ohne Kompromisse"; return ( <> {title} {subtitle} - + {isWebsite ? ( <> - - Manuelle Abläufe binden Kapazitäten. Durch maßgeschneiderte Software ersetze ich fehleranfällige Prozesse und eliminiere Zeitfresser in Ihrem Unternehmen. - Ziel ist der Gewinn wertvoller Arbeitszeit. Digitalisierung ordnet das Chaos. - - Individuelle Prüfung - Ich analysiere Ihren spezifischen Prozess auf technisches Automatisierungspotenzial. Das Ergebnis liefert Klarheit darüber, ob eine Umsetzung wirtschaftlich sinnvoll ist. + + Manuelle Alltags-Aufgaben sind teuer und fehleranfällig. In einer separaten Beauftragung entwickle ich maßgeschneiderte „Helfer“, die Ihre Routine-Prozesse lautlos im Hintergrund automatisieren. + Keine Abos. Keine komplexen neuen Systeme. Nur gezielte Zeitersparnis. + + Individuelle Prüfung + Ich analysiere Ihren spezifischen Prozess auf technisches Automatisierungspotenzial. Das Ergebnis liefert Klarheit darüber, ob eine Umsetzung wirtschaftlich sinnvoll ist. - - Ich automatisiere Angebote und Berichte. Ich reduziere den Zeitaufwand auf 5 Minuten. Ich garantiere fehlerfreie Exporte. + + Erstellung von PDF-Angeboten, Berichten oder Protokollen in Sekunden statt Stunden. - - Ich synchronisiere Ihre Datenbestände. Ich schaffe Echtzeit-Transparenz ohne manuelle Listenpflege. + + Intelligente Tabellen und automatisierte Auswertungen Ihrer Bestandsdaten. - - Ich implementiere Schrifterkennung für analoge Dokumente. Ich übertrage Daten direkt in Ihre Systeme. + + Effizientes Einlesen und Verarbeiten von analogen Dokumenten oder handschriftlichen Notizen. diff --git a/src/components/pdf/modules/BriefingModule.tsx b/src/components/pdf/modules/BriefingModule.tsx index 2221d2a..e0671df 100644 --- a/src/components/pdf/modules/BriefingModule.tsx +++ b/src/components/pdf/modules/BriefingModule.tsx @@ -7,10 +7,6 @@ import { DocumentTitle, COLORS, FONT_SIZES } from '../SharedUI'; const styles = StyleSheet.create({ section: { marginBottom: 24 }, sectionTitle: { fontSize: FONT_SIZES.BODY + 1, fontWeight: 'bold', marginBottom: 8, color: COLORS.CHARCOAL }, - configGrid: { flexDirection: 'row', flexWrap: 'wrap', gap: 6, marginTop: 6 }, - configItem: { width: '24%', marginBottom: 4 }, - configLabel: { fontSize: FONT_SIZES.BLUEPRINT, color: COLORS.TEXT_LIGHT, textTransform: 'uppercase', marginBottom: 2 }, - configValue: { fontSize: FONT_SIZES.TINY, color: COLORS.CHARCOAL, fontWeight: 'bold' }, visionText: { fontSize: FONT_SIZES.BODY, color: COLORS.TEXT_MAIN, lineHeight: 1.8, textAlign: 'justify' }, }); @@ -20,22 +16,13 @@ export const BriefingModule = ({ state }: any) => ( {state.briefingSummary && ( Briefing Analyse - {state.briefingSummary} + {state.briefingSummary} )} - - Kern-Informationen - - Kontakt{state.personName || "—"} - Projekttyp{state.isRelaunch ? 'Website Evolution' : (state.statusQuo || 'Neukonzeption')} - Mitarbeiter{state.employeeCount || "—"} - Zeitplan{state.deadline || 'Flexibel'} - - {state.designVision && ( - - Strategische Vision - {state.designVision} + + Strategische Vision + {state.designVision} )} diff --git a/src/components/pdf/modules/CommonModules.tsx b/src/components/pdf/modules/CommonModules.tsx index 818ed46..4f6b96e 100644 --- a/src/components/pdf/modules/CommonModules.tsx +++ b/src/components/pdf/modules/CommonModules.tsx @@ -97,3 +97,4 @@ export const PrinciplesModule = ({ principles }: any) => ( ); + diff --git a/src/components/pdf/modules/FrontPageModule.tsx b/src/components/pdf/modules/FrontPageModule.tsx index aa7e05b..741a6f7 100644 --- a/src/components/pdf/modules/FrontPageModule.tsx +++ b/src/components/pdf/modules/FrontPageModule.tsx @@ -74,7 +74,7 @@ export const FrontPageModule = ({ state, headerIcon, date }: any) => { {headerIcon ? : M} {fullTitle} - + {date} | Marc Mintel ); diff --git a/src/components/pdf/modules/SitemapModule.tsx b/src/components/pdf/modules/SitemapModule.tsx index 0e2c296..ef768a1 100644 --- a/src/components/pdf/modules/SitemapModule.tsx +++ b/src/components/pdf/modules/SitemapModule.tsx @@ -5,43 +5,67 @@ import { View as PDFView, Text as PDFText, StyleSheet } from '@react-pdf/rendere import { DocumentTitle, Divider, COLORS, FONT_SIZES } from '../SharedUI'; const styles = StyleSheet.create({ - section: { marginBottom: 24 }, - sitemapTree: { marginTop: 20 }, - sitemapRootNode: { flexDirection: 'row', alignItems: 'center', marginBottom: 12 }, - sitemapRootDot: { width: 6, height: 6, borderRadius: 3, backgroundColor: COLORS.CHARCOAL, marginRight: 10 }, - sitemapRootTitle: { fontSize: FONT_SIZES.H3, fontWeight: 'bold', textTransform: 'uppercase', letterSpacing: 1, color: COLORS.CHARCOAL }, - sitemapMainLine: { position: 'absolute', left: 2, top: 20, bottom: 0, width: 0.5, backgroundColor: COLORS.DIVIDER }, - sitemapBranch: { marginLeft: 20, marginBottom: 12, position: 'relative' }, - sitemapNode: { flexDirection: 'row', alignItems: 'center', marginBottom: 4 }, - sitemapRootIcon: { width: 4, height: 4, backgroundColor: COLORS.CHARCOAL, marginRight: 8 }, - sitemapBranchTitle: { fontSize: FONT_SIZES.BODY, fontWeight: 'bold', color: COLORS.TEXT_MAIN }, - sitemapLeaf: { marginLeft: 12, borderLeftWidth: 0.5, borderLeftColor: COLORS.DIVIDER, paddingLeft: 12, marginTop: 4 }, - sitemapLeafNode: { flexDirection: 'row', alignItems: 'flex-start', marginBottom: 6 }, - sitemapLeafPointer: { fontSize: FONT_SIZES.BODY, color: COLORS.TEXT_LIGHT, marginRight: 6 }, - sitemapLeafTitle: { fontSize: FONT_SIZES.BODY, fontWeight: 'bold', color: COLORS.TEXT_MAIN }, - sitemapLeafDesc: { fontSize: FONT_SIZES.TINY, color: COLORS.TEXT_DIM, lineHeight: 1.3, marginTop: 1 }, + section: { marginBottom: 32 }, + intro: { fontSize: FONT_SIZES.BODY, color: COLORS.TEXT_DIM, lineHeight: 1.6, marginBottom: 24, textAlign: 'justify' }, + sitemapTree: { marginTop: 8 }, + rootNode: { + padding: 12, + backgroundColor: COLORS.CHARCOAL, + marginBottom: 20, + borderLeftWidth: 3, + borderLeftColor: COLORS.TEXT_LIGHT + }, + rootTitle: { fontSize: FONT_SIZES.H3, fontWeight: 'bold', color: COLORS.WHITE, letterSpacing: 0.5 }, + categorySection: { marginBottom: 20 }, + categoryHeader: { + flexDirection: 'row', + alignItems: 'center', + paddingBottom: 6, + borderBottomWidth: 1, + borderBottomColor: COLORS.BLUEPRINT, + marginBottom: 10 + }, + categoryIcon: { width: 8, height: 8, backgroundColor: COLORS.CHARCOAL, marginRight: 10 }, + 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' + }, + pageTitle: { fontSize: FONT_SIZES.BODY, fontWeight: 'bold', color: COLORS.TEXT_MAIN, marginBottom: 2 }, + pageDesc: { fontSize: FONT_SIZES.TINY, color: COLORS.TEXT_DIM, lineHeight: 1.4 }, }); export const SitemapModule = ({ state }: any) => ( <> - + - Die folgende Struktur bildet das Fundament für die Benutzerführung und Informationsarchitektur Ihres Projekts. - + + 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. + + - {state.websiteTopic || 'Digitales Ökosystem'} - + + {state.websiteTopic || 'Digitales Ökosystem'} + + {state.sitemap?.map((cat: any, i: number) => ( - - {cat.category} - + + + + {cat.category} + + + {cat.pages.map((p: any, j: number) => ( - - └─ - - {p.title} - {p.desc && {p.desc}} - + + {p.title} + {p.desc && {p.desc}} ))}