Integrate CMS with Marketing Solutions page

Links the marketing solutions frontend page to the Payload CMS Pages
collection via the new API library. Removes legacy static portfolio
routes and components to consolidate marketing content. Enhances the
Header and Footer Astro components with improved responsive styling.
This commit is contained in:
2026-02-27 20:05:43 +08:00
parent b1a8006f12
commit b199f89998
29 changed files with 6475 additions and 2434 deletions

View File

@@ -16,25 +16,9 @@ import { generateMeta } from '@/utilities/generateMeta'
import PageClient from './page.client'
import { LivePreviewListener } from '@/components/LivePreviewListener'
export async function generateStaticParams() {
const payload = await getPayload({ config: configPromise })
const posts = await payload.find({
collection: 'posts',
draft: false,
limit: 1000,
overrideAccess: false,
pagination: false,
select: {
slug: true,
},
})
const params = posts.docs.map(({ slug }) => {
return { slug }
})
return params
}
// Use dynamic rendering instead of static generation
// This avoids the need for database connection during build time
export const dynamic = 'force-dynamic'
type Args = {
params: Promise<{

View File

@@ -8,7 +8,8 @@ import { getPayload } from 'payload'
import React from 'react'
import PageClient from './page.client'
export const dynamic = 'force-static'
// Use dynamic rendering to avoid database connection during build
export const dynamic = 'force-dynamic'
export const revalidate = 600
export default async function Page() {

View File

@@ -9,6 +9,8 @@ import React from 'react'
import PageClient from './page.client'
import { notFound } from 'next/navigation'
// Use dynamic rendering to avoid database connection during build
export const dynamic = 'force-dynamic'
export const revalidate = 600
type Args = {

View File

@@ -0,0 +1,86 @@
import type { Block } from 'payload'
export const ServicesList: Block = {
slug: 'servicesList',
interfaceName: 'ServicesListBlock',
fields: [
{
name: 'services',
type: 'array',
required: true,
admin: {
initCollapsed: true,
},
fields: [
{
name: 'title',
type: 'text',
required: true,
},
{
name: 'description',
type: 'textarea',
required: true,
},
{
name: 'category',
type: 'text',
required: true,
},
{
name: 'iconType',
type: 'select',
defaultValue: 'preset',
options: [
{ label: 'Preset Icon', value: 'preset' },
{ label: 'Custom SVG', value: 'svg' },
{ label: 'Upload Image', value: 'upload' },
],
},
{
name: 'icon',
type: 'text',
admin: {
description: 'Preset icon name: facebook, google, ads, news, youtube, forum, web, video',
condition: (_, siblingData) => siblingData?.iconType === 'preset',
},
},
{
name: 'iconSvg',
type: 'textarea',
admin: {
description: 'Paste SVG code directly (e.g., <svg>...</svg>)',
condition: (_, siblingData) => siblingData?.iconType === 'svg',
},
},
{
name: 'iconImage',
type: 'upload',
relationTo: 'media',
admin: {
description: 'Upload an icon image (SVG, PNG)',
condition: (_, siblingData) => siblingData?.iconType === 'upload',
},
},
{
name: 'isHot',
type: 'checkbox',
defaultValue: false,
},
{
name: 'image',
type: 'upload',
relationTo: 'media',
},
{
name: 'link',
type: 'text',
},
],
},
],
labels: {
singular: 'Services List',
plural: 'Services Lists',
},
}

View File

@@ -8,6 +8,7 @@ import { Archive } from '../../blocks/ArchiveBlock/config'
import { CallToAction } from '../../blocks/CallToAction/config'
import { Content } from '../../blocks/Content/config'
import { MediaBlock } from '../../blocks/MediaBlock/config'
import { ServicesList } from '../../blocks/ServicesList/config'
import { hero } from '@/heros/config'
import { slugField } from '@/fields/slug'
import { populatePublishedAt } from '../../hooks/populatePublishedAt'
@@ -76,7 +77,7 @@ export const Pages: CollectionConfig<'pages'> = {
{
name: 'layout',
type: 'blocks',
blocks: [CallToAction, Content, MediaBlock, Archive],
blocks: [CallToAction, Content, MediaBlock, Archive, ServicesList],
required: true,
admin: {
initCollapsed: true,

View File

@@ -194,7 +194,7 @@ export interface Page {
| null;
media?: (string | null) | Media;
};
layout: (CallToActionBlock | ContentBlock | MediaBlock | ArchiveBlock)[];
layout: (CallToActionBlock | ContentBlock | MediaBlock | ArchiveBlock | ServicesListBlock)[];
meta?: {
title?: string | null;
/**
@@ -564,6 +564,37 @@ export interface ArchiveBlock {
blockName?: string | null;
blockType: 'archive';
}
/**
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "ServicesListBlock".
*/
export interface ServicesListBlock {
services: {
title: string;
description: string;
category: string;
iconType?: ('preset' | 'svg' | 'upload') | null;
/**
* Preset icon name: facebook, google, ads, news, youtube, forum, web, video
*/
icon?: string | null;
/**
* Paste SVG code directly (e.g., <svg>...</svg>)
*/
iconSvg?: string | null;
/**
* Upload an icon image (SVG, PNG)
*/
iconImage?: (string | null) | Media;
isHot?: boolean | null;
image?: (string | null) | Media;
link?: string | null;
id?: string | null;
}[];
id?: string | null;
blockName?: string | null;
blockType: 'servicesList';
}
/**
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "portfolio".
@@ -923,6 +954,7 @@ export interface PagesSelect<T extends boolean = true> {
content?: T | ContentBlockSelect<T>;
mediaBlock?: T | MediaBlockSelect<T>;
archive?: T | ArchiveBlockSelect<T>;
servicesList?: T | ServicesListBlockSelect<T>;
};
meta?:
| T
@@ -1011,6 +1043,29 @@ export interface ArchiveBlockSelect<T extends boolean = true> {
id?: T;
blockName?: T;
}
/**
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "ServicesListBlock_select".
*/
export interface ServicesListBlockSelect<T extends boolean = true> {
services?:
| T
| {
title?: T;
description?: T;
category?: T;
iconType?: T;
icon?: T;
iconSvg?: T;
iconImage?: T;
isHot?: T;
image?: T;
link?: T;
id?: T;
};
id?: T;
blockName?: T;
}
/**
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "posts_select".