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

Это урок 7 в учебнике о том, как создать блог с помощью NextJS, Sanity и Vercel.
Если вы хотите получить помощь в работе со стилизованными компонентами, то вам нужно будет создать свой собственный текст для элементов или следовать моему руководству из первого урока.

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

Я немного подправил реквизиты, которые мы получаем. Я объясню эту часть после планирования, так что если вам нужны только стилизованные компоненты, вы можете пропустить их вперед.
Вы также должны создать дополнительные посты (по крайней мере, 2), чтобы увидеть нашу боковую панель Recent Posts.


Планирование

Никогда не стоит делать стили из кода. Я имею в виду, что вы должны заранее представить, как вы хотите, чтобы все выглядело (даже набросать это), а затем повторить это в коде.

Что касается «набросков», я именно так и поступил. Всего за пару минут я смог создать этот дизайн Figma.

Если у вас нет учетной записи Figma, вам, возможно, придется зарегистрироваться для ее просмотра, но она того стоит. Нельзя недооценивать количество времени, которое вы экономите, делая эскизы.

Я не создал самый сложный пользовательский интерфейс в истории, но для наших нужд он вполне подходит. Вы также можете щелкнуть каждый элемент и увидеть его название (назначение) в левой части экрана под Layers > Desktop-1.

Один из элементов называется Social Media Buttons, поэтому мы собираемся пойти дальше и установить пакет npm, который является стандартным почти для каждого проекта.

В командной строке вашего проекта выполните

npm i react-icons --save &&
npm i react-portable-text
Войти в полноэкранный режим Выйти из полноэкранного режима

Чтение документации по React Icons объяснит, как его использовать, и позволит вам найти любую иконку, которую вы хотите. Все, что нам нужно сделать, это найти код для нужной нам иконки, импортировать его и вставить как компонент React.

React Portable Text — это то, что мы будем использовать для отображения значения body, которое мы не смогли использовать в прошлом уроке.


Оглавление

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

Но я собираюсь разбить его на 5 частей.

  1. Импорты
    • Пара импортов, необходимых для нашей страницы
  2. Стилизованные компоненты
    • Наши стилизованные компоненты (сделаны в файле, не импортированы)
  3. Структура HTML
    • Наш HTML-макет с содержимым
  4. Реквизиты
    • Изменения в нашем getStaticProps
  5. Предварительный просмотр
    • Онлайн песочница, чтобы вы могли посмотреть, как это должно выглядеть, или скопируйте файл /pages/posts/[slug].js.

Импортирует

Это может выглядеть по-разному, если вы решите использовать дополнительные иконки, я же пока импортирую только 3 основных.

import PortableText from "react-portable-text";
import styled from "styled-components";
import Link from "next/link";
import { BsFacebook, BsTwitter, BsInstagram } from "react-icons/bs";
Вход в полноэкранный режим Выход из полноэкранного режима

Импортируем

  • Последняя строка импортирует иконки Facebook, Twitter и Instagram из нашего react-icons.

Стилизованные компоненты

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

Прежде чем перейти к компонентам, я добавил пару вещей в наш файл /styles/globals.css.

@import url('https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;500;600;700&display=swap');

* {
  padding: 0;
  margin: 0;
  font-family: 'Poppins';
  color: #333;
}

body {
  background: rgb(248, 248, 248)
}

a {
  color: inherit;
  text-decoration: none;
}

* {
  box-sizing: border-box;
}
Вход в полноэкранный режим Выход из полноэкранного режима
  • Poppins теперь наш шрифт по умолчанию для всего.
  • Цвет фона body теперь rgb(248, 248, 248).
    • Это белый цвет, который легче для глаз.

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

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

Пока не копируйте его в свой файл, он будет включен в полный список компонентов, который я опубликую после этого объяснения.

const BackButton = styled.div`
  border: 1px solid #333;
  border-radius: 7px;
  text-align: center;
  font-size: 1.2rem;
  width: fit-content;
  padding: 4px 6px;
  transition: all 0.3s;

  :hover {
    background: #333;
    color: white;
    cursor: pointer;
  }

  span {
    position: relative;
    bottom: 3px;
  }
`;
Вход в полноэкранный режим Выход из полноэкранного режима
  • Сначала мы создадим компонент с именем BackButton.

    • Это компонент React, поэтому он должен быть в регистре Pascal (каждое слово заглавное).
  • Мы объявляем, что этот компонент является styled.div.

    • Чтобы использовать его, достаточно заменить <div></div> в коде на <BackButton></BackButton>, и теперь это будет элемент div со стилизацией.
  • Вы также должны знать, что мы оборачиваем CSS для нашего компонента в обратные символы.

  • Теперь внутри находится наш базовый CSS. Я не буду описывать детали моего CSS, или как я использую grid для позиционирования, потому что лучше вам самим поиграть с этим и разобраться. Но если вы все еще не понимаете назначение линии, вы можете погуглить, поиграть с ней в Browser DevTools или даже написать мне в Twitter, и я смогу помочь вам объяснить дальше.

    • Мы применяем стилизацию к нашему элементу div.
    • Что произойдет, когда div будет hovered
    • И, наконец, мы применим стиль к любым элементам span внутри этого div.

После этого краткого примера, вот весь блок кода для всех наших стилей. Помните, вставьте его ниже импорта и выше компонента Post.

const PageContainer = styled.div`
  padding: 70px 110px;
  max-width: 1600px;
  margin-inline: auto;
`;

const BackButton = styled.div`
  border: 1px solid #333;
  border-radius: 7px;
  text-align: center;
  font-size: 1.2rem;
  width: fit-content;
  padding: 4px 6px;
  transition: all 0.3s;

  :hover {
    background: #333;
    color: white;
    cursor: pointer;
  }

  span {
    position: relative;
    bottom: 3px;
  }
`;

const ContentContainer = styled.div`
  display: grid;
  grid-template-columns: 0.5fr 2fr 1fr;
  grid-template-rows: 1fr auto;
  grid-template-areas:
    "header1 header header2"
    "socials main links";
`;

const Header = styled.header`
  grid-area: header;
  text-align: center;
  margin-bottom: 40px;

  h1 {
    text-transform: uppercase;
    color: #222222;
    font-size: 3rem;
  }

  span {
    color: #464646;
  }
`;

const SocialsContainer = styled.ul`
  grid-area: socials;
  display: flex;
  flex-direction: column;
  align-items: end;
  list-style-type: none;
  gap: 30px;
  padding-right: 50px;
  padding-top: 14px;

  li {
    cursor: pointer;
  }
`;

const StyledLi = styled.li`
  svg {
    transition: transform 0.4s;

    path {
      color: #4040ac;
    }
  }

  svg:hover {
    transform: scale(1.2);
  }
`;

const Body = styled.main`
  grid-area: main;

  h1 {
    text-align: center;
    font-size: 2.3rem;
    margin-bottom: 15px;
    padding-right: 160px;
  }

  h2 {
    margin: 5px 0px;
  }

  div {
    display: flex;
    flex-direction: column;
    gap: 5px;
  }
`;

const RecentPostsContainer = styled.div`
  padding-left: 50px;
  grid-area: links;
  display: flex;
  flex-direction: column;
  gap: 20px;
`;

const RecentPost = styled.div`
  display: flex;
  flex-direction: column;
  border: 1px solid #333;
  align-items: center;
  transition: all 0.4s;

  p {
    font-size: 1.1rem;
    font-weight: 500;
  }

  span,
  p {
    transition: all 0.4s;
  }

  :hover {
    background: #333;
    cursor: pointer;

    span,
    p {
      color: white;
    }
  }
`;
Вход в полноэкранный режим Выход из полноэкранного режима

Я стилизую содержимое post.body внутри компонента Body.
Как вы видите, я выбрал только h1, h2 и div, потому что именно они находятся в теле моего поста. Если у вас есть другие элементы, вы можете стилизовать их по своему усмотрению, указав тип элемента и применив свой стиль.


Структура HTML

Если вы вставите все это в текст, это ничего не даст, пока вы не добавите эти компоненты в свой код.

Помните, что ваш код будет ломаться, потому что я изменил способ импорта постов. Об этом будет рассказано далее.

export default function Post({ post, posts }) {
  const postsElements = posts.map((post, index) => (
    <Link key={index} href={`/posts/${post.slug}`}>
      <RecentPost>
        <p>{post.title}</p>
        <span>{new Date(post.publishedAt).toDateString().slice(4)}</span>
      </RecentPost>
    </Link>
  ));

  return (
    <PageContainer>

      <Link href={`/`}>
        <BackButton>
          <span>👈</span>
          <a>Home</a>
        </BackButton>
      </Link>

      <ContentContainer>

        <Header>
          <span>{new Date(post.publishedAt).toDateString()}</span>
          <h1>{post.title}</h1>
        </Header>

        <SocialsContainer>
          <StyledLi>
            <a href="https://facebook.com">
              <BsFacebook size={"3rem"} />
            </a>
          </StyledLi>
          <StyledLi>
            <a href="https://twitter.com">
              <BsTwitter size={"3rem"} />
            </a>
          </StyledLi>
          <StyledLi>
            <a href="https://instagram.com">
              <BsInstagram size={"3rem"} />
            </a>
          </StyledLi>
        </SocialsContainer>

        <Body>
          <PortableText content={post.body} />
        </Body>

        <RecentPostsContainer>
          {postsElements}
        </RecentPostsContainer>

      </ContentContainer>

    </PageContainer>
  );
}
Вход в полноэкранный режим Выход из полноэкранного режима

Это довольно просто, мы используем наши стилизованные компоненты, которые мы только что создали, вместо обычных элементов HTML.

Я укажу на пару вещей, на которые важно обратить внимание.

export default function Post({ post, posts })
Вход в полноэкранный режим Выход из полноэкранного режима
  • Вы можете видеть, что теперь мы импортируем post И posts. Через секунду вы увидите, почему.
const postsElements = posts.map((post, index) => (
    <Link key={index} href={`/posts/${post.slug}`}>
      <RecentPost>
        <p>{post.title}</p>
        <span>{new Date(post.publishedAt).toDateString().slice(4)}</span>
      </RecentPost>
    </Link>
  ));
Вход в полноэкранный режим Выход из полноэкранного режима
  • Мы отображаем посты, которые мы получаем, чтобы создать список ссылок на каждый пост (за исключением поста, который мы сейчас просматриваем).
<BsFacebook size={"3rem"} />
Вход в полноэкранный режим Выход из полноэкранного режима
  • Иконки React стилизуются с помощью атрибута size, поэтому мы увеличиваем размер каждой из них до 3rem.
<Body>
    <PortableText content={post.body} />
</Body>
Вход в полноэкранный режим Выход из полноэкранного режима
  • Вы можете видеть, как импортированный нами PortableText используется для отображения body нашего сообщения, добавив его в качестве content.
  • Стиль PortableText надоедает, поэтому я просто окружаю его стилизованным div и применяю стиль там.
<RecentPostsContainer>{postsElements}</RecentPostsContainer>
Вход в полноэкранный режим Выход из полноэкранного режима
  • И наконец, наша переменная postsElements, которую мы создали, окружена стилизованным компонентом.

Реквизиты

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

export async function getStaticProps({ params }) {
  const query = `*[_type == "post"] {
    _id,
    title,
    publishedAt,
    'slug': slug.current,
    body
  }`;

  let posts = await client.fetch(query);

  const post = await posts.find((post) => post.slug == params.slug);

  posts.splice(
    posts.indexOf(posts.find((post) => post.slug == params.slug)),
    1
  );

  return {
    props: { posts, post },
  };
}
Вход в полноэкранный режим Выход из полноэкранного режима

Не так уж много изменилось, но я объясню общую идею.

  • Мы больше не получаем только текущее сообщение, теперь мы получаем каждую запись с типом post.

  • После того, как все посты возвращены, мы запускаем метод find, чтобы найти пост в нашем массиве, который содержит тот же slug, что и наши url-параметры.

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

  • Наконец, мы возвращаем все наши посты, исключая наш текущий пост, и наш текущий пост.


Предварительный просмотр

Код CodeSandbox — полноэкранный предварительный просмотр
Здесь вы можете посмотреть мой код, есть некоторые изменения, чтобы удалить выборку и структура файла явно неправильная. Это должно быть просто ссылкой на то, как страница и код /pages/posts/[slug].js должны выглядеть для вас (за вычетом небольших изменений).

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

Я знаю, что это было много кода, и всегда есть вероятность, что что-то пойдет не так с вашей стороны. Поэтому, если у вас что-то не получается, напишите мне в Twitter, и я помогу вам, чем смогу.


Следующий урок

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

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

Следующие несколько уроков будут менее ориентированы на код и более связаны с использованием Vercel, GitHub и утилит Sanity.
Наша цель состоит в том, чтобы…

  1. Выложить наш код на GitHub.

  2. Развернуть наш сайт на Vercel.

  3. Развернуть наш интерфейс Sanity Studio на Vercel.

Спасибо всем, кто прочитал эти уроки!

Оцените статью
devanswers.ru
Добавить комментарий