Skip to content

Commit

Permalink
chore(examples): Add 'Sitefinity CMS' Example (#39537)
Browse files Browse the repository at this point in the history
This is an example of how to integrate [Sitefinity CMS
](https://www.progress.com/sitefinity-cms)with next.js

Co-authored-by: Balázs Orbán <info@balazsorban.com>
  • Loading branch information
Gebov and balazsorban44 committed Oct 1, 2022
1 parent 15cc889 commit ccbc9b8
Show file tree
Hide file tree
Showing 44 changed files with 1,065 additions and 0 deletions.
2 changes: 2 additions & 0 deletions examples/cms-sitefinity/.env.local.example
@@ -0,0 +1,2 @@
SF_API_URL=
SF_URL=
36 changes: 36 additions & 0 deletions examples/cms-sitefinity/.gitignore
@@ -0,0 +1,36 @@
# 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*
.pnpm-debug.log*

# local env files
.env*.local

# vercel
.vercel

# typescript
*.tsbuildinfo
next-env.d.ts
103 changes: 103 additions & 0 deletions examples/cms-sitefinity/README.md
@@ -0,0 +1,103 @@
# A statically generated blog example using Next.js and Sitefinity CMS

This is the existing [cms-sitefinity](https://github.com/vercel/next.js/tree/canary/examples/cms-sitefinity) plus TypeScript.
This example showcases [Next.js's Static Generation feature](https://nextjs.org/docs/basic-features/pages) using Sitefinity CMS as the data source.

## Demo

[https://next-cms-sitefinity.vercel.app/](https://next-cms-sitefinity.vercel.app/)

## Deploy your own

Deploy the example using [Vercel](https://vercel.com?utm_source=github&utm_medium=readme&utm_campaign=next-example) or preview live with [StackBlitz](https://stackblitz.com/github/vercel/next.js/tree/canary/examples/cms-sitefinity)

[![Deploy with Vercel](https://vercel.com/button)](https://vercel.com/new/git/external?repository-url=https://github.com/vercel/next.js/tree/canary/examples/cms-sitefinity&project-name=cms-sitefinity&repository-name=cms-sitefinity)

### 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)
- [Cosmic](/examples/cms-cosmic)
- [ButterCMS](/examples/cms-buttercms)
- [Storyblok](/examples/cms-storyblok)
- [GraphCMS](/examples/cms-graphcms)
- [Kontent](/examples/cms-kontent)
- [Umbraco Heartcore](/examples/cms-umbraco-heartcore)
- [Builder.io](/examples/cms-builder-io)
- [TinaCMS](/examples/cms-tina/)

## 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), [Yarn](https://yarnpkg.com/lang/en/docs/cli/create/), or [pnpm](https://pnpm.io) to bootstrap the example:

```bash
npx create-next-app --example cms-sitefinity cms-sitefinity-app
```

```bash
yarn create next-app --example cms-sitefinity cms-sitefinity-app
```

```bash
pnpm create next-app --example cms-sitefinity cms-sitefinity-app
```

## Configuration

### Step 1. Setup the CMS locally (version >=14.27922)

First, [install](https://www.progress.com/documentation/sitefinity-cms/install-sitefinity) and run the CMS Locally.

### Step 2. Import the ready to use dynamic module 'Posts'

For the purpose of this demo a ready to use dynamic module was build containing two types - 'Post' and 'Author'.

In order to install it:

1. Open the CMS Administration under (/Sitefinity)
2. Open the Export/Import screen under (/Sitefinity/Administration/Packaging)
3. Click on Import Zip file and import the file from the [sitefinity folder](./sitefinity/SitefinityExport.zip)

### Step 3. Enable the web service

By default the web services are not allowed for anonymous users, so the yhave to be enabled.

Go to /sitefinity/Administration/WebServices and edit the 'Default' web service to allow it to be accessible by 'Everyone'

### Step 4. Install the GraphQL package

1. Add the [Sitefinity CMS nugget source](https://www.progress.com/documentation/sitefinity-cms/sitefinity-cms-nuget-packages-repository)
2. Install the [Progress.Sitefinity.GraphQL](https://nuget.sitefinity.com/#/package/Progress.Sitefinity.GraphQL) package (enable prerelease filter).

### Step 5. Set up environment variables

Copy the `.env.local.example` file in this directory to `.env.local` (which will be ignored by Git):

```bash
cp .env.local.example .env.local
```

Then set each variable on `.env.local`

- `SF_API_URL` - This is the url of the 'Default' web service that we configured earlier. E.g. http://locahost/api/default/
- `SF_URL` - This is the URL of the CMS itself. E.g. http://localhost/

### Step 6. Run Next.js in development mode

```bash
npm install
npm run dev

# or

yarn
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).
48 changes: 48 additions & 0 deletions examples/cms-sitefinity/components/alert.tsx
@@ -0,0 +1,48 @@
import Container from './container'
import cn from 'classnames'
import { EXAMPLE_PATH } from '../lib/constants'

type Props = {
preview?: boolean
}

const Alert = ({ preview }: Props) => {
return (
<div
className={cn('border-b', {
'bg-neutral-800 border-neutral-800 text-white': preview,
'bg-neutral-50 border-neutral-200': !preview,
})}
>
<Container>
<div className="py-2 text-center text-sm">
{preview ? (
<>
This page is a preview.{' '}
<a
href="/api/exit-preview"
className="underline hover:text-teal-300 duration-200 transition-colors"
>
Click here
</a>{' '}
to exit preview mode.
</>
) : (
<>
The source code for this blog is{' '}
<a
href={`https://github.com/vercel/next.js/tree/canary/examples/${EXAMPLE_PATH}`}
className="underline hover:text-blue-600 duration-200 transition-colors"
>
available on GitHub
</a>
.
</>
)}
</div>
</Container>
</div>
)
}

export default Alert
15 changes: 15 additions & 0 deletions examples/cms-sitefinity/components/avatar.tsx
@@ -0,0 +1,15 @@
type Props = {
name: string
picture: string
}

const Avatar = ({ name, picture }: Props) => {
return (
<div className="flex items-center">
<img src={picture} className="w-12 h-12 rounded-full mr-4" alt={name} />
<div className="text-xl font-bold">{name}</div>
</div>
)
}

export default Avatar
9 changes: 9 additions & 0 deletions examples/cms-sitefinity/components/container.tsx
@@ -0,0 +1,9 @@
type Props = {
children?: React.ReactNode
}

const Container = ({ children }: Props) => {
return <div className="container mx-auto px-5">{children}</div>
}

export default Container
33 changes: 33 additions & 0 deletions examples/cms-sitefinity/components/cover-image.tsx
@@ -0,0 +1,33 @@
import cn from 'classnames'
import Link from 'next/link'

type Props = {
title: string
src: string
slug?: string
}

const CoverImage = ({ title, src, slug }: Props) => {
const image = (
<img
src={src}
alt={`Cover Image for ${title}`}
className={cn('shadow-sm', {
'hover:shadow-lg transition-shadow duration-200': slug,
})}
/>
)
return (
<div className="sm:mx-0">
{slug ? (
<Link as={`/posts${slug}`} href="/posts[slug]">
<a aria-label={title}>{image}</a>
</Link>
) : (
image
)}
</div>
)
}

export default CoverImage
12 changes: 12 additions & 0 deletions examples/cms-sitefinity/components/date-formatter.tsx
@@ -0,0 +1,12 @@
import { parseISO, format } from 'date-fns'

type Props = {
dateString: string
}

const DateFormatter = ({ dateString }: Props) => {
const date = parseISO(dateString)
return <time dateTime={dateString}>{format(date, 'LLLL d, yyyy')}</time>
}

export default DateFormatter
32 changes: 32 additions & 0 deletions examples/cms-sitefinity/components/footer.tsx
@@ -0,0 +1,32 @@
import Container from './container'
import { EXAMPLE_PATH } from '../lib/constants'

const Footer = () => {
return (
<footer className="bg-neutral-50 border-t border-neutral-200">
<Container>
<div className="py-28 flex flex-col lg:flex-row items-center">
<h3 className="text-4xl lg:text-[2.5rem] 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/vercel/next.js/tree/canary/examples/${EXAMPLE_PATH}`}
className="mx-3 font-bold hover:underline"
>
View on GitHub
</a>
</div>
</div>
</Container>
</footer>
)
}

export default Footer
14 changes: 14 additions & 0 deletions examples/cms-sitefinity/components/header.tsx
@@ -0,0 +1,14 @@
import Link from 'next/link'

const 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>
)
}

export default Header
49 changes: 49 additions & 0 deletions examples/cms-sitefinity/components/hero-post.tsx
@@ -0,0 +1,49 @@
import Avatar from './avatar'
import DateFormatter from './date-formatter'
import CoverImage from './cover-image'
import Link from 'next/link'
import type Author from '../interfaces/author'

type Props = {
title: string
coverImage: string
date: string
excerpt: string
author: Author
slug: string
}

const HeroPost = ({
title,
coverImage,
date,
excerpt,
author,
slug,
}: Props) => {
return (
<section>
<div className="mb-8 md:mb-16">
<CoverImage title={title} src={coverImage} slug={slug} />
</div>
<div className="md:grid md:grid-cols-2 md:gap-x-16 lg:gap-x-8 mb-20 md:mb-28">
<div>
<h3 className="mb-4 text-4xl lg:text-5xl 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">
<DateFormatter dateString={date} />
</div>
</div>
<div>
<p className="text-lg leading-relaxed mb-4">{excerpt}</p>
<Avatar name={author.name} picture={author.picture} />
</div>
</div>
</section>
)
}

export default HeroPost
23 changes: 23 additions & 0 deletions examples/cms-sitefinity/components/intro.tsx
@@ -0,0 +1,23 @@
import { CMS_NAME } from '../lib/constants'

const 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-5xl 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-blue-600 duration-200 transition-colors"
>
Next.js
</a>{' '}
and {CMS_NAME}.
</h4>
</section>
)
}

export default Intro

0 comments on commit ccbc9b8

Please sign in to comment.