# ADR-005: Design Tokens как единый источник стилей **Статус:** принято **Дата:** 2026-05-10 --- ## Контекст Проект VoIdea работает на нескольких платформах: - Web (PWA) - iOS (Swift/SwiftUI) - Android (Kotlin) Требуется унифицировать стили (цвета, шрифты, отступы) между всеми платформами. Рассматривались: - **Ручное копирование** — непоследовательно, сложно поддерживать - **Shared library** — требует синхронизации - **Design Tokens (JSON)** — единый источник, генераторы --- ## Решение **Design Tokens в JSON + генераторы для каждой платформы** ``` docs/design-system/tokens.json (источник истины) │ ├── generators/css_generator.py → app/design-tokens/css/theme.css ├── generators/swift_generator.py → app/design-tokens/swift/Colors.swift └── generators/kotlin_generator.py → app/design-tokens/kotlin/colors.xml ``` --- ## Структура tokens.json ```json { "version": "1.0.0", "project": "VoIdea", "themes": ["system", "dark", "light"], "colors": { "primary": { "500": "#6366F1", "600": "#4F46E5", "default": "#6366F1", "hover": "#4F46E5" }, "background": { "system": "auto", "dark": "#0F172A", "light": "#FFFFFF" }, "semantic": { "error": "#EF4444", "warning": "#F59E0B", "success": "#22C55E", "info": "#3B82F6" } }, "typography": { "font_family": { "primary": "Inter, system-ui, sans-serif" }, "size": { "xs": "0.75rem", "sm": "0.875rem", "base": "1rem" } }, "spacing": { "xs": "0.25rem", "sm": "0.5rem", "md": "1rem", "lg": "1.5rem" }, "border_radius": { "sm": "0.25rem", "md": "0.5rem", "lg": "0.75rem" } } ``` --- ## Генераторы ### CSS Generator ```python # docs/design-system/generators/css_generator.py def generate(tokens: dict) -> str: css = ":root {\n" for category, values in tokens.items(): if category == "colors": for name, value in flatten(values): css += f" --color-{name}: {value};\n" elif category == "typography": for name, value in flatten(values): css += f" --font-{name}: {value};\n" elif category == "spacing": for name, value in flatten(values): css += f" --spacing-{name}: {value};\n" css += "}\n" return css ``` **Выход:** `app/design-tokens/css/theme.css` ```css :root { --color-primary: #6366F1; --color-background-dark: #0F172A; --font-family-primary: Inter, system-ui, sans-serif; --spacing-md: 1rem; } ``` --- ### Swift Generator ```python # docs/design-system/generators/swift_generator.py def generate(tokens: dict) -> str: swift = "import SwiftUI\n\n" swift += "enum Colors {\n" for name, value in flatten(tokens["colors"]): snake_to_camel = to_camel_case(name) swift += f' static let {snake_to_camel} = Color(hex: "{value}")\n' swift += "}\n" swift += "enum Typography {\n" # ... font generation return swift ``` **Выход:** `app/design-tokens/swift/Colors.swift` ```swift import SwiftUI enum Colors { static let primary = Color(hex: "#6366F1") static let backgroundDark = Color(hex: "#0F172A") } enum Typography { static let fontFamilyPrimary = "Inter" static let fontSizeBase: CGFloat = 16 } ``` --- ### Kotlin Generator ```python # docs/design-system/generators/kotlin_generator.py def generate(tokens: dict) -> str: xml = '\n' xml += '\n' for name, value in flatten(tokens["colors"]): safe_name = name.replace("_", "_") xml += f' {value}\n' xml += '\n' return xml ``` **Выход:** `app/design-tokens/kotlin/colors.xml` ```xml #6366F1 #0F172A ``` --- ## Темы ### System (Auto) ```css @media (prefers-color-scheme: dark) { :root[data-theme="system"] { --color-background: #0F172A; --color-text: #F8FAFC; } } @media (prefers-color-scheme: light) { :root[data-theme="system"] { --color-background: #FFFFFF; --color-text: #0F172A; } } ``` ### Dark / Light ```css [data-theme="dark"] { --color-background: #0F172A; --color-text: #F8FAFC; } [data-theme="light"] { --color-background: #FFFFFF; --color-text: #0F172A; } ``` --- ## CI/CD Integration ```yaml # .github/workflows/design-system.yml on: push: paths: - 'docs/design-system/tokens.json' jobs: generate: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Generate CSS run: python -m generators css - name: Generate Swift run: python -m generators swift - name: Generate Kotlin run: python -m generators kotlin - name: Commit run: | git add app/design-tokens/ git commit -m "style: regenerate design tokens" git push ``` --- ## Правила использования 1. **Никогда не редактировать сгенерированные файлы вручную** 2. **Все изменения только в tokens.json** 3. **После изменения tokens.json → запустить генераторы** 4. **DocAgent обновляет документацию** --- ## Maintenance ### Обновление tokens.json 1. Открыть `docs/design-system/tokens.json` 2. Внести изменения 3. Запустить `python -m generators all` 4. Проверить сгенерированные файлы 5. Зафиксировать в git ### Добавление новых token ```json { "new_token": { "system": "auto", "dark": "#value", "light": "#value" } } ``` --- ## Последствия ### Положительные - Единый источник истины - Согласованность между платформами - Легко добавлять темы - Автоматическая генерация ### Отрицательные - Дополнительный слой абстракции - Требует генерацию при изменениях - Разные форматы вывода --- ## Ответственный **Decision maker:** Frontend team **Review date:** При добавлении новой платформы --- *Создано: 2026-05-10* *Обновляется DocAgent при изменениях*