Рубріки: Решения

Под любой экран: адаптивная панель навигации с помощью React и Tailwind

Богдан Мирченко

Разработчик Франсиско Мендес опубликовал в блоге туториал по созданию панели навигации, которая адаптируется к различным размерам экрана. Описанный вариант выполнен с помощью React и Tailwind, а навигация будет проводиться по странице, на которой находится пользователь. Вот как это сделать. 

По словам автора туториала, если сделать все правильно, в конце должна получиться такая адаптивная навигационная панель: 

Создание навигационных элементов

Наряду с Tailwind CSS будут использоваться другие инструменты, такие как classnames и react-icons: 

npm install classnames react-icons

Затем создаем файл с названием навигационных элементов: 

// @src/data/navigation.js

export default ["Home", "Discover", "Store", "Inbox", "Profile"];

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

// @src/hooks/useNavigation.js
import { useState, useCallback } from "react";

const useNavigation = () => {
  const [route, setRoute] = useState("Home");

  const selectAction = useCallback(
    (option) => {
      if (route === option) return;
      setRoute(option);
    },
    [route]
  );

  return { currentRoute: route, setCurrentRoute: selectAction };
};

export default useNavigation;

Компонент Navbar

Работу с компонентами следуем начать с работы над панелью навигации. Ниже представлены стили компонента Navbar: 

/* @src/components/Navbar/Navbar.module.css */
.navbar {
  @apply hidden md:flex flex-row items-center justify-between px-8 h-18 rounded-b-3xl bg-white;
}

.logo {
  @apply text-5xl text-gray-800 -mb-1;
}

.navItems {
  @apply flex flex-row self-end h-12;
}

.navItem {
  @apply w-22 text-gray-400 hover:text-gray-700 cursor-pointer font-medium tracking-wide text-sm flex items-start justify-center;
}

.selectedNavItem {
  @apply text-gray-700 border-b-3 border-gray-700 bg-gradient-to-b from-white to-gray-100;
}

.actions {
  @apply bg-white hover:bg-gray-50 border-2 border-gray-900 text-sm text-gray-900 py-3 px-5 rounded-lg font-medium tracking-wide leading-none;
}

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

// @src/components/Navbar/index.jsx
import React from "react";
import { CgMonday } from "react-icons/cg";
import classNames from "classnames";

import styles from "./Navbar.module.css";

const Navbar = ({ navigationData, currentRoute, setCurrentRoute }) => {
  return (
    <nav className={styles.navbar}>
      <span className={styles.logo}>
        <CgMonday />
      </span>
      <ul className={styles.navItems}>
        {navigationData.map((item, index) => (
          <li
            className={classNames([
              styles.navItem,
              currentRoute === item && styles.selectedNavItem,
            ])}
            key={index}
            onClick={() => setCurrentRoute(item)}
          >
            {item}
          </li>
        ))}
      </ul>
      <button className={styles.actions}>Logout</button>
    </nav>
  );
};

export default Navbar;

Компонент Tabbar

Для создания панели вкладок используются следующие стили: 

/* @src/components/Tabbar/Tabbar.module.css */
.tabbar {
  @apply flex md:hidden flex-row items-center justify-around px-8 h-18 bg-white visible md:invisible fixed bottom-0 w-full rounded-t-3xl text-2xl;
}

.tabItem {
  @apply text-gray-400 hover:text-gray-700 cursor-pointer w-18 h-full flex items-center justify-center;
}

.tabItemActive {
  @apply bg-gradient-to-t from-white to-gray-100 border-t-3 border-gray-700 text-gray-700;
}

.icon {
  @apply -mb-1;
}

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

// @src/components/Tabbar/index.jsx

import React, { useCallback } from "react";
import classNames from "classnames";
import { AiFillHome, AiFillCompass } from "react-icons/ai";
import { BsFillBagFill, BsFillPersonFill } from "react-icons/bs";
import { CgInbox } from "react-icons/cg";

import styles from "./Tabbar.module.css";

const Tabbar = ({ navigationData, currentRoute, setCurrentRoute }) => {
  const getTabIcon = useCallback((item) => {
    switch (item) {
      case "Home":
        return <AiFillHome />;
      case "Discover":
        return <AiFillCompass />;
      case "Store":
        return <BsFillBagFill />;
      case "Inbox":
        return <CgInbox />;
      case "Profile":
        return <BsFillPersonFill />;
    }
  }, []);

  return (
    <nav className={styles.tabbar}>
      {navigationData.map((item, index) => (
        <span
          key={index}
          className={classNames([
            styles.tabItem,
            currentRoute === item && styles.tabItemActive,
          ])}
          onClick={() => setCurrentRoute(item)}
        >
          <span className={styles.icon}>{getTabIcon(item)}</span>
        </span>
      ))}
    </nav>
  );
};

export default Tabbar;

Последним шагом нужно перейти к входному файлу App.jsx. Стили будут следующие: 

/* @src/App.module.css */
.container {
  @apply bg-gray-200 h-screen;
}

.devLogo {
  @apply flex items-center justify-center text-5xl text-gray-300 h-5/6;
}

Теперь в App.jsx импортируем навигационные данные, хук и каждый из компонентов, которые создадим ниже, каждому из них передаем указанные пропсы. 

// @src/App.jsx
import React from "react";
import { FaDev } from "react-icons/fa";

import styles from "./App.module.css";
import useNavigation from "./hooks/useNavigation";
import navigationData from "./data/navigation";

import Navbar from "./components/Navbar";
import Tabbar from "./components/Tabbar";

const App = () => {
  const { currentRoute, setCurrentRoute } = useNavigation();

  return (
    <div className={styles.container}>
      <Navbar
        navigationData={navigationData}
        currentRoute={currentRoute}
        setCurrentRoute={setCurrentRoute}
      />
      <Tabbar
        navigationData={navigationData}
        currentRoute={currentRoute}
        setCurrentRoute={setCurrentRoute}
      />
      <div className={styles.devLogo}>
        <FaDev />
      </div>
    </div>
  );
};

export default App;

Вот и все!

Останні статті

Обучение Power BI – какие онлайн курсы аналитики выбрать

Сегодня мы поговорим о том, как выбрать лучшие курсы Power BI в Украине, особенно для…

13.01.2024

Work.ua назвал самые конкурентные вакансии в IТ за 2023 год

В 2023 году во всех крупнейших регионах конкуренция за вакансию выросла на 5–12%. Не исключением…

08.12.2023

Украинская IT-рекрутерка создала бесплатный трекер поиска работы

Unicorn Hunter/Talent Manager Лина Калиш создала бесплатный трекер поиска работы в Notion, систематизирующий все этапы…

07.12.2023

Mate academy отправит работников в 10-дневный оплачиваемый отпуск

Edtech-стартап Mate academy принял решение отправить своих работников в десятидневный отпуск – с 25 декабря…

07.12.2023

Переписки, фото, история браузера: киевский программист зарабатывал на шпионаже

Служба безопасности Украины задержала в Киеве 46-летнего программиста, который за деньги устанавливал шпионские программы и…

07.12.2023

Как вырасти до сеньйора? Девелопер создал популярную подборку на Github

IT-специалист Джордан Катлер создал и выложил на Github подборку разнообразных ресурсов, которые помогут достичь уровня…

07.12.2023