Live preview when editting website! Very cool!

This commit is contained in:
2026-03-26 16:30:28 -05:00
parent b678e405c5
commit 475f1cad85
8 changed files with 78 additions and 6 deletions

View File

@@ -21,6 +21,7 @@
"@gib/backend": "workspace:*",
"@gib/ui": "workspace:*",
"@payloadcms/db-postgres": "^3.80.0",
"@payloadcms/live-preview-react": "^3.80.0",
"@payloadcms/next": "^3.80.0",
"@payloadcms/richtext-lexical": "^3.80.0",
"@sentry/nextjs": "^10.43.0",

View File

@@ -333,6 +333,7 @@ export interface LandingPage {
commandLabel?: string | null;
command?: string | null;
};
_status?: ('draft' | 'published') | null;
updatedAt?: string | null;
createdAt?: string | null;
}
@@ -403,6 +404,7 @@ export interface LandingPageSelect<T extends boolean = true> {
commandLabel?: T;
command?: T;
};
_status?: T;
updatedAt?: T;
createdAt?: T;
globalType?: T;

View File

@@ -1,11 +1,24 @@
import { CTA, Features, Hero, TechStack } from '@/components/landing';
import { RefreshRouteOnSave } from '@/components/payload/refresh-route-on-save';
import { getLandingPageContent } from '@/lib/payload/get-landing-page-content';
const Home = async () => {
const content = await getLandingPageContent();
type HomeProps = {
searchParams: Promise<{
preview?: string | string[];
}>;
};
const Home = async ({ searchParams }: HomeProps) => {
const resolvedSearchParams = await searchParams;
const previewParam = resolvedSearchParams.preview;
const isPreview = Array.isArray(previewParam)
? previewParam.includes('true')
: previewParam === 'true';
const content = await getLandingPageContent(isPreview);
return (
<main className='flex min-h-screen flex-col'>
{isPreview ? <RefreshRouteOnSave /> : null}
<Hero content={content.hero} />
<Features content={content.features} />
<TechStack content={content.techStack} />

View File

@@ -0,0 +1,16 @@
'use client';
import { useRouter } from 'next/navigation';
import { env } from '@/env';
import { RefreshRouteOnSave as PayloadRefreshRouteOnSave } from '@payloadcms/live-preview-react';
export const RefreshRouteOnSave = () => {
const router = useRouter();
return (
<PayloadRefreshRouteOnSave
refresh={() => router.refresh()}
serverURL={env.NEXT_PUBLIC_SITE_URL}
/>
);
};

View File

@@ -8,13 +8,16 @@ import {
import { getPayloadClient } from './get-payload';
export const getLandingPageContent = cache(
async (): Promise<LandingPageContent> => {
async (isPreview = false): Promise<LandingPageContent> => {
const payload = await getPayloadClient();
const landingPage = await (
payload as {
findGlobal: (args: { slug: string }) => Promise<unknown>;
findGlobal: (args: {
slug: string;
draft?: boolean;
}) => Promise<unknown>;
}
).findGlobal({ slug: 'landing-page' });
).findGlobal({ slug: 'landing-page', draft: isPreview });
return mergeLandingPageContent(
(landingPage as Partial<LandingPageContent> | null | undefined) ??

View File

@@ -8,6 +8,38 @@ export const LandingPage: GlobalConfig = {
access: {
read: () => true,
},
admin: {
livePreview: {
url: '/?preview=true',
breakpoints: [
{
label: 'Mobile',
name: 'mobile',
width: 390,
height: 844,
},
{
label: 'Tablet',
name: 'tablet',
width: 768,
height: 1024,
},
{
label: 'Desktop',
name: 'desktop',
width: 1440,
height: 1024,
},
],
},
},
versions: {
drafts: {
autosave: {
interval: 500,
},
},
},
fields: [
{
type: 'tabs',

View File

@@ -6,7 +6,7 @@ import {
} from '@convex-dev/auth/nextjs/server';
const isSignInPage = createRouteMatcher(['/sign-in']);
const isProtectedRoute = createRouteMatcher(['/profile']);
const isProtectedRoute = createRouteMatcher(['/profile', '/admin']);
export default convexAuthNextjsMiddleware(
async (request, { convexAuth }) => {