diff --git a/src/app/(landing)/[locale]/page.tsx b/src/app/(landing)/[locale]/page.tsx
index e5ddd309..a3f4f9b4 100644
--- a/src/app/(landing)/[locale]/page.tsx
+++ b/src/app/(landing)/[locale]/page.tsx
@@ -1,13 +1,6 @@
+import { DeploymentImage } from "@/components/DeploymentImage"
+import { PageBlocks } from "@/components/PageBlockRenderer"
import { LandingContainer } from "@/components/ui/LandingContainer"
-import { HeroSection } from "@/components/sections/HeroSection"
-import { BrandSection } from "@/components/sections/BrandSection"
-import { UseCaseSection } from "@/components/sections/UseCaseSection"
-import { AppFeatureSection } from "@/components/sections/AppFeatureSection"
-import { DeploymentSection } from "@/components/sections/DeploymentSection"
-import { RuntimeFeatureSection } from "@/components/sections/RuntimeFeatureSection"
-import { RoadmapSection } from "@/components/sections/RoadmapSection"
-import { FaqSection } from "@/components/sections/FaqSection"
-import { CtaSection } from "@/components/sections/CtaSection"
import { getLandingPage } from "@/lib/cms"
import type { DeploymentLayoutBlock, HeroLayoutBlock } from "@/lib/cms"
import type { BrandLayoutBlock } from "@/lib/cms"
@@ -26,38 +19,22 @@ export async function generateMetadata({ params }: { params: Promise<{ locale: s
export default async function Page({ params }: { params: Promise<{ locale: string }> }) {
const { locale } = await params
- if (!isSupportedLocale(locale)) {
- notFound()
- }
+ if (!isSupportedLocale(locale)) notFound()
const page = await getLandingPage("main", locale)
- const layout = page?.layout ?? []
- const heroBlock = layout.find((block): block is HeroLayoutBlock => block.blockType === "hero") ?? null
- const brandBlock = layout.find((block): block is BrandLayoutBlock => block.blockType === "brand") ?? null
- const useCaseBlock = layout.find((block): block is UseCaseLayoutBlock => block.blockType === "usecase") ?? null
- const faqBlock = layout.find((block): block is FaqLayoutBlock => block.blockType === "faq") ?? null
- const ctaBlock = layout.find((block): block is CtaLayoutBlock => block.blockType === "cta") ?? null
- const deploymentBlock = layout.find((block): block is DeploymentLayoutBlock => block.blockType === "deployment") ?? null
return (
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+ ,
+ ,
+ ,
+ ]}
+ />
)
}
diff --git a/src/blocks/BentoBlock.ts b/src/blocks/BentoBlock.ts
new file mode 100644
index 00000000..2f6d8382
--- /dev/null
+++ b/src/blocks/BentoBlock.ts
@@ -0,0 +1,66 @@
+import type { Block } from "payload"
+
+export const BentoBlock: Block = {
+ slug: "bento",
+ labels: {
+ singular: "Bento",
+ plural: "Bento Blocks",
+ },
+ fields: [
+ {
+ type: "collapsible",
+ label: "Section",
+ fields: [
+ {
+ name: "sectionHeading",
+ label: "Section Heading",
+ type: "text",
+ required: false,
+ localized: true,
+ },
+ {
+ name: "sectionDescription",
+ label: "Section Description",
+ type: "textarea",
+ required: false,
+ localized: true,
+ },
+ {
+ name: "sectionLinkButton",
+ label: "Section Link Button",
+ type: "group",
+ fields: [
+ {
+ name: "label",
+ type: "text",
+ required: false,
+ localized: true,
+ },
+ {
+ name: "url",
+ type: "text",
+ required: false,
+ },
+ ],
+ },
+ ],
+ },
+ {
+ name: "variant",
+ label: "Variant",
+ type: "select",
+ required: true,
+ defaultValue: "feature",
+ options: [
+ {
+ label: "Feature",
+ value: "feature",
+ },
+ {
+ label: "Runtime",
+ value: "runtime",
+ },
+ ],
+ },
+ ],
+}
diff --git a/src/blocks/CardRowBlock.ts b/src/blocks/CardRowBlock.ts
new file mode 100644
index 00000000..768c75f9
--- /dev/null
+++ b/src/blocks/CardRowBlock.ts
@@ -0,0 +1,92 @@
+import type { Block } from "payload"
+
+export const CardRowBlock: Block = {
+ slug: "cardRow",
+ labels: {
+ singular: "Card Row",
+ plural: "Card Rows",
+ },
+ fields: [
+ {
+ type: "collapsible",
+ label: "Section",
+ fields: [
+ {
+ name: "sectionHeading",
+ label: "Section Heading",
+ type: "text",
+ required: false,
+ localized: true,
+ },
+ {
+ name: "sectionDescription",
+ label: "Section Description",
+ type: "textarea",
+ required: false,
+ localized: true,
+ },
+ {
+ name: "sectionLinkButton",
+ label: "Section Link Button",
+ type: "group",
+ fields: [
+ {
+ name: "label",
+ type: "text",
+ required: false,
+ localized: true,
+ },
+ {
+ name: "url",
+ type: "text",
+ required: false,
+ },
+ ],
+ },
+ ],
+ },
+ {
+ name: "cards",
+ label: "Cards",
+ type: "array",
+ required: false,
+ fields: [
+ {
+ name: "title",
+ type: "text",
+ required: true,
+ localized: true,
+ },
+ {
+ name: "description",
+ type: "textarea",
+ required: false,
+ localized: true,
+ },
+ {
+ name: "link",
+ type: "group",
+ fields: [
+ {
+ name: "label",
+ type: "text",
+ required: false,
+ localized: true,
+ },
+ {
+ name: "url",
+ type: "text",
+ required: false,
+ },
+ ],
+ },
+ {
+ name: "image",
+ type: "upload",
+ relationTo: "media",
+ required: false,
+ },
+ ],
+ },
+ ],
+}
diff --git a/src/blocks/DeploymentBlock.ts b/src/blocks/DeploymentBlock.ts
deleted file mode 100644
index e7412e0d..00000000
--- a/src/blocks/DeploymentBlock.ts
+++ /dev/null
@@ -1,101 +0,0 @@
-import type { Block } from "payload"
-
-export const DeploymentBlock: Block = {
- slug: "deployment",
- labels: {
- singular: "Deployment",
- plural: "Deployment Blocks",
- },
- fields: [
- {
- name: "cloudTitle",
- type: "text",
- required: false,
- localized: true,
- },
- {
- name: "cloudDescription",
- type: "textarea",
- required: false,
- localized: true,
- },
- {
- name: "cloudLink",
- label: "Cloud Link",
- type: "group",
- fields: [
- {
- name: "label",
- type: "text",
- required: false,
- localized: true,
- },
- {
- name: "url",
- type: "text",
- required: false,
- },
- ],
- },
- {
- name: "selfhostTitle",
- type: "text",
- required: false,
- localized: true,
- },
- {
- name: "selfhostDescription",
- type: "textarea",
- required: false,
- localized: true,
- },
- {
- name: "selfhostLink",
- label: "Selfhost Link",
- type: "group",
- fields: [
- {
- name: "label",
- type: "text",
- required: false,
- localized: true,
- },
- {
- name: "url",
- type: "text",
- required: false,
- },
- ],
- },
- {
- name: "dynamicTitle",
- type: "text",
- required: false,
- localized: true,
- },
- {
- name: "dynamicDescription",
- type: "textarea",
- required: false,
- localized: true,
- },
- {
- name: "dynamicLink",
- label: "Dynamic Link",
- type: "group",
- fields: [
- {
- name: "label",
- type: "text",
- required: false,
- localized: true,
- },
- {
- name: "url",
- type: "text",
- required: false,
- },
- ],
- },
- ],
-}
diff --git a/src/blocks/EditionHeroBlock.ts b/src/blocks/EditionHeroBlock.ts
deleted file mode 100644
index 4bbafaca..00000000
--- a/src/blocks/EditionHeroBlock.ts
+++ /dev/null
@@ -1,81 +0,0 @@
-import type { Block } from "payload"
-
-export const EditionHeroBlock: Block = {
- slug: "editionHero",
- labels: {
- singular: "Edition Hero",
- plural: "Edition Hero Blocks",
- },
- fields: [
- {
- name: "heading",
- type: "text",
- required: true,
- localized: true,
- },
- {
- name: "texts",
- label: "Texts",
- type: "array",
- required: false,
- fields: [
- {
- name: "text",
- type: "text",
- required: true,
- localized: true,
- },
- ],
- },
- {
- name: "buttons",
- label: "Buttons",
- type: "array",
- required: false,
- maxRows: 3,
- fields: [
- {
- name: "label",
- type: "text",
- required: true,
- localized: true,
- },
- {
- name: "url",
- type: "text",
- required: true,
- },
- {
- name: "variant",
- type: "select",
- required: false,
- defaultValue: "normal",
- options: [
- {
- label: "None",
- value: "none",
- },
- {
- label: "Normal",
- value: "normal",
- },
- {
- label: "Outlined",
- value: "outlined",
- },
- {
- label: "Filled",
- value: "filled",
- },
- ],
- },
- ],
- },
- {
- name: "imageAlt",
- type: "text",
- required: true,
- localized: true,
- },
- ],
-}
diff --git a/src/blocks/FaqBlock.ts b/src/blocks/FaqBlock.ts
index d2100f3d..8a0d0e0c 100644
--- a/src/blocks/FaqBlock.ts
+++ b/src/blocks/FaqBlock.ts
@@ -7,6 +7,44 @@ export const FaqBlock: Block = {
plural: "FAQ Blocks",
},
fields: [
+ {
+ type: "collapsible",
+ label: "Section",
+ fields: [
+ {
+ name: "sectionHeading",
+ label: "Section Heading",
+ type: "text",
+ required: false,
+ localized: true,
+ },
+ {
+ name: "sectionDescription",
+ label: "Section Description",
+ type: "textarea",
+ required: false,
+ localized: true,
+ },
+ {
+ name: "sectionLinkButton",
+ label: "Section Link Button",
+ type: "group",
+ fields: [
+ {
+ name: "label",
+ type: "text",
+ required: false,
+ localized: true,
+ },
+ {
+ name: "url",
+ type: "text",
+ required: false,
+ },
+ ],
+ },
+ ],
+ },
{
name: "items",
label: "FAQ Items",
diff --git a/src/blocks/HeroBlock.ts b/src/blocks/HeroBlock.ts
index 485b444b..9e57e7e9 100644
--- a/src/blocks/HeroBlock.ts
+++ b/src/blocks/HeroBlock.ts
@@ -24,6 +24,39 @@ export const HeroBlock: Block = {
required: true,
localized: true,
},
+ {
+ name: "centered",
+ label: "Centered layout",
+ type: "checkbox",
+ defaultValue: false,
+ },
+ {
+ name: "grainientColors",
+ label: "Grainient Colors",
+ type: "group",
+ fields: [
+ {
+ name: "color1",
+ type: "text",
+ required: false,
+ },
+ {
+ name: "color2",
+ type: "text",
+ required: false,
+ },
+ {
+ name: "color3",
+ type: "text",
+ required: false,
+ },
+ {
+ name: "backgroundColor",
+ type: "text",
+ required: false,
+ },
+ ],
+ },
{
name: "texts",
label: "Texts",
diff --git a/src/blocks/EditionInstallBlock.ts b/src/blocks/InstallBlock.ts
similarity index 78%
rename from src/blocks/EditionInstallBlock.ts
rename to src/blocks/InstallBlock.ts
index df76cce3..7a2bc955 100644
--- a/src/blocks/EditionInstallBlock.ts
+++ b/src/blocks/InstallBlock.ts
@@ -1,10 +1,10 @@
import type { Block } from "payload"
-export const EditionInstallBlock: Block = {
- slug: "editionInstall",
+export const InstallBlock: Block = {
+ slug: "install",
labels: {
- singular: "Edition Install",
- plural: "Edition Install Blocks",
+ singular: "Install",
+ plural: "Install Blocks",
},
fields: [
{
diff --git a/src/blocks/EditionFeaturesBlock.ts b/src/blocks/OffsetCardsBlock.ts
similarity index 55%
rename from src/blocks/EditionFeaturesBlock.ts
rename to src/blocks/OffsetCardsBlock.ts
index 85332192..2bda514c 100644
--- a/src/blocks/EditionFeaturesBlock.ts
+++ b/src/blocks/OffsetCardsBlock.ts
@@ -1,15 +1,53 @@
import type { Block } from "payload"
-export const EditionFeaturesBlock: Block = {
- slug: "editionFeatures",
+export const OffsetCardsBlock: Block = {
+ slug: "offsetCards",
labels: {
- singular: "Edition Feature",
- plural: "Edition Feature Blocks",
+ singular: "Offset Cards",
+ plural: "Offset Cards Blocks",
},
fields: [
{
- name: "features",
- label: "Features",
+ type: "collapsible",
+ label: "Section",
+ fields: [
+ {
+ name: "sectionHeading",
+ label: "Section Heading",
+ type: "text",
+ required: false,
+ localized: true,
+ },
+ {
+ name: "sectionDescription",
+ label: "Section Description",
+ type: "textarea",
+ required: false,
+ localized: true,
+ },
+ {
+ name: "sectionLinkButton",
+ label: "Section Link Button",
+ type: "group",
+ fields: [
+ {
+ name: "label",
+ type: "text",
+ required: false,
+ localized: true,
+ },
+ {
+ name: "url",
+ type: "text",
+ required: false,
+ },
+ ],
+ },
+ ],
+ },
+ {
+ name: "cards",
+ label: "Cards",
type: "array",
required: true,
fields: [
diff --git a/src/blocks/UseCaseBlock.ts b/src/blocks/RoadmapBlock.ts
similarity index 64%
rename from src/blocks/UseCaseBlock.ts
rename to src/blocks/RoadmapBlock.ts
index 6f187f56..0f6129cf 100644
--- a/src/blocks/UseCaseBlock.ts
+++ b/src/blocks/RoadmapBlock.ts
@@ -1,54 +1,33 @@
import type { Block } from "payload"
-export const UseCaseBlock: Block = {
- slug: "usecase",
+export const RoadmapBlock: Block = {
+ slug: "roadmap",
labels: {
- singular: "Use Case",
- plural: "Use Case Blocks",
+ singular: "Roadmap",
+ plural: "Roadmap Blocks",
},
fields: [
{
- name: "useCases",
- label: "Use Cases",
- type: "array",
- required: true,
+ type: "collapsible",
+ label: "Section",
fields: [
{
- name: "label",
+ name: "sectionHeading",
+ label: "Section Heading",
type: "text",
- required: true,
- localized: true,
- },
- {
- name: "title",
- type: "text",
- required: true,
+ required: false,
localized: true,
},
{
- name: "description",
+ name: "sectionDescription",
+ label: "Section Description",
type: "textarea",
- required: true,
- localized: true,
- },
- {
- name: "image",
- label: "Image",
- type: "upload",
- relationTo: "media",
- required: false,
- },
- {
- name: "bulletPoints",
- label: "Bullet Points",
- type: "text",
required: false,
- hasMany: true,
localized: true,
},
{
- name: "link",
- label: "Link",
+ name: "sectionLinkButton",
+ label: "Section Link Button",
type: "group",
fields: [
{
@@ -66,5 +45,31 @@ export const UseCaseBlock: Block = {
},
],
},
+ {
+ name: "items",
+ label: "Items",
+ type: "array",
+ required: true,
+ fields: [
+ {
+ name: "time",
+ type: "text",
+ required: true,
+ localized: true,
+ },
+ {
+ name: "title",
+ type: "text",
+ required: true,
+ localized: true,
+ },
+ {
+ name: "description",
+ type: "text",
+ required: true,
+ localized: true,
+ },
+ ],
+ },
],
}
diff --git a/src/blocks/ScrollCardBlock.ts b/src/blocks/ScrollCardBlock.ts
new file mode 100644
index 00000000..1270e38b
--- /dev/null
+++ b/src/blocks/ScrollCardBlock.ts
@@ -0,0 +1,145 @@
+import type { Block } from "payload"
+
+export const ScrollCardBlock: Block = {
+ slug: "scrollCards",
+ labels: {
+ singular: "Scroll Cards",
+ plural: "Scroll Cards Blocks",
+ },
+ fields: [
+ {
+ name: "items",
+ label: "Items",
+ type: "array",
+ required: true,
+ fields: [
+ {
+ name: "title",
+ type: "text",
+ required: true,
+ localized: true,
+ },
+ {
+ name: "description",
+ type: "textarea",
+ required: true,
+ localized: true,
+ },
+ {
+ name: "showImageBorder",
+ label: "Show Image Border",
+ type: "checkbox",
+ defaultValue: true,
+ },
+ {
+ name: "sectionLayout",
+ label: "Section Layout",
+ type: "select",
+ required: true,
+ defaultValue: "imageRight",
+ options: [
+ {
+ label: "Image right",
+ value: "imageRight",
+ },
+ {
+ label: "Image left",
+ value: "imageLeft",
+ },
+ ],
+ },
+ {
+ name: "gradient",
+ label: "Gradient",
+ type: "select",
+ required: false,
+ defaultValue: "blue",
+ options: [
+ {
+ label: "Blue",
+ value: "blue",
+ },
+ {
+ label: "Yellow",
+ value: "yellow",
+ },
+ {
+ label: "Pink",
+ value: "pink",
+ },
+ {
+ label: "Aqua",
+ value: "aqua",
+ },
+ {
+ label: "Brand",
+ value: "brand",
+ },
+ {
+ label: "Neutral",
+ value: "neutral",
+ },
+ ],
+ },
+ {
+ name: "gradientDirection",
+ label: "Gradient Direction",
+ type: "select",
+ required: false,
+ defaultValue: "topLeft",
+ options: [
+ {
+ label: "Top left",
+ value: "topLeft",
+ },
+ {
+ label: "Top right",
+ value: "topRight",
+ },
+ {
+ label: "Bottom left",
+ value: "bottomLeft",
+ },
+ {
+ label: "Bottom right",
+ value: "bottomRight",
+ },
+ ],
+ },
+ {
+ name: "bulletPoints",
+ label: "Bullet Points",
+ type: "text",
+ required: false,
+ hasMany: true,
+ localized: true,
+ },
+ {
+ name: "image",
+ label: "Image",
+ type: "upload",
+ relationTo: "media",
+ required: false,
+ },
+ {
+ name: "link",
+ label: "Link",
+ type: "group",
+ fields: [
+ {
+ name: "label",
+ type: "text",
+ required: false,
+ localized: true,
+ },
+ {
+ name: "url",
+ type: "text",
+ required: false,
+ },
+ ],
+ },
+ ],
+ },
+ ],
+}
diff --git a/src/blocks/EditionUseCaseBlock.ts b/src/blocks/SwipeCardBlock.ts
similarity index 67%
rename from src/blocks/EditionUseCaseBlock.ts
rename to src/blocks/SwipeCardBlock.ts
index b9d7514e..9d4fdb88 100644
--- a/src/blocks/EditionUseCaseBlock.ts
+++ b/src/blocks/SwipeCardBlock.ts
@@ -1,27 +1,27 @@
import type { Block } from "payload"
-export const EditionUseCaseBlock: Block = {
- slug: "editionUseCases",
+export const SwipeCardBlock: Block = {
+ slug: "swipeCards",
labels: {
- singular: "Edition UseCases",
- plural: "Edition UseCase Blocks",
+ singular: "Swipe Cards",
+ plural: "Swipe Cards Blocks",
},
- fields: [
- {
- name: "heading",
- type: "text",
- required: true,
- localized: true,
- },
- {
- name: "subheading",
- type: "textarea",
- required: true,
- localized: true,
- },
+ fields: [
+ {
+ name: "heading",
+ type: "text",
+ required: false,
+ localized: true,
+ },
+ {
+ name: "subheading",
+ type: "textarea",
+ required: false,
+ localized: true,
+ },
{
- name: "useCases",
- label: "UseCases",
+ name: "cards",
+ label: "Cards",
type: "array",
required: true,
fields: [
diff --git a/src/collections/pages.ts b/src/collections/pages.ts
index 17f4bd0f..b0ec96ba 100644
--- a/src/collections/pages.ts
+++ b/src/collections/pages.ts
@@ -1,18 +1,19 @@
import { ActionBlock } from "@/blocks/ActionBlock"
-import { EditionUseCaseBlock } from "@/blocks/EditionUseCaseBlock"
+import { SwipeCardBlock } from "@/blocks/SwipeCardBlock"
import { BlogBlock } from "../blocks/BlogBlock"
import { BrandBlock } from "../blocks/BrandBlock"
+import { CardRowBlock } from "../blocks/CardRowBlock"
import { ContactBlock } from "../blocks/ContactBlock"
import { CtaBlock } from "../blocks/CtaBlock"
-import { DeploymentBlock } from "../blocks/DeploymentBlock"
-import { EditionFeaturesBlock } from "../blocks/EditionFeaturesBlock"
-import { EditionHeroBlock } from "../blocks/EditionHeroBlock"
-import { EditionInstallBlock } from "../blocks/EditionInstallBlock"
import { FaqBlock } from "../blocks/FaqBlock"
+import { BentoBlock } from "../blocks/BentoBlock"
import { HeroBlock } from "../blocks/HeroBlock"
+import { InstallBlock } from "../blocks/InstallBlock"
import { JobsBlock } from "../blocks/JobsBlock"
import { MarkdownBlock } from "../blocks/MarkdownBlock"
-import { UseCaseBlock } from "../blocks/UseCaseBlock"
+import { OffsetCardsBlock } from "../blocks/OffsetCardsBlock"
+import { RoadmapBlock } from "../blocks/RoadmapBlock"
+import { ScrollCardBlock } from "../blocks/ScrollCardBlock"
import type { CollectionConfig } from "payload"
export const Pages: CollectionConfig = {
@@ -60,7 +61,7 @@ export const Pages: CollectionConfig = {
name: "layout",
label: "Layout",
type: "blocks",
- blocks: [HeroBlock, EditionHeroBlock, EditionFeaturesBlock, EditionInstallBlock, EditionUseCaseBlock, BrandBlock, UseCaseBlock, FaqBlock, CtaBlock, JobsBlock, BlogBlock, ActionBlock, MarkdownBlock, ContactBlock, DeploymentBlock],
+ blocks: [HeroBlock, BentoBlock, OffsetCardsBlock, InstallBlock, SwipeCardBlock, BrandBlock, FaqBlock, CtaBlock, JobsBlock, BlogBlock, ActionBlock, MarkdownBlock, ContactBlock, CardRowBlock, RoadmapBlock, ScrollCardBlock],
required: false,
localized: true,
},
diff --git a/src/collections/roadmapItems.ts b/src/collections/roadmapItems.ts
deleted file mode 100644
index d64262e0..00000000
--- a/src/collections/roadmapItems.ts
+++ /dev/null
@@ -1,35 +0,0 @@
-import type { CollectionConfig } from "payload"
-
-export const RoadmapItems: CollectionConfig = {
- slug: "roadmapItems",
- admin: {
- useAsTitle: "title",
- defaultColumns: ["time", "title", "updatedAt"],
- },
- access: {
- read: () => true,
- create: ({ req }) => Boolean(req.user),
- update: ({ req }) => Boolean(req.user),
- delete: ({ req }) => Boolean(req.user),
- },
- fields: [
- {
- name: "time",
- type: "text",
- required: true,
- localized: true,
- },
- {
- name: "title",
- type: "text",
- required: true,
- localized: true,
- },
- {
- name: "description",
- type: "text",
- required: true,
- localized: true,
- },
- ],
-}
diff --git a/src/collections/sections.ts b/src/collections/sections.ts
deleted file mode 100644
index e7c26cf2..00000000
--- a/src/collections/sections.ts
+++ /dev/null
@@ -1,72 +0,0 @@
-import { CollectionConfig } from 'payload'
-
-export const Sections: CollectionConfig = {
- slug: 'sections',
- admin: {
- useAsTitle: 'heading',
- },
- fields: [
- {
- name: 'heading',
- type: 'text',
- required: true,
- localized: true,
- },
- {
- name: 'subheading',
- type: 'text',
- required: false,
- localized: true,
- },
- {
- name: 'sectionType',
- label: 'Section Type',
- type: 'select',
- required: true,
- options: [
- {
- label: 'AppFeatureSection',
- value: 'AppFeatureSection',
- },
- {
- label: 'FaqSection',
- value: 'FaqSection',
- },
- {
- label: 'RoadmapSection',
- value: 'RoadmapSection',
- },
- {
- label: 'RuntimeFeatureSection',
- value: 'RuntimeFeatureSection',
- },
- {
- label: 'UseCaseSection',
- value: 'UseCaseSection',
- },
- {
- label: 'DeploymentSection',
- value: 'DeploymentSection',
- },
- ],
- },
- {
- name: 'link_button',
- label: 'Link Button',
- type: 'group',
- fields: [
- {
- name: 'label',
- type: 'text',
- required: false,
- localized: true,
- },
- {
- name: 'url',
- type: 'text',
- required: false,
- },
- ],
- },
- ],
-}
diff --git a/src/components/PageBlockRenderer.tsx b/src/components/PageBlockRenderer.tsx
new file mode 100644
index 00000000..94b11f27
--- /dev/null
+++ b/src/components/PageBlockRenderer.tsx
@@ -0,0 +1,67 @@
+import { BrandSection } from "@/components/sections/BrandSection"
+import { CardRowSection } from "@/components/sections/CardRowSection"
+import { CtaSection } from "@/components/sections/CtaSection"
+import { FaqSection } from "@/components/sections/FaqSection"
+import { BentoSection } from "@/components/sections/BentoSection"
+import { HeroSection } from "@/components/sections/HeroSection"
+import { InstallSection } from "@/components/sections/InstallSection"
+import { OffsetCardsSection } from "@/components/sections/OffsetCardsSection"
+import { RoadmapSection } from "@/components/sections/RoadmapSection"
+import { ScrollCardSection } from "@/components/sections/ScrollCardSection"
+import { SwipeCardSection } from "@/components/sections/SwipeCardSection"
+import type { AppLocale } from "@/lib/i18n"
+import type { Page } from "@/payload-types"
+import React, { type ReactNode } from "react"
+
+type PageBlock = NonNullable
[number]
+
+interface PageBlocksRendererProps {
+ blocks?: PageBlock[] | null
+ cardRowChildren?: ReactNode
+ ctaFloating?: boolean
+ locale?: AppLocale
+}
+
+function renderPageBlock(block: PageBlock, options: Pick) {
+ switch (block.blockType) {
+ case "hero":
+ return
+ case "bento":
+ return
+ case "brand":
+ return
+ case "offsetCards":
+ return
+ case "cardRow":
+ return {options.cardRowChildren}
+ case "faq":
+ return
+ case "cta":
+ return
+ case "install":
+ return
+ case "roadmap":
+ return
+ case "scrollCards":
+ return
+ case "swipeCards":
+ return
+ default:
+ return null
+ }
+}
+
+export function PageBlocks({ blocks, cardRowChildren, ctaFloating = false, locale }: PageBlocksRendererProps) {
+ const renderableBlocks = blocks?.filter((block) => renderPageBlock(block, { cardRowChildren, ctaFloating, locale }) !== null) ?? []
+
+ return (
+ <>
+ {renderableBlocks.map((block, index) => (
+
+ {index > 0 && }
+ {renderPageBlock(block, { cardRowChildren, ctaFloating, locale })}
+
+ ))}
+ >
+ )
+}
diff --git a/src/components/bentos/FeatureBento.tsx b/src/components/bentos/FeatureBento.tsx
new file mode 100644
index 00000000..72d67b92
--- /dev/null
+++ b/src/components/bentos/FeatureBento.tsx
@@ -0,0 +1,21 @@
+import { type AppLocale } from "@/lib/i18n"
+import { BentoGrid } from "../ui/BentoGrid"
+import { ProjectsCard } from "../cards/ProjectsCard"
+import { RoleSystemCard } from "../cards/RoleSystemCard"
+import { OrganizationCard } from "../cards/OrganizationCard"
+import { MemberManagementCard } from "../cards/MemberManagementCard"
+
+interface FeatureBentoProps {
+ locale: AppLocale
+}
+
+export function FeatureBento({ locale }: FeatureBentoProps) {
+ return (
+
+
+
+
+
+
+ )
+}
diff --git a/src/components/bentos/RuntimeBento.tsx b/src/components/bentos/RuntimeBento.tsx
new file mode 100644
index 00000000..0fac284d
--- /dev/null
+++ b/src/components/bentos/RuntimeBento.tsx
@@ -0,0 +1,21 @@
+import { type AppLocale } from "@/lib/i18n"
+import { ActionListCard } from "../cards/ActionListCard"
+import { NodeCard } from "../cards/NodeCard"
+import { RuntimeTypesCard } from "../cards/RuntimeTypesCard"
+import { SuggestionMenuCard } from "../cards/SuggestionMenuCard"
+import { BentoGrid } from "../ui/BentoGrid"
+
+interface RuntimeFeatureSectionProps {
+ locale: AppLocale
+}
+
+export function RuntimeBento({ locale }: RuntimeFeatureSectionProps) {
+ return (
+
+
+
+
+
+
+ )
+}
diff --git a/src/components/cards/EditionUseCaseCard.tsx b/src/components/cards/EditionUseCaseCard.tsx
index 13d27d39..f9412258 100644
--- a/src/components/cards/EditionUseCaseCard.tsx
+++ b/src/components/cards/EditionUseCaseCard.tsx
@@ -30,20 +30,17 @@ export function EditionUseCaseCard({
return (
- {imageUrl ? (
-
+ className="relative flex h-full flex-col items-stretch justify-start overflow-hidden rounded-2xl">
+
+ {imageUrl ? (
+ className="relative overflow-hidden aspect-video w-full rounded-2xl border border-white/10 bg-primary/50">
-
- ) : (
-
- )}
+ ) : (
+
+ )}
+
-
-
+
+
+
{title}
-
+
{description}
{link?.url && link?.label && (
-
- {link.label}
-
+
+
+ {link.label}
+
+
)}
diff --git a/src/components/providers/SectionsProvider.tsx b/src/components/providers/SectionsProvider.tsx
deleted file mode 100644
index 24a870c6..00000000
--- a/src/components/providers/SectionsProvider.tsx
+++ /dev/null
@@ -1,35 +0,0 @@
-"use client"
-
-import type { Section } from "@/payload-types"
-import { createContext, type ReactNode, useContext, useMemo } from "react"
-
-type SectionType = NonNullable
-type SectionsMap = Partial>
-
-const SectionsContext = createContext({})
-
-interface SectionsProviderProps {
- sections: Section[]
- children: ReactNode
-}
-
-export function SectionsProvider({ sections, children }: SectionsProviderProps) {
- const sectionsMap = useMemo(() => {
- return sections.reduce((acc, section) => {
- acc[section.sectionType] = section
- return acc
- }, {})
- }, [sections])
-
- return (
-
- {children}
-
- )
-}
-
-export function usePreloadedSection(sectionType?: SectionType) {
- const sections = useContext(SectionsContext)
- if (!sectionType) return null
- return sections[sectionType] ?? null
-}
diff --git a/src/components/sections/AppFeatureSection.tsx b/src/components/sections/AppFeatureSection.tsx
deleted file mode 100644
index e2c952ec..00000000
--- a/src/components/sections/AppFeatureSection.tsx
+++ /dev/null
@@ -1,24 +0,0 @@
-import { Section } from "@/components/ui/Section"
-import { type AppLocale } from "@/lib/i18n"
-import { MemberManagementCard } from "../cards/MemberManagementCard"
-import { OrganizationCard } from "../cards/OrganizationCard"
-import { RoleSystemCard } from "../cards/RoleSystemCard"
-import { ProjectsCard } from "../cards/ProjectsCard"
-import { BentoGrid } from "../ui/BentoGrid"
-
-interface AppFeatureSectionProps {
- locale: AppLocale
-}
-
-export const AppFeatureSection: React.FC = ({ locale }) => {
- return (
-
- )
-}
diff --git a/src/components/sections/BentoSection.tsx b/src/components/sections/BentoSection.tsx
new file mode 100644
index 00000000..6c064fa7
--- /dev/null
+++ b/src/components/sections/BentoSection.tsx
@@ -0,0 +1,29 @@
+import { FeatureBento } from "@/components/bentos/FeatureBento"
+import { RuntimeBento } from "@/components/bentos/RuntimeBento"
+import { Section } from "@/components/ui/Section"
+import { BentoLayoutBlock } from "@/lib/cms"
+import type { AppLocale } from "@/lib/i18n"
+
+interface BentoSectionProps {
+ content?: BentoLayoutBlock | null
+ locale?: AppLocale
+}
+
+export function BentoSection({ content, locale = "en" }: BentoSectionProps) {
+ const variant = content?.variant ?? "feature"
+
+ return (
+
+ {variant === "runtime" ? (
+
+ ) : (
+
+ )}
+
+ )
+}
diff --git a/src/components/sections/BrandSection.tsx b/src/components/sections/BrandSection.tsx
index bf59481d..2b5e36fa 100644
--- a/src/components/sections/BrandSection.tsx
+++ b/src/components/sections/BrandSection.tsx
@@ -5,22 +5,13 @@ import { Section } from "@/components/ui/Section"
import Image from "next/image"
import type { Media } from "@/payload-types"
import { m as motion, type Variants } from "motion/react"
-
-interface BrandSectionLogo {
- logo: number | Media
- id?: string | null
-}
-
-interface BrandSectionContent {
- description?: string | null
- logos?: BrandSectionLogo[] | null
-}
+import { BrandLayoutBlock } from "@/lib/cms"
interface BrandSectionProps {
- content?: BrandSectionContent | null
+ content?: BrandLayoutBlock | null
}
-export const BrandSection: React.FC = ({ content }) => {
+export function BrandSection({ content }: BrandSectionProps) {
if (!content) return
const logos = (content.logos ?? [])
diff --git a/src/components/sections/CardRowSection.tsx b/src/components/sections/CardRowSection.tsx
new file mode 100644
index 00000000..fb78bd0f
--- /dev/null
+++ b/src/components/sections/CardRowSection.tsx
@@ -0,0 +1,104 @@
+"use client"
+
+import { LinkButton } from "@/components/ui/LinkButton"
+import { Section } from "@/components/ui/Section"
+import { CardRowLayoutBlock } from "@/lib/cms"
+import type { Media } from "@/payload-types"
+import { m as motion, type Variants } from "motion/react"
+import Image from "next/image"
+import React, { Children, type ReactNode } from "react"
+
+interface CardRowSectionProps {
+ content?: CardRowLayoutBlock | null
+ children?: ReactNode
+}
+
+function getImageUrl(image: number | Media | null | undefined) {
+ return typeof image === "object" && image?.url ? image.url : null
+}
+
+export function CardRowSection({ content, children }: CardRowSectionProps) {
+ const cards = content?.cards?.filter((card) => Boolean(card.title)) ?? []
+ const fallbackImages = Children.toArray(children)
+ if (cards.length === 0) return null
+
+ const staggerContainer: Variants = {
+ hidden: {},
+ show: {
+ transition: {
+ staggerChildren: 0.12,
+ delayChildren: 0.08,
+ },
+ },
+ }
+
+ const staggerItem: Variants = {
+ hidden: { opacity: 0, y: 20 },
+ show: {
+ opacity: 1,
+ y: 0,
+ transition: {
+ duration: 0.42,
+ ease: [0.22, 1, 0.36, 1],
+ },
+ },
+ }
+
+ return (
+
+
+
+
+ {cards.map((card, index) => {
+ const mediaImage = typeof card.image === "object" ? card.image : null
+ const imageUrl = getImageUrl(card.image)
+ const fallbackImage = fallbackImages[index]
+
+ return (
+
+
+
+ {imageUrl ? (
+
+
+
+ ) : fallbackImage}
+
+
+
{card.title}
+ {card.description &&
{card.description}
}
+ {card.link?.url && (
+
+ {card.link.label}
+
+ )}
+
+
+ )
+ })}
+
+
+ )
+}
diff --git a/src/components/sections/CtaSection.tsx b/src/components/sections/CtaSection.tsx
index 441dcbe2..210ef02d 100644
--- a/src/components/sections/CtaSection.tsx
+++ b/src/components/sections/CtaSection.tsx
@@ -4,28 +4,19 @@ import { InteractiveGridPattern } from "@/components/InteractiveGridPattern"
import { HapticButtonLink } from "@/components/ui/HapticButtonLink"
import { Section } from "@/components/ui/Section"
import { useMediaQuery } from "@/hooks/useMediaQuery"
+import { CtaLayoutBlock } from "@/lib/cms"
import type { AppLocale } from "@/lib/i18n"
import { cn } from "@/lib/utils"
import { m as motion, type Variants } from "motion/react"
import Image from "next/image"
import React, { useEffect, useRef, useState } from "react"
-interface CtaSectionContent {
- heading: string
- subheading: string
- ctaLink: {
- label: string
- url: string
- }
-}
-
interface CtaSectionProps {
- content?: CtaSectionContent | null
+ content?: CtaLayoutBlock | null
floatingCta?: boolean
- locale?: AppLocale
}
-export const CtaSection: React.FC = ({ content, floatingCta = false, locale }) => {
+export function CtaSection({ content, floatingCta = false }: CtaSectionProps) {
const isTouchDevice = useMediaQuery("(hover: none), (pointer: coarse)")
const [mounted, setMounted] = useState(false)
const [docked, setDocked] = useState(false)
diff --git a/src/components/sections/DeploymentSection.tsx b/src/components/sections/DeploymentSection.tsx
deleted file mode 100644
index aabd4701..00000000
--- a/src/components/sections/DeploymentSection.tsx
+++ /dev/null
@@ -1,123 +0,0 @@
-"use client"
-
-import { Section } from "@/components/ui/Section"
-import { LinkButton } from "@/components/ui/LinkButton"
-import { m as motion, type Variants } from "motion/react"
-import React from "react"
-import { DeploymentImage } from "../DeploymentImage"
-
-interface DeploymentSectionContent {
- cloudTitle?: string | null
- cloudDescription?: string | null
- cloudLink?: {
- label?: string | null
- url?: string | null
- }
- selfhostTitle?: string | null
- selfhostDescription?: string | null
- selfhostLink?: {
- label?: string | null
- url?: string | null
- }
- dynamicTitle?: string | null
- dynamicDescription?: string | null
- dynamicLink?: {
- label?: string | null
- url?: string | null
- }
-}
-
-interface DeploymentSectionProps {
- content?: DeploymentSectionContent | null
-}
-
-export const DeploymentSection: React.FC = ({ content }) => {
- if (!content) return null
-
- const staggerContainer: Variants = {
- hidden: {},
- show: {
- transition: {
- staggerChildren: 0.12,
- delayChildren: 0.08,
- },
- },
- }
-
- const staggerItem: Variants = {
- hidden: { opacity: 0, y: 20 },
- show: {
- opacity: 1,
- y: 0,
- transition: {
- duration: 0.42,
- ease: [0.22, 1, 0.36, 1],
- },
- },
- }
-
- const deploymentCards = [
- {
- badge: "Cloud",
- title: content.cloudTitle,
- description: content.cloudDescription,
- link: content.cloudLink,
- imageColor: "aqua",
- imageIcon: "cloud",
- imageText: "Cloud",
- },
- {
- badge: "Self-hosted",
- title: content.selfhostTitle,
- description: content.selfhostDescription,
- link: content.selfhostLink,
- imageColor: "pink",
- imageIcon: "server",
- imageText: "Selfhost",
- },
- {
- badge: "Dynamic",
- title: content.dynamicTitle,
- description: content.dynamicDescription,
- link: content.dynamicLink,
- imageColor: "brand",
- imageIcon: "cloud-computing",
- imageText: "Dynamic",
- },
- ] as const
-
- return (
-
-
-
-
- {deploymentCards.map((card) => (
-
-
-
-
-
-
{card.title}
-
{card.description}
- {card.link?.url && (
-
- {card.link.label}
-
- )}
-
-
- ))}
-
-
- )
-}
diff --git a/src/components/sections/EditionHeroSection.tsx b/src/components/sections/EditionHeroSection.tsx
deleted file mode 100644
index 27effa86..00000000
--- a/src/components/sections/EditionHeroSection.tsx
+++ /dev/null
@@ -1,112 +0,0 @@
-"use client"
-
-import { Section } from "@/components/ui/Section"
-import type { EditionHeroLayoutBlock } from "@/lib/cms"
-import { cn } from "@/lib/utils"
-import { m as motion, type Variants } from "motion/react"
-import Image from "next/image"
-import React from "react"
-import Grainient from "../ui/Granient"
-import { HapticButtonLink } from "../ui/HapticButtonLink"
-
-type EditionHeroSectionProps = {
- content?: EditionHeroLayoutBlock | null
- imageSrc?: string
- locale: "en" | "de"
- grainientColors?: {
- color1: string
- color2: string
- color3: string
- backgroundColor?: string
- }
-}
-
-export function EditionHeroSection({
- content,
- imageSrc = "/code0_software.png",
- locale,
- grainientColors,
-}: EditionHeroSectionProps) {
- if (!content?.heading || !content?.imageAlt) return null
-
- const texts = content.texts?.map((item) => item.text).filter(Boolean) ?? []
- const buttons = content.buttons?.filter((button) => Boolean(button.label && button.url)) ?? []
-
- const staggerContainer: Variants = {
- hidden: {},
- show: {
- transition: {
- staggerChildren: 0.08,
- delayChildren: 0,
- },
- },
- }
-
- const staggerItem: Variants = {
- hidden: { opacity: 0, y: 12 },
- show: {
- opacity: 1,
- y: 0,
- transition: { duration: 0.3, ease: [0.22, 1, 0.36, 1] },
- },
- }
-
- return (
-
-
-
-
-
-
-
- {content.heading}
-
-
-
- {texts.map((text, index) => (
-
- {text}
- {index < texts.length - 1 &&
}
-
- ))}
-
-
-
- {buttons.map((button, index) => (
-
- {button.label}
-
- ))}
-
-
-
-
-
-
-
- )
-}
diff --git a/src/components/sections/EditionUseCaseSection.tsx b/src/components/sections/EditionUseCaseSection.tsx
deleted file mode 100644
index 01e4a565..00000000
--- a/src/components/sections/EditionUseCaseSection.tsx
+++ /dev/null
@@ -1,177 +0,0 @@
-"use client"
-
-import { useState } from "react"
-import { Section } from "@/components/ui/Section"
-import type { EditionUseCaseLayoutBlock } from "@/lib/cms"
-import { Media } from "@/payload-types"
-import { EditionUseCaseCard } from "@/components/cards/EditionUseCaseCard"
-import { cn } from "@/lib/utils"
-import { Button } from "@code0-tech/pictor"
-import { IconChevronLeft, IconChevronRight } from "@tabler/icons-react"
-import { useWebHaptics } from "web-haptics/react"
-import { m as motion, type PanInfo, type Variants } from "motion/react"
-
-interface EditionUseCaseSectionProps {
- content?: EditionUseCaseLayoutBlock | null
-}
-
-export function EditionUseCaseSection({ content }: EditionUseCaseSectionProps) {
- const [focusedIndex, setFocusedIndex] = useState(0)
- const { trigger } = useWebHaptics()
-
- if (!content?.heading || !content?.subheading || !content?.useCases?.length) return null
-
- const useCases = content.useCases
-
- const handlePrevious = () => {
- trigger("light")
- setFocusedIndex((prev) => (prev === 0 ? useCases.length - 1 : prev - 1))
- }
-
- const handleNext = () => {
- trigger("light")
- setFocusedIndex((prev) => (prev === useCases.length - 1 ? 0 : prev + 1))
- }
-
- const handleDragEnd = (_event: MouseEvent | TouchEvent | PointerEvent, info: PanInfo) => {
- const swipeThreshold = 48
-
- if (Math.abs(info.offset.x) < swipeThreshold) return
-
- if (info.offset.x > 0) {
- handlePrevious()
- return
- }
-
- handleNext()
- }
-
- const staggerContainer: Variants = {
- hidden: {},
- show: {
- transition: {
- staggerChildren: 0.12,
- delayChildren: 0.08,
- },
- },
- }
-
- const staggerItem: Variants = {
- hidden: { opacity: 0, y: 16 },
- show: {
- opacity: 1,
- y: 0,
- transition: {
- duration: 0.4,
- ease: [0.22, 1, 0.36, 1],
- },
- },
- }
-
- const carouselVariants: Variants = {
- hidden: { opacity: 0, scale: 0.96 },
- show: {
- opacity: 1,
- scale: 1,
- transition: {
- duration: 0.5,
- ease: [0.22, 1, 0.36, 1],
- delay: 0.2,
- },
- },
- }
-
- return (
-
-
-
-
-
- {content.heading}
-
-
- {content.subheading}
-
-
-
-
-
-
-
-
-
-
-
-
- {useCases.map((useCase, index) => {
- const offset = index - focusedIndex
- const isVisibleMobile = offset === 0
- const isVisibleDesktop = Math.abs(offset) <= 1
-
- return (
-
-
-
- )
- })}
-
-
-
-
-
-
-
-
- )
-}
diff --git a/src/components/sections/FaqSection.tsx b/src/components/sections/FaqSection.tsx
index 4b4e2996..05b40fbd 100644
--- a/src/components/sections/FaqSection.tsx
+++ b/src/components/sections/FaqSection.tsx
@@ -2,25 +2,16 @@
import { AccordionItem } from "@/components/ui/Accordion"
import { Section } from "@/components/ui/Section"
+import { FaqLayoutBlock } from "@/lib/cms"
import { m as motion } from "motion/react"
import React, { useCallback, useState } from "react"
import { useWebHaptics } from "web-haptics/react"
-interface FaqItem {
- question: string
- answer: string
- id?: string | null
-}
-
-interface FaqSectionContent {
- items: FaqItem[] | null
-}
-
interface FaqSectionProps {
- content?: FaqSectionContent | null
+ content?: FaqLayoutBlock | null
}
-export const FaqSection: React.FC = ({ content }) => {
+export function FaqSection({ content }: FaqSectionProps) {
const [openItem, setOpenItem] = useState(null)
const { trigger } =useWebHaptics()
@@ -32,9 +23,15 @@ export const FaqSection: React.FC = ({ content }) => {
if (!content || !content.items) return
return (
-
+
-
+
{content.items.map((faq, index) => (
= ({ content }) => {
- const [isProductHuntBadgeVisible, setIsProductHuntBadgeVisible] = React.useState(false)
+export function HeroSection({ content, imageSrc = "/code0_software.png" }: HeroSectionProps) {
+ const [isProductHuntBadgeVisible, setIsProductHuntBadgeVisible] = useState(false)
- if (!content || !content.texts || !content.buttons) return
+ if (!content?.heading) return
const staggerContainer: Variants = {
hidden: {},
@@ -59,6 +41,77 @@ export const HeroSection: React.FC = ({ content }) => {
},
}
+ const texts = content.texts?.map((item) => item.text).filter(Boolean) ?? []
+ const buttons = content.buttons?.filter((button) => Boolean(button.label && button.url)) ?? []
+ const centered = Boolean(content.centered)
+ const grainientColors = {
+ color1: content.grainientColors?.color1 ?? undefined,
+ color2: content.grainientColors?.color2 ?? undefined,
+ color3: content.grainientColors?.color3 ?? undefined,
+ backgroundColor: content.grainientColors?.backgroundColor ?? undefined,
+ }
+
+ if (centered) {
+ return (
+
+
+
+
+
+
+
+ {content.heading}
+
+
+
+ {texts.map((text, index) => (
+
+ {text}
+ {index < texts.length - 1 &&
}
+
+ ))}
+
+
+
+ {buttons.map((button, index) => (
+
+ {button.label}
+
+ ))}
+
+
+
+
+
+
+
+ )
+ }
+
return (
@@ -105,18 +158,18 @@ export const HeroSection: React.FC
= ({ content }) => {
- {content.texts.length > 0
- ? content.texts.map((item, index) => (
-
- {item.text}
- {index < content.texts!!.length - 1 &&
}
+ {texts.length > 0
+ ? texts.map((text, index) => (
+
+ {text}
+ {index < texts.length - 1 &&
}
))
: <>Beschreibung1
Beschreibung2>}
- {content.buttons.map((button, index) => (
+ {buttons.map((button, index) => (
= ({ content }) => {
[] = [
+const OFFSET_CARD_ANIMATION_SEQUENCE: Exclude[] = [
"slide-left",
"slide-right",
"slide-left",
]
-export const EditionFeatureSection: React.FC = ({ content }) => {
- if (!content?.features?.length) return null
+export function OffsetCardsSection({ content }: OffsetCardsSectionProps) {
+ if (!content?.cards?.length) return null
const staggerContainer: Variants = {
hidden: {},
@@ -45,10 +45,16 @@ export const EditionFeatureSection: React.FC = ({ co
}
return (
-
+
- {content.features.map((item, index) => {
- const animationPreset = EDITION_FEATURE_ANIMATION_SEQUENCE[index % EDITION_FEATURE_ANIMATION_SEQUENCE.length]
+ {content.cards.map((item, index) => {
+ const animationPreset = OFFSET_CARD_ANIMATION_SEQUENCE[index % OFFSET_CARD_ANIMATION_SEQUENCE.length]
const animationConfig = ANIMATION_PRESETS[animationPreset]
const image = item.image as Media
diff --git a/src/components/sections/RoadmapSection.tsx b/src/components/sections/RoadmapSection.tsx
index 452fb77b..5dff59b4 100644
--- a/src/components/sections/RoadmapSection.tsx
+++ b/src/components/sections/RoadmapSection.tsx
@@ -1,25 +1,30 @@
import { Section } from "@/components/ui/Section"
-import { getRoadmapItems } from "@/lib/cms"
-import { AppLocale } from "@/lib/i18n"
import React from "react"
import { RoadmapItemCard } from "../cards/RoadmapItemCard"
import { cn } from "@/lib/utils"
+import { RoadmapLayoutBlock } from "@/lib/cms"
interface RoadmapSectionProps {
- locale: AppLocale
+ content?: RoadmapLayoutBlock | null
}
-export const RoadmapSection: React.FC
= async ({ locale }) => {
- const items = await getRoadmapItems(locale)
+export function RoadmapSection({ content }: RoadmapSectionProps) {
+ const items = content?.items ?? []
if (!items?.length) return null
return (
-
+
{items.map((item, index) => (
-
+
*:first-child]:order-2 md:[&>*:last-child]:order-1")}>
diff --git a/src/components/sections/RuntimeFeatureSection.tsx b/src/components/sections/RuntimeFeatureSection.tsx
deleted file mode 100644
index b4e9e3f6..00000000
--- a/src/components/sections/RuntimeFeatureSection.tsx
+++ /dev/null
@@ -1,25 +0,0 @@
-import { Section } from "@/components/ui/Section"
-import { type AppLocale } from "@/lib/i18n"
-import React from "react"
-import { ActionListCard } from "../cards/ActionListCard"
-import { NodeCard } from "../cards/NodeCard"
-import { RuntimeTypesCard } from "../cards/RuntimeTypesCard"
-import { SuggestionMenuCard } from "../cards/SuggestionMenuCard"
-import { BentoGrid } from "../ui/BentoGrid"
-
-interface RuntimeFeatureSectionProps {
- locale: AppLocale
-}
-
-export const RuntimeFeatureSection: React.FC
= ({ locale }) => {
- return (
-
- )
-}
diff --git a/src/components/sections/ScrollCardSection.tsx b/src/components/sections/ScrollCardSection.tsx
new file mode 100644
index 00000000..5b8a9390
--- /dev/null
+++ b/src/components/sections/ScrollCardSection.tsx
@@ -0,0 +1,222 @@
+"use client"
+
+import { LinkButton } from "@/components/ui/LinkButton"
+import { Section } from "@/components/ui/Section"
+import type { ScrollCardsLayoutBlock } from "@/lib/cms"
+import { cn } from "@/lib/utils"
+import type { Media } from "@/payload-types"
+import { m as motion } from "motion/react"
+import Image from "next/image"
+import React, { useEffect, useRef, useState } from "react"
+
+interface ScrollCardSectionProps {
+ content?: ScrollCardsLayoutBlock | null
+}
+
+interface PinState {
+ phase: "before" | "active" | "after"
+ left: number
+ width: number
+}
+
+function getImage(image: number | Media | null | undefined) {
+ return typeof image === "object" ? image : null
+}
+
+function clamp(value: number, min: number, max: number) {
+ return Math.min(Math.max(value, min), max)
+}
+
+const cardGradients = {
+ blue: "rgba(114,201,248,0.2)",
+ yellow: "rgba(248,241,114,0.2)",
+ pink: "rgba(248,114,226,0.2)",
+ aqua: "rgba(122,203,255,0.2)",
+ brand: "rgba(145,232,120,0.2)",
+ neutral: "rgba(255,255,255,0.1)",
+} as const
+
+const gradientDirections = {
+ topLeft: "top left",
+ topRight: "top right",
+ bottomLeft: "bottom left",
+ bottomRight: "bottom right",
+} as const
+
+export function ScrollCardSection({ content }: ScrollCardSectionProps) {
+ const containerRef = useRef(null)
+ const [scrollProgress, setScrollProgress] = useState(0)
+ const [viewportHeight, setViewportHeight] = useState(1)
+ const [pinState, setPinState] = useState({
+ phase: "before",
+ left: 0,
+ width: 0,
+ })
+ const items = content?.items?.filter((item) => Boolean(item.title)) ?? []
+
+ useEffect(() => {
+ let frame = 0
+
+ const updateProgress = () => {
+ const container = containerRef.current
+ if (!container) return
+
+ const rect = container.getBoundingClientRect()
+ const topOffset = 96
+ const height = window.innerHeight
+ const containerTop = rect.top + window.scrollY
+ const rawProgress = window.scrollY - containerTop
+ const activeEnd = Math.max((items.length - 1) * height, 0)
+
+ setViewportHeight(height)
+ setScrollProgress(clamp(rawProgress, 0, activeEnd))
+ setPinState({
+ phase: rect.top > topOffset ? "before" : rect.bottom <= height ? "after" : "active",
+ left: rect.left,
+ width: rect.width,
+ })
+ }
+
+ const handleViewportChange = () => {
+ if (frame) return
+ frame = window.requestAnimationFrame(() => {
+ frame = 0
+ updateProgress()
+ })
+ }
+
+ updateProgress()
+ window.addEventListener("scroll", handleViewportChange, { passive: true })
+ window.addEventListener("resize", handleViewportChange)
+
+ return () => {
+ if (frame) window.cancelAnimationFrame(frame)
+ window.removeEventListener("scroll", handleViewportChange)
+ window.removeEventListener("resize", handleViewportChange)
+ }
+ }, [])
+
+ if (items.length === 0) return null
+ const activeShadowIndex = Math.min(
+ items.length - 1,
+ Math.floor(scrollProgress / viewportHeight) + 1,
+ )
+
+ return (
+
+
+
+ {items.map((item, index) => {
+ const image = getImage(item.image)
+ const itemSettings = item as {
+ gradient?: keyof typeof cardGradients | null
+ gradientDirection?: keyof typeof gradientDirections | null
+ sectionLayout?: "imageRight" | "imageLeft" | null
+ showImageBorder?: boolean | null
+ }
+ const isImageLeft = itemSettings.sectionLayout === "imageLeft"
+ const showImageBorder = itemSettings.showImageBorder ?? true
+ const gradient = cardGradients[itemSettings.gradient ?? "blue"] ?? cardGradients.blue
+ const gradientDirection = gradientDirections[itemSettings.gradientDirection ?? "topLeft"] ?? gradientDirections.topLeft
+ const segmentProgress = index === 0
+ ? 1
+ : clamp((scrollProgress - (index - 1) * viewportHeight) / viewportHeight, 0, 1)
+ const translateY = (1 - segmentProgress) * 100
+
+ return (
+
div]:shadow-none!",
+ index === activeShadowIndex && "[&>div]:shadow-[0_16px_44px_rgba(0,0,0,0.3)]!",
+ )}
+ style={{
+ opacity: 1,
+ transform: `translateY(${translateY}%)`,
+ zIndex: index + 1,
+ }}
+ >
+
+
+
+
+
+
+
+ {item.title}
+
+
+ {item.description}
+
+
+
+
+ {item.bulletPoints?.length ? (
+
+ {item.bulletPoints.map((point, pointIndex) => (
+ -
+
+ {point}
+
+ ))}
+
+ ) : null}
+
+ {item.link?.label && item.link?.url ? (
+
+ {item.link.label}
+
+ ) : null}
+
+
+
+
+ {image?.url && (
+
+ )}
+
+
+
+ )
+ })}
+
+
+
+ )
+}
diff --git a/src/components/sections/SwipeCardSection.tsx b/src/components/sections/SwipeCardSection.tsx
new file mode 100644
index 00000000..7abb2eb1
--- /dev/null
+++ b/src/components/sections/SwipeCardSection.tsx
@@ -0,0 +1,192 @@
+"use client"
+
+import { EditionUseCaseCard } from "@/components/cards/EditionUseCaseCard"
+import { Section } from "@/components/ui/Section"
+import { cn } from "@/lib/utils"
+import type { SwipeCardsLayoutBlock } from "@/lib/cms"
+import { Button } from "@code0-tech/pictor"
+import { IconChevronLeft, IconChevronRight } from "@tabler/icons-react"
+import { m as motion, type PanInfo, type Variants } from "motion/react"
+import { useState } from "react"
+import { useWebHaptics } from "web-haptics/react"
+
+interface SwipeCardSectionProps {
+ content?: SwipeCardsLayoutBlock | null
+}
+
+export function SwipeCardSection({ content }: SwipeCardSectionProps) {
+ const [focusedIndex, setFocusedIndex] = useState(0)
+ const { trigger } = useWebHaptics()
+
+ if (!content?.cards?.length) return null
+
+ const cards = content.cards
+ const hasHeader = Boolean(content.heading || content.subheading)
+
+ const handlePrevious = () => {
+ trigger("light")
+ setFocusedIndex((prev) => (prev === 0 ? cards.length - 1 : prev - 1))
+ }
+
+ const handleNext = () => {
+ trigger("light")
+ setFocusedIndex((prev) => (prev === cards.length - 1 ? 0 : prev + 1))
+ }
+
+ const handleDragEnd = (_event: MouseEvent | TouchEvent | PointerEvent, info: PanInfo) => {
+ const swipeThreshold = 48
+
+ if (Math.abs(info.offset.x) < swipeThreshold) return
+
+ if (info.offset.x > 0) {
+ handlePrevious()
+ return
+ }
+
+ handleNext()
+ }
+
+ const staggerContainer: Variants = {
+ hidden: {},
+ show: {
+ transition: {
+ staggerChildren: 0.12,
+ delayChildren: 0.08,
+ },
+ },
+ }
+
+ const staggerItem: Variants = {
+ hidden: { opacity: 0, y: 16 },
+ show: {
+ opacity: 1,
+ y: 0,
+ transition: {
+ duration: 0.4,
+ ease: [0.22, 1, 0.36, 1],
+ },
+ },
+ }
+
+ const carouselVariants: Variants = {
+ hidden: { opacity: 0, scale: 0.96 },
+ show: {
+ opacity: 1,
+ scale: 1,
+ transition: {
+ duration: 0.5,
+ ease: [0.22, 1, 0.36, 1],
+ delay: 0.2,
+ },
+ },
+ }
+
+ return (
+
+
+
+ {hasHeader && (
+
+ {content.heading && (
+
+ {content.heading}
+
+ )}
+ {content.subheading && (
+
+ {content.subheading}
+
+ )}
+
+ )}
+
+
+
+
+
+
+
+
+
+
+ {cards.map((card, index) => (
+
+
+
+ ))}
+
+ {cards.map((card, index) => {
+ const offset = index - focusedIndex
+ const isVisibleMobile = offset === 0
+ const isVisibleDesktop = Math.abs(offset) <= 1
+
+ return (
+
+
+
+ )
+ })}
+
+
+
+
+
+
+
+
+
+
+
+
+ )
+}
diff --git a/src/components/sections/UseCaseSection.tsx b/src/components/sections/UseCaseSection.tsx
deleted file mode 100644
index e672f295..00000000
--- a/src/components/sections/UseCaseSection.tsx
+++ /dev/null
@@ -1,155 +0,0 @@
-"use client"
-
-import { LinkButton } from "@/components/ui/LinkButton"
-import { Section } from "@/components/ui/Section"
-import { ANIMATION_PRESETS, type AnimationPreset } from "@/lib/utils"
-import type { Media } from "@/payload-types"
-import { m as motion, type Variants } from "motion/react"
-import Image from "next/image"
-import React from "react"
-
-interface UseCaseItem {
- label: string
- title: string
- description: string
- image?: Media | number | null
- bulletPoints?: string[] | null
- link?: {
- label?: string | null
- url?: string | null
- } | null
- id?: string | null
-}
-
-interface UseCaseSectionContent {
- useCases: UseCaseItem[] | null
-}
-
-interface UseCaseSectionProps {
- content?: UseCaseSectionContent | null
-}
-
-const USE_CASE_ANIMATION_SEQUENCE: Exclude[] = [
- "slide-left",
- "slide-right",
- "slide-left"
-]
-
-export const UseCaseSection: React.FC = ({ content }) => {
- if (!content?.useCases?.length) return null
-
- const staggerContainer: Variants = {
- hidden: {},
- show: {
- transition: {
- staggerChildren: 0.08,
- delayChildren: 0.06,
- },
- },
- }
-
- const staggerItem: Variants = {
- hidden: { opacity: 0, y: 14 },
- show: {
- opacity: 1,
- y: 0,
- transition: {
- duration: 0.38,
- ease: [0.22, 1, 0.36, 1],
- },
- },
- }
-
- return (
-
-
- {content.useCases.map((item, index) => {
- const animationPreset = USE_CASE_ANIMATION_SEQUENCE[index % USE_CASE_ANIMATION_SEQUENCE.length]
- const animationConfig = ANIMATION_PRESETS[animationPreset]
- const image = item.image as Media
-
- return (
-
-
- {item.title}
- {item.description}
- {item.bulletPoints?.length ? (
-
- {item.bulletPoints.map((point, pointIndex) => (
-
-
- {point}
-
- ))}
-
- ) : null}
- {item.link?.label && item.link?.url ? (
-
-
- {item.link.label}
-
-
- ) : null}
-
-
-
- {image?.url ? (
-
- ) : null}
-
-
- {item.title}
- {item.description}
- {item.bulletPoints?.length ? (
-
- {item.bulletPoints.map((point, pointIndex) => (
-
-
- {point}
-
- ))}
-
- ) : null}
- {item.link?.label && item.link?.url ? (
-
-
- {item.link.label}
-
-
- ) : null}
-
-
- )
- })}
-
-
- )
-}
diff --git a/src/components/ui/Section.tsx b/src/components/ui/Section.tsx
index a8325ace..3f0904c2 100644
--- a/src/components/ui/Section.tsx
+++ b/src/components/ui/Section.tsx
@@ -1,19 +1,24 @@
"use client"
-import { usePreloadedSection } from "@/components/providers/SectionsProvider"
import { LinkButton } from "@/components/ui/LinkButton"
import { getLocaleFromPath, localizeHref } from "@/lib/i18n"
import { ANIMATION_PRESETS, cn, type AnimationPreset } from "@/lib/utils"
-import { Section as SectionDocument } from "@/payload-types"
import { m as motion, type Variants } from "motion/react"
import { usePathname } from "next/navigation"
import { createElement, ReactNode, useEffect, useRef, useState } from "react"
+interface SectionLinkButton {
+ label?: string | null
+ url?: string | null
+}
+
interface SectionProps {
children: ReactNode
funnelType?: "center" | "left"
className?: string
- sectionType?: NonNullable
+ heading?: string | null
+ description?: string | null
+ linkButton?: SectionLinkButton | null
showBlur?: boolean
showFunnel?: boolean
showLinkButton?: boolean
@@ -28,7 +33,9 @@ interface SectionProps {
}
export function Section({
- sectionType,
+ heading,
+ description,
+ linkButton,
children,
className,
funnelType = "center",
@@ -44,13 +51,13 @@ export function Section({
animationViewportMargin,
headingLevel = 2,
}: SectionProps) {
- const sectionData = usePreloadedSection(sectionType) as SectionDocument | null
const sectionRef = useRef(null)
const pathname = usePathname()
const locale = getLocaleFromPath(pathname)
const [isInView, setIsInView] = useState(false)
- const rawLinkUrl = sectionData?.link_button?.url?.trim()
+ const rawLinkUrl = linkButton?.url?.trim()
const linkUrl = rawLinkUrl ? localizeHref(rawLinkUrl, locale) : undefined
+ const shouldShowFunnel = showFunnel && Boolean(heading || description || (showLinkButton && linkUrl && linkButton?.label))
const animationConfig = animationPreset === "none" ? null : ANIMATION_PRESETS[animationPreset]
const staggerContainer: Variants = {
hidden: {},
@@ -116,7 +123,7 @@ export function Section({
{showBlur && funnelType === "center" && (
)}
- {showFunnel && (
+ {shouldShowFunnel && (
funnelType === "center" ? (
+ {description}
+
)}
-
- {sectionData?.subheading}
-
{showLinkButton && linkUrl &&
- {sectionData?.link_button?.label}
+ {linkButton?.label}
}
@@ -152,15 +161,17 @@ export function Section({
{createElement(
motion[headingTag],
{ variants: staggerItem, className: "text-4xl text-white font-semibold" },
- sectionData?.heading,
+ heading,
+ )}
+ {description && (
+
+ {description}
+
)}
-
- {sectionData?.subheading}
-
{showLinkButton && linkUrl &&
- {sectionData?.link_button?.label}
+ {linkButton?.label}
}
diff --git a/src/lib/cms.ts b/src/lib/cms.ts
index c71dd55f..13207974 100644
--- a/src/lib/cms.ts
+++ b/src/lib/cms.ts
@@ -2,7 +2,7 @@
import { DEFAULT_LOCALE, type AppLocale } from "@/lib/i18n"
import { getPayloadClient } from "@/lib/payloadClient"
-import type { Action, Blog, CookieBanner, Feature, Footer, Job, Media, NavbarItem, Page, RoadmapItem as PayloadRoadmapItem, Section, TeamMember } from "@/payload-types"
+import type { Action, Blog, CookieBanner, Feature, Footer, Job, Media, NavbarItem, Page, TeamMember } from "@/payload-types"
import { cache } from "react"
const isBuildPhase = process.env.NEXT_PHASE === "phase-production-build" || process.env.npm_lifecycle_event === "build"
@@ -11,20 +11,21 @@ const hasDatabaseUrl = Boolean(process.env.DATABASE_URL?.trim())
type PageLayoutBlock = NonNullable[number]
export type HeroLayoutBlock = Extract
-export type EditionHeroLayoutBlock = Extract
-export type EditionFeaturesLayoutBlock = Extract
-export type EditionInstallLayoutBlock = Extract
-export type EditionUseCaseLayoutBlock = Extract
+export type BentoLayoutBlock = Extract
+export type OffsetCardsLayoutBlock = Extract
+export type InstallLayoutBlock = Extract
+export type SwipeCardsLayoutBlock = Extract
export type BrandLayoutBlock = Extract
export type CtaLayoutBlock = Extract
export type FaqLayoutBlock = Extract
-export type UseCaseLayoutBlock = Extract
-export type DeploymentLayoutBlock = Extract
+export type CardRowLayoutBlock = Extract
export type JobsLayoutBlock = Extract
export type ActionsLayoutBlock = Extract
export type MarkdownLayoutBlock = Extract
export type ContactLayoutBlock = Extract
export type BlogLayoutBlock = Extract
+export type RoadmapLayoutBlock = Extract
+export type ScrollCardsLayoutBlock = Extract
type FeatureSlug = Feature["slug"]
@@ -59,8 +60,6 @@ type ActionDetailItem = Pick
type JobDetailItem = Pick
export type TeamMemberItem = Pick
-type RoadmapItem = Pick
-
export type BlogPostItem = Pick & {
heroImage?: (number | null) | Media
meta?: Blog["meta"]
@@ -519,37 +518,6 @@ const getBlogSlugsCached = cache(async (locale: AppLocale): Promise =>
})
})
-const getRoadmapItemsCached = cache(async (locale: AppLocale): Promise => {
- return withCmsFallback(`getRoadmapItems(${locale})`, [], async () => {
- const payload = await getPayloadClient()
- const result = await payload.find({
- collection: "roadmapItems",
- locale,
- fallbackLocale: DEFAULT_LOCALE,
- pagination: false,
- sort: "-createdAt",
- depth: 0,
- })
-
- return (result.docs as RoadmapItem[]) ?? []
- })
-})
-
-const getSectionsCached = cache(async (locale: AppLocale): Promise => {
- return withCmsFallback(`getSections(${locale})`, [], async () => {
- const payload = await getPayloadClient()
- const result = await payload.find({
- collection: "sections",
- locale,
- fallbackLocale: DEFAULT_LOCALE,
- pagination: false,
- depth: 0,
- })
-
- return result.docs as Section[]
- })
-})
-
const getSubscriptionConfigCached = cache(async (locale: AppLocale): Promise => {
return withCmsFallback(`getSubscriptionConfig(${locale})`, null, async () => {
const payload = await getPayloadClient()
@@ -630,14 +598,6 @@ export async function getBlogSlugs(locale: AppLocale = DEFAULT_LOCALE): Promise<
return getBlogSlugsCached(locale)
}
-export async function getRoadmapItems(locale: AppLocale = DEFAULT_LOCALE): Promise {
- return getRoadmapItemsCached(locale)
-}
-
-export async function getSections(locale: AppLocale = DEFAULT_LOCALE): Promise {
- return getSectionsCached(locale)
-}
-
export async function getSubscriptionConfig(locale: AppLocale = DEFAULT_LOCALE): Promise {
return getSubscriptionConfigCached(locale)
}
diff --git a/src/migrations/20260427_010_remove_edition_hero_block.ts b/src/migrations/20260427_010_remove_edition_hero_block.ts
new file mode 100644
index 00000000..e8ba47ce
--- /dev/null
+++ b/src/migrations/20260427_010_remove_edition_hero_block.ts
@@ -0,0 +1,1136 @@
+import { MigrateDownArgs, MigrateUpArgs, sql } from '@payloadcms/db-postgres'
+
+export async function up({ db }: MigrateUpArgs): Promise {
+ await db.execute(sql`
+ ALTER TABLE "pages_blocks_hero" ADD COLUMN IF NOT EXISTS "centered" boolean DEFAULT false;
+ ALTER TABLE "pages_blocks_hero" ADD COLUMN IF NOT EXISTS "grainient_colors_color1" varchar;
+ ALTER TABLE "pages_blocks_hero" ADD COLUMN IF NOT EXISTS "grainient_colors_color2" varchar;
+ ALTER TABLE "pages_blocks_hero" ADD COLUMN IF NOT EXISTS "grainient_colors_color3" varchar;
+ ALTER TABLE "pages_blocks_hero" ADD COLUMN IF NOT EXISTS "grainient_colors_background_color" varchar;
+
+ INSERT INTO "pages_blocks_hero" (
+ "_order",
+ "_parent_id",
+ "_path",
+ "_locale",
+ "id",
+ "heading",
+ "centered",
+ "grainient_colors_color1",
+ "grainient_colors_color2",
+ "grainient_colors_color3",
+ "grainient_colors_background_color",
+ "block_name"
+ )
+ SELECT
+ "_order",
+ "_parent_id",
+ "_path",
+ "_locale",
+ "id",
+ "heading",
+ true,
+ CASE WHEN "_path" LIKE '%community-edition%' THEN '#10213a' ELSE '#13102d' END,
+ CASE WHEN "_path" LIKE '%community-edition%' THEN '#f872e2' ELSE '#7472f8' END,
+ CASE WHEN "_path" LIKE '%community-edition%' THEN '#f8f172' ELSE '#72c9f8' END,
+ CASE WHEN "_path" LIKE '%community-edition%' THEN '#0b1324' ELSE '#140c22' END,
+ "block_name"
+ FROM "pages_blocks_edition_hero"
+ ON CONFLICT ("id") DO NOTHING;
+
+ INSERT INTO "pages_blocks_hero_texts" (
+ "_order",
+ "_parent_id",
+ "_locale",
+ "id",
+ "text"
+ )
+ SELECT
+ "_order",
+ "_parent_id",
+ "_locale",
+ "id",
+ "text"
+ FROM "pages_blocks_edition_hero_texts"
+ ON CONFLICT ("id") DO NOTHING;
+
+ INSERT INTO "pages_blocks_hero_buttons" (
+ "_order",
+ "_parent_id",
+ "_locale",
+ "id",
+ "label",
+ "url",
+ "variant"
+ )
+ SELECT
+ "_order",
+ "_parent_id",
+ "_locale",
+ "id",
+ "label",
+ "url",
+ "variant"::text::"enum_pages_blocks_hero_buttons_variant"
+ FROM "pages_blocks_edition_hero_buttons"
+ ON CONFLICT ("id") DO NOTHING;
+
+ DROP TABLE IF EXISTS "pages_blocks_edition_hero_texts" CASCADE;
+ DROP TABLE IF EXISTS "pages_blocks_edition_hero_buttons" CASCADE;
+ DROP TABLE IF EXISTS "pages_blocks_edition_hero" CASCADE;
+ DROP TYPE IF EXISTS "public"."enum_pages_blocks_edition_hero_buttons_variant";
+ `)
+
+ await db.execute(sql`
+ CREATE TABLE IF NOT EXISTS "pages_blocks_card_row" (
+ "_order" integer NOT NULL,
+ "_parent_id" integer NOT NULL,
+ "_path" text NOT NULL,
+ "_locale" "_locales" NOT NULL,
+ "id" varchar PRIMARY KEY NOT NULL,
+ "block_name" varchar
+ );
+
+ CREATE TABLE IF NOT EXISTS "pages_blocks_card_row_cards" (
+ "_order" integer NOT NULL,
+ "_parent_id" varchar NOT NULL,
+ "_locale" "_locales" NOT NULL,
+ "id" varchar PRIMARY KEY NOT NULL,
+ "title" varchar NOT NULL,
+ "description" varchar,
+ "link_label" varchar,
+ "link_url" varchar,
+ "image_id" integer
+ );
+
+ ALTER TABLE "pages_blocks_card_row"
+ ADD CONSTRAINT "pages_blocks_card_row_parent_id_fk"
+ FOREIGN KEY ("_parent_id") REFERENCES "public"."pages"("id")
+ ON DELETE cascade ON UPDATE no action;
+
+ ALTER TABLE "pages_blocks_card_row_cards"
+ ADD CONSTRAINT "pages_blocks_card_row_cards_image_id_media_id_fk"
+ FOREIGN KEY ("image_id") REFERENCES "public"."media"("id")
+ ON DELETE set null ON UPDATE no action;
+
+ ALTER TABLE "pages_blocks_card_row_cards"
+ ADD CONSTRAINT "pages_blocks_card_row_cards_parent_id_fk"
+ FOREIGN KEY ("_parent_id") REFERENCES "public"."pages_blocks_card_row"("id")
+ ON DELETE cascade ON UPDATE no action;
+
+ CREATE INDEX IF NOT EXISTS "pages_blocks_card_row_order_idx" ON "pages_blocks_card_row" USING btree ("_order");
+ CREATE INDEX IF NOT EXISTS "pages_blocks_card_row_parent_id_idx" ON "pages_blocks_card_row" USING btree ("_parent_id");
+ CREATE INDEX IF NOT EXISTS "pages_blocks_card_row_path_idx" ON "pages_blocks_card_row" USING btree ("_path");
+ CREATE INDEX IF NOT EXISTS "pages_blocks_card_row_locale_idx" ON "pages_blocks_card_row" USING btree ("_locale");
+ CREATE INDEX IF NOT EXISTS "pages_blocks_card_row_cards_order_idx" ON "pages_blocks_card_row_cards" USING btree ("_order");
+ CREATE INDEX IF NOT EXISTS "pages_blocks_card_row_cards_parent_id_idx" ON "pages_blocks_card_row_cards" USING btree ("_parent_id");
+ CREATE INDEX IF NOT EXISTS "pages_blocks_card_row_cards_locale_idx" ON "pages_blocks_card_row_cards" USING btree ("_locale");
+ CREATE INDEX IF NOT EXISTS "pages_blocks_card_row_cards_image_idx" ON "pages_blocks_card_row_cards" USING btree ("image_id");
+
+ INSERT INTO "pages_blocks_card_row" (
+ "_order", "_parent_id", "_path", "_locale", "id", "block_name"
+ )
+ SELECT "_order", "_parent_id", "_path", "_locale", "id", "block_name"
+ FROM "pages_blocks_deployment"
+ ON CONFLICT ("id") DO NOTHING;
+
+ INSERT INTO "pages_blocks_card_row_cards" (
+ "_order", "_parent_id", "_locale", "id", "title", "description", "link_label", "link_url"
+ )
+ SELECT 0, "id", "_locale", "id" || '-cloud', COALESCE("cloud_title", ''), "cloud_description", "cloud_link_label", "cloud_link_url"
+ FROM "pages_blocks_deployment"
+ ON CONFLICT ("id") DO NOTHING;
+
+ INSERT INTO "pages_blocks_card_row_cards" (
+ "_order", "_parent_id", "_locale", "id", "title", "description", "link_label", "link_url"
+ )
+ SELECT 1, "id", "_locale", "id" || '-selfhost', COALESCE("selfhost_title", ''), "selfhost_description", "selfhost_link_label", "selfhost_link_url"
+ FROM "pages_blocks_deployment"
+ ON CONFLICT ("id") DO NOTHING;
+
+ INSERT INTO "pages_blocks_card_row_cards" (
+ "_order", "_parent_id", "_locale", "id", "title", "description", "link_label", "link_url"
+ )
+ SELECT 2, "id", "_locale", "id" || '-dynamic', COALESCE("dynamic_title", ''), "dynamic_description", "dynamic_link_label", "dynamic_link_url"
+ FROM "pages_blocks_deployment"
+ ON CONFLICT ("id") DO NOTHING;
+
+ DROP TABLE IF EXISTS "pages_blocks_deployment" CASCADE;
+ `)
+
+ await db.execute(sql`
+ CREATE TABLE IF NOT EXISTS "pages_blocks_offset_cards" (
+ "_order" integer NOT NULL,
+ "_parent_id" integer NOT NULL,
+ "_path" text NOT NULL,
+ "_locale" "_locales" NOT NULL,
+ "id" varchar PRIMARY KEY NOT NULL,
+ "show_section_header" boolean DEFAULT false,
+ "block_name" varchar
+ );
+
+ CREATE TABLE IF NOT EXISTS "pages_blocks_offset_cards_cards" (
+ "_order" integer NOT NULL,
+ "_parent_id" varchar NOT NULL,
+ "_locale" "_locales" NOT NULL,
+ "id" varchar PRIMARY KEY NOT NULL,
+ "label" varchar NOT NULL,
+ "title" varchar NOT NULL,
+ "description" varchar NOT NULL,
+ "image_id" integer,
+ "bullet_points" jsonb,
+ "link_label" varchar,
+ "link_url" varchar
+ );
+
+ ALTER TABLE "pages_blocks_offset_cards"
+ ADD CONSTRAINT "pages_blocks_offset_cards_parent_id_fk"
+ FOREIGN KEY ("_parent_id") REFERENCES "public"."pages"("id")
+ ON DELETE cascade ON UPDATE no action;
+
+ ALTER TABLE "pages_blocks_offset_cards_cards"
+ ADD CONSTRAINT "pages_blocks_offset_cards_cards_image_id_media_id_fk"
+ FOREIGN KEY ("image_id") REFERENCES "public"."media"("id")
+ ON DELETE set null ON UPDATE no action;
+
+ ALTER TABLE "pages_blocks_offset_cards_cards"
+ ADD CONSTRAINT "pages_blocks_offset_cards_cards_parent_id_fk"
+ FOREIGN KEY ("_parent_id") REFERENCES "public"."pages_blocks_offset_cards"("id")
+ ON DELETE cascade ON UPDATE no action;
+
+ CREATE INDEX IF NOT EXISTS "pages_blocks_offset_cards_order_idx" ON "pages_blocks_offset_cards" USING btree ("_order");
+ CREATE INDEX IF NOT EXISTS "pages_blocks_offset_cards_parent_id_idx" ON "pages_blocks_offset_cards" USING btree ("_parent_id");
+ CREATE INDEX IF NOT EXISTS "pages_blocks_offset_cards_path_idx" ON "pages_blocks_offset_cards" USING btree ("_path");
+ CREATE INDEX IF NOT EXISTS "pages_blocks_offset_cards_locale_idx" ON "pages_blocks_offset_cards" USING btree ("_locale");
+ CREATE INDEX IF NOT EXISTS "pages_blocks_offset_cards_cards_order_idx" ON "pages_blocks_offset_cards_cards" USING btree ("_order");
+ CREATE INDEX IF NOT EXISTS "pages_blocks_offset_cards_cards_parent_id_idx" ON "pages_blocks_offset_cards_cards" USING btree ("_parent_id");
+ CREATE INDEX IF NOT EXISTS "pages_blocks_offset_cards_cards_locale_idx" ON "pages_blocks_offset_cards_cards" USING btree ("_locale");
+ CREATE INDEX IF NOT EXISTS "pages_blocks_offset_cards_cards_image_idx" ON "pages_blocks_offset_cards_cards" USING btree ("image_id");
+
+ INSERT INTO "pages_blocks_offset_cards" (
+ "_order", "_parent_id", "_path", "_locale", "id", "show_section_header", "block_name"
+ )
+ SELECT "_order", "_parent_id", "_path", "_locale", "id", true, "block_name"
+ FROM "pages_blocks_usecase"
+ ON CONFLICT ("id") DO NOTHING;
+
+ INSERT INTO "pages_blocks_offset_cards_cards" (
+ "_order", "_parent_id", "_locale", "id", "label", "title", "description", "image_id", "link_label", "link_url"
+ )
+ SELECT "_order", "_parent_id", "_locale", "id", "label", "title", "description", "image_id", "link_label", "link_url"
+ FROM "pages_blocks_usecase_use_cases"
+ ON CONFLICT ("id") DO NOTHING;
+
+ INSERT INTO "pages_blocks_offset_cards" (
+ "_order", "_parent_id", "_path", "_locale", "id", "show_section_header", "block_name"
+ )
+ SELECT "_order", "_parent_id", "_path", "_locale", "id", false, "block_name"
+ FROM "pages_blocks_edition_features"
+ ON CONFLICT ("id") DO NOTHING;
+
+ INSERT INTO "pages_blocks_offset_cards_cards" (
+ "_order", "_parent_id", "_locale", "id", "label", "title", "description", "image_id", "link_label", "link_url"
+ )
+ SELECT "_order", "_parent_id", "_locale", "id", "label", "title", "description", "image_id", "link_label", "link_url"
+ FROM "pages_blocks_edition_features_features"
+ ON CONFLICT ("id") DO NOTHING;
+
+ DROP TABLE IF EXISTS "pages_blocks_usecase_use_cases" CASCADE;
+ DROP TABLE IF EXISTS "pages_blocks_usecase" CASCADE;
+ DROP TABLE IF EXISTS "pages_blocks_edition_features_features" CASCADE;
+ DROP TABLE IF EXISTS "pages_blocks_edition_features" CASCADE;
+ `)
+
+ await db.execute(sql`
+ CREATE TABLE IF NOT EXISTS "pages_blocks_install" (
+ "_order" integer NOT NULL,
+ "_parent_id" integer NOT NULL,
+ "_path" text NOT NULL,
+ "_locale" "_locales" NOT NULL,
+ "id" varchar PRIMARY KEY NOT NULL,
+ "heading" varchar NOT NULL,
+ "subheading" varchar NOT NULL,
+ "label" varchar,
+ "code" varchar NOT NULL,
+ "block_name" varchar
+ );
+
+ CREATE TABLE IF NOT EXISTS "pages_blocks_swipe_cards" (
+ "_order" integer NOT NULL,
+ "_parent_id" integer NOT NULL,
+ "_path" text NOT NULL,
+ "_locale" "_locales" NOT NULL,
+ "id" varchar PRIMARY KEY NOT NULL,
+ "heading" varchar,
+ "subheading" varchar,
+ "block_name" varchar
+ );
+
+ CREATE TABLE IF NOT EXISTS "pages_blocks_swipe_cards_cards" (
+ "_order" integer NOT NULL,
+ "_parent_id" varchar NOT NULL,
+ "_locale" "_locales" NOT NULL,
+ "id" varchar PRIMARY KEY NOT NULL,
+ "title" varchar NOT NULL,
+ "description" varchar NOT NULL,
+ "image_id" integer,
+ "link_label" varchar,
+ "link_url" varchar
+ );
+
+ ALTER TABLE "pages_blocks_install"
+ ADD CONSTRAINT "pages_blocks_install_parent_id_fk"
+ FOREIGN KEY ("_parent_id") REFERENCES "public"."pages"("id")
+ ON DELETE cascade ON UPDATE no action;
+
+ ALTER TABLE "pages_blocks_swipe_cards"
+ ADD CONSTRAINT "pages_blocks_swipe_cards_parent_id_fk"
+ FOREIGN KEY ("_parent_id") REFERENCES "public"."pages"("id")
+ ON DELETE cascade ON UPDATE no action;
+
+ ALTER TABLE "pages_blocks_swipe_cards_cards"
+ ADD CONSTRAINT "pages_blocks_swipe_cards_cards_image_id_media_id_fk"
+ FOREIGN KEY ("image_id") REFERENCES "public"."media"("id")
+ ON DELETE set null ON UPDATE no action;
+
+ ALTER TABLE "pages_blocks_swipe_cards_cards"
+ ADD CONSTRAINT "pages_blocks_swipe_cards_cards_parent_id_fk"
+ FOREIGN KEY ("_parent_id") REFERENCES "public"."pages_blocks_swipe_cards"("id")
+ ON DELETE cascade ON UPDATE no action;
+
+ CREATE INDEX IF NOT EXISTS "pages_blocks_install_order_idx" ON "pages_blocks_install" USING btree ("_order");
+ CREATE INDEX IF NOT EXISTS "pages_blocks_install_parent_id_idx" ON "pages_blocks_install" USING btree ("_parent_id");
+ CREATE INDEX IF NOT EXISTS "pages_blocks_install_path_idx" ON "pages_blocks_install" USING btree ("_path");
+ CREATE INDEX IF NOT EXISTS "pages_blocks_install_locale_idx" ON "pages_blocks_install" USING btree ("_locale");
+ CREATE INDEX IF NOT EXISTS "pages_blocks_swipe_cards_order_idx" ON "pages_blocks_swipe_cards" USING btree ("_order");
+ CREATE INDEX IF NOT EXISTS "pages_blocks_swipe_cards_parent_id_idx" ON "pages_blocks_swipe_cards" USING btree ("_parent_id");
+ CREATE INDEX IF NOT EXISTS "pages_blocks_swipe_cards_path_idx" ON "pages_blocks_swipe_cards" USING btree ("_path");
+ CREATE INDEX IF NOT EXISTS "pages_blocks_swipe_cards_locale_idx" ON "pages_blocks_swipe_cards" USING btree ("_locale");
+ CREATE INDEX IF NOT EXISTS "pages_blocks_swipe_cards_cards_order_idx" ON "pages_blocks_swipe_cards_cards" USING btree ("_order");
+ CREATE INDEX IF NOT EXISTS "pages_blocks_swipe_cards_cards_parent_id_idx" ON "pages_blocks_swipe_cards_cards" USING btree ("_parent_id");
+ CREATE INDEX IF NOT EXISTS "pages_blocks_swipe_cards_cards_locale_idx" ON "pages_blocks_swipe_cards_cards" USING btree ("_locale");
+ CREATE INDEX IF NOT EXISTS "pages_blocks_swipe_cards_cards_image_idx" ON "pages_blocks_swipe_cards_cards" USING btree ("image_id");
+
+ INSERT INTO "pages_blocks_install" (
+ "_order", "_parent_id", "_path", "_locale", "id", "heading", "subheading", "label", "code", "block_name"
+ )
+ SELECT "_order", "_parent_id", "_path", "_locale", "id", "heading", "subheading", "label", "code", "block_name"
+ FROM "pages_blocks_edition_install"
+ ON CONFLICT ("id") DO NOTHING;
+
+ INSERT INTO "pages_blocks_swipe_cards" (
+ "_order", "_parent_id", "_path", "_locale", "id", "heading", "subheading", "block_name"
+ )
+ SELECT "_order", "_parent_id", "_path", "_locale", "id", "heading", "subheading", "block_name"
+ FROM "pages_blocks_edition_use_cases"
+ ON CONFLICT ("id") DO NOTHING;
+
+ INSERT INTO "pages_blocks_swipe_cards_cards" (
+ "_order", "_parent_id", "_locale", "id", "title", "description", "image_id", "link_label", "link_url"
+ )
+ SELECT "_order", "_parent_id", "_locale", "id", "title", "description", "image_id", "link_label", "link_url"
+ FROM "pages_blocks_edition_use_cases_use_cases"
+ ON CONFLICT ("id") DO NOTHING;
+
+ DROP TABLE IF EXISTS "pages_blocks_edition_install" CASCADE;
+ DROP TABLE IF EXISTS "pages_blocks_edition_use_cases_use_cases" CASCADE;
+ DROP TABLE IF EXISTS "pages_blocks_edition_use_cases" CASCADE;
+ `)
+
+ await db.execute(sql`
+ DO $$ BEGIN
+ CREATE TYPE "public"."enum_pages_blocks_bento_variant" AS ENUM('feature', 'runtime');
+ EXCEPTION
+ WHEN duplicate_object THEN null;
+ END $$;
+
+ CREATE TABLE IF NOT EXISTS "pages_blocks_bento" (
+ "_order" integer NOT NULL,
+ "_parent_id" integer NOT NULL,
+ "_path" text NOT NULL,
+ "_locale" "_locales" NOT NULL,
+ "id" varchar PRIMARY KEY NOT NULL,
+ "variant" "enum_pages_blocks_bento_variant" DEFAULT 'feature' NOT NULL,
+ "block_name" varchar
+ );
+
+ ALTER TABLE "pages_blocks_bento"
+ ADD CONSTRAINT "pages_blocks_bento_parent_id_fk"
+ FOREIGN KEY ("_parent_id") REFERENCES "public"."pages"("id")
+ ON DELETE cascade ON UPDATE no action;
+
+ CREATE INDEX IF NOT EXISTS "pages_blocks_bento_order_idx" ON "pages_blocks_bento" USING btree ("_order");
+ CREATE INDEX IF NOT EXISTS "pages_blocks_bento_parent_id_idx" ON "pages_blocks_bento" USING btree ("_parent_id");
+ CREATE INDEX IF NOT EXISTS "pages_blocks_bento_path_idx" ON "pages_blocks_bento" USING btree ("_path");
+ CREATE INDEX IF NOT EXISTS "pages_blocks_bento_locale_idx" ON "pages_blocks_bento" USING btree ("_locale");
+ `)
+
+ await db.execute(sql`
+ CREATE TABLE IF NOT EXISTS "pages_blocks_roadmap" (
+ "_order" integer NOT NULL,
+ "_parent_id" integer NOT NULL,
+ "_path" text NOT NULL,
+ "_locale" "_locales" NOT NULL,
+ "id" varchar PRIMARY KEY NOT NULL,
+ "block_name" varchar
+ );
+
+ CREATE TABLE IF NOT EXISTS "pages_blocks_roadmap_items" (
+ "_order" integer NOT NULL,
+ "_parent_id" varchar NOT NULL,
+ "_locale" "_locales" NOT NULL,
+ "id" varchar PRIMARY KEY NOT NULL,
+ "time" varchar NOT NULL,
+ "title" varchar NOT NULL,
+ "description" varchar NOT NULL
+ );
+
+ ALTER TABLE "pages_blocks_roadmap"
+ ADD CONSTRAINT "pages_blocks_roadmap_parent_id_fk"
+ FOREIGN KEY ("_parent_id") REFERENCES "public"."pages"("id")
+ ON DELETE cascade ON UPDATE no action;
+
+ ALTER TABLE "pages_blocks_roadmap_items"
+ ADD CONSTRAINT "pages_blocks_roadmap_items_parent_id_fk"
+ FOREIGN KEY ("_parent_id") REFERENCES "public"."pages_blocks_roadmap"("id")
+ ON DELETE cascade ON UPDATE no action;
+
+ CREATE INDEX IF NOT EXISTS "pages_blocks_roadmap_order_idx" ON "pages_blocks_roadmap" USING btree ("_order");
+ CREATE INDEX IF NOT EXISTS "pages_blocks_roadmap_parent_id_idx" ON "pages_blocks_roadmap" USING btree ("_parent_id");
+ CREATE INDEX IF NOT EXISTS "pages_blocks_roadmap_path_idx" ON "pages_blocks_roadmap" USING btree ("_path");
+ CREATE INDEX IF NOT EXISTS "pages_blocks_roadmap_locale_idx" ON "pages_blocks_roadmap" USING btree ("_locale");
+ CREATE INDEX IF NOT EXISTS "pages_blocks_roadmap_items_order_idx" ON "pages_blocks_roadmap_items" USING btree ("_order");
+ CREATE INDEX IF NOT EXISTS "pages_blocks_roadmap_items_parent_id_idx" ON "pages_blocks_roadmap_items" USING btree ("_parent_id");
+ CREATE INDEX IF NOT EXISTS "pages_blocks_roadmap_items_locale_idx" ON "pages_blocks_roadmap_items" USING btree ("_locale");
+
+ INSERT INTO "pages_blocks_roadmap" (
+ "_order",
+ "_parent_id",
+ "_path",
+ "_locale",
+ "id"
+ )
+ SELECT
+ COALESCE((
+ SELECT MAX("_order") + 1
+ FROM (
+ SELECT "_order", "_parent_id", "_locale" FROM "pages_blocks_hero"
+ UNION ALL SELECT "_order", "_parent_id", "_locale" FROM "pages_blocks_brand"
+ UNION ALL SELECT "_order", "_parent_id", "_locale" FROM "pages_blocks_faq"
+ UNION ALL SELECT "_order", "_parent_id", "_locale" FROM "pages_blocks_cta"
+ UNION ALL SELECT "_order", "_parent_id", "_locale" FROM "pages_blocks_jobs"
+ UNION ALL SELECT "_order", "_parent_id", "_locale" FROM "pages_blocks_blog"
+ UNION ALL SELECT "_order", "_parent_id", "_locale" FROM "pages_blocks_actions"
+ UNION ALL SELECT "_order", "_parent_id", "_locale" FROM "pages_blocks_markdown"
+ UNION ALL SELECT "_order", "_parent_id", "_locale" FROM "pages_blocks_contact"
+ UNION ALL SELECT "_order", "_parent_id", "_locale" FROM "pages_blocks_bento"
+ UNION ALL SELECT "_order", "_parent_id", "_locale" FROM "pages_blocks_offset_cards"
+ UNION ALL SELECT "_order", "_parent_id", "_locale" FROM "pages_blocks_install"
+ UNION ALL SELECT "_order", "_parent_id", "_locale" FROM "pages_blocks_swipe_cards"
+ UNION ALL SELECT "_order", "_parent_id", "_locale" FROM "pages_blocks_card_row"
+ ) layout_orders
+ WHERE layout_orders."_parent_id" = pages."id"
+ AND layout_orders."_locale" = locale_values."_locale"
+ ), 0),
+ pages."id",
+ 'layout',
+ locale_values."_locale",
+ 'roadmap-' || pages."id" || '-' || locale_values."_locale"::text
+ FROM "pages" pages
+ CROSS JOIN (
+ SELECT DISTINCT "_locale" FROM "roadmap_items_locales"
+ ) locale_values
+ WHERE pages."slug" = 'main'
+ AND EXISTS (
+ SELECT 1 FROM "roadmap_items_locales"
+ WHERE "roadmap_items_locales"."_locale" = locale_values."_locale"
+ )
+ ON CONFLICT ("id") DO NOTHING;
+
+ INSERT INTO "pages_blocks_roadmap_items" (
+ "_order",
+ "_parent_id",
+ "_locale",
+ "id",
+ "time",
+ "title",
+ "description"
+ )
+ SELECT
+ ROW_NUMBER() OVER (PARTITION BY roadmap_locale."_locale" ORDER BY roadmap."created_at" DESC, roadmap."id" DESC) - 1,
+ 'roadmap-' || pages."id" || '-' || roadmap_locale."_locale"::text,
+ roadmap_locale."_locale",
+ 'roadmap-item-' || roadmap."id" || '-' || roadmap_locale."_locale"::text,
+ roadmap_locale."time",
+ roadmap_locale."title",
+ roadmap_locale."description"
+ FROM "roadmap_items" roadmap
+ INNER JOIN "roadmap_items_locales" roadmap_locale ON roadmap_locale."_parent_id" = roadmap."id"
+ INNER JOIN "pages" pages ON pages."slug" = 'main'
+ ON CONFLICT ("id") DO NOTHING;
+
+ ALTER TABLE "payload_locked_documents_rels" DROP CONSTRAINT IF EXISTS "payload_locked_documents_rels_roadmap_items_fk";
+ DROP INDEX IF EXISTS "payload_locked_documents_rels_roadmap_items_id_idx";
+ ALTER TABLE "payload_locked_documents_rels" DROP COLUMN IF EXISTS "roadmap_items_id";
+
+ DROP TABLE IF EXISTS "roadmap_items_locales" CASCADE;
+ DROP TABLE IF EXISTS "roadmap_items" CASCADE;
+ `)
+
+ await db.execute(sql`
+ ALTER TABLE "pages_blocks_bento" ADD COLUMN IF NOT EXISTS "section_heading" varchar;
+ ALTER TABLE "pages_blocks_bento" ADD COLUMN IF NOT EXISTS "section_description" varchar;
+ ALTER TABLE "pages_blocks_bento" ADD COLUMN IF NOT EXISTS "section_link_button_label" varchar;
+ ALTER TABLE "pages_blocks_bento" ADD COLUMN IF NOT EXISTS "section_link_button_url" varchar;
+
+ ALTER TABLE "pages_blocks_roadmap" ADD COLUMN IF NOT EXISTS "section_heading" varchar;
+ ALTER TABLE "pages_blocks_roadmap" ADD COLUMN IF NOT EXISTS "section_description" varchar;
+ ALTER TABLE "pages_blocks_roadmap" ADD COLUMN IF NOT EXISTS "section_link_button_label" varchar;
+ ALTER TABLE "pages_blocks_roadmap" ADD COLUMN IF NOT EXISTS "section_link_button_url" varchar;
+
+ ALTER TABLE "pages_blocks_faq" ADD COLUMN IF NOT EXISTS "section_heading" varchar;
+ ALTER TABLE "pages_blocks_faq" ADD COLUMN IF NOT EXISTS "section_description" varchar;
+ ALTER TABLE "pages_blocks_faq" ADD COLUMN IF NOT EXISTS "section_link_button_label" varchar;
+ ALTER TABLE "pages_blocks_faq" ADD COLUMN IF NOT EXISTS "section_link_button_url" varchar;
+
+ ALTER TABLE "pages_blocks_offset_cards" ADD COLUMN IF NOT EXISTS "section_heading" varchar;
+ ALTER TABLE "pages_blocks_offset_cards" ADD COLUMN IF NOT EXISTS "section_description" varchar;
+ ALTER TABLE "pages_blocks_offset_cards" ADD COLUMN IF NOT EXISTS "section_link_button_label" varchar;
+ ALTER TABLE "pages_blocks_offset_cards" ADD COLUMN IF NOT EXISTS "section_link_button_url" varchar;
+
+ ALTER TABLE "pages_blocks_card_row" ADD COLUMN IF NOT EXISTS "section_heading" varchar;
+ ALTER TABLE "pages_blocks_card_row" ADD COLUMN IF NOT EXISTS "section_description" varchar;
+ ALTER TABLE "pages_blocks_card_row" ADD COLUMN IF NOT EXISTS "section_link_button_label" varchar;
+ ALTER TABLE "pages_blocks_card_row" ADD COLUMN IF NOT EXISTS "section_link_button_url" varchar;
+
+ WITH section_source AS (
+ SELECT
+ sections."section_type",
+ sections."link_button_url",
+ sections_locales."_locale",
+ sections_locales."heading",
+ sections_locales."subheading",
+ sections_locales."link_button_label"
+ FROM "sections"
+ INNER JOIN "sections_locales" ON "sections_locales"."_parent_id" = sections."id"
+ )
+ UPDATE "pages_blocks_bento" block
+ SET
+ "section_heading" = section_source."heading",
+ "section_description" = section_source."subheading",
+ "section_link_button_label" = section_source."link_button_label",
+ "section_link_button_url" = section_source."link_button_url"
+ FROM section_source
+ WHERE block."_locale" = section_source."_locale"
+ AND (
+ (block."variant" = 'feature' AND section_source."section_type" = 'AppFeatureSection')
+ OR (block."variant" = 'runtime' AND section_source."section_type" = 'RuntimeFeatureSection')
+ );
+
+ WITH section_source AS (
+ SELECT
+ sections."section_type",
+ sections."link_button_url",
+ sections_locales."_locale",
+ sections_locales."heading",
+ sections_locales."subheading",
+ sections_locales."link_button_label"
+ FROM "sections"
+ INNER JOIN "sections_locales" ON "sections_locales"."_parent_id" = sections."id"
+ )
+ UPDATE "pages_blocks_roadmap" block
+ SET
+ "section_heading" = section_source."heading",
+ "section_description" = section_source."subheading",
+ "section_link_button_label" = section_source."link_button_label",
+ "section_link_button_url" = section_source."link_button_url"
+ FROM section_source
+ WHERE block."_locale" = section_source."_locale"
+ AND section_source."section_type" = 'RoadmapSection';
+
+ WITH section_source AS (
+ SELECT
+ sections."section_type",
+ sections."link_button_url",
+ sections_locales."_locale",
+ sections_locales."heading",
+ sections_locales."subheading",
+ sections_locales."link_button_label"
+ FROM "sections"
+ INNER JOIN "sections_locales" ON "sections_locales"."_parent_id" = sections."id"
+ )
+ UPDATE "pages_blocks_faq" block
+ SET
+ "section_heading" = section_source."heading",
+ "section_description" = section_source."subheading",
+ "section_link_button_label" = section_source."link_button_label",
+ "section_link_button_url" = section_source."link_button_url"
+ FROM section_source
+ WHERE block."_locale" = section_source."_locale"
+ AND section_source."section_type" = 'FaqSection';
+
+ WITH section_source AS (
+ SELECT
+ sections."section_type",
+ sections."link_button_url",
+ sections_locales."_locale",
+ sections_locales."heading",
+ sections_locales."subheading",
+ sections_locales."link_button_label"
+ FROM "sections"
+ INNER JOIN "sections_locales" ON "sections_locales"."_parent_id" = sections."id"
+ )
+ UPDATE "pages_blocks_offset_cards" block
+ SET
+ "section_heading" = section_source."heading",
+ "section_description" = section_source."subheading",
+ "section_link_button_label" = section_source."link_button_label",
+ "section_link_button_url" = section_source."link_button_url"
+ FROM section_source
+ WHERE block."_locale" = section_source."_locale"
+ AND COALESCE(block."show_section_header", false) = true
+ AND section_source."section_type" = 'UseCaseSection';
+
+ WITH section_source AS (
+ SELECT
+ sections."section_type",
+ sections."link_button_url",
+ sections_locales."_locale",
+ sections_locales."heading",
+ sections_locales."subheading",
+ sections_locales."link_button_label"
+ FROM "sections"
+ INNER JOIN "sections_locales" ON "sections_locales"."_parent_id" = sections."id"
+ )
+ UPDATE "pages_blocks_card_row" block
+ SET
+ "section_heading" = section_source."heading",
+ "section_description" = section_source."subheading",
+ "section_link_button_label" = section_source."link_button_label",
+ "section_link_button_url" = section_source."link_button_url"
+ FROM section_source
+ WHERE block."_locale" = section_source."_locale"
+ AND section_source."section_type" IN ('CardRowSection', 'DeploymentSection');
+
+ ALTER TABLE "pages_blocks_offset_cards" DROP COLUMN IF EXISTS "show_section_header";
+
+ ALTER TABLE "payload_locked_documents_rels" DROP CONSTRAINT IF EXISTS "payload_locked_documents_rels_sections_fk";
+ DROP INDEX IF EXISTS "payload_locked_documents_rels_sections_id_idx";
+ ALTER TABLE "payload_locked_documents_rels" DROP COLUMN IF EXISTS "sections_id";
+
+ DROP TABLE IF EXISTS "sections_locales" CASCADE;
+ DROP TABLE IF EXISTS "sections" CASCADE;
+ DROP TYPE IF EXISTS "public"."enum_sections_section_type";
+ `)
+
+ await db.execute(sql`
+ CREATE TABLE IF NOT EXISTS "pages_blocks_scroll_cards" (
+ "_order" integer NOT NULL,
+ "_parent_id" integer NOT NULL,
+ "_path" text NOT NULL,
+ "_locale" "_locales" NOT NULL,
+ "id" varchar PRIMARY KEY NOT NULL,
+ "block_name" varchar
+ );
+
+ CREATE TABLE IF NOT EXISTS "pages_blocks_scroll_cards_items" (
+ "_order" integer NOT NULL,
+ "_parent_id" varchar NOT NULL,
+ "_locale" "_locales" NOT NULL,
+ "id" varchar PRIMARY KEY NOT NULL,
+ "title" varchar NOT NULL,
+ "description" varchar NOT NULL,
+ "show_image_border" boolean DEFAULT true,
+ "section_layout" varchar DEFAULT 'imageRight' NOT NULL,
+ "gradient" varchar DEFAULT 'blue',
+ "gradient_direction" varchar DEFAULT 'topLeft',
+ "bullet_points" jsonb,
+ "image_id" integer,
+ "link_label" varchar,
+ "link_url" varchar
+ );
+
+ ALTER TABLE "pages_blocks_scroll_cards"
+ ADD CONSTRAINT "pages_blocks_scroll_cards_parent_id_fk"
+ FOREIGN KEY ("_parent_id") REFERENCES "public"."pages"("id")
+ ON DELETE cascade ON UPDATE no action;
+
+ ALTER TABLE "pages_blocks_scroll_cards_items"
+ ADD CONSTRAINT "pages_blocks_scroll_cards_items_image_id_media_id_fk"
+ FOREIGN KEY ("image_id") REFERENCES "public"."media"("id")
+ ON DELETE set null ON UPDATE no action;
+
+ ALTER TABLE "pages_blocks_scroll_cards_items"
+ ADD CONSTRAINT "pages_blocks_scroll_cards_items_parent_id_fk"
+ FOREIGN KEY ("_parent_id") REFERENCES "public"."pages_blocks_scroll_cards"("id")
+ ON DELETE cascade ON UPDATE no action;
+
+ CREATE INDEX IF NOT EXISTS "pages_blocks_scroll_cards_order_idx" ON "pages_blocks_scroll_cards" USING btree ("_order");
+ CREATE INDEX IF NOT EXISTS "pages_blocks_scroll_cards_parent_id_idx" ON "pages_blocks_scroll_cards" USING btree ("_parent_id");
+ CREATE INDEX IF NOT EXISTS "pages_blocks_scroll_cards_path_idx" ON "pages_blocks_scroll_cards" USING btree ("_path");
+ CREATE INDEX IF NOT EXISTS "pages_blocks_scroll_cards_locale_idx" ON "pages_blocks_scroll_cards" USING btree ("_locale");
+ CREATE INDEX IF NOT EXISTS "pages_blocks_scroll_cards_items_order_idx" ON "pages_blocks_scroll_cards_items" USING btree ("_order");
+ CREATE INDEX IF NOT EXISTS "pages_blocks_scroll_cards_items_parent_id_idx" ON "pages_blocks_scroll_cards_items" USING btree ("_parent_id");
+ CREATE INDEX IF NOT EXISTS "pages_blocks_scroll_cards_items_locale_idx" ON "pages_blocks_scroll_cards_items" USING btree ("_locale");
+ CREATE INDEX IF NOT EXISTS "pages_blocks_scroll_cards_items_image_idx" ON "pages_blocks_scroll_cards_items" USING btree ("image_id");
+ `)
+}
+
+export async function down({ db }: MigrateDownArgs): Promise {
+ await db.execute(sql`
+ DROP TABLE IF EXISTS "pages_blocks_scroll_cards_items" CASCADE;
+ DROP TABLE IF EXISTS "pages_blocks_scroll_cards" CASCADE;
+ `)
+
+ await db.execute(sql`
+ DO $$ BEGIN
+ CREATE TYPE "public"."enum_sections_section_type" AS ENUM('AppFeatureSection', 'FaqSection', 'RoadmapSection', 'RuntimeFeatureSection', 'UseCaseSection', 'DeploymentSection', 'CardRowSection');
+ EXCEPTION
+ WHEN duplicate_object THEN null;
+ END $$;
+
+ CREATE TABLE IF NOT EXISTS "sections" (
+ "id" serial PRIMARY KEY NOT NULL,
+ "section_type" "enum_sections_section_type" NOT NULL,
+ "link_button_url" varchar,
+ "updated_at" timestamp(3) with time zone DEFAULT now() NOT NULL,
+ "created_at" timestamp(3) with time zone DEFAULT now() NOT NULL
+ );
+
+ CREATE TABLE IF NOT EXISTS "sections_locales" (
+ "heading" varchar NOT NULL,
+ "subheading" varchar,
+ "link_button_label" varchar,
+ "id" serial PRIMARY KEY NOT NULL,
+ "_locale" "_locales" NOT NULL,
+ "_parent_id" integer NOT NULL
+ );
+
+ ALTER TABLE "sections_locales"
+ ADD CONSTRAINT "sections_locales_parent_id_fk"
+ FOREIGN KEY ("_parent_id") REFERENCES "public"."sections"("id")
+ ON DELETE cascade ON UPDATE no action;
+
+ CREATE INDEX IF NOT EXISTS "sections_updated_at_idx" ON "sections" USING btree ("updated_at");
+ CREATE INDEX IF NOT EXISTS "sections_created_at_idx" ON "sections" USING btree ("created_at");
+ CREATE UNIQUE INDEX IF NOT EXISTS "sections_locales_locale_parent_id_unique" ON "sections_locales" USING btree ("_locale","_parent_id");
+
+ ALTER TABLE "payload_locked_documents_rels" ADD COLUMN IF NOT EXISTS "sections_id" integer;
+ ALTER TABLE "payload_locked_documents_rels"
+ ADD CONSTRAINT "payload_locked_documents_rels_sections_fk"
+ FOREIGN KEY ("sections_id") REFERENCES "public"."sections"("id")
+ ON DELETE cascade ON UPDATE no action;
+ CREATE INDEX IF NOT EXISTS "payload_locked_documents_rels_sections_id_idx" ON "payload_locked_documents_rels" USING btree ("sections_id");
+
+ ALTER TABLE "pages_blocks_offset_cards" ADD COLUMN IF NOT EXISTS "show_section_header" boolean DEFAULT false;
+ ALTER TABLE "pages_blocks_bento" DROP COLUMN IF EXISTS "section_heading";
+ ALTER TABLE "pages_blocks_bento" DROP COLUMN IF EXISTS "section_description";
+ ALTER TABLE "pages_blocks_bento" DROP COLUMN IF EXISTS "section_link_button_label";
+ ALTER TABLE "pages_blocks_bento" DROP COLUMN IF EXISTS "section_link_button_url";
+ ALTER TABLE "pages_blocks_roadmap" DROP COLUMN IF EXISTS "section_heading";
+ ALTER TABLE "pages_blocks_roadmap" DROP COLUMN IF EXISTS "section_description";
+ ALTER TABLE "pages_blocks_roadmap" DROP COLUMN IF EXISTS "section_link_button_label";
+ ALTER TABLE "pages_blocks_roadmap" DROP COLUMN IF EXISTS "section_link_button_url";
+ ALTER TABLE "pages_blocks_faq" DROP COLUMN IF EXISTS "section_heading";
+ ALTER TABLE "pages_blocks_faq" DROP COLUMN IF EXISTS "section_description";
+ ALTER TABLE "pages_blocks_faq" DROP COLUMN IF EXISTS "section_link_button_label";
+ ALTER TABLE "pages_blocks_faq" DROP COLUMN IF EXISTS "section_link_button_url";
+ ALTER TABLE "pages_blocks_offset_cards" DROP COLUMN IF EXISTS "section_heading";
+ ALTER TABLE "pages_blocks_offset_cards" DROP COLUMN IF EXISTS "section_description";
+ ALTER TABLE "pages_blocks_offset_cards" DROP COLUMN IF EXISTS "section_link_button_label";
+ ALTER TABLE "pages_blocks_offset_cards" DROP COLUMN IF EXISTS "section_link_button_url";
+ ALTER TABLE "pages_blocks_card_row" DROP COLUMN IF EXISTS "section_heading";
+ ALTER TABLE "pages_blocks_card_row" DROP COLUMN IF EXISTS "section_description";
+ ALTER TABLE "pages_blocks_card_row" DROP COLUMN IF EXISTS "section_link_button_label";
+ ALTER TABLE "pages_blocks_card_row" DROP COLUMN IF EXISTS "section_link_button_url";
+ `)
+
+ await db.execute(sql`
+ CREATE TABLE IF NOT EXISTS "roadmap_items" (
+ "id" serial PRIMARY KEY NOT NULL,
+ "updated_at" timestamp(3) with time zone DEFAULT now() NOT NULL,
+ "created_at" timestamp(3) with time zone DEFAULT now() NOT NULL
+ );
+
+ CREATE TABLE IF NOT EXISTS "roadmap_items_locales" (
+ "time" varchar NOT NULL,
+ "title" varchar NOT NULL,
+ "description" varchar NOT NULL,
+ "id" serial PRIMARY KEY NOT NULL,
+ "_locale" "_locales" NOT NULL,
+ "_parent_id" integer NOT NULL
+ );
+
+ ALTER TABLE "roadmap_items_locales"
+ ADD CONSTRAINT "roadmap_items_locales_parent_id_fk"
+ FOREIGN KEY ("_parent_id") REFERENCES "public"."roadmap_items"("id")
+ ON DELETE cascade ON UPDATE no action;
+
+ CREATE INDEX IF NOT EXISTS "roadmap_items_updated_at_idx" ON "roadmap_items" USING btree ("updated_at");
+ CREATE INDEX IF NOT EXISTS "roadmap_items_created_at_idx" ON "roadmap_items" USING btree ("created_at");
+ CREATE UNIQUE INDEX IF NOT EXISTS "roadmap_items_locales_locale_parent_id_unique" ON "roadmap_items_locales" USING btree ("_locale","_parent_id");
+
+ ALTER TABLE "payload_locked_documents_rels" ADD COLUMN IF NOT EXISTS "roadmap_items_id" integer;
+ ALTER TABLE "payload_locked_documents_rels"
+ ADD CONSTRAINT "payload_locked_documents_rels_roadmap_items_fk"
+ FOREIGN KEY ("roadmap_items_id") REFERENCES "public"."roadmap_items"("id")
+ ON DELETE cascade ON UPDATE no action;
+ CREATE INDEX IF NOT EXISTS "payload_locked_documents_rels_roadmap_items_id_idx" ON "payload_locked_documents_rels" USING btree ("roadmap_items_id");
+
+ DROP TABLE IF EXISTS "pages_blocks_roadmap_items" CASCADE;
+ DROP TABLE IF EXISTS "pages_blocks_roadmap" CASCADE;
+ `)
+
+ await db.execute(sql`
+ DROP TABLE IF EXISTS "pages_blocks_bento" CASCADE;
+ DROP TYPE IF EXISTS "public"."enum_pages_blocks_bento_variant";
+ `)
+
+ await db.execute(sql`
+ CREATE TABLE IF NOT EXISTS "pages_blocks_edition_install" (
+ "_order" integer NOT NULL,
+ "_parent_id" integer NOT NULL,
+ "_path" text NOT NULL,
+ "_locale" "_locales" NOT NULL,
+ "id" varchar PRIMARY KEY NOT NULL,
+ "heading" varchar NOT NULL,
+ "subheading" varchar NOT NULL,
+ "label" varchar,
+ "code" varchar NOT NULL,
+ "block_name" varchar
+ );
+
+ CREATE TABLE IF NOT EXISTS "pages_blocks_edition_use_cases" (
+ "_order" integer NOT NULL,
+ "_parent_id" integer NOT NULL,
+ "_path" text NOT NULL,
+ "_locale" "_locales" NOT NULL,
+ "id" varchar PRIMARY KEY NOT NULL,
+ "heading" varchar NOT NULL,
+ "subheading" varchar NOT NULL,
+ "block_name" varchar
+ );
+
+ CREATE TABLE IF NOT EXISTS "pages_blocks_edition_use_cases_use_cases" (
+ "_order" integer NOT NULL,
+ "_parent_id" varchar NOT NULL,
+ "_locale" "_locales" NOT NULL,
+ "id" varchar PRIMARY KEY NOT NULL,
+ "title" varchar NOT NULL,
+ "description" varchar NOT NULL,
+ "image_id" integer,
+ "link_label" varchar,
+ "link_url" varchar
+ );
+
+ ALTER TABLE "pages_blocks_edition_install"
+ ADD CONSTRAINT "pages_blocks_edition_install_parent_id_fk"
+ FOREIGN KEY ("_parent_id") REFERENCES "public"."pages"("id")
+ ON DELETE cascade ON UPDATE no action;
+
+ ALTER TABLE "pages_blocks_edition_use_cases"
+ ADD CONSTRAINT "pages_blocks_edition_use_cases_parent_id_fk"
+ FOREIGN KEY ("_parent_id") REFERENCES "public"."pages"("id")
+ ON DELETE cascade ON UPDATE no action;
+
+ ALTER TABLE "pages_blocks_edition_use_cases_use_cases"
+ ADD CONSTRAINT "pages_blocks_edition_use_cases_use_cases_image_id_media_id_fk"
+ FOREIGN KEY ("image_id") REFERENCES "public"."media"("id")
+ ON DELETE set null ON UPDATE no action;
+
+ ALTER TABLE "pages_blocks_edition_use_cases_use_cases"
+ ADD CONSTRAINT "pages_blocks_edition_use_cases_use_cases_parent_id_fk"
+ FOREIGN KEY ("_parent_id") REFERENCES "public"."pages_blocks_edition_use_cases"("id")
+ ON DELETE cascade ON UPDATE no action;
+
+ CREATE INDEX IF NOT EXISTS "pages_blocks_edition_install_order_idx" ON "pages_blocks_edition_install" USING btree ("_order");
+ CREATE INDEX IF NOT EXISTS "pages_blocks_edition_install_parent_id_idx" ON "pages_blocks_edition_install" USING btree ("_parent_id");
+ CREATE INDEX IF NOT EXISTS "pages_blocks_edition_install_path_idx" ON "pages_blocks_edition_install" USING btree ("_path");
+ CREATE INDEX IF NOT EXISTS "pages_blocks_edition_install_locale_idx" ON "pages_blocks_edition_install" USING btree ("_locale");
+ CREATE INDEX IF NOT EXISTS "pages_blocks_edition_use_cases_order_idx" ON "pages_blocks_edition_use_cases" USING btree ("_order");
+ CREATE INDEX IF NOT EXISTS "pages_blocks_edition_use_cases_parent_id_idx" ON "pages_blocks_edition_use_cases" USING btree ("_parent_id");
+ CREATE INDEX IF NOT EXISTS "pages_blocks_edition_use_cases_path_idx" ON "pages_blocks_edition_use_cases" USING btree ("_path");
+ CREATE INDEX IF NOT EXISTS "pages_blocks_edition_use_cases_locale_idx" ON "pages_blocks_edition_use_cases" USING btree ("_locale");
+ CREATE INDEX IF NOT EXISTS "pages_blocks_edition_use_cases_use_cases_order_idx" ON "pages_blocks_edition_use_cases_use_cases" USING btree ("_order");
+ CREATE INDEX IF NOT EXISTS "pages_blocks_edition_use_cases_use_cases_parent_id_idx" ON "pages_blocks_edition_use_cases_use_cases" USING btree ("_parent_id");
+ CREATE INDEX IF NOT EXISTS "pages_blocks_edition_use_cases_use_cases_locale_idx" ON "pages_blocks_edition_use_cases_use_cases" USING btree ("_locale");
+ CREATE INDEX IF NOT EXISTS "pages_blocks_edition_use_cases_use_cases_image_idx" ON "pages_blocks_edition_use_cases_use_cases" USING btree ("image_id");
+
+ INSERT INTO "pages_blocks_edition_install" (
+ "_order", "_parent_id", "_path", "_locale", "id", "heading", "subheading", "label", "code", "block_name"
+ )
+ SELECT "_order", "_parent_id", "_path", "_locale", "id", "heading", "subheading", "label", "code", "block_name"
+ FROM "pages_blocks_install"
+ ON CONFLICT ("id") DO NOTHING;
+
+ INSERT INTO "pages_blocks_edition_use_cases" (
+ "_order", "_parent_id", "_path", "_locale", "id", "heading", "subheading", "block_name"
+ )
+ SELECT "_order", "_parent_id", "_path", "_locale", "id", COALESCE("heading", ''), COALESCE("subheading", ''), "block_name"
+ FROM "pages_blocks_swipe_cards"
+ ON CONFLICT ("id") DO NOTHING;
+
+ INSERT INTO "pages_blocks_edition_use_cases_use_cases" (
+ "_order", "_parent_id", "_locale", "id", "title", "description", "image_id", "link_label", "link_url"
+ )
+ SELECT "_order", "_parent_id", "_locale", "id", "title", "description", "image_id", "link_label", "link_url"
+ FROM "pages_blocks_swipe_cards_cards"
+ ON CONFLICT ("id") DO NOTHING;
+
+ DROP TABLE IF EXISTS "pages_blocks_swipe_cards_cards" CASCADE;
+ DROP TABLE IF EXISTS "pages_blocks_swipe_cards" CASCADE;
+ DROP TABLE IF EXISTS "pages_blocks_install" CASCADE;
+ `)
+
+ await db.execute(sql`
+ CREATE TABLE IF NOT EXISTS "pages_blocks_usecase" (
+ "_order" integer NOT NULL,
+ "_parent_id" integer NOT NULL,
+ "_path" text NOT NULL,
+ "_locale" "_locales" NOT NULL,
+ "id" varchar PRIMARY KEY NOT NULL,
+ "block_name" varchar
+ );
+
+ CREATE TABLE IF NOT EXISTS "pages_blocks_usecase_use_cases" (
+ "_order" integer NOT NULL,
+ "_parent_id" varchar NOT NULL,
+ "_locale" "_locales" NOT NULL,
+ "id" varchar PRIMARY KEY NOT NULL,
+ "label" varchar NOT NULL,
+ "title" varchar NOT NULL,
+ "description" varchar NOT NULL,
+ "image_id" integer,
+ "link_label" varchar,
+ "link_url" varchar
+ );
+
+ CREATE TABLE IF NOT EXISTS "pages_blocks_edition_features" (
+ "_order" integer NOT NULL,
+ "_parent_id" integer NOT NULL,
+ "_path" text NOT NULL,
+ "_locale" "_locales" NOT NULL,
+ "id" varchar PRIMARY KEY NOT NULL,
+ "block_name" varchar
+ );
+
+ CREATE TABLE IF NOT EXISTS "pages_blocks_edition_features_features" (
+ "_order" integer NOT NULL,
+ "_parent_id" varchar NOT NULL,
+ "_locale" "_locales" NOT NULL,
+ "id" varchar PRIMARY KEY NOT NULL,
+ "label" varchar NOT NULL,
+ "title" varchar NOT NULL,
+ "description" varchar NOT NULL,
+ "image_id" integer,
+ "link_label" varchar,
+ "link_url" varchar
+ );
+
+ ALTER TABLE "pages_blocks_usecase"
+ ADD CONSTRAINT "pages_blocks_usecase_parent_id_fk"
+ FOREIGN KEY ("_parent_id") REFERENCES "public"."pages"("id")
+ ON DELETE cascade ON UPDATE no action;
+
+ ALTER TABLE "pages_blocks_usecase_use_cases"
+ ADD CONSTRAINT "pages_blocks_usecase_use_cases_image_id_media_id_fk"
+ FOREIGN KEY ("image_id") REFERENCES "public"."media"("id")
+ ON DELETE set null ON UPDATE no action;
+
+ ALTER TABLE "pages_blocks_usecase_use_cases"
+ ADD CONSTRAINT "pages_blocks_usecase_use_cases_parent_id_fk"
+ FOREIGN KEY ("_parent_id") REFERENCES "public"."pages_blocks_usecase"("id")
+ ON DELETE cascade ON UPDATE no action;
+
+ ALTER TABLE "pages_blocks_edition_features"
+ ADD CONSTRAINT "pages_blocks_edition_features_parent_id_fk"
+ FOREIGN KEY ("_parent_id") REFERENCES "public"."pages"("id")
+ ON DELETE cascade ON UPDATE no action;
+
+ ALTER TABLE "pages_blocks_edition_features_features"
+ ADD CONSTRAINT "pages_blocks_edition_features_features_image_id_media_id_fk"
+ FOREIGN KEY ("image_id") REFERENCES "public"."media"("id")
+ ON DELETE set null ON UPDATE no action;
+
+ ALTER TABLE "pages_blocks_edition_features_features"
+ ADD CONSTRAINT "pages_blocks_edition_features_features_parent_id_fk"
+ FOREIGN KEY ("_parent_id") REFERENCES "public"."pages_blocks_edition_features"("id")
+ ON DELETE cascade ON UPDATE no action;
+
+ CREATE INDEX IF NOT EXISTS "pages_blocks_usecase_order_idx" ON "pages_blocks_usecase" USING btree ("_order");
+ CREATE INDEX IF NOT EXISTS "pages_blocks_usecase_parent_id_idx" ON "pages_blocks_usecase" USING btree ("_parent_id");
+ CREATE INDEX IF NOT EXISTS "pages_blocks_usecase_path_idx" ON "pages_blocks_usecase" USING btree ("_path");
+ CREATE INDEX IF NOT EXISTS "pages_blocks_usecase_locale_idx" ON "pages_blocks_usecase" USING btree ("_locale");
+ CREATE INDEX IF NOT EXISTS "pages_blocks_usecase_use_cases_order_idx" ON "pages_blocks_usecase_use_cases" USING btree ("_order");
+ CREATE INDEX IF NOT EXISTS "pages_blocks_usecase_use_cases_parent_id_idx" ON "pages_blocks_usecase_use_cases" USING btree ("_parent_id");
+ CREATE INDEX IF NOT EXISTS "pages_blocks_usecase_use_cases_locale_idx" ON "pages_blocks_usecase_use_cases" USING btree ("_locale");
+ CREATE INDEX IF NOT EXISTS "pages_blocks_usecase_use_cases_image_idx" ON "pages_blocks_usecase_use_cases" USING btree ("image_id");
+ CREATE INDEX IF NOT EXISTS "pages_blocks_edition_features_order_idx" ON "pages_blocks_edition_features" USING btree ("_order");
+ CREATE INDEX IF NOT EXISTS "pages_blocks_edition_features_parent_id_idx" ON "pages_blocks_edition_features" USING btree ("_parent_id");
+ CREATE INDEX IF NOT EXISTS "pages_blocks_edition_features_path_idx" ON "pages_blocks_edition_features" USING btree ("_path");
+ CREATE INDEX IF NOT EXISTS "pages_blocks_edition_features_locale_idx" ON "pages_blocks_edition_features" USING btree ("_locale");
+ CREATE INDEX IF NOT EXISTS "pages_blocks_edition_features_features_order_idx" ON "pages_blocks_edition_features_features" USING btree ("_order");
+ CREATE INDEX IF NOT EXISTS "pages_blocks_edition_features_features_parent_id_idx" ON "pages_blocks_edition_features_features" USING btree ("_parent_id");
+ CREATE INDEX IF NOT EXISTS "pages_blocks_edition_features_features_locale_idx" ON "pages_blocks_edition_features_features" USING btree ("_locale");
+ CREATE INDEX IF NOT EXISTS "pages_blocks_edition_features_features_image_idx" ON "pages_blocks_edition_features_features" USING btree ("image_id");
+
+ INSERT INTO "pages_blocks_usecase" (
+ "_order", "_parent_id", "_path", "_locale", "id", "block_name"
+ )
+ SELECT "_order", "_parent_id", "_path", "_locale", "id", "block_name"
+ FROM "pages_blocks_offset_cards"
+ WHERE "show_section_header" = true
+ ON CONFLICT ("id") DO NOTHING;
+
+ INSERT INTO "pages_blocks_usecase_use_cases" (
+ "_order", "_parent_id", "_locale", "id", "label", "title", "description", "image_id", "link_label", "link_url"
+ )
+ SELECT card."_order", card."_parent_id", card."_locale", card."id", card."label", card."title", card."description", card."image_id", card."link_label", card."link_url"
+ FROM "pages_blocks_offset_cards_cards" card
+ INNER JOIN "pages_blocks_offset_cards" block ON block."id" = card."_parent_id"
+ WHERE block."show_section_header" = true
+ ON CONFLICT ("id") DO NOTHING;
+
+ INSERT INTO "pages_blocks_edition_features" (
+ "_order", "_parent_id", "_path", "_locale", "id", "block_name"
+ )
+ SELECT "_order", "_parent_id", "_path", "_locale", "id", "block_name"
+ FROM "pages_blocks_offset_cards"
+ WHERE COALESCE("show_section_header", false) = false
+ ON CONFLICT ("id") DO NOTHING;
+
+ INSERT INTO "pages_blocks_edition_features_features" (
+ "_order", "_parent_id", "_locale", "id", "label", "title", "description", "image_id", "link_label", "link_url"
+ )
+ SELECT card."_order", card."_parent_id", card."_locale", card."id", card."label", card."title", card."description", card."image_id", card."link_label", card."link_url"
+ FROM "pages_blocks_offset_cards_cards" card
+ INNER JOIN "pages_blocks_offset_cards" block ON block."id" = card."_parent_id"
+ WHERE COALESCE(block."show_section_header", false) = false
+ ON CONFLICT ("id") DO NOTHING;
+
+ DROP TABLE IF EXISTS "pages_blocks_offset_cards_cards" CASCADE;
+ DROP TABLE IF EXISTS "pages_blocks_offset_cards" CASCADE;
+ `)
+
+ await db.execute(sql`
+ CREATE TABLE IF NOT EXISTS "pages_blocks_deployment" (
+ "_order" integer NOT NULL,
+ "_parent_id" integer NOT NULL,
+ "_path" text NOT NULL,
+ "_locale" "_locales" NOT NULL,
+ "id" varchar PRIMARY KEY NOT NULL,
+ "cloud_title" varchar,
+ "cloud_description" varchar,
+ "cloud_link_label" varchar,
+ "cloud_link_url" varchar,
+ "selfhost_title" varchar,
+ "selfhost_description" varchar,
+ "selfhost_link_label" varchar,
+ "selfhost_link_url" varchar,
+ "dynamic_title" varchar,
+ "dynamic_description" varchar,
+ "dynamic_link_label" varchar,
+ "dynamic_link_url" varchar,
+ "block_name" varchar
+ );
+
+ ALTER TABLE "pages_blocks_deployment"
+ ADD CONSTRAINT "pages_blocks_deployment_parent_id_fk"
+ FOREIGN KEY ("_parent_id") REFERENCES "public"."pages"("id")
+ ON DELETE cascade ON UPDATE no action;
+
+ CREATE INDEX IF NOT EXISTS "pages_blocks_deployment_order_idx" ON "pages_blocks_deployment" USING btree ("_order");
+ CREATE INDEX IF NOT EXISTS "pages_blocks_deployment_parent_id_idx" ON "pages_blocks_deployment" USING btree ("_parent_id");
+ CREATE INDEX IF NOT EXISTS "pages_blocks_deployment_path_idx" ON "pages_blocks_deployment" USING btree ("_path");
+ CREATE INDEX IF NOT EXISTS "pages_blocks_deployment_locale_idx" ON "pages_blocks_deployment" USING btree ("_locale");
+
+ INSERT INTO "pages_blocks_deployment" (
+ "_order", "_parent_id", "_path", "_locale", "id",
+ "cloud_title", "cloud_description", "cloud_link_label", "cloud_link_url",
+ "selfhost_title", "selfhost_description", "selfhost_link_label", "selfhost_link_url",
+ "dynamic_title", "dynamic_description", "dynamic_link_label", "dynamic_link_url",
+ "block_name"
+ )
+ SELECT
+ card_row."_order", card_row."_parent_id", card_row."_path", card_row."_locale", card_row."id",
+ cloud."title", cloud."description", cloud."link_label", cloud."link_url",
+ selfhost."title", selfhost."description", selfhost."link_label", selfhost."link_url",
+ dynamic."title", dynamic."description", dynamic."link_label", dynamic."link_url",
+ card_row."block_name"
+ FROM "pages_blocks_card_row" card_row
+ LEFT JOIN "pages_blocks_card_row_cards" cloud
+ ON cloud."_parent_id" = card_row."id" AND cloud."_order" = 0
+ LEFT JOIN "pages_blocks_card_row_cards" selfhost
+ ON selfhost."_parent_id" = card_row."id" AND selfhost."_order" = 1
+ LEFT JOIN "pages_blocks_card_row_cards" dynamic
+ ON dynamic."_parent_id" = card_row."id" AND dynamic."_order" = 2
+ ON CONFLICT ("id") DO NOTHING;
+
+ DROP TABLE IF EXISTS "pages_blocks_card_row_cards" CASCADE;
+ DROP TABLE IF EXISTS "pages_blocks_card_row" CASCADE;
+ `)
+
+ await db.execute(sql`
+ ALTER TABLE "pages_blocks_hero" DROP COLUMN IF EXISTS "grainient_colors_background_color";
+ ALTER TABLE "pages_blocks_hero" DROP COLUMN IF EXISTS "grainient_colors_color3";
+ ALTER TABLE "pages_blocks_hero" DROP COLUMN IF EXISTS "grainient_colors_color2";
+ ALTER TABLE "pages_blocks_hero" DROP COLUMN IF EXISTS "grainient_colors_color1";
+ ALTER TABLE "pages_blocks_hero" DROP COLUMN IF EXISTS "centered";
+
+ CREATE TYPE "public"."enum_pages_blocks_edition_hero_buttons_variant" AS ENUM('none', 'normal', 'outlined', 'filled');
+
+ CREATE TABLE IF NOT EXISTS "pages_blocks_edition_hero" (
+ "_order" integer NOT NULL,
+ "_parent_id" integer NOT NULL,
+ "_path" text NOT NULL,
+ "_locale" "_locales" NOT NULL,
+ "id" varchar PRIMARY KEY NOT NULL,
+ "heading" varchar NOT NULL,
+ "image_alt" varchar DEFAULT '' NOT NULL,
+ "block_name" varchar
+ );
+
+ CREATE TABLE IF NOT EXISTS "pages_blocks_edition_hero_texts" (
+ "_order" integer NOT NULL,
+ "_parent_id" varchar NOT NULL,
+ "_locale" "_locales" NOT NULL,
+ "id" varchar PRIMARY KEY NOT NULL,
+ "text" varchar NOT NULL
+ );
+
+ CREATE TABLE IF NOT EXISTS "pages_blocks_edition_hero_buttons" (
+ "_order" integer NOT NULL,
+ "_parent_id" varchar NOT NULL,
+ "_locale" "_locales" NOT NULL,
+ "id" varchar PRIMARY KEY NOT NULL,
+ "label" varchar NOT NULL,
+ "url" varchar NOT NULL,
+ "variant" "enum_pages_blocks_edition_hero_buttons_variant" DEFAULT 'normal'
+ );
+
+ ALTER TABLE "pages_blocks_edition_hero"
+ ADD CONSTRAINT "pages_blocks_edition_hero_parent_id_fk"
+ FOREIGN KEY ("_parent_id") REFERENCES "public"."pages"("id")
+ ON DELETE cascade ON UPDATE no action;
+
+ ALTER TABLE "pages_blocks_edition_hero_texts"
+ ADD CONSTRAINT "pages_blocks_edition_hero_texts_parent_id_fk"
+ FOREIGN KEY ("_parent_id") REFERENCES "public"."pages_blocks_edition_hero"("id")
+ ON DELETE cascade ON UPDATE no action;
+
+ ALTER TABLE "pages_blocks_edition_hero_buttons"
+ ADD CONSTRAINT "pages_blocks_edition_hero_buttons_parent_id_fk"
+ FOREIGN KEY ("_parent_id") REFERENCES "public"."pages_blocks_edition_hero"("id")
+ ON DELETE cascade ON UPDATE no action;
+
+ CREATE INDEX IF NOT EXISTS "pages_blocks_edition_hero_order_idx" ON "pages_blocks_edition_hero" USING btree ("_order");
+ CREATE INDEX IF NOT EXISTS "pages_blocks_edition_hero_parent_id_idx" ON "pages_blocks_edition_hero" USING btree ("_parent_id");
+ CREATE INDEX IF NOT EXISTS "pages_blocks_edition_hero_path_idx" ON "pages_blocks_edition_hero" USING btree ("_path");
+ CREATE INDEX IF NOT EXISTS "pages_blocks_edition_hero_locale_idx" ON "pages_blocks_edition_hero" USING btree ("_locale");
+ CREATE INDEX IF NOT EXISTS "pages_blocks_edition_hero_texts_order_idx" ON "pages_blocks_edition_hero_texts" USING btree ("_order");
+ CREATE INDEX IF NOT EXISTS "pages_blocks_edition_hero_texts_parent_id_idx" ON "pages_blocks_edition_hero_texts" USING btree ("_parent_id");
+ CREATE INDEX IF NOT EXISTS "pages_blocks_edition_hero_texts_locale_idx" ON "pages_blocks_edition_hero_texts" USING btree ("_locale");
+ CREATE INDEX IF NOT EXISTS "pages_blocks_edition_hero_buttons_order_idx" ON "pages_blocks_edition_hero_buttons" USING btree ("_order");
+ CREATE INDEX IF NOT EXISTS "pages_blocks_edition_hero_buttons_parent_id_idx" ON "pages_blocks_edition_hero_buttons" USING btree ("_parent_id");
+ CREATE INDEX IF NOT EXISTS "pages_blocks_edition_hero_buttons_locale_idx" ON "pages_blocks_edition_hero_buttons" USING btree ("_locale");
+ `)
+}
diff --git a/src/migrations/index.ts b/src/migrations/index.ts
index 31277611..f1f21361 100644
--- a/src/migrations/index.ts
+++ b/src/migrations/index.ts
@@ -9,6 +9,7 @@ import * as migration_20260412_174023_006_contact_page_description from './20260
import * as migration_20260415_025537_007_subscription_workflow_executions from './20260415_025537_007_subscription_workflow_executions';
import * as migration_20260425_134031_009_actions from './20260425_134031_009_actions';
import * as migration_20260424_151900_008_footer_contact_legal_fields from './20260424_151900_008_footer_contact_legal_fields';
+import * as migration_20260427_010_remove_edition_hero_block from './20260427_010_remove_edition_hero_block';
export const migrations = [
{
@@ -66,4 +67,9 @@ export const migrations = [
down: migration_20260424_151900_008_footer_contact_legal_fields.down,
name: '20260424_151900_008_footer_contact_legal_fields'
},
+ {
+ up: migration_20260427_010_remove_edition_hero_block.up,
+ down: migration_20260427_010_remove_edition_hero_block.down,
+ name: '20260427_010_remove_edition_hero_block'
+ },
];
diff --git a/src/payload-types.ts b/src/payload-types.ts
index 711bdfcb..a7719e71 100644
--- a/src/payload-types.ts
+++ b/src/payload-types.ts
@@ -70,7 +70,6 @@ export interface Config {
users: User;
media: Media;
navbarItems: NavbarItem;
- sections: Section;
footer: Footer;
'cookie-banner': CookieBanner;
pages: Page;
@@ -78,7 +77,6 @@ export interface Config {
actions: Action;
jobs: Job;
blog: Blog;
- roadmapItems: RoadmapItem;
'team-members': TeamMember;
subscriptionConfig: SubscriptionConfig;
exports: Export;
@@ -94,7 +92,6 @@ export interface Config {
users: UsersSelect | UsersSelect;
media: MediaSelect | MediaSelect;
navbarItems: NavbarItemsSelect | NavbarItemsSelect;
- sections: SectionsSelect | SectionsSelect;
footer: FooterSelect | FooterSelect;
'cookie-banner': CookieBannerSelect | CookieBannerSelect;
pages: PagesSelect | PagesSelect;
@@ -102,7 +99,6 @@ export interface Config {
actions: ActionsSelect | ActionsSelect;
jobs: JobsSelect | JobsSelect;
blog: BlogSelect | BlogSelect;
- roadmapItems: RoadmapItemsSelect | RoadmapItemsSelect;
'team-members': TeamMembersSelect | TeamMembersSelect;
subscriptionConfig: SubscriptionConfigSelect | SubscriptionConfigSelect;
exports: ExportsSelect | ExportsSelect;
@@ -229,28 +225,6 @@ export interface NavbarItem {
updatedAt: string;
createdAt: string;
}
-/**
- * This interface was referenced by `Config`'s JSON-Schema
- * via the `definition` "sections".
- */
-export interface Section {
- id: number;
- heading: string;
- subheading?: string | null;
- sectionType:
- | 'AppFeatureSection'
- | 'FaqSection'
- | 'RoadmapSection'
- | 'RuntimeFeatureSection'
- | 'UseCaseSection'
- | 'DeploymentSection';
- link_button?: {
- label?: string | null;
- url?: string | null;
- };
- updatedAt: string;
- createdAt: string;
-}
/**
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "footer".
@@ -363,6 +337,13 @@ export interface Page {
badge?: string | null;
badge_link?: string | null;
heading: string;
+ centered?: boolean | null;
+ grainientColors?: {
+ color1?: string | null;
+ color2?: string | null;
+ color3?: string | null;
+ backgroundColor?: string | null;
+ };
texts?:
| {
text: string;
@@ -382,28 +363,25 @@ export interface Page {
blockType: 'hero';
}
| {
- heading: string;
- texts?:
- | {
- text: string;
- id?: string | null;
- }[]
- | null;
- buttons?:
- | {
- label: string;
- url: string;
- variant?: ('none' | 'normal' | 'outlined' | 'filled') | null;
- id?: string | null;
- }[]
- | null;
- imageAlt: string;
+ sectionHeading?: string | null;
+ sectionDescription?: string | null;
+ sectionLinkButton?: {
+ label?: string | null;
+ url?: string | null;
+ };
+ variant: 'feature' | 'runtime';
id?: string | null;
blockName?: string | null;
- blockType: 'editionHero';
+ blockType: 'bento';
}
| {
- features: {
+ sectionHeading?: string | null;
+ sectionDescription?: string | null;
+ sectionLinkButton?: {
+ label?: string | null;
+ url?: string | null;
+ };
+ cards: {
label: string;
title: string;
description: string;
@@ -417,7 +395,7 @@ export interface Page {
}[];
id?: string | null;
blockName?: string | null;
- blockType: 'editionFeatures';
+ blockType: 'offsetCards';
}
| {
heading: string;
@@ -426,12 +404,12 @@ export interface Page {
code: string;
id?: string | null;
blockName?: string | null;
- blockType: 'editionInstall';
+ blockType: 'install';
}
| {
- heading: string;
- subheading: string;
- useCases: {
+ heading?: string | null;
+ subheading?: string | null;
+ cards: {
title: string;
description: string;
image?: (number | null) | Media;
@@ -443,7 +421,7 @@ export interface Page {
}[];
id?: string | null;
blockName?: string | null;
- blockType: 'editionUseCases';
+ blockType: 'swipeCards';
}
| {
description: string;
@@ -458,23 +436,12 @@ export interface Page {
blockType: 'brand';
}
| {
- useCases: {
- label: string;
- title: string;
- description: string;
- image?: (number | null) | Media;
- bulletPoints?: string[] | null;
- link?: {
- label?: string | null;
- url?: string | null;
- };
- id?: string | null;
- }[];
- id?: string | null;
- blockName?: string | null;
- blockType: 'usecase';
- }
- | {
+ sectionHeading?: string | null;
+ sectionDescription?: string | null;
+ sectionLinkButton?: {
+ label?: string | null;
+ url?: string | null;
+ };
items: {
question: string;
answer: string;
@@ -568,27 +535,64 @@ export interface Page {
blockType: 'contact';
}
| {
- cloudTitle?: string | null;
- cloudDescription?: string | null;
- cloudLink?: {
+ sectionHeading?: string | null;
+ sectionDescription?: string | null;
+ sectionLinkButton?: {
label?: string | null;
url?: string | null;
};
- selfhostTitle?: string | null;
- selfhostDescription?: string | null;
- selfhostLink?: {
- label?: string | null;
- url?: string | null;
- };
- dynamicTitle?: string | null;
- dynamicDescription?: string | null;
- dynamicLink?: {
+ cards?:
+ | {
+ title: string;
+ description?: string | null;
+ link?: {
+ label?: string | null;
+ url?: string | null;
+ };
+ image?: (number | null) | Media;
+ id?: string | null;
+ }[]
+ | null;
+ id?: string | null;
+ blockName?: string | null;
+ blockType: 'cardRow';
+ }
+ | {
+ sectionHeading?: string | null;
+ sectionDescription?: string | null;
+ sectionLinkButton?: {
label?: string | null;
url?: string | null;
};
+ items: {
+ time: string;
+ title: string;
+ description: string;
+ id?: string | null;
+ }[];
id?: string | null;
blockName?: string | null;
- blockType: 'deployment';
+ blockType: 'roadmap';
+ }
+ | {
+ items: {
+ title: string;
+ description: string;
+ showImageBorder?: boolean | null;
+ sectionLayout: 'imageRight' | 'imageLeft';
+ gradient?: ('blue' | 'yellow' | 'pink' | 'aqua' | 'brand' | 'neutral') | null;
+ gradientDirection?: ('topLeft' | 'topRight' | 'bottomLeft' | 'bottomRight') | null;
+ bulletPoints?: string[] | null;
+ image?: (number | null) | Media;
+ link?: {
+ label?: string | null;
+ url?: string | null;
+ };
+ id?: string | null;
+ }[];
+ id?: string | null;
+ blockName?: string | null;
+ blockType: 'scrollCards';
}
)[]
| null;
@@ -739,18 +743,6 @@ export interface TeamMember {
updatedAt: string;
createdAt: string;
}
-/**
- * This interface was referenced by `Config`'s JSON-Schema
- * via the `definition` "roadmapItems".
- */
-export interface RoadmapItem {
- id: number;
- time: string;
- title: string;
- description: string;
- updatedAt: string;
- createdAt: string;
-}
/**
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "subscriptionConfig".
@@ -1086,10 +1078,6 @@ export interface PayloadLockedDocument {
relationTo: 'navbarItems';
value: number | NavbarItem;
} | null)
- | ({
- relationTo: 'sections';
- value: number | Section;
- } | null)
| ({
relationTo: 'footer';
value: number | Footer;
@@ -1118,10 +1106,6 @@ export interface PayloadLockedDocument {
relationTo: 'blog';
value: number | Blog;
} | null)
- | ({
- relationTo: 'roadmapItems';
- value: number | RoadmapItem;
- } | null)
| ({
relationTo: 'team-members';
value: number | TeamMember;
@@ -1236,23 +1220,6 @@ export interface NavbarItemsSelect {
updatedAt?: T;
createdAt?: T;
}
-/**
- * This interface was referenced by `Config`'s JSON-Schema
- * via the `definition` "sections_select".
- */
-export interface SectionsSelect {
- heading?: T;
- subheading?: T;
- sectionType?: T;
- link_button?:
- | T
- | {
- label?: T;
- url?: T;
- };
- updatedAt?: T;
- createdAt?: T;
-}
/**
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "footer_select".
@@ -1382,6 +1349,15 @@ export interface PagesSelect {
badge?: T;
badge_link?: T;
heading?: T;
+ centered?: T;
+ grainientColors?:
+ | T
+ | {
+ color1?: T;
+ color2?: T;
+ color3?: T;
+ backgroundColor?: T;
+ };
texts?:
| T
| {
@@ -1399,32 +1375,33 @@ export interface PagesSelect {
id?: T;
blockName?: T;
};
- editionHero?:
+ bento?:
| T
| {
- heading?: T;
- texts?:
- | T
- | {
- text?: T;
- id?: T;
- };
- buttons?:
+ sectionHeading?: T;
+ sectionDescription?: T;
+ sectionLinkButton?:
| T
| {
label?: T;
url?: T;
- variant?: T;
- id?: T;
};
- imageAlt?: T;
+ variant?: T;
id?: T;
blockName?: T;
};
- editionFeatures?:
+ offsetCards?:
| T
| {
- features?:
+ sectionHeading?: T;
+ sectionDescription?: T;
+ sectionLinkButton?:
+ | T
+ | {
+ label?: T;
+ url?: T;
+ };
+ cards?:
| T
| {
label?: T;
@@ -1443,7 +1420,7 @@ export interface PagesSelect {
id?: T;
blockName?: T;
};
- editionInstall?:
+ install?:
| T
| {
heading?: T;
@@ -1453,12 +1430,12 @@ export interface PagesSelect {
id?: T;
blockName?: T;
};
- editionUseCases?:
+ swipeCards?:
| T
| {
heading?: T;
subheading?: T;
- useCases?:
+ cards?:
| T
| {
title?: T;
@@ -1488,31 +1465,17 @@ export interface PagesSelect {
id?: T;
blockName?: T;
};
- usecase?:
+ faq?:
| T
| {
- useCases?:
+ sectionHeading?: T;
+ sectionDescription?: T;
+ sectionLinkButton?:
| T
| {
label?: T;
- title?: T;
- description?: T;
- image?: T;
- bulletPoints?: T;
- link?:
- | T
- | {
- label?: T;
- url?: T;
- };
- id?: T;
+ url?: T;
};
- id?: T;
- blockName?: T;
- };
- faq?:
- | T
- | {
items?:
| T
| {
@@ -1600,33 +1563,78 @@ export interface PagesSelect {
id?: T;
blockName?: T;
};
- deployment?:
+ cardRow?:
| T
| {
- cloudTitle?: T;
- cloudDescription?: T;
- cloudLink?:
+ sectionHeading?: T;
+ sectionDescription?: T;
+ sectionLinkButton?:
| T
| {
label?: T;
url?: T;
};
- selfhostTitle?: T;
- selfhostDescription?: T;
- selfhostLink?:
+ cards?:
| T
| {
- label?: T;
- url?: T;
+ title?: T;
+ description?: T;
+ link?:
+ | T
+ | {
+ label?: T;
+ url?: T;
+ };
+ image?: T;
+ id?: T;
};
- dynamicTitle?: T;
- dynamicDescription?: T;
- dynamicLink?:
+ id?: T;
+ blockName?: T;
+ };
+ roadmap?:
+ | T
+ | {
+ sectionHeading?: T;
+ sectionDescription?: T;
+ sectionLinkButton?:
| T
| {
label?: T;
url?: T;
};
+ items?:
+ | T
+ | {
+ time?: T;
+ title?: T;
+ description?: T;
+ id?: T;
+ };
+ id?: T;
+ blockName?: T;
+ };
+ scrollCards?:
+ | T
+ | {
+ items?:
+ | T
+ | {
+ title?: T;
+ description?: T;
+ showImageBorder?: T;
+ sectionLayout?: T;
+ gradient?: T;
+ gradientDirection?: T;
+ bulletPoints?: T;
+ image?: T;
+ link?:
+ | T
+ | {
+ label?: T;
+ url?: T;
+ };
+ id?: T;
+ };
id?: T;
blockName?: T;
};
@@ -1719,17 +1727,6 @@ export interface BlogSelect {
updatedAt?: T;
createdAt?: T;
}
-/**
- * This interface was referenced by `Config`'s JSON-Schema
- * via the `definition` "roadmapItems_select".
- */
-export interface RoadmapItemsSelect {
- time?: T;
- title?: T;
- description?: T;
- updatedAt?: T;
- createdAt?: T;
-}
/**
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "team-members_select".
@@ -2025,7 +2022,6 @@ export interface TaskCreateCollectionExport {
| 'users'
| 'media'
| 'navbarItems'
- | 'sections'
| 'footer'
| 'cookie-banner'
| 'pages'
@@ -2033,7 +2029,6 @@ export interface TaskCreateCollectionExport {
| 'actions'
| 'jobs'
| 'blog'
- | 'roadmapItems'
| 'team-members'
| 'subscriptionConfig'
| 'exports'
diff --git a/src/payload.config.ts b/src/payload.config.ts
index c711e92e..fe0f891d 100644
--- a/src/payload.config.ts
+++ b/src/payload.config.ts
@@ -16,8 +16,6 @@ import { Jobs } from './collections/jobs'
import { Media } from './collections/media'
import { NavbarItems } from './collections/navbarItems'
import { Pages } from './collections/pages'
-import { RoadmapItems } from './collections/roadmapItems'
-import { Sections } from './collections/sections'
import { SubscriptionCollection } from './collections/subscriptionConfig'
import { TeamMembers } from './collections/teamMembers'
import { Users } from './collections/users'
@@ -27,7 +25,9 @@ const filename = fileURLToPath(import.meta.url)
const dirname = path.dirname(filename)
const smtpHost = process.env.SMTP_HOST
const isBuildPhase = process.env.NEXT_PHASE === "phase-production-build" || process.env.npm_lifecycle_event === "build"
+const isDevelopment = process.env.NODE_ENV === "development"
const shouldSkipEmailVerify =
+ isDevelopment ||
isBuildPhase ||
process.env.PAYLOAD_SKIP_EMAIL_VERIFY === "true" ||
!smtpHost
@@ -43,7 +43,7 @@ export default buildConfig({
locales: ['en', 'de'],
defaultLocale: 'en',
},
- collections: [Users, Media, NavbarItems, Sections, Footer, CookieBanner, Pages, Features, Actions, Jobs, Blog, RoadmapItems, TeamMembers, SubscriptionCollection],
+ collections: [Users, Media, NavbarItems, Footer, CookieBanner, Pages, Features, Actions, Jobs, Blog, TeamMembers, SubscriptionCollection],
jobs: {
autoRun: [{
cron: '*/5 * * * *', // Check every 5 minutes
@@ -89,7 +89,6 @@ export default buildConfig({
{ slug: 'users', },
{ slug: 'media', },
{ slug: 'navbarItems' },
- { slug: 'sections' },
{ slug: 'footer' },
{ slug: 'cookie-banner' },
{ slug: 'pages' },
@@ -97,7 +96,6 @@ export default buildConfig({
{ slug: 'actions' },
{ slug: 'jobs' },
{ slug: 'blog' },
- { slug: 'roadmapItems' },
{ slug: 'team-members' },
{ slug: 'subscriptionConfig' }
]