Landing Devtool
Лендинг CLI-инструмента — инженерный архетип: установка одной командой сразу после hero (разработчик пришёл ставить, а не читать), спецификации цифрами, ролик с главами вместо длинного текста, честное сравнение с grep и IDE. Терминальная зелень на сетке лучей; две новые секции встали в страницу в день рождения.
Установка
npx shadcn@latest add https://motiva.pages.dev/r/landing-devtool.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 { NavSticky } from "@/components/nav-sticky";
import { HeroCentered } from "@/components/hero-centered";
import { GridBeams } from "@/components/grid-beams";
import { DownloadCli } from "@/components/download-cli";
import { SpecsGrid } from "@/components/specs-grid";
import { FeaturesColumns } from "@/components/features-columns";
import { VideoChapters } from "@/components/video-chapters";
import { ComparisonTable } from "@/components/comparison-table";
import { FaqAccordion } from "@/components/faq-accordion";
import { CtaSplit } from "@/components/cta-split";
import { FooterMinimal } from "@/components/footer-minimal";
/**
* Лендинг CLI-инструмента — «инженерный» архетип: установка одной командой
* СРАЗУ после hero (разработчик пришёл ставить, а не читать), спецификации
* цифрами, ролик с главами вместо длинного текста. Две новые секции
* (download-cli и video-chapters) встали в страницу в день рождения.
*
* Характер — терминальная зелень (--ds-accent-h: 150) на сетке лучей в hero:
* дев-инструменту идёт машинная эстетика, а не маркетинговый глянец.
*/
export function LandingDevtool() {
return (
<div
className="ldt ds-scope"
style={{
textAlign: "start",
["--ds-accent-h" as string]: "150",
["--ds-section-y" as string]: "clamp(44px, 6vw, 84px)",
background: "var(--ds-bg, oklch(0.14 0.02 275))",
}}
>
<NavSticky brand="grep2" links={["Установка", "Возможности", "Сравнение", "Доки"]} cta="Поставить" />
<HeroCentered
badge="поиск по коду · открытый код"
title="Ищет по миллиону строк быстрее, чем вы моргаете"
accentWords={4}
sub="grep2 — поиск по коду с пониманием синтаксиса: находит символы, а не подстроки. Один бинарник, ноль конфигурации."
primary="Поставить за минуту"
secondary="Смотреть на деле"
note="macOS · Linux · Windows"
background={<GridBeams />}
tone="dark"
/>
<DownloadCli
eyebrow="установка"
title="Одна команда — и в деле"
sub="Выберите свой менеджер. Обновления приедут тем же путём."
managers={[
{ name: "brew", command: "brew install grep2" },
{ name: "winget", command: "winget install grep2" },
{ name: "apt", command: "sudo apt install grep2" },
{ name: "cargo", command: "cargo install grep2" },
]}
altText="Не любите менеджеры?"
altLabel="Бинарники и исходники"
/>
<SpecsGrid
eyebrow="цифры"
title="Скорость — это спецификация"
items={[
{ value: "38", unit: "мс", label: "поиск по монорепе на миллион строк" },
{ value: "1", unit: "файл", label: "бинарник без зависимостей" },
{ value: "9", unit: "МБ", label: "вес установки" },
{ value: "40", unit: "языков", label: "синтаксис из коробки" },
]}
/>
<FeaturesColumns
eyebrow="возможности"
title="Три вещи, которые он делает лучше всех"
numbered
items={[
{ title: "Символы, не подстроки", text: "Ищет определения и использования: «где объявлена useCart» вместо тысячи совпадений по слову cart." },
{ title: "Понимает гит", text: "Игнорирует то же, что и репозиторий, ищет по правкам и веткам: «где это менялось за неделю»." },
{ title: "Отдаёт машине", text: "Вывод в JSON одной опцией — редакторы, скрипты и агенты читают без парсинга человеческого текста." },
]}
/>
<VideoChapters
eyebrow="на деле"
title="Пятнадцать секунд работы"
sub="Кликните главу — ролик перемотается к нужному приёму."
chapters={[
{ at: "0:00", title: "Холодный старт", note: "Первый поиск сразу после установки" },
{ at: "0:04", title: "Поиск символа", note: "Определение против использований" },
{ at: "0:09", title: "Фильтр по гиту", note: "Только то, что менялось в ветке" },
{ at: "0:13", title: "JSON-вывод", note: "Отдаём результат скрипту" },
]}
/>
<ComparisonTable
eyebrow="сравнение"
title="Против классики"
sub="Классика прекрасна. Мы просто про другую задачу."
columns={[
{ name: "grep", note: "эталон" },
{ name: "grep2", note: "этот инструмент", featured: true },
{ name: "IDE-поиск", note: "в редакторе" },
]}
rows={[
{ label: "Понимает синтаксис", cells: [false, true, true] },
{ label: "Работает в пайпах", cells: [true, true, false] },
{ label: "Скорость на монорепе", cells: ["секунды", "38 мс", "после индексации"] },
{ label: "Вне своего редактора", cells: [true, true, false] },
{ label: "JSON для машин", cells: [false, true, false] },
]}
note="Сравнивали на публичной монорепе в 1,1 млн строк; методика в доках."
/>
<FaqAccordion
eyebrow="вопросы"
title="Спрашивают перед установкой"
items={[
{ q: "Это замена grep?", a: "Нет, дополнение: для подстрок grep быстрее и везде есть. grep2 — когда нужен смысл: символы, области видимости, правки." },
{ q: "Нужна ли индексация?", a: "Нет. Разбор ленивый, кеш прогревается первым запросом и живёт рядом с репозиторием." },
{ q: "Что с приватностью?", a: "Инструмент офлайновый: ни телеметрии, ни сети. Проверяемо — код открыт." },
{ q: "Мой язык поддержан?", a: "Сорок языков из коробки; свой добавляется грамматикой tree-sitter за вечер." },
]}
/>
<CtaSplit
title="Поставьте — и попробуйте на своём коде"
sub="Одна команда, девять мегабайт. Если не приживётся — удалить так же просто."
primary="brew install grep2"
secondary="Читать доки"
/>
<FooterMinimal
brand="grep2"
tagline="Поиск по коду с пониманием синтаксиса"
columns={[
{ title: "Продукт", links: ["Установка", "Возможности", "Изменения", "Дорожная карта"] },
{ title: "Разработчикам", links: ["Документация", "Грамматики", "JSON-схема", "GitHub"] },
{ title: "Сообщество", links: ["Обсуждения", "Багтрекер", "hello@grep2.dev"] },
]}
/>
</div>
);
}