mirror of
https://github.com/Matysh/houseplan-card
synced 2026-07-31 08:28:31 +00:00
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
This commit is contained in:
@@ -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.38.2"
|
VERSION = "1.38.3"
|
||||||
|
|
||||||
DEFAULT_CONFIG: dict = {
|
DEFAULT_CONFIG: dict = {
|
||||||
"spaces": [],
|
"spaces": [],
|
||||||
|
|||||||
@@ -598,6 +598,11 @@ const t=globalThis,e=t.ShadowRoot&&(void 0===t.ShadyCSS||t.ShadyCSS.nativeShadow
|
|||||||
stroke-width: 2.5;
|
stroke-width: 2.5;
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
}
|
}
|
||||||
|
/* Plan editor: trimmed outlines use the markup blue */
|
||||||
|
.room-outline.outlined {
|
||||||
|
stroke: rgba(62, 166, 255, 0.55);
|
||||||
|
stroke-opacity: 1;
|
||||||
|
}
|
||||||
.openwalls.hot .openwall {
|
.openwalls.hot .openwall {
|
||||||
stroke: #ffc14d;
|
stroke: #ffc14d;
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
@@ -1693,16 +1698,17 @@ const t=globalThis,e=t.ShadowRoot&&(void 0===t.ShadyCSS||t.ShadyCSS.nativeShadow
|
|||||||
${this._editing&&!this._markup?j`<rect x="${i[0]}" y="${i[1]}" width="${i[2]}" height="${i[3]}" fill="url(#hp-grid)" pointer-events="none"></rect>`:G}
|
${this._editing&&!this._markup?j`<rect x="${i[0]}" y="${i[1]}" width="${i[2]}" height="${i[3]}" fill="url(#hp-grid)" pointer-events="none"></rect>`:G}
|
||||||
${e.bg?j`<image href="${e.bg.href}" x="${e.bg.x}" y="${e.bg.y}" width="${e.bg.w}" height="${e.bg.h}" preserveAspectRatio="none" />`:G}
|
${e.bg?j`<image href="${e.bg.href}" x="${e.bg.x}" y="${e.bg.y}" width="${e.bg.w}" height="${e.bg.h}" preserveAspectRatio="none" />`:G}
|
||||||
${this._renderDecorLayer()}
|
${this._renderDecorLayer()}
|
||||||
${e.rooms.filter(t=>t.area||this._markup||o.showBorders).map(t=>{let i="room "+(e.bg?"overlay":"yard")+(this._markup?" outlined":"");!this._markup||t.id!==this._mergeSel&&t.id!==this._splitSel?.roomId||(i+=" picked");let s="";if(!this._markup&&(o.showBorders||"none"!==o.fill)){i+=" styled";const e=[];e.push(`--room-stroke:${o.color}`,`--room-stroke-op:${o.showBorders?o.opacity:0}`);const n="glow"===o.fill?this._fillColors.glow_base:t.area?Qe(o.fill,"lqi"===o.fill?this._roomLqi(t.area):null,"light"===o.fill?vi(this.hass,this._devices,t.area):"none","temp"===o.fill?yi(this.hass,this._devices,t.area):null,o.tempMin,o.tempMax,this._fillColors):null;n?(i+=" filled",e.push(`--room-fill:${n.c}`,`--room-fill-op:${n.a.toFixed(3)}`)):e.push("--room-fill:transparent","--room-fill-op:0"),s=e.join(";")}const r=e=>this._showTip(e,t.name,this._t("tip.room"),n?this._roomLqi(t.area):null,t.area?yi(this.hass,this._devices,t.area):null),a=!e.bg&&!o.showNames&&!this._markup,l=this._roomCenter(t),c=!this._markup&&t.id?this._openPairs().filter(e=>e.a.id===t.id||e.b.id===t.id).flatMap(t=>t.segs):[];c.length&&(i+=" noedge");const h=we(t),p=h?function(t,e,i=1e-6){const s=e.filter(e=>Re(t,e,i));return s.filter(t=>!s.some(e=>e!==t&&Re(e,t,i)))}(h,e.rooms.filter(e=>e!==t).map(t=>we(t)).filter(Boolean)):[],d=p.length&&h?j`<path class="${i}" style="${s}" fill-rule="evenodd"
|
${e.rooms.filter(t=>t.area||this._markup||o.showBorders).map(t=>{let i="room "+(e.bg?"overlay":"yard")+(this._markup?" outlined":"");!this._markup||t.id!==this._mergeSel&&t.id!==this._splitSel?.roomId||(i+=" picked");let s="";if(!this._markup&&(o.showBorders||"none"!==o.fill)){i+=" styled";const e=[];e.push(`--room-stroke:${o.color}`,`--room-stroke-op:${o.showBorders?o.opacity:0}`);const n="glow"===o.fill?this._fillColors.glow_base:t.area?Qe(o.fill,"lqi"===o.fill?this._roomLqi(t.area):null,"light"===o.fill?vi(this.hass,this._devices,t.area):"none","temp"===o.fill?yi(this.hass,this._devices,t.area):null,o.tempMin,o.tempMax,this._fillColors):null;n?(i+=" filled",e.push(`--room-fill:${n.c}`,`--room-fill-op:${n.a.toFixed(3)}`)):e.push("--room-fill:transparent","--room-fill-op:0"),s=e.join(";")}const r=e=>this._showTip(e,t.name,this._t("tip.room"),n?this._roomLqi(t.area):null,t.area?yi(this.hass,this._devices,t.area):null),a=!e.bg&&!o.showNames&&!this._markup,l=this._roomCenter(t),c=this._markup&&(t.id===this._mergeSel||t.id===this._splitSel?.roomId),h=t.id&&!c?this._openPairs().filter(e=>e.a.id===t.id||e.b.id===t.id).flatMap(t=>t.segs):[];h.length&&(i+=" noedge");const p=we(t),d=p?function(t,e,i=1e-6){const s=e.filter(e=>Re(t,e,i));return s.filter(t=>!s.some(e=>e!==t&&Re(e,t,i)))}(p,e.rooms.filter(e=>e!==t).map(t=>we(t)).filter(Boolean)):[],u=d.length&&p?j`<path class="${i}" style="${s}" fill-rule="evenodd"
|
||||||
d="${[h,...p].map(t=>"M "+t.map(t=>t[0]+" "+t[1]).join(" L ")+" Z").join(" ")}"
|
d="${[p,...d].map(t=>"M "+t.map(t=>t[0]+" "+t[1]).join(" L ")+" Z").join(" ")}"
|
||||||
@click=${()=>this._clickRoom(t)} @mousemove=${r}
|
@click=${()=>this._clickRoom(t)} @mousemove=${r}
|
||||||
@mouseleave=${()=>this._tip=null}></path>`:t.poly?j`<polygon class="${i}" style="${s}" points="${t.poly.map(t=>t.join(",")).join(" ")}"
|
@mouseleave=${()=>this._tip=null}></path>`:t.poly?j`<polygon class="${i}" style="${s}" points="${t.poly.map(t=>t.join(",")).join(" ")}"
|
||||||
@click=${()=>this._clickRoom(t)} @mousemove=${r}
|
@click=${()=>this._clickRoom(t)} @mousemove=${r}
|
||||||
@mouseleave=${()=>this._tip=null}></polygon>`:j`<rect class="${i}" style="${s}"
|
@mouseleave=${()=>this._tip=null}></polygon>`:j`<rect class="${i}" style="${s}"
|
||||||
x="${t.x}" y="${t.y}" width="${t.w}" height="${t.h}" rx="${.03*Math.min(t.w,t.h)}"
|
x="${t.x}" y="${t.y}" width="${t.w}" height="${t.h}" rx="${.03*Math.min(t.w,t.h)}"
|
||||||
@click=${()=>this._clickRoom(t)} @mousemove=${r}
|
@click=${()=>this._clickRoom(t)} @mousemove=${r}
|
||||||
@mouseleave=${()=>this._tip=null}></rect>`,u=c.length&&h?function(t,e,i=1e-6){const s=[];for(let o=0;o<t.length;o++){const n=t[o],r=t[(o+1)%t.length],a=r[0]-n[0],l=r[1]-n[1],c=Math.hypot(a,l);if(c<i)continue;const h=a/c,p=l/c,d=[];for(const t of e){const e=Math.abs((t[0]-n[0])*p-(t[1]-n[1])*h),s=Math.abs((t[2]-n[0])*p-(t[3]-n[1])*h),o=Math.max(i,1e-6*c);if(e>o||s>o)continue;const r=(t[0]-n[0])*h+(t[1]-n[1])*p,a=(t[2]-n[0])*h+(t[3]-n[1])*p,l=Math.max(0,Math.min(r,a)),u=Math.min(c,Math.max(r,a));u-l>i&&d.push([l,u])}if(!d.length){s.push([n[0],n[1],r[0],r[1]]);continue}d.sort((t,e)=>t[0]-e[0]);let u=0;for(const[t,e]of d)t-u>i&&s.push([n[0]+h*u,n[1]+p*u,n[0]+h*t,n[1]+p*t]),u=Math.max(u,e);c-u>i&&s.push([n[0]+h*u,n[1]+p*u,r[0],r[1]])}return s}(h,c,.02*this._gridPitch):null,_=u?j`<path class="room-outline" d="${u.map(t=>`M ${t[0]} ${t[1]} L ${t[2]} ${t[3]}`).join(" ")}"
|
@mouseleave=${()=>this._tip=null}></rect>`,_=h.length&&p?function(t,e,i=1e-6){const s=[];for(let o=0;o<t.length;o++){const n=t[o],r=t[(o+1)%t.length],a=r[0]-n[0],l=r[1]-n[1],c=Math.hypot(a,l);if(c<i)continue;const h=a/c,p=l/c,d=[];for(const t of e){const e=Math.abs((t[0]-n[0])*p-(t[1]-n[1])*h),s=Math.abs((t[2]-n[0])*p-(t[3]-n[1])*h),o=Math.max(i,1e-6*c);if(e>o||s>o)continue;const r=(t[0]-n[0])*h+(t[1]-n[1])*p,a=(t[2]-n[0])*h+(t[3]-n[1])*p,l=Math.max(0,Math.min(r,a)),u=Math.min(c,Math.max(r,a));u-l>i&&d.push([l,u])}if(!d.length){s.push([n[0],n[1],r[0],r[1]]);continue}d.sort((t,e)=>t[0]-e[0]);let u=0;for(const[t,e]of d)t-u>i&&s.push([n[0]+h*u,n[1]+p*u,n[0]+h*t,n[1]+p*t]),u=Math.max(u,e);c-u>i&&s.push([n[0]+h*u,n[1]+p*u,r[0],r[1]])}return s}(p,h,.02*this._gridPitch):null,g=_?j`<path class="room-outline ${this._markup?"outlined":""}"
|
||||||
style="stroke:${o.color};stroke-opacity:${o.showBorders&&!this._markup?o.opacity:0}"></path>`:G;return j`${d}${_}${a?j`<text class="rlabel" x="${l[0]}" y="${l[1]}">${t.name}</text>`:G}`})}
|
d="${_.map(t=>`M ${t[0]} ${t[1]} L ${t[2]} ${t[3]}`).join(" ")}"
|
||||||
|
style=${this._markup?G:`stroke:${o.color};stroke-opacity:${o.showBorders?o.opacity:0}`}></path>`:G;return j`${u}${g}${a?j`<text class="rlabel" x="${l[0]}" y="${l[1]}">${t.name}</text>`:G}`})}
|
||||||
${"glow"!==o.fill||this._markup?G:this._renderGlowLayer(e)}
|
${"glow"!==o.fill||this._markup?G:this._renderGlowLayer(e)}
|
||||||
${this._renderOpenWalls(o)}
|
${this._renderOpenWalls(o)}
|
||||||
${this._markup?this._renderMarkupLayer(i):G}
|
${this._markup?this._renderMarkupLayer(i):G}
|
||||||
@@ -2300,4 +2306,4 @@ const t=globalThis,e=t.ShadowRoot&&(void 0===t.ShadyCSS||t.ShadyCSS.nativeShadow
|
|||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>`}}Ki.properties={hass:{attribute:!1},_config:{state:!0},_space:{state:!0},_layout:{state:!0},_devices:{state:!0},_tip:{state:!0},_selId:{state:!0},_toast:{state:!0},_serverCfg:{state:!0},_mode:{state:!0},_tool:{state:!0},_path:{state:!0},_cursorPt:{state:!0},_mergeSel:{state:!0},_openingDialog:{state:!0},_openingInfo:{state:!0},_mergeDialog:{state:!0},_splitSel:{state:!0},_decorTool:{state:!0},_decorStyle:{state:!0},_decorDraft:{state:!0},_decorSel:{state:!0},_decorTextDialog:{state:!0},_areaSel:{state:!0},_nameSel:{state:!0},_roomDialog:{state:!0},_spaceDialog:{state:!0},_infoCard:{state:!0},_rulesDialog:{state:!0},_settingsDialog:{state:!0},_importDialog:{state:!0},_markerDialog:{state:!0},_zoom:{state:!0},_view:{state:!0}},Ki.styles=Mi,customElements.get("houseplan-card")||customElements.define("houseplan-card",Ki),window.customCards=window.customCards||[],window.customCards.find(t=>"houseplan-card"===t.type)||window.customCards.push({type:"houseplan-card",name:"House Plan Card",description:"Interactive house plan: spaces, rooms and devices with live states and drag layout."}),console.info("%c HOUSEPLAN-CARD %c v1.38.2 ","background:#3ea6ff;color:#04121f;font-weight:700","");
|
</div>`}}Ki.properties={hass:{attribute:!1},_config:{state:!0},_space:{state:!0},_layout:{state:!0},_devices:{state:!0},_tip:{state:!0},_selId:{state:!0},_toast:{state:!0},_serverCfg:{state:!0},_mode:{state:!0},_tool:{state:!0},_path:{state:!0},_cursorPt:{state:!0},_mergeSel:{state:!0},_openingDialog:{state:!0},_openingInfo:{state:!0},_mergeDialog:{state:!0},_splitSel:{state:!0},_decorTool:{state:!0},_decorStyle:{state:!0},_decorDraft:{state:!0},_decorSel:{state:!0},_decorTextDialog:{state:!0},_areaSel:{state:!0},_nameSel:{state:!0},_roomDialog:{state:!0},_spaceDialog:{state:!0},_infoCard:{state:!0},_rulesDialog:{state:!0},_settingsDialog:{state:!0},_importDialog:{state:!0},_markerDialog:{state:!0},_zoom:{state:!0},_view:{state:!0}},Ki.styles=Mi,customElements.get("houseplan-card")||customElements.define("houseplan-card",Ki),window.customCards=window.customCards||[],window.customCards.find(t=>"houseplan-card"===t.type)||window.customCards.push({type:"houseplan-card",name:"House Plan Card",description:"Interactive house plan: spaces, rooms and devices with live states and drag layout."}),console.info("%c HOUSEPLAN-CARD %c v1.38.3 ","background:#3ea6ff;color:#04121f;font-weight:700","");
|
||||||
|
|||||||
@@ -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.38.2"
|
"version": "1.38.3"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,7 +24,12 @@ const res = await page.evaluate(async () => {
|
|||||||
const gi = order.indexOf('glowlayer');
|
const gi = order.indexOf('glowlayer');
|
||||||
const oi = order.indexOf('openwalls');
|
const oi = order.indexOf('openwalls');
|
||||||
out.dashAboveGlow = gi === -1 || oi > gi;
|
out.dashAboveGlow = gi === -1 || oi > gi;
|
||||||
c._setMode('plan'); c._tool = 'openwall'; await c.updateComplete;
|
// в редакторе плана: пунктир виден, штрих комнат вырезан, контур синий
|
||||||
|
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;
|
c._openWallClick([550, 0.25 * H]); await c.updateComplete;
|
||||||
out.toggledOff = !(c._curSpaceCfg.rooms.find((r) => r.id === 'r1').open_to || []).includes('r2');
|
out.toggledOff = !(c._curSpaceCfg.rooms.find((r) => r.id === 'r1').open_to || []).includes('r2');
|
||||||
|
|||||||
@@ -598,6 +598,11 @@ const t=globalThis,e=t.ShadowRoot&&(void 0===t.ShadyCSS||t.ShadyCSS.nativeShadow
|
|||||||
stroke-width: 2.5;
|
stroke-width: 2.5;
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
}
|
}
|
||||||
|
/* Plan editor: trimmed outlines use the markup blue */
|
||||||
|
.room-outline.outlined {
|
||||||
|
stroke: rgba(62, 166, 255, 0.55);
|
||||||
|
stroke-opacity: 1;
|
||||||
|
}
|
||||||
.openwalls.hot .openwall {
|
.openwalls.hot .openwall {
|
||||||
stroke: #ffc14d;
|
stroke: #ffc14d;
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
@@ -1693,16 +1698,17 @@ const t=globalThis,e=t.ShadowRoot&&(void 0===t.ShadyCSS||t.ShadyCSS.nativeShadow
|
|||||||
${this._editing&&!this._markup?j`<rect x="${i[0]}" y="${i[1]}" width="${i[2]}" height="${i[3]}" fill="url(#hp-grid)" pointer-events="none"></rect>`:G}
|
${this._editing&&!this._markup?j`<rect x="${i[0]}" y="${i[1]}" width="${i[2]}" height="${i[3]}" fill="url(#hp-grid)" pointer-events="none"></rect>`:G}
|
||||||
${e.bg?j`<image href="${e.bg.href}" x="${e.bg.x}" y="${e.bg.y}" width="${e.bg.w}" height="${e.bg.h}" preserveAspectRatio="none" />`:G}
|
${e.bg?j`<image href="${e.bg.href}" x="${e.bg.x}" y="${e.bg.y}" width="${e.bg.w}" height="${e.bg.h}" preserveAspectRatio="none" />`:G}
|
||||||
${this._renderDecorLayer()}
|
${this._renderDecorLayer()}
|
||||||
${e.rooms.filter(t=>t.area||this._markup||o.showBorders).map(t=>{let i="room "+(e.bg?"overlay":"yard")+(this._markup?" outlined":"");!this._markup||t.id!==this._mergeSel&&t.id!==this._splitSel?.roomId||(i+=" picked");let s="";if(!this._markup&&(o.showBorders||"none"!==o.fill)){i+=" styled";const e=[];e.push(`--room-stroke:${o.color}`,`--room-stroke-op:${o.showBorders?o.opacity:0}`);const n="glow"===o.fill?this._fillColors.glow_base:t.area?Qe(o.fill,"lqi"===o.fill?this._roomLqi(t.area):null,"light"===o.fill?vi(this.hass,this._devices,t.area):"none","temp"===o.fill?yi(this.hass,this._devices,t.area):null,o.tempMin,o.tempMax,this._fillColors):null;n?(i+=" filled",e.push(`--room-fill:${n.c}`,`--room-fill-op:${n.a.toFixed(3)}`)):e.push("--room-fill:transparent","--room-fill-op:0"),s=e.join(";")}const r=e=>this._showTip(e,t.name,this._t("tip.room"),n?this._roomLqi(t.area):null,t.area?yi(this.hass,this._devices,t.area):null),a=!e.bg&&!o.showNames&&!this._markup,l=this._roomCenter(t),c=!this._markup&&t.id?this._openPairs().filter(e=>e.a.id===t.id||e.b.id===t.id).flatMap(t=>t.segs):[];c.length&&(i+=" noedge");const h=we(t),p=h?function(t,e,i=1e-6){const s=e.filter(e=>Re(t,e,i));return s.filter(t=>!s.some(e=>e!==t&&Re(e,t,i)))}(h,e.rooms.filter(e=>e!==t).map(t=>we(t)).filter(Boolean)):[],d=p.length&&h?j`<path class="${i}" style="${s}" fill-rule="evenodd"
|
${e.rooms.filter(t=>t.area||this._markup||o.showBorders).map(t=>{let i="room "+(e.bg?"overlay":"yard")+(this._markup?" outlined":"");!this._markup||t.id!==this._mergeSel&&t.id!==this._splitSel?.roomId||(i+=" picked");let s="";if(!this._markup&&(o.showBorders||"none"!==o.fill)){i+=" styled";const e=[];e.push(`--room-stroke:${o.color}`,`--room-stroke-op:${o.showBorders?o.opacity:0}`);const n="glow"===o.fill?this._fillColors.glow_base:t.area?Qe(o.fill,"lqi"===o.fill?this._roomLqi(t.area):null,"light"===o.fill?vi(this.hass,this._devices,t.area):"none","temp"===o.fill?yi(this.hass,this._devices,t.area):null,o.tempMin,o.tempMax,this._fillColors):null;n?(i+=" filled",e.push(`--room-fill:${n.c}`,`--room-fill-op:${n.a.toFixed(3)}`)):e.push("--room-fill:transparent","--room-fill-op:0"),s=e.join(";")}const r=e=>this._showTip(e,t.name,this._t("tip.room"),n?this._roomLqi(t.area):null,t.area?yi(this.hass,this._devices,t.area):null),a=!e.bg&&!o.showNames&&!this._markup,l=this._roomCenter(t),c=this._markup&&(t.id===this._mergeSel||t.id===this._splitSel?.roomId),h=t.id&&!c?this._openPairs().filter(e=>e.a.id===t.id||e.b.id===t.id).flatMap(t=>t.segs):[];h.length&&(i+=" noedge");const p=we(t),d=p?function(t,e,i=1e-6){const s=e.filter(e=>Re(t,e,i));return s.filter(t=>!s.some(e=>e!==t&&Re(e,t,i)))}(p,e.rooms.filter(e=>e!==t).map(t=>we(t)).filter(Boolean)):[],u=d.length&&p?j`<path class="${i}" style="${s}" fill-rule="evenodd"
|
||||||
d="${[h,...p].map(t=>"M "+t.map(t=>t[0]+" "+t[1]).join(" L ")+" Z").join(" ")}"
|
d="${[p,...d].map(t=>"M "+t.map(t=>t[0]+" "+t[1]).join(" L ")+" Z").join(" ")}"
|
||||||
@click=${()=>this._clickRoom(t)} @mousemove=${r}
|
@click=${()=>this._clickRoom(t)} @mousemove=${r}
|
||||||
@mouseleave=${()=>this._tip=null}></path>`:t.poly?j`<polygon class="${i}" style="${s}" points="${t.poly.map(t=>t.join(",")).join(" ")}"
|
@mouseleave=${()=>this._tip=null}></path>`:t.poly?j`<polygon class="${i}" style="${s}" points="${t.poly.map(t=>t.join(",")).join(" ")}"
|
||||||
@click=${()=>this._clickRoom(t)} @mousemove=${r}
|
@click=${()=>this._clickRoom(t)} @mousemove=${r}
|
||||||
@mouseleave=${()=>this._tip=null}></polygon>`:j`<rect class="${i}" style="${s}"
|
@mouseleave=${()=>this._tip=null}></polygon>`:j`<rect class="${i}" style="${s}"
|
||||||
x="${t.x}" y="${t.y}" width="${t.w}" height="${t.h}" rx="${.03*Math.min(t.w,t.h)}"
|
x="${t.x}" y="${t.y}" width="${t.w}" height="${t.h}" rx="${.03*Math.min(t.w,t.h)}"
|
||||||
@click=${()=>this._clickRoom(t)} @mousemove=${r}
|
@click=${()=>this._clickRoom(t)} @mousemove=${r}
|
||||||
@mouseleave=${()=>this._tip=null}></rect>`,u=c.length&&h?function(t,e,i=1e-6){const s=[];for(let o=0;o<t.length;o++){const n=t[o],r=t[(o+1)%t.length],a=r[0]-n[0],l=r[1]-n[1],c=Math.hypot(a,l);if(c<i)continue;const h=a/c,p=l/c,d=[];for(const t of e){const e=Math.abs((t[0]-n[0])*p-(t[1]-n[1])*h),s=Math.abs((t[2]-n[0])*p-(t[3]-n[1])*h),o=Math.max(i,1e-6*c);if(e>o||s>o)continue;const r=(t[0]-n[0])*h+(t[1]-n[1])*p,a=(t[2]-n[0])*h+(t[3]-n[1])*p,l=Math.max(0,Math.min(r,a)),u=Math.min(c,Math.max(r,a));u-l>i&&d.push([l,u])}if(!d.length){s.push([n[0],n[1],r[0],r[1]]);continue}d.sort((t,e)=>t[0]-e[0]);let u=0;for(const[t,e]of d)t-u>i&&s.push([n[0]+h*u,n[1]+p*u,n[0]+h*t,n[1]+p*t]),u=Math.max(u,e);c-u>i&&s.push([n[0]+h*u,n[1]+p*u,r[0],r[1]])}return s}(h,c,.02*this._gridPitch):null,_=u?j`<path class="room-outline" d="${u.map(t=>`M ${t[0]} ${t[1]} L ${t[2]} ${t[3]}`).join(" ")}"
|
@mouseleave=${()=>this._tip=null}></rect>`,_=h.length&&p?function(t,e,i=1e-6){const s=[];for(let o=0;o<t.length;o++){const n=t[o],r=t[(o+1)%t.length],a=r[0]-n[0],l=r[1]-n[1],c=Math.hypot(a,l);if(c<i)continue;const h=a/c,p=l/c,d=[];for(const t of e){const e=Math.abs((t[0]-n[0])*p-(t[1]-n[1])*h),s=Math.abs((t[2]-n[0])*p-(t[3]-n[1])*h),o=Math.max(i,1e-6*c);if(e>o||s>o)continue;const r=(t[0]-n[0])*h+(t[1]-n[1])*p,a=(t[2]-n[0])*h+(t[3]-n[1])*p,l=Math.max(0,Math.min(r,a)),u=Math.min(c,Math.max(r,a));u-l>i&&d.push([l,u])}if(!d.length){s.push([n[0],n[1],r[0],r[1]]);continue}d.sort((t,e)=>t[0]-e[0]);let u=0;for(const[t,e]of d)t-u>i&&s.push([n[0]+h*u,n[1]+p*u,n[0]+h*t,n[1]+p*t]),u=Math.max(u,e);c-u>i&&s.push([n[0]+h*u,n[1]+p*u,r[0],r[1]])}return s}(p,h,.02*this._gridPitch):null,g=_?j`<path class="room-outline ${this._markup?"outlined":""}"
|
||||||
style="stroke:${o.color};stroke-opacity:${o.showBorders&&!this._markup?o.opacity:0}"></path>`:G;return j`${d}${_}${a?j`<text class="rlabel" x="${l[0]}" y="${l[1]}">${t.name}</text>`:G}`})}
|
d="${_.map(t=>`M ${t[0]} ${t[1]} L ${t[2]} ${t[3]}`).join(" ")}"
|
||||||
|
style=${this._markup?G:`stroke:${o.color};stroke-opacity:${o.showBorders?o.opacity:0}`}></path>`:G;return j`${u}${g}${a?j`<text class="rlabel" x="${l[0]}" y="${l[1]}">${t.name}</text>`:G}`})}
|
||||||
${"glow"!==o.fill||this._markup?G:this._renderGlowLayer(e)}
|
${"glow"!==o.fill||this._markup?G:this._renderGlowLayer(e)}
|
||||||
${this._renderOpenWalls(o)}
|
${this._renderOpenWalls(o)}
|
||||||
${this._markup?this._renderMarkupLayer(i):G}
|
${this._markup?this._renderMarkupLayer(i):G}
|
||||||
@@ -2300,4 +2306,4 @@ const t=globalThis,e=t.ShadowRoot&&(void 0===t.ShadyCSS||t.ShadyCSS.nativeShadow
|
|||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>`}}Ki.properties={hass:{attribute:!1},_config:{state:!0},_space:{state:!0},_layout:{state:!0},_devices:{state:!0},_tip:{state:!0},_selId:{state:!0},_toast:{state:!0},_serverCfg:{state:!0},_mode:{state:!0},_tool:{state:!0},_path:{state:!0},_cursorPt:{state:!0},_mergeSel:{state:!0},_openingDialog:{state:!0},_openingInfo:{state:!0},_mergeDialog:{state:!0},_splitSel:{state:!0},_decorTool:{state:!0},_decorStyle:{state:!0},_decorDraft:{state:!0},_decorSel:{state:!0},_decorTextDialog:{state:!0},_areaSel:{state:!0},_nameSel:{state:!0},_roomDialog:{state:!0},_spaceDialog:{state:!0},_infoCard:{state:!0},_rulesDialog:{state:!0},_settingsDialog:{state:!0},_importDialog:{state:!0},_markerDialog:{state:!0},_zoom:{state:!0},_view:{state:!0}},Ki.styles=Mi,customElements.get("houseplan-card")||customElements.define("houseplan-card",Ki),window.customCards=window.customCards||[],window.customCards.find(t=>"houseplan-card"===t.type)||window.customCards.push({type:"houseplan-card",name:"House Plan Card",description:"Interactive house plan: spaces, rooms and devices with live states and drag layout."}),console.info("%c HOUSEPLAN-CARD %c v1.38.2 ","background:#3ea6ff;color:#04121f;font-weight:700","");
|
</div>`}}Ki.properties={hass:{attribute:!1},_config:{state:!0},_space:{state:!0},_layout:{state:!0},_devices:{state:!0},_tip:{state:!0},_selId:{state:!0},_toast:{state:!0},_serverCfg:{state:!0},_mode:{state:!0},_tool:{state:!0},_path:{state:!0},_cursorPt:{state:!0},_mergeSel:{state:!0},_openingDialog:{state:!0},_openingInfo:{state:!0},_mergeDialog:{state:!0},_splitSel:{state:!0},_decorTool:{state:!0},_decorStyle:{state:!0},_decorDraft:{state:!0},_decorSel:{state:!0},_decorTextDialog:{state:!0},_areaSel:{state:!0},_nameSel:{state:!0},_roomDialog:{state:!0},_spaceDialog:{state:!0},_infoCard:{state:!0},_rulesDialog:{state:!0},_settingsDialog:{state:!0},_importDialog:{state:!0},_markerDialog:{state:!0},_zoom:{state:!0},_view:{state:!0}},Ki.styles=Mi,customElements.get("houseplan-card")||customElements.define("houseplan-card",Ki),window.customCards=window.customCards||[],window.customCards.find(t=>"houseplan-card"===t.type)||window.customCards.push({type:"houseplan-card",name:"House Plan Card",description:"Interactive house plan: spaces, rooms and devices with live states and drag layout."}),console.info("%c HOUSEPLAN-CARD %c v1.38.3 ","background:#3ea6ff;color:#04121f;font-weight:700","");
|
||||||
|
|||||||
Vendored
+11
-5
@@ -598,6 +598,11 @@ const t=globalThis,e=t.ShadowRoot&&(void 0===t.ShadyCSS||t.ShadyCSS.nativeShadow
|
|||||||
stroke-width: 2.5;
|
stroke-width: 2.5;
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
}
|
}
|
||||||
|
/* Plan editor: trimmed outlines use the markup blue */
|
||||||
|
.room-outline.outlined {
|
||||||
|
stroke: rgba(62, 166, 255, 0.55);
|
||||||
|
stroke-opacity: 1;
|
||||||
|
}
|
||||||
.openwalls.hot .openwall {
|
.openwalls.hot .openwall {
|
||||||
stroke: #ffc14d;
|
stroke: #ffc14d;
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
@@ -1693,16 +1698,17 @@ const t=globalThis,e=t.ShadowRoot&&(void 0===t.ShadyCSS||t.ShadyCSS.nativeShadow
|
|||||||
${this._editing&&!this._markup?j`<rect x="${i[0]}" y="${i[1]}" width="${i[2]}" height="${i[3]}" fill="url(#hp-grid)" pointer-events="none"></rect>`:G}
|
${this._editing&&!this._markup?j`<rect x="${i[0]}" y="${i[1]}" width="${i[2]}" height="${i[3]}" fill="url(#hp-grid)" pointer-events="none"></rect>`:G}
|
||||||
${e.bg?j`<image href="${e.bg.href}" x="${e.bg.x}" y="${e.bg.y}" width="${e.bg.w}" height="${e.bg.h}" preserveAspectRatio="none" />`:G}
|
${e.bg?j`<image href="${e.bg.href}" x="${e.bg.x}" y="${e.bg.y}" width="${e.bg.w}" height="${e.bg.h}" preserveAspectRatio="none" />`:G}
|
||||||
${this._renderDecorLayer()}
|
${this._renderDecorLayer()}
|
||||||
${e.rooms.filter(t=>t.area||this._markup||o.showBorders).map(t=>{let i="room "+(e.bg?"overlay":"yard")+(this._markup?" outlined":"");!this._markup||t.id!==this._mergeSel&&t.id!==this._splitSel?.roomId||(i+=" picked");let s="";if(!this._markup&&(o.showBorders||"none"!==o.fill)){i+=" styled";const e=[];e.push(`--room-stroke:${o.color}`,`--room-stroke-op:${o.showBorders?o.opacity:0}`);const n="glow"===o.fill?this._fillColors.glow_base:t.area?Qe(o.fill,"lqi"===o.fill?this._roomLqi(t.area):null,"light"===o.fill?vi(this.hass,this._devices,t.area):"none","temp"===o.fill?yi(this.hass,this._devices,t.area):null,o.tempMin,o.tempMax,this._fillColors):null;n?(i+=" filled",e.push(`--room-fill:${n.c}`,`--room-fill-op:${n.a.toFixed(3)}`)):e.push("--room-fill:transparent","--room-fill-op:0"),s=e.join(";")}const r=e=>this._showTip(e,t.name,this._t("tip.room"),n?this._roomLqi(t.area):null,t.area?yi(this.hass,this._devices,t.area):null),a=!e.bg&&!o.showNames&&!this._markup,l=this._roomCenter(t),c=!this._markup&&t.id?this._openPairs().filter(e=>e.a.id===t.id||e.b.id===t.id).flatMap(t=>t.segs):[];c.length&&(i+=" noedge");const h=we(t),p=h?function(t,e,i=1e-6){const s=e.filter(e=>Re(t,e,i));return s.filter(t=>!s.some(e=>e!==t&&Re(e,t,i)))}(h,e.rooms.filter(e=>e!==t).map(t=>we(t)).filter(Boolean)):[],d=p.length&&h?j`<path class="${i}" style="${s}" fill-rule="evenodd"
|
${e.rooms.filter(t=>t.area||this._markup||o.showBorders).map(t=>{let i="room "+(e.bg?"overlay":"yard")+(this._markup?" outlined":"");!this._markup||t.id!==this._mergeSel&&t.id!==this._splitSel?.roomId||(i+=" picked");let s="";if(!this._markup&&(o.showBorders||"none"!==o.fill)){i+=" styled";const e=[];e.push(`--room-stroke:${o.color}`,`--room-stroke-op:${o.showBorders?o.opacity:0}`);const n="glow"===o.fill?this._fillColors.glow_base:t.area?Qe(o.fill,"lqi"===o.fill?this._roomLqi(t.area):null,"light"===o.fill?vi(this.hass,this._devices,t.area):"none","temp"===o.fill?yi(this.hass,this._devices,t.area):null,o.tempMin,o.tempMax,this._fillColors):null;n?(i+=" filled",e.push(`--room-fill:${n.c}`,`--room-fill-op:${n.a.toFixed(3)}`)):e.push("--room-fill:transparent","--room-fill-op:0"),s=e.join(";")}const r=e=>this._showTip(e,t.name,this._t("tip.room"),n?this._roomLqi(t.area):null,t.area?yi(this.hass,this._devices,t.area):null),a=!e.bg&&!o.showNames&&!this._markup,l=this._roomCenter(t),c=this._markup&&(t.id===this._mergeSel||t.id===this._splitSel?.roomId),h=t.id&&!c?this._openPairs().filter(e=>e.a.id===t.id||e.b.id===t.id).flatMap(t=>t.segs):[];h.length&&(i+=" noedge");const p=we(t),d=p?function(t,e,i=1e-6){const s=e.filter(e=>Re(t,e,i));return s.filter(t=>!s.some(e=>e!==t&&Re(e,t,i)))}(p,e.rooms.filter(e=>e!==t).map(t=>we(t)).filter(Boolean)):[],u=d.length&&p?j`<path class="${i}" style="${s}" fill-rule="evenodd"
|
||||||
d="${[h,...p].map(t=>"M "+t.map(t=>t[0]+" "+t[1]).join(" L ")+" Z").join(" ")}"
|
d="${[p,...d].map(t=>"M "+t.map(t=>t[0]+" "+t[1]).join(" L ")+" Z").join(" ")}"
|
||||||
@click=${()=>this._clickRoom(t)} @mousemove=${r}
|
@click=${()=>this._clickRoom(t)} @mousemove=${r}
|
||||||
@mouseleave=${()=>this._tip=null}></path>`:t.poly?j`<polygon class="${i}" style="${s}" points="${t.poly.map(t=>t.join(",")).join(" ")}"
|
@mouseleave=${()=>this._tip=null}></path>`:t.poly?j`<polygon class="${i}" style="${s}" points="${t.poly.map(t=>t.join(",")).join(" ")}"
|
||||||
@click=${()=>this._clickRoom(t)} @mousemove=${r}
|
@click=${()=>this._clickRoom(t)} @mousemove=${r}
|
||||||
@mouseleave=${()=>this._tip=null}></polygon>`:j`<rect class="${i}" style="${s}"
|
@mouseleave=${()=>this._tip=null}></polygon>`:j`<rect class="${i}" style="${s}"
|
||||||
x="${t.x}" y="${t.y}" width="${t.w}" height="${t.h}" rx="${.03*Math.min(t.w,t.h)}"
|
x="${t.x}" y="${t.y}" width="${t.w}" height="${t.h}" rx="${.03*Math.min(t.w,t.h)}"
|
||||||
@click=${()=>this._clickRoom(t)} @mousemove=${r}
|
@click=${()=>this._clickRoom(t)} @mousemove=${r}
|
||||||
@mouseleave=${()=>this._tip=null}></rect>`,u=c.length&&h?function(t,e,i=1e-6){const s=[];for(let o=0;o<t.length;o++){const n=t[o],r=t[(o+1)%t.length],a=r[0]-n[0],l=r[1]-n[1],c=Math.hypot(a,l);if(c<i)continue;const h=a/c,p=l/c,d=[];for(const t of e){const e=Math.abs((t[0]-n[0])*p-(t[1]-n[1])*h),s=Math.abs((t[2]-n[0])*p-(t[3]-n[1])*h),o=Math.max(i,1e-6*c);if(e>o||s>o)continue;const r=(t[0]-n[0])*h+(t[1]-n[1])*p,a=(t[2]-n[0])*h+(t[3]-n[1])*p,l=Math.max(0,Math.min(r,a)),u=Math.min(c,Math.max(r,a));u-l>i&&d.push([l,u])}if(!d.length){s.push([n[0],n[1],r[0],r[1]]);continue}d.sort((t,e)=>t[0]-e[0]);let u=0;for(const[t,e]of d)t-u>i&&s.push([n[0]+h*u,n[1]+p*u,n[0]+h*t,n[1]+p*t]),u=Math.max(u,e);c-u>i&&s.push([n[0]+h*u,n[1]+p*u,r[0],r[1]])}return s}(h,c,.02*this._gridPitch):null,_=u?j`<path class="room-outline" d="${u.map(t=>`M ${t[0]} ${t[1]} L ${t[2]} ${t[3]}`).join(" ")}"
|
@mouseleave=${()=>this._tip=null}></rect>`,_=h.length&&p?function(t,e,i=1e-6){const s=[];for(let o=0;o<t.length;o++){const n=t[o],r=t[(o+1)%t.length],a=r[0]-n[0],l=r[1]-n[1],c=Math.hypot(a,l);if(c<i)continue;const h=a/c,p=l/c,d=[];for(const t of e){const e=Math.abs((t[0]-n[0])*p-(t[1]-n[1])*h),s=Math.abs((t[2]-n[0])*p-(t[3]-n[1])*h),o=Math.max(i,1e-6*c);if(e>o||s>o)continue;const r=(t[0]-n[0])*h+(t[1]-n[1])*p,a=(t[2]-n[0])*h+(t[3]-n[1])*p,l=Math.max(0,Math.min(r,a)),u=Math.min(c,Math.max(r,a));u-l>i&&d.push([l,u])}if(!d.length){s.push([n[0],n[1],r[0],r[1]]);continue}d.sort((t,e)=>t[0]-e[0]);let u=0;for(const[t,e]of d)t-u>i&&s.push([n[0]+h*u,n[1]+p*u,n[0]+h*t,n[1]+p*t]),u=Math.max(u,e);c-u>i&&s.push([n[0]+h*u,n[1]+p*u,r[0],r[1]])}return s}(p,h,.02*this._gridPitch):null,g=_?j`<path class="room-outline ${this._markup?"outlined":""}"
|
||||||
style="stroke:${o.color};stroke-opacity:${o.showBorders&&!this._markup?o.opacity:0}"></path>`:G;return j`${d}${_}${a?j`<text class="rlabel" x="${l[0]}" y="${l[1]}">${t.name}</text>`:G}`})}
|
d="${_.map(t=>`M ${t[0]} ${t[1]} L ${t[2]} ${t[3]}`).join(" ")}"
|
||||||
|
style=${this._markup?G:`stroke:${o.color};stroke-opacity:${o.showBorders?o.opacity:0}`}></path>`:G;return j`${u}${g}${a?j`<text class="rlabel" x="${l[0]}" y="${l[1]}">${t.name}</text>`:G}`})}
|
||||||
${"glow"!==o.fill||this._markup?G:this._renderGlowLayer(e)}
|
${"glow"!==o.fill||this._markup?G:this._renderGlowLayer(e)}
|
||||||
${this._renderOpenWalls(o)}
|
${this._renderOpenWalls(o)}
|
||||||
${this._markup?this._renderMarkupLayer(i):G}
|
${this._markup?this._renderMarkupLayer(i):G}
|
||||||
@@ -2300,4 +2306,4 @@ const t=globalThis,e=t.ShadowRoot&&(void 0===t.ShadyCSS||t.ShadyCSS.nativeShadow
|
|||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>`}}Ki.properties={hass:{attribute:!1},_config:{state:!0},_space:{state:!0},_layout:{state:!0},_devices:{state:!0},_tip:{state:!0},_selId:{state:!0},_toast:{state:!0},_serverCfg:{state:!0},_mode:{state:!0},_tool:{state:!0},_path:{state:!0},_cursorPt:{state:!0},_mergeSel:{state:!0},_openingDialog:{state:!0},_openingInfo:{state:!0},_mergeDialog:{state:!0},_splitSel:{state:!0},_decorTool:{state:!0},_decorStyle:{state:!0},_decorDraft:{state:!0},_decorSel:{state:!0},_decorTextDialog:{state:!0},_areaSel:{state:!0},_nameSel:{state:!0},_roomDialog:{state:!0},_spaceDialog:{state:!0},_infoCard:{state:!0},_rulesDialog:{state:!0},_settingsDialog:{state:!0},_importDialog:{state:!0},_markerDialog:{state:!0},_zoom:{state:!0},_view:{state:!0}},Ki.styles=Mi,customElements.get("houseplan-card")||customElements.define("houseplan-card",Ki),window.customCards=window.customCards||[],window.customCards.find(t=>"houseplan-card"===t.type)||window.customCards.push({type:"houseplan-card",name:"House Plan Card",description:"Interactive house plan: spaces, rooms and devices with live states and drag layout."}),console.info("%c HOUSEPLAN-CARD %c v1.38.2 ","background:#3ea6ff;color:#04121f;font-weight:700","");
|
</div>`}}Ki.properties={hass:{attribute:!1},_config:{state:!0},_space:{state:!0},_layout:{state:!0},_devices:{state:!0},_tip:{state:!0},_selId:{state:!0},_toast:{state:!0},_serverCfg:{state:!0},_mode:{state:!0},_tool:{state:!0},_path:{state:!0},_cursorPt:{state:!0},_mergeSel:{state:!0},_openingDialog:{state:!0},_openingInfo:{state:!0},_mergeDialog:{state:!0},_splitSel:{state:!0},_decorTool:{state:!0},_decorStyle:{state:!0},_decorDraft:{state:!0},_decorSel:{state:!0},_decorTextDialog:{state:!0},_areaSel:{state:!0},_nameSel:{state:!0},_roomDialog:{state:!0},_spaceDialog:{state:!0},_infoCard:{state:!0},_rulesDialog:{state:!0},_settingsDialog:{state:!0},_importDialog:{state:!0},_markerDialog:{state:!0},_zoom:{state:!0},_view:{state:!0}},Ki.styles=Mi,customElements.get("houseplan-card")||customElements.define("houseplan-card",Ki),window.customCards=window.customCards||[],window.customCards.find(t=>"houseplan-card"===t.type)||window.customCards.push({type:"houseplan-card",name:"House Plan Card",description:"Interactive house plan: spaces, rooms and devices with live states and drag layout."}),console.info("%c HOUSEPLAN-CARD %c v1.38.3 ","background:#3ea6ff;color:#04121f;font-weight:700","");
|
||||||
|
|||||||
@@ -1,5 +1,10 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
## v1.38.3 — 2026-07-23
|
||||||
|
- The Plan editor now shows open boundaries as a true dash as well: the blue
|
||||||
|
markup outlines are trimmed under the open stretches (rooms picked for
|
||||||
|
merge/split keep their full amber highlight).
|
||||||
|
|
||||||
## v1.38.2 — 2026-07-23
|
## v1.38.2 — 2026-07-23
|
||||||
- The card now **remembers where you were**: the selected space and the active
|
- The card now **remembers where you were**: the selected space and the active
|
||||||
editor survive navigation and closing the tab (localStorage; edit modes are
|
editor survive navigation and closing the tab (localStorage; edit modes are
|
||||||
|
|||||||
@@ -140,6 +140,9 @@ 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
|
||||||
|
- [ ] Dashed boundaries in the Plan editor (v1.38.3): open stretches render as
|
||||||
|
a true dash in markup too (blue trimmed outlines); merge/split-picked
|
||||||
|
rooms keep their full amber highlight [auto]
|
||||||
- [ ] Nav persistence (v1.38.2): closing/reopening the tab restores the last
|
- [ ] Nav persistence (v1.38.2): closing/reopening the tab restores the last
|
||||||
space AND editor mode (admins; localStorage); a #space= deep link beats
|
space AND editor mode (admins; localStorage); a #space= deep link beats
|
||||||
the saved space; a stale cache without the saved space retries after the
|
the saved space; a stale cache without the saved space retries after the
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "houseplan-card",
|
"name": "houseplan-card",
|
||||||
"version": "1.38.2",
|
"version": "1.38.3",
|
||||||
"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",
|
||||||
|
|||||||
@@ -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.38.2';
|
const CARD_VERSION = '1.38.3';
|
||||||
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';
|
||||||
@@ -3201,8 +3201,11 @@ class HouseplanCard extends LitElement {
|
|||||||
const label = !space.bg && !disp.showNames && !this._markup;
|
const label = !space.bg && !disp.showNames && !this._markup;
|
||||||
const c = this._roomCenter(r);
|
const c = this._roomCenter(r);
|
||||||
// open boundaries: this room's solid stroke must not run beneath
|
// open boundaries: this room's solid stroke must not run beneath
|
||||||
// the dashed stretches — suppress it and draw a trimmed outline
|
// the dashed stretches — suppress it and draw a trimmed outline.
|
||||||
const openCuts = !this._markup && r.id
|
// Applies in the Plan editor too (picked rooms keep their full
|
||||||
|
// amber highlight — the merge/split selection must stay visible).
|
||||||
|
const isPicked = this._markup && (r.id === this._mergeSel || r.id === this._splitSel?.roomId);
|
||||||
|
const openCuts = r.id && !isPicked
|
||||||
? this._openPairs()
|
? this._openPairs()
|
||||||
.filter((pp) => pp.a.id === r.id || pp.b.id === r.id)
|
.filter((pp) => pp.a.id === r.id || pp.b.id === r.id)
|
||||||
.flatMap((pp) => pp.segs)
|
.flatMap((pp) => pp.segs)
|
||||||
@@ -3232,8 +3235,9 @@ class HouseplanCard extends LitElement {
|
|||||||
? outlineWithout(myPoly, openCuts, this._gridPitch * 0.02)
|
? outlineWithout(myPoly, openCuts, this._gridPitch * 0.02)
|
||||||
: null;
|
: null;
|
||||||
const outline = trimmed
|
const outline = trimmed
|
||||||
? svg`<path class="room-outline" d="${trimmed.map((sg) => `M ${sg[0]} ${sg[1]} L ${sg[2]} ${sg[3]}`).join(' ')}"
|
? svg`<path class="room-outline ${this._markup ? 'outlined' : ''}"
|
||||||
style="stroke:${disp.color};stroke-opacity:${disp.showBorders && !this._markup ? disp.opacity : 0}"></path>`
|
d="${trimmed.map((sg) => `M ${sg[0]} ${sg[1]} L ${sg[2]} ${sg[3]}`).join(' ')}"
|
||||||
|
style=${this._markup ? nothing : `stroke:${disp.color};stroke-opacity:${disp.showBorders ? disp.opacity : 0}`}></path>`
|
||||||
: nothing;
|
: nothing;
|
||||||
return svg`${shape}${outline}${label ? svg`<text class="rlabel" x="${c[0]}" y="${c[1]}">${r.name}</text>` : nothing}`;
|
return svg`${shape}${outline}${label ? svg`<text class="rlabel" x="${c[0]}" y="${c[1]}">${r.name}</text>` : nothing}`;
|
||||||
})}
|
})}
|
||||||
|
|||||||
@@ -595,6 +595,11 @@ export const cardStyles = css`
|
|||||||
stroke-width: 2.5;
|
stroke-width: 2.5;
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
}
|
}
|
||||||
|
/* Plan editor: trimmed outlines use the markup blue */
|
||||||
|
.room-outline.outlined {
|
||||||
|
stroke: rgba(62, 166, 255, 0.55);
|
||||||
|
stroke-opacity: 1;
|
||||||
|
}
|
||||||
.openwalls.hot .openwall {
|
.openwalls.hot .openwall {
|
||||||
stroke: #ffc14d;
|
stroke: #ffc14d;
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
|
|||||||
Reference in New Issue
Block a user