mirror of
https://github.com/home-assistant/frontend.git
synced 2025-07-31 21:17:47 +00:00
First commit
This commit is contained in:
parent
c238c7dbbc
commit
326d912b84
200
src/panels/lovelace/cards/hui-person-card.ts
Normal file
200
src/panels/lovelace/cards/hui-person-card.ts
Normal file
@ -0,0 +1,200 @@
|
|||||||
|
import { mdiBattery70 } from "@mdi/js";
|
||||||
|
import {
|
||||||
|
css,
|
||||||
|
CSSResultGroup,
|
||||||
|
html,
|
||||||
|
LitElement,
|
||||||
|
PropertyValues,
|
||||||
|
TemplateResult,
|
||||||
|
} from "lit";
|
||||||
|
import { customElement, property, state } from "lit/decorators";
|
||||||
|
import { applyThemesOnElement } from "../../../common/dom/apply_themes_on_element";
|
||||||
|
import { computeStateDisplay } from "../../../common/entity/compute_state_display";
|
||||||
|
import { computeStateName } from "../../../common/entity/compute_state_name";
|
||||||
|
import "../../../components/ha-card";
|
||||||
|
import "../../../components/ha-svg-icon";
|
||||||
|
import { computeUserInitials } from "../../../data/user";
|
||||||
|
import { HomeAssistant } from "../../../types";
|
||||||
|
// eslint-disable-next-line import/no-duplicates
|
||||||
|
import "../components/hui-warning";
|
||||||
|
// eslint-disable-next-line import/no-duplicates
|
||||||
|
import { createEntityNotFoundWarning } from "../components/hui-warning";
|
||||||
|
import { LovelaceCard, LovelaceCardEditor } from "../types";
|
||||||
|
import { PersonCardConfig } from "./types";
|
||||||
|
|
||||||
|
@customElement("hui-person-card")
|
||||||
|
export class HuiPersonCard extends LitElement implements LovelaceCard {
|
||||||
|
public static async getConfigElement(): Promise<LovelaceCardEditor> {
|
||||||
|
await import("../editor/config-elements/hui-person-card-editor");
|
||||||
|
return document.createElement("hui-person-card-editor");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static getStubConfig(): PersonCardConfig {
|
||||||
|
return {
|
||||||
|
type: "person",
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
@property({ attribute: false }) public hass?: HomeAssistant;
|
||||||
|
|
||||||
|
@state() protected _config?: PersonCardConfig;
|
||||||
|
|
||||||
|
public getCardSize(): number {
|
||||||
|
return 5;
|
||||||
|
}
|
||||||
|
|
||||||
|
public setConfig(config: PersonCardConfig): void {
|
||||||
|
if (!config || !config.entity) {
|
||||||
|
throw new Error("Entity required");
|
||||||
|
}
|
||||||
|
|
||||||
|
this._config = config;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected shouldUpdate(changedProps: PropertyValues): boolean {
|
||||||
|
if (changedProps.size === 1 && changedProps.has("hass")) {
|
||||||
|
return !changedProps.get("hass");
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected updated(changedProps: PropertyValues): void {
|
||||||
|
super.updated(changedProps);
|
||||||
|
if (!this._config || !this.hass) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const oldHass = changedProps.get("hass") as HomeAssistant | undefined;
|
||||||
|
const oldConfig = changedProps.get("_config") as
|
||||||
|
| PersonCardConfig
|
||||||
|
| undefined;
|
||||||
|
|
||||||
|
if (
|
||||||
|
!oldHass ||
|
||||||
|
!oldConfig ||
|
||||||
|
oldHass.themes !== this.hass.themes ||
|
||||||
|
oldConfig.theme !== this._config.theme
|
||||||
|
) {
|
||||||
|
applyThemesOnElement(this, this.hass.themes, this._config.theme);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected render(): TemplateResult {
|
||||||
|
if (!this._config || !this.hass) {
|
||||||
|
return html``;
|
||||||
|
}
|
||||||
|
|
||||||
|
const stateObj = this.hass.states[this._config.entity!];
|
||||||
|
|
||||||
|
if (!stateObj) {
|
||||||
|
return html`
|
||||||
|
<hui-warning>
|
||||||
|
${createEntityNotFoundWarning(this.hass, this._config.entity!)}
|
||||||
|
</hui-warning>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
let backgroundColor: string | undefined;
|
||||||
|
let foregroundColor = "";
|
||||||
|
let image = stateObj.attributes.entity_picture;
|
||||||
|
let batteryPercent: number | undefined;
|
||||||
|
|
||||||
|
if (stateObj.attributes.source) {
|
||||||
|
batteryPercent =
|
||||||
|
this.hass.states[stateObj.attributes.source].attributes.battery;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!image) {
|
||||||
|
if (backgroundColor === undefined) {
|
||||||
|
const computedStyle = getComputedStyle(document.body);
|
||||||
|
backgroundColor = encodeURIComponent(
|
||||||
|
computedStyle.getPropertyValue("--light-primary-color").trim()
|
||||||
|
);
|
||||||
|
foregroundColor = encodeURIComponent(
|
||||||
|
(
|
||||||
|
computedStyle.getPropertyValue("--text-light-primary-color") ||
|
||||||
|
computedStyle.getPropertyValue("--primary-text-color")
|
||||||
|
).trim()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
const initials = computeUserInitials(
|
||||||
|
stateObj.attributes.friendly_name || ""
|
||||||
|
);
|
||||||
|
image = `data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 50 50' width='50' height='50' style='background-color:${backgroundColor}'%3E%3Cg%3E%3Ctext font-family='roboto' x='50%25' y='50%25' text-anchor='middle' stroke='${foregroundColor}' font-size='1.3em' dy='.3em'%3E${initials}%3C/text%3E%3C/g%3E%3C/svg%3E`;
|
||||||
|
}
|
||||||
|
|
||||||
|
return html`
|
||||||
|
<ha-card>
|
||||||
|
<hui-image .hass=${this.hass} .image=${image}></hui-image>
|
||||||
|
<div class="name">${computeStateName(stateObj)}</div>
|
||||||
|
<div class="state">
|
||||||
|
${computeStateDisplay(
|
||||||
|
this.hass!.localize,
|
||||||
|
stateObj,
|
||||||
|
this.hass.locale
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
<div class="battery">
|
||||||
|
<ha-svg-icon .path=${mdiBattery70}></ha-svg-icon> ${batteryPercent} %
|
||||||
|
</div>
|
||||||
|
</ha-card>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
static get styles(): CSSResultGroup {
|
||||||
|
return css`
|
||||||
|
ha-card {
|
||||||
|
overflow: hidden;
|
||||||
|
height: 100%;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
padding: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
ha-card.clickable {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
hui-image {
|
||||||
|
display: block;
|
||||||
|
width: 100%;
|
||||||
|
max-width: 250px;
|
||||||
|
border-radius: 50%;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.name {
|
||||||
|
font-size: 24px;
|
||||||
|
padding-top: 16px;
|
||||||
|
font-weight: 500;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.state {
|
||||||
|
color: var(--disabled-text-color);
|
||||||
|
padding-top: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.battery {
|
||||||
|
border: 1px solid var(--divider-color);
|
||||||
|
border-radius: 4px;
|
||||||
|
padding: 4px;
|
||||||
|
font-size: 16px;
|
||||||
|
background-color: var(
|
||||||
|
--ha-card-background,
|
||||||
|
var(--card-background-color, white)
|
||||||
|
);
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
declare global {
|
||||||
|
interface HTMLElementTagNameMap {
|
||||||
|
"hui-person-card": HuiPersonCard;
|
||||||
|
}
|
||||||
|
}
|
@ -288,6 +288,10 @@ export interface PictureCardConfig extends LovelaceCardConfig {
|
|||||||
double_tap_action?: ActionConfig;
|
double_tap_action?: ActionConfig;
|
||||||
theme?: string;
|
theme?: string;
|
||||||
}
|
}
|
||||||
|
export interface PersonCardConfig extends LovelaceCardConfig {
|
||||||
|
entity?: string;
|
||||||
|
theme?: string;
|
||||||
|
}
|
||||||
|
|
||||||
export interface PictureElementsCardConfig extends LovelaceCardConfig {
|
export interface PictureElementsCardConfig extends LovelaceCardConfig {
|
||||||
title?: string;
|
title?: string;
|
||||||
|
@ -59,6 +59,7 @@ const LAZY_LOAD_TYPES = {
|
|||||||
"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"),
|
||||||
"media-control": () => import("../cards/hui-media-control-card"),
|
"media-control": () => import("../cards/hui-media-control-card"),
|
||||||
|
person: () => import("../cards/hui-person-card"),
|
||||||
"picture-elements": () => import("../cards/hui-picture-elements-card"),
|
"picture-elements": () => import("../cards/hui-picture-elements-card"),
|
||||||
"picture-entity": () => import("../cards/hui-picture-entity-card"),
|
"picture-entity": () => import("../cards/hui-picture-entity-card"),
|
||||||
"picture-glance": () => import("../cards/hui-picture-glance-card"),
|
"picture-glance": () => import("../cards/hui-picture-glance-card"),
|
||||||
|
@ -0,0 +1,110 @@
|
|||||||
|
import "@polymer/paper-input/paper-input";
|
||||||
|
import { CSSResultGroup, html, LitElement, TemplateResult } from "lit";
|
||||||
|
import { customElement, property, state } from "lit/decorators";
|
||||||
|
import { assert, assign, object, optional, string } from "superstruct";
|
||||||
|
import { fireEvent } from "../../../../common/dom/fire_event";
|
||||||
|
import "../../../../components/ha-icon-picker";
|
||||||
|
import { HomeAssistant } from "../../../../types";
|
||||||
|
import { PersonCardConfig } from "../../cards/types";
|
||||||
|
import "../../components/hui-action-editor";
|
||||||
|
import "../../components/hui-entity-editor";
|
||||||
|
import "../../components/hui-theme-select-editor";
|
||||||
|
import { LovelaceCardEditor } from "../../types";
|
||||||
|
import { baseLovelaceCardConfig } from "../structs/base-card-struct";
|
||||||
|
import { EditorTarget } from "../types";
|
||||||
|
import { configElementStyle } from "./config-elements-style";
|
||||||
|
|
||||||
|
const cardConfigStruct = assign(
|
||||||
|
baseLovelaceCardConfig,
|
||||||
|
object({
|
||||||
|
entity: optional(string()),
|
||||||
|
theme: optional(string()),
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
@customElement("hui-person-card-editor")
|
||||||
|
export class HuiPersonCardEditor
|
||||||
|
extends LitElement
|
||||||
|
implements LovelaceCardEditor
|
||||||
|
{
|
||||||
|
@property({ attribute: false }) public hass?: HomeAssistant;
|
||||||
|
|
||||||
|
@state() private _config?: PersonCardConfig;
|
||||||
|
|
||||||
|
public setConfig(config: PersonCardConfig): void {
|
||||||
|
assert(config, cardConfigStruct);
|
||||||
|
this._config = config;
|
||||||
|
}
|
||||||
|
|
||||||
|
get _theme(): string {
|
||||||
|
return this._config!.theme || "";
|
||||||
|
}
|
||||||
|
|
||||||
|
get _entity(): string {
|
||||||
|
return this._config!.entity || "";
|
||||||
|
}
|
||||||
|
|
||||||
|
protected render(): TemplateResult {
|
||||||
|
if (!this.hass || !this._config) {
|
||||||
|
return html``;
|
||||||
|
}
|
||||||
|
|
||||||
|
return html`
|
||||||
|
<div class="card-config">
|
||||||
|
<ha-entity-picker
|
||||||
|
.label="${this.hass.localize(
|
||||||
|
"ui.panel.lovelace.editor.card.generic.entity"
|
||||||
|
)} (${this.hass.localize(
|
||||||
|
"ui.panel.lovelace.editor.card.config.required"
|
||||||
|
)})"
|
||||||
|
.hass=${this.hass}
|
||||||
|
.value=${this._entity}
|
||||||
|
.configValue=${"entity"}
|
||||||
|
@value-changed=${this._valueChanged}
|
||||||
|
allow-custom-entity
|
||||||
|
></ha-entity-picker>
|
||||||
|
|
||||||
|
<hui-theme-select-editor
|
||||||
|
.hass=${this.hass}
|
||||||
|
.value=${this._theme}
|
||||||
|
.configValue=${"theme"}
|
||||||
|
@value-changed=${this._valueChanged}
|
||||||
|
></hui-theme-select-editor>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
private _valueChanged(ev: CustomEvent): void {
|
||||||
|
if (!this._config || !this.hass) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const target = ev.target! as EditorTarget;
|
||||||
|
const value = ev.detail.value;
|
||||||
|
|
||||||
|
if (this[`_${target.configValue}`] === value) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (target.configValue) {
|
||||||
|
if (value !== false && !value) {
|
||||||
|
this._config = { ...this._config };
|
||||||
|
delete this._config[target.configValue!];
|
||||||
|
} else {
|
||||||
|
this._config = {
|
||||||
|
...this._config,
|
||||||
|
[target.configValue!]: value,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fireEvent(this, "config-changed", { config: this._config });
|
||||||
|
}
|
||||||
|
|
||||||
|
static get styles(): CSSResultGroup {
|
||||||
|
return configElementStyle;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
declare global {
|
||||||
|
interface HTMLElementTagNameMap {
|
||||||
|
"hui-person-card-editor": HuiPersonCardEditor;
|
||||||
|
}
|
||||||
|
}
|
@ -57,6 +57,10 @@ export const coreCards: Card[] = [
|
|||||||
type: "media-control",
|
type: "media-control",
|
||||||
showElement: true,
|
showElement: true,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
type: "person",
|
||||||
|
showElement: true,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
type: "picture",
|
type: "picture",
|
||||||
showElement: true,
|
showElement: true,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user