mirror of
https://github.com/home-assistant/frontend.git
synced 2025-07-16 05:46:35 +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: [
|
||||
{ type: "custom:ha-demo-card" },
|
||||
{
|
||||
type: "grid",
|
||||
columns: 4,
|
||||
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",
|
||||
type: "picture-entity",
|
||||
show_name: false,
|
||||
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: "sensor.presence_isa",
|
||||
entity: "switch.stefan_radiator_3",
|
||||
},
|
||||
{
|
||||
image: "/assets/teachingbirds/Stefan_square.jpg",
|
||||
type: "picture-entity",
|
||||
show_name: false,
|
||||
tap_action: {
|
||||
action: "more-info",
|
||||
style: {
|
||||
top: "90%",
|
||||
left: "50%",
|
||||
},
|
||||
entity: "sensor.presence_stefan",
|
||||
},
|
||||
{
|
||||
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",
|
||||
type: "state-label",
|
||||
entity: "sensor.temperature_stefan",
|
||||
},
|
||||
],
|
||||
type: "horizontal-stack",
|
||||
type: "picture-elements",
|
||||
},
|
||||
{
|
||||
cards: [
|
||||
image: "/assets/teachingbirds/background_square.png",
|
||||
elements: [
|
||||
{
|
||||
graph: "line",
|
||||
type: "sensor",
|
||||
entity: "sensor.temperature_passage",
|
||||
},
|
||||
{
|
||||
graph: "line",
|
||||
type: "sensor",
|
||||
name: "Laundry",
|
||||
entity: "sensor.temperature_downstairs_bathroom",
|
||||
style: {
|
||||
"--mdc-icon-size": "100%",
|
||||
top: "50%",
|
||||
left: "50%",
|
||||
},
|
||||
type: "icon",
|
||||
tap_action: {
|
||||
action: "navigate",
|
||||
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 { 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> {
|
||||
await import(
|
||||
/* 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[];
|
||||
|
||||
@internalProperty() private _config?: StackCardConfig;
|
||||
@internalProperty() protected _config?: T;
|
||||
|
||||
public getCardSize(): number | Promise<number> {
|
||||
return 1;
|
||||
}
|
||||
|
||||
public setConfig(config: StackCardConfig): void {
|
||||
public setConfig(config: T): void {
|
||||
if (!config || !config.cards || !Array.isArray(config.cards)) {
|
||||
throw new Error("Card config incorrect");
|
||||
}
|
||||
|
@ -288,6 +288,11 @@ export interface StackCardConfig extends LovelaceCardConfig {
|
||||
title?: string;
|
||||
}
|
||||
|
||||
export interface GridCardConfig extends StackCardConfig {
|
||||
columns?: number;
|
||||
square?: boolean;
|
||||
}
|
||||
|
||||
export interface ThermostatCardConfig extends LovelaceCardConfig {
|
||||
entity: string;
|
||||
theme?: string;
|
||||
|
@ -37,6 +37,7 @@ const LAZY_LOAD_TYPES = {
|
||||
"alarm-panel": () => import("../cards/hui-alarm-panel-card"),
|
||||
error: () => import("../cards/hui-error-card"),
|
||||
"empty-state": () => import("../cards/hui-empty-state-card"),
|
||||
grid: () => import("../cards/hui-grid-card"),
|
||||
starting: () => import("../cards/hui-starting-card"),
|
||||
"entity-filter": () => import("../cards/hui-entity-filter-card"),
|
||||
humidifier: () => import("../cards/hui-humidifier-card"),
|
||||
|
@ -29,6 +29,10 @@ export const coreCards: Card[] = [
|
||||
type: "glance",
|
||||
showElement: true,
|
||||
},
|
||||
{
|
||||
type: "grid",
|
||||
showElement: true,
|
||||
},
|
||||
{
|
||||
type: "history-graph",
|
||||
showElement: true,
|
||||
|
Loading…
x
Reference in New Issue
Block a user