fix: hide disabled room names

Issue: #203
User-Visible: yes
This commit is contained in:
Sergey Matyunin
2026-08-19 18:47:33 +03:00
parent 84e62dcd0f
commit 1290927f10
16 changed files with 348 additions and 175 deletions
File diff suppressed because one or more lines are too long
+152
View File
@@ -0,0 +1,152 @@
// #203: `show_names:false` means no permanent room labels in every read-only
// renderer. Plan keeps its editor-only card and saving never discards layout.
import { launch, checkAll, finish } from './serve.mjs';
const { page, browser } = await launch({ width: 1000, height: 850 });
const out = await page.evaluate(async () => {
const card = window.__card;
const root = (node = card) => node.renderRoot || node.shadowRoot;
const frame = () => new Promise((done) => requestAnimationFrame(() => requestAnimationFrame(done)));
const settle = async () => { await card.updateComplete; await frame(); };
const waitMode = async () => {
await settle();
while (card._modeTransitionBusy) await frame();
};
const labels = (node = card) => root(node).querySelectorAll('[data-hp="room-label"]');
const htmlLabels = (node = card) => root(node).querySelectorAll('div.roomlabel[data-hp="room-label"]');
const svgLabels = (node = card) => root(node).querySelectorAll('text.rlabel[data-hp="room-label"]');
card._setMode('view');
await waitMode();
const space = card._serverCfg.spaces.find((item) => item.id === card._space);
delete space.plan_url;
delete space.plan_aspect;
const room = space.rooms.find((item) => item.name && item.id && item.area)
|| space.rooms.find((item) => item.name && item.id);
if (!room) throw new Error('fixture has no named room');
space.settings = {
...(space.settings || {}), show_borders: true, show_names: true,
label_temp: true, label_hum: true, label_lqi: true, label_light: true,
};
const layoutKey = `rl_${room.id}`;
card._layout[layoutKey] = { s: space.id, x: 0.23, y: 0.31, k: 1.6 };
card._cfgEpoch++;
card._regSignature = '';
card.requestUpdate();
await settle();
const first = root().querySelector(`[data-hp="room-label"][data-id="${room.id}"]`);
const savedLayout = JSON.stringify(card._layout[layoutKey]);
const trueState = {
oneHtmlPerNamedRoom: htmlLabels().length === space.rooms.filter((item) => item.name).length,
noLegacySvg: svgLabels().length === 0,
savedScaleApplied: first?.getAttribute('style')?.includes('--rl-scale:1.6') === true,
areaIconKept: !room.area || !!first?.querySelector('.rlgo'),
};
// Cancel: the live preview follows the pending false, but persisted config
// and the room-label layout return untouched when the dialog is dismissed.
card._openSpaceDialog('edit', space.id);
card._spaceDialog = { ...card._spaceDialog, showNames: false };
card.requestUpdate();
await settle();
const livePreviewHidesAll = labels().length === 0;
card._spaceDialog = null;
card.requestUpdate();
await settle();
const cancelRestoresTrue = space.settings.show_names === true && htmlLabels().length > 0
&& JSON.stringify(card._layout[layoutKey]) === savedLayout;
// Save + reopen: exercise the real existing-space persistence path.
card._openSpaceDialog('edit', space.id);
card._spaceDialog = { ...card._spaceDialog, showNames: false };
await card._saveSpaceDialog();
await settle();
card._openSpaceDialog('edit', space.id);
const reopenReadsFalse = card._spaceDialog?.showNames === false
&& space.settings.show_names === false;
card._spaceDialog = null;
card.requestUpdate();
await settle();
const flatFalseHasNoLabels = labels().length === 0
&& htmlLabels().length === 0 && svgLabels().length === 0;
card._setMode('plan');
await waitMode();
const planFalseKeepsEditorCard = htmlLabels().length > 0
&& svgLabels().length === 0 && !!root().querySelector('.rlgearbtn');
card._setMode('view');
await waitMode();
const viewAfterPlanStillHidden = labels().length === 0;
// The Labs registry flag is intentionally expired; use the same dormant
// renderer fixture hook as the canonical Stage 2 smokes.
const active = Object.freeze(['iso']);
card._onLabsSnapshot({ active, space: '' });
window.__hpLabs = active;
await settle();
card._setProjection('iso');
await settle();
const isoFalseHasNoLabels = !!root().querySelector('[data-hp="iso-walls"]')
&& labels().length === 0;
card._setProjection('flat');
await settle();
await customElements.whenDefined('houseplan-space-card');
const cfgFalse = structuredClone(card._serverCfg);
const layout = structuredClone(card._layout);
const staticHass = {
...card.hass,
callWS: async (message) => {
if (message.type === 'houseplan/config/get') return { config: cfgFalse, rev: 1 };
if (message.type === 'houseplan/layout/get') return { layout, rev: 1 };
return { ok: true };
},
};
const host = document.createElement('div');
document.body.appendChild(host);
const compact = document.createElement('houseplan-space-card');
compact.setConfig({ type: 'custom:houseplan-space-card', space: space.id, show_button: false });
compact.hass = staticHass;
host.appendChild(compact);
const deadline = Date.now() + 6000;
while (!root(compact)?.querySelector('.hp-static-stage') && Date.now() < deadline) {
await new Promise((done) => setTimeout(done, 60));
}
await compact.updateComplete;
const compactFalseHasNoLabels = labels(compact).length === 0
&& htmlLabels(compact).length === 0 && svgLabels(compact).length === 0;
// Turning names back on restores the existing HTML card and saved layout.
space.settings.show_names = true;
card._cfgEpoch++;
card.requestUpdate();
await settle();
const restored = root().querySelector(`[data-hp="room-label"][data-id="${room.id}"]`);
const trueRestoresExistingCard = !!restored
&& restored.tagName.toLowerCase() === 'div'
&& restored.getAttribute('style')?.includes('--rl-scale:1.6') === true
&& JSON.stringify(card._layout[layoutKey]) === savedLayout;
host.remove();
card._onLabsSnapshot({ active: Object.freeze([]), space: '' });
window.__hpLabs = Object.freeze([]);
await settle();
return {
...trueState,
livePreviewHidesAll,
cancelRestoresTrue,
reopenReadsFalse,
flatFalseHasNoLabels,
planFalseKeepsEditorCard,
viewAfterPlanStillHidden,
isoFalseHasNoLabels,
compactFalseHasNoLabels,
trueRestoresExistingCard,
};
});
checkAll(out);
await finish(browser, out);
+5 -8
View File
@@ -3,7 +3,7 @@
// НАХОДЯТСЯ через querySelector — ровно так, как их будет искать чужой CSS.
// 1) устройство: data-hp="device" + data-id + data-entity + data-area;
// 2) комната: data-hp="room" + data-id + data-area;
// 3) подпись комнаты: data-hp="room-label" + data-id (и в SVG, и в HTML-карточке);
// 3) видимая подпись комнаты: data-hp="room-label" + data-id на HTML-карточке;
// 4) проём: data-hp="opening" + data-id + data-kind (door/window/gate);
// 5) декор: data-hp="decor" + data-id + data-kind (line/rect/ellipse/text);
// 6) вкладка пространства: data-hp="space-tab" + data-id;
@@ -50,8 +50,8 @@ const res = await page.evaluate(async () => {
out.roomIsAnSvgShape = !!kitchen && ['polygon', 'rect', 'path'].includes(kitchen.tagName.toLowerCase());
// ============ 3. подписи комнат ============
// одно имя — две разные реализации: <text> в SVG на плане без подложки и
// HTML-карточка, когда включены «имена на плане». Хук на обеих один и тот же.
// #203: false означает отсутствие подписи, а не вторую SVG-реализацию.
// При true единственный публичный hook живёт на HTML-карточке.
const disp = c._curSpaceCfg.settings || (c._curSpaceCfg.settings = {});
const wasNames = disp.show_names;
const planUrl = c._curSpaceCfg.plan_url;
@@ -60,11 +60,8 @@ const res = await page.evaluate(async () => {
await c.updateComplete; await sleep(60); await c.updateComplete;
};
delete c._curSpaceCfg.plan_url; disp.show_names = false; await redraw();
const svgLabels = qa('text.rlabel[data-hp="room-label"]');
out.svgRoomLabelHooked = svgLabels.length > 0
&& svgLabels.every((e) => !!e.getAttribute('data-id'));
out.svgRoomLabelFoundById = !!q('text[data-hp="room-label"][data-id="r1"]');
out.svgRoomLabelHasArea = q('text[data-hp="room-label"][data-id="r1"]')?.getAttribute('data-area') === 'living_room';
out.hiddenRoomLabelsAreAbsent = qa('[data-hp="room-label"]').length === 0
&& qa('text.rlabel').length === 0;
c._curSpaceCfg.plan_url = planUrl; disp.show_names = true; await redraw();
const htmlLabel = q('div.roomlabel[data-hp="room-label"][data-id="r2"]');
out.htmlRoomLabelHooked = !!htmlLabel;
File diff suppressed because one or more lines are too long
+25 -39
View File
File diff suppressed because one or more lines are too long
+7
View File
@@ -2,6 +2,13 @@
## v1.65.0-beta.4 — 2026-08-19
- Turning off **Show names** now removes room names completely in View, kiosk,
the static card and hidden isometric mode, while Plan still exposes the
existing draggable card for positioning. Re-enabling names restores its
saved layout. **Breaking styling-hook change:** the fallback SVG
`text.rlabel` / `.rlabel` public hook has been removed; enabled room names
use `[data-hp="room-label"].roomlabel`
([#203](https://github.com/Matysh/houseplan-card/issues/203)).
- Closing a virtual room boundary now inherits the real thickness of an
adjacent wall even when another room splits that saved wall into smaller
atomic stretches. A 20/22 cm wall therefore no longer receives an accidental
+8
View File
@@ -8,6 +8,14 @@
## v1.65.0-beta.4 — 2026-08-19
- Выключение **«Показывать названия»** теперь полностью убирает названия комнат
из Просмотра, киоска, статической карточки и скрытой изометрии, а редактор
Плана по-прежнему временно показывает существующую карточку для настройки
позиции. Повторное включение восстанавливает сохранённую компоновку.
**Несовместимое изменение styling-hook:** публичный резервный SVG-хук
`text.rlabel` / `.rlabel` удалён; включённые названия используют
`[data-hp="room-label"].roomlabel`
([#203](https://github.com/Matysh/houseplan-card/issues/203)).
- При закрытии виртуальной границы теперь наследуется реальная толщина соседней
стены, даже если другая комната разделила сохранённую стену на несколько
атомарных участков. Поэтому на стене 20/22 см больше не появляется случайная
+7 -1
View File
@@ -92,7 +92,6 @@ Everything in this table is **public API**.
| --- | --- | --- | --- | --- |
| Device marker | `div` (HTML, marker layer) | `device` | `data-id` = marker/device id, `data-entity` = primary entity id, `data-area` = area id, `data-binding-status` = `active` \| `ha-disabled` \| `orphaned` \| `unverified`, `data-disabled-reason` = `device` \| `entity` \| `all-entities` when applicable | `.dev` |
| Room shape | `polygon` / `rect` / `path` (SVG) | `room` | `data-id` = room id, `data-area` = area id | `.room` |
| Room name (no metrics) | `text` (SVG) | `room-label` | `data-id` = room id, `data-area` | `.rlabel` |
| Room card (name + metrics) | `div` (HTML, marker layer) | `room-label` | `data-id` = room id, `data-area` | `.roomlabel` |
| Door / window / gate | `g` (SVG) | `opening` | `data-id` = opening id, `data-kind` = `door` \| `window` \| `gate` | `.opening` |
| Coloured tunnel inside a thick opening | `path` / `g` (SVG) | `opening-tunnel` | `data-id` = opening id, `data-kind` = `door` \| `window` \| `gate` | `.opening-tunnel` |
@@ -132,6 +131,13 @@ usually wants:
Inside a room card: `.rlname` (the name) and `.rlmetrics` / `.rlm` (the
metric row and one metric in it).
**Breaking hook change in #203.** The former SVG fallback
`text.rlabel[data-hp="room-label"]` has been removed. A space with
`show_names: false` now emits no permanent room-label element at all, as the
setting promises. Target the HTML room-card hook
`[data-hp="room-label"].roomlabel` when room names are enabled. Plan editor
temporarily renders the same HTML card so it can still be positioned.
### 3.2 Public state classes
These are set on `.dev` and describe **live state**, so a rule may key off
+16 -2
View File
@@ -2081,7 +2081,7 @@ require hands on real hardware — they remain for the human pass.
carries `data-hp="device"`, `data-id`, `data-entity` and `data-area`; a
room `data-hp="room"` + `data-id` + `data-area`; a door/window/gate
`data-hp="opening"` + `data-kind`; a decor shape `data-hp="decor"` +
`data-kind`; a room caption `data-hp="room-label"`; a floor tab
`data-kind`; a visible room card `data-hp="room-label"`; a floor tab
`data-hp="space-tab"`. The ids are the ones in your config, not DOM
positions — they survive a reload [auto: smoke_styling_hooks]
- [ ] **Absent is absent**: a virtual marker has NO `data-entity` at all, and a
@@ -2092,7 +2092,7 @@ require hands on real hardware — they remain for the human pass.
signal badges disappear and nothing else moves. Then target one marker by
`[data-entity="…"]` and confirm it is the only one affected [manual]
- [ ] **The static card carries the same hooks**: a `houseplan-space-card`
has `data-hp` on its rooms, room labels and markers (it draws no openings
has `data-hp` on its rooms, visible room labels and markers (it draws no openings
and no decor, so those are simply absent), and it needs its OWN card-mod
block — it is a different card with its own shadow root
[auto: smoke_styling_hooks]
@@ -2359,6 +2359,20 @@ require hands on real hardware — they remain for the human pass.
## Hiding layers: decor, openings, virtual walls (docs/UX-MODES.md, dev, unreleased)
- [ ] **Room names have one literal off state (#203)**: disable «Показывать
названия» in the live space dialog, save and reopen it. Full View, kiosk,
hidden isometric and `houseplan-space-card` contain no
`[data-hp="room-label"]` and no legacy `text.rlabel`. Plan temporarily
shows the same draggable HTML card and gear; returning to View hides it.
Cancel restores the previous setting, while re-enabling names restores
the saved card position and area icon
[auto: `smoke_hide_room_names`, `smoke_styling_hooks`].
- [ ] **Each renderer can fail independently**: restoring the old full-card SVG
fallback, compact-card SVG fallback or hidden-isometric override makes
the dedicated smoke red
[mutation: `hidden-room-names-full-svg-fallback`,
`hidden-room-names-compact-svg-fallback`,
`hidden-room-names-iso-override`].
- [ ] **«Скрыть декоративный слой»** (owner 2026-08-05): a space with lines,
labels or furniture on it → space settings → Display → tick the box, save.
The plan loses all of it, in View, in the Plan editor and in the Device
+5 -1
View File
@@ -268,7 +268,7 @@ desktop: для точного рисования, Resize, модификато
|---|---|---|
| Масштаб | Сантиметров на клетку | Переводит сетку в реальные размеры и площади; начальное значение 5 см |
| Отображение | Всегда показывать границы | Рисует контуры комнат в просмотре |
| Отображение | Показывать названия | Рисует карточки/названия комнат; их можно двигать в редакторе плана |
| Отображение | Показывать названия | Рисует карточки комнат в Просмотре, киоске и статической карточке; при выключении не оставляет упрощённых подписей |
| Отображение | Показывать LQI | Переопределяет базовую настройку карточки для этого пространства |
| Отображение | Скрыть декоративный слой | Не рисует линии, фигуры, текст и мебель в просмотре; в редакторе подложки они остаются видимыми |
| Отображение | Скрыть проёмы | Скрывает только символы дверей, окон и ворот; свет, солнечные лучи и датчики проёмов продолжают работать |
@@ -277,6 +277,10 @@ desktop: для точного рисования, Resize, модификато
Карточка комнаты остаётся частью плана: её можно перемещать и масштабировать в
редакторе, а в просмотре она собирает только включённые метрики.
Если «Показывать названия» выключено, редактор Плана временно показывает
карточку только для настройки её позиции. После возврата в Просмотр она снова
исчезает; сохранённая позиция не теряется и используется при повторном
включении названий.
![Карточка комнаты с температурой, LQI и состоянием света](images/08-room-card.png)
| Стиль | Цвет и прозрачность | Общий цвет границ и названий |
+10 -3
View File
@@ -111,7 +111,7 @@ Header in View: space tabs, device count, zoom cluster. Nothing else.
### What a space may choose not to draw (2026-08-05)
Three switches in the space's Display section decide how much of the plan is
Four switches in the space's Display section decide how much of the plan is
inked. All of them are **display only** — nothing is deleted, nothing changes
meaning, and each layer stays visible in the editor that owns it, because a
layer you cannot see is a layer you cannot edit.
@@ -119,6 +119,7 @@ layer you cannot see is a layer you cannot edit.
| Setting | Off (default) | On | Always drawn in |
|---|---|---|---|
| `show_borders` — «Всегда отображать границы комнат» | in View, borders and dashed **virtual walls** are hidden | both are drawn | room borders: Plan; virtual walls: all editors |
| `show_names` — «Показывать названия» | no room name/card is drawn in View, kiosk or the static card | the HTML room card is drawn | Plan, for positioning only |
| `hide_decor` — «Скрыть декоративный слой» | decor is drawn | lines, shapes, labels and furniture are hidden | the Background editor |
| `hide_openings` — «Скрыть проёмы» | doors, windows and gates are drawn | their symbols are hidden | the Plan editor |
@@ -127,6 +128,11 @@ layer you cannot see is a layer you cannot edit.
only walls were a few floating dashed stretches. Every editor deliberately
shows them regardless of the switch: hiding geometry while editing a plan,
device placement or its underlay makes those modes visually ambiguous.
- **`show_names: false` means no permanent fallback label.** View, kiosk,
hidden isometric and `houseplan-space-card` all omit the room name. Plan may
show the same HTML card temporarily so its saved position remains editable;
returning to View hides it again. Re-enabling names restores the saved
layout rather than creating a new one.
- **Their geometry and their presentation are separate.** Every virtual span
still ends on the real wall centreline. In View the thick wall body is
painted over the dash ends, so they visually stop at its faces; editors paint
@@ -135,9 +141,10 @@ layer you cannot see is a layer you cannot edit.
through it, the sun still enters at a window, a contact sensor still opens
it, and the resize tool still anchors to it. Anything else would be a second
meaning for one setting.
- Both new switches store **nothing when off** (the key is omitted, as
- Both hide switches store **nothing when off** (the key is omitted, as
`bg_color` is), so a plan written before this reads back byte-for-byte.
Backend: `hide_decor` / `hide_openings`, strictly `bool`, both optional.
Backend: `show_names`, `hide_decor` and `hide_openings` are strictly `bool`
and optional.
## Devices — placement and marker configuration
+11 -11
View File
@@ -1,7 +1,7 @@
{
"version": 1,
"fixture": "synthetic-only",
"sourceFingerprint": "51c4bdb005b2539779085578bcce5ee1b4b3e3137542ef1aeb440232344c3105",
"sourceFingerprint": "49963a7758df03d7aaaa3af3b9f198d629f4ca44af5c8ef9834c7afce5fda8ba",
"captureScriptSha256": "34f2219790d46efd8250e7a1bd829cb8fc0b0547e1260635fefa52407551b41b",
"command": "npm run build && node demo/docs/capture.mjs",
"scenarios": {
@@ -13,7 +13,7 @@
},
"theme": "dark",
"language": "en",
"sourceSha256": "51c4bdb005b2539779085578bcce5ee1b4b3e3137542ef1aeb440232344c3105",
"sourceSha256": "49963a7758df03d7aaaa3af3b9f198d629f4ca44af5c8ef9834c7afce5fda8ba",
"imageSha256": "d36b6f9f8139f31ef73a780c6511a640a26055efd9d7a24c24fd48b1d8379bf0"
},
"view-touch": {
@@ -24,7 +24,7 @@
},
"theme": "dark",
"language": "en",
"sourceSha256": "51c4bdb005b2539779085578bcce5ee1b4b3e3137542ef1aeb440232344c3105",
"sourceSha256": "49963a7758df03d7aaaa3af3b9f198d629f4ca44af5c8ef9834c7afce5fda8ba",
"imageSha256": "358e25ff9984d0fb0c03cfbb848df40c425fdfe64cd5f4f613b1e754ca9d4249"
},
"space-create": {
@@ -35,7 +35,7 @@
},
"theme": "dark",
"language": "en",
"sourceSha256": "51c4bdb005b2539779085578bcce5ee1b4b3e3137542ef1aeb440232344c3105",
"sourceSha256": "49963a7758df03d7aaaa3af3b9f198d629f4ca44af5c8ef9834c7afce5fda8ba",
"imageSha256": "c53db2e5c642a5549c13f3c93a5b359fed69bdb2621bf71a243a877ffcb95e6b"
},
"room-contour-close": {
@@ -46,7 +46,7 @@
},
"theme": "dark",
"language": "en",
"sourceSha256": "51c4bdb005b2539779085578bcce5ee1b4b3e3137542ef1aeb440232344c3105",
"sourceSha256": "49963a7758df03d7aaaa3af3b9f198d629f4ca44af5c8ef9834c7afce5fda8ba",
"imageSha256": "2f13ea645af306eee9cc7c52699c928377b72f412b08c1a3db6beb848ace1b51"
},
"plan-context-tray": {
@@ -57,7 +57,7 @@
},
"theme": "dark",
"language": "en",
"sourceSha256": "51c4bdb005b2539779085578bcce5ee1b4b3e3137542ef1aeb440232344c3105",
"sourceSha256": "49963a7758df03d7aaaa3af3b9f198d629f4ca44af5c8ef9834c7afce5fda8ba",
"imageSha256": "a6c526fede11bc3503fd2384bd4a3f6afa008f481c5c47578f06cae6c81c6f9b"
},
"device-editor": {
@@ -68,7 +68,7 @@
},
"theme": "dark",
"language": "en",
"sourceSha256": "51c4bdb005b2539779085578bcce5ee1b4b3e3137542ef1aeb440232344c3105",
"sourceSha256": "49963a7758df03d7aaaa3af3b9f198d629f4ca44af5c8ef9834c7afce5fda8ba",
"imageSha256": "7c3e25534fc819c45431907616c3d523961505859ee68af27cce2daec9f04fb0"
},
"device-display-preview": {
@@ -79,7 +79,7 @@
},
"theme": "dark",
"language": "en",
"sourceSha256": "51c4bdb005b2539779085578bcce5ee1b4b3e3137542ef1aeb440232344c3105",
"sourceSha256": "49963a7758df03d7aaaa3af3b9f198d629f4ca44af5c8ef9834c7afce5fda8ba",
"imageSha256": "df3a54395c83bffd7a161f1fb3de0143e12e76567535aedf9883873ead74df91"
},
"background-editor": {
@@ -90,7 +90,7 @@
},
"theme": "dark",
"language": "en",
"sourceSha256": "51c4bdb005b2539779085578bcce5ee1b4b3e3137542ef1aeb440232344c3105",
"sourceSha256": "49963a7758df03d7aaaa3af3b9f198d629f4ca44af5c8ef9834c7afce5fda8ba",
"imageSha256": "d7cfe70551d9260169df8efd832e32ed7df99c7f60b55d1fd4a8322bd4c47175"
},
"room-card": {
@@ -101,7 +101,7 @@
},
"theme": "dark",
"language": "en",
"sourceSha256": "51c4bdb005b2539779085578bcce5ee1b4b3e3137542ef1aeb440232344c3105",
"sourceSha256": "49963a7758df03d7aaaa3af3b9f198d629f4ca44af5c8ef9834c7afce5fda8ba",
"imageSha256": "176abba71d41cfb045a33f82a794d9fbb2a5d3c48e6df66e6ec3a8e448311b11"
},
"device-info": {
@@ -112,7 +112,7 @@
},
"theme": "dark",
"language": "en",
"sourceSha256": "51c4bdb005b2539779085578bcce5ee1b4b3e3137542ef1aeb440232344c3105",
"sourceSha256": "49963a7758df03d7aaaa3af3b9f198d629f4ca44af5c8ef9834c7afce5fda8ba",
"imageSha256": "2199ed88b215bf2bff63bf665028f78b2aa6a92c3032b803931790f2ef071893"
}
}
+50
View File
@@ -404,6 +404,56 @@ export const MUTANTS = [
replace: ' if (!replacingRemoved && prevPos && prevPos.s === targetSpaceId && !roomChanged) {',
}],
},
{
id: 'hidden-room-names-full-svg-fallback',
guard: 'node demo/smoke_hide_room_names.mjs',
because: 'show_names:false must remove every permanent label from the full flat renderer; '
+ 'the smoke must reject the legacy centred SVG substitute independently of compact and iso',
patches: [{
file: 'src/houseplan-card.ts',
find: " ${this._renderOpeningTunnelFills(space, glowBase, 'glow-base')}\n"
+ ' ${glowLayerVisible ? this._renderGlowLayer(space, disp) : nothing}',
replace: " ${this._renderOpeningTunnelFills(space, glowBase, 'glow-base')}\n"
+ ' ${!space.bg && !disp.showNames && !this._markup ? svg`<g class="room-svg-labels" pointer-events="none">${space.rooms.map((room) => {\n'
+ ' const center = this._roomCenter(room);\n'
+ ' return svg`<text class="rlabel" data-hp="room-label" data-id=${room.id || nothing}\n'
+ ' data-area=${room.area || nothing} x=${center[0]} y=${center[1]}>${room.name}</text>`;\n'
+ ' })}</g>` : nothing}\n'
+ ' ${glowLayerVisible ? this._renderGlowLayer(space, disp) : nothing}',
}],
},
{
id: 'hidden-room-names-compact-svg-fallback',
guard: 'node demo/smoke_hide_room_names.mjs',
because: 'the compact card is an independent renderer and must not replace a disabled HTML '
+ 'room card with the old SVG name even when the full card is correct',
patches: [{
file: 'src/space-render.ts',
find: ' spaceModels, defaultPositions, markerPos, labelPos, spaceFrame, iconCqw, NORM_W,',
replace: ' spaceModels, roomCenter, defaultPositions, markerPos, labelPos, spaceFrame, iconCqw, NORM_W,',
}, {
file: 'src/space-render.ts',
find: ' ${passageGlowTunnels}\n ${wallUnion',
replace: ' ${passageGlowTunnels}\n'
+ ' ${!space.bg && !disp.showNames ? svg`<g class="room-svg-labels" pointer-events="none">${space.rooms.map((room) => {\n'
+ ' const center = roomCenter(room);\n'
+ ' return svg`<text class="rlabel" data-hp="room-label" data-id=${room.id || nothing}\n'
+ ' data-area=${room.area || nothing} x=${center[0]} y=${center[1]}>${room.name}</text>`;\n'
+ ' })}</g>` : nothing}\n'
+ ' ${wallUnion',
}],
},
{
id: 'hidden-room-names-iso-override',
guard: 'node demo/smoke_hide_room_names.mjs',
because: 'hidden isometric View must obey the same show_names:false contract instead of '
+ 'forcing an HTML room card solely because the space has no backdrop',
patches: [{
file: 'src/houseplan-card.ts',
find: ' ${disp.showNames || this._markup\n',
replace: ' ${disp.showNames || (iso && !space.bg) || this._markup\n',
}],
},
{
id: 'plan-room-area-icon-hidden',
guard: 'node demo/smoke_room_link.mjs',
+1 -13
View File
@@ -10907,17 +10907,6 @@ class HouseplanCard extends LitElement {
return svg`<g class="glow-base-layer" aria-hidden="true" pointer-events="none">${shapes}</g>` as unknown as TemplateResult;
}
private _renderSvgRoomLabels(space: SpaceModel, disp: SpaceDisplay): TemplateResult {
if (this._renderProjection === 'iso' || space.bg || disp.showNames || this._markup)
return svg`` as unknown as TemplateResult;
return svg`<g class="room-svg-labels" pointer-events="none">${space.rooms.map((room) => {
const center = this._roomCenter(room);
return svg`<text class="rlabel" data-hp="room-label"
data-id=${room.id || nothing} data-area=${room.area || nothing}
x=${center[0]} y=${center[1]}>${room.name}</text>`;
})}</g>` as unknown as TemplateResult;
}
private _renderWallBodies(disp: SpaceDisplay): TemplateResult {
if (this._renderProjection === 'iso') return svg`` as unknown as TemplateResult;
if (disp && !disp.showBorders && (this._mode === 'view' || this._mode === 'devices'))
@@ -15754,7 +15743,6 @@ class HouseplanCard extends LitElement {
${this._renderOpeningTunnelFills(space, roomFills)}
${this._renderGlowBaseRooms(space, glowBase)}
${this._renderOpeningTunnelFills(space, glowBase, 'glow-base')}
${this._renderSvgRoomLabels(space, disp)}
${glowLayerVisible ? this._renderGlowLayer(space, disp) : nothing}
${this._renderSunRays(space)}
${this._editing ? svg`<g class="hp-editor-only-layer"
@@ -15822,7 +15810,7 @@ class HouseplanCard extends LitElement {
${this._renderVacuums(devs, view)}
${this._renderVacFit(view)}
${this._renderOpeningLocks(view)}
${disp.showNames || (iso && !space.bg) || this._markup
${disp.showNames || this._markup
? space.rooms.map((r) => this._renderRoomLabel(r, space, view, disp))
: nothing}
${this._markup ? space.rooms.map((r) => this._renderRoomGear(r, space, view)) : nothing}
+1 -11
View File
@@ -42,7 +42,7 @@ import { contentFingerprint } from './visual-continuity';
import type { VirtualLightSnapshot } from './virtual-light-state';
import { renderOpeningTunnelFills } from './render/opening-tunnels';
import {
spaceModels, roomCenter, defaultPositions, markerPos, labelPos, spaceFrame, iconCqw, NORM_W,
spaceModels, defaultPositions, markerPos, labelPos, spaceFrame, iconCqw, NORM_W,
GRID_STEP_N, GRID_PITCH, staticPassageOpenings,
type Layout, type ContentItem,
} from './space-geometry';
@@ -342,15 +342,6 @@ export function renderSpaceStatic(o: StaticRenderOpts): TemplateResult | null {
? { color: colors.glow_base.c, opacity: colors.glow_base.a, mode: 'glow' }
: null);
}
const staticSvgLabels = !space.bg && !disp.showNames
? space.rooms.map((room) => {
const center = roomCenter(room);
return svg`<text class="rlabel" data-hp="room-label"
data-id=${room.id || nothing} data-area=${room.area || nothing}
x=${center[0]} y=${center[1]}>${room.name}</text>`;
})
: [];
const planLightSources = resolvedLightSources(planHass, devs, null, o.virtualLights);
const markers = devs.map((d) => {
const p = markerPos(d, o.layout, o.cfg, defPos, space);
@@ -529,7 +520,6 @@ export function renderSpaceStatic(o: StaticRenderOpts): TemplateResult | null {
? svg`<g class="glow-base-layer" aria-hidden="true" pointer-events="none">${glowBaseShapes}</g>`
: nothing}
${passageGlowTunnels}
<g class="room-svg-labels" pointer-events="none">${staticSvgLabels}</g>
${wallUnion
? svg`<g class="wallbodies" style="--room-stroke:${wallStroke}">
<path class="wallbody-fill" d="${wallUnion.d}"
-8
View File
@@ -1328,7 +1328,6 @@ export const cardStyles = css`
.stage .room,
.stage .devlayer,
.stage .opening,
.stage .rlabel,
.stage .room-outline,
.stage .wallbodies,
.stage .opening-tunnels,
@@ -1395,13 +1394,6 @@ export const cardStyles = css`
fill: var(--hp-open, #ff9800);
pointer-events: none;
}
.rlabel {
fill: var(--hp-muted);
font-size: 15px;
font-weight: 600;
pointer-events: none;
text-anchor: middle;
}
.stage.edit .room {
pointer-events: none;
}