10 KiB
Дизайн-система WealthLedger
Общий фундамент находится в
frontend/src/shared/theme.
Его public API экспортирует theme, cssVariablesResolver, colorRoles, designTokens и
подключает базовые CSS. App владеет MantineProvider; Storybook подключает свой
изолированный provider к тому же API. Тема и значения не копируются в preview.
Оба runtime используют светлую схему; dark 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 проверяет source через
установленный Zod и tokens.schema.ts,
затем адаптирует данные в Mantine. Схема проверяет структуру, единицы и диапазоны,
число оттенков и ссылки ролей; ошибочные данные не подменяются defaults.
Размеры px преобразуются native rem, сохраняя --mantine-scale, тени собираются
из слоёв с rgba, а breakpoints остаются em без масштабирования. Неопубликованные
палитры и настройки поведения компонентов остаются defaults Mantine.
Используйте props Mantine (gap="md", p="xl", radius="md", shadow="xs")
или --mantine-spacing-*, --mantine-radius-* и другие native CSS variables.
Foundations
читает эффективную тему и описания из 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. |
Имена палитр dimmed и bright зарезервированы адаптером Mantine;
white и black принадлежат base colors. Вес шрифта ограничен диапазоном 1–1000.
Внешний потребитель читает raw JSON напрямую. Например, из workspace root, без Node, React или Mantine:
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. Минимальный
каталог включает две существующие реализации, реально используемые приложением:
| Компонент | Контракт и правила |
|---|---|
| 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.
Границы доказательств
Каталог использует synthetic fixtures, локальные Actions и MemoryRouter, без application API/auth/storage runtime. Dependency-cruiser проверяет FSD и транзитивную runtime-изоляцию stories. Browser проверяет виды, размеры, focus и действия. Эти примеры не доказывают API recovery и прохождение инвестиционного сценария. Продуктовый пилот остаётся отдельным change и здесь не проводился.