Когда дело доходит до Gatsby, есть несколько уникальных приемов, о которых вам следует знать, чтобы успешно создать темный режим для вашего приложения.

В этом посте мы пройдем всю реализацию от начала до конца.

Предпосылки

Начиная

Добавьте простую команду ниже, чтобы создать новый сайт.

npm init gatsby

💡 Примечание. Продолжайте следовать инструкциям, чтобы выбрать нужный язык (JavaScript или TypeScript), CMS, инструменты для оформления и другие функции.

Когда все будет загружено, вы получите уведомление с инструкциями о том, как перейти на ваш сайт и выполнить его локально.

// Start by going to the directory with
cd my-gatsby-site

// Start the local development server with
npm run develop

💡 Примечание. Перейдите на localhost: 8000, и вы должны увидеть, что ваше приложение работает. Отредактируйте домашнюю страницу в src/pages/index.js, сохраните ее и перезагрузите страницу, чтобы увидеть изменения в браузере.

Часть 1: Добавление переменных CSS

Цель состоит в том, чтобы использовать переменные CSS и хук UseState в React. Любой альтернативный менеджер состояния также будет работать, но для простоты мы просто воспользуемся стандартным хуком UseState.

Мы начнем создавать CSS для темного режима.

/* 1 */
:root {
  --color-primary: #CD104D;
  --color-text: #2e353f;
  --color-text-light: #4f5969;
  --color-heading: #1a202c;
  --color-heading-black: #000000;
  --color-accent: #d1dce5;
  --color-background: #FFFFFF;
  --dark-mode: #000;
  --dark-mode-hf: #CD104D;
}

/* 2 */
body {
  color: var(--color-text);
  background-color: var(--color-background);
}

💡 Примечание. Добавляя эти переменные к элементу body, они становятся доступными для всех наших компонентов и классов по всему миру.

Далее мы добавим значения к переменным темного и светлого режима. Мы достигнем этого, определив класс.

/* 3 */
body.dark {
  --color-background: #171717;
  --color-primary: #CD104D;
  --color-text: #ffffff;
  --color-text-light: #4f5969;
  --color-heading: #DFDFDE;
  --color-heading-black: #EDEDED;
  --color-accent: #d1dce5;
  --image: url("./images/sun.svg");
}

/* 4 */
body.light {
  --color-primary: #CD104D;
  --color-text: #2e353f;
  --color-text-light: #4f5969;
  --color-heading: #1a202c;
  --color-heading-black: black;
  --color-accent: #d1dce5;
  --color-background: #FFFFFF;
  --image: url("./images/moon.svg");
}

💡 Примечание. Теперь мы определили темы для светлого и темного режимов.

Часть 2. Добавление кнопки переключения между темной и светлой темами

У нас будет компонент переключатель, который появляется на всех наших страницах, поэтому кажется разумным иметь там кнопку переключения.

Вот как выглядит компонент toggle:

import React from "react"
import "../style.scss"
import Sun from "../images/sun.svg"
import Moon from "../images/moon.svg"

export default function DarkMode() {
  const [isDark, setIsDark] = React.useState(false)

  React.useEffect(() => {
    if (isDark) {
      document.body.classList.add('dark');
    } else {
      document.body.classList.remove('dark');
    }  
  }, [isDark])

  return (
    <div className="global-toggle-switch">
      <span>
        {isDark ? (<img onClick={() => setIsDark(!isDark)} src={Sun} alt="sun img" />) : (<img onClick={() => setIsDark(!isDark)} src={Moon} alt="moon img" />)}
      </span>
    </div>
  )
}

💡 Примечание. Эти значки функционируют как кнопки, и при выборе они либо добавляют, либо удаляют класс .dark из тела, изменяя тему приложения.

Часть 3. Сохранение темы по умолчанию в локальном хранилище

Теперь нам также нужно сохранить предпочтительный режим в локальном хранилище, чтобы он оставался даже при сбросе страницы или приложения. Для этого я создаю глобальную служебную функцию с именем getDefaultTheme:

/* 5 */
function getDefaultTheme() {
    const savedTheme = window.localStorage.getItem('theme');
    return savedTheme ? savedTheme : 'light';
}

💡 Примечание. Теперь этот метод должен вызываться в хуке useState, созданном в моем компоненте DarkMode.

/* 6 */
const [isDark, setIsDark] = React.useState(getDefaultTheme())

Для этого я возвращаюсь к хуку useEffect и вставляю следующий код:

/* 7 */
  React.useEffect(() => {
    if (isDark === 'dark') {
      document.body.classList.add('dark');
    } else {
      document.body.classList.remove('dark');
    }
      window.localStorage.setItem('theme', isDark);
  }, [isDark])

Если вы следовали инструкциям, ваш готовый код должен выглядеть так:

import React from "react"
import "../style.scss"
import Sun from "../images/sun.svg"
import Moon from "../images/moon.svg"

function getDefaultTheme() {
  const savedTheme = window.localStorage.getItem("theme")
  return savedTheme ? savedTheme : "light"
}

export default function DarkMode() {
  const [isDark, setIsDark] = React.useState(getDefaultTheme())

  React.useEffect(() => {
    if (isDark === "dark") {
      document.body.classList.add("dark")
    } else {
      document.body.classList.remove("dark")
    }
    window.localStorage.setItem("theme", isDark)
  }, [isDark])

  return (
    <div className="global-toggle-switch">
      <span onClick={() => setIsDark(isDark === "dark" ? "light" : "dark")}>
        {isDark === "dark" ? (
          <img src={Sun} alt="sun img" />
        ) : (
          <img src={Moon} alt="moon img" />
        )}
      </span>
    </div>
  )
}