# План: переезд на новый дизайн (refs) — параллельная сборка > Статус: **archived** Архивирован: 2026-09-26 Удалить после: 2026-10-26 > Причина: переезд на новый дизайн завершён (C17/C18/Q3), C20 и C21 выполнены, > пункты полировки разобраны и разложены по `docs/backlog.md`. Источник правды > по визуальному языку — `web/src/app.css`, `web/src/lib/components/**`, витрина > `/kit` и приёмка в `docs/checklist-manual-testing.md`. Использование: только > историческая справка > Статус: C17 **выполнен**, C18 **выполнен**, Q3 (удаление старого UI) > **выполнен**, C20 **выполнен**, C21 **выполнен**. Открытых шагов не осталось. > Покупка домена НЕ была блокером C17: домен нужен для S1 (`plan-seo.md`) — > canonical, sitemap, снятие `noindex`. > > Источники: `refs/` — Next/React-референс (правда по пикселям и интерактиву), > `refs-html/` — статические HTML-снимки для быстрого просмотра в браузере. > > **Историческая стратегия перехода:** сначала новый UI собирался отдельно, > затем стал production, после чего legacy-ветка была удалена Q3. Текущие > критерии относятся только к production UI; старые решения и детали перехода > остаются в архивных планах. ## 0. Почему меняем стратегию - Переход выполнялся параллельной сборкой, чтобы новый UI можно было проверить независимо; теперь production использует только новые маршруты и `app.css`. - Дизайн-токены и глобальные стили живут в `web/src/app.css`; отдельные layout для удалённого UI-v1 больше не нужны. ## 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`, 16–17px, 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 + ``, опц. строка подсказок | | `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), 16–17px, stroke, muted. ## 5. Изоляция старого и нового (критично) Без префиксов и обёрток — только за счёт того, какие layout грузят какой CSS. - **Корневой layout `src/routes/+layout.svelte`** перестаёт импортировать `../app.css`. В нём остаётся только общая логика (init темы/locale) и нейтральный `
{children}
` без глобальных стилей дизайна. - **Старая ветка `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` и рендерит ``. Сюда же — новые страницы (§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. Маршрутизация: историческая схема перехода Во время перехода UI-kit проверялся в отдельной ветке, затем его страницы были перенесены на production-маршруты. Эта схема нужна только для восстановления контекста C17; текущая структура описана в разделе 7, отдельных preview- или legacy-layouts в production больше нет. ## 7. Фазы выполнения - **C1–C16 — UI-kit и проверка нового дизайна.** Токены, компоненты и интерактивные состояния приняты; детали перехода остаются в архивном `plan-design-fix.md`. - **C17/C18 — production-переход.** Новые страницы перенесены на реальные корневые маршруты; `app.css` стал единственным production-стилем. - **Q3/C19 — cleanup.** Удалены UI-v1, legacy CSS, v1-тесты, fixtures и isolation-конфигурация; production build и verify проверяются отдельно. - **C20 — следующий этап.** Финальный проход по брейкпоинтам и визуальной приёмке production UI. - **C21 — отдельная уборка.** Удалить `refs/` и `refs-html/`, если они больше не нужны. Критерии каждого этапа — зелёные `test`/`check`/`build`, отсутствие остаточных legacy-путей в production-коде и ревью в браузере для UI-изменений. ## 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. Открытые вопросы - **Имя финального каталога компонентов:** решено на C1 — писали в `kit/`, C17 разложил его в `components/` (подпапки fields/layout/ui). На C21 — только навести порядок внутри `components/`, переименование не требуется. - **Единый production CSS:** `app.css` подключается в корневом layout; отдельных legacy-layouts и переключателей версий больше нет. - **Mono-лейблы рефа на английском** (`PROCESSING PIPELINE`): завести i18n- ключи, но допустить часть английских брендовых («приборная панель»). - **Версия в шапке/футере:** из `package.json` через `define` или захардкодить — мелочь, решить при сборке topbar. - **`refs/` и `refs-html/` — одноразовый источник, НЕ поддерживаемый.** После внедрения нового дизайна все правки дизайна делаются сразу в продакшен-коде (`design2.css` + `kit/`), а не в `refs/`. Механизм синхронизации «ref → код» не нужен и не создаётся. `refs/` и `refs-html/` — только историческая справка; их можно удалить в C21, они не являются частью рантайма. ## 10. План исполнения (мелкие коммиты) Ветка `feat/redesign`. Каждый шаг — отдельный коммит, цель < ~500 строк. Перед стартом: `test`/`build` зелёные на базе (якорь регрессии). ### Шаг 0. Изоляция layout (без дизайна) - [x] **[C1]** Сделать корневой `routes/+layout.svelte` нейтральным: убрать `import '../app.css'`, оставить только init темы/locale и `
{children}
`. - [x] **[C2]** Создать `routes/(old)/+layout.svelte` (импорт `app.css` + старая шапка/подвал) и перенести старые страницы (`+page`, `demo`, `list-tools`, `tools/[id]`) в `(old)/`. URL не меняются. Проверка: старый сайт идентичен. _(файлы — move, объём строк минимален)_ ### Шаг 1. Фундамент нового дизайна - [x] **[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). - [x] **[C4]** _(слит в C3: шрифты нельзя подключить до создания `design2.css`)_ `[data-theme='dark']` (таблица §2). Без утилитарных классов. - [x] **[C5]** Примитивы batch 1: `AppShell`, `BlueprintGrid`, `CheckerCanvas`, `MonoLabel`, `StatusDot`/`StatusLine`. - [x] **[C6]** Примитивы batch 2: `Panel`, `PanelHeading`, `SettingGroup`, `SettingsFooter`, `MetaRow`/`MetaList`, `Segmented`, `Badge`, `StepCard`, `ToolCard`, `ImageCard`/`PreviewTile`. - [x] **[C7]** Контролы: `Icon`, `IconButton`, `Button`, `Field`, `SliderField`, `ColorField`, `TextField`, `SelectField`, `CheckboxField`, `Toggle`, `SegmentedControl` (= `Segmented` из C6), `EmptyState`, `CodeBlock`, `DownloadButton`. ### Шаг 2. Витрина kit (проверка компонентов) - [x] **[C8]** `preview/+layout.svelte` (импорт `design2.css` + `` + переключатель темы) и временная `preview/kit` страница со всеми состояниями (light/dark, hover/disabled, варианты Button/Segmented/Badge и пр.) ### Шаг 3. Новые страницы - [x] **[C9]** `/preview` — воркспейс (eyebrow, h1, lede, поиск, «открыть последний»). Поиск фильтрует `TOOLS` из `$lib/registry`; карточки результата пока ведут на `#` (реальные `/preview/tools/[id]` подключим на C12, иначе prerender падает на 404). - [x] **[C10]** `/preview/list-tools` — каталог карточек (группировка по `CATEGORIES`, `ToolCard`). Ссылки пока `#` (реальные `/preview/tools/[id]` подключим на C12). - [x] **[C11]** `/preview/demo` — зеркало воркспейса (4 шага + панель превью), статичный приёмочный стенд. - [x] **[C12]** `/preview/tools/[id]` — data-driven settings-panel + preview-panel (gradient live, остальные — плейсхолдер); `NumberField`, `entries()` для prerender, ToolCard-ссылки подключены. - [x] **[C13]** `/preview/tools/[id]` — comparison-grid для file-source инструментов (`Dropzone` + before/after `CheckerCanvas`, `result-meta`); охватывает background-remover и прочие. - [x] **[C14]** `/preview/tools/[id]` — исполняемая цепочка: `StepCard`-шаги (параметры inline) + «Add step» (chainable), живой прогон пайплайна на исходнике, превью каждого шага + итог + Download. ### Шаг 4. Переключатель и проверка - [x] **[C15]** В старой шапке ссылка «Preview v2» → `/preview`, ставит `localStorage['easy-png-tools:preview-v2']='1'`. - [x] **[C16]** База под дизайн: рабочий переключатель тем (persist в localStorage, применяется на ``; проверено — фон `#eef1f4`↔`#11171d`), `TopBar` приведён к виду `demo.html` (бренд + синий хлебный крош `/* страница */`, безрамочные иконки, язык — active = `--foreground`/`--background`), страницы `/preview/*` на всю ширину (убран `max-width`). Точечное выравнивание к рефу отложено: реф-дизайн неконсистентен. (доказательство отсутствия регресса). Фиксы по результатам — отдельными мелкими коммитами. ### Шаг 5. Сделать новый дизайн основным > C17 — **выполнен** (`docs/archive/plan-c17.md`): production-маршруты > перенесены в корень, `app.css` стал корневым. C18 (правки импортов/редиректов > после переноса, проверка билда) — **выполнен**. Q3 удалил старые UI-маршруты и > код. Остались C20 и C21. - [x] **[C17]** Перенести `preview/*` → реальные маршруты (move), удалить `(old)/`, корневой `+layout.svelte` импортирует `design2.css` + новый shell. Убрать флаг/кнопку. **Снять `noindex, nofollow`** со страницы инструмента (`preview/tools/[id]/+page.svelte`) — страницы становятся боевыми лендингами ровно в момент переезда (SEO: `plan-seo.md`, S1a). **Временное решение:** если домен ещё не куплен, `noindex` можно оставить до S1 — тогда C17 делается без снятия `noindex`, а снятие происходит вместе с подключением canonical в S1. **И обновить `newCode` в `web/eslint.config.js`:** заменить `src/routes/preview/**` на `src/routes/**` (после переезда все маршруты — новый дизайн), компонентный glob `src/lib/components/kit/**` пока оставить. _(Итог: `newCode` обновлён (`components/**`, `routes/**`), `noindex` оставлен до S1 — домен ещё не куплен. Детали: `docs/archive/plan-c17.md`.)_ - [x] **[C18]** Правки импортов/редиректов после переноса, проверка билда. _(Билд собирается без ошибок, линт/свелт-чека нет — выполнен.)_ ### Шаг 6. Проверка нового дизайна - [x] **[C20]** Финальный проход: grep по старым токенам и классам пуст (0 совпадений по `--bg`/`--surface`/`--text`/`--blue`/`--panel` в `web/src`), `app.css` — единственный production-стиль, `components/` разложен как в C17 (`fields`/`layout`/`ui`), production-маршруты и пользовательские потоки покрыты e2e. Визуальная приёмка живёт в `docs/checklist-manual-testing.md`. ### Шаг 7. Cleanup - [x] **[C19/Q3]** Удалить старое: маршруты `routes/v1/**`, код `lib/v1/**`, `app_v1.css`, v1-тесты, fixtures и isolation-плагин; убрать v1-исключения из конфигурации и активной документации. - [x] **[C21]** `refs/` и `refs-html/` удалены — каталогов в репозитории нет. - [x] Навести порядок в `components/`: подпапки `fields`/`layout`/`ui`. > C19/Q3 — отдельная cleanup-задача, не источник пользовательской ценности. > После удаления проверяются только production-маршруты и общие модули. > > Если какой-то коммит тянет за собой > 500 строк (например, C6/C7), разбивать > на под-коммиты по 2–4 компонента. Тесты/билд прогонять после каждого коммита, > чтобы регрессия локализовалась одним шагом назад. > > **Атомарность и точки «поломки» между коммитами.** > > - C1+C2 уже сделаны вместе (связаны: нейтральный root без `(old)`-layout > ломает старый сайт). Аналогично связанных пар больше нет. > - C3 и C4 слиты: шрифты подключаются внутри `design2.css`, поэтому файл должен > существовать в том же коммите. > - Коммиты **C3→C16 не трогают старый сайт** `(old)/` — они только добавляют > новые файлы/маршруты, сломать старый сайт на них нельзя. > - **C17 — атомарный переключатель**: перенос `preview/*` на реальные пути + > удаление `(old)/` + смена root-layout — в ОДНОМ коммите. Снятие `noindex` > также в C17, **если домен уже куплен**; иначе — отложить на S1. Не дробить > сам C17. > - Очерёдность зависимостей: `design2.css` (C3) и kit-компоненты (C5–C7) должны > существовать до страниц, которые их импортируют (C8–C14). ## Бэклог полировки — закрыт по итогам реализации Пять пунктов проверены по коду: четыре сняты как выполненные, один перенесён в `docs/backlog.md`. - `Toggle` прямоугольный — выполнено (`border-radius: 0`). - `Segmented`: последняя кнопка не растянута — выполнено (`flex: 1` у пунктов). - Отступ в `DownloadButton` между текстом и size-чипом — снято как неактуальное: size-чипа больше нет, компонент тонкая обёртка над `Button`. - Паддинги в полях — выполнено: `TextField` и `SelectField` имеют `padding: var(--space-s) var(--space-m)`. - Радиусы бордеров против референсов — перенесено в `docs/backlog.md`.