From fe33deaa130aeadafc492f26e769c8efd40dbca1 Mon Sep 17 00:00:00 2001 From: Sergey Matyunin Date: Thu, 20 Aug 2026 13:07:49 +0300 Subject: [PATCH] docs: specify text marker shell geometry Issue: #217 User-Visible: no --- docs/specs/217-text-shell-outline.md | 260 +++++++++++++++++++++++++++ docs/specs/README.md | 1 + 2 files changed, 261 insertions(+) create mode 100644 docs/specs/217-text-shell-outline.md diff --git a/docs/specs/217-text-shell-outline.md b/docs/specs/217-text-shell-outline.md new file mode 100644 index 00000000..a687140d --- /dev/null +++ b/docs/specs/217-text-shell-outline.md @@ -0,0 +1,260 @@ +# Issue #217 — внешняя рамка Text-маркера должна быть капсулой + +- **Issue:** https://github.com/Matysh/houseplan-card/issues/217 +- **Связанные завершённые задачи:** #179, #211, #213 +- **Нормативный дизайн:** `demo/srv/reference/device-icons/Light/Text Default.svg` + и `demo/srv/reference/device-icons/Dark/Text Default.svg` из пакета #179 +- **Тип:** bug / polish, обычный трек +- **Приоритет:** P1 +- **Пользовательское изменение:** да + +## 1. Сценарий и персона + +**Персона:** домочадец или гость, который читает текстовое состояние устройства +в View/kiosk, и администратор, который проверяет тот же маркер в редакторе. + +**Сценарий:** пользователь видит Text-маркер с широким значением, например +`498 ppm`, и ожидает, что внешний shell повторяет капсульную форму внутреннего +белого core. После #213 core остаётся капсулой, но внешняя рамка стала эллипсом: +вместо прямого среднего участка верхняя и нижняя границы изгибаются по всей +ширине. + +## 2. Что человек увидит до и после + +До исправления широкий Text-маркер окружён овальной рамкой, которая визуально +не совпадает ни с core, ни с дизайн-пакетом #179. После исправления внешняя +рамка имеет форму stadium: торцы являются полуокружностями, а между ними идут +прямые горизонтальные участки. Размер, положение и интерактивная область +маркера не меняются. + +## 3. Подтверждённая причина + +`src/styles.ts` задаёт правильный общий fallback +`border-radius: 9999px` для `.device-shell-frame`, но затем правило +`.device-shell:not(.with-values) .device-shell-frame` заменяет его на `50%`. +Text-маркер имеет класс `.text-shell`, но не `.with-values`, поэтому для широкой +рамки `50%` вычисляется отдельно по ширине и высоте и даёт эллипс. + +Регрессия появилась в реализации #213. Проверки её не поймали, потому что: + +1. smoke `textCoreIsStadium` проверяет только внутренний core; +2. capsule smoke проверяет hover/action, а не форму внешней рамки; +3. существующий golden показывает Text-маркер слишком мелко, поэтому неверная + кривизна не была заметна при визуальном review. + +## 4. Нормативные источники и приоритет + +При расхождении применяются: + +1. решения владельца в #217; +2. это ТЗ после зелёного SPEC-REVIEW; +3. Light/Dark `Text Default.svg` из принятого пакета #179; +4. контракты #213 для размеров, inset, соосности и полной hover/action-области; +5. текущая реализация как compatibility baseline для поведения, которое это ТЗ + явно не меняет. + +Reference SVG задаёт stadium как для core, так и для внешней рамки Text. + +## 5. Цели + +1. Вернуть внешней рамке Text-маркера форму stadium во всех поверхностях. +2. Не изменить размеры, inset, anchor, цвета и поведение маркера. +3. Добавить автоматическую проверку именно внешней рамки, падающую при `50%`. +4. Сделать дефект заметным в Light/Dark golden review. + +## 6. Scope + +В задачу входят: + +- общий Text device face в full View, kiosk, Device editor/preview и + `houseplan-space-card`; +- Light/Dark и цветной фон плана; +- короткие и длинные Text-значения на поддерживаемой матрице размеров; +- CSS-правило формы внешнего `.device-shell-frame`; +- source/unit contract, targeted browser smoke и крупный golden-сценарий; +- оба changelog и testing-документация. + +## 7. Не входит в задачу + +- изменение ширины, высоты, inset, stroke, shadow, цвета или opacity; +- изменение сохранённой координаты, `icon_size`, marker `size` или badge side; +- изменение core, MDI-глифа, LQI, pulse, availability или virtual-state; +- изменение Icon-only, Double/value/legacy capsule и opening Lock/Unlock; +- изменение hover/action target, tooltip, z-index, keyboard или touch поведения; +- новые настройки, строки, schema или миграция данных; +- откат остальных изменений #213; +- принятие golden baseline на Windows или выпуск без команды владельца. + +## 8. Визуальный контракт + +### 8.1. Text + +Для `.device-shell.text-shell .device-shell-frame`: + +- внешний shell имеет stadium-форму при любой ширине больше высоты; +- радиус каждого внешнего угла визуально равен половине итоговой высоты рамки с + допуском browser layout/raster quantum; +- верхняя и нижняя границы между торцами имеют прямой горизонтальный участок; +- рамка окружает core с существующим `--device-shell-inset`; +- core и shell сохраняют текущие размеры, центр и относительное положение; +- CSS `border-radius: 50%` не применяется к широкой Text-рамке. + +Нормативный CSS-подход может использовать saturating radius (`9999px`) либо +эквивалентное height-derived значение. Запрещены фиксированные pixel-компенсации +по размеру, viewport или DPR. + +### 8.2. Неизменяемые варианты + +- Icon-only shell остаётся окружностью; +- внутренний Text core остаётся stadium; +- Double/value/legacy shell сохраняет существующую capsule geometry; +- opening Lock/Unlock остаётся круглым; +- внешний footprint и hit area всех вариантов не меняются. + +### 8.3. Матрица + +Контракт проверяется минимум на: + +- длинном значении (`498 ppm` либо более длинной локализованной строке); +- effective base 24, 32, 56, 96 и 112 CSS px; +- DPR 1, 1.25, 1.5 и 2; +- Light и Dark; +- full, preview и static/space-card parity surfaces. + +## 9. UX, accessibility и touch + +Вся внешняя Text-капсула по-прежнему является одной hover- и action-областью, +как принято в #213. Минимальная интерактивная область остаётся не меньше 44×44 +CSS px. Focus-visible, tooltip, accessible name, tab order, confirmation и +действие не меняются. Touch/pen не получают новый hover; unavailable сохраняет +текущее поведение. + +## 10. Данные, migration и i18n + +Config, layout, localStorage, backend schema и сериализация не меняются. +Миграция не нужна; Open → Save не материализует новые поля. Новых +пользовательских строк и i18n-ключей нет. + +## 11. Архитектура и зоны изменений + +Исправление должно оставаться в общем device face и применяться ко всем +поверхностям без второго renderer: + +```text +device presentation + → shared renderDeviceFace classes + → common device styles + → Text-only stadium shell / Icon-only circle +``` + +Ожидаемые зоны изменений: + +- `src/styles.ts` — сузить circular override так, чтобы он не захватывал Text; +- `test/device-marker-polish-contract.test.mjs` — source regression contract; +- `demo/smoke_device_icon_design.mjs` — computed-style/geometry matrix внешней + Text-рамки и неизменённой круглой Icon-рамки; +- golden/reference matrix — крупный Text marker в Light/Dark; +- `docs/TESTING.md`, `docs/CHANGELOG.md`, `docs/CHANGELOG.ru.md`. + +## 12. Performance и security + +Исправление является CSS-only geometry change. Нельзя добавлять per-frame JS, +ResizeObserver, media listener, отдельный DOM-слой, backdrop-filter или новую +анимацию. Число paint/compositor layers не увеличивается. Action и security +paths не меняются. + +## 13. Acceptance criteria + +1. **AC1 — stadium shell.** Длинный Text-маркер имеет внешнюю stadium-рамку с + прямым средним участком в Light/Dark. **Доказательство:** browser smoke и + reviewed крупный golden. +2. **AC2 — защита от `50%`.** Regression test проверяет внешнюю рамку и краснеет + на documented mutant, возвращающем `border-radius: 50%` для Text. + **Доказательство:** source/computed-style smoke + mutant result. +3. **AC3 — матрица размеров.** Контракт Text shell выполняется на §8.3 без + per-size/DPR исключений. **Доказательство:** browser matrix. +4. **AC4 — геометрическая совместимость.** До/после совпадают outer rect, inset, + core rect и anchor с допуском одного browser layout quantum; меняется только + corner shape. **Доказательство:** browser rect assertions. +5. **AC5 — соседние варианты.** Icon-only остаётся кругом, внутренний Text core + и Double/value/legacy capsule не меняются. **Доказательство:** targeted smoke + и existing device-face tests. +6. **AC6 — interaction parity.** Hover и действие по всей Text-капсуле, + 44×44 minimum target, mouse/touch modality и unavailable остаются как в + #213. **Доказательство:** existing capsule hover/action smoke. +7. **AC7 — surface/theme parity.** Full View/kiosk, preview и static/space-card + показывают одинаковую форму в Light/Dark. **Доказательство:** parity smoke и + golden. +8. **AC8 — data/i18n/security/performance.** Нет schema, storage, i18n, action, + observer, animation или compositor changes. **Доказательство:** unit/source + review и fast performance sanity. +9. **AC9 — release artifacts.** Оба changelog, testing docs, smoke/golden + fixtures и visual fingerprints актуальны. **Доказательство:** docs diff, + `check-docs` и release review. + +## 14. План автотестов + +### 14.1. Цикл реализации + +```bash +npm run typecheck +npm test +npm run build +node scripts/check-docs.mjs --external +``` + +Source/unit guard должен явно различать Text и Icon-only selector contract. +Browser smoke получает внешнюю рамку через `.device-shell-frame`, проверяет +Text saturating radius и круглую Icon-рамку, сравнивает rect/inset до и после +смены размеров и фиксирует documented mutant `50%` как failing case. + +### 14.2. Targeted smoke перед S7 + +- `node demo/smoke_device_icon_design.mjs`; +- `node demo/smoke_device_preview_parity.mjs`; +- `node demo/smoke_static_icon.mjs`; +- capsule hover/action smoke из #213; +- Light/Dark reference/golden capture с крупным длинным Text-маркером. + +Golden на Windows используется только диагностически. Канонический baseline +принимается из reviewed Linux CI artifact перед beta. + +## 15. Риски и меры + +| Риск | Мера | +| --- | --- | +| Слишком широкое правило перестанет округлять Icon-only | Явная Icon-vs-Text source/browser проверка | +| Исправление изменит footprint или anchor | До/после rect/inset assertions | +| Double/value capsule получит новый радиус | Отдельный unchanged regression check | +| Дефект снова потеряется на мелком golden | Выделенный крупный long-Text сценарий в Light/Dark | +| Появится surface-specific CSS | Проверка shared face parity без второго renderer | + +## 16. Откат + +Откат одного implementation commit возвращает прежний selector и visual +fixtures. Данных и миграций нет. Golden baseline возвращается только через +нормативный Linux artifact, а не ручным принятием локального Windows capture. + +## 17. Release-артефакты + +В user-visible implementation commit одновременно обновляются: + +- `docs/CHANGELOG.md` и `docs/CHANGELOG.ru.md` со ссылкой на #217; +- `docs/TESTING.md` с новым Text-shell regression contract; +- browser smoke и крупный Light/Dark golden/reference сценарий; +- screenshot/golden fingerprints, если их источник изменён. + +Release note: внешняя рамка текстовых маркеров снова соответствует капсульной +форме дизайн-пакета вместо овала. Сначала beta; stable — только по отдельной +команде владельца. + +## 18. Принятые предположения + +1. Дизайн-пакет #179 однозначно задаёт stadium для внешней рамки Text, поэтому + дополнительного продуктового вопроса не требуется. +2. Исправляется только форма внешней Text-рамки; её размеры, inset и цвета + остаются текущими. +3. Icon-only остаётся кругом, Double/value/legacy и opening lock не меняются. +4. Новых настроек, строк и миграций нет. +5. Для визуального review используется отдельный крупный длинный Text marker, + а не только существующий общий мелкий golden. diff --git a/docs/specs/README.md b/docs/specs/README.md index 550ecee1..c855b387 100644 --- a/docs/specs/README.md +++ b/docs/specs/README.md @@ -56,6 +56,7 @@ GitHub Issues и GitHub Projects (v2) остаются единственным | [#179](https://github.com/Matysh/houseplan-card/issues/179) Новый визуальный язык маркеров устройств | [179-device-icons-redesign.md](179-device-icons-redesign.md) | | [#210](https://github.com/Matysh/houseplan-card/issues/210) Фиксированное пространство экземпляра карточки | [210-fixed-floor-card.md](210-fixed-floor-card.md) | | [#211](https://github.com/Matysh/houseplan-card/issues/211) Визуальное соответствие маркеров дизайн-пакету #179 | [211-device-icons-visual-parity.md](211-device-icons-visual-parity.md) | +| [#217](https://github.com/Matysh/houseplan-card/issues/217) Внешняя рамка Text-маркера должна быть капсулой | [217-text-shell-outline.md](217-text-shell-outline.md) | | [#205](https://github.com/Matysh/houseplan-card/issues/205) Продолжение следа после короткой остановки пылесоса | [205-vacuum-trail-resume-grace.md](205-vacuum-trail-resume-grace.md) | ## P2