This is the written guide for our dynamic website tutorial series (Part 3). You can find the full length video here: https://youtu.be/8BXT64lnTXc
--- This guide is WIP and will be extended & improved ---
Root Layout
https://nextjs.org/docs/app/building-your-application/upgrading/app-router-migration#step-2-creating-a-root-layout
TailwindCSS Setup
Website Layout
import React, { ReactNode } from 'react'
export default function layout({children}: {children: ReactNode}) {
return (
<div>
{/* Header */}
{children}
{/* Footer */}
</div>
)
}
[slug]/page.tsx file
import type { Metadata } from 'next'
import config from '@payload-config'
import { getPayloadHMR } from '@payloadcms/next/utilities'
import React, { cache } from 'react'
import type { Page as PageType } from '../../../payload-types'
import { Blocks } from '@/utils/RenderBlocks'
import { generateMeta } from '@/utils/generateMeta'
import { notFound } from 'next/navigation'
const queryPageBySlug = cache(async ({ slug }: { slug: string }) => {
const parsedSlug = decodeURIComponent(slug)
const payload = await getPayloadHMR({ config })
const result = await payload.find({
collection: 'pages',
limit: 1,
where: {
slug: {
equals: parsedSlug,
},
},
})
return result.docs?.[0] || null
})
export async function generateStaticParams() {
const payload = await getPayloadHMR({ config })
const pages = await payload.find({
collection: 'pages',
draft: false,
limit: 1000,
})
return pages.docs
?.filter((doc) => {
return doc.slug !== 'index'
})
.map(({ slug }) => slug)
}
export default async function Page({ params: { slug = 'index' } }) {
let page: PageType | null
page = await queryPageBySlug({
slug,
})
if (!page) {
return notFound()
}
return (
<article className="pt-16 pb-24">
<Blocks blocks={page.layout} />
</article>
)
}
RenderBlocks
import { Page } from '@/payload-types'
import React, { Fragment } from 'react'
const blockComponents = {
}
export const RenderBlocks: React.FC<{
blocks: Page['layout'][0][]
}> = (props) => {
const { blocks } = props
const hasBlocks = blocks && Array.isArray(blocks) && blocks.length > 0
if (hasBlocks) {
return (
<Fragment>
{blocks.map((block, index) => {
const { blockName, blockType } = block
if (blockType && blockType in blockComponents) {
const Block = blockComponents[blockType]
if (Block) {
return (
<div className="my-16" key={index}>
<Block id={blockName} {...block} />
</div>
)
}
}
return null
})}
</Fragment>
)
}
return null
}
RichText
You can find the RichText parser from the official Payload Website Template here: