From 28d6b9ccd9de11fa00a685f5521e82087b256763 Mon Sep 17 00:00:00 2001 From: Sergey Matyunin Date: Thu, 20 Aug 2026 14:38:35 +0300 Subject: [PATCH] docs: specify lock and orange icon palette Issue: #219 User-Visible: no --- docs/specs/219-lock-orange-palette.md | 254 ++++++++++++++++++++++++++ docs/specs/README.md | 1 + 2 files changed, 255 insertions(+) create mode 100644 docs/specs/219-lock-orange-palette.md diff --git a/docs/specs/219-lock-orange-palette.md b/docs/specs/219-lock-orange-palette.md new file mode 100644 index 00000000..bb3b564b --- /dev/null +++ b/docs/specs/219-lock-orange-palette.md @@ -0,0 +1,254 @@ +# Issue #219 — единая палитра замков и glyph на оранжевых подложках + +- **Issue:** https://github.com/Matysh/houseplan-card/issues/219 +- **Связанные контракты:** #179, #211, #213, #217 +- **Тип:** bug / polish, обычный полный трек +- **Приоритет:** P1 +- **Пользовательское изменение:** да + +## 1. Сценарий и персона + +**Персона:** домочадец, который по плану проверяет, открыта ли дверь, заперт ли +замок и работает ли устройство; администратор, который сверяет те же состояния +в Device preview и статической карточке пространства. + +**Сценарий:** в светлой теме рядом находятся два устройства с оранжевой +semantic-подложкой. Активное устройство рисует белый glyph, а открытая дверь — +тёмный. Одновременно lock-состояние проёма всё ещё использует прежние black / amber +цвета, хотя владелец принял новый red / green смысл. + +## 2. Что человек увидит до и после + +До исправления одинаковая оранжевая подложка может содержать и белые, и тёмные +иконки в одной теме. Закрытый замок выглядит чёрным, открытый — оранжевым. + +После исправления каждый glyph на оранжевой подложке белый в светлой теме и +`#252525` в тёмной. Замок имеет отдельную однозначную палитру: открыто / +разблокировано — красный, закрыто / заблокировано — зелёный. + +## 3. Подтверждённая причина + +`src/styles.ts` задаёт разные правила для состояний, использующих оранжевую +подложку: + +- `.dev.on` уже имеет theme-specific foreground: white / `#252525`; +- `.dev.open` всегда использует `#4a2800`, независимо от темы; +- `.dev.lock-unlocked` и `.oplock.unlocked` используют старый amber-контракт; +- `.dev.lock-locked` и `.oplock.locked` используют старый black-контракт. + +Все три device-поверхности используют `cardStyles` и общий `renderDeviceFace()`, +поэтому причина не в разных renderer, а в несовместимых semantic CSS tokens. + +## 4. Нормативные источники и приоритет + +При расхождении применяются в следующем порядке: + +1. решение владельца в #219: lock open = red, lock closed = green; orange glyph + = white в Light и black в Dark; +2. это ТЗ после зелёного SPEC-REVIEW; +3. геометрия, слои, темы и interaction priority из #179/#211/#213/#217; +4. текущая реализация для всего поведения, явно не изменяемого этой задачей. + +Новое решение заменяет только state-цвета старого Lock/Unlock-контракта. Оно не +отменяет принятые размеры, glyph paths, shell/core geometry, тени и действия. + +## 5. Цели + +1. Дать lock-состояниям одну red/green палитру во всех представлениях. +2. Устранить theme-расхождение всех device glyph на оранжевой подложке. +3. Сохранить общий renderer и действующий приоритет interaction/alert слоёв. +4. Зафиксировать новую таблицу цветов автоматическими и визуальными проверками. + +## 6. Scope + +В задачу входят: + +- semantic CSS states в `src/styles.ts`; +- ordinary device marker для `lock-locked`, `lock-unlocked`, `on`, `open`; +- compact `.oplock` badge у door/gate opening; +- одинаковая проекция на интерактивном плане, в Device preview и static space + card через существующие shared DOM/CSS; +- contract/unit tests и существующая light/dark device state-table golden; +- оба changelog, `docs/TESTING.md`, при необходимости канонический документ + device icon states, generated bundles и screenshot fingerprint. + +## 7. Не входит в задачу + +- новые настройки цветов или миграция конфига; +- изменение определения `on`, `open`, `locked`, `unlocked`; +- изменение MDI icon, размеров, shell/core ratio, теней или stroke width; +- изменение hit-area, hover target, click/tap/keyboard/lock action; +- изменение alarm, unavailable, virtual, selected, focus или pulse animation; +- изменение оранжевых линий/створок проёмов, selection ring, room fill или Glow; +- изменение info-card текста и red warning-кнопки Unlock; +- принятие golden baseline на Windows, выпуск беты или закрытие issue. + +## 8. Нормативная таблица состояний + +### 8.1. Замки + +| Состояние | Core и semantic stroke | Glyph Light | Glyph Dark | +|---|---|---|---| +| `locked` / закрыто | green `#66D17A` | white `#FFFFFF` | `#252525` | +| `unlocked` / открыто | red `#F0410C` | white `#FFFFFF` | `#252525` | +| unknown/unavailable | существующая neutral-проекция | без изменений | без изменений | + +Таблица применяется одинаково к `.dev.lock-*` и `.oplock.*`. Locked использует +`mdi:lock`, unlocked/known-open — `mdi:lock-open-variant`, unknown — текущий +`mdi:lock-question`. Состояния `locking`/`unlocking` сохраняют текущую known-open +классификацию и не получают новой state machine в этой задаче. + +### 8.2. Оранжевая device-подложка + +После изменения оранжевую semantic-подложку device core имеют обычные состояния +`on`/working (`#F0A00C`) и physical `open` (`var(--hp-open)`). Для обоих: + +- Light glyph: `#FFFFFF`; +- Dark glyph: `#252525`; +- CSS `light-dark()` остаётся fallback, а явные `.theme-light/.theme-dark` + классы являются авторитетными при доступном `hass.themes.darkMode`. + +Оранжевый selection ring не является подложкой и не меняет текущий glyph. + +## 9. Приоритет состояний и взаимодействие + +Порядок существующих слоёв не меняется: + +- alarm остаётся выше hover/focus/selected и использует свой red alert contract; +- hover меняет ordinary state core/glyph на blue theme projection; +- focus и selected остаются отдельными ring-слоями и не стирают semantic core; +- unavailable остаётся серым, полупрозрачным и без hover; +- virtual сохраняет dashed shell с ordinary state core; +- press feedback, pulse и reduced motion не меняются. + +Правка не добавляет selectors, зависящих от pointer modality, и не меняет +touch/pen/mouse/keyboard contract. + +## 10. Архитектура и зоны изменений + +Ожидаемая реализация остаётся декларативной: + +```text +ResolvedDevicePresentation classes / opening lock state + → shared semantic CSS variables in cardStyles + → existing device-face / oplock DOM + → plan + preview + static card +``` + +Ожидаемые файлы: + +- `src/styles.ts` — state tokens и theme-specific foreground; +- `test/device-marker-polish-contract.test.mjs` — точные semantic contracts; +- `demo/golden/matrix.mjs` и `test/golden-matrix.test.mjs` — orange `open` рядом + с `on`, обе темы, lock red/green states; +- `docs/TESTING.md`, оба changelog и при необходимости device-icon docs; +- три generated bundle после `npm run build`. + +`src/device-presentation.ts`, `src/device-face.ts` и `src/houseplan-card.ts` не +должны меняться, если анализ реализации не обнаружит, что CSS-классы не доходят +до одной из уже общих поверхностей. Такое расширение сначала фиксируется в +implementation evidence; новый renderer запрещён. + +## 11. Данные, i18n, accessibility, privacy и security + +Config/backend schema, persisted layout, localStorage и сериализация не меняются; +миграция не нужна. Новых строк и i18n-ключей нет. `aria-label`, state text, +tooltip и действия сохраняются; красный/зелёный не становятся единственным +носителем смысла, потому что glyph и текст состояния различаются. Network, +permissions и private data не затрагиваются. + +## 12. Performance + +Изменение ограничено CSS variables и fixture/test metadata. Оно не добавляет DOM, +JS в render path, observers, timers, filters, blur или layout measurement. +Performance budget и размер hit-area должны остаться без изменений. + +## 13. Риски + +| Риск | Последствие | Снижение риска и доказательство | +|---|---|---| +| Broad selector перекрасит alert/hover/unavailable | Семантически более важное состояние станет неверным | Сохраняется текущая specificity/порядок; unit проверяет selectors, golden — комбинации | +| Compact opening badge и device marker разойдутся | Одна lock-сущность будет иметь два цвета | Один contract test проверяет обе пары `.oplock` и `.dev.lock-*` | +| `light-dark()` не следует HA theme | Цвет зависит от browser color-scheme | Сохраняются явные `.theme-light/.theme-dark`; тест требует обе проекции | +| Golden покажет ожидаемую дельту вместе с посторонней | Можно принять лишнее визуальное изменение | Меняется существующая state-table, reviewer сверяет light/dark artifacts; baseline принимается только полным Linux-run по процессу | +| Красный/зелёный затронут info-card action status | Меняется не запрошенная UX-семантика | Scope ограничен marker/badge CSS; info-card selectors и код действий остаются byte-unchanged | + +## 14. Acceptance criteria + +1. **AC1 — lock badge palette.** Compact opening badge показывает `locked` с + core/stroke `#66D17A`, `unlocked` с core/stroke `#F0410C`; Light glyph белый, + Dark glyph `#252525`; unknown остаётся neutral. **Доказательство:** contract + unit + light/dark visual artifact. +2. **AC2 — lock marker parity.** Обычный marker lock-сущности использует ту же + red/green таблицу и прежние `mdi:lock` / `mdi:lock-open-variant` во View, + Device preview и static card. **Доказательство:** presentation/unit source + contract + shared-renderer test + golden state-table. +3. **AC3 — orange glyph parity.** `on` и physical `open` на оранжевой подложке + имеют белый glyph в Light и `#252525` в Dark; failing-before-fix assertion + ловит прежний постоянный `#4a2800` у `.dev.open`. **Доказательство:** contract + unit + state-table light/dark golden с одновременно видимыми `on` и `open`. +4. **AC4 — interaction priority.** Alarm, hover, focus, selected, unavailable, + virtual и press/pulse selectors сохраняют прежний приоритет и значения; + hit-area и действия не меняются. **Доказательство:** существующие device + presentation/polish/pointer tests + source review. +5. **AC5 — поверхности и темы.** Plan, preview и static card используют один + `cardStyles`/`renderDeviceFace` contract; обе темы проверены одной fixture без + поверхностных fork. **Доказательство:** shared-renderer unit + golden matrix. +6. **AC6 — невидимые контракты.** Нет изменений config/backend/i18n/a11y text, + DOM geometry, touch и performance path. **Доказательство:** diff review, + typecheck, полный unit и build. +7. **AC7 — release artifacts.** Оба changelog и `docs/TESTING.md` описывают новую + палитру; `dist`, demo и integration bundle идентичны; screenshot manifest + актуален. **Доказательство:** diff, hash comparison, `check-docs`. + +## 15. Проверки реализации и ревью + +Обязательный implementation loop: + +```text +npm run typecheck +npm test +npm run build +``` + +Дополнительно по изменённой поверхности: + +- targeted device marker contract tests; +- `npm run golden:verify` на code review / предрелизном гейте с обязательной + проверкой `device-icon-state-table-light` и `device-icon-state-table-dark`; +- сверка SHA-256 трёх bundle; +- `node scripts/check-docs.mjs --external`. + +Golden baseline не принимается автором реализации. Если baseline должен +измениться, это делается только через процесс reviewed Linux artifact. + +## 16. Release-артефакты + +- `docs/CHANGELOG.md`; +- `docs/CHANGELOG.ru.md`; +- `docs/TESTING.md`; +- актуализация канонической таблицы device states, если она дублирует старую + black/amber lock-палитру; +- light/dark state-table golden artifact для review; +- `docs/images/screenshots.json` после штатного capture, если source fingerprint + изменился; PNG коммитятся только при реальной проверенной дельте; +- три идентичных generated bundle. + +## 17. Откат + +Откат — один product commit #219 вместе с обоими changelog, документацией, +fixture/test metadata и generated bundles. Данные пользователя не меняются, +поэтому миграции назад нет. Частичный откат только одной из lock-проекций или +одной темы запрещён: он восстановит исходное расхождение. + +## 18. Принятые предположения + +1. «Чёрный в тёмной теме» — существующий designer foreground `#252525`. +2. Red/green lock palette применяется и к compact opening badge, и к обычному + marker lock-сущности. +3. Red/green используют существующие semantic цвета `#F0410C` / `#66D17A`; это + не настраиваемая пользователем палитра. +4. «Все иконки на оранжевой подложке» относится к device core. Оранжевые линии + проёмов, selection ring и activity ripple не являются подложкой glyph. +5. Дополнительных предупреждений, настроек и текстов не требуется. + diff --git a/docs/specs/README.md b/docs/specs/README.md index ff5d5c18..5bf54fbe 100644 --- a/docs/specs/README.md +++ b/docs/specs/README.md @@ -58,6 +58,7 @@ GitHub Issues и GitHub Projects (v2) остаются единственным | [#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) | | [#218](https://github.com/Matysh/houseplan-card/issues/218) Floating-point шум комнаты не гасит Glow пространства | [218-glow-floor-geometry.md](218-glow-floor-geometry.md) | +| [#219](https://github.com/Matysh/houseplan-card/issues/219) Единая палитра замков и glyph на оранжевых подложках | [219-lock-orange-palette.md](219-lock-orange-palette.md) | | [#205](https://github.com/Matysh/houseplan-card/issues/205) Продолжение следа после короткой остановки пылесоса | [205-vacuum-trail-resume-grace.md](205-vacuum-trail-resume-grace.md) | ## P2