309 lines
41 KiB
Markdown
309 lines
41 KiB
Markdown
# KT AI Design System v3.0 «Mono» (токены v5)
|
||
|
||
Канон дизайн-системы KT AI. v3.0 от 2026-06-21 – визуальный язык в духе ElevenLabs: **light-first**, тёплый near-white фон, **near-black primary-кнопка** (в dark инвертируется в near-white), плоские поверхности на hairline-границах и шёпот-тенях, крупные жирные тёмные заголовки, цвет – только функциональный (статусы, чарты, единичная AI-искра орба Төре). Синий **демотирован** в ссылки/фокус/идентичность KT, перестал быть цветом primary-действия. Геометрия и Attio-детали (rounded-rect теги, frameless-таблицы с горизонтальными разделителями рядов — без вертикальных колонок-сепараторов, property-rows) сохранены; aurora-свечение карточек и тяжёлые AI-ореолы убраны. История: CHANGELOG.md. Анатомия shell/таблиц/рядов: COMPONENTS.md. Продуктовый контракт прототипа: PRODUCT_CONTRACT.md.
|
||
|
||
Файлы:
|
||
|
||
| Файл | Роль |
|
||
|---|---|
|
||
| `tokens.json` | ЕДИНСТВЕННЫЙ источник значений токенов. Правки только здесь |
|
||
| `scripts/build_tokens.py` | генератор: tokens.css, print.css, figma-variables.json, tailwind-preset |
|
||
| `kt-ai-tokens.css` | AUTOGENERATED: переменные, обе темы, @layer kt-tokens |
|
||
| `kt-ai-print.css` | AUTOGENERATED: @media print (light, A4, скрытие shell) |
|
||
| `figma-variables.json` | AUTOGENERATED: импорт в Figma Variables (dark/light) |
|
||
| `kt-ai-tailwind-preset.cjs` | AUTOGENERATED: preset для Next.js/kt-ai-shadcn |
|
||
| `kt-ai-components.css` | компоненты v2 на токенах, имена классов совместимы с v1 |
|
||
| `COMPONENTS.md` | нормативная анатомия shell, таблиц, рядов, тулбаров (перенос из v1-архива) |
|
||
| `showcase.html` | живая галерея всех компонентов с переключателем тем – открыть в браузере |
|
||
| `icons/kt-ai-lucide-sprite.svg` | локальный monochrome Lucide-sprite |
|
||
| `COMPONENTS.md` | правила компоновки экрана (активно) |
|
||
| `ELEVENLABS_DESIGN.md` | эталон эстетики/плотности/деталей (язык ElevenLabs) |
|
||
| `archive/` | замороженный v1 (kt_design_system, DESIGN_v1_archive, kt_ai_terminal_tokens.css, kt_ai_terminal_routes, kt_ai_atomic_product_system) – только история, вынесен в `08_Дизайн-система_история/archive/` |
|
||
|
||
Брендовые ассеты: `03_База знаний/Логотипы и бренд/` (ktai.svg, kt-logo.svg).
|
||
|
||
## Принципы
|
||
|
||
Полный контракт UX-принципов (Нильсен, гештальт, законы взаимодействия): `PRINCIPLES.md`. Единый чек-лист «прошло или нет» (Definition of Done, прогонять при любом изменении UI): `CHECKLIST.md`. Оба обязательны при проектировании.
|
||
|
||
1. Плотный операционный интерфейс: первый экран – рабочая поверхность, не лендинг.
|
||
2. Плоские поверхности на hairline-границах: в light – лёгкая тень (`card-shadow`/`shadow-sm`) + рамка, в dark – рамка без тени. Полновесные тени – только у overlay (modal, drawer, dropdown, command, toast). Никаких декоративных свечений/градиентов в контенте. Blur – только на sticky-хроме (топбар `bg-glass`) и overlay.
|
||
3. Тихие границы, приглушённые метаданные, один primary-акцент на экран.
|
||
4. **Mono-доминанта.** Primary-действие – монохром: `primary` = near-black (light) / near-white (dark), белый/тёмный текст. Синий (`link`, `focus`, `brand-blue`) – ссылки, фокус и идентичность KT, **не** заливка кнопок. AI-градиент (`ai-gradient`) – единичная сдержанная искра только на орбе Төре, send-кнопке и кромке prompt-bar в фокусе; тяжёлые ореолы и aurora-свечение карточек убраны. Остальные цвета – только статусы, чипы и графики.
|
||
5. Геометрия компонентов не зависит от темы: темы меняют только цвет.
|
||
6. Никаких сырых hex в продуктовом CSS – только semantic-токены.
|
||
|
||
## Архитектура токенов
|
||
|
||
Три уровня, имена v1 (`--kt-ai-*`) полностью сохранены – старые продукты работают без правок.
|
||
|
||
1. **Primitives** (`--kt-blue-500`, `--kt-gray-900`, `--kt-green-a22`...) – сырая палитра и шкалы. В продуктах напрямую НЕ используются.
|
||
2. **Semantic** – смысловые роли, переключаются темой:
|
||
- поверхности: `--kt-ai-bg`, `-bg-soft`, `-bg-elevated`, `-bg-sunken`;
|
||
- state-слои: `-bg-hover`, `-bg-active`, `-selection`;
|
||
- текст: `-fg`, `-fg-muted`, `-fg-faint`, `-fg-on-fill`;
|
||
- границы: `-border`, `-border-strong`, `-divider`;
|
||
- интерактив: `-primary`, `-primary-hover`, `-primary-subtle`, `-link`, `-danger`, `-danger-hover`;
|
||
- фокус: `-focus-ring`, `-focus-shadow`;
|
||
- статусы/чипы/чарты: как в v1;
|
||
- тени: `-shadow-sm/md/lg/xl`.
|
||
3. **Component** – размеры контролов: `--kt-ai-control-h-sm/md/lg` (28/32/40), layout-переменные v1.
|
||
|
||
Тема-независимые шкалы (в `:root`):
|
||
|
||
- **Spacing** `--kt-ai-space-1..12`: 2, 4, 6, 8, 12, 16, 20, 24, 32, 40, 48, 64. Всё на 4px-сетке, плотный низ шкалы.
|
||
- **Типографика** `--kt-ai-text-2xs..3xl`: 11, 12, 13, 14, 15, 18, 26, 32. Body = 13px (`text-sm`). Веса 400/500/600/700. Числа – JetBrains Mono с `tabular-nums`.
|
||
- **Трекинг зависит от размера** (не одно значение на всё): крупные заголовки — отрицательный (`-.02em` дисплей, `-.01em` H1/H2), body — около `0`. Тесним заголовки, body оставляем нейтральным.
|
||
- **Leading обратно размеру:** плотный на крупных заголовках (`leading-tight` 1.25), свободнее на body (`leading-normal` 1.5). Иерархия строится связкой вес+размер+leading, а не размером одним.
|
||
- **Радиусы** (значения — в `tokens.json`, `scales.radius`): xs, sm, md, tag, lg, xl, 2xl, 3xl, full. Nav-ряды lg; кнопки/инпуты xl; карточки, modal, command, prompt-bar – 3xl; теги/статусы – tag (rounded-rect, не pill).
|
||
- **Моушн** `--kt-ai-dur-fast/base/slow/slower` (100/160/240/400ms), easing standard/enter/exit. `prefers-reduced-motion` обнуляет длительности автоматически.
|
||
- **Z-index**: sticky 20, dropdown 30, drawer 40, modal 50, toast 60, tooltip 70.
|
||
|
||
## Темы
|
||
|
||
Light – дефолт (`:root`, `data-theme="light"` или `kt-ai-terminal-light`): тёплый near-white, near-black primary – основной офисный вид (v3 «Mono», light-first). Dark – полноправный паритетный вариант (`data-theme="dark"` или `kt-ai-terminal`): near-black фон, primary инвертируется в near-white. `data-theme="auto"` следует за системной темой.
|
||
|
||
Правила паритета:
|
||
|
||
- каждый semantic-токен определён в обеих темах; добавил токен в dark – обязан добавить в light;
|
||
- интерактивный синий: dark `#4b9ce2`, light `#0077c8` (AA-контраст на своих фонах); фирменный KT blue `#0096d7` общий;
|
||
- статусные пары построены зеркально: в dark светлый текст на прозрачной подложке, в light тёмный текст на прозрачной подложке;
|
||
- проверка паритета – переключателем в `showcase.html`, это обязательный QA-шаг.
|
||
|
||
## Компоненты (kt-ai-components.css)
|
||
|
||
Имена классов v1 сохранены (`.kt-ai-card`, `.kt-ai-row`, `.kt-ai-chip`, `.kt-ai-nav-item`, `.kt-ai-table*`, `.kt-ai-search`, `.kt-ai-kbd`, `.kt-ai-icon-button`, `.kt-ai-segmented`...). Новое в v2:
|
||
|
||
- **Кнопки** `.kt-ai-btn`: варианты `data-variant="primary|ghost|danger"` (без атрибута – вторичная), размеры `data-size="sm|lg"`. Один primary на экран.
|
||
- **Формы**: `.kt-ai-field` (label + контрол + hint/error), `.kt-ai-input`, `.kt-ai-select`, `.kt-ai-textarea`, `data-invalid="true"`, `.kt-ai-checkbox`, `.kt-ai-switch`. Фокус: border primary + `--kt-ai-focus-shadow`.
|
||
- **Tabs** `.kt-ai-tabs/.kt-ai-tab` (`data-active`), сегменты как в v1.
|
||
- **Banner** `.kt-ai-banner data-tone="info|warn|risk|ok"` – строчные предупреждения в контенте.
|
||
- **Modal** `.kt-ai-modal-overlay/.kt-ai-modal` – bg-elevated, radius-2xl, shadow-xl, анимация rise.
|
||
- **Toast** `.kt-ai-toast-stack/.kt-ai-toast data-tone` – нижний правый угол, точка-индикатор тона.
|
||
- **Tooltip** `.kt-ai-tooltip[data-tip]` – чистый CSS.
|
||
- **Skeleton** `.kt-ai-skeleton` (shimmer), **Empty** `.kt-ai-empty` (иконка + title + действие).
|
||
- **KPI** `.kt-ai-kpi-strip/.kt-ai-kpi` – тихая метрик-полоса, не карточки.
|
||
- **Avatar**, `.kt-ai-divider`, `.kt-ai-status-pill` с точкой-индикатором.
|
||
- **Drawer** `.kt-ai-drawer` – правая панель деталей (правило: детали в drawer, не на новой странице).
|
||
- **Документ-артефакт** `.kt-ai-doc` / `.kt-ai-doc-list` – карточка выходного документа (иконка + имя + статус/формат + кнопка «Скачать»). То, что продукт ПРОИЗВОДИТ (ТС, отчёт, СЗ), показывается как скачиваемый документ — в drawer (секция «Документы» из `_docs` строки) и в nav-секции-коллекции (`nav.view="documents"`, фильтр по `docType`). Контракт: `table.rows[]._docs`.
|
||
|
||
Новое в v2.3 «Aurora × Attio»:
|
||
|
||
- **Карточки** – `card-bg/card-border/card-shadow` токены: в dark – hairline-рамка + фиолетовое aurora-свечение из угла (`data-glow="strong"` – усиленный hero-вариант с двойным свечением), в light – белая поверхность с тенью без рамки. Радиус — `radius-3xl`.
|
||
- **Кнопки (Attio)** – secondary: поверхность bg-elevated + рамка + shadow-sm, радиус 8; ghost/danger без поверхности.
|
||
- **Теги (Attio)** – chip/status-pill/filter-chip: rounded-rect `radius-tag` (5px), не pill.
|
||
- **Таблицы (ElevenLabs)** – дефолт frameless full-bleed: hairline под шапкой и между рядами, **без вертикальных колонок-сепараторов** (тихо, воздушно), заголовки sentence-case 12px medium muted; контейнерный вариант – `data-framed="true"`. Для стабильности ширин при фильтрации фильтруемым таблицам задаётся `table-layout:fixed` + colgroup.
|
||
- **Property-row** `.kt-ai-prop` (`.k` – иконка+метка 148px, `.v` – значение, `data-empty`) – детали объекта в drawer/карточке.
|
||
- **AI-aurora** – токены `ai-accent`, `ai-gradient` (синий → фиолет): градиентная кромка prompt-bar в фокусе + ореол, градиентные send-кнопка и streaming-каретка, орб-атрибуция вместо ✦, `.kt-ai-btn[data-ai="true"]` – точка входа AI. Градиент НЕ используется вне AI-моментов.
|
||
- **Тихая ссылка** `.kt-ai-link[data-arrow]` – «Подробнее →», стрелка сдвигается на hover.
|
||
- **Dot-grid** текстура на `.kt-ai-empty`. Mono-голос: label, cmd-group, время уведомлений, ключи filter-chips. Активный таб – синий. Трекинг заголовков -.02em/-.01em. Sidebar-ряды 26px.
|
||
|
||
Новое в v2.2:
|
||
|
||
- **Topbar** `.kt-ai-topbar` – канонический glass-хром: sticky, `bg-glass` + blur(8). Blur разрешён только здесь и на overlay.
|
||
- **AI-диалог**: `.kt-ai-chat` + `.kt-ai-msg data-role="user|assistant"` (ассистент – полная ширина без пузыря, пользователь – пузырь bg-soft ≤76%), `data-streaming="true"` – каретка; `.kt-ai-prompt-bar` (autogrow textarea + `.kt-ai-prompt-send`, `data-busy`), `.kt-ai-suggestions/.kt-ai-suggestion` – стартовые подсказки, `.kt-ai-source-pill` – ссылка-источник в ответе, `.kt-ai-gen-label` – атрибуция «Сгенерировано ИИ» (обязательна для AI-контента).
|
||
- **Menu** `.kt-ai-menu-anchor > .kt-ai-menu[data-open]` – dropdown действий (kebab в рядах таблиц): `.item` (`data-danger`), `.sep`.
|
||
- **Command palette** – достроена: `.kt-ai-command-overlay`, `.cmd-input`, `.cmd-list`, `.cmd-group`, `.cmd-item[data-active]`, `.cmd-empty`.
|
||
- **Filter-chips** `.kt-ai-filterbar` + `.kt-ai-filter-chip` (`.k` – имя фильтра, `.remove`) + `.clear-all` – применённые фильтры над таблицей.
|
||
- **Radio** `.kt-ai-radio`, `.kt-ai-radio-group`.
|
||
- **Toast**: `.action` (undo-ссылка) и `.close`.
|
||
- **Popover** `.kt-ai-popover-anchor > .kt-ai-popover[data-open]` (`data-align="right"`) – якорный интерактивный слой (date-picker, настройки колонок).
|
||
- **Bulk-bar** `data-floating="true"` – плавающий вариант снизу по центру для длинных таблиц.
|
||
- **Row actions** `.kt-ai-row .actions` / `.kt-ai-table tr .actions` – тихие действия, видимы на hover/focus-within/selected; на touch видимы всегда.
|
||
- Активный пункт навигации получает 2px-акцент слева (работает и в icon-rail).
|
||
|
||
Анатомия shell, таблиц, рядов – COMPONENTS.md (перенесено из v1-архива, нормативно).
|
||
|
||
## Operational Dashboard Contract
|
||
|
||
- Boilerplate задаёт обязательный shell: sidebar, `.kt-ai-topbar`, theme toggle и AI-кнопку Төре. Эти элементы нельзя перерисовывать, заменять самодельными глифами или делать декоративными. Main content проектируется под задачу процесса.
|
||
- Для рабочих очередей, реестров и консолидации закупок предпочтителен classic app-shell: таблица как главный объект, детали в drawer, короткие workflow-status, одно primary-действие. Custom workspace, матрица, split-view или decision panel используются только когда таблица + drawer не решают основную работу пользователя.
|
||
- H1/topbar title – короткий рабочий объект, 1-3 слова. Не использовать описание процесса как заголовок.
|
||
- Subtitle – одна короткая scope-фраза до 90 символов.
|
||
- KPI показывают рабочее состояние текущего пользователя: новые, требуют решения, риски, ждут документы, просрочено, закрыто сегодня, SLA или сумма риска. ROI, FTE, экономия часов и тенге эффекта не выводятся на пользовательский dashboard по умолчанию. Эти метрики относятся к management/reporting view, паспорту или расчёту эффекта проекта. Исключение – операционный экран консолидации, где пользователю нужны рабочие числа для решения: сколько ТС обработано, сколько имеют потенциал консолидации, какой предварительный потенциал экономии в тенге.
|
||
- Search, theme toggle, AI button and visible primary actions must work in the prototype when shown. Search inputs are empty by default and must not be prefilled with arbitrary examples.
|
||
- Primary filters – только workflow-status, максимум 4 пункта плюс `Все`. Confidence, risk type, системы и длинные причины не попадают в default segmented filters.
|
||
- Workflow `status`, `confidence` и `riskType` моделируются разными полями.
|
||
- Labels компактные: filter до 2 слов, status до 4 слов, table header до 2 слов; детали и длинные объяснения – в drawer/help.
|
||
- UI-copy не показывает внутреннюю кухню генерации: `модель вернула`, `fallback`, `не проходит дизайн-систему`, `shell`, `JSON` и похожие формулировки запрещены в пользовательском интерфейсе.
|
||
- **Голос интерфейса нейтрален и продуктовый.** Запрещены: дисклеймеры прототипа («это прототип на дизайн-системе», «данные иллюстративны»); нравоучения про human-in-the-loop («AI не действует на клиента сам», «решение подтверждает человек», «контрольная точка») — человек-в-контуре показывается контролами (рекомендация + кнопки accept/reject), а не объяснениями; лозунг-лейблы капсом («РЕШЕНИЕ — ЗА ВАМИ») — секции называются нейтральными существительными («Решение»). Любой продукт-специфичный текст (что сделал агент, разбор) живёт в контракте (`scenario.aiSummary`), а не зашит в shell — иначе он протекает в другие продукты. Валидатор ловит эти формулировки (`PREACHY_LANG`).
|
||
|
||
## Состояния интерактива
|
||
|
||
Единая лестница: default → hover (`-bg-hover` или border-strong) → active/selected (`-bg-active`) → focus-visible (outline `-focus-ring`) → disabled (opacity .4). Hover-переходы `dur-fast`, появления `dur-base`, drawer/modal `dur-slow`. Нажатие кнопки: `scale(.98)` 60ms.
|
||
|
||
## Движение (motion)
|
||
|
||
Правила — не украшение, а поведение. Каждое имеет причину.
|
||
|
||
- **Длительности по типу:** микро/hover 100–150мс (`dur-fast` 100), обычное появление/смена 150–250мс (`dur-base` 160), overlay/drawer/modal ~240мс (`dur-slow`). Дольше 300мс движение начинает раздражать; короче — пропадает читаемость перехода.
|
||
- **Появляйся от `scale(.95)`, не от `scale(0)`** (и не от `opacity:0` в одиночку): элемент «подрастает» из своего места, а не возникает из ниоткуда. Уводи так же — до `.95`, не в `0`.
|
||
- **Отклик на нажатие, не на отпускание:** подсветка/`scale(.98)` на pointer-down мгновенно; коммит — на pointer-up. Лаг убивает ощущение прямоты.
|
||
- **Переходы прерываемы и обратимы:** закрывающийся drawer можно открыть на полпути. Анимируй от ТЕКУЩЕГО значения (presentation), а не от целевого — иначе «прыжок».
|
||
- **Вход и выход по одному пути; overlay привязан к источнику:** меню/popover растут из кнопки (`transform-origin` = триггер), drawer уходит туда, откуда пришёл. На реверсе — зеркальный easing (`ease-enter` ↔ `ease-exit`).
|
||
- **Анимируй только `transform` и `opacity`** (композиторные, без ре-лейаута). Не анимируй `width/height/top/left/box-shadow` — дёргается кадр.
|
||
- **`prefers-reduced-motion`** обнуляет длительности автоматически (токены + компоненты); оставляем только opacity/цвет, что помогают понять переход.
|
||
|
||
## Иконки
|
||
|
||
Lucide из локального sprite, монохром через `currentColor`, stroke 1.75. Размеры 16 (база), 14 (плотные ряды), 20 (крупные). Без CDN-шрифтов и CSS-псевдоиконок. Правила и список имён – v1-архив.
|
||
|
||
## Доступность и QA
|
||
|
||
- Контраст: основной текст ≥ 7:1, muted ≥ 4.5:1, faint только для необязательных подписей.
|
||
- Фокус видим всегда: глобальный `:focus-visible` в components.css.
|
||
- `prefers-reduced-motion` поддержан на уровне токенов (обнуляет длительности).
|
||
- `prefers-contrast: more`: толще фокус-кольцо, границы = `border-strong`, ссылки подчёркнуты, обводка у пилюль.
|
||
- `prefers-reduced-transparency: reduce`: blur на sticky-топбаре снимается, фон становится плотным (легибельность > эффект).
|
||
- Чек-лист перед сдачей экрана — единый гейт `CHECKLIST.md` (Definition of Done): обе темы, состояния loading/empty/error, один primary, нет сырых hex, адаптив, паритет, валидатор 0/0. Прогоняется при любом изменении UI, не только при сдаче нового экрана.
|
||
|
||
## Подключение
|
||
|
||
```html
|
||
<link rel="stylesheet" href="kt-ai-tokens.css">
|
||
<link rel="stylesheet" href="kt-ai-components.css">
|
||
<body class="kt-ai-app" data-theme="dark">
|
||
```
|
||
|
||
Для Next.js-прототипов – кит `templates/kt-ai-shadcn` (**внутри папки ДС**, рядом с app-shell — ДС одна самодостаточная папка; переменные совместимы, источник значений – kt-ai-tokens.css; установка – его `templates/kt-ai-shadcn/PROTOTYPING_WORKFLOW.md`).
|
||
|
||
**Два рантайма одного контракта.** HTML app-shell (`templates/kt-ai-app-shell.html`) — демо-рантайм с роутингом разделов: рендерит nav-секции (`view="documents"`, мастер `steps`), баннер-навигацию (`banner.actionNav`), коллекции документов. React-кит — **одноэкранный handoff для разработки**: рендерит главный архетип-экран (queue/dashboard/…) + drawer (включая секцию «Документы» из `_docs`), но НЕ роутит вторичные nav-секции — это намеренно (их реализует разработчик под свой роутер). Поэтому `nav.view`, `steps`, `banner.actionNav` — поведение HTML-рантайма; в React это точки расширения.
|
||
|
||
## Миграция v1 → v2
|
||
|
||
1. Заменить подключение `archive/kt_ai_terminal_tokens.css` на пару `kt-ai-tokens.css` + `kt-ai-components.css`. Все старые переменные и классы продолжают работать.
|
||
2. Hardcoded-размеры и цвета постепенно переводить на шкалы (`--kt-ai-space-*`, `--kt-ai-text-*`, semantic-цвета).
|
||
3. Новые компоненты (кнопки, формы, modal, toast, banner, skeleton, empty) не писать заново – брать из components.css.
|
||
4. Паритет тем проверять в showcase.html.
|
||
|
||
## Ритм отступов (правило близости)
|
||
|
||
`space-*` – сырая шкала для внутренних отступов компонента. **Расстояние МЕЖДУ блоками экрана берётся из отдельной шкалы `stack-*`** – одно значение на роль, а не решение каждого компонента:
|
||
|
||
| Токен | Значение | Когда |
|
||
|---|---|---|
|
||
| `--kt-ai-stack-tight` | 12px | внутри группы: подпись ↔ контрол, контрол ↔ контрол в одном ряду |
|
||
| `--kt-ai-stack-block` | 16px | между элементами одного блока; полоса карточек KPI; панель управления ↔ то, чем она управляет |
|
||
| `--kt-ai-stack-group` | 24px | **между блоками экрана**: шапка / баннер / KPI / чарт / таблица. Значение по умолчанию |
|
||
| `--kt-ai-stack-region` | 32px | поля рабочей области, топбар ↔ заголовок |
|
||
| `--kt-ai-pad-card` | 20px | интерьер карточки/секции |
|
||
|
||
Почему шкала, а не `space-*` напрямую: раньше каждый компонент выбирал отбивку сам, и на одном экране получалось пять разных значений для одного и того же отношения «блок ↔ блок» (8/12/16/20/24). Глаз не читает такую разницу как иерархию – он читает её как небрежность, и экран выглядит захламлённым при формально верных токенах. Ровно так разошлись два рантайма: HTML-шелл давал 16/20, React-кит 24/28.
|
||
|
||
Правило разрешения споров прежнее: если сомневаешься, к какой группе элемент относится визуально – он стоит неправильно. Секционный разрыв (40+, `space-10`) остаётся для смены смысла страницы, а не для соседних блоков одного экрана.
|
||
|
||
### Одинаковый зазор — не ритм
|
||
|
||
Шкала не означает «поставь `stack-group` на всё». Ровно так экран становится плоским: панель фильтров, её вкладки и карточки списка расходятся на одно и то же расстояние, и глаз не видит ни одной группы — только столбец одинаково далёких полос. Разнобой читается как небрежность, равномерность — как «здесь ничто ни с чем не связано». Обе ошибки одинаково дорогие.
|
||
|
||
**Рецепт экрана — три ступени, не одна:**
|
||
|
||
```
|
||
шапка страницы ← 24 (stack-group): регион
|
||
системный баннер ← 24 (stack-group): регион
|
||
┌ панель управления ← 12 (stack-tight): фильтры и вкладки — ОДНА вещь
|
||
│ фильтры
|
||
│ вкладки
|
||
└ ← 16 (stack-block): панель ближе к тому, чем управляет
|
||
┌ содержимое
|
||
│ KPI · чарт · карточки списка ← 16 между блоками, 12 между однородными карточками
|
||
└
|
||
```
|
||
|
||
Выражается стеком, а не своим классом продукта: `<div class="kt-ai-v" data-gap="group|block|tight|region">`. Если продукту понадобился собственный `app-stack-*` — это сигнал, что группировку не выразили, а обошли.
|
||
|
||
**Проверка одной фразой:** пройди по вертикали и назови каждый зазор. Если все числа разные — сломана согласованность. Если все одинаковые — сломана группировка. Правильно, когда чисел ровно столько, сколько на экране уровней вложенности.
|
||
|
||
## Отзывчивость
|
||
|
||
Брейкпоинты: sm 640 / md 832 / lg 1024 / xl 1280 (`--kt-ai-bp-*`; в media-запросах значения дублируются числом – var() там недоступен).
|
||
|
||
Shell – три состояния (реализовано в components.css):
|
||
|
||
1. ≥ lg: полный sidebar 232px.
|
||
2. md..lg: icon-rail 52px – подписи прячутся; в разметке подписи пунктов оборачивать в `<span class="nav-label">`.
|
||
3. < md: sidebar = overlay-drawer (`data-open="true"`), в топбаре burger; drawer документов – full-screen.
|
||
|
||
Touch (`pointer: coarse`): токены контролов автоматически растут (sm 36, md 44, lg 48, nav-row 40, table-row 52) – компоненты масштабируются сами, ничего переопределять не нужно.
|
||
|
||
Мобильный топбар: на < sm в топбаре остаются логотип (без текста), статус-чип с ellipsis и одно главное действие; текстовые кнопки прячутся или сворачиваются в иконки; элементы с flex-shrink:0 допустимы только для иконок и тумблера. Бургер для off-canvas панелей – иконка `menu` из спрайта (три линии), не самодельные глифы. Горизонтальный скролл страницы запрещён и гасится системой на < md (overflow-x hidden на .kt-ai-app/.kt-ai-shell).
|
||
|
||
Таблицы: горизонтальный скролл внутри `table-wrap`; первая колонка может быть sticky (`.kt-ai-sticky-first`); при < md и более 4 колонок – переключаться на список карточек.
|
||
|
||
## API компонентов (enum-контракт)
|
||
|
||
| Компонент | Атрибут | Значения |
|
||
|---|---|---|
|
||
| `.kt-ai-btn` | data-variant | (нет) = secondary, `primary`, `ghost`, `danger` |
|
||
| `.kt-ai-btn` | data-size | (нет) = md, `sm`, `lg` |
|
||
| `.kt-ai-btn` | data-loading | `true` – спиннер, клики заблокированы |
|
||
| `.kt-ai-chip` | data-tone | `gray`, `green`, `orange`, `blue`, `purple`, `red` |
|
||
| `.kt-ai-chip` | data-removable | присутствие + `<span class="remove">×</span>` |
|
||
| `.kt-ai-status-pill` | data-status | `ok`, `warn`, `risk`, `info` |
|
||
| `.kt-ai-banner`, `.kt-ai-toast` | data-tone | `ok`, `warn`, `risk`, `info` |
|
||
| `.kt-ai-input/.kt-ai-textarea` | data-invalid | `true` |
|
||
| `.kt-ai-field` | data-invalid | `true` — красит вложенный input/select/textarea (удобно, когда состояние живёт на поле) |
|
||
| `.kt-ai-table` | data-density | (нет) = 48px, `compact`/`dense` 38, `relaxed` 56 (значения из `tokens.json`) |
|
||
| `.kt-ai-table th` | data-sort | присутствие = сортируемая, `asc`, `desc` |
|
||
| `.kt-ai-step-item` | data-state | (нет) = upcoming, `current`, `done` |
|
||
| `.kt-ai-combobox` | data-open | `true` – меню видно |
|
||
| `.kt-ai-table td` | data-label | подпись ячейки в мобильном card-режиме (≤640px). Без неё значение просто выравнивается влево |
|
||
| `.kt-ai-switch-row` | — | готовая строка «подпись + свитч справа». Сам `.kt-ai-switch` — только трек 34px |
|
||
| `.kt-ai-modal` | — | ОБЯЗАТЕЛЬНО внутри `.kt-ai-modal-overlay` — оверлей и есть центрирующий контейнер (`position: fixed` + flex). Соседями они не работают: модалка встанет в поток и уедет со скроллом |
|
||
| `.kt-ai-scroll-locked` | — | на `<html>`, пока открыт модал/drawer: иначе фон скроллится под оверлеем. Снимать при закрытии |
|
||
| `.kt-ai-disclosure` | data-open | `true` — раскрыт. Карточка, разворачивающаяся НА МЕСТЕ. Для очередей, где объекты сравнивают: drawer закрывает список и заставляет открывать по одному. Части: `-head` (кнопка, `aria-expanded`), `-chevron`, `-body`, `-actions` |
|
||
| `.kt-ai-kpi` | — | подпись всегда над значением, порядок `.label`/`.value` в разметке любой |
|
||
| `.kt-ai-combobox .option` | data-selected, data-active | `true` |
|
||
| `.kt-ai-dropzone` | data-drag | `true` – состояние перетаскивания |
|
||
| `.kt-ai-table-bulkbar` | data-open | `true` |
|
||
| `.kt-ai-sidebar` | data-open | `true` (только < md, overlay) |
|
||
| `.kt-ai-notif-item` | data-unread | `true` |
|
||
| `.kt-ai-theme-toggle` | data-mode | `dark`, `light` – бегунок и подсветка иконки |
|
||
| `.kt-ai-diff .line` | data-op | `add`, `del` |
|
||
| nav-item, tab, segmented .seg, pagination .page-btn | data-active | `true` |
|
||
| `.kt-ai-msg` | data-role | `user`, `assistant` |
|
||
| `.kt-ai-msg` | data-streaming | `true` – каретка генерации |
|
||
| `.kt-ai-prompt-bar` | data-busy | `true` – ввод заблокирован на время генерации |
|
||
| `.kt-ai-menu`, `.kt-ai-popover` | data-open | `true` |
|
||
| `.kt-ai-menu .item` | data-danger | `true` – деструктивный пункт |
|
||
| `.kt-ai-popover` | data-align | (нет) = left, `right` |
|
||
| `.kt-ai-table-bulkbar` | data-floating | `true` – плавающий снизу |
|
||
| `.kt-ai-command .cmd-item` | data-active | `true` |
|
||
| `.kt-ai-card` | data-glow | `strong` – усиленное aurora-свечение (hero/AI) |
|
||
| `.kt-ai-btn` | data-ai | `true` – градиентная AI-кнопка (точка входа Төре) |
|
||
| `.kt-ai-table-wrap` | data-framed | `true` – контейнер с рамкой (дефолт – frameless) |
|
||
| `.kt-ai-link` | data-arrow | присутствие – тихая ссылка «… →» |
|
||
| `.kt-ai-prop .v` | data-empty | `true` – незаполненное значение |
|
||
| `.kt-ai-kpi-strip` | data-cards | `true` – сетка стат-карточек (radius-2xl, card-токены) вместо тихой полосы |
|
||
|
||
## Локализация
|
||
|
||
- Казахские строки длиннее русских на ~20%: запрещены фиксированные ширины под текст кнопок, чипов, пунктов меню; truncation с ellipsis + tooltip полного значения.
|
||
- Числа: тысячи пробелом (`1 240`), тенге после числа (`1 240 ₸`), числа в таблицах — **sans + `tabular-nums`** (цифры Inter выровнены по ширине; в JetBrains Mono нет глифа ₸, из-за чего валюта подставлялась из другого шрифта и рвала колонку). Моноширинный остаётся только у `.kt-ai-kbd` и командных групп.
|
||
- Даты: `dd.mm.yyyy`, время `hh:mm`, относительные («2 мин», «вчера») только в уведомлениях и лентах.
|
||
|
||
## Чарты
|
||
|
||
Максимум 6 серий на график (порядок: chart-blue, green, orange, salmon, pink, red). Оси и подписи – fg-faint, сетка – divider. Заливка под линией – только primary-subtle и только для одной серии. Без 3D, теней и градиентов в данных. Пустое состояние графика – kt-ai-empty, не пустые оси.
|
||
|
||
## Печать и экспорт
|
||
|
||
Подключить `kt-ai-print.css` (генерируется из tokens.json): при печати принудительно light-палитра, скрываются shell/кнопки/тосты, формат A4 с полями 18/16 мм, карточки и таблицы не разрываются. Элементы, которые не должны попасть в PDF, помечать `data-no-print`.
|
||
|
||
## Иконочные кнопки и деструктивные действия
|
||
|
||
Icon-only кнопка обязана иметь tooltip (`.kt-ai-tooltip[data-tip]`) и aria-label. Деструктивные действия: никогда не icon-only; подтверждение в modal; кнопка подтверждения – глаголом действия («Удалить агента», «Отправить в Реестр»), никогда «Да»/«ОК»; для необратимых операций – ввод имени объекта.
|
||
|
||
## Правило двух продуктов
|
||
|
||
Новый компонент попадает в систему только когда он понадобился второму продукту. До этого живёт в продукте. Это держит систему маленькой и честной.
|
||
|
||
## Визуальная регрессия
|
||
|
||
`scripts/visual_check.mjs` (Playwright): скриншоты showcase в обеих темах и трёх ширинах (1280/900/600), сравнение с эталонами в `scripts/__screenshots__/`. Запуск локально: `npx playwright install chromium && node scripts/visual_check.mjs`. Прогонять при любом изменении tokens.json или components.css.
|
||
|
||
## Do / Don't
|
||
|
||
- Do: ряды вместо крупных карточек; таблица – главный объект экрана; детали в drawer; метрики тихой полосой (в дашбордах/кабинетах с 2-4 главными метриками – `data-cards="true"`); primary-действие монохромное (near-black/near-white); кнопки create/«Новый X» – с ведущим «+»; один фильтрующий поиск на экран; AI-кнопка Төре – в топбаре рядом с поиском; продукт-специфичный текст – в контракте, не в shell.
|
||
- Don't: карточки в карточках; декоративные градиенты, свечения и blur в контенте (исключения: единичная AI-искра орба/send/prompt-bar, blur на sticky-хроме и overlay); синий как заливка primary-кнопки; больше одного primary; цвет hex напрямую; новые цвета/иконки/геометрия под отдельный продукт; разная геометрия в темах; дисклеймеры/нравоучения в UI; два одинаково фильтрующих поиска; лишний input/селект там, где хватает прямой кнопки.
|