Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d8435fdb34 | ||
|
|
66bd3d6922 |
@@ -1,111 +1,111 @@
|
||||
{
|
||||
"schema": 1,
|
||||
"fingerprint": "96c69e4400be9bc5c58d138a95af946a3cf0486ac19b272137ade84bb9b35878",
|
||||
"fingerprint": "420f1f87e66a879316f23c4dd573991c8cf2bfcf5ef013191e55e4216031f3be",
|
||||
"entry": "houseplan-card.js",
|
||||
"initialViewFiles": [
|
||||
"houseplan-assets/houseplan-card-0bp2acAx.js",
|
||||
"houseplan-assets/houseplan-card-BarpA18i.js",
|
||||
"houseplan-card.js"
|
||||
],
|
||||
"initialViewGzipBytes": 255993,
|
||||
"initialViewGzipBytes": 256012,
|
||||
"lazyFiles": [
|
||||
"houseplan-assets/de-6NWhGw9L.js",
|
||||
"houseplan-assets/editor-6tQQPtIj.js",
|
||||
"houseplan-assets/houseplan-editor-runtime-B_ONl04j.js",
|
||||
"houseplan-assets/houseplan-onboarding-runtime-BiFQfFve.js",
|
||||
"houseplan-assets/space-deletion-TvTQ5fz7.js"
|
||||
"houseplan-assets/de-L64iNsLu.js",
|
||||
"houseplan-assets/editor-B45l6syb.js",
|
||||
"houseplan-assets/houseplan-editor-runtime-D6vKsLjO.js",
|
||||
"houseplan-assets/houseplan-onboarding-runtime-BUDnRMK5.js",
|
||||
"houseplan-assets/space-deletion-05RPnoUh.js"
|
||||
],
|
||||
"lazyGzipBytes": 160368,
|
||||
"lazyGzipBytes": 160359,
|
||||
"lazyEditorFiles": [
|
||||
"houseplan-assets/editor-6tQQPtIj.js",
|
||||
"houseplan-assets/houseplan-editor-runtime-B_ONl04j.js",
|
||||
"houseplan-assets/space-deletion-TvTQ5fz7.js"
|
||||
"houseplan-assets/editor-B45l6syb.js",
|
||||
"houseplan-assets/houseplan-editor-runtime-D6vKsLjO.js",
|
||||
"houseplan-assets/space-deletion-05RPnoUh.js"
|
||||
],
|
||||
"lazyEditorGzipBytes": 131845,
|
||||
"lazyEditorGzipBytes": 131837,
|
||||
"lazyOnboardingFiles": [
|
||||
"houseplan-assets/houseplan-onboarding-runtime-BiFQfFve.js",
|
||||
"houseplan-assets/space-deletion-TvTQ5fz7.js"
|
||||
"houseplan-assets/houseplan-onboarding-runtime-BUDnRMK5.js",
|
||||
"houseplan-assets/space-deletion-05RPnoUh.js"
|
||||
],
|
||||
"lazyOnboardingGzipBytes": 7201,
|
||||
"lazyOnboardingGzipBytes": 7198,
|
||||
"lazyLocaleFiles": [
|
||||
"houseplan-assets/de-6NWhGw9L.js"
|
||||
"houseplan-assets/de-L64iNsLu.js"
|
||||
],
|
||||
"lazyLocaleGzipBytes": 21877,
|
||||
"lazyLocaleGzipBytes": 21878,
|
||||
"files": [
|
||||
{
|
||||
"path": "houseplan-assets/de-6NWhGw9L.js",
|
||||
"sha256": "a72feee3e2cc31e1c8897224fb9a8eaaf853d24ccab6482f21273ce7b451ae67",
|
||||
"path": "houseplan-assets/de-L64iNsLu.js",
|
||||
"sha256": "472ff7eb5679b16bacedce870ac7a23379c8a03ee3470b660c0c996a76f29b7e",
|
||||
"rawBytes": 71477,
|
||||
"gzipBytes": 21877,
|
||||
"gzipBytes": 21878,
|
||||
"isEntry": false,
|
||||
"imports": [],
|
||||
"dynamicImports": []
|
||||
},
|
||||
{
|
||||
"path": "houseplan-assets/editor-6tQQPtIj.js",
|
||||
"sha256": "ee7ab8a2feb290f7e21da873a1df47d8712e69bdcab3aed0b57fee4305a880b1",
|
||||
"path": "houseplan-assets/editor-B45l6syb.js",
|
||||
"sha256": "2df6678b9adc8c3423d6e250b111461f7f3a75f4377a36ed72e5cbee51ce4bf2",
|
||||
"rawBytes": 3831,
|
||||
"gzipBytes": 1584,
|
||||
"gzipBytes": 1583,
|
||||
"isEntry": false,
|
||||
"imports": [
|
||||
"houseplan-assets/houseplan-card-0bp2acAx.js"
|
||||
"houseplan-assets/houseplan-card-BarpA18i.js"
|
||||
],
|
||||
"dynamicImports": []
|
||||
},
|
||||
{
|
||||
"path": "houseplan-assets/houseplan-card-0bp2acAx.js",
|
||||
"sha256": "2e4f5a4d3a78c2c89842bf3b375bada8d00efad5534fe81e1a32f03bfd43f99a",
|
||||
"rawBytes": 909954,
|
||||
"gzipBytes": 255811,
|
||||
"path": "houseplan-assets/houseplan-card-BarpA18i.js",
|
||||
"sha256": "b3276d12591e3face8174420b981e9d7626ca9ab02667982ad83943d93194ef1",
|
||||
"rawBytes": 910025,
|
||||
"gzipBytes": 255830,
|
||||
"isEntry": false,
|
||||
"imports": [],
|
||||
"dynamicImports": [
|
||||
"houseplan-assets/de-6NWhGw9L.js",
|
||||
"houseplan-assets/editor-6tQQPtIj.js",
|
||||
"houseplan-assets/houseplan-editor-runtime-B_ONl04j.js",
|
||||
"houseplan-assets/houseplan-onboarding-runtime-BiFQfFve.js"
|
||||
"houseplan-assets/de-L64iNsLu.js",
|
||||
"houseplan-assets/editor-B45l6syb.js",
|
||||
"houseplan-assets/houseplan-editor-runtime-D6vKsLjO.js",
|
||||
"houseplan-assets/houseplan-onboarding-runtime-BUDnRMK5.js"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "houseplan-assets/houseplan-editor-runtime-B_ONl04j.js",
|
||||
"sha256": "e362c070b2ae1eee9e91f346baa4ae46ad8e58a68cf49885a129abd42ce8dc2e",
|
||||
"path": "houseplan-assets/houseplan-editor-runtime-D6vKsLjO.js",
|
||||
"sha256": "8cf01ac6ca2eb3ee4f8f1191ab15eb92884ee25013356ea4e12bfffdeb0b1fd2",
|
||||
"rawBytes": 504959,
|
||||
"gzipBytes": 129706,
|
||||
"gzipBytes": 129700,
|
||||
"isEntry": false,
|
||||
"imports": [
|
||||
"houseplan-assets/houseplan-card-0bp2acAx.js",
|
||||
"houseplan-assets/space-deletion-TvTQ5fz7.js"
|
||||
"houseplan-assets/houseplan-card-BarpA18i.js",
|
||||
"houseplan-assets/space-deletion-05RPnoUh.js"
|
||||
],
|
||||
"dynamicImports": []
|
||||
},
|
||||
{
|
||||
"path": "houseplan-assets/houseplan-onboarding-runtime-BiFQfFve.js",
|
||||
"sha256": "eb6b88d822151bb3ded528ecf03a2e3b698c86fd3ca887925df57fa1f896a698",
|
||||
"path": "houseplan-assets/houseplan-onboarding-runtime-BUDnRMK5.js",
|
||||
"sha256": "2439e9cdf2c7873b737d46261a8f489c398c5434bc1fecd71a481ca80519443d",
|
||||
"rawBytes": 26356,
|
||||
"gzipBytes": 6646,
|
||||
"gzipBytes": 6644,
|
||||
"isEntry": false,
|
||||
"imports": [
|
||||
"houseplan-assets/houseplan-card-0bp2acAx.js",
|
||||
"houseplan-assets/space-deletion-TvTQ5fz7.js"
|
||||
"houseplan-assets/houseplan-card-BarpA18i.js",
|
||||
"houseplan-assets/space-deletion-05RPnoUh.js"
|
||||
],
|
||||
"dynamicImports": []
|
||||
},
|
||||
{
|
||||
"path": "houseplan-assets/space-deletion-TvTQ5fz7.js",
|
||||
"sha256": "e9573e60cc49ef932bf8b4d6ac2128c30312bf2c92f5b97ef8404edba7adbd86",
|
||||
"path": "houseplan-assets/space-deletion-05RPnoUh.js",
|
||||
"sha256": "2cf11df1b1bcd463ef90c1089b35ae89be7ce4d92370bb6a9ee3e94987a3d65f",
|
||||
"rawBytes": 911,
|
||||
"gzipBytes": 555,
|
||||
"gzipBytes": 554,
|
||||
"isEntry": false,
|
||||
"imports": [],
|
||||
"dynamicImports": []
|
||||
},
|
||||
{
|
||||
"path": "houseplan-card.js",
|
||||
"sha256": "a354023944e1da091a71a7c5cf0cc2b9d61207ec3ebef70c0afe6170aef8485e",
|
||||
"sha256": "aa89ff5b93e00716f50c19cbb8efd81900451bca43220ddf3a74d9de7bf6a57e",
|
||||
"rawBytes": 190,
|
||||
"gzipBytes": 182,
|
||||
"isEntry": true,
|
||||
"imports": [
|
||||
"houseplan-assets/houseplan-card-0bp2acAx.js"
|
||||
"houseplan-assets/houseplan-card-BarpA18i.js"
|
||||
],
|
||||
"dynamicImports": []
|
||||
}
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="96c69e4400be9bc5c58d138a95af946a3cf0486ac19b272137ade84bb9b35878";import{c as e,l as o,t,d2 as s,A as a,d3 as i,d4 as l,d5 as n,E as r,b as c}from"./houseplan-card-0bp2acAx.js";class h extends e{constructor(){super(...arguments),this._spaces=null,this._spacesLoading=!1,this._spacesAuthoritative=!1}setConfig(e){this._config=e}async _loadSpaces(){if(!this._spaces&&!this._spacesLoading&&this.hass){this._spacesLoading=!0;try{const e=await this.hass.callWS({type:"houseplan/config/get"});this._spaces=(e?.config?.spaces||[]).map(e=>({value:e.id,label:e.title||e.id})),this._spacesAuthoritative=!0}catch{this._spaces=[],this._spacesAuthoritative=!1}finally{this._spacesLoading=!1}}}get _lang(){return o(this.hass,this._config?.language)}get _floorToken(){const e=this._config?.floor;return"number"==typeof e?`__houseplan_yaml_floor_index__:${String(e)}`:null}get _formData(){const e={...this._config},o=this._floorToken;return o?e.floor=o:Object.prototype.hasOwnProperty.call(e,"floor")||(e.floor=""),e}get _schema(){const e=this._spaces||[],o=this._lang,a=[{value:"",label:t(o,"editor.floor_none")}],i=this._floorToken;i&&a.push({value:i,label:t(o,"editor.floor_index",{index:String(this._config?.floor)})});const l="string"==typeof this._config?.floor?this._config.floor:"";l&&!e.some(e=>e.value===l)&&a.push({value:l,label:l}),a.push(...e);const n="string"==typeof this._config?.default_floor?this._config.default_floor:"",r=[...e];return n&&!e.some(e=>e.value===n)&&r.unshift({value:n,label:n}),[{name:"title",selector:{text:{}}},{name:"floor",selector:{select:{mode:"dropdown",options:a}}},e.length?{name:"default_floor",selector:{select:{mode:"dropdown",options:r}}}:{name:"default_floor",selector:{text:{}}},{name:"language",selector:{select:{mode:"dropdown",options:s(t(o,"editor.lang_auto"),this._config?.language)}}},{name:"icon_size",selector:{number:{min:1,max:6,step:.1,mode:"box"}}},{name:"show_temperature",selector:{boolean:{}}},{name:"live_states",selector:{boolean:{}}},{name:"show_signal",selector:{boolean:{}}},{name:"kiosk",selector:{boolean:{}}},{name:"cycle",selector:{number:{min:0,max:3600,step:5,mode:"box"}}}]}render(){if(!this.hass||!this._config)return a;const e=i(this,l,o(this.hass,this._config.language));if("cold"===e)return n();if("warm"===e)return r;this._loadSpaces();const s=this._lang,h={title:t(s,"editor.title"),floor:t(s,"editor.floor"),default_floor:t(s,"editor.default_floor"),language:t(s,"editor.language"),icon_size:t(s,"editor.icon_size"),show_temperature:t(s,"editor.show_temperature"),live_states:t(s,"editor.live_states"),show_signal:t(s,"editor.show_signal"),kiosk:t(s,"editor.kiosk"),cycle:t(s,"editor.cycle")},f=this._schema,_=function(e,o,t){if(!t||null===o)return null;const s="string"==typeof e?.default_floor?e.default_floor:"";return!s||o.some(e=>e.value===s)?null:s}(this._config,this._spaces,this._spacesAuthoritative),d=e=>c`<ha-form
|
||||
globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="420f1f87e66a879316f23c4dd573991c8cf2bfcf5ef013191e55e4216031f3be";import{c as e,l as o,t,d2 as s,A as a,d3 as i,d4 as l,d5 as n,E as r,b as c}from"./houseplan-card-BarpA18i.js";class f extends e{constructor(){super(...arguments),this._spaces=null,this._spacesLoading=!1,this._spacesAuthoritative=!1}setConfig(e){this._config=e}async _loadSpaces(){if(!this._spaces&&!this._spacesLoading&&this.hass){this._spacesLoading=!0;try{const e=await this.hass.callWS({type:"houseplan/config/get"});this._spaces=(e?.config?.spaces||[]).map(e=>({value:e.id,label:e.title||e.id})),this._spacesAuthoritative=!0}catch{this._spaces=[],this._spacesAuthoritative=!1}finally{this._spacesLoading=!1}}}get _lang(){return o(this.hass,this._config?.language)}get _floorToken(){const e=this._config?.floor;return"number"==typeof e?`__houseplan_yaml_floor_index__:${String(e)}`:null}get _formData(){const e={...this._config},o=this._floorToken;return o?e.floor=o:Object.prototype.hasOwnProperty.call(e,"floor")||(e.floor=""),e}get _schema(){const e=this._spaces||[],o=this._lang,a=[{value:"",label:t(o,"editor.floor_none")}],i=this._floorToken;i&&a.push({value:i,label:t(o,"editor.floor_index",{index:String(this._config?.floor)})});const l="string"==typeof this._config?.floor?this._config.floor:"";l&&!e.some(e=>e.value===l)&&a.push({value:l,label:l}),a.push(...e);const n="string"==typeof this._config?.default_floor?this._config.default_floor:"",r=[...e];return n&&!e.some(e=>e.value===n)&&r.unshift({value:n,label:n}),[{name:"title",selector:{text:{}}},{name:"floor",selector:{select:{mode:"dropdown",options:a}}},e.length?{name:"default_floor",selector:{select:{mode:"dropdown",options:r}}}:{name:"default_floor",selector:{text:{}}},{name:"language",selector:{select:{mode:"dropdown",options:s(t(o,"editor.lang_auto"),this._config?.language)}}},{name:"icon_size",selector:{number:{min:1,max:6,step:.1,mode:"box"}}},{name:"show_temperature",selector:{boolean:{}}},{name:"live_states",selector:{boolean:{}}},{name:"show_signal",selector:{boolean:{}}},{name:"kiosk",selector:{boolean:{}}},{name:"cycle",selector:{number:{min:0,max:3600,step:5,mode:"box"}}}]}render(){if(!this.hass||!this._config)return a;const e=i(this,l,o(this.hass,this._config.language));if("cold"===e)return n();if("warm"===e)return r;this._loadSpaces();const s=this._lang,f={title:t(s,"editor.title"),floor:t(s,"editor.floor"),default_floor:t(s,"editor.default_floor"),language:t(s,"editor.language"),icon_size:t(s,"editor.icon_size"),show_temperature:t(s,"editor.show_temperature"),live_states:t(s,"editor.live_states"),show_signal:t(s,"editor.show_signal"),kiosk:t(s,"editor.kiosk"),cycle:t(s,"editor.cycle")},h=this._schema,_=function(e,o,t){if(!t||null===o)return null;const s="string"==typeof e?.default_floor?e.default_floor:"";return!s||o.some(e=>e.value===s)?null:s}(this._config,this._spaces,this._spacesAuthoritative),d=e=>c`<ha-form
|
||||
.hass=${this.hass}
|
||||
.data=${this._formData}
|
||||
.schema=${e}
|
||||
.computeLabel=${e=>h[e.name]||e.name}
|
||||
.computeLabel=${e=>f[e.name]||e.name}
|
||||
@value-changed=${this._valueChanged}
|
||||
></ha-form>`;return c`
|
||||
${d(f.slice(0,3))}
|
||||
${d(h.slice(0,3))}
|
||||
${_?c`<div class="default-floor-error" role="alert"
|
||||
style="color:var(--error-color,#db4437);margin:-4px 0 12px;overflow-wrap:anywhere">
|
||||
${t(s,"editor.default_floor_missing",{id:_})}
|
||||
</div>`:a}
|
||||
${d(f.slice(3))}
|
||||
`}_valueChanged(e){const o={...this._config,...e.detail.value};""===o.floor?delete o.floor:o.floor===this._floorToken&&(o.floor=this._config?.floor);const t=new Event("config-changed",{bubbles:!0,composed:!0});t.detail={config:o},this.dispatchEvent(t)}}h.properties={hass:{attribute:!1},_config:{state:!0},_spaces:{state:!0}},customElements.get("houseplan-card-editor")||customElements.define("houseplan-card-editor",h);
|
||||
${d(h.slice(3))}
|
||||
`}_valueChanged(e){const o={...this._config,...e.detail.value};""===o.floor?delete o.floor:o.floor===this._floorToken&&(o.floor=this._config?.floor);const t=new Event("config-changed",{bubbles:!0,composed:!0});t.detail={config:o},this.dispatchEvent(t)}}f.properties={hass:{attribute:!1},_config:{state:!0},_spaces:{state:!0}},customElements.get("houseplan-card-editor")||customElements.define("houseplan-card-editor",f);
|
||||
@@ -1,4 +1,4 @@
|
||||
globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="96c69e4400be9bc5c58d138a95af946a3cf0486ac19b272137ade84bb9b35878";import{bU as t,bV as s,bW as e,bX as o,aq as a,bY as l,c1 as i,bZ as h,b_ as n,b$ as c,c0 as r,b as p,A as _,cV as d,ap as u,ar as g,cW as m}from"./houseplan-card-0bp2acAx.js";import{i as b,c as $,a as v,s as y,t as f}from"./space-deletion-TvTQ5fz7.js";const w=1e3,D=t=>{if(!t.trim())return null;const s=Number(t.replace(",","."));return Number.isFinite(s)?s:null},S="96c69e4400be9bc5c58d138a95af946a3cf0486ac19b272137ade84bb9b35878";class C{constructor(t){this.host=t,this._toggleServerPlans=async()=>{const t=this.host._spaceDialog;if(t)if(t.pickSaved)this.host._spaceDialog={...t,pickSaved:!1};else{this.host._spaceDialog={...t,pickSaved:!0,savedBusy:!0};try{const t=await this.host.hass.callWS({type:"houseplan/plans/list"}),s=this.host._spaceDialog;s&&(this.host._spaceDialog={...s,saved:t?.plans||[],savedBusy:!1})}catch(t){const s=this.host._spaceDialog;s&&(this.host._spaceDialog={...s,saved:[],savedBusy:!1}),this.host._showToast(this.host._t("toast.plans_list_failed",{err:this.host._errText(t)}))}}}}_openSpaceDialog(p,_){if(!this.host._serverStorage||!this.host._serverCfg)return void this.host._showToast(this.host._t("toast.integration_missing"));if("edit"===p){const i=this.host._serverCfg.spaces.find(t=>t.id===_);if(!i)return;const h=t(i),n=i.settings?.custom_fill&&"object"==typeof i.settings.custom_fill?s(i.settings.custom_fill):null,c="none"===h.fill?{...n||e,a:0}:n;return void(this.host._spaceDialog={mode:p,spaceId:_,title:i.title,planUrl:i.plan_url||null,planFile:null,source:i.plan_url?"file":"draw",showBorders:h.showBorders,showNames:h.showNames,zeroWallStyle:l(i),displayTouched:!0,hideDecor:h.hideDecor,hideOpenings:h.hideOpenings,roomColor:h.color,roomOpacity:h.opacity,fillMode:"none"===h.fill?"custom":h.fill,customFill:c,glowEnabled:h.glow,bgColor:h.bgColor,bgMode:"static"===i.settings?.bg_mode||"daynight"===i.settings?.bg_mode?i.settings.bg_mode:null,northDeg:a({},i.settings),sunRays:"boolean"==typeof i.settings?.sun_rays?i.settings.sun_rays:null,tempMin:h.tempMin,tempMax:h.tempMax,showLqi:h.showLqi??this.host._config?.show_signal??!0,cardFontScale:h.cardFontScale,labelTemp:h.labelTemp,labelHum:h.labelHum,labelLqi:h.labelLqi,labelLight:h.labelLight,cellCm:Number(i.cell_cm)>0?Number(i.cell_cm):5,cellCmInput:o(Number(i.cell_cm)>0?Number(i.cell_cm):5,this.host._imperial),cellCmTouched:!1,busy:!1})}const d=i(this.host._imperial);this.host._spaceDialog={mode:p,title:"",planUrl:null,planFile:null,...b(),hideDecor:!1,hideOpenings:!1,zeroWallStyle:"dashed",roomColor:r,roomOpacity:c,fillMode:"custom",customFill:{...e,a:0},glowEnabled:!0,bgColor:null,bgMode:"daynight",northDeg:null,sunRays:null,tempMin:n,tempMax:h,showLqi:this.host._config?.show_signal??!0,cardFontScale:1,labelTemp:!1,labelHum:!1,labelLqi:!1,labelLight:!1,cellCm:d,cellCmInput:o(d,this.host._imperial),cellCmTouched:!1,busy:!1}}async _pickPlanFile(t){const s=t.target,e=s.files?.[0];if(!e||!this.host._spaceDialog)return;const o={"image/svg+xml":"svg","image/png":"png","image/jpeg":"jpg","image/webp":"webp"}[e.type]||(e.name.toLowerCase().endsWith(".svg")?"svg":"");if(!o)return void this.host._showToast(this.host._t("toast.plan_formats"));const a=new Uint8Array(await e.arrayBuffer());let l="";for(let t=0;t<a.length;t+=32768)l+=String.fromCharCode(...a.subarray(t,t+32768));const i=btoa(l),h=URL.createObjectURL(e),n=await new Promise(t=>{const s=new Image;s.onload=()=>t(s.naturalWidth&&s.naturalHeight?s.naturalWidth/s.naturalHeight:1.414),s.onerror=()=>t(1.414),s.src=h});URL.revokeObjectURL(h),this.host._spaceDialog={...this.host._spaceDialog,planFile:{ext:o,b64:i,aspect:n,name:e.name}}}_useServerPlan(t){const s=this.host._spaceDialog;s&&(this.host._spaceDialog={...s,planUrl:t,planFile:null,pickSaved:!1,savedAspect:void 0},this.host._aspectJob=this._readPlanAspect(t))}async _readPlanAspect(t){for(let s=0;s<40;s++){const s=this.host._display(t);if(s){const e=await new Promise(t=>{const e=new Image;e.onload=()=>t(e.naturalWidth&&e.naturalHeight?e.naturalWidth/e.naturalHeight:0),e.onerror=()=>t(0),e.src=s}),o=this.host._spaceDialog;return o&&o.planUrl===t&&Number.isFinite(e)&&e>0?(this.host._spaceDialog={...o,savedAspect:e},e):0}if(await new Promise(t=>setTimeout(t,150)),this.host._spaceDialog?.planUrl!==t)return 0}return 0}async _deleteServerPlan(t){if(confirm(this.host._t("confirm.delete_plan",{name:t})))try{await this.host.hass.callWS({type:"houseplan/plans/delete",name:t});const s=this.host._spaceDialog;s?.saved&&(this.host._spaceDialog={...s,saved:s.saved.filter(s=>s.name!==t)})}catch(t){this.host._showToast(this.host._t("toast.plan_delete_failed",{err:this.host._errText(t)}))}}_renderServerPlans(t){if(t.savedBusy)return p`<div class="savedplans muted">${this.host._t("space.loading")}</div>`;const s=t.saved||[];if(!s.length)return p`<div class="savedplans muted">${this.host._t("space.no_saved")}</div>`;return p`<div class="savedplans">
|
||||
globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="420f1f87e66a879316f23c4dd573991c8cf2bfcf5ef013191e55e4216031f3be";import{bU as t,bV as s,bW as e,bX as o,aq as a,bY as l,c1 as i,bZ as h,b_ as n,b$ as c,c0 as r,b as p,A as _,cV as d,ap as u,ar as g,cW as m}from"./houseplan-card-BarpA18i.js";import{i as b,c as $,a as v,s as f,t as y}from"./space-deletion-05RPnoUh.js";const w=1e3,D=t=>{if(!t.trim())return null;const s=Number(t.replace(",","."));return Number.isFinite(s)?s:null},S="420f1f87e66a879316f23c4dd573991c8cf2bfcf5ef013191e55e4216031f3be";class C{constructor(t){this.host=t,this._toggleServerPlans=async()=>{const t=this.host._spaceDialog;if(t)if(t.pickSaved)this.host._spaceDialog={...t,pickSaved:!1};else{this.host._spaceDialog={...t,pickSaved:!0,savedBusy:!0};try{const t=await this.host.hass.callWS({type:"houseplan/plans/list"}),s=this.host._spaceDialog;s&&(this.host._spaceDialog={...s,saved:t?.plans||[],savedBusy:!1})}catch(t){const s=this.host._spaceDialog;s&&(this.host._spaceDialog={...s,saved:[],savedBusy:!1}),this.host._showToast(this.host._t("toast.plans_list_failed",{err:this.host._errText(t)}))}}}}_openSpaceDialog(p,_){if(!this.host._serverStorage||!this.host._serverCfg)return void this.host._showToast(this.host._t("toast.integration_missing"));if("edit"===p){const i=this.host._serverCfg.spaces.find(t=>t.id===_);if(!i)return;const h=t(i),n=i.settings?.custom_fill&&"object"==typeof i.settings.custom_fill?s(i.settings.custom_fill):null,c="none"===h.fill?{...n||e,a:0}:n;return void(this.host._spaceDialog={mode:p,spaceId:_,title:i.title,planUrl:i.plan_url||null,planFile:null,source:i.plan_url?"file":"draw",showBorders:h.showBorders,showNames:h.showNames,zeroWallStyle:l(i),displayTouched:!0,hideDecor:h.hideDecor,hideOpenings:h.hideOpenings,roomColor:h.color,roomOpacity:h.opacity,fillMode:"none"===h.fill?"custom":h.fill,customFill:c,glowEnabled:h.glow,bgColor:h.bgColor,bgMode:"static"===i.settings?.bg_mode||"daynight"===i.settings?.bg_mode?i.settings.bg_mode:null,northDeg:a({},i.settings),sunRays:"boolean"==typeof i.settings?.sun_rays?i.settings.sun_rays:null,tempMin:h.tempMin,tempMax:h.tempMax,showLqi:h.showLqi??this.host._config?.show_signal??!0,cardFontScale:h.cardFontScale,labelTemp:h.labelTemp,labelHum:h.labelHum,labelLqi:h.labelLqi,labelLight:h.labelLight,cellCm:Number(i.cell_cm)>0?Number(i.cell_cm):5,cellCmInput:o(Number(i.cell_cm)>0?Number(i.cell_cm):5,this.host._imperial),cellCmTouched:!1,busy:!1})}const d=i(this.host._imperial);this.host._spaceDialog={mode:p,title:"",planUrl:null,planFile:null,...b(),hideDecor:!1,hideOpenings:!1,zeroWallStyle:"dashed",roomColor:r,roomOpacity:c,fillMode:"custom",customFill:{...e,a:0},glowEnabled:!0,bgColor:null,bgMode:"daynight",northDeg:null,sunRays:null,tempMin:n,tempMax:h,showLqi:this.host._config?.show_signal??!0,cardFontScale:1,labelTemp:!1,labelHum:!1,labelLqi:!1,labelLight:!1,cellCm:d,cellCmInput:o(d,this.host._imperial),cellCmTouched:!1,busy:!1}}async _pickPlanFile(t){const s=t.target,e=s.files?.[0];if(!e||!this.host._spaceDialog)return;const o={"image/svg+xml":"svg","image/png":"png","image/jpeg":"jpg","image/webp":"webp"}[e.type]||(e.name.toLowerCase().endsWith(".svg")?"svg":"");if(!o)return void this.host._showToast(this.host._t("toast.plan_formats"));const a=new Uint8Array(await e.arrayBuffer());let l="";for(let t=0;t<a.length;t+=32768)l+=String.fromCharCode(...a.subarray(t,t+32768));const i=btoa(l),h=URL.createObjectURL(e),n=await new Promise(t=>{const s=new Image;s.onload=()=>t(s.naturalWidth&&s.naturalHeight?s.naturalWidth/s.naturalHeight:1.414),s.onerror=()=>t(1.414),s.src=h});URL.revokeObjectURL(h),this.host._spaceDialog={...this.host._spaceDialog,planFile:{ext:o,b64:i,aspect:n,name:e.name}}}_useServerPlan(t){const s=this.host._spaceDialog;s&&(this.host._spaceDialog={...s,planUrl:t,planFile:null,pickSaved:!1,savedAspect:void 0},this.host._aspectJob=this._readPlanAspect(t))}async _readPlanAspect(t){for(let s=0;s<40;s++){const s=this.host._display(t);if(s){const e=await new Promise(t=>{const e=new Image;e.onload=()=>t(e.naturalWidth&&e.naturalHeight?e.naturalWidth/e.naturalHeight:0),e.onerror=()=>t(0),e.src=s}),o=this.host._spaceDialog;return o&&o.planUrl===t&&Number.isFinite(e)&&e>0?(this.host._spaceDialog={...o,savedAspect:e},e):0}if(await new Promise(t=>setTimeout(t,150)),this.host._spaceDialog?.planUrl!==t)return 0}return 0}async _deleteServerPlan(t){if(confirm(this.host._t("confirm.delete_plan",{name:t})))try{await this.host.hass.callWS({type:"houseplan/plans/delete",name:t});const s=this.host._spaceDialog;s?.saved&&(this.host._spaceDialog={...s,saved:s.saved.filter(s=>s.name!==t)})}catch(t){this.host._showToast(this.host._t("toast.plan_delete_failed",{err:this.host._errText(t)}))}}_renderServerPlans(t){if(t.savedBusy)return p`<div class="savedplans muted">${this.host._t("space.loading")}</div>`;const s=t.saved||[];if(!s.length)return p`<div class="savedplans muted">${this.host._t("space.no_saved")}</div>`;return p`<div class="savedplans">
|
||||
${s.map(s=>{return p`
|
||||
<div class="savedplan ${s.url===t.planUrl?"cur":""}">
|
||||
<img src=${this.host._display(s.url)} alt="" loading="lazy" decoding="async" />
|
||||
@@ -46,7 +46,7 @@ globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="96c69e4400be9bc5c58d138a95af946a3cf0
|
||||
<label>${this.host._t("space.plan_label")}</label>
|
||||
<label class="srcrow">
|
||||
<input type="radio" name="plansrc" .checked=${"file"===t.source}
|
||||
@change=${()=>this.host._spaceDialog=y(t,"file")} />
|
||||
@change=${()=>this.host._spaceDialog=f(t,"file")} />
|
||||
<span>${this.host._t("space.source_file")}</span>
|
||||
</label>
|
||||
${"file"===t.source?p`<div class="planrow">
|
||||
@@ -68,7 +68,7 @@ globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="96c69e4400be9bc5c58d138a95af946a3cf0
|
||||
${t.pickSaved?this._renderServerPlans(t):_}`:_}
|
||||
<label class="srcrow">
|
||||
<input type="radio" name="plansrc" .checked=${"draw"===t.source}
|
||||
@change=${()=>this.host._spaceDialog=y(t,"draw")} />
|
||||
@change=${()=>this.host._spaceDialog=f(t,"draw")} />
|
||||
<span>${this.host._t("space.source_draw")}</span>
|
||||
</label>
|
||||
|
||||
@@ -85,7 +85,7 @@ globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="96c69e4400be9bc5c58d138a95af946a3cf0
|
||||
|
||||
<label class="dispsection">${this.host._t("space.display_section")}</label>
|
||||
<label class="srcrow">
|
||||
${this._boolInput(t.showBorders,s=>{this.host._spaceDialog=f(t,"showBorders",s)})}
|
||||
${this._boolInput(t.showBorders,s=>{this.host._spaceDialog=y(t,"showBorders",s)})}
|
||||
<span>${this.host._t("space.show_borders")}</span>
|
||||
</label>
|
||||
<label>${this.host._t("space.zero_wall_style")}</label>
|
||||
@@ -99,7 +99,7 @@ globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="96c69e4400be9bc5c58d138a95af946a3cf0
|
||||
</select>
|
||||
<div class="rhint">${this.host._t("space.zero_wall_help")}</div>
|
||||
<label class="srcrow">
|
||||
${this._boolInput(t.showNames,s=>{this.host._spaceDialog=f(t,"showNames",s)})}
|
||||
${this._boolInput(t.showNames,s=>{this.host._spaceDialog=y(t,"showNames",s)})}
|
||||
<span>${this.host._t("space.show_names")}</span>
|
||||
</label>
|
||||
<label class="srcrow">
|
||||
@@ -1 +1 @@
|
||||
function e(e,o){return{id:e,title:o,plan_url:null,view_box:[0,0,1,1],rooms:[],wall_segments:[]}}function o(e="file"){const o="draw"===e;return{source:e,showBorders:o,showNames:o,displayTouched:!1}}function r(e,o){if(e.displayTouched)return{...e,source:o};const r="draw"===o;return{...e,source:o,showBorders:r,showNames:r}}function s(e,o,r){return{...e,[o]:r,displayTouched:!0}}function t(e,o,r){const s=(e?.spaces||[]).find(e=>e?.id===r),t=new Set((s?.rooms||[]).map(e=>String(e?.id||"")).filter(Boolean)),a=[...new Set((e?.markers||[]).filter(e=>!0!==e?.removed&&"string"==typeof e?.id).filter(e=>e.space===r||"string"==typeof e.room_id&&t.has(e.room_id)||o?.[e.id]?.s===r).map(e=>e.id))].sort((e,o)=>e.localeCompare(o));return{markerIds:a,count:a.length}}globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="96c69e4400be9bc5c58d138a95af946a3cf0486ac19b272137ade84bb9b35878";export{t as a,e as c,o as i,r as s,s as t};
|
||||
function e(e,o){return{id:e,title:o,plan_url:null,view_box:[0,0,1,1],rooms:[],wall_segments:[]}}function o(e="file"){const o="draw"===e;return{source:e,showBorders:o,showNames:o,displayTouched:!1}}function r(e,o){if(e.displayTouched)return{...e,source:o};const r="draw"===o;return{...e,source:o,showBorders:r,showNames:r}}function s(e,o,r){return{...e,[o]:r,displayTouched:!0}}function t(e,o,r){const s=(e?.spaces||[]).find(e=>e?.id===r),t=new Set((s?.rooms||[]).map(e=>String(e?.id||"")).filter(Boolean)),n=[...new Set((e?.markers||[]).filter(e=>!0!==e?.removed&&"string"==typeof e?.id).filter(e=>e.space===r||"string"==typeof e.room_id&&t.has(e.room_id)||o?.[e.id]?.s===r).map(e=>e.id))].sort((e,o)=>e.localeCompare(o));return{markerIds:n,count:n.length}}globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="420f1f87e66a879316f23c4dd573991c8cf2bfcf5ef013191e55e4216031f3be";export{t as a,e as c,o as i,r as s,s as t};
|
||||
@@ -1 +1 @@
|
||||
globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="96c69e4400be9bc5c58d138a95af946a3cf0486ac19b272137ade84bb9b35878";export{d6 as HouseplanCard}from"./houseplan-assets/houseplan-card-0bp2acAx.js";
|
||||
globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="420f1f87e66a879316f23c4dd573991c8cf2bfcf5ef013191e55e4216031f3be";export{d6 as HouseplanCard}from"./houseplan-assets/houseplan-card-BarpA18i.js";
|
||||
|
||||
@@ -1,111 +1,111 @@
|
||||
{
|
||||
"schema": 1,
|
||||
"fingerprint": "96c69e4400be9bc5c58d138a95af946a3cf0486ac19b272137ade84bb9b35878",
|
||||
"fingerprint": "420f1f87e66a879316f23c4dd573991c8cf2bfcf5ef013191e55e4216031f3be",
|
||||
"entry": "houseplan-card.js",
|
||||
"initialViewFiles": [
|
||||
"houseplan-assets/houseplan-card-0bp2acAx.js",
|
||||
"houseplan-assets/houseplan-card-BarpA18i.js",
|
||||
"houseplan-card.js"
|
||||
],
|
||||
"initialViewGzipBytes": 255993,
|
||||
"initialViewGzipBytes": 256012,
|
||||
"lazyFiles": [
|
||||
"houseplan-assets/de-6NWhGw9L.js",
|
||||
"houseplan-assets/editor-6tQQPtIj.js",
|
||||
"houseplan-assets/houseplan-editor-runtime-B_ONl04j.js",
|
||||
"houseplan-assets/houseplan-onboarding-runtime-BiFQfFve.js",
|
||||
"houseplan-assets/space-deletion-TvTQ5fz7.js"
|
||||
"houseplan-assets/de-L64iNsLu.js",
|
||||
"houseplan-assets/editor-B45l6syb.js",
|
||||
"houseplan-assets/houseplan-editor-runtime-D6vKsLjO.js",
|
||||
"houseplan-assets/houseplan-onboarding-runtime-BUDnRMK5.js",
|
||||
"houseplan-assets/space-deletion-05RPnoUh.js"
|
||||
],
|
||||
"lazyGzipBytes": 160368,
|
||||
"lazyGzipBytes": 160359,
|
||||
"lazyEditorFiles": [
|
||||
"houseplan-assets/editor-6tQQPtIj.js",
|
||||
"houseplan-assets/houseplan-editor-runtime-B_ONl04j.js",
|
||||
"houseplan-assets/space-deletion-TvTQ5fz7.js"
|
||||
"houseplan-assets/editor-B45l6syb.js",
|
||||
"houseplan-assets/houseplan-editor-runtime-D6vKsLjO.js",
|
||||
"houseplan-assets/space-deletion-05RPnoUh.js"
|
||||
],
|
||||
"lazyEditorGzipBytes": 131845,
|
||||
"lazyEditorGzipBytes": 131837,
|
||||
"lazyOnboardingFiles": [
|
||||
"houseplan-assets/houseplan-onboarding-runtime-BiFQfFve.js",
|
||||
"houseplan-assets/space-deletion-TvTQ5fz7.js"
|
||||
"houseplan-assets/houseplan-onboarding-runtime-BUDnRMK5.js",
|
||||
"houseplan-assets/space-deletion-05RPnoUh.js"
|
||||
],
|
||||
"lazyOnboardingGzipBytes": 7201,
|
||||
"lazyOnboardingGzipBytes": 7198,
|
||||
"lazyLocaleFiles": [
|
||||
"houseplan-assets/de-6NWhGw9L.js"
|
||||
"houseplan-assets/de-L64iNsLu.js"
|
||||
],
|
||||
"lazyLocaleGzipBytes": 21877,
|
||||
"lazyLocaleGzipBytes": 21878,
|
||||
"files": [
|
||||
{
|
||||
"path": "houseplan-assets/de-6NWhGw9L.js",
|
||||
"sha256": "a72feee3e2cc31e1c8897224fb9a8eaaf853d24ccab6482f21273ce7b451ae67",
|
||||
"path": "houseplan-assets/de-L64iNsLu.js",
|
||||
"sha256": "472ff7eb5679b16bacedce870ac7a23379c8a03ee3470b660c0c996a76f29b7e",
|
||||
"rawBytes": 71477,
|
||||
"gzipBytes": 21877,
|
||||
"gzipBytes": 21878,
|
||||
"isEntry": false,
|
||||
"imports": [],
|
||||
"dynamicImports": []
|
||||
},
|
||||
{
|
||||
"path": "houseplan-assets/editor-6tQQPtIj.js",
|
||||
"sha256": "ee7ab8a2feb290f7e21da873a1df47d8712e69bdcab3aed0b57fee4305a880b1",
|
||||
"path": "houseplan-assets/editor-B45l6syb.js",
|
||||
"sha256": "2df6678b9adc8c3423d6e250b111461f7f3a75f4377a36ed72e5cbee51ce4bf2",
|
||||
"rawBytes": 3831,
|
||||
"gzipBytes": 1584,
|
||||
"gzipBytes": 1583,
|
||||
"isEntry": false,
|
||||
"imports": [
|
||||
"houseplan-assets/houseplan-card-0bp2acAx.js"
|
||||
"houseplan-assets/houseplan-card-BarpA18i.js"
|
||||
],
|
||||
"dynamicImports": []
|
||||
},
|
||||
{
|
||||
"path": "houseplan-assets/houseplan-card-0bp2acAx.js",
|
||||
"sha256": "2e4f5a4d3a78c2c89842bf3b375bada8d00efad5534fe81e1a32f03bfd43f99a",
|
||||
"rawBytes": 909954,
|
||||
"gzipBytes": 255811,
|
||||
"path": "houseplan-assets/houseplan-card-BarpA18i.js",
|
||||
"sha256": "b3276d12591e3face8174420b981e9d7626ca9ab02667982ad83943d93194ef1",
|
||||
"rawBytes": 910025,
|
||||
"gzipBytes": 255830,
|
||||
"isEntry": false,
|
||||
"imports": [],
|
||||
"dynamicImports": [
|
||||
"houseplan-assets/de-6NWhGw9L.js",
|
||||
"houseplan-assets/editor-6tQQPtIj.js",
|
||||
"houseplan-assets/houseplan-editor-runtime-B_ONl04j.js",
|
||||
"houseplan-assets/houseplan-onboarding-runtime-BiFQfFve.js"
|
||||
"houseplan-assets/de-L64iNsLu.js",
|
||||
"houseplan-assets/editor-B45l6syb.js",
|
||||
"houseplan-assets/houseplan-editor-runtime-D6vKsLjO.js",
|
||||
"houseplan-assets/houseplan-onboarding-runtime-BUDnRMK5.js"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "houseplan-assets/houseplan-editor-runtime-B_ONl04j.js",
|
||||
"sha256": "e362c070b2ae1eee9e91f346baa4ae46ad8e58a68cf49885a129abd42ce8dc2e",
|
||||
"path": "houseplan-assets/houseplan-editor-runtime-D6vKsLjO.js",
|
||||
"sha256": "8cf01ac6ca2eb3ee4f8f1191ab15eb92884ee25013356ea4e12bfffdeb0b1fd2",
|
||||
"rawBytes": 504959,
|
||||
"gzipBytes": 129706,
|
||||
"gzipBytes": 129700,
|
||||
"isEntry": false,
|
||||
"imports": [
|
||||
"houseplan-assets/houseplan-card-0bp2acAx.js",
|
||||
"houseplan-assets/space-deletion-TvTQ5fz7.js"
|
||||
"houseplan-assets/houseplan-card-BarpA18i.js",
|
||||
"houseplan-assets/space-deletion-05RPnoUh.js"
|
||||
],
|
||||
"dynamicImports": []
|
||||
},
|
||||
{
|
||||
"path": "houseplan-assets/houseplan-onboarding-runtime-BiFQfFve.js",
|
||||
"sha256": "eb6b88d822151bb3ded528ecf03a2e3b698c86fd3ca887925df57fa1f896a698",
|
||||
"path": "houseplan-assets/houseplan-onboarding-runtime-BUDnRMK5.js",
|
||||
"sha256": "2439e9cdf2c7873b737d46261a8f489c398c5434bc1fecd71a481ca80519443d",
|
||||
"rawBytes": 26356,
|
||||
"gzipBytes": 6646,
|
||||
"gzipBytes": 6644,
|
||||
"isEntry": false,
|
||||
"imports": [
|
||||
"houseplan-assets/houseplan-card-0bp2acAx.js",
|
||||
"houseplan-assets/space-deletion-TvTQ5fz7.js"
|
||||
"houseplan-assets/houseplan-card-BarpA18i.js",
|
||||
"houseplan-assets/space-deletion-05RPnoUh.js"
|
||||
],
|
||||
"dynamicImports": []
|
||||
},
|
||||
{
|
||||
"path": "houseplan-assets/space-deletion-TvTQ5fz7.js",
|
||||
"sha256": "e9573e60cc49ef932bf8b4d6ac2128c30312bf2c92f5b97ef8404edba7adbd86",
|
||||
"path": "houseplan-assets/space-deletion-05RPnoUh.js",
|
||||
"sha256": "2cf11df1b1bcd463ef90c1089b35ae89be7ce4d92370bb6a9ee3e94987a3d65f",
|
||||
"rawBytes": 911,
|
||||
"gzipBytes": 555,
|
||||
"gzipBytes": 554,
|
||||
"isEntry": false,
|
||||
"imports": [],
|
||||
"dynamicImports": []
|
||||
},
|
||||
{
|
||||
"path": "houseplan-card.js",
|
||||
"sha256": "a354023944e1da091a71a7c5cf0cc2b9d61207ec3ebef70c0afe6170aef8485e",
|
||||
"sha256": "aa89ff5b93e00716f50c19cbb8efd81900451bca43220ddf3a74d9de7bf6a57e",
|
||||
"rawBytes": 190,
|
||||
"gzipBytes": 182,
|
||||
"isEntry": true,
|
||||
"imports": [
|
||||
"houseplan-assets/houseplan-card-0bp2acAx.js"
|
||||
"houseplan-assets/houseplan-card-BarpA18i.js"
|
||||
],
|
||||
"dynamicImports": []
|
||||
}
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="96c69e4400be9bc5c58d138a95af946a3cf0486ac19b272137ade84bb9b35878";import{c as e,l as o,t,d2 as s,A as a,d3 as i,d4 as l,d5 as n,E as r,b as c}from"./houseplan-card-0bp2acAx.js";class h extends e{constructor(){super(...arguments),this._spaces=null,this._spacesLoading=!1,this._spacesAuthoritative=!1}setConfig(e){this._config=e}async _loadSpaces(){if(!this._spaces&&!this._spacesLoading&&this.hass){this._spacesLoading=!0;try{const e=await this.hass.callWS({type:"houseplan/config/get"});this._spaces=(e?.config?.spaces||[]).map(e=>({value:e.id,label:e.title||e.id})),this._spacesAuthoritative=!0}catch{this._spaces=[],this._spacesAuthoritative=!1}finally{this._spacesLoading=!1}}}get _lang(){return o(this.hass,this._config?.language)}get _floorToken(){const e=this._config?.floor;return"number"==typeof e?`__houseplan_yaml_floor_index__:${String(e)}`:null}get _formData(){const e={...this._config},o=this._floorToken;return o?e.floor=o:Object.prototype.hasOwnProperty.call(e,"floor")||(e.floor=""),e}get _schema(){const e=this._spaces||[],o=this._lang,a=[{value:"",label:t(o,"editor.floor_none")}],i=this._floorToken;i&&a.push({value:i,label:t(o,"editor.floor_index",{index:String(this._config?.floor)})});const l="string"==typeof this._config?.floor?this._config.floor:"";l&&!e.some(e=>e.value===l)&&a.push({value:l,label:l}),a.push(...e);const n="string"==typeof this._config?.default_floor?this._config.default_floor:"",r=[...e];return n&&!e.some(e=>e.value===n)&&r.unshift({value:n,label:n}),[{name:"title",selector:{text:{}}},{name:"floor",selector:{select:{mode:"dropdown",options:a}}},e.length?{name:"default_floor",selector:{select:{mode:"dropdown",options:r}}}:{name:"default_floor",selector:{text:{}}},{name:"language",selector:{select:{mode:"dropdown",options:s(t(o,"editor.lang_auto"),this._config?.language)}}},{name:"icon_size",selector:{number:{min:1,max:6,step:.1,mode:"box"}}},{name:"show_temperature",selector:{boolean:{}}},{name:"live_states",selector:{boolean:{}}},{name:"show_signal",selector:{boolean:{}}},{name:"kiosk",selector:{boolean:{}}},{name:"cycle",selector:{number:{min:0,max:3600,step:5,mode:"box"}}}]}render(){if(!this.hass||!this._config)return a;const e=i(this,l,o(this.hass,this._config.language));if("cold"===e)return n();if("warm"===e)return r;this._loadSpaces();const s=this._lang,h={title:t(s,"editor.title"),floor:t(s,"editor.floor"),default_floor:t(s,"editor.default_floor"),language:t(s,"editor.language"),icon_size:t(s,"editor.icon_size"),show_temperature:t(s,"editor.show_temperature"),live_states:t(s,"editor.live_states"),show_signal:t(s,"editor.show_signal"),kiosk:t(s,"editor.kiosk"),cycle:t(s,"editor.cycle")},f=this._schema,_=function(e,o,t){if(!t||null===o)return null;const s="string"==typeof e?.default_floor?e.default_floor:"";return!s||o.some(e=>e.value===s)?null:s}(this._config,this._spaces,this._spacesAuthoritative),d=e=>c`<ha-form
|
||||
globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="420f1f87e66a879316f23c4dd573991c8cf2bfcf5ef013191e55e4216031f3be";import{c as e,l as o,t,d2 as s,A as a,d3 as i,d4 as l,d5 as n,E as r,b as c}from"./houseplan-card-BarpA18i.js";class f extends e{constructor(){super(...arguments),this._spaces=null,this._spacesLoading=!1,this._spacesAuthoritative=!1}setConfig(e){this._config=e}async _loadSpaces(){if(!this._spaces&&!this._spacesLoading&&this.hass){this._spacesLoading=!0;try{const e=await this.hass.callWS({type:"houseplan/config/get"});this._spaces=(e?.config?.spaces||[]).map(e=>({value:e.id,label:e.title||e.id})),this._spacesAuthoritative=!0}catch{this._spaces=[],this._spacesAuthoritative=!1}finally{this._spacesLoading=!1}}}get _lang(){return o(this.hass,this._config?.language)}get _floorToken(){const e=this._config?.floor;return"number"==typeof e?`__houseplan_yaml_floor_index__:${String(e)}`:null}get _formData(){const e={...this._config},o=this._floorToken;return o?e.floor=o:Object.prototype.hasOwnProperty.call(e,"floor")||(e.floor=""),e}get _schema(){const e=this._spaces||[],o=this._lang,a=[{value:"",label:t(o,"editor.floor_none")}],i=this._floorToken;i&&a.push({value:i,label:t(o,"editor.floor_index",{index:String(this._config?.floor)})});const l="string"==typeof this._config?.floor?this._config.floor:"";l&&!e.some(e=>e.value===l)&&a.push({value:l,label:l}),a.push(...e);const n="string"==typeof this._config?.default_floor?this._config.default_floor:"",r=[...e];return n&&!e.some(e=>e.value===n)&&r.unshift({value:n,label:n}),[{name:"title",selector:{text:{}}},{name:"floor",selector:{select:{mode:"dropdown",options:a}}},e.length?{name:"default_floor",selector:{select:{mode:"dropdown",options:r}}}:{name:"default_floor",selector:{text:{}}},{name:"language",selector:{select:{mode:"dropdown",options:s(t(o,"editor.lang_auto"),this._config?.language)}}},{name:"icon_size",selector:{number:{min:1,max:6,step:.1,mode:"box"}}},{name:"show_temperature",selector:{boolean:{}}},{name:"live_states",selector:{boolean:{}}},{name:"show_signal",selector:{boolean:{}}},{name:"kiosk",selector:{boolean:{}}},{name:"cycle",selector:{number:{min:0,max:3600,step:5,mode:"box"}}}]}render(){if(!this.hass||!this._config)return a;const e=i(this,l,o(this.hass,this._config.language));if("cold"===e)return n();if("warm"===e)return r;this._loadSpaces();const s=this._lang,f={title:t(s,"editor.title"),floor:t(s,"editor.floor"),default_floor:t(s,"editor.default_floor"),language:t(s,"editor.language"),icon_size:t(s,"editor.icon_size"),show_temperature:t(s,"editor.show_temperature"),live_states:t(s,"editor.live_states"),show_signal:t(s,"editor.show_signal"),kiosk:t(s,"editor.kiosk"),cycle:t(s,"editor.cycle")},h=this._schema,_=function(e,o,t){if(!t||null===o)return null;const s="string"==typeof e?.default_floor?e.default_floor:"";return!s||o.some(e=>e.value===s)?null:s}(this._config,this._spaces,this._spacesAuthoritative),d=e=>c`<ha-form
|
||||
.hass=${this.hass}
|
||||
.data=${this._formData}
|
||||
.schema=${e}
|
||||
.computeLabel=${e=>h[e.name]||e.name}
|
||||
.computeLabel=${e=>f[e.name]||e.name}
|
||||
@value-changed=${this._valueChanged}
|
||||
></ha-form>`;return c`
|
||||
${d(f.slice(0,3))}
|
||||
${d(h.slice(0,3))}
|
||||
${_?c`<div class="default-floor-error" role="alert"
|
||||
style="color:var(--error-color,#db4437);margin:-4px 0 12px;overflow-wrap:anywhere">
|
||||
${t(s,"editor.default_floor_missing",{id:_})}
|
||||
</div>`:a}
|
||||
${d(f.slice(3))}
|
||||
`}_valueChanged(e){const o={...this._config,...e.detail.value};""===o.floor?delete o.floor:o.floor===this._floorToken&&(o.floor=this._config?.floor);const t=new Event("config-changed",{bubbles:!0,composed:!0});t.detail={config:o},this.dispatchEvent(t)}}h.properties={hass:{attribute:!1},_config:{state:!0},_spaces:{state:!0}},customElements.get("houseplan-card-editor")||customElements.define("houseplan-card-editor",h);
|
||||
${d(h.slice(3))}
|
||||
`}_valueChanged(e){const o={...this._config,...e.detail.value};""===o.floor?delete o.floor:o.floor===this._floorToken&&(o.floor=this._config?.floor);const t=new Event("config-changed",{bubbles:!0,composed:!0});t.detail={config:o},this.dispatchEvent(t)}}f.properties={hass:{attribute:!1},_config:{state:!0},_spaces:{state:!0}},customElements.get("houseplan-card-editor")||customElements.define("houseplan-card-editor",f);
|
||||
@@ -1,4 +1,4 @@
|
||||
globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="96c69e4400be9bc5c58d138a95af946a3cf0486ac19b272137ade84bb9b35878";import{bU as t,bV as s,bW as e,bX as o,aq as a,bY as l,c1 as i,bZ as h,b_ as n,b$ as c,c0 as r,b as p,A as _,cV as d,ap as u,ar as g,cW as m}from"./houseplan-card-0bp2acAx.js";import{i as b,c as $,a as v,s as y,t as f}from"./space-deletion-TvTQ5fz7.js";const w=1e3,D=t=>{if(!t.trim())return null;const s=Number(t.replace(",","."));return Number.isFinite(s)?s:null},S="96c69e4400be9bc5c58d138a95af946a3cf0486ac19b272137ade84bb9b35878";class C{constructor(t){this.host=t,this._toggleServerPlans=async()=>{const t=this.host._spaceDialog;if(t)if(t.pickSaved)this.host._spaceDialog={...t,pickSaved:!1};else{this.host._spaceDialog={...t,pickSaved:!0,savedBusy:!0};try{const t=await this.host.hass.callWS({type:"houseplan/plans/list"}),s=this.host._spaceDialog;s&&(this.host._spaceDialog={...s,saved:t?.plans||[],savedBusy:!1})}catch(t){const s=this.host._spaceDialog;s&&(this.host._spaceDialog={...s,saved:[],savedBusy:!1}),this.host._showToast(this.host._t("toast.plans_list_failed",{err:this.host._errText(t)}))}}}}_openSpaceDialog(p,_){if(!this.host._serverStorage||!this.host._serverCfg)return void this.host._showToast(this.host._t("toast.integration_missing"));if("edit"===p){const i=this.host._serverCfg.spaces.find(t=>t.id===_);if(!i)return;const h=t(i),n=i.settings?.custom_fill&&"object"==typeof i.settings.custom_fill?s(i.settings.custom_fill):null,c="none"===h.fill?{...n||e,a:0}:n;return void(this.host._spaceDialog={mode:p,spaceId:_,title:i.title,planUrl:i.plan_url||null,planFile:null,source:i.plan_url?"file":"draw",showBorders:h.showBorders,showNames:h.showNames,zeroWallStyle:l(i),displayTouched:!0,hideDecor:h.hideDecor,hideOpenings:h.hideOpenings,roomColor:h.color,roomOpacity:h.opacity,fillMode:"none"===h.fill?"custom":h.fill,customFill:c,glowEnabled:h.glow,bgColor:h.bgColor,bgMode:"static"===i.settings?.bg_mode||"daynight"===i.settings?.bg_mode?i.settings.bg_mode:null,northDeg:a({},i.settings),sunRays:"boolean"==typeof i.settings?.sun_rays?i.settings.sun_rays:null,tempMin:h.tempMin,tempMax:h.tempMax,showLqi:h.showLqi??this.host._config?.show_signal??!0,cardFontScale:h.cardFontScale,labelTemp:h.labelTemp,labelHum:h.labelHum,labelLqi:h.labelLqi,labelLight:h.labelLight,cellCm:Number(i.cell_cm)>0?Number(i.cell_cm):5,cellCmInput:o(Number(i.cell_cm)>0?Number(i.cell_cm):5,this.host._imperial),cellCmTouched:!1,busy:!1})}const d=i(this.host._imperial);this.host._spaceDialog={mode:p,title:"",planUrl:null,planFile:null,...b(),hideDecor:!1,hideOpenings:!1,zeroWallStyle:"dashed",roomColor:r,roomOpacity:c,fillMode:"custom",customFill:{...e,a:0},glowEnabled:!0,bgColor:null,bgMode:"daynight",northDeg:null,sunRays:null,tempMin:n,tempMax:h,showLqi:this.host._config?.show_signal??!0,cardFontScale:1,labelTemp:!1,labelHum:!1,labelLqi:!1,labelLight:!1,cellCm:d,cellCmInput:o(d,this.host._imperial),cellCmTouched:!1,busy:!1}}async _pickPlanFile(t){const s=t.target,e=s.files?.[0];if(!e||!this.host._spaceDialog)return;const o={"image/svg+xml":"svg","image/png":"png","image/jpeg":"jpg","image/webp":"webp"}[e.type]||(e.name.toLowerCase().endsWith(".svg")?"svg":"");if(!o)return void this.host._showToast(this.host._t("toast.plan_formats"));const a=new Uint8Array(await e.arrayBuffer());let l="";for(let t=0;t<a.length;t+=32768)l+=String.fromCharCode(...a.subarray(t,t+32768));const i=btoa(l),h=URL.createObjectURL(e),n=await new Promise(t=>{const s=new Image;s.onload=()=>t(s.naturalWidth&&s.naturalHeight?s.naturalWidth/s.naturalHeight:1.414),s.onerror=()=>t(1.414),s.src=h});URL.revokeObjectURL(h),this.host._spaceDialog={...this.host._spaceDialog,planFile:{ext:o,b64:i,aspect:n,name:e.name}}}_useServerPlan(t){const s=this.host._spaceDialog;s&&(this.host._spaceDialog={...s,planUrl:t,planFile:null,pickSaved:!1,savedAspect:void 0},this.host._aspectJob=this._readPlanAspect(t))}async _readPlanAspect(t){for(let s=0;s<40;s++){const s=this.host._display(t);if(s){const e=await new Promise(t=>{const e=new Image;e.onload=()=>t(e.naturalWidth&&e.naturalHeight?e.naturalWidth/e.naturalHeight:0),e.onerror=()=>t(0),e.src=s}),o=this.host._spaceDialog;return o&&o.planUrl===t&&Number.isFinite(e)&&e>0?(this.host._spaceDialog={...o,savedAspect:e},e):0}if(await new Promise(t=>setTimeout(t,150)),this.host._spaceDialog?.planUrl!==t)return 0}return 0}async _deleteServerPlan(t){if(confirm(this.host._t("confirm.delete_plan",{name:t})))try{await this.host.hass.callWS({type:"houseplan/plans/delete",name:t});const s=this.host._spaceDialog;s?.saved&&(this.host._spaceDialog={...s,saved:s.saved.filter(s=>s.name!==t)})}catch(t){this.host._showToast(this.host._t("toast.plan_delete_failed",{err:this.host._errText(t)}))}}_renderServerPlans(t){if(t.savedBusy)return p`<div class="savedplans muted">${this.host._t("space.loading")}</div>`;const s=t.saved||[];if(!s.length)return p`<div class="savedplans muted">${this.host._t("space.no_saved")}</div>`;return p`<div class="savedplans">
|
||||
globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="420f1f87e66a879316f23c4dd573991c8cf2bfcf5ef013191e55e4216031f3be";import{bU as t,bV as s,bW as e,bX as o,aq as a,bY as l,c1 as i,bZ as h,b_ as n,b$ as c,c0 as r,b as p,A as _,cV as d,ap as u,ar as g,cW as m}from"./houseplan-card-BarpA18i.js";import{i as b,c as $,a as v,s as f,t as y}from"./space-deletion-05RPnoUh.js";const w=1e3,D=t=>{if(!t.trim())return null;const s=Number(t.replace(",","."));return Number.isFinite(s)?s:null},S="420f1f87e66a879316f23c4dd573991c8cf2bfcf5ef013191e55e4216031f3be";class C{constructor(t){this.host=t,this._toggleServerPlans=async()=>{const t=this.host._spaceDialog;if(t)if(t.pickSaved)this.host._spaceDialog={...t,pickSaved:!1};else{this.host._spaceDialog={...t,pickSaved:!0,savedBusy:!0};try{const t=await this.host.hass.callWS({type:"houseplan/plans/list"}),s=this.host._spaceDialog;s&&(this.host._spaceDialog={...s,saved:t?.plans||[],savedBusy:!1})}catch(t){const s=this.host._spaceDialog;s&&(this.host._spaceDialog={...s,saved:[],savedBusy:!1}),this.host._showToast(this.host._t("toast.plans_list_failed",{err:this.host._errText(t)}))}}}}_openSpaceDialog(p,_){if(!this.host._serverStorage||!this.host._serverCfg)return void this.host._showToast(this.host._t("toast.integration_missing"));if("edit"===p){const i=this.host._serverCfg.spaces.find(t=>t.id===_);if(!i)return;const h=t(i),n=i.settings?.custom_fill&&"object"==typeof i.settings.custom_fill?s(i.settings.custom_fill):null,c="none"===h.fill?{...n||e,a:0}:n;return void(this.host._spaceDialog={mode:p,spaceId:_,title:i.title,planUrl:i.plan_url||null,planFile:null,source:i.plan_url?"file":"draw",showBorders:h.showBorders,showNames:h.showNames,zeroWallStyle:l(i),displayTouched:!0,hideDecor:h.hideDecor,hideOpenings:h.hideOpenings,roomColor:h.color,roomOpacity:h.opacity,fillMode:"none"===h.fill?"custom":h.fill,customFill:c,glowEnabled:h.glow,bgColor:h.bgColor,bgMode:"static"===i.settings?.bg_mode||"daynight"===i.settings?.bg_mode?i.settings.bg_mode:null,northDeg:a({},i.settings),sunRays:"boolean"==typeof i.settings?.sun_rays?i.settings.sun_rays:null,tempMin:h.tempMin,tempMax:h.tempMax,showLqi:h.showLqi??this.host._config?.show_signal??!0,cardFontScale:h.cardFontScale,labelTemp:h.labelTemp,labelHum:h.labelHum,labelLqi:h.labelLqi,labelLight:h.labelLight,cellCm:Number(i.cell_cm)>0?Number(i.cell_cm):5,cellCmInput:o(Number(i.cell_cm)>0?Number(i.cell_cm):5,this.host._imperial),cellCmTouched:!1,busy:!1})}const d=i(this.host._imperial);this.host._spaceDialog={mode:p,title:"",planUrl:null,planFile:null,...b(),hideDecor:!1,hideOpenings:!1,zeroWallStyle:"dashed",roomColor:r,roomOpacity:c,fillMode:"custom",customFill:{...e,a:0},glowEnabled:!0,bgColor:null,bgMode:"daynight",northDeg:null,sunRays:null,tempMin:n,tempMax:h,showLqi:this.host._config?.show_signal??!0,cardFontScale:1,labelTemp:!1,labelHum:!1,labelLqi:!1,labelLight:!1,cellCm:d,cellCmInput:o(d,this.host._imperial),cellCmTouched:!1,busy:!1}}async _pickPlanFile(t){const s=t.target,e=s.files?.[0];if(!e||!this.host._spaceDialog)return;const o={"image/svg+xml":"svg","image/png":"png","image/jpeg":"jpg","image/webp":"webp"}[e.type]||(e.name.toLowerCase().endsWith(".svg")?"svg":"");if(!o)return void this.host._showToast(this.host._t("toast.plan_formats"));const a=new Uint8Array(await e.arrayBuffer());let l="";for(let t=0;t<a.length;t+=32768)l+=String.fromCharCode(...a.subarray(t,t+32768));const i=btoa(l),h=URL.createObjectURL(e),n=await new Promise(t=>{const s=new Image;s.onload=()=>t(s.naturalWidth&&s.naturalHeight?s.naturalWidth/s.naturalHeight:1.414),s.onerror=()=>t(1.414),s.src=h});URL.revokeObjectURL(h),this.host._spaceDialog={...this.host._spaceDialog,planFile:{ext:o,b64:i,aspect:n,name:e.name}}}_useServerPlan(t){const s=this.host._spaceDialog;s&&(this.host._spaceDialog={...s,planUrl:t,planFile:null,pickSaved:!1,savedAspect:void 0},this.host._aspectJob=this._readPlanAspect(t))}async _readPlanAspect(t){for(let s=0;s<40;s++){const s=this.host._display(t);if(s){const e=await new Promise(t=>{const e=new Image;e.onload=()=>t(e.naturalWidth&&e.naturalHeight?e.naturalWidth/e.naturalHeight:0),e.onerror=()=>t(0),e.src=s}),o=this.host._spaceDialog;return o&&o.planUrl===t&&Number.isFinite(e)&&e>0?(this.host._spaceDialog={...o,savedAspect:e},e):0}if(await new Promise(t=>setTimeout(t,150)),this.host._spaceDialog?.planUrl!==t)return 0}return 0}async _deleteServerPlan(t){if(confirm(this.host._t("confirm.delete_plan",{name:t})))try{await this.host.hass.callWS({type:"houseplan/plans/delete",name:t});const s=this.host._spaceDialog;s?.saved&&(this.host._spaceDialog={...s,saved:s.saved.filter(s=>s.name!==t)})}catch(t){this.host._showToast(this.host._t("toast.plan_delete_failed",{err:this.host._errText(t)}))}}_renderServerPlans(t){if(t.savedBusy)return p`<div class="savedplans muted">${this.host._t("space.loading")}</div>`;const s=t.saved||[];if(!s.length)return p`<div class="savedplans muted">${this.host._t("space.no_saved")}</div>`;return p`<div class="savedplans">
|
||||
${s.map(s=>{return p`
|
||||
<div class="savedplan ${s.url===t.planUrl?"cur":""}">
|
||||
<img src=${this.host._display(s.url)} alt="" loading="lazy" decoding="async" />
|
||||
@@ -46,7 +46,7 @@ globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="96c69e4400be9bc5c58d138a95af946a3cf0
|
||||
<label>${this.host._t("space.plan_label")}</label>
|
||||
<label class="srcrow">
|
||||
<input type="radio" name="plansrc" .checked=${"file"===t.source}
|
||||
@change=${()=>this.host._spaceDialog=y(t,"file")} />
|
||||
@change=${()=>this.host._spaceDialog=f(t,"file")} />
|
||||
<span>${this.host._t("space.source_file")}</span>
|
||||
</label>
|
||||
${"file"===t.source?p`<div class="planrow">
|
||||
@@ -68,7 +68,7 @@ globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="96c69e4400be9bc5c58d138a95af946a3cf0
|
||||
${t.pickSaved?this._renderServerPlans(t):_}`:_}
|
||||
<label class="srcrow">
|
||||
<input type="radio" name="plansrc" .checked=${"draw"===t.source}
|
||||
@change=${()=>this.host._spaceDialog=y(t,"draw")} />
|
||||
@change=${()=>this.host._spaceDialog=f(t,"draw")} />
|
||||
<span>${this.host._t("space.source_draw")}</span>
|
||||
</label>
|
||||
|
||||
@@ -85,7 +85,7 @@ globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="96c69e4400be9bc5c58d138a95af946a3cf0
|
||||
|
||||
<label class="dispsection">${this.host._t("space.display_section")}</label>
|
||||
<label class="srcrow">
|
||||
${this._boolInput(t.showBorders,s=>{this.host._spaceDialog=f(t,"showBorders",s)})}
|
||||
${this._boolInput(t.showBorders,s=>{this.host._spaceDialog=y(t,"showBorders",s)})}
|
||||
<span>${this.host._t("space.show_borders")}</span>
|
||||
</label>
|
||||
<label>${this.host._t("space.zero_wall_style")}</label>
|
||||
@@ -99,7 +99,7 @@ globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="96c69e4400be9bc5c58d138a95af946a3cf0
|
||||
</select>
|
||||
<div class="rhint">${this.host._t("space.zero_wall_help")}</div>
|
||||
<label class="srcrow">
|
||||
${this._boolInput(t.showNames,s=>{this.host._spaceDialog=f(t,"showNames",s)})}
|
||||
${this._boolInput(t.showNames,s=>{this.host._spaceDialog=y(t,"showNames",s)})}
|
||||
<span>${this.host._t("space.show_names")}</span>
|
||||
</label>
|
||||
<label class="srcrow">
|
||||
@@ -1 +1 @@
|
||||
function e(e,o){return{id:e,title:o,plan_url:null,view_box:[0,0,1,1],rooms:[],wall_segments:[]}}function o(e="file"){const o="draw"===e;return{source:e,showBorders:o,showNames:o,displayTouched:!1}}function r(e,o){if(e.displayTouched)return{...e,source:o};const r="draw"===o;return{...e,source:o,showBorders:r,showNames:r}}function s(e,o,r){return{...e,[o]:r,displayTouched:!0}}function t(e,o,r){const s=(e?.spaces||[]).find(e=>e?.id===r),t=new Set((s?.rooms||[]).map(e=>String(e?.id||"")).filter(Boolean)),a=[...new Set((e?.markers||[]).filter(e=>!0!==e?.removed&&"string"==typeof e?.id).filter(e=>e.space===r||"string"==typeof e.room_id&&t.has(e.room_id)||o?.[e.id]?.s===r).map(e=>e.id))].sort((e,o)=>e.localeCompare(o));return{markerIds:a,count:a.length}}globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="96c69e4400be9bc5c58d138a95af946a3cf0486ac19b272137ade84bb9b35878";export{t as a,e as c,o as i,r as s,s as t};
|
||||
function e(e,o){return{id:e,title:o,plan_url:null,view_box:[0,0,1,1],rooms:[],wall_segments:[]}}function o(e="file"){const o="draw"===e;return{source:e,showBorders:o,showNames:o,displayTouched:!1}}function r(e,o){if(e.displayTouched)return{...e,source:o};const r="draw"===o;return{...e,source:o,showBorders:r,showNames:r}}function s(e,o,r){return{...e,[o]:r,displayTouched:!0}}function t(e,o,r){const s=(e?.spaces||[]).find(e=>e?.id===r),t=new Set((s?.rooms||[]).map(e=>String(e?.id||"")).filter(Boolean)),n=[...new Set((e?.markers||[]).filter(e=>!0!==e?.removed&&"string"==typeof e?.id).filter(e=>e.space===r||"string"==typeof e.room_id&&t.has(e.room_id)||o?.[e.id]?.s===r).map(e=>e.id))].sort((e,o)=>e.localeCompare(o));return{markerIds:n,count:n.length}}globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="420f1f87e66a879316f23c4dd573991c8cf2bfcf5ef013191e55e4216031f3be";export{t as a,e as c,o as i,r as s,s as t};
|
||||
@@ -1 +1 @@
|
||||
globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="96c69e4400be9bc5c58d138a95af946a3cf0486ac19b272137ade84bb9b35878";export{d6 as HouseplanCard}from"./houseplan-assets/houseplan-card-0bp2acAx.js";
|
||||
globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="420f1f87e66a879316f23c4dd573991c8cf2bfcf5ef013191e55e4216031f3be";export{d6 as HouseplanCard}from"./houseplan-assets/houseplan-card-BarpA18i.js";
|
||||
|
||||
@@ -2,6 +2,11 @@
|
||||
|
||||
## Unreleased
|
||||
|
||||
- A very acute apex between walls of different thickness (say 15 and 30 cm)
|
||||
on legacy plans renders as an honest tip again instead of the "trident":
|
||||
the inner-face convergence accounts for both thicknesses, not just the
|
||||
larger one ([#339](https://github.com/Matysh/houseplan-card/issues/339)).
|
||||
|
||||
## v1.69.0-beta.1 — 2026-08-28
|
||||
|
||||
- House Plan now has a complete German interface. `Deutsch` can be selected
|
||||
|
||||
@@ -8,6 +8,11 @@
|
||||
|
||||
## Не выпущено
|
||||
|
||||
- Очень острая вершина между стенами разной толщины (например, 15 и 30 см)
|
||||
на старых планах снова рисуется честным остриём, а не «трезубцем»: расчёт
|
||||
смыкания внутренних граней учитывает обе толщины, а не одну наибольшую
|
||||
([#339](https://github.com/Matysh/houseplan-card/issues/339)).
|
||||
|
||||
## v1.69.0-beta.1 — 2026-08-28
|
||||
|
||||
- В House Plan появилась полная немецкая локализация. `Deutsch` можно выбрать
|
||||
|
||||
|
Before Width: | Height: | Size: 164 KiB After Width: | Height: | Size: 198 KiB |
|
Before Width: | Height: | Size: 51 KiB After Width: | Height: | Size: 62 KiB |
|
Before Width: | Height: | Size: 42 KiB After Width: | Height: | Size: 54 KiB |
|
Before Width: | Height: | Size: 288 KiB After Width: | Height: | Size: 343 KiB |
|
Before Width: | Height: | Size: 277 KiB After Width: | Height: | Size: 334 KiB |
|
Before Width: | Height: | Size: 246 KiB After Width: | Height: | Size: 319 KiB |
|
Before Width: | Height: | Size: 244 KiB After Width: | Height: | Size: 317 KiB |
|
Before Width: | Height: | Size: 242 KiB After Width: | Height: | Size: 296 KiB |
|
Before Width: | Height: | Size: 27 KiB After Width: | Height: | Size: 32 KiB |
|
Before Width: | Height: | Size: 116 KiB After Width: | Height: | Size: 141 KiB |
@@ -2,8 +2,8 @@
|
||||
"version": 1,
|
||||
"fixture": "synthetic-only",
|
||||
"chromium": "151.0.7922.34",
|
||||
"oxipng": "oxipng 10.2.0",
|
||||
"sourceFingerprint": "be9676025788af910419abcb7cd2896e99eb69619e5944639312c55661266c60",
|
||||
"oxipng": null,
|
||||
"sourceFingerprint": "2db152f8ea0fb3fcd5eb248c894a5c85aab3f7f08d755ace7c2124da1abf6ed3",
|
||||
"captureScriptSha256": "fe76c8e2e27501e9a377d7aa15dd6cba6a018d55c07deb602dbee097f0a0a5ba",
|
||||
"command": "npm run build && node demo/docs/capture.mjs",
|
||||
"scenarios": {
|
||||
@@ -15,8 +15,8 @@
|
||||
},
|
||||
"theme": "dark",
|
||||
"language": "en",
|
||||
"sourceSha256": "be9676025788af910419abcb7cd2896e99eb69619e5944639312c55661266c60",
|
||||
"imageSha256": "f8c9541c9d7fde462d0efba63dff70944dc03df76ce988eecaf2b269e2863a96"
|
||||
"sourceSha256": "2db152f8ea0fb3fcd5eb248c894a5c85aab3f7f08d755ace7c2124da1abf6ed3",
|
||||
"imageSha256": "0ca982495a7749907c48ebbddfd089c54385a4347f79f64e94af2c5a8d5c03eb"
|
||||
},
|
||||
"view-touch": {
|
||||
"file": "02-view-touch.png",
|
||||
@@ -26,8 +26,8 @@
|
||||
},
|
||||
"theme": "dark",
|
||||
"language": "en",
|
||||
"sourceSha256": "be9676025788af910419abcb7cd2896e99eb69619e5944639312c55661266c60",
|
||||
"imageSha256": "21c6fe7d79ff5c878ade8e98a64cc90dfd7bcc66338c864fb5a0bd411471313d"
|
||||
"sourceSha256": "2db152f8ea0fb3fcd5eb248c894a5c85aab3f7f08d755ace7c2124da1abf6ed3",
|
||||
"imageSha256": "3be239a5a494f6776540a9c0049694ee6f9d2ba927c8bcb4b26ee5a69a228a7d"
|
||||
},
|
||||
"space-create": {
|
||||
"file": "03-space-create.png",
|
||||
@@ -37,8 +37,8 @@
|
||||
},
|
||||
"theme": "dark",
|
||||
"language": "en",
|
||||
"sourceSha256": "be9676025788af910419abcb7cd2896e99eb69619e5944639312c55661266c60",
|
||||
"imageSha256": "f6d190f0b2ac9125cea68aea2ebbcdf9a7081ae2a3565ff253fb1ed0c4a56483"
|
||||
"sourceSha256": "2db152f8ea0fb3fcd5eb248c894a5c85aab3f7f08d755ace7c2124da1abf6ed3",
|
||||
"imageSha256": "a55b463055a565892ca139014e314a8f63fb5301c87fff2e48d7e69210fe9b6c"
|
||||
},
|
||||
"room-contour-close": {
|
||||
"file": "04-room-contour-close.png",
|
||||
@@ -48,8 +48,8 @@
|
||||
},
|
||||
"theme": "dark",
|
||||
"language": "en",
|
||||
"sourceSha256": "be9676025788af910419abcb7cd2896e99eb69619e5944639312c55661266c60",
|
||||
"imageSha256": "ca8bb143d0d6679ff09f8e9c1f5ad68b2ca7cfd96a4740a4a650c251f55dfba5"
|
||||
"sourceSha256": "2db152f8ea0fb3fcd5eb248c894a5c85aab3f7f08d755ace7c2124da1abf6ed3",
|
||||
"imageSha256": "dfad9a27371cfa397a3fd8dce7005f42d24649743f5322105ee894067d3a9f16"
|
||||
},
|
||||
"plan-context-tray": {
|
||||
"file": "05-plan-context-tray.png",
|
||||
@@ -59,8 +59,8 @@
|
||||
},
|
||||
"theme": "dark",
|
||||
"language": "en",
|
||||
"sourceSha256": "be9676025788af910419abcb7cd2896e99eb69619e5944639312c55661266c60",
|
||||
"imageSha256": "06b67c5108f9ee29a226cc2920484ccffe0c79840aec09721072b25b91ef8f03"
|
||||
"sourceSha256": "2db152f8ea0fb3fcd5eb248c894a5c85aab3f7f08d755ace7c2124da1abf6ed3",
|
||||
"imageSha256": "b75f348c632296da5c2fc142d53df613f757e1516acac315be50f5b4557729cc"
|
||||
},
|
||||
"device-editor": {
|
||||
"file": "06-device-editor.png",
|
||||
@@ -70,8 +70,8 @@
|
||||
},
|
||||
"theme": "dark",
|
||||
"language": "en",
|
||||
"sourceSha256": "be9676025788af910419abcb7cd2896e99eb69619e5944639312c55661266c60",
|
||||
"imageSha256": "c2f629ef6592cd34420fe2711326a6cfffe386b3018242f9bb2aee3dbf01826b"
|
||||
"sourceSha256": "2db152f8ea0fb3fcd5eb248c894a5c85aab3f7f08d755ace7c2124da1abf6ed3",
|
||||
"imageSha256": "8affadfce926fe2f6cf344c33f611c44fcbc79c1969f69c3a6935ff2e99c36c3"
|
||||
},
|
||||
"device-display-preview": {
|
||||
"file": "06-device-display-preview.png",
|
||||
@@ -81,8 +81,8 @@
|
||||
},
|
||||
"theme": "dark",
|
||||
"language": "en",
|
||||
"sourceSha256": "be9676025788af910419abcb7cd2896e99eb69619e5944639312c55661266c60",
|
||||
"imageSha256": "cc5abe1b3364bf9812bea6ea5cfa84f35120ff9639ed3c4c92958cb646a8caf7"
|
||||
"sourceSha256": "2db152f8ea0fb3fcd5eb248c894a5c85aab3f7f08d755ace7c2124da1abf6ed3",
|
||||
"imageSha256": "6f628abe6b89d7c4b352e6d73ac0b126526f6fdba5927bb774c5b884e484ca19"
|
||||
},
|
||||
"background-editor": {
|
||||
"file": "07-background-editor.png",
|
||||
@@ -92,8 +92,8 @@
|
||||
},
|
||||
"theme": "dark",
|
||||
"language": "en",
|
||||
"sourceSha256": "be9676025788af910419abcb7cd2896e99eb69619e5944639312c55661266c60",
|
||||
"imageSha256": "7e308a2b105fa6a9f788449ca30b8183375a32f0d0f8726f4a131e4f35527f57"
|
||||
"sourceSha256": "2db152f8ea0fb3fcd5eb248c894a5c85aab3f7f08d755ace7c2124da1abf6ed3",
|
||||
"imageSha256": "a1d1a905f1410f73231d2ea5d1dfbd8ae79c2fe8b0a79cff87ebb977ac7a3103"
|
||||
},
|
||||
"room-card": {
|
||||
"file": "08-room-card.png",
|
||||
@@ -103,8 +103,8 @@
|
||||
},
|
||||
"theme": "dark",
|
||||
"language": "en",
|
||||
"sourceSha256": "be9676025788af910419abcb7cd2896e99eb69619e5944639312c55661266c60",
|
||||
"imageSha256": "f1bc10b478f7afc68e70cb4c37148f680b0bbd41d50a7d63a21067fc952ff134"
|
||||
"sourceSha256": "2db152f8ea0fb3fcd5eb248c894a5c85aab3f7f08d755ace7c2124da1abf6ed3",
|
||||
"imageSha256": "48a5685039a5e0de2a28190d857b193c86e2e63606e3c7a8c40fc9d2b190da4e"
|
||||
},
|
||||
"device-info": {
|
||||
"file": "09-device-info.png",
|
||||
@@ -114,8 +114,8 @@
|
||||
},
|
||||
"theme": "dark",
|
||||
"language": "en",
|
||||
"sourceSha256": "be9676025788af910419abcb7cd2896e99eb69619e5944639312c55661266c60",
|
||||
"imageSha256": "2634cd7ead5720ce46ea4d6fa8f31006b740c520a73ddc97afe9a6d9d3b49778"
|
||||
"sourceSha256": "2db152f8ea0fb3fcd5eb248c894a5c85aab3f7f08d755ace7c2124da1abf6ed3",
|
||||
"imageSha256": "29a342811aaedaebc54ba337792d60cb454a7cf4c3063b210f6c4bafe0a4d87b"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,170 @@
|
||||
# Код-ревью issue #339 — заход r1
|
||||
|
||||
Вердикт: зелёный · заход r1 · блокирующих циклов 0/2 · High: 0 · Medium: 0
|
||||
|
||||
## Скоуп
|
||||
|
||||
Одна поверхность: `isDegenerateApexCorner` (`src/wall-thickness.ts`), функция,
|
||||
классифицирующая острый (<15°) угол легаси-плана как вырожденный для целей
|
||||
рендера контура стены (`outsetContour`/`insetContour`). Путь записи не тронут
|
||||
(П1 из #329 запрещает создавать такие углы заново — правка чисто
|
||||
рендер-легаси). Коммит `66bd3d69`, HEAD совпадает с веткой
|
||||
`issue/339-mixed-thickness-apex`, один коммит поверх актуального `origin/dev`
|
||||
(dev — предок HEAD, дерево чистое).
|
||||
|
||||
Диапазон изменённых файлов по существу: `src/wall-thickness.ts` (24 строки),
|
||||
`test/junction-limits.test.mjs` (+29 строк, только добавление). Остальное в
|
||||
диффе — синхронизированный бандл (`dist/`, `custom_components/.../frontend`),
|
||||
пересъём скриншотов и CHANGELOG (en+ru) — сопутствующие, не код.
|
||||
|
||||
Трек — `trivial` (§5.1 PROCESS.md): тип bug, одна поверхность, без миграций/
|
||||
i18n/перфа/touch, ожидаемое поведение зафиксировано (§4 спеки #329 +
|
||||
собственный анализ автора в S2 с точной геометрической выкладкой). Соответствие
|
||||
критериям — под вопросом не было, поэтому не проверяю отдельно: сам S2-анализ
|
||||
содержит доказательство (таблица смыканий), которое я перепроверил численно.
|
||||
|
||||
## Что закрывает задачу продуктово
|
||||
|
||||
`docs/SCOPE.md` J6 — «Keep the plan true as the home evolves»: честный рендер
|
||||
геометрии для существующих (легаси) планов — это условие доверия к карточке.
|
||||
Баг — визуальный дефект унаследованного плана, не новая функциональность;
|
||||
подходящая строка ровно эта.
|
||||
|
||||
## Как проверялось
|
||||
|
||||
**Математика.** Формула в PR: `alongPrev = (halfNext + halfPrev·cosθ)/sinθ`,
|
||||
`alongNext = (halfPrev + halfNext·cosθ)/sinθ`, вырожденность — обе величины
|
||||
внутри своих рёбер. Перепроверил численно для кейса из S2-анализа (10°, 15+30
|
||||
см на рёбрах по 160 см):
|
||||
|
||||
```
|
||||
along(edge h=7.5) = 128.916 см
|
||||
along(edge h=15) = 128.260 см
|
||||
```
|
||||
|
||||
Совпадает с таблицей автора (128.3/128.9 см < 160 см) с точностью до
|
||||
округления. Тождество со старой формулой `h/tan(θ/2)` при `h1=h2=h`
|
||||
проверил алгебраически: `(1+cosθ)/sinθ = cot(θ/2)` — верно, регресс
|
||||
равнотолщинных углов исключён по построению, а не только по утверждению.
|
||||
|
||||
**Тест умеет падать.** Временно вернул старую версию `src/wall-thickness.ts`
|
||||
(`git show origin/dev:...`), пересобрал `test-build`, прогнал новый тест
|
||||
`#339` — упал ожидаемо (`false !== true`, "смешанные толщины [prev=0.0125,
|
||||
next=0.00625] обязаны быть вырождены"). Восстановил рабочее дерево, тест
|
||||
снова зелёный, `git status` чист.
|
||||
|
||||
**Гейты, прогнанные мной лично на `66bd3d69`:**
|
||||
|
||||
| Гейт | Результат |
|
||||
|---|---|
|
||||
| `npx tsc --noEmit` | чисто, без вывода |
|
||||
| `npm test` | 1461/1461 pass, 1 skipped, 0 fail |
|
||||
| `npm run build` + сверка 3 копий бандла | сборка ок; `diff dist/houseplan-card.js custom_components/.../houseplan-card.js` — идентичны; `diff dist/houseplan-assets.json ...` — идентичны; после `npm run build` `git status` чист (рабочее дерево уже содержало актуальный синхронизированный бандл) |
|
||||
| `node scripts/check-docs.mjs` (diff трогает `src/**`) | "Documentation checks passed (7 files, 10 external links)" |
|
||||
| `npm run golden:verify` (диф меняет геометрию рендера) | полный прогон, все сцены `passed`, 0 `failed`, exit code 0; включая `sharp-apex-legacy-dark` (равнотолщинная контрольная сцена #329 — подтверждает отсутствие регресса) |
|
||||
| Мутационная проверка нового юнита | тест падает на дооткатной версии функции, зелёный на текущей — не тавтология |
|
||||
|
||||
Порядок был непустой: `demo/srv/assets` в репозитории не хранится, и первый
|
||||
прогон `golden:verify` упал таймаутом на `Failed to fetch dynamically
|
||||
imported module` — потребовался `npm run bundle:sync`, чтобы наполнить
|
||||
рабочую копию стенда. Это состояние окружения ревью, не находка о ветке.
|
||||
|
||||
**Инварианты модели (`npm run invariants -- --config ...`) — не прогонял.**
|
||||
Обоснование: изменённая функция работает исключительно внутри
|
||||
`outsetContour`/`insetContour` — строит точки контура для рендера, не
|
||||
трогает ключи рёбер (`keyOf`), записи толщины или `WallBodyPath.key`/`cm`
|
||||
(они вычисляются отдельно, до вызова `isDegenerateApexCorner`, и не зависят
|
||||
от неё). Три вопроса, на которые отвечают инварианты — исчезновение записи
|
||||
толщины, разрешимость ссылок, совпадение ключа записи с ключом решёточного
|
||||
ребра — не про эту функцию: она ничего не пишет и не адресует по ключу,
|
||||
только решает геометрическую развилку рендера. `npm test` уже прогоняет
|
||||
инварианты на всех моделях проекта и прошёл (см. выше).
|
||||
|
||||
**Смоки `demo/smoke_*.mjs` — не прогонял ни одного вручную.**
|
||||
`node scripts/smoke-select.mjs --base origin/dev --head HEAD` вернул
|
||||
НЕОПРЕДЕЛЁННОСТЬ (0 связанных символов, порог широкого символа — 39). Решение
|
||||
за мной: полный `golden:verify` уже пиксельно проверяет рендер стен по всей
|
||||
матрице (включая профильную сцену `sharp-apex-legacy-dark` и десяток
|
||||
`junction-*`/`opening-*`/`wall-*` сцен с разными толщинами и углами) — это
|
||||
более сильная и более прямая проверка именно этой функции, чем интерактивные
|
||||
браузерные смоки (`real_plan_masonry`, `resize_pointer_real_plan`,
|
||||
`plan_drawing_repairs`, `junction_limits`), которые автор прогнал вручную и
|
||||
на которые я не полагаюсь без независимого доказательства. К тому же
|
||||
интерактивные смоки идут через путь записи, а он не может создать угол <15°
|
||||
(П1 из #329) — значит, воспроизвести именно легаси-конфигурацию 15+30 см
|
||||
через них нельзя в принципе, они бы проверяли не тот код. Юнит-тест
|
||||
считает точную геометрию напрямую, golden проверяет пиксели напрямую — этого
|
||||
достаточно для узкой чистой функции.
|
||||
|
||||
**`npm run golden:capture`/`accept`, `python -m pytest tests_backend`,
|
||||
performance-профили** — не прогонял: diff не трогает `custom_components/**/
|
||||
*.py`, AC не называют перф, `golden:verify` (без `capture`) — правильный режим
|
||||
для проверки отсутствия регрессии, а не пересъёма эталонов.
|
||||
|
||||
**«Одно число — один источник»** — не применимо: диф не добавляет и не
|
||||
меняет ни одной видимой пользователю величины (не показывает толщину,
|
||||
площадь, длину и т.п. — это решение внутренней геометрии контура). Новый
|
||||
`test/single-source-numbers.test.mjs` не задет и не должен быть.
|
||||
|
||||
## Проверка AC (из S2-анализа, зафиксированного в S5-ready)
|
||||
|
||||
- **AC1** — угол 10°, смежные рёбра 15+30 см в оба порядка обхода: вырождена.
|
||||
Доказано юнитом `#339: вершина 10° со смежными рёбрами 15+30 см вырождена в
|
||||
оба обхода` — оба порядка (`[7.5,7.5,15]` и `[15,7.5,7.5]`) дают `true`;
|
||||
плюс рендер-проверка: `outsetContour` даёт ровно одну точку внешнего
|
||||
контура у вершины плана (острие в `(0,0)` с точностью 1e-9). **Выполнено.**
|
||||
- **AC2** — равные толщины и обычные углы: вердикты байт-прежние, существующие
|
||||
§4-юниты и golden `sharp-apex-legacy-dark` зелёные без правок. Тестовый файл
|
||||
не содержит правок существующих кейсов (только добавление в конец), все
|
||||
1461 юнит зелёные, `sharp-apex-legacy-dark` — `passed` в полном
|
||||
`golden:verify`. Алгебраическое тождество `(1+cosθ)/sinθ = cot(θ/2)`
|
||||
подтверждает, что для `halfPrev = halfNext` формулы `alongPrev`/`alongNext`
|
||||
сводятся к старой `half/tan(θ/2)` без приближений. **Выполнено.**
|
||||
- **AC3** — 30° со смешанными толщинами не вырождена (пара #310), нулевая
|
||||
толщина не вырождена. Оба случая — отдельные `assert.equal(..., false)` в
|
||||
том же юните. **Выполнено.**
|
||||
|
||||
## Трейлеры и changelog
|
||||
|
||||
`Issue: #339`, `User-Visible: yes` — оба присутствуют в теле коммита
|
||||
`66bd3d69`. При `User-Visible: yes` правки обязаны быть в обоих changelog в
|
||||
том же коммите — проверено: `docs/CHANGELOG.md` и `docs/CHANGELOG.ru.md`
|
||||
получили симметричные записи в разделе `## Unreleased` в этом же коммите.
|
||||
`docs/USER-GUIDE.ru.md` не тронут и не должен быть — новой терминологии
|
||||
интерфейса задача не вводит (внутренняя геометрия рендера, не новый
|
||||
UX-контракт), критерию `trivial`-трека это не противоречит.
|
||||
|
||||
## Что проверено и корректно
|
||||
|
||||
- Формула замены математически верна и алгебраически регресс-безопасна
|
||||
(равные толщины ⇒ старая формула тождественно).
|
||||
- Новый тест не тавтологичен: падает на предыдущей версии функции, проходит
|
||||
на текущей — проверено мутацией, а не по одному прочтению кода.
|
||||
- Полный прогон golden (все сцены каталога `demo/golden/matrix.mjs`) зелёный,
|
||||
включая контрольную сцену именно для этого класса дефекта.
|
||||
- Бандл синхронизирован побайтово между `dist` и обеими копиями,
|
||||
`check-docs` зелёный несмотря на пересъём 9 скриншотов (фингерпринт по
|
||||
`src/**` учтён и принят).
|
||||
- Путь записи не затронут — П1 (#329) остаётся в силе, новых углов <15° по
|
||||
прежнему нельзя создать; правка не расширяет и не сужает контракт записи.
|
||||
|
||||
## Чего не проверял
|
||||
|
||||
- `npm run invariants -- --config <...>` на конкретной конфигурации — не
|
||||
нашёл предмета: функция не адресует по ключу и не пишет записи толщины
|
||||
(см. обоснование выше). Общие инварианты по всем моделям прогнаны через
|
||||
`npm test`.
|
||||
- Интерактивные браузерные смоки (`real_plan_masonry`,
|
||||
`resize_pointer_real_plan`, `plan_drawing_repairs`, `junction_limits`) —
|
||||
не прогонял сам; полагаюсь на `golden:verify` (пиксельно строже) и на то,
|
||||
что путь записи, который эти смоки в основном упражняют, не может
|
||||
воспроизвести исследуемый легаси-кейс.
|
||||
- `golden:capture`/`golden:accept`, `pytest tests_backend`, perf-профили —
|
||||
вне скоупа диффа, не прогонял намеренно (см. обоснование выше).
|
||||
- Ручного тестирования в браузере не было — как и предписано для стадии code
|
||||
для этого цикла: доказательство — автотест плюс чтение кода, оба выполнены.
|
||||
|
||||
## Находки
|
||||
|
||||
Нет. High: 0, Medium: 0. Зелёный вердикт, возврата автору не требуется,
|
||||
issue вне скоупа не заводится.
|
||||
@@ -3631,13 +3631,23 @@ export function isDegenerateApexCorner(
|
||||
const theta = Math.acos(cos);
|
||||
if (!(theta > 1e-9)) return false;
|
||||
if (theta >= (DEGENERATE_APEX_MAX_DEGREES * Math.PI) / 180) return false;
|
||||
const half = Math.max(
|
||||
Math.max(0, offsets[(index - 1 + n) % n]), Math.max(0, offsets[index]),
|
||||
);
|
||||
if (!(half > 0)) return false;
|
||||
const distance = half / Math.tan(theta / 2);
|
||||
return Number.isFinite(distance) && distance > 0
|
||||
&& distance < lenPrev - 1e-9 && distance < lenNext - 1e-9;
|
||||
const halfPrev = Math.max(0, offsets[(index - 1 + n) % n]);
|
||||
const halfNext = Math.max(0, offsets[index]);
|
||||
if (!(halfPrev > 0) && !(halfNext > 0)) return false;
|
||||
// #339: the inner faces sit halfPrev and halfNext away from their own
|
||||
// edges; the true meeting point of two such lines lands at
|
||||
// (hOther + hOwn·cosθ)/sinθ along each edge. The corner is degenerate only
|
||||
// when the meeting point lies INSIDE both edges. With equal halves this
|
||||
// reduces algebraically to the old h/tan(θ/2) — which, taken as
|
||||
// max(h₁,h₂)/tan(θ/2) for mixed thicknesses, overstated the distance and
|
||||
// left a 15+30 cm legacy apex rendering as the #329 trident.
|
||||
const sin = Math.sin(theta);
|
||||
if (!(sin > 1e-12)) return false;
|
||||
const alongPrev = (halfNext + halfPrev * cos) / sin;
|
||||
const alongNext = (halfPrev + halfNext * cos) / sin;
|
||||
return Number.isFinite(alongPrev) && Number.isFinite(alongNext)
|
||||
&& alongPrev > 0 && alongNext > 0
|
||||
&& alongPrev < lenPrev - 1e-9 && alongNext < lenNext - 1e-9;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -578,3 +578,32 @@ test('#331 AC1: квантование .5-тика одинаково в обо
|
||||
assert.ok(checkNodes(rays).some((item) => item.rule === 'valence'),
|
||||
'2.5e-7 квантуется вверх и сливается с 3e-7 — семь лучей в одном узле');
|
||||
});
|
||||
|
||||
// --- #339: смешанные толщины у вырожденной вершины ---
|
||||
|
||||
test('#339: вершина 10° со смежными рёбрами 15+30 см вырождена в оба обхода', async () => {
|
||||
const { isDegenerateApexCorner, outsetContour } =
|
||||
await import('../test-build/wall-thickness.js');
|
||||
const th = (10 * Math.PI) / 180;
|
||||
const reach = cm(160);
|
||||
const tri = [[0, 0], [reach, 0], [reach * Math.cos(th), reach * Math.sin(th)]];
|
||||
// AC1: оба порядка толщин на смежных рёбрах вершины 0 — вырождена.
|
||||
for (const offsets of [[cm(7.5), cm(7.5), cm(15)], [cm(15), cm(7.5), cm(7.5)]]) {
|
||||
// offsets[2] и offsets[0] — рёбра, смежные с вершиной 0.
|
||||
assert.equal(isDegenerateApexCorner(tri, offsets, 0), true,
|
||||
`смешанные толщины [prev=${offsets[2]}, next=${offsets[0]}] обязаны быть вырождены`);
|
||||
}
|
||||
// Рендер: внешний контур несёт РОВНО одну точку у вершины — остриё в
|
||||
// вершине плана, как в §4 #329 для равных толщин.
|
||||
const offsets = [cm(15), cm(7.5), cm(7.5)];
|
||||
const outset = outsetContour(tri, offsets, null);
|
||||
assert.ok(outset, 'контур строится');
|
||||
const near = outset.filter((p) => Math.hypot(p[0], p[1]) < cm(30));
|
||||
assert.equal(near.length, 1, 'у вершины ровно одна точка внешнего контура');
|
||||
assert.ok(Math.hypot(near[0][0], near[0][1]) < 1e-9, 'остриё в вершине плана');
|
||||
// AC3: 30° со смешанными — обычная пара #310; худая геометрия — false.
|
||||
const th30 = (30 * Math.PI) / 180;
|
||||
const tri30 = [[0, 0], [reach, 0], [reach * Math.cos(th30), reach * Math.sin(th30)]];
|
||||
assert.equal(isDegenerateApexCorner(tri30, offsets, 0), false);
|
||||
assert.equal(isDegenerateApexCorner(tri, [0, 0, 0], 0), false, 'нулевые толщины — нет тел');
|
||||
});
|
||||
|
||||