6 Commits

Author SHA1 Message Date
34a96f8aef fix(blog): resolve IconList string collision rendering 'Check' text
All checks were successful
Build & Deploy / 🔍 Prepare (push) Successful in 7s
Build & Deploy / 🏗️ Build (push) Successful in 16m0s
Build & Deploy / 🚀 Deploy (push) Successful in 13s
Build & Deploy / 🧪 QA (push) Successful in 1m9s
Build & Deploy / 🧪 Post-Deploy Verification (push) Successful in 2m34s
Build & Deploy / 🔔 Notify (push) Successful in 2s
2026-03-05 21:50:05 +01:00
4e6f3f29cf fix(blog): add missing mintelP/TLDR renderers, fix iconList, diagram blocks, reduce AI components to 13
All checks were successful
Build & Deploy / 🔍 Prepare (push) Successful in 7s
Build & Deploy / 🏗️ Build (push) Successful in 11m52s
Build & Deploy / 🚀 Deploy (push) Successful in 14s
Build & Deploy / 🧪 QA (push) Successful in 1m15s
Build & Deploy / 🧪 Post-Deploy Verification (push) Successful in 6m31s
Build & Deploy / 🔔 Notify (push) Successful in 2s
- Add mintelP renderer with inline markdown link/marker support (228 broken blocks)
- Add mintelTldr renderer for summary boxes
- Fix iconList to display item.title instead of empty item.description
- Rewire all 6 diagram block types to render via Mermaid
- Remove ai property from 30 non-essential blocks (46 -> 13)
- Tighten MemeCard to 5 verified templates, max 1 per article
- Fix PerformanceChartBlock syntax after ai removal
2026-03-05 17:39:57 +01:00
1bd516fbe4 fix: production container names in cms-sync and pin zod version for consistency
All checks were successful
Build & Deploy / 🔍 Prepare (push) Successful in 6s
Build & Deploy / 🏗️ Build (push) Successful in 10m16s
Build & Deploy / 🚀 Deploy (push) Successful in 14s
Build & Deploy / 🧪 QA (push) Successful in 51s
Build & Deploy / 🧪 Post-Deploy Verification (push) Successful in 2m52s
Build & Deploy / 🔔 Notify (push) Successful in 1s
2026-03-05 15:57:50 +01:00
4d0e3433a6 ci(deploy): remove unnecessary next.js build cache from docker image to save disk space
All checks were successful
Build & Deploy / 🔍 Prepare (push) Successful in 51s
Build & Deploy / 🏗️ Build (push) Successful in 13m0s
Build & Deploy / 🚀 Deploy (push) Successful in 13s
Build & Deploy / 🧪 QA (push) Successful in 51s
Build & Deploy / 🧪 Post-Deploy Verification (push) Successful in 2m21s
Build & Deploy / 🔔 Notify (push) Successful in 1s
2026-03-05 14:22:49 +01:00
ee9cde1ed0 ci(deploy): fix yaml syntax and ensure docker prune runs before build
Some checks failed
Build & Deploy / 🔍 Prepare (push) Successful in 14s
Build & Deploy / 🏗️ Build (push) Failing after 16m44s
Build & Deploy / 🚀 Deploy (push) Has been skipped
Build & Deploy / 🧪 QA (push) Has been skipped
Build & Deploy / 🧪 Post-Deploy Verification (push) Has been skipped
Build & Deploy / 🔔 Notify (push) Successful in 2s
2026-03-05 14:06:30 +01:00
33cf701034 ci(deploy): isolate docker buildcache per target env to prevent registry blob upload collisions
Some checks failed
Build & Deploy / 🔍 Prepare (push) Successful in 8s
Build & Deploy / 🏗️ Build (push) Failing after 12m6s
Build & Deploy / 🚀 Deploy (push) Has been skipped
Build & Deploy / 🧪 QA (push) Has been skipped
Build & Deploy / 🧪 Post-Deploy Verification (push) Has been skipped
Build & Deploy / 🔔 Notify (push) Successful in 2s
2026-03-05 13:41:51 +01:00
36 changed files with 103 additions and 230 deletions

View File

@@ -285,8 +285,15 @@ jobs:
perl -pi -e 's/link:\.\/_at-mintel\/packages\/pdf"/link:.\/_at-mintel\/packages\/pdf-library"/g' package.json perl -pi -e 's/link:\.\/_at-mintel\/packages\/pdf"/link:.\/_at-mintel\/packages\/pdf-library"/g' package.json
perl -pi -e 's/"\@mintel\/([^"]+)"\s*:\s*"[^"]+"/"\@mintel\/$1": "link:..\/\.\.\/_at-mintel\/packages\/$1"/g' apps/web/package.json perl -pi -e 's/"\@mintel\/([^"]+)"\s*:\s*"[^"]+"/"\@mintel\/$1": "link:..\/\.\.\/_at-mintel\/packages\/$1"/g' apps/web/package.json
perl -pi -e 's/link:\.\.\/\.\.\/_at-mintel\/packages\/pdf"/link:..\/\.\.\/_at-mintel\/packages\/pdf-library"/g' apps/web/package.json perl -pi -e 's/link:\.\.\/\.\.\/_at-mintel\/packages\/pdf"/link:..\/\.\.\/_at-mintel\/packages\/pdf-library"/g' apps/web/package.json
- name: 🧹 Free Disk Space
run: |
docker builder prune -af || true
docker image prune -af || true
- name: 🐳 Set up Docker Buildx - name: 🐳 Set up Docker Buildx
uses: docker/setup-buildx-action@v3 uses: docker/setup-buildx-action@v3
- name: 🔐 Registry Login - name: 🔐 Registry Login
run: | run: |
echo "${{ secrets.REGISTRY_PASS }}" | docker login registry.infra.mintel.me -u "${{ secrets.REGISTRY_USER }}" --password-stdin echo "${{ secrets.REGISTRY_PASS }}" | docker login registry.infra.mintel.me -u "${{ secrets.REGISTRY_USER }}" --password-stdin
@@ -304,8 +311,8 @@ jobs:
DIRECTUS_URL=${{ needs.prepare.outputs.directus_url }} DIRECTUS_URL=${{ needs.prepare.outputs.directus_url }}
NPM_TOKEN=${{ secrets.NPM_TOKEN }} NPM_TOKEN=${{ secrets.NPM_TOKEN }}
tags: registry.infra.mintel.me/mintel/mintel.me:${{ needs.prepare.outputs.image_tag }} tags: registry.infra.mintel.me/mintel/mintel.me:${{ needs.prepare.outputs.image_tag }}
cache-from: type=registry,ref=registry.infra.mintel.me/mintel/mintel.me:buildcache cache-from: type=registry,ref=registry.infra.mintel.me/mintel/mintel.me:buildcache-${{ needs.prepare.outputs.target }}
cache-to: type=registry,ref=registry.infra.mintel.me/mintel/mintel.me:buildcache,mode=max cache-to: type=registry,ref=registry.infra.mintel.me/mintel/mintel.me:buildcache-${{ needs.prepare.outputs.target }},mode=max
secrets: | secrets: |
NPM_TOKEN=${{ secrets.NPM_TOKEN }} NPM_TOKEN=${{ secrets.NPM_TOKEN }}

View File

@@ -48,7 +48,7 @@ WORKDIR /app
COPY --from=builder /app/apps/web/public ./apps/web/public COPY --from=builder /app/apps/web/public ./apps/web/public
COPY --from=builder /app/apps/web/.next/standalone ./ COPY --from=builder /app/apps/web/.next/standalone ./
COPY --from=builder /app/apps/web/.next/static ./apps/web/.next/static COPY --from=builder /app/apps/web/.next/static ./apps/web/.next/static
COPY --from=builder /app/apps/web/.next/cache ./apps/web/.next/cache
# Start from the app directory to ensure references solve correctly # Start from the app directory to ensure references solve correctly
WORKDIR /app/apps/web WORKDIR /app/apps/web

View File

@@ -89,14 +89,14 @@ resolve_target() {
prod|production) prod|production)
REMOTE_PROJECT="mintel-me-production" REMOTE_PROJECT="mintel-me-production"
REMOTE_DB_CONTAINER="mintel-me-production-postgres-db-1" REMOTE_DB_CONTAINER="mintel-me-production-postgres-db-1"
REMOTE_APP_CONTAINER="mintel-me-production-app-1" REMOTE_APP_CONTAINER="mintel-me-production-mintel-me-app-1"
REMOTE_SITE_DIR="/home/deploy/sites/mintel.me" REMOTE_SITE_DIR="/home/deploy/sites/mintel.me"
;; ;;
branch-*) branch-*)
local SLUG=${TARGET#branch-} local SLUG=${TARGET#branch-}
REMOTE_PROJECT="mintel-me-branch-$SLUG" REMOTE_PROJECT="mintel-me-branch-$SLUG"
REMOTE_DB_CONTAINER="${REMOTE_PROJECT}-postgres-db-1" REMOTE_DB_CONTAINER="${REMOTE_PROJECT}-postgres-db-1"
REMOTE_APP_CONTAINER="${REMOTE_PROJECT}-app-1" REMOTE_APP_CONTAINER="${REMOTE_PROJECT}-mintel-me-app-1"
REMOTE_SITE_DIR="/home/deploy/sites/branch.mintel.me/$SLUG" REMOTE_SITE_DIR="/home/deploy/sites/branch.mintel.me/$SLUG"
;; ;;
*) *)

View File

@@ -5,6 +5,39 @@ import { Mermaid } from "@/src/components/Mermaid";
import { LeadMagnet } from "@/src/components/LeadMagnet"; import { LeadMagnet } from "@/src/components/LeadMagnet";
import { ComparisonRow } from "@/src/components/Landing/ComparisonRow"; import { ComparisonRow } from "@/src/components/Landing/ComparisonRow";
import { mdxComponents } from "../content-engine/components"; import { mdxComponents } from "../content-engine/components";
import React from "react";
/**
* Renders markdown-style inline links [text](/url) as <a> tags.
* Used by mintelP blocks which store body text with links.
*/
function renderInlineMarkdown(text: string): React.ReactNode {
if (!text) return null;
const parts = text.split(/(\[[^\]]+\]\([^)]+\)|<Marker>[^<]*<\/Marker>)/);
return parts.map((part, i) => {
const linkMatch = part.match(/\[([^\]]+)\]\(([^)]+)\)/);
if (linkMatch) {
return (
<a
key={i}
href={linkMatch[2]}
className="text-slate-900 underline underline-offset-4 hover:text-slate-600 transition-colors"
>
{linkMatch[1]}
</a>
);
}
const markerMatch = part.match(/<Marker>([^<]*)<\/Marker>/);
if (markerMatch) {
return (
<mark key={i} className="bg-yellow-100/60 px-1 rounded">
{markerMatch[1]}
</mark>
);
}
return <React.Fragment key={i}>{part}</React.Fragment>;
});
}
const jsxConverters: JSXConverters = { const jsxConverters: JSXConverters = {
blocks: { blocks: {
@@ -49,6 +82,15 @@ const jsxConverters: JSXConverters = {
showShare={true} showShare={true}
/> />
), ),
// --- Core text blocks ---
mintelP: ({ node }: any) => (
<p className="text-base md:text-lg text-slate-600 leading-relaxed mb-6">
{renderInlineMarkdown(node.fields.text)}
</p>
),
mintelTldr: ({ node }: any) => (
<mdxComponents.TLDR>{node.fields.content}</mdxComponents.TLDR>
),
// --- MDX Registry Injections --- // --- MDX Registry Injections ---
leadParagraph: ({ node }: any) => ( leadParagraph: ({ node }: any) => (
<mdxComponents.LeadParagraph> <mdxComponents.LeadParagraph>
@@ -81,37 +123,46 @@ const jsxConverters: JSXConverters = {
/> />
), ),
diagramState: ({ node }: any) => ( diagramState: ({ node }: any) => (
<mdxComponents.DiagramState <div className="my-8">
states={[]} <Mermaid id={`diagram-state-${node.fields.id || Date.now()}`}>
transitions={[]} {node.fields.definition}
caption={node.fields.definition} </Mermaid>
/> </div>
), ),
diagramTimeline: ({ node }: any) => ( diagramTimeline: ({ node }: any) => (
<mdxComponents.DiagramTimeline <div className="my-8">
events={[]} <Mermaid id={`diagram-timeline-${node.fields.id || Date.now()}`}>
title={node.fields.definition} {node.fields.definition}
/> </Mermaid>
</div>
), ),
diagramGantt: ({ node }: any) => ( diagramGantt: ({ node }: any) => (
<mdxComponents.DiagramGantt tasks={[]} title={node.fields.definition} /> <div className="my-8">
<Mermaid id={`diagram-gantt-${node.fields.id || Date.now()}`}>
{node.fields.definition}
</Mermaid>
</div>
), ),
diagramPie: ({ node }: any) => ( diagramPie: ({ node }: any) => (
<mdxComponents.DiagramPie data={[]} title={node.fields.definition} /> <div className="my-8">
<Mermaid id={`diagram-pie-${node.fields.id || Date.now()}`}>
{node.fields.definition}
</Mermaid>
</div>
), ),
diagramSequence: ({ node }: any) => ( diagramSequence: ({ node }: any) => (
<mdxComponents.DiagramSequence <div className="my-8">
participants={[]} <Mermaid id={`diagram-seq-${node.fields.id || Date.now()}`}>
steps={[]} {node.fields.definition}
title={node.fields.definition} </Mermaid>
/> </div>
), ),
diagramFlow: ({ node }: any) => ( diagramFlow: ({ node }: any) => (
<mdxComponents.DiagramFlow <div className="my-8">
nodes={[]} <Mermaid id={`diagram-flow-${node.fields.id || Date.now()}`}>
edges={[]} {node.fields.definition}
title={node.fields.definition} </Mermaid>
/> </div>
), ),
waterfallChart: ({ node }: any) => ( waterfallChart: ({ node }: any) => (
@@ -128,12 +179,22 @@ const jsxConverters: JSXConverters = {
), ),
iconList: ({ node }: any) => ( iconList: ({ node }: any) => (
<mdxComponents.IconList> <mdxComponents.IconList>
{node.fields.items?.map((item: any, i: number) => ( {node.fields.items?.map((item: any, i: number) => {
// @ts-ignore const isCheck = item.icon === "check" || !item.icon;
<mdxComponents.IconListItem key={i} icon={item.icon || "check"}> const isCross = item.icon === "x" || item.icon === "cross";
{item.description} const isBullet = item.icon === "circle" || item.icon === "bullet";
</mdxComponents.IconListItem> return (
))} // @ts-ignore
<mdxComponents.IconListItem
key={i}
check={isCheck}
cross={isCross}
bullet={isBullet}
>
{item.title || item.description}
</mdxComponents.IconListItem>
);
})}
</mdxComponents.IconList> </mdxComponents.IconList>
), ),
statsGrid: ({ node }: any) => { statsGrid: ({ node }: any) => {

View File

@@ -11,12 +11,6 @@ export const ArchitectureBuilderBlock: MintelBlock = {
admin: { admin: {
group: "MDX Components", group: "MDX Components",
}, },
ai: {
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 />'",
},
fields: [ fields: [
{ {
name: "preset", name: "preset",

View File

@@ -11,12 +11,6 @@ export const ArticleBlockquoteBlock: MintelBlock = {
admin: { admin: {
group: "MDX Components", group: "MDX Components",
}, },
ai: {
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>'",
},
fields: [ fields: [
{ {
name: "quote", name: "quote",

View File

@@ -10,13 +10,6 @@ export const ArticleMemeBlock: MintelBlock = {
admin: { admin: {
group: "MDX Components", group: "MDX Components",
}, },
ai: {
name: "ArticleMeme",
description:
"Real image-based meme from the media library. Use for static screenshots or custom memes that are not available via memegen.link.",
usageExample:
'<ArticleMeme image="/media/my-meme.png" alt="Sarcastic dev meme" caption="When the code finally builds." />',
},
fields: [ fields: [
{ {
name: "image", name: "image",

View File

@@ -11,13 +11,6 @@ export const ButtonBlock: MintelBlock = {
admin: { admin: {
group: "MDX Components", group: "MDX Components",
}, },
ai: {
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>',
},
fields: [ fields: [
{ {
name: "label", name: "label",

View File

@@ -11,13 +11,6 @@ export const CarouselBlock: MintelBlock = {
admin: { admin: {
group: "MDX Components", group: "MDX Components",
}, },
ai: {
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..."',
},
fields: [ fields: [
{ {
name: "slides", name: "slides",

View File

@@ -11,12 +11,6 @@ export const DiagramFlowBlock: MintelBlock = {
admin: { admin: {
group: "MDX Components", group: "MDX Components",
}, },
ai: {
name: "DiagramFlow",
description:
"Mermaid flowchart diagram defining the graph structure. MUST output raw mermaid code, no quotes or HTML.",
usageExample: "graph TD\\n A[Start] --> B[End]",
},
fields: [ fields: [
{ {
name: "definition", name: "definition",

View File

@@ -11,12 +11,6 @@ export const DiagramGanttBlock: MintelBlock = {
admin: { admin: {
group: "MDX Components", group: "MDX Components",
}, },
ai: {
name: "DiagramGantt",
description: "Mermaid Gantt timeline chart. MUST output raw mermaid code.",
usageExample:
"gantt\\n title Project Roadmap\\n dateFormat YYYY-MM-DD\\n Section Design\\n Draft UI :a1, 2024-01-01, 7d",
},
fields: [ fields: [
{ {
name: "definition", name: "definition",

View File

@@ -11,11 +11,6 @@ export const DiagramPieBlock: MintelBlock = {
admin: { admin: {
group: "MDX Components", group: "MDX Components",
}, },
ai: {
name: "DiagramPie",
description: "Mermaid pie chart diagram. MUST output raw mermaid code.",
usageExample: 'pie title Market Share\\n "Chrome" : 60\\n "Safari" : 20',
},
fields: [ fields: [
{ {
name: "definition", name: "definition",

View File

@@ -11,13 +11,6 @@ export const DiagramSequenceBlock: MintelBlock = {
admin: { admin: {
group: "MDX Components", group: "MDX Components",
}, },
ai: {
name: "DiagramSequence",
description:
"Mermaid sequence diagram showing actor interactions. MUST output raw mermaid code.",
usageExample:
"sequenceDiagram\\n Client->>Server: GET /api\\n Server-->>Client: 200 OK",
},
fields: [ fields: [
{ {
name: "definition", name: "definition",

View File

@@ -11,12 +11,6 @@ export const DiagramStateBlock: MintelBlock = {
admin: { admin: {
group: "MDX Components", group: "MDX Components",
}, },
ai: {
name: "DiagramState",
description:
"Mermaid state diagram showing states and transitions. MUST output raw mermaid code.",
usageExample: "stateDiagram-v2\\n [*] --> Idle\\n Idle --> Loading",
},
fields: [ fields: [
{ {
name: "definition", name: "definition",

View File

@@ -11,13 +11,6 @@ export const DiagramTimelineBlock: MintelBlock = {
admin: { admin: {
group: "MDX Components", group: "MDX Components",
}, },
ai: {
name: "DiagramTimeline",
description:
"Mermaid timeline or journey diagram. MUST output raw mermaid code.",
usageExample:
"timeline\\n title Project Timeline\\n 2024\\n : Q1 : Planning\\n : Q2 : Execution",
},
fields: [ fields: [
{ {
name: "definition", name: "definition",

View File

@@ -11,12 +11,6 @@ export const DigitalAssetVisualizerBlock: MintelBlock = {
admin: { admin: {
group: "MDX Components", group: "MDX Components",
}, },
ai: {
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 />'",
},
fields: [ fields: [
{ {
name: "assetId", name: "assetId",

View File

@@ -16,13 +16,6 @@ export const FAQSectionBlock: MintelBlock = {
admin: { admin: {
group: "MDX Components", group: "MDX Components",
}, },
ai: {
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>'",
},
fields: [ fields: [
{ {
name: "content", name: "content",

View File

@@ -11,12 +11,6 @@ export const ImageTextBlock: MintelBlock = {
admin: { admin: {
group: "MDX Components", group: "MDX Components",
}, },
ai: {
name: "ImageText",
description: "Layout component for image next to explanatory text.",
usageExample:
'\'<ImageText image="/img.jpg" title="Architektur">Erklärung...</ImageText>\'',
},
fields: [ fields: [
{ {
name: "image", name: "image",

View File

@@ -11,13 +11,6 @@ export const LinkedInEmbedBlock: MintelBlock = {
admin: { admin: {
group: "MDX Components", group: "MDX Components",
}, },
ai: {
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\" />'",
},
fields: [ fields: [
{ {
name: "url", name: "url",

View File

@@ -11,12 +11,6 @@ export const LoadTimeSimulatorBlock: MintelBlock = {
admin: { admin: {
group: "MDX Components", group: "MDX Components",
}, },
ai: {
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 />'",
},
fields: [ fields: [
{ {
name: "initialLoadTime", name: "initialLoadTime",

View File

@@ -11,12 +11,6 @@ export const MarkerBlock: MintelBlock = {
admin: { admin: {
group: "MDX Components", group: "MDX Components",
}, },
ai: {
name: "Marker",
description:
"Inline highlight (yellow marker effect) for emphasizing key phrases within paragraphs.",
usageExample: "'<Marker>entscheidender Wettbewerbsvorteil</Marker>'",
},
fields: [ fields: [
{ {
name: "text", name: "text",

View File

@@ -13,7 +13,7 @@ export const MemeCardBlock: MintelBlock = {
ai: { ai: {
name: "MemeCard", name: "MemeCard",
description: 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".', "Real meme from memegen.link. ONLY use these templates: drake, distracted-bf, change-my-mind, uno-draw-25, always-has-been. Captions MUST be in German, extremely sarcastic, max 6 words per line. Use pipe | to separate caption lines. Use sparingly: MAX 1 meme per article.",
usageExample: `<div className="my-8"> usageExample: `<div className="my-8">
<MemeCard template="drake" captions="47 WordPress Plugins installieren|Eine saubere Serverless Architektur" /> <MemeCard template="drake" captions="47 WordPress Plugins installieren|Eine saubere Serverless Architektur" />
</div>`, </div>`,

View File

@@ -11,12 +11,6 @@ export const MetricBarBlock: MintelBlock = {
admin: { admin: {
group: "MDX Components", group: "MDX Components",
}, },
ai: {
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',
},
fields: [ fields: [
{ {
name: "label", name: "label",

View File

@@ -11,13 +11,6 @@ export const PerformanceChartBlock: MintelBlock = {
admin: { admin: {
group: "MDX Components", group: "MDX Components",
}, },
ai: {
name: "PerformanceChart",
description:
"A visual chart illustrating performance metrics (e.g. PageSpeed, TTFB) over time or in comparison. Use to emphasize technical improvements.",
usageExample:
'<PerformanceChart items={[{ label: "Vorher", value: 12 }, { label: "Nachher", value: 98 }]} />',
},
fields: [ fields: [
{ {
name: "title", name: "title",

View File

@@ -11,12 +11,6 @@ export const PerformanceROICalculatorBlock: MintelBlock = {
admin: { admin: {
group: "MDX Components", group: "MDX Components",
}, },
ai: {
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 />'",
},
fields: [ fields: [
{ {
name: "baseConversionRate", name: "baseConversionRate",

View File

@@ -11,13 +11,6 @@ export const PremiumComparisonChartBlock: MintelBlock = {
admin: { admin: {
group: "MDX Components", group: "MDX Components",
}, },
ai: {
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"',
},
fields: [ fields: [
{ {
name: "title", name: "title",

View File

@@ -12,13 +12,6 @@ export const RevealBlock: MintelBlock = {
admin: { admin: {
group: "MDX Components", group: "MDX Components",
}, },
ai: {
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>\'',
},
fields: [ fields: [
{ {
name: "direction", name: "direction",

View File

@@ -11,12 +11,6 @@ export const RevenueLossCalculatorBlock: MintelBlock = {
admin: { admin: {
group: "MDX Components", group: "MDX Components",
}, },
ai: {
name: "RevenueLossCalculator",
description:
"Interactive calculator that estimates financial loss due to slow page load times. Use to build a business case for performance optimization.",
usageExample: "<RevenueLossCalculator />",
},
fields: [ fields: [
{ {
name: "title", name: "title",

View File

@@ -12,12 +12,6 @@ export const SectionBlock: MintelBlock = {
admin: { admin: {
group: "MDX Components", group: "MDX Components",
}, },
ai: {
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>'",
},
fields: [ fields: [
{ {
name: "title", name: "title",

View File

@@ -11,13 +11,6 @@ export const StatsDisplayBlock: MintelBlock = {
admin: { admin: {
group: "MDX Components", group: "MDX Components",
}, },
ai: {
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." />\'',
},
fields: [ fields: [
{ {
name: "label", name: "label",

View File

@@ -11,13 +11,6 @@ export const StatsGridBlock: MintelBlock = {
admin: { admin: {
group: "MDX Components", group: "MDX Components",
}, },
ai: {
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\" />'",
},
fields: [ fields: [
{ {
name: "stats", name: "stats",

View File

@@ -11,13 +11,6 @@ export const TrackedLinkBlock: MintelBlock = {
admin: { admin: {
group: "MDX Components", group: "MDX Components",
}, },
ai: {
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>\'',
},
fields: [ fields: [
{ {
name: "href", name: "href",

View File

@@ -11,13 +11,6 @@ export const TwitterEmbedBlock: MintelBlock = {
admin: { admin: {
group: "MDX Components", group: "MDX Components",
}, },
ai: {
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" />\'',
},
fields: [ fields: [
{ {
name: "url", name: "url",

View File

@@ -11,15 +11,6 @@ export const WaterfallChartBlock: MintelBlock = {
admin: { admin: {
group: "MDX Components", group: "MDX Components",
}, },
ai: {
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`,
},
fields: [ fields: [
{ {
name: "title", name: "title",

View File

@@ -11,12 +11,6 @@ export const WebVitalsScoreBlock: MintelBlock = {
admin: { admin: {
group: "MDX Components", group: "MDX Components",
}, },
ai: {
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",
},
fields: [ fields: [
{ {
name: "lcp", name: "lcp",

View File

@@ -52,7 +52,8 @@
"pnpm": { "pnpm": {
"overrides": { "overrides": {
"@sentry/nextjs": "10.38.0", "@sentry/nextjs": "10.38.0",
"eslint": "10.0.0" "eslint": "10.0.0",
"zod": "^3.23.8"
}, },
"onlyBuiltDependencies": [ "onlyBuiltDependencies": [
"@parcel/watcher", "@parcel/watcher",