Move section edit logic to its own component (#27017)

This commit is contained in:
Paul Bottein 2025-09-12 10:51:10 +02:00 committed by GitHub
parent 7082646fe5
commit 0eaf9ead9e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 167 additions and 144 deletions

View File

@ -0,0 +1,152 @@
import { mdiDelete, mdiDrag, mdiPencil } from "@mdi/js";
import type { CSSResultGroup, TemplateResult } from "lit";
import { LitElement, css, html } from "lit";
import { customElement, property } from "lit/decorators";
import "../../../components/ha-button-menu";
import "../../../components/ha-icon-button";
import "../../../components/ha-list-item";
import "../../../components/ha-svg-icon";
import { showConfirmationDialog } from "../../../dialogs/generic/show-dialog-box";
import { haStyle } from "../../../resources/styles";
import type { HomeAssistant } from "../../../types";
import { deleteSection } from "../editor/config-util";
import { findLovelaceContainer } from "../editor/lovelace-path";
import { showEditSectionDialog } from "../editor/section-editor/show-edit-section-dialog";
import type { Lovelace } from "../types";
@customElement("hui-section-edit-mode")
export class HuiSectionEditMode extends LitElement {
@property({ attribute: false }) public hass!: HomeAssistant;
@property({ attribute: false }) public lovelace!: Lovelace;
@property({ attribute: false, type: Number }) public index!: number;
@property({ attribute: false, type: Number }) public viewIndex!: number;
protected render(): TemplateResult {
return html`
<div class="section-header">
<div class="section-actions">
<ha-svg-icon
aria-hidden="true"
class="handle"
.path=${mdiDrag}
></ha-svg-icon>
<ha-icon-button
.label=${this.hass.localize("ui.common.edit")}
@click=${this._editSection}
.path=${mdiPencil}
></ha-icon-button>
<ha-icon-button
.label=${this.hass.localize("ui.common.delete")}
@click=${this._deleteSection}
.path=${mdiDelete}
></ha-icon-button>
</div>
</div>
<div class="section-wrapper">
<slot></slot>
</div>
`;
}
private async _editSection(ev) {
ev.stopPropagation();
showEditSectionDialog(this, {
lovelace: this.lovelace!,
lovelaceConfig: this.lovelace!.config,
saveConfig: (newConfig) => {
this.lovelace!.saveConfig(newConfig);
},
viewIndex: this.viewIndex,
sectionIndex: this.index,
});
}
private async _deleteSection(ev) {
ev.stopPropagation();
const path = [this.viewIndex, this.index] as [number, number];
const section = findLovelaceContainer(this.lovelace!.config, path);
const cardCount = "cards" in section && section.cards?.length;
if (cardCount) {
const confirm = await showConfirmationDialog(this, {
title: this.hass.localize(
"ui.panel.lovelace.editor.delete_section.title"
),
text: this.hass.localize(
`ui.panel.lovelace.editor.delete_section.text`
),
confirmText: this.hass.localize("ui.common.delete"),
destructive: true,
});
if (!confirm) return;
}
const newConfig = deleteSection(
this.lovelace!.config,
this.viewIndex,
this.index
);
this.lovelace!.saveConfig(newConfig);
}
static get styles(): CSSResultGroup {
return [
haStyle,
css`
.section-header {
position: relative;
height: 34px;
display: flex;
flex-direction: column;
justify-content: flex-end;
}
.section-actions {
position: absolute;
height: 36px;
bottom: -2px;
right: 0;
inset-inline-end: 0;
inset-inline-start: initial;
opacity: 1;
display: flex;
align-items: center;
justify-content: center;
transition: opacity 0.2s ease-in-out;
border-radius: var(--ha-card-border-radius, 12px);
border-bottom-left-radius: 0px;
border-bottom-right-radius: 0px;
background: var(--secondary-background-color);
--mdc-icon-button-size: 36px;
--mdc-icon-size: 20px;
color: var(--primary-text-color);
}
.handle {
cursor: grab;
padding: 8px;
}
.section-wrapper {
padding: 8px;
border-radius: var(--ha-card-border-radius, 12px);
border-start-end-radius: 0;
border: 2px dashed var(--divider-color);
min-height: var(--row-height);
}
`,
];
}
}
declare global {
interface HTMLElementTagNameMap {
"hui-section-edit-mode": HuiSectionEditMode;
}
}

View File

@ -99,12 +99,7 @@ export class GridSection extends LitElement implements LovelaceSectionElement {
@item-removed=${this._cardRemoved}
invert-swap
>
<div
class="container ${classMap({
"edit-mode": editMode,
"import-only": this.importOnly,
})}"
>
<div class="container">
${repeat(
cardsConfig,
(cardConfig) => this._getKey(cardConfig),
@ -238,19 +233,6 @@ export class GridSection extends LitElement implements LovelaceSectionElement {
margin: 0 auto;
}
.container.edit-mode {
padding: 8px;
border-radius: var(--ha-card-border-radius, 12px);
border-start-end-radius: 0;
border: 2px dashed var(--divider-color);
min-height: var(--row-height);
}
.container.import-only {
border: none;
padding: 0 !important;
}
.card {
border-radius: var(--ha-card-border-radius, 12px);
position: relative;

View File

@ -1,11 +1,5 @@
import { ResizeController } from "@lit-labs/observers/resize-controller";
import {
mdiDelete,
mdiDrag,
mdiEyeOff,
mdiPencil,
mdiViewGridPlus,
} from "@mdi/js";
import { mdiEyeOff, mdiViewGridPlus } from "@mdi/js";
import type { PropertyValues } from "lit";
import { css, html, LitElement, nothing } from "lit";
import { customElement, property, state } from "lit/decorators";
@ -22,28 +16,21 @@ import type { LovelaceViewElement } from "../../../data/lovelace";
import type { LovelaceCardConfig } from "../../../data/lovelace/config/card";
import type { LovelaceSectionConfig } from "../../../data/lovelace/config/section";
import type { LovelaceViewConfig } from "../../../data/lovelace/config/view";
import { showConfirmationDialog } from "../../../dialogs/generic/show-dialog-box";
import type { HomeAssistant } from "../../../types";
import type { HuiBadge } from "../badges/hui-badge";
import "./hui-view-header";
import type { HuiCard } from "../cards/hui-card";
import "../components/hui-badge-edit-mode";
import {
addSection,
deleteSection,
moveCard,
moveSection,
} from "../editor/config-util";
import "../components/hui-section-edit-mode";
import { addSection, moveCard, moveSection } from "../editor/config-util";
import type { LovelaceCardPath } from "../editor/lovelace-path";
import {
findLovelaceContainer,
findLovelaceItems,
getLovelaceContainerPath,
parseLovelaceCardPath,
} from "../editor/lovelace-path";
import { showEditSectionDialog } from "../editor/section-editor/show-edit-section-dialog";
import type { HuiSection } from "../sections/hui-section";
import type { Lovelace } from "../types";
import "./hui-view-header";
export const DEFAULT_MAX_COLUMNS = 4;
@ -205,41 +192,19 @@ export class SectionsView extends LitElement implements LovelaceViewElement {
})}
>
${
this.lovelace?.editMode
editMode
? html`
<div class="section-header">
${editMode
? html`
<div class="section-actions">
<ha-svg-icon
aria-hidden="true"
class="handle"
.path=${mdiDrag}
></ha-svg-icon>
<ha-icon-button
.label=${this.hass.localize(
"ui.common.edit"
)}
@click=${this._editSection}
.index=${idx}
.path=${mdiPencil}
></ha-icon-button>
<ha-icon-button
.label=${this.hass.localize(
"ui.common.delete"
)}
@click=${this._deleteSection}
.index=${idx}
.path=${mdiDelete}
></ha-icon-button>
</div>
`
: nothing}
</div>
<hui-section-edit-mode
.hass=${this.hass}
.lovelace=${this.lovelace}
.index=${idx}
.viewIndex=${this.index}
>
${section}
</hui-section-edit-mode>
`
: nothing
: section
}
${section}
</div>
</div>
`;
@ -375,48 +340,6 @@ export class SectionsView extends LitElement implements LovelaceViewElement {
this.lovelace!.saveConfig(newConfig);
}
private async _editSection(ev) {
const index = ev.currentTarget.index;
showEditSectionDialog(this, {
lovelace: this.lovelace!,
lovelaceConfig: this.lovelace!.config,
saveConfig: (newConfig) => {
this.lovelace!.saveConfig(newConfig);
},
viewIndex: this.index!,
sectionIndex: index,
});
}
private async _deleteSection(ev) {
const index = ev.currentTarget.index;
const path = [this.index!, index] as [number, number];
const section = findLovelaceContainer(this.lovelace!.config, path);
const cardCount = "cards" in section && section.cards?.length;
if (cardCount) {
const confirm = await showConfirmationDialog(this, {
title: this.hass.localize(
"ui.panel.lovelace.editor.delete_section.title"
),
text: this.hass.localize(
`ui.panel.lovelace.editor.delete_section.text`
),
confirmText: this.hass.localize("ui.common.delete"),
destructive: true,
});
if (!confirm) return;
}
const newConfig = deleteSection(this.lovelace!.config, this.index!, index);
this.lovelace!.saveConfig(newConfig);
}
private _sectionMoved(ev: CustomEvent) {
ev.stopPropagation();
const { oldIndex, newIndex } = ev.detail;
@ -486,11 +409,6 @@ export class SectionsView extends LitElement implements LovelaceViewElement {
grid-auto-flow: row dense;
}
.handle {
cursor: grab;
padding: 8px;
}
.create-section-container {
position: relative;
display: flex;
@ -574,35 +492,6 @@ export class SectionsView extends LitElement implements LovelaceViewElement {
);
}
.section-header {
position: relative;
height: 34px;
display: flex;
flex-direction: column;
justify-content: flex-end;
}
.section-actions {
position: absolute;
height: 36px;
bottom: -2px;
right: 0;
inset-inline-end: 0;
inset-inline-start: initial;
opacity: 1;
display: flex;
align-items: center;
justify-content: center;
transition: opacity 0.2s ease-in-out;
border-radius: var(--ha-card-border-radius, 12px);
border-bottom-left-radius: 0px;
border-bottom-right-radius: 0px;
background: var(--secondary-background-color);
--mdc-icon-button-size: 36px;
--mdc-icon-size: 20px;
color: var(--primary-text-color);
}
.imported-cards {
--column-span: var(--column-count);
--row-span: 1;