Landing Portfolio
Личный сайт — портфольный архетип и самая короткая готовая страница: семь секций, потому что у одного человека нет тарифов и команды — есть работы, тексты и почта; краткость и есть дизайн-решение. В сокете hero — тихая интерференция iridescence, витрина — showcase-gallery, журнал — blog-index со снимком за курсором.
Установка
npx shadcn@latest add https://motiva.pages.dev/r/landing-portfolio.jsonЧто нужно в проекте до установки
Файл
components.jsonв корнеИз него CLI узнаёт, куда класть файлы. Алиасы — в такой форме:
"aliases": { "components": "@/components", "lib": "@/lib" }Нет файла — установка не начнётся вовсе.
Алиас
@объявлен дваждыВ корневом
tsconfig.jsonи в конфиге сборщика. В Vite корневой tsconfig часто содержит толькоreferences— этого мало."paths": { "@/*": ["./src/*"] } // tsconfig.json resolve.alias = { "@": "/src" } // vite.config.tsБез
pathsCLI молча создаёт папку с именем@.Токены подключены один раз на приложение
Они приезжают вместе с записью — достаточно импортировать их в точке входа:
import "@/styles/motiva-tokens.css";Без них блок потеряет цвета, ритм и тему.
Своя типографика не спорит с блоком
Наследуемые свойства протекают внутрь:
text-align: centerна обёртке отцентрует содержимое секции. То же касаетсяfont-familyиline-height.Проект без TypeScript? всё равно нужен tsconfig
CLI грузит
tsconfig.jsonбезусловно, а при"tsx": falseидёт заjsconfig.jsonи падает так же. Минимум — файл сpathsи"tsx": trueвcomponents.json.Приехавший рядом
.tsxможно не трогать — вам нужен.vanilla.js.
Экспорт
Код
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>
);
}