From 464b4c3d6a605389fbf526c315af990aa7d33763 Mon Sep 17 00:00:00 2001 From: Joe Fusco Date: Fri, 18 Aug 2023 16:08:13 -0400 Subject: [PATCH 01/13] Add new block-support example project Signed-off-by: Joe Fusco --- examples/next/block-support/.env.local.sample | 5 + examples/next/block-support/.eslintignore | 2 + examples/next/block-support/.gitignore | 2 + examples/next/block-support/README.md | 3 + .../block-support/components/Container.js | 12 + .../components/ContentWrapper.js | 13 + .../block-support/components/EntryHeader.js | 34 + .../block-support/components/FeaturedImage.js | 51 ++ .../next/block-support/components/Footer.js | 18 + .../block-support/components/FormatDate.js | 16 + .../next/block-support/components/Head.js | 58 ++ .../next/block-support/components/Header.js | 45 ++ .../next/block-support/components/Heading.js | 7 + .../next/block-support/components/Hero.js | 17 + .../next/block-support/components/Main.js | 18 + .../components/NavigationMenu.js | 67 ++ .../next/block-support/components/Post.js | 40 + .../next/block-support/components/PostInfo.js | 19 + .../components/SkipNavigationLink.js | 16 + .../next/block-support/components/index.js | 15 + .../next/block-support/constants/menus.js | 2 + .../next/block-support/constants/selectors.js | 1 + examples/next/block-support/faust.config.js | 12 + .../fragments/GeneralSettings.js | 8 + examples/next/block-support/next.config.js | 18 + examples/next/block-support/package.json | 30 + .../block-support/pages/[...wordpressNode].js | 16 + examples/next/block-support/pages/_app.js | 25 + .../pages/api/faust/[[...route]].js | 4 + examples/next/block-support/pages/example.js | 79 ++ examples/next/block-support/pages/index.js | 9 + examples/next/block-support/pages/preview.js | 5 + .../next/block-support/styles/_blocks.scss | 14 + .../block-support/styles/_breakpoints.scss | 5 + .../next/block-support/styles/_utilities.scss | 25 + .../styles/components/Container.module.scss | 7 + .../components/ContentWrapper.module.scss | 134 ++++ .../styles/components/EntryHeader.module.scss | 65 ++ .../styles/components/Footer.module.scss | 11 + .../styles/components/Header.module.scss | 72 ++ .../styles/components/Hero.module.scss | 26 + .../styles/components/Main.module.scss | 4 + .../components/NavigationMenu.module.scss | 101 +++ .../NavigationMenuClassesFromWP.module.scss | 25 + .../styles/components/Post.module.scss | 16 + .../styles/components/PostInfo.module.scss | 3 + .../components/SkipNavigationLink.module.scss | 9 + .../next/block-support/styles/global.scss | 7 + examples/next/block-support/theme.json | 741 ++++++++++++++++++ .../next/block-support/wp-blocks/index.js | 15 + .../block-support/wp-templates/category.js | 106 +++ .../block-support/wp-templates/front-page.js | 74 ++ .../next/block-support/wp-templates/index.js | 13 + .../next/block-support/wp-templates/page.js | 126 +++ .../next/block-support/wp-templates/single.js | 137 ++++ .../next/block-support/wp-templates/tag.js | 106 +++ package-lock.json | 252 ++++++ package.json | 1 + 58 files changed, 2762 insertions(+) create mode 100644 examples/next/block-support/.env.local.sample create mode 100644 examples/next/block-support/.eslintignore create mode 100644 examples/next/block-support/.gitignore create mode 100644 examples/next/block-support/README.md create mode 100644 examples/next/block-support/components/Container.js create mode 100644 examples/next/block-support/components/ContentWrapper.js create mode 100644 examples/next/block-support/components/EntryHeader.js create mode 100644 examples/next/block-support/components/FeaturedImage.js create mode 100644 examples/next/block-support/components/Footer.js create mode 100644 examples/next/block-support/components/FormatDate.js create mode 100644 examples/next/block-support/components/Head.js create mode 100644 examples/next/block-support/components/Header.js create mode 100644 examples/next/block-support/components/Heading.js create mode 100644 examples/next/block-support/components/Hero.js create mode 100644 examples/next/block-support/components/Main.js create mode 100644 examples/next/block-support/components/NavigationMenu.js create mode 100644 examples/next/block-support/components/Post.js create mode 100644 examples/next/block-support/components/PostInfo.js create mode 100644 examples/next/block-support/components/SkipNavigationLink.js create mode 100644 examples/next/block-support/components/index.js create mode 100644 examples/next/block-support/constants/menus.js create mode 100644 examples/next/block-support/constants/selectors.js create mode 100644 examples/next/block-support/faust.config.js create mode 100644 examples/next/block-support/fragments/GeneralSettings.js create mode 100644 examples/next/block-support/next.config.js create mode 100644 examples/next/block-support/package.json create mode 100644 examples/next/block-support/pages/[...wordpressNode].js create mode 100644 examples/next/block-support/pages/_app.js create mode 100644 examples/next/block-support/pages/api/faust/[[...route]].js create mode 100644 examples/next/block-support/pages/example.js create mode 100644 examples/next/block-support/pages/index.js create mode 100644 examples/next/block-support/pages/preview.js create mode 100644 examples/next/block-support/styles/_blocks.scss create mode 100644 examples/next/block-support/styles/_breakpoints.scss create mode 100644 examples/next/block-support/styles/_utilities.scss create mode 100644 examples/next/block-support/styles/components/Container.module.scss create mode 100644 examples/next/block-support/styles/components/ContentWrapper.module.scss create mode 100644 examples/next/block-support/styles/components/EntryHeader.module.scss create mode 100644 examples/next/block-support/styles/components/Footer.module.scss create mode 100644 examples/next/block-support/styles/components/Header.module.scss create mode 100644 examples/next/block-support/styles/components/Hero.module.scss create mode 100644 examples/next/block-support/styles/components/Main.module.scss create mode 100644 examples/next/block-support/styles/components/NavigationMenu.module.scss create mode 100644 examples/next/block-support/styles/components/NavigationMenuClassesFromWP.module.scss create mode 100644 examples/next/block-support/styles/components/Post.module.scss create mode 100644 examples/next/block-support/styles/components/PostInfo.module.scss create mode 100644 examples/next/block-support/styles/components/SkipNavigationLink.module.scss create mode 100644 examples/next/block-support/styles/global.scss create mode 100644 examples/next/block-support/theme.json create mode 100644 examples/next/block-support/wp-blocks/index.js create mode 100644 examples/next/block-support/wp-templates/category.js create mode 100644 examples/next/block-support/wp-templates/front-page.js create mode 100644 examples/next/block-support/wp-templates/index.js create mode 100644 examples/next/block-support/wp-templates/page.js create mode 100644 examples/next/block-support/wp-templates/single.js create mode 100644 examples/next/block-support/wp-templates/tag.js diff --git a/examples/next/block-support/.env.local.sample b/examples/next/block-support/.env.local.sample new file mode 100644 index 000000000..dc631ae73 --- /dev/null +++ b/examples/next/block-support/.env.local.sample @@ -0,0 +1,5 @@ +# Your WordPress site URL +NEXT_PUBLIC_WORDPRESS_URL=https://faustexample.wpengine.com + +# Plugin secret found in WordPress Settings->Faust +# FAUST_SECRET_KEY=YOUR_PLUGIN_SECRET diff --git a/examples/next/block-support/.eslintignore b/examples/next/block-support/.eslintignore new file mode 100644 index 000000000..d89107ecc --- /dev/null +++ b/examples/next/block-support/.eslintignore @@ -0,0 +1,2 @@ +components +pages diff --git a/examples/next/block-support/.gitignore b/examples/next/block-support/.gitignore new file mode 100644 index 000000000..0729a3526 --- /dev/null +++ b/examples/next/block-support/.gitignore @@ -0,0 +1,2 @@ +globalStylesheet.css +possibleTypes.json diff --git a/examples/next/block-support/README.md b/examples/next/block-support/README.md new file mode 100644 index 000000000..02038a0ef --- /dev/null +++ b/examples/next/block-support/README.md @@ -0,0 +1,3 @@ +# @faustwp/block-support-example + +Example showcasing Faust.js block editor support. diff --git a/examples/next/block-support/components/Container.js b/examples/next/block-support/components/Container.js new file mode 100644 index 000000000..b6634f65b --- /dev/null +++ b/examples/next/block-support/components/Container.js @@ -0,0 +1,12 @@ +import styles from '../styles/components/Container.module.scss'; +import className from 'classnames/bind'; + +let cx = className.bind(styles); + +export function Container({ children, className }) { + return ( +
+ {children} +
+ ); +} diff --git a/examples/next/block-support/components/ContentWrapper.js b/examples/next/block-support/components/ContentWrapper.js new file mode 100644 index 000000000..75e728af6 --- /dev/null +++ b/examples/next/block-support/components/ContentWrapper.js @@ -0,0 +1,13 @@ +import className from 'classnames/bind'; +import styles from '../styles/components/ContentWrapper.module.scss'; + +let cx = className.bind(styles); + +export function ContentWrapper({ content, children, className }) { + return ( +
+
+ {children} +
+ ); +} diff --git a/examples/next/block-support/components/EntryHeader.js b/examples/next/block-support/components/EntryHeader.js new file mode 100644 index 000000000..edfaa2b35 --- /dev/null +++ b/examples/next/block-support/components/EntryHeader.js @@ -0,0 +1,34 @@ +import className from 'classnames/bind'; +import { Heading, PostInfo, Container, FeaturedImage } from '.'; +import styles from '../styles/components/EntryHeader.module.scss'; + +let cx = className.bind(styles); + +export function EntryHeader({ title, image, date, author, className }) { + const hasText = title || date || author; + + return ( +
+ {image && ( + + )} + + {hasText && ( +
+ + {!!title && {title}} + + +
+ )} +
+ ); +} diff --git a/examples/next/block-support/components/FeaturedImage.js b/examples/next/block-support/components/FeaturedImage.js new file mode 100644 index 000000000..a25a027e5 --- /dev/null +++ b/examples/next/block-support/components/FeaturedImage.js @@ -0,0 +1,51 @@ +import { gql } from '@apollo/client'; +import Image from 'next/image'; + +export function FeaturedImage({ + image, + width, + height, + className, + priority, + layout, + ...props +}) { + const src = image?.sourceUrl; + const { altText } = image || ''; + + width = width ? width : image?.mediaDetails?.width; + height = height ? height : image?.mediaDetails?.height; + layout = layout ?? 'fill'; + + return src && width && height ? ( +
+ {altText} +
+ ) : null; +} + +FeaturedImage.fragments = { + entry: gql` + fragment FeaturedImageFragment on NodeWithFeaturedImage { + featuredImage { + node { + id + sourceUrl + altText + mediaDetails { + width + height + } + } + } + } + `, +}; diff --git a/examples/next/block-support/components/Footer.js b/examples/next/block-support/components/Footer.js new file mode 100644 index 000000000..905cfe5d6 --- /dev/null +++ b/examples/next/block-support/components/Footer.js @@ -0,0 +1,18 @@ +import classNames from 'classnames/bind'; +import { Container, NavigationMenu } from '.'; +import styles from '../styles/components/Footer.module.scss'; + +let cx = classNames.bind(styles); + +export function Footer({ title, menuItems }) { + const year = new Date().getFullYear(); + + return ( +
+ + +

{`${title} © ${year}. Powered by WordPress.`}

+
+
+ ); +} diff --git a/examples/next/block-support/components/FormatDate.js b/examples/next/block-support/components/FormatDate.js new file mode 100644 index 000000000..cb6a762fd --- /dev/null +++ b/examples/next/block-support/components/FormatDate.js @@ -0,0 +1,16 @@ +export function FormatDate({ date }) { + let formattedDate = new Date(date); + + if (isNaN(formattedDate.valueOf())) { + return null; + } + + const timeformat = { + year: 'numeric', + month: 'long', + day: 'numeric', + hour12: false + }; + + return <>{formattedDate.toLocaleDateString('en-US', timeformat)}; +} diff --git a/examples/next/block-support/components/Head.js b/examples/next/block-support/components/Head.js new file mode 100644 index 000000000..39a2b16d7 --- /dev/null +++ b/examples/next/block-support/components/Head.js @@ -0,0 +1,58 @@ +import NextHead from 'next/head'; + +/** + * Adds meta tags to a page. + * + * @param {Props} props The props object. + * @param {string} props.title Used for the page title, og:title, twitter:title, etc. + * @param {string} props.description Used for the meta description, og:description, twitter:description, etc. + * @param {string} props.imageUrl Used for the og:image and twitter:image. NOTE: Must be an absolute url. + * @param {string} props.url Used for the og:url and twitter:url. + * + * @returns {React.ReactElement} The Head component + */ +export function Head({ title, description, imageUrl, url }) { + if (!title && !description && !imageUrl && !url) { + return null; + } + + return ( + <> + + + + + {title && ( + <> + {title} + + + + + )} + + {description && ( + <> + + + + + )} + + {imageUrl && ( + <> + + + + )} + + {url && ( + <> + + + + )} + + + ); +} diff --git a/examples/next/block-support/components/Header.js b/examples/next/block-support/components/Header.js new file mode 100644 index 000000000..d9170467c --- /dev/null +++ b/examples/next/block-support/components/Header.js @@ -0,0 +1,45 @@ +import { useState } from 'react'; +import classNames from 'classnames/bind'; +import Link from 'next/link'; +import { Container, NavigationMenu, SkipNavigationLink } from '.'; +import styles from '../styles/components/Header.module.scss'; + +let cx = classNames.bind(styles); + +export function Header({ + title = 'Headless by WP Engine', + description, + menuItems +}) { + const [isNavShown, setIsNavShown] = useState(false); + + return ( +
+ + +
+
+ + {title} + + {description &&

{description}

} +
+ + +
+
+
+ ); +} diff --git a/examples/next/block-support/components/Heading.js b/examples/next/block-support/components/Heading.js new file mode 100644 index 000000000..c1a6baabe --- /dev/null +++ b/examples/next/block-support/components/Heading.js @@ -0,0 +1,7 @@ +import React from 'react'; + +export function Heading({ level = 'h1', children, className }) { + const Tag = ({ ...props }) => React.createElement(level, props, children); + + return {children}; +} diff --git a/examples/next/block-support/components/Hero.js b/examples/next/block-support/components/Hero.js new file mode 100644 index 000000000..9a0b2c036 --- /dev/null +++ b/examples/next/block-support/components/Hero.js @@ -0,0 +1,17 @@ +import React from 'react'; +import className from 'classnames/bind'; +import { Heading } from '.'; +import styles from '../styles/components/Hero.module.scss'; + +let cx = className.bind(styles); + +export function Hero({ title, level = 'h2', children, className }) { + return ( +
+ + {title} + + {children} +
+ ); +} diff --git a/examples/next/block-support/components/Main.js b/examples/next/block-support/components/Main.js new file mode 100644 index 000000000..049c4eb0f --- /dev/null +++ b/examples/next/block-support/components/Main.js @@ -0,0 +1,18 @@ +import classNames from 'classnames/bind'; +import * as SELECTORS from '../constants/selectors'; +import styles from '../styles/components/Main.module.scss'; + +let cx = classNames.bind(styles); + +export function Main({ children, className, ...props }) { + return ( +
+ {children} +
+ ); +} diff --git a/examples/next/block-support/components/NavigationMenu.js b/examples/next/block-support/components/NavigationMenu.js new file mode 100644 index 000000000..755c69dca --- /dev/null +++ b/examples/next/block-support/components/NavigationMenu.js @@ -0,0 +1,67 @@ +import classNames from 'classnames/bind'; +import { gql } from '@apollo/client'; +import Link from 'next/link'; +import styles from '../styles/components/NavigationMenu.module.scss'; +import stylesFromWP from '../styles/components/NavigationMenuClassesFromWP.module.scss'; + +import { flatListToHierarchical } from '@faustwp/core'; + +let cx = classNames.bind(styles); +let cxFromWp = classNames.bind(stylesFromWP); + +export function NavigationMenu({ menuItems, className }) { + if (!menuItems) { + return null; + } + + // Based on https://www.wpgraphql.com/docs/menus/#hierarchical-data + const hierarchicalMenuItems = flatListToHierarchical(menuItems); + + function renderMenu(items) { + return ( + + ); + } + + return ( + + ); +} + +NavigationMenu.fragments = { + entry: gql` + fragment NavigationMenuItemFragment on MenuItem { + id + path + label + parentId + cssClasses + menu { + node { + name + } + } + } + `, +}; diff --git a/examples/next/block-support/components/Post.js b/examples/next/block-support/components/Post.js new file mode 100644 index 000000000..7da5ab1bc --- /dev/null +++ b/examples/next/block-support/components/Post.js @@ -0,0 +1,40 @@ +import Link from 'next/link'; +import { FeaturedImage } from './FeaturedImage'; +import { PostInfo } from './PostInfo'; +import styles from '../styles/components/Post.module.scss'; + +export function Post({ + title, + content, + date, + author, + uri, + featuredImage, +}) { + return ( + + ); +} diff --git a/examples/next/block-support/components/PostInfo.js b/examples/next/block-support/components/PostInfo.js new file mode 100644 index 000000000..ec731d850 --- /dev/null +++ b/examples/next/block-support/components/PostInfo.js @@ -0,0 +1,19 @@ +import { FormatDate } from '.'; + +export function PostInfo({ date, author, className }) { + if (!date && !author) { + return null; + } + + return ( +
+ {date && ( + + )} + {date && author && <> } + {author && by {author}} +
+ ); +} diff --git a/examples/next/block-support/components/SkipNavigationLink.js b/examples/next/block-support/components/SkipNavigationLink.js new file mode 100644 index 000000000..cbb8add11 --- /dev/null +++ b/examples/next/block-support/components/SkipNavigationLink.js @@ -0,0 +1,16 @@ +import classNames from 'classnames/bind'; +import * as SELECTORS from '../constants/selectors'; +import styles from '../styles/components/SkipNavigationLink.module.scss'; + +let cx = classNames.bind(styles); + +export function SkipNavigationLink() { + return ( + + Skip To Main Content + + ); +} diff --git a/examples/next/block-support/components/index.js b/examples/next/block-support/components/index.js new file mode 100644 index 000000000..835b3a4d3 --- /dev/null +++ b/examples/next/block-support/components/index.js @@ -0,0 +1,15 @@ +export { Container } from './Container'; +export { ContentWrapper } from './ContentWrapper'; +export { EntryHeader } from './EntryHeader'; +export { FeaturedImage } from './FeaturedImage'; +export { Footer } from './Footer'; +export { FormatDate } from './FormatDate'; +export { Header } from './Header'; +export { Heading } from './Heading'; +export { Main } from './Main'; +export { NavigationMenu } from './NavigationMenu'; +export { PostInfo } from './PostInfo'; +export { SkipNavigationLink } from './SkipNavigationLink'; +export { Hero } from './Hero'; +export { Post } from './Post'; +export { Head } from './Head'; diff --git a/examples/next/block-support/constants/menus.js b/examples/next/block-support/constants/menus.js new file mode 100644 index 000000000..c60ded9df --- /dev/null +++ b/examples/next/block-support/constants/menus.js @@ -0,0 +1,2 @@ + export const PRIMARY_LOCATION = 'PRIMARY'; + export const FOOTER_LOCATION = 'FOOTER'; diff --git a/examples/next/block-support/constants/selectors.js b/examples/next/block-support/constants/selectors.js new file mode 100644 index 000000000..0fef48aaa --- /dev/null +++ b/examples/next/block-support/constants/selectors.js @@ -0,0 +1 @@ +export const MAIN_CONTENT_ID = 'main-content'; diff --git a/examples/next/block-support/faust.config.js b/examples/next/block-support/faust.config.js new file mode 100644 index 000000000..c6478a6d6 --- /dev/null +++ b/examples/next/block-support/faust.config.js @@ -0,0 +1,12 @@ +import { setConfig } from '@faustwp/core'; +import templates from './wp-templates'; +import possibleTypes from './possibleTypes.json'; + +/** + * @type {import('@faustwp/core').FaustConfig} + **/ +export default setConfig({ + templates, + experimentalPlugins: [], + possibleTypes, +}); diff --git a/examples/next/block-support/fragments/GeneralSettings.js b/examples/next/block-support/fragments/GeneralSettings.js new file mode 100644 index 000000000..f478789d3 --- /dev/null +++ b/examples/next/block-support/fragments/GeneralSettings.js @@ -0,0 +1,8 @@ +import { gql } from '@apollo/client'; + +export const BlogInfoFragment = gql` + fragment BlogInfoFragment on GeneralSettings { + title + description + } +`; diff --git a/examples/next/block-support/next.config.js b/examples/next/block-support/next.config.js new file mode 100644 index 000000000..671f1eca0 --- /dev/null +++ b/examples/next/block-support/next.config.js @@ -0,0 +1,18 @@ +const { withFaust, getWpHostname } = require('@faustwp/core'); + +/** + * @type {import('next').NextConfig} + **/ +module.exports = withFaust({ + reactStrictMode: true, + sassOptions: { + includePaths: ['node_modules'], + }, + images: { + domains: [getWpHostname()], + }, + i18n: { + locales: ['en'], + defaultLocale: 'en', + }, +}); diff --git a/examples/next/block-support/package.json b/examples/next/block-support/package.json new file mode 100644 index 000000000..fa70a9fc0 --- /dev/null +++ b/examples/next/block-support/package.json @@ -0,0 +1,30 @@ +{ + "name": "@faustwp/block-support-example", + "private": true, + "version": "0.1.0", + "scripts": { + "predev": "faust generatePossibleTypes && faust generateGlobalStylesheet", + "prebuild": "faust generatePossibleTypes && faust generateGlobalStylesheet", + "dev": "faust dev", + "build": "faust build", + "start": "faust start" + }, + "dependencies": { + "@apollo/client": "^3.6.6", + "@faustwp/blocks": "1.2.0", + "@faustwp/cli": "1.0.1", + "@faustwp/core": "1.0.3", + "@wordpress/base-styles": "^4.26.0", + "@wordpress/block-library": "^7.19.0", + "classnames": "^2.3.1", + "graphql": "^16.6.0", + "next": "^12.1.6", + "react": "^17.0.2", + "react-dom": "^17.0.2", + "sass": "^1.54.9" + }, + "engines": { + "node": ">=16", + "npm": ">=8" + } +} diff --git a/examples/next/block-support/pages/[...wordpressNode].js b/examples/next/block-support/pages/[...wordpressNode].js new file mode 100644 index 000000000..fe51bbcc9 --- /dev/null +++ b/examples/next/block-support/pages/[...wordpressNode].js @@ -0,0 +1,16 @@ +import { getWordPressProps, WordPressTemplate } from '@faustwp/core'; + +export default function Page(props) { + return ; +} + +export function getStaticProps(ctx) { + return getWordPressProps({ ctx }); +} + +export async function getStaticPaths() { + return { + paths: [], + fallback: 'blocking', + }; +} diff --git a/examples/next/block-support/pages/_app.js b/examples/next/block-support/pages/_app.js new file mode 100644 index 000000000..9fb2e166c --- /dev/null +++ b/examples/next/block-support/pages/_app.js @@ -0,0 +1,25 @@ +import '../faust.config'; +import React from 'react'; +import { useRouter } from 'next/router'; +import { WordPressBlocksProvider, fromThemeJson } from '@faustwp/blocks'; +import { FaustProvider } from '@faustwp/core'; +import blocks from '../wp-blocks'; +import themeJson from '../theme.json'; +import '../globalStylesheet.css'; // <-- Generated by @faustwp/cli +import '../styles/global.scss'; + +export default function MyApp({ Component, pageProps }) { + const router = useRouter(); + + return ( + + + + + + ); +} diff --git a/examples/next/block-support/pages/api/faust/[[...route]].js b/examples/next/block-support/pages/api/faust/[[...route]].js new file mode 100644 index 000000000..e73fd7919 --- /dev/null +++ b/examples/next/block-support/pages/api/faust/[[...route]].js @@ -0,0 +1,4 @@ +import '../../../faust.config'; +import { apiRouter } from '@faustwp/core'; + +export default apiRouter; diff --git a/examples/next/block-support/pages/example.js b/examples/next/block-support/pages/example.js new file mode 100644 index 000000000..aa524a8f0 --- /dev/null +++ b/examples/next/block-support/pages/example.js @@ -0,0 +1,79 @@ +import { gql, useQuery } from '@apollo/client'; +import * as MENUS from '../constants/menus'; +import { BlogInfoFragment } from '../fragments/GeneralSettings'; +import { + Header, + Hero, + Footer, + Main, + Container, + NavigationMenu, + Head, +} from '../components'; +import { getNextStaticProps } from '@faustwp/core'; + +export default function Page(props) { + const { data } = useQuery(Page.query, { + variables: Page.variables(), + }); + const title = props.title; + + const { title: siteTitle, description: siteDescription } = data?.generalSettings; + const primaryMenu = data?.headerMenuItems?.nodes ?? []; + const footerMenu = data?.footerMenuItems?.nodes ?? []; + + return ( + <> + +
+
+ + +
+

This page is utilizing the Next.js File based routes.

+ pages/example.js +
+
+
+