Основная панель: без счётчика устройств, × редактора в своём слоте — ширина шапки не меняется (#647)

Счётчик «N устр.» и ключ count.devices удалены вместе с правилом
`.head .count` (скрывало счётчик на ≤1100 px). Крестик закрытия редактора
вынесен из активной кнопки режима в отдельный слот `.editor-close-slot`
сразу после группы кнопок режимов: 24 × 24 px (--hp-editor-close-size),
одинаковый в редакторе и вне его; вне редактора слот пуст, aria-hidden,
без фокуса и pointer-events. Кликабельная зона × — весь слот (≥24×24, #195),
глиф 13 px; × виден на любой ширине, где видны кнопки режимов.

Смок smoke_toolbar_stable_width (1400/1000/768/390 px, en/ru): ширина
шапки и отступы кнопок стабильны во всех переходах, × виден, попадание
в край зоны закрывает редактор, нет нового overflow. smoke_editor_tabs,
smoke_edge_cases, smoke_hidden_flag переведены на слот/список устройств.
6 мутантов. docs: UX-MODES.md, STYLING-HOOKS.md, data-hp-contract.json.

Issue: #647
User-Visible: yes
This commit is contained in:
Claude
2026-09-25 08:35:57 +00:00
committed by claude[bot]
parent 632d6a2f8e
commit f0ba7c5da9
88 changed files with 905 additions and 691 deletions
+6 -8
View File
@@ -10807,17 +10807,15 @@ export class HouseplanCard extends LitElement {
title=${this._t(('mode.' + m + '_tip') as any)}
@click=${() => this._setMode(m)}>
<ha-icon icon=${ic}></ha-icon><span class="ml">${this._t(('mode.' + m) as any)}</span>
${this._mode === m
? html`<ha-icon class="closex" icon="mdi:close" title=${this._t('title.close_editor')}
data-hp="editor-close"
data-editor-navigation="view"
@click=${(e: Event) => { e.stopPropagation(); this._setMode('view'); }}></ha-icon>`
: nothing}
</button>`,
)}
</div>`
</div>${''/* #647: X owns a fixed slot (the old device-count place): header width never changes */}
<span class="editor-close-slot" aria-hidden=${this._mode === 'view' ? 'true' : nothing}>${this._mode !== 'view'
? html`<button class="closex" title=${this._t('title.close_editor')} aria-label=${this._t('title.close_editor')}
data-hp="editor-close" data-editor-navigation="view"
@click=${(e: Event) => { e.stopPropagation(); this._setMode('view'); }}><ha-icon icon="mdi:close"></ha-icon></button>`
: nothing}</span>`
: nothing}
<span class="count">${this._t('count.devices', { n: devs.filter((d) => !d.hidden).length })}</span>
<span class="spacer"></span>
${this._labsIso && this._mode === 'view' && !this._kiosk
? html`<button class="btn projection-toggle ${iso ? 'on' : ''}"
-1
View File
@@ -50,7 +50,6 @@
"physical.allowed_range": "Erlaubt: {min}–{max} {unit}",
"physical.column_size_title": "Außenmaß der per Klick platzierten quadratischen Säule (1–150 cm).",
"card.title": "Hausplan",
"count.devices": "{n} Entwicklung",
"empty.no_spaces": "Noch keine Bereiche.",
"nav.spaces": "House-Plan-Bereiche",
"empty.add_first": "Ersten Bereich hinzufügen und einen Grundriss hochladen.",
-1
View File
@@ -50,7 +50,6 @@
"physical.allowed_range": "Allowed: {min}–{max} {unit}",
"physical.column_size_title": "Outer side of the square column placed by the click (1–150 cm).",
"card.title": "House plan",
"count.devices": "{n} dev.",
"empty.no_spaces": "No spaces yet.",
"nav.spaces": "House Plan spaces",
"empty.add_first": "Add the first space and upload a floor plan.",
-1
View File
@@ -50,7 +50,6 @@
"physical.allowed_range": "Autorisé : {min}–{max} {unit}",
"physical.column_size_title": "Côté extérieur de la colonne carrée placée par le clic (1–150 cm).",
"card.title": "Plan de la maison",
"count.devices": "{n} app.",
"empty.no_spaces": "Aucun espace pour le moment.",
"nav.spaces": "Espaces House Plan",
"empty.add_first": "Ajoutez le premier espace et importez un plan.",
-1
View File
@@ -50,7 +50,6 @@
"physical.allowed_range": "Допустимо: {min}–{max} {unit}",
"physical.column_size_title": "Внешняя сторона квадратной колонны, создаваемой кликом (1–150 см).",
"card.title": "План дома",
"count.devices": "{n} устр.",
"empty.no_spaces": "Пространств пока нет.",
"nav.spaces": "Пространства House Plan",
"empty.add_first": "Добавьте первое пространство и загрузите план этажа.",
+31 -11
View File
@@ -151,25 +151,45 @@ const chromeCoreStyles = css`
.tab.dragging { cursor: grabbing; opacity: 0.55; }
.tab.drop-before { box-shadow: inset 2px 0 0 0 var(--primary-color, #03a9f4); }
.tab.drop-after { box-shadow: inset -2px 0 0 0 var(--primary-color, #03a9f4); }
.modetab .closex {
--mdc-icon-size: 13px;
/* #647: the editor X owns a fixed slot right after the mode tabs (where
the device count used to be). One size for both states, so entering,
leaving or switching editors never changes the header width; the slot is
the X's pointer target (>= 24 x 24, #195) around a 13 px glyph. */
.editor-close-slot {
--hp-editor-close-size: 24px;
box-sizing: border-box;
display: inline-flex;
flex: none;
align-items: center;
justify-content: center;
width: var(--hp-editor-close-size);
height: var(--hp-editor-close-size);
}
.editor-close-slot[aria-hidden='true'] { pointer-events: none; }
.editor-close-slot .closex {
box-sizing: border-box;
display: inline-flex;
align-items: center;
justify-content: center;
width: 24px;
height: 24px;
min-width: 24px;
min-height: 24px;
/* Keep the old 13 × 13 flex footprint (+2 px left margin) while the
pointer target grows around it. Header width, height and wrapping do
not move; only near-misses that used to hit the active tab reach X. */
margin: -5.5px -5.5px -5.5px -3.5px;
width: 100%;
height: 100%;
margin: 0;
padding: 0;
border: 0;
background: transparent;
color: var(--hp-muted);
opacity: 0.75;
cursor: pointer;
border-radius: var(--rad-s);
font: inherit;
}
.editor-close-slot .closex ha-icon { --mdc-icon-size: 13px; }
:host([data-pointer-hover]) .editor-close-slot .closex:hover { opacity: 1; }
.editor-close-slot .closex:focus-visible {
outline: 2px solid var(--primary-color, #03a9f4);
outline-offset: 1px;
opacity: 1;
}
:host([data-pointer-hover]) .modetab .closex:hover { opacity: 1; }
.editbar .barclose {
box-sizing: border-box;
width: 40px;
-7
View File
@@ -24,17 +24,10 @@ export const dialogsStyles = css`
color: var(--hp-accent);
--mdc-icon-size: 18px;
}
@media (max-width: 1100px) {
.head .count { display: none; }
}
@media (max-width: 620px) {
.head { gap: var(--sp-3); padding: var(--sp-4) 10px; }
.head .title { font-size: var(--fs-m); }
}
.count {
font-size: var(--fs-s);
color: var(--hp-muted);
}
.btn {
display: inline-flex;
align-items: center;