[
  {
    "path": ".gitignore",
    "content": "dist\n.next\nnode_modules\nnpm-debug.log\n.DS_Store\n\n.env\n.vercel\n"
  },
  {
    "path": "README.md",
    "content": "# React CMS-powered application built with Next.js\n\n## Important Notice\nThis project was created as an example use case of ButterCMS with React and Next.JS, and will not be actively maintained. \n\nIf you’re interested in exploring the best, most up-to-date way to integrate Butter into javascript frameworks like React and Next.js, you can check out the following resources:\n\n### Starter Projects\n\nThe following turn-key starters are fully integrated with dynamic sample content from your ButterCMS account, including main menu, pages, blog posts, categories, and tags, all with a beautiful, custom theme with already-implemented search functionality. All of the included sample content is automatically created in your account dashboard when you sign up for a free trial of ButterCMS.\n- [Next.js Starter](https://buttercms.com/starters/nextjs-starter-project/)\n- [Angular Starter](https://buttercms.com/starters/angular-starter-project/)\n- [React Starter](https://buttercms.com/starters/react-starter-project/)\n- [Vue.js Starter](https://buttercms.com/starters/vuejs-starter-project/)\n- Or see a list of all our [currently-maintained starters](https://buttercms.com/starters/). (Over a dozen and counting!)\n\n### Other Resources\n- Check out the [official ButterCMS Docs](https://buttercms.com/docs/)\n- Check out the [official ButterCMS API docs](https://buttercms.com/docs/api/)\n\n## Project Description\n\n[![Deploy with Vercel](https://vercel.com/button)](https://vercel.com/new/git/external?repository-url=https%3A%2F%2Fgithub.com%2Fbuttercms%2Freact-cms-blog-with-next-js)\n\n- Demo: https://react-cms-blog-with-next-js.orlyohreally.vercel.app/\n\n[Next.js](https://github.com/vercel/next.js/) is a small framework for building universal React webapps. Next.js comes with Webpack and Babel built-in. You can read more about the philosophy behind Next.js [here](https://zeit.co/blog/next).\n\n[ButterCMS](https://buttercms.com) is a hosted API-based CMS and blog engine that lets you build CMS-powered apps using any programming language. You can think of Butter as similar to WordPress except that you build your website in your language of choice and then plug-in the dynamic content using an API.\n\nThis projects shows how to integrate ButterCMS into Next.js application:\n\n- How to create page with a list of blog posts and pages for each post. Learn more about blog integration [here](https://buttercms.com/docs/api/#get-your-blog-posts).\n- How to dynamically create pages using data from ButterCMS pages. Learn more about fetching single pages and pages with types [here](https://buttercms.com/docs/api/#pages).\n- How to display collections items on the page. Learn more on how to query collections [here](https://buttercms.com/docs/api/#retrieve-a-collection).\n- How to get all posts categories. Learn more about categories [here](https://buttercms.com/docs/api/#categories).\n- How to create pages with RSS, Atom, and Sitemap feeds. Learn more [here](https://buttercms.com/docs/api/#feeds).\n\nLink to ButterCMS API documentation is https://buttercms.com/docs/api/.\n\n## Set up ButterCMS account\n\n1. Create a free account on ButterCMS - https://buttercms.com/.\n2. To see the project locally you need to create this data in your account:\n   - Create and publish customer case study pages (page with type `customer_case_study`) with this structure:\n     ![customer case study page type configuration](https://buttercms.com/static/images/docs/guides/PagesNewPageType1Gridsome.png)\n     Learn more about page types [here](https://buttercms.com/docs/api-client/nextjs#PagesPageType).\n   - Create collection `faq_items` with this structure:\n     ![faq items collection configuration](images/faq_items.png)\n     Learn more about collections [here](https://buttercms.com/docs/api-client/nextjs#Collections).\n3. Find your read API token from the home page or from settings page, it will be needed later.\n\n## Requirements\n\n- Node >= 12.0.0\n\n## Running project locally\n\n1. Clone and cd into project:\n\n```\ngit clone https://github.com/ButterCMS/react-cms-blog-with-next-js.git\ncd react-cms-blog-with-next-js.git\n```\n\n2. Install all dependencies\n\n```\nnpm install\n```\n\nor\n\n```\nyarn install\n```\n\n1. Copy `.env.example` file as `.env` and replace `BUTTER_CMS_API_KEY` value with your read API token\n2. Run the app in development mode\n\n```\nnpm run dev\n```\n\nor\n\n```\nyarn dev\n```\n\nThe application should be available at `http://localhost:3000`.\n\nTo build the project run `npm run build` and to start run `npm start`\n\n## Deploy on Vercel\n\n1. Create a Vercel account at https://vercel.com/signup and download [the CLI](https://vercel.com/download)\n2. Run `vercel` at the project root\n\n## Webhooks to trigger deployment\n\nWe can make use of the ButterCMS webhooks to notify the application every time a post, page or collection item are added or modified, and reload the Next.js application.\n\nYou can add a new webhook by going to the [https://buttercms.com/webhooks/](https://buttercms.com/webhooks/) page.\n\n![webhook page](images/webhooks.png)\n\nIf you use Vercel, you can create deploy webhooks there. ![Vercel deploy webhooks](images/webhooks-vercel.png)\n\n## Wrap up\n\nNext.js is a powerful framework that makes it easy to build universal React apps. With ButterCMS you can quickly build CMS-powered applications and websites with React and Node.js.\n\nWe hope you enjoyed this tutorial. If you have any questions about setting up your ButterCMS-powered application feel free to contact ButterCMS support.\n\n## Other\n\nView ReactJS [Blog engine](https://buttercms.com/react-blog-engine/) and [Full CMS](https://buttercms.com/react-cms/) for other examples of using ButterCMS with ReactJS. And check out [Next.js Blog engine](https://buttercms.com/nextjs-blog-engine/) and [Next.js CMS](https://buttercms.com/nextjs-cms/) for other Next.js examples.\n"
  },
  {
    "path": "components/avatar.js",
    "content": "import Image from \"next/image\";\n\nexport default function Avatar({ name, picture }) {\n  return (\n    <div className=\"flex items-center\">\n      <div className=\" mr-4\">\n        <Image\n          src={picture}\n          height=\"48px\"\n          width=\"48px\"\n          className=\"w-12 h-12 rounded-full grayscale\"\n          alt={name}\n        />\n      </div>\n      <div className=\"text-xl font-bold\">{name}</div>\n    </div>\n  );\n}\n"
  },
  {
    "path": "components/container.js",
    "content": "export default function Container({ children }) {\n  return <div className=\"container mx-auto px-5\">{children}</div>;\n}\n"
  },
  {
    "path": "components/cover-image.js",
    "content": "import Link from \"next/link\";\nimport Image from \"next/image\";\n\nexport default function CoverImage({ title, url, slug }) {\n  return (\n    <div className=\"sm:mx-0\">\n      {slug ? (\n        <Link href={`/posts/${slug}`}>\n          <a aria-label={title}>\n            <div style={{ position: \"relative\", height: \"300px\" }}>\n              <Image\n                alt={title}\n                src={url}\n                layout=\"fill\"\n                objectFit=\"cover\"\n                quality={100}\n                className=\"rounded-lg\"\n              />\n            </div>\n          </a>\n        </Link>\n      ) : (\n        <div style={{ position: \"relative\", height: \"300px\" }}>\n          <Image\n            alt={title}\n            src={url}\n            layout=\"fill\"\n            objectFit=\"cover\"\n            quality={100}\n            className=\"rounded-lg\"\n          />\n        </div>\n      )}\n    </div>\n  );\n}\n"
  },
  {
    "path": "components/date.js",
    "content": "import { parseISO, format } from \"date-fns\";\n\nexport default function Date({ dateString }) {\n  const date = parseISO(dateString);\n  return <time dateTime={dateString}>{format(date, \"LLLL\td, yyyy\")}</time>;\n}\n"
  },
  {
    "path": "components/footer.js",
    "content": "import Container from \"./container\";\n\nexport default function Footer() {\n  return (\n    <footer className=\"bg-accent-1 border-t border-accent-2\">\n      <Container>\n        <div className=\"py-28 flex flex-col lg:flex-row items-center\">\n          <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\">\n            Statically Generated with Next.js and ButterCMS\n          </h3>\n          <div className=\"flex flex-col lg:flex-row justify-center items-center lg:pl-4 lg:w-1/2\">\n            <a\n              href=\"https://buttercms.com/docs/api/?javascript#\"\n              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\"\n            >\n              Read Documentation\n            </a>\n            <a\n              href={`https://github.com/ButterCMS/react-cms-blog-with-next-js/`}\n              className=\"mx-3 font-bold hover:underline\"\n            >\n              View on GitHub\n            </a>\n          </div>\n        </div>\n      </Container>\n    </footer>\n  );\n}\n"
  },
  {
    "path": "components/header.js",
    "content": "export default function Header({ title }) {\n  return (\n    <h2 className=\"text-2xl md:text-4xl font-bold tracking-tight md:tracking-tighter leading-tight px-4 mb-20 mt-8\">\n      {title}\n    </h2>\n  );\n}\n"
  },
  {
    "path": "components/layout.js",
    "content": "import Link from \"next/link\";\nimport Footer from \"./footer\";\n\nexport default function Layout({ children }) {\n  return (\n    <>\n      <div className=\"min-h-screen mb-20\">\n        <div className=\"relative pt-6 pb-6 px-4 sm:px-6 lg:px-8\">\n          <nav\n            className=\"relative flex items-center justify-between sm:h-10 lg:justify-start\"\n            aria-label=\"Global\"\n          >\n            <div className=\"ml-10 pr-4 space-x-8\">\n              <Link href=\"/\">\n                <a className=\"font-medium text-gray-500 hover:text-gray-900\">\n                  Home\n                </a>\n              </Link>\n              <Link href=\"/posts\">\n                <a className=\"font-medium text-gray-500 hover:text-gray-900\">\n                  Blog\n                </a>\n              </Link>\n              <Link href=\"/case-studies\">\n                <a className=\"font-medium text-gray-500 hover:text-gray-900\">\n                  Pages with types\n                </a>\n              </Link>\n              <Link href=\"/faq\">\n                <a className=\"font-medium text-gray-500 hover:text-gray-900\">\n                  Collections\n                </a>\n              </Link>\n            </div>\n          </nav>\n        </div>\n        <main>{children}</main>\n      </div>\n      <Footer />\n    </>\n  );\n}\n"
  },
  {
    "path": "components/post-body.js",
    "content": "export default function PostBody({ content }) {\n  return (\n    <div className=\"max-w-2xl mx-auto\">\n      <div className=\"prose\" dangerouslySetInnerHTML={{ __html: content }} />\n    </div>\n  );\n}\n"
  },
  {
    "path": "components/post-header.js",
    "content": "import Link from \"next/link\";\n\nimport Avatar from \"@/components/avatar\";\nimport Date from \"@/components/date\";\nimport CoverImage from \"@/components/cover-image\";\nimport PostTitle from \"@/components/post-title\";\n\nexport default function PostHeader({\n  title,\n  coverImage,\n  date,\n  author,\n  categories,\n}) {\n  return (\n    <>\n      <PostTitle>{title}</PostTitle>\n      <div className=\"hidden md:block md:mb-12\">\n        <Avatar\n          name={`${author.first_name} ${author.last_name}`}\n          picture={author.profile_image}\n        />\n      </div>\n      <div className=\"mb-8 md:mb-16 sm:mx-0\">\n        <CoverImage title={title} url={coverImage} />\n      </div>\n      <div className=\"max-w-2xl mx-auto\">\n        <div className=\"block md:hidden mb-6\">\n          <Avatar\n            name={`${author.first_name} ${author.last_name}`}\n            picture={author.profile_image}\n          />\n        </div>\n        <div className=\"mb-6 text-lg\">\n          {categories.map(({ name, slug }) => {\n            return (\n              <Link href={`/posts/category/${slug}`} key={slug}>\n                <a className=\"mr-2 hover:underline leading-snug\">{name}</a>\n              </Link>\n            );\n          })}\n        </div>\n        <div className=\"mb-6 text-lg\">\n          <Date dateString={date} />\n        </div>\n      </div>\n    </>\n  );\n}\n"
  },
  {
    "path": "components/post-preview.js",
    "content": "import Avatar from \"./avatar\";\nimport Date from \"./date\";\nimport CoverImage from \"./cover-image\";\nimport Link from \"next/link\";\n\nexport default function PostPreview({\n  title,\n  coverImage,\n  date,\n  excerpt,\n  author,\n  slug,\n}) {\n  return (\n    <div>\n      <div className=\"mb-5\">\n        {coverImage && (\n          <CoverImage slug={slug} title={title} url={coverImage} />\n        )}\n      </div>\n      <h3 className=\"text-3xl mb-3 leading-snug\">\n        <Link href={`/posts/${slug}`}>\n          <a className=\"hover:underline\">{title}</a>\n        </Link>\n      </h3>\n      <div className=\"text-lg mb-4\">\n        <Date dateString={date} />\n      </div>\n      <p className=\"text-lg leading-relaxed mb-4\">{excerpt}</p>\n      <Avatar\n        name={`${author.first_name} ${author.last_name}`}\n        picture={author.profile_image}\n      />\n    </div>\n  );\n}\n"
  },
  {
    "path": "components/post-title.js",
    "content": "export default function PostTitle({ children }) {\n  return (\n    <h1 className=\"text-6xl md:text-7xl lg:text-8xl font-bold tracking-tighter leading-tight md:leading-none mb-12 text-center md:text-left\">\n      {children}\n    </h1>\n  )\n}\n"
  },
  {
    "path": "jsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"baseUrl\": \".\",\n    \"paths\": {\n      \"@/components/*\": [\"components/*\"],\n      \"@/lib/*\": [\"lib/*\"],\n      \"@/styles/*\": [\"styles/*\"]\n    }\n  }\n}\n"
  },
  {
    "path": "lib/api.js",
    "content": "import Butter from \"buttercms\";\nconst butter = Butter(process.env.BUTTER_CMS_API_KEY);\n\nconst postsPageSize = 10;\n\nexport async function getPreviewPostBySlug(slug) {\n  const postResponse = await butter.post.retrieve(slug, {\n    preview: 1,\n  });\n  return postResponse?.data?.data;\n}\n\nexport async function getPostsData(page = 1, pageSize = postsPageSize) {\n  // https://buttercms.com/docs/api/node?javascript#get-your-blog-posts\n  const response = await butter.post.list({\n    page_size: pageSize,\n    page: page,\n  });\n\n  return {\n    posts: response?.data?.data,\n    prevPage: response?.data?.meta.previous_page,\n    nextPage: response?.data?.meta.next_page,\n  };\n}\n\nexport async function getAllPostsPaginated(pageSize = postsPageSize) {\n  const paginatedPosts = [];\n  let currentPage = 1;\n  while (!!currentPage) {\n    const pagePostsData = await getPostsData(currentPage, pageSize);\n    paginatedPosts[currentPage - 1] = pagePostsData.posts;\n    currentPage = pagePostsData.nextPage;\n  }\n  return paginatedPosts;\n}\n\nexport async function getCategories() {\n  const categories = await butter.category.list();\n  return categories?.data?.data;\n}\n\nexport async function getCategoryWithPosts(slug) {\n  const response = await butter.category.retrieve(slug, {\n    include: \"recent_posts\",\n  });\n  return response?.data?.data;\n}\n\nexport async function getAtomData() {\n  const atom = await butter.feed.retrieve(\"atom\");\n  return atom?.data?.data;\n}\n\nexport async function getRssData() {\n  const rss = await butter.feed.retrieve(\"rss\");\n  return rss?.data?.data;\n}\n\nexport async function getSitemapData() {\n  const sitemap = await butter.feed.retrieve(\"sitemap\");\n  return sitemap?.data?.data;\n}\n\nexport async function getPagesByType(type) {\n  const pages = await butter.page.list(type);\n  return pages?.data?.data;\n}\n\nexport async function getPageWithType(type, slug) {\n  const page = await butter.page.retrieve(type, slug);\n  return page?.data?.data;\n}\n\nexport async function getPost(slug) {\n  const post = await butter.post.retrieve(slug);\n  return post?.data?.data;\n}\n\nexport async function getCollectionsItems(collectionsSlugs) {\n  const collectionsItems = await butter.content.retrieve(collectionsSlugs);\n  return collectionsItems?.data?.data;\n}\n\nexport async function getPostAndMorePosts(slug, preview) {\n  const postResponse = await butter.post.retrieve(slug, {\n    preview: preview ? 1 : 0,\n  });\n  const postListResponse = await butter.post.list();\n  return {\n    post: postResponse?.data?.data,\n    morePosts: postListResponse?.data?.data.filter(\n      ({ slug: postSlug }) => postSlug !== slug\n    ),\n  };\n}\n"
  },
  {
    "path": "next.config.js",
    "content": "module.exports = {\n  async rewrites() {\n    return [\n      {\n        source: \"/posts\",\n        destination: \"/posts/page/1\",\n      },\n    ];\n  },\n  async redirects() {\n    return [\n      {\n        source: \"/posts/page\",\n        destination: \"/posts\",\n        permanent: true,\n      },\n    ];\n  },\n  images: {\n    domains: [\"cdn.buttercms.com\"],\n  },\n};\n"
  },
  {
    "path": "package.json",
    "content": "{\n  \"name\": \"react-blog\",\n  \"scripts\": {\n    \"start\": \"next start\",\n    \"dev\": \"next\",\n    \"build\": \"next build\"\n  },\n  \"engines\": {\n    \"node\": \">=12.0.0\"\n  },\n  \"dependencies\": {\n    \"@tailwindcss/typography\": \"^0.3.1\",\n    \"autoprefixer\": \"^10.0.4\",\n    \"buttercms\": \"^1.2.3\",\n    \"date-fns\": \"^2.16.1\",\n    \"next\": \"latest\",\n    \"postcss\": \"^8.2.13\",\n    \"react\": \"^17.0.1\",\n    \"react-dom\": \"^17.0.1\",\n    \"tailwindcss\": \"^2.0.1\"\n  },\n  \"devDependencies\": {\n    \"postcss-flexbugs-fixes\": \"4.2.1\",\n    \"postcss-preset-env\": \"^6.7.0\"\n  }\n}"
  },
  {
    "path": "pages/_app.js",
    "content": "import '@/styles/index.css'\n\nfunction MyApp({ Component, pageProps }) {\n  return <Component {...pageProps} />\n}\n\nexport default MyApp\n"
  },
  {
    "path": "pages/_document.js",
    "content": "import Document, { Html, Head, Main, NextScript } from 'next/document'\n\nexport default class MyDocument extends Document {\n  render() {\n    return (\n      <Html lang=\"en\">\n        <Head />\n        <body>\n          <Main />\n          <NextScript />\n        </body>\n      </Html>\n    )\n  }\n}\n"
  },
  {
    "path": "pages/atom.js",
    "content": "import { getAtomData } from \"@/lib/api\";\n\nexport default function Atom({ atom }) {\n  return atom;\n}\n\nexport async function getStaticProps() {\n  const atom = await getAtomData();\n  return { props: { atom } };\n}\n"
  },
  {
    "path": "pages/case-studies/[slug].js",
    "content": "import React from \"react\";\nimport Head from \"next/head\";\nimport { useRouter } from \"next/router\";\nimport ErrorPage from \"next/error\";\nimport Image from \"next/image\";\n\nimport Layout from \"@/components/layout\";\nimport Date from \"@/components/date\";\nimport Header from \"@/components/header\";\nimport Container from \"@/components/container\";\nimport { getPagesByType, getPageWithType } from \"@/lib/api\";\n\nexport default function caseStudy({\n  slug,\n  name,\n  customerLogo,\n  headline,\n  customerIndustry,\n  customerSubindustry,\n  studyBody,\n  studyDate,\n  customerReviewedCaseStudy,\n}) {\n  const router = useRouter();\n  if (!router.isFallback && !slug) {\n    return <ErrorPage statusCode={404} />;\n  }\n\n  return (\n    <Layout>\n      <Container>\n        {router.isFallback ? (\n          <div>Loading…</div>\n        ) : (\n          <article>\n            <Head>\n              <title>{name}</title>\n            </Head>\n            <Header title={headline}></Header>\n            <div className=\"grid grid-flow-col auto-cols-max gap-4 mb-5\">\n              <div\n                style={{\n                  position: \"relative\",\n                  width: \"300px\",\n                  height: \"300px\",\n                }}\n              >\n                <Image\n                  alt={name}\n                  src={customerLogo}\n                  layout=\"fill\"\n                  objectFit=\"cover\"\n                  quality={100}\n                  className=\"rounded-lg\"\n                />\n              </div>\n              <div>\n                <div>\n                  Study date: <Date dateString={studyDate}></Date>\n                </div>\n                <div>Industry: {customerIndustry}</div>\n                <div>Subindustry: {customerSubindustry}</div>\n                {customerReviewedCaseStudy && <div>Reviewed by customer </div>}\n              </div>\n            </div>\n            <div\n              className=\"mb-10\"\n              dangerouslySetInnerHTML={{ __html: studyBody }}\n            />\n          </article>\n        )}\n      </Container>\n    </Layout>\n  );\n}\n\nexport async function getStaticProps({ params }) {\n  const page = await getPageWithType(\"customer_case_study\", params.slug);\n\n  return {\n    props: {\n      slug: page.slug,\n      name: page.name,\n      headline: page.fields.headline,\n      customerLogo: page.fields.customer_logo,\n      customerIndustry: page.fields.customer_industry,\n      customerSubindustry: page.fields.customer_subindustry,\n      studyBody: page.fields.study_body,\n      studyDate: page.fields.study_date,\n      customerReviewedCaseStudy: page.fields.customer_reviewed_case_study,\n    },\n  };\n}\n\nexport async function getStaticPaths() {\n  const caseStudiesPages = await getPagesByType(\"customer_case_study\");\n\n  return {\n    paths: caseStudiesPages?.map((page) => `/case-studies/${page.slug}`) || [],\n    fallback: true,\n  };\n}\n"
  },
  {
    "path": "pages/case-studies.js",
    "content": "import Link from \"next/link\";\nimport Head from \"next/head\";\nimport Image from \"next/image\";\n\nimport Header from \"@/components/header\";\nimport Layout from \"@/components/layout\";\nimport Date from \"@/components/date\";\nimport Container from \"@/components/container\";\nimport { getPagesByType } from \"@/lib/api\";\n\nexport default function caseStudies({ pages }) {\n  return (\n    <Layout>\n      <Container>\n        <Head>\n          <title>Case studies</title>\n        </Head>\n        <Header title=\"Case studies\"></Header>\n\n        {pages.map(({ slug, fields }, key) => {\n          return (\n            <div\n              key={key}\n              className=\"grid grid-flow-col auto-rows-max gap-4 mb-5\"\n            >\n              <div\n                style={{\n                  position: \"relative\",\n                  width: \"300px\",\n                  height: \"300px\",\n                }}\n              >\n                <Link href={`/case-studies/${slug}`}>\n                  <a>\n                    <Image\n                      alt={fields.headline}\n                      src={fields.customer_logo}\n                      layout=\"fill\"\n                      objectFit=\"cover\"\n                      quality={100}\n                      className=\"rounded-lg\"\n                    />\n                  </a>\n                </Link>\n              </div>\n              <div>\n                <h3 className=\"text-3xl mb-3 mt-3 leading-snug\">\n                  <Link href={`/case-studies/${slug}`}>\n                    <a className=\"hover:underline\">{fields.headline}</a>\n                  </Link>\n                </h3>\n                Study date: <Date dateString={fields.study_date}></Date>\n                {fields.customer_reviewed_case_study && (\n                  <div>Reviewed by customer </div>\n                )}\n              </div>\n            </div>\n          );\n        })}\n      </Container>\n    </Layout>\n  );\n}\n\nexport async function getStaticProps() {\n  const pages = await getPagesByType(\"customer_case_study\");\n\n  return { props: { pages } };\n}\n"
  },
  {
    "path": "pages/faq.js",
    "content": "import Head from \"next/head\";\n\nimport Layout from \"@/components/layout\";\nimport Container from \"@/components/container\";\nimport Header from \"@/components/header\";\nimport { getCollectionsItems } from \"@/lib/api\";\n\nexport default function FAQ({ faqItems }) {\n  return (\n    <Layout>\n      <Container>\n        <Head>\n          <title>FAQ</title>\n        </Head>\n        <>\n          <Header title=\"FAQ\"></Header>\n          <ul>\n            {faqItems.map(({ question, answer }, index) => {\n              return (\n                <li key={index} className=\"mb-5\">\n                  <div className=\"text-lg leading-6 font-medium text-gray-900\">\n                    {question}\n                  </div>\n                  <div className=\"mt-4 text-base text-gray-500\">{answer}</div>\n                </li>\n              );\n            })}\n          </ul>\n        </>\n      </Container>\n    </Layout>\n  );\n}\n\nexport async function getStaticProps() {\n  const { faq_items: faqItems } = await getCollectionsItems([\"faq_items\"]);\n  return { props: { faqItems } };\n}\n"
  },
  {
    "path": "pages/index.js",
    "content": "import Head from \"next/head\";\nimport Link from \"next/link\";\n\nimport Container from \"@/components/container\";\nimport Header from \"@/components/header\";\nimport Layout from \"@/components/layout\";\n\nexport default function Posts() {\n  return (\n    <Layout>\n      <Container>\n        <Head>\n          <title></title>\n        </Head>\n        <Header title=\"ButterCMS. Headless CMS you'll melt over\"></Header>\n        <div className=\"bg-gray-50 mb-5 rounded-lg\">\n          <div className=\"max-w-7xl mx-auto py-12 px-4 sm:px-6\">\n            <h2 className=\"text-3xl font-extrabold tracking-tight text-gray-900 sm:text-4xl lg:mr-5\">\n              <span className=\"block\">Blog Engine</span>\n              <span className=\"block text-indigo-600\">\n                You've got better things to do than building another blog.\n              </span>\n            </h2>\n            <div className=\"mt-8\">\n              <div className=\"inline-flex rounded-md shadow\">\n                <Link href=\"/posts\">\n                  <a className=\"inline-flex items-center justify-center px-5 py-3 border border-transparent text-base font-medium rounded-md text-white bg-indigo-600 hover:bg-indigo-700\">\n                    Preview integration\n                  </a>\n                </Link>\n              </div>\n              <div className=\"ml-3 inline-flex rounded-md shadow\">\n                <a\n                  href=\"https://buttercms.com/features/#flexiblecontentmodeling-blog-engine\"\n                  className=\"inline-flex items-center justify-center px-5 py-3 border border-transparent text-base font-medium rounded-md text-indigo-600 bg-white hover:bg-indigo-50\"\n                >\n                  Learn more\n                </a>\n              </div>\n            </div>\n          </div>\n        </div>\n\n        <div className=\"bg-gray-50 mb-5 rounded-lg\">\n          <div className=\"max-w-7xl mx-auto py-12 px-4 sm:px-6\">\n            <h2 className=\"text-3xl font-extrabold tracking-tight text-gray-900 sm:text-4xl lg:mr-5\">\n              <span className=\"block\">Pages</span>\n              <span className=\"block text-indigo-600\">\n                Build SEO landing pages, knowledge base, news articles, and more\n                by using Page Types.\n              </span>\n            </h2>\n            <div className=\"mt-8\">\n              <div className=\"inline-flex rounded-md shadow\">\n                <Link href=\"/case-studies\">\n                  <a className=\"inline-flex items-center justify-center px-5 py-3 border border-transparent text-base font-medium rounded-md text-white bg-indigo-600 hover:bg-indigo-700\">\n                    Preview integration\n                  </a>\n                </Link>\n              </div>\n              <div className=\"ml-3 inline-flex rounded-md shadow\">\n                <a\n                  href=\"https://buttercms.com/features/#flexiblecontentmodeling-page-types\"\n                  className=\"inline-flex items-center justify-center px-5 py-3 border border-transparent text-base font-medium rounded-md text-indigo-600 bg-white hover:bg-indigo-50\"\n                >\n                  Learn more\n                </a>\n              </div>\n            </div>\n          </div>\n        </div>\n        <div className=\"bg-gray-50 mb-5 rounded-lg\">\n          <div className=\"max-w-7xl mx-auto py-12 px-4 sm:px-6\">\n            <h2 className=\"text-3xl font-extrabold tracking-tight text-gray-900 sm:text-4xl lg:mr-5\">\n              <span className=\"block\">Collections</span>\n              <span className=\"block text-indigo-600\">\n                Create reusable promotional content and more with Collections.\n              </span>\n            </h2>\n            <div className=\"mt-8\">\n              <div className=\"inline-flex rounded-md shadow\">\n                <Link href=\"/faq\">\n                  <a className=\"inline-flex items-center justify-center px-5 py-3 border border-transparent text-base font-medium rounded-md text-white bg-indigo-600 hover:bg-indigo-700\">\n                    Preview integration\n                  </a>\n                </Link>\n              </div>\n              <div className=\"ml-3 inline-flex rounded-md shadow\">\n                <a\n                  href=\"https://buttercms.com/features/#flexiblecontentmodeling-collections\"\n                  className=\"inline-flex items-center justify-center px-5 py-3 border border-transparent text-base font-medium rounded-md text-indigo-600 bg-white hover:bg-indigo-50\"\n                >\n                  Learn more\n                </a>\n              </div>\n            </div>\n          </div>\n        </div>\n      </Container>\n    </Layout>\n  );\n}\n"
  },
  {
    "path": "pages/posts/[slug].js",
    "content": "import { useRouter } from \"next/router\";\nimport ErrorPage from \"next/error\";\nimport Head from \"next/head\";\n\nimport Container from \"@/components/container\";\nimport PostBody from \"@/components/post-body\";\nimport PostHeader from \"@/components/post-header\";\nimport Layout from \"@/components/layout\";\nimport { getAllPostsPaginated, getPost } from \"@/lib/api\";\n\nexport default function Post({ post }) {\n  const router = useRouter();\n  if (!router.isFallback && !post?.slug) {\n    return <ErrorPage statusCode={404} />;\n  }\n  return (\n    <Layout>\n      <Container>\n        {router.isFallback ? (\n          <div>Loading…</div>\n        ) : (\n          <>\n            <article>\n              <Head>\n                <title>{post.seo_title}</title>\n                <meta name=\"description\" content={post.meta_description} />\n                <meta name=\"og:image\" content={post.featured_image} />\n              </Head>\n\n              <PostHeader\n                title={post.title}\n                coverImage={post.featured_image}\n                date={post.published}\n                author={post.author}\n                categories={post.categories}\n              />\n              <PostBody content={post.body} />\n            </article>\n          </>\n        )}\n      </Container>\n    </Layout>\n  );\n}\n\nexport async function getStaticProps({ params }) {\n  const post = await getPost(params.slug);\n\n  return {\n    props: {\n      post,\n    },\n  };\n}\n\nexport async function getStaticPaths() {\n  const allPosts = await getAllPostsPaginated(100);\n  const paths = Object.entries(allPosts).reduce((res, [pageIndex, posts]) => {\n    const pagePaths = posts.map((post) => `/posts/${post.slug}`);\n    return [...res, ...pagePaths];\n  }, []);\n\n  return {\n    paths,\n    fallback: true,\n  };\n}\n"
  },
  {
    "path": "pages/posts/categories.js",
    "content": "import Head from \"next/head\";\nimport Link from \"next/link\";\n\nimport Layout from \"@/components/layout\";\nimport Header from \"@/components/header\";\nimport Container from \"@/components/container\";\nimport { getCategories } from \"@/lib/api\";\n\nexport default function Categories({ categories }) {\n  return (\n    <Layout>\n      <Container>\n        <Head>\n          <title>Post categories</title>\n        </Head>\n        <Header title=\"Posts categories\"></Header>\n        <ul>\n          {categories.map(({ name, slug }, key) => {\n            return (\n              <li key={key} className=\"mb-5\">\n                <Link href={`/posts/category/${slug}`}>\n                  <a className=\"text-lg leading-6 font-medium\">{name}</a>\n                </Link>\n              </li>\n            );\n          })}\n        </ul>\n      </Container>\n    </Layout>\n  );\n}\n\nexport async function getStaticProps() {\n  const categories = await getCategories();\n  return { props: { categories } };\n}\n"
  },
  {
    "path": "pages/posts/category/[slug].js",
    "content": "import Head from \"next/head\";\nimport ErrorPage from \"next/error\";\nimport { useRouter } from \"next/router\";\n\nimport Layout from \"@/components/layout\";\nimport Container from \"@/components/container\";\nimport PostPreview from \"@/components/post-preview\";\nimport { getCategories, getCategoryWithPosts } from \"@/lib/api\";\nimport Header from \"@/components/header\";\n\nexport default function Category({ name, slug, recentPosts }) {\n  const router = useRouter();\n  if (!router.isFallback && !slug) {\n    return <ErrorPage statusCode={404} />;\n  }\n  return (\n    <Layout>\n      <Container>\n        <Head>\n          <title>{name} | Post category</title>\n        </Head>\n        {router.isFallback ? (\n          <div>Loading…</div>\n        ) : (\n          <article>\n            <Header title={`Blog posts with category \"${name}\"`}></Header>\n\n            <div className=\"grid grid-cols-1 md:grid-cols-2 md:col-gap-16 lg:col-gap-32 row-gap-20 md:row-gap-32 mb-10\">\n              {recentPosts.map(\n                ({\n                  slug: postSlug,\n                  title: postTitle,\n                  featured_image: featuredImage,\n                  published,\n                  author,\n                  summary,\n                }) => {\n                  return (\n                    <PostPreview\n                      key={postSlug}\n                      title={postTitle}\n                      coverImage={featuredImage}\n                      date={published}\n                      author={author}\n                      slug={postSlug}\n                      excerpt={summary}\n                    />\n                  );\n                }\n              )}\n            </div>\n          </article>\n        )}\n      </Container>\n    </Layout>\n  );\n}\n\nexport async function getStaticProps({ params }) {\n  const { name, slug, recent_posts } = await getCategoryWithPosts(params.slug);\n\n  return {\n    props: { name, slug, recentPosts: recent_posts },\n  };\n}\n\nexport async function getStaticPaths() {\n  const categories = await getCategories();\n\n  return {\n    paths:\n      categories?.map((category) => `/posts/category/${category.slug}`) || [],\n    fallback: true,\n  };\n}\n"
  },
  {
    "path": "pages/posts/page/[page].js",
    "content": "import Link from \"next/link\";\nimport Head from \"next/head\";\nimport { useRouter } from \"next/router\";\nimport ErrorPage from \"next/error\";\n\nimport Layout from \"@/components/layout\";\nimport Header from \"@/components/header\";\nimport Container from \"@/components/container\";\nimport PostPreview from \"@/components/post-preview\";\nimport { getPostsData, getAllPostsPaginated } from \"@/lib/api\";\n\nexport default function Posts({ posts, prevPage, nextPage }) {\n  const router = useRouter();\n  if (!router.isFallback && !posts) {\n    return <ErrorPage statusCode={404} />;\n  }\n  return (\n    <Layout>\n      <Container>\n        {router.isFallback ? (\n          <div>Loading…</div>\n        ) : (\n          <>\n            <Head>\n              <title>Blog posts</title>\n              <meta\n                name=\"description\"\n                content=\"Blog posts fetched from ButterCMS\"\n              />\n            </Head>\n\n            <Header title=\"Blog\"></Header>\n\n            <div className=\"grid grid-cols-1 md:grid-cols-2 md:gap-x-8 lg:gap-x-16 gap-y-10 md:gap-y-16\">\n              {posts.map((post) => (\n                <PostPreview\n                  key={post.slug}\n                  title={post.title}\n                  coverImage={post.featured_image}\n                  date={post.published}\n                  author={post.author}\n                  slug={post.slug}\n                  excerpt={post.summary}\n                />\n              ))}\n            </div>\n            {(prevPage || nextPage) && (\n              <div className=\"text-right mb-10\">\n                <nav\n                  className=\"relative z-0 inline-flex shadow-sm -space-x-px\"\n                  aria-label=\"Pagination\"\n                >\n                  {prevPage && (\n                    <Link href={`/posts/page/${prevPage}`}>\n                      <a className=\"relative inline-flex items-center px-2 py-2 rounded-l-md border border-gray-300 bg-white text-sm font-medium text-gray-500 hover:bg-gray-50\">\n                        <span className=\"sr-only\">Previous</span>\n                        <svg\n                          className=\"h-5 w-5\"\n                          xmlns=\"http://www.w3.org/2000/svg\"\n                          viewBox=\"0 0 20 20\"\n                          fill=\"currentColor\"\n                          aria-hidden=\"true\"\n                        >\n                          <path\n                            fill-rule=\"evenodd\"\n                            d=\"M12.707 5.293a1 1 0 010 1.414L9.414 10l3.293 3.293a1 1 0 01-1.414 1.414l-4-4a1 1 0 010-1.414l4-4a1 1 0 011.414 0z\"\n                            clipRule=\"evenodd\"\n                          />\n                        </svg>\n                      </a>\n                    </Link>\n                  )}\n                  {nextPage && (\n                    <Link href={`/posts/page/${nextPage}`}>\n                      <a className=\"relative inline-flex items-center px-2 py-2 rounded-r-md border border-gray-300 bg-white text-sm font-medium text-gray-500 hover:bg-gray-50\">\n                        <span className=\"sr-only\">Next</span>\n                        <svg\n                          className=\"h-5 w-5\"\n                          xmlns=\"http://www.w3.org/2000/svg\"\n                          viewBox=\"0 0 20 20\"\n                          fill=\"currentColor\"\n                          aria-hidden=\"true\"\n                        >\n                          <path\n                            fill-rule=\"evenodd\"\n                            d=\"M7.293 14.707a1 1 0 010-1.414L10.586 10 7.293 6.707a1 1 0 011.414-1.414l4 4a1 1 0 010 1.414l-4 4a1 1 0 01-1.414 0z\"\n                            clipRule=\"evenodd\"\n                          />\n                        </svg>\n                      </a>\n                    </Link>\n                  )}\n                </nav>\n              </div>\n            )}\n          </>\n        )}\n      </Container>\n    </Layout>\n  );\n}\n\nexport async function getStaticProps({ params }) {\n  const page = parseInt(params.page, 10);\n  const { posts, prevPage, nextPage } = await getPostsData(page);\n\n  return {\n    props: { posts, prevPage, nextPage },\n    revalidate: 1,\n  };\n}\n\nexport async function getStaticPaths() {\n  const allPosts = await getAllPostsPaginated();\n  const paths = Object.keys(allPosts).map(\n    (pageIndex) => `/posts/page/${parseInt(pageIndex, 10) + 1}`\n  );\n\n  return {\n    paths,\n    fallback: true,\n  };\n}\n"
  },
  {
    "path": "pages/rss.js",
    "content": "import { getRssData } from \"@/lib/api\";\n\nexport default function Rss({ rss }) {\n  return rss;\n}\n\nexport async function getStaticProps() {\n  const rss = await getRssData();\n  return { props: { rss } };\n}\n"
  },
  {
    "path": "pages/sitemap.js",
    "content": "import { getSitemapData } from \"@/lib/api\";\n\nexport default function Sitemap({ sitemap }) {\n  return sitemap;\n}\n\nexport async function getStaticProps() {\n  const sitemap = await getSitemapData();\n  return { props: { sitemap } };\n}\n"
  },
  {
    "path": "postcss.config.js",
    "content": "module.exports = {\n  plugins: [\n    'tailwindcss',\n    'postcss-flexbugs-fixes',\n    [\n      'postcss-preset-env',\n      {\n        autoprefixer: {\n          flexbox: 'no-2009',\n        },\n        stage: 3,\n        features: {\n          'custom-properties': false,\n        },\n      },\n    ],\n  ],\n}\n"
  },
  {
    "path": "styles/index.css",
    "content": "@tailwind base;\n@tailwind components;\n@tailwind utilities;\n\n.grayscale {\n  filter: grayscale(1);\n}\n\niframe {\n  max-width: 100%;\n}\n"
  },
  {
    "path": "tailwind.config.js",
    "content": "module.exports = {\n  purge: [\"./components/**/*.js\", \"./pages/**/*.js\"],\n  theme: {\n    extend: {\n      fontFamily: {\n        sans:\n          '-apple-system, \"Helvetica Neue\", \"Segoe UI\", Roboto, Arial, \"Noto Sans\", sans-serif, \"Apple Color Emoji\", \"Segoe UI Emoji\", \"Segoe UI Symbol\", \"Noto Color Emoji\"',\n      },\n      colors: {\n        \"accent-1\": \"#FAFAFA\",\n        \"accent-2\": \"#EAEAEA\",\n        \"accent-7\": \"#333\",\n        success: \"#0070f3\",\n        cyan: \"#79FFE1\",\n      },\n      spacing: {\n        28: \"7rem\",\n      },\n      letterSpacing: {\n        tighter: \"-.04em\",\n      },\n      lineHeight: {\n        tight: 1.2,\n      },\n      fontSize: {\n        \"5xl\": \"2.5rem\",\n        \"6xl\": \"2.75rem\",\n        \"7xl\": \"4.5rem\",\n        \"8xl\": \"6.25rem\",\n      },\n      boxShadow: {\n        small: \"0 5px 10px rgba(0, 0, 0, 0.12)\",\n        medium: \"0 8px 30px rgba(0, 0, 0, 0.12)\",\n      },\n    },\n  },\n  plugins: [require(\"@tailwindcss/typography\")],\n};\n"
  }
]