From fde1bb7d6a60d5926116d5c836a553944de080c7 Mon Sep 17 00:00:00 2001 From: Paul Bottein Date: Fri, 11 Oct 2024 12:03:38 +0200 Subject: [PATCH] Allow to resize card in the grid with more precision --- src/components/ha-grid-size-picker.ts | 13 +- .../lovelace/common/compute-card-grid-size.ts | 8 +- .../card-editor/hui-card-layout-editor.ts | 116 +++++++++++++++--- .../lovelace/sections/hui-grid-section.ts | 6 +- src/panels/lovelace/types.ts | 1 + src/translations/en.json | 4 +- 6 files changed, 117 insertions(+), 31 deletions(-) diff --git a/src/components/ha-grid-size-picker.ts b/src/components/ha-grid-size-picker.ts index c7c15df287..813f1e17ff 100644 --- a/src/components/ha-grid-size-picker.ts +++ b/src/components/ha-grid-size-picker.ts @@ -14,6 +14,12 @@ import { } from "../panels/lovelace/common/compute-card-grid-size"; import { HomeAssistant } from "../types"; +declare global { + interface HASSDomEvents { + "grid-reset": undefined; + } +} + @customElement("ha-grid-size-picker") export class HaGridSizeEditor extends LitElement { @property({ attribute: false }) public hass!: HomeAssistant; @@ -184,12 +190,7 @@ export class HaGridSizeEditor extends LitElement { private _reset(ev) { ev.stopPropagation(); - fireEvent(this, "value-changed", { - value: { - rows: undefined, - columns: undefined, - }, - }); + fireEvent(this, "grid-reset"); } private _sliderMoved(ev) { diff --git a/src/panels/lovelace/common/compute-card-grid-size.ts b/src/panels/lovelace/common/compute-card-grid-size.ts index c27b5a55ba..ceb7b29be9 100644 --- a/src/panels/lovelace/common/compute-card-grid-size.ts +++ b/src/panels/lovelace/common/compute-card-grid-size.ts @@ -11,6 +11,8 @@ export type CardGridSize = { columns: number | "full"; }; +export const GRID_COLUMN_MULTIPLIER = 3; + export const computeCardGridSize = ( options: LovelaceLayoutOptions ): CardGridSize => { @@ -20,14 +22,16 @@ export const computeCardGridSize = ( const maxRows = options.grid_max_rows; const minColumns = options.grid_min_columns; const maxColumns = options.grid_max_columns; + const precisionMode = options.grid_precision_mode; const clampedRows = typeof rows === "string" ? rows : conditionalClamp(rows, minRows, maxRows); const clampedColumns = - typeof columns === "string" + typeof columns === "string" || precisionMode ? columns - : conditionalClamp(columns, minColumns, maxColumns); + : conditionalClamp(columns, minColumns, maxColumns) * + GRID_COLUMN_MULTIPLIER; return { rows: clampedRows, diff --git a/src/panels/lovelace/editor/card-editor/hui-card-layout-editor.ts b/src/panels/lovelace/editor/card-editor/hui-card-layout-editor.ts index 6ee81aba24..add84d392c 100644 --- a/src/panels/lovelace/editor/card-editor/hui-card-layout-editor.ts +++ b/src/panels/lovelace/editor/card-editor/hui-card-layout-editor.ts @@ -26,6 +26,7 @@ import { HuiCard } from "../../cards/hui-card"; import { CardGridSize, computeCardGridSize, + GRID_COLUMN_MULTIPLIER, } from "../../common/compute-card-grid-size"; import { LovelaceLayoutOptions } from "../../types"; @@ -57,11 +58,24 @@ export class HuiCardLayoutEditor extends LitElement { }) ); - private _computeCardGridSize = memoizeOne(computeCardGridSize); + private _computeCardGridSize = memoizeOne( + (options: LovelaceLayoutOptions) => { + const size = computeCardGridSize(options); + if (!options.grid_precision_mode) { + size.columns = + typeof size.columns === "number" + ? Math.round(size.columns / GRID_COLUMN_MULTIPLIER) + : size.columns; + } + return size; + } + ); private _isDefault = memoizeOne( (options?: LovelaceLayoutOptions) => - options?.grid_columns === undefined && options?.grid_rows === undefined + options?.grid_columns === undefined && + options?.grid_rows === undefined && + options?.grid_precision_mode === undefined ); render() { @@ -74,6 +88,8 @@ export class HuiCardLayoutEditor extends LitElement { const totalColumns = (this.sectionConfig.column_span ?? 1) * 4; + const precisionMode = options.grid_precision_mode ?? false; + return html`

@@ -135,20 +151,39 @@ export class HuiCardLayoutEditor extends LitElement { > ` : html` - + ${precisionMode + ? html` + + ` + : html` + + `} ${this.hass.localize( @@ -167,6 +202,24 @@ export class HuiCardLayoutEditor extends LitElement { > + + + ${this.hass.localize( + "ui.panel.lovelace.editor.edit_card.layout.precision_mode" + )} + + + ${this.hass.localize( + "ui.panel.lovelace.editor.edit_card.layout.precision_mode_helper" + )} + + + + `} `; } @@ -211,9 +264,6 @@ export class HuiCardLayoutEditor extends LitElement { case 1: this._yamlMode = true; break; - case 2: - this._reset(); - break; } } @@ -275,6 +325,34 @@ export class HuiCardLayoutEditor extends LitElement { fireEvent(this, "value-changed", { value: newConfig }); } + private _precisionModeChanged(ev): void { + ev.stopPropagation(); + const value = ev.target.checked; + + const preciseMode = value; + const gridColumns = this.config.layout_options?.grid_columns; + + const newGridColumns = + typeof gridColumns === "number" + ? preciseMode + ? gridColumns * GRID_COLUMN_MULTIPLIER + : Math.round(gridColumns / GRID_COLUMN_MULTIPLIER) + : gridColumns; + + const newConfig: LovelaceCardConfig = { + ...this.config, + layout_options: { + ...this.config.layout_options, + grid_columns: newGridColumns, + grid_precision_mode: preciseMode || undefined, + }, + }; + if (Object.keys(newConfig.layout_options!).length === 0) { + delete newConfig.layout_options; + } + fireEvent(this, "value-changed", { value: newConfig }); + } + static styles = [ haStyle, css` diff --git a/src/panels/lovelace/sections/hui-grid-section.ts b/src/panels/lovelace/sections/hui-grid-section.ts index 73894cc3bb..109c9651c6 100644 --- a/src/panels/lovelace/sections/hui-grid-section.ts +++ b/src/panels/lovelace/sections/hui-grid-section.ts @@ -165,7 +165,7 @@ export class GridSection extends LitElement implements LovelaceSectionElement { haStyle, css` :host { - --base-column-count: 4; + --base-column-count: 12; --row-gap: var(--ha-section-grid-row-gap, 8px); --column-gap: var(--ha-section-grid-column-gap, 8px); --row-height: var(--ha-section-grid-row-height, 56px); @@ -230,8 +230,8 @@ export class GridSection extends LitElement implements LovelaceSectionElement { .add { outline: none; - grid-row: span var(--row-size, 1); - grid-column: span var(--column-size, 2); + grid-row: span 1; + grid-column: span 6; background: none; cursor: pointer; border-radius: var(--ha-card-border-radius, 12px); diff --git a/src/panels/lovelace/types.ts b/src/panels/lovelace/types.ts index 7a30f3e1f8..ca7bc938d1 100644 --- a/src/panels/lovelace/types.ts +++ b/src/panels/lovelace/types.ts @@ -49,6 +49,7 @@ export type LovelaceLayoutOptions = { grid_min_columns?: number; grid_min_rows?: number; grid_max_rows?: number; + grid_precision_mode?: boolean; }; export interface LovelaceCard extends HTMLElement { diff --git a/src/translations/en.json b/src/translations/en.json index cb94cc44a3..02e1eb12f2 100644 --- a/src/translations/en.json +++ b/src/translations/en.json @@ -5645,7 +5645,9 @@ }, "layout": { "full_width": "Full width card", - "full_width_helper": "Take up the full width of the section whatever its size" + "full_width_helper": "Take up the full width of the section whatever its size", + "precision_mode": "Precision mode", + "precision_mode_helper": "Change the card width with precision without limits" } }, "edit_badge": {