fix(web): remove redundant prop-types and unblock lint pipeline
Some checks failed
Build & Deploy / 🔍 Prepare (push) Successful in 10s
Build & Deploy / 🧪 QA (push) Failing after 2m24s
Build & Deploy / 🏗️ Build (push) Failing after 3m40s
Build & Deploy / 🚀 Deploy (push) Has been skipped
Build & Deploy / 🩺 Health Check (push) Has been skipped
Build & Deploy / 🔔 Notify (push) Successful in 3s

This commit is contained in:
2026-02-24 11:38:43 +01:00
parent 95a8b702fe
commit 6864903cff
205 changed files with 6570 additions and 1324 deletions

View File

@@ -1,40 +1,39 @@
import { LeadParagraph } from "../components/ArticleParagraph";
import { H1, H2, H3 } from "../components/ArticleHeading";
import { Paragraph } from "../components/ArticleParagraph";
import { ArticleBlockquote } from "../components/ArticleBlockquote";
import { Marker } from "../components/Marker";
import { ComparisonRow } from "../components/Landing/ComparisonRow";
import { StatsDisplay } from "../components/StatsDisplay";
import { Mermaid } from "../components/Mermaid";
import { DiagramState } from "../components/DiagramState";
import { DiagramTimeline } from "../components/DiagramTimeline";
import { DiagramGantt } from "../components/DiagramGantt";
import { DiagramPie } from "../components/DiagramPie";
import { DiagramSequence } from "../components/DiagramSequence";
import { DiagramFlow } from "../components/DiagramFlow";
import { IconList, IconListItem } from "../components/IconList";
import { ArticleMeme } from "../components/ArticleMeme";
import { MemeCard } from "../components/MemeCard";
import { ExternalLink } from "../components/ExternalLink";
import { StatsGrid } from "../components/StatsGrid";
import { MetricBar } from "../components/MetricBar";
import { ArticleQuote } from "../components/ArticleQuote";
import { BoldNumber } from "../components/BoldNumber";
import { WebVitalsScore } from "../components/WebVitalsScore";
import { WaterfallChart } from "../components/WaterfallChart";
import { Button } from "../components/Button";
import { LeadMagnet } from "../components/LeadMagnet";
import { TrackedLink } from "../components/analytics/TrackedLink";
import { FAQSection } from "../components/FAQSection";
import { LeadParagraph } from '../components/ArticleParagraph';
import { H1, H2, H3 } from '../components/ArticleHeading';
import { Paragraph } from '../components/ArticleParagraph';
import { ArticleBlockquote } from '../components/ArticleBlockquote';
import { Marker } from '../components/Marker';
import { ComparisonRow } from '../components/Landing/ComparisonRow';
import { StatsDisplay } from '../components/StatsDisplay';
import { Mermaid } from '../components/Mermaid';
import { DiagramState } from '../components/DiagramState';
import { DiagramTimeline } from '../components/DiagramTimeline';
import { DiagramGantt } from '../components/DiagramGantt';
import { DiagramPie } from '../components/DiagramPie';
import { DiagramSequence } from '../components/DiagramSequence';
import { DiagramFlow } from '../components/DiagramFlow';
import { IconList, IconListItem } from '../components/IconList';
import { ArticleMeme } from '../components/ArticleMeme';
import { MemeCard } from '../components/MemeCard';
import { ExternalLink } from '../components/ExternalLink';
import { StatsGrid } from '../components/StatsGrid';
import { MetricBar } from '../components/MetricBar';
import { ArticleQuote } from '../components/ArticleQuote';
import { BoldNumber } from '../components/BoldNumber';
import { WebVitalsScore } from '../components/WebVitalsScore';
import { WaterfallChart } from '../components/WaterfallChart';
import { Button } from '../components/Button';
import { LeadMagnet } from '../components/LeadMagnet';
import { TrackedLink } from '../components/analytics/TrackedLink';
import { FAQSection } from '../components/FAQSection';
import { PremiumComparisonChart } from "../components/PremiumComparisonChart";
import { ImageText } from "../components/ImageText";
import { Carousel } from "../components/Carousel";
import { PremiumComparisonChart } from '../components/PremiumComparisonChart';
import { ImageText } from '../components/ImageText';
import { Carousel } from '../components/Carousel';
import { Section } from '../components/Section';
import { Reveal } from '../components/Reveal';
import { TableOfContents } from '../components/TableOfContents';
import { Section } from "../components/Section";
import { Reveal } from "../components/Reveal";
import { TableOfContents } from "../components/TableOfContents";
import { RevenueLossCalculator } from "../components/RevenueLossCalculator";
import { PerformanceChart } from "../components/PerformanceChart";
@@ -43,56 +42,61 @@ import { LoadTimeSimulator } from "../components/simulations/LoadTimeSimulator";
import { ArchitectureBuilder } from "../components/simulations/ArchitectureBuilder";
import { DigitalAssetVisualizer } from "../components/simulations/DigitalAssetVisualizer";
import { TwitterEmbed } from '../components/TwitterEmbed';
import { YouTubeEmbed } from '../components/YouTubeEmbed';
import { LinkedInEmbed } from '../components/LinkedInEmbed';
import { TwitterEmbed } from "../components/TwitterEmbed";
import { YouTubeEmbed } from "../components/YouTubeEmbed";
import { LinkedInEmbed } from "../components/LinkedInEmbed";
import { TLDR } from "../components/TLDR";
/**
* Single Source of Truth for MDX component rendering.
* Handled separately from Payload blocks to avoid SVG import issues in Node.js.
*/
export const mdxComponents = {
// Named exports for explicit MDX usage
LeadParagraph,
H1,
H2,
H3,
Paragraph,
ArticleBlockquote,
Marker,
ComparisonRow,
StatsDisplay,
Mermaid,
DiagramState,
DiagramTimeline,
DiagramGantt,
DiagramPie,
DiagramSequence,
DiagramFlow,
IconList,
IconListItem,
ArticleMeme,
MemeCard,
ExternalLink,
StatsGrid,
MetricBar,
ArticleQuote,
BoldNumber,
WebVitalsScore,
WaterfallChart,
PremiumComparisonChart,
ImageText,
Carousel,
Section,
Reveal,
TableOfContents,
RevenueLossCalculator,
PerformanceChart,
PerformanceROICalculator,
LoadTimeSimulator,
ArchitectureBuilder,
DigitalAssetVisualizer,
TwitterEmbed,
YouTubeEmbed,
LinkedInEmbed,
Button,
LeadMagnet,
TrackedLink,
FAQSection
LeadParagraph,
H1,
H2,
H3,
Paragraph,
ArticleBlockquote,
Marker,
ComparisonRow,
StatsDisplay,
Mermaid,
DiagramState,
DiagramTimeline,
DiagramGantt,
DiagramPie,
DiagramSequence,
DiagramFlow,
IconList,
IconListItem,
ArticleMeme,
MemeCard,
ExternalLink,
StatsGrid,
MetricBar,
ArticleQuote,
BoldNumber,
WebVitalsScore,
WaterfallChart,
PremiumComparisonChart,
ImageText,
Carousel,
Section,
Reveal,
TableOfContents,
RevenueLossCalculator,
PerformanceChart,
PerformanceROICalculator,
LoadTimeSimulator,
ArchitectureBuilder,
DigitalAssetVisualizer,
TwitterEmbed,
YouTubeEmbed,
LinkedInEmbed,
Button,
LeadMagnet,
TrackedLink,
FAQSection,
TLDR,
};

View File

@@ -1,296 +1,9 @@
import { ComponentDefinition } from '@mintel/content-engine';
import { ComponentDefinition } from "@mintel/content-engine";
import { allComponentDefinitions } from "../payload/blocks/allBlocks";
/**
* Single Source of Truth for all MDX component definitions.
* Used by:
* - content-engine.config.ts (for the optimization script)
* - The AI content pipeline (for component injection)
*
* Keep in sync with: src/content-engine/components.ts (the MDX runtime registry)
* Now dynamically generated from individual Payload block definitions.
*/
export const componentDefinitions: ComponentDefinition[] = [
{
name: 'LeadParagraph',
description: 'Larger, emphasized paragraph for the article introduction. Use 1-3 at the start.',
usageExample: '<LeadParagraph>\n Unternehmen investieren oft Unsummen in glänzende Oberflächen, während das technische Fundament bröckelt.\n</LeadParagraph>'
},
{
name: 'H2',
description: 'Main section heading. Used for top-level content sections.',
usageExample: '<H2>Der wirtschaftliche Case</H2>'
},
{
name: 'BoldNumber',
description: 'Large centerpiece number with label for primary statistics.',
usageExample: '<BoldNumber value="5x" label="höhere Conversion-Rate" source="Portent" />'
},
{
name: 'PremiumComparisonChart',
description: 'Advanced chart for comparing performance metrics with industrial aesthetics.',
usageExample: '<PremiumComparisonChart title="TTFB Vergleich" items={[{ label: "Alt", value: 800, max: 1000, color: "red" }, { label: "Mintel", value: 50, max: 1000, color: "green" }]} />'
},
{
name: 'ImageText',
description: 'Layout component for image next to explanatory text.',
usageExample: '<ImageText image="/img.jpg" title="Architektur">Erklärung...</ImageText>'
},
{
name: 'Carousel',
description: 'Interactive swipeable slider for multi-step explanations. IMPORTANT: items array must contain at least 2 items with substantive title and content text (no empty content).',
usageExample: '<Carousel items={[{ title: "Schritt 1", content: "Analyse der aktuellen Performance..." }, { title: "Schritt 2", content: "Architektur-Optimierung..." }]} />'
},
{
name: 'H3',
description: 'Subsection heading. Used within H2 sections.',
usageExample: '<H3>Die drei Säulen meiner Umsetzung</H3>'
},
{
name: 'Paragraph',
description: 'Standard body text paragraph. All body text must be wrapped in this.',
usageExample: '<Paragraph>\n Mein System ist kein Kostenfaktor, sondern ein <Marker>ROI-Beschleuniger</Marker>.\n</Paragraph>'
},
{
name: 'ArticleBlockquote',
description: 'Styled blockquote for expert quotes or key statements.',
usageExample: '<ArticleBlockquote>\n Performance ist keine IT-Kennzahl, sondern ein ökonomischer Hebel.\n</ArticleBlockquote>'
},
{
name: 'Marker',
description: 'Inline highlight (yellow marker effect) for emphasizing key phrases within paragraphs.',
usageExample: '<Marker>entscheidender Wettbewerbsvorteil</Marker>'
},
{
name: 'ComparisonRow',
description: 'Side-by-side comparison: negative "Standard" approach vs positive "Mintel" approach. Props include showShare boolean.',
usageExample: `<ComparisonRow
description="Architektur-Vergleich"
negativeLabel="Legacy CMS"
negativeText="Langsame Datenbankabfragen, verwundbare Plugins."
positiveLabel="Mintel Stack"
positiveText="Statische Generierung, perfekte Sicherheit."
showShare={true}
/>`
},
{
name: 'StatsDisplay',
description: 'A single large stat card with prominent value, label, and optional subtext.',
usageExample: '<StatsDisplay value="-20%" label="Conversion" subtext="Jede Sekunde Verzögerung kostet." />'
},
{
name: 'Mermaid',
description: 'Renders a Mermaid.js diagram (flowchart, sequence, pie, etc.). Diagram code goes as children. Keep it tiny (max 3-4 nodes). Wrap in div with className="my-8".',
usageExample: `<div className="my-8">
<Mermaid id="my-diagram" title="System Architecture" showShare={true}>
graph TD
A["Request"] --> B["CDN Edge"]
B --> C["Static HTML"]
</Mermaid>
</div>`
},
{
name: 'DiagramFlow',
description: 'Structured flowchart diagram. Use for process flows, architecture diagrams, etc. Supports structured nodes/edges. direction defaults to LR.',
usageExample: `<DiagramFlow
nodes={[
{ id: "A", label: "Start" },
{ id: "B", label: "Process", style: "fill:#f00" }
]}
edges={[
{ from: "A", to: "B", label: "trigger" }
]}
title="Process Flow"
id="flow-1"
showShare={true}
/>`
},
{
name: 'DiagramPie',
description: 'Pie chart with structured data props.',
usageExample: `<DiagramPie
data={[
{ label: "JavaScript", value: 35 },
{ label: "CSS", value: 25 },
{ label: "Images", value: 20 }
]}
title="Performance Bottlenecks"
id="perf-pie"
showShare={true}
/>`
},
{
name: 'DiagramGantt',
description: 'Gantt timeline chart comparing durations of tasks.',
usageExample: `<DiagramGantt
tasks={[
{ id: "task-1", name: "Legacy: 4 Wochen", start: "2024-01-01", duration: "4w" },
{ id: "task-2", name: "Mintel: 1 Woche", start: "2024-01-01", duration: "1w" }
]}
title="Zeitvergleich"
id="gantt-comparison"
showShare={true}
/>`
},
{
name: 'DiagramState',
description: 'State diagram showing states and transitions.',
usageExample: `<DiagramState
states={["Idle", "Loading", "Loaded", "Error"]}
transitions={[
{ from: "Idle", to: "Loading", label: "fetch" },
{ from: "Loading", to: "Loaded", label: "success" }
]}
initialState="Idle"
title="Request Lifecycle"
id="state-diagram"
showShare={true}
/>`
},
{
name: 'DiagramSequence',
description: 'Sequence diagram (uses raw Mermaid sequence syntax as children).',
usageExample: `<DiagramSequence id="seq-diagram" title="Request Flow" showShare={true}>
sequenceDiagram
Browser->>CDN: GET /page
CDN->>Browser: Static HTML (< 50ms)
</DiagramSequence>`
},
{
name: 'DiagramTimeline',
description: 'Timeline diagram (uses raw Mermaid timeline syntax as children).',
usageExample: `<DiagramTimeline id="timeline" title="Project Timeline" showShare={true}>
timeline
2024 : Planung
2025 : Entwicklung
2026 : Launch
</DiagramTimeline>`
},
{
name: 'IconList',
description: 'Checklist with check/cross icons. Wrap IconListItem children inside.',
usageExample: `<IconList>
<IconListItem check>
<strong>Zero-Computation:</strong> Statische Seiten, kein Serverwarten.
</IconListItem>
<IconListItem cross>
<strong>Legacy CMS:</strong> Datenbankabfragen bei jedem Request.
</IconListItem>
</IconList>`
},
{
name: 'ArticleMeme',
description: 'Real meme image from memegen.link. template must be a valid memegen.link ID. IMPORTANT: Captions must be EXTREMELY SARCASTIC and PUNCHY (mocking bad B2B agencies, max 6 words per line). Best templates: drake (2-line prefer/dislike), gru (4-step plan backfire), disastergirl (burning house), fine (this is fine dog). Use German captions. Wrap in div with className="my-8".',
usageExample: `<div className="my-8">
<ArticleMeme template="drake" captions="47 WordPress Plugins installieren|Eine saubere Serverless Architektur" />
</div>`
},
{
name: 'Section',
description: 'Wraps a thematic section block with optional heading.',
usageExample: '<Section>\n <h3>Section Title</h3>\n <p>Content here.</p>\n</Section>'
},
{
name: 'Reveal',
description: 'Scroll-triggered reveal animation wrapper. Wrap any content to animate on scroll.',
usageExample: '<Reveal>\n <StatsDisplay value="100" label="PageSpeed Score" />\n</Reveal>'
},
{
name: 'StatsGrid',
description: 'Grid of 24 stat cards in a row. Use tilde (~) to separate stats, pipe (|) to separate value|label|subtext within each stat.',
usageExample: '<StatsGrid stats="53%|Mehr Umsatz|Rakuten 24~33%|Conversion Boost|nach CWV Fix~24%|Top 3 Ranking|bei bestandenen CWV" />'
},
{
name: 'MetricBar',
description: 'Animated horizontal progress bar. Use multiple in sequence to compare metrics. IMPORTANT: value MUST be a real number > 0, never use 0 or placeholder values. Props: label, value (number), max (default 100), unit (default %), color (red|green|blue|slate).',
usageExample: `<MetricBar label="WordPress Sites" value={33} color="red" />
<MetricBar label="Static Sites" value={92} color="green" />`
},
{
name: 'ArticleQuote',
description: 'Dark-themed quote card. Use for expert quotes or statements. Use isCompany={true} for brands/orgs to show an entity icon instead of personal initials. MANDATORY: always include source and sourceUrl for verifiability. Props: quote, author, role (optional), source (REQUIRED), sourceUrl (REQUIRED), isCompany (optional), translated (optional boolean).',
usageExample: '<ArticleQuote quote="Optimizing for speed." author="Google" isCompany={true} source="web.dev" sourceUrl="https://web.dev" translated={true} />'
},
{
name: 'BoldNumber',
description: 'Full-width hero number card with dark gradient, animated count-up, and share button. Use for the most impactful single statistics. IMPORTANT: Always provide source and sourceUrl. Numbers without comparison context should use PremiumComparisonChart or paired MetricBar instead. Props: value (string like "53%" or "2.5M€"), label (short description), source (REQUIRED), sourceUrl (REQUIRED).',
usageExample: '<BoldNumber value="8.4%" label="Conversion-Steigerung pro 0.1s schnellere Ladezeit" source="Deloitte Digital" sourceUrl="https://www2.deloitte.com/..." />'
},
{
name: 'WebVitalsScore',
description: 'Displays Core Web Vitals (LCP, INP, CLS) in a premium card layout with automatic traffic light coloring (Good/Needs Improvement/Poor). Use for performance audits or comparisons.',
usageExample: '<WebVitalsScore values={{ lcp: 2.5, inp: 200, cls: 0.1 }} description="All metrics passing Google standards." />'
},
{
name: 'WaterfallChart',
description: 'A timeline visualization of network requests (waterfall). Use to show loading sequences or bottlenecks. Labels auto-color coded by type (JS, HTML, IMG).',
usageExample: `<WaterfallChart
title="Initial Load"
events={[
{ name: "Document", start: 0, duration: 150 },
{ name: "main.js", start: 150, duration: 50 },
{ name: "hero.jpg", start: 200, duration: 300 }
]}
/>`
},
{
name: 'ExternalLink',
description: 'Inline external link with ↗ icon and outbound analytics tracking. Use for all source citations and external references within Paragraph text.',
usageExample: '<ExternalLink href="https://web.dev/articles/vitals">Google Core Web Vitals</ExternalLink>'
},
{
name: 'TwitterEmbed',
description: 'Embeds a post from X.com (Twitter). Used to provide social proof, industry quotes, or examples. Provide the numerical tweetId.',
usageExample: '<TwitterEmbed tweetId="1753464161943834945" theme="light" />'
},
{
name: 'YouTubeEmbed',
description: 'Embeds a YouTube video to visualize concepts or provide deep dives. Use the 11-character videoId.',
usageExample: '<YouTubeEmbed videoId="dQw4w9WgXcQ" title="Performance Explanation" />'
},
{
name: 'LinkedInEmbed',
description: 'Embeds a professional post from LinkedIn. Use the activity URN (e.g. urn:li:activity:1234567890).',
usageExample: '<LinkedInEmbed urn="urn:li:activity:7153664326573674496" />'
},
{
name: 'TrackedLink',
description: 'A wrapper around next/link that tracks clicks. Use for all INTERNAL navigational links that should be tracked.',
usageExample: '<TrackedLink href="/contact" className="text-blue-600 font-bold">Jetzt anfragen</TrackedLink>'
},
{
name: 'Button',
description: 'DEPRECATED: Use <LeadMagnet /> instead for main CTAs. Only use for small secondary links.',
usageExample: '<Button href="/contact" variant="outline">Webprojekt anfragen</Button>'
},
{
name: 'LeadMagnet',
description: 'Premium B2B conversion card. Use 1-2 per article as main high-impact CTAs. Props: title (strong headline), description (value prop), buttonText (action), href (link), variant (performance|security|standard).',
usageExample: '<LeadMagnet title="Performance-Check anfragen" description="Wir analysieren Ihre Core Web Vitals und decken Umsatzpotenziale auf." buttonText="Jetzt analysieren lassen" href="/contact" variant="performance" />'
},
{
name: 'PerformanceROICalculator',
description: 'Interactive simulation calculator showing the monetary ROI of improving load times (based on Deloitte B2B metrics). Use exactly once in performance-related articles to provide a highly engaging simulation. Requires no props.',
usageExample: '<PerformanceROICalculator />'
},
{
name: 'LoadTimeSimulator',
description: 'Interactive visual race simulating the loading experience of a slow legacy CMS vs a fast headless stack. Great for articles discussing load times, technical debt, or user frustration. Requires no props.',
usageExample: '<LoadTimeSimulator />'
},
{
name: 'FAQSection',
description: 'Semantic wrapper for FAQ questions at the end of the article. Put standard Markdown H3/Paragraphs inside.',
usageExample: '<FAQSection>\n <H3>Frage 1</H3>\n <Paragraph>Antwort 1</Paragraph>\n</FAQSection>'
},
{
name: 'ArchitectureBuilder',
description: 'Interactive comparison between a standard SaaS rental approach and a custom Built-First (Mintel) architecture. Useful for articles discussing digital ownership, software rent vs. build, or technological assets. Requires no props.',
usageExample: '<ArchitectureBuilder />'
},
{
name: 'DigitalAssetVisualizer',
description: 'Interactive visualization illustrating the financial difference between software as a liability (SaaS/rent) and software as a digital asset (Custom IP). Great for articles concerning CTO strategies, business value of code, and digital independence. Requires no props.',
usageExample: '<DigitalAssetVisualizer />'
}
];
export const componentDefinitions: ComponentDefinition[] =
allComponentDefinitions;