⟨/⟩ 40_Arch/Tech/Angular/ADR_UI_004_Styling.cs

175 строк · в начало

using System;
using Ban.Sdaid.Notation.Documents;
using Ban.Sdaid.Icd;

namespace Ban.Sdaid.Icd.Arch.Tech.Angular
{
    /// <summary>
    /// ADR-UI-004: Стилевая система и токены. Двухуровневые дизайн-токены (примитивы + семантика)
    /// на CSS custom properties `--icd-*`, значения — в `ui/tokens/`. Без внешнего UI-kit.
    /// </summary>
    public class ADR_UI_004_Styling : IAdrDocument, IFolder<ArchAngularFolder>
    {
        public string Name => "ADR-UI-004. Стилевая система и токены";

        public string Description =>
            @"Нужна единая токен-система: согласованный набор цветов, интервалов, типографики — один
источник, никаких «магических» значений по компонентам. Механизм — CSS custom properties `--icd-*`
(без препроцессорной палитры), что заодно открывает runtime-смену темы. Значения токенов ведём в
`ui/tokens/`.";

        public string Version => "1.0";
        public string Status => "accepted";
        public string[] Comments => new[]
        {
            "2026-08-11. Принято следом за ADR-UI-003.",
        };

        public Type? Supersedes => null;

        public static string S1_Context = """
            ## Контекст и постановка задачи

            Любому компоненту набора `ui/` нужен единый источник цветов, интервалов и типографики — чтобы
            менять тему в одной точке и не плодить разрозненные значения по компонентам. Механизм
            зафиксирован предыдущими ADR: CSS custom properties `--icd-*` в `ui/tokens/`, SCSS для
            организации, без внешнего UI-kit (ADR-UI-001, ADR-UI-003). Здесь фиксируется **модель токенов**
            (структура, именование, правила).
            """;

        public static string S2_DecisionDrivers = """
            ## Драйверы решения

            1. **Один источник значений** — никаких HEX/«магических» px в компонентах; всё через токены.
            2. **Явная семантика** — компонент выражает намерение («цвет ссылки», «фон primary-кнопки»), а не
               сырой тон.
            3. **Переносимость** — токены живут в `ui/tokens/` и едут вместе с набором; набор самодостаточен.
            4. **Runtime-темизация** — CSS custom properties позволяют переопределять тему без пересборки
               (тёмная тема / тема под клиента — на будущее).
            """;

        public static string S3_ConsideredOptions = """
            ## Рассмотренные варианты

            - **A. Препроцессорная палитра** (Less/SCSS-миксины, значения на этапе сборки) — не даёт
              runtime-темизации, значения «зашиты» в собранный CSS.
            - **B. CSS custom properties, двухуровневые (примитивы + семантика)** — runtime-темизация,
              явная семантика, самодостаточный набор токенов в `ui/tokens/`.
            - **C. Захардкоженные значения / utility-фреймворк** — рвёт единый источник и семантику, чужая
              шкала.
            """;

        public static string S4_DecisionOutcome = """
            ## Решение

            Выбран **Вариант B**. Токены — CSS custom properties с префиксом `--icd-*`, **двухуровневые**:
            слой примитивов и слой семантики. Значения ведём в `ui/tokens/`; по правилу одного факта в этом
            ADR фиксируются структура, именование и правила, а не полный перечень значений.

            ### Двухуровневая модель токенов

            1. **Примитивы** — «сырые» значения ролей и шкалы тонов. Роли: `primary`, `neutral`, `danger`,
               `success`, `warning`, `info`, `green`. Шкала тонов `100…1000` (заполняется по факту
               использования). Пример: `--icd-primary-600: #5c6bf2;`.
            2. **Семантические токены** — назначение поверх примитивов, через `var(...)`. Группы:
               `text` / `bg` / `brd` / `icon` (общие и семантические), `control` (кнопки: типы
               `primary/secondary/tertiary/ghost/danger/inverse` × состояния `default/hover/click/disable/focus`),
               `form` (поле/метка/значение/маска по состояниям), `link`. Пример:
               `--icd-color-text-link-default: var(--icd-primary-600);`.

            Компоненты `ui/` обращаются к токенам через `var(--icd-...)` — по возможности к **семантическим**
            (не к примитивам напрямую), чтобы смысл был явным.

            ### Именование токенов

            Дефисная нотация с префиксом `--icd-`, по шаблону «группа → уточнения → состояние»:

            | Тип | CSS custom property | Пример значения |
            |---|---|---|
            | Примитив цвета | `--icd-primary-600` | `#5c6bf2` |
            | Семантика цвета | `--icd-color-text-link-default` | `var(--icd-primary-600)` |
            | Control (кнопка) | `--icd-color-bg-control-primary-default` | `var(--icd-primary-500)` |
            | Интервал | `--icd-space-x2` | `8px` (шкала на базе 4px) |
            | Радиус | `--icd-radius-field` | `8px` |
            | Высота | `--icd-size-height-button` | `32px` |
            | Focus | `--icd-border-focus` | `4px` |

            ### Типографика

            Шрифтовые **примитивы** — CSS-переменные: семейства `--icd-font-header`, `--icd-font-body`;
            размеры, веса (`400/500/600`), межстрочные интервалы. **Текстовые стили** (заголовки `H1…H5`,
            body `M/S/XS` в вариантах веса) оформляются как SCSS-миксины/utility-классы набора — композитный
            стиль удобнее миксином, чем одной CSS-переменной.

            ### Структура `ui/tokens/`

            ```
            app/ui/tokens/
            ├── _primitives.scss   # :root { --icd-<role>-<tone>: … } — цвета-примитивы + база
            ├── _semantic.scss     # :root { --icd-color-…: var(--icd-…) } — семантика
            ├── _typography.scss    # шрифтовые переменные + миксины текстовых стилей
            ├── _spacing.scss       # --icd-space-x*, радиусы, высоты, border, focus
            └── index.scss          # агрегатор (подключается из src/styles.scss)
            ```

            ### Кастомизация под проект

            Значения по умолчанию лежат в `ui/tokens/`. Переопределение (тёмная тема, тон под клиента) —
            в `src/styles/theme/` переопределением значений тех же переменных (ADR-UI-003), без правки
            компонентов.

            ### Правила

            1. **Значения — только в `ui/tokens/`** (и переопределения в `styles/theme/`). В компонентах —
               только `var(--icd-...)`.
            2. **Никаких HEX / «магических» px** в стилях компонентов и inline-стилях.
            3. Предпочитать **семантические** токены примитивам в компонентах.
            4. Интервалы — только `--icd-space-*`; радиусы/высоты/типографика — соответствующие токены/миксины.
            """;

        public static string S5_PositiveConsequences = """
            ## Положительные следствия

            - Смена темы/тона — одна точка (`ui/tokens/` или `styles/theme/`), компоненты не трогаются.
            - Явная семантика токенов делает стили компонентов читаемыми и устойчивыми к смене палитры.
            - CSS custom properties дают runtime-темизацию (тёмная тема и пр.) без пересборки.
            - Токены самодостаточны в `ui/tokens/` — набор переносится без внешних стилевых зависимостей.
            """;

        public static string S6_NegativeConsequences = """
            ## Отрицательные следствия и компромиссы

            - Двухуровневость (примитивы + семантика) — больше файлов/имён, чем плоская палитра; окупается
              явностью смысла.
            - Дисциплина: каждый варьируемый параметр компонента должен идти через токен, а не литерал.
            - Шкала тонов заполняется по факту — часть ступеней долгое время пустует.
            """;

        public static string S7_Validation = """
            ## Проверка

            - В стилях компонентов нет HEX-литералов и «магических» px (grep по `#[0-9a-fA-F]{3,}` и голым
              px вне `ui/tokens/`).
            - Смена значения `--icd-primary-600` перекрашивает primary-акценты во всём приложении без других
              правок.
            - Каждый компонент `ui/` использует только `var(--icd-...)` для цветов, интервалов и типографики.
            """;

        public static string S8_OpenQuestions = """
            ## Открытые вопросы / отложено

            - **Подключение шрифтов** (self-host / источник, набор начертаний) — уточнить при первой
              реализации.
            - **Тёмная тема / тема под клиента** — возможна на CSS custom properties; реализация отложена до
              требования.
            """;

        public static string S99_Related = $"""
            ## Связанные артефакты

            - {nameof(Ban.Sdaid.Icd.Arch.Tech.Angular.ADR_UI_001_Stack)} — Технологический стек (SCSS, CSS-токены).
            - {nameof(Ban.Sdaid.Icd.Arch.Tech.Angular.ADR_UI_003_ProjectStructure)} — Размещение токенов в `ui/tokens/` и `styles/theme/`.
            """;
    }
}