Add layout options to cards and improve grid and sections defaults (#20001)

* Add grid options to cards

* Fix the height of the card it's rows option is provided

* Add variable

* Adjust grid margin

* Use layout options

* Fix max width when only one column

* Update card API
This commit is contained in:
Paul Bottein 2024-03-07 11:22:26 +01:00 committed by GitHub
parent 00669ac0c3
commit b593b15f27
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
8 changed files with 81 additions and 37 deletions

View File

@ -1,7 +1,10 @@
import { LovelaceLayoutOptions } from "../../../panels/lovelace/types";
export interface LovelaceCardConfig {
index?: number;
view_index?: number;
view_layout?: any;
layout_options?: LovelaceLayoutOptions;
type: string;
[key: string]: any;
}

View File

@ -52,7 +52,11 @@ import { actionHandler } from "../common/directives/action-handler-directive";
import { findEntities } from "../common/find-entities";
import { hasAction } from "../common/has-action";
import { createEntityNotFoundWarning } from "../components/hui-warning";
import { LovelaceCard, LovelaceCardEditor } from "../types";
import {
LovelaceCard,
LovelaceCardEditor,
LovelaceLayoutOptions,
} from "../types";
import { ButtonCardConfig } from "./types";
export const getEntityDefaultButtonAction = (entityId?: string) =>
@ -143,14 +147,14 @@ export class HuiButtonCard extends LitElement implements LovelaceCard {
);
}
public getGridSize(): [number, number] {
public getLayoutOptions(): LovelaceLayoutOptions {
if (
this._config?.show_icon &&
(this._config?.show_name || this._config?.show_state)
) {
return [2, 2];
return { grid_rows: 2, grid_columns: 2 };
}
return [1, 1];
return { grid_rows: 1, grid_columns: 1 };
}
public setConfig(config: ButtonCardConfig): void {

View File

@ -1,11 +1,11 @@
import { css, CSSResultGroup } from "lit";
import { HassEntity } from "home-assistant-js-websocket/dist/types";
import { css, CSSResultGroup } from "lit";
import { customElement } from "lit/decorators";
import { computeDomain } from "../../../common/entity/compute_domain";
import { HomeAssistant } from "../../../types";
import { findEntities } from "../common/find-entities";
import { GraphHeaderFooterConfig } from "../header-footer/types";
import { LovelaceCardEditor } from "../types";
import { LovelaceCardEditor, LovelaceLayoutOptions } from "../types";
import { HuiEntityCard } from "./hui-entity-card";
import { EntityCardConfig, SensorCardConfig } from "./types";
@ -72,8 +72,11 @@ class HuiSensorCard extends HuiEntityCard {
super.setConfig(entityCardConfig);
}
public getGridSize(): [number, number] {
return [2, 2];
public getLayoutOptions(): LovelaceLayoutOptions {
return {
grid_columns: 2,
grid_rows: 2,
};
}
static get styles(): CSSResultGroup {

View File

@ -48,7 +48,11 @@ import { findEntities } from "../common/find-entities";
import { handleAction } from "../common/handle-action";
import { hasAction } from "../common/has-action";
import "../components/hui-timestamp-display";
import type { LovelaceCard, LovelaceCardEditor } from "../types";
import type {
LovelaceCard,
LovelaceCardEditor,
LovelaceLayoutOptions,
} from "../types";
import { renderTileBadge } from "./tile/badges/tile-badge";
import type { ThermostatCardConfig, TileCardConfig } from "./types";
@ -124,16 +128,18 @@ export class HuiTileCard extends LitElement implements LovelaceCard {
);
}
public getGridSize(): [number, number] {
const width = 2;
let height = 1;
public getLayoutOptions(): LovelaceLayoutOptions {
const options = {
grid_columns: 2,
grid_rows: 1,
};
if (this._config?.features?.length) {
height += Math.ceil((this._config.features.length * 2) / 3);
options.grid_rows += Math.ceil((this._config.features.length * 2) / 3);
}
if (this._config?.vertical) {
height++;
options.grid_rows++;
}
return [width, height];
return options;
}
private _handleAction(ev: ActionHandlerEvent) {

View File

@ -3,4 +3,5 @@ import { object, string, any } from "superstruct";
export const baseLovelaceCardConfig = object({
type: string(),
view_layout: any(),
layout_options: any(),
});

View File

@ -14,7 +14,7 @@ import type { HomeAssistant } from "../../../types";
import { HuiErrorCard } from "../cards/hui-error-card";
import "../components/hui-card-edit-mode";
import { moveCard } from "../editor/config-util";
import type { Lovelace, LovelaceCard } from "../types";
import type { Lovelace, LovelaceCard, LovelaceLayoutOptions } from "../types";
const CARD_SORTABLE_OPTIONS: HaSortableOptions = {
delay: 100,
@ -97,14 +97,26 @@ export class GridSection extends LitElement implements LovelaceSectionElement {
const card = this.cards![idx];
(card as any).editMode = editMode;
(card as any).lovelace = this.lovelace;
const size = card && (card as any).getGridSize?.();
const configOptions = _cardConfig.layout_options;
const cardOptions = (card as any)?.getLayoutOptions?.() as
| LovelaceLayoutOptions
| undefined;
const options = {
...cardOptions,
...configOptions,
} as LovelaceLayoutOptions;
return html`
<div
class="card"
style=${styleMap({
"--column-size": size?.[0],
"--row-size": size?.[1],
"--column-size": options.grid_columns,
"--row-size": options.grid_rows,
})}
class="card ${classMap({
"fit-rows": typeof options?.grid_rows === "number",
})}"
>
${editMode
? html`
@ -171,16 +183,18 @@ export class GridSection extends LitElement implements LovelaceSectionElement {
haStyle,
css`
:host {
--grid-gap: 8px;
--grid-row-height: 66px;
display: flex;
flex-direction: column;
gap: 8px;
gap: var(--grid-gap);
}
.container {
--column-count: 4;
display: grid;
grid-template-columns: repeat(var(--column-count), minmax(0, 1fr));
grid-auto-rows: minmax(66px, auto);
gap: 8px;
grid-auto-rows: minmax(var(--grid-row-height), auto);
gap: var(--grid-gap);
padding: 0;
margin: 0 auto;
}
@ -189,7 +203,7 @@ export class GridSection extends LitElement implements LovelaceSectionElement {
padding: 8px;
border-radius: var(--ha-card-border-radius, 12px);
border: 2px dashed var(--divider-color);
min-height: 66px;
min-height: var(var(--grid-row-height));
}
.title {
@ -216,6 +230,14 @@ export class GridSection extends LitElement implements LovelaceSectionElement {
grid-column: span var(--column-size, 4);
}
.card.fit-rows {
height: calc(
(var(--row-size, 1) * (var(--grid-row-height) + var(--grid-gap))) - var(
--grid-gap
)
);
}
.card:has(> *) {
display: block;
}
@ -232,7 +254,7 @@ export class GridSection extends LitElement implements LovelaceSectionElement {
cursor: pointer;
border-radius: var(--ha-card-border-radius, 12px);
border: 2px dashed var(--primary-color);
height: 66px;
height: var(--grid-row-height);
order: 1;
}
.add:focus {

View File

@ -39,12 +39,17 @@ export interface LovelaceBadge extends HTMLElement {
setConfig(config: LovelaceBadgeConfig): void;
}
export type LovelaceLayoutOptions = {
grid_columns?: number;
grid_rows?: number;
};
export interface LovelaceCard extends HTMLElement {
hass?: HomeAssistant;
isPanel?: boolean;
editMode?: boolean;
getCardSize(): number | Promise<number>;
getGridSize?(): [number, number];
getLayoutOptions?(): LovelaceLayoutOptions;
setConfig(config: LovelaceCardConfig): void;
}

View File

@ -234,11 +234,15 @@ export class SectionsView extends LitElement implements LovelaceViewElement {
static get styles(): CSSResultGroup {
return css`
:host {
--grid-gap: 32px;
--grid-max-section-count: 4;
--grid-section-min-width: 320px;
--grid-section-max-width: 500px;
display: block;
}
.badges {
margin: 12px 8px 16px 8px;
margin: 12px 8px 4px 8px;
font-size: 85%;
text-align: center;
}
@ -246,18 +250,13 @@ export class SectionsView extends LitElement implements LovelaceViewElement {
.section {
position: relative;
border-radius: var(--ha-card-border-radius, 12px);
max-width: var(--grid-section-max-width);
width: 100%;
}
.container {
/* Inputs */
--grid-gap: 32px;
--grid-max-section-count: 4;
--grid-section-min-width: 320px;
--grid-section-max-width: 500px;
/* Calculated */
--max-count: min(var(--section-count), var(--grid-max-section-count));
--grid-max-width: min(
--max-width: min(
calc(
(var(--max-count) + 1) * var(--grid-section-min-width) +
(var(--max-count) + 2) * var(--grid-gap) - 1px
@ -267,8 +266,9 @@ export class SectionsView extends LitElement implements LovelaceViewElement {
(var(--max-count) + 1) * var(--grid-gap)
)
);
display: grid;
align-items: start;
justify-items: center;
grid-template-columns: repeat(
auto-fit,
minmax(min(var(--grid-section-min-width), 100%), 1fr)
@ -276,7 +276,7 @@ export class SectionsView extends LitElement implements LovelaceViewElement {
grid-gap: 8px var(--grid-gap);
padding: 8px var(--grid-gap);
box-sizing: border-box;
max-width: var(--grid-max-width);
max-width: var(--max-width);
margin: 0 auto;
}