Как я создал блог и личный сайт на Next.js (Бесплатный хостинг!)

Cover Image for Как я создал блог и личный сайт на Next.js (Бесплатный хостинг!)

Привет! Я решил создать свой блог и личную страницу. Для блога использовал готовый шаблон, который адаптировал под себя, а личную страницу сверстал с нуля. В этой статье расскажу, как выбирал шаблон, дорабатывал его, придумывал дизайн и верстал сайт. Если ты тоже хочешь сделать что-то похожее, возможно, здесь найдешь полезные идеи.

Screenshot Website

Screenshot Website

Выбор шаблона:

Когда я начал работать над блогом, понял, что писать его с нуля — слишком долго. Поэтому решил поискать готовые шаблоны для Next.js. У них есть целый каталог с решениями для блогов, интернет-магазинов, личных страниц и даже сайтов AI-стартапов.

Screenshot Next.js

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

Моя цель — бесплатный блог без затрат на инфраструктуру. Поэтому я выбрал шаблон с статической генерацией Next.js и Markdown-файлами в качестве источника данных. Такой подход позволяет легко добавлять новые статьи и при этом не платить за сервер.

Установка проекта:

Для начала нужно создать проект с помощью командной строки:

npx create-next-app --example blog-starter blog-starter-app

После этого достаточно заменить статьи из шаблона на свои.

Screenshot code

Осталось лишь настроить GitHub Pages для репозитория и привязать CNAME к нужному домену.

Дизайн личной страницы:

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

В Figma Community есть множество бесплатных и платных шаблонов, которые можно использовать в своих проектах. Главное — учитывать лицензию. Я искал варианты Free to use, но в итоге просто вдохновился готовыми решениями и создал свой собственный дизайн.

Screenshot Figma

Верстка и реализация:

Для верстки я использовал Next.js и Tailwind CSS.

  • Next.js отлично подошел, так как я встроил личную страницу в уже готовый шаблон блога.
  • Tailwind CSS выбрал за его удобство: он позволяет быстро стилизовать элементы прямо в коде, без написания отдельных CSS-файлов. Это ускоряет процесс разработки.

Благодаря такому подходу реализация заняла минимум времени.

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

const Header: React.FC<{ opacity?: boolean }> = ({ opacity }) => {
  const { asPath, locale } = useRouter();
  const { t } = useTranslation();

  return (
    <>
      <header
        className={cn(
          "sticky top-0 w-full specm:h-[54px] h-[36px] z-10 font-montserrat font-semibold text-[14px] flex items-center border-b border-neutral-200",
          opacity ? "bg-[#ffffff99]" : "bg-white"
        )}
      >
        <SpecContainer className="flex justify-between">
          <Link href="/" locale={locale} className="font-[arial-black]">
            PROGOSLING
          </Link>
          <div className="flex specm:gap-[40px] gap-[10px]">
            <Link
              href="/"
              locale={locale}
              aria-disabled={asPath === "/"}
              className="aria-disabled:opacity-50 aria-disabled:pointer-events-none hover:underline"
            >
              {t("common:header.home")}
            </Link>
            <Link
              href="/blog"
              locale={locale}
              aria-disabled={asPath === "/blog"}
              className="aria-disabled:opacity-50 aria-disabled:pointer-events-none hover:underline"
            >
              {t("common:header.blog")}
            </Link>
            <Link locale={locale} href="/#projects" className="hover:underline">
              {t("common:header.projects")}
            </Link>
          </div>
          <div className="specm:block hidden" />
        </SpecContainer>
      </header>
      <div className="bg-[#381DDB] font-raleway font-bold text-[12px] text-white">
        <SpecContainer className="flex justify-between items-center">
          <nav className="flex gap-2 items-center">
            {locales.map(({ id, name }, i) => (
              <React.Fragment key={id}>
                {i > 0 && <span>•</span>}
                <Link
                  href={asPath}
                  locale={id}
                  aria-disabled={locale === id}
                  className="block py-[6px] aria-disabled:opacity-50 aria-disabled:pointer-events-none"
                >
                  {name}
                </Link>
              </React.Fragment>
            ))}
          </nav>
          <ul className="flex specm:gap-2">
            {social.map(({ element, id }) => (
              <li key={id}>{element}</li>
            ))}
          </ul>
          <a href="mailto:[email protected]" className="group">
            {email}
          </a>
        </SpecContainer>
      </div>
    </>
  );
};

А вот так — основная страница:

export default function Index({
  allPosts,
  postsCount,
}: {
  allPosts: Post[];
  postsCount: number;
}) {
  const { locale } = useRouter();
  const { t } = useTranslation();

  return (
    <Layout
      title={t("index-page:meta.title")}
      description={t("index-page:meta.description")}
      header={<Header />}
    >
      <div className="mt-[3rem]" />
      <Main />
      <div className="w-full specl:my-[6.25rem] specm:my-[5rem] my-[40px] border-b border-neutral-200" />
      <AboutMe />
      <LastProjects />
      <Blog allPosts={allPosts} postsCount={postsCount} />
    </Layout>
  );
}

Итоги:

В итоге получилось:

Блог — работает на статической генерации, без бэкенда и БД.
Личная страница — интегрирована в проект и адаптирована под мой стиль.
Хостинг — полностью бесплатный (GitHub Pages).

Теперь можно добавлять контент и развивать проект дальше.

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