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;