├── .eslintrc.json ├── .env.local.example ├── .gitignore ├── preview.png ├── app ├── globals.css ├── api │ ├── exit-draft │ │ └── route.js │ ├── draft │ │ └── route.js │ ├── preview-links │ │ └── route.js │ ├── post-install │ │ └── route.js │ └── seo-readability-metadata │ │ └── route.js ├── layout.js ├── page.js └── posts │ └── [slug] │ └── page.js ├── next.config.js ├── postcss.config.js ├── netlify.toml ├── components ├── section-separator.js ├── container.js ├── date.js ├── post-title.js ├── header.js ├── draft-post-page.js ├── draft-post-index.js ├── avatar.js ├── cover-image.js ├── post-index.js ├── post-page.js ├── more-stories.js ├── post-body.js ├── intro.js ├── post-preview.js ├── post-header.js ├── hero-post.js ├── footer.js └── alert.js ├── jsconfig.json ├── lib ├── fragments.js └── datocms.js ├── datocms.json ├── package.json ├── tailwind.config.js └── README.md /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "next/core-web-vitals" 3 | } 4 | -------------------------------------------------------------------------------- /.env.local.example: -------------------------------------------------------------------------------- 1 | NEXT_DATOCMS_API_TOKEN= 2 | NEXT_DATOCMS_PREVIEW_SECRET= -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .env 2 | .env.local 3 | .now 4 | .next 5 | node_modules/ 6 | out/ -------------------------------------------------------------------------------- /preview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datocms/nextjs-demo/HEAD/preview.png -------------------------------------------------------------------------------- /app/globals.css: -------------------------------------------------------------------------------- 1 | @tailwind base; 2 | @tailwind components; 3 | @tailwind utilities; 4 | -------------------------------------------------------------------------------- /next.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('next').NextConfig} */ 2 | const nextConfig = {} 3 | 4 | module.exports = nextConfig 5 | -------------------------------------------------------------------------------- /postcss.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: { 3 | tailwindcss: {}, 4 | autoprefixer: {}, 5 | }, 6 | } 7 | -------------------------------------------------------------------------------- /netlify.toml: -------------------------------------------------------------------------------- 1 | [build] 2 | publish = ".next" 3 | command = "npm run build" 4 | 5 | [[plugins]] 6 | package = "@netlify/plugin-nextjs" -------------------------------------------------------------------------------- /components/section-separator.js: -------------------------------------------------------------------------------- 1 | export default function SectionSeparator() { 2 | return
; 3 | } 4 | -------------------------------------------------------------------------------- /components/container.js: -------------------------------------------------------------------------------- 1 | export default function Container({ children }) { 2 | return
{children}
; 3 | } 4 | -------------------------------------------------------------------------------- /jsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "baseUrl": ".", 4 | "paths": { 5 | "@/components/*": [ 6 | "components/*" 7 | ], 8 | "@/lib/*": [ 9 | "lib/*" 10 | ] 11 | } 12 | } 13 | } -------------------------------------------------------------------------------- /components/date.js: -------------------------------------------------------------------------------- 1 | import { parseISO, format } from "date-fns"; 2 | 3 | export default function Date({ dateString }) { 4 | const date = parseISO(dateString); 5 | return ; 6 | } 7 | -------------------------------------------------------------------------------- /app/api/exit-draft/route.js: -------------------------------------------------------------------------------- 1 | import { draftMode } from 'next/headers' 2 | import { redirect } from 'next/navigation' 3 | 4 | export async function GET() { 5 | // Exit the current user from "Draft Mode". This function accepts no args. 6 | draftMode().disable() 7 | redirect('/') 8 | } 9 | -------------------------------------------------------------------------------- /components/post-title.js: -------------------------------------------------------------------------------- 1 | export default function PostTitle({ children }) { 2 | return ( 3 |

4 | {children} 5 |

6 | ); 7 | } 8 | -------------------------------------------------------------------------------- /components/header.js: -------------------------------------------------------------------------------- 1 | import Link from "next/link"; 2 | 3 | export default function Header() { 4 | return ( 5 |

6 | Blog. 7 |

8 | ); 9 | } 10 | -------------------------------------------------------------------------------- /components/draft-post-page.js: -------------------------------------------------------------------------------- 1 | "use client"; 2 | 3 | import { useQuerySubscription } from "react-datocms/use-query-subscription"; 4 | import { PostPage } from "./post-page"; 5 | 6 | export function DraftPostPage({ subscription }) { 7 | const { data } = useQuerySubscription(subscription); 8 | 9 | return ; 10 | } 11 | -------------------------------------------------------------------------------- /components/draft-post-index.js: -------------------------------------------------------------------------------- 1 | "use client"; 2 | 3 | import { useQuerySubscription } from "react-datocms/use-query-subscription"; 4 | import { PostIndex } from "./post-index"; 5 | 6 | export function DraftPostIndex({ subscription }) { 7 | const { data } = useQuerySubscription(subscription); 8 | 9 | return ; 10 | } 11 | -------------------------------------------------------------------------------- /components/avatar.js: -------------------------------------------------------------------------------- 1 | import { Image } from "react-datocms"; 2 | 3 | export default function Avatar({ name, picture }) { 4 | return ( 5 |
6 |
7 | {name} 12 |
13 |
{name}
14 |
15 | ); 16 | } 17 | -------------------------------------------------------------------------------- /lib/fragments.js: -------------------------------------------------------------------------------- 1 | // See: https://www.datocms.com/blog/offer-responsive-progressive-lqip-images-in-2020 2 | export const responsiveImageFragment = ` 3 | fragment responsiveImageFragment on ResponsiveImage { 4 | srcSet 5 | webpSrcSet 6 | sizes 7 | src 8 | width 9 | height 10 | aspectRatio 11 | alt 12 | title 13 | base64 14 | } 15 | `; 16 | 17 | export const metaTagsFragment = ` 18 | fragment metaTagsFragment on Tag { 19 | attributes 20 | content 21 | tag 22 | } 23 | `; 24 | -------------------------------------------------------------------------------- /datocms.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Next.js Blog", 3 | "description": "Simple blog website built with Next.js and DatoCMS, with real-time updates in preview mode", 4 | "previewImage": "https://www.datocms-assets.com/205/1605198221-screenshot2020-11-12-next-js-blog-example-with-datocms-1.jpg?crop=top&fit=crop&h=500&w=600&auto=format", 5 | "datocmsProjectId": "23796", 6 | "deploymentType": "static", 7 | "buildCommand": "npm run build", 8 | "datocmsApiTokenEnvName": "NEXT_DATOCMS_API_TOKEN", 9 | "livePreviewUrl": "https://nextjs-demo-bay.vercel.app/", 10 | "postInstallUrl": "/api/post-install" 11 | } 12 | -------------------------------------------------------------------------------- /app/layout.js: -------------------------------------------------------------------------------- 1 | import "./globals.css"; 2 | 3 | import Alert from "@/components/alert"; 4 | import Footer from "@/components/footer"; 5 | 6 | import { draftMode } from "next/headers"; 7 | import Container from "@/components/container"; 8 | 9 | export default function RootLayout({ children }) { 10 | const { isEnabled } = draftMode(); 11 | 12 | return ( 13 | 14 | 15 |
16 | 17 |
18 | {children} 19 |
20 |
21 |