docs: update docs - plan, archive

This commit is contained in:
2026-08-22 20:33:01 +05:00
parent da92815b3a
commit dcc7c346c4
6 changed files with 87 additions and 12 deletions
@@ -1,6 +1,6 @@
# План: единая дизайн-система # План: единая дизайн-система
Статус: план к выполнению. Следующий этап после MVP, до UX-работ из backlog (реактивные параметры, слайдеры/пипетка, раскладка). > **СТАТУС: ВЫПОЛНЕН 2026-08-22.**
## 1. Цели и принципы ## 1. Цели и принципы
@@ -13,7 +13,7 @@
- **«Приглушённый текст»** (`--text-muted` + размер 0.85–0.95rem) — повторён в семи местах: `ToolPage` (.description, .hint), главная (.lead, .card-desc), лейаут (.nav-link, footer), `Preview` (.dims), `ParamForm` (label), `InfoPanel` (dt). - **«Приглушённый текст»** (`--text-muted` + размер 0.85–0.95rem) — повторён в семи местах: `ToolPage` (.description, .hint), главная (.lead, .card-desc), лейаут (.nav-link, footer), `Preview` (.dims), `ParamForm` (label), `InfoPanel` (dt).
- **«Заголовок секции капсом»** (uppercase, letter-spacing, muted) — точная копипаста в `ToolPage` и на главной. - **«Заголовок секции капсом»** (uppercase, letter-spacing, muted) — точная копипаста в `ToolPage` и на главной.
- **Базовые инпуты** (padding, border, radius) — живут только внутри `ParamForm`; слайдеры/пипетка из backlog потребуют копирования. - **Базовые инпуты** (padding, border, radius) — живут только внутри `ParamForm`; любые новые типы контролов (слайдеры, пипетка цвета) пришлось бы копировать вручную.
- **Блок «label + отступы»** — дублировался бы в каждом `*Field`; решается обёрткой `Field.svelte`. - **Блок «label + отступы»** — дублировался бы в каждом `*Field`; решается обёрткой `Field.svelte`.
- **«Панель»** (surface + border + radius) — три ручные реализации одного паттерна: `DropZone`, карточки главной, строки `InfoPanel`. - **«Панель»** (surface + border + radius) — три ручные реализации одного паттерна: `DropZone`, карточки главной, строки `InfoPanel`.
- **Кнопки** — глобальные классы `.primary`/`.secondary` без компонента; состояния «занят/недоступен» каждый описывает заново. - **Кнопки** — глобальные классы `.primary`/`.secondary` без компонента; состояния «занят/недоступен» каждый описывает заново.
@@ -70,11 +70,11 @@
| `Field.svelte` | `id`, `label`, `hint?`, слот контрола | label + раскладка поля; единая точка для hint'ов и ошибок валидации | | `Field.svelte` | `id`, `label`, `hint?`, слот контрола | label + раскладка поля; единая точка для hint'ов и ошибок валидации |
| `Button.svelte` | `variant: 'primary' \| 'secondary'`, `disabled`, `busy`, слот текста | глобальные `.primary`/`.secondary`, локальный busy в `DownloadButton` | | `Button.svelte` | `variant: 'primary' \| 'secondary'`, `disabled`, `busy`, слот текста | глобальные `.primary`/`.secondary`, локальный busy в `DownloadButton` |
| `TextField.svelte` | `id`, `label`, `type: 'number' \| 'text'`, `min/max/step`, `value = $bindable()` | number/text ветки `ParamForm` | | `TextField.svelte` | `id`, `label`, `type: 'number' \| 'text'`, `min/max/step`, `value = $bindable()` | number/text ветки `ParamForm` |
| `SliderField.svelte` | `id`, `label`, `min/max/step`, `value = $bindable()`, показ значения рядом | ничего — база для backlog п.2 (яркость, качество, порог) | | `SliderField.svelte` | `id`, `label`, `min/max/step`, `value = $bindable()`, показ значения рядом | ничего — готовая база для будущих слайдеров (яркость, качество, порог) |
| `SelectField.svelte` | `id`, `label`, `options`, `value = $bindable()` | select-ветка `ParamForm` | | `SelectField.svelte` | `id`, `label`, `options`, `value = $bindable()` | select-ветка `ParamForm` |
| `CheckboxField.svelte` | `id`, `label`, `checked = $bindable()` | чекбокс `ParamForm` | | `CheckboxField.svelte` | `id`, `label`, `checked = $bindable()` | чекбокс `ParamForm` |
| `ColorField.svelte` | `id`, `label`, `value = $bindable()` | color-ветка `ParamForm`; точка будущего расширения пипеткой | | `ColorField.svelte` | `id`, `label`, `value = $bindable()` | color-ветка `ParamForm`; точка будущего расширения пипеткой |
| `EmptyState.svelte` | `title`, `hint`, слот действия | «Обработка…», будущие пустые панели исходника/результата (backlog п.3) | | `EmptyState.svelte` | `title`, `hint`, слот действия | «Обработка…», будущие пустые панели исходника/результата |
`Field` — чисто раскладочная обёртка (`<div class="field"><label for>…</label><slot /></div>`), ничего не знает о типе контрола. На ней построены `TextField`, `SliderField`, `SelectField`, `ColorField`. Исключение — `CheckboxField`: у чекбокса label оборачивает контрол (кликабельная строка), поэтому у него своя раскладка. `Field` — чисто раскладочная обёртка (`<div class="field"><label for>…</label><slot /></div>`), ничего не знает о типе контрола. На ней построены `TextField`, `SliderField`, `SelectField`, `ColorField`. Исключение — `CheckboxField`: у чекбокса label оборачивает контрол (кликабельная строка), поэтому у него своя раскладка.
+2 -1
View File
@@ -1,8 +1,9 @@
# План начальной реализации: минимальный рабочий MVP # План начальной реализации: минимальный рабочий MVP
> **СТАТУС: ВЫПОЛНЕН И ЗАКРЫТ 2026-08-22. Документ перенесён в архив** (`docs/archive/`) и больше не развивается. > **СТАТУС: ВЫПОЛНЕН 2026-08-22.**
> >
> **Что сделано по плану:** > **Что сделано по плану:**
>
> - Шаг 0 — каркас: SvelteKit + adapter-static, design-токены на CSS, лейаут с навигацией по категориям ✔ > - Шаг 0 — каркас: SvelteKit + adapter-static, design-токены на CSS, лейаут с навигацией по категориям ✔
> - Шаг 1 — ядро: `PixelImage`, декодирование файлов, кодирование PNG/JPEG/WebP, скачивание ✔ > - Шаг 1 — ядро: `PixelImage`, декодирование файлов, кодирование PNG/JPEG/WebP, скачивание ✔
> - Шаг 2 — операции ядра: color / geometry / alpha / analyze, чистые функции без DOM ✔ > - Шаг 2 — операции ядра: color / geometry / alpha / analyze, чистые функции без DOM ✔
@@ -1,6 +1,16 @@
# План: раскладка «исходник слева — результат справа» + вставка изображения # План: раскладка «исходник слева — результат справа» + вставка изображения
Реализует пункт 3 из [backlog.md](./backlog.md). Выполняется поверх дизайн-системы (`design-system.md` выполнен). > **СТАТУС: ВЫПОЛНЕН 2026-08-22.**
>
> **Что сделано по этапам:**
>
> - A — общая MIME-валидация `isSupportedImage` + `unsupportedImageMessage` в `core/io.ts`; `DropZone` переведён на них ✔
> - B — постоянная двухпанельная раскладка: одна карточка-«сцена» с равными половинами «Исходник | Результат», кнопки внутри своих половин, параметры — отдельной карточкой ниже; контент сайта растянут на всю ширину окна ✔
> - C — Ctrl+V: `<svelte:window onpaste>`, поиск image-item в буфере, общая валидация; текстовые вставки не затрагиваются ✔
> - D — drag-замена: компонент `DropOverlay` с вуалью-подсказкой и счётчиком `dragenter/dragleave` против мерцания; тот же счётчик в `DropZone`
> - E — верификация: тесты 85/85, svelte-check 0 ошибок, статический билд с 11 страницами; ручной смоук-чеклист §5 пройден ✔
>
> **Отступления от исходного плана в ходе реализации:** вместо пропа `overlay` у `DropZone` сделан отдельный компонент-обёртка `DropOverlay` (drag-события ловит контент под курсором); раскладка доработана по ревью — одна карточка равных половин вместо двух независимых колонок, сайт без ограничения ширины.
## 1. Целевое поведение ## 1. Целевое поведение
@@ -57,8 +67,8 @@
- Ошибочные файлы и отмена перетаскивания не портят текущий исходник. - Ошибочные файлы и отмена перетаскивания не портят текущий исходник.
- `test/check/build` зелёные; чеклист §5 пройден. - `test/check/build` зелёные; чеклист §5 пройден.
## 7. Что сознательно не делаем ## 7. Что сознательно не делаем (граница скоупа этого плана)
- Множественная загрузка / пакетная обработка — это batch-страница следующих фаз. - Множественная загрузка / пакетная обработка — вне скоупа этого плана.
- Камера/скриншот-инструменты захвата — только буфер обмена. - Камера/скриншот-инструменты захвата — только буфер обмена.
- Прогресс-бары декодирования — файлы читаются быстро, достаточно индикации «Обработка…». - Прогресс-бары декодирования — файлы читаются быстро, достаточно индикации «Обработка…».
+1 -1
View File
@@ -15,7 +15,7 @@
- **Range slider вместо полей ввода** там, где это удобнее (яркость/контраст, качество JPEG/WebP, порог похожести) — желательно slider с присоединённым числовым значением. - **Range slider вместо полей ввода** там, где это удобнее (яркость/контраст, качество JPEG/WebP, порог похожести) — желательно slider с присоединённым числовым значением.
- **Пипетка для цвета** — выбор цвета удаления/подложки кликом прямо по превью изображения (в дополнение к `<input type="color">`). - **Пипетка для цвета** — выбор цвета удаления/подложки кликом прямо по превью изображения (в дополнение к `<input type="color">`).
## 3. Загрузка изображений и раскладка страницы ## 3. Загрузка изображений и раскладка страницы — выполнено 2026-08-22
Убрать отдельное состояние «страница загрузки» и сделать постоянную двухпанельную раскладку: Убрать отдельное состояние «страница загрузки» и сделать постоянную двухпанельную раскладку:
+66
View File
@@ -0,0 +1,66 @@
# План: декомпозиция страницы инструмента, реактивные параметры, предпросмотр маски
> Статус: план к выполнению.
## 1. Зачем
- Страница инструмента (`ToolPage.svelte`) разрослась: состояние процесса, загрузка файлов, вставка из буфера и разметка трёх зон живут в одном файле.
- Назревают два требования к процессу: параметры применяются автоматически без кнопки; у части утилит на экране показывается одно — визуализация фильтра/маски, а скачивается (и в будущем передаётся следующему инструменту) другое — результат.
## 2. Контракт «результат и маска» в реестре
- `run(img, params)` — как сейчас: возвращает итоговое изображение. Его скачивают и будут передавать дальше по цепочке.
- Запись реестра получает опциональное поле `preview?(img, params)` — возвращает картинку для показа на экране (маску/фильтр).
- Если у записи есть `preview`, в карточке результата появляется переключатель «Показать маску». Включён — на превью маска, выключен (по умолчанию) — результат. Скачивание всегда отдаёт результат `run`, независимо от положения переключателя.
- Первая реализация — удаление цвета: в ядро добавляется чистая функция `colorMask(img, hex, tolerance)` — чёрно-белая маска, где удаляемые пиксели белые; с юнит-тестами; `preview` записи вызывает её.
## 3. Декомпозиция страницы
Новая папка `components/tool/`; карточки — чисто отображательные, состояние живёт только в оркестраторе:
- **`SourceCard.svelte`** — левая половина сцены: пусто → зона перетаскивания; загружено → превью исходника под оверлеем замены с кнопкой «Заменить изображение».
- **`ResultCard.svelte`** — правая половина: пустые состояния, превью результата или сводка, чип «Пересчёт…», кнопка скачивания, при наличии `preview` — переключатель маски.
- **`ParamsCard.svelte`** — форма параметров и подпись «Изменения применяются автоматически»; для инструментов без параметров не выводится.
- **`ToolPage.svelte`** остаётся оркестратором: состояние (исходник, результат, сводка, статус, ошибка, значения), декодирование файлов, вставка из буфера, сброс, токен запусков и эффект с задержкой. Ожидаемо худеет примерно вдвое.
Карточки переиспользуются будущим многошаговым режимом.
## 4. Реактивные параметры (в этом же проходе)
- Кнопки «Применить» больше нет ни у одного инструмента.
- Изменение параметра запускает вычисление через 300 мс после последнего изменения; каждое новое изменение перезапускает таймер.
- Токен запусков: если во время вычисления параметры поменялись, устаревший ответ отбрасывается.
- Загрузка и замена файла считают сразу и подавляют ровно один авто-запуск эффекта.
- Ошибка пересчёта — баннер сверху, прежний результат не сбрасывается.
## 5. Этапы и проверки
- **A. Декомпозиция** — перенос разметки в три карточки один к одному, поведение не меняется. Проверка: `check/build`, визуально идентично.
- **B. Реактивность** — токен, задержка, чип пересчёта, минус кнопка. Проверка: смоук §6 пп. 1–6.
- **C. Маска** — типы реестра, `colorMask` с тестами, переключатель в карточке результата, пример на удалении цвета. Проверка: тесты + смоук §6 пп. 7–9.
- **D. Итог** — полный прогон `test/check/build`.
## 6. Смоук-чеклист
1. Загрузка файла → результат появляется сразу.
2. Изменить параметр → около 0.3 с и результат обновился сам.
3. Быстро изменить яркость несколько раз → одна финальная версия, промежуточные не мелькают.
4. Во время пересчёта чип виден, предыдущий результат не исчезает.
5. Инструмент без параметров и информационная страница ведут себя как раньше.
6. Некорректные параметры (обрезка вне картинки) → баннер ошибки, прежний результат цел.
7. Переключатель «Показать маску» у удаления цвета: включён — белым по чёрному видно, что удалится; выключен — обычный полупрозрачный результат.
8. С включённой маской скачивание всё равно сохраняет прозрачный результат, а не маску.
9. Замена исходника возвращает переключатель маски в выключенное состояние.
## 7. Критерии готовности
- `ToolPage` содержит только оркестрацию состояния и эффектов; вся разметка панелей — в `components/tool/*`.
- Кнопки «Применить» нет ни на одной странице.
- Скачивание всегда соответствует `run`; экран может показывать `preview`.
- `test/check/build` зелёные, смоук §6 пройден.
## 8. Что сознательно не делаем
- Вынос вычислений в веб-воркер; настраиваемая задержка — фиксированные 300 мс.
- Редактор масок (кисть, слои, история) — только автогенерация из параметров инструмента.
- Передача результата между инструментами — придёт вместе с многошаговым режимом позже.
+1 -3
View File
@@ -1,7 +1,5 @@
# План разработки: easy-png-tools # План разработки: easy-png-tools
Сопутствующий документ: [analysis.md](./analysis.md) — перечень и уровни утилит.
## 0. Решения ## 0. Решения
- **Набор PNG-утилит, всё в браузере** (SvelteKit + `adapter-static`), данные не покидают машину. - **Набор PNG-утилит, всё в браузере** (SvelteKit + `adapter-static`), данные не покидают машину.
@@ -41,7 +39,7 @@ easy-png-tools/
1.4 **Пайплайн-workspace** (`/workspace`): загрузил изображение → список шагов (инструмент + его параметры) → последовательное применение с превью каждого шага → скачивание финального результата. Добавление/удаление/перестановка шагов. Сохранение пайплайнов в localStorage, экспорт/импорт JSON. Общие компоненты: DropZone, Preview, ParamForm, Download, PipelineSteps. 1.4 **Пайплайн-workspace** (`/workspace`): загрузил изображение → список шагов (инструмент + его параметры) → последовательное применение с превью каждого шага → скачивание финального результата. Добавление/удаление/перестановка шагов. Сохранение пайплайнов в localStorage, экспорт/импорт JSON. Общие компоненты: DropZone, Preview, ParamForm, Download, PipelineSteps.
1.5 **Массовая реализация EASY-инструментов** по категориям из analysis.md: 1.5 **Массовая реализация EASY-инструментов** по категориям:
- конвертация форматов (png/jpg/webp/bmp/base64/gif) и текстовые представления; - конвертация форматов (png/jpg/webp/bmp/base64/gif) и текстовые представления;
- прозрачность и альфа-канал; - прозрачность и альфа-канал;