OmniRoute — Design System & Visual Identity (Русский)
1. Назначение
Заголовок раздела «1. Назначение»Маркетинговый сайт (viral.omniroute.online, why.omniroute.online, omniroute.online) и дашборд продукта должны выглядеть как единый продукт. Сайт уже заимствовал палитру из дашборда — в его css/tokens.css даже указано: «Палитра соответствует дашборду OmniRoute (src/app/globals.css)». Таким образом, на уровне цветов они уже согласованы примерно на 80%. Чего не хватает дашборду:
- Фона с сеткой в стиле миллиметровой бумаги, который используется на каждой странице сайта.
- Нескольких общих дизайн-токенов, которые есть на сайте, но отсутствуют в дашборде (шкала радиусов, фирменный градиент,
surface-2, моноширинный шрифт). - Согласованности на уровне компонентов — ряд компонентов дашборда обходит токены темы, используя жёстко заданные значения hex/rgba.
Этот документ содержит анализ и план.
2. Принципы
Заголовок раздела «2. Принципы»- Единый источник истины —
src/app/globals.css. Сайт следует за дашбордом, но не наоборот. Новые токены сначала добавляются вglobals.css. - Токены вместо литералов. Компоненты используют семантические токены (
bg-surface,text-primary,border-border), а не необработанные значения#hex. - Ненавязчивость вместо броскости. Сетка — это едва заметный фон позади содержимого; она не должна снижать контрастность текста или отвлекать от интерфейса.
- Поддержка тем. Всё работает как в
.dark(фирменном стиле продукта), так и в светлой теме. - Поэтапное внедрение. Сначала выпускаются сетка и токены (низкий риск, высокая заметность), затем компоненты приводятся в порядок несколькими волнами.
3. Текущее состояние — что уже согласовано, а что ещё нет
Заголовок раздела «3. Текущее состояние — что уже согласовано, а что ещё нет»3.1 Цвета — уже унифицированы ✅
Заголовок раздела «3.1 Цвета — уже унифицированы ✅»Каждый фирменный цвет и цвет поверхности уже соответствует сайту по значению (различаются только имена — в дашборде используется префикс --color-). Проверено в src/app/globals.css:30-128:
| Понятие | Токен сайта (tokens.css) |
Токен дашборда (globals.css) |
Соответствие |
|---|---|---|---|
| основной | --primary #e54d5e |
--color-primary #e54d5e |
✅ |
| основной при наведении | --primary-hover #c93d4e |
--color-primary-hover #c93d4e |
✅ |
| акцентный | --accent #6366f1 |
--color-accent #6366f1 |
✅ |
| акцентный-2 | --accent-2 #8b5cf6 |
--color-accent-hover #8b5cf6 |
✅ (переименован) |
| акцентный-3 | --accent-3 #a855f7 |
--color-accent-light #a855f7 |
✅ (переименован) |
| успех / предупреждение / ошибка | #22c55e / #f59e0b / #ef4444 |
идентичны | ✅ |
| сигналы светофора | #ff5f56 / #ffbd2e / #27c93f |
идентичны | ✅ |
| тёмный фон / поверхность / граница | #0b0e14 / #161b22 / rgba(255,255,255,.08) |
идентичны | ✅ |
| светлый фон / поверхность / текст | #f9f9fb / #fff / #1a1a2e |
идентичны | ✅ |
Вывод: миграция цветов не требуется. Визуальный стиль уже является общим; мы завершаем его унификацию, а не перестраиваем заново.
3.2 Пробелы — чего не хватает дашборду
Заголовок раздела «3.2 Пробелы — чего не хватает дашборду»| Несоответствие | На сайте есть | Панель управления | Действие |
|---|---|---|---|
| Фоновая сетка | body::before в стиле миллиметровки, --grid-line, --grid-size 32px, --section-alt |
✅ добавлено (Этап 1) | Часть A |
| Шкала скруглений | --radius 14px, --radius-sm 9px |
--radius 14px добавлен; -sm и переназначение компонентов ожидаются |
Часть B / Этап 2 |
| Фирменный градиент | --grad-brand 135deg primary→accent-3 |
✅ токен добавлен (Этап 1); будет использован на Этапе 2 | Часть B |
| Вложенная поверхность | --surface-2 #1c2230 |
✅ добавлено (Этап 1) | Часть B |
| Моноширинный шрифт | --font-mono (стек ui-monospace) |
ожидается (Этап 4, вместе с использующими компонентами) | Часть B |
text-muted (тёмная тема) |
#8b8b9e |
#a1a1aa (zinc-400) |
согласовать — Часть B |
3.3 Механика темизации (чтобы ничего не сломать)
Заголовок раздела «3.3 Механика темизации (чтобы ничего не сломать)»- Tailwind v4, подход CSS-first (без
tailwind.config.*). Токены определены в:root/.darkи доступны утилитам через@theme inline(globals.css:130-179). - Тёмная тема через класс
.darkна<html>(@custom-variant darkвglobals.css:22), переключаемый пользовательским хранилищем Zustand (src/store/themeStore.ts); тема по умолчанию =system(src/shared/constants/appConfig.ts:11). Вместо этого сайт используетhtml[data-theme="light"]— механизмы различаются, но никогда не пересекаются (разные источники), поэтому конфликта нет. Сохраняем механизм панели управления на основе.dark. - Есть переопределение основного цвета во время выполнения (
themeStore.ts:85-97, предустановки вCOLOR_THEMES) — пользователи могут менять--color-primary. Любой новый токен (градиент и т. п.), ссылающийся на--color-primary, автоматически наследует эти переопределения. ✅ - Зарезервированные имена радиусов в Tailwind v4:
--radius-sm/md/lg/...лежат в основе утилитrounded-*. Их переопределение задним числом изменит все существующиеrounded-*(например,rounded-smиспользуется в 12 файлах). Поэтому значение малого радиуса и переназначение компонентов намеренно отложены до Этапа 2, где использующие их компоненты будут изменены одновременно.
4. Часть A — Фон в виде сетки миллиметровой бумаги (основная задача) — РЕАЛИЗОВАНО (этап 1)
Заголовок раздела «4. Часть A — Фон в виде сетки миллиметровой бумаги (основная задача) — РЕАЛИЗОВАНО (этап 1)»4.1 Что это такое
Заголовок раздела «4.1 Что это такое»Точный рецепт с сайта (_mono_repo/omnirouteSite/css/base.css): фиксированный псевдоэлемент размером во всю область просмотра, отрисовывающий два градиента с линиями толщиной 1px и расположенный с z-index:-1 позади всего содержимого.
body::before { content: ""; position: fixed; inset: 0; z-index: -1; pointer-events: none; background-image: linear-gradient(to right, var(--grid-line) 1px, transparent 1px), linear-gradient(to bottom, var(--grid-line) 1px, transparent 1px); background-size: var(--grid-size) var(--grid-size);}Почему это работает, несмотря на непрозрачный background-color у body: ::before с z-index:-1 отрисовывается поверх собственного фона элемента, но под его содержимым в потоке. Таким образом, --color-bg служит базовой заливкой, сетка накладывается поверх неё, а приложение отображается над сеткой.
4.2 Уже существующий прецедент в кодовой базе
Заголовок раздела «4.2 Уже существующий прецедент в кодовой базе»src/app/landing/page.tsx:16-26 уже реализует такую же сетку на уровне страницы, но с красными линиями (#E54D5E, непрозрачность 0.06) с шагом 50px, а также с анимированными сферами. Таким образом, этот паттерн уже проверен в продукте; данная работа превращает его в глобальный фон с поддержкой тем.
4.3 Добавленные токены (в globals.css)
Заголовок раздела «4.3 Добавленные токены (в globals.css)»:root { /* светлая тема — непрозрачность сетки увеличена относительно значения 0.045 с сайта, чтобы фон был действительно виден на плотной панели управления (карточки и элементы интерфейса закрывают большую часть области просмотра) */ --grid-line: rgba(0, 0, 0, 0.07); --grid-size: 32px; --section-alt: rgba(0, 0, 0, 0.022);}.dark { /* тёмная тема — значение увеличено относительно 0.035 по той же причине */ --grid-line: rgba(255, 255, 255, 0.06); --section-alt: rgba(255, 255, 255, 0.018);}4.4 Единственное препятствие — устранено
Заголовок раздела «4.4 Единственное препятствие — устранено»Сетка глобальна по своей реализации (она сразу охватывает панель, auth/login, страницы ошибок — все маршруты). Внутри панели её скрывал ровно один элемент:
-
src/shared/components/layouts/DashboardLayout.tsx— внешняя обёртка отрисовывала непрозрачный фонbg-bg. Всё, что находится под ней, уже прозрачно (<main>, контейнер прокрутки и внутренний контейнерmax-w-7xl), поэтому удалениеbg-bgпозволяет сеткеbodyпросвечивать в области содержимого (при этом--color-bgуbodyостаётся базовой заливкой).<div className="flex h-dvh min-h-0 w-full overflow-hidden bg-bg"><div className="flex h-dvh min-h-0 w-full overflow-hidden">
4.5 Взаимодействие с элементами интерфейса (боковая панель / заголовок)
Заголовок раздела «4.5 Взаимодействие с элементами интерфейса (боковая панель / заголовок)»Header(Header.tsx:207,bg-bg) иSidebar(Sidebar.tsx:430,bg-sidebar) остаются непрозрачными → сетка отображается только в области содержимого, обрамлённой сплошными элементами интерфейса. Спокойный вариант по умолчанию, соответствующий тому, как на сайте элементы интерфейса отделены от рабочей области (решение D3 = сплошной фон).
4.6 Страницы входа / аутентификации / ошибок
Заголовок раздела «4.6 Страницы входа / аутентификации / ошибок»Они отображаются непосредственно внутри <body> (без элементов интерфейса панели), поэтому глобальная сетка должна автоматически появляться позади них. Этап 5 — ВЫПОЛНЕН: автономные полноэкранные обёртки действительно были непрозрачными (min-h-screen … bg-bg, где bg-bg — та же сплошная заливка, что и у <body>), из-за чего сетка скрывалась на всех экранах вне панели, а не только на странице входа. Теперь все они прозрачны, поэтому общий фон виден насквозь: login, forgot-password, callback, maintenance, offline, status, terms, privacy, onboarding и ErrorPageScaffold (охватывает 400/401). Это закрывает D4 (область действия расширена со страницы входа на все автономные экраны). Проверяется тестом tests/unit/design-grid-background.test.ts.
4.7 Целевая страница
Заголовок раздела «4.7 Целевая страница»landing/page.tsx сохраняет свой более насыщенный анимированный фон (сферы + виньетка) — собственную маркетинговую заставку (решение D5 = оставить без изменений).
5. Часть B — унификация токенов
Заголовок раздела «5. Часть B — унификация токенов»На этапе 1 добавляются инертные, не вызывающие коллизий идентификационные токены (--surface-2/--color-surface-2, --grad-brand, --radius). На этапе 2 шкала радиусов подключается к Tailwind и компоненты переводятся на неё; на этапе 4 добавляется --font-mono и его потребители.
| Токен | Зачем | Этап |
|---|---|---|
--radius / --radius-sm |
Единая шкала радиусов (14/9) вместо разрозненных 6/8/12 | 1 (значение) / 2 (подключение + перевод) |
--grad-brand |
Фирменный градиент для основных CTA (красный→фиолетовый), соответствующий сайту | 1 (токен) / 2 (Button) |
--surface-2 |
Вложенные панели / заголовки таблиц / внутренние строки | 1 |
--font-mono |
Блоки кода, терминал, ID, эндпоинты | 4 |
Согласование --text-muted |
Выбрать одно значение для сайта и панели (#a1a1aa рекомендуется) |
2 |
D2 (text-muted): сайт — #8b8b9e, дашборд — #a1a1aa. Рекомендуется сохранить значение дашборда #a1a1aa и обновить сайт для соответствия. Косметическое изменение.
6. Часть C — стандартизация компонентов (этапы 2–4)
Заголовок раздела «6. Часть C — стандартизация компонентов (этапы 2–4)»Собственные компоненты (без shadcn/Radix), Tailwind v4, семантические токены в основном внедрены (195 файлов импортируют общий barrel-файл). Задача — устранить обходные решения. Расположение: src/shared/components/.
| # | Элемент | Файл(ы) | Проблема → целевое состояние | Этап |
|---|---|---|---|---|
| C1 | Согласование радиусов | Button.tsx:14-18, Card.tsx:39, Modal.tsx, Input.tsx, Select.tsx |
смесь 6/8/12px → --radius/--radius-sm (14/9) |
2 |
| C2 | Градиент Button + вариант accent |
Button.tsx:5-12 |
основной вариант использует плоский переход красный→красный; привести к --grad-brand; добавить отсутствующий вариант accent. ~195 импортирующих файлов — максимальная заметность |
2 |
| C3 | Таблицы | DataTable.tsx:122-176, logTableStyles.ts, globals.css:405-414 |
полностью встроенные жёстко заданные rgba + несуществующие переменные; перенести на токены, удалить расходящиеся стили | 3 |
| C4 | Централизация цветов статусов | flow/edgeStyles.ts, TokenHealthBadge.tsx, DegradationBadge.tsx, ProviderCascadeNode.tsx, Badge.tsx + 5 вспомогательных модулей |
6+ копий одних и тех же hex-значений → один модуль на основе --color-success/warning/error |
3 |
| C5 | Рамка Card | Card.tsx:39 |
border-white/5 → фирменный цвет /8 |
2 |
| C6 | Согласование фокусного кольца ✅ ГОТОВО | globals.css --focus-ring (accent) и ring-primary/30 у элементов форм |
унифицировано на accent (фиолетовом) для соответствия глобальному кольцу и визуального отличия от красного кольца ошибки; ошибка остаётся красной | 4 |
| C7 | Добавить Checkbox + Textarea |
необработанные <input>/<textarea> со встроенным accentColor:#6366f1 |
примитивы на основе токенов | 4 |
| C8 | Удаление жёстко заданных hex-значений | ConsoleLogViewer.tsx:240, ComboLiveStudio.tsx:306, точки Modal, ~14 файлов диаграмм |
литералы → токены | 4 |
| C9 | cn() → clsx + tailwind-merge |
src/shared/utils/cn.ts |
конфликтующие классы накладываются друг на друга; требуется для переопределений C1 | 2 |
Уже соответствуют фирменному стилю (основаны на токенах, требуется только обновление радиусов): Badge, Toggle, SegmentedControl, Input, Select.
7. План развёртывания
Заголовок раздела «7. План развёртывания»- Фаза 1 — Сетка + токены идентичности (ЭТОТ PR). Сетка в
globals.css+ токены--surface-2/--grad-brand/--radius; фоновое изображениеbody::before; удаление блокирующегоbg-bg; статический защитный тест. Низкий риск, можно откатить одним коммитом. - Фаза 2 — Примитивы (C1, C2, C5) — ВЫПОЛНЕНО в этом PR. Семантические утилиты радиуса
rounded-card(14px) /rounded-control(9px) добавлены через@theme(пользовательские имена, поэтому стандартныеrounded-sm/md/lg/xlостаются без изменений — без массового затрагивания 400 файлов); Card/Modal → 14px, Button/Input/Select → 9px; основной Button →--grad-brand(красный→фиолетовый) + новый вариантaccent; границы Card → токенborder-border(0.08). Отложено: дляcn()→tailwind-merge (C9) нужны новые зависимости; массовая замена нестандартныхrounded-lg(326 файлов) оставлена без изменений, поскольку примитивы охватывают основную часть поверхностей. - Фаза 3 — Цвета статусов + таблицы (C3, C4) — ВЫПОЛНЕНО в этом PR. ✅ C4 (
src/shared/constants/statusColors.ts— единый источникSTATUS_HEX;flow/edgeStyles.ts+TokenHealthBadgeпереведены на него, без изменений/с теми же hex-значениями). ✅ Токен--font-mono. ✅ C3 (DataTable) — все встроенные значения rgba и неработающие резервные значенияvar(--bg-table-header)/var(--text-secondary)заменены набором токенов--table-*(--table-header-bg/-row-zebra/-row-hover/-cell-border/-row-selected), чьи значения для тёмной темы в точности соответствуют старым жёстко заданным rgba (побайтовая идентичность для тёмной темы), а значения для светлой темы исправляют ранее всегда тёмное оформление. Граница заголовка →--color-border, вторичный текст →--color-text-muted. Перед слиянием требуется визуальная проверка. (Не затронуты:logTableStyles.tsи устаревшие правила Ant.ant-table— это отдельная задача с более низким приоритетом.) - Фаза 4 — Очистка (C6, C7, C9 выполнены; C8 ожидает выполнения). ✅ C9
cn()→twMerge(clsx(...))(clsx + tailwind-merge добавлены как зависимости) — теперьclassNameвызывающего кода корректно заменяет конфликтующий класс примитива, а не добавляется поверх него. ✅ C7 новые примитивыCheckbox+Textarea(на основе токенов, экспортируются из barrel-файла; изменение аддитивное — переход 32 обычных чекбоксов / 41 обычного текстового поля можно выполнять постепенно). ✅ C6 согласование кольца фокуса — элементы форм (Input/Select/Textarea/Toggle/Checkbox) теперь при фокусе используют кольцо акцентного (фиолетового) цвета, чтобы соответствовать глобальному--focus-ringи не конфликтовать с красным кольцом ошибки; красное состояние ошибки не изменено. ⏳ C8 — проверка hex-значений НЕ является слепым поиском и заменой — подтверждены случаи, которые являются намеренными и должны остаться:ConsoleLogViewer.tsx:240(терминал всегда с тёмной темой), всплывающее окноTokenHealthBadge, SVG-обводки ReactFlow. Переносить следует только те hex-значения, которые действительно должны учитывать тему.
Для каждой фазы: npm run lint + npm run typecheck:core + визуальная проверка.
8. Открытые решения (рекомендации)
Заголовок раздела «8. Открытые решения (рекомендации)»- D1 — Основной Button: оставить красный→красный или перейти на красный→фиолетовый
--grad-brand? Рекомендация: красный→фиолетовый (Фаза 2). - D2 — Цвет линий сетки: нейтральный (стиль сайта) — выбрано — вместо фирменного красного. Размер 32px (уменьшен примерно на 30% относительно исходных 46px после обратной связи от владельца — ячейки 46px выглядели слишком крупными в макете панели управления).
- D3 — Выразительность chrome-элементов: боковая панель/заголовок сплошные — выбрано.
- D4 — Сетка аутентификации/входа: ✅ ВЫПОЛНЕНО (Фаза 5) — непрозрачный
bg-bgудалён из всех автономных полноэкранных обёрток (не только со страницы входа), поэтому сетка отображается на всех экранах. См. §4.6. - D5 — Посадочная страница: оставить анимированную заставку без изменений. Выбрано.
- D6 — Радиус 14/9 во всём продукте: рекомендация: да (Фаза 2).
- D7 — Фаза 1 выпускается первой: выбрано.
- D8 — Ширина макета (Фаза 5): оболочка содержимого панели управления была ограничена
max-w-7xl(1280px), из-за чего на больших мониторах содержимое центрировалось с широкими пустыми полями по бокам. ✅ ВЫПОЛНЕНО — ограничение увеличено до адаптивногоmax-w-[3840px](настоящие 4K): теперь содержимое следует за шириной области просмотра примерно до 4K и центрируется только за её пределами (DashboardLayout.tsx). Намеренно узкие страницы по-прежнему остаются узкими (ProviderOnboardingWizardmax-w-5xl,Rtk/CavemanContextPageClientmax-w-6xl). - D9 — Непрозрачные таблицы данных (Фаза 6): после того как область содержимого панели управления стала прозрачной (чтобы через неё была видна фоновая сетка, Фаза 5), в таблицах данных, чей контейнер не был непрозрачной поверхностью, сетка просвечивала через прозрачные чётные строки / зебру с низкой альфа-прозрачностью. ✅ ВЫПОЛНЕНО — каждая таблица без Card теперь отрисовывает
bg-surface(или, для примитива<DataTable>,background: var(--color-surface)в контейнере прокрутки). Исправлены:DataTable(примитив),ProxyLogger/RequestLoggerV2(их оттенок<Card>bg-black/5 dark:bg-black/20имел приоритет надbg-surfaceCard из-за tailwind-merge → прозрачность около 95%),BatchListTab/FilesListTab/CacheEntriesTab/ReasoningCacheTab/cache page/FreePoolTab/ModelMappingTable/HeaderTable, а также две CSS-grid-«таблицы» в представлениях кэша (bg-surface/35→bg-surface). Таблицы, уже находящиеся внутри<Card>/Modal, были проверены на непрозрачность и намеренно оставлены без изменений (bg-surfaceтам был бы избыточной пустой операцией). Саму сетку изменять не потребовалось —body::beforeпанели управления побайтово идентичен сайту (--grid-size: 32px); любая «более крупная сетка», видимая в работающем экземпляре, относится к устаревшей сборке до#4143, а не к текущему коду. Контролируется тестомtests/unit/design-grid-background.test.ts(блок Фазы 6).
9. Вне области работ / риски
Заголовок раздела «9. Вне области работ / риски»- Без изменения палитры — цвета уже соответствуют требованиям; мы лишь добавляем недостающие токены. Нулевой риск изменения цветовой схемы продукта.
- Без изменения механизма тем — сохраняем
.dark+ хранилище Zustand. - Изменение радиусов скругления (этап 2) носит масштабный характер — затрагивает каждую карточку, кнопку и поле ввода; перед слиянием визуально проверьте насыщенные элементами экраны (таблицы, модальные окна).
- Таблицы (C3) содержат больше всего жёстко заданных стилей и имеют наибольшую поверхность регрессий — вынесите их в отдельный PR.
10. Справочный указатель
Заголовок раздела «10. Справочный указатель»| Область | Путь |
|---|---|
| Токены панели управления | src/app/globals.css (:root, .dark, @theme inline, body, body::before) |
| Хранилище темы | src/store/themeStore.ts, src/shared/components/ThemeProvider.tsx, src/shared/constants/appConfig.ts:9-11 |
| Оболочка панели (сетка разблокируется здесь) | src/shared/components/layouts/DashboardLayout.tsx |
| Элементы интерфейса | src/shared/components/Header.tsx:207, src/shared/components/Sidebar.tsx:430 |
| Пример реализации сетки | src/app/landing/page.tsx:16-26 |
| Примитивы | src/shared/components/{Button,Card,Input,Select,Badge,Modal,Toggle,SegmentedControl,Loading,Tooltip,DataTable}.tsx |
| Источники цветов статусов | flow/edgeStyles.ts, TokenHealthBadge.tsx, DegradationBadge.tsx, logTableStyles.ts |
Утилита cn |
src/shared/utils/cn.ts |
| Защитный тест этапа 1 | tests/unit/design-grid-background.test.ts |
| Эталон сайта | _mono_repo/omnirouteSite/css/tokens.css, css/base.css |
HagiCode
HagiCode — агентная среда разработки со структурированными процессами, параллельным выполнением несколькими агентами и интерфейсами Hero Dungeon.
Превращайте идеи в полезное ПО с более умным, быстрым и увлекательным агентным рабочим процессом.

- SmartСтруктурированные процессы превращают намерение в исполнимый путь от идеи до готового изменения.
- EfficientМультиагентные процессы параллельно продвигают исследование, реализацию и проверку.
- FunHero Dungeon делает длительную совместную разработку наглядной и увлекательной.