Files
houseplan-card/demo/smoke_openwall.mjs
T
Matysh 9c92bcdf2f ux v1.38.3: true dashed open boundaries in the Plan editor too
- room outline trimming applies in markup (blue .room-outline.outlined);
  merge/split-picked rooms keep the full amber stroke
- smoke_openwall extended (14 checks); TESTING/CHANGELOG same-commit
2026-07-23 17:17:01 +03:00

67 lines
3.9 KiB
JavaScript

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._setMode('plan'); c._tool = 'openwall'; await c.updateComplete;
// r1|r2 делят стену x=0.55 → клик по ней открывает границу
const H = 1000 / (c._curSpaceCfg.aspect || 1);
c._openWallClick([550, 0.25 * H]);
await c.updateComplete;
const r1 = c._curSpaceCfg.rooms.find((r) => r.id === 'r1');
const r2 = c._curSpaceCfg.rooms.find((r) => r.id === 'r2');
out.linked = (r1.open_to || []).includes('r2') && (r2.open_to || []).includes('r1');
// пунктир отрисован
out.dashes = sr().querySelectorAll('.openwall').length > 0;
out.hotClass = !!sr().querySelector('.openwalls.hot');
// в Просмотре: сплошной штрих комнаты снят, контур без выреза + пунктир ПОВЕРХ glow
c._setMode('view'); await c.updateComplete;
out.noedge = sr().querySelectorAll('.room.noedge').length >= 2;
out.trimmedOutline = sr().querySelectorAll('.room-outline').length >= 2;
const svgEl = sr().querySelector('svg');
const order = [...svgEl.children].map((el) => el.classList?.[0] || el.tagName);
const gi = order.indexOf('glowlayer');
const oi = order.indexOf('openwalls');
out.dashAboveGlow = gi === -1 || oi > gi;
// в редакторе плана: пунктир виден, штрих комнат вырезан, контур синий
c._setMode('plan'); c._tool = 'draw'; await c.updateComplete;
out.planDashes = sr().querySelectorAll('.openwall').length > 0;
out.planNoedge = sr().querySelectorAll('.room.noedge').length >= 2;
out.planBlueOutline = sr().querySelectorAll('.room-outline.outlined').length >= 2;
c._tool = 'openwall'; await c.updateComplete;
// повторный клик закрывает
c._openWallClick([550, 0.25 * H]); await c.updateComplete;
out.toggledOff = !(c._curSpaceCfg.rooms.find((r) => r.id === 'r1').open_to || []).includes('r2');
out.dashesGone = sr().querySelectorAll('.openwall').length === 0;
// клик мимо стен — тост, без изменений
c._openWallClick([100, 100]);
out.missToast = !!c._toast;
// снова открыть для glow-теста
c._openWallClick([550, 0.25 * H]); await c.updateComplete;
// glow: свет из r1 заливает и r2 (clip содержит оба полигона)
c._setMode('view'); await c.updateComplete;
c._serverCfg = { ...c._serverCfg, spaces: c._serverCfg.spaces.map((s) => s.id !== c._space ? s : ({
...s, settings: { ...(s.settings || {}), fill_mode: 'glow' } })) };
const litLight = c._devices.find((d) => d.space === c._space && d.entities.some((e) => e.startsWith('light.') && c.hass.states[e]?.state === 'on'));
const c1 = c._roomCenter(c._spaceModel().rooms.find((r) => r.id === 'r1'));
const aspect = c._curSpaceCfg.aspect || 1;
c._layout = { ...c._layout, [litLight.id]: { s: c._space, x: c1[0] / 1000, y: c1[1] / (1000 / aspect) } };
c.requestUpdate(); await c.updateComplete;
const clip = sr().querySelector('defs clipPath[id^="hp-glowclip"]');
out.zoneClip = clip ? clip.querySelectorAll('path').length >= 2 : false;
// транзитивность: r2↔r3 тоже открыть → clip получит 3 полигона
const rr2 = c._curSpaceCfg.rooms.find((r) => r.id === 'r2');
const rr3 = c._curSpaceCfg.rooms.find((r) => r.id === 'r3');
if (rr3) {
rr2.open_to = [...(rr2.open_to || []), 'r3'];
rr3.open_to = [...(rr3.open_to || []), 'r2'];
c._regSignature = ''; c.requestUpdate(); await c.updateComplete;
const clip2 = sr().querySelector('defs clipPath[id^="hp-glowclip"]');
out.transitive = clip2 ? clip2.querySelectorAll('path').length >= 3 : false;
} else out.transitive = 'no r3';
return out;
});
console.log(JSON.stringify(res, null, 1));
await browser.close();