Шапка на телефоне: одна строка — вкладки, масштаб и шестерёнка с меню остального (#616)

На окне не шире 480 px шапка карточки и страницы бокового меню занимает одну
строку ≤ 56 px: вкладки пространств (без шестерёнок и «+», прокрутка вбок,
текущая вкладка докручивается в видимую область), масштаб, одна шестерёнка
«Действия и настройки» и у админа слот крестика #647. Заголовок скрыт.

Меню шестерёнки (src/header-menu.ts): редакторы, настройки и добавление
пространства, общие настройки, PDF, помощь, сводная панель и объёмный вид
(alpha) — в фиксированном порядке и с теми же условиями и действиями, что у
прежних кнопок. Пункт закрывает меню; Escape возвращает фокус на шестерёнку;
касание вне меню поглощается прозрачной подложкой. На > 480 px шапка прежняя,
в киоске меню нет.

- три кнопки шапки вынесены в renderHeaderActions — шапка карточки не растёт;
- сводная панель отдаёт свои пункты методом menuItems();
- i18n: title.header_menu (en/ru/de/fr);
- потолок initial View 291 000 → 292 600 (замер 291 635), база bundleBytes;
- смок smoke_mobile_view_header, юнит header-menu, 10 мутантов; смоки
  support_feedback, gear_tabs, modes, toolbar_stable_width переведены на
  меню на ≤ 480 px; подпись вкладки в span.tabtitle без pointer-events;
- USER-GUIDE.ru, UX-MODES, TOUCH-SUPPORT, STYLING-HOOKS, data-hp-contract,
  оба changelog.

Issue: #616
User-Visible: yes
This commit is contained in:
Claude
2026-09-25 14:22:36 +03:00
parent dc6018ed5a
commit 255330b9bc
97 changed files with 1640 additions and 742 deletions
@@ -1,436 +1,436 @@
{
"schema": 1,
"fingerprint": "24813ef5e0b24d0f550c9e330f8ef7806dfb0724a8f69bd5e14e312c73438264",
"fingerprint": "1d6151ba58a0ce1dc15ed85a133606dca280b90dea173557fa34ac9531c10ffb",
"entry": "houseplan-card.js",
"panelEntry": "houseplan-panel.js",
"initialViewFiles": [
"houseplan-assets/houseplan-card-B4joz-YO.js",
"houseplan-assets/houseplan-card-C_DbrDoi.js",
"houseplan-card.js"
],
"initialViewGzipBytes": 290052,
"initialViewGzipBytes": 291626,
"initialPanelFiles": [
"houseplan-assets/houseplan-card-B4joz-YO.js",
"houseplan-assets/houseplan-card-C_DbrDoi.js",
"houseplan-panel.js"
],
"initialPanelGzipBytes": 291574,
"initialPanelGzipBytes": 293148,
"initialPanelOnlyFiles": [
"houseplan-panel.js"
],
"initialPanelOnlyGzipBytes": 2327,
"initialPanelOnlyGzipBytes": 2322,
"lazyFiles": [
"houseplan-assets/backdrop-pick-D4aD5usf.js",
"houseplan-assets/de-CSQe6eub.js",
"houseplan-assets/editor-8h7C9dFV.js",
"houseplan-assets/form-kit.styles-Cqg1K3-F.js",
"houseplan-assets/fr-Dh71LzVb.js",
"houseplan-assets/furniture-plan-art.generated-CdVUTs9f.js",
"houseplan-assets/houseplan-editor-runtime-u-EF5jme.js",
"houseplan-assets/houseplan-onboarding-runtime-CvUernez.js",
"houseplan-assets/hp-zigbee-topology-overlay-BS2sDfiR.js",
"houseplan-assets/iso-scene-render-DeEYFVoG.js",
"houseplan-assets/live-interaction-runtime-C9YY0yeQ.js",
"houseplan-assets/namespace-language-BYcyqH-y.js",
"houseplan-assets/pdf-export-CCnDAi0D.js",
"houseplan-assets/summary-panel-runtime-loaded-DEMxCIRi.js",
"houseplan-assets/zigbee-topology-CcCg6XRV.js",
"houseplan-assets/zigbee-topology-runtime-DokImShf.js"
"houseplan-assets/backdrop-pick-Bz7hJpF4.js",
"houseplan-assets/de-VB-iDL1g.js",
"houseplan-assets/editor-DQBHGNp6.js",
"houseplan-assets/form-kit.styles-DM0qkJ72.js",
"houseplan-assets/fr-BfiF5RLs.js",
"houseplan-assets/furniture-plan-art.generated-CPBOH0tA.js",
"houseplan-assets/houseplan-editor-runtime-DutTWtCh.js",
"houseplan-assets/houseplan-onboarding-runtime-Co9leXWb.js",
"houseplan-assets/hp-zigbee-topology-overlay-DTsCpj16.js",
"houseplan-assets/iso-scene-render-C7ED1tZ2.js",
"houseplan-assets/live-interaction-runtime-DMtf8_eH.js",
"houseplan-assets/namespace-language-CaTQ_Mbw.js",
"houseplan-assets/pdf-export-DtfAv3U1.js",
"houseplan-assets/summary-panel-runtime-loaded-CSKGlmFL.js",
"houseplan-assets/zigbee-topology-DgG5_y8E.js",
"houseplan-assets/zigbee-topology-runtime-DxupIWcF.js"
],
"lazyGzipBytes": 448980,
"lazyGzipBytes": 449033,
"lazyEditorFiles": [
"houseplan-assets/backdrop-pick-D4aD5usf.js",
"houseplan-assets/editor-8h7C9dFV.js",
"houseplan-assets/form-kit.styles-Cqg1K3-F.js",
"houseplan-assets/furniture-plan-art.generated-CdVUTs9f.js",
"houseplan-assets/houseplan-editor-runtime-u-EF5jme.js",
"houseplan-assets/namespace-language-BYcyqH-y.js",
"houseplan-assets/zigbee-topology-CcCg6XRV.js"
"houseplan-assets/backdrop-pick-Bz7hJpF4.js",
"houseplan-assets/editor-DQBHGNp6.js",
"houseplan-assets/form-kit.styles-DM0qkJ72.js",
"houseplan-assets/furniture-plan-art.generated-CPBOH0tA.js",
"houseplan-assets/houseplan-editor-runtime-DutTWtCh.js",
"houseplan-assets/namespace-language-CaTQ_Mbw.js",
"houseplan-assets/zigbee-topology-DgG5_y8E.js"
],
"lazyEditorGzipBytes": 231941,
"lazyEditorGzipBytes": 231917,
"lazyOnboardingFiles": [
"houseplan-assets/backdrop-pick-D4aD5usf.js",
"houseplan-assets/form-kit.styles-Cqg1K3-F.js",
"houseplan-assets/houseplan-onboarding-runtime-CvUernez.js",
"houseplan-assets/namespace-language-BYcyqH-y.js"
"houseplan-assets/backdrop-pick-Bz7hJpF4.js",
"houseplan-assets/form-kit.styles-DM0qkJ72.js",
"houseplan-assets/houseplan-onboarding-runtime-Co9leXWb.js",
"houseplan-assets/namespace-language-CaTQ_Mbw.js"
],
"lazyOnboardingGzipBytes": 27903,
"lazyOnboardingGzipBytes": 27890,
"lazyLocaleFiles": [
"houseplan-assets/de-CSQe6eub.js",
"houseplan-assets/fr-Dh71LzVb.js"
"houseplan-assets/de-VB-iDL1g.js",
"houseplan-assets/fr-BfiF5RLs.js"
],
"lazyLocaleGzipBytes": 55674,
"lazyLocaleGzipBytes": 55693,
"lazyIsometricFiles": [
"houseplan-assets/iso-scene-render-DeEYFVoG.js"
"houseplan-assets/iso-scene-render-C7ED1tZ2.js"
],
"lazyIsometricGzipBytes": 17642,
"lazyIsometricGzipBytes": 17640,
"lazyFurnitureArtFiles": [
"houseplan-assets/furniture-plan-art.generated-CdVUTs9f.js"
"houseplan-assets/furniture-plan-art.generated-CPBOH0tA.js"
],
"lazyFurnitureArtGzipBytes": 16938,
"lazyFurnitureArtGzipBytes": 16940,
"lazyPdfFiles": [
"houseplan-assets/furniture-plan-art.generated-CdVUTs9f.js",
"houseplan-assets/pdf-export-CCnDAi0D.js"
"houseplan-assets/furniture-plan-art.generated-CPBOH0tA.js",
"houseplan-assets/pdf-export-DtfAv3U1.js"
],
"lazyPdfGzipBytes": 126825,
"lazyNamespaceLocaleFiles": [
"houseplan-assets/settings-de-HTN5Jwb3.js",
"houseplan-assets/settings-fr-Cu0K0jLh.js",
"houseplan-assets/settings-ru-mPF-h4Sr.js",
"houseplan-assets/support-de-DHkC6Wjm.js",
"houseplan-assets/support-fr-BdDUwgb3.js",
"houseplan-assets/support-ru-RZ8n67t7.js",
"houseplan-assets/topology-de-BJ666mPT.js",
"houseplan-assets/topology-fr-SHOT77wV.js",
"houseplan-assets/topology-ru-CDSUN1by.js"
"houseplan-assets/settings-de-BsLzFQwo.js",
"houseplan-assets/settings-fr-BUJAFfXA.js",
"houseplan-assets/settings-ru-CCGpXggj.js",
"houseplan-assets/support-de-Cs8HYxjq.js",
"houseplan-assets/support-fr-B3NcsP5x.js",
"houseplan-assets/support-ru-k4cHCEhB.js",
"houseplan-assets/topology-de-Uwmiwye1.js",
"houseplan-assets/topology-fr-CKSa9BzH.js",
"houseplan-assets/topology-ru-Ib-FDcAJ.js"
],
"lazyNamespaceLocaleGzipBytes": 20904,
"lazyNamespaceLocaleGzipBytes": 20876,
"files": [
{
"path": "houseplan-assets/backdrop-pick-D4aD5usf.js",
"sha256": "5cba278bb74bac9f2e1bbf709d772c26211d3ce0539e493ea196cabbe42a60f0",
"path": "houseplan-assets/backdrop-pick-Bz7hJpF4.js",
"sha256": "350299d7149a052cb53d91fcf601bd385427b2801d8498c6d8a33c3b15a1c472",
"rawBytes": 53888,
"gzipBytes": 17524,
"gzipBytes": 17522,
"isEntry": false,
"imports": [
"houseplan-assets/form-kit.styles-Cqg1K3-F.js",
"houseplan-assets/houseplan-card-B4joz-YO.js",
"houseplan-assets/namespace-language-BYcyqH-y.js"
"houseplan-assets/form-kit.styles-DM0qkJ72.js",
"houseplan-assets/houseplan-card-C_DbrDoi.js",
"houseplan-assets/namespace-language-CaTQ_Mbw.js"
],
"dynamicImports": [
"houseplan-assets/settings-de-HTN5Jwb3.js",
"houseplan-assets/settings-fr-Cu0K0jLh.js",
"houseplan-assets/settings-ru-mPF-h4Sr.js"
"houseplan-assets/settings-de-BsLzFQwo.js",
"houseplan-assets/settings-fr-BUJAFfXA.js",
"houseplan-assets/settings-ru-CCGpXggj.js"
]
},
{
"path": "houseplan-assets/de-CSQe6eub.js",
"sha256": "7cc2f4b7c80659d531c0a5850a43be9671173460415ac729acd6aa4472e93f65",
"rawBytes": 93034,
"gzipBytes": 28064,
"path": "houseplan-assets/de-VB-iDL1g.js",
"sha256": "e36748c22559aa830e9ff4ee9f7be25d44e20e3f395e57ce76ba9ef4d8286efe",
"rawBytes": 93083,
"gzipBytes": 28072,
"isEntry": false,
"imports": [],
"dynamicImports": []
},
{
"path": "houseplan-assets/editor-8h7C9dFV.js",
"sha256": "a6d7ddf821b1a21f4ee661eb9f5c8ff63a63f61d5cd7fc4772952ad7fc3d4ac3",
"path": "houseplan-assets/editor-DQBHGNp6.js",
"sha256": "cc64a5d977ec9bf02ac510bd97ed5e3167116609f3558708d90b303a52717b08",
"rawBytes": 3833,
"gzipBytes": 1584,
"gzipBytes": 1580,
"isEntry": false,
"imports": [
"houseplan-assets/houseplan-card-B4joz-YO.js"
"houseplan-assets/houseplan-card-C_DbrDoi.js"
],
"dynamicImports": []
},
{
"path": "houseplan-assets/form-kit.styles-Cqg1K3-F.js",
"sha256": "6f6610b54843341a4e29102712a9678f69cb6375dd636391939478f074ab50f4",
"path": "houseplan-assets/form-kit.styles-DM0qkJ72.js",
"sha256": "34dfe537bbb82eae5ac40f42786c6be679f3f155484210df72ad16a0892faaf2",
"rawBytes": 25600,
"gzipBytes": 5057,
"gzipBytes": 5055,
"isEntry": false,
"imports": [],
"dynamicImports": []
},
{
"path": "houseplan-assets/fr-Dh71LzVb.js",
"sha256": "834d506dac720eb993be19d336c601aeb53f199e4d8799d09943143c8247efcd",
"rawBytes": 95381,
"gzipBytes": 27610,
"path": "houseplan-assets/fr-BfiF5RLs.js",
"sha256": "9d66bd6595ebdbca5e957c025de80c465cb49d78d215a90ca1210261ed1457a7",
"rawBytes": 95424,
"gzipBytes": 27621,
"isEntry": false,
"imports": [],
"dynamicImports": []
},
{
"path": "houseplan-assets/furniture-plan-art.generated-CdVUTs9f.js",
"sha256": "efbb991928c394343bbe062963a704d4806b38d6064e5eb1cc07afc16ef41c2b",
"path": "houseplan-assets/furniture-plan-art.generated-CPBOH0tA.js",
"sha256": "45adddf9c0b9773ed9cd19e1c05cca97e11cc0caba6cb6502cb46b229eb847d4",
"rawBytes": 52035,
"gzipBytes": 16938,
"gzipBytes": 16940,
"isEntry": false,
"imports": [],
"dynamicImports": []
},
{
"path": "houseplan-assets/houseplan-card-B4joz-YO.js",
"sha256": "9730f2f454d3026e8bbcf36cb5e0ecf397f77fe839470e1214a7a060d315af42",
"rawBytes": 1024896,
"gzipBytes": 289247,
"path": "houseplan-assets/houseplan-card-C_DbrDoi.js",
"sha256": "46b34df9315327c7f69f2895cdc9c412bc7347bd27f231732ff450be1f083720",
"rawBytes": 1030556,
"gzipBytes": 290826,
"isEntry": false,
"imports": [],
"dynamicImports": [
"houseplan-assets/de-CSQe6eub.js",
"houseplan-assets/editor-8h7C9dFV.js",
"houseplan-assets/fr-Dh71LzVb.js",
"houseplan-assets/furniture-plan-art.generated-CdVUTs9f.js",
"houseplan-assets/houseplan-editor-runtime-u-EF5jme.js",
"houseplan-assets/houseplan-onboarding-runtime-CvUernez.js",
"houseplan-assets/hp-zigbee-topology-overlay-BS2sDfiR.js",
"houseplan-assets/iso-scene-render-DeEYFVoG.js",
"houseplan-assets/live-interaction-runtime-C9YY0yeQ.js",
"houseplan-assets/pdf-export-CCnDAi0D.js",
"houseplan-assets/summary-panel-runtime-loaded-DEMxCIRi.js"
"houseplan-assets/de-VB-iDL1g.js",
"houseplan-assets/editor-DQBHGNp6.js",
"houseplan-assets/fr-BfiF5RLs.js",
"houseplan-assets/furniture-plan-art.generated-CPBOH0tA.js",
"houseplan-assets/houseplan-editor-runtime-DutTWtCh.js",
"houseplan-assets/houseplan-onboarding-runtime-Co9leXWb.js",
"houseplan-assets/hp-zigbee-topology-overlay-DTsCpj16.js",
"houseplan-assets/iso-scene-render-C7ED1tZ2.js",
"houseplan-assets/live-interaction-runtime-DMtf8_eH.js",
"houseplan-assets/pdf-export-DtfAv3U1.js",
"houseplan-assets/summary-panel-runtime-loaded-CSKGlmFL.js"
]
},
{
"path": "houseplan-assets/houseplan-editor-runtime-u-EF5jme.js",
"sha256": "ce66247c36d42724cd1b9f66d0bfe0f2705929aa664aa5c03935e7ab2f1df7d0",
"path": "houseplan-assets/houseplan-editor-runtime-DutTWtCh.js",
"sha256": "92bfe9fc262153ba1949668fa5fbae24eb5da38edb3df6a02f9d2246d20bb0cf",
"rawBytes": 667315,
"gzipBytes": 186124,
"gzipBytes": 186119,
"isEntry": false,
"imports": [
"houseplan-assets/backdrop-pick-D4aD5usf.js",
"houseplan-assets/form-kit.styles-Cqg1K3-F.js",
"houseplan-assets/furniture-plan-art.generated-CdVUTs9f.js",
"houseplan-assets/houseplan-card-B4joz-YO.js",
"houseplan-assets/namespace-language-BYcyqH-y.js",
"houseplan-assets/zigbee-topology-CcCg6XRV.js"
"houseplan-assets/backdrop-pick-Bz7hJpF4.js",
"houseplan-assets/form-kit.styles-DM0qkJ72.js",
"houseplan-assets/furniture-plan-art.generated-CPBOH0tA.js",
"houseplan-assets/houseplan-card-C_DbrDoi.js",
"houseplan-assets/namespace-language-CaTQ_Mbw.js",
"houseplan-assets/zigbee-topology-DgG5_y8E.js"
],
"dynamicImports": [
"houseplan-assets/support-de-DHkC6Wjm.js",
"houseplan-assets/support-fr-BdDUwgb3.js",
"houseplan-assets/support-ru-RZ8n67t7.js",
"houseplan-assets/zigbee-topology-runtime-DokImShf.js"
"houseplan-assets/support-de-Cs8HYxjq.js",
"houseplan-assets/support-fr-B3NcsP5x.js",
"houseplan-assets/support-ru-k4cHCEhB.js",
"houseplan-assets/zigbee-topology-runtime-DxupIWcF.js"
]
},
{
"path": "houseplan-assets/houseplan-onboarding-runtime-CvUernez.js",
"sha256": "da9b468fd43654b9265696a4b61204c46a70ff7b6dbd1e236b6413ad688fa233",
"path": "houseplan-assets/houseplan-onboarding-runtime-Co9leXWb.js",
"sha256": "9d6a434656cde134477479db58662ddd3d54c299e7745049a753c80004b79c3e",
"rawBytes": 15886,
"gzipBytes": 4910,
"gzipBytes": 4905,
"isEntry": false,
"imports": [
"houseplan-assets/backdrop-pick-D4aD5usf.js",
"houseplan-assets/form-kit.styles-Cqg1K3-F.js",
"houseplan-assets/houseplan-card-B4joz-YO.js",
"houseplan-assets/namespace-language-BYcyqH-y.js"
"houseplan-assets/backdrop-pick-Bz7hJpF4.js",
"houseplan-assets/form-kit.styles-DM0qkJ72.js",
"houseplan-assets/houseplan-card-C_DbrDoi.js",
"houseplan-assets/namespace-language-CaTQ_Mbw.js"
],
"dynamicImports": []
},
{
"path": "houseplan-assets/hp-zigbee-topology-overlay-BS2sDfiR.js",
"sha256": "2dd7cf101133530d59cdfb10afbad166b3df0a33c5653ffb9990473622721a8f",
"path": "houseplan-assets/hp-zigbee-topology-overlay-DTsCpj16.js",
"sha256": "4a4f0e5f6e5ccb6a50f4865a49900c449a8d0d61227bc4cba80cc22ca31fa648",
"rawBytes": 10958,
"gzipBytes": 3767,
"gzipBytes": 3764,
"isEntry": false,
"imports": [
"houseplan-assets/houseplan-card-B4joz-YO.js",
"houseplan-assets/namespace-language-BYcyqH-y.js",
"houseplan-assets/zigbee-topology-CcCg6XRV.js",
"houseplan-assets/zigbee-topology-runtime-DokImShf.js"
"houseplan-assets/houseplan-card-C_DbrDoi.js",
"houseplan-assets/namespace-language-CaTQ_Mbw.js",
"houseplan-assets/zigbee-topology-DgG5_y8E.js",
"houseplan-assets/zigbee-topology-runtime-DxupIWcF.js"
],
"dynamicImports": []
},
{
"path": "houseplan-assets/iso-scene-render-DeEYFVoG.js",
"sha256": "db33e97b3530f4f241921ddb4921977863e29145aeed1bf4737152b615e2948a",
"path": "houseplan-assets/iso-scene-render-C7ED1tZ2.js",
"sha256": "2a784be05890d7e7520b5632a972ebe00d0b4c7d29869ff3b0e3b41a1d4fab8d",
"rawBytes": 51983,
"gzipBytes": 17642,
"gzipBytes": 17640,
"isEntry": false,
"imports": [
"houseplan-assets/houseplan-card-B4joz-YO.js"
"houseplan-assets/houseplan-card-C_DbrDoi.js"
],
"dynamicImports": []
},
{
"path": "houseplan-assets/live-interaction-runtime-C9YY0yeQ.js",
"sha256": "d1a44279a5d79dfdac22870473ba1a712198034ce1aa58e97e1a4bddeddbcb13",
"path": "houseplan-assets/live-interaction-runtime-DMtf8_eH.js",
"sha256": "90387449e12a77bdb17f665fa5f2440b5795eb899e8ceec8086c4e61f1b63f3c",
"rawBytes": 8216,
"gzipBytes": 3206,
"gzipBytes": 3204,
"isEntry": false,
"imports": [
"houseplan-assets/houseplan-card-B4joz-YO.js"
"houseplan-assets/houseplan-card-C_DbrDoi.js"
],
"dynamicImports": []
},
{
"path": "houseplan-assets/namespace-language-BYcyqH-y.js",
"sha256": "0eaa7380f1d79bf929be82084c0aed262880fb160683887d962f235ad5d64295",
"path": "houseplan-assets/namespace-language-CaTQ_Mbw.js",
"sha256": "ceb020823bfc799edadbc276f361748f56bfdbe2eb4b51db81d33b7646fc4200",
"rawBytes": 675,
"gzipBytes": 412,
"gzipBytes": 408,
"isEntry": false,
"imports": [
"houseplan-assets/houseplan-card-B4joz-YO.js"
"houseplan-assets/houseplan-card-C_DbrDoi.js"
],
"dynamicImports": []
},
{
"path": "houseplan-assets/pdf-export-CCnDAi0D.js",
"sha256": "d97fc1612c07914c4466a188d389cf61267b4ca2ba4165bba23fef5b9e204b58",
"path": "houseplan-assets/pdf-export-DtfAv3U1.js",
"sha256": "e973cc5f41add5f1d8f8c8a8957bd83439d888a61e6abbd1826534e92a20e354",
"rawBytes": 236264,
"gzipBytes": 109887,
"gzipBytes": 109885,
"isEntry": false,
"imports": [
"houseplan-assets/furniture-plan-art.generated-CdVUTs9f.js",
"houseplan-assets/houseplan-card-B4joz-YO.js"
"houseplan-assets/furniture-plan-art.generated-CPBOH0tA.js",
"houseplan-assets/houseplan-card-C_DbrDoi.js"
],
"dynamicImports": []
},
{
"path": "houseplan-assets/settings-de-HTN5Jwb3.js",
"sha256": "a884ce3c5cdb63ec15889e3f332fc208178bbc2cee8c9e41f9963814e95b671a",
"path": "houseplan-assets/settings-de-BsLzFQwo.js",
"sha256": "25a89c6fd096db94f94d37e9bc0d8e8fe9bef5f34034da00babc64aacbcc4d9e",
"rawBytes": 7248,
"gzipBytes": 2826,
"gzipBytes": 2823,
"isEntry": false,
"imports": [],
"dynamicImports": []
},
{
"path": "houseplan-assets/settings-fr-Cu0K0jLh.js",
"sha256": "ff3400bc130198f8922fb4b88c82b388e28ecaf1cd90aac858bc5ed8b5519ad6",
"path": "houseplan-assets/settings-fr-BUJAFfXA.js",
"sha256": "f682adb4e762eace27b5eaf9bdbcd0ab0199bb39412d3cab5d0f56075a6a8d3d",
"rawBytes": 7483,
"gzipBytes": 2788,
"gzipBytes": 2784,
"isEntry": false,
"imports": [],
"dynamicImports": []
},
{
"path": "houseplan-assets/settings-ru-mPF-h4Sr.js",
"sha256": "f7fdef6c801cda38e11217273824dbda8aab3bdeac756d5f40f03361d5c3a099",
"path": "houseplan-assets/settings-ru-CCGpXggj.js",
"sha256": "681d6b2bbac7dff0aa693b8260141a635203396e9c26f95677ca329873228653",
"rawBytes": 10128,
"gzipBytes": 3273,
"gzipBytes": 3270,
"isEntry": false,
"imports": [],
"dynamicImports": []
},
{
"path": "houseplan-assets/summary-panel-editor-Rflrcwgs.js",
"sha256": "e1d3e4d56cf13ec4724d20e44a0cdca84a0879e304e08bc3762639c26c888b1b",
"path": "houseplan-assets/summary-panel-editor-BYh50PV_.js",
"sha256": "8e87a35b3806ef5b98bdd65eefa9fa482d7de062ba22d22267c0c098964aac9d",
"rawBytes": 14862,
"gzipBytes": 3430,
"gzipBytes": 3423,
"isEntry": false,
"imports": [
"houseplan-assets/form-kit.styles-Cqg1K3-F.js",
"houseplan-assets/houseplan-card-B4joz-YO.js",
"houseplan-assets/summary-panel-runtime-loaded-DEMxCIRi.js"
"houseplan-assets/form-kit.styles-DM0qkJ72.js",
"houseplan-assets/houseplan-card-C_DbrDoi.js",
"houseplan-assets/summary-panel-runtime-loaded-CSKGlmFL.js"
],
"dynamicImports": []
},
{
"path": "houseplan-assets/summary-panel-metrics-C32cC2x4.js",
"sha256": "ca293e294e686fd021361fa40f207adb35aad2b390d90573884476d4487fe619",
"path": "houseplan-assets/summary-panel-metrics-CUaycNn2.js",
"sha256": "682848fd7a5104f76e0aa202e4ecdc835272ab5de70eae4ba0db66d81d698fec",
"rawBytes": 2611,
"gzipBytes": 1307,
"gzipBytes": 1302,
"isEntry": false,
"imports": [
"houseplan-assets/houseplan-card-B4joz-YO.js"
"houseplan-assets/houseplan-card-C_DbrDoi.js"
],
"dynamicImports": []
},
{
"path": "houseplan-assets/summary-panel-runtime-loaded-DEMxCIRi.js",
"sha256": "c63a95699435e821e0b3eeb1c24b12d98d3b7c614b2b6c16d3a6cf0b60ca6a70",
"rawBytes": 72637,
"gzipBytes": 20162,
"path": "houseplan-assets/summary-panel-runtime-loaded-CSKGlmFL.js",
"sha256": "60c380a98a02c13d25c0fe6a4544017a84498a0509afaa41894c475ed787a275",
"rawBytes": 72956,
"gzipBytes": 20238,
"isEntry": false,
"imports": [
"houseplan-assets/form-kit.styles-Cqg1K3-F.js",
"houseplan-assets/houseplan-card-B4joz-YO.js"
"houseplan-assets/form-kit.styles-DM0qkJ72.js",
"houseplan-assets/houseplan-card-C_DbrDoi.js"
],
"dynamicImports": [
"houseplan-assets/summary-panel-editor-Rflrcwgs.js",
"houseplan-assets/summary-panel-metrics-C32cC2x4.js"
"houseplan-assets/summary-panel-editor-BYh50PV_.js",
"houseplan-assets/summary-panel-metrics-CUaycNn2.js"
]
},
{
"path": "houseplan-assets/support-de-DHkC6Wjm.js",
"sha256": "16cc51b1639440e2ea04c50ef20feb663cdc3953b463119559db5f3118ff2083",
"path": "houseplan-assets/support-de-Cs8HYxjq.js",
"sha256": "66f3812a322232a9373bb15a8cdc38c2d50d60f1146edea0adbcd0b5f96ec48a",
"rawBytes": 6167,
"gzipBytes": 2399,
"gzipBytes": 2395,
"isEntry": false,
"imports": [],
"dynamicImports": []
},
{
"path": "houseplan-assets/support-fr-BdDUwgb3.js",
"sha256": "e9aecf2130ab83711bc114ec9d4b251edaad69b318d1cb519d7aa1fc70ed9daa",
"path": "houseplan-assets/support-fr-B3NcsP5x.js",
"sha256": "856b622a98ac9861401ed364e510e6de6b5abdc911fec8201355c56c52493eea",
"rawBytes": 6333,
"gzipBytes": 2433,
"gzipBytes": 2429,
"isEntry": false,
"imports": [],
"dynamicImports": []
},
{
"path": "houseplan-assets/support-ru-RZ8n67t7.js",
"sha256": "2119dbbce4133700daee48826a67255c3ddbd660c8876f04f1b39b56a866ca31",
"path": "houseplan-assets/support-ru-k4cHCEhB.js",
"sha256": "e542140f6e6be396835fe0cb1b2ea2acfed810cf3239cffa4d1bd820d77b11ee",
"rawBytes": 8376,
"gzipBytes": 2878,
"gzipBytes": 2875,
"isEntry": false,
"imports": [],
"dynamicImports": []
},
{
"path": "houseplan-assets/topology-de-BJ666mPT.js",
"sha256": "3a04273c59dea448e4d5fcc19b9671b123e964d17c256cc289d5d6464b7386fc",
"path": "houseplan-assets/topology-de-Uwmiwye1.js",
"sha256": "dd585dc78a9f200e43d5909d5c72b57e86d11333c9ba7405e988b3a83d147414",
"rawBytes": 2698,
"gzipBytes": 1335,
"gzipBytes": 1333,
"isEntry": false,
"imports": [],
"dynamicImports": []
},
{
"path": "houseplan-assets/topology-fr-SHOT77wV.js",
"sha256": "40a71548a23c392623c97ab143f9bc06a5262f610561a8d3050b953dd002faa2",
"path": "houseplan-assets/topology-fr-CKSa9BzH.js",
"sha256": "b7058476bb543892b5da6dc760d9ee3eb45021b47dfb724cf7d19fb510c77a0c",
"rawBytes": 2718,
"gzipBytes": 1356,
"gzipBytes": 1353,
"isEntry": false,
"imports": [],
"dynamicImports": []
},
{
"path": "houseplan-assets/topology-ru-CDSUN1by.js",
"sha256": "8a982c8d089794ae4c1dcfd30741fa1b0fa17d0e34b19be8e7160ce94cdf261a",
"path": "houseplan-assets/topology-ru-Ib-FDcAJ.js",
"sha256": "9f53d289d1dd543ba8795e2bc523a7e5cab5a5c3cf4ff34c766e02f42c707fb5",
"rawBytes": 3669,
"gzipBytes": 1616,
"gzipBytes": 1614,
"isEntry": false,
"imports": [],
"dynamicImports": []
},
{
"path": "houseplan-assets/zigbee-topology-CcCg6XRV.js",
"sha256": "cd8d3d0b16900240b4f96724bcd08dbb31b5ed25a1c3dd50adf82645c583c830",
"path": "houseplan-assets/zigbee-topology-DgG5_y8E.js",
"sha256": "395bad3d94b8bd570ae380fc47f3ba063f33fb145bda2ff84928c374aa0ec723",
"rawBytes": 10958,
"gzipBytes": 4302,
"gzipBytes": 4293,
"isEntry": false,
"imports": [
"houseplan-assets/houseplan-card-B4joz-YO.js",
"houseplan-assets/namespace-language-BYcyqH-y.js"
"houseplan-assets/houseplan-card-C_DbrDoi.js",
"houseplan-assets/namespace-language-CaTQ_Mbw.js"
],
"dynamicImports": [
"houseplan-assets/topology-de-BJ666mPT.js",
"houseplan-assets/topology-fr-SHOT77wV.js",
"houseplan-assets/topology-ru-CDSUN1by.js"
"houseplan-assets/topology-de-Uwmiwye1.js",
"houseplan-assets/topology-fr-CKSa9BzH.js",
"houseplan-assets/topology-ru-Ib-FDcAJ.js"
]
},
{
"path": "houseplan-assets/zigbee-topology-runtime-DokImShf.js",
"sha256": "4959616d27f0369955687c2813e88001a11f263799bed0bdfabacdf207558d15",
"path": "houseplan-assets/zigbee-topology-runtime-DxupIWcF.js",
"sha256": "87f04630b08483cdc29451e92a0be8ffa6355cc096825d58f6418a766c6a2d95",
"rawBytes": 3983,
"gzipBytes": 1791,
"gzipBytes": 1787,
"isEntry": false,
"imports": [
"houseplan-assets/houseplan-card-B4joz-YO.js",
"houseplan-assets/namespace-language-BYcyqH-y.js",
"houseplan-assets/zigbee-topology-CcCg6XRV.js"
"houseplan-assets/houseplan-card-C_DbrDoi.js",
"houseplan-assets/namespace-language-CaTQ_Mbw.js",
"houseplan-assets/zigbee-topology-DgG5_y8E.js"
],
"dynamicImports": []
},
{
"path": "houseplan-card.js",
"sha256": "4e9f8fb5bb4ac6fb8c982c42f12595fb704112437ca24a17d5026844917f1e8e",
"sha256": "0f22a82da607d75edf6267268399a5b50e86143a4b4fe1b582cd7cde7ef6ca11",
"rawBytes": 1205,
"gzipBytes": 805,
"gzipBytes": 800,
"isEntry": true,
"imports": [
"houseplan-assets/houseplan-card-B4joz-YO.js"
"houseplan-assets/houseplan-card-C_DbrDoi.js"
],
"dynamicImports": []
},
{
"path": "houseplan-panel.js",
"sha256": "5eff237665abb540e69511ede6760f1100c65b718bc6bbd9e66c725595435222",
"sha256": "d112fa85e40363bb1441d40a48de625de3373ae01682db6e74a68d092c043201",
"rawBytes": 6165,
"gzipBytes": 2327,
"gzipBytes": 2322,
"isEntry": true,
"imports": [
"houseplan-assets/houseplan-card-B4joz-YO.js"
"houseplan-assets/houseplan-card-C_DbrDoi.js"
],
"dynamicImports": []
}
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -1,14 +1,14 @@
globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="24813ef5e0b24d0f550c9e330f8ef7806dfb0724a8f69bd5e14e312c73438264";import{aD as e,l as o,aG as t,ee as s,A as a,ef as i,eg as l,eh as n,E as r,c}from"./houseplan-card-B4joz-YO.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
globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="1d6151ba58a0ce1dc15ed85a133606dca280b90dea173557fa34ac9531c10ffb";import{aD as e,l as o,aG as t,ee as s,A as a,ef as i,eg as l,eh as n,E as r,c}from"./houseplan-card-C_DbrDoi.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
.hass=${this.hass}
.data=${this._formData}
.schema=${e}
.computeLabel=${e=>f[e.name]||e.name}
.computeLabel=${e=>h[e.name]||e.name}
@value-changed=${this._valueChanged}
></ha-form>`;return c`
${d(h.slice(0,3))}
${d(f.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(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);
${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);
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -1 +0,0 @@
globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="24813ef5e0b24d0f550c9e330f8ef7806dfb0724a8f69bd5e14e312c73438264";import{ej as e,ek as n,eg as o}from"./houseplan-card-B4joz-YO.js";function r(o,r){return new e([{code:"en",dictionary:o},{code:"ru",loadDictionary:r.ru},{code:"de",loadDictionary:r.de},{code:"fr",loadDictionary:r.fr}],"24813ef5e0b24d0f550c9e330f8ef7806dfb0724a8f69bd5e14e312c73438264",console.warn,n)}function a(e){return function(e,n){return{state:o=>{const r=e.state(o);return"pending"!==r&&n.some(e=>"pending"===e.state(o))?"pending":r},dictionary:n=>e.dictionary(n),ensure:o=>Promise.all([e,...n].map(e=>e.ensure(o))).then(()=>{})}}(o,e)}export{r as n,a as s};
@@ -0,0 +1 @@
globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="1d6151ba58a0ce1dc15ed85a133606dca280b90dea173557fa34ac9531c10ffb";import{ej as a,ek as e,eg as n}from"./houseplan-card-C_DbrDoi.js";function c(n,c){return new a([{code:"en",dictionary:n},{code:"ru",loadDictionary:c.ru},{code:"de",loadDictionary:c.de},{code:"fr",loadDictionary:c.fr}],"1d6151ba58a0ce1dc15ed85a133606dca280b90dea173557fa34ac9531c10ffb",console.warn,e)}function d(a){return function(a,e){return{state:n=>{const c=a.state(n);return"pending"!==c&&e.some(a=>"pending"===a.state(n))?"pending":c},dictionary:e=>a.dictionary(e),ensure:n=>Promise.all([a,...e].map(a=>a.ensure(n))).then(()=>{})}}(n,a)}export{c as n,d as s};
@@ -1,4 +1,4 @@
globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="24813ef5e0b24d0f550c9e330f8ef7806dfb0724a8f69bd5e14e312c73438264";import{c as a,A as e}from"./houseplan-card-B4joz-YO.js";import{s,n as t,a as l,m as r,b as o,c as i,d as u}from"./summary-panel-runtime-loaded-DEMxCIRi.js";import"./form-kit.styles-Cqg1K3-F.js";const m=m=>{const{host:c,dialog:d,problems:n,t:b}=m,y=n.find(a=>"error"===a.kind),$=d.localShow!==d.baseLocalShow||!d.localOnly&&!s(t(d.draft),d.base),p=$&&!d.busy&&!y,v=a=>n.find(e=>e.path===a),h=a=>a?b(`summary.problem.${a.code}`):"",k=()=>m.close(),g=a`<label class="summary-switch" for="summary-local-show">
globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="1d6151ba58a0ce1dc15ed85a133606dca280b90dea173557fa34ac9531c10ffb";import{c as a,A as e}from"./houseplan-card-C_DbrDoi.js";import{s,n as t,a as l,m as r,b as o,c as i,d as u}from"./summary-panel-runtime-loaded-CSKGlmFL.js";import"./form-kit.styles-DM0qkJ72.js";const m=m=>{const{host:c,dialog:d,problems:n,t:b}=m,y=n.find(a=>"error"===a.kind),$=d.localShow!==d.baseLocalShow||!d.localOnly&&!s(t(d.draft),d.base),p=$&&!d.busy&&!y,v=a=>n.find(e=>e.path===a),h=a=>a?b(`summary.problem.${a.code}`):"",k=()=>m.close(),g=a`<label class="summary-switch" for="summary-local-show">
<span class="summary-switch-caption"><strong>${b("summary.show_local")}</strong>
<small id="summary-local-show-hint">${b("summary.show_local_hint")}</small></span>
<input id="summary-local-show" data-summary-local-show type="checkbox"
@@ -1 +0,0 @@
globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="24813ef5e0b24d0f550c9e330f8ef7806dfb0724a8f69bd5e14e312c73438264";import{em as e,N as t,b2 as n,L as i,ae as o,ac as r,bY as s,bX as a,b1 as l,b0 as c,b3 as u,en as d,eo as f,b_ as m,ep as g}from"./houseplan-card-B4joz-YO.js";function v(e){if(!e.registry.authoritative)return null;const t=new Set,n=u(e.markers);for(const i of Object.values(e.registry.devices||{}))i?.id&&"service"!==i.entry_type&&!n.devices.has(i.id)&&i.area_id&&e.areaToSpace[i.area_id]&&t.add(i.id);for(const i of e.markers||[]){if(i.removed||"virtual"===i.binding)continue;const o=String(i.binding||"").indexOf(":");if(o<1)continue;const r=i.binding.slice(0,o),s=i.binding.slice(o+1),a="device"===r?e.registry.devices?.[s]:null,l="entity"===r?e.registry.entities?.[s]:null,c="device"===r?s:l?.device_id,u="device"===r?a?.area_id:l?.area_id||c&&e.registry.devices?.[c]?.area_id,d="string"==typeof i.room_id&&i.room_id.length>0&&null===i.area?"":i.area||u||"",f=d&&e.areaToSpace[d]||i.space||e.firstSpaceId;c&&e.registry.devices?.[c]&&e.spaceIds.has(f)&&(!n.devices.has(c)||"entity"===r&&n.liveEntities.has(s))&&t.add(c)}return t}function y(e,t){return e?.length?t?.length?g(e,t):e:t}function _(e,t){const n=l(e.rooms,t.walls,t.openCuts,[],i,t.cellCm,o,r);return{roomGeom:"ok"===n.status||"degraded-extra"===n.status?n.roomGeom:void 0,multiWallNodes:c(e.rooms,t.walls,t.openCuts,i,t.cellCm,o,r)}}function*b(l,c,u=_){try{let d=0;for(const f of c){const c=l.spaces.find(e=>String(e?.id)===f.id);if(!c)continue;const m=e(c,f),g=u(f,m);let v=null;for(const e of f.rooms){if(!e.id)continue;const a=t(e);if(!a)continue;const l=n(f.rooms,e.id,m.walls,m.openCuts,i,m.cellCm,o,r,g.roomGeom,g.multiWallNodes)||a;v=y(v,s(l,m.physicalBodies)),yield}const _=m.cellCm/o;d+=a(v)*_*_/1e4}return d}catch{return null}}function p(e,t,n=_){const i=b(e,t,n);let o=i.next();for(;!o.done;)o=i.next();return o.value}function h(e,t,n,i){if("system"!==e.type)return null;if("device_count"===e.key)return null===t.deviceCount?null:String(t.deviceCount);if("total_area"===e.key)return null===t.areaM2?null:m(t.areaM2,"mi"===n?.config?.unit_system?.length);try{return new Intl.DateTimeFormat(i||void 0,{dateStyle:"short",timeStyle:"short",timeZone:n?.config?.time_zone||void 0}).format(t.now)}catch{return t.now.toLocaleString()}}function S(e,t){const n=e?.states?.[t];if(!n)return null;const i=d(e,t);return i?f(i,String(n.attributes?.unit_of_measurement||"")):null}export{b as cleanFloorAreaSteps,v as representedHaDeviceIds,_ as spaceWallGeometry,S as summaryEntityValue,h as summarySystemValue,p as totalCleanFloorAreaM2};
@@ -0,0 +1 @@
globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="1d6151ba58a0ce1dc15ed85a133606dca280b90dea173557fa34ac9531c10ffb";import{em as e,N as t,b2 as n,L as i,ae as o,ac as r,bY as s,bX as a,b1 as c,b0 as l,b3 as d,en as u,eo as f,b_ as m,ep as g}from"./houseplan-card-C_DbrDoi.js";function v(e){if(!e.registry.authoritative)return null;const t=new Set,n=d(e.markers);for(const i of Object.values(e.registry.devices||{}))i?.id&&"service"!==i.entry_type&&!n.devices.has(i.id)&&i.area_id&&e.areaToSpace[i.area_id]&&t.add(i.id);for(const i of e.markers||[]){if(i.removed||"virtual"===i.binding)continue;const o=String(i.binding||"").indexOf(":");if(o<1)continue;const r=i.binding.slice(0,o),s=i.binding.slice(o+1),a="device"===r?e.registry.devices?.[s]:null,c="entity"===r?e.registry.entities?.[s]:null,l="device"===r?s:c?.device_id,d="device"===r?a?.area_id:c?.area_id||l&&e.registry.devices?.[l]?.area_id,u="string"==typeof i.room_id&&i.room_id.length>0&&null===i.area?"":i.area||d||"",f=u&&e.areaToSpace[u]||i.space||e.firstSpaceId;l&&e.registry.devices?.[l]&&e.spaceIds.has(f)&&(!n.devices.has(l)||"entity"===r&&n.liveEntities.has(s))&&t.add(l)}return t}function y(e,t){return e?.length?t?.length?g(e,t):e:t}function _(e,t){const n=c(e.rooms,t.walls,t.openCuts,[],i,t.cellCm,o,r);return{roomGeom:"ok"===n.status||"degraded-extra"===n.status?n.roomGeom:void 0,multiWallNodes:l(e.rooms,t.walls,t.openCuts,i,t.cellCm,o,r)}}function*b(c,l,d=_){try{let u=0;for(const f of l){const l=c.spaces.find(e=>String(e?.id)===f.id);if(!l)continue;const m=e(l,f),g=d(f,m);let v=null;for(const e of f.rooms){if(!e.id)continue;const a=t(e);if(!a)continue;const c=n(f.rooms,e.id,m.walls,m.openCuts,i,m.cellCm,o,r,g.roomGeom,g.multiWallNodes)||a;v=y(v,s(c,m.physicalBodies)),yield}const _=m.cellCm/o;u+=a(v)*_*_/1e4}return u}catch{return null}}function p(e,t,n=_){const i=b(e,t,n);let o=i.next();for(;!o.done;)o=i.next();return o.value}function h(e,t,n,i){if("system"!==e.type)return null;if("device_count"===e.key)return null===t.deviceCount?null:String(t.deviceCount);if("total_area"===e.key)return null===t.areaM2?null:m(t.areaM2,"mi"===n?.config?.unit_system?.length);try{return new Intl.DateTimeFormat(i||void 0,{dateStyle:"short",timeStyle:"short",timeZone:n?.config?.time_zone||void 0}).format(t.now)}catch{return t.now.toLocaleString()}}function S(e,t){const n=e?.states?.[t];if(!n)return null;const i=u(e,t);return i?f(i,String(n.attributes?.unit_of_measurement||"")):null}export{b as cleanFloorAreaSteps,v as representedHaDeviceIds,_ as spaceWallGeometry,S as summaryEntityValue,h as summarySystemValue,p as totalCleanFloorAreaM2};
@@ -1 +1 @@
globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="24813ef5e0b24d0f550c9e330f8ef7806dfb0724a8f69bd5e14e312c73438264";var e={title:"Zigbee-Verbindungen",toggle:"Zigbee-Verbindungen beim Darüberfahren über ein Gerät anzeigen",hint:"Es werden nur beobachtete direkte Nachbarn angezeigt. Beim Darüberfahren werden keine Daten abgerufen.",help:"Zeigt, mit welchen Zigbee-Geräten jedes Gerät direkt verbunden ist. Die Linienfarbe ist die Verbindungsqualität (LQI) auf derselben Skala wie der LQI-Wert des Geräts: rot bei 40 und darunter, grün bei 180 und darüber. Eine gestrichelte Linie bedeutet, dass die Qualität nicht gemeldet wurde. Ein Pfeil zeigt auf das nächste Gerät auf dem Weg zum Koordinator: ein Pfeil führt hinaus, eingehende Pfeile sind die Geräte, die über dieses Gerät routen. Eine Linie ohne Pfeil ist ein Ersatznachbar. Das ist der Routenbaum, den House Plan bildet, nicht der Weg eines Pakets in diesem Moment: eine Beschriftung am Pfeilende bedeutet, dass das Ziel nicht auf diesem Plan liegt, und ein fehlender Pfeil, dass die Route unbekannt ist. Die Daten stammen aus dem letzten Laden und veralten; Verbindungen sind nur mit der Maus sichtbar.",help_aria:"Hilfe: Zigbee-Verbindungen",admin_only:"Topologiedaten sind nur für Home-Assistant-Administratoren verfügbar.",save_first:"Speichere diese Einstellung, bevor Topologiedaten geladen werden.",zha:"ZHA",zha_read:"ZHA-Daten lesen",zha_hint:"Liest den ZHA-Topologiecache; es wird kein Funkscan gestartet.",z2m:"Zigbee2MQTT",z2m_topics:"Basistopics (eines pro Zeile)",z2m_update:"Karte aktualisieren",z2m_warning:"Ein Netzwerkscan kann 10 Sekunden bis 2 Minuten dauern und Zigbee vorübergehend verlangsamen.",status_idle:"Daten nicht geladen",status_loading:"Wird geladen…",status_ready:"Empfangen: {time}",status_stale:"Empfangen: {time} · veraltet",status_partial:"Empfangen: {time} · einige Knoten fehlen",status_no_links:"Empfangen: {time} · keine beobachteten Verbindungen gefunden",error_permission:"Administratorrechte sind erforderlich.",error_unsupported:"Dieser Anbieter oder die Home-Assistant-API ist nicht verfügbar.",error_timeout:"Der Anbieter hat nicht rechtzeitig geantwortet.",error_invalid_topic:"Prüfe das Zigbee2MQTT-Basistopic.",error_invalid_payload:"Der Anbieter hat nicht unterstützte Topologiedaten geliefert.",error_provider:"Topologiedaten konnten nicht geladen werden.",remote_count:"+{n} in anderen Bereichen",route_device_not_on_plan:"Gerät ist nicht im Plan",route_coordinator_not_on_plan:"Koordinator ist nicht im Plan",route_other_space:"anderer Bereich"};const n="24813ef5e0b24d0f550c9e330f8ef7806dfb0724a8f69bd5e14e312c73438264";export{e as dictionary,n as fingerprint};
globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="1d6151ba58a0ce1dc15ed85a133606dca280b90dea173557fa34ac9531c10ffb";var e={title:"Zigbee-Verbindungen",toggle:"Zigbee-Verbindungen beim Darüberfahren über ein Gerät anzeigen",hint:"Es werden nur beobachtete direkte Nachbarn angezeigt. Beim Darüberfahren werden keine Daten abgerufen.",help:"Zeigt, mit welchen Zigbee-Geräten jedes Gerät direkt verbunden ist. Die Linienfarbe ist die Verbindungsqualität (LQI) auf derselben Skala wie der LQI-Wert des Geräts: rot bei 40 und darunter, grün bei 180 und darüber. Eine gestrichelte Linie bedeutet, dass die Qualität nicht gemeldet wurde. Ein Pfeil zeigt auf das nächste Gerät auf dem Weg zum Koordinator: ein Pfeil führt hinaus, eingehende Pfeile sind die Geräte, die über dieses Gerät routen. Eine Linie ohne Pfeil ist ein Ersatznachbar. Das ist der Routenbaum, den House Plan bildet, nicht der Weg eines Pakets in diesem Moment: eine Beschriftung am Pfeilende bedeutet, dass das Ziel nicht auf diesem Plan liegt, und ein fehlender Pfeil, dass die Route unbekannt ist. Die Daten stammen aus dem letzten Laden und veralten; Verbindungen sind nur mit der Maus sichtbar.",help_aria:"Hilfe: Zigbee-Verbindungen",admin_only:"Topologiedaten sind nur für Home-Assistant-Administratoren verfügbar.",save_first:"Speichere diese Einstellung, bevor Topologiedaten geladen werden.",zha:"ZHA",zha_read:"ZHA-Daten lesen",zha_hint:"Liest den ZHA-Topologiecache; es wird kein Funkscan gestartet.",z2m:"Zigbee2MQTT",z2m_topics:"Basistopics (eines pro Zeile)",z2m_update:"Karte aktualisieren",z2m_warning:"Ein Netzwerkscan kann 10 Sekunden bis 2 Minuten dauern und Zigbee vorübergehend verlangsamen.",status_idle:"Daten nicht geladen",status_loading:"Wird geladen…",status_ready:"Empfangen: {time}",status_stale:"Empfangen: {time} · veraltet",status_partial:"Empfangen: {time} · einige Knoten fehlen",status_no_links:"Empfangen: {time} · keine beobachteten Verbindungen gefunden",error_permission:"Administratorrechte sind erforderlich.",error_unsupported:"Dieser Anbieter oder die Home-Assistant-API ist nicht verfügbar.",error_timeout:"Der Anbieter hat nicht rechtzeitig geantwortet.",error_invalid_topic:"Prüfe das Zigbee2MQTT-Basistopic.",error_invalid_payload:"Der Anbieter hat nicht unterstützte Topologiedaten geliefert.",error_provider:"Topologiedaten konnten nicht geladen werden.",remote_count:"+{n} in anderen Bereichen",route_device_not_on_plan:"Gerät ist nicht im Plan",route_coordinator_not_on_plan:"Koordinator ist nicht im Plan",route_other_space:"anderer Bereich"};const n="1d6151ba58a0ce1dc15ed85a133606dca280b90dea173557fa34ac9531c10ffb";export{e as dictionary,n as fingerprint};
@@ -1 +1 @@
globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="24813ef5e0b24d0f550c9e330f8ef7806dfb0724a8f69bd5e14e312c73438264";var e={title:"Liens Zigbee",toggle:"Afficher les liens Zigbee au survol d’un appareil",hint:"Seuls les voisins directs observés sont affichés. Le survol ne lance aucune requête.",help:"Montre avec quels appareils Zigbee chaque appareil communique directement. La couleur de la ligne est la qualité du lien (LQI) sur la même échelle que l'indicateur LQI de l'appareil : rouge à 40 et en dessous, vert à 180 et au-dessus. Une ligne pointillée signifie que la qualité n'a pas été communiquée. Une flèche pointe vers l'appareil suivant sur le chemin du coordinateur : une flèche part, les flèches entrantes sont les appareils qui passent par celui-ci. Une ligne sans flèche est un voisin de secours. C'est l'arbre de routes que construit House Plan, pas le trajet d'un paquet à cet instant : une étiquette au bout d'une flèche signifie que sa cible n'est pas sur ce plan, et l'absence de flèche que la route est inconnue. Les données proviennent du dernier chargement et vieillissent ; les liens ne sont visibles qu'à la souris.",help_aria:"Aide : liens Zigbee",admin_only:"Les données de topologie sont réservées aux administrateurs Home Assistant.",save_first:"Enregistrez ce réglage avant de charger les données de topologie.",zha:"ZHA",zha_read:"Lire les données ZHA",zha_hint:"Lit la topologie en cache de ZHA sans lancer d’analyse radio.",z2m:"Zigbee2MQTT",z2m_topics:"Topics de base (un par ligne)",z2m_update:"Actualiser la carte",z2m_warning:"L’analyse de la carte réseau peut durer de 10 secondes à 2 minutes et réduire temporairement la réactivité de Zigbee.",status_idle:"Données non chargées",status_loading:"Chargement…",status_ready:"Reçu : {time}",status_stale:"Reçu : {time} · obsolète",status_partial:"Reçu : {time} · certains nœuds sont omis",status_no_links:"Reçu : {time} · aucun lien observé trouvé",error_permission:"Les droits administrateur sont requis.",error_unsupported:"Ce fournisseur ou l’API Home Assistant n’est pas disponible.",error_timeout:"Le fournisseur n’a pas répondu à temps.",error_invalid_topic:"Vérifiez le topic de base Zigbee2MQTT.",error_invalid_payload:"Le fournisseur a renvoyé des données de topologie non prises en charge.",error_provider:"Impossible de charger les données de topologie.",remote_count:"+{n} dans d’autres espaces",route_device_not_on_plan:"appareil absent du plan",route_coordinator_not_on_plan:"coordinateur absent du plan",route_other_space:"autre espace"};const s="24813ef5e0b24d0f550c9e330f8ef7806dfb0724a8f69bd5e14e312c73438264";export{e as dictionary,s as fingerprint};
globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="1d6151ba58a0ce1dc15ed85a133606dca280b90dea173557fa34ac9531c10ffb";var e={title:"Liens Zigbee",toggle:"Afficher les liens Zigbee au survol d’un appareil",hint:"Seuls les voisins directs observés sont affichés. Le survol ne lance aucune requête.",help:"Montre avec quels appareils Zigbee chaque appareil communique directement. La couleur de la ligne est la qualité du lien (LQI) sur la même échelle que l'indicateur LQI de l'appareil : rouge à 40 et en dessous, vert à 180 et au-dessus. Une ligne pointillée signifie que la qualité n'a pas été communiquée. Une flèche pointe vers l'appareil suivant sur le chemin du coordinateur : une flèche part, les flèches entrantes sont les appareils qui passent par celui-ci. Une ligne sans flèche est un voisin de secours. C'est l'arbre de routes que construit House Plan, pas le trajet d'un paquet à cet instant : une étiquette au bout d'une flèche signifie que sa cible n'est pas sur ce plan, et l'absence de flèche que la route est inconnue. Les données proviennent du dernier chargement et vieillissent ; les liens ne sont visibles qu'à la souris.",help_aria:"Aide : liens Zigbee",admin_only:"Les données de topologie sont réservées aux administrateurs Home Assistant.",save_first:"Enregistrez ce réglage avant de charger les données de topologie.",zha:"ZHA",zha_read:"Lire les données ZHA",zha_hint:"Lit la topologie en cache de ZHA sans lancer d’analyse radio.",z2m:"Zigbee2MQTT",z2m_topics:"Topics de base (un par ligne)",z2m_update:"Actualiser la carte",z2m_warning:"L’analyse de la carte réseau peut durer de 10 secondes à 2 minutes et réduire temporairement la réactivité de Zigbee.",status_idle:"Données non chargées",status_loading:"Chargement…",status_ready:"Reçu : {time}",status_stale:"Reçu : {time} · obsolète",status_partial:"Reçu : {time} · certains nœuds sont omis",status_no_links:"Reçu : {time} · aucun lien observé trouvé",error_permission:"Les droits administrateur sont requis.",error_unsupported:"Ce fournisseur ou l’API Home Assistant n’est pas disponible.",error_timeout:"Le fournisseur n’a pas répondu à temps.",error_invalid_topic:"Vérifiez le topic de base Zigbee2MQTT.",error_invalid_payload:"Le fournisseur a renvoyé des données de topologie non prises en charge.",error_provider:"Impossible de charger les données de topologie.",remote_count:"+{n} dans d’autres espaces",route_device_not_on_plan:"appareil absent du plan",route_coordinator_not_on_plan:"coordinateur absent du plan",route_other_space:"autre espace"};const s="1d6151ba58a0ce1dc15ed85a133606dca280b90dea173557fa34ac9531c10ffb";export{e as dictionary,s as fingerprint};
@@ -1 +1 @@
globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="24813ef5e0b24d0f550c9e330f8ef7806dfb0724a8f69bd5e14e312c73438264";var e={title:"Связи Zigbee",toggle:"Показывать связи Zigbee при наведении на устройство",hint:"Показываются только наблюдаемые прямые соседи. Наведение ничего не запрашивает.",help:"Показывает, с какими устройствами Zigbee каждое связано напрямую. Цвет линии — качество связи (LQI) по той же шкале, что у показателя LQI устройства: красный при 40 и ниже, зелёный при 180 и выше. Пунктир — качество не сообщено. Стрелка ведёт к следующему устройству по пути к координатору: исходящая одна, входящие — те, кто ходит через это устройство. Линия без стрелки — запасной сосед. Это дерево маршрутов, которое строит House Plan, а не путь пакета в эту секунду: подпись на конце стрелки значит, что цель не на этом плане, а отсутствие стрелки — что путь неизвестен. Данные из последней загрузки и устаревают, связи видны только при работе мышью.",help_aria:"Справка: связи Zigbee",admin_only:"Данные топологии доступны только администраторам Home Assistant.",save_first:"Сохраните настройку перед загрузкой данных топологии.",zha:"ZHA",zha_read:"Прочитать данные ZHA",zha_hint:"Читает сохранённую топологию ZHA и не запускает радио-сканирование.",z2m:"Zigbee2MQTT",z2m_topics:"Базовые топики (по одному в строке)",z2m_update:"Обновить карту",z2m_warning:"Сканирование карты сети занимает от 10 секунд до 2 минут и временно может снизить отзывчивость Zigbee.",status_idle:"Данные не загружены",status_loading:"Загрузка…",status_ready:"Получено: {time}",status_stale:"Получено: {time} · данные устарели",status_partial:"Получено: {time} · часть узлов не показана",status_no_links:"Получено: {time} · наблюдаемые связи не найдены",error_permission:"Нужны права администратора.",error_unsupported:"Провайдер или API Home Assistant недоступен.",error_timeout:"Провайдер не ответил вовремя.",error_invalid_topic:"Проверьте базовый топик Zigbee2MQTT.",error_invalid_payload:"Провайдер вернул неподдерживаемые данные топологии.",error_provider:"Не удалось загрузить данные топологии.",remote_count:"+{n} в других пространствах",route_device_not_on_plan:"устройства нет на плане",route_coordinator_not_on_plan:"координатора нет на плане",route_other_space:"другое пространство"};const t="24813ef5e0b24d0f550c9e330f8ef7806dfb0724a8f69bd5e14e312c73438264";export{e as dictionary,t as fingerprint};
globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="1d6151ba58a0ce1dc15ed85a133606dca280b90dea173557fa34ac9531c10ffb";var e={title:"Связи Zigbee",toggle:"Показывать связи Zigbee при наведении на устройство",hint:"Показываются только наблюдаемые прямые соседи. Наведение ничего не запрашивает.",help:"Показывает, с какими устройствами Zigbee каждое связано напрямую. Цвет линии — качество связи (LQI) по той же шкале, что у показателя LQI устройства: красный при 40 и ниже, зелёный при 180 и выше. Пунктир — качество не сообщено. Стрелка ведёт к следующему устройству по пути к координатору: исходящая одна, входящие — те, кто ходит через это устройство. Линия без стрелки — запасной сосед. Это дерево маршрутов, которое строит House Plan, а не путь пакета в эту секунду: подпись на конце стрелки значит, что цель не на этом плане, а отсутствие стрелки — что путь неизвестен. Данные из последней загрузки и устаревают, связи видны только при работе мышью.",help_aria:"Справка: связи Zigbee",admin_only:"Данные топологии доступны только администраторам Home Assistant.",save_first:"Сохраните настройку перед загрузкой данных топологии.",zha:"ZHA",zha_read:"Прочитать данные ZHA",zha_hint:"Читает сохранённую топологию ZHA и не запускает радио-сканирование.",z2m:"Zigbee2MQTT",z2m_topics:"Базовые топики (по одному в строке)",z2m_update:"Обновить карту",z2m_warning:"Сканирование карты сети занимает от 10 секунд до 2 минут и временно может снизить отзывчивость Zigbee.",status_idle:"Данные не загружены",status_loading:"Загрузка…",status_ready:"Получено: {time}",status_stale:"Получено: {time} · данные устарели",status_partial:"Получено: {time} · часть узлов не показана",status_no_links:"Получено: {time} · наблюдаемые связи не найдены",error_permission:"Нужны права администратора.",error_unsupported:"Провайдер или API Home Assistant недоступен.",error_timeout:"Провайдер не ответил вовремя.",error_invalid_topic:"Проверьте базовый топик Zigbee2MQTT.",error_invalid_payload:"Провайдер вернул неподдерживаемые данные топологии.",error_provider:"Не удалось загрузить данные топологии.",remote_count:"+{n} в других пространствах",route_device_not_on_plan:"устройства нет на плане",route_coordinator_not_on_plan:"координатора нет на плане",route_other_space:"другое пространство"};const a="1d6151ba58a0ce1dc15ed85a133606dca280b90dea173557fa34ac9531c10ffb";export{e as dictionary,a as fingerprint};
@@ -1 +1 @@
globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="24813ef5e0b24d0f550c9e330f8ef7806dfb0724a8f69bd5e14e312c73438264";import{n as t,c as n}from"./zigbee-topology-CcCg6XRV.js";import{aM as e}from"./houseplan-card-B4joz-YO.js";import"./namespace-language-BYcyqH-y.js";const o=new WeakMap;function i(t){const n=function(t){const n=t?.connection||t;return!n||"object"!=typeof n&&"function"!=typeof n?null:n}(t);if(!n)return null;let e=o.get(n);return e||(e={revision:0,topologies:[],states:{},listeners:new Set,inflight:new Map},o.set(n,e)),e}function r(t,n,e){t.states={...t.states,[n]:e},function(t){t.revision++;for(const n of t.listeners)n()}(t)}function s(t){const n=t?.code;if("permission"===n||"unsupported"===n||"timeout"===n||"invalid_topic"===n||"invalid_payload"===n)return n;const e=String(t?.message||"").toLowerCase();return e.includes("unauthor")||e.includes("permission")?"permission":e.includes("unknown_command")||e.includes("not found")?"unsupported":"provider"}function a(t){return Object.assign(new Error(t),{code:t})}function c(t,n,e){const o=t.inflight.get(n);if(o)return o;r(t,n,{phase:"loading"});const i=e().then(n=>{if(!n.nodes.length&&n.warnings.some(t=>"invalid_payload"===t.code))throw a("invalid_payload");!function(t,n){t.topologies=[...t.topologies.filter(t=>!(t.provider===n.provider&&t.instanceId===n.instanceId)),n],r(t,"zha"===n.provider?"zha":`z2m:${n.instanceId}`,{phase:"ready",obtainedAt:n.obtainedAt,partial:n.warnings.length>0})}(t,n)}).catch(e=>{r(t,n,{phase:"error",error:s(e)})}).finally(()=>t.inflight.delete(n));return t.inflight.set(n,i),i}function l(t){const n=i(t);return n?{revision:n.revision,topologies:n.topologies,states:n.states}:{revision:0,topologies:[],states:{}}}function u(t,n){const e=i(t);return e?(e.listeners.add(n),()=>e.listeners.delete(n)):()=>{}}function p(t){if(!0!==t?.user?.is_admin)throw a("permission")}function f(n){const e=i(n);return e?c(e,"zha",async()=>{if(p(n),"function"!=typeof n?.callWS)throw a("unsupported");return t(await n.callWS({type:"zha/devices"}))}):Promise.resolve()}function d(t){return null!==t&&"object"==typeof t?t:null}function h(t){const n=d(t),e=n?.payload??t;if("string"!=typeof e)return e;try{return JSON.parse(e)}catch{return null}}async function m(t,n){let e;try{return await Promise.race([t,new Promise((t,o)=>{e=globalThis.setTimeout(()=>o(a("timeout")),Math.max(1,n))})])}finally{void 0!==e&&globalThis.clearTimeout(e)}}function g(t,o,r=15e4){const s=i(t);if(!s)return Promise.resolve();const l=e(o);return c(s,`z2m:${l||String(o)}`,async()=>{if(p(t),!l)throw a("invalid_topic");const e=t.connection,o=e?.subscribeMessage;if("function"!=typeof o||"function"!=typeof t?.callService)throw a("unsupported");const i=function(){const t=globalThis.crypto;return"function"==typeof t?.randomUUID?`houseplan-${t.randomUUID()}`:`houseplan-${Date.now().toString(36)}-${Math.random().toString(36).slice(2)}`}(),s=Date.now()+Math.max(1,r);let c=!1,u=null,f=null,g=null;const y=new Promise(t=>{u=t}),w=new Promise((t,n)=>{f=t,g=n}),b=[];try{const r=await o.call(e,t=>{!0===d(t)?.retain&&h(t)&&u?.()},{type:"mqtt/subscribe",topic:`${l}/bridge/info`});"function"==typeof r&&b.push(r);const p=await o.call(e,t=>{if(!0===d(t)?.retain)return;const n=h(t);null!==n?n&&function(t){const n=d(t),e=n?.transaction??d(n?.data)?.transaction;return"string"==typeof e||"number"==typeof e?String(e):null}(n)===i&&f?.(n):c&&g?.(a("invalid_payload"))},{type:"mqtt/subscribe",topic:`${l}/bridge/response/networkmap`});"function"==typeof p&&b.push(p),await m(y,Math.min(4e3,Math.max(1,s-Date.now()))),c=!0,await t.callService("mqtt","publish",{topic:`${l}/bridge/request/networkmap`,payload:JSON.stringify({type:"raw",routes:!1,transaction:i}),qos:0,retain:!1});const v=await m(w,s-Date.now()),_=d(v)?.status;if(_&&"ok"!==_)throw a("provider");return n(v,l)}finally{for(const t of b)try{t()}catch{}}})}export{f as readZhaTopology,g as refreshZ2mTopology,u as subscribeZigbeeTopology,l as zigbeeTopologyRuntimeSnapshot};
globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="1d6151ba58a0ce1dc15ed85a133606dca280b90dea173557fa34ac9531c10ffb";import{n as t,c as n}from"./zigbee-topology-DgG5_y8E.js";import{aM as e}from"./houseplan-card-C_DbrDoi.js";import"./namespace-language-CaTQ_Mbw.js";const o=new WeakMap;function i(t){const n=function(t){const n=t?.connection||t;return!n||"object"!=typeof n&&"function"!=typeof n?null:n}(t);if(!n)return null;let e=o.get(n);return e||(e={revision:0,topologies:[],states:{},listeners:new Set,inflight:new Map},o.set(n,e)),e}function r(t,n,e){t.states={...t.states,[n]:e},function(t){t.revision++;for(const n of t.listeners)n()}(t)}function s(t){const n=t?.code;if("permission"===n||"unsupported"===n||"timeout"===n||"invalid_topic"===n||"invalid_payload"===n)return n;const e=String(t?.message||"").toLowerCase();return e.includes("unauthor")||e.includes("permission")?"permission":e.includes("unknown_command")||e.includes("not found")?"unsupported":"provider"}function a(t){return Object.assign(new Error(t),{code:t})}function c(t,n,e){const o=t.inflight.get(n);if(o)return o;r(t,n,{phase:"loading"});const i=e().then(n=>{if(!n.nodes.length&&n.warnings.some(t=>"invalid_payload"===t.code))throw a("invalid_payload");!function(t,n){t.topologies=[...t.topologies.filter(t=>!(t.provider===n.provider&&t.instanceId===n.instanceId)),n],r(t,"zha"===n.provider?"zha":`z2m:${n.instanceId}`,{phase:"ready",obtainedAt:n.obtainedAt,partial:n.warnings.length>0})}(t,n)}).catch(e=>{r(t,n,{phase:"error",error:s(e)})}).finally(()=>t.inflight.delete(n));return t.inflight.set(n,i),i}function l(t){const n=i(t);return n?{revision:n.revision,topologies:n.topologies,states:n.states}:{revision:0,topologies:[],states:{}}}function u(t,n){const e=i(t);return e?(e.listeners.add(n),()=>e.listeners.delete(n)):()=>{}}function p(t){if(!0!==t?.user?.is_admin)throw a("permission")}function f(n){const e=i(n);return e?c(e,"zha",async()=>{if(p(n),"function"!=typeof n?.callWS)throw a("unsupported");return t(await n.callWS({type:"zha/devices"}))}):Promise.resolve()}function d(t){return null!==t&&"object"==typeof t?t:null}function h(t){const n=d(t),e=n?.payload??t;if("string"!=typeof e)return e;try{return JSON.parse(e)}catch{return null}}async function m(t,n){let e;try{return await Promise.race([t,new Promise((t,o)=>{e=globalThis.setTimeout(()=>o(a("timeout")),Math.max(1,n))})])}finally{void 0!==e&&globalThis.clearTimeout(e)}}function g(t,o,r=15e4){const s=i(t);if(!s)return Promise.resolve();const l=e(o);return c(s,`z2m:${l||String(o)}`,async()=>{if(p(t),!l)throw a("invalid_topic");const e=t.connection,o=e?.subscribeMessage;if("function"!=typeof o||"function"!=typeof t?.callService)throw a("unsupported");const i=function(){const t=globalThis.crypto;return"function"==typeof t?.randomUUID?`houseplan-${t.randomUUID()}`:`houseplan-${Date.now().toString(36)}-${Math.random().toString(36).slice(2)}`}(),s=Date.now()+Math.max(1,r);let c=!1,u=null,f=null,g=null;const y=new Promise(t=>{u=t}),w=new Promise((t,n)=>{f=t,g=n}),b=[];try{const r=await o.call(e,t=>{!0===d(t)?.retain&&h(t)&&u?.()},{type:"mqtt/subscribe",topic:`${l}/bridge/info`});"function"==typeof r&&b.push(r);const p=await o.call(e,t=>{if(!0===d(t)?.retain)return;const n=h(t);null!==n?n&&function(t){const n=d(t),e=n?.transaction??d(n?.data)?.transaction;return"string"==typeof e||"number"==typeof e?String(e):null}(n)===i&&f?.(n):c&&g?.(a("invalid_payload"))},{type:"mqtt/subscribe",topic:`${l}/bridge/response/networkmap`});"function"==typeof p&&b.push(p),await m(y,Math.min(4e3,Math.max(1,s-Date.now()))),c=!0,await t.callService("mqtt","publish",{topic:`${l}/bridge/request/networkmap`,payload:JSON.stringify({type:"raw",routes:!1,transaction:i}),qos:0,retain:!1});const v=await m(w,s-Date.now()),_=d(v)?.status;if(_&&"ok"!==_)throw a("provider");return n(v,l)}finally{for(const t of b)try{t()}catch{}}})}export{f as readZhaTopology,g as refreshZ2mTopology,u as subscribeZigbeeTopology,l as zigbeeTopologyRuntimeSnapshot};
@@ -1 +1 @@
globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="24813ef5e0b24d0f550c9e330f8ef7806dfb0724a8f69bd5e14e312c73438264";try{await import("./houseplan-assets/houseplan-card-B4joz-YO.js")}catch(e){if(!customElements.get("houseplan-card")){const l=String(navigator.language||"en").toLowerCase();const m=l.startsWith("ru")?"House Plan обновился — перезагрузите страницу (Ctrl+F5).":l.startsWith("de")?"House Plan wurde aktualisiert — bitte laden Sie die Seite neu (Strg+F5).":l.startsWith("fr")?"House Plan a été mis à jour — veuillez recharger la page (Ctrl+F5).":"House Plan was updated — please reload the page (Ctrl+F5).";customElements.define("houseplan-card",class extends HTMLElement{setConfig(){}getCardSize(){return 1}connectedCallback(){this.style.cssText="display:block;box-sizing:border-box;padding:16px;border:1px solid var(--divider-color,#e0e0e0);border-radius:var(--ha-card-border-radius,12px);background:var(--card-background-color,#fff);color:var(--primary-text-color,#212121);font:14px/1.4 var(--paper-font-body1_-_font-family,sans-serif)";this.textContent=m}})}console.error("[houseplan] stale houseplan-card.js: the implementation chunk is unavailable",e)}
globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="1d6151ba58a0ce1dc15ed85a133606dca280b90dea173557fa34ac9531c10ffb";try{await import("./houseplan-assets/houseplan-card-C_DbrDoi.js")}catch(e){if(!customElements.get("houseplan-card")){const l=String(navigator.language||"en").toLowerCase();const m=l.startsWith("ru")?"House Plan обновился — перезагрузите страницу (Ctrl+F5).":l.startsWith("de")?"House Plan wurde aktualisiert — bitte laden Sie die Seite neu (Strg+F5).":l.startsWith("fr")?"House Plan a été mis à jour — veuillez recharger la page (Ctrl+F5).":"House Plan was updated — please reload the page (Ctrl+F5).";customElements.define("houseplan-card",class extends HTMLElement{setConfig(){}getCardSize(){return 1}connectedCallback(){this.style.cssText="display:block;box-sizing:border-box;padding:16px;border:1px solid var(--divider-color,#e0e0e0);border-radius:var(--ha-card-border-radius,12px);background:var(--card-background-color,#fff);color:var(--primary-text-color,#212121);font:14px/1.4 var(--paper-font-body1_-_font-family,sans-serif)";this.textContent=m}})}console.error("[houseplan] stale houseplan-card.js: the implementation chunk is unavailable",e)}
File diff suppressed because one or more lines are too long
+13 -6
View File
@@ -81,7 +81,8 @@ const kio = await page.evaluate(() => {
});
for (const [k, v] of Object.entries(kio)) check(k, v);
// мобильный вид: ряд вкладок переносится, а не выезжает за карточку
// мобильный вид (#616): ряд вкладок не выезжает за карточку, а «+» на ≤ 480 px
// живёт в меню шестерёнки — пункт есть, внутри карточки и попадает под палец.
await page.setViewportSize({ width: 390, height: 760 });
const narrow = await page.evaluate(async () => {
const out = {};
@@ -90,19 +91,25 @@ const narrow = await page.evaluate(async () => {
c.requestUpdate(); await c.updateComplete;
const sr = c.shadowRoot || c.renderRoot;
const head = sr.querySelector('.head');
const btn = sr.querySelector('.tab.tabadd');
out.narrowAddPresent = !!btn;
out.narrowNoHOverflow = head.scrollWidth <= head.clientWidth + 1
? true : `scrollW=${head.scrollWidth} > clientW=${head.clientWidth}`;
out.narrowInlineAddHidden = !sr.querySelector('.tab.tabadd')?.getClientRects().length;
sr.querySelector('[data-hp="header-menu"]')?.click();
await c.updateComplete;
const btn = sr.querySelector('[data-hp="header-menu-item"][data-id="space-add"]');
out.narrowAddPresent = !!btn;
btn?.scrollIntoView({ block: 'nearest', inline: 'nearest' });
const cr = sr.querySelector('ha-card').getBoundingClientRect();
const br = btn ? btn.getBoundingClientRect() : null;
out.narrowAddInsideCard = !br ? 'нет кнопки'
out.narrowAddInsideCard = !br ? 'нет пункта'
: br.right <= cr.right + 1 && br.left >= cr.left - 1 ? true
: `btn ${Math.round(br.left)}..${Math.round(br.right)} vs card ${Math.round(cr.left)}..${Math.round(cr.right)}`;
out.narrowAddHittable = !br ? 'нет кнопки' : (() => {
out.narrowAddHittable = !br ? 'нет пункта' : (() => {
const hit = sr.elementFromPoint(br.left + br.width / 2, br.top + br.height / 2);
return hit && hit.closest && hit.closest('.tab.tabadd') === btn ? true : 'перекрыта';
return hit && hit.closest && hit.closest('[data-hp="header-menu-item"]') === btn ? true : 'перекрыта';
})();
sr.querySelector('[data-hp="header-menu"]')?.click();
await c.updateComplete;
return out;
});
for (const [k, v] of Object.entries(narrow)) check(k, v);
+297
View File
@@ -0,0 +1,297 @@
// #616: компактная шапка на телефоне (≤ 480 px). В одной строке ≤ 56 px —
// вкладки пространств, зум и одна шестерёнка; всё, что строка убрала, — пункты
// её меню с теми же действиями, что у прежних кнопок. Тап вне меню поглощается,
// Escape возвращает фокус на шестерёнку, активная вкладка видна в прокрутке.
// На > 480 px шапка прежняя, в киоске меню нет. Клики — настоящие (Playwright
// по координатам), приватные поля карточки только читаются.
import { launch, check, finish } from './serve.mjs';
const { page, browser } = await launch({ width: 390, height: 844 }, 1);
// Как в golden: карточка во всю ширину окна, а не фиксированные 780 px стенда.
await page.addStyleTag({ content: '#host{width:min(100%,1120px)!important;margin:0 auto!important;padding:0!important}' });
const out = {};
const settle = () => page.evaluate(() => window.__hpTest.settled());
const size = async (width) => { await page.setViewportSize({ width, height: 844 }); await settle(); };
// Снимок шапки: что видно, одна ли строка, высота.
const header = () => page.evaluate(() => {
const sr = window.__card.shadowRoot;
const head = sr.querySelector('.hdr > .head');
const shown = (el) => !!el && el.getClientRects().length > 0 && getComputedStyle(el).visibility !== 'hidden';
const kids = [...head.children].filter((el) => shown(el) && el.getBoundingClientRect().width > 0);
const mids = kids.map((el) => { const r = el.getBoundingClientRect(); return r.top + r.height / 2; });
const gear = sr.querySelector('[data-hp="header-menu"]');
const g = gear?.getBoundingClientRect();
return {
height: head.getBoundingClientRect().height,
oneRow: mids.length > 0 && Math.max(...mids) - Math.min(...mids) <= 6,
title: shown(head.querySelector(':scope > .title')),
tabs: shown(head.querySelector(':scope > .tabs')),
zoom: shown(head.querySelector(':scope > .zoomctl')),
gear: shown(gear),
gear44: !!g && g.width >= 44 && g.height >= 44,
hiddenInline: ['.modes', '.header-action', '.summary-control', '.projection-toggle', '.tabedit', '.tabadd']
.filter((selector) => [...head.querySelectorAll(selector)].some(shown)),
tabEditInDom: !!head.querySelector('.tabedit, .tabadd'),
inlineVisible: ['.header-action', '.summary-control'].filter((selector) => [...head.querySelectorAll(selector)].some(shown)),
};
});
const menuState = () => page.evaluate(() => {
const sr = window.__card.shadowRoot;
const menu = sr.querySelector('#hp-header-menu');
const gear = sr.querySelector('[data-hp="header-menu"]');
const items = [...sr.querySelectorAll('[data-hp="header-menu-item"]')];
return {
open: !!menu, expanded: gear?.getAttribute('aria-expanded'),
ids: items.map((el) => el.dataset.id),
pressed: Object.fromEntries(items.filter((el) => el.hasAttribute('aria-pressed')).map((el) => [el.dataset.id, el.getAttribute('aria-pressed')])),
current: items.filter((el) => el.getAttribute('aria-current') === 'true').map((el) => el.dataset.id),
items44: items.every((el) => el.getBoundingClientRect().height >= 44),
inViewport: !menu || (() => { const r = menu.getBoundingClientRect(); return r.left >= 0 && r.right <= innerWidth + 0.5 && r.bottom <= innerHeight + 0.5; })(),
};
});
const clickAt = async (selector) => {
const box = await page.evaluate((s) => {
const el = window.__card.shadowRoot.querySelector(s);
if (!el) return null;
el.scrollIntoView({ block: 'nearest', inline: 'nearest' });
const r = el.getBoundingClientRect();
return { x: r.left + r.width / 2, y: r.top + r.height / 2 };
}, selector);
if (!box) throw new Error(`нет ${selector}`);
await page.mouse.click(box.x, box.y);
await settle();
};
const openMenu = async () => { if (!(await menuState()).open) await clickAt('[data-hp="header-menu"]'); };
const dialogKinds = () => page.evaluate(() => {
const kinds = [];
const walk = (root) => {
for (const d of root.querySelectorAll('hp-dialog[data-kind]')) kinds.push(d.getAttribute('data-kind'));
for (const el of root.querySelectorAll('*')) if (el.shadowRoot) walk(el.shadowRoot);
};
walk(window.__card.shadowRoot);
return kinds.sort();
});
const closeDialogs = async () => {
for (let i = 0; i < 4 && (await dialogKinds()).length; i++) {
await page.evaluate(() => window.__hpTest.close());
}
};
const mode = () => page.evaluate(() => window.__card.shadowRoot.querySelector('ha-card[data-hp-mode]')?.getAttribute('data-hp-mode'));
// ---- администратор (стенд) --------------------------------------------------
const ADMIN_VIEW = ['mode-plan', 'mode-devices', 'mode-decor', 'space-settings', 'space-add', 'settings', 'pdf', 'support', 'summary-settings', 'summary-toggle'];
for (const width of [390, 320]) {
await size(width);
const h = await header();
out[`admin${width}_oneRow56`] = h.oneRow && h.height <= 56;
out[`admin${width}_rowContent`] = !h.title && h.tabs && h.zoom && h.gear && h.gear44;
out[`admin${width}_inlineHidden`] = h.hiddenInline.length === 0 ? true : h.hiddenInline.join(',');
await openMenu();
const m = await menuState();
out[`admin${width}_menuItems`] = m.ids.join(',') === ADMIN_VIEW.join(',') ? true : m.ids.join(',');
out[`admin${width}_menuTargets`] = m.items44 && m.inViewport && m.expanded === 'true';
await clickAt('[data-hp="header-menu"]');
out[`admin${width}_gearToggles`] = !(await menuState()).open;
}
// Каждый пункт делает то же, что прежняя кнопка: сначала прежняя кнопка на
// 1400 px (эталон эффекта), потом пункт меню на 390 px.
const same = {};
for (const [id, inline] of [['settings', '[data-hp="settings"]'], ['pdf', '[data-hp="pdf"]'], ['support', '[data-hp="support"]'],
['space-settings', '[data-hp="space-settings"]'], ['space-add', '[data-hp="space-add"]'], ['summary-settings', '.summary-control > button:first-child']]) {
await size(1400);
await clickAt(inline);
await page.waitForTimeout(250);
const expected = await dialogKinds();
await closeDialogs();
await size(390);
await openMenu();
await clickAt(`[data-hp="header-menu-item"][data-id="${id}"]`);
await page.waitForTimeout(250);
const actual = await dialogKinds();
const closed = !(await menuState()).open;
// Открытое меню перехватывает Escape — диалог тогда не закрыть; это провал пункта, а не смока.
const closeError = await closeDialogs().then(() => '', (error) => String(error.message || error).slice(0, 80));
if ((await menuState()).open) await clickAt('[data-hp="header-menu"]');
if (closeError) await closeDialogs().catch(() => {});
same[id] = expected.length > 0 && expected.join() === actual.join() && closed && !closeError
? true : `${expected}|${actual}|closed=${closed}|${closeError}`;
}
out.itemsSameEffect = Object.values(same).every((v) => v === true) ? true : JSON.stringify(same);
// Сводная панель: переключатель меняет то же локальное состояние, что и кнопка.
await openMenu();
const before = (await menuState()).pressed['summary-toggle'];
await clickAt('[data-hp="header-menu-item"][data-id="summary-toggle"]');
await openMenu();
const after = (await menuState()).pressed['summary-toggle'];
await clickAt('[data-hp="header-menu-item"][data-id="summary-toggle"]');
out.summaryToggleFlips = before !== after && ['true', 'false'].includes(after);
// Редактор с телефона: вход из меню, строка одна, × виден и закрывает.
await openMenu();
await clickAt('[data-hp="header-menu-item"][data-id="mode-plan"]');
await page.waitForTimeout(300);
out.editorFromMenu = (await mode()) === 'plan';
const inEditor = await header();
out.editorOneRow56 = inEditor.oneRow && inEditor.height <= 56 && inEditor.hiddenInline.length === 0;
await openMenu();
const editorMenu = await menuState();
out.editorMenuMarksCurrent = editorMenu.current.join() === 'mode-plan' && !editorMenu.ids.includes('summary-toggle');
await clickAt('[data-hp="header-menu"]');
await clickAt('[data-hp="editor-close"]');
await page.waitForTimeout(300);
out.crossClosesOnPhone = (await mode()) === 'view';
// Escape закрывает меню и возвращает фокус на шестерёнку.
await openMenu();
await page.keyboard.press('Escape');
await settle();
out.escapeClosesAndFocuses = await page.evaluate(() => {
const sr = window.__card.shadowRoot;
return !sr.querySelector('#hp-header-menu') && sr.activeElement === sr.querySelector('[data-hp="header-menu"]');
});
// Тап вне меню поглощается: под пальцем маркер устройства, но до него тап не доходит.
const target = await page.evaluate(() => {
const sr = window.__card.shadowRoot;
const top = sr.querySelector('.hdr').getBoundingClientRect().bottom + 40;
for (const el of sr.querySelectorAll('[data-hp="device"]')) {
const r = el.getBoundingClientRect();
const x = r.left + r.width / 2; const y = r.top + r.height / 2;
if (r.width > 0 && y > top && y < innerHeight - 20 && x > 20 && x < innerWidth - 20) {
const hit = sr.elementFromPoint(x, y);
if (hit && (hit === el || el.contains(hit))) return { x, y, id: el.getAttribute('data-id') };
}
}
return null;
});
if (target) {
await openMenu();
const shield = await page.evaluate(({ x, y }) => window.__card.shadowRoot.elementFromPoint(x, y)?.getAttribute('data-hp'), target);
const states = () => page.evaluate(() => JSON.stringify(window.__card.hass.states));
const dialogsBefore = await dialogKinds();
const statesBefore = await states();
await page.mouse.click(target.x, target.y);
await settle();
await page.waitForTimeout(250);
out.outsideTapClosesMenu = !(await menuState()).open;
out.outsideTapSwallowed = shield === 'header-menu-scrim' && (await states()) === statesBefore
&& (await dialogKinds()).join() === dialogsBefore.join();
} else {
out.outsideTapClosesMenu = 'нет маркера под шапкой';
out.outsideTapSwallowed = 'нет маркера под шапкой';
}
// Много пространств с длинными названиями: строка одна, активная вкладка видна.
await page.evaluate(() => window.__hpTest.setServerConfig((cfg) => {
const base = cfg.spaces[0];
for (let i = 1; i <= 4; i++) {
cfg.spaces.push({ ...structuredClone(base), id: `smoke-long-${i}`, title: `Очень длинное пространство ${i}`, floor: undefined });
}
return cfg;
}));
await size(390);
const lastId = await page.evaluate(() => [...window.__card.shadowRoot.querySelectorAll('[data-hp="space-tab"]')].at(-1)?.dataset.id);
await page.evaluate((id) => window.__hpTest.switchSpace(id), lastId);
await page.waitForTimeout(200);
const tabVisible = () => page.evaluate(() => {
const sr = window.__card.shadowRoot;
const nav = sr.querySelector('.head .tabs').getBoundingClientRect();
const tab = sr.querySelector('.head .tab.active').getBoundingClientRect();
return tab.left >= nav.left - 0.5 && tab.right <= nav.right + 0.5;
});
const many = await header();
out.manySpacesOneRow = many.oneRow && many.height <= 56;
out.activeTabRevealedOnSwitch = await tabVisible();
const firstId = await page.evaluate(() => window.__card.shadowRoot.querySelector('[data-hp="space-tab"]').dataset.id);
await page.evaluate((id) => window.__hpTest.switchSpace(id), firstId);
await page.waitForTimeout(200);
out.activeTabRevealedBack = await tabVisible();
// > 480 px: прежняя шапка, кнопки меню не видно.
for (const width of [481, 768, 1400]) {
await size(width);
const w = await header();
out[`admin${width}_unchanged`] = !w.gear && w.inlineVisible.length === 2 && w.title ? true : JSON.stringify(w);
}
// ---- не-админ ---------------------------------------------------------------
await page.evaluate(async () => {
const base = window.__mkHass();
const hass = {
...base, user: { id: 'household', name: 'Household', is_admin: false },
callWS: async (m) => {
const r = await base.callWS(m);
return m.type === 'houseplan/config/get' ? { ...r, can_write: false } : r;
},
};
const host = document.getElementById('host');
host.replaceChildren();
const card = document.createElement('houseplan-card');
card.setConfig({ type: 'custom:houseplan-card', title: 'House Plan' });
host.append(card);
card.hass = hass;
window.__card = card;
const until = Date.now() + 8000;
while (Date.now() < until && !card.shadowRoot?.querySelector('[data-hp="space-tab"]')) await new Promise((r) => setTimeout(r, 50));
await new Promise((r) => setTimeout(r, 600));
});
for (const width of [390, 320]) {
await size(width);
const h = await header();
out[`household${width}_oneRow56`] = h.oneRow && h.height <= 56;
out[`household${width}_rowContent`] = !h.title && h.tabs && h.zoom && h.gear && !h.tabEditInDom;
await openMenu();
const m = await menuState();
out[`household${width}_menuItems`] = m.ids.join(',') === 'summary-settings,summary-toggle' ? true : m.ids.join(',');
await page.keyboard.press('Escape');
await settle();
}
// «После загрузки на последнем»: вкладка запомнена, новая карточка открывает
// её же — и докручивает в видимую область без участия человека.
await size(390);
const lastHouseholdId = await page.evaluate(() => [...window.__card.shadowRoot.querySelectorAll('[data-hp="space-tab"]')].at(-1)?.dataset.id);
await page.evaluate((id) => window.__hpTest.switchSpace(id), lastHouseholdId);
await page.evaluate(async () => {
const old = window.__card;
const hass = old.hass;
const host = document.getElementById('host');
host.replaceChildren();
const card = document.createElement('houseplan-card');
card.setConfig({ type: 'custom:houseplan-card', title: 'House Plan' });
host.append(card);
card.hass = hass;
window.__card = card;
const until = Date.now() + 8000;
while (Date.now() < until && !card.shadowRoot?.querySelector('.head .tab.active')) await new Promise((r) => setTimeout(r, 50));
await new Promise((r) => setTimeout(r, 800));
});
out.reloadOpensLastSpace = await page.evaluate((id) => window.__card.shadowRoot.querySelector('.head .tab.active')?.dataset.id === id, lastHouseholdId);
out.activeTabRevealedOnLoad = await tabVisible();
await size(1400);
const wide = await header();
out.household1400_noTabEditing = !wide.tabEditInDom && !wide.gear;
// ---- киоск: шапки нет, меню не рендерится ------------------------------------
await size(390);
await page.evaluate(async () => {
const host = document.getElementById('host');
host.replaceChildren();
const card = document.createElement('houseplan-card');
card.setConfig({ type: 'custom:houseplan-card', kiosk: true });
host.append(card);
card.hass = window.__mkHass();
window.__card = card;
const until = Date.now() + 8000;
while (Date.now() < until && !card.shadowRoot?.querySelector('.hdr')) await new Promise((r) => setTimeout(r, 50));
await new Promise((r) => setTimeout(r, 400));
});
out.kioskNoMenu = await page.evaluate(() => {
const sr = window.__card.shadowRoot;
return getComputedStyle(sr.querySelector('.hdr')).display === 'none' && !sr.querySelector('[data-hp="header-menu"]');
});
for (const [name, value] of Object.entries(out)) check(name, value);
await finish(browser, out);
+2 -1
View File
@@ -10,7 +10,8 @@ const st = () => page.evaluate(() => {
mode: c._mode,
modeTabs: sr.querySelectorAll('.modetab').length,
active: sr.querySelector('.modetab.active')?.textContent.trim(),
editBtns: sr.querySelectorAll('.head .btn:not(.zb)').length,
// #616: the phone gear (.header-menu-button) is in the DOM but hidden above 480 px.
editBtns: sr.querySelectorAll('.head .btn:not(.zb):not(.header-menu-button)').length,
gears: sr.querySelectorAll('.tabedit').length,
// The last bar stays mounted for the exit animation; only an open chrome
// is an active/visible editor bar.
+11 -2
View File
@@ -426,7 +426,16 @@ const responsive = async (viewport) => {
if (card._supportDialog) await card._editorRuntime._closeSupportDialog();
card._setMode('view');
await card.updateComplete;
const button = card.renderRoot.querySelector('.support-button');
// #616: at ≤ 480 px the entry point is the header menu item, not the header
// button (hidden there); its hit target is what the phone user taps.
let button = card.renderRoot.querySelector('.support-button');
let entryRect = null;
if (innerWidth <= 480) {
card.renderRoot.querySelector('[data-hp="header-menu"]')?.click();
await card.updateComplete;
button = card.renderRoot.querySelector('[data-hp="header-menu-item"][data-id="support"]');
entryRect = button?.getBoundingClientRect();
}
button?.click();
await card.updateComplete;
await new Promise((resolve) => requestAnimationFrame(() => requestAnimationFrame(resolve)));
@@ -434,7 +443,7 @@ const responsive = async (viewport) => {
const body = dialog?.querySelector('.supportbody');
const footer = dialog?.querySelector('.supportfooter');
const dialogRect = dialog?.getBoundingClientRect();
const buttonRect = button?.getBoundingClientRect();
const buttonRect = entryRect ?? button?.getBoundingClientRect();
return !!dialog && !!body && !!footer && !!dialogRect && !!buttonRect
&& dialogRect.left >= -1 && dialogRect.right <= innerWidth + 1
&& dialogRect.top >= -1 && dialogRect.bottom <= innerHeight + 1
+9 -3
View File
@@ -21,13 +21,18 @@ for (const width of WIDTHS) {
const head = () => sr().querySelector('.head');
const slot = () => sr().querySelector('.editor-close-slot');
const cross = () => sr().querySelector('.editor-close-slot .closex');
const tabs = () => [...sr().querySelectorAll('[data-hp="mode-tab"]')];
// #616: на ≤ 480 px кнопки режимов живут в меню шестерёнки; соседи × в строке —
// вкладки пространств, зум и шестерёнка, их положение и меряется.
const phone = width <= 480;
const tabs = () => [...sr().querySelectorAll(phone
? '.head > .tabs, .head > .zoomctl, [data-hp="header-menu"]' : '[data-hp="mode-tab"]')];
await hp.setMode('view');
await new Promise((resolve) => requestAnimationFrame(() => requestAnimationFrame(resolve)));
// Позиции — относительно левого края шапки: прокрутка страницы их не меняет.
const measure = () => {
const origin = head().getBoundingClientRect().left;
const nextEl = slot()?.nextElementSibling;
let nextEl = slot()?.nextElementSibling;
while (nextEl && !nextEl.getClientRects().length) nextEl = nextEl.nextElementSibling;
return {
head: head().getBoundingClientRect().width,
tabs: tabs().map((t) => t.getBoundingClientRect().left - origin),
@@ -35,7 +40,8 @@ for (const width of WIDTHS) {
next: nextEl ? nextEl.getBoundingClientRect().left - origin : null,
};
};
const visibleTabs = tabs().filter((t) => t.getBoundingClientRect().width > 0).length === 3;
const visibleTabs = tabs().filter((t) => t.getBoundingClientRect().width > 0).length === 3
&& (!phone || [...sr().querySelectorAll('[data-hp="mode-tab"]')].every((t) => !t.getClientRects().length));
o.tabsVisible = visibleTabs;
// AC1: числа нет — ни узла, ни текста вида «N dev.».
+206 -206
View File
@@ -1,436 +1,436 @@
{
"schema": 1,
"fingerprint": "24813ef5e0b24d0f550c9e330f8ef7806dfb0724a8f69bd5e14e312c73438264",
"fingerprint": "1d6151ba58a0ce1dc15ed85a133606dca280b90dea173557fa34ac9531c10ffb",
"entry": "houseplan-card.js",
"panelEntry": "houseplan-panel.js",
"initialViewFiles": [
"houseplan-assets/houseplan-card-B4joz-YO.js",
"houseplan-assets/houseplan-card-C_DbrDoi.js",
"houseplan-card.js"
],
"initialViewGzipBytes": 290052,
"initialViewGzipBytes": 291626,
"initialPanelFiles": [
"houseplan-assets/houseplan-card-B4joz-YO.js",
"houseplan-assets/houseplan-card-C_DbrDoi.js",
"houseplan-panel.js"
],
"initialPanelGzipBytes": 291574,
"initialPanelGzipBytes": 293148,
"initialPanelOnlyFiles": [
"houseplan-panel.js"
],
"initialPanelOnlyGzipBytes": 2327,
"initialPanelOnlyGzipBytes": 2322,
"lazyFiles": [
"houseplan-assets/backdrop-pick-D4aD5usf.js",
"houseplan-assets/de-CSQe6eub.js",
"houseplan-assets/editor-8h7C9dFV.js",
"houseplan-assets/form-kit.styles-Cqg1K3-F.js",
"houseplan-assets/fr-Dh71LzVb.js",
"houseplan-assets/furniture-plan-art.generated-CdVUTs9f.js",
"houseplan-assets/houseplan-editor-runtime-u-EF5jme.js",
"houseplan-assets/houseplan-onboarding-runtime-CvUernez.js",
"houseplan-assets/hp-zigbee-topology-overlay-BS2sDfiR.js",
"houseplan-assets/iso-scene-render-DeEYFVoG.js",
"houseplan-assets/live-interaction-runtime-C9YY0yeQ.js",
"houseplan-assets/namespace-language-BYcyqH-y.js",
"houseplan-assets/pdf-export-CCnDAi0D.js",
"houseplan-assets/summary-panel-runtime-loaded-DEMxCIRi.js",
"houseplan-assets/zigbee-topology-CcCg6XRV.js",
"houseplan-assets/zigbee-topology-runtime-DokImShf.js"
"houseplan-assets/backdrop-pick-Bz7hJpF4.js",
"houseplan-assets/de-VB-iDL1g.js",
"houseplan-assets/editor-DQBHGNp6.js",
"houseplan-assets/form-kit.styles-DM0qkJ72.js",
"houseplan-assets/fr-BfiF5RLs.js",
"houseplan-assets/furniture-plan-art.generated-CPBOH0tA.js",
"houseplan-assets/houseplan-editor-runtime-DutTWtCh.js",
"houseplan-assets/houseplan-onboarding-runtime-Co9leXWb.js",
"houseplan-assets/hp-zigbee-topology-overlay-DTsCpj16.js",
"houseplan-assets/iso-scene-render-C7ED1tZ2.js",
"houseplan-assets/live-interaction-runtime-DMtf8_eH.js",
"houseplan-assets/namespace-language-CaTQ_Mbw.js",
"houseplan-assets/pdf-export-DtfAv3U1.js",
"houseplan-assets/summary-panel-runtime-loaded-CSKGlmFL.js",
"houseplan-assets/zigbee-topology-DgG5_y8E.js",
"houseplan-assets/zigbee-topology-runtime-DxupIWcF.js"
],
"lazyGzipBytes": 448980,
"lazyGzipBytes": 449033,
"lazyEditorFiles": [
"houseplan-assets/backdrop-pick-D4aD5usf.js",
"houseplan-assets/editor-8h7C9dFV.js",
"houseplan-assets/form-kit.styles-Cqg1K3-F.js",
"houseplan-assets/furniture-plan-art.generated-CdVUTs9f.js",
"houseplan-assets/houseplan-editor-runtime-u-EF5jme.js",
"houseplan-assets/namespace-language-BYcyqH-y.js",
"houseplan-assets/zigbee-topology-CcCg6XRV.js"
"houseplan-assets/backdrop-pick-Bz7hJpF4.js",
"houseplan-assets/editor-DQBHGNp6.js",
"houseplan-assets/form-kit.styles-DM0qkJ72.js",
"houseplan-assets/furniture-plan-art.generated-CPBOH0tA.js",
"houseplan-assets/houseplan-editor-runtime-DutTWtCh.js",
"houseplan-assets/namespace-language-CaTQ_Mbw.js",
"houseplan-assets/zigbee-topology-DgG5_y8E.js"
],
"lazyEditorGzipBytes": 231941,
"lazyEditorGzipBytes": 231917,
"lazyOnboardingFiles": [
"houseplan-assets/backdrop-pick-D4aD5usf.js",
"houseplan-assets/form-kit.styles-Cqg1K3-F.js",
"houseplan-assets/houseplan-onboarding-runtime-CvUernez.js",
"houseplan-assets/namespace-language-BYcyqH-y.js"
"houseplan-assets/backdrop-pick-Bz7hJpF4.js",
"houseplan-assets/form-kit.styles-DM0qkJ72.js",
"houseplan-assets/houseplan-onboarding-runtime-Co9leXWb.js",
"houseplan-assets/namespace-language-CaTQ_Mbw.js"
],
"lazyOnboardingGzipBytes": 27903,
"lazyOnboardingGzipBytes": 27890,
"lazyLocaleFiles": [
"houseplan-assets/de-CSQe6eub.js",
"houseplan-assets/fr-Dh71LzVb.js"
"houseplan-assets/de-VB-iDL1g.js",
"houseplan-assets/fr-BfiF5RLs.js"
],
"lazyLocaleGzipBytes": 55674,
"lazyLocaleGzipBytes": 55693,
"lazyIsometricFiles": [
"houseplan-assets/iso-scene-render-DeEYFVoG.js"
"houseplan-assets/iso-scene-render-C7ED1tZ2.js"
],
"lazyIsometricGzipBytes": 17642,
"lazyIsometricGzipBytes": 17640,
"lazyFurnitureArtFiles": [
"houseplan-assets/furniture-plan-art.generated-CdVUTs9f.js"
"houseplan-assets/furniture-plan-art.generated-CPBOH0tA.js"
],
"lazyFurnitureArtGzipBytes": 16938,
"lazyFurnitureArtGzipBytes": 16940,
"lazyPdfFiles": [
"houseplan-assets/furniture-plan-art.generated-CdVUTs9f.js",
"houseplan-assets/pdf-export-CCnDAi0D.js"
"houseplan-assets/furniture-plan-art.generated-CPBOH0tA.js",
"houseplan-assets/pdf-export-DtfAv3U1.js"
],
"lazyPdfGzipBytes": 126825,
"lazyNamespaceLocaleFiles": [
"houseplan-assets/settings-de-HTN5Jwb3.js",
"houseplan-assets/settings-fr-Cu0K0jLh.js",
"houseplan-assets/settings-ru-mPF-h4Sr.js",
"houseplan-assets/support-de-DHkC6Wjm.js",
"houseplan-assets/support-fr-BdDUwgb3.js",
"houseplan-assets/support-ru-RZ8n67t7.js",
"houseplan-assets/topology-de-BJ666mPT.js",
"houseplan-assets/topology-fr-SHOT77wV.js",
"houseplan-assets/topology-ru-CDSUN1by.js"
"houseplan-assets/settings-de-BsLzFQwo.js",
"houseplan-assets/settings-fr-BUJAFfXA.js",
"houseplan-assets/settings-ru-CCGpXggj.js",
"houseplan-assets/support-de-Cs8HYxjq.js",
"houseplan-assets/support-fr-B3NcsP5x.js",
"houseplan-assets/support-ru-k4cHCEhB.js",
"houseplan-assets/topology-de-Uwmiwye1.js",
"houseplan-assets/topology-fr-CKSa9BzH.js",
"houseplan-assets/topology-ru-Ib-FDcAJ.js"
],
"lazyNamespaceLocaleGzipBytes": 20904,
"lazyNamespaceLocaleGzipBytes": 20876,
"files": [
{
"path": "houseplan-assets/backdrop-pick-D4aD5usf.js",
"sha256": "5cba278bb74bac9f2e1bbf709d772c26211d3ce0539e493ea196cabbe42a60f0",
"path": "houseplan-assets/backdrop-pick-Bz7hJpF4.js",
"sha256": "350299d7149a052cb53d91fcf601bd385427b2801d8498c6d8a33c3b15a1c472",
"rawBytes": 53888,
"gzipBytes": 17524,
"gzipBytes": 17522,
"isEntry": false,
"imports": [
"houseplan-assets/form-kit.styles-Cqg1K3-F.js",
"houseplan-assets/houseplan-card-B4joz-YO.js",
"houseplan-assets/namespace-language-BYcyqH-y.js"
"houseplan-assets/form-kit.styles-DM0qkJ72.js",
"houseplan-assets/houseplan-card-C_DbrDoi.js",
"houseplan-assets/namespace-language-CaTQ_Mbw.js"
],
"dynamicImports": [
"houseplan-assets/settings-de-HTN5Jwb3.js",
"houseplan-assets/settings-fr-Cu0K0jLh.js",
"houseplan-assets/settings-ru-mPF-h4Sr.js"
"houseplan-assets/settings-de-BsLzFQwo.js",
"houseplan-assets/settings-fr-BUJAFfXA.js",
"houseplan-assets/settings-ru-CCGpXggj.js"
]
},
{
"path": "houseplan-assets/de-CSQe6eub.js",
"sha256": "7cc2f4b7c80659d531c0a5850a43be9671173460415ac729acd6aa4472e93f65",
"rawBytes": 93034,
"gzipBytes": 28064,
"path": "houseplan-assets/de-VB-iDL1g.js",
"sha256": "e36748c22559aa830e9ff4ee9f7be25d44e20e3f395e57ce76ba9ef4d8286efe",
"rawBytes": 93083,
"gzipBytes": 28072,
"isEntry": false,
"imports": [],
"dynamicImports": []
},
{
"path": "houseplan-assets/editor-8h7C9dFV.js",
"sha256": "a6d7ddf821b1a21f4ee661eb9f5c8ff63a63f61d5cd7fc4772952ad7fc3d4ac3",
"path": "houseplan-assets/editor-DQBHGNp6.js",
"sha256": "cc64a5d977ec9bf02ac510bd97ed5e3167116609f3558708d90b303a52717b08",
"rawBytes": 3833,
"gzipBytes": 1584,
"gzipBytes": 1580,
"isEntry": false,
"imports": [
"houseplan-assets/houseplan-card-B4joz-YO.js"
"houseplan-assets/houseplan-card-C_DbrDoi.js"
],
"dynamicImports": []
},
{
"path": "houseplan-assets/form-kit.styles-Cqg1K3-F.js",
"sha256": "6f6610b54843341a4e29102712a9678f69cb6375dd636391939478f074ab50f4",
"path": "houseplan-assets/form-kit.styles-DM0qkJ72.js",
"sha256": "34dfe537bbb82eae5ac40f42786c6be679f3f155484210df72ad16a0892faaf2",
"rawBytes": 25600,
"gzipBytes": 5057,
"gzipBytes": 5055,
"isEntry": false,
"imports": [],
"dynamicImports": []
},
{
"path": "houseplan-assets/fr-Dh71LzVb.js",
"sha256": "834d506dac720eb993be19d336c601aeb53f199e4d8799d09943143c8247efcd",
"rawBytes": 95381,
"gzipBytes": 27610,
"path": "houseplan-assets/fr-BfiF5RLs.js",
"sha256": "9d66bd6595ebdbca5e957c025de80c465cb49d78d215a90ca1210261ed1457a7",
"rawBytes": 95424,
"gzipBytes": 27621,
"isEntry": false,
"imports": [],
"dynamicImports": []
},
{
"path": "houseplan-assets/furniture-plan-art.generated-CdVUTs9f.js",
"sha256": "efbb991928c394343bbe062963a704d4806b38d6064e5eb1cc07afc16ef41c2b",
"path": "houseplan-assets/furniture-plan-art.generated-CPBOH0tA.js",
"sha256": "45adddf9c0b9773ed9cd19e1c05cca97e11cc0caba6cb6502cb46b229eb847d4",
"rawBytes": 52035,
"gzipBytes": 16938,
"gzipBytes": 16940,
"isEntry": false,
"imports": [],
"dynamicImports": []
},
{
"path": "houseplan-assets/houseplan-card-B4joz-YO.js",
"sha256": "9730f2f454d3026e8bbcf36cb5e0ecf397f77fe839470e1214a7a060d315af42",
"rawBytes": 1024896,
"gzipBytes": 289247,
"path": "houseplan-assets/houseplan-card-C_DbrDoi.js",
"sha256": "46b34df9315327c7f69f2895cdc9c412bc7347bd27f231732ff450be1f083720",
"rawBytes": 1030556,
"gzipBytes": 290826,
"isEntry": false,
"imports": [],
"dynamicImports": [
"houseplan-assets/de-CSQe6eub.js",
"houseplan-assets/editor-8h7C9dFV.js",
"houseplan-assets/fr-Dh71LzVb.js",
"houseplan-assets/furniture-plan-art.generated-CdVUTs9f.js",
"houseplan-assets/houseplan-editor-runtime-u-EF5jme.js",
"houseplan-assets/houseplan-onboarding-runtime-CvUernez.js",
"houseplan-assets/hp-zigbee-topology-overlay-BS2sDfiR.js",
"houseplan-assets/iso-scene-render-DeEYFVoG.js",
"houseplan-assets/live-interaction-runtime-C9YY0yeQ.js",
"houseplan-assets/pdf-export-CCnDAi0D.js",
"houseplan-assets/summary-panel-runtime-loaded-DEMxCIRi.js"
"houseplan-assets/de-VB-iDL1g.js",
"houseplan-assets/editor-DQBHGNp6.js",
"houseplan-assets/fr-BfiF5RLs.js",
"houseplan-assets/furniture-plan-art.generated-CPBOH0tA.js",
"houseplan-assets/houseplan-editor-runtime-DutTWtCh.js",
"houseplan-assets/houseplan-onboarding-runtime-Co9leXWb.js",
"houseplan-assets/hp-zigbee-topology-overlay-DTsCpj16.js",
"houseplan-assets/iso-scene-render-C7ED1tZ2.js",
"houseplan-assets/live-interaction-runtime-DMtf8_eH.js",
"houseplan-assets/pdf-export-DtfAv3U1.js",
"houseplan-assets/summary-panel-runtime-loaded-CSKGlmFL.js"
]
},
{
"path": "houseplan-assets/houseplan-editor-runtime-u-EF5jme.js",
"sha256": "ce66247c36d42724cd1b9f66d0bfe0f2705929aa664aa5c03935e7ab2f1df7d0",
"path": "houseplan-assets/houseplan-editor-runtime-DutTWtCh.js",
"sha256": "92bfe9fc262153ba1949668fa5fbae24eb5da38edb3df6a02f9d2246d20bb0cf",
"rawBytes": 667315,
"gzipBytes": 186124,
"gzipBytes": 186119,
"isEntry": false,
"imports": [
"houseplan-assets/backdrop-pick-D4aD5usf.js",
"houseplan-assets/form-kit.styles-Cqg1K3-F.js",
"houseplan-assets/furniture-plan-art.generated-CdVUTs9f.js",
"houseplan-assets/houseplan-card-B4joz-YO.js",
"houseplan-assets/namespace-language-BYcyqH-y.js",
"houseplan-assets/zigbee-topology-CcCg6XRV.js"
"houseplan-assets/backdrop-pick-Bz7hJpF4.js",
"houseplan-assets/form-kit.styles-DM0qkJ72.js",
"houseplan-assets/furniture-plan-art.generated-CPBOH0tA.js",
"houseplan-assets/houseplan-card-C_DbrDoi.js",
"houseplan-assets/namespace-language-CaTQ_Mbw.js",
"houseplan-assets/zigbee-topology-DgG5_y8E.js"
],
"dynamicImports": [
"houseplan-assets/support-de-DHkC6Wjm.js",
"houseplan-assets/support-fr-BdDUwgb3.js",
"houseplan-assets/support-ru-RZ8n67t7.js",
"houseplan-assets/zigbee-topology-runtime-DokImShf.js"
"houseplan-assets/support-de-Cs8HYxjq.js",
"houseplan-assets/support-fr-B3NcsP5x.js",
"houseplan-assets/support-ru-k4cHCEhB.js",
"houseplan-assets/zigbee-topology-runtime-DxupIWcF.js"
]
},
{
"path": "houseplan-assets/houseplan-onboarding-runtime-CvUernez.js",
"sha256": "da9b468fd43654b9265696a4b61204c46a70ff7b6dbd1e236b6413ad688fa233",
"path": "houseplan-assets/houseplan-onboarding-runtime-Co9leXWb.js",
"sha256": "9d6a434656cde134477479db58662ddd3d54c299e7745049a753c80004b79c3e",
"rawBytes": 15886,
"gzipBytes": 4910,
"gzipBytes": 4905,
"isEntry": false,
"imports": [
"houseplan-assets/backdrop-pick-D4aD5usf.js",
"houseplan-assets/form-kit.styles-Cqg1K3-F.js",
"houseplan-assets/houseplan-card-B4joz-YO.js",
"houseplan-assets/namespace-language-BYcyqH-y.js"
"houseplan-assets/backdrop-pick-Bz7hJpF4.js",
"houseplan-assets/form-kit.styles-DM0qkJ72.js",
"houseplan-assets/houseplan-card-C_DbrDoi.js",
"houseplan-assets/namespace-language-CaTQ_Mbw.js"
],
"dynamicImports": []
},
{
"path": "houseplan-assets/hp-zigbee-topology-overlay-BS2sDfiR.js",
"sha256": "2dd7cf101133530d59cdfb10afbad166b3df0a33c5653ffb9990473622721a8f",
"path": "houseplan-assets/hp-zigbee-topology-overlay-DTsCpj16.js",
"sha256": "4a4f0e5f6e5ccb6a50f4865a49900c449a8d0d61227bc4cba80cc22ca31fa648",
"rawBytes": 10958,
"gzipBytes": 3767,
"gzipBytes": 3764,
"isEntry": false,
"imports": [
"houseplan-assets/houseplan-card-B4joz-YO.js",
"houseplan-assets/namespace-language-BYcyqH-y.js",
"houseplan-assets/zigbee-topology-CcCg6XRV.js",
"houseplan-assets/zigbee-topology-runtime-DokImShf.js"
"houseplan-assets/houseplan-card-C_DbrDoi.js",
"houseplan-assets/namespace-language-CaTQ_Mbw.js",
"houseplan-assets/zigbee-topology-DgG5_y8E.js",
"houseplan-assets/zigbee-topology-runtime-DxupIWcF.js"
],
"dynamicImports": []
},
{
"path": "houseplan-assets/iso-scene-render-DeEYFVoG.js",
"sha256": "db33e97b3530f4f241921ddb4921977863e29145aeed1bf4737152b615e2948a",
"path": "houseplan-assets/iso-scene-render-C7ED1tZ2.js",
"sha256": "2a784be05890d7e7520b5632a972ebe00d0b4c7d29869ff3b0e3b41a1d4fab8d",
"rawBytes": 51983,
"gzipBytes": 17642,
"gzipBytes": 17640,
"isEntry": false,
"imports": [
"houseplan-assets/houseplan-card-B4joz-YO.js"
"houseplan-assets/houseplan-card-C_DbrDoi.js"
],
"dynamicImports": []
},
{
"path": "houseplan-assets/live-interaction-runtime-C9YY0yeQ.js",
"sha256": "d1a44279a5d79dfdac22870473ba1a712198034ce1aa58e97e1a4bddeddbcb13",
"path": "houseplan-assets/live-interaction-runtime-DMtf8_eH.js",
"sha256": "90387449e12a77bdb17f665fa5f2440b5795eb899e8ceec8086c4e61f1b63f3c",
"rawBytes": 8216,
"gzipBytes": 3206,
"gzipBytes": 3204,
"isEntry": false,
"imports": [
"houseplan-assets/houseplan-card-B4joz-YO.js"
"houseplan-assets/houseplan-card-C_DbrDoi.js"
],
"dynamicImports": []
},
{
"path": "houseplan-assets/namespace-language-BYcyqH-y.js",
"sha256": "0eaa7380f1d79bf929be82084c0aed262880fb160683887d962f235ad5d64295",
"path": "houseplan-assets/namespace-language-CaTQ_Mbw.js",
"sha256": "ceb020823bfc799edadbc276f361748f56bfdbe2eb4b51db81d33b7646fc4200",
"rawBytes": 675,
"gzipBytes": 412,
"gzipBytes": 408,
"isEntry": false,
"imports": [
"houseplan-assets/houseplan-card-B4joz-YO.js"
"houseplan-assets/houseplan-card-C_DbrDoi.js"
],
"dynamicImports": []
},
{
"path": "houseplan-assets/pdf-export-CCnDAi0D.js",
"sha256": "d97fc1612c07914c4466a188d389cf61267b4ca2ba4165bba23fef5b9e204b58",
"path": "houseplan-assets/pdf-export-DtfAv3U1.js",
"sha256": "e973cc5f41add5f1d8f8c8a8957bd83439d888a61e6abbd1826534e92a20e354",
"rawBytes": 236264,
"gzipBytes": 109887,
"gzipBytes": 109885,
"isEntry": false,
"imports": [
"houseplan-assets/furniture-plan-art.generated-CdVUTs9f.js",
"houseplan-assets/houseplan-card-B4joz-YO.js"
"houseplan-assets/furniture-plan-art.generated-CPBOH0tA.js",
"houseplan-assets/houseplan-card-C_DbrDoi.js"
],
"dynamicImports": []
},
{
"path": "houseplan-assets/settings-de-HTN5Jwb3.js",
"sha256": "a884ce3c5cdb63ec15889e3f332fc208178bbc2cee8c9e41f9963814e95b671a",
"path": "houseplan-assets/settings-de-BsLzFQwo.js",
"sha256": "25a89c6fd096db94f94d37e9bc0d8e8fe9bef5f34034da00babc64aacbcc4d9e",
"rawBytes": 7248,
"gzipBytes": 2826,
"gzipBytes": 2823,
"isEntry": false,
"imports": [],
"dynamicImports": []
},
{
"path": "houseplan-assets/settings-fr-Cu0K0jLh.js",
"sha256": "ff3400bc130198f8922fb4b88c82b388e28ecaf1cd90aac858bc5ed8b5519ad6",
"path": "houseplan-assets/settings-fr-BUJAFfXA.js",
"sha256": "f682adb4e762eace27b5eaf9bdbcd0ab0199bb39412d3cab5d0f56075a6a8d3d",
"rawBytes": 7483,
"gzipBytes": 2788,
"gzipBytes": 2784,
"isEntry": false,
"imports": [],
"dynamicImports": []
},
{
"path": "houseplan-assets/settings-ru-mPF-h4Sr.js",
"sha256": "f7fdef6c801cda38e11217273824dbda8aab3bdeac756d5f40f03361d5c3a099",
"path": "houseplan-assets/settings-ru-CCGpXggj.js",
"sha256": "681d6b2bbac7dff0aa693b8260141a635203396e9c26f95677ca329873228653",
"rawBytes": 10128,
"gzipBytes": 3273,
"gzipBytes": 3270,
"isEntry": false,
"imports": [],
"dynamicImports": []
},
{
"path": "houseplan-assets/summary-panel-editor-Rflrcwgs.js",
"sha256": "e1d3e4d56cf13ec4724d20e44a0cdca84a0879e304e08bc3762639c26c888b1b",
"path": "houseplan-assets/summary-panel-editor-BYh50PV_.js",
"sha256": "8e87a35b3806ef5b98bdd65eefa9fa482d7de062ba22d22267c0c098964aac9d",
"rawBytes": 14862,
"gzipBytes": 3430,
"gzipBytes": 3423,
"isEntry": false,
"imports": [
"houseplan-assets/form-kit.styles-Cqg1K3-F.js",
"houseplan-assets/houseplan-card-B4joz-YO.js",
"houseplan-assets/summary-panel-runtime-loaded-DEMxCIRi.js"
"houseplan-assets/form-kit.styles-DM0qkJ72.js",
"houseplan-assets/houseplan-card-C_DbrDoi.js",
"houseplan-assets/summary-panel-runtime-loaded-CSKGlmFL.js"
],
"dynamicImports": []
},
{
"path": "houseplan-assets/summary-panel-metrics-C32cC2x4.js",
"sha256": "ca293e294e686fd021361fa40f207adb35aad2b390d90573884476d4487fe619",
"path": "houseplan-assets/summary-panel-metrics-CUaycNn2.js",
"sha256": "682848fd7a5104f76e0aa202e4ecdc835272ab5de70eae4ba0db66d81d698fec",
"rawBytes": 2611,
"gzipBytes": 1307,
"gzipBytes": 1302,
"isEntry": false,
"imports": [
"houseplan-assets/houseplan-card-B4joz-YO.js"
"houseplan-assets/houseplan-card-C_DbrDoi.js"
],
"dynamicImports": []
},
{
"path": "houseplan-assets/summary-panel-runtime-loaded-DEMxCIRi.js",
"sha256": "c63a95699435e821e0b3eeb1c24b12d98d3b7c614b2b6c16d3a6cf0b60ca6a70",
"rawBytes": 72637,
"gzipBytes": 20162,
"path": "houseplan-assets/summary-panel-runtime-loaded-CSKGlmFL.js",
"sha256": "60c380a98a02c13d25c0fe6a4544017a84498a0509afaa41894c475ed787a275",
"rawBytes": 72956,
"gzipBytes": 20238,
"isEntry": false,
"imports": [
"houseplan-assets/form-kit.styles-Cqg1K3-F.js",
"houseplan-assets/houseplan-card-B4joz-YO.js"
"houseplan-assets/form-kit.styles-DM0qkJ72.js",
"houseplan-assets/houseplan-card-C_DbrDoi.js"
],
"dynamicImports": [
"houseplan-assets/summary-panel-editor-Rflrcwgs.js",
"houseplan-assets/summary-panel-metrics-C32cC2x4.js"
"houseplan-assets/summary-panel-editor-BYh50PV_.js",
"houseplan-assets/summary-panel-metrics-CUaycNn2.js"
]
},
{
"path": "houseplan-assets/support-de-DHkC6Wjm.js",
"sha256": "16cc51b1639440e2ea04c50ef20feb663cdc3953b463119559db5f3118ff2083",
"path": "houseplan-assets/support-de-Cs8HYxjq.js",
"sha256": "66f3812a322232a9373bb15a8cdc38c2d50d60f1146edea0adbcd0b5f96ec48a",
"rawBytes": 6167,
"gzipBytes": 2399,
"gzipBytes": 2395,
"isEntry": false,
"imports": [],
"dynamicImports": []
},
{
"path": "houseplan-assets/support-fr-BdDUwgb3.js",
"sha256": "e9aecf2130ab83711bc114ec9d4b251edaad69b318d1cb519d7aa1fc70ed9daa",
"path": "houseplan-assets/support-fr-B3NcsP5x.js",
"sha256": "856b622a98ac9861401ed364e510e6de6b5abdc911fec8201355c56c52493eea",
"rawBytes": 6333,
"gzipBytes": 2433,
"gzipBytes": 2429,
"isEntry": false,
"imports": [],
"dynamicImports": []
},
{
"path": "houseplan-assets/support-ru-RZ8n67t7.js",
"sha256": "2119dbbce4133700daee48826a67255c3ddbd660c8876f04f1b39b56a866ca31",
"path": "houseplan-assets/support-ru-k4cHCEhB.js",
"sha256": "e542140f6e6be396835fe0cb1b2ea2acfed810cf3239cffa4d1bd820d77b11ee",
"rawBytes": 8376,
"gzipBytes": 2878,
"gzipBytes": 2875,
"isEntry": false,
"imports": [],
"dynamicImports": []
},
{
"path": "houseplan-assets/topology-de-BJ666mPT.js",
"sha256": "3a04273c59dea448e4d5fcc19b9671b123e964d17c256cc289d5d6464b7386fc",
"path": "houseplan-assets/topology-de-Uwmiwye1.js",
"sha256": "dd585dc78a9f200e43d5909d5c72b57e86d11333c9ba7405e988b3a83d147414",
"rawBytes": 2698,
"gzipBytes": 1335,
"gzipBytes": 1333,
"isEntry": false,
"imports": [],
"dynamicImports": []
},
{
"path": "houseplan-assets/topology-fr-SHOT77wV.js",
"sha256": "40a71548a23c392623c97ab143f9bc06a5262f610561a8d3050b953dd002faa2",
"path": "houseplan-assets/topology-fr-CKSa9BzH.js",
"sha256": "b7058476bb543892b5da6dc760d9ee3eb45021b47dfb724cf7d19fb510c77a0c",
"rawBytes": 2718,
"gzipBytes": 1356,
"gzipBytes": 1353,
"isEntry": false,
"imports": [],
"dynamicImports": []
},
{
"path": "houseplan-assets/topology-ru-CDSUN1by.js",
"sha256": "8a982c8d089794ae4c1dcfd30741fa1b0fa17d0e34b19be8e7160ce94cdf261a",
"path": "houseplan-assets/topology-ru-Ib-FDcAJ.js",
"sha256": "9f53d289d1dd543ba8795e2bc523a7e5cab5a5c3cf4ff34c766e02f42c707fb5",
"rawBytes": 3669,
"gzipBytes": 1616,
"gzipBytes": 1614,
"isEntry": false,
"imports": [],
"dynamicImports": []
},
{
"path": "houseplan-assets/zigbee-topology-CcCg6XRV.js",
"sha256": "cd8d3d0b16900240b4f96724bcd08dbb31b5ed25a1c3dd50adf82645c583c830",
"path": "houseplan-assets/zigbee-topology-DgG5_y8E.js",
"sha256": "395bad3d94b8bd570ae380fc47f3ba063f33fb145bda2ff84928c374aa0ec723",
"rawBytes": 10958,
"gzipBytes": 4302,
"gzipBytes": 4293,
"isEntry": false,
"imports": [
"houseplan-assets/houseplan-card-B4joz-YO.js",
"houseplan-assets/namespace-language-BYcyqH-y.js"
"houseplan-assets/houseplan-card-C_DbrDoi.js",
"houseplan-assets/namespace-language-CaTQ_Mbw.js"
],
"dynamicImports": [
"houseplan-assets/topology-de-BJ666mPT.js",
"houseplan-assets/topology-fr-SHOT77wV.js",
"houseplan-assets/topology-ru-CDSUN1by.js"
"houseplan-assets/topology-de-Uwmiwye1.js",
"houseplan-assets/topology-fr-CKSa9BzH.js",
"houseplan-assets/topology-ru-Ib-FDcAJ.js"
]
},
{
"path": "houseplan-assets/zigbee-topology-runtime-DokImShf.js",
"sha256": "4959616d27f0369955687c2813e88001a11f263799bed0bdfabacdf207558d15",
"path": "houseplan-assets/zigbee-topology-runtime-DxupIWcF.js",
"sha256": "87f04630b08483cdc29451e92a0be8ffa6355cc096825d58f6418a766c6a2d95",
"rawBytes": 3983,
"gzipBytes": 1791,
"gzipBytes": 1787,
"isEntry": false,
"imports": [
"houseplan-assets/houseplan-card-B4joz-YO.js",
"houseplan-assets/namespace-language-BYcyqH-y.js",
"houseplan-assets/zigbee-topology-CcCg6XRV.js"
"houseplan-assets/houseplan-card-C_DbrDoi.js",
"houseplan-assets/namespace-language-CaTQ_Mbw.js",
"houseplan-assets/zigbee-topology-DgG5_y8E.js"
],
"dynamicImports": []
},
{
"path": "houseplan-card.js",
"sha256": "4e9f8fb5bb4ac6fb8c982c42f12595fb704112437ca24a17d5026844917f1e8e",
"sha256": "0f22a82da607d75edf6267268399a5b50e86143a4b4fe1b582cd7cde7ef6ca11",
"rawBytes": 1205,
"gzipBytes": 805,
"gzipBytes": 800,
"isEntry": true,
"imports": [
"houseplan-assets/houseplan-card-B4joz-YO.js"
"houseplan-assets/houseplan-card-C_DbrDoi.js"
],
"dynamicImports": []
},
{
"path": "houseplan-panel.js",
"sha256": "5eff237665abb540e69511ede6760f1100c65b718bc6bbd9e66c725595435222",
"sha256": "d112fa85e40363bb1441d40a48de625de3373ae01682db6e74a68d092c043201",
"rawBytes": 6165,
"gzipBytes": 2327,
"gzipBytes": 2322,
"isEntry": true,
"imports": [
"houseplan-assets/houseplan-card-B4joz-YO.js"
"houseplan-assets/houseplan-card-C_DbrDoi.js"
],
"dynamicImports": []
}
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -1,14 +1,14 @@
globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="24813ef5e0b24d0f550c9e330f8ef7806dfb0724a8f69bd5e14e312c73438264";import{aD as e,l as o,aG as t,ee as s,A as a,ef as i,eg as l,eh as n,E as r,c}from"./houseplan-card-B4joz-YO.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
globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="1d6151ba58a0ce1dc15ed85a133606dca280b90dea173557fa34ac9531c10ffb";import{aD as e,l as o,aG as t,ee as s,A as a,ef as i,eg as l,eh as n,E as r,c}from"./houseplan-card-C_DbrDoi.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
.hass=${this.hass}
.data=${this._formData}
.schema=${e}
.computeLabel=${e=>f[e.name]||e.name}
.computeLabel=${e=>h[e.name]||e.name}
@value-changed=${this._valueChanged}
></ha-form>`;return c`
${d(h.slice(0,3))}
${d(f.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(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);
${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);
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
-1
View File
@@ -1 +0,0 @@
globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="24813ef5e0b24d0f550c9e330f8ef7806dfb0724a8f69bd5e14e312c73438264";import{ej as e,ek as n,eg as o}from"./houseplan-card-B4joz-YO.js";function r(o,r){return new e([{code:"en",dictionary:o},{code:"ru",loadDictionary:r.ru},{code:"de",loadDictionary:r.de},{code:"fr",loadDictionary:r.fr}],"24813ef5e0b24d0f550c9e330f8ef7806dfb0724a8f69bd5e14e312c73438264",console.warn,n)}function a(e){return function(e,n){return{state:o=>{const r=e.state(o);return"pending"!==r&&n.some(e=>"pending"===e.state(o))?"pending":r},dictionary:n=>e.dictionary(n),ensure:o=>Promise.all([e,...n].map(e=>e.ensure(o))).then(()=>{})}}(o,e)}export{r as n,a as s};
+1
View File
@@ -0,0 +1 @@
globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="1d6151ba58a0ce1dc15ed85a133606dca280b90dea173557fa34ac9531c10ffb";import{ej as a,ek as e,eg as n}from"./houseplan-card-C_DbrDoi.js";function c(n,c){return new a([{code:"en",dictionary:n},{code:"ru",loadDictionary:c.ru},{code:"de",loadDictionary:c.de},{code:"fr",loadDictionary:c.fr}],"1d6151ba58a0ce1dc15ed85a133606dca280b90dea173557fa34ac9531c10ffb",console.warn,e)}function d(a){return function(a,e){return{state:n=>{const c=a.state(n);return"pending"!==c&&e.some(a=>"pending"===a.state(n))?"pending":c},dictionary:e=>a.dictionary(e),ensure:n=>Promise.all([a,...e].map(a=>a.ensure(n))).then(()=>{})}}(n,a)}export{c as n,d as s};
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -1,4 +1,4 @@
globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="24813ef5e0b24d0f550c9e330f8ef7806dfb0724a8f69bd5e14e312c73438264";import{c as a,A as e}from"./houseplan-card-B4joz-YO.js";import{s,n as t,a as l,m as r,b as o,c as i,d as u}from"./summary-panel-runtime-loaded-DEMxCIRi.js";import"./form-kit.styles-Cqg1K3-F.js";const m=m=>{const{host:c,dialog:d,problems:n,t:b}=m,y=n.find(a=>"error"===a.kind),$=d.localShow!==d.baseLocalShow||!d.localOnly&&!s(t(d.draft),d.base),p=$&&!d.busy&&!y,v=a=>n.find(e=>e.path===a),h=a=>a?b(`summary.problem.${a.code}`):"",k=()=>m.close(),g=a`<label class="summary-switch" for="summary-local-show">
globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="1d6151ba58a0ce1dc15ed85a133606dca280b90dea173557fa34ac9531c10ffb";import{c as a,A as e}from"./houseplan-card-C_DbrDoi.js";import{s,n as t,a as l,m as r,b as o,c as i,d as u}from"./summary-panel-runtime-loaded-CSKGlmFL.js";import"./form-kit.styles-DM0qkJ72.js";const m=m=>{const{host:c,dialog:d,problems:n,t:b}=m,y=n.find(a=>"error"===a.kind),$=d.localShow!==d.baseLocalShow||!d.localOnly&&!s(t(d.draft),d.base),p=$&&!d.busy&&!y,v=a=>n.find(e=>e.path===a),h=a=>a?b(`summary.problem.${a.code}`):"",k=()=>m.close(),g=a`<label class="summary-switch" for="summary-local-show">
<span class="summary-switch-caption"><strong>${b("summary.show_local")}</strong>
<small id="summary-local-show-hint">${b("summary.show_local_hint")}</small></span>
<input id="summary-local-show" data-summary-local-show type="checkbox"
@@ -1 +0,0 @@
globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="24813ef5e0b24d0f550c9e330f8ef7806dfb0724a8f69bd5e14e312c73438264";import{em as e,N as t,b2 as n,L as i,ae as o,ac as r,bY as s,bX as a,b1 as l,b0 as c,b3 as u,en as d,eo as f,b_ as m,ep as g}from"./houseplan-card-B4joz-YO.js";function v(e){if(!e.registry.authoritative)return null;const t=new Set,n=u(e.markers);for(const i of Object.values(e.registry.devices||{}))i?.id&&"service"!==i.entry_type&&!n.devices.has(i.id)&&i.area_id&&e.areaToSpace[i.area_id]&&t.add(i.id);for(const i of e.markers||[]){if(i.removed||"virtual"===i.binding)continue;const o=String(i.binding||"").indexOf(":");if(o<1)continue;const r=i.binding.slice(0,o),s=i.binding.slice(o+1),a="device"===r?e.registry.devices?.[s]:null,l="entity"===r?e.registry.entities?.[s]:null,c="device"===r?s:l?.device_id,u="device"===r?a?.area_id:l?.area_id||c&&e.registry.devices?.[c]?.area_id,d="string"==typeof i.room_id&&i.room_id.length>0&&null===i.area?"":i.area||u||"",f=d&&e.areaToSpace[d]||i.space||e.firstSpaceId;c&&e.registry.devices?.[c]&&e.spaceIds.has(f)&&(!n.devices.has(c)||"entity"===r&&n.liveEntities.has(s))&&t.add(c)}return t}function y(e,t){return e?.length?t?.length?g(e,t):e:t}function _(e,t){const n=l(e.rooms,t.walls,t.openCuts,[],i,t.cellCm,o,r);return{roomGeom:"ok"===n.status||"degraded-extra"===n.status?n.roomGeom:void 0,multiWallNodes:c(e.rooms,t.walls,t.openCuts,i,t.cellCm,o,r)}}function*b(l,c,u=_){try{let d=0;for(const f of c){const c=l.spaces.find(e=>String(e?.id)===f.id);if(!c)continue;const m=e(c,f),g=u(f,m);let v=null;for(const e of f.rooms){if(!e.id)continue;const a=t(e);if(!a)continue;const l=n(f.rooms,e.id,m.walls,m.openCuts,i,m.cellCm,o,r,g.roomGeom,g.multiWallNodes)||a;v=y(v,s(l,m.physicalBodies)),yield}const _=m.cellCm/o;d+=a(v)*_*_/1e4}return d}catch{return null}}function p(e,t,n=_){const i=b(e,t,n);let o=i.next();for(;!o.done;)o=i.next();return o.value}function h(e,t,n,i){if("system"!==e.type)return null;if("device_count"===e.key)return null===t.deviceCount?null:String(t.deviceCount);if("total_area"===e.key)return null===t.areaM2?null:m(t.areaM2,"mi"===n?.config?.unit_system?.length);try{return new Intl.DateTimeFormat(i||void 0,{dateStyle:"short",timeStyle:"short",timeZone:n?.config?.time_zone||void 0}).format(t.now)}catch{return t.now.toLocaleString()}}function S(e,t){const n=e?.states?.[t];if(!n)return null;const i=d(e,t);return i?f(i,String(n.attributes?.unit_of_measurement||"")):null}export{b as cleanFloorAreaSteps,v as representedHaDeviceIds,_ as spaceWallGeometry,S as summaryEntityValue,h as summarySystemValue,p as totalCleanFloorAreaM2};
@@ -0,0 +1 @@
globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="1d6151ba58a0ce1dc15ed85a133606dca280b90dea173557fa34ac9531c10ffb";import{em as e,N as t,b2 as n,L as i,ae as o,ac as r,bY as s,bX as a,b1 as c,b0 as l,b3 as d,en as u,eo as f,b_ as m,ep as g}from"./houseplan-card-C_DbrDoi.js";function v(e){if(!e.registry.authoritative)return null;const t=new Set,n=d(e.markers);for(const i of Object.values(e.registry.devices||{}))i?.id&&"service"!==i.entry_type&&!n.devices.has(i.id)&&i.area_id&&e.areaToSpace[i.area_id]&&t.add(i.id);for(const i of e.markers||[]){if(i.removed||"virtual"===i.binding)continue;const o=String(i.binding||"").indexOf(":");if(o<1)continue;const r=i.binding.slice(0,o),s=i.binding.slice(o+1),a="device"===r?e.registry.devices?.[s]:null,c="entity"===r?e.registry.entities?.[s]:null,l="device"===r?s:c?.device_id,d="device"===r?a?.area_id:c?.area_id||l&&e.registry.devices?.[l]?.area_id,u="string"==typeof i.room_id&&i.room_id.length>0&&null===i.area?"":i.area||d||"",f=u&&e.areaToSpace[u]||i.space||e.firstSpaceId;l&&e.registry.devices?.[l]&&e.spaceIds.has(f)&&(!n.devices.has(l)||"entity"===r&&n.liveEntities.has(s))&&t.add(l)}return t}function y(e,t){return e?.length?t?.length?g(e,t):e:t}function _(e,t){const n=c(e.rooms,t.walls,t.openCuts,[],i,t.cellCm,o,r);return{roomGeom:"ok"===n.status||"degraded-extra"===n.status?n.roomGeom:void 0,multiWallNodes:l(e.rooms,t.walls,t.openCuts,i,t.cellCm,o,r)}}function*b(c,l,d=_){try{let u=0;for(const f of l){const l=c.spaces.find(e=>String(e?.id)===f.id);if(!l)continue;const m=e(l,f),g=d(f,m);let v=null;for(const e of f.rooms){if(!e.id)continue;const a=t(e);if(!a)continue;const c=n(f.rooms,e.id,m.walls,m.openCuts,i,m.cellCm,o,r,g.roomGeom,g.multiWallNodes)||a;v=y(v,s(c,m.physicalBodies)),yield}const _=m.cellCm/o;u+=a(v)*_*_/1e4}return u}catch{return null}}function p(e,t,n=_){const i=b(e,t,n);let o=i.next();for(;!o.done;)o=i.next();return o.value}function h(e,t,n,i){if("system"!==e.type)return null;if("device_count"===e.key)return null===t.deviceCount?null:String(t.deviceCount);if("total_area"===e.key)return null===t.areaM2?null:m(t.areaM2,"mi"===n?.config?.unit_system?.length);try{return new Intl.DateTimeFormat(i||void 0,{dateStyle:"short",timeStyle:"short",timeZone:n?.config?.time_zone||void 0}).format(t.now)}catch{return t.now.toLocaleString()}}function S(e,t){const n=e?.states?.[t];if(!n)return null;const i=u(e,t);return i?f(i,String(n.attributes?.unit_of_measurement||"")):null}export{b as cleanFloorAreaSteps,v as representedHaDeviceIds,_ as spaceWallGeometry,S as summaryEntityValue,h as summarySystemValue,p as totalCleanFloorAreaM2};
File diff suppressed because one or more lines are too long
@@ -1 +1 @@
globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="24813ef5e0b24d0f550c9e330f8ef7806dfb0724a8f69bd5e14e312c73438264";var e={title:"Zigbee-Verbindungen",toggle:"Zigbee-Verbindungen beim Darüberfahren über ein Gerät anzeigen",hint:"Es werden nur beobachtete direkte Nachbarn angezeigt. Beim Darüberfahren werden keine Daten abgerufen.",help:"Zeigt, mit welchen Zigbee-Geräten jedes Gerät direkt verbunden ist. Die Linienfarbe ist die Verbindungsqualität (LQI) auf derselben Skala wie der LQI-Wert des Geräts: rot bei 40 und darunter, grün bei 180 und darüber. Eine gestrichelte Linie bedeutet, dass die Qualität nicht gemeldet wurde. Ein Pfeil zeigt auf das nächste Gerät auf dem Weg zum Koordinator: ein Pfeil führt hinaus, eingehende Pfeile sind die Geräte, die über dieses Gerät routen. Eine Linie ohne Pfeil ist ein Ersatznachbar. Das ist der Routenbaum, den House Plan bildet, nicht der Weg eines Pakets in diesem Moment: eine Beschriftung am Pfeilende bedeutet, dass das Ziel nicht auf diesem Plan liegt, und ein fehlender Pfeil, dass die Route unbekannt ist. Die Daten stammen aus dem letzten Laden und veralten; Verbindungen sind nur mit der Maus sichtbar.",help_aria:"Hilfe: Zigbee-Verbindungen",admin_only:"Topologiedaten sind nur für Home-Assistant-Administratoren verfügbar.",save_first:"Speichere diese Einstellung, bevor Topologiedaten geladen werden.",zha:"ZHA",zha_read:"ZHA-Daten lesen",zha_hint:"Liest den ZHA-Topologiecache; es wird kein Funkscan gestartet.",z2m:"Zigbee2MQTT",z2m_topics:"Basistopics (eines pro Zeile)",z2m_update:"Karte aktualisieren",z2m_warning:"Ein Netzwerkscan kann 10 Sekunden bis 2 Minuten dauern und Zigbee vorübergehend verlangsamen.",status_idle:"Daten nicht geladen",status_loading:"Wird geladen…",status_ready:"Empfangen: {time}",status_stale:"Empfangen: {time} · veraltet",status_partial:"Empfangen: {time} · einige Knoten fehlen",status_no_links:"Empfangen: {time} · keine beobachteten Verbindungen gefunden",error_permission:"Administratorrechte sind erforderlich.",error_unsupported:"Dieser Anbieter oder die Home-Assistant-API ist nicht verfügbar.",error_timeout:"Der Anbieter hat nicht rechtzeitig geantwortet.",error_invalid_topic:"Prüfe das Zigbee2MQTT-Basistopic.",error_invalid_payload:"Der Anbieter hat nicht unterstützte Topologiedaten geliefert.",error_provider:"Topologiedaten konnten nicht geladen werden.",remote_count:"+{n} in anderen Bereichen",route_device_not_on_plan:"Gerät ist nicht im Plan",route_coordinator_not_on_plan:"Koordinator ist nicht im Plan",route_other_space:"anderer Bereich"};const n="24813ef5e0b24d0f550c9e330f8ef7806dfb0724a8f69bd5e14e312c73438264";export{e as dictionary,n as fingerprint};
globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="1d6151ba58a0ce1dc15ed85a133606dca280b90dea173557fa34ac9531c10ffb";var e={title:"Zigbee-Verbindungen",toggle:"Zigbee-Verbindungen beim Darüberfahren über ein Gerät anzeigen",hint:"Es werden nur beobachtete direkte Nachbarn angezeigt. Beim Darüberfahren werden keine Daten abgerufen.",help:"Zeigt, mit welchen Zigbee-Geräten jedes Gerät direkt verbunden ist. Die Linienfarbe ist die Verbindungsqualität (LQI) auf derselben Skala wie der LQI-Wert des Geräts: rot bei 40 und darunter, grün bei 180 und darüber. Eine gestrichelte Linie bedeutet, dass die Qualität nicht gemeldet wurde. Ein Pfeil zeigt auf das nächste Gerät auf dem Weg zum Koordinator: ein Pfeil führt hinaus, eingehende Pfeile sind die Geräte, die über dieses Gerät routen. Eine Linie ohne Pfeil ist ein Ersatznachbar. Das ist der Routenbaum, den House Plan bildet, nicht der Weg eines Pakets in diesem Moment: eine Beschriftung am Pfeilende bedeutet, dass das Ziel nicht auf diesem Plan liegt, und ein fehlender Pfeil, dass die Route unbekannt ist. Die Daten stammen aus dem letzten Laden und veralten; Verbindungen sind nur mit der Maus sichtbar.",help_aria:"Hilfe: Zigbee-Verbindungen",admin_only:"Topologiedaten sind nur für Home-Assistant-Administratoren verfügbar.",save_first:"Speichere diese Einstellung, bevor Topologiedaten geladen werden.",zha:"ZHA",zha_read:"ZHA-Daten lesen",zha_hint:"Liest den ZHA-Topologiecache; es wird kein Funkscan gestartet.",z2m:"Zigbee2MQTT",z2m_topics:"Basistopics (eines pro Zeile)",z2m_update:"Karte aktualisieren",z2m_warning:"Ein Netzwerkscan kann 10 Sekunden bis 2 Minuten dauern und Zigbee vorübergehend verlangsamen.",status_idle:"Daten nicht geladen",status_loading:"Wird geladen…",status_ready:"Empfangen: {time}",status_stale:"Empfangen: {time} · veraltet",status_partial:"Empfangen: {time} · einige Knoten fehlen",status_no_links:"Empfangen: {time} · keine beobachteten Verbindungen gefunden",error_permission:"Administratorrechte sind erforderlich.",error_unsupported:"Dieser Anbieter oder die Home-Assistant-API ist nicht verfügbar.",error_timeout:"Der Anbieter hat nicht rechtzeitig geantwortet.",error_invalid_topic:"Prüfe das Zigbee2MQTT-Basistopic.",error_invalid_payload:"Der Anbieter hat nicht unterstützte Topologiedaten geliefert.",error_provider:"Topologiedaten konnten nicht geladen werden.",remote_count:"+{n} in anderen Bereichen",route_device_not_on_plan:"Gerät ist nicht im Plan",route_coordinator_not_on_plan:"Koordinator ist nicht im Plan",route_other_space:"anderer Bereich"};const n="1d6151ba58a0ce1dc15ed85a133606dca280b90dea173557fa34ac9531c10ffb";export{e as dictionary,n as fingerprint};
@@ -1 +1 @@
globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="24813ef5e0b24d0f550c9e330f8ef7806dfb0724a8f69bd5e14e312c73438264";var e={title:"Liens Zigbee",toggle:"Afficher les liens Zigbee au survol d’un appareil",hint:"Seuls les voisins directs observés sont affichés. Le survol ne lance aucune requête.",help:"Montre avec quels appareils Zigbee chaque appareil communique directement. La couleur de la ligne est la qualité du lien (LQI) sur la même échelle que l'indicateur LQI de l'appareil : rouge à 40 et en dessous, vert à 180 et au-dessus. Une ligne pointillée signifie que la qualité n'a pas été communiquée. Une flèche pointe vers l'appareil suivant sur le chemin du coordinateur : une flèche part, les flèches entrantes sont les appareils qui passent par celui-ci. Une ligne sans flèche est un voisin de secours. C'est l'arbre de routes que construit House Plan, pas le trajet d'un paquet à cet instant : une étiquette au bout d'une flèche signifie que sa cible n'est pas sur ce plan, et l'absence de flèche que la route est inconnue. Les données proviennent du dernier chargement et vieillissent ; les liens ne sont visibles qu'à la souris.",help_aria:"Aide : liens Zigbee",admin_only:"Les données de topologie sont réservées aux administrateurs Home Assistant.",save_first:"Enregistrez ce réglage avant de charger les données de topologie.",zha:"ZHA",zha_read:"Lire les données ZHA",zha_hint:"Lit la topologie en cache de ZHA sans lancer d’analyse radio.",z2m:"Zigbee2MQTT",z2m_topics:"Topics de base (un par ligne)",z2m_update:"Actualiser la carte",z2m_warning:"L’analyse de la carte réseau peut durer de 10 secondes à 2 minutes et réduire temporairement la réactivité de Zigbee.",status_idle:"Données non chargées",status_loading:"Chargement…",status_ready:"Reçu : {time}",status_stale:"Reçu : {time} · obsolète",status_partial:"Reçu : {time} · certains nœuds sont omis",status_no_links:"Reçu : {time} · aucun lien observé trouvé",error_permission:"Les droits administrateur sont requis.",error_unsupported:"Ce fournisseur ou l’API Home Assistant n’est pas disponible.",error_timeout:"Le fournisseur n’a pas répondu à temps.",error_invalid_topic:"Vérifiez le topic de base Zigbee2MQTT.",error_invalid_payload:"Le fournisseur a renvoyé des données de topologie non prises en charge.",error_provider:"Impossible de charger les données de topologie.",remote_count:"+{n} dans d’autres espaces",route_device_not_on_plan:"appareil absent du plan",route_coordinator_not_on_plan:"coordinateur absent du plan",route_other_space:"autre espace"};const s="24813ef5e0b24d0f550c9e330f8ef7806dfb0724a8f69bd5e14e312c73438264";export{e as dictionary,s as fingerprint};
globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="1d6151ba58a0ce1dc15ed85a133606dca280b90dea173557fa34ac9531c10ffb";var e={title:"Liens Zigbee",toggle:"Afficher les liens Zigbee au survol d’un appareil",hint:"Seuls les voisins directs observés sont affichés. Le survol ne lance aucune requête.",help:"Montre avec quels appareils Zigbee chaque appareil communique directement. La couleur de la ligne est la qualité du lien (LQI) sur la même échelle que l'indicateur LQI de l'appareil : rouge à 40 et en dessous, vert à 180 et au-dessus. Une ligne pointillée signifie que la qualité n'a pas été communiquée. Une flèche pointe vers l'appareil suivant sur le chemin du coordinateur : une flèche part, les flèches entrantes sont les appareils qui passent par celui-ci. Une ligne sans flèche est un voisin de secours. C'est l'arbre de routes que construit House Plan, pas le trajet d'un paquet à cet instant : une étiquette au bout d'une flèche signifie que sa cible n'est pas sur ce plan, et l'absence de flèche que la route est inconnue. Les données proviennent du dernier chargement et vieillissent ; les liens ne sont visibles qu'à la souris.",help_aria:"Aide : liens Zigbee",admin_only:"Les données de topologie sont réservées aux administrateurs Home Assistant.",save_first:"Enregistrez ce réglage avant de charger les données de topologie.",zha:"ZHA",zha_read:"Lire les données ZHA",zha_hint:"Lit la topologie en cache de ZHA sans lancer d’analyse radio.",z2m:"Zigbee2MQTT",z2m_topics:"Topics de base (un par ligne)",z2m_update:"Actualiser la carte",z2m_warning:"L’analyse de la carte réseau peut durer de 10 secondes à 2 minutes et réduire temporairement la réactivité de Zigbee.",status_idle:"Données non chargées",status_loading:"Chargement…",status_ready:"Reçu : {time}",status_stale:"Reçu : {time} · obsolète",status_partial:"Reçu : {time} · certains nœuds sont omis",status_no_links:"Reçu : {time} · aucun lien observé trouvé",error_permission:"Les droits administrateur sont requis.",error_unsupported:"Ce fournisseur ou l’API Home Assistant n’est pas disponible.",error_timeout:"Le fournisseur n’a pas répondu à temps.",error_invalid_topic:"Vérifiez le topic de base Zigbee2MQTT.",error_invalid_payload:"Le fournisseur a renvoyé des données de topologie non prises en charge.",error_provider:"Impossible de charger les données de topologie.",remote_count:"+{n} dans d’autres espaces",route_device_not_on_plan:"appareil absent du plan",route_coordinator_not_on_plan:"coordinateur absent du plan",route_other_space:"autre espace"};const s="1d6151ba58a0ce1dc15ed85a133606dca280b90dea173557fa34ac9531c10ffb";export{e as dictionary,s as fingerprint};
@@ -1 +1 @@
globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="24813ef5e0b24d0f550c9e330f8ef7806dfb0724a8f69bd5e14e312c73438264";var e={title:"Связи Zigbee",toggle:"Показывать связи Zigbee при наведении на устройство",hint:"Показываются только наблюдаемые прямые соседи. Наведение ничего не запрашивает.",help:"Показывает, с какими устройствами Zigbee каждое связано напрямую. Цвет линии — качество связи (LQI) по той же шкале, что у показателя LQI устройства: красный при 40 и ниже, зелёный при 180 и выше. Пунктир — качество не сообщено. Стрелка ведёт к следующему устройству по пути к координатору: исходящая одна, входящие — те, кто ходит через это устройство. Линия без стрелки — запасной сосед. Это дерево маршрутов, которое строит House Plan, а не путь пакета в эту секунду: подпись на конце стрелки значит, что цель не на этом плане, а отсутствие стрелки — что путь неизвестен. Данные из последней загрузки и устаревают, связи видны только при работе мышью.",help_aria:"Справка: связи Zigbee",admin_only:"Данные топологии доступны только администраторам Home Assistant.",save_first:"Сохраните настройку перед загрузкой данных топологии.",zha:"ZHA",zha_read:"Прочитать данные ZHA",zha_hint:"Читает сохранённую топологию ZHA и не запускает радио-сканирование.",z2m:"Zigbee2MQTT",z2m_topics:"Базовые топики (по одному в строке)",z2m_update:"Обновить карту",z2m_warning:"Сканирование карты сети занимает от 10 секунд до 2 минут и временно может снизить отзывчивость Zigbee.",status_idle:"Данные не загружены",status_loading:"Загрузка…",status_ready:"Получено: {time}",status_stale:"Получено: {time} · данные устарели",status_partial:"Получено: {time} · часть узлов не показана",status_no_links:"Получено: {time} · наблюдаемые связи не найдены",error_permission:"Нужны права администратора.",error_unsupported:"Провайдер или API Home Assistant недоступен.",error_timeout:"Провайдер не ответил вовремя.",error_invalid_topic:"Проверьте базовый топик Zigbee2MQTT.",error_invalid_payload:"Провайдер вернул неподдерживаемые данные топологии.",error_provider:"Не удалось загрузить данные топологии.",remote_count:"+{n} в других пространствах",route_device_not_on_plan:"устройства нет на плане",route_coordinator_not_on_plan:"координатора нет на плане",route_other_space:"другое пространство"};const t="24813ef5e0b24d0f550c9e330f8ef7806dfb0724a8f69bd5e14e312c73438264";export{e as dictionary,t as fingerprint};
globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="1d6151ba58a0ce1dc15ed85a133606dca280b90dea173557fa34ac9531c10ffb";var e={title:"Связи Zigbee",toggle:"Показывать связи Zigbee при наведении на устройство",hint:"Показываются только наблюдаемые прямые соседи. Наведение ничего не запрашивает.",help:"Показывает, с какими устройствами Zigbee каждое связано напрямую. Цвет линии — качество связи (LQI) по той же шкале, что у показателя LQI устройства: красный при 40 и ниже, зелёный при 180 и выше. Пунктир — качество не сообщено. Стрелка ведёт к следующему устройству по пути к координатору: исходящая одна, входящие — те, кто ходит через это устройство. Линия без стрелки — запасной сосед. Это дерево маршрутов, которое строит House Plan, а не путь пакета в эту секунду: подпись на конце стрелки значит, что цель не на этом плане, а отсутствие стрелки — что путь неизвестен. Данные из последней загрузки и устаревают, связи видны только при работе мышью.",help_aria:"Справка: связи Zigbee",admin_only:"Данные топологии доступны только администраторам Home Assistant.",save_first:"Сохраните настройку перед загрузкой данных топологии.",zha:"ZHA",zha_read:"Прочитать данные ZHA",zha_hint:"Читает сохранённую топологию ZHA и не запускает радио-сканирование.",z2m:"Zigbee2MQTT",z2m_topics:"Базовые топики (по одному в строке)",z2m_update:"Обновить карту",z2m_warning:"Сканирование карты сети занимает от 10 секунд до 2 минут и временно может снизить отзывчивость Zigbee.",status_idle:"Данные не загружены",status_loading:"Загрузка…",status_ready:"Получено: {time}",status_stale:"Получено: {time} · данные устарели",status_partial:"Получено: {time} · часть узлов не показана",status_no_links:"Получено: {time} · наблюдаемые связи не найдены",error_permission:"Нужны права администратора.",error_unsupported:"Провайдер или API Home Assistant недоступен.",error_timeout:"Провайдер не ответил вовремя.",error_invalid_topic:"Проверьте базовый топик Zigbee2MQTT.",error_invalid_payload:"Провайдер вернул неподдерживаемые данные топологии.",error_provider:"Не удалось загрузить данные топологии.",remote_count:"+{n} в других пространствах",route_device_not_on_plan:"устройства нет на плане",route_coordinator_not_on_plan:"координатора нет на плане",route_other_space:"другое пространство"};const a="1d6151ba58a0ce1dc15ed85a133606dca280b90dea173557fa34ac9531c10ffb";export{e as dictionary,a as fingerprint};
File diff suppressed because one or more lines are too long
@@ -1 +1 @@
globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="24813ef5e0b24d0f550c9e330f8ef7806dfb0724a8f69bd5e14e312c73438264";import{n as t,c as n}from"./zigbee-topology-CcCg6XRV.js";import{aM as e}from"./houseplan-card-B4joz-YO.js";import"./namespace-language-BYcyqH-y.js";const o=new WeakMap;function i(t){const n=function(t){const n=t?.connection||t;return!n||"object"!=typeof n&&"function"!=typeof n?null:n}(t);if(!n)return null;let e=o.get(n);return e||(e={revision:0,topologies:[],states:{},listeners:new Set,inflight:new Map},o.set(n,e)),e}function r(t,n,e){t.states={...t.states,[n]:e},function(t){t.revision++;for(const n of t.listeners)n()}(t)}function s(t){const n=t?.code;if("permission"===n||"unsupported"===n||"timeout"===n||"invalid_topic"===n||"invalid_payload"===n)return n;const e=String(t?.message||"").toLowerCase();return e.includes("unauthor")||e.includes("permission")?"permission":e.includes("unknown_command")||e.includes("not found")?"unsupported":"provider"}function a(t){return Object.assign(new Error(t),{code:t})}function c(t,n,e){const o=t.inflight.get(n);if(o)return o;r(t,n,{phase:"loading"});const i=e().then(n=>{if(!n.nodes.length&&n.warnings.some(t=>"invalid_payload"===t.code))throw a("invalid_payload");!function(t,n){t.topologies=[...t.topologies.filter(t=>!(t.provider===n.provider&&t.instanceId===n.instanceId)),n],r(t,"zha"===n.provider?"zha":`z2m:${n.instanceId}`,{phase:"ready",obtainedAt:n.obtainedAt,partial:n.warnings.length>0})}(t,n)}).catch(e=>{r(t,n,{phase:"error",error:s(e)})}).finally(()=>t.inflight.delete(n));return t.inflight.set(n,i),i}function l(t){const n=i(t);return n?{revision:n.revision,topologies:n.topologies,states:n.states}:{revision:0,topologies:[],states:{}}}function u(t,n){const e=i(t);return e?(e.listeners.add(n),()=>e.listeners.delete(n)):()=>{}}function p(t){if(!0!==t?.user?.is_admin)throw a("permission")}function f(n){const e=i(n);return e?c(e,"zha",async()=>{if(p(n),"function"!=typeof n?.callWS)throw a("unsupported");return t(await n.callWS({type:"zha/devices"}))}):Promise.resolve()}function d(t){return null!==t&&"object"==typeof t?t:null}function h(t){const n=d(t),e=n?.payload??t;if("string"!=typeof e)return e;try{return JSON.parse(e)}catch{return null}}async function m(t,n){let e;try{return await Promise.race([t,new Promise((t,o)=>{e=globalThis.setTimeout(()=>o(a("timeout")),Math.max(1,n))})])}finally{void 0!==e&&globalThis.clearTimeout(e)}}function g(t,o,r=15e4){const s=i(t);if(!s)return Promise.resolve();const l=e(o);return c(s,`z2m:${l||String(o)}`,async()=>{if(p(t),!l)throw a("invalid_topic");const e=t.connection,o=e?.subscribeMessage;if("function"!=typeof o||"function"!=typeof t?.callService)throw a("unsupported");const i=function(){const t=globalThis.crypto;return"function"==typeof t?.randomUUID?`houseplan-${t.randomUUID()}`:`houseplan-${Date.now().toString(36)}-${Math.random().toString(36).slice(2)}`}(),s=Date.now()+Math.max(1,r);let c=!1,u=null,f=null,g=null;const y=new Promise(t=>{u=t}),w=new Promise((t,n)=>{f=t,g=n}),b=[];try{const r=await o.call(e,t=>{!0===d(t)?.retain&&h(t)&&u?.()},{type:"mqtt/subscribe",topic:`${l}/bridge/info`});"function"==typeof r&&b.push(r);const p=await o.call(e,t=>{if(!0===d(t)?.retain)return;const n=h(t);null!==n?n&&function(t){const n=d(t),e=n?.transaction??d(n?.data)?.transaction;return"string"==typeof e||"number"==typeof e?String(e):null}(n)===i&&f?.(n):c&&g?.(a("invalid_payload"))},{type:"mqtt/subscribe",topic:`${l}/bridge/response/networkmap`});"function"==typeof p&&b.push(p),await m(y,Math.min(4e3,Math.max(1,s-Date.now()))),c=!0,await t.callService("mqtt","publish",{topic:`${l}/bridge/request/networkmap`,payload:JSON.stringify({type:"raw",routes:!1,transaction:i}),qos:0,retain:!1});const v=await m(w,s-Date.now()),_=d(v)?.status;if(_&&"ok"!==_)throw a("provider");return n(v,l)}finally{for(const t of b)try{t()}catch{}}})}export{f as readZhaTopology,g as refreshZ2mTopology,u as subscribeZigbeeTopology,l as zigbeeTopologyRuntimeSnapshot};
globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="1d6151ba58a0ce1dc15ed85a133606dca280b90dea173557fa34ac9531c10ffb";import{n as t,c as n}from"./zigbee-topology-DgG5_y8E.js";import{aM as e}from"./houseplan-card-C_DbrDoi.js";import"./namespace-language-CaTQ_Mbw.js";const o=new WeakMap;function i(t){const n=function(t){const n=t?.connection||t;return!n||"object"!=typeof n&&"function"!=typeof n?null:n}(t);if(!n)return null;let e=o.get(n);return e||(e={revision:0,topologies:[],states:{},listeners:new Set,inflight:new Map},o.set(n,e)),e}function r(t,n,e){t.states={...t.states,[n]:e},function(t){t.revision++;for(const n of t.listeners)n()}(t)}function s(t){const n=t?.code;if("permission"===n||"unsupported"===n||"timeout"===n||"invalid_topic"===n||"invalid_payload"===n)return n;const e=String(t?.message||"").toLowerCase();return e.includes("unauthor")||e.includes("permission")?"permission":e.includes("unknown_command")||e.includes("not found")?"unsupported":"provider"}function a(t){return Object.assign(new Error(t),{code:t})}function c(t,n,e){const o=t.inflight.get(n);if(o)return o;r(t,n,{phase:"loading"});const i=e().then(n=>{if(!n.nodes.length&&n.warnings.some(t=>"invalid_payload"===t.code))throw a("invalid_payload");!function(t,n){t.topologies=[...t.topologies.filter(t=>!(t.provider===n.provider&&t.instanceId===n.instanceId)),n],r(t,"zha"===n.provider?"zha":`z2m:${n.instanceId}`,{phase:"ready",obtainedAt:n.obtainedAt,partial:n.warnings.length>0})}(t,n)}).catch(e=>{r(t,n,{phase:"error",error:s(e)})}).finally(()=>t.inflight.delete(n));return t.inflight.set(n,i),i}function l(t){const n=i(t);return n?{revision:n.revision,topologies:n.topologies,states:n.states}:{revision:0,topologies:[],states:{}}}function u(t,n){const e=i(t);return e?(e.listeners.add(n),()=>e.listeners.delete(n)):()=>{}}function p(t){if(!0!==t?.user?.is_admin)throw a("permission")}function f(n){const e=i(n);return e?c(e,"zha",async()=>{if(p(n),"function"!=typeof n?.callWS)throw a("unsupported");return t(await n.callWS({type:"zha/devices"}))}):Promise.resolve()}function d(t){return null!==t&&"object"==typeof t?t:null}function h(t){const n=d(t),e=n?.payload??t;if("string"!=typeof e)return e;try{return JSON.parse(e)}catch{return null}}async function m(t,n){let e;try{return await Promise.race([t,new Promise((t,o)=>{e=globalThis.setTimeout(()=>o(a("timeout")),Math.max(1,n))})])}finally{void 0!==e&&globalThis.clearTimeout(e)}}function g(t,o,r=15e4){const s=i(t);if(!s)return Promise.resolve();const l=e(o);return c(s,`z2m:${l||String(o)}`,async()=>{if(p(t),!l)throw a("invalid_topic");const e=t.connection,o=e?.subscribeMessage;if("function"!=typeof o||"function"!=typeof t?.callService)throw a("unsupported");const i=function(){const t=globalThis.crypto;return"function"==typeof t?.randomUUID?`houseplan-${t.randomUUID()}`:`houseplan-${Date.now().toString(36)}-${Math.random().toString(36).slice(2)}`}(),s=Date.now()+Math.max(1,r);let c=!1,u=null,f=null,g=null;const y=new Promise(t=>{u=t}),w=new Promise((t,n)=>{f=t,g=n}),b=[];try{const r=await o.call(e,t=>{!0===d(t)?.retain&&h(t)&&u?.()},{type:"mqtt/subscribe",topic:`${l}/bridge/info`});"function"==typeof r&&b.push(r);const p=await o.call(e,t=>{if(!0===d(t)?.retain)return;const n=h(t);null!==n?n&&function(t){const n=d(t),e=n?.transaction??d(n?.data)?.transaction;return"string"==typeof e||"number"==typeof e?String(e):null}(n)===i&&f?.(n):c&&g?.(a("invalid_payload"))},{type:"mqtt/subscribe",topic:`${l}/bridge/response/networkmap`});"function"==typeof p&&b.push(p),await m(y,Math.min(4e3,Math.max(1,s-Date.now()))),c=!0,await t.callService("mqtt","publish",{topic:`${l}/bridge/request/networkmap`,payload:JSON.stringify({type:"raw",routes:!1,transaction:i}),qos:0,retain:!1});const v=await m(w,s-Date.now()),_=d(v)?.status;if(_&&"ok"!==_)throw a("provider");return n(v,l)}finally{for(const t of b)try{t()}catch{}}})}export{f as readZhaTopology,g as refreshZ2mTopology,u as subscribeZigbeeTopology,l as zigbeeTopologyRuntimeSnapshot};
+1 -1
View File
@@ -1 +1 @@
globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="24813ef5e0b24d0f550c9e330f8ef7806dfb0724a8f69bd5e14e312c73438264";try{await import("./houseplan-assets/houseplan-card-B4joz-YO.js")}catch(e){if(!customElements.get("houseplan-card")){const l=String(navigator.language||"en").toLowerCase();const m=l.startsWith("ru")?"House Plan обновился — перезагрузите страницу (Ctrl+F5).":l.startsWith("de")?"House Plan wurde aktualisiert — bitte laden Sie die Seite neu (Strg+F5).":l.startsWith("fr")?"House Plan a été mis à jour — veuillez recharger la page (Ctrl+F5).":"House Plan was updated — please reload the page (Ctrl+F5).";customElements.define("houseplan-card",class extends HTMLElement{setConfig(){}getCardSize(){return 1}connectedCallback(){this.style.cssText="display:block;box-sizing:border-box;padding:16px;border:1px solid var(--divider-color,#e0e0e0);border-radius:var(--ha-card-border-radius,12px);background:var(--card-background-color,#fff);color:var(--primary-text-color,#212121);font:14px/1.4 var(--paper-font-body1_-_font-family,sans-serif)";this.textContent=m}})}console.error("[houseplan] stale houseplan-card.js: the implementation chunk is unavailable",e)}
globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="1d6151ba58a0ce1dc15ed85a133606dca280b90dea173557fa34ac9531c10ffb";try{await import("./houseplan-assets/houseplan-card-C_DbrDoi.js")}catch(e){if(!customElements.get("houseplan-card")){const l=String(navigator.language||"en").toLowerCase();const m=l.startsWith("ru")?"House Plan обновился — перезагрузите страницу (Ctrl+F5).":l.startsWith("de")?"House Plan wurde aktualisiert — bitte laden Sie die Seite neu (Strg+F5).":l.startsWith("fr")?"House Plan a été mis à jour — veuillez recharger la page (Ctrl+F5).":"House Plan was updated — please reload the page (Ctrl+F5).";customElements.define("houseplan-card",class extends HTMLElement{setConfig(){}getCardSize(){return 1}connectedCallback(){this.style.cssText="display:block;box-sizing:border-box;padding:16px;border:1px solid var(--divider-color,#e0e0e0);border-radius:var(--ha-card-border-radius,12px);background:var(--card-background-color,#fff);color:var(--primary-text-color,#212121);font:14px/1.4 var(--paper-font-body1_-_font-family,sans-serif)";this.textContent=m}})}console.error("[houseplan] stale houseplan-card.js: the implementation chunk is unavailable",e)}
+1 -1
View File
File diff suppressed because one or more lines are too long
+9
View File
@@ -9,6 +9,15 @@
vacuum responses no longer expose the internal map-source entity ID;
administrators retain full access
([#626](https://github.com/Matysh/houseplan-card/issues/626)).
- On a phone (a window 480 px wide or less) the header now takes a single row:
space tabs, zoom and one **Actions and settings** gear. The tabs scroll
sideways and keep the current one in view; the card title is hidden. The
gear's menu holds everything the row no longer shows — the editors, space
settings, adding a space, general settings, PDF, help, and the summary-panel
settings and show/hide — each doing exactly what its old button did. A tap
outside the menu only closes it. Users without edit rights see only the
summary-panel items; wider screens and kiosk are unchanged
([#616](https://github.com/Matysh/houseplan-card/issues/616)).
- The main toolbar no longer shows the device count (“37 dev.”), and it stops
jumping sideways when you open, close or switch editors: the editor’s close
**×** now has its own fixed place right after the mode buttons, kept empty
+10
View File
@@ -15,6 +15,16 @@
только редакторам, а ответ с маршрутом больше не раскрывает внутренний entity
ID источника карты; администраторы сохраняют полный доступ
([#626](https://github.com/Matysh/houseplan-card/issues/626)).
- На телефоне (окно не шире 480 px) шапка теперь занимает одну строку:
вкладки пространств, масштаб и одна шестерёнка **«Действия и настройки»**.
Вкладки прокручиваются вбок, текущая всегда на виду; заголовок карточки
скрыт. В меню шестерёнки — всё, чего больше нет в строке: редакторы,
настройки и добавление пространства, общие настройки, PDF, помощь,
настройки и показ сводной панели; каждый пункт делает ровно то же, что
прежняя кнопка. Касание вне меню только закрывает его. Пользователь без
права редактирования видит только пункты сводной панели; на широком экране
и в киоске ничего не изменилось
([#616](https://github.com/Matysh/houseplan-card/issues/616)).
- Основная панель больше не показывает счётчик устройств («37 устр.») и не
дёргается по горизонтали при входе в редактор, выходе из него и
переключении редакторов: крестик **×** закрытия редактора теперь стоит на
+13
View File
@@ -397,6 +397,19 @@ Zoom controls remain in the DOM inside the CSS-hidden kiosk header, exactly as
before. `space-add` keeps its stricter existing rule and is not rendered in
kiosk mode.
### 7.3a Phone header menu (#616)
At a window width of 480 px or less the header is one row: space tabs, zoom
and a gear `[data-hp="header-menu"]` (44 × 44, `aria-haspopup`,
`aria-expanded`). Everything the row drops — editor tabs, space settings, add
space, general settings, PDF, help, the summary-panel pair and the alpha
projection toggle — is a `[data-hp="header-menu-item"][data-id="…"]` button of
its menu (`#hp-header-menu`, `role="group"`), each at least 44 px high; the
vocabulary of `data-id` is in the JSON inventory. While the menu is open a
transparent `[data-hp="header-menu-scrim"]` swallows the tap that dismisses it.
Above 480 px the gear is in the DOM but hidden, and the ordinary buttons are
unchanged. Kiosk renders neither.
### 7.4 Editors
Each active editor exposes one primary
+3
View File
@@ -33,6 +33,9 @@ editor parity with desktop is not promised.
On phones, tablets, wall panels and HA Companion apps, the ordinary View must:
- render the plan and current states correctly;
- on a phone (≤ 480 px) keep the header to one row of at most 56 px — space
tabs, zoom and one gear whose menu holds every other header action, each
item a 44 px target (#616);
- support convenient pan, pinch zoom and space switching;
- fit the whole plan after two clean taps on free scene background, while one
tap on a room keeps the immediate room-fit action;
+15
View File
@@ -258,6 +258,21 @@ title: План дома
| Киоск | Настенный экран | Интерактивны как в просмотре | Только отображение | Только отображение; редакторы отсутствуют |
| Статическая карточка | Компактная схема пространства | Живые состояния, значения и тревоги как в просмотре (`live_states`), без подсказок и more-info | Только рисунок | Без интерактивности; см. §18 |
### Шапка на телефоне
Когда окно не шире 480 px, шапка занимает одну строку: вкладки пространств,
кнопки масштаба и одна шестерёнка **«Действия и настройки»**. Вкладки не
переносятся, а прокручиваются вбок; текущая вкладка всегда остаётся на виду.
Заголовок карточки на телефоне не показывается. Всё остальное открывается
шестерёнкой: администратору — **Редактор плана**, **Редактор устройств**,
**Редактор подложки**, **Настроить пространство**, **Добавить пространство**,
**Общие настройки**, **Сохранить в PDF** и **Помощь и обратная связь**; в
просмотре любому пользователю — **Настройки сводной панели** и показ или
скрытие сводной панели. Пункт делает то же, что прежняя кнопка, и закрывает
меню; Escape или касание вне меню просто закрывают его — касание при этом не
нажимает ничего на плане. В редакторе крестик закрытия остаётся в строке. На
более широком экране шапка прежняя, в киоске её нет.
### Сводная панель
Составная кнопка в конце шапки режима просмотра открывает левой шестерёнкой
+14 -1
View File
@@ -14,6 +14,19 @@ full card used on dashboards. In panel-host mode only the duplicated product
title disappears; space tabs, editor navigation, zoom and actions remain (the
header device count was removed in #647). Dashboard and kiosk behaviour is unchanged.
**Phone header (≤ 480 px window width, #616).** The header is a single row of at
most 56 px: space tabs (one line, scrolling sideways, the active tab scrolled
into view; no per-tab gear and no «+»), the zoom cluster, one gear and — for an
admin — the editor X slot of #647. The card title is hidden. Everything else is
an item of the gear's menu, in a fixed order: the three editors (current one
marked), Configure space, Add space (not with a fixed space), General settings,
Save as PDF, Help and feedback; in View also the summary-panel settings and
show/hide pair and, with `hp_alpha`, the volumetric/flat toggle. An item does
exactly what the button it replaces does and closes the menu; Escape closes it
and returns focus to the gear; a tap outside only closes it and never reaches
the plan. A user without write access sees just the summary-panel items. Wider
windows and kiosk are unchanged.
A segmented control in the card header with three tabs; the active one is visually
highlighted, and edit modes add a colored frame around the stage so the mode is
obvious at a glance:
@@ -128,7 +141,7 @@ Removed from this mode (they move, not die):
- every edit button in the header (+device, 👁 show-all, ↺ reset, ⬡ rules, ⚙ general,
per-space gear, markup toggle).
Header in View: space tabs, device count, summary control and zoom cluster.
Header in View: space tabs, summary control and zoom cluster; on a phone (≤ 480 px) space tabs, zoom and one gear whose menu holds the rest (#616).
## Plan — geometry and appearance of the space
+16
View File
@@ -69,6 +69,22 @@
"since": "1.73.0-beta.7",
"audience": ["test"]
},
"header-menu": {
"elements": ["button"],
"since": "1.78.0-beta.3",
"audience": ["styling", "test"]
},
"header-menu-item": {
"elements": ["button"],
"since": "1.78.0-beta.3",
"audience": ["styling", "test"],
"attributes": { "data-id": ["mode-plan", "mode-devices", "mode-decor", "space-settings", "space-add", "settings", "pdf", "support", "summary-settings", "summary-toggle", "projection"] }
},
"header-menu-scrim": {
"elements": ["div"],
"since": "1.78.0-beta.3",
"audience": ["test"]
},
"mode-tab": {
"elements": ["button"],
"since": "1.78.0-beta.2",
+7 -1
View File
@@ -340,8 +340,14 @@ export const LOW_HEADROOM_WARNING_BYTES = 15_000;
* он передаёт начавшийся на кнопке жест существующему pinch-навигационному
* контуру. Факт оставляет 978 Б сверху и 1 022 Б до нижней границы; общий
* бюджет не меняется.
*
* 2026-09-25, #616: 291 000 → 292 600 (замер 291 635). Компактная шапка
* телефона — строка, меню шестерёнки и его стили — часть View домочадца на
* телефоне и обязана работать до загрузки ленивого редактора: у не-админа
* редактор не грузится вовсе. Факт оставляет 965 Б сверху и 1 035 Б до нижней
* границы; общий бюджет не меняется.
*/
export const INITIAL_VIEW_GZIP_CEILING = 291_000;
export const INITIAL_VIEW_GZIP_CEILING = 292_600;
export const INITIAL_VIEW_CEILING_BAND = 2_000;
/**
+1 -1
View File
@@ -4,5 +4,5 @@
"hostRefs": 4883,
"portPrivates": 94,
"harnessPrivates": 101,
"bundleBytes": 2521909
"bundleBytes": 2528415
}
+101
View File
@@ -7384,6 +7384,107 @@ const MUTANT_DEFINITIONS = [
replace: " .editor-close-slot .closex ha-icon { --mdc-icon-size: 13px; }\n @media (max-width: 1100px) { .editor-close-slot .closex { display: none; } }",
}],
},
{
id: 'phone-header-shows-title',
guard: 'node demo/smoke_mobile_view_header.mjs',
because: '#616 AC1: on a phone the card title alone takes a row; the one-row header must hide it',
patches: [{
file: 'src/styles/chrome.styles.ts',
find: ' .head > .title, .head > .modes, .head > .spacer, .head > .header-action,',
replace: ' .head > .modes, .head > .spacer, .head > .header-action,',
}],
},
{
id: 'tab-editing-without-write-access',
guard: 'node demo/smoke_mobile_view_header.mjs',
because: '#616 AC1: a household member has no write access — per-tab gears must not render for them at any width',
patches: [{
file: 'src/houseplan-card.ts',
find: ' <span class="tabtitle">${s.title}</span>${this._norm && this._canEdit\n',
replace: ' <span class="tabtitle">${s.title}</span>${this._norm\n',
}],
},
{
id: 'phone-header-wraps',
guard: 'node demo/smoke_mobile_view_header.mjs',
because: '#616 AC2: the phone header is one row of at most 56 px; wrapping brings back the three-row chrome',
patches: [{
file: 'src/styles/chrome.styles.ts',
find: ' .hdr > .head { flex-wrap: nowrap; padding: 5px 8px; gap: 6px; }',
replace: ' .hdr > .head { flex-wrap: wrap; padding: 5px 8px; gap: 6px; }',
}],
},
{
id: 'header-menu-drops-pdf',
guard: 'npx tsc -p tsconfig.test.json && node scripts/fix-test-build.mjs '
+ '&& node --test test/header-menu.test.mjs',
because: '#616 AC3: every header action the phone row drops must be an item of the gear menu',
patches: [{
file: 'src/header-menu.ts',
find: " { id: 'pdf', icon: 'mdi:printer-outline', label: t('title.export_pdf'), run: actions.pdf },\n",
replace: '',
}],
},
{
id: 'header-menu-item-keeps-menu-open',
guard: 'node demo/smoke_mobile_view_header.mjs',
because: '#616 AC3: an item does what its button did and closes the menu; a menu left open covers the plan',
patches: [{
file: 'src/header-menu.ts',
find: ' const run = (item: HeaderMenuItem) => { this.close(false); item.run(); };',
replace: ' const run = (item: HeaderMenuItem) => { item.run(); };',
}],
},
{
id: 'header-menu-outside-tap-reaches-plan',
guard: 'node demo/smoke_mobile_view_header.mjs',
because: '#616 AC4: the tap that dismisses the menu must not toggle a light under it',
patches: [{
file: 'src/styles/chrome.styles.ts',
find: ' position: fixed;\n inset: 0;\n z-index: 1;\n background: transparent;',
replace: ' position: fixed;\n inset: auto;\n z-index: 1;\n background: transparent;',
}],
},
{
id: 'header-menu-escape-ignored',
guard: 'node demo/smoke_mobile_view_header.mjs',
because: '#616 AC4: Escape closes the menu and returns focus to the gear',
patches: [{
file: 'src/header-menu.ts',
find: " if (event.key !== 'Escape' || !this.open) return;",
replace: " if (event.key !== 'Esc' || !this.open) return;",
}],
},
{
id: 'active-tab-not-revealed',
guard: 'node demo/smoke_mobile_view_header.mjs',
because: '#616 AC5: with many spaces the active tab must be scrolled into view on load and on switch',
patches: [{
file: 'src/header-menu.ts',
find: ' if (!nav || !tab || nav.clientWidth === 0) return;',
replace: ' if (!nav || !tab || nav.clientWidth >= 0) return;',
}],
},
{
id: 'header-menu-item-below-44',
guard: 'node demo/smoke_mobile_view_header.mjs',
because: '#616 AC6: menu items are touch targets of at least 44 px',
patches: [{
file: 'src/styles/chrome.styles.ts',
find: ' min-height: 44px;\n padding: 0 var(--sp-4);',
replace: ' min-height: 30px;\n padding: 0 var(--sp-4);',
}],
},
{
id: 'phone-header-at-tablet-width',
guard: 'node demo/smoke_mobile_view_header.mjs',
because: '#616 AC7: above 480 px the ordinary header stays exactly as it was',
patches: [{
file: 'src/styles/chrome.styles.ts',
find: ' @media (max-width: 480px) {\n .hdr > .head',
replace: ' @media (max-width: 768px) {\n .hdr > .head',
}],
},
{
id: 'tab-reorder-not-persisted',
guard: 'node demo/smoke_space_tab_reorder.mjs',
+9 -2
View File
@@ -29,10 +29,17 @@
export const SMOKE_LINKS = [
{
symbols: ['chromeStyles', 'dialogsStyles'],
smokes: ['smoke_toolbar_stable_width.mjs', 'smoke_editor_tabs.mjs'],
smokes: ['smoke_toolbar_stable_width.mjs', 'smoke_editor_tabs.mjs', 'smoke_mobile_view_header.mjs'],
because: '#647: the header X slot (.editor-close-slot) and the removed .head .count rule are '
+ 'CSS in these sheets; the smokes measure the rendered header width, tab offsets, the X '
+ 'hit target and its visibility at 1400/1000/768/390 px — no TS symbol names that layout',
+ 'hit target and its visibility at 1400/1000/768/390 px — no TS symbol names that layout; '
+ '#616: the phone one-row header rules live in chromeStyles too',
},
{
symbols: ['HeaderMenu', 'headerMenuItems', 'renderHeaderActions'],
smokes: ['smoke_mobile_view_header.mjs', 'smoke_support_feedback.mjs', 'smoke_gear_tabs.mjs'],
because: '#616: the one-row phone header (<= 480 px) and its gear menu are a media query plus '
+ 'these symbols; the smokes tap the real gear and items at 320/390 px and prove >480 px is unchanged',
},
{
symbols: ['confirmIcon', 'HpConfirmRequest'],
+191
View File
@@ -0,0 +1,191 @@
/**
* #616: компактная шапка на телефоне (≤ 480 px, docs/UX-MODES.md).
*
* В строке остаются вкладки пространств, зум и одна шестерёнка; всё прочее из
* шапки — пункты её меню, в фиксированном порядке и ровно с теми же действиями,
* что у прежних кнопок. Состав меню — чистая функция (`headerMenuItems`),
* проверяется юнитом; раскрытие, закрытие и видимость активной вкладки —
* `HeaderMenu`. На > 480 px кнопка и меню в разметке есть, но скрыты CSS
* (`chrome.styles.ts`), прежние кнопки видны — поэтому поведение широкой
* шапки не зависит от этого модуля.
*/
import { html, nothing, type TemplateResult } from 'lit';
import type { I18nKey } from './i18n';
export type HeaderMode = 'view' | 'plan' | 'devices' | 'decor';
export type HeaderMenuItem = {
/** Стабильный id пункта: `data-id` в разметке, ключ в тестах. */
id: string;
label: string;
run: () => void;
icon?: string;
glyph?: TemplateResult;
/** Переключатель: состояние для `aria-pressed`. */
pressed?: boolean;
/** Текущий редактор: `aria-current`. */
current?: boolean;
};
export type HeaderMenuActions = {
setMode(mode: Exclude<HeaderMode, 'view'>): void;
configureSpace(): void;
addSpace(): void;
settings(): void;
pdf(): void;
support(): void;
projection(next: 'flat' | 'iso'): void;
};
export type HeaderMenuInput = {
canEdit: boolean;
kiosk: boolean;
mode: HeaderMode;
hasFixedFloor: boolean;
labsIso: boolean;
iso: boolean;
/** Пункты сводной панели (её рантайм отдаёт их только в просмотре). */
summary: HeaderMenuItem[];
t: (key: I18nKey) => string;
actions: HeaderMenuActions;
};
const EDITORS = [['plan', 'mdi:floor-plan'], ['devices', 'mdi:tune-variant'], ['decor', 'mdi:draw']] as const;
/**
* Состав меню по роли и режиму (ТЗ #616 п.4). Условия — те же, что у
* прежних кнопок шапки: редакторы, пространство и настройки — `canEdit`;
* «Добавить пространство» — ещё и без фиксированного пространства; сводная
* панель и объёмный вид — только в просмотре; в киоске меню нет.
*/
export function headerMenuItems(input: HeaderMenuInput): HeaderMenuItem[] {
if (input.kiosk) return [];
const { t, actions } = input;
const items: HeaderMenuItem[] = [];
if (input.canEdit) {
for (const [mode, icon] of EDITORS) {
items.push({
id: `mode-${mode}`, icon, label: t(`mode.${mode}` as I18nKey),
current: input.mode === mode, run: () => actions.setMode(mode),
});
}
items.push({ id: 'space-settings', icon: 'mdi:cog-outline', label: t('title.configure_space'), run: actions.configureSpace });
if (!input.hasFixedFloor) {
items.push({ id: 'space-add', icon: 'mdi:plus', label: t('title.add_space'), run: actions.addSpace });
}
items.push(
{ id: 'settings', icon: 'mdi:cog-outline', label: t('title.general_settings'), run: actions.settings },
{ id: 'pdf', icon: 'mdi:printer-outline', label: t('title.export_pdf'), run: actions.pdf },
{ id: 'support', icon: 'mdi:help-circle-outline', label: t('support.title'), run: actions.support },
);
}
if (input.mode === 'view') {
items.push(...input.summary);
if (input.labsIso) {
items.push({
id: 'projection', icon: input.iso ? 'mdi:view-grid-outline' : 'mdi:cube-outline',
label: t(input.iso ? 'view.flat' : 'view.volumetric'), pressed: input.iso,
run: () => actions.projection(input.iso ? 'flat' : 'iso'),
});
}
}
return items;
}
/** What the menu needs from the card: a re-render and its shadow root — not the editor host port. */
type MenuOwner = { requestUpdate(): void; renderRoot: ParentNode };
export class HeaderMenu {
open = false;
private revealedFor = '';
private readonly onKey = (event: KeyboardEvent): void => {
if (event.key !== 'Escape' || !this.open) return;
event.stopPropagation();
this.close(true);
};
constructor(private readonly owner: MenuOwner) {}
toggle(): void {
if (this.open) this.close(false);
else {
this.open = true;
window.addEventListener('keydown', this.onKey, true);
this.owner.requestUpdate();
}
}
close(focusButton: boolean): void {
if (!this.open) return;
this.open = false;
window.removeEventListener('keydown', this.onKey, true);
this.owner.requestUpdate();
if (focusButton) {
(this.owner.renderRoot.querySelector('[data-hp="header-menu"]') as HTMLElement | null)?.focus();
}
}
disconnect(): void {
this.open = false;
window.removeEventListener('keydown', this.onKey, true);
}
/**
* Вкладки на телефоне прокручиваются в одну строку. Активная вкладка
* докручивается в видимую область один раз на каждую смену пространства —
* не на каждом рендере: иначе обновление hass отнимало бы у человека
* ручную прокрутку вкладок.
*/
revealActiveTab(): void {
const nav = this.owner.renderRoot.querySelector('.head .tabs') as HTMLElement | null;
const tab = nav?.querySelector('.tab.active') as HTMLElement | null;
if (!nav || !tab || nav.clientWidth === 0) return;
const id = tab.dataset.id || '';
if (id === this.revealedFor) return;
this.revealedFor = id;
const box = nav.getBoundingClientRect();
const rect = tab.getBoundingClientRect();
if (rect.left < box.left) nav.scrollLeft -= box.left - rect.left;
else if (rect.right > box.right) nav.scrollLeft += rect.right - box.right;
}
render(items: HeaderMenuItem[], label: string): TemplateResult | typeof nothing {
if (!items.length) return nothing;
const run = (item: HeaderMenuItem) => { this.close(false); item.run(); };
return html`<span class="header-menu-wrap">
<button class="btn header-menu-button ${this.open ? 'on' : ''}" data-hp="header-menu"
aria-haspopup="true" aria-expanded=${this.open ? 'true' : 'false'} aria-controls="hp-header-menu"
title=${label} aria-label=${label} @click=${() => this.toggle()}>
<ha-icon icon="mdi:cog-outline"></ha-icon>
</button>
${this.open ? html`<div class="header-menu-scrim" data-hp="header-menu-scrim"
@click=${(event: Event) => { event.stopPropagation(); this.close(false); }}></div>
<div class="header-menu" id="hp-header-menu" role="group" aria-label=${label}>
${items.map((item) => html`<button type="button" class="header-menu-item ${item.current || item.pressed ? 'on' : ''}"
data-hp="header-menu-item" data-id=${item.id}
aria-current=${item.current ? 'true' : nothing}
aria-pressed=${item.pressed === undefined ? nothing : item.pressed ? 'true' : 'false'}
@click=${() => run(item)}>
${item.glyph ?? html`<ha-icon icon=${item.icon ?? 'mdi:circle-small'}></ha-icon>`}<span>${item.label}</span>
</button>`)}
</div>` : nothing}
</span>`;
}
}
/** Прежние кнопки шапки (> 480 px): вынесены сюда, чтобы шапка карточки не росла. */
export function renderHeaderActions(
t: (key: I18nKey) => string, open: { settings(): void; pdf(): void; support(): void },
): TemplateResult {
return html`<button class="btn header-action settings-button" data-hp="settings" @click=${open.settings} title=${t('title.general_settings')}>
<ha-icon icon="mdi:cog-outline"></ha-icon>
</button>
<button class="btn header-action pdf-button" data-hp="pdf" @click=${open.pdf}
title=${t('title.export_pdf')} aria-label=${t('title.export_pdf')}>
<ha-icon icon="mdi:printer-outline"></ha-icon>
</button>
<button class="btn header-action support-button" data-hp="support" @click=${open.support}
title=${t('support.title')} aria-label=${t('support.title')}>
<ha-icon icon="mdi:help-circle-outline"></ha-icon>
</button>`;
}
+12 -16
View File
@@ -291,6 +291,7 @@ import {
} from './space-order';
import type { MarkerRoomReferenceSnapshot } from './room-reference-transaction';
import { SummaryRuntimeSlot, summaryRuntimeLoader } from './summary-runtime-loader';
import { HeaderMenu, headerMenuItems, renderHeaderActions } from './header-menu';
import { displayVersion } from './card-version';
const CARD_VERSION = '1.78.0-beta.2';
@@ -2167,6 +2168,7 @@ export class HouseplanCard extends LitElement {
private _renderProjection: 'flat' | 'iso' = 'flat';
// ---- kiosk (wall device) mode ----
private _kioskScale: { icon: number; font: number } = { icon: 1, font: 1 }; private _kioskDialog = false;
private readonly _headerMenu = new HeaderMenu(this);
private _summary?: import('./summary-panel-runtime-loaded').LoadedSummaryPanelRuntime; private readonly _summarySlot = new SummaryRuntimeSlot(summaryRuntimeLoader, this, (runtime) => { this._summary = runtime; this._capturedSnapshotSequence = -1; /* summary entities (re)join the live subscription */ if (this.isConnected) { runtime.connect(); if (this.hasUpdated) this.requestUpdate(); } }); // #506: warm code attaches before the first render
/**
* Previous entity states + the short event/terminal-transition window for
@@ -2652,7 +2654,7 @@ export class HouseplanCard extends LitElement {
this._tabSuppressClickTimer = undefined;
this._tabSuppressClick = false;
clearInterval(this._cycleTimer);
clearTimeout(this._kioskDotsTimer);
clearTimeout(this._kioskDotsTimer); this._headerMenu.disconnect();
clearTimeout(this._kioskHoldTimer);
clearTimeout(this._reloadRetry);
clearTimeout(this._loadRetryTimer);
@@ -4031,7 +4033,7 @@ export class HouseplanCard extends LitElement {
this._captureRenderDeviceSnapshot();
}
protected updated(): void {
this._summary?.updated(); this._liveRt?.commit();
this._summary?.updated(); this._liveRt?.commit(); this._headerMenu.revealActiveTab();
this._editorRuntime?._commitLiveEditor();
this._pruneDevicePressFeedback();
this._syncDayCycleClock();
@@ -10775,7 +10777,7 @@ export class HouseplanCard extends LitElement {
@pointercancel=${() => this._endTabDrag()}
@click=${() => this._tabClick(s.id)}
>
${s.title}${this._norm && this._canEdit
<span class="tabtitle">${s.title}</span>${this._norm && this._canEdit
? html`<ha-icon class="tabedit" icon="mdi:cog-outline"
data-hp="space-settings" data-id=${s.id}
title=${this._t('title.configure_space')}
@@ -10835,20 +10837,14 @@ export class HouseplanCard extends LitElement {
title=${this._t('title.zoom_fit')}><ha-icon icon="mdi:fit-to-page-outline"></ha-icon></button>
<button class="btn zb" data-hp="zoom-in" @click=${() => this._stepZoom(1)} title=${this._t('title.zoom_in')}><ha-icon icon="mdi:plus"></ha-icon></button>
</div>
${this._norm && this._canEdit
? html`<button class="btn header-action settings-button" data-hp="settings" @click=${this._openSettingsDialog} title=${this._t('title.general_settings')}>
<ha-icon icon="mdi:cog-outline"></ha-icon>
</button>
<button class="btn header-action pdf-button" data-hp="pdf" @click=${this._openPdfDialog}
title=${this._t('title.export_pdf')} aria-label=${this._t('title.export_pdf')}>
<ha-icon icon="mdi:printer-outline"></ha-icon>
</button>
<button class="btn header-action support-button" data-hp="support" @click=${this._openSupportDialog}
title=${this._t('support.title')} aria-label=${this._t('support.title')}>
<ha-icon icon="mdi:help-circle-outline"></ha-icon>
</button>`
: nothing}
${this._norm && this._canEdit ? renderHeaderActions((k) => this._t(k), { settings: this._openSettingsDialog, pdf: this._openPdfDialog, support: this._openSupportDialog }) : nothing}
${!this._kiosk ? this._summary?.renderControls(false) : nothing}
${''/* #616: ≤ 480 px — one gear holds everything the phone row drops */}${this._kiosk ? nothing : this._headerMenu.render(headerMenuItems({
canEdit: this._norm && this._canEdit, kiosk: this._kiosk, mode: this._mode, hasFixedFloor: this._hasFixedFloor, labsIso: this._labsIso, iso,
summary: this._summary?.menuItems() ?? [], t: (k) => this._t(k),
actions: { setMode: (m) => this._setMode(m), configureSpace: () => this._openSpaceDialog('edit', this._space), addSpace: () => this._openSpaceDialog('create'),
settings: this._openSettingsDialog, pdf: this._openPdfDialog, support: this._openSupportDialog, projection: (next) => this._setProjection(next) },
}), this._t('title.header_menu'))}
</div>
${this._canEdit && !this._kiosk
? html`<div class="editorchrome ${this._editing || this._modeTransitionBusy ? 'open' : ''}${this._modeTransitionBusy ? ' transitioning' : ''}"
+1
View File
@@ -439,6 +439,7 @@
"editor.button_target": "Ziel-Dashboard-Pfad",
"marker.sub_entity": "Entität",
"title.general_settings": "Allgemeine Einstellungen",
"title.header_menu": "Aktionen und Einstellungen",
"title.export_pdf": "Als PDF speichern",
"pdf.title": "Als PDF speichern",
"pdf.dimensions": "Maße und Flächen anzeigen",
+1
View File
@@ -439,6 +439,7 @@
"editor.button_target": "Target dashboard path",
"marker.sub_entity": "entity",
"title.general_settings": "General settings",
"title.header_menu": "Actions and settings",
"title.export_pdf": "Save as PDF",
"pdf.title": "Save as PDF",
"pdf.dimensions": "Show dimensions and areas",
+1
View File
@@ -439,6 +439,7 @@
"editor.button_target": "Chemin du tableau de bord cible",
"marker.sub_entity": "entité",
"title.general_settings": "Paramètres généraux",
"title.header_menu": "Actions et réglages",
"title.export_pdf": "Enregistrer en PDF",
"pdf.title": "Enregistrement en PDF",
"pdf.dimensions": "Afficher les dimensions et les surfaces",
+1
View File
@@ -439,6 +439,7 @@
"editor.button_target": "Путь дашборда (куда вести)",
"marker.sub_entity": "сущность",
"title.general_settings": "Общие настройки",
"title.header_menu": "Действия и настройки",
"title.export_pdf": "Сохранить в PDF",
"pdf.title": "Сохранение в PDF",
"pdf.dimensions": "Отображать размеры и площади",
+70
View File
@@ -34,6 +34,7 @@ const chromeCoreStyles = css`
:host([data-pointer-hover]) .tab:hover {
color: var(--hp-txt);
}
.tab .tabtitle { pointer-events: none; }
.tab.active {
background: var(--hp-accent);
color: var(--text-primary-color, #fff);
@@ -96,6 +97,75 @@ const chromeCoreStyles = css`
margin-top: -4px;
}
.hdr.kioskhide { display: none; }
.header-menu-wrap { display: none; position: relative; flex: none; }
.header-menu-button {
min-width: 44px;
min-height: 44px;
justify-content: center;
padding: var(--sp-3);
}
.header-menu-scrim {
position: fixed;
inset: 0;
z-index: 1;
background: transparent;
}
.header-menu {
position: absolute;
top: calc(100% + var(--sp-2));
right: 0;
z-index: 2;
display: flex;
flex-direction: column;
width: max-content;
min-width: 220px;
max-width: calc(100vw - 16px);
max-height: calc(100dvh - 120px);
overflow-y: auto;
padding: var(--sp-2);
border: 1px solid var(--hp-line);
border-radius: var(--rad-m);
background: var(--card-background-color, var(--hp-bg));
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.28);
}
.header-menu-item {
display: flex;
align-items: center;
gap: var(--sp-4);
min-height: 44px;
padding: 0 var(--sp-4);
border: 0;
border-radius: var(--rad-s);
background: transparent;
color: var(--hp-txt);
font: inherit;
font-size: var(--fs-m);
text-align: start;
cursor: pointer;
}
.header-menu-item ha-icon, .header-menu-item svg { --mdc-icon-size: 20px; width: 20px; height: 20px; flex: none; }
.header-menu-item.on { color: var(--hp-accent); font-weight: 600; }
:host([data-pointer-hover]) .header-menu-item:hover { background: rgba(127, 127, 127, 0.14); }
.header-menu-item:focus-visible { outline: 2px solid var(--hp-accent); outline-offset: -2px; }
@media (max-width: 480px) {
.hdr > .head { flex-wrap: nowrap; padding: 5px 8px; gap: 6px; }
.head > .title, .head > .modes, .head > .spacer, .head > .header-action,
.head > .summary-control, .head > .projection-toggle { display: none; }
.head > .tabs {
flex: 1 1 auto;
min-width: 0;
flex-wrap: nowrap;
overflow-x: auto;
overscroll-behavior-x: contain;
scrollbar-width: none;
}
.head > .tabs::-webkit-scrollbar { display: none; }
.head > .tabs .tab { flex: none; white-space: nowrap; max-width: 100%; }
.head > .tabs .tabtitle { min-width: 0; overflow: hidden; text-overflow: ellipsis; }
.head > .tabs .tabedit, .head > .tabs .tabadd { display: none; }
.head > .zoomctl, .head > .editor-close-slot { flex: none; }
.header-menu-wrap { display: inline-flex; }
}
.decorbar .dcolor {
width: 30px; height: 26px; padding: 0; border: none; background: none; cursor: pointer;
}
+19 -3
View File
@@ -22,6 +22,7 @@ import { summaryIcon } from './summary-panel-icons';
import { SummaryPanelPresentation } from './summary-panel-presentation';
import { summaryPanelText } from './summary-panel-i18n';
import type { SummaryPanelHost } from './summary-panel-host';
import type { HeaderMenuItem } from './header-menu';
import { stableSummaryPlacementSlot } from './summary-panel-identity';
import {
refreshSummaryEntityIndex, type SummaryEntityIndex,
@@ -233,8 +234,18 @@ export class LoadedSummaryPanelRuntime {
</aside>`;
}
public renderControls(kiosk = false): TemplateResult | typeof nothing {
if (this.host._mode !== 'view') return nothing;
/** #616: the same two actions as `renderControls` — items of the phone header menu
* (the menu itself offers them only in View, as `renderControls` does). */
public menuItems(): HeaderMenuItem[] {
const toggleTitle = this.toggleTitle();
return [
{ id: 'summary-settings', glyph: summaryIcon('settings'), label: this.t('summary.settings'), run: () => void this.openDialog() },
{ id: 'summary-toggle', glyph: summaryIcon('sidebar'), label: toggleTitle, pressed: this.local.show,
run: () => this.saveLocal({ show: !this.local.show }) },
];
}
private toggleTitle(): string {
const resolved = this.config();
const layout = this.layout();
const temporaryReason = this.local.show && (
@@ -245,7 +256,12 @@ export class LoadedSummaryPanelRuntime {
? this.t('summary.hidden_narrow_unknown')
: !layout.fits ? this.t('summary.hidden_small') : ''
);
const toggleTitle = temporaryReason || this.t(this.local.show ? 'summary.hide' : 'summary.show');
return temporaryReason || this.t(this.local.show ? 'summary.hide' : 'summary.show');
}
public renderControls(kiosk = false): TemplateResult | typeof nothing {
if (this.host._mode !== 'view') return nothing;
const toggleTitle = this.toggleTitle();
const stop = (event: Event) => event.stopPropagation();
return html`<div class="summary-control ${kiosk ? 'kiosk' : ''}" role="group"
aria-label=${this.t('summary.controls')} @click=${stop} @dblclick=${stop}
+66
View File
@@ -0,0 +1,66 @@
// #616: состав меню шестерёнки телефонной шапки — ТЗ п.4. Порядок фиксирован,
// условия те же, что у прежних кнопок: редакторы и настройки — только с правом
// записи, «Добавить пространство» — без фиксированного пространства, сводная
// панель и объёмный вид — только в просмотре, в киоске меню нет.
import assert from 'node:assert/strict';
import test from 'node:test';
import { headerMenuItems } from '../test-build/header-menu.js';
const calls = [];
const actions = {
setMode: (m) => calls.push(`mode:${m}`), configureSpace: () => calls.push('configure'),
addSpace: () => calls.push('add'), settings: () => calls.push('settings'), pdf: () => calls.push('pdf'),
support: () => calls.push('support'), projection: (p) => calls.push(`projection:${p}`),
};
const summary = [{ id: 'summary-settings', label: 's', run: () => calls.push('summary-settings') },
{ id: 'summary-toggle', label: 't', pressed: false, run: () => calls.push('summary-toggle') }];
const input = (over = {}) => ({
canEdit: true, kiosk: false, mode: 'view', hasFixedFloor: false, labsIso: false, iso: false,
summary, t: (key) => `«${key}»`, actions, ...over,
});
const ids = (over) => headerMenuItems(input(over)).map((item) => item.id);
const ADMIN = ['mode-plan', 'mode-devices', 'mode-decor', 'space-settings', 'space-add', 'settings', 'pdf', 'support'];
test('#616 админ в просмотре: редакторы · пространство · приложение · сводная панель — в этом порядке', () => {
assert.deepEqual(ids(), [...ADMIN, 'summary-settings', 'summary-toggle']);
});
test('#616 не-админ: только сводная панель; без неё меню пусто — кнопки нет', () => {
assert.deepEqual(ids({ canEdit: false }), ['summary-settings', 'summary-toggle']);
assert.deepEqual(ids({ canEdit: false, summary: [] }), []);
});
test('#616 редактор: сводной панели и объёмного вида нет, текущий редактор отмечен', () => {
const items = headerMenuItems(input({ mode: 'devices', labsIso: true }));
assert.deepEqual(items.map((i) => i.id), ADMIN);
assert.deepEqual(items.filter((i) => i.current).map((i) => i.id), ['mode-devices']);
});
test('#616 фиксированное пространство убирает «Добавить пространство», киоск — всё меню', () => {
assert.ok(!ids({ hasFixedFloor: true }).includes('space-add'));
assert.ok(ids({ hasFixedFloor: true }).includes('space-settings'));
assert.deepEqual(ids({ kiosk: true }), []);
assert.deepEqual(ids({ kiosk: true, canEdit: false }), []);
});
test('#616 объёмный вид — только с hp_alpha и в просмотре; пункт — переключатель', () => {
assert.ok(!ids().includes('projection'));
const flat = headerMenuItems(input({ labsIso: true })).at(-1);
assert.deepEqual([flat.id, flat.pressed, flat.label], ['projection', false, '«view.volumetric»']);
const iso = headerMenuItems(input({ labsIso: true, iso: true, canEdit: false })).at(-1);
assert.deepEqual([iso.id, iso.pressed, iso.label], ['projection', true, '«view.flat»']);
});
test('#616 каждый пункт вызывает то же действие, что прежняя кнопка', () => {
calls.length = 0;
for (const item of headerMenuItems(input({ labsIso: true }))) item.run();
assert.deepEqual(calls, ['mode:plan', 'mode:devices', 'mode:decor', 'configure', 'add', 'settings', 'pdf', 'support',
'summary-settings', 'summary-toggle', 'projection:iso']);
});
test('#616 подписи — существующие ключи интерфейса', () => {
assert.deepEqual(headerMenuItems(input({ summary: [] })).map((i) => i.label), [
'«mode.plan»', '«mode.devices»', '«mode.decor»', '«title.configure_space»', '«title.add_space»',
'«title.general_settings»', '«title.export_pdf»', '«support.title»',
]);
});
+7 -1
View File
@@ -123,7 +123,13 @@ test('Help is lazy, ordered after settings, and owns the single About/Guide surf
assert.equal((runtime.match(/_t\('gs\.about_version'/g) || []).length, 1);
assert.match(runtime, /docs\/USER-GUIDE\.ru\.md/);
assert.match(runtime, /docs\/USER-GUIDE\.md/);
assert.equal((header.match(/header-action/g) || []).length, 3);
// #616: the three header buttons are rendered by src/header-menu.ts (the card
// passes the openers in the same order); on a phone they are its menu items.
const headerMenu = readFileSync(new URL('../src/header-menu.ts', import.meta.url), 'utf8');
const actions = headerMenu.slice(headerMenu.indexOf('export function renderHeaderActions'));
assert.equal((actions.match(/header-action/g) || []).length, 3);
assert.ok(actions.indexOf('open.settings') < actions.indexOf('open.pdf'));
assert.ok(actions.indexOf('open.pdf') < actions.indexOf('open.support'));
assert.match(styles, /\.header-action\s*\{[\s\S]*?min-width:\s*44px;[\s\S]*?min-height:\s*44px;/);
assert.match(dialogStyles, /\.supportmessage\s*\{[\s\S]*?background:\s*var\(--hp-bg\);/);
});
+1 -1
View File
@@ -21,7 +21,7 @@
"src/resize.ts", "src/resize-labels.ts", "src/resize-controller.ts", "src/wall-record-preservation.ts",
"src/rules.ts",
"src/devices.ts", "src/device-inbox.ts",
"src/virtual-light-state.ts", "src/config-store.ts", "src/config-reload-authority.ts", "src/config-write-conflict.ts", "src/summary-panel.ts", "src/summary-panel-metrics.ts", "src/summary-panel-i18n.ts", "src/summary-panel-identity.ts", "src/summary-panel-picker.ts", "src/summary-panel-runtime-loaded.ts",
"src/virtual-light-state.ts", "src/config-store.ts", "src/config-reload-authority.ts", "src/config-write-conflict.ts", "src/summary-panel.ts", "src/summary-panel-metrics.ts", "src/summary-panel-i18n.ts", "src/summary-panel-identity.ts", "src/summary-panel-picker.ts", "src/summary-panel-runtime-loaded.ts", "src/header-menu.ts",
"src/backdrop-probe.ts",
"src/types.ts", "src/editors/dialog-baseline.ts", "src/editors/color-tile-ink.ts", "src/editors/general-form-state.ts", "src/editors/space-form-state.ts", "src/editors/marker-form-state.ts", "src/editors/room-form-state.ts",
"src/space-geometry.ts", "src/junction-limits.ts", "src/room-gear-drag.ts",