mirror of
https://github.com/home-assistant/frontend.git
synced 2025-07-17 14:26:35 +00:00
Add tile card to gallery (#15394)
This commit is contained in:
parent
6c2a767896
commit
7e92d62936
3
gallery/src/pages/lovelace/tile-card.markdown
Normal file
3
gallery/src/pages/lovelace/tile-card.markdown
Normal file
@ -0,0 +1,3 @@
|
||||
---
|
||||
title: Tile Card
|
||||
---
|
173
gallery/src/pages/lovelace/tile-card.ts
Normal file
173
gallery/src/pages/lovelace/tile-card.ts
Normal file
@ -0,0 +1,173 @@
|
||||
import { html, LitElement, PropertyValues, TemplateResult } from "lit";
|
||||
import { customElement, query } from "lit/decorators";
|
||||
import { CoverEntityFeature } from "../../../../src/data/cover";
|
||||
import { LightColorMode } from "../../../../src/data/light";
|
||||
import { VacuumEntityFeature } from "../../../../src/data/vacuum";
|
||||
import { getEntity } from "../../../../src/fake_data/entity";
|
||||
import { provideHass } from "../../../../src/fake_data/provide_hass";
|
||||
import "../../components/demo-cards";
|
||||
|
||||
const ENTITIES = [
|
||||
getEntity("switch", "tv_outlet", "on", {
|
||||
friendly_name: "TV outlet",
|
||||
device_class: "outlet",
|
||||
}),
|
||||
getEntity("light", "bed_light", "on", {
|
||||
friendly_name: "Bed Light",
|
||||
supported_color_modes: [LightColorMode.HS],
|
||||
}),
|
||||
getEntity("light", "unavailable", "unavailable", {
|
||||
friendly_name: "Unavailable entity",
|
||||
}),
|
||||
getEntity("climate", "thermostat", "heat", {
|
||||
current_temperature: 73,
|
||||
min_temp: 45,
|
||||
max_temp: 95,
|
||||
temperature: 80,
|
||||
hvac_modes: ["heat", "cool", "auto", "off"],
|
||||
friendly_name: "Thermostat",
|
||||
hvac_action: "heating",
|
||||
}),
|
||||
getEntity("person", "paulus", "home", {
|
||||
friendly_name: "Paulus",
|
||||
}),
|
||||
getEntity("vacuum", "first_floor_vacuum", "docked", {
|
||||
friendly_name: "First floor vacuum",
|
||||
supported_features:
|
||||
VacuumEntityFeature.START +
|
||||
VacuumEntityFeature.STOP +
|
||||
VacuumEntityFeature.RETURN_HOME,
|
||||
}),
|
||||
getEntity("cover", "kitchen_shutter", "open", {
|
||||
friendly_name: "Kitchen shutter",
|
||||
device_class: "shutter",
|
||||
supported_features:
|
||||
CoverEntityFeature.CLOSE +
|
||||
CoverEntityFeature.OPEN +
|
||||
CoverEntityFeature.STOP,
|
||||
}),
|
||||
getEntity("cover", "pergola_roof", "open", {
|
||||
friendly_name: "Pergola Roof",
|
||||
supported_features:
|
||||
CoverEntityFeature.CLOSE_TILT +
|
||||
CoverEntityFeature.OPEN_TILT +
|
||||
CoverEntityFeature.STOP_TILT,
|
||||
}),
|
||||
];
|
||||
|
||||
const CONFIGS = [
|
||||
{
|
||||
heading: "Basic example",
|
||||
config: `
|
||||
- type: tile
|
||||
entity: switch.tv_outlet
|
||||
`,
|
||||
},
|
||||
{
|
||||
heading: "Vertical example",
|
||||
config: `
|
||||
- type: tile
|
||||
entity: switch.tv_outlet
|
||||
vertical: true
|
||||
`,
|
||||
},
|
||||
{
|
||||
heading: "Custom color",
|
||||
config: `
|
||||
- type: tile
|
||||
entity: switch.tv_outlet
|
||||
color: pink
|
||||
`,
|
||||
},
|
||||
{
|
||||
heading: "Unknown entity",
|
||||
config: `
|
||||
- type: tile
|
||||
entity: light.unknown
|
||||
`,
|
||||
},
|
||||
{
|
||||
heading: "Unavailable entity",
|
||||
config: `
|
||||
- type: tile
|
||||
entity: light.unavailable
|
||||
`,
|
||||
},
|
||||
{
|
||||
heading: "Climate",
|
||||
config: `
|
||||
- type: tile
|
||||
entity: climate.thermostat
|
||||
`,
|
||||
},
|
||||
{
|
||||
heading: "Person",
|
||||
config: `
|
||||
- type: tile
|
||||
entity: person.paulus
|
||||
`,
|
||||
},
|
||||
{
|
||||
heading: "Light brightness feature",
|
||||
config: `
|
||||
- type: tile
|
||||
entity: light.bed_light
|
||||
features:
|
||||
- type: "light-brightness"
|
||||
`,
|
||||
},
|
||||
{
|
||||
heading: "Vacuum commands feature",
|
||||
config: `
|
||||
- type: tile
|
||||
entity: vacuum.first_floor_vacuum
|
||||
features:
|
||||
- type: "vacuum-commands"
|
||||
commands:
|
||||
- start_pause
|
||||
- stop
|
||||
- return_home
|
||||
`,
|
||||
},
|
||||
{
|
||||
heading: "Cover open close feature",
|
||||
config: `
|
||||
- type: tile
|
||||
entity: cover.kitchen_shutter
|
||||
features:
|
||||
- type: "cover-open-close"
|
||||
`,
|
||||
},
|
||||
{
|
||||
heading: "Cover tilt feature",
|
||||
config: `
|
||||
- type: tile
|
||||
entity: cover.pergola_roof
|
||||
features:
|
||||
- type: "cover-tilt"
|
||||
`,
|
||||
},
|
||||
];
|
||||
|
||||
@customElement("demo-lovelace-tile-card")
|
||||
class DemoTile extends LitElement {
|
||||
@query("#demos") private _demoRoot!: HTMLElement;
|
||||
|
||||
protected render(): TemplateResult {
|
||||
return html`<demo-cards id="demos" .configs=${CONFIGS}></demo-cards>`;
|
||||
}
|
||||
|
||||
protected firstUpdated(changedProperties: PropertyValues) {
|
||||
super.firstUpdated(changedProperties);
|
||||
const hass = provideHass(this._demoRoot);
|
||||
hass.updateTranslations(null, "en");
|
||||
hass.updateTranslations("lovelace", "en");
|
||||
hass.addEntities(ENTITIES);
|
||||
}
|
||||
}
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
"demo-lovelace-tile-card": DemoTile;
|
||||
}
|
||||
}
|
@ -25,6 +25,8 @@ export class HaTileInfo extends LitElement {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
justify-content: center;
|
||||
min-height: 40px;
|
||||
}
|
||||
span {
|
||||
text-overflow: ellipsis;
|
||||
|
@ -16,7 +16,6 @@ import memoizeOne from "memoize-one";
|
||||
import { computeCssColor } from "../../../common/color/compute-color";
|
||||
import { hsv2rgb, rgb2hex, rgb2hsv } from "../../../common/color/convert-color";
|
||||
import { DOMAINS_TOGGLE } from "../../../common/const";
|
||||
import { stopPropagation } from "../../../common/dom/stop_propagation";
|
||||
import { computeDomain } from "../../../common/entity/compute_domain";
|
||||
import { computeStateDisplay } from "../../../common/entity/compute_state_display";
|
||||
import { stateActive } from "../../../common/entity/state_active";
|
||||
@ -263,27 +262,29 @@ export class HuiTileCard extends LitElement implements LovelaceCard {
|
||||
const entityId = this._config.entity;
|
||||
const stateObj = entityId ? this.hass.states[entityId] : undefined;
|
||||
|
||||
const tileClasses = { vertical: Boolean(this._config.vertical) };
|
||||
const contentClasses = { vertical: Boolean(this._config.vertical) };
|
||||
|
||||
if (!stateObj) {
|
||||
return html`
|
||||
<ha-card class="disabled">
|
||||
<div class="tile ${classMap(tileClasses)}">
|
||||
<div class="icon-container">
|
||||
<ha-tile-icon class="icon" .iconPath=${mdiHelp}></ha-tile-icon>
|
||||
<ha-tile-badge
|
||||
class="badge"
|
||||
.iconPath=${mdiExclamationThick}
|
||||
style=${styleMap({
|
||||
"--tile-badge-background-color": `var(--red-color)`,
|
||||
})}
|
||||
></ha-tile-badge>
|
||||
<ha-card>
|
||||
<div class="tile">
|
||||
<div class="content ${classMap(contentClasses)}">
|
||||
<div class="icon-container">
|
||||
<ha-tile-icon class="icon" .iconPath=${mdiHelp}></ha-tile-icon>
|
||||
<ha-tile-badge
|
||||
class="badge"
|
||||
.iconPath=${mdiExclamationThick}
|
||||
style=${styleMap({
|
||||
"--tile-badge-background-color": `var(--red-color)`,
|
||||
})}
|
||||
></ha-tile-badge>
|
||||
</div>
|
||||
<ha-tile-info
|
||||
class="info"
|
||||
.primary=${entityId}
|
||||
secondary=${this.hass.localize("ui.card.tile.not_found")}
|
||||
></ha-tile-info>
|
||||
</div>
|
||||
<ha-tile-info
|
||||
class="info"
|
||||
.primary=${entityId}
|
||||
secondary=${this.hass.localize("ui.card.tile.not_found")}
|
||||
></ha-tile-info>
|
||||
</div>
|
||||
</ha-card>
|
||||
`;
|
||||
@ -315,66 +316,62 @@ export class HuiTileCard extends LitElement implements LovelaceCard {
|
||||
return html`
|
||||
<ha-card style=${styleMap(style)} class=${classMap({ active })}>
|
||||
${this._shouldRenderRipple ? html`<mwc-ripple></mwc-ripple>` : null}
|
||||
<div
|
||||
class="tile ${classMap(tileClasses)}"
|
||||
@action=${this._handleAction}
|
||||
.actionHandler=${actionHandler()}
|
||||
role="button"
|
||||
tabindex="0"
|
||||
@mousedown=${this.handleRippleActivate}
|
||||
@mouseup=${this.handleRippleDeactivate}
|
||||
@mouseenter=${this.handleRippleMouseEnter}
|
||||
@mouseleave=${this.handleRippleMouseLeave}
|
||||
@touchstart=${this.handleRippleActivate}
|
||||
@touchend=${this.handleRippleDeactivate}
|
||||
@touchcancel=${this.handleRippleDeactivate}
|
||||
>
|
||||
<div class="tile">
|
||||
<div
|
||||
class="icon-container"
|
||||
class="background"
|
||||
@action=${this._handleAction}
|
||||
.actionHandler=${actionHandler()}
|
||||
role="button"
|
||||
tabindex="0"
|
||||
@action=${this._handleIconAction}
|
||||
.actionHandler=${actionHandler()}
|
||||
@mousedown=${stopPropagation}
|
||||
@mouseup=${stopPropagation}
|
||||
@mouseenter=${stopPropagation}
|
||||
@mouseleave=${stopPropagation}
|
||||
@touchstart=${stopPropagation}
|
||||
@touchend=${stopPropagation}
|
||||
@touchcancel=${stopPropagation}
|
||||
>
|
||||
${imageUrl
|
||||
? html`
|
||||
<ha-tile-image
|
||||
class="icon"
|
||||
.imageUrl=${imageUrl}
|
||||
></ha-tile-image>
|
||||
`
|
||||
: html`
|
||||
<ha-tile-icon
|
||||
class="icon"
|
||||
.icon=${icon}
|
||||
.iconPath=${iconPath}
|
||||
></ha-tile-icon>
|
||||
`}
|
||||
${badge
|
||||
? html`
|
||||
<ha-tile-badge
|
||||
class="badge"
|
||||
.icon=${badge.icon}
|
||||
.iconPath=${badge.iconPath}
|
||||
style=${styleMap({
|
||||
"--tile-badge-background-color": badge.color,
|
||||
})}
|
||||
></ha-tile-badge>
|
||||
`
|
||||
: null}
|
||||
@mousedown=${this.handleRippleActivate}
|
||||
@mouseup=${this.handleRippleDeactivate}
|
||||
@mouseenter=${this.handleRippleMouseEnter}
|
||||
@mouseleave=${this.handleRippleMouseLeave}
|
||||
@touchstart=${this.handleRippleActivate}
|
||||
@touchend=${this.handleRippleDeactivate}
|
||||
@touchcancel=${this.handleRippleDeactivate}
|
||||
></div>
|
||||
<div class="content ${classMap(contentClasses)}">
|
||||
<div
|
||||
class="icon-container"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
@action=${this._handleIconAction}
|
||||
.actionHandler=${actionHandler()}
|
||||
>
|
||||
${imageUrl
|
||||
? html`
|
||||
<ha-tile-image
|
||||
class="icon"
|
||||
.imageUrl=${imageUrl}
|
||||
></ha-tile-image>
|
||||
`
|
||||
: html`
|
||||
<ha-tile-icon
|
||||
class="icon"
|
||||
.icon=${icon}
|
||||
.iconPath=${iconPath}
|
||||
></ha-tile-icon>
|
||||
`}
|
||||
${badge
|
||||
? html`
|
||||
<ha-tile-badge
|
||||
class="badge"
|
||||
.icon=${badge.icon}
|
||||
.iconPath=${badge.iconPath}
|
||||
style=${styleMap({
|
||||
"--tile-badge-background-color": badge.color,
|
||||
})}
|
||||
></ha-tile-badge>
|
||||
`
|
||||
: null}
|
||||
</div>
|
||||
<ha-tile-info
|
||||
class="info"
|
||||
.primary=${name}
|
||||
.secondary=${stateDisplay}
|
||||
></ha-tile-info>
|
||||
</div>
|
||||
<ha-tile-info
|
||||
class="info"
|
||||
.primary=${name}
|
||||
.secondary=${stateDisplay}
|
||||
></ha-tile-info>
|
||||
</div>
|
||||
${supportedFeatures?.length
|
||||
? html`
|
||||
@ -424,16 +421,15 @@ export class HuiTileCard extends LitElement implements LovelaceCard {
|
||||
--tile-color: var(--state-inactive-color);
|
||||
-webkit-tap-highlight-color: transparent;
|
||||
}
|
||||
ha-card:has(.tile:focus-visible) {
|
||||
ha-card:has(.background:focus-visible) {
|
||||
border-color: var(--tile-color);
|
||||
box-shadow: 0 0 0 1px var(--tile-color);
|
||||
}
|
||||
ha-card {
|
||||
--mdc-ripple-color: var(--tile-color);
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
// For safari overflow hidden
|
||||
z-index: 0;
|
||||
overflow: hidden;
|
||||
}
|
||||
ha-card.active {
|
||||
--tile-color: var(--state-icon-color);
|
||||
@ -444,7 +440,14 @@ export class HuiTileCard extends LitElement implements LovelaceCard {
|
||||
[role="button"]:focus {
|
||||
outline: none;
|
||||
}
|
||||
.tile {
|
||||
.background {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
}
|
||||
.content {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
@ -473,6 +476,10 @@ export class HuiTileCard extends LitElement implements LovelaceCard {
|
||||
}
|
||||
.icon-container .icon {
|
||||
--tile-icon-color: var(--tile-color);
|
||||
user-select: none;
|
||||
-ms-user-select: none;
|
||||
-webkit-user-select: none;
|
||||
-moz-user-select: none;
|
||||
}
|
||||
.icon-container .badge {
|
||||
position: absolute;
|
||||
@ -488,9 +495,9 @@ export class HuiTileCard extends LitElement implements LovelaceCard {
|
||||
padding: 12px;
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
min-height: 40px;
|
||||
transition: background-color 180ms ease-in-out;
|
||||
box-sizing: border-box;
|
||||
pointer-events: none;
|
||||
}
|
||||
`;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user