mirror of
https://github.com/home-assistant/frontend.git
synced 2025-07-18 23:06:40 +00:00
Add Grid card (#7476)
This commit is contained in:
parent
d63493a859
commit
c3718ff7dd
@ -7,205 +7,183 @@ export const demoLovelaceTeachingbirds: DemoConfig["lovelace"] = () => ({
|
|||||||
cards: [
|
cards: [
|
||||||
{ type: "custom:ha-demo-card" },
|
{ type: "custom:ha-demo-card" },
|
||||||
{
|
{
|
||||||
|
type: "grid",
|
||||||
|
columns: 4,
|
||||||
cards: [
|
cards: [
|
||||||
{
|
{
|
||||||
cards: [
|
image: "/assets/teachingbirds/isa_square.jpg",
|
||||||
|
type: "picture-entity",
|
||||||
|
show_name: false,
|
||||||
|
tap_action: {
|
||||||
|
action: "more-info",
|
||||||
|
},
|
||||||
|
entity: "sensor.presence_isa",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
image: "/assets/teachingbirds/Stefan_square.jpg",
|
||||||
|
type: "picture-entity",
|
||||||
|
show_name: false,
|
||||||
|
tap_action: {
|
||||||
|
action: "more-info",
|
||||||
|
},
|
||||||
|
entity: "sensor.presence_stefan",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
image: "/assets/teachingbirds/background_square.png",
|
||||||
|
elements: [
|
||||||
{
|
{
|
||||||
image: "/assets/teachingbirds/isa_square.jpg",
|
state_image: {
|
||||||
type: "picture-entity",
|
on: "/assets/teachingbirds/radiator_on.jpg",
|
||||||
show_name: false,
|
off: "/assets/teachingbirds/radiator_off.jpg",
|
||||||
|
},
|
||||||
|
type: "image",
|
||||||
|
style: {
|
||||||
|
width: "100%",
|
||||||
|
top: "50%",
|
||||||
|
left: "50%",
|
||||||
|
},
|
||||||
tap_action: {
|
tap_action: {
|
||||||
action: "more-info",
|
action: "more-info",
|
||||||
},
|
},
|
||||||
entity: "sensor.presence_isa",
|
entity: "switch.stefan_radiator_3",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
image: "/assets/teachingbirds/Stefan_square.jpg",
|
style: {
|
||||||
type: "picture-entity",
|
top: "90%",
|
||||||
show_name: false,
|
left: "50%",
|
||||||
tap_action: {
|
|
||||||
action: "more-info",
|
|
||||||
},
|
},
|
||||||
entity: "sensor.presence_stefan",
|
type: "state-label",
|
||||||
},
|
|
||||||
{
|
|
||||||
image: "/assets/teachingbirds/background_square.png",
|
|
||||||
elements: [
|
|
||||||
{
|
|
||||||
state_image: {
|
|
||||||
on: "/assets/teachingbirds/radiator_on.jpg",
|
|
||||||
off: "/assets/teachingbirds/radiator_off.jpg",
|
|
||||||
},
|
|
||||||
type: "image",
|
|
||||||
style: {
|
|
||||||
width: "100%",
|
|
||||||
top: "50%",
|
|
||||||
left: "50%",
|
|
||||||
},
|
|
||||||
tap_action: {
|
|
||||||
action: "more-info",
|
|
||||||
},
|
|
||||||
entity: "switch.stefan_radiator_3",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
style: {
|
|
||||||
top: "90%",
|
|
||||||
left: "50%",
|
|
||||||
},
|
|
||||||
type: "state-label",
|
|
||||||
entity: "sensor.temperature_stefan",
|
|
||||||
},
|
|
||||||
],
|
|
||||||
type: "picture-elements",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
image: "/assets/teachingbirds/background_square.png",
|
|
||||||
elements: [
|
|
||||||
{
|
|
||||||
style: {
|
|
||||||
"--mdc-icon-size": "100%",
|
|
||||||
top: "50%",
|
|
||||||
left: "50%",
|
|
||||||
},
|
|
||||||
type: "icon",
|
|
||||||
tap_action: {
|
|
||||||
action: "navigate",
|
|
||||||
navigation_path: "/lovelace/home_info",
|
|
||||||
},
|
|
||||||
icon: "mdi:car",
|
|
||||||
},
|
|
||||||
],
|
|
||||||
type: "picture-elements",
|
|
||||||
},
|
|
||||||
],
|
|
||||||
type: "horizontal-stack",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
cards: [
|
|
||||||
{
|
|
||||||
show_name: false,
|
|
||||||
type: "picture-entity",
|
|
||||||
name: "Alarm",
|
|
||||||
image: "/assets/teachingbirds/House_square.jpg",
|
|
||||||
entity: "alarm_control_panel.house",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "Roomba",
|
|
||||||
image: "/assets/teachingbirds/roomba_square.jpg",
|
|
||||||
show_name: false,
|
|
||||||
type: "picture-entity",
|
|
||||||
state_image: {
|
|
||||||
"Not Today": "/assets/teachingbirds/roomba_bw_square.jpg",
|
|
||||||
},
|
|
||||||
entity: "input_select.roomba_mode",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
show_name: false,
|
|
||||||
type: "picture-entity",
|
|
||||||
state_image: {
|
|
||||||
Mail: "/assets/teachingbirds/mailbox_square.jpg",
|
|
||||||
"Package and mail":
|
|
||||||
"/assets/teachingbirds/mailbox_square.jpg",
|
|
||||||
Empty: "/assets/teachingbirds/mailbox_bw_square.jpg",
|
|
||||||
Package: "/assets/teachingbirds/mailbox_square.jpg",
|
|
||||||
},
|
|
||||||
entity: "sensor.mailbox",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
show_name: false,
|
|
||||||
state_image: {
|
|
||||||
"Put out": "/assets/teachingbirds/trash_square.jpg",
|
|
||||||
"Take in": "/assets/teachingbirds/trash_square.jpg",
|
|
||||||
},
|
|
||||||
type: "picture-entity",
|
|
||||||
image: "/assets/teachingbirds/trash_bear_bw_square.jpg",
|
|
||||||
entity: "sensor.trash_status",
|
|
||||||
},
|
|
||||||
],
|
|
||||||
type: "horizontal-stack",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
cards: [
|
|
||||||
{
|
|
||||||
state_image: {
|
|
||||||
Idle: "/assets/teachingbirds/washer_square.jpg",
|
|
||||||
Running: "/assets/teachingbirds/laundry_running_square.jpg",
|
|
||||||
Clean: "/assets/teachingbirds/laundry_clean_2_square.jpg",
|
|
||||||
},
|
|
||||||
entity: "input_select.washing_machine_status",
|
|
||||||
type: "picture-entity",
|
|
||||||
show_name: false,
|
|
||||||
name: "Washer",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
state_image: {
|
|
||||||
Idle: "/assets/teachingbirds/dryer_square.jpg",
|
|
||||||
Running: "/assets/teachingbirds/clothes_drying_square.jpg",
|
|
||||||
Clean: "/assets/teachingbirds/folded_clothes_square.jpg",
|
|
||||||
},
|
|
||||||
entity: "input_select.dryer_status",
|
|
||||||
type: "picture-entity",
|
|
||||||
show_name: false,
|
|
||||||
name: "Dryer",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
image: "/assets/teachingbirds/guests_square.jpg",
|
|
||||||
type: "picture-entity",
|
|
||||||
show_name: false,
|
|
||||||
tap_action: {
|
|
||||||
action: "toggle",
|
|
||||||
},
|
|
||||||
entity: "input_boolean.guest_mode",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
image: "/assets/teachingbirds/cleaning_square.jpg",
|
|
||||||
type: "picture-entity",
|
|
||||||
show_name: false,
|
|
||||||
tap_action: {
|
|
||||||
action: "toggle",
|
|
||||||
},
|
|
||||||
entity: "input_boolean.cleaning_day",
|
|
||||||
},
|
|
||||||
],
|
|
||||||
type: "horizontal-stack",
|
|
||||||
},
|
|
||||||
],
|
|
||||||
type: "vertical-stack",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
type: "vertical-stack",
|
|
||||||
cards: [
|
|
||||||
{
|
|
||||||
cards: [
|
|
||||||
{
|
|
||||||
graph: "line",
|
|
||||||
type: "sensor",
|
|
||||||
entity: "sensor.temperature_bedroom",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
graph: "line",
|
|
||||||
type: "sensor",
|
|
||||||
name: "S's room",
|
|
||||||
entity: "sensor.temperature_stefan",
|
entity: "sensor.temperature_stefan",
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
type: "horizontal-stack",
|
type: "picture-elements",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
cards: [
|
image: "/assets/teachingbirds/background_square.png",
|
||||||
|
elements: [
|
||||||
{
|
{
|
||||||
graph: "line",
|
style: {
|
||||||
type: "sensor",
|
"--mdc-icon-size": "100%",
|
||||||
entity: "sensor.temperature_passage",
|
top: "50%",
|
||||||
},
|
left: "50%",
|
||||||
{
|
},
|
||||||
graph: "line",
|
type: "icon",
|
||||||
type: "sensor",
|
tap_action: {
|
||||||
name: "Laundry",
|
action: "navigate",
|
||||||
entity: "sensor.temperature_downstairs_bathroom",
|
navigation_path: "/lovelace/home_info",
|
||||||
|
},
|
||||||
|
icon: "mdi:car",
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
type: "horizontal-stack",
|
type: "picture-elements",
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
show_name: false,
|
||||||
|
type: "picture-entity",
|
||||||
|
name: "Alarm",
|
||||||
|
image: "/assets/teachingbirds/House_square.jpg",
|
||||||
|
entity: "alarm_control_panel.house",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Roomba",
|
||||||
|
image: "/assets/teachingbirds/roomba_square.jpg",
|
||||||
|
show_name: false,
|
||||||
|
type: "picture-entity",
|
||||||
|
state_image: {
|
||||||
|
"Not Today": "/assets/teachingbirds/roomba_bw_square.jpg",
|
||||||
|
},
|
||||||
|
entity: "input_select.roomba_mode",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
show_name: false,
|
||||||
|
type: "picture-entity",
|
||||||
|
state_image: {
|
||||||
|
Mail: "/assets/teachingbirds/mailbox_square.jpg",
|
||||||
|
"Package and mail": "/assets/teachingbirds/mailbox_square.jpg",
|
||||||
|
Empty: "/assets/teachingbirds/mailbox_bw_square.jpg",
|
||||||
|
Package: "/assets/teachingbirds/mailbox_square.jpg",
|
||||||
|
},
|
||||||
|
entity: "sensor.mailbox",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
show_name: false,
|
||||||
|
state_image: {
|
||||||
|
"Put out": "/assets/teachingbirds/trash_square.jpg",
|
||||||
|
"Take in": "/assets/teachingbirds/trash_square.jpg",
|
||||||
|
},
|
||||||
|
type: "picture-entity",
|
||||||
|
image: "/assets/teachingbirds/trash_bear_bw_square.jpg",
|
||||||
|
entity: "sensor.trash_status",
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
state_image: {
|
||||||
|
Idle: "/assets/teachingbirds/washer_square.jpg",
|
||||||
|
Running: "/assets/teachingbirds/laundry_running_square.jpg",
|
||||||
|
Clean: "/assets/teachingbirds/laundry_clean_2_square.jpg",
|
||||||
|
},
|
||||||
|
entity: "input_select.washing_machine_status",
|
||||||
|
type: "picture-entity",
|
||||||
|
show_name: false,
|
||||||
|
name: "Washer",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
state_image: {
|
||||||
|
Idle: "/assets/teachingbirds/dryer_square.jpg",
|
||||||
|
Running: "/assets/teachingbirds/clothes_drying_square.jpg",
|
||||||
|
Clean: "/assets/teachingbirds/folded_clothes_square.jpg",
|
||||||
|
},
|
||||||
|
entity: "input_select.dryer_status",
|
||||||
|
type: "picture-entity",
|
||||||
|
show_name: false,
|
||||||
|
name: "Dryer",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
image: "/assets/teachingbirds/guests_square.jpg",
|
||||||
|
type: "picture-entity",
|
||||||
|
show_name: false,
|
||||||
|
tap_action: {
|
||||||
|
action: "toggle",
|
||||||
|
},
|
||||||
|
entity: "input_boolean.guest_mode",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
image: "/assets/teachingbirds/cleaning_square.jpg",
|
||||||
|
type: "picture-entity",
|
||||||
|
show_name: false,
|
||||||
|
tap_action: {
|
||||||
|
action: "toggle",
|
||||||
|
},
|
||||||
|
entity: "input_boolean.cleaning_day",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: "grid",
|
||||||
|
columns: 2,
|
||||||
|
cards: [
|
||||||
|
{
|
||||||
|
graph: "line",
|
||||||
|
type: "sensor",
|
||||||
|
entity: "sensor.temperature_bedroom",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
graph: "line",
|
||||||
|
type: "sensor",
|
||||||
|
name: "S's room",
|
||||||
|
entity: "sensor.temperature_stefan",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
graph: "line",
|
||||||
|
type: "sensor",
|
||||||
|
entity: "sensor.temperature_passage",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
graph: "line",
|
||||||
|
type: "sensor",
|
||||||
|
name: "Laundry",
|
||||||
|
entity: "sensor.temperature_downstairs_bathroom",
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
75
src/panels/lovelace/cards/hui-grid-card.ts
Normal file
75
src/panels/lovelace/cards/hui-grid-card.ts
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
import { css, CSSResult } from "lit-element";
|
||||||
|
import { computeCardSize } from "../common/compute-card-size";
|
||||||
|
import { HuiStackCard } from "./hui-stack-card";
|
||||||
|
import { GridCardConfig } from "./types";
|
||||||
|
|
||||||
|
const DEFAULT_COLUMNS = 3;
|
||||||
|
|
||||||
|
class HuiGridCard extends HuiStackCard<GridCardConfig> {
|
||||||
|
public async getCardSize(): Promise<number> {
|
||||||
|
if (!this._cards || !this._config) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
const promises: Array<Promise<number> | number> = [];
|
||||||
|
|
||||||
|
for (const element of this._cards) {
|
||||||
|
promises.push(computeCardSize(element));
|
||||||
|
}
|
||||||
|
|
||||||
|
const results = await Promise.all(promises);
|
||||||
|
|
||||||
|
const maxCardSize = Math.max(...results);
|
||||||
|
|
||||||
|
return maxCardSize * (this._cards.length / this.columns);
|
||||||
|
}
|
||||||
|
|
||||||
|
get columns() {
|
||||||
|
return this._config!.columns || DEFAULT_COLUMNS;
|
||||||
|
}
|
||||||
|
|
||||||
|
setConfig(config: GridCardConfig) {
|
||||||
|
super.setConfig(config);
|
||||||
|
this.style.setProperty("--grid-card-column-count", String(this.columns));
|
||||||
|
this.toggleAttribute("square", config.square !== false);
|
||||||
|
}
|
||||||
|
|
||||||
|
static get styles(): CSSResult[] {
|
||||||
|
return [
|
||||||
|
super.sharedStyles,
|
||||||
|
css`
|
||||||
|
#root {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(
|
||||||
|
var(--grid-card-column-count, ${DEFAULT_COLUMNS}),
|
||||||
|
minmax(0, 1fr)
|
||||||
|
);
|
||||||
|
grid-gap: var(--grid-card-gap, 8px);
|
||||||
|
}
|
||||||
|
:host([square]) #root {
|
||||||
|
grid-auto-rows: 1fr;
|
||||||
|
}
|
||||||
|
:host([square]) #root::before {
|
||||||
|
content: "";
|
||||||
|
width: 0;
|
||||||
|
padding-bottom: 100%;
|
||||||
|
grid-row: 1 / 1;
|
||||||
|
grid-column: 1 / 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
:host([square]) #root > *:first-child {
|
||||||
|
grid-row: 1 / 1;
|
||||||
|
grid-column: 1 / 1;
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
declare global {
|
||||||
|
interface HTMLElementTagNameMap {
|
||||||
|
"hui-grid-card": HuiGridCard;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
customElements.define("hui-grid-card", HuiGridCard);
|
@ -14,7 +14,9 @@ import { createCardElement } from "../create-element/create-card-element";
|
|||||||
import { LovelaceCard, LovelaceCardEditor } from "../types";
|
import { LovelaceCard, LovelaceCardEditor } from "../types";
|
||||||
import { StackCardConfig } from "./types";
|
import { StackCardConfig } from "./types";
|
||||||
|
|
||||||
export abstract class HuiStackCard extends LitElement implements LovelaceCard {
|
export abstract class HuiStackCard<T extends StackCardConfig = StackCardConfig>
|
||||||
|
extends LitElement
|
||||||
|
implements LovelaceCard {
|
||||||
public static async getConfigElement(): Promise<LovelaceCardEditor> {
|
public static async getConfigElement(): Promise<LovelaceCardEditor> {
|
||||||
await import(
|
await import(
|
||||||
/* webpackChunkName: "hui-stack-card-editor" */ "../editor/config-elements/hui-stack-card-editor"
|
/* webpackChunkName: "hui-stack-card-editor" */ "../editor/config-elements/hui-stack-card-editor"
|
||||||
@ -32,13 +34,13 @@ export abstract class HuiStackCard extends LitElement implements LovelaceCard {
|
|||||||
|
|
||||||
@property() protected _cards?: LovelaceCard[];
|
@property() protected _cards?: LovelaceCard[];
|
||||||
|
|
||||||
@internalProperty() private _config?: StackCardConfig;
|
@internalProperty() protected _config?: T;
|
||||||
|
|
||||||
public getCardSize(): number | Promise<number> {
|
public getCardSize(): number | Promise<number> {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
public setConfig(config: StackCardConfig): void {
|
public setConfig(config: T): void {
|
||||||
if (!config || !config.cards || !Array.isArray(config.cards)) {
|
if (!config || !config.cards || !Array.isArray(config.cards)) {
|
||||||
throw new Error("Card config incorrect");
|
throw new Error("Card config incorrect");
|
||||||
}
|
}
|
||||||
|
@ -288,6 +288,11 @@ export interface StackCardConfig extends LovelaceCardConfig {
|
|||||||
title?: string;
|
title?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface GridCardConfig extends StackCardConfig {
|
||||||
|
columns?: number;
|
||||||
|
square?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
export interface ThermostatCardConfig extends LovelaceCardConfig {
|
export interface ThermostatCardConfig extends LovelaceCardConfig {
|
||||||
entity: string;
|
entity: string;
|
||||||
theme?: string;
|
theme?: string;
|
||||||
|
@ -37,6 +37,7 @@ const LAZY_LOAD_TYPES = {
|
|||||||
"alarm-panel": () => import("../cards/hui-alarm-panel-card"),
|
"alarm-panel": () => import("../cards/hui-alarm-panel-card"),
|
||||||
error: () => import("../cards/hui-error-card"),
|
error: () => import("../cards/hui-error-card"),
|
||||||
"empty-state": () => import("../cards/hui-empty-state-card"),
|
"empty-state": () => import("../cards/hui-empty-state-card"),
|
||||||
|
grid: () => import("../cards/hui-grid-card"),
|
||||||
starting: () => import("../cards/hui-starting-card"),
|
starting: () => import("../cards/hui-starting-card"),
|
||||||
"entity-filter": () => import("../cards/hui-entity-filter-card"),
|
"entity-filter": () => import("../cards/hui-entity-filter-card"),
|
||||||
humidifier: () => import("../cards/hui-humidifier-card"),
|
humidifier: () => import("../cards/hui-humidifier-card"),
|
||||||
|
@ -29,6 +29,10 @@ export const coreCards: Card[] = [
|
|||||||
type: "glance",
|
type: "glance",
|
||||||
showElement: true,
|
showElement: true,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
type: "grid",
|
||||||
|
showElement: true,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
type: "history-graph",
|
type: "history-graph",
|
||||||
showElement: true,
|
showElement: true,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user