Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 43 additions & 0 deletions examples/nextjs/kitchen-sink/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.

# dependencies
/node_modules
/.pnp
.pnp.*
.yarn/*
!.yarn/patches
!.yarn/plugins
!.yarn/releases
!.yarn/versions

# testing
/coverage

# next.js
/.next/
/out/

# production
/build

# misc
.DS_Store
*.pem

# debug
npm-debug.log*
yarn-debug.log*
yarn-error.log*
.pnpm-debug.log*

# env files (can opt-in for committing if needed)
.env*

# vercel
.vercel

# typescript
*.tsbuildinfo
next-env.d.ts

package-lock.json
40 changes: 40 additions & 0 deletions examples/nextjs/kitchen-sink/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
# Kitchen Sink Example

A comprehensive Next.js example showcasing FaustJS features including template hierarchy, data fetching, and WordPress integration.

## Features

- **Template Hierarchy**: Dynamic WordPress template mapping (single, page, archive, home)
- **Data Fetching**: Server-side rendering with WordPress GraphQL data
- **Preview Mode**: WordPress post/page previews with authentication
- **Fallback Routing**: Catch-all routing with blocking fallback strategy
- **Dynamic Loading**: Code-split templates for optimal performance

## Quick Start

1. Install dependencies:

```bash
npm install
```

2. Configure environment variables:

```bash
cp .env.example .env.local
# Add your NEXT_PUBLIC_WORDPRESS_URL
```

3. Run development server:
```bash
npm run dev
```

## Architecture

- Uses `[[...identifier]].js` for dynamic WordPress routing
- Template queries are fetched server-side using `@faustjs/data-fetching`
- WordPress templates are dynamically loaded based on content type
- Supports both static generation and draft previews

Perfect for testing FaustJS capabilities and as a reference implementation.
20 changes: 20 additions & 0 deletions examples/nextjs/kitchen-sink/eslint.config.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { FlatCompat } from "@eslint/eslintrc";
import js from "@eslint/js";
import { dirname } from "path";
import { fileURLToPath } from "url";

const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);

const compat = new FlatCompat({
baseDirectory: __dirname,
recommendedConfig: js.configs.recommended,
});

const eslintConfig = [
...compat.config({
extends: ["eslint:recommended", "next/core-web-vitals"],
}),
];

export default eslintConfig;
7 changes: 7 additions & 0 deletions examples/nextjs/kitchen-sink/jsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"compilerOptions": {
"paths": {
"@/*": ["./src/*"]
}
}
}
6 changes: 6 additions & 0 deletions examples/nextjs/kitchen-sink/next.config.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
/** @type {import('next').NextConfig} */
const nextConfig = {
reactStrictMode: true,
};

export default nextConfig;
28 changes: 28 additions & 0 deletions examples/nextjs/kitchen-sink/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
{
"name": "@faustjs/kitchen-sink-example",
"version": "0.1.0",
"private": true,
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start",
"lint": "next lint"
},
"dependencies": {
"@faustjs/nextjs": "workspace:*",
"@faustjs/template-hierarchy": "workspace:*",
"@faustjs/data-fetching": "workspace:*",
"graphql": "^16.11.0",
"graphql-tag": "^2.12.6",
"next": "15.2.4",
"react": "^19.0.0",
"react-dom": "^19.0.0"
},
"devDependencies": {
"@eslint/eslintrc": "^3",
"@tailwindcss/postcss": "^4",
"eslint": "^9",
"eslint-config-next": "15.2.4",
"tailwindcss": "^4"
}
}
5 changes: 5 additions & 0 deletions examples/nextjs/kitchen-sink/postcss.config.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
const config = {
plugins: ["@tailwindcss/postcss"],
};

export default config;
Binary file added examples/nextjs/kitchen-sink/public/favicon.ico
Binary file not shown.
32 changes: 32 additions & 0 deletions examples/nextjs/kitchen-sink/src/components/BlogPostItem.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import Link from "next/link";

export function BlogPostItem({ post }) {
const { title, date, excerpt, uri, featuredImage } = post ?? {};

return (
<article className='container max-w-4xl px-10 py-6 mx-auto rounded-lg shadow-sm bg-gray-50 mb-4'>
<time dateTime={date} className='text-sm text-gray-600'>
{new Date(date).toLocaleDateString("en-US", {
year: "numeric",
month: "long",
})}
</time>

{featuredImage && (
<img src={featuredImage?.node?.sourceUrl} alt='' className='w-full h-48 object-cover rounded-t-lg mt-2 mb-4' />
)}

<h2 className='mt-3'>
<Link href={uri} className='text-2xl font-bold hover:underline'>
{title}
</Link>
</h2>

<div className='mt-2 mb-4' dangerouslySetInnerHTML={{ __html: excerpt }} />

<Link href={uri} className='hover:underline text-orange-600 mt-4'>
Read more
</Link>
</article>
);
}
20 changes: 20 additions & 0 deletions examples/nextjs/kitchen-sink/src/components/Header.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
/* eslint-disable @next/next/no-html-link-for-pages */
import Link from 'next/link';

export default function Header() {
return (
<header className="bg-gray-800 text-white py-4 px-8">
<div className="flex justify-between items-center max-w-4xl mx-auto">
<div className="text-3xl font-semibold">
<Link href="/">Headless</Link>
</div>

<nav className="space-x-6">
<Link href="/" className="text-lg hover:underline">
Home
</Link>
</nav>
</div>
</header>
);
}
18 changes: 18 additions & 0 deletions examples/nextjs/kitchen-sink/src/components/Layout.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { useRouter } from 'next/router';
import Header from './Header';
import PreviewButton from './PreviewButton';

export default function Layout({ children }) {
const router = useRouter();

return (
<>
<Header />
<main className="bg-stone-100 text-gray-800 pb-16 pt-8 min-h-screen">
{children}

{router.isPreview && <PreviewButton />}
</main>
</>
);
}
17 changes: 17 additions & 0 deletions examples/nextjs/kitchen-sink/src/components/PreviewButton.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { useRouter } from "next/router";

export default function PreviewButton() {
const router = useRouter();

return (
<div className='fixed bottom-4 right-4 bg-[#0ECAD4] text-[#002447] pl-4 pr-2 py-2 rounded-lg shadow-lg flex items-center gap-3 z-50 max-w-xs'>
<span className='font-semibold text-sm'>Preview mode is on</span>

<button
onClick={() => router.push("/api/disable-preview")}
className='bg-[#002447] text-white text-sm px-3 py-2 rounded-md hover:opacity-90 transition cursor-pointer'>
Exit preview mode
</button>
</div>
);
}
85 changes: 85 additions & 0 deletions examples/nextjs/kitchen-sink/src/pages/[[...identifier]].js
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
import { getAuthString } from '@/utils/getAuthString';
import availableTemplates from '@/wp-templates';
import availableQueries from '@/wp-templates/templateQueries';
import {
createDefaultClient,
setGraphQLClient,
uriToTemplate,
} from '@faustjs/nextjs/pages';
import { fetchTemplateQueries } from '@faustjs/data-fetching';

export default function Page(props) {
const { templateData } = props;

const PageTemplate = availableTemplates[templateData?.template?.id];

return <PageTemplate {...props} />;
}

export async function getStaticProps({
params,
draftMode: isDraftModeEnabled,
}) {
// Send the authentication string only if draft mode is enabled
const headers = isDraftModeEnabled
? {
Authorization: getAuthString(),
}
: null;

const client = createDefaultClient(
process.env.NEXT_PUBLIC_WORDPRESS_URL,
headers,
);

setGraphQLClient(client);

const uri = params?.identifier ? `/${params.identifier.join('/')}/` : '/';

const variables = isDraftModeEnabled
? {
id: params.identifier?.[0],
asPreview: true,
}
: { uri };

try {
const templateData = await uriToTemplate({
...variables,
availableTemplates: Object.keys(availableTemplates),
wordpressUrl: process.env.NEXT_PUBLIC_WORDPRESS_URL,
});

if (
!templateData?.template?.id ||
templateData?.template?.id === '404 Not Found'
) {
return { notFound: true };
}

const queriesData = await fetchTemplateQueries({
availableQueries,
templateData,
client,
locale: templateData?.seedNode?.locale,
});

return {
props: {
uri,
templateData: JSON.parse(JSON.stringify(templateData)),
queriesData,
},
};
} catch (error) {
console.error('Error resolving template:', error);
return { notFound: true };
}
}

export async function getStaticPaths() {
return {
paths: [],
fallback: 'blocking',
};
}
10 changes: 10 additions & 0 deletions examples/nextjs/kitchen-sink/src/pages/_app.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import Layout from '@/components/Layout';
import '@/styles/globals.css';

export default function App({ Component, pageProps }) {
return (
<Layout>
<Component {...pageProps} />
</Layout>
);
}
13 changes: 13 additions & 0 deletions examples/nextjs/kitchen-sink/src/pages/_document.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { Html, Head, Main, NextScript } from "next/document";

export default function Document() {
return (
<Html lang="en">
<Head />
<body className="antialiased">
<Main />
<NextScript />
</body>
</Html>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
export default async function handler(_, res) {
// This removes __prerender_bypass cookie
// More info: https://nextjs.org/docs/pages/guides/draft-mode#clear-the-draft-mode-cookie
res.setDraftMode({ enable: false });

return res.redirect("/");
}
9 changes: 9 additions & 0 deletions examples/nextjs/kitchen-sink/src/pages/api/preview.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { getAuthString } from '@/utils/getAuthString';
import { enablePreview } from '@faustjs/nextjs/pages';

export default enablePreview({
wordpressUrl: process.env.NEXT_PUBLIC_WORDPRESS_URL,
expectedSecret: process.env.WP_PREVIEW_SECRET,
// graphqlClient: client,
bearerToken: getAuthString(),
});
Loading
Loading