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
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:
28
apps/web/src/payload/blocks/ArchitectureBuilderBlock.ts
Normal file
28
apps/web/src/payload/blocks/ArchitectureBuilderBlock.ts
Normal file
@@ -0,0 +1,28 @@
|
||||
import { MintelBlock } from "./types";
|
||||
|
||||
import type { Block } from "payload";
|
||||
|
||||
export const ArchitectureBuilderBlock: MintelBlock = {
|
||||
slug: "architectureBuilder",
|
||||
labels: {
|
||||
singular: "Architecture Builder",
|
||||
plural: "Architecture Builders",
|
||||
},
|
||||
admin: {
|
||||
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: [
|
||||
{
|
||||
name: "preset",
|
||||
type: "text",
|
||||
defaultValue: "standard",
|
||||
admin: { description: "Geben Sie den Text für preset ein." },
|
||||
},
|
||||
],
|
||||
};
|
||||
59
apps/web/src/payload/blocks/ArticleBlockquoteBlock.ts
Normal file
59
apps/web/src/payload/blocks/ArticleBlockquoteBlock.ts
Normal file
@@ -0,0 +1,59 @@
|
||||
import { MintelBlock } from "./types";
|
||||
|
||||
import type { Block } from "payload";
|
||||
|
||||
export const ArticleBlockquoteBlock: MintelBlock = {
|
||||
slug: "articleBlockquote",
|
||||
labels: {
|
||||
singular: "Article Blockquote",
|
||||
plural: "Article Blockquotes",
|
||||
},
|
||||
admin: {
|
||||
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: [
|
||||
{
|
||||
name: "quote",
|
||||
type: "textarea",
|
||||
required: true,
|
||||
admin: {
|
||||
components: {
|
||||
afterInput: [
|
||||
"@/src/payload/components/FieldGenerators/AiFieldButton#AiFieldButton",
|
||||
],
|
||||
},
|
||||
description: "Geben Sie den mehrzeiligen Text für quote ein.",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "author",
|
||||
type: "text",
|
||||
admin: {
|
||||
components: {
|
||||
afterInput: [
|
||||
"@/src/payload/components/FieldGenerators/AiFieldButton#AiFieldButton",
|
||||
],
|
||||
},
|
||||
description: "Geben Sie den Text für author ein.",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "role",
|
||||
type: "text",
|
||||
admin: {
|
||||
components: {
|
||||
afterInput: [
|
||||
"@/src/payload/components/FieldGenerators/AiFieldButton#AiFieldButton",
|
||||
],
|
||||
},
|
||||
description: "Geben Sie den Text für role ein.",
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
||||
54
apps/web/src/payload/blocks/ArticleMemeBlock.ts
Normal file
54
apps/web/src/payload/blocks/ArticleMemeBlock.ts
Normal file
@@ -0,0 +1,54 @@
|
||||
import { MintelBlock } from "./types";
|
||||
import type { Block } from "payload";
|
||||
|
||||
export const ArticleMemeBlock: MintelBlock = {
|
||||
slug: "articleMeme",
|
||||
labels: {
|
||||
singular: "Article Meme",
|
||||
plural: "Article Memes",
|
||||
},
|
||||
admin: {
|
||||
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: [
|
||||
{
|
||||
name: "image",
|
||||
type: "upload",
|
||||
relationTo: "media",
|
||||
required: true,
|
||||
admin: { description: "Laden Sie die Datei für image hoch." },
|
||||
},
|
||||
{
|
||||
name: "alt",
|
||||
type: "text",
|
||||
required: true,
|
||||
admin: {
|
||||
components: {
|
||||
afterInput: [
|
||||
"@/src/payload/components/FieldGenerators/AiFieldButton#AiFieldButton",
|
||||
],
|
||||
},
|
||||
description: "Geben Sie den Text für alt ein.",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "caption",
|
||||
type: "text",
|
||||
admin: {
|
||||
components: {
|
||||
afterInput: [
|
||||
"@/src/payload/components/FieldGenerators/AiFieldButton#AiFieldButton",
|
||||
],
|
||||
},
|
||||
description: "Geben Sie den Text für caption ein.",
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
||||
97
apps/web/src/payload/blocks/ArticleQuoteBlock.ts
Normal file
97
apps/web/src/payload/blocks/ArticleQuoteBlock.ts
Normal file
@@ -0,0 +1,97 @@
|
||||
import { MintelBlock } from "./types";
|
||||
|
||||
import type { Block } from "payload";
|
||||
|
||||
export const ArticleQuoteBlock: MintelBlock = {
|
||||
slug: "articleQuote",
|
||||
labels: {
|
||||
singular: "Article Quote",
|
||||
plural: "Article Quotes",
|
||||
},
|
||||
admin: {
|
||||
group: "MDX Components",
|
||||
},
|
||||
ai: {
|
||||
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',
|
||||
},
|
||||
fields: [
|
||||
{
|
||||
name: "quote",
|
||||
type: "textarea",
|
||||
required: true,
|
||||
admin: {
|
||||
components: {
|
||||
afterInput: [
|
||||
"@/src/payload/components/FieldGenerators/AiFieldButton#AiFieldButton",
|
||||
],
|
||||
},
|
||||
description: "Geben Sie den mehrzeiligen Text für quote ein.",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "author",
|
||||
type: "text",
|
||||
required: true,
|
||||
admin: {
|
||||
components: {
|
||||
afterInput: [
|
||||
"@/src/payload/components/FieldGenerators/AiFieldButton#AiFieldButton",
|
||||
],
|
||||
},
|
||||
description: "Geben Sie den Text für author ein.",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "role",
|
||||
type: "text",
|
||||
admin: {
|
||||
components: {
|
||||
afterInput: [
|
||||
"@/src/payload/components/FieldGenerators/AiFieldButton#AiFieldButton",
|
||||
],
|
||||
},
|
||||
description: "Geben Sie den Text für role ein.",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "source",
|
||||
type: "text",
|
||||
admin: {
|
||||
components: {
|
||||
afterInput: [
|
||||
"@/src/payload/components/FieldGenerators/AiFieldButton#AiFieldButton",
|
||||
],
|
||||
},
|
||||
description: "Geben Sie den Text für source ein.",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "sourceUrl",
|
||||
type: "text",
|
||||
admin: {
|
||||
components: {
|
||||
afterInput: [
|
||||
"@/src/payload/components/FieldGenerators/AiFieldButton#AiFieldButton",
|
||||
],
|
||||
},
|
||||
description: "Geben Sie den Text für sourceUrl ein.",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "translated",
|
||||
type: "checkbox",
|
||||
defaultValue: false,
|
||||
admin: { description: "Wert für translated eingeben." },
|
||||
},
|
||||
{
|
||||
name: "isCompany",
|
||||
type: "checkbox",
|
||||
defaultValue: false,
|
||||
admin: { description: "Wert für isCompany eingeben." },
|
||||
},
|
||||
],
|
||||
};
|
||||
72
apps/web/src/payload/blocks/BoldNumberBlock.ts
Normal file
72
apps/web/src/payload/blocks/BoldNumberBlock.ts
Normal file
@@ -0,0 +1,72 @@
|
||||
import { MintelBlock } from "./types";
|
||||
|
||||
import type { Block } from "payload";
|
||||
|
||||
export const BoldNumberBlock: MintelBlock = {
|
||||
slug: "boldNumber",
|
||||
labels: {
|
||||
singular: "Bold Number",
|
||||
plural: "Bold Numbers",
|
||||
},
|
||||
admin: {
|
||||
group: "MDX Components",
|
||||
},
|
||||
ai: {
|
||||
name: "BoldNumber",
|
||||
description: "Large centerpiece number with label for primary statistics.",
|
||||
usageExample:
|
||||
'\'<BoldNumber value="5x" label="höhere Conversion-Rate" source="Portent" />\'',
|
||||
},
|
||||
fields: [
|
||||
{
|
||||
name: "value",
|
||||
type: "text",
|
||||
required: true,
|
||||
admin: {
|
||||
description: "e.g. 53% or 2.5M€",
|
||||
components: {
|
||||
afterInput: [
|
||||
"@/src/payload/components/FieldGenerators/AiFieldButton#AiFieldButton",
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "label",
|
||||
type: "text",
|
||||
required: true,
|
||||
admin: {
|
||||
components: {
|
||||
afterInput: [
|
||||
"@/src/payload/components/FieldGenerators/AiFieldButton#AiFieldButton",
|
||||
],
|
||||
},
|
||||
description: "Geben Sie den Text für label ein.",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "source",
|
||||
type: "text",
|
||||
admin: {
|
||||
components: {
|
||||
afterInput: [
|
||||
"@/src/payload/components/FieldGenerators/AiFieldButton#AiFieldButton",
|
||||
],
|
||||
},
|
||||
description: "Geben Sie den Text für source ein.",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "sourceUrl",
|
||||
type: "text",
|
||||
admin: {
|
||||
components: {
|
||||
afterInput: [
|
||||
"@/src/payload/components/FieldGenerators/AiFieldButton#AiFieldButton",
|
||||
],
|
||||
},
|
||||
description: "Geben Sie den Text für sourceUrl ein.",
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
||||
69
apps/web/src/payload/blocks/ButtonBlock.ts
Normal file
69
apps/web/src/payload/blocks/ButtonBlock.ts
Normal file
@@ -0,0 +1,69 @@
|
||||
import { MintelBlock } from "./types";
|
||||
|
||||
import type { Block } from "payload";
|
||||
|
||||
export const ButtonBlock: MintelBlock = {
|
||||
slug: "buttonBlock",
|
||||
labels: {
|
||||
singular: "Button Block",
|
||||
plural: "Button Blocks",
|
||||
},
|
||||
admin: {
|
||||
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: [
|
||||
{
|
||||
name: "label",
|
||||
type: "text",
|
||||
required: true,
|
||||
admin: {
|
||||
components: {
|
||||
afterInput: [
|
||||
"@/src/payload/components/FieldGenerators/AiFieldButton#AiFieldButton",
|
||||
],
|
||||
},
|
||||
description: "Geben Sie den Text für label ein.",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "href",
|
||||
type: "text",
|
||||
required: true,
|
||||
admin: { description: "Geben Sie den Text für href ein." },
|
||||
},
|
||||
{
|
||||
name: "variant",
|
||||
type: "select",
|
||||
options: [
|
||||
{ label: "Primary", value: "primary" },
|
||||
{ label: "Outline", value: "outline" },
|
||||
{ label: "Ghost", value: "ghost" },
|
||||
],
|
||||
defaultValue: "primary",
|
||||
admin: { description: "Wählen Sie eine Option für variant aus." },
|
||||
},
|
||||
{
|
||||
name: "size",
|
||||
type: "select",
|
||||
options: [
|
||||
{ label: "Normal", value: "normal" },
|
||||
{ label: "Large", value: "large" },
|
||||
],
|
||||
defaultValue: "normal",
|
||||
admin: { description: "Wählen Sie eine Option für size aus." },
|
||||
},
|
||||
{
|
||||
name: "showArrow",
|
||||
type: "checkbox",
|
||||
defaultValue: true,
|
||||
admin: { description: "Wert für showArrow eingeben." },
|
||||
},
|
||||
],
|
||||
};
|
||||
48
apps/web/src/payload/blocks/CarouselBlock.ts
Normal file
48
apps/web/src/payload/blocks/CarouselBlock.ts
Normal file
@@ -0,0 +1,48 @@
|
||||
import { MintelBlock } from "./types";
|
||||
|
||||
import type { Block } from "payload";
|
||||
|
||||
export const CarouselBlock: MintelBlock = {
|
||||
slug: "carousel",
|
||||
labels: {
|
||||
singular: "Carousel",
|
||||
plural: "Carousels",
|
||||
},
|
||||
admin: {
|
||||
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: [
|
||||
{
|
||||
name: "slides",
|
||||
type: "array",
|
||||
fields: [
|
||||
{
|
||||
name: "image",
|
||||
type: "upload",
|
||||
relationTo: "media",
|
||||
admin: { description: "Laden Sie die Datei für image hoch." },
|
||||
},
|
||||
{
|
||||
name: "caption",
|
||||
type: "text",
|
||||
admin: {
|
||||
components: {
|
||||
afterInput: [
|
||||
"@/src/payload/components/FieldGenerators/AiFieldButton#AiFieldButton",
|
||||
],
|
||||
},
|
||||
description: "Geben Sie den Text für caption ein.",
|
||||
},
|
||||
},
|
||||
],
|
||||
admin: { description: "Fügen Sie Elemente zur Liste slides hinzu." },
|
||||
},
|
||||
],
|
||||
};
|
||||
102
apps/web/src/payload/blocks/ComparisonRowBlock.ts
Normal file
102
apps/web/src/payload/blocks/ComparisonRowBlock.ts
Normal file
@@ -0,0 +1,102 @@
|
||||
import { MintelBlock } from "./types";
|
||||
|
||||
import type { Block } from "payload";
|
||||
|
||||
export const ComparisonRowBlock: MintelBlock = {
|
||||
slug: "comparisonRow",
|
||||
labels: {
|
||||
singular: "Comparison Row",
|
||||
plural: "Comparison Rows",
|
||||
},
|
||||
admin: {
|
||||
group: "MDX Components",
|
||||
},
|
||||
ai: {
|
||||
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`,
|
||||
},
|
||||
fields: [
|
||||
{
|
||||
name: "description",
|
||||
type: "text",
|
||||
admin: {
|
||||
description: "Optional overarching description for the comparison.",
|
||||
components: {
|
||||
afterInput: [
|
||||
"@/src/payload/components/FieldGenerators/AiFieldButton#AiFieldButton",
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "negativeLabel",
|
||||
type: "text",
|
||||
required: true,
|
||||
defaultValue: "Legacy",
|
||||
admin: {
|
||||
components: {
|
||||
afterInput: [
|
||||
"@/src/payload/components/FieldGenerators/AiFieldButton#AiFieldButton",
|
||||
],
|
||||
},
|
||||
description: "Geben Sie den Text für negativeLabel ein.",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "negativeText",
|
||||
type: "text",
|
||||
required: true,
|
||||
admin: {
|
||||
components: {
|
||||
afterInput: [
|
||||
"@/src/payload/components/FieldGenerators/AiFieldButton#AiFieldButton",
|
||||
],
|
||||
},
|
||||
description: "Geben Sie den Text für negativeText ein.",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "positiveLabel",
|
||||
type: "text",
|
||||
required: true,
|
||||
defaultValue: "Mintel Stack",
|
||||
admin: {
|
||||
components: {
|
||||
afterInput: [
|
||||
"@/src/payload/components/FieldGenerators/AiFieldButton#AiFieldButton",
|
||||
],
|
||||
},
|
||||
description: "Geben Sie den Text für positiveLabel ein.",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "positiveText",
|
||||
type: "text",
|
||||
required: true,
|
||||
admin: {
|
||||
components: {
|
||||
afterInput: [
|
||||
"@/src/payload/components/FieldGenerators/AiFieldButton#AiFieldButton",
|
||||
],
|
||||
},
|
||||
description: "Geben Sie den Text für positiveText ein.",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "reverse",
|
||||
type: "checkbox",
|
||||
defaultValue: false,
|
||||
admin: {
|
||||
description: "Swap the visual order of the positive/negative cards?",
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
||||
35
apps/web/src/payload/blocks/DiagramFlowBlock.ts
Normal file
35
apps/web/src/payload/blocks/DiagramFlowBlock.ts
Normal file
@@ -0,0 +1,35 @@
|
||||
import { MintelBlock } from "./types";
|
||||
|
||||
import type { Block } from "payload";
|
||||
|
||||
export const DiagramFlowBlock: MintelBlock = {
|
||||
slug: "diagramFlow",
|
||||
labels: {
|
||||
singular: "Diagram Flow",
|
||||
plural: "Diagram Flows",
|
||||
},
|
||||
admin: {
|
||||
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: [
|
||||
{
|
||||
name: "definition",
|
||||
type: "textarea",
|
||||
required: true,
|
||||
admin: {
|
||||
components: {
|
||||
afterInput: [
|
||||
"@/src/payload/components/FieldGenerators/AiFieldButton#AiFieldButton",
|
||||
],
|
||||
},
|
||||
description: "Geben Sie den mehrzeiligen Text für definition ein.",
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
||||
35
apps/web/src/payload/blocks/DiagramGanttBlock.ts
Normal file
35
apps/web/src/payload/blocks/DiagramGanttBlock.ts
Normal file
@@ -0,0 +1,35 @@
|
||||
import { MintelBlock } from "./types";
|
||||
|
||||
import type { Block } from "payload";
|
||||
|
||||
export const DiagramGanttBlock: MintelBlock = {
|
||||
slug: "diagramGantt",
|
||||
labels: {
|
||||
singular: "Diagram Gantt",
|
||||
plural: "Diagram Gantts",
|
||||
},
|
||||
admin: {
|
||||
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: [
|
||||
{
|
||||
name: "definition",
|
||||
type: "textarea",
|
||||
required: true,
|
||||
admin: {
|
||||
components: {
|
||||
afterInput: [
|
||||
"@/src/payload/components/FieldGenerators/AiFieldButton#AiFieldButton",
|
||||
],
|
||||
},
|
||||
description: "Geben Sie den mehrzeiligen Text für definition ein.",
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
||||
34
apps/web/src/payload/blocks/DiagramPieBlock.ts
Normal file
34
apps/web/src/payload/blocks/DiagramPieBlock.ts
Normal file
@@ -0,0 +1,34 @@
|
||||
import { MintelBlock } from "./types";
|
||||
|
||||
import type { Block } from "payload";
|
||||
|
||||
export const DiagramPieBlock: MintelBlock = {
|
||||
slug: "diagramPie",
|
||||
labels: {
|
||||
singular: "Diagram Pie",
|
||||
plural: "Diagram Pies",
|
||||
},
|
||||
admin: {
|
||||
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: [
|
||||
{
|
||||
name: "definition",
|
||||
type: "textarea",
|
||||
required: true,
|
||||
admin: {
|
||||
components: {
|
||||
afterInput: [
|
||||
"@/src/payload/components/FieldGenerators/AiFieldButton#AiFieldButton",
|
||||
],
|
||||
},
|
||||
description: "Geben Sie den mehrzeiligen Text für definition ein.",
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
||||
36
apps/web/src/payload/blocks/DiagramSequenceBlock.ts
Normal file
36
apps/web/src/payload/blocks/DiagramSequenceBlock.ts
Normal file
@@ -0,0 +1,36 @@
|
||||
import { MintelBlock } from "./types";
|
||||
|
||||
import type { Block } from "payload";
|
||||
|
||||
export const DiagramSequenceBlock: MintelBlock = {
|
||||
slug: "diagramSequence",
|
||||
labels: {
|
||||
singular: "Diagram Sequence",
|
||||
plural: "Diagram Sequences",
|
||||
},
|
||||
admin: {
|
||||
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: [
|
||||
{
|
||||
name: "definition",
|
||||
type: "textarea",
|
||||
required: true,
|
||||
admin: {
|
||||
components: {
|
||||
afterInput: [
|
||||
"@/src/payload/components/FieldGenerators/AiFieldButton#AiFieldButton",
|
||||
],
|
||||
},
|
||||
description: "Geben Sie den mehrzeiligen Text für definition ein.",
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
||||
35
apps/web/src/payload/blocks/DiagramStateBlock.ts
Normal file
35
apps/web/src/payload/blocks/DiagramStateBlock.ts
Normal file
@@ -0,0 +1,35 @@
|
||||
import { MintelBlock } from "./types";
|
||||
|
||||
import type { Block } from "payload";
|
||||
|
||||
export const DiagramStateBlock: MintelBlock = {
|
||||
slug: "diagramState",
|
||||
labels: {
|
||||
singular: "Diagram State",
|
||||
plural: "Diagram States",
|
||||
},
|
||||
admin: {
|
||||
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: [
|
||||
{
|
||||
name: "definition",
|
||||
type: "textarea",
|
||||
required: true,
|
||||
admin: {
|
||||
components: {
|
||||
afterInput: [
|
||||
"@/src/payload/components/FieldGenerators/AiFieldButton#AiFieldButton",
|
||||
],
|
||||
},
|
||||
description: "Geben Sie den mehrzeiligen Text für definition ein.",
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
||||
36
apps/web/src/payload/blocks/DiagramTimelineBlock.ts
Normal file
36
apps/web/src/payload/blocks/DiagramTimelineBlock.ts
Normal file
@@ -0,0 +1,36 @@
|
||||
import { MintelBlock } from "./types";
|
||||
|
||||
import type { Block } from "payload";
|
||||
|
||||
export const DiagramTimelineBlock: MintelBlock = {
|
||||
slug: "diagramTimeline",
|
||||
labels: {
|
||||
singular: "Diagram Timeline",
|
||||
plural: "Diagram Timelines",
|
||||
},
|
||||
admin: {
|
||||
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: [
|
||||
{
|
||||
name: "definition",
|
||||
type: "textarea",
|
||||
required: true,
|
||||
admin: {
|
||||
components: {
|
||||
afterInput: [
|
||||
"@/src/payload/components/FieldGenerators/AiFieldButton#AiFieldButton",
|
||||
],
|
||||
},
|
||||
description: "Geben Sie den mehrzeiligen Text für definition ein.",
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
||||
27
apps/web/src/payload/blocks/DigitalAssetVisualizerBlock.ts
Normal file
27
apps/web/src/payload/blocks/DigitalAssetVisualizerBlock.ts
Normal file
@@ -0,0 +1,27 @@
|
||||
import { MintelBlock } from "./types";
|
||||
|
||||
import type { Block } from "payload";
|
||||
|
||||
export const DigitalAssetVisualizerBlock: MintelBlock = {
|
||||
slug: "digitalAssetVisualizer",
|
||||
labels: {
|
||||
singular: "Digital Asset Visualizer",
|
||||
plural: "Digital Asset Visualizers",
|
||||
},
|
||||
admin: {
|
||||
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: [
|
||||
{
|
||||
name: "assetId",
|
||||
type: "text",
|
||||
admin: { description: "Geben Sie den Text für assetId ein." },
|
||||
},
|
||||
],
|
||||
};
|
||||
42
apps/web/src/payload/blocks/ExternalLinkBlock.ts
Normal file
42
apps/web/src/payload/blocks/ExternalLinkBlock.ts
Normal file
@@ -0,0 +1,42 @@
|
||||
import { MintelBlock } from "./types";
|
||||
|
||||
import type { Block } from "payload";
|
||||
|
||||
export const ExternalLinkBlock: MintelBlock = {
|
||||
slug: "externalLink",
|
||||
labels: {
|
||||
singular: "External Link",
|
||||
plural: "External Links",
|
||||
},
|
||||
admin: {
|
||||
group: "MDX Components",
|
||||
},
|
||||
ai: {
|
||||
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>'",
|
||||
},
|
||||
fields: [
|
||||
{
|
||||
name: "href",
|
||||
type: "text",
|
||||
required: true,
|
||||
admin: { description: "Geben Sie den Text für href ein." },
|
||||
},
|
||||
{
|
||||
name: "label",
|
||||
type: "text",
|
||||
required: true,
|
||||
admin: {
|
||||
components: {
|
||||
afterInput: [
|
||||
"@/src/payload/components/FieldGenerators/AiFieldButton#AiFieldButton",
|
||||
],
|
||||
},
|
||||
description: "Geben Sie den Text für label ein.",
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
||||
47
apps/web/src/payload/blocks/FAQSectionBlock.ts
Normal file
47
apps/web/src/payload/blocks/FAQSectionBlock.ts
Normal file
@@ -0,0 +1,47 @@
|
||||
import { MintelBlock } from "./types";
|
||||
|
||||
import type { Block } from "payload";
|
||||
import { lexicalEditor, BlocksFeature } from "@payloadcms/richtext-lexical";
|
||||
import { HeadingBlock } from "./HeadingBlock";
|
||||
import { ParagraphBlock } from "./ParagraphBlock";
|
||||
import { ExternalLinkBlock } from "./ExternalLinkBlock";
|
||||
import { TrackedLinkBlock } from "./TrackedLinkBlock";
|
||||
|
||||
export const FAQSectionBlock: MintelBlock = {
|
||||
slug: "faqSection",
|
||||
labels: {
|
||||
singular: "Faq Section",
|
||||
plural: "Faq Sections",
|
||||
},
|
||||
admin: {
|
||||
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: [
|
||||
{
|
||||
name: "content",
|
||||
type: "richText",
|
||||
editor: lexicalEditor({
|
||||
features: ({ defaultFeatures }) => [
|
||||
...defaultFeatures,
|
||||
BlocksFeature({
|
||||
blocks: [
|
||||
HeadingBlock,
|
||||
ParagraphBlock,
|
||||
ExternalLinkBlock,
|
||||
TrackedLinkBlock,
|
||||
].map(({ ai, render, ...b }) => b),
|
||||
}),
|
||||
],
|
||||
}),
|
||||
required: true,
|
||||
admin: { description: "Formatierter Textbereich für content." },
|
||||
},
|
||||
],
|
||||
};
|
||||
24
apps/web/src/payload/blocks/H2Block.ts
Normal file
24
apps/web/src/payload/blocks/H2Block.ts
Normal file
@@ -0,0 +1,24 @@
|
||||
import type { MintelBlock } from "./types";
|
||||
|
||||
export const H2Block: MintelBlock = {
|
||||
slug: "mintelH2",
|
||||
labels: {
|
||||
singular: "Heading 2",
|
||||
plural: "Headings 2",
|
||||
},
|
||||
fields: [
|
||||
{
|
||||
name: "text",
|
||||
type: "text",
|
||||
required: true,
|
||||
admin: {
|
||||
description: "Geben Sie den Text für die H2-Überschrift ein.",
|
||||
components: {
|
||||
afterInput: [
|
||||
"@/src/payload/components/FieldGenerators/AiFieldButton#AiFieldButton",
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
||||
24
apps/web/src/payload/blocks/H3Block.ts
Normal file
24
apps/web/src/payload/blocks/H3Block.ts
Normal file
@@ -0,0 +1,24 @@
|
||||
import type { MintelBlock } from "./types";
|
||||
|
||||
export const H3Block: MintelBlock = {
|
||||
slug: "mintelH3",
|
||||
labels: {
|
||||
singular: "Heading 3",
|
||||
plural: "Headings 3",
|
||||
},
|
||||
fields: [
|
||||
{
|
||||
name: "text",
|
||||
type: "text",
|
||||
required: true,
|
||||
admin: {
|
||||
description: "Geben Sie den Text für die H3-Überschrift ein.",
|
||||
components: {
|
||||
afterInput: [
|
||||
"@/src/payload/components/FieldGenerators/AiFieldButton#AiFieldButton",
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
||||
50
apps/web/src/payload/blocks/HeadingBlock.ts
Normal file
50
apps/web/src/payload/blocks/HeadingBlock.ts
Normal file
@@ -0,0 +1,50 @@
|
||||
import { MintelBlock } from "./types";
|
||||
|
||||
export const HeadingBlock: MintelBlock = {
|
||||
slug: "mintelHeading",
|
||||
labels: {
|
||||
singular: "Heading",
|
||||
plural: "Headings",
|
||||
},
|
||||
admin: {
|
||||
group: "MDX Components",
|
||||
},
|
||||
ai: {
|
||||
name: "Heading",
|
||||
description:
|
||||
"Flexible heading component with separated SEO and visual display levels.",
|
||||
usageExample:
|
||||
'\'<Heading seoLevel="h2" displayLevel="h3">Titel</Heading>\'',
|
||||
},
|
||||
fields: [
|
||||
{
|
||||
name: "text",
|
||||
type: "text",
|
||||
required: true,
|
||||
admin: {
|
||||
description: "Der Text der Überschrift.",
|
||||
components: {
|
||||
afterInput: [
|
||||
"@/src/payload/components/FieldGenerators/AiFieldButton#AiFieldButton",
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "seoLevel",
|
||||
type: "select",
|
||||
options: ["h1", "h2", "h3", "h4", "h5", "h6"],
|
||||
defaultValue: "h2",
|
||||
admin: { description: "Das semantische HTML-Tag für SEO." },
|
||||
},
|
||||
{
|
||||
name: "displayLevel",
|
||||
type: "select",
|
||||
options: ["h1", "h2", "h3", "h4", "h5", "h6"],
|
||||
defaultValue: "h2",
|
||||
admin: {
|
||||
description: "Die visuelle Größe der Überschrift (unabhängig von SEO).",
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
||||
69
apps/web/src/payload/blocks/IconListBlock.ts
Normal file
69
apps/web/src/payload/blocks/IconListBlock.ts
Normal file
@@ -0,0 +1,69 @@
|
||||
import { MintelBlock } from "./types";
|
||||
|
||||
import type { Block } from "payload";
|
||||
|
||||
export const IconListBlock: MintelBlock = {
|
||||
slug: "iconList",
|
||||
labels: {
|
||||
singular: "Icon List",
|
||||
plural: "Icon Lists",
|
||||
},
|
||||
admin: {
|
||||
group: "MDX Components",
|
||||
},
|
||||
ai: {
|
||||
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>`,
|
||||
},
|
||||
fields: [
|
||||
{
|
||||
name: "items",
|
||||
type: "array",
|
||||
fields: [
|
||||
{
|
||||
name: "icon",
|
||||
type: "text",
|
||||
admin: {
|
||||
description: "Lucide icon",
|
||||
components: { Field: "@/src/payload/components/IconSelector" },
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "title",
|
||||
type: "text",
|
||||
required: true,
|
||||
admin: {
|
||||
components: {
|
||||
afterInput: [
|
||||
"@/src/payload/components/FieldGenerators/AiFieldButton#AiFieldButton",
|
||||
],
|
||||
},
|
||||
description: "Geben Sie den Text für title ein.",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "description",
|
||||
type: "textarea",
|
||||
admin: {
|
||||
components: {
|
||||
afterInput: [
|
||||
"@/src/payload/components/FieldGenerators/AiFieldButton#AiFieldButton",
|
||||
],
|
||||
},
|
||||
description: "Geben Sie den mehrzeiligen Text für description ein.",
|
||||
},
|
||||
},
|
||||
],
|
||||
admin: { description: "Fügen Sie Elemente zur Liste items hinzu." },
|
||||
},
|
||||
],
|
||||
};
|
||||
52
apps/web/src/payload/blocks/ImageTextBlock.ts
Normal file
52
apps/web/src/payload/blocks/ImageTextBlock.ts
Normal file
@@ -0,0 +1,52 @@
|
||||
import { MintelBlock } from "./types";
|
||||
|
||||
import type { Block } from "payload";
|
||||
|
||||
export const ImageTextBlock: MintelBlock = {
|
||||
slug: "imageText",
|
||||
labels: {
|
||||
singular: "Image Text",
|
||||
plural: "Image Texts",
|
||||
},
|
||||
admin: {
|
||||
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: [
|
||||
{
|
||||
name: "image",
|
||||
type: "upload",
|
||||
relationTo: "media",
|
||||
required: true,
|
||||
admin: { description: "Laden Sie die Datei für image hoch." },
|
||||
},
|
||||
{
|
||||
name: "text",
|
||||
type: "textarea",
|
||||
required: true,
|
||||
admin: {
|
||||
components: {
|
||||
afterInput: [
|
||||
"@/src/payload/components/FieldGenerators/AiFieldButton#AiFieldButton",
|
||||
],
|
||||
},
|
||||
description: "Geben Sie den mehrzeiligen Text für text ein.",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "alignment",
|
||||
type: "select",
|
||||
options: [
|
||||
{ label: "Left", value: "left" },
|
||||
{ label: "Right", value: "right" },
|
||||
],
|
||||
defaultValue: "left",
|
||||
admin: { description: "Wählen Sie eine Option für alignment aus." },
|
||||
},
|
||||
],
|
||||
};
|
||||
81
apps/web/src/payload/blocks/LeadMagnetBlock.ts
Normal file
81
apps/web/src/payload/blocks/LeadMagnetBlock.ts
Normal file
@@ -0,0 +1,81 @@
|
||||
import { MintelBlock } from "./types";
|
||||
|
||||
import type { Block } from "payload";
|
||||
|
||||
export const LeadMagnetBlock: MintelBlock = {
|
||||
slug: "leadMagnet",
|
||||
labels: {
|
||||
singular: "Lead Magnet CTA",
|
||||
plural: "Lead Magnet CTAs",
|
||||
},
|
||||
admin: {
|
||||
group: "MDX Components",
|
||||
},
|
||||
ai: {
|
||||
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" />\'',
|
||||
},
|
||||
fields: [
|
||||
{
|
||||
name: "title",
|
||||
type: "text",
|
||||
required: true,
|
||||
admin: {
|
||||
description: "The strong headline for the Call-to-Action",
|
||||
components: {
|
||||
afterInput: [
|
||||
"@/src/payload/components/FieldGenerators/AiFieldButton#AiFieldButton",
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "description",
|
||||
type: "text",
|
||||
required: true,
|
||||
admin: {
|
||||
description: "The value proposition text.",
|
||||
components: {
|
||||
afterInput: [
|
||||
"@/src/payload/components/FieldGenerators/AiFieldButton#AiFieldButton",
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "buttonText",
|
||||
type: "text",
|
||||
required: true,
|
||||
defaultValue: "Jetzt anfragen",
|
||||
admin: {
|
||||
components: {
|
||||
afterInput: [
|
||||
"@/src/payload/components/FieldGenerators/AiFieldButton#AiFieldButton",
|
||||
],
|
||||
},
|
||||
description: "Geben Sie den Text für buttonText ein.",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "href",
|
||||
type: "text",
|
||||
required: true,
|
||||
defaultValue: "/contact",
|
||||
admin: { description: "Geben Sie den Text für href ein." },
|
||||
},
|
||||
{
|
||||
name: "variant",
|
||||
type: "select",
|
||||
options: [
|
||||
{ label: "Performance", value: "performance" },
|
||||
{ label: "Security", value: "security" },
|
||||
{ label: "Standard", value: "standard" },
|
||||
],
|
||||
defaultValue: "standard",
|
||||
admin: { description: "Wählen Sie eine Option für variant aus." },
|
||||
},
|
||||
],
|
||||
};
|
||||
36
apps/web/src/payload/blocks/LeadParagraphBlock.ts
Normal file
36
apps/web/src/payload/blocks/LeadParagraphBlock.ts
Normal file
@@ -0,0 +1,36 @@
|
||||
import { MintelBlock } from "./types";
|
||||
|
||||
import type { Block } from "payload";
|
||||
|
||||
export const LeadParagraphBlock: MintelBlock = {
|
||||
slug: "leadParagraph",
|
||||
labels: {
|
||||
singular: "Lead Paragraph",
|
||||
plural: "Lead Paragraphs",
|
||||
},
|
||||
admin: {
|
||||
group: "MDX Components",
|
||||
},
|
||||
ai: {
|
||||
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>'",
|
||||
},
|
||||
fields: [
|
||||
{
|
||||
name: "text",
|
||||
type: "textarea",
|
||||
required: true,
|
||||
admin: {
|
||||
components: {
|
||||
afterInput: [
|
||||
"@/src/payload/components/FieldGenerators/AiFieldButton#AiFieldButton",
|
||||
],
|
||||
},
|
||||
description: "Geben Sie den mehrzeiligen Text für text ein.",
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
||||
29
apps/web/src/payload/blocks/LinkedInEmbedBlock.ts
Normal file
29
apps/web/src/payload/blocks/LinkedInEmbedBlock.ts
Normal file
@@ -0,0 +1,29 @@
|
||||
import { MintelBlock } from "./types";
|
||||
|
||||
import type { Block } from "payload";
|
||||
|
||||
export const LinkedInEmbedBlock: MintelBlock = {
|
||||
slug: "linkedInEmbed",
|
||||
labels: {
|
||||
singular: "Linked In Embed",
|
||||
plural: "Linked In Embeds",
|
||||
},
|
||||
admin: {
|
||||
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: [
|
||||
{
|
||||
name: "url",
|
||||
type: "text",
|
||||
required: true,
|
||||
admin: { description: "Geben Sie den Text für url ein." },
|
||||
},
|
||||
],
|
||||
};
|
||||
31
apps/web/src/payload/blocks/LoadTimeSimulatorBlock.ts
Normal file
31
apps/web/src/payload/blocks/LoadTimeSimulatorBlock.ts
Normal file
@@ -0,0 +1,31 @@
|
||||
import { MintelBlock } from "./types";
|
||||
|
||||
import type { Block } from "payload";
|
||||
|
||||
export const LoadTimeSimulatorBlock: MintelBlock = {
|
||||
slug: "loadTimeSimulator",
|
||||
labels: {
|
||||
singular: "Load Time Simulator",
|
||||
plural: "Load Time Simulators",
|
||||
},
|
||||
admin: {
|
||||
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: [
|
||||
{
|
||||
name: "initialLoadTime",
|
||||
type: "number",
|
||||
defaultValue: 3.5,
|
||||
admin: {
|
||||
description:
|
||||
"Tragen Sie einen numerischen Wert für initialLoadTime ein.",
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
||||
51
apps/web/src/payload/blocks/MarkerBlock.ts
Normal file
51
apps/web/src/payload/blocks/MarkerBlock.ts
Normal file
@@ -0,0 +1,51 @@
|
||||
import { MintelBlock } from "./types";
|
||||
|
||||
import type { Block } from "payload";
|
||||
|
||||
export const MarkerBlock: MintelBlock = {
|
||||
slug: "marker",
|
||||
labels: {
|
||||
singular: "Marker",
|
||||
plural: "Markers",
|
||||
},
|
||||
admin: {
|
||||
group: "MDX Components",
|
||||
},
|
||||
ai: {
|
||||
name: "Marker",
|
||||
description:
|
||||
"Inline highlight (yellow marker effect) for emphasizing key phrases within paragraphs.",
|
||||
usageExample: "'<Marker>entscheidender Wettbewerbsvorteil</Marker>'",
|
||||
},
|
||||
fields: [
|
||||
{
|
||||
name: "text",
|
||||
type: "text",
|
||||
required: true,
|
||||
admin: {
|
||||
components: {
|
||||
afterInput: [
|
||||
"@/src/payload/components/FieldGenerators/AiFieldButton#AiFieldButton",
|
||||
],
|
||||
},
|
||||
description: "Geben Sie den Text für text ein.",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "color",
|
||||
type: "text",
|
||||
admin: {
|
||||
description: "Hex or rgba color",
|
||||
components: { Field: "@/src/payload/components/ColorPicker" },
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "delay",
|
||||
type: "number",
|
||||
defaultValue: 0,
|
||||
admin: {
|
||||
description: "Tragen Sie einen numerischen Wert für delay ein.",
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
||||
51
apps/web/src/payload/blocks/MemeCardBlock.ts
Normal file
51
apps/web/src/payload/blocks/MemeCardBlock.ts
Normal file
@@ -0,0 +1,51 @@
|
||||
import { MintelBlock } from "./types";
|
||||
import type { Block } from "payload";
|
||||
|
||||
export const MemeCardBlock: MintelBlock = {
|
||||
slug: "memeCard",
|
||||
labels: {
|
||||
singular: "Meme Card",
|
||||
plural: "Meme Cards",
|
||||
},
|
||||
admin: {
|
||||
group: "MDX Components",
|
||||
},
|
||||
ai: {
|
||||
name: "MemeCard",
|
||||
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">
|
||||
<MemeCard template="drake" captions="47 WordPress Plugins installieren|Eine saubere Serverless Architektur" />
|
||||
</div>`,
|
||||
},
|
||||
fields: [
|
||||
{
|
||||
name: "template",
|
||||
type: "text",
|
||||
required: true,
|
||||
admin: {
|
||||
description:
|
||||
"The template ID from memegen.link (e.g. 'drake', 'disastergirl')",
|
||||
components: {
|
||||
afterInput: [
|
||||
"@/src/payload/components/FieldGenerators/AiFieldButton#AiFieldButton",
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "captions",
|
||||
type: "textarea",
|
||||
required: true,
|
||||
admin: {
|
||||
description:
|
||||
"Pipe-separated captions for the meme (e.g. 'Legacy Code|Mintel Stack'). Maximum 6 words per line.",
|
||||
components: {
|
||||
afterInput: [
|
||||
"@/src/payload/components/FieldGenerators/AiFieldButton#AiFieldButton",
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
||||
68
apps/web/src/payload/blocks/MermaidBlock.ts
Normal file
68
apps/web/src/payload/blocks/MermaidBlock.ts
Normal file
@@ -0,0 +1,68 @@
|
||||
import { MintelBlock } from "./types";
|
||||
|
||||
import type { Block } from "payload";
|
||||
|
||||
export const MermaidBlock: MintelBlock = {
|
||||
slug: "mermaid",
|
||||
labels: {
|
||||
singular: "Mermaid",
|
||||
plural: "Mermaids",
|
||||
},
|
||||
admin: {
|
||||
group: "MDX Components",
|
||||
},
|
||||
ai: {
|
||||
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`,
|
||||
},
|
||||
fields: [
|
||||
{
|
||||
name: "id",
|
||||
type: "text",
|
||||
required: true,
|
||||
admin: {
|
||||
description:
|
||||
"A unique ASCII ID for the diagram (e.g. 'architecture-1').",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "title",
|
||||
type: "text",
|
||||
required: false,
|
||||
admin: {
|
||||
description: "Optional title displayed above the diagram.",
|
||||
components: {
|
||||
afterInput: [
|
||||
"@/src/payload/components/FieldGenerators/AiFieldButton#AiFieldButton",
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "showShare",
|
||||
type: "checkbox",
|
||||
defaultValue: false,
|
||||
admin: {
|
||||
description: "Show the share button for this diagram?",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "chartDefinition",
|
||||
type: "code",
|
||||
required: true,
|
||||
admin: {
|
||||
language: "markdown",
|
||||
description:
|
||||
"The raw Mermaid.js syntax (e.g. graph TD... shadowing, loops, etc.).",
|
||||
components: {
|
||||
afterInput: [
|
||||
"@/src/payload/components/FieldGenerators/AiFieldButton#AiFieldButton",
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
||||
68
apps/web/src/payload/blocks/MetricBarBlock.ts
Normal file
68
apps/web/src/payload/blocks/MetricBarBlock.ts
Normal file
@@ -0,0 +1,68 @@
|
||||
import { MintelBlock } from "./types";
|
||||
|
||||
import type { Block } from "payload";
|
||||
|
||||
export const MetricBarBlock: MintelBlock = {
|
||||
slug: "metricBar",
|
||||
labels: {
|
||||
singular: "Metric Bar",
|
||||
plural: "Metric Bars",
|
||||
},
|
||||
admin: {
|
||||
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: [
|
||||
{
|
||||
name: "label",
|
||||
type: "text",
|
||||
required: true,
|
||||
admin: {
|
||||
components: {
|
||||
afterInput: [
|
||||
"@/src/payload/components/FieldGenerators/AiFieldButton#AiFieldButton",
|
||||
],
|
||||
},
|
||||
description: "Geben Sie den Text für label ein.",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "value",
|
||||
type: "number",
|
||||
required: true,
|
||||
admin: { description: "Percentage 0-100" },
|
||||
},
|
||||
{
|
||||
name: "max",
|
||||
type: "number",
|
||||
defaultValue: 100,
|
||||
admin: { description: "Tragen Sie einen numerischen Wert für max ein." },
|
||||
},
|
||||
{
|
||||
name: "unit",
|
||||
type: "text",
|
||||
defaultValue: "%",
|
||||
admin: {
|
||||
components: {
|
||||
afterInput: [
|
||||
"@/src/payload/components/FieldGenerators/AiFieldButton#AiFieldButton",
|
||||
],
|
||||
},
|
||||
description: "Geben Sie den Text für unit ein.",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "color",
|
||||
type: "text",
|
||||
admin: {
|
||||
components: { Field: "@/src/payload/components/ColorPicker" },
|
||||
description: "Geben Sie den Text für color ein.",
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
||||
36
apps/web/src/payload/blocks/ParagraphBlock.ts
Normal file
36
apps/web/src/payload/blocks/ParagraphBlock.ts
Normal file
@@ -0,0 +1,36 @@
|
||||
import { MintelBlock } from "./types";
|
||||
|
||||
import type { Block } from "payload";
|
||||
|
||||
export const ParagraphBlock: MintelBlock = {
|
||||
slug: "mintelP",
|
||||
labels: {
|
||||
singular: "Paragraph",
|
||||
plural: "Paragraphs",
|
||||
},
|
||||
admin: {
|
||||
group: "MDX Components",
|
||||
},
|
||||
ai: {
|
||||
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>'",
|
||||
},
|
||||
fields: [
|
||||
{
|
||||
name: "text",
|
||||
type: "textarea",
|
||||
required: true,
|
||||
admin: {
|
||||
components: {
|
||||
afterInput: [
|
||||
"@/src/payload/components/FieldGenerators/AiFieldButton#AiFieldButton",
|
||||
],
|
||||
},
|
||||
description: "Geben Sie den mehrzeiligen Text für text ein.",
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
||||
36
apps/web/src/payload/blocks/PerformanceChartBlock.ts
Normal file
36
apps/web/src/payload/blocks/PerformanceChartBlock.ts
Normal file
@@ -0,0 +1,36 @@
|
||||
import { MintelBlock } from "./types";
|
||||
|
||||
import type { Block } from "payload";
|
||||
|
||||
export const PerformanceChartBlock: MintelBlock = {
|
||||
slug: "performanceChart",
|
||||
labels: {
|
||||
singular: "Performance Chart",
|
||||
plural: "Performance Charts",
|
||||
},
|
||||
admin: {
|
||||
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: [
|
||||
{
|
||||
name: "title",
|
||||
type: "text",
|
||||
defaultValue: "Website Performance",
|
||||
admin: {
|
||||
components: {
|
||||
afterInput: [
|
||||
"@/src/payload/components/FieldGenerators/AiFieldButton#AiFieldButton",
|
||||
],
|
||||
},
|
||||
description: "Geben Sie den Text für title ein.",
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
||||
40
apps/web/src/payload/blocks/PerformanceROICalculatorBlock.ts
Normal file
40
apps/web/src/payload/blocks/PerformanceROICalculatorBlock.ts
Normal file
@@ -0,0 +1,40 @@
|
||||
import { MintelBlock } from "./types";
|
||||
|
||||
import type { Block } from "payload";
|
||||
|
||||
export const PerformanceROICalculatorBlock: MintelBlock = {
|
||||
slug: "performanceROICalculator",
|
||||
labels: {
|
||||
singular: "Performance R O I Calculator",
|
||||
plural: "Performance R O I Calculators",
|
||||
},
|
||||
admin: {
|
||||
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: [
|
||||
{
|
||||
name: "baseConversionRate",
|
||||
type: "number",
|
||||
defaultValue: 2.5,
|
||||
admin: {
|
||||
description:
|
||||
"Tragen Sie einen numerischen Wert für baseConversionRate ein.",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "monthlyVisitors",
|
||||
type: "number",
|
||||
defaultValue: 50000,
|
||||
admin: {
|
||||
description:
|
||||
"Tragen Sie einen numerischen Wert für monthlyVisitors ein.",
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
||||
115
apps/web/src/payload/blocks/PremiumComparisonChartBlock.ts
Normal file
115
apps/web/src/payload/blocks/PremiumComparisonChartBlock.ts
Normal file
@@ -0,0 +1,115 @@
|
||||
import { MintelBlock } from "./types";
|
||||
|
||||
import type { Block } from "payload";
|
||||
|
||||
export const PremiumComparisonChartBlock: MintelBlock = {
|
||||
slug: "premiumComparisonChart",
|
||||
labels: {
|
||||
singular: "Premium Comparison Chart",
|
||||
plural: "Premium Comparison Charts",
|
||||
},
|
||||
admin: {
|
||||
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: [
|
||||
{
|
||||
name: "title",
|
||||
type: "text",
|
||||
admin: {
|
||||
components: {
|
||||
afterInput: [
|
||||
"@/src/payload/components/FieldGenerators/AiFieldButton#AiFieldButton",
|
||||
],
|
||||
},
|
||||
description: "Geben Sie den Text für title ein.",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "subtitle",
|
||||
type: "text",
|
||||
admin: {
|
||||
components: {
|
||||
afterInput: [
|
||||
"@/src/payload/components/FieldGenerators/AiFieldButton#AiFieldButton",
|
||||
],
|
||||
},
|
||||
description: "Geben Sie den Text für subtitle ein.",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "datasets",
|
||||
type: "array",
|
||||
fields: [
|
||||
{
|
||||
name: "label",
|
||||
type: "text",
|
||||
required: true,
|
||||
admin: {
|
||||
components: {
|
||||
afterInput: [
|
||||
"@/src/payload/components/FieldGenerators/AiFieldButton#AiFieldButton",
|
||||
],
|
||||
},
|
||||
description: "Geben Sie den Text für label ein.",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "value",
|
||||
type: "number",
|
||||
required: true,
|
||||
admin: {
|
||||
description: "Tragen Sie einen numerischen Wert für value ein.",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "max",
|
||||
type: "number",
|
||||
defaultValue: 100,
|
||||
admin: {
|
||||
description: "Tragen Sie einen numerischen Wert für max ein.",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "unit",
|
||||
type: "text",
|
||||
admin: {
|
||||
components: {
|
||||
afterInput: [
|
||||
"@/src/payload/components/FieldGenerators/AiFieldButton#AiFieldButton",
|
||||
],
|
||||
},
|
||||
description: "Geben Sie den Text für unit ein.",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "color",
|
||||
type: "text",
|
||||
admin: {
|
||||
components: { Field: "@/src/payload/components/ColorPicker" },
|
||||
description: "Geben Sie den Text für color ein.",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "description",
|
||||
type: "text",
|
||||
admin: {
|
||||
components: {
|
||||
afterInput: [
|
||||
"@/src/payload/components/FieldGenerators/AiFieldButton#AiFieldButton",
|
||||
],
|
||||
},
|
||||
description: "Geben Sie den Text für description ein.",
|
||||
},
|
||||
},
|
||||
],
|
||||
admin: { description: "Fügen Sie Elemente zur Liste datasets hinzu." },
|
||||
},
|
||||
],
|
||||
};
|
||||
51
apps/web/src/payload/blocks/RevealBlock.ts
Normal file
51
apps/web/src/payload/blocks/RevealBlock.ts
Normal file
@@ -0,0 +1,51 @@
|
||||
import { MintelBlock } from "./types";
|
||||
|
||||
import type { Block } from "payload";
|
||||
import { lexicalEditor } from "@payloadcms/richtext-lexical";
|
||||
|
||||
export const RevealBlock: MintelBlock = {
|
||||
slug: "mintelReveal",
|
||||
labels: {
|
||||
singular: "Reveal Wrap",
|
||||
plural: "Reveal Wraps",
|
||||
},
|
||||
admin: {
|
||||
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: [
|
||||
{
|
||||
name: "direction",
|
||||
type: "select",
|
||||
options: [
|
||||
{ label: "Up", value: "up" },
|
||||
{ label: "Down", value: "down" },
|
||||
{ label: "Left", value: "left" },
|
||||
{ label: "Right", value: "right" },
|
||||
],
|
||||
defaultValue: "up",
|
||||
admin: { description: "Wählen Sie eine Option für direction aus." },
|
||||
},
|
||||
{
|
||||
name: "delay",
|
||||
type: "number",
|
||||
defaultValue: 0.1,
|
||||
admin: {
|
||||
description: "Tragen Sie einen numerischen Wert für delay ein.",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "content",
|
||||
type: "richText",
|
||||
editor: lexicalEditor({}),
|
||||
required: true,
|
||||
admin: { description: "Formatierter Textbereich für content." },
|
||||
},
|
||||
],
|
||||
};
|
||||
35
apps/web/src/payload/blocks/RevenueLossCalculatorBlock.ts
Normal file
35
apps/web/src/payload/blocks/RevenueLossCalculatorBlock.ts
Normal file
@@ -0,0 +1,35 @@
|
||||
import { MintelBlock } from "./types";
|
||||
|
||||
import type { Block } from "payload";
|
||||
|
||||
export const RevenueLossCalculatorBlock: MintelBlock = {
|
||||
slug: "revenueLossCalculator",
|
||||
labels: {
|
||||
singular: "Revenue Loss Calculator",
|
||||
plural: "Revenue Loss Calculators",
|
||||
},
|
||||
admin: {
|
||||
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: [
|
||||
{
|
||||
name: "title",
|
||||
type: "text",
|
||||
defaultValue: "Performance Revenue Simulator",
|
||||
admin: {
|
||||
components: {
|
||||
afterInput: [
|
||||
"@/src/payload/components/FieldGenerators/AiFieldButton#AiFieldButton",
|
||||
],
|
||||
},
|
||||
description: "Geben Sie den Text für title ein.",
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
||||
42
apps/web/src/payload/blocks/SectionBlock.ts
Normal file
42
apps/web/src/payload/blocks/SectionBlock.ts
Normal file
@@ -0,0 +1,42 @@
|
||||
import { MintelBlock } from "./types";
|
||||
|
||||
import type { Block } from "payload";
|
||||
import { lexicalEditor } from "@payloadcms/richtext-lexical";
|
||||
|
||||
export const SectionBlock: MintelBlock = {
|
||||
slug: "mintelSection",
|
||||
labels: {
|
||||
singular: "Section Wrap",
|
||||
plural: "Section Wraps",
|
||||
},
|
||||
admin: {
|
||||
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: [
|
||||
{
|
||||
name: "title",
|
||||
type: "text",
|
||||
admin: {
|
||||
components: {
|
||||
afterInput: [
|
||||
"@/src/payload/components/FieldGenerators/AiFieldButton#AiFieldButton",
|
||||
],
|
||||
},
|
||||
description: "Geben Sie den Text für title ein.",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "content",
|
||||
type: "richText",
|
||||
editor: lexicalEditor({}),
|
||||
required: true,
|
||||
admin: { description: "Formatierter Textbereich für content." },
|
||||
},
|
||||
],
|
||||
};
|
||||
60
apps/web/src/payload/blocks/StatsDisplayBlock.ts
Normal file
60
apps/web/src/payload/blocks/StatsDisplayBlock.ts
Normal file
@@ -0,0 +1,60 @@
|
||||
import { MintelBlock } from "./types";
|
||||
|
||||
import type { Block } from "payload";
|
||||
|
||||
export const StatsDisplayBlock: MintelBlock = {
|
||||
slug: "statsDisplay",
|
||||
labels: {
|
||||
singular: "Stats Display",
|
||||
plural: "Stats Displays",
|
||||
},
|
||||
admin: {
|
||||
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: [
|
||||
{
|
||||
name: "label",
|
||||
type: "text",
|
||||
admin: {
|
||||
components: {
|
||||
afterInput: [
|
||||
"@/src/payload/components/FieldGenerators/AiFieldButton#AiFieldButton",
|
||||
],
|
||||
},
|
||||
description: "Geben Sie den Text für label ein.",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "value",
|
||||
type: "text",
|
||||
required: true,
|
||||
admin: {
|
||||
components: {
|
||||
afterInput: [
|
||||
"@/src/payload/components/FieldGenerators/AiFieldButton#AiFieldButton",
|
||||
],
|
||||
},
|
||||
description: "Geben Sie den Text für value ein.",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "subtext",
|
||||
type: "text",
|
||||
admin: {
|
||||
components: {
|
||||
afterInput: [
|
||||
"@/src/payload/components/FieldGenerators/AiFieldButton#AiFieldButton",
|
||||
],
|
||||
},
|
||||
description: "Geben Sie den Text für subtext ein.",
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
||||
56
apps/web/src/payload/blocks/StatsGridBlock.ts
Normal file
56
apps/web/src/payload/blocks/StatsGridBlock.ts
Normal file
@@ -0,0 +1,56 @@
|
||||
import { MintelBlock } from "./types";
|
||||
|
||||
import type { Block } from "payload";
|
||||
|
||||
export const StatsGridBlock: MintelBlock = {
|
||||
slug: "statsGrid",
|
||||
labels: {
|
||||
singular: "Stats Grid",
|
||||
plural: "Stats Grids",
|
||||
},
|
||||
admin: {
|
||||
group: "MDX Components",
|
||||
},
|
||||
ai: {
|
||||
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\" />'",
|
||||
},
|
||||
fields: [
|
||||
{
|
||||
name: "stats",
|
||||
type: "array",
|
||||
fields: [
|
||||
{
|
||||
name: "label",
|
||||
type: "text",
|
||||
required: true,
|
||||
admin: {
|
||||
components: {
|
||||
afterInput: [
|
||||
"@/src/payload/components/FieldGenerators/AiFieldButton#AiFieldButton",
|
||||
],
|
||||
},
|
||||
description: "Geben Sie den Text für label ein.",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "value",
|
||||
type: "text",
|
||||
required: true,
|
||||
admin: {
|
||||
components: {
|
||||
afterInput: [
|
||||
"@/src/payload/components/FieldGenerators/AiFieldButton#AiFieldButton",
|
||||
],
|
||||
},
|
||||
description: "Geben Sie den Text für value ein.",
|
||||
},
|
||||
},
|
||||
],
|
||||
admin: { description: "Fügen Sie Elemente zur Liste stats hinzu." },
|
||||
},
|
||||
],
|
||||
};
|
||||
35
apps/web/src/payload/blocks/TLDRBlock.ts
Normal file
35
apps/web/src/payload/blocks/TLDRBlock.ts
Normal file
@@ -0,0 +1,35 @@
|
||||
import { MintelBlock } from "./types";
|
||||
import type { Block } from "payload";
|
||||
|
||||
export const TLDRBlock: MintelBlock = {
|
||||
slug: "mintelTldr",
|
||||
labels: {
|
||||
singular: "TL;DR Block",
|
||||
plural: "TL;DR Blocks",
|
||||
},
|
||||
admin: {
|
||||
group: "MDX Components",
|
||||
},
|
||||
ai: {
|
||||
name: "TLDR",
|
||||
description:
|
||||
"Presents a bite-sized summary of the article in a premium dark card. Use exactly once at the very beginning.",
|
||||
usageExample:
|
||||
"'<TLDR>\n Stabilität ist kein Zufall, sondern das Ergebnis einer Clean Code Strategie.\n</TLDR>'",
|
||||
},
|
||||
fields: [
|
||||
{
|
||||
name: "content",
|
||||
type: "textarea",
|
||||
required: true,
|
||||
admin: {
|
||||
description: "The summary content for the TLDR box.",
|
||||
components: {
|
||||
afterInput: [
|
||||
"@/src/payload/components/FieldGenerators/AiFieldButton#AiFieldButton",
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
||||
48
apps/web/src/payload/blocks/TrackedLinkBlock.ts
Normal file
48
apps/web/src/payload/blocks/TrackedLinkBlock.ts
Normal file
@@ -0,0 +1,48 @@
|
||||
import { MintelBlock } from "./types";
|
||||
|
||||
import type { Block } from "payload";
|
||||
|
||||
export const TrackedLinkBlock: MintelBlock = {
|
||||
slug: "trackedLink",
|
||||
labels: {
|
||||
singular: "Tracked Link",
|
||||
plural: "Tracked Links",
|
||||
},
|
||||
admin: {
|
||||
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: [
|
||||
{
|
||||
name: "href",
|
||||
type: "text",
|
||||
required: true,
|
||||
admin: { description: "Geben Sie den Text für href ein." },
|
||||
},
|
||||
{
|
||||
name: "label",
|
||||
type: "text",
|
||||
required: true,
|
||||
admin: {
|
||||
components: {
|
||||
afterInput: [
|
||||
"@/src/payload/components/FieldGenerators/AiFieldButton#AiFieldButton",
|
||||
],
|
||||
},
|
||||
description: "Geben Sie den Text für label ein.",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "eventName",
|
||||
type: "text",
|
||||
required: true,
|
||||
admin: { description: "Geben Sie den Text für eventName ein." },
|
||||
},
|
||||
],
|
||||
};
|
||||
29
apps/web/src/payload/blocks/TwitterEmbedBlock.ts
Normal file
29
apps/web/src/payload/blocks/TwitterEmbedBlock.ts
Normal file
@@ -0,0 +1,29 @@
|
||||
import { MintelBlock } from "./types";
|
||||
|
||||
import type { Block } from "payload";
|
||||
|
||||
export const TwitterEmbedBlock: MintelBlock = {
|
||||
slug: "twitterEmbed",
|
||||
labels: {
|
||||
singular: "Twitter (X) Embed",
|
||||
plural: "Twitter (X) Embeds",
|
||||
},
|
||||
admin: {
|
||||
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: [
|
||||
{
|
||||
name: "url",
|
||||
type: "text",
|
||||
required: true,
|
||||
admin: { description: "Geben Sie den Text für url ein." },
|
||||
},
|
||||
],
|
||||
};
|
||||
73
apps/web/src/payload/blocks/WaterfallChartBlock.ts
Normal file
73
apps/web/src/payload/blocks/WaterfallChartBlock.ts
Normal file
@@ -0,0 +1,73 @@
|
||||
import { MintelBlock } from "./types";
|
||||
|
||||
import type { Block } from "payload";
|
||||
|
||||
export const WaterfallChartBlock: MintelBlock = {
|
||||
slug: "waterfallChart",
|
||||
labels: {
|
||||
singular: "Waterfall Chart",
|
||||
plural: "Waterfall Charts",
|
||||
},
|
||||
admin: {
|
||||
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: [
|
||||
{
|
||||
name: "title",
|
||||
type: "text",
|
||||
admin: {
|
||||
components: {
|
||||
afterInput: [
|
||||
"@/src/payload/components/FieldGenerators/AiFieldButton#AiFieldButton",
|
||||
],
|
||||
},
|
||||
description: "Geben Sie den Text für title ein.",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "metrics",
|
||||
type: "array",
|
||||
fields: [
|
||||
{
|
||||
name: "label",
|
||||
type: "text",
|
||||
required: true,
|
||||
admin: {
|
||||
components: {
|
||||
afterInput: [
|
||||
"@/src/payload/components/FieldGenerators/AiFieldButton#AiFieldButton",
|
||||
],
|
||||
},
|
||||
description: "Geben Sie den Text für label ein.",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "duration",
|
||||
type: "number",
|
||||
required: true,
|
||||
admin: {
|
||||
description: "Tragen Sie einen numerischen Wert für duration ein.",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "color",
|
||||
type: "text",
|
||||
admin: {
|
||||
components: { Field: "@/src/payload/components/ColorPicker" },
|
||||
description: "Geben Sie den Text für color ein.",
|
||||
},
|
||||
},
|
||||
],
|
||||
admin: { description: "Fügen Sie Elemente zur Liste metrics hinzu." },
|
||||
},
|
||||
],
|
||||
};
|
||||
52
apps/web/src/payload/blocks/WebVitalsScoreBlock.ts
Normal file
52
apps/web/src/payload/blocks/WebVitalsScoreBlock.ts
Normal file
@@ -0,0 +1,52 @@
|
||||
import { MintelBlock } from "./types";
|
||||
|
||||
import type { Block } from "payload";
|
||||
|
||||
export const WebVitalsScoreBlock: MintelBlock = {
|
||||
slug: "webVitalsScore",
|
||||
labels: {
|
||||
singular: "Web Vitals Score",
|
||||
plural: "Web Vitals Scores",
|
||||
},
|
||||
admin: {
|
||||
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: [
|
||||
{
|
||||
name: "lcp",
|
||||
type: "number",
|
||||
required: true,
|
||||
admin: { description: "Largest Contentful Paint (s)" },
|
||||
},
|
||||
{
|
||||
name: "inp",
|
||||
type: "number",
|
||||
required: true,
|
||||
admin: { description: "Interaction to Next Paint (ms)" },
|
||||
},
|
||||
{
|
||||
name: "cls",
|
||||
type: "number",
|
||||
required: true,
|
||||
admin: { description: "Cumulative Layout Shift" },
|
||||
},
|
||||
{
|
||||
name: "description",
|
||||
type: "text",
|
||||
admin: {
|
||||
components: {
|
||||
afterInput: [
|
||||
"@/src/payload/components/FieldGenerators/AiFieldButton#AiFieldButton",
|
||||
],
|
||||
},
|
||||
description: "Geben Sie den Text für description ein.",
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
||||
41
apps/web/src/payload/blocks/YouTubeEmbedBlock.ts
Normal file
41
apps/web/src/payload/blocks/YouTubeEmbedBlock.ts
Normal file
@@ -0,0 +1,41 @@
|
||||
import { MintelBlock } from "./types";
|
||||
|
||||
import type { Block } from "payload";
|
||||
|
||||
export const YouTubeEmbedBlock: MintelBlock = {
|
||||
slug: "youTubeEmbed",
|
||||
labels: {
|
||||
singular: "You Tube Embed",
|
||||
plural: "You Tube Embeds",
|
||||
},
|
||||
admin: {
|
||||
group: "MDX Components",
|
||||
},
|
||||
ai: {
|
||||
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" />\'',
|
||||
},
|
||||
fields: [
|
||||
{
|
||||
name: "videoId",
|
||||
type: "text",
|
||||
required: true,
|
||||
admin: { description: "Geben Sie den Text für videoId ein." },
|
||||
},
|
||||
{
|
||||
name: "title",
|
||||
type: "text",
|
||||
admin: {
|
||||
components: {
|
||||
afterInput: [
|
||||
"@/src/payload/components/FieldGenerators/AiFieldButton#AiFieldButton",
|
||||
],
|
||||
},
|
||||
description: "Geben Sie den Text für title ein.",
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
||||
104
apps/web/src/payload/blocks/allBlocks.ts
Normal file
104
apps/web/src/payload/blocks/allBlocks.ts
Normal file
@@ -0,0 +1,104 @@
|
||||
import { MintelBlock } from "./types";
|
||||
import { MemeCardBlock } from "./MemeCardBlock";
|
||||
import { MermaidBlock } from "./MermaidBlock";
|
||||
import { LeadMagnetBlock } from "./LeadMagnetBlock";
|
||||
import { ComparisonRowBlock } from "./ComparisonRowBlock";
|
||||
import { LeadParagraphBlock } from "./LeadParagraphBlock";
|
||||
import { ArticleBlockquoteBlock } from "./ArticleBlockquoteBlock";
|
||||
import { FAQSectionBlock } from "./FAQSectionBlock";
|
||||
import { StatsDisplayBlock } from "./StatsDisplayBlock";
|
||||
import { DiagramStateBlock } from "./DiagramStateBlock";
|
||||
import { DiagramTimelineBlock } from "./DiagramTimelineBlock";
|
||||
import { DiagramGanttBlock } from "./DiagramGanttBlock";
|
||||
import { DiagramPieBlock } from "./DiagramPieBlock";
|
||||
import { DiagramSequenceBlock } from "./DiagramSequenceBlock";
|
||||
import { DiagramFlowBlock } from "./DiagramFlowBlock";
|
||||
import { WaterfallChartBlock } from "./WaterfallChartBlock";
|
||||
import { PremiumComparisonChartBlock } from "./PremiumComparisonChartBlock";
|
||||
import { IconListBlock } from "./IconListBlock";
|
||||
import { StatsGridBlock } from "./StatsGridBlock";
|
||||
import { MetricBarBlock } from "./MetricBarBlock";
|
||||
import { CarouselBlock } from "./CarouselBlock";
|
||||
import { ImageTextBlock } from "./ImageTextBlock";
|
||||
import { RevenueLossCalculatorBlock } from "./RevenueLossCalculatorBlock";
|
||||
import { PerformanceChartBlock } from "./PerformanceChartBlock";
|
||||
import { PerformanceROICalculatorBlock } from "./PerformanceROICalculatorBlock";
|
||||
import { LoadTimeSimulatorBlock } from "./LoadTimeSimulatorBlock";
|
||||
import { ArchitectureBuilderBlock } from "./ArchitectureBuilderBlock";
|
||||
import { DigitalAssetVisualizerBlock } from "./DigitalAssetVisualizerBlock";
|
||||
import { TwitterEmbedBlock } from "./TwitterEmbedBlock";
|
||||
import { YouTubeEmbedBlock } from "./YouTubeEmbedBlock";
|
||||
import { LinkedInEmbedBlock } from "./LinkedInEmbedBlock";
|
||||
import { ExternalLinkBlock } from "./ExternalLinkBlock";
|
||||
import { TrackedLinkBlock } from "./TrackedLinkBlock";
|
||||
import { ArticleMemeBlock } from "./ArticleMemeBlock";
|
||||
import { MarkerBlock } from "./MarkerBlock";
|
||||
import { BoldNumberBlock } from "./BoldNumberBlock";
|
||||
import { WebVitalsScoreBlock } from "./WebVitalsScoreBlock";
|
||||
import { ButtonBlock } from "./ButtonBlock";
|
||||
import { ArticleQuoteBlock } from "./ArticleQuoteBlock";
|
||||
import { RevealBlock } from "./RevealBlock";
|
||||
import { SectionBlock } from "./SectionBlock";
|
||||
import { TLDRBlock } from "./TLDRBlock";
|
||||
import { HeadingBlock } from "./HeadingBlock";
|
||||
import { ParagraphBlock } from "./ParagraphBlock";
|
||||
import { H2Block } from "./H2Block";
|
||||
import { H3Block } from "./H3Block";
|
||||
|
||||
export const allBlocks: MintelBlock[] = [
|
||||
TLDRBlock,
|
||||
HeadingBlock,
|
||||
H2Block,
|
||||
H3Block,
|
||||
ParagraphBlock,
|
||||
MemeCardBlock,
|
||||
MermaidBlock,
|
||||
LeadMagnetBlock,
|
||||
ComparisonRowBlock,
|
||||
LeadParagraphBlock,
|
||||
ArticleBlockquoteBlock,
|
||||
FAQSectionBlock,
|
||||
StatsDisplayBlock,
|
||||
DiagramStateBlock,
|
||||
DiagramTimelineBlock,
|
||||
DiagramGanttBlock,
|
||||
DiagramPieBlock,
|
||||
DiagramSequenceBlock,
|
||||
DiagramFlowBlock,
|
||||
WaterfallChartBlock,
|
||||
PremiumComparisonChartBlock,
|
||||
IconListBlock,
|
||||
StatsGridBlock,
|
||||
MetricBarBlock,
|
||||
CarouselBlock,
|
||||
ImageTextBlock,
|
||||
RevenueLossCalculatorBlock,
|
||||
PerformanceChartBlock,
|
||||
PerformanceROICalculatorBlock,
|
||||
LoadTimeSimulatorBlock,
|
||||
ArchitectureBuilderBlock,
|
||||
DigitalAssetVisualizerBlock,
|
||||
TwitterEmbedBlock,
|
||||
YouTubeEmbedBlock,
|
||||
LinkedInEmbedBlock,
|
||||
ExternalLinkBlock,
|
||||
TrackedLinkBlock,
|
||||
ArticleMemeBlock,
|
||||
MarkerBlock,
|
||||
BoldNumberBlock,
|
||||
WebVitalsScoreBlock,
|
||||
ButtonBlock,
|
||||
ArticleQuoteBlock,
|
||||
RevealBlock,
|
||||
SectionBlock,
|
||||
];
|
||||
|
||||
/**
|
||||
* Payload 3.x silently drops blocks containing unknown properties.
|
||||
* We strip `ai` and `render` so Payload gets clean Block objects.
|
||||
*/
|
||||
export const payloadBlocks = allBlocks.map(({ ai, render, ...block }) => block);
|
||||
|
||||
export const allComponentDefinitions = allBlocks
|
||||
.filter((block) => !!block.ai)
|
||||
.map((block) => block.ai!);
|
||||
45
apps/web/src/payload/blocks/index.ts
Normal file
45
apps/web/src/payload/blocks/index.ts
Normal file
@@ -0,0 +1,45 @@
|
||||
export * from "./ArchitectureBuilderBlock";
|
||||
export * from "./ArticleBlockquoteBlock";
|
||||
export * from "./ArticleMemeBlock";
|
||||
export * from "./ArticleQuoteBlock";
|
||||
export * from "./BoldNumberBlock";
|
||||
export * from "./ButtonBlock";
|
||||
export * from "./CarouselBlock";
|
||||
export * from "./ComparisonRowBlock";
|
||||
export * from "./DiagramFlowBlock";
|
||||
export * from "./DiagramGanttBlock";
|
||||
export * from "./DiagramPieBlock";
|
||||
export * from "./DiagramSequenceBlock";
|
||||
export * from "./DiagramStateBlock";
|
||||
export * from "./DiagramTimelineBlock";
|
||||
export * from "./DigitalAssetVisualizerBlock";
|
||||
export * from "./ExternalLinkBlock";
|
||||
export * from "./FAQSectionBlock";
|
||||
export * from "./IconListBlock";
|
||||
export * from "./ImageTextBlock";
|
||||
export * from "./LeadMagnetBlock";
|
||||
export * from "./LeadParagraphBlock";
|
||||
export * from "./LinkedInEmbedBlock";
|
||||
export * from "./LoadTimeSimulatorBlock";
|
||||
export * from "./MarkerBlock";
|
||||
export * from "./MemeCardBlock";
|
||||
export * from "./MermaidBlock";
|
||||
export * from "./MetricBarBlock";
|
||||
export * from "./PerformanceChartBlock";
|
||||
export * from "./PerformanceROICalculatorBlock";
|
||||
export * from "./PremiumComparisonChartBlock";
|
||||
export * from "./RevealBlock";
|
||||
export * from "./RevenueLossCalculatorBlock";
|
||||
export * from "./SectionBlock";
|
||||
export * from "./StatsDisplayBlock";
|
||||
export * from "./StatsGridBlock";
|
||||
export * from "./TrackedLinkBlock";
|
||||
export * from "./TwitterEmbedBlock";
|
||||
export * from "./WaterfallChartBlock";
|
||||
export * from "./WebVitalsScoreBlock";
|
||||
export * from "./YouTubeEmbedBlock";
|
||||
export * from "./HeadingBlock";
|
||||
export * from "./H2Block";
|
||||
export * from "./H3Block";
|
||||
export * from "./ParagraphBlock";
|
||||
export * from "./TLDRBlock";
|
||||
8
apps/web/src/payload/blocks/types.ts
Normal file
8
apps/web/src/payload/blocks/types.ts
Normal file
@@ -0,0 +1,8 @@
|
||||
import type { Block } from "payload";
|
||||
import type { ComponentDefinition } from "@mintel/content-engine";
|
||||
import type { ComponentType } from "react";
|
||||
|
||||
export type MintelBlock = Block & {
|
||||
ai?: ComponentDefinition;
|
||||
render?: ComponentType<any>;
|
||||
};
|
||||
Reference in New Issue
Block a user