136 lines
11 KiB
Markdown
136 lines
11 KiB
Markdown
# Дизайн-система WealthLedger
|
||
|
||
Общий фундамент находится в
|
||
[`frontend/src/shared/theme`](../../frontend/src/shared/theme/index.ts).
|
||
Его public API экспортирует `theme`, `cssVariablesResolver`, `colorRoles`, `designTokens` и
|
||
подключает базовые CSS. App владеет MantineProvider; Storybook подключает свой
|
||
изолированный provider к тому же API. Тема и значения не копируются в preview.
|
||
Оба runtime используют светлую схему; dark theme не заявлена как поддерживаемая.
|
||
|
||
## Тема и токены
|
||
|
||
[`tokens.json`](../../frontend/src/shared/theme/tokens.json) — единственный
|
||
редактируемый источник опубликованных токенов WealthLedger. Он содержит восемь
|
||
палитр по десять оттенков: blue, gray, dark, red, green, yellow, grape и orange;
|
||
базовые white/black, оттенки по умолчанию, семантические роли с описаниями,
|
||
типографику, интервалы, радиусы, тени и breakpoints. Существующие значения
|
||
приняты из темы приложения и Mantine 9.5.1; теперь ими владеет JSON. Default
|
||
radius остаётся md, font family заголовков совпадает с общей.
|
||
|
||
[`theme.ts`](../../frontend/src/shared/theme/theme.ts) напрямую адаптирует JSON
|
||
в Mantine. Файл — доверенная конфигурация репозитория; приложение не загружает
|
||
внешние или пользовательские токены и не проверяет JSON runtime-схемой.
|
||
Размеры px преобразуются native `rem`, сохраняя `--mantine-scale`, тени собираются
|
||
из слоёв с `rgba`, а breakpoints остаются em без масштабирования. Неопубликованные
|
||
палитры и настройки поведения компонентов остаются defaults Mantine.
|
||
Небольшой [`theme.test.ts`](../../frontend/src/shared/theme/theme.test.ts)
|
||
проверяет преобразования адаптера; корректность изменений локального JSON
|
||
проверяется при review, сборке и проверке внешнего вида.
|
||
|
||
Используйте props Mantine (`gap="md"`, `p="xl"`, `radius="md"`, `shadow="xs"`)
|
||
или `--mantine-spacing-*`, `--mantine-radius-*` и другие native CSS variables.
|
||
[Foundations](http://localhost:6006/?path=/story/design-system-foundations--colors)
|
||
читает эффективную тему и описания из JSON, показывает фактические значения
|
||
и образцы. Обновление Mantine не заменяет принятые шкалы автоматически и требует
|
||
повторной проверки адаптера и внешнего вида приложения.
|
||
|
||
`colorRoles` связывает смысл и native Mantine reference; resolver создаёт
|
||
`--wl-color-<role>`, ссылающийся на Mantine variable, без повторного hex-значения.
|
||
|
||
| Role | Native reference | Применение |
|
||
| --- | --- | --- |
|
||
| canvas | gray.2 | Фон приложения |
|
||
| surface | white | Paper и формы в светлой схеме |
|
||
| subtle | gray.0 | Приглушённая поверхность |
|
||
| text | dark.7 | Основной текст страницы |
|
||
| muted | gray.6 | Вторичный текст (dimmed светлой схемы) |
|
||
| border | gray.3 | Граница поверхности |
|
||
| primary | blue filled | Основное действие и активная навигация |
|
||
| info | blue.6 | Информация |
|
||
| positive | green.6 | Положительный результат с текстом/знаком |
|
||
| negative | red.6 | Ошибка или отрицательный результат с текстом/знаком |
|
||
| warning | yellow.6 | Предупреждение, не мелкий текст на белом |
|
||
|
||
Базовые CSS используют canvas/text aliases. Остальные роли доступны для
|
||
постепенного использования; существующие локальные Mantine references не
|
||
переписаны массово. Цвет не заменяет подпись статуса. Палитра не гарантирует
|
||
доступный контраст произвольных сочетаний: для текста и фона проверяйте контекст.
|
||
Grape и orange используются Product; предметные значения задают их FSD-владельцы.
|
||
|
||
Особые card gradients/shadows, размеры страницы и финансовые цвета CSS остаются
|
||
у своих FSD-владельцев. Это сохранение существующего UI, а не завершённый редизайн
|
||
или миграция всех literals в tokens. Новую общую шкалу стоит вводить только при
|
||
реальном повторном использовании, если native Mantine scale не подходит.
|
||
|
||
## Переносимый JSON
|
||
|
||
Файл использует собственный формат WealthLedger `formatVersion: 1`, без runtime
|
||
imports, CSS variables или исполняемого кода. Это контракт данных, а не заявление
|
||
о совместимости с DTCG или importer конкретной системы.
|
||
|
||
| Данные | Представление |
|
||
| --- | --- |
|
||
| Цвета | Hex; palette — массив оттенков 0–9; base — именованные white/black. |
|
||
| Семантическая роль | `color`, `shade`, `description`; ссылка на palette или base. Для palette `shade: null` означает `primaryShade.light`, для base оттенок не нужен. |
|
||
| Типографика | CSS font stacks; размеры и headings в px, веса числовые, line heights без единиц. |
|
||
| Интервалы и радиусы | Именованные `values` xs–xl с `unit: "px"`; `radius.default` выбирает имя шкалы. |
|
||
| Тени | Упорядоченные слои: offsetX/offsetY/blur/spread в px, ссылка `color` на base и opacity 0–1. |
|
||
| Breakpoints | Именованные `values` xs–xl с `unit: "em"`, не зависят от масштаба UI. |
|
||
|
||
Не используйте для палитр специальные имена Mantine `dimmed` и `bright`;
|
||
`white` и `black` принадлежат base colors. Задавайте вес шрифта в диапазоне
|
||
CSS 1–1000. Это правила редактирования формата, а не runtime-проверки.
|
||
|
||
Внешний потребитель читает raw JSON напрямую. Например, из workspace root,
|
||
без Node, React или Mantine:
|
||
|
||
```python
|
||
import json
|
||
from pathlib import Path
|
||
|
||
tokens = json.loads(Path("frontend/src/shared/theme/tokens.json").read_text())
|
||
assert tokens["formatVersion"] == 1
|
||
colors = tokens["color"]
|
||
role = colors["roles"]["primary"]
|
||
shade = role["shade"]
|
||
if shade is None:
|
||
shade = colors["primaryShade"]["light"]
|
||
primary_hex = colors["palettes"][role["color"]][shade]
|
||
```
|
||
|
||
`shared/theme/index.ts` предназначен для frontend: он подключает CSS и Mantine
|
||
runtime. При интеграции с другой системой сопоставьте единицы, font stacks,
|
||
слои теней и semantic references с её форматом; парсер JSON сам этого не делает.
|
||
Несовместимое изменение требует новой версии контракта. Внешняя интеграция,
|
||
генератор артефактов и публикация пакета пока не реализованы.
|
||
|
||
## Общие компоненты
|
||
|
||
Public API — [`shared/ui`](../../frontend/src/shared/ui/index.ts). Минимальный
|
||
каталог включает две существующие реализации, реально используемые приложением:
|
||
|
||
| Компонент | Контракт и правила |
|
||
| --- | --- |
|
||
| StateView | Empty/error с title, text, необязательным action; error получает role alert. Кнопке нужен доступный текст; не использовать для initial loading. |
|
||
| LoadingSkeleton | Общая status/busy-область с доступной label; caller задаёт только декоративные shapes без фокуса. Структура skeleton принадлежит section/page. |
|
||
|
||
Они не импортируют API, auth, счета или позиции. Не создаются wrappers над всеми
|
||
примитивами: для действий используется Mantine Button с общей темой. В каталоге
|
||
показаны filled для основного действия, default для вторичного/retry и subtle
|
||
для вспомогательного, а также loading и disabled. Provider не меняет defaults
|
||
Button или Paper ради каталога. Loading действия не заменяет loading страницы;
|
||
при refetch сохраняются данные и показывается локальное состояние.
|
||
|
||
Route-aware AppShell не входит в заявленный общий набор. Бизнес-компоненты
|
||
и композиции остаются у entities/pages и показываются в Product; витрина не
|
||
определяет FSD ownership. Подробности запуска, взаимодействий и coverage —
|
||
[UI-каталог Storybook](ui-catalog.md).
|
||
|
||
## Границы доказательств
|
||
|
||
Каталог использует synthetic fixtures, локальные Actions и MemoryRouter, без
|
||
application API/auth/storage runtime. Dependency-cruiser проверяет FSD и
|
||
транзитивную runtime-изоляцию stories. Browser проверяет виды, размеры, focus и
|
||
действия. Эти примеры не доказывают API recovery и прохождение инвестиционного
|
||
сценария. Продуктовый пилот остаётся отдельным change и здесь не проводился.
|