145 lines
9.2 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Дизайн-системный рефакторинг брокерских страниц — Plan
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development
> (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use
> checkbox (`- [ ]`) syntax for tracking.
**Goal:** Удалить legacy-стили из страниц и компонентов брокерского раздела: CSS-классы,
`inline styles`, `SkeletonBlock`, `TableSkeleton` → перевести на `@moex-vibe/design-system`.
**Architecture:** Бизнес-логика, контракты и маршрутизация меняться не будут.
Градиенты героических секций, которые не имеют DS-эквивалента, сохраняются как `sx`-инлайн-стили.
SVG-диаграмма (`BrokerAllocationChart`) сохраняется как есть, меняются только обёртки.
**Tech Stack:** React 18, MUI 6.5, `@moex-vibe/design-system` 0.1.0, CSS custom properties.
**Связанные документы:**
- Epic: `docs/epics/BrokerPortfolio.md`
- Функциональная базовая фича: `docs/features/broker-account-sections/spec.md`
- Research: `docs/research/2026-06-18-broker-account-sections.md`
---
## Task 1: BrokerAccountLayout
Заменить layout shell на DS.
- `div.broker-account``<Box component="div">`
- `header.broker-account__header``<Box>` flex
- `h1``<Heading level={1}>`
- `nav.broker-account__navigation``<Box component="nav">`
- `NavLink` классы → при оставлении `className` callback (уникальный prefix для active state), но в первую очередь сменить на `Box` + `<Button>` или DS Tabs если доступен (DS Tabs/doc check)
- `div.broker-account__workspace``<Box>` grid (desktop sidebar + mobile row)
- `div.broker-account__content``<Box>` c overflow-auto
- Удалить CSS для `.broker-account__header`, `.broker-account__workspace`, `.broker-account__navigation`, `.broker-account__link`, `.broker-account__content` в `styles.css`
## Task 2: BrokerAccountOverviewPage, BrokerSummary, BrokerAssetCards
Перевести три связанных компонента overview на DS.
- `div.broker-overview``<Box component="div">`
- `section.broker-overview__summary``<Box>` grid
- `div.broker-overview__card` + inline-спаны → `<Box>` (card container) + `<Text>`
- `<span className="broker-overview__label">``<Text variant="label" tone="secondary">`
- `<strong>` значения → `<Text sx={{ fontWeight: 700 }}>`
- `ul.broker-overview__cash``<Box component="ul">` + `<Box component="li">`
- `section.broker-overview__assets``<Box>` grid
- `Link.broker-overview__asset-link``<Link>` + `<Box>` для layout карточки
- `<strong className="broker-overview__asset-title">``<Text sx={{ fontWeight: 700 }}>`
- Спаны значений/процентов → `<Box component="span">` + `<Text>`
- Оставить hero-gradient (`broker-overview__hero`-style) на caretaker'е (см. Out of scope)
## Task 3: BrokerOverviewSkeleton
Заменить старые skeleton на DS-component.
- Импорт `SkeletonBlock` → DS `Skeleton`
- `div.broker-overview__card``<Box>` для контейнера skeleton-элементов
- `SkeletonBlock height={...} width={...}``<Skeleton height={...} width={...} shape="text">`
- `SkeletonBlock borderRadius={80}``<Skeleton height={160} width={160} shape="circular">`
## Task 4: BrokerAllocationChart (wrap only)
Оставить SVG без изменений, мигрировать только обёртки.
- `figure.broker-allocation``<Box component="figure">`
- `figcaption``<Box component="figcaption">`
- `<p>` в пустом состоянии → `<Text tone="muted">`
- `<ul>` / `<li>` легенды → `<Box component="ul">` + `<Box component="li">`
- `span.broker-allocation__swatch``<Box}` с inline-цветом в `sx`
- Спаны текста легенды → `<Text>` или `<Box component="span">` с кастомным `fontSize`
- `ul.broker-allocation__negative``<Box component="ul">`
- Удалить CSS для `.broker-allocation*` в `styles.css` (кроме SVG-правил, которые оставить нетронутыми или перенести в inline)
## Task 5: BrokerPositionTable, PositionTicker
Миграция таблицы позиций.
- Вспомогательные типы для `headerStyle`, `cellStyle`, `pagButtonStyle` → MUI `sx` через `<Box>`, `<Button>`
- Импорт `SkeletonBlock` в компоненте → удалить, использовать `Skeleton` через `<TableSkeleton>` (см. Task 6)
- `h2` inline-стили → `<Heading level={2}>` с кастомной `sx` для размера/масштаба
- Ошибки/пустые `<p>``<Text>` через Box с inline-цветом
- `PositionTicker`: `<Link style={{ fontWeight: 700 }}>``<Link>` с `<Text sx={{ fontWeight: 700 }}>` внутри
- `table``<table component="table">` или оставить нативным table, но стилизовать через `sx`
- Сохранить `loading-spinner` класс в `styles.css` (глобальный):
- `TableSkeleton``<Skeleton>` after DS migration
- Keep `table-container` as minimal CSS or remove; convert `loading-overlay` to Box.
## Task 6: TableSkeleton
Заменить импорт `SkeletonBlock` на DS `Skeleton`.
- Убрать импорт `SkeletonBlock`, заменить на `Skeleton` из `@moex-vibe/design-system`.
- `SkeletonBlock height={12} width={col.width}``<Skeleton height={12} width={col.width} shape="text"/>`.
## Task 7: BrokerOperationsTable
Миграция таблицы операций.
- Вспомогательные стили (`tableStyle`, `thStyle`, `tdStyle`, `pagButtonStyle`) → inline-`sx` или `<Box>`
- Оставить `<select>` нативный, но обёрнуть в `<Box component="label">`
- `h2 inline``<Heading level={2}>` с `sx={{ fontSize: 20 }}`
- `<span role="status">` с `loading-spinner``<Skeleton shape="circular" width={14} height={14} />` (если DS поддерживает) или оставить `<span className="loading-spinner">` временно; DS `Skeleton` не имеет circular-only без width/height — оставить на этой итерации, можно оставить loading-spinner, так как это глобальный анимационный класс, а не DS.
- Пустые состояния / alert-тексты → `<Text tone="muted">` / `<Text tone="negative">`
- Пагинация `<button>``<Button variant="secondary">`
- `aria-label` — сохранить.
## Task 8: BrokerPositionsPage, BrokerOperationsPage
Миграция "обёрточных" страниц-секций.
- `section``<Box component="section">`
- `h2 inline``<Heading level={2}>` с `sx={{ fontSize: 20 }}`
- `p role="alert"``<Text tone="negative" component="p">` (или `<Box component="p">`)
- `p.empty``<Text tone="muted">`
- `div.broker-operations__toolbar``<Box>` с flex
- `label > span + select``<Box component="label">` + `<Text>` + `<select>`
## Task 9: SkeletonBlock удаление
После замены всех потребителей:
1. Удалить `apps/frontend/src/shared/ui/SkeletonBlock.tsx`.
2. Удалить экспорт из `apps/frontend/src/shared/ui/index.ts`.
3. Убедиться, что `import { SkeletonBlock }` не осталось нигде.
## Task 10: Очистка `styles.css`
- Удалить все selector'ы из блока `broker-account__*`, `broker-overview__*`, `broker-allocation__*` (SVG стили оставить), `broker-operations__toolbar*`.
- Оставить косметические классы, которые ещё не мигрированы (если таковые возникнут).
- Оставить `.loading-spinner` (глобальный анимационный класс, применяется через `className` где-то еще).
- Оставить `:root` CSS variables — они DS взаиморасчётные токены.
## Task 11: Тестирование и сборка
- [ ] `npm run test:frontend` — все тесты PASS.
- [ ] `npm run lint -w apps/frontend` — без ошибок.
- [ ] `npm run build:frontend` — без TypeScript/Vite ошибок.
- [ ] Проверить, что нет остатков `SkeletonBlock` импортов в кодовой базе: `grep -r "SkeletonBlock" apps/frontend/src`.
- [ ] Проверить, что нет остатков `broker-account__*`, `broker-overview__*`, `broker-allocation__*`, `broker-operations__toolbar` в TSX: `grep -rE "broker-(account|overview|allocation|operations)" apps/frontend/src --include='*.{ts,tsx}'`.
## Task 12: Вердикт и записка
- [ ] Обновить `docs/features/broker-account-sections-ds-migration/tasks.md` — отметить все выполненные пункты.