From 33ebe696f8bddde28e43b80f57d9e7734e14b3ec Mon Sep 17 00:00:00 2001
From: cws
Date: Wed, 9 Dec 2020 00:52:19 +0100
Subject: [PATCH] add cms-ghost
---
examples/cms-agilitycms/README.md | 1 +
examples/cms-buttercms/README.md | 1 +
examples/cms-contentful/README.md | 1 +
examples/cms-cosmic/README.md | 1 +
examples/cms-datocms/README.md | 1 +
examples/cms-ghost/.env.local.example | 2 +
examples/cms-ghost/.gitignore | 34 +++++++
examples/cms-ghost/README.md | 90 ++++++++++++++++++
examples/cms-ghost/components/alert.js | 42 ++++++++
examples/cms-ghost/components/avatar.js | 14 +++
examples/cms-ghost/components/container.js | 3 +
examples/cms-ghost/components/cover-image.js | 35 +++++++
examples/cms-ghost/components/date.js | 6 ++
examples/cms-ghost/components/footer.js | 30 ++++++
examples/cms-ghost/components/header.js | 12 +++
examples/cms-ghost/components/hero-post.js | 37 +++++++
examples/cms-ghost/components/intro.js | 28 ++++++
examples/cms-ghost/components/layout.js | 18 ++++
.../components/markdown-styles.module.css | 18 ++++
examples/cms-ghost/components/meta.js | 42 ++++++++
examples/cms-ghost/components/more-stories.js | 24 +++++
examples/cms-ghost/components/post-body.js | 12 +++
examples/cms-ghost/components/post-header.js | 26 +++++
examples/cms-ghost/components/post-preview.js | 31 ++++++
examples/cms-ghost/components/post-title.js | 7 ++
.../cms-ghost/components/section-separator.js | 3 +
examples/cms-ghost/jsconfig.json | 10 ++
examples/cms-ghost/lib/api.js | 75 +++++++++++++++
examples/cms-ghost/lib/constants.js | 5 +
examples/cms-ghost/package.json | 25 +++++
examples/cms-ghost/pages/_app.js | 7 ++
examples/cms-ghost/pages/_document.js | 15 +++
examples/cms-ghost/pages/api/exit-preview.js | 8 ++
examples/cms-ghost/pages/api/preview.js | 28 ++++++
examples/cms-ghost/pages/index.js | 43 +++++++++
examples/cms-ghost/pages/posts/[slug].js | 69 ++++++++++++++
examples/cms-ghost/postcss.config.js | 18 ++++
.../public/favicon/android-chrome-192x192.png | Bin 0 -> 4795 bytes
.../public/favicon/android-chrome-512x512.png | Bin 0 -> 14640 bytes
.../public/favicon/apple-touch-icon.png | Bin 0 -> 1327 bytes
.../public/favicon/browserconfig.xml | 9 ++
.../public/favicon/favicon-16x16.png | Bin 0 -> 595 bytes
.../public/favicon/favicon-32x32.png | Bin 0 -> 880 bytes
examples/cms-ghost/public/favicon/favicon.ico | Bin 0 -> 15086 bytes
.../public/favicon/mstile-150x150.png | Bin 0 -> 3567 bytes
.../public/favicon/safari-pinned-tab.svg | 33 +++++++
.../cms-ghost/public/favicon/site.webmanifest | 19 ++++
examples/cms-ghost/styles/index.css | 3 +
examples/cms-ghost/tailwind.config.js | 33 +++++++
examples/cms-graphcms/README.md | 1 +
examples/cms-kontent/README.md | 1 +
examples/cms-prismic/README.md | 1 +
examples/cms-sanity/README.md | 1 +
examples/cms-storyblok/README.md | 1 +
examples/cms-strapi/README.md | 1 +
examples/cms-takeshape/README.md | 1 +
examples/cms-wordpress/README.md | 1 +
57 files changed, 927 insertions(+)
create mode 100644 examples/cms-ghost/.env.local.example
create mode 100644 examples/cms-ghost/.gitignore
create mode 100644 examples/cms-ghost/README.md
create mode 100644 examples/cms-ghost/components/alert.js
create mode 100644 examples/cms-ghost/components/avatar.js
create mode 100644 examples/cms-ghost/components/container.js
create mode 100644 examples/cms-ghost/components/cover-image.js
create mode 100644 examples/cms-ghost/components/date.js
create mode 100644 examples/cms-ghost/components/footer.js
create mode 100644 examples/cms-ghost/components/header.js
create mode 100644 examples/cms-ghost/components/hero-post.js
create mode 100644 examples/cms-ghost/components/intro.js
create mode 100644 examples/cms-ghost/components/layout.js
create mode 100644 examples/cms-ghost/components/markdown-styles.module.css
create mode 100644 examples/cms-ghost/components/meta.js
create mode 100644 examples/cms-ghost/components/more-stories.js
create mode 100644 examples/cms-ghost/components/post-body.js
create mode 100644 examples/cms-ghost/components/post-header.js
create mode 100644 examples/cms-ghost/components/post-preview.js
create mode 100644 examples/cms-ghost/components/post-title.js
create mode 100644 examples/cms-ghost/components/section-separator.js
create mode 100644 examples/cms-ghost/jsconfig.json
create mode 100644 examples/cms-ghost/lib/api.js
create mode 100644 examples/cms-ghost/lib/constants.js
create mode 100644 examples/cms-ghost/package.json
create mode 100644 examples/cms-ghost/pages/_app.js
create mode 100644 examples/cms-ghost/pages/_document.js
create mode 100644 examples/cms-ghost/pages/api/exit-preview.js
create mode 100644 examples/cms-ghost/pages/api/preview.js
create mode 100644 examples/cms-ghost/pages/index.js
create mode 100644 examples/cms-ghost/pages/posts/[slug].js
create mode 100644 examples/cms-ghost/postcss.config.js
create mode 100644 examples/cms-ghost/public/favicon/android-chrome-192x192.png
create mode 100644 examples/cms-ghost/public/favicon/android-chrome-512x512.png
create mode 100644 examples/cms-ghost/public/favicon/apple-touch-icon.png
create mode 100644 examples/cms-ghost/public/favicon/browserconfig.xml
create mode 100644 examples/cms-ghost/public/favicon/favicon-16x16.png
create mode 100644 examples/cms-ghost/public/favicon/favicon-32x32.png
create mode 100644 examples/cms-ghost/public/favicon/favicon.ico
create mode 100644 examples/cms-ghost/public/favicon/mstile-150x150.png
create mode 100644 examples/cms-ghost/public/favicon/safari-pinned-tab.svg
create mode 100644 examples/cms-ghost/public/favicon/site.webmanifest
create mode 100644 examples/cms-ghost/styles/index.css
create mode 100644 examples/cms-ghost/tailwind.config.js
diff --git a/examples/cms-agilitycms/README.md b/examples/cms-agilitycms/README.md
index d53c27ee3e0b7..cad5a6853c1c0 100644
--- a/examples/cms-agilitycms/README.md
+++ b/examples/cms-agilitycms/README.md
@@ -29,6 +29,7 @@ Once you have access to [the environment variables you'll need](#step-15-set-up-
- [Storyblok](/examples/cms-storyblok)
- [GraphCMS](/examples/cms-graphcms)
- [Kontent](/examples/cms-kontent)
+- [Ghost](/examples/cms-ghost)
- [Blog Starter](/examples/blog-starter)
## How to use
diff --git a/examples/cms-buttercms/README.md b/examples/cms-buttercms/README.md
index b455eaa19d133..49493ca3d0fc8 100644
--- a/examples/cms-buttercms/README.md
+++ b/examples/cms-buttercms/README.md
@@ -26,6 +26,7 @@ Once you have access to [the environment variables you'll need](#step-2-set-up-e
- [Storyblok](/examples/cms-storyblok)
- [GraphCMS](/examples/cms-graphcms)
- [Kontent](/examples/cms-kontent)
+- [Ghost](/examples/cms-ghost)
- [Blog Starter](/examples/blog-starter)
## How to use
diff --git a/examples/cms-contentful/README.md b/examples/cms-contentful/README.md
index 88690dd7d1a92..ab6c3a682d0d0 100644
--- a/examples/cms-contentful/README.md
+++ b/examples/cms-contentful/README.md
@@ -26,6 +26,7 @@ Once you have access to [the environment variables you'll need](#step-5-set-up-e
- [Storyblok](/examples/cms-storyblok)
- [GraphCMS](/examples/cms-graphcms)
- [Kontent](/examples/cms-kontent)
+- [Ghost](/examples/cms-ghost)
- [Blog Starter](/examples/blog-starter)
## How to use
diff --git a/examples/cms-cosmic/README.md b/examples/cms-cosmic/README.md
index c4b795c11612c..d7e90213183c2 100644
--- a/examples/cms-cosmic/README.md
+++ b/examples/cms-cosmic/README.md
@@ -26,6 +26,7 @@ Once you have access to [the environment variables you'll need](#step-3-set-up-e
- [Storyblok](/examples/cms-storyblok)
- [GraphCMS](/examples/cms-graphcms)
- [Kontent](/examples/cms-kontent)
+- [Ghost](/examples/cms-ghost)
- [Blog Starter](/examples/blog-starter)
## How to use
diff --git a/examples/cms-datocms/README.md b/examples/cms-datocms/README.md
index 79f501d1fa291..3b394d1b3fbe8 100644
--- a/examples/cms-datocms/README.md
+++ b/examples/cms-datocms/README.md
@@ -20,6 +20,7 @@ This example showcases Next.js's [Static Generation](https://nextjs.org/docs/bas
- [Storyblok](/examples/cms-storyblok)
- [GraphCMS](/examples/cms-graphcms)
- [Kontent](/examples/cms-kontent)
+- [Ghost](/examples/cms-ghost)
- [Blog Starter](/examples/blog-starter)
## Deploy your own
diff --git a/examples/cms-ghost/.env.local.example b/examples/cms-ghost/.env.local.example
new file mode 100644
index 0000000000000..e60e609d4d49c
--- /dev/null
+++ b/examples/cms-ghost/.env.local.example
@@ -0,0 +1,2 @@
+GHOST_API_URL=
+GHOST_API_KEY=
diff --git a/examples/cms-ghost/.gitignore b/examples/cms-ghost/.gitignore
new file mode 100644
index 0000000000000..1437c53f70bc2
--- /dev/null
+++ b/examples/cms-ghost/.gitignore
@@ -0,0 +1,34 @@
+# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
+
+# dependencies
+/node_modules
+/.pnp
+.pnp.js
+
+# testing
+/coverage
+
+# next.js
+/.next/
+/out/
+
+# production
+/build
+
+# misc
+.DS_Store
+*.pem
+
+# debug
+npm-debug.log*
+yarn-debug.log*
+yarn-error.log*
+
+# local env files
+.env.local
+.env.development.local
+.env.test.local
+.env.production.local
+
+# vercel
+.vercel
diff --git a/examples/cms-ghost/README.md b/examples/cms-ghost/README.md
new file mode 100644
index 0000000000000..fd159c4bc9127
--- /dev/null
+++ b/examples/cms-ghost/README.md
@@ -0,0 +1,90 @@
+# A statically generated blog example using Next.js and Ghost
+
+This example showcases Next.js's [Static Generation](https://nextjs.org/docs/basic-features/pages) feature using [Ghost](https://ghost.org/) as the data source.
+
+> This boilerplate demonstrates simple usage and best practices. If you are looking for a more feature richt Next.js generator for Ghost including the Casper theme,
+> check out [next-cms-ghost](https://github.com/styxlab/next-cms-ghost).
+
+## Demo
+
+[https://ghost-next-blog.vercel.app/](https://ghost-next-blog.vercel.app/)
+
+## Deploy your own
+
+Once you have access to [the environment variables you'll need](#step-2-set-up-environment-variables), deploy the example using [Vercel](https://vercel.com?utm_source=github&utm_medium=readme&utm_campaign=next-example):
+
+[![Deploy with Vercel](https://vercel.com/button)](https://vercel.com/import/git?c=1&s=https://github.com/vercel/next.js/tree/canary/examples/cms-ghost&env=ghost_BUCKET_SLUG,ghost_READ_KEY,ghost_PREVIEW_SECRET&envDescription=Required%20to%20connect%20the%20app%20with%20ghost&envLink=https://vercel.link/cms-ghost-env)
+
+### Related examples
+
+- [WordPress](/examples/cms-wordpress)
+- [DatoCMS](/examples/cms-datocms)
+- [Sanity](/examples/cms-sanity)
+- [TakeShape](/examples/cms-takeshape)
+- [Prismic](/examples/cms-prismic)
+- [Contentful](/examples/cms-contentful)
+- [Strapi](/examples/cms-strapi)
+- [Agility CMS](/examples/cms-agilitycms)
+- [ButterCMS](/examples/cms-buttercms)
+- [Storyblok](/examples/cms-storyblok)
+- [GraphCMS](/examples/cms-graphcms)
+- [Kontent](/examples/cms-kontent)
+- [Blog Starter](/examples/blog-starter)
+
+## How to use
+
+Execute [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app) with [npm](https://docs.npmjs.com/cli/init) or [Yarn](https://yarnpkg.com/lang/en/docs/cli/create/) to bootstrap the example:
+
+```bash
+npx create-next-app --example cms-ghost cms-ghost-app
+# or
+yarn create next-app --example cms-ghost cms-ghost-app
+```
+
+### Setp 1. Run Next.js in development mode
+
+To get started, no configuration is needed as this example sources the content from a demo Ghost CMS.
+
+```bash
+npm install
+npm run dev
+
+# or
+
+yarn install
+yarn dev
+```
+
+Your blog should be up and running on [http://localhost:3000](http://localhost:3000)! If it doesn't work, post on [GitHub discussions](https://github.com/vercel/next.js/discussions).
+
+### Step 2. Set up environment variables
+
+If you already have a Ghost CMS running, you should create new Content API keys in the Ghost Admin panel under Integrations -> Add custom integration.
+Once your keys are generated, copy them into the environment variables as follows. Your `.env.local` file should look like this:
+
+```bash
+GHOST_API_URL=...
+GHOST_API_KEY=...
+```
+
+Make sure to use the Content API Key.
+
+### Step 3. Set up Headless Ghost CMS
+
+If you do not have access to a Ghost CMS, you need to create one for your own content. The demo Ghost CMS is running on Hetzner Cloud, which is described in [Ghost CMS on Hetzner Cloud](https://www.jamify.org/2020/04/07/ghost-cms-on-hetzner-cloud/). Note that a Ghost install on localhost is not sufficient for public deploys, as the images on your local computer are not accessible from outside.
+
+### Step 4. Deploy on Vercel
+
+You can deploy this app to the cloud with [Vercel](https://vercel.com?utm_source=github&utm_medium=readme&utm_campaign=next-example) ([Documentation](https://nextjs.org/docs/deployment)).
+
+#### Deploy Your Local Project
+
+To deploy your local project to Vercel, push it to GitHub/GitLab/Bitbucket and [import to Vercel](https://vercel.com/import/git?utm_source=github&utm_medium=readme&utm_campaign=next-example).
+
+**Important**: When you import your project on Vercel, make sure to click on **Environment Variables** and set them to match your `.env.local` file.
+
+#### Deploy from Our Template
+
+Alternatively, you can deploy using our template by clicking on the Deploy button below.
+
+[![Deploy with Vercel](https://vercel.com/button)](https://vercel.com/import/git?c=1&s=https://github.com/vercel/next.js/tree/canary/examples/cms-ghost&env=GHOST_API_URL,GHOST_API_KEY&envDescription=Required%20to%20connect%20the%20app%20with%20ghost&envLink=https://vercel.link/cms-ghost-env)
diff --git a/examples/cms-ghost/components/alert.js b/examples/cms-ghost/components/alert.js
new file mode 100644
index 0000000000000..e6fd18b175c8c
--- /dev/null
+++ b/examples/cms-ghost/components/alert.js
@@ -0,0 +1,42 @@
+import Container from './container'
+import cn from 'classnames'
+import { EXAMPLE_PATH } from '@/lib/constants'
+
+export default function Alert({ preview }) {
+ return (
+
+
+
+ {preview ? (
+ <>
+ This is page is a preview.{' '}
+
+ Click here
+ {' '}
+ to exit preview mode.
+ >
+ ) : (
+ <>
+ The source code for this blog is{' '}
+
+ available on GitHub
+
+ .
+ >
+ )}
+
+
+
+ )
+}
diff --git a/examples/cms-ghost/components/avatar.js b/examples/cms-ghost/components/avatar.js
new file mode 100644
index 0000000000000..271037ba41c1d
--- /dev/null
+++ b/examples/cms-ghost/components/avatar.js
@@ -0,0 +1,14 @@
+export default function Avatar({ name, picture }) {
+ return (
+
+ {picture && (
+
+ )}
+
{name}
+
+ )
+}
diff --git a/examples/cms-ghost/components/container.js b/examples/cms-ghost/components/container.js
new file mode 100644
index 0000000000000..fc1c29dfb0747
--- /dev/null
+++ b/examples/cms-ghost/components/container.js
@@ -0,0 +1,3 @@
+export default function Container({ children }) {
+ return {children}
+}
diff --git a/examples/cms-ghost/components/cover-image.js b/examples/cms-ghost/components/cover-image.js
new file mode 100644
index 0000000000000..499a8ce501c0e
--- /dev/null
+++ b/examples/cms-ghost/components/cover-image.js
@@ -0,0 +1,35 @@
+import cn from 'classnames'
+import Link from 'next/link'
+import Imgix from 'react-imgix'
+
+export default function CoverImage({ title, url, slug }) {
+ const image = (
+
+ )
+ return (
+
+ {slug ? (
+
+
{image}
+
+ ) : (
+ image
+ )}
+
+ )
+}
diff --git a/examples/cms-ghost/components/date.js b/examples/cms-ghost/components/date.js
new file mode 100644
index 0000000000000..eac5681378bfd
--- /dev/null
+++ b/examples/cms-ghost/components/date.js
@@ -0,0 +1,6 @@
+import { parseISO, format } from 'date-fns'
+
+export default function Date({ dateString }) {
+ const date = parseISO(dateString)
+ return {format(date, 'LLLL d, yyyy')}
+}
diff --git a/examples/cms-ghost/components/footer.js b/examples/cms-ghost/components/footer.js
new file mode 100644
index 0000000000000..102872d195df0
--- /dev/null
+++ b/examples/cms-ghost/components/footer.js
@@ -0,0 +1,30 @@
+import Container from './container'
+import { EXAMPLE_PATH } from '@/lib/constants'
+
+export default function Footer() {
+ return (
+
+
+
+
+ Statically Generated with Next.js.
+
+
+
+
+
+ )
+}
diff --git a/examples/cms-ghost/components/header.js b/examples/cms-ghost/components/header.js
new file mode 100644
index 0000000000000..562e7e3eebb6a
--- /dev/null
+++ b/examples/cms-ghost/components/header.js
@@ -0,0 +1,12 @@
+import Link from 'next/link'
+
+export default function Header() {
+ return (
+
+
+ Blog
+
+ .
+
+ )
+}
diff --git a/examples/cms-ghost/components/hero-post.js b/examples/cms-ghost/components/hero-post.js
new file mode 100644
index 0000000000000..59dd46e301901
--- /dev/null
+++ b/examples/cms-ghost/components/hero-post.js
@@ -0,0 +1,37 @@
+import Avatar from './avatar'
+import Date from './date'
+import CoverImage from './cover-image'
+import Link from 'next/link'
+
+export default function HeroPost({
+ title,
+ coverImage,
+ date,
+ excerpt,
+ author,
+ slug,
+}) {
+ return (
+
+ )
+}
diff --git a/examples/cms-ghost/components/intro.js b/examples/cms-ghost/components/intro.js
new file mode 100644
index 0000000000000..c3003c6196642
--- /dev/null
+++ b/examples/cms-ghost/components/intro.js
@@ -0,0 +1,28 @@
+import { CMS_NAME, CMS_URL } from '@/lib/constants'
+
+export default function Intro() {
+ return (
+
+ )
+}
diff --git a/examples/cms-ghost/components/layout.js b/examples/cms-ghost/components/layout.js
new file mode 100644
index 0000000000000..ff54d53992783
--- /dev/null
+++ b/examples/cms-ghost/components/layout.js
@@ -0,0 +1,18 @@
+import Alert from './alert'
+import Footer from './footer'
+import Meta from './meta'
+import 'lazysizes'
+import 'lazysizes/plugins/parent-fit/ls.parent-fit'
+
+export default function Layout({ preview, children }) {
+ return (
+ <>
+
+
+
+ >
+ )
+}
diff --git a/examples/cms-ghost/components/markdown-styles.module.css b/examples/cms-ghost/components/markdown-styles.module.css
new file mode 100644
index 0000000000000..95d4f8b04172d
--- /dev/null
+++ b/examples/cms-ghost/components/markdown-styles.module.css
@@ -0,0 +1,18 @@
+.markdown {
+ @apply text-lg leading-relaxed;
+}
+
+.markdown p,
+.markdown ul,
+.markdown ol,
+.markdown blockquote {
+ @apply my-6;
+}
+
+.markdown h2 {
+ @apply text-3xl mt-12 mb-4 leading-snug;
+}
+
+.markdown h3 {
+ @apply text-2xl mt-8 mb-4 leading-snug;
+}
diff --git a/examples/cms-ghost/components/meta.js b/examples/cms-ghost/components/meta.js
new file mode 100644
index 0000000000000..cec622742089e
--- /dev/null
+++ b/examples/cms-ghost/components/meta.js
@@ -0,0 +1,42 @@
+import Head from 'next/head'
+import { CMS_NAME, HOME_OG_IMAGE_URL } from '@/lib/constants'
+
+export default function Meta() {
+ return (
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ )
+}
diff --git a/examples/cms-ghost/components/more-stories.js b/examples/cms-ghost/components/more-stories.js
new file mode 100644
index 0000000000000..92eefcf51c36f
--- /dev/null
+++ b/examples/cms-ghost/components/more-stories.js
@@ -0,0 +1,24 @@
+import PostPreview from './post-preview'
+
+export default function MoreStories({ posts }) {
+ return (
+
+
+ More Stories
+
+
+ {posts.map((post) => (
+
+ ))}
+
+
+ )
+}
diff --git a/examples/cms-ghost/components/post-body.js b/examples/cms-ghost/components/post-body.js
new file mode 100644
index 0000000000000..4cc2bb52bccef
--- /dev/null
+++ b/examples/cms-ghost/components/post-body.js
@@ -0,0 +1,12 @@
+import markdownStyles from './markdown-styles.module.css'
+
+export default function PostBody({ content }) {
+ return (
+
+ )
+}
diff --git a/examples/cms-ghost/components/post-header.js b/examples/cms-ghost/components/post-header.js
new file mode 100644
index 0000000000000..53ed1d6a6cd71
--- /dev/null
+++ b/examples/cms-ghost/components/post-header.js
@@ -0,0 +1,26 @@
+import Avatar from './avatar'
+import Date from './date'
+import CoverImage from './cover-image'
+import PostTitle from './post-title'
+
+export default function PostHeader({ title, coverImage, date, author }) {
+ return (
+ <>
+ {title}
+
+
+
+
+
+ >
+ )
+}
diff --git a/examples/cms-ghost/components/post-preview.js b/examples/cms-ghost/components/post-preview.js
new file mode 100644
index 0000000000000..c34388de0b872
--- /dev/null
+++ b/examples/cms-ghost/components/post-preview.js
@@ -0,0 +1,31 @@
+import Avatar from './avatar'
+import Date from './date'
+import CoverImage from './cover-image'
+import Link from 'next/link'
+
+export default function PostPreview({
+ title,
+ coverImage,
+ date,
+ excerpt,
+ author,
+ slug,
+}) {
+ return (
+
+
+
+
+
+
+
+
+
{excerpt}
+
+
+ )
+}
diff --git a/examples/cms-ghost/components/post-title.js b/examples/cms-ghost/components/post-title.js
new file mode 100644
index 0000000000000..edd8cba65c257
--- /dev/null
+++ b/examples/cms-ghost/components/post-title.js
@@ -0,0 +1,7 @@
+export default function PostTitle({ children }) {
+ return (
+
+ {children}
+
+ )
+}
diff --git a/examples/cms-ghost/components/section-separator.js b/examples/cms-ghost/components/section-separator.js
new file mode 100644
index 0000000000000..4ca5c65fdc6ee
--- /dev/null
+++ b/examples/cms-ghost/components/section-separator.js
@@ -0,0 +1,3 @@
+export default function SectionSeparator() {
+ return
+}
diff --git a/examples/cms-ghost/jsconfig.json b/examples/cms-ghost/jsconfig.json
new file mode 100644
index 0000000000000..1bac23a7cd556
--- /dev/null
+++ b/examples/cms-ghost/jsconfig.json
@@ -0,0 +1,10 @@
+{
+ "compilerOptions": {
+ "baseUrl": ".",
+ "paths": {
+ "@/components/*": ["components/*"],
+ "@/lib/*": ["lib/*"],
+ "@/styles/*": ["styles/*"]
+ }
+ }
+}
diff --git a/examples/cms-ghost/lib/api.js b/examples/cms-ghost/lib/api.js
new file mode 100644
index 0000000000000..b3d2791441956
--- /dev/null
+++ b/examples/cms-ghost/lib/api.js
@@ -0,0 +1,75 @@
+import GhostContentAPI from '@tryghost/content-api'
+
+const GHOST_API_URL = process.env.GHOST_API_URL || 'https://cms.gotsby.org'
+const GHOST_API_KEY = process.env.GHOST_API_KEY || '387f956eaa95345f7bb484d0b8'
+
+const api = new GhostContentAPI({
+ url: GHOST_API_URL,
+ key: GHOST_API_KEY,
+ version: 'v3',
+})
+
+const is404 = (error) => /not found/i.test(error.message)
+
+export async function getPreviewPostBySlug(slug) {
+ const params = {
+ slug,
+ fields: 'slug',
+ limit: 'all',
+ }
+
+ try {
+ const post = await api.posts.read(params)
+ return post
+ } catch (error) {
+ // Don't throw if an slug doesn't exist
+ if (is404(error)) return
+ throw error
+ }
+}
+
+export async function getAllPostsWithSlug() {
+ const params = {
+ fields: 'slug',
+ limit: 'all',
+ }
+ const posts = await api.posts.browse(params)
+ return posts
+}
+
+export async function getAllPostsForHome(preview) {
+ const params = {
+ limit: 'all',
+ include: 'authors',
+ order: 'published_at DESC',
+ ...(preview && { status: 'all' }),
+ }
+ const posts = await api.posts.browse(params)
+ return posts
+}
+
+export async function getPostAndMorePosts(slug, preview) {
+ const singleObjectParams = {
+ slug,
+ include: 'authors',
+ ...(preview && { status: 'all' }),
+ }
+ const moreObjectParams = {
+ limit: 3,
+ include: 'authors',
+ ...(preview && { status: 'all' }),
+ }
+ const post = await api.posts.read(singleObjectParams).catch((error) => {
+ // Don't throw if an slug doesn't exist
+ if (is404(error)) return
+ throw error
+ })
+ const morePosts = (await api.posts.browse(moreObjectParams))
+ ?.filter(({ slug }) => post.slug !== slug)
+ .slice(0, 2)
+
+ return {
+ post,
+ morePosts,
+ }
+}
diff --git a/examples/cms-ghost/lib/constants.js b/examples/cms-ghost/lib/constants.js
new file mode 100644
index 0000000000000..c9ffa5f43d2de
--- /dev/null
+++ b/examples/cms-ghost/lib/constants.js
@@ -0,0 +1,5 @@
+export const EXAMPLE_PATH = 'cms-ghost'
+export const CMS_NAME = 'Ghost'
+export const CMS_URL = 'https://ghost.org/'
+export const HOME_OG_IMAGE_URL =
+ 'https://og-image.now.sh/Next.js%20Example%20Blog%20with%20**Ghost**.png?theme=light&md=1&fontSize=75px&images=https%3A%2F%2Fassets.vercel.com%2Fimage%2Fupload%2Ffront%2Fassets%2Fdesign%2Fnextjs-black-logo.svg&images=https%3A%2F%2Fghost.org%2Fimages%2Flogo.svg'
diff --git a/examples/cms-ghost/package.json b/examples/cms-ghost/package.json
new file mode 100644
index 0000000000000..a4bbe0acc80ab
--- /dev/null
+++ b/examples/cms-ghost/package.json
@@ -0,0 +1,25 @@
+{
+ "name": "cms-ghost",
+ "version": "1.0.0",
+ "scripts": {
+ "dev": "next",
+ "build": "next build",
+ "start": "next start"
+ },
+ "dependencies": {
+ "@tryghost/content-api": "^1.4.10",
+ "classnames": "2.2.6",
+ "date-fns": "2.14.0",
+ "lazysizes": "^5.2.1-rc2",
+ "next": "latest",
+ "react": "^16.13.1",
+ "react-imgix": "^9.0.2",
+ "react-dom": "^16.13.1"
+ },
+ "devDependencies": {
+ "postcss-flexbugs-fixes": "4.2.1",
+ "postcss-preset-env": "^6.7.0",
+ "tailwindcss": "^1.4.6"
+ },
+ "license": "MIT"
+}
diff --git a/examples/cms-ghost/pages/_app.js b/examples/cms-ghost/pages/_app.js
new file mode 100644
index 0000000000000..f18e112c7cf79
--- /dev/null
+++ b/examples/cms-ghost/pages/_app.js
@@ -0,0 +1,7 @@
+import '@/styles/index.css'
+
+function MyApp({ Component, pageProps }) {
+ return
+}
+
+export default MyApp
diff --git a/examples/cms-ghost/pages/_document.js b/examples/cms-ghost/pages/_document.js
new file mode 100644
index 0000000000000..c55951c0d5daf
--- /dev/null
+++ b/examples/cms-ghost/pages/_document.js
@@ -0,0 +1,15 @@
+import Document, { Html, Head, Main, NextScript } from 'next/document'
+
+export default class MyDocument extends Document {
+ render() {
+ return (
+
+
+
+
+
+
+
+ )
+ }
+}
diff --git a/examples/cms-ghost/pages/api/exit-preview.js b/examples/cms-ghost/pages/api/exit-preview.js
new file mode 100644
index 0000000000000..6c63a0a6e8a42
--- /dev/null
+++ b/examples/cms-ghost/pages/api/exit-preview.js
@@ -0,0 +1,8 @@
+export default async function exit(_, res) {
+ // Exit the current user from "Preview Mode". This function accepts no args.
+ res.clearPreviewData()
+
+ // Redirect the user back to the index page.
+ res.writeHead(307, { Location: '/' })
+ res.end()
+}
diff --git a/examples/cms-ghost/pages/api/preview.js b/examples/cms-ghost/pages/api/preview.js
new file mode 100644
index 0000000000000..852c8858f3c32
--- /dev/null
+++ b/examples/cms-ghost/pages/api/preview.js
@@ -0,0 +1,28 @@
+import { getPreviewPostBySlug } from '@/lib/api'
+
+export default async function preview(req, res) {
+ // Check the secret and next parameters
+ // This secret should only be known to this API route and the CMS
+ if (
+ req.query.secret !== process.env.GHOST_PREVIEW_SECRET ||
+ !req.query.slug
+ ) {
+ return res.status(401).json({ message: 'Invalid token' })
+ }
+
+ // Fetch the headless CMS to check if the provided `slug` exists
+ const post = await getPreviewPostBySlug(req.query.slug)
+
+ // If the slug doesn't exist prevent preview mode from being enabled
+ if (!post) {
+ return res.status(401).json({ message: 'Invalid slug' })
+ }
+
+ // Enable Preview Mode by setting the cookies
+ res.setPreviewData({})
+
+ // Redirect to the path from the fetched post
+ // We don't redirect to req.query.slug as that might lead to open redirect vulnerabilities
+ res.writeHead(307, { Location: `/posts/${post.slug}` })
+ res.end()
+}
diff --git a/examples/cms-ghost/pages/index.js b/examples/cms-ghost/pages/index.js
new file mode 100644
index 0000000000000..21ca17a8a5be9
--- /dev/null
+++ b/examples/cms-ghost/pages/index.js
@@ -0,0 +1,43 @@
+import Container from '@/components/container'
+import MoreStories from '@/components/more-stories'
+import HeroPost from '@/components/hero-post'
+import Intro from '@/components/intro'
+import Layout from '@/components/layout'
+import { getAllPostsForHome } from '@/lib/api'
+import Head from 'next/head'
+import { CMS_NAME } from '@/lib/constants'
+
+export default function Index({ allPosts }) {
+ const heroPost = allPosts[0]
+ const morePosts = allPosts.slice(1)
+ return (
+ <>
+
+
+ Next.js Blog Example with {CMS_NAME}
+
+
+
+ {heroPost && (
+
+ )}
+ {morePosts.length > 0 && }
+
+
+ >
+ )
+}
+
+export async function getStaticProps({ preview }) {
+ const allPosts = (await getAllPostsForHome(preview)) || []
+ return {
+ props: { allPosts },
+ }
+}
diff --git a/examples/cms-ghost/pages/posts/[slug].js b/examples/cms-ghost/pages/posts/[slug].js
new file mode 100644
index 0000000000000..bf2a6b4b266a4
--- /dev/null
+++ b/examples/cms-ghost/pages/posts/[slug].js
@@ -0,0 +1,69 @@
+import { useRouter } from 'next/router'
+import ErrorPage from 'next/error'
+import Container from '@/components/container'
+import PostBody from '@/components/post-body'
+import MoreStories from '@/components/more-stories'
+import Header from '@/components/header'
+import PostHeader from '@/components/post-header'
+import SectionSeparator from '@/components/section-separator'
+import Layout from '@/components/layout'
+import { getAllPostsWithSlug, getPostAndMorePosts } from '@/lib/api'
+import PostTitle from '@/components/post-title'
+import Head from 'next/head'
+import { CMS_NAME } from '@/lib/constants'
+
+export default function Post({ post, morePosts, preview }) {
+ const router = useRouter()
+ if (!router.isFallback && !post?.slug) {
+ return
+ }
+ return (
+
+
+
+ {router.isFallback ? (
+ Loading…
+ ) : (
+ <>
+
+
+
+ {post.title} | Next.js Blog Example with {CMS_NAME}
+
+
+
+
+
+
+
+ {morePosts.length > 0 && }
+ >
+ )}
+
+
+ )
+}
+
+export async function getStaticProps({ params, preview = null }) {
+ const { post, morePosts } = await getPostAndMorePosts(params.slug, preview)
+ return {
+ props: {
+ preview,
+ post,
+ morePosts: morePosts || [],
+ },
+ }
+}
+
+export async function getStaticPaths() {
+ const allPosts = (await getAllPostsWithSlug()) || []
+ return {
+ paths: allPosts.map((post) => `/posts/${post.slug}`),
+ fallback: true,
+ }
+}
diff --git a/examples/cms-ghost/postcss.config.js b/examples/cms-ghost/postcss.config.js
new file mode 100644
index 0000000000000..6f2d25c4e3509
--- /dev/null
+++ b/examples/cms-ghost/postcss.config.js
@@ -0,0 +1,18 @@
+module.exports = {
+ plugins: [
+ 'tailwindcss',
+ 'postcss-flexbugs-fixes',
+ [
+ 'postcss-preset-env',
+ {
+ autoprefixer: {
+ flexbox: 'no-2009',
+ },
+ stage: 3,
+ features: {
+ 'custom-properties': false,
+ },
+ },
+ ],
+ ],
+}
diff --git a/examples/cms-ghost/public/favicon/android-chrome-192x192.png b/examples/cms-ghost/public/favicon/android-chrome-192x192.png
new file mode 100644
index 0000000000000000000000000000000000000000..2f07282a59cdadaf579b129d650f588d89bef63e
GIT binary patch
literal 4795
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
literal 0
HcmV?d00001
diff --git a/examples/cms-ghost/public/favicon/android-chrome-512x512.png b/examples/cms-ghost/public/favicon/android-chrome-512x512.png
new file mode 100644
index 0000000000000000000000000000000000000000..dbb0faea84049b991417262cb8f14ae08201c443
GIT binary patch
literal 14640
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
MboFyt=akR{06}d?wEzGB
literal 0
HcmV?d00001
diff --git a/examples/cms-ghost/public/favicon/browserconfig.xml b/examples/cms-ghost/public/favicon/browserconfig.xml
new file mode 100644
index 0000000000000..9824d87b11517
--- /dev/null
+++ b/examples/cms-ghost/public/favicon/browserconfig.xml
@@ -0,0 +1,9 @@
+
+
+
+
+
+ #000000
+
+
+
diff --git a/examples/cms-ghost/public/favicon/favicon-16x16.png b/examples/cms-ghost/public/favicon/favicon-16x16.png
new file mode 100644
index 0000000000000000000000000000000000000000..29deaf6716e7744b24b8d2f94443b50d3acffe68
GIT binary patch
literal 595
zcmeAS@N?(olHy`uVBq!ia0vp^0wB!60wlNoGJgf6SkfJR9T^xl_H+M9WCijSl0AZa
z85pY67#JE_7#My5g&JNkFq9fFFuY1&V6d9Oz#v{QXIG#NP=YDR+ueoXe|!I#{Xiaj
ziKnkC`y&=<4t4b@G6n~MLO(oR978nD=T6+{bvQtxb^jfYOS`%RMA#j5UMSyS|6pbD
zi;d6k9bZ#^z+(Rks>-)2dl_&J^V`G?Q{pEo#nr8;@~
z`krL*_G;*v!^IjrakA;BEvmm}T6sI&)8w8wxgoVPV2$ltj)nWqZSPSP<9cp)#pk-y
z3!nU3->tb0Uyz+-@SssyAx-@8dugfqY?qVb-(9v$nAvu{N21_p{^`Vs3aO80xy!%&
z$oZzjQ>@>dc#PfLX7k6kor!0-63$vnKbR`q7inF2)PmzwPWtVW3*#8c~vxSdwa$T$Bo=7>o=IEp!b`
zbdAhI3@ogSErCeez{twLptqKz2}MJ0eoAIqC2kFW6gJoaHH24%M3e+2mMat#<)>xl
zq$-qD7Nja<7L+72FjUNW{E3I7Fib<^l>g~7o=<}qn3cKplDUPIg}o<>FbgZVG?*Mt
wVOHK8qHy}gl@mwK9FaM~e!9V9ftMb`D{;Y+Pfn&&fmSehy85}Sb4q9e02)x*r~m)}
literal 0
HcmV?d00001
diff --git a/examples/cms-ghost/public/favicon/favicon-32x32.png b/examples/cms-ghost/public/favicon/favicon-32x32.png
new file mode 100644
index 0000000000000000000000000000000000000000..e3b4277bf093d204f4088ba46590bc9e6f37bf67
GIT binary patch
literal 880
zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE0wix1Z>k4UEa{HEjtmSN`?>!lvVtU&J%W50
z7^>757#dm_7=8hT8eT9klo~KFyh>nTu$sZZAYL$MSD+10f+@+{-G$+Qd;gjJKpuOE
zr>`sfBNk~6b@eGS1_y!iqMj~}As)x)PCc6)94K(Key6_H)~zdg8;|I@2rLO(;bG?z
zv&88`{sbpi5kZkx_Z~U92;G^MrtDPSr1Z{Z$_>33u1k7BO}vhVOI&wNh%niD+%@X$
zZ@)Q_cPr<7PJ1`kQuttQpkKj6ndP1vjjEhOWtlh|D8oV>EHcW
z2`<~itr`hdERnPRyIxS?X6yERwEJ~uLB~SbPr1@5O?#Bx=6LEzEKE!9dp*_eMU(Ed
zOXYj7Gp6&Iy74^bx!uWbaa8i1;AYbmu2VWbzipE=f6`I4{V1>b0b5hc!z--i9*Rrf
zc~&FA*drwr$HMEyV|ezVK~u}Z``UW*K1{N?ewgD|Z@JAOtM4m~kM0y;b3Sd&eAu1q
z$c$$R0{c=ke$>x>Y&m@gTTSxW-@a09s_U6r8pQY`9`a?bI&&PJ`$1|x1z#mL#e9}@HJ8bK
zzir;N-}0T6{L6#yK6nF6GpZ%75hW>!C8<`)MX5lF!N|bSLf61V*T_7?z{1Md5{R@7
zjI0a{dTTkFP&DM`r(~v8;@0p-VS^n|LwHq4L`hI$xk5ovep+TuszOO+L8?M#K}j+L
zL&coOpLjS5!!$Hb`JX=H`80@uS(#fenOj&{*n6@Fv#^3ogUR6(X64Nx3a4*eIdSC7
j5t$?GryD#LcNSTKFL46_E}iL5mO)AEZS|
zhz??kp>#q_Pa+X9S9!)q#7v>f>h;_1zJ2P{J?EY~6zP?$I_K=Y*ZTkWKIiUX?Ol$O
z;bc0!dO3Q{aq`JLhPRsE;xZ>o<~Kd63*DEFk1M;XdugYEZ_Oa-Nh{-%0D^{MKAR3)TR78`8wfiHZP
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
literal 0
HcmV?d00001
diff --git a/examples/cms-ghost/public/favicon/mstile-150x150.png b/examples/cms-ghost/public/favicon/mstile-150x150.png
new file mode 100644
index 0000000000000000000000000000000000000000..f2dfd904bf1be62be8351fcbc60a1028269923f0
GIT binary patch
literal 3567
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
AfdBvi
literal 0
HcmV?d00001
diff --git a/examples/cms-ghost/public/favicon/safari-pinned-tab.svg b/examples/cms-ghost/public/favicon/safari-pinned-tab.svg
new file mode 100644
index 0000000000000..72ab6e050cb11
--- /dev/null
+++ b/examples/cms-ghost/public/favicon/safari-pinned-tab.svg
@@ -0,0 +1,33 @@
+
+
+
+
+Created by potrace 1.11, written by Peter Selinger 2001-2013
+
+
+
+
+
+
+
+
+
+
diff --git a/examples/cms-ghost/public/favicon/site.webmanifest b/examples/cms-ghost/public/favicon/site.webmanifest
new file mode 100644
index 0000000000000..a672d9a233c59
--- /dev/null
+++ b/examples/cms-ghost/public/favicon/site.webmanifest
@@ -0,0 +1,19 @@
+{
+ "name": "Next.js",
+ "short_name": "Next.js",
+ "icons": [
+ {
+ "src": "/favicons/android-chrome-192x192.png",
+ "sizes": "192x192",
+ "type": "image/png"
+ },
+ {
+ "src": "/favicons/android-chrome-512x512.png",
+ "sizes": "512x512",
+ "type": "image/png"
+ }
+ ],
+ "theme_color": "#000000",
+ "background_color": "#000000",
+ "display": "standalone"
+}
diff --git a/examples/cms-ghost/styles/index.css b/examples/cms-ghost/styles/index.css
new file mode 100644
index 0000000000000..b5c61c956711f
--- /dev/null
+++ b/examples/cms-ghost/styles/index.css
@@ -0,0 +1,3 @@
+@tailwind base;
+@tailwind components;
+@tailwind utilities;
diff --git a/examples/cms-ghost/tailwind.config.js b/examples/cms-ghost/tailwind.config.js
new file mode 100644
index 0000000000000..dc81b5174ced5
--- /dev/null
+++ b/examples/cms-ghost/tailwind.config.js
@@ -0,0 +1,33 @@
+module.exports = {
+ purge: ['./components/**/*.js', './pages/**/*.js'],
+ theme: {
+ extend: {
+ colors: {
+ 'accent-1': '#FAFAFA',
+ 'accent-2': '#EAEAEA',
+ 'accent-7': '#333',
+ success: '#0070f3',
+ cyan: '#79FFE1',
+ },
+ spacing: {
+ 28: '7rem',
+ },
+ letterSpacing: {
+ tighter: '-.04em',
+ },
+ lineHeight: {
+ tight: 1.2,
+ },
+ fontSize: {
+ '5xl': '2.5rem',
+ '6xl': '2.75rem',
+ '7xl': '4.5rem',
+ '8xl': '6.25rem',
+ },
+ boxShadow: {
+ small: '0 5px 10px rgba(0, 0, 0, 0.12)',
+ medium: '0 8px 30px rgba(0, 0, 0, 0.12)',
+ },
+ },
+ },
+}
diff --git a/examples/cms-graphcms/README.md b/examples/cms-graphcms/README.md
index b52731c715166..50e84453e3ad5 100644
--- a/examples/cms-graphcms/README.md
+++ b/examples/cms-graphcms/README.md
@@ -23,6 +23,7 @@ This example showcases Next.js's [Static Generation](https://nextjs.org/docs/bas
- [ButterCMS](/examples/cms-buttercms)
- [Storyblok](/examples/cms-storyblok)
- [Kontent](/examples/cms-kontent)
+- [Ghost](/examples/cms-ghost)
- [Blog Starter](/examples/blog-starter)
## Deploy your own
diff --git a/examples/cms-kontent/README.md b/examples/cms-kontent/README.md
index cdb721f0c8fee..2c98df4d795fc 100644
--- a/examples/cms-kontent/README.md
+++ b/examples/cms-kontent/README.md
@@ -26,6 +26,7 @@ Once you have access to [the environment variables you'll need](#step-3-set-up-e
- [ButterCMS](/examples/cms-buttercms)
- [Storyblok](/examples/cms-storyblok)
- [GraphCMS](/examples/cms-graphcms)
+- [Ghost](/examples/cms-ghost)
- [Blog Starter](/examples/blog-starter)
## How to use
diff --git a/examples/cms-prismic/README.md b/examples/cms-prismic/README.md
index 3eb460ac6d764..6ed2338ecb011 100644
--- a/examples/cms-prismic/README.md
+++ b/examples/cms-prismic/README.md
@@ -25,6 +25,7 @@ Once you have access to [the environment variables you'll need](#step-5-set-up-e
- [ButterCMS](/examples/cms-buttercms)
- [Storyblok](/examples/cms-storyblok)
- [Kontent](/examples/cms-kontent)
+- [Ghost](/examples/cms-ghost)
- [Blog Starter](/examples/blog-starter)
## How to use
diff --git a/examples/cms-sanity/README.md b/examples/cms-sanity/README.md
index 2a50081b795a8..d6f9c389e3b06 100644
--- a/examples/cms-sanity/README.md
+++ b/examples/cms-sanity/README.md
@@ -26,6 +26,7 @@ Once you have access to [the environment variables you'll need](#step-4-set-up-e
- [Storyblok](/examples/cms-storyblok)
- [GraphCMS](/examples/cms-graphcms)
- [Kontent](/examples/cms-kontent)
+- [Ghost](/examples/cms-ghost)
- [Blog Starter](/examples/blog-starter)
## How to use
diff --git a/examples/cms-storyblok/README.md b/examples/cms-storyblok/README.md
index 755776384a05a..26e97b000f280 100644
--- a/examples/cms-storyblok/README.md
+++ b/examples/cms-storyblok/README.md
@@ -26,6 +26,7 @@ Once you have access to [the environment variables you'll need](#step-6-set-up-e
- [ButterCMS](/examples/cms-buttercms)
- [GraphCMS](/examples/cms-graphcms)
- [Kontent](/examples/cms-kontent)
+- [Ghost](/examples/cms-ghost)
- [Blog Starter](/examples/blog-starter)
## How to use
diff --git a/examples/cms-strapi/README.md b/examples/cms-strapi/README.md
index 6d71a3fed34e1..239a6cda1c82d 100644
--- a/examples/cms-strapi/README.md
+++ b/examples/cms-strapi/README.md
@@ -26,6 +26,7 @@ Once you have access to [the environment variables you'll need](#step-7-set-up-e
- [Storyblok](/examples/cms-storyblok)
- [GraphCMS](/examples/cms-graphcms)
- [Kontent](/examples/cms-kontent)
+- [Ghost](/examples/cms-ghost)
- [Blog Starter](/examples/blog-starter)
## How to use
diff --git a/examples/cms-takeshape/README.md b/examples/cms-takeshape/README.md
index e231149cfa9fc..d7c31a3f9336e 100644
--- a/examples/cms-takeshape/README.md
+++ b/examples/cms-takeshape/README.md
@@ -26,6 +26,7 @@ Once you have access to [the environment variables you'll need](#step-5-set-up-e
- [Storyblok](/examples/cms-storyblok)
- [GraphCMS](/examples/cms-graphcms)
- [Kontent](/examples/cms-kontent)
+- [Ghost](/examples/cms-ghost)
- [Blog Starter](/examples/blog-starter)
## How to use
diff --git a/examples/cms-wordpress/README.md b/examples/cms-wordpress/README.md
index 4a6f7db4da8e0..ac4ebc281eb15 100644
--- a/examples/cms-wordpress/README.md
+++ b/examples/cms-wordpress/README.md
@@ -26,6 +26,7 @@ Once you have access to [the environment variables you'll need](#step-3-set-up-e
- [Storyblok](/examples/cms-storyblok)
- [GraphCMS](/examples/cms-graphcms)
- [Kontent](/examples/cms-kontent)
+- [Ghost](/examples/cms-ghost)
- [Blog Starter](/examples/blog-starter)
## How to use