diff --git a/custom_components/houseplan/const.py b/custom_components/houseplan/const.py index 6493f80..58ece3d 100755 --- a/custom_components/houseplan/const.py +++ b/custom_components/houseplan/const.py @@ -11,7 +11,7 @@ PLANS_DIR = "houseplan/plans" # relative to the HA configuration directory FILES_URL = "/houseplan_files/files" FILES_DIR = "houseplan/files" CONF_ADMIN_ONLY = "admin_only" -VERSION = "1.30.0" +VERSION = "1.30.1" DEFAULT_CONFIG: dict = { "spaces": [], diff --git a/custom_components/houseplan/frontend/houseplan-card.js b/custom_components/houseplan/frontend/houseplan-card.js index 681c8dc..31d9fb5 100755 --- a/custom_components/houseplan/frontend/houseplan-card.js +++ b/custom_components/houseplan/frontend/houseplan-card.js @@ -83,6 +83,8 @@ const t=globalThis,e=t.ShadowRoot&&(void 0===t.ShadyCSS||t.ShadyCSS.nativeShadow border: 0; background: transparent; color: var(--hp-muted); + display: inline-flex; + align-items: center; padding: 6px 13px; border-radius: 8px; font-size: 13px; @@ -673,9 +675,10 @@ const t=globalThis,e=t.ShadowRoot&&(void 0===t.ShadyCSS||t.ShadyCSS.nativeShadow } .tab .tabedit { --mdc-icon-size: 13px; + display: inline-flex; + align-items: center; margin-left: 6px; opacity: 0.4; - vertical-align: middle; } .tab:hover .tabedit { opacity: 0.9; @@ -1337,7 +1340,7 @@ const t=globalThis,e=t.ShadowRoot&&(void 0===t.ShadyCSS||t.ShadyCSS.nativeShadow class="tab ${this._space===t.id?"active":""}" @click=${()=>{this._space=t.id,this._selId=null,this._restoreZoom()}} > - ${t.title}${this._norm&&"plan"===this._mode?H`{e.stopPropagation(),this._openSpaceDialog("edit",t.id)}}>`:W} `)} @@ -1887,4 +1890,4 @@ const t=globalThis,e=t.ShadowRoot&&(void 0===t.ShadyCSS||t.ShadyCSS.nativeShadow - `}}Ii.properties={hass:{attribute:!1},_config:{state:!0},_space:{state:!0},_layout:{state:!0},_devices:{state:!0},_tip:{state:!0},_selId:{state:!0},_toast:{state:!0},_serverCfg:{state:!0},_mode:{state:!0},_tool:{state:!0},_path:{state:!0},_cursorPt:{state:!0},_mergeSel:{state:!0},_openingDialog:{state:!0},_openingInfo:{state:!0},_mergeDialog:{state:!0},_splitSel:{state:!0},_areaSel:{state:!0},_nameSel:{state:!0},_roomDialog:{state:!0},_spaceDialog:{state:!0},_infoCard:{state:!0},_rulesDialog:{state:!0},_settingsDialog:{state:!0},_importDialog:{state:!0},_markerDialog:{state:!0},_zoom:{state:!0},_view:{state:!0}},Ii.styles=mi,customElements.get("houseplan-card")||customElements.define("houseplan-card",Ii),window.customCards=window.customCards||[],window.customCards.find(t=>"houseplan-card"===t.type)||window.customCards.push({type:"houseplan-card",name:"House Plan Card",description:"Interactive house plan: spaces, rooms and devices with live states and drag layout."}),console.info("%c HOUSEPLAN-CARD %c v1.30.0 ","background:#3ea6ff;color:#04121f;font-weight:700",""); + `}}Ii.properties={hass:{attribute:!1},_config:{state:!0},_space:{state:!0},_layout:{state:!0},_devices:{state:!0},_tip:{state:!0},_selId:{state:!0},_toast:{state:!0},_serverCfg:{state:!0},_mode:{state:!0},_tool:{state:!0},_path:{state:!0},_cursorPt:{state:!0},_mergeSel:{state:!0},_openingDialog:{state:!0},_openingInfo:{state:!0},_mergeDialog:{state:!0},_splitSel:{state:!0},_areaSel:{state:!0},_nameSel:{state:!0},_roomDialog:{state:!0},_spaceDialog:{state:!0},_infoCard:{state:!0},_rulesDialog:{state:!0},_settingsDialog:{state:!0},_importDialog:{state:!0},_markerDialog:{state:!0},_zoom:{state:!0},_view:{state:!0}},Ii.styles=mi,customElements.get("houseplan-card")||customElements.define("houseplan-card",Ii),window.customCards=window.customCards||[],window.customCards.find(t=>"houseplan-card"===t.type)||window.customCards.push({type:"houseplan-card",name:"House Plan Card",description:"Interactive house plan: spaces, rooms and devices with live states and drag layout."}),console.info("%c HOUSEPLAN-CARD %c v1.30.1 ","background:#3ea6ff;color:#04121f;font-weight:700",""); diff --git a/custom_components/houseplan/manifest.json b/custom_components/houseplan/manifest.json index 9c8f138..80e8ec3 100755 --- a/custom_components/houseplan/manifest.json +++ b/custom_components/houseplan/manifest.json @@ -16,5 +16,5 @@ "issue_tracker": "https://github.com/Matysh/houseplan-card/issues", "requirements": [], "single_config_entry": true, - "version": "1.30.0" + "version": "1.30.1" } diff --git a/demo/smoke_gear_tabs.mjs b/demo/smoke_gear_tabs.mjs new file mode 100644 index 0000000..437281d --- /dev/null +++ b/demo/smoke_gear_tabs.mjs @@ -0,0 +1,35 @@ +import { launch } from './serve.mjs'; +const { page, browser } = await launch(); +const res = await page.evaluate(async () => { + const out = {}; + const c = window.__card; + const sr = () => c.shadowRoot || c.renderRoot; + const gears = () => sr().querySelectorAll('.tab .tabedit').length; + // шестерёнки видны во всех трёх режимах + out.viewGears = gears() > 0; + c._setMode('plan'); await c.updateComplete; + out.planGears = gears() > 0; + c._setMode('devices'); await c.updateComplete; + out.devGears = gears() > 0; + c._setMode('view'); await c.updateComplete; + // выравнивание: центр иконки ~ центру текста таба + const tab = sr().querySelector('.tab'); + const icon = tab.querySelector('.tabedit'); + const tb = tab.getBoundingClientRect(), ib = icon.getBoundingClientRect(); + const tabMid = tb.top + tb.height / 2, iconMid = ib.top + ib.height / 2; + out.alignDelta = Math.abs(tabMid - iconMid); + out.aligned = out.alignDelta <= 1.5; + // клик по шестерёнке в Просмотре открывает диалог пространства и не переключает таб + const cur = c._space; + icon.click(); await c.updateComplete; + out.dialogOpens = !!c._spaceDialog; + out.tabNotSwitched = c._space === cur; + c._spaceDialog = null; await c.updateComplete; + // кнопка "+" по-прежнему только в Плане + out.noAddInView = !sr().querySelector('.tab.tabadd'); + c._setMode('plan'); await c.updateComplete; + out.addInPlan = !!sr().querySelector('.tab.tabadd'); + return out; +}); +console.log(JSON.stringify(res, null, 1)); +await browser.close(); diff --git a/demo/srv/assets/houseplan-card.js b/demo/srv/assets/houseplan-card.js index 681c8dc..31d9fb5 100755 --- a/demo/srv/assets/houseplan-card.js +++ b/demo/srv/assets/houseplan-card.js @@ -83,6 +83,8 @@ const t=globalThis,e=t.ShadowRoot&&(void 0===t.ShadyCSS||t.ShadyCSS.nativeShadow border: 0; background: transparent; color: var(--hp-muted); + display: inline-flex; + align-items: center; padding: 6px 13px; border-radius: 8px; font-size: 13px; @@ -673,9 +675,10 @@ const t=globalThis,e=t.ShadowRoot&&(void 0===t.ShadyCSS||t.ShadyCSS.nativeShadow } .tab .tabedit { --mdc-icon-size: 13px; + display: inline-flex; + align-items: center; margin-left: 6px; opacity: 0.4; - vertical-align: middle; } .tab:hover .tabedit { opacity: 0.9; @@ -1337,7 +1340,7 @@ const t=globalThis,e=t.ShadowRoot&&(void 0===t.ShadyCSS||t.ShadyCSS.nativeShadow class="tab ${this._space===t.id?"active":""}" @click=${()=>{this._space=t.id,this._selId=null,this._restoreZoom()}} > - ${t.title}${this._norm&&"plan"===this._mode?H`{e.stopPropagation(),this._openSpaceDialog("edit",t.id)}}>`:W} `)} @@ -1887,4 +1890,4 @@ const t=globalThis,e=t.ShadowRoot&&(void 0===t.ShadyCSS||t.ShadyCSS.nativeShadow - `}}Ii.properties={hass:{attribute:!1},_config:{state:!0},_space:{state:!0},_layout:{state:!0},_devices:{state:!0},_tip:{state:!0},_selId:{state:!0},_toast:{state:!0},_serverCfg:{state:!0},_mode:{state:!0},_tool:{state:!0},_path:{state:!0},_cursorPt:{state:!0},_mergeSel:{state:!0},_openingDialog:{state:!0},_openingInfo:{state:!0},_mergeDialog:{state:!0},_splitSel:{state:!0},_areaSel:{state:!0},_nameSel:{state:!0},_roomDialog:{state:!0},_spaceDialog:{state:!0},_infoCard:{state:!0},_rulesDialog:{state:!0},_settingsDialog:{state:!0},_importDialog:{state:!0},_markerDialog:{state:!0},_zoom:{state:!0},_view:{state:!0}},Ii.styles=mi,customElements.get("houseplan-card")||customElements.define("houseplan-card",Ii),window.customCards=window.customCards||[],window.customCards.find(t=>"houseplan-card"===t.type)||window.customCards.push({type:"houseplan-card",name:"House Plan Card",description:"Interactive house plan: spaces, rooms and devices with live states and drag layout."}),console.info("%c HOUSEPLAN-CARD %c v1.30.0 ","background:#3ea6ff;color:#04121f;font-weight:700",""); + `}}Ii.properties={hass:{attribute:!1},_config:{state:!0},_space:{state:!0},_layout:{state:!0},_devices:{state:!0},_tip:{state:!0},_selId:{state:!0},_toast:{state:!0},_serverCfg:{state:!0},_mode:{state:!0},_tool:{state:!0},_path:{state:!0},_cursorPt:{state:!0},_mergeSel:{state:!0},_openingDialog:{state:!0},_openingInfo:{state:!0},_mergeDialog:{state:!0},_splitSel:{state:!0},_areaSel:{state:!0},_nameSel:{state:!0},_roomDialog:{state:!0},_spaceDialog:{state:!0},_infoCard:{state:!0},_rulesDialog:{state:!0},_settingsDialog:{state:!0},_importDialog:{state:!0},_markerDialog:{state:!0},_zoom:{state:!0},_view:{state:!0}},Ii.styles=mi,customElements.get("houseplan-card")||customElements.define("houseplan-card",Ii),window.customCards=window.customCards||[],window.customCards.find(t=>"houseplan-card"===t.type)||window.customCards.push({type:"houseplan-card",name:"House Plan Card",description:"Interactive house plan: spaces, rooms and devices with live states and drag layout."}),console.info("%c HOUSEPLAN-CARD %c v1.30.1 ","background:#3ea6ff;color:#04121f;font-weight:700",""); diff --git a/dist/houseplan-card.js b/dist/houseplan-card.js index 681c8dc..31d9fb5 100755 --- a/dist/houseplan-card.js +++ b/dist/houseplan-card.js @@ -83,6 +83,8 @@ const t=globalThis,e=t.ShadowRoot&&(void 0===t.ShadyCSS||t.ShadyCSS.nativeShadow border: 0; background: transparent; color: var(--hp-muted); + display: inline-flex; + align-items: center; padding: 6px 13px; border-radius: 8px; font-size: 13px; @@ -673,9 +675,10 @@ const t=globalThis,e=t.ShadowRoot&&(void 0===t.ShadyCSS||t.ShadyCSS.nativeShadow } .tab .tabedit { --mdc-icon-size: 13px; + display: inline-flex; + align-items: center; margin-left: 6px; opacity: 0.4; - vertical-align: middle; } .tab:hover .tabedit { opacity: 0.9; @@ -1337,7 +1340,7 @@ const t=globalThis,e=t.ShadowRoot&&(void 0===t.ShadyCSS||t.ShadyCSS.nativeShadow class="tab ${this._space===t.id?"active":""}" @click=${()=>{this._space=t.id,this._selId=null,this._restoreZoom()}} > - ${t.title}${this._norm&&"plan"===this._mode?H`{e.stopPropagation(),this._openSpaceDialog("edit",t.id)}}>`:W} `)} @@ -1887,4 +1890,4 @@ const t=globalThis,e=t.ShadowRoot&&(void 0===t.ShadyCSS||t.ShadyCSS.nativeShadow - `}}Ii.properties={hass:{attribute:!1},_config:{state:!0},_space:{state:!0},_layout:{state:!0},_devices:{state:!0},_tip:{state:!0},_selId:{state:!0},_toast:{state:!0},_serverCfg:{state:!0},_mode:{state:!0},_tool:{state:!0},_path:{state:!0},_cursorPt:{state:!0},_mergeSel:{state:!0},_openingDialog:{state:!0},_openingInfo:{state:!0},_mergeDialog:{state:!0},_splitSel:{state:!0},_areaSel:{state:!0},_nameSel:{state:!0},_roomDialog:{state:!0},_spaceDialog:{state:!0},_infoCard:{state:!0},_rulesDialog:{state:!0},_settingsDialog:{state:!0},_importDialog:{state:!0},_markerDialog:{state:!0},_zoom:{state:!0},_view:{state:!0}},Ii.styles=mi,customElements.get("houseplan-card")||customElements.define("houseplan-card",Ii),window.customCards=window.customCards||[],window.customCards.find(t=>"houseplan-card"===t.type)||window.customCards.push({type:"houseplan-card",name:"House Plan Card",description:"Interactive house plan: spaces, rooms and devices with live states and drag layout."}),console.info("%c HOUSEPLAN-CARD %c v1.30.0 ","background:#3ea6ff;color:#04121f;font-weight:700",""); + `}}Ii.properties={hass:{attribute:!1},_config:{state:!0},_space:{state:!0},_layout:{state:!0},_devices:{state:!0},_tip:{state:!0},_selId:{state:!0},_toast:{state:!0},_serverCfg:{state:!0},_mode:{state:!0},_tool:{state:!0},_path:{state:!0},_cursorPt:{state:!0},_mergeSel:{state:!0},_openingDialog:{state:!0},_openingInfo:{state:!0},_mergeDialog:{state:!0},_splitSel:{state:!0},_areaSel:{state:!0},_nameSel:{state:!0},_roomDialog:{state:!0},_spaceDialog:{state:!0},_infoCard:{state:!0},_rulesDialog:{state:!0},_settingsDialog:{state:!0},_importDialog:{state:!0},_markerDialog:{state:!0},_zoom:{state:!0},_view:{state:!0}},Ii.styles=mi,customElements.get("houseplan-card")||customElements.define("houseplan-card",Ii),window.customCards=window.customCards||[],window.customCards.find(t=>"houseplan-card"===t.type)||window.customCards.push({type:"houseplan-card",name:"House Plan Card",description:"Interactive house plan: spaces, rooms and devices with live states and drag layout."}),console.info("%c HOUSEPLAN-CARD %c v1.30.1 ","background:#3ea6ff;color:#04121f;font-weight:700",""); diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index 23bd7f8..4573f4f 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +## v1.30.1 — 2026-07-22 (space gear polish) +- The gear icon next to the space name is now visible in **every mode** (not + just Plan) for users who can edit, so space settings are always one click + away. The "+" (add space) tab remains Plan-only. +- Fixed the gear's vertical alignment — it sat noticeably lower than the space + name (baseline-aligned web component); tabs are now flex-centered. + ## v1.30.0 — 2026-07-22 (lock action in the opening info card) - The door/window info card (View mode) now offers an explicit **Unlock/Lock button** when a lock entity is bound and available. Unlock is styled red as a diff --git a/docs/TESTING.md b/docs/TESTING.md index 8347e6f..d74ac5b 100644 --- a/docs/TESTING.md +++ b/docs/TESTING.md @@ -140,6 +140,9 @@ Run the *core flows* (marked ★ below) in each environment at least once per mi (explicit ripple color still wins); off/white lights unchanged [auto] - [ ] Alarm pulse (v1.27.0): leak/smoke/gas/CO/siren in 'on' pulse a red ring over any display mode; clears on 'off'; unavailable never alarms [auto]; reduced-motion static +- [ ] Space gear (v1.30.1): the cog next to the space name is visible in every + mode (admins only), vertically centered with the tab text; clicking it + opens space settings without switching the tab; "+" tab stays Plan-only [auto] - [ ] Lock action (v1.30.0): opening info card (View) shows Unlock (red) when locked / Lock when unlocked; button calls the lock service; disabled while locking/unlocking; hidden when unavailable; plan-icon tap still never diff --git a/package.json b/package.json index f585fe2..6d9e1e2 100755 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "houseplan-card", - "version": "1.30.0", + "version": "1.30.1", "description": "Interactive house plan Lovelace card for Home Assistant", "license": "MIT", "type": "module", diff --git a/src/houseplan-card.ts b/src/houseplan-card.ts index 552493a..84fef1b 100755 --- a/src/houseplan-card.ts +++ b/src/houseplan-card.ts @@ -32,7 +32,7 @@ import './space-card'; import { cardStyles } from './styles'; import { langOf, t, type I18nKey } from './i18n'; -const CARD_VERSION = '1.30.0'; +const CARD_VERSION = '1.30.1'; const LS_KEY = 'houseplan_card_layout_v1'; const LS_CFG = 'houseplan_card_cfg_v1'; // cache of the server config+layout for instant rendering const LS_ZOOM = 'houseplan_card_zoom_v1'; @@ -2408,7 +2408,7 @@ class HouseplanCard extends LitElement { this._restoreZoom(); }} > - ${s.title}${this._norm && this._mode === 'plan' + ${s.title}${this._norm && this._canEdit ? html` { diff --git a/src/styles.ts b/src/styles.ts index 1a59d73..d2f6291 100644 --- a/src/styles.ts +++ b/src/styles.ts @@ -80,6 +80,8 @@ export const cardStyles = css` border: 0; background: transparent; color: var(--hp-muted); + display: inline-flex; + align-items: center; padding: 6px 13px; border-radius: 8px; font-size: 13px; @@ -670,9 +672,10 @@ export const cardStyles = css` } .tab .tabedit { --mdc-icon-size: 13px; + display: inline-flex; + align-items: center; margin-left: 6px; opacity: 0.4; - vertical-align: middle; } .tab:hover .tabedit { opacity: 0.9;