mirror of
https://github.com/home-assistant/frontend.git
synced 2025-07-30 20:56:36 +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;
|
||||
theme?: string;
|
||||
}
|
||||
export interface PersonCardConfig extends LovelaceCardConfig {
|
||||
entity?: string;
|
||||
theme?: string;
|
||||
}
|
||||
|
||||
export interface PictureElementsCardConfig extends LovelaceCardConfig {
|
||||
title?: string;
|
||||
|
@ -59,6 +59,7 @@ const LAZY_LOAD_TYPES = {
|
||||
"entity-filter": () => import("../cards/hui-entity-filter-card"),
|
||||
humidifier: () => import("../cards/hui-humidifier-card"),
|
||||
"media-control": () => import("../cards/hui-media-control-card"),
|
||||
person: () => import("../cards/hui-person-card"),
|
||||
"picture-elements": () => import("../cards/hui-picture-elements-card"),
|
||||
"picture-entity": () => import("../cards/hui-picture-entity-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",
|
||||
showElement: true,
|
||||
},
|
||||
{
|
||||
type: "person",
|
||||
showElement: true,
|
||||
},
|
||||
{
|
||||
type: "picture",
|
||||
showElement: true,
|
||||
|
Loading…
x
Reference in New Issue
Block a user