Live preview when editting website! Very cool!
This commit is contained in:
@@ -21,6 +21,7 @@
|
|||||||
"@gib/backend": "workspace:*",
|
"@gib/backend": "workspace:*",
|
||||||
"@gib/ui": "workspace:*",
|
"@gib/ui": "workspace:*",
|
||||||
"@payloadcms/db-postgres": "^3.80.0",
|
"@payloadcms/db-postgres": "^3.80.0",
|
||||||
|
"@payloadcms/live-preview-react": "^3.80.0",
|
||||||
"@payloadcms/next": "^3.80.0",
|
"@payloadcms/next": "^3.80.0",
|
||||||
"@payloadcms/richtext-lexical": "^3.80.0",
|
"@payloadcms/richtext-lexical": "^3.80.0",
|
||||||
"@sentry/nextjs": "^10.43.0",
|
"@sentry/nextjs": "^10.43.0",
|
||||||
|
|||||||
@@ -333,6 +333,7 @@ export interface LandingPage {
|
|||||||
commandLabel?: string | null;
|
commandLabel?: string | null;
|
||||||
command?: string | null;
|
command?: string | null;
|
||||||
};
|
};
|
||||||
|
_status?: ('draft' | 'published') | null;
|
||||||
updatedAt?: string | null;
|
updatedAt?: string | null;
|
||||||
createdAt?: string | null;
|
createdAt?: string | null;
|
||||||
}
|
}
|
||||||
@@ -403,6 +404,7 @@ export interface LandingPageSelect<T extends boolean = true> {
|
|||||||
commandLabel?: T;
|
commandLabel?: T;
|
||||||
command?: T;
|
command?: T;
|
||||||
};
|
};
|
||||||
|
_status?: T;
|
||||||
updatedAt?: T;
|
updatedAt?: T;
|
||||||
createdAt?: T;
|
createdAt?: T;
|
||||||
globalType?: T;
|
globalType?: T;
|
||||||
|
|||||||
@@ -1,11 +1,24 @@
|
|||||||
import { CTA, Features, Hero, TechStack } from '@/components/landing';
|
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';
|
import { getLandingPageContent } from '@/lib/payload/get-landing-page-content';
|
||||||
|
|
||||||
const Home = async () => {
|
type HomeProps = {
|
||||||
const content = await getLandingPageContent();
|
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 (
|
return (
|
||||||
<main className='flex min-h-screen flex-col'>
|
<main className='flex min-h-screen flex-col'>
|
||||||
|
{isPreview ? <RefreshRouteOnSave /> : null}
|
||||||
<Hero content={content.hero} />
|
<Hero content={content.hero} />
|
||||||
<Features content={content.features} />
|
<Features content={content.features} />
|
||||||
<TechStack content={content.techStack} />
|
<TechStack content={content.techStack} />
|
||||||
|
|||||||
16
apps/next/src/components/payload/refresh-route-on-save.tsx
Normal file
16
apps/next/src/components/payload/refresh-route-on-save.tsx
Normal 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}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};
|
||||||
@@ -8,13 +8,16 @@ import {
|
|||||||
import { getPayloadClient } from './get-payload';
|
import { getPayloadClient } from './get-payload';
|
||||||
|
|
||||||
export const getLandingPageContent = cache(
|
export const getLandingPageContent = cache(
|
||||||
async (): Promise<LandingPageContent> => {
|
async (isPreview = false): Promise<LandingPageContent> => {
|
||||||
const payload = await getPayloadClient();
|
const payload = await getPayloadClient();
|
||||||
const landingPage = await (
|
const landingPage = await (
|
||||||
payload as {
|
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(
|
return mergeLandingPageContent(
|
||||||
(landingPage as Partial<LandingPageContent> | null | undefined) ??
|
(landingPage as Partial<LandingPageContent> | null | undefined) ??
|
||||||
|
|||||||
@@ -8,6 +8,38 @@ export const LandingPage: GlobalConfig = {
|
|||||||
access: {
|
access: {
|
||||||
read: () => true,
|
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: [
|
fields: [
|
||||||
{
|
{
|
||||||
type: 'tabs',
|
type: 'tabs',
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import {
|
|||||||
} from '@convex-dev/auth/nextjs/server';
|
} from '@convex-dev/auth/nextjs/server';
|
||||||
|
|
||||||
const isSignInPage = createRouteMatcher(['/sign-in']);
|
const isSignInPage = createRouteMatcher(['/sign-in']);
|
||||||
const isProtectedRoute = createRouteMatcher(['/profile']);
|
const isProtectedRoute = createRouteMatcher(['/profile', '/admin']);
|
||||||
|
|
||||||
export default convexAuthNextjsMiddleware(
|
export default convexAuthNextjsMiddleware(
|
||||||
async (request, { convexAuth }) => {
|
async (request, { convexAuth }) => {
|
||||||
|
|||||||
5
bun.lock
5
bun.lock
@@ -73,6 +73,7 @@
|
|||||||
"@gib/backend": "workspace:*",
|
"@gib/backend": "workspace:*",
|
||||||
"@gib/ui": "workspace:*",
|
"@gib/ui": "workspace:*",
|
||||||
"@payloadcms/db-postgres": "^3.80.0",
|
"@payloadcms/db-postgres": "^3.80.0",
|
||||||
|
"@payloadcms/live-preview-react": "^3.80.0",
|
||||||
"@payloadcms/next": "^3.80.0",
|
"@payloadcms/next": "^3.80.0",
|
||||||
"@payloadcms/richtext-lexical": "^3.80.0",
|
"@payloadcms/richtext-lexical": "^3.80.0",
|
||||||
"@sentry/nextjs": "^10.43.0",
|
"@sentry/nextjs": "^10.43.0",
|
||||||
@@ -1155,6 +1156,10 @@
|
|||||||
|
|
||||||
"@payloadcms/graphql": ["@payloadcms/graphql@3.80.0", "", { "dependencies": { "graphql-scalars": "1.22.2", "pluralize": "8.0.0", "ts-essentials": "10.0.3", "tsx": "4.21.0" }, "peerDependencies": { "graphql": "^16.8.1", "payload": "3.80.0" }, "bin": { "payload-graphql": "bin.js" } }, "sha512-AlJcFI/R+4SRPWW51ny2BsIj+4j6qVxyn0W5Kz1f5MMfheuD844tc92O+IwmUsrRsb0l6zv3zI3G3M6V2WdFFQ=="],
|
"@payloadcms/graphql": ["@payloadcms/graphql@3.80.0", "", { "dependencies": { "graphql-scalars": "1.22.2", "pluralize": "8.0.0", "ts-essentials": "10.0.3", "tsx": "4.21.0" }, "peerDependencies": { "graphql": "^16.8.1", "payload": "3.80.0" }, "bin": { "payload-graphql": "bin.js" } }, "sha512-AlJcFI/R+4SRPWW51ny2BsIj+4j6qVxyn0W5Kz1f5MMfheuD844tc92O+IwmUsrRsb0l6zv3zI3G3M6V2WdFFQ=="],
|
||||||
|
|
||||||
|
"@payloadcms/live-preview": ["@payloadcms/live-preview@3.80.0", "", {}, "sha512-O28f7DoiE7n5z1ukiquVNNyqJcLgzNP1Qb/g9tmY1ppe16c+jni0NbSRw55uAsZ0PdfZuiJNZ+50iubEtsXCdw=="],
|
||||||
|
|
||||||
|
"@payloadcms/live-preview-react": ["@payloadcms/live-preview-react@3.80.0", "", { "dependencies": { "@payloadcms/live-preview": "3.80.0" }, "peerDependencies": { "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.1 || ^19.1.2 || ^19.2.1", "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.1 || ^19.1.2 || ^19.2.1" } }, "sha512-J0IUH9gow3wWJqUitJdS56z5Dj2cxBHZZjrnHwb4qF5bV3wChSDTLZvzRB8lZ1/m2vB7yGTgateHDLBZ6Q5PpA=="],
|
||||||
|
|
||||||
"@payloadcms/next": ["@payloadcms/next@3.80.0", "", { "dependencies": { "@dnd-kit/core": "6.3.1", "@dnd-kit/modifiers": "9.0.0", "@dnd-kit/sortable": "10.0.0", "@payloadcms/graphql": "3.80.0", "@payloadcms/translations": "3.80.0", "@payloadcms/ui": "3.80.0", "busboy": "^1.6.0", "dequal": "2.0.3", "file-type": "19.3.0", "graphql-http": "^1.22.0", "graphql-playground-html": "1.6.30", "http-status": "2.1.0", "path-to-regexp": "6.3.0", "qs-esm": "7.0.2", "sass": "1.77.4", "uuid": "10.0.0" }, "peerDependencies": { "graphql": "^16.8.1", "next": ">=15.2.9 <15.3.0 || >=15.3.9 <15.4.0 || >=15.4.11 <15.5.0 || >=16.2.0-canary.10 <17.0.0", "payload": "3.80.0" } }, "sha512-JL7Ydi/rm7hoLDzMO6H1mBQdvxJ5Dww26aomMOYMziUr9YzU6w+W5EnJgN3x2vH0myvDr9VUfNTTBNK616G5LQ=="],
|
"@payloadcms/next": ["@payloadcms/next@3.80.0", "", { "dependencies": { "@dnd-kit/core": "6.3.1", "@dnd-kit/modifiers": "9.0.0", "@dnd-kit/sortable": "10.0.0", "@payloadcms/graphql": "3.80.0", "@payloadcms/translations": "3.80.0", "@payloadcms/ui": "3.80.0", "busboy": "^1.6.0", "dequal": "2.0.3", "file-type": "19.3.0", "graphql-http": "^1.22.0", "graphql-playground-html": "1.6.30", "http-status": "2.1.0", "path-to-regexp": "6.3.0", "qs-esm": "7.0.2", "sass": "1.77.4", "uuid": "10.0.0" }, "peerDependencies": { "graphql": "^16.8.1", "next": ">=15.2.9 <15.3.0 || >=15.3.9 <15.4.0 || >=15.4.11 <15.5.0 || >=16.2.0-canary.10 <17.0.0", "payload": "3.80.0" } }, "sha512-JL7Ydi/rm7hoLDzMO6H1mBQdvxJ5Dww26aomMOYMziUr9YzU6w+W5EnJgN3x2vH0myvDr9VUfNTTBNK616G5LQ=="],
|
||||||
|
|
||||||
"@payloadcms/richtext-lexical": ["@payloadcms/richtext-lexical@3.80.0", "", { "dependencies": { "@lexical/clipboard": "0.41.0", "@lexical/headless": "0.41.0", "@lexical/html": "0.41.0", "@lexical/link": "0.41.0", "@lexical/list": "0.41.0", "@lexical/mark": "0.41.0", "@lexical/react": "0.41.0", "@lexical/rich-text": "0.41.0", "@lexical/selection": "0.41.0", "@lexical/table": "0.41.0", "@lexical/utils": "0.41.0", "@payloadcms/translations": "3.80.0", "@payloadcms/ui": "3.80.0", "@types/uuid": "10.0.0", "acorn": "8.16.0", "bson-objectid": "2.0.4", "csstype": "3.1.3", "dequal": "2.0.3", "escape-html": "1.0.3", "jsox": "1.2.121", "lexical": "0.41.0", "mdast-util-from-markdown": "2.0.2", "mdast-util-mdx-jsx": "3.1.3", "micromark-extension-mdx-jsx": "3.0.1", "qs-esm": "7.0.2", "react-error-boundary": "4.1.2", "ts-essentials": "10.0.3", "uuid": "10.0.0" }, "peerDependencies": { "@faceless-ui/modal": "3.0.0", "@faceless-ui/scroll-info": "2.0.0", "@payloadcms/next": "3.80.0", "payload": "3.80.0", "react": "^19.0.1 || ^19.1.2 || ^19.2.1", "react-dom": "^19.0.1 || ^19.1.2 || ^19.2.1" } }, "sha512-P7F7VoCS4dZFxdausUdxc79t6tlMpeusf2QwdtyBnB4FwuC8sAc2TW9dxsP+N/gvAnEuPR6rAd/kUma1kQoJug=="],
|
"@payloadcms/richtext-lexical": ["@payloadcms/richtext-lexical@3.80.0", "", { "dependencies": { "@lexical/clipboard": "0.41.0", "@lexical/headless": "0.41.0", "@lexical/html": "0.41.0", "@lexical/link": "0.41.0", "@lexical/list": "0.41.0", "@lexical/mark": "0.41.0", "@lexical/react": "0.41.0", "@lexical/rich-text": "0.41.0", "@lexical/selection": "0.41.0", "@lexical/table": "0.41.0", "@lexical/utils": "0.41.0", "@payloadcms/translations": "3.80.0", "@payloadcms/ui": "3.80.0", "@types/uuid": "10.0.0", "acorn": "8.16.0", "bson-objectid": "2.0.4", "csstype": "3.1.3", "dequal": "2.0.3", "escape-html": "1.0.3", "jsox": "1.2.121", "lexical": "0.41.0", "mdast-util-from-markdown": "2.0.2", "mdast-util-mdx-jsx": "3.1.3", "micromark-extension-mdx-jsx": "3.0.1", "qs-esm": "7.0.2", "react-error-boundary": "4.1.2", "ts-essentials": "10.0.3", "uuid": "10.0.0" }, "peerDependencies": { "@faceless-ui/modal": "3.0.0", "@faceless-ui/scroll-info": "2.0.0", "@payloadcms/next": "3.80.0", "payload": "3.80.0", "react": "^19.0.1 || ^19.1.2 || ^19.2.1", "react-dom": "^19.0.1 || ^19.1.2 || ^19.2.1" } }, "sha512-P7F7VoCS4dZFxdausUdxc79t6tlMpeusf2QwdtyBnB4FwuC8sAc2TW9dxsP+N/gvAnEuPR6rAd/kUma1kQoJug=="],
|
||||||
|
|||||||
Reference in New Issue
Block a user