Files
evening_detective_frontend/docs/DESIGN_SYSTEM.md
T
2026-10-14 23:39:17 +07:00

302 lines
27 KiB
Markdown

# Дизайн-система сайта и игры «Вечерний детектив»
Два направления с общим логотипом: сайт помогает выбрать дело и управлять
участием, игра погружает в расследование. Визуальные правила описаны здесь;
единственный источник правил реализации — [FRONTEND_CODE_STANDARD.md](FRONTEND_CODE_STANDARD.md).
Рабочие страницы мигрируют постепенно; образцы не меняют их оформление.
## Области применения
| Направление | Где применяется | Характер |
| --------------------- | ----------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------- |
| Сайт «Золотой вечер» | Главная, каталог, кабинет, страницы организатора, редакторы и обычные формы | Тёмные ровные панели, машинописный шрифт, ярко-жёлтые действия, лёгкие фактуры |
| Игра «Материалы дела» | Расследование команды, улики, сюжетные документы, игровое управление и печатные материалы | Существующие бумага, кожа, металл, машинописный текст, бронзовые надписи и фактурные кнопки |
Превью сюжетного документа внутри каталога или редактора использует игровой
стиль; окружающие управление и формы — стиль сайта. Игровые изображения и
фоны сценариев сохраняют собственное оформление.
## Живые образцы
Запустить `npm run dev` и открыть `/design-system` на адресе Vite. Вкладка
«Сайт» открывается первой, «Игра» показывает отдельные материалы и управление,
«Компоненты» — последовательный каталог: заголовок компонента, живой пример,
описание контракта и код подключения; затем следующий компонент.
Страница доступна только в разработке, без входа и пункта основного меню;
маршрут и компоненты образцов исключены из production-сборки.
Все данные вымышлены. Форма, модальное окно и ход игры работают локально;
игровой ход не вызывает API и не меняет данные игры. Сайт использует `SiteThemeProvider`, игровые образцы —
собственный `NConfigProvider`: тема сайта не попадает в игровые компоненты.
## Общий бренд и логотип
Использовать [существующий знак](../src/assets/images/лого.jpg): детектив в
шляпе, чёрный круг, золотая окантовка. Не растягивать, не обрезать окантовку,
не перерисовывать. Свободное поле — не меньше четверти диаметра;
промежуток до названия — от 12 px. Размеры образцов — 48 и 144 px.
Изображение рядом с названием имеет пустой `alt`, самостоятельный знак —
описательный. JPEG сохраняет белый фон внутри круга, круглое размещение
допускает `border-radius: 50%`. Прозрачного и векторного исходника нет;
качество крупной печати и узнаваемость favicon проверяются отдельно.
Основной цвет текста обоих стилей на тёмных поверхностях — светлый `#EEE`,
второстепенный — `#BDB8AE`. Игровой бежевый `#BFA07D` используется точечно:
в бренде, декоративных надписях и текстовыделителе. Цвета статусов сохраняют
значение; текст на бумаге и жёлтых кнопках остаётся тёмным. Общий блок бренда
`DesignBrand` содержит логотип 48 px, промежуток 12 px и название
«Вечерний детектив» через `HeaderText`. На узком экране название может
переноситься; название направления «Материалы дела» располагается отдельно.
Общие правила: mobile-first, desktop от 1024 px, текущие контейнеры 700/1200 px,
явные состояния ошибки и загрузки, доступность с клавиатуры. Шкала отступов:
4, 8, 12, 16, 24, 32, 48, 64 px. Цвета задавать семантическими CSS-переменными.
## Сайт «Золотой вечер»
### Палитра
Токены находятся в `src/assets/base.css`. `--brand-bronze` и бумага связывают
оформление с игрой; жёлтый primary относится к сайту, а не к игровым действиям.
| CSS-переменная | Цвет | Назначение |
| ------------------------ | --------- | -------------------------------------------------- |
| `--brand-background` | `#111111` | Фон сайта; текст на золотой кнопке и бумаге |
| `--brand-surface` | `#222222` | Карточки, панели, окна |
| `--brand-surface-hover` | `#2E2E39` | Подсветка поверхности при наведении |
| `--brand-text` | `#EEEEEE` | Основной текст |
| `--brand-text-muted` | `#BDB8AE` | Пояснения, подписи, второстепенные данные |
| `--brand-accent` | `#FFD43B` | Основное действие, ссылки, активный элемент, focus |
| `--brand-accent-hover` | `#FFE066` | Наведение на основное действие |
| `--brand-accent-pressed` | `#F5C518` | Нажатие на основное действие |
| `--brand-border` | `#77737F` | Границы полей и панелей |
| `--brand-success` | `#87C99D` | Успех |
| `--brand-info` | `#94BFEE` | Информация |
| `--brand-error` | `#F29A9A` | Ошибка и опасное действие |
| `--brand-bronze` | `#BFA07D` | Бренд, текстовыделитель и декоративные надписи |
| `--brand-paper` | `#F4EDE0` | Бумажные материалы |
Предупреждение использует золото и явную подпись. Статусы не передавать только
цветом: добавлять текст и штатную иконку. Жёлтый акцент не использовать как цвет
обычного текста на бумаге или белом фоне.
## Типографика и компоновка
Весь стиль сайта использует существующий `font_old_typer`: заголовки, основной
текст, подписи, меню, кнопки, формы, таблицы и модальные окна. Новые шрифты не
загружаются. Шрифт задаётся на контейнере и в локальной теме Naive UI, чтобы
сохраняться в телепортируемых окнах. Игровая типографика остаётся прежней.
| Элемент | Размер | Вес | Межстрочный интервал |
| ----------------------------- | ------------------------ | ------------------------------- | -------------------- |
| Главный заголовок | `clamp(32px, 4vw, 48px)` | 600 | 1.15 |
| Заголовок раздела | 28 px | 600 | 1.3 |
| Заголовок блока | 22 px | 600 | 1.4 |
| Вступление | 18 px | 400 | 1.5 |
| Основной текст | 18 px | 400 | 1.5 |
| Подпись | 14 px | 400 | 1.5 |
| Короткая надпись над разделом | 14 px | 400 | 1.5 |
| Бумажный текст | 18 px | существующий вес `MessagePaper` | 1.5 |
Шкала отступов: 4, 8, 12, 16, 24, 32, 48, 64 px. На мобильном экране внешние
поля 16 px, на desktop — 24 px; между разделами 32 px на мобильном и 48 px на desktop, без сложения
верхних и нижних отступов соседних секций. Базовое скругление
8 px. Панели имеют тонкую границу; выраженную тень оставить бумажному слою и
существующим фактурным компонентам.
Использовать текущие контейнеры `.width700` для дел и `.width1200` для списков,
прокрутку `.center-block-custom` и шапку высотой 70 px. Mobile-first;
desktop-порог — `@media (width >= 1024px)`. До него колонки складываются
вертикально, кнопки переносятся; широкая таблица прокручивается внутри себя.
Главный блок выравнивается по верхнему краю, между колонками 32 px. Внутри
карточек поля 16 px на мобильном и 24 px на desktop, между элементами 16 px,
перед главным действием 24 px. Отступы абзацев по умолчанию нулевые;
интервалы задаются контейнерами. Не сжимать машинописный заголовок отрицательным
межбуквенным интервалом. Небольшие папки каталога сохраняют подписи не меньше 14 px.
### Компоненты и материалы
Использовать Naive UI. `NConfigProvider` берёт тему из CSS-токенов. Primary
имеет сплошную заливку `#FFD43B`, hover `#FFE066`, pressed `#F5C518`, текст
`#111`; сохранять машинописный шрифт и видимый focus. Опасное действие
использует красный акцент. Disabled и loading — штатные состояния Naive UI.
Главный блок, карточки, формы, таблицы и окна имеют ровные поверхности. Кожа
допускается как небольшая полоса в шапке (`BeltBlock`), бумага — в документальных фрагментах превью дела (`paper.jpg`);
не оформлять весь сайт стопками листов. Название с логотипом в обоих стилях использует общий `DesignBrand` и
существующий `HeaderText`: бежевый `#BFA07D`, машинописный шрифт 22 px,
вес 600 и разрядка 2 px. Меню и основной текст сайта используют `font_old_typer`.
Ссылки жёлтые на тёмном фоне; на светлом ярлыке текст тёмный. Формы имеют
подписи и ошибки у полей, таблицы — локальную прокрутку при необходимости.
Модальные окна — `n-modal` + `n-card`, заголовок, role dialog и aria-modal.
### Доска расследования
Без градиентов и свечения. Главный блок использует композицию
из текстовых улик: записка, билет, время отправления, номера и соединительные
линии приглушённого бронзового цвета. Логотип остаётся в шапке, не заменяет
обложку каждого дела. Под композицией — название, параметры и жёлтое действие.
На desktop фрагменты расположены асимметрично с небольшими поворотами;
на мобильном — вертикально, без наложения текста. Бумага использует существующую
фактуру. Машинописный шрифт допустим внутри документальных фрагментов;
описания, навигация, формы и кнопки тоже используют `font_old_typer`.
Документальные фрагменты декоративные, не имеют самостоятельных hover или действий. Линии не перехватывают
клики. Формы и служебные панели сохраняют ровные поверхности. Большая доска использует `CaseBoard`; каталог — повторяемые папки
`CaseFolder` с предметными обложками.
### Детали досье
| Приём | Где и как применять |
| -------------------- | --------------------------------------------------------------------------------------------------- |
| Папка с ярлыком | Карточка каталога, номер на выступающем ярлыке; оставлять 32 px между карточками |
| Бежевый маркер | Одно важное выражение в заголовке, тёмный текст на бежевой неровной полосе |
| Улика на обороте | Явная кнопка раскрывает цитату, `aria-expanded` и `aria-controls`; без 3D-переворота |
| Архивные разделители | Пунктир между разделами, номера и уголки на обложках; не дополнительные рамки вокруг каждого текста |
| Предметная обложка | Билет, ключ или письмо из существующих иконок и бумажных фактур; тот же символ рядом с названием |
| Заметка на полях | Короткая сюжетная подпись рядом с большой доской; на мобильном — ниже композиции |
| Штамп статуса | «Новое дело», «Скоро», «Пройдено»; только при наличии соответствующего реального состояния |
| Подсветка связи | Одна бронзовая линия становится жёлтой при hover или фокусе действия в карточке |
| Конец досье | Номер листа, название проекта, тонкая линия и «Продолжение — в следующем деле» |
Карточки поднимаются на 3 px при наведении мыши и фокусе внутри. Переходы
занимают 160 ms; при `prefers-reduced-motion` подъём и переходы отключаются,
раскрытие цитат продолжает работать. Touch не зависит от hover: цитата
открывается кнопкой. Декоративные слои и линии не перехватывают клики.
Три папки в образцах вымышлены, их штампы не обозначают реальные публикации
или историю пользователя. В образце дело «Скоро» имеет отключённое основное действие через отдельный
`disabled`; сам статус не управляет доступностью.
На рабочем сайте привязать состояния к данным; не вычислять «новое» или
«пройдено» по предположениям. Формы и таблицы сохраняют спокойный вид.
## Игра «Материалы дела»
### Эталон и палитра
Эталон — текущее оформление расследования команды, а не тема сайта.
Сохранить `MessagePaper`, `IntroBlock`, `GameInputForm`, `BeltBlock`,
`MetalPlate` и их фактуры. Окружение тёмное `#111`, панели `#222`, основной текст
`#EEE`, бумажный текст чёрный, декоративные надписи бронзовые `#BFA07D`.
Существующие мятные состояния и фактурные игровые кнопки сохраняются;
жёлтую тему сайта не передавать игровому provider.
### Материалы и управление
| Материал | Источник | Применение |
| ------------------ | ------------------------------------------------- | ------------------------------------------------------------ |
| Бумага | `MessagePaper`, `paper.jpg`, `paper_white.jpg` | Вступление, точки, улики и фотографии; сохранять слои и тени |
| Кожа | `BeltBlock`, `belt.png` | Полосы управления и фактурные действия |
| Металл | `MetalPlate`, `metal.png`, `pin.png` | Детали панелей, без заливки всей страницы |
| Игровое управление | `GameInputForm`, `input_center.png`, `button.png` | Место назначения, счётчики и фактурная кнопка |
Машинописный шрифт сохраняется в документах и существующих игровых
компонентах; сайт использует тот же шрифт по собственным правилам компоновки. `HeaderText` — для
бронзовых игровых надписей. В образцах подписи на коже и металле используют
чёрную подложку 80% для читаемости. Это локальное оформление образцов,
не массовая переделка рабочих игровых компонентов.
Вступление и улика используют настоящие компоненты с демонстрационными
данными. Панель хода повторяет поведение игры: успешный локальный ход очищает
поле и показывает результат. В образцах панель размещена в потоке страницы;
в рабочей игре остаётся её существующее фиксированное положение.
### Печатные материалы
Светлые внутренние страницы, тёмный текст, небольшие золотые метки. Тёмное
оформление допустимо для обложек. Не печатать свечение интерфейса. Номера,
подписи и статусы должны читаться в чёрно-белом виде; сюжетные изображения
сохраняют собственную стилистику.
## Проверка изменённого экрана
- На ширинах 375, 768 и 1280 px нет горизонтальной прокрутки всей страницы;
таблица может прокручиваться локально.
- Текст имеет контраст от 4.5:1; крупный текст и значимые границы управления —
от 3:1. Проверять реальные пары цветов, в том числе hover и pressed.
- Все действия доступны с клавиатуры; focus виден, окно закрывается и возвращает
фокус на открывший его элемент.
- Ошибка, успех, загрузка и пустое состояние различимы без цвета.
- Логотип не деформирован; весь UI сайта использует `font_old_typer`, включая окна.
- Компонентные стили локальны, глобальная тема изменяется только при осознанной
миграции. Типы, ESLint и Stylelint проходят; изменения маршрутов проверены сборкой.
- Переключение вкладок доступно с клавиатуры; сайт открывается первым.
- Жёлтая тема сайта не меняет игровые кнопки и документы.
- Игровой ход в образцах работает без сетевых запросов.
## Подключение библиотеки
Компоненты находятся в `src/components`, импортируются напрямую и не зависят
от dev-маршрута. Отдельного пакета и глобальной регистрации нет. Демонстрационные
данные остаются в `SiteDesignPreview`, `GameDesignPreview` и `ComponentDesignCatalog`.
Рабочие экраны пока не мигрируют.
```vue
<script setup lang="ts">
import { NButton, NCard } from 'naive-ui'
import SiteThemeProvider from '@/components/SiteThemeProvider.vue'
import CaseFolder from '@/components/CaseFolder.vue'
function openCase(title: string) {
// Здесь родитель выполняет нужную навигацию или загрузку.
console.log(title)
}
</script>
<template>
<SiteThemeProvider>
<NCard title="Материалы"><NButton type="primary">Открыть</NButton></NCard>
<CaseFolder
number="014"
title="Последний поезд"
description="Письмо и билет"
quote="Не доверяй времени"
object="ticket"
cover-label="Материал 014 / Билет"
cover-caption="23:40 · Вагон 03"
@open="openCase"
/>
</SiteThemeProvider>
</template>
```
Provider читает существующие CSS-токены при монтировании, задаёт darkTheme,
цвета, машинописный шрифт и размеры Naive UI; кнопки, поля, таблицы и окна
используются непосредственно из `naive-ui`. Телепортируемые окна сохраняют
тему; для текста внутри `NCard` используйте машинописный шрифт на классе окна,
как в каталоге. `--site-card-padding` позволяет контейнеру задавать поля карточек.
Игровые компоненты размещайте вне provider сайта, под своим
`NConfigProvider :theme="darkTheme" :theme-overrides="{}"`.
| Компонент | Props | Slots / события |
| --- | --- | --- |
| `SiteThemeProvider` | Нет | default / нет |
| `DesignBrand` | Нет | Нет |
| `CaseFolder` | number, title, description, quote, object: ticket/key/letter, coverLabel, coverCaption; status?, disabled=false, actionLabel='Открыть дело' | Нет / open(title: string) |
| `CaseBoard` | label, fragments: readonly массив { number, title, text, caption?, detail?, kind?: note/ticket/timetable }, footer? | footer / нет |
| `ObjectCover` | object: ticket/key/letter, label, caption, status? | Нет |
| `StatusStamp` | text? | default заменяет text / нет |
| `TextHighlight` | Нет | default / нет |
| `SectionHeading` | title, id?, eyebrow? | default заменяет title / нет |
| `DossierFooter` | label | default / нет |
| `MessagePaper` | Нет | default / нет |
| `HeaderText` | Нет | default / нет |
| `BeltBlock` | Нет | default / нет |
| `MetalPlate` | Нет | default / нет |
| `IntroBlock` | introduction: EditableIntroduction, mode: show/show-editor/edit | default в режиме edit / update:mode |
| `GameInputForm` | addAction: (code: string) => Promise<boolean>, allPlacesCount, newPlacesCount, gameStatus | Нет; true от addAction очищает поле |
Статус папки необязателен и только показывает текст. Доступность задаёт родитель
через `disabled`, подпись действия — через `actionLabel`. Событие `open` передаёт
название; маршрутизация и API остаются у родителя. Каждая цитата получает
уникальный Vue `useId()`, даже для повторных карточек одного дела.
Вкладки переключаются стрелками по кругу, Home открывает «Сайт», End —
«Компоненты». Каталог показывает disabled, loading, ошибку и успешную форму,
обрабатывает open локально и не отправляет запросы к серверу.