Files
voidea/docs/adr/005-design-tokens.md
T

330 lines
6.9 KiB
Markdown

# 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 = '<?xml version="1.0" encoding="utf-8"?>\n'
xml += '<resources>\n'
for name, value in flatten(tokens["colors"]):
safe_name = name.replace("_", "_")
xml += f' <color name="{safe_name}">{value}</color>\n'
xml += '</resources>\n'
return xml
```
**Выход:** `app/design-tokens/kotlin/colors.xml`
```xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="primary">#6366F1</color>
<color name="background_dark">#0F172A</color>
</resources>
```
---
## Темы
### 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 при изменениях*