ux v1.40.1: room click removed — link icon on the room card instead

- rooms inert in View (default cursor); mdi:open-in-new after the room
  name (View, rooms with an area) navigates to the HA area
- smoke_room_link.mjs (7 checks); TESTING/CHANGELOG/UX-MODES same-commit
This commit is contained in:
Matysh
2026-07-23 17:46:11 +03:00
parent df9e158efb
commit 4b4df4b3a2
14 changed files with 141 additions and 33 deletions
+1 -1
View File
@@ -11,7 +11,7 @@ PLANS_DIR = "houseplan/plans" # relative to the HA configuration directory
FILES_URL = "/houseplan_files/files" FILES_URL = "/houseplan_files/files"
FILES_DIR = "houseplan/files" FILES_DIR = "houseplan/files"
CONF_ADMIN_ONLY = "admin_only" CONF_ADMIN_ONLY = "admin_only"
VERSION = "1.40.0" VERSION = "1.40.1"
DEFAULT_CONFIG: dict = { DEFAULT_CONFIG: dict = {
"spaces": [], "spaces": [],
File diff suppressed because one or more lines are too long
+1 -1
View File
@@ -16,5 +16,5 @@
"issue_tracker": "https://github.com/Matysh/houseplan-card/issues", "issue_tracker": "https://github.com/Matysh/houseplan-card/issues",
"requirements": [], "requirements": [],
"single_config_entry": true, "single_config_entry": true,
"version": "1.40.0" "version": "1.40.1"
} }
+38
View File
@@ -0,0 +1,38 @@
import { launch } from './serve.mjs';
const { page, browser } = await launch();
const res = await page.evaluate(async () => {
const out = {};
const c = window.__card;
const sr = () => c.shadowRoot || c.renderRoot;
// включить имена комнат
c._serverCfg = { ...c._serverCfg, spaces: c._serverCfg.spaces.map((s) => s.id !== c._space ? s : ({
...s, settings: { ...(s.settings || {}), show_names: true } })) };
c._setMode('view'); c.requestUpdate(); await c.updateComplete;
await new Promise((r) => setTimeout(r, 250));
// 1) комната не кликабельна: cursor default, обработчика клика нет
const room = sr().querySelector('.room');
out.roomCursor = getComputedStyle(room).cursor === 'default';
// 2) значок ссылки у комнат с зоной, кликабелен, ведёт в зону
const links = sr().querySelectorAll('.rlgo');
out.linksShown = links.length > 0;
const withArea = c._spaceModel().rooms.filter((r) => r.name && r.area).length;
out.linkPerArearoom = links.length === withArea;
const icon = links[0];
out.linkCursor = getComputedStyle(icon).cursor === 'pointer';
out.linkClickable = getComputedStyle(icon).pointerEvents === 'auto';
// навигация: перехват history
let navTo = null;
const orig = history.pushState.bind(history);
history.pushState = (a, b, url) => { navTo = url; };
icon.dispatchEvent(new MouseEvent('click', { bubbles: true, composed: true }));
await c.updateComplete;
history.pushState = orig;
out.navigates = typeof navTo === 'string' && navTo.includes('/config/areas/area/');
// 3) комнаты без зоны — без значка (проверено соотношением выше); в разметке значков нет
c._setMode('plan'); await c.updateComplete;
out.noneInPlan = sr().querySelectorAll('.rlgo').length === 0;
c._setMode('view'); await c.updateComplete;
return out;
});
console.log(JSON.stringify(res, null, 1));
await browser.close();
File diff suppressed because one or more lines are too long
+21 -7
View File
File diff suppressed because one or more lines are too long
+6
View File
@@ -1,5 +1,11 @@
# Changelog # Changelog
## v1.40.1 — 2026-07-23
- Rooms are no longer clickable in View (default cursor, empty space does
nothing). Instead the room card shows a small **open-in-new icon** after
the name — clicking it opens the HA area. Rooms without an area (and all
editors) have no icon.
## v1.40.0 — 2026-07-23 (smart guides) ## v1.40.0 — 2026-07-23 (smart guides)
- **Alignment helper in every editor**: while drawing an outline, a cut or a - **Alignment helper in every editor**: while drawing an outline, a cut or a
decor shape, and while dragging icons, room cards or decor, thin dashed decor shape, and while dragging icons, room cards or decor, thin dashed
+4
View File
@@ -140,6 +140,10 @@ Run the *core flows* (marked ★ below) in each environment at least once per mi
(explicit ripple color still wins); off/white lights unchanged [auto] (explicit ripple color still wins); off/white lights unchanged [auto]
- [ ] Alarm pulse (v1.27.0): leak/smoke/gas/CO/siren in 'on' pulse a red ring over any - [ ] Alarm pulse (v1.27.0): leak/smoke/gas/CO/siren in 'on' pulse a red ring over any
display mode; clears on 'off'; unavailable never alarms [auto]; reduced-motion static display mode; clears on 'off'; unavailable never alarms [auto]; reduced-motion static
- [ ] Room link icon (v1.40.1): clicking empty room space in View does
nothing (default cursor); an open-in-new icon after the room name (rooms
with an HA area, View only) navigates to the area; no icon in editors or
on area-less rooms [auto]
- [ ] Smart guides (v1.40.0): while drawing (outline, cut, decor shapes) or - [ ] Smart guides (v1.40.0): while drawing (outline, cut, decor shapes) or
dragging (icons, room cards, decor) dashed accent guides appear from the dragging (icons, room cards, decor) dashed accent guides appear from the
nearest object sharing the X and/or Y (max two, with a dot at the nearest object sharing the X and/or Y (max two, with a dot at the
+1 -1
View File
@@ -35,7 +35,7 @@ Allowed: pan/zoom (wheel, pinch, buttons), switching spaces, device tap
(info / more-info / toggle per settings), long-press → info card, opening tap → (info / more-info / toggle per settings), long-press → info card, opening tap →
door/lock info card (with an explicit Unlock/Lock button when a lock is bound — door/lock info card (with an explicit Unlock/Lock button when a lock is bound —
the only way to operate a lock from the card; plan-icon taps never toggle locks), the only way to operate a lock from the card; plan-icon taps never toggle locks),
room tap → HA area, hover tooltips (name, temperature, signal). room-card link icon → HA area (room taps do nothing since v1.40.1), hover tooltips (name, temperature, signal).
Removed from this mode (they move, not die): Removed from this mode (they move, not die):
- icon dragging ("drag anywhere", v1.9 — consciously reversed), - icon dragging ("drag anywhere", v1.9 — consciously reversed),
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "houseplan-card", "name": "houseplan-card",
"version": "1.40.0", "version": "1.40.1",
"description": "Interactive house plan Lovelace card for Home Assistant", "description": "Interactive house plan Lovelace card for Home Assistant",
"license": "MIT", "license": "MIT",
"type": "module", "type": "module",
+10 -5
View File
@@ -32,7 +32,7 @@ import './space-card';
import { cardStyles } from './styles'; import { cardStyles } from './styles';
import { langOf, t, type I18nKey } from './i18n'; import { langOf, t, type I18nKey } from './i18n';
const CARD_VERSION = '1.40.0'; const CARD_VERSION = '1.40.1';
const LS_KEY = 'houseplan_card_layout_v1'; const LS_KEY = 'houseplan_card_layout_v1';
const LS_CFG = 'houseplan_card_cfg_v1'; // cache of the server config+layout for instant rendering const LS_CFG = 'houseplan_card_cfg_v1'; // cache of the server config+layout for instant rendering
const LS_ZOOM = 'houseplan_card_zoom_v1'; const LS_ZOOM = 'houseplan_card_zoom_v1';
@@ -3223,15 +3223,15 @@ class HouseplanCard extends LitElement {
const shape = holes.length && myPoly const shape = holes.length && myPoly
? svg`<path class="${cls}" style="${style}" fill-rule="evenodd" ? svg`<path class="${cls}" style="${style}" fill-rule="evenodd"
d="${[myPoly, ...holes].map(pathD).join(' ')}" d="${[myPoly, ...holes].map(pathD).join(' ')}"
@click=${() => this._clickRoom(r)} @mousemove=${tip} @mousemove=${tip}
@mouseleave=${() => (this._tip = null)}></path>` @mouseleave=${() => (this._tip = null)}></path>`
: r.poly : r.poly
? svg`<polygon class="${cls}" style="${style}" points="${r.poly.map((p) => p.join(',')).join(' ')}" ? svg`<polygon class="${cls}" style="${style}" points="${r.poly.map((p) => p.join(',')).join(' ')}"
@click=${() => this._clickRoom(r)} @mousemove=${tip} @mousemove=${tip}
@mouseleave=${() => (this._tip = null)}></polygon>` @mouseleave=${() => (this._tip = null)}></polygon>`
: svg`<rect class="${cls}" style="${style}" : svg`<rect class="${cls}" style="${style}"
x="${r.x}" y="${r.y}" width="${r.w}" height="${r.h}" rx="${Math.min(r.w!, r.h!) * 0.03}" x="${r.x}" y="${r.y}" width="${r.w}" height="${r.h}" rx="${Math.min(r.w!, r.h!) * 0.03}"
@click=${() => this._clickRoom(r)} @mousemove=${tip} @mousemove=${tip}
@mouseleave=${() => (this._tip = null)}></rect>`; @mouseleave=${() => (this._tip = null)}></rect>`;
const trimmed = openCuts.length && myPoly const trimmed = openCuts.length && myPoly
? outlineWithout(myPoly, openCuts, this._gridPitch * 0.02) ? outlineWithout(myPoly, openCuts, this._gridPitch * 0.02)
@@ -3510,7 +3510,12 @@ class HouseplanCard extends LitElement {
@pointermove=${(e: PointerEvent) => this._labelMove(e, r, space.id)} @pointermove=${(e: PointerEvent) => this._labelMove(e, r, space.id)}
@pointerup=${() => this._labelUp(r)} @pointerup=${() => this._labelUp(r)}
@pointercancel=${() => this._labelUp(r)} @pointercancel=${() => this._labelUp(r)}
><span class="rlname">${r.name}</span> ><span class="rlname">${r.name}${!this._markup && r.area
? html`<ha-icon class="rlgo" icon="mdi:open-in-new"
title=${this._t('room.open_area')}
@click=${(e: Event) => { e.stopPropagation(); this._clickRoom(r); }}
@pointerdown=${(e: Event) => e.stopPropagation()}></ha-icon>`
: nothing}</span>
${rows.length ? html`<span class="rlmetrics">${rows}</span>` : nothing} ${rows.length ? html`<span class="rlmetrics">${rows}</span>` : nothing}
${this._mode === 'plan' ${this._mode === 'plan'
? ['tl', 'tr', 'bl', 'br'].map( ? ['tl', 'tr', 'bl', 'br'].map(
+2 -1
View File
@@ -300,5 +300,6 @@
"marker.from_ha_option": "Pick from the HA list", "marker.from_ha_option": "Pick from the HA list",
"marker.show_entities": "Show entities", "marker.show_entities": "Show entities",
"marker.show_entities_tip": "Adds not only devices to the list, but all their entities too", "marker.show_entities_tip": "Adds not only devices to the list, but all their entities too",
"marker.pick_ph": "Choose a device…" "marker.pick_ph": "Choose a device…",
"room.open_area": "Open the HA area"
} }
+2 -1
View File
@@ -300,5 +300,6 @@
"marker.from_ha_option": "Выбрать из списка HA", "marker.from_ha_option": "Выбрать из списка HA",
"marker.show_entities": "Отображать сущности", "marker.show_entities": "Отображать сущности",
"marker.show_entities_tip": "Добавляет в список не только устройства, но и все их сущности", "marker.show_entities_tip": "Добавляет в список не только устройства, но и все их сущности",
"marker.pick_ph": "Выберите устройство…" "marker.pick_ph": "Выберите устройство…",
"room.open_area": "Открыть зону в HA"
} }
+12 -1
View File
@@ -189,7 +189,7 @@ export const cardStyles = css`
} }
.room { .room {
transition: 0.12s; transition: 0.12s;
cursor: pointer; cursor: default; /* v1.40.1: rooms are not clickable — the label's link icon is */
} }
.room.overlay { .room.overlay {
fill: transparent; fill: transparent;
@@ -377,6 +377,17 @@ export const cardStyles = css`
gap: 0.15em; gap: 0.15em;
text-align: center; text-align: center;
} }
.rlname { display: inline-flex; align-items: center; gap: 0.25em; }
.rlgo {
--mdc-icon-size: 0.85em;
display: inline-flex;
opacity: 0.55;
}
.stage.mode-view .rlgo {
pointer-events: auto;
cursor: pointer;
}
.stage.mode-view .rlgo:hover { opacity: 1; }
.roomlabel .rlmetrics { .roomlabel .rlmetrics {
display: flex; display: flex;
align-items: center; align-items: center;