Светлый и темный режимы в веб-приложениях React на основе CSS Tailwind

Ниже представлены основные функции будущего приложения.

  • Переключение между темным и светлым режимами.
  • Получение случайных шуток и изображений.
  • Возможность делиться ими в социальных сетях, таких как Facebook и Twitter.

Можете посмотреть демонстрацию в live-режиме здесь:

В этом руководстве используются Visual Studio Code в качестве редактора и Netlify для развертывания приложения. Допустимы и другие инструменты.

Вот что вы узнаете из этого руководства.

  • Как установить CSS Tailwind с помощью Create React App.
  • Как переключать темы для темного и светлого режимов.
  • Как извлекать Joke API.

Хорошо, начнем!

Как установить CSS Tailwind с помощью Create React App

Вначале несколько слов о Tailwind CSS. Официальная платформа TailwindCSS призывает пользователей: “Быстро создавайте современные веб-сайты, никогда не покидая HTML”. Это означает, что вам не придется писать много строк CSS-кода, но при этом надо иметь индивидуально настраиваемый интерфейс с использованием HTML. Словом, стоит попробовать создать приложение с TailwindCSS.

Продолжаем двигаться дальше! Чтобы установить CSS Tailwind с помощью Create React App, необходимо выполнить действия, описанные здесь.

Когда приложение React будет установлено, перейдите в файл tailwind.config.js и настройте его следующим образом:

// tailwind.config.js
module.exports = {
  purge: ['./src/**/*.{js,jsx,ts,tsx}', './public/index.html'],
  darkMode: 'class',
  theme: {
    container: {
      center: true,
       padding: {
        DEFAULT: '1rem',
        sm: '2rem',
        lg: '4rem',
        xl: '5rem',
        '2xl': '6rem',
      },
    
    },
  },
  variants: {
    extend: {},
  },
  plugins: [],
}

Затем перейдите в файл index.css и добавьте эти строки:

@tailwind base;
  @tailwind components;
  @tailwind utilities;

  @import url("https://fonts.googleapis.com/css2?family=VT323&display=swap");

  body {
    font-family: "VT323",
    monospace;
  }

Вот и все, что нужно для настройки CSS-файла. В этом и заключается прелесть использования TailwindCSS  —  он избавляет вас от долго настраиваемого CSS-кода и делает приложение более простым и быстрым. Прежде чем двигаться дальше, ознакомьтесь с подробной информации об этом фреймворке здесь.

Как переключать темы для темного и светлого режимов

Чтобы включать темный и светлый режимы с помощью TailwindCSS, необходимо создать следующие компоненты Javascript: Background.js, ThemeContext.js и ThemeToggle.js. Погрузимся в детали и код.

Background.js использует имя класса “bg-white dark:bg-black transition-all” в элементе тела, чтобы тема переключалась между белым и черным фоном. Вы можете выбрать другие цвета фона в зависимости от ваших потребностей.

//Background.jsimport React from 'react';

const Background = ( { children } ) =>
{
    return (
       
        <body className="bg-white dark:bg-black transition-all">
            {children}
        </body>
    )
}

export default Background;

ThemeContext.js создает родительского поставщика для темы в действии.

//ThemeContext.jsimport React from 'react';

const getInitialTheme = () => {
    if (typeof window !== 'undefined' && window.localStorage) {
        const storedPrefs = window.localStorage.getItem('color-theme');
        if (typeof storedPrefs === 'string') {
            return storedPrefs;
        }

        const userMedia = window.matchMedia('(prefers-color-scheme: dark)');
        if (userMedia.matches) {
            return 'dark';
        }
    }

   return 'light' // Светлая тема по умолчанию;
};
export const ThemeContext = React.createContext();

export const ThemeProvider = ({ initialTheme, children }) => {
    const [theme, setTheme] = React.useState(getInitialTheme);

    const rawSetTheme = (rawTheme) => {
        const root = window.document.documentElement;
        const isDark = rawTheme === 'dark';

        root.classList.remove(isDark ? 'light' : 'dark');
        root.classList.add(rawTheme);

        localStorage.setItem('color-theme', rawTheme);
    };

    if (initialTheme) {
        rawSetTheme(initialTheme);
    }

    React.useEffect(() => {
        rawSetTheme(theme);
    }, [theme]);

    return (
        <ThemeContext.Provider value={{ theme, setTheme }}>
            {children}
        </ThemeContext.Provider>
    );
};

ThemeToggle.js подготавливает дочерние элементы интерфейса для переключения между светлым и темным режимами. Не забудьте установить react-иконки, если используете их таким образом:

//ThemeToggle.jsimport React from 'react';
import { FaSun, FaMoon} from "react-icons/fa";
import { ThemeContext } from './ThemeContext';

const Toggle = () => {
    const { theme, setTheme } = React.useContext(ThemeContext);

    return (
        <div className="transition duration-500 ease-in-out rounded-full p-2">
            {theme === 'dark' ? (
                <FaSun
                    onClick={() => setTheme(theme === 'dark' ? 'light' : 'dark')}
                    className="text-gray-500 dark:text-gray-400 text-2xl cursor-pointer"
                />
            ) : (
                    <FaMoon
                        onClick={() => setTheme(theme === 'dark' ? 'light' : 'dark')}
                        className="text-gray-500 dark:text-gray-400 text-2xl cursor-pointer"
                    />
                )}
        </div>
    );
};

export default Toggle;

Теперь импортируйте все эти компоненты в файл index.js, как показано ниже:

//index.jsimport React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import { ThemeProvider } from './components/ThemeContext';
import Background from './components/Background';
import Toggle from './components/ThemeToggle';

ReactDOM.render(
  <React.StrictMode>
        <ThemeProvider>
      <Background>
         <div className="absolute right-0 top-0 mr-4 mt-4 md:mr-6 md:mt-6">
            <Toggle />
          </div>
       
        <App />
          </Background>
    </ThemeProvider>,
  </React.StrictMode>,
  document.getElementById('root')
);

Вот и все для режима темы в действии. Переходим к основному файлу App.js.

Как извлекать Joke API

Joke API взят из этого репозитория. По желанию вы можете добавить в него больше шуток.

Если вы используете Axios для извлечения данных, не забудьте установить его в приложение React.

//App.jsimport React from 'react';
import axios from 'axios'
import { FaFacebook, FaTwitter, FaSync, FaQuoteLeft } from "react-icons/fa"
const API = "https://raw.githubusercontent.com/15Dkatz/official_joke_api/master/jokes/index.json";
class App extends React.Component
{
 
  state = {
    jokes: [
      {
        setup:"What did the fish say when it hit the wall?",
        punchline: "Dam.",
        type: "general"
      }
    ],
    index: 0
  };
  componentDidMount() {
    this.fetchJoke();
  }

   fetchJoke = () => {
    axios.get(API)
      .then((res) => {
          this.setState(
          {
            jokes: res.data
          },
          this.getRandomIndex
        );
      })
      .catch((error) => {
        console.log(error);
      });
  }
  getRandomIndex = () => {
    const { jokes } = this.state;
    if (jokes.length > 0) {
      const index = Math.floor(Math.random() * jokes.length);
      this.setState({
        index
      });
    }
  };
  render ()
  {
   
    const { jokes, index } = this.state;
    const joke = jokes[index];    const tweetURL = `https://twitter.com/intent/tweet?text=${joke.setup} ${joke.punchline} - ${joke.type}`;
    const facebookURL =
      "https://www.facebook.com/sharer/sharer.php?u=https://try-not-to-laugh-challenge.netlify.app/";
    return (
     
      <body className="flex flex-col min-h-screen">
        
      <header className="flex flex-col items-center justify-center p-8">
           <img className="shadow-lg rounded-full inline-block w-40 h-40 m-8" src={`https://picsum.photos/600?grayscale&random=${index}`} alt="logo" />
        <h1 className="font-bold capitalize text-gray-500 dark:text-gray-400 text-center text-lg pt-4">Try-Not-to-Laugh Challenge</h1>
        </header>
         <main class="flex-grow">
        
          
        <div className="container text-gray-500 dark:text-gray-400 flex flex-col items-center justify-center gap-4 p-4 md:p-8" id="quote-box">
          {joke && (
            <div className="text-2xl">
              <p id="text">
                  <FaQuoteLeft />&nbsp; { joke.setup }
                  &nbsp;{joke.punchline}
              </p>
              <cite id="author" className="float-right">
                -{joke.type}
              </cite>
            </div>
          )}
          <div className="grid grid-cols-1 md:grid-cols-3 gap-6 m-8">
            <a
              id="tweet-quote"
              className="flex items-center justify-center border-2 rounded-full py-1 px-6"
              target="_blank"
              rel="noreferrer"
              href={tweetURL}
            >
              <FaTwitter/>&nbsp; Tweet
            </a>
            <a
              id="fb-quote"
              className="flex items-center justify-center border-2 rounded-full py-1 px-6"
              target="_blank"
              rel="noreferrer"
              href={facebookURL}
            >
             <FaFacebook/>
                 &nbsp; Share
            </a>
            <button
              className="flex items-center justify-center bg-gray-800 border-2 rounded-full py-1 px-6"
              onClick={this.getRandomIndex}
              id="new-quote"
            >
             <FaSync/>
              &nbsp; Get Joke
            </button>
          </div>
            </div>
           
          </main>
        <footer className="text-gray-500 dark:text-gray-400">
          <div className="text-center text-xs p-2">
            Made with TailwindCSS by <a target="_blank" rel="noreferrer" href="https://hellojuninguyen.netlify.app/">juniNguyen.</a>
            </div>
        </footer>
           </body>
    );
  }
}
export default App;

Чтобы получить случайную шутку, нужно вызвать функцию getRandomIndex(), которая обрабатывает событие кнопкой Get Joke при каждом нажатии. Чтобы делиться шутками в социальных сетях, просто используйте react-иконки в качестве кнопок и создайте атрибут URL-ссылки href, подобный этому:

const tweetURL = `https://twitter.com/intent/tweet?text=${joke.setup} ${joke.punchline} - ${joke.type}`;

const facebookURL = "https://www.facebook.com/sharer/sharer.php?u=https://try-not-to-laugh-challenge.netlify.app/";

Случайные изображения взяты из Lorem Picsum. Внутри элемента img добавьте источник следующим образом:

<img className="shadow-lg rounded-full inline-block w-40 h-40 m-8" src={`https://picsum.photos/600?grayscale&random=${index}`} alt="logo" />

Вот и все. Исходный код для этого приложения находится здесь.

Читайте также:

Читайте нас в Telegram, VK и Яндекс.Дзен


Перевод статьи juniNguyen.: Light and Dark Mode in React Web Application with Tailwind CSS

Предыдущая статьяОдин за всех и все за одного: 8 принципов командной разработки
Следующая статьяАлгоритм JavaScript: Array.forEach()