Files
easy-png-tools2/docs/plan-redesign.md
T

29 KiB
Raw Blame History

План: переезд на новый дизайн (refs) — параллельная сборка

Статус: план к выполнению.

Источники: refs/ — Next/React-референс (правда по пикселям и интерактиву), refs-html/ — статические HTML-снимки для быстрого просмотра в браузере.

Стратегия изменена. Вместо in-place рестайла (старый план A–F, правка общих компонентов на месте с алиасами токенов) — параллельная сборка: новый дизайн строится отдельно, изолируется от старого, проверяется целиком, затем становится основным и старый удаляется. Старое приложение остаётся рабочим и шippable на всём протяжении перехода.

0. Почему меняем стратегию

  • Старый план (AF): правим ui/* и страницы на месте, держим старые токены как алиасы, чтобы ничего не сломалось до этапа F. Риск: общие компоненты редактируются вживую → регресс старого UI во время работы, новый дизайн нельзя принять изолированно.
  • Новый подход (5 фаз): (1) строим новый ui-kit, (2) строим новые страницы рядом, не трогая старые, (3) проверяем новый дизайн, (4) делаем его основным, (5) удаляем старый. Ниже фазы 1–5 — это требуемые шаги.
  • Главный технический риск и его решение. Сейчас web/src/app.css импортируется в корневом web/src/routes/+layout.svelte:2 и потому грузится на ВСЕХ маршрутах, включая новые. Решение — не префиксовать новый CSS (никакого .ds2), а разнести глобальные стили по layout'ам без наследования: (а) убрать import '../app.css' из корневого layout; (б) старые маршруты обернуть группой (old)/ с собственным layout, импортирующим app.css; (в) новые маршруты (preview/*) — собственный layout, импортирующий design2.css. SvelteKit делает code-splitting CSS по маршрутам, а стили компонентов скоупятся сами — поэтому глобальные стили каждого дизайна живут только в своей ветке, и префикс-обёртка .ds2 не нужна. Старые ui/ и страницы не трогаются до фазы 5.

1. Источники и их оценка

refs-html/ — витрина разметки

Покрытие достаточное:

Файл Что показывает Оценка
index.html Главная: pipeline-воркспейс + превью
demo.html Зеркало index.html (идентичны) ⚠️ дубликат
gradient.html Инструмент «Градиент»: настройки + превью (тёмная тема)
background-remover.html Инструмент «Удаление фона»: source/result (тёмная тема)
list-tools.html Каталог инструментов
  • Статика без JS — интерактив (тумблеры/слайдеры/перетаскивание) брать из кода refs/, не из HTML. HTML — только визуальная правда по разметке/классам.
  • По 4 файлам собран инвентарь классов — это и есть спецификация kit'а: app-shell, page-grid, eyebrow, brand-mark, topbar, footer, panel-heading, setting-group, settings-footer, settings-panel, segmented, status, step-card (step-index/step-heading/step-type/ step-body/drag), color-field (swatch/native-color), preview-toolbar/checker (tile-canvas/remover-canvas/comparison-grid), result-meta/meta-row, tool-card/image-card (tool-icon/tool-index/ tool-copy), code-block, icon-btn, download-btn, reset-btn, lede, auto-note, label, toggle/toggle-group, direction-grid, gradient-bar.
  • Дыры в refs-html: нет состояний empty/error/loading, нет глобальных модалок/тултипов, i18n не представлен (все лейблы — английские брендовые). Решения — см. §9.

2. Токены (фундамент нового дизайна)

Живут в src/lib/styles/design2.css как обычный :root { … } (плюс [data-theme='dark'] { … }). Файл грузится только layout'ом новой ветки (§5), поэтому глобально не конфликтует со старым app.css. Маппинг старых токенов web/src/app.css → новые:

Старый Новый Light Dark
--bg --background #eef1f4 #11171d
--surface --panel #f8fafb #182129
--text --foreground #17212b #e8eef2
--text-muted --muted #6d7883 #91a0ac
--border --line #cbd3da #33414c
--accent --blue #1769d2 #54a2ff
--cyan #00a8c7 #00a8c7
--amber #bd7411 #bd7411
--success #25a96a #25a96a (статус-точки)
--danger без изменений #e5484d #ff7479

Прочее:

  • Радиусы: один --radius: 4px (мягкость старой темы уходит).
  • Шрифты: IBM Plex Sans + IBM Plex Mono, self-host через @fontsource (offline-first, CDN нельзя). Mono — рабочий шрифт для лейблов/метаданных/ цифр; Sans — заголовки и текст. Задаются на .app-shell (корень новой ветки), чтобы не зависеть от старых глобальных правил body.
  • Фон-сетка (32px blueprint-grid) и шахматка канвасов — утилиты .page-grid и .checker-canvas внутри .ds2, не токены.
  • Тёмная тема — на [data-theme='dark'] (инлайн-скрипт уже есть в app.html); класс .dark-mode из рефа не переносим, используем наш механизм. На переходный период никаких алиасов старых токенов (старые страницы сами живут на своём app.css).

3. Базовые примитивы дизайн-системы (все — компоненты)

Правило фазы 1: любой повторяющийся паттерн — компонент, даже «просто div с двумя стилями». Никакой копипасты классов между страницами. Каждый примитив ниже — отдельный .svelte в src/lib/components/kit/.

  • MonoLabel — микро-лейбл: mono 10px, uppercase, letter-spacing .1em, muted; слот-модификатор accent (синие eyebrow/version).
  • StatusDot / StatusLine — точка --success + подпись («AUTO PIPELINE», «LIVE PREVIEW»).
  • Panel / PanelHeading / SettingGroup / SettingsFooter — панель с 1px-бордером, составные части с разделителями.
  • CheckerCanvas — рабочая поверхность превью: тёмная подложка + шахматка.
  • MetaRow / MetaList — пары «CAPTION значение».
  • Segmented — сегмент-переключатель (язык, тип градиента, пресеты).
  • Badge — тег типа шага (BACKGROUND/TRANSFORM/STYLE), чип «✓ AUTO».
  • StepCard — нумерованная карточка этапа: индекс 01, drag-handle, Badge типа, заголовок, кнопка удаления; слот для параметров.
  • ToolCard — карточка каталога (icon, index, title, copy, arrow).
  • ImageCard / PreviewTile — label сверху + canvas-превью.
  • AppShell — корневой контейнер .app-shell + .page-grid (обёртка новой ветки маршрутов); задаёт шрифты и фон нового дизайна.
  • BlueprintGrid — фоновая сетка (используется в AppShell).
  • IconButton, Icon (обёртка lucide-svelte, 1617px, muted).

4. Минимальный UI-kit (src/lib/components/kit/)

Контролы, поверх примитивов §3. API проектируем сразу под новый дизайн (обратной совместимости со старым ui/ не нужно — старые страницы его продолжают использовать).

Компонент Назначение
Button.svelte primary (solid blue) / secondary (outline) / ghost + icon
Field.svelte обёртка: MonoLabel + слот значения/контрола
SliderField.svelte range + <output>, опц. строка подсказок
ColorField.svelte swatch + hex-input + нативный picker
TextField.svelte текстовый ввод в стиле дизайна
SelectField.svelte селект в стиле дизайна
CheckboxField.svelte чекбокс → switch-toggle 32×18
Toggle.svelte переключатель (для toggle-group)
SegmentedControl.svelte на базе Segmented — RU/EN, Linear/Radial, пресеты
Badge.svelte на базе Badge
MetaList.svelte на базе MetaRow
EmptyState.svelte пустое состояние под новый стиль
CodeBlock.svelte блок кода (gradient-art / direction-grid)
DownloadButton.svelte кнопка скачивания (можно переиспользовать идею старой)

Иконки: lucide-svelte (те же пути, MIT), 1617px, stroke, muted.

5. Изоляция старого и нового (критично)

Без префиксов и обёрток — только за счёт того, какие layout грузят какой CSS.

  • Корневой layout src/routes/+layout.svelte перестаёт импортировать ../app.css. В нём остаётся только общая логика (init темы/locale) и нейтральный <div>{children}</div> без глобальных стилей дизайна.
  • Старая ветка src/routes/(old)/+layout.svelte импортирует app.css и содержит текущую шапку/подвал (разметку из нынешнего корневого layout). Все старые страницы переносятся внутрь (old)/ (группа в скобках не меняет URL): (old)/+page.svelte, (old)/demo/..., (old)/list-tools/..., (old)/tools/[id]/....
  • Новая ветка src/routes/preview/+layout.svelte импортирует design2.css и рендерит <AppShell>. Сюда же — новые страницы (§6).
  • Благодаря code-splitting CSS в SvelteKit: на старых маршрутах грузится только app.css, на preview/* — только design2.css. Скоуп стилей Svelte-компонентов добавляет второй уровень изоляции. Никаких .ds2.
  • Переключатель для ручной проверки: временный флаг previewDesign в localStorage + кнопка в старой шапке («Preview v2»), ведущая на /preview. На фазе 4 флаг убираем.

Почему не (new)-группа с теми же путями вместо preview/*: две группы не могут одновременно определять один и тот же URL ((old)/+page.svelte и (new)/+page.svelte оба → / = конфликт маршрутов). Поэтому новая ветка живёт под префиксом preview/, а на фазе 4 файлы переносятся на реальные пути и группа (old) удаляется.

Это совпадает с рекомендованным в документации SvelteKit паттерном: «put your entire app inside one or more groups except the routes that should not inherit the common layouts» — старое целиком в (old), новое снаружи. Синтаксис @-breakout (+layout@.svelte, +page@.svelte) здесь не требуется: «выломаться» можно лишь до корня, а нам нужно, чтобы именно у корня НЕ было app.css; если позже захотим держать новые маршруты внутри группы, @ пригодится для сброса родительского layout.

6. Маршрутизация параллельных страниц

Новые страницы живут в отдельной ветке preview/*, не трогая старые:

src/routes/+layout.svelte              # нейтральный, БЕЗ app.css
src/routes/(old)/+layout.svelte        # импорт app.css + старая шапка/подвал
src/routes/(old)/+page.svelte          # /        (старое)
src/routes/(old)/demo/+page.svelte     # /demo
src/routes/(old)/list-tools/...
src/routes/(old)/tools/[id]/...
src/routes/preview/+layout.svelte      # импорт design2.css, <AppShell>
src/routes/preview/+page.svelte        # /preview        — воркспейс (index/demo)
src/routes/preview/demo/+page.svelte   # /preview/demo
src/routes/preview/list-tools/+page.svelte
src/routes/preview/tools/[id]/+page.svelte
  • Каждая новая страница импортирует только kit/*. Старые страницы не изменяются (только перемещены в (old)/).
  • Фаза 4: содержимое preview/* переносится на реальные маршруты (move-файлы), группа (old)/ удаляется, design2.css подключается в корневом +layout.svelte (как новый основной слой), временный флаг/кнопка убираются.

7. Фазы выполнения (1–5 по запросу)

Каждая фаза заканчивается зелёными test/check/build и ревью в браузере (обе темы) против refs-html/.

  • Фаза 1 — Фундамент + UI-kit. Токены §2, design2.css по §5, все примитивы §3 и контролы §4 как отдельные компоненты. Критерий: демо-страница kit'а (/preview или временная) показывает все состояния (light/dark, hover/disabled, все варианты Button/Segmented/Badge); unit-тесты форм не падают; старые страницы визуально не изменились (изоляция работает).

  • Фаза 2 — Новые страницы. Под preview/* (§6): воркспейс, demo, list-tools, tool-page (двухпанельная раскладка из рефа: settings-panel + preview-panel, step-cards для chain). Критерий: разметка соответствует refs-html/index.html, gradient.html, background-remover.html, list-tools.html; интерактив (слайдеры/тоглы/загрузка/автозапуск) работает в новом стиле; старые маршруты продолжают работать как раньше.

  • Фазa 3 — Проверка нового дизайна. Смоук §8 (обе темы, узкий экран, 800px), скриншоты против refs-html/, прогон старого тест-сьюта для доказательства отсутствия регресса, RU/EN-локализация новых лейблов. Критерий: визуальное совпадение с рефом, зелёные тесты, записанные скриншоты приняты.

  • Фаза 4 — Сделать новый дизайн основным. Перенос preview/* → реальные маршруты; design2.css подключается в корневом +layout.svelte; удаление preview-группы и временного флага/кнопки. Старые страницы теперь не используются (мёртвый код), но физически ещё в репо. Критерий: реальные маршруты отдают новый дизайн, тесты зелёные, билд без предупреждений.

  • Фаза 5 — Удалить старый дизайн. Удаление старых страниц, старого ui/, старого app.css (и его токенов), неиспользуемых классов; переименование kit/ui/ (финальное имя) либо оставление kit/ как основного — решается на фазе 1. Финальный проход по брейкпоинтам 1200/1100/800/480. Критерий: grep по старым токенам/классам пуст, build чистый, старый дизайн нигде не упоминается.

Оценка объёма: Фаза 1 — фундамент+kit (~1 день), Фаза 2 — страницы (~1–2 дня), Фаза 3 — проверка (~полдня), Фаза 4–5 — переключение и чистка (~полдня).

8. Смоук (после фазы 3, контроль на фазе 4)

  1. Светлая и тёмная тема: сетка фона, панели, шахматка канвасов читаются, контраст mono-лейблов достаточный.
  2. Инструмент с параметрами (градиент): slider/color/toggle в стиле setting-groups, автозапуск не регрессировал.
  3. Удаление фона: сравнение source/result, маска, пипетка работают на новой шахматке.
  4. Chain из 3+ инструментов: step-cards рендерятся, удаление/сброс работают.
  5. Узкий экран 800px: настройки над превью, sticky выключается как в рефе.
  6. RU/EN: новые лейблы локализованы; mono-лейблы рефа — либо ключи i18n, либо осознанно английские брендовые элементы (см. §9).

9. Открытые вопросы

  • Имя финального каталога компонентов: оставить kit/ как основное имя или переименовать в ui/ на фазе 5 (удалив старое ui/). Рекомендую сразу писать в kit/, на фазе 5 переименовать в ui/. Решить на фазе 1.
  • Изоляция через layout: app.css вынесен из корневого layout в (old)/+layout.svelte; новый design2.css — только в preview/+layout. Проверить на фазе 1, что на /preview/* не попадают стили старого дизайна (DevTools → вкладка Styles, нет правил из app.css).
  • Переключатель для проверки: рекомендую localStorage-флаг + кнопка «Preview v2» в старой шапке + группа preview/*. Убрать на фазе 4.
  • Mono-лейблы рефа на английском (PROCESSING PIPELINE): завести i18n- ключи, но допустить часть английских брендовых («приборная панель»).
  • Версия в шапке/футере: из package.json через define или захардкодить — мелочь, решить при сборке topbar.
  • refs/ и refs-html/ — одноразовый источник, НЕ поддерживаемый. После внедрения нового дизайна все правки дизайна делаются сразу в продакшен-коде (design2.css + kit/), а не в refs/. Механизм синхронизации «ref → код» не нужен и не создаётся. refs/ и refs-html/ можно удалить из репо на фазе 5 (по желанию), они не являются частью рантайма.

10. План исполнения (мелкие коммиты)

Ветка feat/redesign. Каждый шаг — отдельный коммит, цель < ~500 строк. Перед стартом: test/build зелёные на базе (якорь регрессии).

Шаг 0. Изоляция layout (без дизайна)

  • [C1] Сделать корневой routes/+layout.svelte нейтральным: убрать import '../app.css', оставить только init темы/locale и <div>{children}</div>.
  • [C2] Создать routes/(old)/+layout.svelte (импорт app.css + старая шапка/подвал) и перенести старые страницы (+page, demo, list-tools, tools/[id]) в (old)/. URL не меняются. Проверка: старый сайт идентичен. (файлы — move, объём строк минимален)

Шаг 1. Фундамент нового дизайна

  • [C3] Создать src/lib/styles/design2.css (токены :root + [data-theme='dark'] по §2) и подключить @fontsource/ibm-plex-sans + @fontsource/ibm-plex-mono (self-host, offline-first). подключить шрифты в design2.css (self-host, offline-first).
  • [C4] (слит в C3: шрифты нельзя подключить до создания design2.css) [data-theme='dark'] (таблица §2). Без утилитарных классов.
  • [C5] Примитивы batch 1: AppShell, BlueprintGrid, CheckerCanvas, MonoLabel, StatusDot/StatusLine.
  • [C6] Примитивы batch 2: Panel, PanelHeading, SettingGroup, SettingsFooter, MetaRow/MetaList, Segmented, Badge, StepCard, ToolCard, ImageCard/PreviewTile. (при превышении 500 строк — разбить на C6a/C6b)
  • [C7] Контролы: Icon, IconButton, Button, Field, SliderField, ColorField, TextField, SelectField, CheckboxField, Toggle, SegmentedControl, EmptyState, CodeBlock, DownloadButton.

Шаг 2. Витрина kit (проверка компонентов)

  • [C8] preview/+layout.svelte (импорт design2.css + <AppShell>) и временная preview/kit страница со всеми состояниями (light/dark, hover/disabled, варианты Button/Segmented/Badge). Проверка: визуально против refs-html/, старый сайт не затронут.

Шаг 3. Новые страницы

  • [C9] /preview — воркспейс (eyebrow, h1, lede, поиск, «открыть последний»).
  • [C10] /preview/list-tools — каталог карточек.
  • [C11] /preview/demo — зеркало воркспейса (приёмочный стенд).
  • [C12] /preview/tools/[id] — раскладка gradient (settings-panel + preview-panel).
  • [C13] /preview/tools/[id] — раскладка background-remover (comparison-grid).
  • [C14] step-cards для chain в tool-page.

Шаг 4. Переключатель и проверка

  • [C15] Кнопка «Preview v2» + localStorage-флаг в старой шапке (ведёт на /preview).
  • [C16] Смоук §8, скриншоты против refs-html/, прогон старых тестов (доказательство отсутствия регресса). Фиксы по результатам — отдельными мелкими коммитами.

Шаг 5. Сделать новый дизайн основным

  • [C17] Перенести preview/* → реальные маршруты (move), удалить (old)/, корневой +layout.svelte импортирует design2.css + новый shell. Убрать флаг/кнопку.
  • [C18] Правки импортов/редиректов после переноса, проверка билда.

Шаг 6. Удаление старого

  • [C19] Удалить старое ui/, прочие старые компоненты, старый app.css, неиспользуемые классы. Переименовать kit/ui/ (если решено на C1).
  • [C20] Финальный проход по брейкпоинтам 1200/1100/800/480; build без предупреждений; grep по старым токенам/классам пуст.
  • [C21] (опционально) Удалить refs/ и refs-html/ из репо — они больше не источник правды.

Если какой-то коммит тянет за собой > 500 строк (например, C6/C7), разбивать на под-коммиты по 2–4 компонента. Тесты/билд прогонять после каждого коммита, чтобы регрессия локализовалась одним шагом назад.

Атомарность и точки «поломки» между коммитами.

  • C1+C2 уже сделаны вместе (связаны: нейтральный root без (old)-layout ломает старый сайт). Аналогично связанных пар больше нет.
  • C3 и C4 слиты: шрифты подключаются внутри design2.css, поэтому файл должен существовать в том же коммите.
  • Коммиты C3→C16 не трогают старый сайт (old)/ — они только добавляют новые файлы/маршруты, сломать старый сайт на них нельзя.
  • C17 — единственный атомарный переключатель: перенос preview/* на реальные пути + удаление (old)/ + смена root-layout должны быть в ОДНОМ коммите (иначе конфликт маршрутов или пропажа страниц). Не дробить.
  • C19 должен идти строго после C17 (старый app.css/ui/ удаляем только когда old-сайт уже выключен).
  • Очерёдность зависимостей: design2.css (C3) и kit-компоненты (C5–C7) должны существовать до страниц, которые их импортируют (C8–C14).