Motiva
Мои коллекции
← каталог

Landing Portfolio

Личный сайт — портфольный архетип и самая короткая готовая страница: семь секций, потому что у одного человека нет тарифов и команды — есть работы, тексты и почта; краткость и есть дизайн-решение. В сокете hero — тихая интерференция iridescence, витрина — showcase-gallery, журнал — blog-index со снимком за курсором.

cssoglloadscrollrevealbasic~12 КБreduced-motion ✓
↗
↕ демо длиннее кадра — прокрутите его

Установка

npx shadcn@latest add https://motiva.pages.dev/r/landing-portfolio.json
Что нужно в проекте до установки
  1. Файл components.json в корне

    Из него CLI узнаёт, куда класть файлы. Алиасы — в такой форме:

    "aliases": { "components": "@/components", "lib": "@/lib" }

    Нет файла — установка не начнётся вовсе.

  2. Алиас @ объявлен дважды

    В корневом tsconfig.json и в конфиге сборщика. В Vite корневой tsconfig часто содержит только references — этого мало.

    "paths": { "@/*": ["./src/*"] }        // tsconfig.json
    resolve.alias = { "@": "/src" }        // vite.config.ts

    Без paths CLI молча создаёт папку с именем @.

  3. Токены подключены один раз на приложение

    Они приезжают вместе с записью — достаточно импортировать их в точке входа:

    import "@/styles/motiva-tokens.css";

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

  4. Своя типографика не спорит с блоком

    Наследуемые свойства протекают внутрь: text-align: center на обёртке отцентрует содержимое секции. То же касается font-familyи line-height.

  5. Проект без TypeScript? всё равно нужен tsconfig

    CLI грузит tsconfig.json безусловно, а при "tsx": false идёт за jsconfig.json и падает так же. Минимум — файл с pathsи "tsx": true в components.json.

    Приехавший рядом .tsx можно не трогать — вам нужен .vanilla.js.

Экспорт

↓ Скачать .zip

Код

import { NavBlend } from "@/components/nav-blend";
import { HeroCentered } from "@/components/hero-centered";
import { Iridescence } from "@/components/iridescence";
import { ShowcaseGallery } from "@/components/showcase-gallery";
import { StatsBand } from "@/components/stats-band";
import { BlogIndex } from "@/components/blog-index";
import { ContactSplit } from "@/components/contact-split";
import { FooterMinimal } from "@/components/footer-minimal";

/**
 * Личный сайт — «портфольный» архетип и самая КОРОТКАЯ готовая страница: семь
 * секций, потому что у одного человека нет тарифов, команды и сравнений — есть
 * работы, тексты и почта. Краткость здесь и есть дизайн-решение.
 *
 * В сокете hero — интерференция тонкой плёнки (iridescence): переливчатая, но
 * тихая — личному сайту нужен характер, а не аттракцион. Витрина — showcase-gallery
 * с наездом кадра по ховеру; журнал — blog-index со снимком за курсором.
 */
export function LandingPortfolio() {
  return (
    <div
      className="lpf ds-scope"
      style={{
        textAlign: "start",
        ["--ds-accent-h" as string]: "330",
        ["--ds-section-y" as string]: "clamp(48px, 7vw, 96px)",
        background: "var(--ds-bg, oklch(0.14 0.02 275))",
      }}
    >
      <NavBlend brand="m.major" links={["Работы", "Заметки", "Контакт"]} cta="Написать" />

      <HeroCentered
        badge="дизайнер и разработчик"
        title="Делаю интерфейсы, которые приятно трогать"
        accentWords={3}
        sub="Десять лет собираю продукты руками: от прототипа до продакшена. Беру один проект за раз — поэтому дохожу до конца."
        primary="Посмотреть работы"
        secondary="Написать мне"
        note="свободна с ноября"
        background={<Iridescence purity={0.5} speed={0.25} />}
        tone="dark"
        scrim={0.62}
      />

      <ShowcaseGallery
        eyebrow="работы"
        title="Шесть проектов, за которые отвечаю"
        items={[
          { src: "https://motiva.pages.dev/img/1016-900x675.jpg", title: "Nordwind", tag: "продукт · 2026", wide: true },
          { src: "https://motiva.pages.dev/img/1043-900x675.jpg", title: "Kernel", tag: "дизайн-система" },
          { src: "https://motiva.pages.dev/img/1057-900x675.jpg", title: "Luma", tag: "моушен" },
          { src: "https://motiva.pages.dev/img/1067-900x675.jpg", title: "Vertex", tag: "веб-приложение", wide: true },
          { src: "https://motiva.pages.dev/img/1074-900x675.jpg", title: "Okapi", tag: "айдентика" },
          { src: "https://motiva.pages.dev/img/1080-900x675.jpg", title: "Solaris", tag: "лендинг" },
        ]}
      />

      <StatsBand
        items={[
          { value: 10, label: "лет в ремесле" },
          { value: 34, label: "запущенных проекта" },
          { value: 6, label: "продуктов живут годами" },
          { value: 1, label: "проект за раз" },
        ]}
      />

      <BlogIndex
        eyebrow="заметки"
        title="Пишу, когда есть что сказать"
        items={[
          { title: "Почему я больше не делаю «вау» без замера", tag: "практика", date: "20.08", image: "https://motiva.pages.dev/img/1015-600x800.jpg" },
          { title: "Один проект за раз: экономика фокуса", tag: "процесс", date: "07.07", image: "https://motiva.pages.dev/img/1019-600x750.jpg" },
          { title: "Интерфейс на ощупь: чек-лист отклика", tag: "практика", date: "11.06", image: "https://motiva.pages.dev/img/1021-600x750.jpg" },
        ]}
      />

      <ContactSplit
        eyebrow="контакт"
        title="Расскажите, что делаете"
        sub="Отвечаю лично и быстро. Если проект не возьму — скажу сразу и посоветую коллег."
        contacts={[
          { label: "почта", value: "hi@mmajor.dev", href: "mailto:hi@mmajor.dev" },
          { label: "телеграм", value: "@m_major", href: "#" },
          { label: "часовой пояс", value: "UTC+1, Лиссабон" },
        ]}
      />

      <FooterMinimal
        brand="m.major"
        tagline="Интерфейсы, которые приятно трогать"
        columns={[
          { title: "Сайт", links: ["Работы", "Заметки", "Контакт"] },
          { title: "Ещё", links: ["Резюме PDF", "Гитхаб", "Фигма-комьюнити"] },
        ]}
      />
    </div>
  );
}
лицензия: MITавтор: Motivaисточник: оригинал (Motiva)v1.0.0