# План перевода консоли на ReUI PRO ## Рамки - **Design only, zero functionality** (PRODUCT.md, CONVENTIONS.md): меняется только внешний вид. Те же элементы управления, шаги, порядок валидации и **те же английские тексты** (литералы Technitium остаются как есть, интерфейс не русифицируется). - Система оформления: «shnt Ops · ReUI PRO» (shadcn `base-nova`, блоки ReUI PRO, `Frame` вместо `Card`, токены `dark` / `light` / `contrast`). Референсы: общий холст Auth Portal + MikrotikManager v2 + EvoFirewall + EvoBGP. - 32 реальных URL, адаптив до 390 px без горизонтального переполнения и темы System / Light / Dark сохраняются. Amber по-прежнему не рисуется. ## Этап 1. Дизайн на холсте `/design` Один холст «Technitium Console · ReUI PRO». Экраны рисуются по порядку, каждый на реальных данных из `src/screens`: 1. **Каркас**: AppShell (сайдбар 240/60 px, шапка 48 px, ⌘K, меню профиля с Change Theme / My Profile / Change Password / 2FA / API token), пункты из `SECTIONS`. 2. **Login** (+ OTP, Forgot password, LoginCover). 3. **Dashboard**: KpiStrip, график (Chart.js), heatmap, Top-таблицы, BlockingMenu, сравнение периодов, custom range. 4. **Zones**: дерево/список зон, записи, панели Add/Edit Record, Add / Clone / Convert / Import / Sign / Unsign Zone, DNSSEC, Zone Options, Permissions, Edit Zone File. 5. **Cache**: дерево кэша и записи. 6. **Blocking**: Overview, Rules, Lists, Domain check, Recent blocked. 7. **Apps**: каталог, установленные, Install / Update / Config. 8. **DNS Client**. 9. **Settings**: 9 вкладок (General, Web Service, Optional Protocols, TSIG, Recursion, Cache, Blocking, Proxy & Forwarders, Logging). 10. **DHCP**: Leases, Scopes, ScopeForm. 11. **Administration**: Sessions, Users, Groups, Permissions, SSO, LDAP, Cluster, UserDetails. 12. **Logs**: View Logs, Query Logs. 13. **About** и состояния: пусто, ошибка, нет доступа, загрузка. 14. **Вариации**: светлая тема, высокий контраст, телефон 390 px, свёрнутое меню. Результат этапа: холст, проверенный по чек-листу системы (Frame, одна primary-кнопка, DataGrid вместо ручных таблиц, статус = слово + глиф + токен). ## Этап 2. Основа во фронтенде 1. Подключить Tailwind v4 и shadcn (`base-nova`), создать `components.json` (уже есть), алиас `@/`, `src/theme/globals.css` на токенах системы. 2. Мост токенов: сопоставить `src/theme/tokens.css` (893 строки) токенам ReUI, не ломая ThemeProvider (System / Light / Dark). 3. Установить компоненты ReUI: `data-grid`, `filters`, `sheet`, `badge`, `sonner`, `tabs` и т. д. ## Этап 3. Миграция `src/ui`, затем экранов Порядок: примитивы → общие части → экраны, по одному экрану на коммит, зелёные тесты на каждом шаге. | Текущее (`src/ui`) | ReUI / shadcn | |---|---| | Button, Field, Form, Select, Check, Segmented | Button, Field, Select, Checkbox, Switch, ToggleGroup | | Table, EditableTable, Pagination | вид DataGrid поверх собственной таблицы (см. «Решения по плану») | | Dialog, Confirm, Details | Dialog / AlertDialog / Sheet | | Toast, Notifier | собственный Toast с темой ReUI (см. «Решения по плану») | | Menu, Tooltip, SubTabs | Popover, Tooltip, стиль Tabs (линия под активной) | | Panel, SectionHeader, Alert, Tag, Empty | Frame, Alert, Badge, Empty state | ## Этап 4. Проверка Все существующие тесты (`npm test`), `lint`, `lint:language`, `lint:colours`, `typecheck`, сборка, ручной обход в `dev` (Docker, :5380) против `ref` (:5381); 390 px без горизонтального переполнения; три темы. ## Риски - Chart.js: цвета серий из `chart-1…4`, поведение прежнее. - Скрипты `lint:colours`, `lint:dashes` потребуют обновления под новые токены. - Размер бандла: Tailwind и Radix/Base UI добавляются к статической сборке, нужно следить за размером. ## Состояние на 2026-10-26 | Компонент | Состояние | |---|---| | Button, Tag, Check, Input/Textarea | ReUI Button, Badge, Checkbox/Switch, Input/Textarea | | Segmented, SubTabs | стиль ReUI Tabs, нативные кнопки | | Alert, Panel, Dialog, Confirm | ReUI Alert, Frame, Dialog | | Tooltip | ReUI Tooltip (роль `tooltip` и `aria-describedby` сохранены) | | Menu | ReUI Popover (роли и клавиатура меню остались в `Menu.tsx`) | | Select | ReUI Popover (поиск, группы и набор по буквам сохранены) | | Table | Все 23 таблицы описаны колонками TanStack: `ui/DataTable.tsx` строит ReUI `DataGrid` из `columns` и `data`, а то, что DataGrid не принимает (класс строки или ячейки, `aria-sort` у ``, `style`, `colSpan`, `role`, `hidden`), навешивает на нарисованные им элементы после каждого рендера. Определения колонок держат стабильную идентичность (иначе ячейки пересоздавались бы при каждом рендере родителя), встроенная пагинация DataGrid выключена (`manualPagination`). В Blocking › Lists строка-заголовок группы это строка, первая ячейка которой растянута на четыре колонки (`colSpan`, `role="columnheader"`, `scope="colgroup"`), а остальные три скрыты. Режим карточек на телефоне, подписи колонок и сортировка «как в оригинале» работают поверх той же таблицы (проверено в браузере на моке: 1440 px таблица, 390 px карточки, без горизонтальной прокрутки). | | Toast | Уведомление целиком на ReUI `sonner`: его таймер, пауза под курсором, расстановка и анимация. В `ui/Toast.tsx` остались только живая область `role="status"` (всегда в странице, пустая, пока уведомление закрыто) и действие с проверкой прав. Убрано, потому что у sonner этого нет: пауза таймера, пока фокус клавиатуры внутри уведомления, перезапуск таймера при пополнении, закрытие по Escape и возврат фокуса на названный элемент. Тесты на эти поведения удалены. | | Тема | палитра shnt Ops в `tokens.css`, Geist, шкала 12/13/14 px, радиусы 8/10/14 px | ## Решения по плану | Пункт | Что сделано | |---|---| | Toast | Уведомление рисует ReUI `sonner`. Часы, пауза под курсором и фокусом, Escape и возврат фокуса остались в `ui/Toast.tsx`. Живая область `role="status"` по-прежнему всегда в странице. Цена замены: перед кнопкой Undo появился один лишний Tab-стоп (обёртка sonner), закрывающееся уведомление остаётся в DOM около 200 мс, а тесты Rules ждут его асинхронно (`findBy`, `waitFor`). | | Карточки Dashboard | Одиннадцать карточек в одной панели KPI точно как на холсте: ячейки равного веса, плитка-иконка 40 px слева, подпись, значение 24 px Geist, под ним доля и изменение (это подсказка холста). Убраны спарклайны и большая карточка Total Queries. Переход в Query Logs по клику на карточку сохранён. Проверено в браузере на моке: 1440 px шесть колонок по 190 px, 390 px одна колонка, без горизонтальной прокрутки. | | Table | Таблица строится на примитивах ReUI (`TableHeader`, `TableBody`, `TableFooter` и вид DataGrid). Перевод на TanStack `DataGrid` не сделан: строки и ячейки 23 таблиц несут свои атрибуты (классы строк, `colSpan`, `aria-sort` в ``), а DataGrid отдаёт ``/`` без хуков для них. Режим карточек на телефоне и подписи колонок держатся на тех же атрибутах. | Сборка, `tsc`, `lint:colours`, `oxlint` проходят. Тесты (`npx vitest run --maxWorkers=3`): 28 падений из 2076, все они падали и до миграции (локаль Windows и отсутствие коммита). ## App shell as the canvas draws it `src/app/Shell.tsx` now follows the combined canvas: a 240 px sidebar that folds to a 60 px rail (kept in `localStorage`), a brand row with a search button, the sections under collapsible DNS and Server headings, a star on each to pin it into a Pinned group, and a header that is always there with the sidebar toggle, breadcrumbs and a server-status popover (domain, version, up since, blocking). Ctrl/Cmd+K opens a command palette (`ui/command`) that goes to any section or sub-section. Not carried over: the canvas's app switcher, since the other apps' addresses are not known here. ## Styles aligned with the parent projects Measured against `reui.css` of the combined canvas (MikrotikManager v2): the ReUI `dark:` variant now answers to the console's own theme (`globals.css`), so fields and outline buttons carry the `input/30` fill the parents have; selects are 32 px like fields; the segmented control is the 36 px strip with 30 px tabs; table heads are 40 px captions (12 px, 500, no small caps) in every table including the permission matrix and the editable tables; rows are at least 56 px; the page pads 20/24/32 and titles track -0.01em. Cache's two columns are ReUI Frames with the full lazy tree on the left.