Allow to resize card in the grid with more precision

This commit is contained in:
Paul Bottein 2024-10-11 12:03:38 +02:00
parent 07e5aa30c6
commit fde1bb7d6a
No known key found for this signature in database
6 changed files with 117 additions and 31 deletions

View File

@ -14,6 +14,12 @@ import {
} from "../panels/lovelace/common/compute-card-grid-size"; } from "../panels/lovelace/common/compute-card-grid-size";
import { HomeAssistant } from "../types"; import { HomeAssistant } from "../types";
declare global {
interface HASSDomEvents {
"grid-reset": undefined;
}
}
@customElement("ha-grid-size-picker") @customElement("ha-grid-size-picker")
export class HaGridSizeEditor extends LitElement { export class HaGridSizeEditor extends LitElement {
@property({ attribute: false }) public hass!: HomeAssistant; @property({ attribute: false }) public hass!: HomeAssistant;
@ -184,12 +190,7 @@ export class HaGridSizeEditor extends LitElement {
private _reset(ev) { private _reset(ev) {
ev.stopPropagation(); ev.stopPropagation();
fireEvent(this, "value-changed", { fireEvent(this, "grid-reset");
value: {
rows: undefined,
columns: undefined,
},
});
} }
private _sliderMoved(ev) { private _sliderMoved(ev) {

View File

@ -11,6 +11,8 @@ export type CardGridSize = {
columns: number | "full"; columns: number | "full";
}; };
export const GRID_COLUMN_MULTIPLIER = 3;
export const computeCardGridSize = ( export const computeCardGridSize = (
options: LovelaceLayoutOptions options: LovelaceLayoutOptions
): CardGridSize => { ): CardGridSize => {
@ -20,14 +22,16 @@ export const computeCardGridSize = (
const maxRows = options.grid_max_rows; const maxRows = options.grid_max_rows;
const minColumns = options.grid_min_columns; const minColumns = options.grid_min_columns;
const maxColumns = options.grid_max_columns; const maxColumns = options.grid_max_columns;
const precisionMode = options.grid_precision_mode;
const clampedRows = const clampedRows =
typeof rows === "string" ? rows : conditionalClamp(rows, minRows, maxRows); typeof rows === "string" ? rows : conditionalClamp(rows, minRows, maxRows);
const clampedColumns = const clampedColumns =
typeof columns === "string" typeof columns === "string" || precisionMode
? columns ? columns
: conditionalClamp(columns, minColumns, maxColumns); : conditionalClamp(columns, minColumns, maxColumns) *
GRID_COLUMN_MULTIPLIER;
return { return {
rows: clampedRows, rows: clampedRows,

View File

@ -26,6 +26,7 @@ import { HuiCard } from "../../cards/hui-card";
import { import {
CardGridSize, CardGridSize,
computeCardGridSize, computeCardGridSize,
GRID_COLUMN_MULTIPLIER,
} from "../../common/compute-card-grid-size"; } from "../../common/compute-card-grid-size";
import { LovelaceLayoutOptions } from "../../types"; 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( private _isDefault = memoizeOne(
(options?: LovelaceLayoutOptions) => (options?: LovelaceLayoutOptions) =>
options?.grid_columns === undefined && options?.grid_rows === undefined options?.grid_columns === undefined &&
options?.grid_rows === undefined &&
options?.grid_precision_mode === undefined
); );
render() { render() {
@ -74,6 +88,8 @@ export class HuiCardLayoutEditor extends LitElement {
const totalColumns = (this.sectionConfig.column_span ?? 1) * 4; const totalColumns = (this.sectionConfig.column_span ?? 1) * 4;
const precisionMode = options.grid_precision_mode ?? false;
return html` return html`
<div class="header"> <div class="header">
<p class="intro"> <p class="intro">
@ -135,20 +151,39 @@ export class HuiCardLayoutEditor extends LitElement {
></ha-yaml-editor> ></ha-yaml-editor>
` `
: html` : html`
${precisionMode
? html`
<ha-grid-size-picker <ha-grid-size-picker
style=${styleMap({ style=${styleMap({
"max-width": `${totalColumns * 45 + 50}px`, "max-width": `${totalColumns * 50 + 50}px`,
})}
.columns=${totalColumns * GRID_COLUMN_MULTIPLIER}
.hass=${this.hass}
.value=${value}
.isDefault=${this._isDefault(this.config.layout_options)}
@grid-reset=${this._reset}
@value-changed=${this._gridSizeChanged}
.rowMin=${options.grid_min_rows}
.rowMax=${options.grid_max_rows}
></ha-grid-size-picker>
`
: html`
<ha-grid-size-picker
style=${styleMap({
"max-width": `${totalColumns * 50 + 50}px`,
})} })}
.columns=${totalColumns} .columns=${totalColumns}
.hass=${this.hass} .hass=${this.hass}
.value=${value} .value=${value}
.isDefault=${this._isDefault(this.config.layout_options)} .isDefault=${this._isDefault(this.config.layout_options)}
@grid-reset=${this._reset}
@value-changed=${this._gridSizeChanged} @value-changed=${this._gridSizeChanged}
.rowMin=${options.grid_min_rows} .rowMin=${options.grid_min_rows}
.rowMax=${options.grid_max_rows} .rowMax=${options.grid_max_rows}
.columnMin=${options.grid_min_columns} .columnMin=${options.grid_min_columns}
.columnMax=${options.grid_max_columns} .columnMax=${options.grid_max_columns}
></ha-grid-size-picker> ></ha-grid-size-picker>
`}
<ha-settings-row> <ha-settings-row>
<span slot="heading" data-for="full-width"> <span slot="heading" data-for="full-width">
${this.hass.localize( ${this.hass.localize(
@ -167,6 +202,24 @@ export class HuiCardLayoutEditor extends LitElement {
> >
</ha-switch> </ha-switch>
</ha-settings-row> </ha-settings-row>
<ha-settings-row>
<span slot="heading" data-for="full-width">
${this.hass.localize(
"ui.panel.lovelace.editor.edit_card.layout.precision_mode"
)}
</span>
<span slot="description" data-for="full-width">
${this.hass.localize(
"ui.panel.lovelace.editor.edit_card.layout.precision_mode_helper"
)}
</span>
<ha-switch
@change=${this._precisionModeChanged}
.checked=${precisionMode}
name="full-precision_mode"
>
</ha-switch>
</ha-settings-row>
`} `}
`; `;
} }
@ -211,9 +264,6 @@ export class HuiCardLayoutEditor extends LitElement {
case 1: case 1:
this._yamlMode = true; this._yamlMode = true;
break; break;
case 2:
this._reset();
break;
} }
} }
@ -275,6 +325,34 @@ export class HuiCardLayoutEditor extends LitElement {
fireEvent(this, "value-changed", { value: newConfig }); 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 = [ static styles = [
haStyle, haStyle,
css` css`

View File

@ -165,7 +165,7 @@ export class GridSection extends LitElement implements LovelaceSectionElement {
haStyle, haStyle,
css` css`
:host { :host {
--base-column-count: 4; --base-column-count: 12;
--row-gap: var(--ha-section-grid-row-gap, 8px); --row-gap: var(--ha-section-grid-row-gap, 8px);
--column-gap: var(--ha-section-grid-column-gap, 8px); --column-gap: var(--ha-section-grid-column-gap, 8px);
--row-height: var(--ha-section-grid-row-height, 56px); --row-height: var(--ha-section-grid-row-height, 56px);
@ -230,8 +230,8 @@ export class GridSection extends LitElement implements LovelaceSectionElement {
.add { .add {
outline: none; outline: none;
grid-row: span var(--row-size, 1); grid-row: span 1;
grid-column: span var(--column-size, 2); grid-column: span 6;
background: none; background: none;
cursor: pointer; cursor: pointer;
border-radius: var(--ha-card-border-radius, 12px); border-radius: var(--ha-card-border-radius, 12px);

View File

@ -49,6 +49,7 @@ export type LovelaceLayoutOptions = {
grid_min_columns?: number; grid_min_columns?: number;
grid_min_rows?: number; grid_min_rows?: number;
grid_max_rows?: number; grid_max_rows?: number;
grid_precision_mode?: boolean;
}; };
export interface LovelaceCard extends HTMLElement { export interface LovelaceCard extends HTMLElement {

View File

@ -5645,7 +5645,9 @@
}, },
"layout": { "layout": {
"full_width": "Full width card", "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": { "edit_badge": {