fix(blog): optimize component share logic, typography, and modal layouts
Some checks failed
Build & Deploy / 🔍 Prepare (push) Successful in 5s
Build & Deploy / 🏗️ Build (push) Failing after 14s
Build & Deploy / 🧪 QA (push) Failing after 1m48s
Build & Deploy / 🚀 Deploy (push) Has been skipped
Build & Deploy / 🩺 Health Check (push) Has been skipped
Build & Deploy / 🔔 Notify (push) Successful in 2s
Some checks failed
Build & Deploy / 🔍 Prepare (push) Successful in 5s
Build & Deploy / 🏗️ Build (push) Failing after 14s
Build & Deploy / 🧪 QA (push) Failing after 1m48s
Build & Deploy / 🚀 Deploy (push) Has been skipped
Build & Deploy / 🩺 Health Check (push) Has been skipped
Build & Deploy / 🔔 Notify (push) Successful in 2s
This commit is contained in:
@@ -12,11 +12,35 @@ 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 { 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 { Section } from '../components/Section';
|
||||
import { Reveal } from '../components/Reveal';
|
||||
import { TableOfContents } from '../components/TableOfContents';
|
||||
|
||||
import { RevenueLossCalculator } from "../components/RevenueLossCalculator";
|
||||
import { PerformanceChart } from "../components/PerformanceChart";
|
||||
|
||||
import { TwitterEmbed } from '../components/TwitterEmbed';
|
||||
import { YouTubeEmbed } from '../components/YouTubeEmbed';
|
||||
import { LinkedInEmbed } from '../components/LinkedInEmbed';
|
||||
|
||||
export const mdxComponents = {
|
||||
// Named exports for explicit MDX usage
|
||||
@@ -35,9 +59,30 @@ export const mdxComponents = {
|
||||
DiagramGantt,
|
||||
DiagramPie,
|
||||
DiagramSequence,
|
||||
DiagramFlow,
|
||||
IconList,
|
||||
IconListItem,
|
||||
ArticleMeme,
|
||||
MemeCard,
|
||||
ExternalLink,
|
||||
StatsGrid,
|
||||
MetricBar,
|
||||
ArticleQuote,
|
||||
BoldNumber,
|
||||
WebVitalsScore,
|
||||
WaterfallChart,
|
||||
PremiumComparisonChart,
|
||||
ImageText,
|
||||
Carousel,
|
||||
Section,
|
||||
Reveal
|
||||
Reveal,
|
||||
TableOfContents,
|
||||
RevenueLossCalculator,
|
||||
PerformanceChart,
|
||||
TwitterEmbed,
|
||||
YouTubeEmbed,
|
||||
LinkedInEmbed,
|
||||
Button,
|
||||
TrackedLink,
|
||||
FAQSection
|
||||
};
|
||||
|
||||
@@ -1,55 +1,271 @@
|
||||
|
||||
import { ComponentDefinition } from '@mintel/content-engine';
|
||||
|
||||
/**
|
||||
* 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)
|
||||
*/
|
||||
export const componentDefinitions: ComponentDefinition[] = [
|
||||
{
|
||||
name: 'LeadParagraph',
|
||||
description: 'Large, introductory text for the beginning of the article.',
|
||||
usageExample: '<LeadParagraph>First meaningful sentence.</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: 'Section heading.',
|
||||
usageExample: '<H2>Section Title</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.',
|
||||
usageExample: '<H3>Subtitle</H3>'
|
||||
description: 'Subsection heading. Used within H2 sections.',
|
||||
usageExample: '<H3>Die drei Säulen meiner Umsetzung</H3>'
|
||||
},
|
||||
{
|
||||
name: 'Paragraph',
|
||||
description: 'Standard body text paragraph.',
|
||||
usageExample: '<Paragraph>Some text...</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: 'A prominent quote block for key insights.',
|
||||
usageExample: '<ArticleBlockquote>Important quote</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: 'Yellow highlighter effect for very important phrases.',
|
||||
usageExample: '<Marker>Highlighted Text</Marker>'
|
||||
description: 'Inline highlight (yellow marker effect) for emphasizing key phrases within paragraphs.',
|
||||
usageExample: '<Marker>entscheidender Wettbewerbsvorteil</Marker>'
|
||||
},
|
||||
{
|
||||
name: 'ComparisonRow',
|
||||
description: 'A component comparing a negative vs positive scenario.',
|
||||
usageExample: '<ComparisonRow description="Cost Comparison" negativeLabel="Lock-In" negativeText="High costs" positiveLabel="Open" positiveText="Control" />'
|
||||
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 bold visual component to highlight a key statistic or number.',
|
||||
usageExample: '<StatsDisplay value="42%" label="Cost Reduction" subtext="Average savings by switching to open standards." />'
|
||||
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 diagram.',
|
||||
usageExample: '<Mermaid graph="graph TD..." id="my-diagram" />'
|
||||
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: 'A state transition diagram.',
|
||||
usageExample: '<DiagramState states={["A", "B"]} ... />'
|
||||
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 2–4 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: 'Premium pill-shaped button for high-impact CTAs. Variants: primary (solid dark), outline (bordered), ghost (text only). use size="large" for main sections.',
|
||||
usageExample: '<Button href="/contact" variant="outline">Webprojekt anfragen</Button>'
|
||||
},
|
||||
{
|
||||
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>'
|
||||
}
|
||||
];
|
||||
|
||||
Reference in New Issue
Block a user