🎉

【Next.js】Next.js & Contentful BlogApp 【17tailwind darkmode】

2022/12/03に公開

【17tailwind darkmode】

YouTube:https://youtu.be/U6ujzixl-rc

https://youtu.be/U6ujzixl-rc

今回からtailwind cssのdarkモードの設定を何回かに分けて解説します。
今回は、darkモードの初期設定とスタイリングを実装します。

まずはtailwindのコンフィグファイルの末尾に
darkModeの設定を追加します。

tailwind.config.js
/** @type {import('tailwindcss').Config} */
module.exports = {
  content: [
    './pages/**/*.{js,ts,jsx,tsx}',
    './components/**/*.{js,ts,jsx,tsx}',
  ],
  theme: {
    extend: {},
  },
  plugins: [],
  darkMode: 'class',
}

そして、darkモードの対象となる一番上の親要素に「dark」のクラスを追加して、
各要素のスタイリングには「dark:from-purple-800」のように
先頭に「dark:」を設定します。

components/Layout.js
import Head from 'next/head'
import Navbar from './Navbar'

const Layout = ({ children, title = 'My Blog App' }) => {
  return (
    <div className={`dark`}>
      <Head>
        <title>{title}</title>
      </Head>

      <div className="w-full min-h-screen bg-gradient-to-r from-yellow-500 to-red-500 dark:from-purple-800 dark:to-pink-600">
        <Navbar />
        <main>{children}</main>

        <footer className="py-3 text-center dark:text-white">
          <span>&copy; My Blog App</span>
        </footer>
      </div>
    </div>
  )
}

export default Layout

darkモードにすると、テキストの黒字が見えにくくなりますので、
darkモードの際にはテキストの色が白になるように設定します。

components/Heor.js
import Image from 'next/image'

const Hero = () => {
  return (
    <div className="w-full">
      <div className="max-w-7xl flex flex-wrap justify-around items-center mx-auto py-6 px-3 gap-3">
        <div className="dark:text-white">
          <h1 className="font-bold text-8xl pb-5 mb-1">My Blog App</h1>
          <p className="font-bold text-5xl mb-4">Next.js & Contentful</p>
          <p className="font-bold text-2xl mb-2">Web Frontend & Backend</p>
        </div>
        <div>
          <Image
            src="/images/img_hero.png"
            alt="main_visual"
            width={600}
            height={600}
          />
        </div>
      </div>
    </div>
  )
}

export default Hero
pages/posts/[slug].js
import Image from 'next/image'
import Layout from '../../components/Layout'
import { client } from '../../utils/contentfulClient'
import { documentToReactComponents } from '@contentful/rich-text-react-renderer'
import { options } from '../../lib/richTextOptions'

export const getStaticPaths = async () => {
  const res = await client.getEntries({
    content_type: 'myPosts',
  })
  const paths = res.items.map((item) => {
    return {
      params: { slug: item.fields.slug },
    }
  })

  return {
    paths,
    fallback: 'blocking',
  }
}

export const getStaticProps = async ({ params }) => {
  const { items } = await client.getEntries({
    content_type: 'myPosts',
    'fields.slug': params.slug,
  })

  if (!items.length) {
    return {
      notFound: true,
    }
  }

  return {
    props: { item: items[0] },
    revalidate: 10,
  }
}

const PostDetailsPage = ({ item }) => {
  return (
    <Layout title={item.fields.slug}>
      <div className="w-full">
        <div className="max-w-6xl flex flex-wrap justify-between items-center mx-auto py-6 px-5 gap-3">
          <div className="dark:text-white">
            <h1 className="font-bold text-3xl sm:text-4xl md:text-4xl lg:text-5xl py-3 mb-1">
              {item.fields.title}
            </h1>
            <p className="font-bold text-2xl mb-2">
              {item.sys.createdAt.substring(0, 10)}
            </p>
          </div>
          <div>
            <Image
              src={`https:${item.fields.image.fields.file.url}`}
              alt={item.fields.image.fields.description}
              width={500}
              height={500}
              className="rounded"
            />
          </div>
        </div>
      </div>
      <div className="max-w-6xl mx-auto p-5 dark:text-white">
        {documentToReactComponents(item.fields.content, options)}
      </div>
    </Layout>
  )
}

export default PostDetailsPage

Discussion