mirror of
https://github.com/home-assistant/frontend.git
synced 2025-07-24 09:46:36 +00:00
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:
parent
7c5f947865
commit
5a229e3c88
@ -5,6 +5,7 @@ import type { LovelaceStrategyConfig } from "./strategy";
|
||||
export interface LovelaceBaseSectionConfig {
|
||||
title?: string;
|
||||
visibility?: Condition[];
|
||||
column_span?: number;
|
||||
}
|
||||
|
||||
export interface LovelaceSectionConfig extends LovelaceBaseSectionConfig {
|
||||
|
@ -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) {
|
||||
|
@ -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);
|
||||
|
@ -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) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user