Skip to content

Commit

Permalink
feat(basic-starter): add Draft Mode to basic-starter and graphql-starter
Browse files Browse the repository at this point in the history
Issue #601
  • Loading branch information
JohnAlbin committed Apr 18, 2024
1 parent 499d023 commit 81d56ad
Show file tree
Hide file tree
Showing 27 changed files with 263 additions and 168 deletions.
3 changes: 1 addition & 2 deletions starters/basic-starter/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,7 @@
.pnp.js
.yarn/install-state.gz

# build/test artifacts
/.turbo
# testing
/coverage

# next.js
Expand Down
2 changes: 1 addition & 1 deletion starters/basic-starter/README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Basic Starter

A simple starter for building your site with Next.js and Drupal.
A simple starter for building your site with Next.js' Pages Router and Drupal.

## How to use

Expand Down
20 changes: 3 additions & 17 deletions starters/basic-starter/components/Layout.tsx
Original file line number Diff line number Diff line change
@@ -1,27 +1,13 @@
import Link from "next/link"
import { PreviewAlert } from "@/components/PreviewAlert"
import { HeaderNav } from "@/components/navigation/HeaderNav"
import { PreviewAlert } from "@/components/misc/PreviewAlert"
import type { ReactNode } from "react"

export function Layout({ children }: { children: ReactNode }) {
return (
<>
<PreviewAlert />
<div className="max-w-screen-md px-6 mx-auto">
<header>
<div className="container flex items-center justify-between py-6 mx-auto">
<Link href="/" className="text-2xl font-semibold no-underline">
Next.js for Drupal
</Link>
<Link
href="https://next-drupal.org/docs"
target="_blank"
rel="external"
className="hover:text-blue-600"
>
Read the docs
</Link>
</div>
</header>
<HeaderNav />
<main className="container py-10 mx-auto">{children}</main>
</div>
</>
Expand Down
2 changes: 1 addition & 1 deletion starters/basic-starter/components/drupal/ArticleTeaser.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import Image from "next/image"
import Link from "next/link"
import { Link } from "@/components/navigation/Link"
import { absoluteUrl, formatDate } from "@/lib/utils"
import type { DrupalNode } from "next-drupal"

Expand Down
21 changes: 21 additions & 0 deletions starters/basic-starter/components/navigation/HeaderNav.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { Link } from "@/components/navigation/Link"

export function HeaderNav() {
return (
<header>
<div className="container flex items-center justify-between py-6 mx-auto">
<Link href="/" className="text-2xl font-semibold no-underline">
Next.js for Drupal
</Link>
<Link
href="https://next-drupal.org/docs"
target="_blank"
rel="external"
className="hover:text-blue-600"
>
Read the docs
</Link>
</div>
</header>
)
}
23 changes: 23 additions & 0 deletions starters/basic-starter/components/navigation/Link.tsx
Original file line number Diff line number Diff line change
@@ -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<AnchorHTMLAttributes<HTMLAnchorElement>, keyof NextLinkProps> & {
children?: ReactNode
}

export const Link = forwardRef<HTMLAnchorElement, LinkProps>(
function LinkWithRef(
{
// Turn next/link prefetching off by default.
// @see https://github.com/vercel/next.js/discussions/24009
prefetch = false,
...rest
},
ref
) {
return <NextLink prefetch={prefetch} {...rest} ref={ref} />
}
)
8 changes: 5 additions & 3 deletions starters/basic-starter/lib/drupal.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
import { DrupalClient } from "next-drupal"

const baseUrl: string = process.env.NEXT_PUBLIC_DRUPAL_BASE_URL || ""
const clientId = process.env.DRUPAL_CLIENT_ID || ""
const clientSecret = process.env.DRUPAL_CLIENT_SECRET || ""
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 DrupalClient(baseUrl, {
auth: {
clientId,
clientSecret,
},
// debug: true,
// useDefaultResourceTypeEntry: true,
})
7 changes: 3 additions & 4 deletions starters/basic-starter/pages/api/exit-preview.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
import { drupal } from "@/lib/drupal"
import type { NextApiRequest, NextApiResponse } from "next"

export default async function exit(
_: NextApiRequest,
request: NextApiRequest,
response: NextApiResponse
) {
response.clearPreviewData()
response.writeHead(307, { Location: "/" })
response.end()
await drupal.previewDisable(request, response)
}
5 changes: 3 additions & 2 deletions starters/basic-starter/pages/api/preview.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import { drupal } from "@/lib/drupal"
import type { NextApiRequest, NextApiResponse } from "next"

export default async function handler(
export default async function draft(
request: NextApiRequest,
response: NextApiResponse
) {
await drupal.preview(request, response)
// Enables Preview mode and Draft mode.
await drupal.preview(request, response, { enable: true })
}
7 changes: 6 additions & 1 deletion starters/basic-starter/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,15 @@
"isolatedModules": true,
"jsx": "preserve",
"incremental": true,
"plugins": [
{
"name": "next"
}
],
"paths": {
"@/*": ["./*"]
}
},
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"],
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
"exclude": ["node_modules"]
}
3 changes: 1 addition & 2 deletions starters/graphql-starter/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,7 @@
.pnp.js
.yarn/install-state.gz

# build/test artifacts
/.turbo
# testing
/coverage

# next.js
Expand Down
20 changes: 3 additions & 17 deletions starters/graphql-starter/components/Layout.tsx
Original file line number Diff line number Diff line change
@@ -1,27 +1,13 @@
import Link from "next/link"
import { PreviewAlert } from "@/components/PreviewAlert"
import { HeaderNav } from "@/components/navigation/HeaderNav"
import { PreviewAlert } from "@/components/misc/PreviewAlert"
import type { ReactNode } from "react"

export function Layout({ children }: { children: ReactNode }) {
return (
<>
<PreviewAlert />
<div className="max-w-screen-md px-6 mx-auto">
<header>
<div className="container flex items-center justify-between py-6 mx-auto">
<Link href="/" className="text-2xl font-semibold no-underline">
Next.js for Drupal
</Link>
<Link
href="https://next-drupal.org/docs"
target="_blank"
rel="external"
className="hover:text-blue-600"
>
Read the docs
</Link>
</div>
</header>
<HeaderNav />
<main className="container py-10 mx-auto">{children}</main>
</div>
</>
Expand Down
11 changes: 5 additions & 6 deletions starters/graphql-starter/components/drupal/Article.tsx
Original file line number Diff line number Diff line change
@@ -1,23 +1,22 @@
import Image from "next/image"
import { formatDate } from "@/lib/utils"
import type { NodeArticle } from "@/types"
import type { DrupalArticle } from "@/types"

interface ArticleProps {
node: NodeArticle
node: DrupalArticle
}

export function Article({ node, ...props }: ArticleProps) {
return (
<article {...props}>
<h1 className="mb-4 text-6xl font-black leading-tight">{node.title}</h1>
<div className="mb-4 text-gray-600">
{node.author?.displayName ? (
{node.author?.name ? (
<span>
Posted by{" "}
<span className="font-semibold">{node.author.displayName}</span>
Posted by <span className="font-semibold">{node.author.name}</span>
</span>
) : null}
<span> - {formatDate(node.created)}</span>
<span> - {formatDate(node.created.time)}</span>
</div>
{node.image && (
<figure>
Expand Down
13 changes: 6 additions & 7 deletions starters/graphql-starter/components/drupal/ArticleTeaser.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import Image from "next/image"
import Link from "next/link"
import { Link } from "@/components/navigation/Link"
import { formatDate } from "@/lib/utils"
import type { NodeArticle } from "@/types"
import type { DrupalArticle } from "@/types"

interface ArticleTeaserProps {
node: Partial<NodeArticle>
node: Partial<DrupalArticle>
}

export function ArticleTeaser({ node, ...props }: ArticleTeaserProps) {
Expand All @@ -14,13 +14,12 @@ export function ArticleTeaser({ node, ...props }: ArticleTeaserProps) {
<h2 className="mb-4 text-4xl font-bold">{node.title}</h2>
</Link>
<div className="mb-4 text-gray-600">
{node.author?.displayName ? (
{node.author?.name ? (
<span>
Posted by{" "}
<span className="font-semibold">{node.author.displayName}</span>
Posted by <span className="font-semibold">{node.author.name}</span>
</span>
) : null}
{node.created && <span> - {formatDate(node.created)}</span>}
{node.created && <span> - {formatDate(node.created.time)}</span>}
</div>
{node.image && (
<figure className="my-4">
Expand Down
4 changes: 2 additions & 2 deletions starters/graphql-starter/components/drupal/BasicPage.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import type { NodePage } from "@/types"
import type { DrupalPage } from "@/types"

interface BasicPageProps {
node: NodePage
node: DrupalPage
}

export function BasicPage({ node, ...props }: BasicPageProps) {
Expand Down
21 changes: 21 additions & 0 deletions starters/graphql-starter/components/navigation/HeaderNav.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { Link } from "@/components/navigation/Link"

export function HeaderNav() {
return (
<header>
<div className="container flex items-center justify-between py-6 mx-auto">
<Link href="/" className="text-2xl font-semibold no-underline">
Next.js for Drupal
</Link>
<Link
href="https://next-drupal.org/docs"
target="_blank"
rel="external"
className="hover:text-blue-600"
>
Read the docs
</Link>
</div>
</header>
)
}
23 changes: 23 additions & 0 deletions starters/graphql-starter/components/navigation/Link.tsx
Original file line number Diff line number Diff line change
@@ -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<AnchorHTMLAttributes<HTMLAnchorElement>, keyof NextLinkProps> & {
children?: ReactNode
}

export const Link = forwardRef<HTMLAnchorElement, LinkProps>(
function LinkWithRef(
{
// Turn next/link prefetching off by default.
// @see https://github.com/vercel/next.js/discussions/24009
prefetch = false,
...rest
},
ref
) {
return <NextLink prefetch={prefetch} {...rest} ref={ref} />
}
)
50 changes: 6 additions & 44 deletions starters/graphql-starter/lib/drupal.ts
Original file line number Diff line number Diff line change
@@ -1,51 +1,13 @@
import { DrupalClient } from "next-drupal"
import { NextDrupalGraphQL } from "./next-drupal-graphql"

const baseUrl: string = process.env.NEXT_PUBLIC_DRUPAL_BASE_URL || ""
const clientId = process.env.DRUPAL_CLIENT_ID || ""
const clientSecret = process.env.DRUPAL_CLIENT_SECRET || ""
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 DrupalClient(baseUrl, {
export const drupal = new NextDrupalGraphQL(baseUrl, {
auth: {
clientId,
clientSecret,
},
// debug: true,
})

export const graphqlEndpoint = drupal.buildUrl("/graphql")

type QueryPayload = {
query: string
variables?: Record<string, string>
}

type QueryJsonResponse<DataType> = {
data?: DataType
errors?: { message: string }[]
}

// This is a wrapper around drupal.fetch.
// Acts as a query helper.
export async function query<DataType>(payload: QueryPayload) {
const response = await drupal.fetch(graphqlEndpoint.toString(), {
method: "POST",
body: JSON.stringify(payload),
withAuth: true, // Make authenticated requests using OAuth.
headers: {
"Content-Type": "application/json",
Accept: "application/json",
},
})

if (!response?.ok) {
throw new Error(response.statusText)
}

const { data, errors }: QueryJsonResponse<DataType> = await response.json()

if (errors) {
console.log(errors)
throw new Error(errors?.map((e) => e.message).join("\n") ?? "unknown")
}

return data
}
Loading

0 comments on commit 81d56ad

Please sign in to comment.