DI2: отчёт по этапу 2 (мост тем/скинов iistwin)

This commit is contained in:
2026-09-06 23:33:18 +03:00
parent b4579340ff
commit 0834356286

View File

@@ -0,0 +1,47 @@
# Отчёт этапа 2 — Мост тем/скинов iistwin в DI2
Дата: 2026-09-07. Коммит: **`b457934`** — `DI2: мост тем/скинов iistwin — Di2ThemeProvider, общий generated-skins.css, токены в формате основного клиента` (32 файла, +588/−348). Push в main выполнен, pre-push hook (check+build) — «All checks passed». Автодеплой запущен.
## Что сделано
### Общий код тем
- `vite.config.di2.ts` — алиас `@skin` → `client/src/themes` (resolve.alias; покрывает `@skin` и `@skin/*`).
- `client-di2/tsconfig.json` — paths: `"@skin": ["../client/src/themes/index.ts"]`, `"@skin/*": ["../client/src/themes/*"]`.
- `client-di2/src/index.css` — первой строкой `@import '../../client/src/themes/styles/generated-skins.css'` (8 селекторов `[data-skin="..."][data-theme="..."]` в собранном CSS — проверено).
### Di2ThemeProvider (`client-di2/src/themes/Di2ThemeProvider.tsx`, новый)
- Порт логики `client/src/themes/ThemeProvider.tsx` без useAuth/useQuery (plain fetch, credentials: include).
- Приоритет скина: `localStorage['skin']` (валидация среди BUILT_IN_SKINS + кастомных с сервера) → `GET /api/organization/current-skin` → `'iistwin'`. Формат ответов сверён с `server/routes/organization-skins.routes.ts` (`{success, skins: [{id, name, description, isEditable, isBuiltIn}]}`, `{success, skinId, skin}`, `{success, skin}`).
- Кастомные скины: список через `/api/organization/skins`, токены текущего кастомного — через `/api/organization/skins/:id`; runtime CSS через `generateSkinCss` в `<style id="skin-runtime">` (тот же генератор, что в основном клиенте).
- Тема: `localStorage['theme']` → `prefers-color-scheme` + слушатель.
- На `<html>`: `data-skin`, `data-theme`, класс `light|dark`. Ключи localStorage общие с основным приложением — выбор синхронизируется iistwin ↔ /di2.
- Экспортирует `useDi2Theme()` (theme/setTheme/toggleTheme/skinId/setSkinId/availableSkins) и `useDi2Skin()` — для переключателя темы на этапе 3.
- `client-di2/src/main.tsx` — `<Router base="/di2"><Di2ThemeProvider><App/></Di2ThemeProvider></Router>`.
### Перевод DI2 на полный формат токенов
- `client-di2/tailwind.config.ts` — все цвета `hsl(var(--x) / <alpha-value>)` → `var(--x)`; радиусы → `var(--radius)` + каскад `calc(-2px/-4px)`; добавлены `warning/success/info` (+foreground); структура `sidebar`/`sidebar-primary`/`sidebar-accent` и DI2-nested border'ы (`card.border` → `card-border` и т.д.) сохранены; `status` (rgb, неиспользуемый) оставлен без изменений.
- `client-di2/src/index.css` — собственные `:root`/`.dark` HSL-тройки заменены fallback-блоками из `client/src/index.css:13-138`; DI2-only переменные переопределены: `--card-border`/`--popover-border` → `var(--border)`, `--primary-border`/`--secondary-border`/`--muted-border`/`--accent-border`/`--destructive-border`/`--sidebar-primary-border`/`--sidebar-accent-border` → `color-mix(in oklab, var(--X) 82%, black)`, `--button-outline` → `color-mix(in oklab, var(--primary) 35%, transparent)`, `--badge-outline` → `color-mix(in oklab, var(--muted-foreground) 35%, transparent)`, `--elevate-1/2` → `rgba(0,0,0,.05/.08)` (в `.dark` — светлые); удалены `--opaque-button-border-intensity` и все `hsl(from ...)` relative-color блоки; жёсткие `--font-sans: Open Sans` и т.п. удалены (шрифты эмитит `generateSkinCss` из токенов скина); `hsl(var(--muted-foreground))` в contenteditable-плейсхолдере → `var(--muted-foreground)`. Слой elevate-утилит DI2 (hover-elevate и т.д.) сохранён — используется badge/button.
- `client-di2/index.html` — `lang="ru"`, viewport без `maximum-scale=1` + `interactive-widget=resizes-content`, оба preconnect и мега-link (23 семейства) заменены одним линком Inter + DM Mono как в `client/index.html:23`.
### Alpha-модификаторы семантических цветов — важная находка
Эмпирическая проверка на Tailwind 3.4.19 (тестовый скрипт, затем удалён): класс с модификатором прозрачности (`bg-muted/50`) для цвета-`var()` **молча не генерируется** в CSS вообще (Tailwind не умеет alpha для var-цветов; трюки с `<alpha-value>` + color-mix в конфиге дают битый CSS через legacy `--tw-bg-opacity`). Основной клиент iistwin живёт с этим же ограничением.
Решение (как в плане): 166 вхождений в client-di2/src заменены скриптом `tmp/di2-alpha-replace.cjs` (удалён после прогона) на arbitrary values: `bg-muted/50` → `bg-[color-mix(in_oklab,var(--muted)_50%,transparent)]`. Варианты (`hover:`, `aria-selected:`, arbitrary-variant) сохраняются. Палитровые цвета (`bg-green-500/10`, `bg-black/80` и т.п. — с ними alpha работает штатно) не тронуты. Полный список заменённых паттернов — в выводе скрипта (скопирован в git-коммит-сообщение частично, полный лог не сохранялся; повторяемость: bg-muted/50 ×37, bg-muted/30 ×28, border-muted-foreground/30 ×10 и т.д.).
## Проверки
- `npm run check` (tsc корневой + `tsc -p client-di2/tsconfig.json`) — чисто.
- `npm run build` (main → di2 → server) — успешно.
- Собранный `dist/public-di2/assets/index-*.css` (116.4 kB, было 88.3 kB) проверен grep/node: `.bg-primary{background-color:var(--primary)}`, 8 селекторов `[data-skin=...]`, правила `color-mix(in oklab,var(--muted) N%,transparent)` для bg/border/divide/stroke/text + hover-варианты, `border-radius:var(--radius)`.
- JS-бандл DI2 вырос с 1363 до 1405 kB (~42 kB — модули тем/скинов), ожидаемо.
## Отклонения от плана
1. План предполагал, что замена alpha-модификаторов может быть не нужна, если Tailwind справится; фактически без замены классы исчезли бы из CSS — замена выполнена массово (166 мест), как и предписывал план.
2. `--elevate-1/2`: план → `rgba(0,0,0,.05/.08)`; основной клиент использует `.03/.08` (light) и `.03/.08` (dark). Следовал плану: light `.05/.08`, dark `rgba(255,255,255,.05/.08)`.
3. `bg-warning` и др. пока не используются в DI2 — классы не генерируются (конфиг готов к этапу 3).
4. В собранном CSS замечен `var(--color-border)` из `client-di2/src/components/ui/chart.tsx` (собственная индикатор-переменная recharts-обёртки, inline-стили) — не конфликтует с нашими токенами, не трогал.
## Оставшееся (этапы 3–4)
Этап 3 (визуальный рестайл: графики var(--chart-*), хардкод-цвета, таблицы, контролы, нижняя панель по референсу FinanceBottomNav.reference.tsx, переключатель темы), этап 4 (проверка, документация, ручной Google redirect URI).