Skip to content

Commit

Permalink
[examples] Added blog-starter example using Ghost CMS (#19990)
Browse files Browse the repository at this point in the history
  • Loading branch information
styxlab committed Feb 7, 2021
1 parent fb843a5 commit e69a4d7
Show file tree
Hide file tree
Showing 59 changed files with 944 additions and 0 deletions.
1 change: 1 addition & 0 deletions examples/cms-agilitycms/README.md
Expand Up @@ -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
Expand Down
1 change: 1 addition & 0 deletions examples/cms-buttercms/README.md
Expand Up @@ -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
Expand Down
1 change: 1 addition & 0 deletions examples/cms-contentful/README.md
Expand Up @@ -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
Expand Down
1 change: 1 addition & 0 deletions examples/cms-cosmic/README.md
Expand Up @@ -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
Expand Down
1 change: 1 addition & 0 deletions examples/cms-datocms/README.md
Expand Up @@ -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
Expand Down
2 changes: 2 additions & 0 deletions examples/cms-ghost/.env.local.example
@@ -0,0 +1,2 @@
GHOST_API_URL=
GHOST_API_KEY=
34 changes: 34 additions & 0 deletions 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
86 changes: 86 additions & 0 deletions examples/cms-ghost/README.md
@@ -0,0 +1,86 @@
# 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).
## 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)
42 changes: 42 additions & 0 deletions 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 (
<div
className={cn('border-b', {
'bg-accent-7 border-accent-7 text-white': preview,
'bg-accent-1 border-accent-2': !preview,
})}
>
<Container>
<div className="py-2 text-center text-sm">
{preview ? (
<>
This is page is a preview.{' '}
<a
href="/api/exit-preview"
className="underline hover:text-cyan duration-200 transition-colors"
>
Click here
</a>{' '}
to exit preview mode.
</>
) : (
<>
The source code for this blog is{' '}
<a
href={`https://github.com/zeit/next.js/tree/canary/examples/${EXAMPLE_PATH}`}
className="underline hover:text-success duration-200 transition-colors"
>
available on GitHub
</a>
.
</>
)}
</div>
</Container>
</div>
)
}
14 changes: 14 additions & 0 deletions examples/cms-ghost/components/avatar.js
@@ -0,0 +1,14 @@
export default function Avatar({ name, picture }) {
return (
<div className="flex items-center">
{picture && (
<img
src={`${picture}?auto=format,compress,enhance&w=100&h=100`}
className="w-12 h-12 rounded-full mr-4"
alt={name}
/>
)}
<div className="text-xl font-bold">{name}</div>
</div>
)
}
3 changes: 3 additions & 0 deletions examples/cms-ghost/components/container.js
@@ -0,0 +1,3 @@
export default function Container({ children }) {
return <div className="container mx-auto px-5">{children}</div>
}
29 changes: 29 additions & 0 deletions examples/cms-ghost/components/cover-image.js
@@ -0,0 +1,29 @@
import cn from 'classnames'
import Link from 'next/link'
import Image from 'next/image'

export default function CoverImage({ title, url, slug, width, height }) {
const image = (
<Image
src={url}
alt={`Cover Image for ${title}`}
className={cn('shadow-sm', {
'hover:shadow-md transition-shadow duration-200': slug,
})}
layout="responsive"
width={width}
height={height}
/>
)
return (
<div className="sm:mx-0">
{slug ? (
<Link href={`/posts/${slug}`}>
<a aria-label={title}>{image}</a>
</Link>
) : (
image
)}
</div>
)
}
6 changes: 6 additions & 0 deletions 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 <time dateTime={dateString}>{format(date, 'LLLL d, yyyy')}</time>
}
30 changes: 30 additions & 0 deletions 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 (
<footer className="bg-accent-1 border-t border-accent-2">
<Container>
<div className="py-28 flex flex-col lg:flex-row items-center">
<h3 className="text-4xl lg:text-5xl font-bold tracking-tighter leading-tight text-center lg:text-left mb-10 lg:mb-0 lg:pr-4 lg:w-1/2">
Statically Generated with Next.js.
</h3>
<div className="flex flex-col lg:flex-row justify-center items-center lg:pl-4 lg:w-1/2">
<a
href="https://nextjs.org/docs/basic-features/pages"
className="mx-3 bg-black hover:bg-white hover:text-black border border-black text-white font-bold py-3 px-12 lg:px-8 duration-200 transition-colors mb-6 lg:mb-0"
>
Read Documentation
</a>
<a
href={`https://github.com/zeit/next.js/tree/canary/examples/${EXAMPLE_PATH}`}
className="mx-3 font-bold hover:underline"
>
View on GitHub
</a>
</div>
</div>
</Container>
</footer>
)
}
12 changes: 12 additions & 0 deletions examples/cms-ghost/components/header.js
@@ -0,0 +1,12 @@
import Link from 'next/link'

export default function Header() {
return (
<h2 className="text-2xl md:text-4xl font-bold tracking-tight md:tracking-tighter leading-tight mb-20 mt-8">
<Link href="/">
<a className="hover:underline">Blog</a>
</Link>
.
</h2>
)
}
43 changes: 43 additions & 0 deletions examples/cms-ghost/components/hero-post.js
@@ -0,0 +1,43 @@
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 (
<section>
<div className="mb-8 md:mb-16">
<CoverImage
title={title}
url={coverImage}
slug={slug}
width={2000}
height={1216}
/>
</div>
<div className="md:grid md:grid-cols-2 md:col-gap-16 lg:col-gap-8 mb-20 md:mb-28">
<div>
<h3 className="mb-4 text-4xl lg:text-6xl leading-tight">
<Link as={`/posts/${slug}`} href="/posts/[slug]">
<a className="hover:underline">{title}</a>
</Link>
</h3>
<div className="mb-4 md:mb-0 text-lg">
<Date dateString={date} />
</div>
</div>
<div>
<p className="text-lg leading-relaxed mb-4">{excerpt}</p>
<Avatar name={author.name} picture={author.profile_image} />
</div>
</div>
</section>
)
}
28 changes: 28 additions & 0 deletions examples/cms-ghost/components/intro.js
@@ -0,0 +1,28 @@
import { CMS_NAME, CMS_URL } from '@/lib/constants'

export default function Intro() {
return (
<section className="flex-col md:flex-row flex items-center md:justify-between mt-16 mb-16 md:mb-12">
<h1 className="text-6xl md:text-8xl font-bold tracking-tighter leading-tight md:pr-8">
Blog.
</h1>
<h4 className="text-center md:text-left text-lg mt-5 md:pl-8">
A statically generated blog example using{' '}
<a
href="https://nextjs.org/"
className="underline hover:text-success duration-200 transition-colors"
>
Next.js
</a>{' '}
and{' '}
<a
href={CMS_URL}
className="underline hover:text-success duration-200 transition-colors"
>
{CMS_NAME}
</a>
.
</h4>
</section>
)
}
18 changes: 18 additions & 0 deletions 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 (
<>
<Meta />
<div className="min-h-screen">
<Alert preview={preview} />
<main>{children}</main>
</div>
<Footer />
</>
)
}

0 comments on commit e69a4d7

Please sign in to comment.