Allow resizing section to span multiple columns (#21742)

* WIP: Allow to resize section

* Use listeners

* Rename variables

* Rename variables

* Remove column min width

* Make column breakpoints optional

* Use old logic to calculate the number of columns

* Remove breakpoints

* Simplify column span
This commit is contained in:
Paul Bottein 2024-08-28 09:54:03 +02:00 committed by GitHub
parent 7c5f947865
commit 5a229e3c88
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 74 additions and 25 deletions

View File

@ -5,6 +5,7 @@ import type { LovelaceStrategyConfig } from "./strategy";
export interface LovelaceBaseSectionConfig {
title?: string;
visibility?: Condition[];
column_span?: number;
}
export interface LovelaceSectionConfig extends LovelaceBaseSectionConfig {

View File

@ -13,10 +13,15 @@ const SCHEMA = [
name: "title",
selector: { text: {} },
},
{
name: "column_span",
selector: { number: { min: 1, max: 3 } },
},
] as const satisfies HaFormSchema[];
type SettingsData = {
title: string;
column_span?: number;
};
@customElement("hui-section-settings-editor")
@ -28,6 +33,7 @@ export class HuiDialogEditSection extends LitElement {
render() {
const data: SettingsData = {
title: this.config.title || "",
column_span: this.config.column_span || 1,
};
return html`
@ -59,6 +65,7 @@ export class HuiDialogEditSection extends LitElement {
const newConfig: LovelaceSectionRawConfig = {
...this.config,
title: newData.title,
column_span: newData.column_span,
};
if (!newConfig.title) {

View File

@ -220,8 +220,14 @@ export class GridSection extends LitElement implements LovelaceSectionElement {
gap: var(--row-gap);
}
.container {
--grid-column-count: calc(
var(--column-count) * var(--column-span, 1)
);
display: grid;
grid-template-columns: repeat(var(--column-count), minmax(0, 1fr));
grid-template-columns: repeat(
var(--grid-column-count),
minmax(0, 1fr)
);
grid-auto-rows: minmax(var(--row-height), auto);
row-gap: var(--row-gap);
column-gap: var(--column-gap);

View File

@ -1,3 +1,4 @@
import { ResizeController } from "@lit-labs/observers/resize-controller";
import { mdiArrowAll, mdiDelete, mdiPencil, mdiViewGridPlus } from "@mdi/js";
import {
CSSResultGroup,
@ -26,6 +27,10 @@ import { showEditSectionDialog } from "../editor/section-editor/show-edit-sectio
import { HuiSection } from "../sections/hui-section";
import type { Lovelace } from "../types";
export const DEFAULT_MAX_COLUMNS = 4;
const parsePx = (value: string) => parseInt(value.replace("px", ""));
@customElement("hui-sections-view")
export class SectionsView extends LitElement implements LovelaceViewElement {
@property({ attribute: false }) public hass!: HomeAssistant;
@ -46,6 +51,30 @@ export class SectionsView extends LitElement implements LovelaceViewElement {
@state() _dragging = false;
private _columnsController = new ResizeController(this, {
callback: (entries) => {
const totalWidth = entries[0]?.contentRect.width;
const style = getComputedStyle(this);
const container = this.shadowRoot!.querySelector(".container")!;
const containerStyle = getComputedStyle(container);
const paddingLeft = parsePx(containerStyle.paddingLeft);
const paddingRight = parsePx(containerStyle.paddingRight);
const padding = paddingLeft + paddingRight;
const minColumnWidth = parsePx(
style.getPropertyValue("--column-min-width")
);
const columnGap = parsePx(containerStyle.columnGap);
const columns = Math.floor(
(totalWidth - padding + columnGap) / (minColumnWidth + columnGap)
);
const maxColumns = this._config?.max_columns ?? DEFAULT_MAX_COLUMNS;
return Math.max(Math.min(maxColumns, columns), 1);
},
});
public setConfig(config: LovelaceViewConfig): void {
this._config = config;
}
@ -95,10 +124,11 @@ export class SectionsView extends LitElement implements LovelaceViewElement {
if (!this.lovelace) return nothing;
const sections = this.sections;
const totalCount = this._sectionCount + (this.lovelace?.editMode ? 1 : 0);
const totalSectionCount =
this._sectionCount + (this.lovelace?.editMode ? 1 : 0);
const editMode = this.lovelace.editMode;
const maxColumnsCount = this._config?.max_columns;
const maxColumnCount = this._columnsController.value ?? 1;
return html`
<hui-view-badges
@ -118,17 +148,29 @@ export class SectionsView extends LitElement implements LovelaceViewElement {
<div
class="container"
style=${styleMap({
"--max-columns-count": maxColumnsCount,
"--total-count": totalCount,
"--total-section-count": totalSectionCount,
"--max-column-count": maxColumnCount,
})}
>
${repeat(
sections,
(section) => this._getSectionKey(section),
(section, idx) => {
const sectionConfig = this._config?.sections?.[idx];
const columnSpan = Math.min(
sectionConfig?.column_span || 1,
maxColumnCount
);
(section as any).itemPath = [idx];
return html`
<div class="section">
<div
class="section"
style=${styleMap({
"--column-span": columnSpan,
})}
>
${editMode
? html`
<div class="section-overlay">
@ -252,19 +294,19 @@ export class SectionsView extends LitElement implements LovelaceViewElement {
--row-height: var(--ha-view-sections-row-height, 56px);
--row-gap: var(--ha-view-sections-row-gap, 8px);
--column-gap: var(--ha-view-sections-column-gap, 32px);
--column-min-width: var(--ha-view-sections-column-min-width, 320px);
--column-max-width: var(--ha-view-sections-column-max-width, 500px);
--column-min-width: var(--ha-view-sections-column-min-width, 320px);
display: block;
}
.container > * {
position: relative;
max-width: var(--column-max-width);
width: 100%;
}
.section {
border-radius: var(--ha-card-border-radius, 12px);
grid-column: span var(--column-span);
}
.section:not(:has(> *:not([hidden]))) {
@ -272,29 +314,22 @@ export class SectionsView extends LitElement implements LovelaceViewElement {
}
.container {
--max-count: min(var(--total-count), var(--max-columns-count, 4));
--max-width: min(
calc(
(var(--max-count) + 1) * var(--column-min-width) +
(var(--max-count) + 2) * var(--column-gap) - 1px
),
calc(
var(--max-count) * var(--column-max-width) + (var(--max-count) + 1) *
var(--column-gap)
)
--column-count: min(
var(--max-column-count),
var(--total-section-count)
);
display: grid;
align-items: start;
justify-items: center;
grid-template-columns: repeat(
auto-fit,
minmax(min(var(--column-min-width), 100%), 1fr)
);
justify-content: center;
grid-template-columns: repeat(var(--column-count), 1fr);
gap: var(--row-gap) var(--column-gap);
padding: var(--row-gap) var(--column-gap);
box-sizing: border-box;
max-width: var(--max-width);
box-sizing: content-box;
margin: 0 auto;
max-width: calc(
var(--column-count) * var(--column-max-width) +
(var(--column-count) - 1) * var(--column-gap)
);
}
@media (max-width: 600px) {