diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml index 9b4473896..158573757 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yml +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -19,6 +19,7 @@ body: - next-drupal (NPM package) - basic-starter - graphql-starter + - pages-starter - example-auth - example-blog - example-client diff --git a/.github/ISSUE_TEMPLATE/feature_request.yml b/.github/ISSUE_TEMPLATE/feature_request.yml index f02bd6192..7a78bf0c9 100644 --- a/.github/ISSUE_TEMPLATE/feature_request.yml +++ b/.github/ISSUE_TEMPLATE/feature_request.yml @@ -14,6 +14,7 @@ body: - next-drupal (NPM package) - basic-starter - graphql-starter + - pages-starter - example-auth - example-blog - example-client diff --git a/.github/ISSUE_TEMPLATE/question.yml b/.github/ISSUE_TEMPLATE/question.yml index 5ff543ca2..70a5c2fa6 100644 --- a/.github/ISSUE_TEMPLATE/question.yml +++ b/.github/ISSUE_TEMPLATE/question.yml @@ -14,6 +14,7 @@ body: - next-drupal (NPM package) - basic-starter - graphql-starter + - pages-starter - example-auth - example-blog - example-client diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index 8436a0552..2a4cfbbad 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -5,6 +5,7 @@ This pull request is for: (mark with an "x") - [ ] `packages/next-drupal` - [ ] `starters/basic-starter` - [ ] `starters/graphql-starter` +- [ ] `starters/pages-starter` - [ ] Other GitHub Issue: # diff --git a/MAINTAINING.md b/MAINTAINING.md index d342fb96e..62d321685 100644 --- a/MAINTAINING.md +++ b/MAINTAINING.md @@ -168,6 +168,7 @@ The code in the examples repos do not strictly require a versioned release since - [basic-starter](https://github.com/chapter-three/next-drupal-basic-starter/releases) - [graphql-starter](https://github.com/chapter-three/next-drupal-graphql-starter/releases) + - [pages-starter](https://github.com/chapter-three/next-drupal-pages-starter/releases) And then: diff --git a/starters/pages-starter/.env.example b/starters/pages-starter/.env.example new file mode 100644 index 000000000..951ea909b --- /dev/null +++ b/starters/pages-starter/.env.example @@ -0,0 +1,12 @@ +# See https://next-drupal.org/docs/environment-variables + +# Required +NEXT_PUBLIC_DRUPAL_BASE_URL=https://site.example.com +NEXT_IMAGE_DOMAIN=site.example.com + +# Authentication +DRUPAL_CLIENT_ID=Retrieve this from /admin/config/services/consumer +DRUPAL_CLIENT_SECRET=Retrieve this from /admin/config/services/consumer + +# Required for On-demand Revalidation +DRUPAL_REVALIDATE_SECRET=Retrieve this from /admin/config/services/next diff --git a/starters/pages-starter/.eslintrc.json b/starters/pages-starter/.eslintrc.json new file mode 100644 index 000000000..7c1a3addb --- /dev/null +++ b/starters/pages-starter/.eslintrc.json @@ -0,0 +1,4 @@ +{ + "extends": "next/core-web-vitals", + "root": true +} diff --git a/starters/pages-starter/.gitignore b/starters/pages-starter/.gitignore new file mode 100644 index 000000000..081b7c172 --- /dev/null +++ b/starters/pages-starter/.gitignore @@ -0,0 +1,40 @@ +# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. + +# dependencies +/node_modules +/.pnp +.pnp.js +.yarn/install-state.gz + +# testing +/coverage + +# next.js +/.next/ +/out/ + +# production +/build + +# misc +.DS_Store +*.pem + +# IDE files +/.idea +/.vscode + +# debug +npm-debug.log* +yarn-debug.log* +yarn-error.log* + +# local env files +.env*.local + +# vercel +.vercel + +# typescript +*.tsbuildinfo +next-env.d.ts diff --git a/starters/pages-starter/.nvmrc b/starters/pages-starter/.nvmrc new file mode 100644 index 000000000..9a2a0e219 --- /dev/null +++ b/starters/pages-starter/.nvmrc @@ -0,0 +1 @@ +v20 diff --git a/starters/pages-starter/.prettierignore b/starters/pages-starter/.prettierignore new file mode 100644 index 000000000..03c8a68b9 --- /dev/null +++ b/starters/pages-starter/.prettierignore @@ -0,0 +1,18 @@ +# Ignore everything. +/* + +# Format most files in the root directory. +!/*.js +!/*.ts +!/*.md +!/*.json +# But ignore some. +/package.json +/package-lock.json +/CHANGELOG.md + +# Don't ignore these nested directories. +!/app +!/components +!/lib +!/pages diff --git a/starters/pages-starter/.prettierrc.json b/starters/pages-starter/.prettierrc.json new file mode 100644 index 000000000..3c60a7b54 --- /dev/null +++ b/starters/pages-starter/.prettierrc.json @@ -0,0 +1,4 @@ +{ + "semi": false, + "trailingComma": "es5" +} diff --git a/starters/pages-starter/CHANGELOG.md b/starters/pages-starter/CHANGELOG.md new file mode 100644 index 000000000..b260bf9b4 --- /dev/null +++ b/starters/pages-starter/CHANGELOG.md @@ -0,0 +1,409 @@ +# Change Log + +All notable changes to this project will be documented in this file. +See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. + +# [1.8.0](https://github.com/chapter-three/next-drupal/compare/basic-starter@1.7.2...basic-starter@1.8.0) (2022-12-06) + +**Note:** Version bump only for package basic-starter + + + + + +## [1.7.2](https://github.com/chapter-three/next-drupal/compare/basic-starter@1.7.1...basic-starter@1.7.2) (2022-12-06) + +**Note:** Version bump only for package basic-starter + + + + + +## [1.7.1](https://github.com/chapter-three/next-drupal/compare/basic-starter@1.7.0...basic-starter@1.7.1) (2022-09-07) + +**Note:** Version bump only for package basic-starter + + + + + +# [1.7.0](https://github.com/chapter-three/next-drupal/compare/basic-starter@1.6.0...basic-starter@1.7.0) (2022-07-29) + + +### Features + +* **basic-starter:** add type to next.config.js ([c1db60d](https://github.com/chapter-three/next-drupal/commit/c1db60d460ec2c0b2f3149d455e8c1b4bcc4a080)) +* **basic-starter:** fix jsonapi params to work with vanilla drupal ([258019f](https://github.com/chapter-three/next-drupal/commit/258019f5bc0fa34e3ce3a824f99b28ea60b5ad30)) +* **basic-starter:** update the example env variables ([1ed83da](https://github.com/chapter-three/next-drupal/commit/1ed83da4c0ec6ef3f0487f43faf1d8a4fdb29858)) + + + + + +# [1.6.0](https://github.com/chapter-three/next-drupal/compare/basic-starter@1.6.0-rc.0...basic-starter@1.6.0) (2022-06-14) + +**Note:** Version bump only for package basic-starter + + + + + +# [1.6.0-rc.0](https://github.com/chapter-three/next-drupal/compare/basic-starter@1.5.3-rc.1...basic-starter@1.6.0-rc.0) (2022-06-14) + + +### Features + +* **basic-starter:** update to DrupalClient ([e2dc220](https://github.com/chapter-three/next-drupal/commit/e2dc2202d01a09aba5695ffbbe35d990981d3301)) + + + + + +## [1.5.3-rc.1](https://github.com/chapter-three/next-drupal/compare/basic-starter@1.5.3-rc.0...basic-starter@1.5.3-rc.1) (2022-06-10) + +**Note:** Version bump only for package basic-starter + + + + + +## [1.5.3-rc.0](https://github.com/chapter-three/next-drupal/compare/basic-starter@1.5.3-alpha.0...basic-starter@1.5.3-rc.0) (2022-06-06) + +**Note:** Version bump only for package basic-starter + + + + + +## [1.5.3-alpha.0](https://github.com/chapter-three/next-drupal/compare/basic-starter@1.5.2...basic-starter@1.5.3-alpha.0) (2022-06-02) + + +### Bug Fixes + +* **basic-starter:** rename api pages to .ts ([40456b0](https://github.com/chapter-three/next-drupal/commit/40456b08ae288c441195fe38b8d5008736bfce05)) + + + + + +## [1.5.2](https://github.com/chapter-three/next-drupal/compare/basic-starter@1.5.1...basic-starter@1.5.2) (2022-05-02) + +**Note:** Version bump only for package basic-starter + + + + + +## [1.5.1](https://github.com/chapter-three/next-drupal/compare/basic-starter@1.5.0...basic-starter@1.5.1) (2022-04-25) + +**Note:** Version bump only for package basic-starter + + + + + +# [1.5.0](https://github.com/chapter-three/next-drupal/compare/basic-starter@1.4.1-rc.0...basic-starter@1.5.0) (2022-04-19) + + +### Bug Fixes + +* **basic-starter:** rename eslint.json ([844bd93](https://github.com/chapter-three/next-drupal/commit/844bd93b0d4e6a3d24e6e76622067f344e440def)) + + + + + +## [1.4.1-rc.0](https://github.com/chapter-three/next-drupal/compare/basic-starter@1.4.1-alpha.0...basic-starter@1.4.1-rc.0) (2022-04-19) + +**Note:** Version bump only for package basic-starter + + + + + +## [1.4.1-alpha.0](https://github.com/chapter-three/next-drupal/compare/basic-starter@1.4.0...basic-starter@1.4.1-alpha.0) (2022-04-18) + + +### Bug Fixes + +* update tests ([0f4d49e](https://github.com/chapter-three/next-drupal/commit/0f4d49e9bb3b8767577bdba4ef52d7e58ad6bf91)) + + + + + +# [1.4.0](https://github.com/chapter-three/next-drupal/compare/basic-starter@1.3.1...basic-starter@1.4.0) (2022-04-11) + + +### Bug Fixes + +* **basic-starter:** use a tag for exit preview ([8f68023](https://github.com/chapter-three/next-drupal/commit/8f680232a53740f083fd7c208b54f4293ad0f58a)) + + +### Features + +* **basic-starter:** show only published articles on index ([d209af9](https://github.com/chapter-three/next-drupal/commit/d209af9c08b4db12f8c2f7adfb7adfc3840a8f02)) +* **basic-starter:** update starter ([ad6afa9](https://github.com/chapter-three/next-drupal/commit/ad6afa999b59f49d5f6b199aaa4b3e3c1683c352)) + + + + + +## [1.3.1](https://github.com/chapter-three/next-drupal/compare/basic-starter@1.3.0...basic-starter@1.3.1) (2022-03-28) + +**Note:** Version bump only for package basic-starter + + + + + +# [1.3.0](https://github.com/chapter-three/next-drupal/compare/basic-starter@1.2.0...basic-starter@1.3.0) (2022-02-24) + + +### Bug Fixes + +* **basic-starter:** fix type for private in package.json ([b1a6e90](https://github.com/chapter-three/next-drupal/commit/b1a6e907e22de61354b42b0126e5a084bd90f57b)) +* **basic-starter:** update @tailwindcss/typography ([aa70f4e](https://github.com/chapter-three/next-drupal/commit/aa70f4ee6287e7fcc6ce1352114a4ef24474e404)) +* **basic-starter:** update typescript ([3eda875](https://github.com/chapter-three/next-drupal/commit/3eda8755dbf2c904e9253bff7df67a9992bbdc12)) + + +### Features + +* bump all examples to next 12.1.0 ([00b15f2](https://github.com/chapter-three/next-drupal/commit/00b15f2b308a0a9fcb298789a9ca712f4efa7eff)) +* **basic-starter:** simplify starter by removing menus ([7ce44ac](https://github.com/chapter-three/next-drupal/commit/7ce44ac11b628f06849b09a1831069df5da2a926)) +* **basic-starter:** use server-side menus ([58f1150](https://github.com/chapter-three/next-drupal/commit/58f1150e750d860cb62b60f28edca3673dbb3c68)) + + + + + +# [1.2.0](https://github.com/chapter-three/next-drupal/compare/basic-starter@1.1.1...basic-starter@1.2.0) (2022-01-17) + + +### Features + +* **basic-starter:** update tailwind and dependencies ([5de7337](https://github.com/chapter-three/next-drupal/commit/5de7337c7372afe44692b3ba49bcf10afdf9cfd6)) + + + + + +## [1.1.1](https://github.com/chapter-three/next-drupal/compare/basic-starter@1.1.0...basic-starter@1.1.1) (2022-01-12) + +**Note:** Version bump only for package basic-starter + + + + + +# [1.1.0](https://github.com/chapter-three/next-drupal/compare/basic-starter@1.0.0...basic-starter@1.1.0) (2021-12-21) + + +### Features + +* **basic-starter:** bump next to 12 ([3185cd4](https://github.com/chapter-three/next-drupal/commit/3185cd4f720e87e91d2a03e335729a6ae8df4e78)) + + + + + +# [1.0.0](https://github.com/chapter-three/next-drupal/compare/basic-starter@0.7.0...basic-starter@1.0.0) (2021-12-03) + +**Note:** Version bump only for package basic-starter + + + + + +# [0.7.0](https://github.com/chapter-three/next-drupal/compare/basic-starter@0.6.0...basic-starter@0.7.0) (2021-11-24) + + +### Features + +* **basic-starter:** update dependencies and components ([233549b](https://github.com/chapter-three/next-drupal/commit/233549b1c2c3f401fac9b4290dcbe53682670d2f)) + + + + + +# [0.6.0](https://github.com/chapter-three/next-drupal/compare/basic-starter@0.6.0-alpha.0...basic-starter@0.6.0) (2021-11-01) + +**Note:** Version bump only for package basic-starter + + + + + +# [0.6.0-alpha.0](https://github.com/chapter-three/next-drupal/compare/basic-starter@0.5.2...basic-starter@0.6.0-alpha.0) (2021-11-01) + +**Note:** Version bump only for package basic-starter + + + + + +## [0.5.2](https://github.com/chapter-three/next-drupal/compare/basic-starter@0.5.1...basic-starter@0.5.2) (2021-10-14) + +**Note:** Version bump only for package basic-starter + + + + + +## [0.5.1](https://github.com/chapter-three/next-drupal/compare/basic-starter@0.5.0...basic-starter@0.5.1) (2021-10-14) + +**Note:** Version bump only for package basic-starter + + + + + +# [0.5.0](https://github.com/chapter-three/next-drupal/compare/basic-starter@0.4.2...basic-starter@0.5.0) (2021-10-13) + + +### Bug Fixes + +* rename repo links ([48d52dd](https://github.com/chapter-three/next-drupal/commit/48d52dde79f69396ef706d152c03670117b6a480)) +* **basic-starter:** update next ([ea46504](https://github.com/chapter-three/next-drupal/commit/ea465044bec1865bab850f588e856be2fcaaf34c)) + + +### Features + +* **basic-starter:** update the basic starter ([a7efdcd](https://github.com/chapter-three/next-drupal/commit/a7efdcdf2fb38057027aad12e11e63ba21318b32)) + + + + + +## [0.4.2](https://github.com/chapter-three/next-drupal/compare/basic-starter@0.4.1...basic-starter@0.4.2) (2021-08-11) + +**Note:** Version bump only for package basic-starter + + + + + +## [0.4.1](https://github.com/chapter-three/next-drupal/compare/basic-starter@0.4.0...basic-starter@0.4.1) (2021-08-07) + +**Note:** Version bump only for package basic-starter + + + + + +# [0.4.0](https://github.com/chapter-three/next-drupal/compare/basic-starter@0.3.9...basic-starter@0.4.0) (2021-06-22) + + +### Bug Fixes + +* **basic-starter:** add props to NodeMeta ([613a2e1](https://github.com/chapter-three/next-drupal/commit/613a2e1c732b2fe94538ffdd66e42d3af60d0088)) + + +### Features + +* **basic-starter:** update the basic starter ([db2f99c](https://github.com/chapter-three/next-drupal/commit/db2f99c3872a7e46cedcad66650b6f03fd645dbb)) + + + + + +## [0.3.9](https://github.com/chapter-three/next-drupal/compare/basic-starter@0.3.8...basic-starter@0.3.9) (2021-06-16) + +**Note:** Version bump only for package basic-starter + + + + + +## [0.3.8](https://github.com/chapter-three/next-drupal/compare/basic-starter@0.3.7...basic-starter@0.3.8) (2021-06-16) + +**Note:** Version bump only for package basic-starter + + + + + +## [0.3.7](https://github.com/chapter-three/next-drupal/compare/basic-starter@0.3.6...basic-starter@0.3.7) (2021-06-15) + +**Note:** Version bump only for package basic-starter + + + + + +## [0.3.6](https://github.com/chapter-three/next-drupal/compare/basic-starter@0.3.5...basic-starter@0.3.6) (2021-06-14) + +**Note:** Version bump only for package basic-starter + + + + + +## [0.3.5](https://github.com/chapter-three/next-drupal/compare/basic-starter@0.3.4...basic-starter@0.3.5) (2021-06-13) + +**Note:** Version bump only for package basic-starter + + + + + +## [0.3.4](https://github.com/chapter-three/next-drupal/compare/basic-starter@0.3.3...basic-starter@0.3.4) (2021-06-13) + +**Note:** Version bump only for package basic-starter + + + + + +## [0.3.3](https://github.com/chapter-three/next-drupal/compare/basic-starter@0.3.2...basic-starter@0.3.3) (2021-06-13) + +**Note:** Version bump only for package basic-starter + + + + + +## [0.3.2](https://github.com/chapter-three/next-drupal/compare/basic-starter@0.3.1...basic-starter@0.3.2) (2021-06-11) + +**Note:** Version bump only for package basic-starter + + + + + +## [0.3.1](https://github.com/chapter-three/next-drupal/compare/basic-starter@0.3.0...basic-starter@0.3.1) (2021-06-10) + +**Note:** Version bump only for package basic-starter + + + + + +# [0.3.0](https://github.com/chapter-three/next-drupal/compare/basic-starter@0.2.0...basic-starter@0.3.0) (2021-05-17) + + +### Features + +* add getEntityByPath ([072ead7](https://github.com/chapter-three/next-drupal/commit/072ead7ecc3b7f158e4b81e03d17f0bf1a5b511c)) + + + + + +# [0.2.0](https://github.com/chapter-three/next-drupal/compare/basic-starter@0.1.0...basic-starter@0.2.0) (2021-05-17) + + +### Features + +* deserialize entities by default ([8b53ae2](https://github.com/chapter-three/next-drupal/commit/8b53ae222717b8983568194373be04903944a032)) + + + + + +# 0.1.0 (2021-05-07) + + +### Features + +* add basic-starter ([92b746a](https://github.com/chapter-three/next-drupal/commit/92b746aef6b59d893cb3c2f49d35d7dcc733c7c8)) diff --git a/starters/pages-starter/README.md b/starters/pages-starter/README.md new file mode 100644 index 000000000..2acfc085d --- /dev/null +++ b/starters/pages-starter/README.md @@ -0,0 +1,15 @@ +# Pages Starter + +A simple starter for building your site with Next.js' Pages Router and Drupal. + +## How to use + +`npx create-next-app -e https://github.com/chapter-three/next-drupal-pages-starter` + +## Deploy to Vercel + +[![Deploy with Vercel](https://vercel.com/button)](https://vercel.com/new/clone?repository-url=https%3A%2F%2Fgithub.com%2Fchapter-three%2Fnext-drupal-pages-starter&env=NEXT_PUBLIC_DRUPAL_BASE_URL,NEXT_IMAGE_DOMAIN,DRUPAL_CLIENT_ID,DRUPAL_CLIENT_SECRET&envDescription=Learn%20more%20about%20environment%20variables&envLink=https%3A%2F%2Fnext-drupal.org%2Fdocs%2Fenvironment-variables&project-name=next-drupal&demo-title=Next.js%20for%20Drupal&demo-description=A%20next-generation%20front-end%20for%20your%20Drupal%20site.&demo-url=https%3A%2F%2Fdemo.next-drupal.org&demo-image=https%3A%2F%2Fnext-drupal.org%2Fimages%2Fdemo-screenshot.jpg) + +## Documentation + +See https://next-drupal.org diff --git a/starters/pages-starter/components/Layout.tsx b/starters/pages-starter/components/Layout.tsx new file mode 100644 index 000000000..cb1f40126 --- /dev/null +++ b/starters/pages-starter/components/Layout.tsx @@ -0,0 +1,15 @@ +import { HeaderNav } from "@/components/navigation/HeaderNav" +import { PreviewAlert } from "@/components/misc/PreviewAlert" +import type { ReactNode } from "react" + +export function Layout({ children }: { children: ReactNode }) { + return ( + <> + +
+ +
{children}
+
+ + ) +} diff --git a/starters/pages-starter/components/drupal/Article.tsx b/starters/pages-starter/components/drupal/Article.tsx new file mode 100644 index 000000000..b4d3d234e --- /dev/null +++ b/starters/pages-starter/components/drupal/Article.tsx @@ -0,0 +1,46 @@ +import Image from "next/image" +import { absoluteUrl, formatDate } from "@/lib/utils" +import type { DrupalNode } from "next-drupal" + +interface ArticleProps { + node: DrupalNode +} + +export function Article({ node, ...props }: ArticleProps) { + return ( +
+

{node.title}

+
+ {node.uid?.display_name ? ( + + Posted by{" "} + {node.uid?.display_name} + + ) : null} + - {formatDate(node.created)} +
+ {node.field_image && ( +
+ {node.field_image.resourceIdObjMeta.alt + {node.field_image.resourceIdObjMeta.title && ( +
+ {node.field_image.resourceIdObjMeta.title} +
+ )} +
+ )} + {node.body?.processed && ( +
+ )} +
+ ) +} diff --git a/starters/pages-starter/components/drupal/ArticleTeaser.tsx b/starters/pages-starter/components/drupal/ArticleTeaser.tsx new file mode 100644 index 000000000..8efeac62e --- /dev/null +++ b/starters/pages-starter/components/drupal/ArticleTeaser.tsx @@ -0,0 +1,54 @@ +import Image from "next/image" +import { Link } from "@/components/navigation/Link" +import { absoluteUrl, formatDate } from "@/lib/utils" +import type { DrupalNode } from "next-drupal" + +interface ArticleTeaserProps { + node: DrupalNode +} + +export function ArticleTeaser({ node, ...props }: ArticleTeaserProps) { + return ( +
+ +

{node.title}

+ +
+ {node.uid?.display_name ? ( + + Posted by{" "} + {node.uid?.display_name} + + ) : null} + - {formatDate(node.created)} +
+ {node.field_image && ( +
+ {node.field_image.resourceIdObjMeta.alt} +
+ )} + + Read article + + + + +
+ ) +} diff --git a/starters/pages-starter/components/drupal/BasicPage.tsx b/starters/pages-starter/components/drupal/BasicPage.tsx new file mode 100644 index 000000000..88d7f00b4 --- /dev/null +++ b/starters/pages-starter/components/drupal/BasicPage.tsx @@ -0,0 +1,19 @@ +import type { DrupalNode } from "next-drupal" + +interface BasicPageProps { + node: DrupalNode +} + +export function BasicPage({ node, ...props }: BasicPageProps) { + return ( +
+

{node.title}

+ {node.body?.processed && ( +
+ )} +
+ ) +} diff --git a/starters/pages-starter/components/misc/PreviewAlert.tsx b/starters/pages-starter/components/misc/PreviewAlert.tsx new file mode 100644 index 000000000..edce57204 --- /dev/null +++ b/starters/pages-starter/components/misc/PreviewAlert.tsx @@ -0,0 +1,35 @@ +import { useEffect, useState } from "react" +import { useRouter } from "next/router" + +export function PreviewAlert() { + const router = useRouter() + const isPreview = router.isPreview + const [showPreviewAlert, setShowPreviewAlert] = useState(false) + + useEffect(() => { + setShowPreviewAlert(isPreview && window.top === window.self) + }, [isPreview]) + + if (!showPreviewAlert) { + return null + } + + function buttonHandler() { + void fetch("/api/exit-preview") + setShowPreviewAlert(false) + } + + return ( +
+

+ This page is a preview.{" "} + +

+
+ ) +} diff --git a/starters/pages-starter/components/navigation/HeaderNav.tsx b/starters/pages-starter/components/navigation/HeaderNav.tsx new file mode 100644 index 000000000..bccb4e4ca --- /dev/null +++ b/starters/pages-starter/components/navigation/HeaderNav.tsx @@ -0,0 +1,21 @@ +import { Link } from "@/components/navigation/Link" + +export function HeaderNav() { + return ( +
+
+ + Next.js for Drupal + + + Read the docs + +
+
+ ) +} diff --git a/starters/pages-starter/components/navigation/Link.tsx b/starters/pages-starter/components/navigation/Link.tsx new file mode 100644 index 000000000..23dbc4c0b --- /dev/null +++ b/starters/pages-starter/components/navigation/Link.tsx @@ -0,0 +1,23 @@ +import { forwardRef } from "react" +import NextLink from "next/link" +import type { AnchorHTMLAttributes, ReactNode } from "react" +import type { LinkProps as NextLinkProps } from "next/link" + +type LinkProps = NextLinkProps & + Omit, keyof NextLinkProps> & { + children?: ReactNode + } + +export const Link = forwardRef( + function LinkWithRef( + { + // Turn next/link prefetching off by default. + // @see https://github.com/vercel/next.js/discussions/24009 + prefetch = false, + ...rest + }, + ref + ) { + return + } +) diff --git a/starters/pages-starter/lib/drupal.ts b/starters/pages-starter/lib/drupal.ts new file mode 100644 index 000000000..9b2f40c07 --- /dev/null +++ b/starters/pages-starter/lib/drupal.ts @@ -0,0 +1,14 @@ +import { NextDrupalPages } from "next-drupal" + +const baseUrl = process.env.NEXT_PUBLIC_DRUPAL_BASE_URL as string +const clientId = process.env.DRUPAL_CLIENT_ID as string +const clientSecret = process.env.DRUPAL_CLIENT_SECRET as string + +export const drupal = new NextDrupalPages(baseUrl, { + auth: { + clientId, + clientSecret, + }, + useDefaultEndpoints: true, + // debug: true, +}) diff --git a/starters/pages-starter/lib/utils.ts b/starters/pages-starter/lib/utils.ts new file mode 100644 index 000000000..d83a0d733 --- /dev/null +++ b/starters/pages-starter/lib/utils.ts @@ -0,0 +1,12 @@ +export function formatDate(input: string): string { + const date = new Date(input) + return date.toLocaleDateString("en-US", { + month: "long", + day: "numeric", + year: "numeric", + }) +} + +export function absoluteUrl(input: string) { + return `${process.env.NEXT_PUBLIC_DRUPAL_BASE_URL}${input}` +} diff --git a/starters/pages-starter/next.config.js b/starters/pages-starter/next.config.js new file mode 100644 index 000000000..0a7fabac4 --- /dev/null +++ b/starters/pages-starter/next.config.js @@ -0,0 +1,16 @@ +/** @type {import('next').NextConfig} */ +const nextConfig = { + reactStrictMode: true, + images: { + remotePatterns: [ + { + // protocol: 'https', + hostname: process.env.NEXT_IMAGE_DOMAIN, + // port: '', + // pathname: '/sites/default/files/**', + }, + ], + }, +} + +module.exports = nextConfig diff --git a/starters/pages-starter/package.json b/starters/pages-starter/package.json new file mode 100644 index 000000000..a910663fa --- /dev/null +++ b/starters/pages-starter/package.json @@ -0,0 +1,34 @@ +{ + "name": "pages-starter", + "version": "2.0.0-alpha.0", + "private": true, + "license": "MIT", + "scripts": { + "dev": "next dev", + "build": "next build", + "start": "next start", + "preview": "next build && next start", + "lint": "next lint", + "format": "prettier --write .", + "format:check": "prettier --check ." + }, + "dependencies": { + "next": "^14.2.2", + "next-drupal": "^2.0.0-alpha.1", + "react": "^18.2.0", + "react-dom": "^18.2.0" + }, + "devDependencies": { + "@tailwindcss/typography": "^0.5.12", + "@types/node": "^20.12.7", + "@types/react": "^18.2.79", + "@types/react-dom": "^18.2.25", + "autoprefixer": "^10.4.19", + "eslint": "^8.57.0", + "eslint-config-next": "^14.2.2", + "postcss": "^8.4.38", + "prettier": "^3.2.5", + "tailwindcss": "^3.4.3", + "typescript": "^5.4.5" + } +} diff --git a/starters/pages-starter/pages/[...slug].tsx b/starters/pages-starter/pages/[...slug].tsx new file mode 100644 index 000000000..9894d5f0d --- /dev/null +++ b/starters/pages-starter/pages/[...slug].tsx @@ -0,0 +1,92 @@ +import Head from "next/head" +import { Article } from "@/components/drupal/Article" +import { BasicPage } from "@/components/drupal/BasicPage" +import { Layout } from "@/components/Layout" +import { drupal } from "@/lib/drupal" +import type { + GetStaticPaths, + GetStaticProps, + InferGetStaticPropsType, +} from "next" +import type { DrupalNode } from "next-drupal" + +const RESOURCE_TYPES = ["node--page", "node--article"] + +export const getStaticPaths = (async (context) => { + return { + paths: await drupal.getStaticPathsFromContext(RESOURCE_TYPES, context), + fallback: "blocking", + } +}) satisfies GetStaticPaths + +export const getStaticProps = (async (context) => { + const path = await drupal.translatePathFromContext(context) + + if (!path) { + return { + notFound: true, + } + } + + const type = path?.jsonapi?.resourceName + + let params = {} + if (type === "node--article") { + params = { + include: "field_image,uid", + } + } + + const resource = await drupal.getResourceFromContext( + path, + context, + { + params, + } + ) + + // At this point, we know the path exists and it points to a resource. + // If we receive an error, it means something went wrong on Drupal. + // We throw an error to tell revalidation to skip this for now. + // Revalidation can try again on next request. + if (!resource) { + throw new Error(`Failed to fetch resource: ${path?.jsonapi?.individual}`) + } + + // If we're not in preview mode and the resource is not published, + // Return page not found. + if (!context.preview && resource?.status === false) { + return { + notFound: true, + } + } + + return { + props: { + resource, + }, + } +}) satisfies GetStaticProps<{ + resource: DrupalNode +}> + +export default function NodePage({ + resource, +}: InferGetStaticPropsType) { + if (!resource) return null + + return ( + + + {resource.title} + + + {resource.type === "node--page" && } + {resource.type === "node--article" &&
} + + ) +} diff --git a/starters/pages-starter/pages/_app.tsx b/starters/pages-starter/pages/_app.tsx new file mode 100644 index 000000000..70739e9b0 --- /dev/null +++ b/starters/pages-starter/pages/_app.tsx @@ -0,0 +1,6 @@ +import "@/styles/globals.css" +import type { AppProps } from "next/app" + +export default function App({ Component, pageProps }: AppProps) { + return +} diff --git a/starters/pages-starter/pages/_document.tsx b/starters/pages-starter/pages/_document.tsx new file mode 100644 index 000000000..097cb7ff3 --- /dev/null +++ b/starters/pages-starter/pages/_document.tsx @@ -0,0 +1,13 @@ +import { Html, Head, Main, NextScript } from "next/document" + +export default function Document() { + return ( + + + +
+ + + + ) +} diff --git a/starters/pages-starter/pages/api/exit-preview.ts b/starters/pages-starter/pages/api/exit-preview.ts new file mode 100644 index 000000000..f8847b399 --- /dev/null +++ b/starters/pages-starter/pages/api/exit-preview.ts @@ -0,0 +1,9 @@ +import { drupal } from "@/lib/drupal" +import type { NextApiRequest, NextApiResponse } from "next" + +export default async function exit( + request: NextApiRequest, + response: NextApiResponse +) { + await drupal.previewDisable(request, response) +} diff --git a/starters/pages-starter/pages/api/preview.ts b/starters/pages-starter/pages/api/preview.ts new file mode 100644 index 000000000..a0733440a --- /dev/null +++ b/starters/pages-starter/pages/api/preview.ts @@ -0,0 +1,10 @@ +import { drupal } from "@/lib/drupal" +import type { NextApiRequest, NextApiResponse } from "next" + +export default async function draft( + request: NextApiRequest, + response: NextApiResponse +) { + // Enables Preview mode and Draft mode. + await drupal.preview(request, response, { enable: true }) +} diff --git a/starters/pages-starter/pages/api/revalidate.ts b/starters/pages-starter/pages/api/revalidate.ts new file mode 100644 index 000000000..368a16c88 --- /dev/null +++ b/starters/pages-starter/pages/api/revalidate.ts @@ -0,0 +1,29 @@ +import type { NextApiRequest, NextApiResponse } from "next" + +export default async function handler( + request: NextApiRequest, + response: NextApiResponse +) { + let path = request.query.path as string + const secret = request.query.secret as string + + // Validate secret. + if (secret !== process.env.DRUPAL_REVALIDATE_SECRET) { + return response.status(401).json({ message: "Invalid secret." }) + } + + // Validate path. + if (!path) { + return response.status(400).json({ message: "Invalid path." }) + } + + try { + await response.revalidate(path) + + return response.json({}) + } catch (error) { + return response.status(404).json({ + message: (error as Error).message, + }) + } +} diff --git a/starters/pages-starter/pages/index.tsx b/starters/pages-starter/pages/index.tsx new file mode 100644 index 000000000..e5963b983 --- /dev/null +++ b/starters/pages-starter/pages/index.tsx @@ -0,0 +1,57 @@ +import Head from "next/head" +import { ArticleTeaser } from "@/components/drupal/ArticleTeaser" +import { Layout } from "@/components/Layout" +import { drupal } from "@/lib/drupal" +import type { InferGetStaticPropsType, GetStaticProps } from "next" +import type { DrupalNode } from "next-drupal" + +export const getStaticProps = (async (context) => { + const nodes = await drupal.getResourceCollectionFromContext( + "node--article", + context, + { + params: { + "filter[status]": 1, + "fields[node--article]": "title,path,field_image,uid,created", + include: "field_image,uid", + sort: "-created", + }, + } + ) + + return { + props: { + nodes, + }, + } +}) satisfies GetStaticProps<{ + nodes: DrupalNode[] +}> + +export default function Home({ + nodes, +}: InferGetStaticPropsType) { + return ( + + + Next.js for Drupal + + +

Latest Articles.

+ {nodes?.length ? ( + nodes.map((node) => ( +
+ +
+
+ )) + ) : ( +

No nodes found

+ )} +
+ ) +} diff --git a/starters/pages-starter/postcss.config.js b/starters/pages-starter/postcss.config.js new file mode 100644 index 000000000..3fa0a9514 --- /dev/null +++ b/starters/pages-starter/postcss.config.js @@ -0,0 +1,8 @@ +// If you want to use other PostCSS plugins, see the following: +// https://tailwindcss.com/docs/using-with-preprocessors +module.exports = { + plugins: { + tailwindcss: {}, + autoprefixer: {}, + }, +} diff --git a/starters/pages-starter/public/favicon.ico b/starters/pages-starter/public/favicon.ico new file mode 100644 index 000000000..ea2f437d9 Binary files /dev/null and b/starters/pages-starter/public/favicon.ico differ diff --git a/starters/pages-starter/public/robots.txt b/starters/pages-starter/public/robots.txt new file mode 100644 index 000000000..14267e903 --- /dev/null +++ b/starters/pages-starter/public/robots.txt @@ -0,0 +1,2 @@ +User-agent: * +Allow: / \ No newline at end of file diff --git a/starters/pages-starter/styles/globals.css b/starters/pages-starter/styles/globals.css new file mode 100644 index 000000000..b5c61c956 --- /dev/null +++ b/starters/pages-starter/styles/globals.css @@ -0,0 +1,3 @@ +@tailwind base; +@tailwind components; +@tailwind utilities; diff --git a/starters/pages-starter/tailwind.config.ts b/starters/pages-starter/tailwind.config.ts new file mode 100644 index 000000000..c7f5c8a18 --- /dev/null +++ b/starters/pages-starter/tailwind.config.ts @@ -0,0 +1,18 @@ +import type { Config } from "tailwindcss" + +const config: Config = { + content: [ + "./pages/**/*.{js,ts,jsx,tsx,mdx}", + "./components/**/*.{js,ts,jsx,tsx,mdx}", + "./app/**/*.{js,ts,jsx,tsx,mdx}", + ], + theme: { + extend: {}, + }, + variants: { + extend: {}, + }, + plugins: [require("@tailwindcss/typography")], +} + +export default config diff --git a/starters/pages-starter/tsconfig.json b/starters/pages-starter/tsconfig.json new file mode 100644 index 000000000..23ba4fd54 --- /dev/null +++ b/starters/pages-starter/tsconfig.json @@ -0,0 +1,28 @@ +{ + "compilerOptions": { + "target": "es5", + "lib": ["dom", "dom.iterable", "esnext"], + "allowJs": true, + "skipLibCheck": true, + "strict": true, + "forceConsistentCasingInFileNames": true, + "noEmit": true, + "esModuleInterop": true, + "module": "esnext", + "moduleResolution": "bundler", + "resolveJsonModule": true, + "isolatedModules": true, + "jsx": "preserve", + "incremental": true, + "plugins": [ + { + "name": "next" + } + ], + "paths": { + "@/*": ["./*"] + } + }, + "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"], + "exclude": ["node_modules"] +}