mirror of
https://github.com/home-assistant/frontend.git
synced 2025-07-08 18:06:36 +00:00
Love: Rework PictureEntityCard (#1359)
* Love: Rework picture-entity-card * Rework * Use OFFLINE const * Add optional title * Fix issue, lint
This commit is contained in:
parent
3442700e1f
commit
038f5b644b
@ -12,7 +12,7 @@ class HuiColumnCard extends PolymerElement {
|
||||
#root {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
margin-top: -4px
|
||||
margin-top: -4px;
|
||||
margin-bottom: -8px;
|
||||
}
|
||||
#root > * {
|
||||
|
@ -1,144 +0,0 @@
|
||||
import { html } from '@polymer/polymer/lib/utils/html-tag.js';
|
||||
import { PolymerElement } from '@polymer/polymer/polymer-element.js';
|
||||
|
||||
import '../../../components/ha-card.js';
|
||||
|
||||
import { STATES_ON } from '../../../common/const.js';
|
||||
import computeDomain from '../../../common/entity/compute_domain.js';
|
||||
import computeStateDisplay from '../../../common/entity/compute_state_display.js';
|
||||
import computeStateName from '../../../common/entity/compute_state_name.js';
|
||||
|
||||
import LocalizeMixin from '../../../mixins/localize-mixin.js';
|
||||
|
||||
const DOMAINS_NO_STATE = ['scene', 'script', 'weblink'];
|
||||
|
||||
/*
|
||||
* @appliesMixin LocalizeMixin
|
||||
*/
|
||||
class HuiPictureCard extends LocalizeMixin(PolymerElement) {
|
||||
static get template() {
|
||||
return html`
|
||||
<style>
|
||||
ha-card {
|
||||
position: relative;
|
||||
cursor: pointer;
|
||||
min-height: 48px;
|
||||
line-height: 0;
|
||||
}
|
||||
img {
|
||||
width: 100%;
|
||||
height: auto;
|
||||
border-radius: 2px;
|
||||
}
|
||||
img.state-off {
|
||||
filter: grayscale(100%);
|
||||
}
|
||||
.text {
|
||||
@apply --paper-font-common-nowrap;
|
||||
position: absolute;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background-color: rgba(0, 0, 0, 0.3);
|
||||
padding: 16px;
|
||||
font-size: 16px;
|
||||
line-height: 16px;
|
||||
color: white;
|
||||
border-bottom-left-radius: 2px;
|
||||
border-bottom-right-radius: 2px;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
.text .title {
|
||||
font-weight: 500;
|
||||
}
|
||||
.error {
|
||||
background-color: red;
|
||||
color: white;
|
||||
text-align: center;
|
||||
}
|
||||
</style>
|
||||
|
||||
<ha-card on-click="_cardClicked">
|
||||
<img class$="[[_computeClass(config.entity, hass.states)]]" src="[[config.image]]">
|
||||
<div class="text">
|
||||
<div class="title">[[_computeTitle(config.entity, hass.states)]]</div>
|
||||
<div>[[_computeState(config.entity, hass.states)]]</div>
|
||||
</div>
|
||||
<template is="dom-if" if="[[_error]]">
|
||||
<div class="error">[[_error]]</div>
|
||||
</template>
|
||||
</ha-card>
|
||||
`;
|
||||
}
|
||||
|
||||
static get properties() {
|
||||
return {
|
||||
hass: Object,
|
||||
config: {
|
||||
type: Object,
|
||||
observer: '_configChanged'
|
||||
},
|
||||
_error: String
|
||||
};
|
||||
}
|
||||
|
||||
getCardSize() {
|
||||
return 3;
|
||||
}
|
||||
|
||||
_configChanged(config) {
|
||||
if (config && config.entity && config.image) {
|
||||
this._error = null;
|
||||
} else {
|
||||
this._error = 'Error in card configuration.';
|
||||
}
|
||||
}
|
||||
|
||||
_computeClass(entityId, states) {
|
||||
return DOMAINS_NO_STATE.includes(computeDomain(entityId)) ||
|
||||
STATES_ON.includes(states[entityId].state) ? '' : 'state-off';
|
||||
}
|
||||
|
||||
_computeTitle(entityId, states) {
|
||||
return entityId && entityId in states && computeStateName(states[entityId]);
|
||||
}
|
||||
|
||||
_computeState(entityId, states) {
|
||||
const domain = computeDomain(entityId);
|
||||
switch (domain) {
|
||||
case 'scene':
|
||||
return this.localize('ui.card.scene.activate');
|
||||
case 'script':
|
||||
return this.localize('ui.card.script.execute');
|
||||
case 'weblink':
|
||||
return 'Open';
|
||||
default:
|
||||
return computeStateDisplay(this.localize, states[entityId]);
|
||||
}
|
||||
}
|
||||
|
||||
_cardClicked() {
|
||||
const entityId = this.config.entity;
|
||||
const domain = computeDomain(entityId);
|
||||
if (domain === 'weblink') {
|
||||
window.open(this.hass.states[entityId].state);
|
||||
} else {
|
||||
const turnOn = !STATES_ON.includes(this.hass.states[entityId].state);
|
||||
let service;
|
||||
switch (domain) {
|
||||
case 'lock':
|
||||
service = turnOn ? 'unlock' : 'lock';
|
||||
break;
|
||||
case 'cover':
|
||||
service = turnOn ? 'open_cover' : 'close_cover';
|
||||
break;
|
||||
default:
|
||||
service = turnOn ? 'turn_on' : 'turn_off';
|
||||
}
|
||||
this.hass.callService(domain, service, { entity_id: entityId });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define('hui-entity-picture-card', HuiPictureCard);
|
@ -2,6 +2,7 @@ import { html } from '@polymer/polymer/lib/utils/html-tag.js';
|
||||
import { PolymerElement } from '@polymer/polymer/polymer-element.js';
|
||||
|
||||
import './hui-error-card.js';
|
||||
import '../../../components/ha-card.js';
|
||||
import '../../../components/state-history-charts.js';
|
||||
import '../../../data/ha-state-history-data.js';
|
||||
|
||||
|
165
src/panels/lovelace/cards/hui-picture-entity-card.js
Normal file
165
src/panels/lovelace/cards/hui-picture-entity-card.js
Normal file
@ -0,0 +1,165 @@
|
||||
import { html } from '@polymer/polymer/lib/utils/html-tag.js';
|
||||
import { PolymerElement } from '@polymer/polymer/polymer-element.js';
|
||||
|
||||
import './hui-error-card.js';
|
||||
import '../../../components/ha-card.js';
|
||||
|
||||
import { STATES_OFF } from '../../../common/const.js';
|
||||
import computeDomain from '../../../common/entity/compute_domain.js';
|
||||
import computeStateDisplay from '../../../common/entity/compute_state_display.js';
|
||||
import computeStateDomain from '../../../common/entity/compute_state_domain.js';
|
||||
import computeStateName from '../../../common/entity/compute_state_name.js';
|
||||
import createErrorCardConfig from '../common/create-error-card-config.js';
|
||||
|
||||
import LocalizeMixin from '../../../mixins/localize-mixin.js';
|
||||
|
||||
const OFFLINE = 'Offline';
|
||||
|
||||
/*
|
||||
* @appliesMixin LocalizeMixin
|
||||
*/
|
||||
class HuiPictureEntityCard extends LocalizeMixin(PolymerElement) {
|
||||
static get template() {
|
||||
return html`
|
||||
<style>
|
||||
ha-card {
|
||||
position: relative;
|
||||
cursor: pointer;
|
||||
overflow: hidden;
|
||||
}
|
||||
img {
|
||||
display: block;
|
||||
width: 100%;
|
||||
height: auto;
|
||||
}
|
||||
.box {
|
||||
@apply --paper-font-common-nowrap;
|
||||
position: absolute;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background-color: rgba(0, 0, 0, 0.3);
|
||||
padding: 16px;
|
||||
font-size: 16px;
|
||||
line-height: 16px;
|
||||
color: white;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
#title {
|
||||
font-weight: 500;
|
||||
}
|
||||
</style>
|
||||
|
||||
<ha-card on-click="_cardClicked">
|
||||
<img id="image" src="">
|
||||
<div class="box">
|
||||
<div id="title"></div>
|
||||
<div id="state"></div>
|
||||
</div>
|
||||
<template is="dom-if" if="[[_error]]">
|
||||
<hui-error-card config="[[_error]]"></hui-error-card>
|
||||
</template>
|
||||
</ha-card>
|
||||
`;
|
||||
}
|
||||
|
||||
static get properties() {
|
||||
return {
|
||||
hass: {
|
||||
type: Object,
|
||||
observer: '_hassChanged'
|
||||
},
|
||||
config: {
|
||||
type: Object,
|
||||
observer: '_configChanged'
|
||||
},
|
||||
_error: Object
|
||||
};
|
||||
}
|
||||
|
||||
getCardSize() {
|
||||
return 3;
|
||||
}
|
||||
|
||||
_configChanged(config) {
|
||||
if (!config || !config.entity || (!config.image && !config.state_image)) {
|
||||
const error = 'Error in card configuration.';
|
||||
this._error = createErrorCardConfig(error, config);
|
||||
return;
|
||||
}
|
||||
this._error = null;
|
||||
}
|
||||
|
||||
_hassChanged(hass) {
|
||||
const config = this.config;
|
||||
const entityId = config && config.entity;
|
||||
if (!entityId) {
|
||||
return;
|
||||
}
|
||||
if (!(entityId in hass.states) && this._oldState === OFFLINE) {
|
||||
return;
|
||||
}
|
||||
if (!(entityId in hass.states) || hass.states[entityId].state !== this._oldState) {
|
||||
this._updateState(hass, entityId, config);
|
||||
}
|
||||
}
|
||||
|
||||
_updateState(hass, entityId, config) {
|
||||
const state = entityId in hass.states ? hass.states[entityId].state : OFFLINE;
|
||||
const stateImg = config.state_image &&
|
||||
(config.state_image[state] || config.state_image.default);
|
||||
|
||||
this.$.image.src = stateImg || config.image;
|
||||
this.$.image.style.filter = stateImg || (!STATES_OFF.includes(state) && state !== OFFLINE) ?
|
||||
'' : 'grayscale(100%)';
|
||||
this.$.title.innerText = config.title || (state === OFFLINE ?
|
||||
entityId : computeStateName(hass.states[entityId]));
|
||||
this.$.state.innerText = state === OFFLINE ?
|
||||
OFFLINE : this._computeState(hass.states[entityId]);
|
||||
this._oldState = state;
|
||||
}
|
||||
|
||||
_computeState(stateObj) {
|
||||
const domain = computeStateDomain(stateObj);
|
||||
switch (domain) {
|
||||
case 'scene':
|
||||
return this.localize('ui.card.scene.activate');
|
||||
case 'script':
|
||||
return this.localize('ui.card.script.execute');
|
||||
case 'weblink':
|
||||
return 'Open';
|
||||
default:
|
||||
return computeStateDisplay(this.localize, stateObj);
|
||||
}
|
||||
}
|
||||
|
||||
_cardClicked() {
|
||||
const entityId = this.config && this.config.entity;
|
||||
if (!(entityId in this.hass.states)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const stateDomain = computeDomain(entityId);
|
||||
if (stateDomain === 'weblink') {
|
||||
window.open(this.hass.states[entityId].state);
|
||||
} else {
|
||||
const turnOn = STATES_OFF.includes(this.hass.states[entityId].state);
|
||||
let service;
|
||||
switch (stateDomain) {
|
||||
case 'lock':
|
||||
service = turnOn ? 'unlock' : 'lock';
|
||||
break;
|
||||
case 'cover':
|
||||
service = turnOn ? 'open_cover' : 'close_cover';
|
||||
break;
|
||||
default:
|
||||
service = turnOn ? 'turn_on' : 'turn_off';
|
||||
}
|
||||
const serviceDomain = stateDomain === 'group' ? 'homeassistant' : stateDomain;
|
||||
this.hass.callService(serviceDomain, service, { entity_id: entityId });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define('hui-picture-entity-card', HuiPictureEntityCard);
|
@ -10,8 +10,8 @@ import '../cards/hui-history-graph-card.js';
|
||||
import '../cards/hui-iframe-card.js';
|
||||
import '../cards/hui-markdown-card.js';
|
||||
import '../cards/hui-media-control-card.js';
|
||||
import '../cards/hui-entity-picture-card.js';
|
||||
import '../cards/hui-picture-elements-card';
|
||||
import '../cards/hui-picture-entity-card';
|
||||
import '../cards/hui-picture-glance-card';
|
||||
import '../cards/hui-plant-status-card.js';
|
||||
import '../cards/hui-row-card.js';
|
||||
@ -24,7 +24,6 @@ const CARD_TYPES = [
|
||||
'column',
|
||||
'entities',
|
||||
'entity-filter',
|
||||
'entity-picture',
|
||||
'error',
|
||||
'glance',
|
||||
'history-graph',
|
||||
@ -32,6 +31,7 @@ const CARD_TYPES = [
|
||||
'markdown',
|
||||
'media-control',
|
||||
'picture-elements',
|
||||
'picture-entity',
|
||||
'picture-glance',
|
||||
'plant-status',
|
||||
'row',
|
||||
|
Loading…
x
Reference in New Issue
Block a user