mirror of
https://github.com/home-assistant/frontend.git
synced 2025-08-01 13:37:47 +00:00
commit
f0a4a99654
@ -1,23 +1,36 @@
|
||||
import { getEntity } from "../../../src/fake_data/entity";
|
||||
|
||||
export const createMediaPlayerEntities = () => [
|
||||
getEntity("media_player", "bedroom", "playing", {
|
||||
media_content_type: "movie",
|
||||
media_title: "Epic sax guy 10 hours",
|
||||
app_name: "YouTube",
|
||||
friendly_name: "Skip, no pause",
|
||||
supported_features: 32,
|
||||
}),
|
||||
getEntity("media_player", "family_room", "paused", {
|
||||
friendly_name: "Paused, music",
|
||||
getEntity("media_player", "music_paused", "paused", {
|
||||
friendly_name: "Pausing The Music",
|
||||
media_content_type: "music",
|
||||
media_title: "I Wanna Be A Hippy (Flamman & Abraxas Radio Mix)",
|
||||
media_artist: "Technohead",
|
||||
supported_features: 16417,
|
||||
supported_features: 64063,
|
||||
entity_picture: "/images/album_cover.jpg",
|
||||
media_duration: 300,
|
||||
media_position: 50,
|
||||
media_position_updated_at: new Date(
|
||||
// 23 seconds in
|
||||
new Date().getTime() - 23000
|
||||
).toISOString(),
|
||||
}),
|
||||
getEntity("media_player", "family_room_no_play", "paused", {
|
||||
friendly_name: "Paused, no play",
|
||||
getEntity("media_player", "music_playing", "playing", {
|
||||
friendly_name: "Playing The Music",
|
||||
media_content_type: "music",
|
||||
media_title: "I Wanna Be A Hippy (Flamman & Abraxas Radio Mix)",
|
||||
media_artist: "Technohead",
|
||||
supported_features: 64063,
|
||||
entity_picture: "/images/album_cover.jpg",
|
||||
media_duration: 300,
|
||||
media_position: 0,
|
||||
media_position_updated_at: new Date(
|
||||
// 23 seconds in
|
||||
new Date().getTime() - 23000
|
||||
).toISOString(),
|
||||
}),
|
||||
getEntity("media_player", "stream_playing", "playing", {
|
||||
friendly_name: "Playing the Stream",
|
||||
media_content_type: "movie",
|
||||
media_title: "Epic sax guy 10 hours",
|
||||
app_name: "YouTube",
|
||||
@ -31,25 +44,19 @@ export const createMediaPlayerEntities = () => [
|
||||
app_name: "Netflix",
|
||||
supported_features: 1,
|
||||
}),
|
||||
getEntity("media_player", "lounge_room", "idle", {
|
||||
friendly_name: "Screen casting",
|
||||
media_content_type: "music",
|
||||
media_title: "I Wanna Be A Hippy (Flamman & Abraxas Radio Mix)",
|
||||
media_artist: "Technohead",
|
||||
supported_features: 1,
|
||||
getEntity("media_player", "sonos_idle", "idle", {
|
||||
friendly_name: "Sonos Idle",
|
||||
supported_features: 64063,
|
||||
}),
|
||||
getEntity("media_player", "theater", "off", {
|
||||
friendly_name: "Chromcast Idle",
|
||||
media_content_type: "movie",
|
||||
media_title: "Epic sax guy 10 hours",
|
||||
app_name: "YouTube",
|
||||
supported_features: 33,
|
||||
friendly_name: "TV Off",
|
||||
supported_features: 161,
|
||||
}),
|
||||
getEntity("media_player", "android_cast", "playing", {
|
||||
friendly_name: "Player Off",
|
||||
friendly_name: "Casting App",
|
||||
media_title: "Android Screen Casting",
|
||||
app_name: "Screen Mirroring",
|
||||
supported_features: 21437,
|
||||
// supported_features: 21437,
|
||||
}),
|
||||
getEntity("media_player", "unavailable", "unavailable", {
|
||||
friendly_name: "Player Unavailable",
|
||||
@ -59,4 +66,17 @@ export const createMediaPlayerEntities = () => [
|
||||
friendly_name: "Player Unknown",
|
||||
supported_features: 21437,
|
||||
}),
|
||||
getEntity("media_player", "receiver_on", "on", {
|
||||
source_list: ["AirPlay", "Blu-Ray", "TV", "USB", "iPod (USB)"],
|
||||
volume_level: 0.63,
|
||||
is_volume_muted: false,
|
||||
source: "TV",
|
||||
friendly_name: "Receiver",
|
||||
supported_features: 84364,
|
||||
}),
|
||||
getEntity("media_player", "receiver_off", "off", {
|
||||
source_list: ["AirPlay", "Blu-Ray", "TV", "USB", "iPod (USB)"],
|
||||
friendly_name: "Receiver",
|
||||
supported_features: 84364,
|
||||
}),
|
||||
];
|
||||
|
@ -7,24 +7,24 @@ import { createMediaPlayerEntities } from "../data/media_players";
|
||||
|
||||
const CONFIGS = [
|
||||
{
|
||||
heading: "Skip, no pause",
|
||||
heading: "Paused music",
|
||||
config: `
|
||||
- type: media-control
|
||||
entity: media_player.bedroom
|
||||
entity: media_player.music_paused
|
||||
`,
|
||||
},
|
||||
{
|
||||
heading: "Paused, music",
|
||||
heading: "Playing music",
|
||||
config: `
|
||||
- type: media-control
|
||||
entity: media_player.family_room
|
||||
entity: media_player.music_playing
|
||||
`,
|
||||
},
|
||||
{
|
||||
heading: "Paused, no play",
|
||||
heading: "Playing stream",
|
||||
config: `
|
||||
- type: media-control
|
||||
entity: media_player.family_room_no_play
|
||||
entity: media_player.stream_playing
|
||||
`,
|
||||
},
|
||||
{
|
||||
@ -42,10 +42,10 @@ const CONFIGS = [
|
||||
`,
|
||||
},
|
||||
{
|
||||
heading: "Chromcast Idle",
|
||||
heading: "Sonos Idle",
|
||||
config: `
|
||||
- type: media-control
|
||||
entity: media_player.lounge_room
|
||||
entity: media_player.sonos_idle
|
||||
`,
|
||||
},
|
||||
{
|
||||
@ -69,6 +69,20 @@ const CONFIGS = [
|
||||
entity: media_player.unknown
|
||||
`,
|
||||
},
|
||||
{
|
||||
heading: "Receiver On",
|
||||
config: `
|
||||
- type: media-control
|
||||
entity: media_player.receiver_on
|
||||
`,
|
||||
},
|
||||
{
|
||||
heading: "Receiver Off",
|
||||
config: `
|
||||
- type: media-control
|
||||
entity: media_player.receiver_off
|
||||
`,
|
||||
},
|
||||
];
|
||||
|
||||
class DemoHuiMediControlCard extends PolymerElement {
|
||||
|
@ -11,17 +11,17 @@ const CONFIGS = [
|
||||
config: `
|
||||
- type: entities
|
||||
entities:
|
||||
- entity: media_player.bedroom
|
||||
name: Skip, no pause
|
||||
- entity: media_player.family_room
|
||||
name: Paused, music
|
||||
- entity: media_player.family_room_no_play
|
||||
- entity: media_player.music_paused
|
||||
name: Paused music
|
||||
- entity: media_player.music_playing
|
||||
name: Playing music
|
||||
- entity: media_player.stream_playing
|
||||
name: Paused, no play
|
||||
- entity: media_player.living_room
|
||||
name: Pause, No skip, tvshow
|
||||
- entity: media_player.android_cast
|
||||
name: Screen casting
|
||||
- entity: media_player.lounge_room
|
||||
- entity: media_player.sonos_idle
|
||||
name: Chromcast Idle
|
||||
- entity: media_player.theater
|
||||
name: Player Off
|
||||
|
BIN
public/static/images/config_freebox.png
Normal file
BIN
public/static/images/config_freebox.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 29 KiB |
2
setup.py
2
setup.py
@ -2,7 +2,7 @@ from setuptools import setup, find_packages
|
||||
|
||||
setup(
|
||||
name="home-assistant-frontend",
|
||||
version="20200311.1",
|
||||
version="20200312.0",
|
||||
description="The Home Assistant frontend",
|
||||
url="https://github.com/home-assistant/home-assistant-polymer",
|
||||
author="The Home Assistant Authors",
|
||||
|
@ -83,9 +83,7 @@ export const domainIcon = (domain: string, state?: string): string => {
|
||||
return state && state === "unlocked" ? "hass:lock-open" : "hass:lock";
|
||||
|
||||
case "media_player":
|
||||
return state && state !== "off" && state !== "idle"
|
||||
? "hass:cast-connected"
|
||||
: "hass:cast";
|
||||
return state && state === "playing" ? "hass:cast-connected" : "hass:cast";
|
||||
|
||||
case "zwave":
|
||||
switch (state) {
|
||||
|
@ -11,6 +11,7 @@ export const iconColorCSS = css`
|
||||
ha-icon[data-domain="light"][data-state="on"],
|
||||
ha-icon[data-domain="input_boolean"][data-state="on"],
|
||||
ha-icon[data-domain="lock"][data-state="unlocked"],
|
||||
ha-icon[data-domain="media_player"][data-state="on"],
|
||||
ha-icon[data-domain="media_player"][data-state="paused"],
|
||||
ha-icon[data-domain="media_player"][data-state="playing"],
|
||||
ha-icon[data-domain="script"][data-state="running"],
|
||||
|
@ -534,6 +534,10 @@ export class HaDataTable extends LitElement {
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.mdc-data-table__cell.mdc-data-table__cell--icon {
|
||||
overflow: initial;
|
||||
}
|
||||
|
||||
.mdc-data-table__header-cell--checkbox,
|
||||
.mdc-data-table__cell--checkbox {
|
||||
/* @noflip */
|
||||
|
@ -90,6 +90,27 @@ class HaMap extends LitElement {
|
||||
}
|
||||
}
|
||||
|
||||
protected shouldUpdate(changedProps) {
|
||||
if (!changedProps.has("hass") || changedProps.size > 1) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const oldHass = changedProps.get("hass") as HomeAssistant | undefined;
|
||||
|
||||
if (!oldHass || !this.entities) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Check if any state has changed
|
||||
for (const entity of this.entities) {
|
||||
if (oldHass.states[entity] !== this.hass!.states[entity]) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
protected updated(changedProps: PropertyValues): void {
|
||||
if (changedProps.has("hass")) {
|
||||
this._drawEntities();
|
||||
|
@ -14,7 +14,6 @@ export const SUPPORT_SELECT_SOURCE = 2048;
|
||||
export const SUPPORT_STOP = 4096;
|
||||
export const SUPPORTS_PLAY = 16384;
|
||||
export const SUPPORT_SELECT_SOUND_MODE = 65536;
|
||||
export const OFF_STATES = ["off", "idle"];
|
||||
export const CONTRAST_RATIO = 3.5;
|
||||
|
||||
export interface MediaPlayerThumbnail {
|
||||
@ -56,9 +55,7 @@ export const computeMediaDescription = (stateObj: HassEntity): string => {
|
||||
}
|
||||
break;
|
||||
default:
|
||||
secondaryTitle = stateObj.attributes.app_name
|
||||
? stateObj.attributes.app_name
|
||||
: "";
|
||||
secondaryTitle = stateObj.attributes.app_name || "";
|
||||
}
|
||||
|
||||
return secondaryTitle;
|
||||
|
@ -15,12 +15,15 @@ import "../../../components/map/ha-map";
|
||||
import { HomeAssistant } from "../../../types";
|
||||
import { showZoneEditor } from "../../../data/zone";
|
||||
import { fireEvent } from "../../../common/dom/fire_event";
|
||||
import memoizeOne from "memoize-one";
|
||||
|
||||
@customElement("more-info-person")
|
||||
class MoreInfoPerson extends LitElement {
|
||||
@property() public hass!: HomeAssistant;
|
||||
@property() public stateObj?: HassEntity;
|
||||
|
||||
private _entityArray = memoizeOne((entityId: string) => [entityId]);
|
||||
|
||||
protected render(): TemplateResult {
|
||||
if (!this.hass || !this.stateObj) {
|
||||
return html``;
|
||||
@ -35,7 +38,7 @@ class MoreInfoPerson extends LitElement {
|
||||
? html`
|
||||
<ha-map
|
||||
.hass=${this.hass}
|
||||
.entities=${[this.stateObj.entity_id]}
|
||||
.entities=${this._entityArray(this.stateObj.entity_id)}
|
||||
></ha-map>
|
||||
`
|
||||
: ""}
|
||||
|
@ -142,9 +142,6 @@ class DialogAreaDetail extends LitElement {
|
||||
return [
|
||||
haStyleDialog,
|
||||
css`
|
||||
ha-paper-dialog {
|
||||
min-width: 400px;
|
||||
}
|
||||
.form {
|
||||
padding-bottom: 24px;
|
||||
}
|
||||
|
@ -250,6 +250,7 @@ export class DialogEntityEditor extends LitElement {
|
||||
|
||||
ha-paper-dialog {
|
||||
width: 450px;
|
||||
max-height: none !important;
|
||||
}
|
||||
|
||||
/* overrule the ha-style-dialog max-height on small screens */
|
||||
|
@ -241,18 +241,11 @@ export class EntityRegistrySettings extends LitElement {
|
||||
}
|
||||
mwc-button.warning {
|
||||
margin-right: auto;
|
||||
--mdc-theme-primary: var(--google-red-500);
|
||||
}
|
||||
.error {
|
||||
color: var(--google-red-500);
|
||||
}
|
||||
.row {
|
||||
margin-top: 8px;
|
||||
color: var(--primary-text-color);
|
||||
}
|
||||
.secondary {
|
||||
color: var(--secondary-text-color);
|
||||
}
|
||||
`,
|
||||
];
|
||||
}
|
||||
|
@ -6,6 +6,7 @@ import {
|
||||
LitElement,
|
||||
property,
|
||||
TemplateResult,
|
||||
query,
|
||||
} from "lit-element";
|
||||
import "../../../components/ha-dialog";
|
||||
import { HomeAssistant } from "../../../types";
|
||||
@ -44,6 +45,7 @@ export class DialogHelperDetail extends LitElement {
|
||||
@property() private _platform?: string;
|
||||
@property() private _error?: string;
|
||||
@property() private _submitting = false;
|
||||
@query(".form") private _form?: HTMLDivElement;
|
||||
|
||||
public async showDialog(): Promise<void> {
|
||||
this._platform = undefined;
|
||||
@ -108,11 +110,13 @@ export class DialogHelperDetail extends LitElement {
|
||||
${Object.keys(HELPERS).map((platform: string) => {
|
||||
const isLoaded = isComponentLoaded(this.hass, platform);
|
||||
return html`
|
||||
<div>
|
||||
<div class="form">
|
||||
<paper-icon-item
|
||||
.disabled=${!isLoaded}
|
||||
@click=${this._platformPicked}
|
||||
@keydown=${this._handleEnter}
|
||||
.platform=${platform}
|
||||
dialogInitialFocus
|
||||
>
|
||||
<ha-icon
|
||||
slot="item-icon"
|
||||
@ -166,12 +170,29 @@ export class DialogHelperDetail extends LitElement {
|
||||
}
|
||||
}
|
||||
|
||||
private _handleEnter(ev: KeyboardEvent) {
|
||||
if (ev.keyCode !== 13) {
|
||||
return;
|
||||
}
|
||||
ev.stopPropagation();
|
||||
ev.preventDefault();
|
||||
this._platformPicked(ev);
|
||||
}
|
||||
|
||||
private _platformPicked(ev: Event): void {
|
||||
this._platform = (ev.currentTarget! as any).platform;
|
||||
this._focusForm();
|
||||
}
|
||||
|
||||
private async _focusForm(): Promise<void> {
|
||||
await this.updateComplete;
|
||||
(this._form?.lastElementChild as HTMLElement).focus();
|
||||
}
|
||||
|
||||
private _goBack() {
|
||||
this._platform = undefined;
|
||||
this._item = undefined;
|
||||
this._error = undefined;
|
||||
}
|
||||
|
||||
static get styles(): CSSResult[] {
|
||||
|
@ -36,6 +36,14 @@ class HaInputBooleanForm extends LitElement {
|
||||
}
|
||||
}
|
||||
|
||||
public focus() {
|
||||
this.updateComplete.then(() =>
|
||||
(this.shadowRoot?.querySelector(
|
||||
"[dialogInitialFocus]"
|
||||
) as HTMLElement)?.focus()
|
||||
);
|
||||
}
|
||||
|
||||
protected render(): TemplateResult {
|
||||
if (!this.hass) {
|
||||
return html``;
|
||||
@ -55,6 +63,7 @@ class HaInputBooleanForm extends LitElement {
|
||||
"ui.dialogs.helper_settings.required_error_msg"
|
||||
)}"
|
||||
.invalid=${nameInvalid}
|
||||
dialogInitialFocus
|
||||
></paper-input>
|
||||
<ha-icon-input
|
||||
.value=${this._icon}
|
||||
|
@ -44,6 +44,14 @@ class HaInputDateTimeForm extends LitElement {
|
||||
}
|
||||
}
|
||||
|
||||
public focus() {
|
||||
this.updateComplete.then(() =>
|
||||
(this.shadowRoot?.querySelector(
|
||||
"[dialogInitialFocus]"
|
||||
) as HTMLElement)?.focus()
|
||||
);
|
||||
}
|
||||
|
||||
protected render(): TemplateResult {
|
||||
if (!this.hass) {
|
||||
return html``;
|
||||
@ -63,6 +71,7 @@ class HaInputDateTimeForm extends LitElement {
|
||||
"ui.dialogs.helper_settings.required_error_msg"
|
||||
)}"
|
||||
.invalid=${nameInvalid}
|
||||
dialogInitialFocus
|
||||
></paper-input>
|
||||
<ha-icon-input
|
||||
.value=${this._icon}
|
||||
|
@ -55,6 +55,14 @@ class HaInputNumberForm extends LitElement {
|
||||
}
|
||||
}
|
||||
|
||||
public focus() {
|
||||
this.updateComplete.then(() =>
|
||||
(this.shadowRoot?.querySelector(
|
||||
"[dialogInitialFocus]"
|
||||
) as HTMLElement)?.focus()
|
||||
);
|
||||
}
|
||||
|
||||
protected render(): TemplateResult {
|
||||
if (!this.hass) {
|
||||
return html``;
|
||||
@ -74,6 +82,7 @@ class HaInputNumberForm extends LitElement {
|
||||
"ui.dialogs.helper_settings.required_error_msg"
|
||||
)}"
|
||||
.invalid=${nameInvalid}
|
||||
dialogInitialFocus
|
||||
></paper-input>
|
||||
<ha-icon-input
|
||||
.value=${this._icon}
|
||||
|
@ -44,6 +44,14 @@ class HaInputSelectForm extends LitElement {
|
||||
}
|
||||
}
|
||||
|
||||
public focus() {
|
||||
this.updateComplete.then(() =>
|
||||
(this.shadowRoot?.querySelector(
|
||||
"[dialogInitialFocus]"
|
||||
) as HTMLElement)?.focus()
|
||||
);
|
||||
}
|
||||
|
||||
protected render(): TemplateResult {
|
||||
if (!this.hass) {
|
||||
return html``;
|
||||
@ -63,6 +71,7 @@ class HaInputSelectForm extends LitElement {
|
||||
"ui.dialogs.helper_settings.required_error_msg"
|
||||
)}"
|
||||
.invalid=${nameInvalid}
|
||||
dialogInitialFocus
|
||||
></paper-input>
|
||||
<ha-icon-input
|
||||
.value=${this._icon}
|
||||
|
@ -47,6 +47,14 @@ class HaInputTextForm extends LitElement {
|
||||
}
|
||||
}
|
||||
|
||||
public focus() {
|
||||
this.updateComplete.then(() =>
|
||||
(this.shadowRoot?.querySelector(
|
||||
"[dialogInitialFocus]"
|
||||
) as HTMLElement)?.focus()
|
||||
);
|
||||
}
|
||||
|
||||
protected render(): TemplateResult {
|
||||
if (!this.hass) {
|
||||
return html``;
|
||||
@ -66,6 +74,7 @@ class HaInputTextForm extends LitElement {
|
||||
"ui.dialogs.helper_settings.required_error_msg"
|
||||
)}"
|
||||
.invalid=${nameInvalid}
|
||||
dialogInitialFocus
|
||||
></paper-input>
|
||||
<ha-icon-input
|
||||
.value=${this._icon}
|
||||
|
@ -29,6 +29,7 @@ import { configSections } from "../ha-panel-config";
|
||||
import { showEntityEditorDialog } from "../entities/show-dialog-entity-editor";
|
||||
import { showHelperDetailDialog } from "./show-dialog-helper-detail";
|
||||
import { HELPER_DOMAINS } from "./const";
|
||||
import { domainIcon } from "../../../common/entity/domain_icon";
|
||||
|
||||
@customElement("ha-config-helpers")
|
||||
export class HaConfigHelpers extends LitElement {
|
||||
@ -44,8 +45,8 @@ export class HaConfigHelpers extends LitElement {
|
||||
icon: {
|
||||
title: "",
|
||||
type: "icon",
|
||||
template: (icon) => html`
|
||||
<ha-icon slot="item-icon" .icon=${icon}></ha-icon>
|
||||
template: (icon, helper: any) => html`
|
||||
<ha-icon .icon=${icon || domainIcon(helper.type)}></ha-icon>
|
||||
`,
|
||||
},
|
||||
name: {
|
||||
@ -76,7 +77,7 @@ export class HaConfigHelpers extends LitElement {
|
||||
),
|
||||
sortable: true,
|
||||
filterable: true,
|
||||
width: "30%",
|
||||
width: "25%",
|
||||
};
|
||||
}
|
||||
columns.type = {
|
||||
@ -84,7 +85,7 @@ export class HaConfigHelpers extends LitElement {
|
||||
"ui.panel.config.helpers.picker.headers.type"
|
||||
),
|
||||
sortable: true,
|
||||
width: "30%",
|
||||
width: "25%",
|
||||
filterable: true,
|
||||
template: (type) =>
|
||||
html`
|
||||
@ -92,6 +93,27 @@ export class HaConfigHelpers extends LitElement {
|
||||
type}
|
||||
`,
|
||||
};
|
||||
columns.editable = {
|
||||
title: "",
|
||||
type: "icon",
|
||||
template: (editable) => html`
|
||||
${!editable
|
||||
? html`
|
||||
<div
|
||||
tabindex="0"
|
||||
style="display:inline-block; position: relative;"
|
||||
>
|
||||
<ha-icon icon="hass:pencil-off"></ha-icon>
|
||||
<paper-tooltip position="left">
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.entities.picker.status.readonly"
|
||||
)}
|
||||
</paper-tooltip>
|
||||
</div>
|
||||
`
|
||||
: ""}
|
||||
`,
|
||||
};
|
||||
return columns;
|
||||
}
|
||||
);
|
||||
|
@ -104,6 +104,7 @@ export class DialogLovelaceDashboardDetail extends LitElement {
|
||||
.errorMessage=${this.hass.localize(
|
||||
"ui.panel.config.lovelace.dashboards.detail.title_required"
|
||||
)}
|
||||
dialogInitialFocus
|
||||
></paper-input>
|
||||
<ha-icon-input
|
||||
.value=${this._icon}
|
||||
@ -293,9 +294,6 @@ export class DialogLovelaceDashboardDetail extends LitElement {
|
||||
return [
|
||||
haStyleDialog,
|
||||
css`
|
||||
.form {
|
||||
padding-bottom: 24px;
|
||||
}
|
||||
ha-switch {
|
||||
padding: 16px 0;
|
||||
}
|
||||
|
@ -72,7 +72,9 @@ export class HaConfigLovelaceDashboards extends LitElement {
|
||||
icon="hass:check-circle-outline"
|
||||
></ha-icon>
|
||||
<paper-tooltip>
|
||||
This is the default dashdoard.
|
||||
${this.hass.localize(
|
||||
`ui.panel.config.lovelace.dashboards.default_dashboard`
|
||||
)}
|
||||
</paper-tooltip>
|
||||
`
|
||||
: ""}
|
||||
|
@ -86,6 +86,7 @@ export class DialogLovelaceResourceDetail extends LitElement {
|
||||
"ui.panel.config.lovelace.resources.detail.url_error_msg"
|
||||
)}
|
||||
.invalid=${urlInvalid}
|
||||
dialogInitialFocus
|
||||
></paper-input>
|
||||
<br />
|
||||
<ha-paper-dropdown-menu
|
||||
@ -210,9 +211,6 @@ export class DialogLovelaceResourceDetail extends LitElement {
|
||||
return [
|
||||
haStyleDialog,
|
||||
css`
|
||||
.form {
|
||||
padding-bottom: 24px;
|
||||
}
|
||||
.warning {
|
||||
color: var(--error-color);
|
||||
}
|
||||
|
@ -272,10 +272,6 @@ class DialogZoneDetail extends LitElement {
|
||||
return [
|
||||
haStyleDialog,
|
||||
css`
|
||||
.form {
|
||||
padding-bottom: 24px;
|
||||
color: var(--primary-text-color);
|
||||
}
|
||||
.location {
|
||||
display: flex;
|
||||
}
|
||||
@ -298,9 +294,6 @@ class DialogZoneDetail extends LitElement {
|
||||
a {
|
||||
color: var(--primary-color);
|
||||
}
|
||||
p {
|
||||
color: var(--primary-text-color);
|
||||
}
|
||||
`,
|
||||
];
|
||||
}
|
||||
|
@ -33,7 +33,6 @@ import { findEntities } from "../common/find-entites";
|
||||
import { LovelaceConfig } from "../../../data/lovelace";
|
||||
import { UNAVAILABLE, UNKNOWN } from "../../../data/entity";
|
||||
import {
|
||||
OFF_STATES,
|
||||
SUPPORT_PAUSE,
|
||||
SUPPORT_TURN_ON,
|
||||
SUPPORT_PREVIOUS_TRACK,
|
||||
@ -44,11 +43,14 @@ import {
|
||||
CONTRAST_RATIO,
|
||||
getCurrentProgress,
|
||||
computeMediaDescription,
|
||||
SUPPORT_TURN_OFF,
|
||||
} from "../../../data/media-player";
|
||||
|
||||
import "../../../components/ha-card";
|
||||
import "../../../components/ha-icon";
|
||||
import "../components/hui-marquee";
|
||||
// tslint:disable-next-line: no-duplicate-imports
|
||||
import { PaperIconButtonElement } from "@polymer/paper-icon-button/paper-icon-button";
|
||||
|
||||
function getContrastRatio(
|
||||
rgb1: [number, number, number],
|
||||
@ -57,6 +59,11 @@ function getContrastRatio(
|
||||
return Math.round((contrast(rgb1, rgb2) + Number.EPSILON) * 100) / 100;
|
||||
}
|
||||
|
||||
interface ControlButton {
|
||||
icon: string;
|
||||
action: string;
|
||||
}
|
||||
|
||||
@customElement("hui-media-control-card")
|
||||
export class HuiMediaControlCard extends LitElement implements LovelaceCard {
|
||||
public static async getConfigElement(): Promise<LovelaceCardEditor> {
|
||||
@ -118,7 +125,7 @@ export class HuiMediaControlCard extends LitElement implements LovelaceCard {
|
||||
return;
|
||||
}
|
||||
|
||||
const stateObj = this.hass.states[this._config.entity] as MediaEntity;
|
||||
const stateObj = this._stateObj;
|
||||
|
||||
if (!stateObj) {
|
||||
return;
|
||||
@ -130,7 +137,7 @@ export class HuiMediaControlCard extends LitElement implements LovelaceCard {
|
||||
stateObj.state === "playing"
|
||||
) {
|
||||
this._progressInterval = window.setInterval(
|
||||
() => this._updateProgressBar(stateObj),
|
||||
() => this._updateProgressBar(),
|
||||
1000
|
||||
);
|
||||
}
|
||||
@ -147,7 +154,7 @@ export class HuiMediaControlCard extends LitElement implements LovelaceCard {
|
||||
if (!this.hass || !this._config) {
|
||||
return html``;
|
||||
}
|
||||
const stateObj = this.hass.states[this._config.entity] as MediaEntity;
|
||||
const stateObj = this._stateObj;
|
||||
|
||||
if (!stateObj) {
|
||||
return html`
|
||||
@ -162,22 +169,34 @@ export class HuiMediaControlCard extends LitElement implements LovelaceCard {
|
||||
}
|
||||
|
||||
const imageStyle = {
|
||||
"background-image": `url(${this.hass.hassUrl(this._image)})`,
|
||||
"background-image": this._image
|
||||
? `url(${this.hass.hassUrl(this._image)})`
|
||||
: "none",
|
||||
width: `${this._cardHeight}px`,
|
||||
"background-color": this._backgroundColor || "",
|
||||
};
|
||||
|
||||
const gradientStyle = {
|
||||
"background-image": `linear-gradient(to right, ${this._backgroundColor}, transparent)`,
|
||||
"background-image": `linear-gradient(to right, ${
|
||||
this._backgroundColor
|
||||
}, ${this._backgroundColor + "00"})`,
|
||||
width: `${this._cardHeight}px`,
|
||||
};
|
||||
|
||||
const isOffState = OFF_STATES.includes(stateObj.state);
|
||||
const state = stateObj.state;
|
||||
|
||||
const isOffState = state === "off";
|
||||
const isUnavailable =
|
||||
stateObj.state === UNAVAILABLE ||
|
||||
stateObj.state === UNKNOWN ||
|
||||
(stateObj.state === "off" && !supportsFeature(stateObj, SUPPORT_TURN_ON));
|
||||
state === UNAVAILABLE ||
|
||||
state === UNKNOWN ||
|
||||
(state === "off" && !supportsFeature(stateObj, SUPPORT_TURN_ON));
|
||||
const hasNoImage = !this._image;
|
||||
const controls = this._getControls();
|
||||
const showControls =
|
||||
controls &&
|
||||
(!this._veryNarrow || isOffState || state === "idle" || state === "on");
|
||||
|
||||
const mediaDescription = computeMediaDescription(stateObj);
|
||||
|
||||
return html`
|
||||
<ha-card>
|
||||
@ -215,7 +234,8 @@ export class HuiMediaControlCard extends LitElement implements LovelaceCard {
|
||||
"no-image": hasNoImage,
|
||||
narrow: this._narrow && !this._veryNarrow,
|
||||
off: isOffState || isUnavailable,
|
||||
"no-progress": !this._showProgressBar && !this._veryNarrow,
|
||||
"no-progress": this._veryNarrow || !this._showProgressBar,
|
||||
"no-controls": !showControls,
|
||||
})}"
|
||||
style=${styleMap({ color: this._foregroundColor || "" })}
|
||||
>
|
||||
@ -246,98 +266,35 @@ export class HuiMediaControlCard extends LitElement implements LovelaceCard {
|
||||
: `${this._cardHeight - 40}px`,
|
||||
})}
|
||||
>
|
||||
${isOffState
|
||||
${!mediaDescription && !stateObj.attributes.media_title
|
||||
? ""
|
||||
: html`
|
||||
<div class="media-info">
|
||||
<div class="title">
|
||||
<hui-marquee
|
||||
.text=${stateObj.attributes.media_title ||
|
||||
computeMediaDescription(stateObj)}
|
||||
.active=${this._marqueeActive}
|
||||
@mouseover=${this._marqueeMouseOver}
|
||||
@mouseleave=${this._marqueeMouseLeave}
|
||||
></hui-marquee>
|
||||
</div>
|
||||
<hui-marquee
|
||||
.text=${stateObj.attributes.media_title ||
|
||||
mediaDescription}
|
||||
.active=${this._marqueeActive}
|
||||
@mouseover=${this._marqueeMouseOver}
|
||||
@mouseleave=${this._marqueeMouseLeave}
|
||||
></hui-marquee>
|
||||
${!stateObj.attributes.media_title
|
||||
? ""
|
||||
: computeMediaDescription(stateObj)}
|
||||
: mediaDescription}
|
||||
</div>
|
||||
`}
|
||||
${this._veryNarrow && !isOffState
|
||||
${!showControls
|
||||
? ""
|
||||
: html`
|
||||
<div class="controls">
|
||||
<div>
|
||||
${(stateObj.state === "off" &&
|
||||
!supportsFeature(stateObj, SUPPORT_TURN_ON)) ||
|
||||
!isOffState
|
||||
? ""
|
||||
: html`
|
||||
<paper-icon-button
|
||||
icon="hass:power"
|
||||
.action=${stateObj.state === "off"
|
||||
? "turn_on"
|
||||
: "turn_off"}
|
||||
@click=${this._handleClick}
|
||||
></paper-icon-button>
|
||||
`}
|
||||
</div>
|
||||
${isOffState
|
||||
? ""
|
||||
: html`
|
||||
<div class="playback-controls">
|
||||
${!supportsFeature(
|
||||
stateObj,
|
||||
SUPPORT_PREVIOUS_TRACK
|
||||
)
|
||||
? ""
|
||||
: html`
|
||||
<paper-icon-button
|
||||
icon="hass:skip-previous"
|
||||
.action=${"media_previous_track"}
|
||||
@click=${this._handleClick}
|
||||
></paper-icon-button>
|
||||
`}
|
||||
${(stateObj.state !== "playing" &&
|
||||
!supportsFeature(
|
||||
stateObj,
|
||||
SUPPORTS_PLAY
|
||||
)) ||
|
||||
stateObj.state === UNAVAILABLE ||
|
||||
(stateObj.state === "playing" &&
|
||||
!supportsFeature(stateObj, SUPPORT_PAUSE) &&
|
||||
!supportsFeature(stateObj, SUPPORT_STOP))
|
||||
? ""
|
||||
: html`
|
||||
<paper-icon-button
|
||||
class="playPauseButton"
|
||||
.icon=${stateObj.state !== "playing"
|
||||
? "hass:play"
|
||||
: supportsFeature(
|
||||
stateObj,
|
||||
SUPPORT_PAUSE
|
||||
)
|
||||
? "hass:pause"
|
||||
: "hass:stop"}
|
||||
.action=${"media_play_pause"}
|
||||
@click=${this._handleClick}
|
||||
></paper-icon-button>
|
||||
`}
|
||||
${!supportsFeature(
|
||||
stateObj,
|
||||
SUPPORT_NEXT_TRACK
|
||||
)
|
||||
? ""
|
||||
: html`
|
||||
<paper-icon-button
|
||||
icon="hass:skip-next"
|
||||
.action=${"media_next_track"}
|
||||
@click=${this._handleClick}
|
||||
></paper-icon-button>
|
||||
`}
|
||||
</div>
|
||||
`}
|
||||
${controls!.map(
|
||||
(control) => html`
|
||||
<paper-icon-button
|
||||
.icon=${control.icon}
|
||||
action=${control.action}
|
||||
@click=${this._handleClick}
|
||||
></paper-icon-button>
|
||||
`
|
||||
)}
|
||||
</div>
|
||||
`}
|
||||
</div>
|
||||
@ -346,7 +303,6 @@ export class HuiMediaControlCard extends LitElement implements LovelaceCard {
|
||||
: html`
|
||||
<paper-progress
|
||||
.max=${stateObj.attributes.media_duration}
|
||||
class="progress"
|
||||
style=${styleMap({
|
||||
"--paper-progress-active-color":
|
||||
this._foregroundColor || "var(--accent-color)",
|
||||
@ -354,8 +310,7 @@ export class HuiMediaControlCard extends LitElement implements LovelaceCard {
|
||||
? "pointer"
|
||||
: "initial",
|
||||
})}
|
||||
@click=${(e: MouseEvent) =>
|
||||
this._handleSeek(e, stateObj)}
|
||||
@click=${this._handleSeek}
|
||||
></paper-progress>
|
||||
`}
|
||||
`}
|
||||
@ -374,13 +329,20 @@ export class HuiMediaControlCard extends LitElement implements LovelaceCard {
|
||||
|
||||
protected updated(changedProps: PropertyValues): void {
|
||||
super.updated(changedProps);
|
||||
|
||||
if (!this._config || !this.hass || !changedProps.has("hass")) {
|
||||
return;
|
||||
}
|
||||
|
||||
const stateObj = this.hass.states[this._config.entity] as MediaEntity;
|
||||
const stateObj = this._stateObj;
|
||||
|
||||
if (!stateObj) {
|
||||
if (this._progressInterval) {
|
||||
clearInterval(this._progressInterval);
|
||||
this._progressInterval = undefined;
|
||||
}
|
||||
this._foregroundColor = undefined;
|
||||
this._backgroundColor = undefined;
|
||||
return;
|
||||
}
|
||||
|
||||
@ -398,13 +360,15 @@ export class HuiMediaControlCard extends LitElement implements LovelaceCard {
|
||||
applyThemesOnElement(this, this.hass.themes, this._config.theme);
|
||||
}
|
||||
|
||||
this._updateProgressBar();
|
||||
|
||||
if (
|
||||
!this._progressInterval &&
|
||||
this._showProgressBar &&
|
||||
stateObj.state === "playing"
|
||||
) {
|
||||
this._progressInterval = window.setInterval(
|
||||
() => this._updateProgressBar(stateObj),
|
||||
() => this._updateProgressBar(),
|
||||
1000
|
||||
);
|
||||
} else if (
|
||||
@ -427,16 +391,97 @@ export class HuiMediaControlCard extends LitElement implements LovelaceCard {
|
||||
|
||||
if (this._image !== oldImage) {
|
||||
this._setColors();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
private _getControls(): ControlButton[] | undefined {
|
||||
const stateObj = this._stateObj;
|
||||
|
||||
if (!stateObj) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const state = stateObj.state;
|
||||
|
||||
if (state === UNAVAILABLE || state === UNKNOWN) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
if (state === "off") {
|
||||
return supportsFeature(stateObj, SUPPORT_TURN_ON)
|
||||
? [
|
||||
{
|
||||
icon: "hass:power",
|
||||
action: "turn_on",
|
||||
},
|
||||
]
|
||||
: undefined;
|
||||
}
|
||||
|
||||
if (state === "on") {
|
||||
return supportsFeature(stateObj, SUPPORT_TURN_OFF)
|
||||
? [
|
||||
{
|
||||
icon: "hass:power",
|
||||
action: "turn_off",
|
||||
},
|
||||
]
|
||||
: undefined;
|
||||
}
|
||||
|
||||
if (state === "idle") {
|
||||
return supportsFeature(stateObj, SUPPORTS_PLAY)
|
||||
? [
|
||||
{
|
||||
icon: "hass:play",
|
||||
action: "media_play",
|
||||
},
|
||||
]
|
||||
: undefined;
|
||||
}
|
||||
|
||||
const buttons: ControlButton[] = [];
|
||||
|
||||
if (supportsFeature(stateObj, SUPPORT_PREVIOUS_TRACK)) {
|
||||
buttons.push({
|
||||
icon: "hass:skip-previous",
|
||||
action: "media_previous_track",
|
||||
});
|
||||
}
|
||||
|
||||
if (
|
||||
(state === "playing" &&
|
||||
(supportsFeature(stateObj, SUPPORT_PAUSE) ||
|
||||
supportsFeature(stateObj, SUPPORT_STOP))) ||
|
||||
(state === "paused" && supportsFeature(stateObj, SUPPORTS_PLAY))
|
||||
) {
|
||||
buttons.push({
|
||||
icon:
|
||||
state !== "playing"
|
||||
? "hass:play"
|
||||
: supportsFeature(stateObj, SUPPORT_PAUSE)
|
||||
? "hass:pause"
|
||||
: "hass:stop",
|
||||
action: "media_play_pause",
|
||||
});
|
||||
}
|
||||
|
||||
if (supportsFeature(stateObj, SUPPORT_NEXT_TRACK)) {
|
||||
buttons.push({
|
||||
icon: "hass:skip-next",
|
||||
action: "media_next_track",
|
||||
});
|
||||
}
|
||||
|
||||
return buttons.length > 0 ? buttons : undefined;
|
||||
}
|
||||
|
||||
private get _image() {
|
||||
if (!this.hass || !this._config) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const stateObj = this.hass.states[this._config.entity] as MediaEntity;
|
||||
const stateObj = this._stateObj;
|
||||
|
||||
if (!stateObj) {
|
||||
return undefined;
|
||||
@ -449,21 +494,20 @@ export class HuiMediaControlCard extends LitElement implements LovelaceCard {
|
||||
}
|
||||
|
||||
private get _showProgressBar() {
|
||||
if (!this.hass || !this._config) {
|
||||
if (!this.hass || !this._config || this._narrow) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const stateObj = this.hass.states[this._config.entity] as MediaEntity;
|
||||
const stateObj = this._stateObj;
|
||||
|
||||
if (!stateObj) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return (
|
||||
!OFF_STATES.includes(stateObj.state) &&
|
||||
stateObj.attributes.media_duration &&
|
||||
stateObj.attributes.media_position &&
|
||||
!this._narrow
|
||||
(stateObj.state === "playing" || stateObj.state === "paused") &&
|
||||
"media_duration" in stateObj.attributes &&
|
||||
"media_position" in stateObj.attributes
|
||||
);
|
||||
}
|
||||
|
||||
@ -490,7 +534,12 @@ export class HuiMediaControlCard extends LitElement implements LovelaceCard {
|
||||
debounce(() => this._measureCard(), 250, false)
|
||||
);
|
||||
|
||||
this._resizeObserver.observe(this);
|
||||
const card = this.shadowRoot!.querySelector("ha-card");
|
||||
// If we show an error or warning there is no ha-card
|
||||
if (!card) {
|
||||
return;
|
||||
}
|
||||
this._resizeObserver.observe(card);
|
||||
}
|
||||
|
||||
private _handleMoreInfo(): void {
|
||||
@ -500,18 +549,28 @@ export class HuiMediaControlCard extends LitElement implements LovelaceCard {
|
||||
}
|
||||
|
||||
private _handleClick(e: MouseEvent): void {
|
||||
this.hass!.callService("media_player", (e.currentTarget! as any).action, {
|
||||
entity_id: this._config!.entity,
|
||||
});
|
||||
this.hass!.callService(
|
||||
"media_player",
|
||||
(e.currentTarget! as PaperIconButtonElement).getAttribute("action")!,
|
||||
{
|
||||
entity_id: this._config!.entity,
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
private _updateProgressBar(stateObj: MediaEntity): void {
|
||||
private _updateProgressBar(): void {
|
||||
if (this._progressBar) {
|
||||
this._progressBar.value = getCurrentProgress(stateObj);
|
||||
this._progressBar.value = getCurrentProgress(this._stateObj!);
|
||||
}
|
||||
}
|
||||
|
||||
private _handleSeek(e: MouseEvent, stateObj: MediaEntity): void {
|
||||
private get _stateObj(): MediaEntity | undefined {
|
||||
return this.hass!.states[this._config!.entity] as MediaEntity;
|
||||
}
|
||||
|
||||
private _handleSeek(e: MouseEvent): void {
|
||||
const stateObj = this._stateObj!;
|
||||
|
||||
if (!supportsFeature(stateObj, SUPPORT_SEEK)) {
|
||||
return;
|
||||
}
|
||||
@ -710,9 +769,12 @@ export class HuiMediaControlCard extends LitElement implements LovelaceCard {
|
||||
height: 44px;
|
||||
}
|
||||
|
||||
.playPauseButton {
|
||||
width: 56px !important;
|
||||
height: 56px !important;
|
||||
paper-icon-button[action="media_play"],
|
||||
paper-icon-button[action="media_play_pause"],
|
||||
paper-icon-button[action="turn_on"],
|
||||
paper-icon-button[action="turn_off"] {
|
||||
width: 56px;
|
||||
height: 56px;
|
||||
}
|
||||
|
||||
.top-info {
|
||||
@ -742,19 +804,16 @@ export class HuiMediaControlCard extends LitElement implements LovelaceCard {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
hui-marquee {
|
||||
font-size: 1.2em;
|
||||
margin: 0px 0 4px;
|
||||
}
|
||||
|
||||
.title-controls {
|
||||
padding-top: 16px;
|
||||
}
|
||||
|
||||
.title {
|
||||
font-size: 1.2em;
|
||||
margin: 0px 0 4px;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.progress {
|
||||
paper-progress {
|
||||
width: 100%;
|
||||
height: var(--paper-progress-height, 4px);
|
||||
margin-top: 4px;
|
||||
@ -770,16 +829,6 @@ export class HuiMediaControlCard extends LitElement implements LovelaceCard {
|
||||
filter: grayscale(1);
|
||||
}
|
||||
|
||||
.off .controls paper-icon-button {
|
||||
width: 55px;
|
||||
height: 55px;
|
||||
}
|
||||
|
||||
.off.player,
|
||||
.narrow.player {
|
||||
padding-bottom: 16px !important;
|
||||
}
|
||||
|
||||
.narrow .controls,
|
||||
.no-progress .controls {
|
||||
padding-bottom: 0;
|
||||
@ -790,12 +839,14 @@ export class HuiMediaControlCard extends LitElement implements LovelaceCard {
|
||||
height: 40px;
|
||||
}
|
||||
|
||||
.narrow .playPauseButton {
|
||||
width: 50px !important;
|
||||
height: 50px !important;
|
||||
.narrow paper-icon-button[action="media_play"],
|
||||
.narrow paper-icon-button[action="media_play_pause"],
|
||||
.narrow paper-icon-button[action="turn_on"] {
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
}
|
||||
|
||||
.no-progress.player {
|
||||
.no-progress.player:not(.no-controls) {
|
||||
padding-bottom: 0px;
|
||||
}
|
||||
`;
|
||||
|
@ -41,7 +41,9 @@ export abstract class HuiStackCard extends LitElement implements LovelaceCard {
|
||||
}
|
||||
}
|
||||
|
||||
public abstract getCardSize(): number;
|
||||
public getCardSize(): number {
|
||||
return 1;
|
||||
}
|
||||
|
||||
public setConfig(config: StackCardConfig): void {
|
||||
if (!config || !config.cards || !Array.isArray(config.cards)) {
|
||||
|
@ -32,7 +32,6 @@ class ActionHandler extends HTMLElement implements ActionHandler {
|
||||
public ripple: Ripple;
|
||||
protected timer?: number;
|
||||
protected held = false;
|
||||
protected touch?: boolean;
|
||||
private dblClickTimeout?: number;
|
||||
|
||||
constructor() {
|
||||
@ -92,22 +91,6 @@ class ActionHandler extends HTMLElement implements ActionHandler {
|
||||
return false;
|
||||
});
|
||||
|
||||
const touchStart = (ev: TouchEvent) => {
|
||||
if (this.touch === false) {
|
||||
return;
|
||||
}
|
||||
this.touch = true;
|
||||
start(ev);
|
||||
};
|
||||
|
||||
const clickStart = (ev: MouseEvent) => {
|
||||
if (this.touch === true) {
|
||||
return;
|
||||
}
|
||||
this.touch = false;
|
||||
start(ev);
|
||||
};
|
||||
|
||||
const start = (ev: Event) => {
|
||||
this.held = false;
|
||||
let x;
|
||||
@ -126,29 +109,16 @@ class ActionHandler extends HTMLElement implements ActionHandler {
|
||||
}, this.holdTime);
|
||||
};
|
||||
|
||||
const touchEnd = (ev: TouchEvent) => {
|
||||
if (this.touch === false) {
|
||||
return;
|
||||
}
|
||||
end(ev);
|
||||
};
|
||||
|
||||
const clickEnd = (ev: MouseEvent) => {
|
||||
if (this.touch === true) {
|
||||
return;
|
||||
}
|
||||
end(ev);
|
||||
};
|
||||
|
||||
const handleEnter = (ev: KeyboardEvent) => {
|
||||
if (this.touch === true || ev.keyCode !== 13) {
|
||||
if (ev.keyCode !== 13) {
|
||||
return;
|
||||
}
|
||||
this.touch = false;
|
||||
end(ev);
|
||||
};
|
||||
|
||||
const end = (ev: Event) => {
|
||||
// Prevent mouse event if touch event
|
||||
ev.preventDefault();
|
||||
if (
|
||||
["touchend", "touchcancel"].includes(ev.type) &&
|
||||
this.timer === undefined
|
||||
@ -177,15 +147,14 @@ class ActionHandler extends HTMLElement implements ActionHandler {
|
||||
} else {
|
||||
fireEvent(element, "action", { action: "tap" });
|
||||
}
|
||||
window.setTimeout(() => (this.touch = undefined), this.holdTime);
|
||||
};
|
||||
|
||||
element.addEventListener("touchstart", touchStart, { passive: true });
|
||||
element.addEventListener("touchend", touchEnd);
|
||||
element.addEventListener("touchcancel", touchEnd);
|
||||
element.addEventListener("touchstart", start, { passive: true });
|
||||
element.addEventListener("touchend", end);
|
||||
element.addEventListener("touchcancel", end);
|
||||
|
||||
element.addEventListener("mousedown", clickStart, { passive: true });
|
||||
element.addEventListener("click", clickEnd);
|
||||
element.addEventListener("mousedown", start, { passive: true });
|
||||
element.addEventListener("click", end);
|
||||
|
||||
element.addEventListener("keyup", handleEnter);
|
||||
}
|
||||
|
@ -94,27 +94,27 @@ class HuiGenericEntityRow extends LitElement {
|
||||
? html`
|
||||
<div class="secondary">
|
||||
${this.secondaryText ||
|
||||
this.config.secondary_info === "entity-id"
|
||||
? stateObj.entity_id
|
||||
: this.config.secondary_info === "last-changed"
|
||||
? html`
|
||||
<ha-relative-time
|
||||
.hass=${this.hass}
|
||||
.datetime=${stateObj.last_changed}
|
||||
></ha-relative-time>
|
||||
`
|
||||
: this.config.secondary_info === "last-triggered"
|
||||
? stateObj.attributes.last_triggered
|
||||
(this.config.secondary_info === "entity-id"
|
||||
? stateObj.entity_id
|
||||
: this.config.secondary_info === "last-changed"
|
||||
? html`
|
||||
<ha-relative-time
|
||||
.hass=${this.hass}
|
||||
.datetime=${stateObj.attributes.last_triggered}
|
||||
.datetime=${stateObj.last_changed}
|
||||
></ha-relative-time>
|
||||
`
|
||||
: this.hass.localize(
|
||||
"ui.panel.lovelace.cards.entities.never_triggered"
|
||||
)
|
||||
: ""}
|
||||
: this.config.secondary_info === "last-triggered"
|
||||
? stateObj.attributes.last_triggered
|
||||
? html`
|
||||
<ha-relative-time
|
||||
.hass=${this.hass}
|
||||
.datetime=${stateObj.attributes.last_triggered}
|
||||
></ha-relative-time>
|
||||
`
|
||||
: this.hass.localize(
|
||||
"ui.panel.lovelace.cards.entities.never_triggered"
|
||||
)
|
||||
: "")}
|
||||
</div>
|
||||
`
|
||||
: ""}
|
||||
|
@ -8,13 +8,25 @@ import {
|
||||
CSSResult,
|
||||
property,
|
||||
} from "lit-element";
|
||||
import { classMap } from "lit-html/directives/class-map";
|
||||
|
||||
@customElement("hui-marquee")
|
||||
class HuiMarquee extends LitElement {
|
||||
@property() public text?: string;
|
||||
@property() public active?: boolean;
|
||||
@property() private _animating = false;
|
||||
@property({ type: Boolean }) public active?: boolean;
|
||||
@property({ reflect: true, type: Boolean, attribute: "animating" })
|
||||
private _animating = false;
|
||||
|
||||
protected firstUpdated(changedProps) {
|
||||
super.firstUpdated(changedProps);
|
||||
|
||||
this.addEventListener("mouseover", () => this.classList.add("hovering"), {
|
||||
// Capture because we need to run before a parent sets active on us.
|
||||
// Hovering will disable the overflow, allowing us to calc if we overflow.
|
||||
capture: true,
|
||||
});
|
||||
this.addEventListener("mouseout", () => this.classList.remove("hovering"));
|
||||
}
|
||||
|
||||
protected updated(changedProperties: PropertyValues): void {
|
||||
super.updated(changedProperties);
|
||||
|
||||
@ -33,12 +45,7 @@ class HuiMarquee extends LitElement {
|
||||
}
|
||||
|
||||
return html`
|
||||
<div
|
||||
class="marquee-inner ${classMap({
|
||||
animating: this._animating,
|
||||
})}"
|
||||
@animationiteration=${this._onIteration}
|
||||
>
|
||||
<div class="marquee-inner" @animationiteration=${this._onIteration}>
|
||||
<span>${this.text}</span>
|
||||
${this._animating
|
||||
? html`
|
||||
@ -61,15 +68,29 @@ class HuiMarquee extends LitElement {
|
||||
display: flex;
|
||||
position: relative;
|
||||
align-items: center;
|
||||
height: 25px;
|
||||
height: 1em;
|
||||
}
|
||||
|
||||
.marquee-inner {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
right: 0;
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
animation: marquee 10s linear infinite paused;
|
||||
}
|
||||
|
||||
.animating {
|
||||
:host(.hovering) .marquee-inner {
|
||||
text-overflow: initial;
|
||||
overflow: initial;
|
||||
}
|
||||
|
||||
:host([animating]) .marquee-inner {
|
||||
left: initial;
|
||||
right: initial;
|
||||
}
|
||||
|
||||
:host([animating]) > div {
|
||||
animation-play-state: running;
|
||||
}
|
||||
|
||||
|
@ -183,7 +183,7 @@ export class HuiCardPicker extends LitElement {
|
||||
.preview {
|
||||
pointer-events: none;
|
||||
margin: 20px;
|
||||
flex: 1 1 0;
|
||||
flex-grow: 1;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
@ -20,7 +20,6 @@ import { supportsFeature } from "../../../common/entity/supports-feature";
|
||||
import {
|
||||
SUPPORTS_PLAY,
|
||||
SUPPORT_NEXT_TRACK,
|
||||
OFF_STATES,
|
||||
SUPPORT_PAUSE,
|
||||
} from "../../../data/media-player";
|
||||
import { hasConfigOrEntityChanged } from "../common/has-changed";
|
||||
@ -68,7 +67,7 @@ class HuiMediaPlayerEntityRow extends LitElement implements LovelaceRow {
|
||||
.config=${this._config}
|
||||
.secondaryText=${this._computeMediaTitle(stateObj)}
|
||||
>
|
||||
${OFF_STATES.includes(stateObj.state)
|
||||
${stateObj.state === "off" || stateObj.state === "idle"
|
||||
? html`
|
||||
<div class="text-content">
|
||||
${this.hass!.localize(`state.media_player.${stateObj.state}`) ||
|
||||
|
@ -476,7 +476,7 @@ class HUIRoot extends LitElement {
|
||||
newSelectView = "hass-unused-entities";
|
||||
} else if (this._routeData!.view) {
|
||||
const selectedView = this._routeData!.view;
|
||||
const selectedViewInt = parseInt(selectedView, 10);
|
||||
const selectedViewInt = Number(selectedView);
|
||||
let index = 0;
|
||||
for (let i = 0; i < views.length; i++) {
|
||||
if (views[i].path === selectedView || i === selectedViewInt) {
|
||||
|
@ -76,6 +76,22 @@ export const haStyle = css`
|
||||
@apply --paper-font-title;
|
||||
}
|
||||
|
||||
.secondary {
|
||||
color: var(--secondary-text-color);
|
||||
}
|
||||
|
||||
.error {
|
||||
color: var(--google-red-500);
|
||||
}
|
||||
|
||||
.warning {
|
||||
color: var(--google-red-500);
|
||||
}
|
||||
|
||||
mwc-button.warning {
|
||||
--mdc-theme-primary: var(--google-red-500);
|
||||
}
|
||||
|
||||
button.link {
|
||||
background: none;
|
||||
color: inherit;
|
||||
@ -160,8 +176,10 @@ export const haStyleDialog = css`
|
||||
padding: 8px;
|
||||
}
|
||||
|
||||
.paper-dialog-buttons .warning {
|
||||
--mdc-theme-primary: var(--google-red-500);
|
||||
@media all and (min-width: 450px) {
|
||||
ha-paper-dialog {
|
||||
min-width: 400px;
|
||||
}
|
||||
}
|
||||
|
||||
@media all and (max-width: 450px), all and (max-height: 500px) {
|
||||
@ -185,9 +203,16 @@ export const haStyleDialog = css`
|
||||
ha-dialog {
|
||||
--mdc-dialog-min-width: 400px;
|
||||
--mdc-dialog-max-width: 600px;
|
||||
--mdc-dialog-title-ink-color: var(--primary-text-color);
|
||||
--mdc-dialog-heading-ink-color: var(--primary-text-color);
|
||||
--justify-action-buttons: space-between;
|
||||
color: var(--primary-text-color);
|
||||
}
|
||||
|
||||
ha-dialog .form {
|
||||
padding-bottom: 24px;
|
||||
color: var(--primary-text-color);
|
||||
}
|
||||
|
||||
/* make dialog fullscreen on small screens */
|
||||
@media all and (max-width: 450px), all and (max-height: 500px) {
|
||||
ha-dialog {
|
||||
|
@ -673,8 +673,8 @@
|
||||
"mode": "What do you want to input"
|
||||
},
|
||||
"input_text": {
|
||||
"min": "Minimum lenght",
|
||||
"max": "Maximum lenght",
|
||||
"min": "Minimum length",
|
||||
"max": "Maximum length",
|
||||
"mode": "Display mode",
|
||||
"text": "Text",
|
||||
"password": "Password",
|
||||
@ -857,6 +857,7 @@
|
||||
"caption": "Lovelace Dashboards",
|
||||
"description": "Configure your Lovelace Dashboards",
|
||||
"dashboards": {
|
||||
"default_dashboard": "This is the default dashboard",
|
||||
"caption": "Dashboards",
|
||||
"conf_mode": {
|
||||
"yaml": "YAML file",
|
||||
@ -882,8 +883,8 @@
|
||||
"new_dashboard": "Add new dashboard",
|
||||
"dismiss": "Close",
|
||||
"show_sidebar": "Show in sidebar",
|
||||
"icon": "Sidebar icon",
|
||||
"title": "Sidebar title",
|
||||
"icon": "Icon",
|
||||
"title": "Title",
|
||||
"title_required": "Title is required.",
|
||||
"url": "Url",
|
||||
"url_error_msg": "The url can not contain spaces or special characters, except for _ and -",
|
||||
|
@ -210,6 +210,14 @@ export type MediaEntity = HassEntityBase & {
|
||||
icon?: string;
|
||||
entity_picture_local?: string;
|
||||
};
|
||||
state:
|
||||
| "playing"
|
||||
| "paused"
|
||||
| "idle"
|
||||
| "off"
|
||||
| "on"
|
||||
| "unavailable"
|
||||
| "unknown";
|
||||
};
|
||||
|
||||
export type InputSelectEntity = HassEntityBase & {
|
||||
|
@ -651,8 +651,12 @@
|
||||
"name": "Navn"
|
||||
},
|
||||
"input_datetime": {
|
||||
"date": "Dato",
|
||||
"datetime": "Dato og tid",
|
||||
"has_date": "Dato",
|
||||
"has_time": "Tid"
|
||||
"has_time": "Tid",
|
||||
"mode": "Hvad vil du indtaste",
|
||||
"time": "Tid"
|
||||
},
|
||||
"input_number": {
|
||||
"box": "Inputfelt",
|
||||
|
@ -651,8 +651,12 @@
|
||||
"name": "Name"
|
||||
},
|
||||
"input_datetime": {
|
||||
"date": "Datum",
|
||||
"datetime": "Datum und Uhrzeit",
|
||||
"has_date": "Datum",
|
||||
"has_time": "Zeit"
|
||||
"has_time": "Zeit",
|
||||
"mode": "Was möchten Sie eingeben",
|
||||
"time": "Uhrzeit"
|
||||
},
|
||||
"input_number": {
|
||||
"box": "Eingabefeld",
|
||||
@ -2162,6 +2166,7 @@
|
||||
},
|
||||
"glance": {
|
||||
"columns": "Spalten",
|
||||
"description": "Die Glance-Karte ist nützlich, um mehrere Sensoren in einer kompakten Übersicht zu gruppieren.",
|
||||
"name": "Glance"
|
||||
},
|
||||
"history-graph": {
|
||||
@ -2169,6 +2174,7 @@
|
||||
"name": "History Graph"
|
||||
},
|
||||
"horizontal-stack": {
|
||||
"description": "Mit der Karte \"Horizontaler Stapel\" können Sie mehrere Karten so gruppieren, dass sie immer nebeneinander sitzen und gemeinsam die Breite einer Spalte einnehmen.",
|
||||
"name": "Horizontaler Stapel"
|
||||
},
|
||||
"iframe": {
|
||||
@ -2189,6 +2195,7 @@
|
||||
},
|
||||
"markdown": {
|
||||
"content": "Inhalt",
|
||||
"description": "Die Markdown-Karte wird zum Rendern von Markdown verwendet.",
|
||||
"name": "Markdown"
|
||||
},
|
||||
"media-control": {
|
||||
@ -2204,6 +2211,7 @@
|
||||
"name": "Picture Entity"
|
||||
},
|
||||
"picture-glance": {
|
||||
"description": "Die Bild Glance-Karte zeigt ein Bild und die entsprechenden Entitätszustände als Symbol. Die Entitäten auf der rechten Seite ermöglichen das Umschalten von Aktionen, andere zeigen den Dialog mit weiteren Informationen an.",
|
||||
"name": "Picture Glance"
|
||||
},
|
||||
"picture": {
|
||||
@ -2234,6 +2242,7 @@
|
||||
"name": "Vertikaler Stapel"
|
||||
},
|
||||
"weather-forecast": {
|
||||
"description": "Die Wettervorhersagekarte zeigt das vorhergesagte Wetter an. Sehr nützlich für wandmontierte Displays.",
|
||||
"name": "Wettervorhersage"
|
||||
}
|
||||
},
|
||||
|
@ -1317,7 +1317,8 @@
|
||||
"device": "Device",
|
||||
"integration": "Integration",
|
||||
"manufacturer": "Manufacturer",
|
||||
"model": "Model"
|
||||
"model": "Model",
|
||||
"no_devices": "No devices"
|
||||
},
|
||||
"description": "Manage connected devices",
|
||||
"details": "Here are all the details of your device.",
|
||||
@ -1559,7 +1560,8 @@
|
||||
"headers": {
|
||||
"type": "Type",
|
||||
"url": "Url"
|
||||
}
|
||||
},
|
||||
"no_resources": "No resources"
|
||||
},
|
||||
"refresh_body": "You have to refresh the page to complete the removal, do you want to refresh now?",
|
||||
"refresh_header": "Do you want to refresh?",
|
||||
@ -2275,7 +2277,10 @@
|
||||
"move_right": "Move view right",
|
||||
"tab_badges": "Badges",
|
||||
"tab_settings": "Settings",
|
||||
"tab_visibility": "Visibility"
|
||||
"tab_visibility": "Visibility",
|
||||
"visibility": {
|
||||
"select_users": "Select which users should see this view in the navigation"
|
||||
}
|
||||
},
|
||||
"header": "Edit UI",
|
||||
"menu": {
|
||||
@ -2352,6 +2357,7 @@
|
||||
"existing_cards": "You can't delete a view that has cards in it. Remove the cards first."
|
||||
},
|
||||
"warning": {
|
||||
"attribute_not_found": "Attribute {attribute} not available in: {entity}",
|
||||
"entity_non_numeric": "Entity is non-numeric: {entity}",
|
||||
"entity_not_found": "Entity not available: {entity}"
|
||||
}
|
||||
|
@ -394,9 +394,9 @@
|
||||
},
|
||||
"ui": {
|
||||
"auth_store": {
|
||||
"ask": "¿Quieres guardar este inicio de sesión?",
|
||||
"confirm": "Guardar usuario",
|
||||
"decline": "No, gracias"
|
||||
"ask": "¿Quieres permanecer conectado?",
|
||||
"confirm": "Sí",
|
||||
"decline": "No"
|
||||
},
|
||||
"card": {
|
||||
"alarm_control_panel": {
|
||||
@ -651,8 +651,12 @@
|
||||
"name": "Nombre"
|
||||
},
|
||||
"input_datetime": {
|
||||
"date": "Fecha",
|
||||
"datetime": "Fecha y hora",
|
||||
"has_date": "Fecha",
|
||||
"has_time": "Hora"
|
||||
"has_time": "Hora",
|
||||
"mode": "¿Qué quieres introducir?",
|
||||
"time": "Hora"
|
||||
},
|
||||
"input_number": {
|
||||
"box": "Campo de entrada",
|
||||
@ -679,9 +683,9 @@
|
||||
},
|
||||
"not_editable": "No editable",
|
||||
"not_editable_text": "Esta entidad no se puede cambiar desde la interfaz de usuario porque está definida en configuration.yaml.",
|
||||
"platform_not_loaded": "El componente {platform} no está cargado, por favor añádalo a su configuración. Ya sea agregando 'default_config:' o '{platform}:'.",
|
||||
"platform_not_loaded": "El componente {platform} no está cargado, por favor añádelo a tu configuración. Ya sea agregando 'default_config:' o '{platform}:'.",
|
||||
"required_error_msg": "Este campo es obligatorio",
|
||||
"yaml_not_editable": "La configuración de esta entidad no se puede editar desde la interfaz de usuario. Solo las entidades configuradas desde la interfaz de usuario se pueden configurar desde la interfaz de usuario."
|
||||
"yaml_not_editable": "La configuración de esta entidad no se puede editar desde la IU. Solo las entidades configuradas desde la IU se pueden configurar desde la IU"
|
||||
},
|
||||
"more_info_control": {
|
||||
"dismiss": "Descartar diálogo",
|
||||
@ -806,6 +810,10 @@
|
||||
"areas": {
|
||||
"caption": "Áreas",
|
||||
"create_area": "CREAR ÁREA",
|
||||
"delete": {
|
||||
"confirmation_text": "Todos los dispositivos en esta área quedarán sin asignar.",
|
||||
"confirmation_title": "¿Estás seguro de que deseas eliminar esta área?"
|
||||
},
|
||||
"description": "Visión general de todas las áreas de tu casa.",
|
||||
"editor": {
|
||||
"create": "CREAR",
|
||||
@ -875,7 +883,7 @@
|
||||
"conditions": {
|
||||
"add": "Añadir condición",
|
||||
"delete": "Eliminar",
|
||||
"delete_confirm": "¿Seguro que quieres eliminarlo?",
|
||||
"delete_confirm": "¿Estás seguro de que quieres eliminarlo?",
|
||||
"duplicate": "Duplicar",
|
||||
"header": "Condiciones",
|
||||
"introduction": "Las condiciones son opcionales e impedirán cualquier\nejecución posterior a menos que se cumplan todas las condiciones.",
|
||||
@ -948,7 +956,7 @@
|
||||
"triggers": {
|
||||
"add": "Añadir desencadenante",
|
||||
"delete": "Eliminar",
|
||||
"delete_confirm": "¿Seguro que quieres eliminarlo?",
|
||||
"delete_confirm": "¿Estás seguro de que quieres eliminarlo?",
|
||||
"duplicate": "Duplicar",
|
||||
"header": "Desencadenantes",
|
||||
"introduction": "Los desencadenantes son los que inician el funcionamiento de una regla de automatización. Es posible especificar varios desencadenantes para la misma regla. Una vez que se inicia un desencadenante, Home Assistant comprobará las condiciones, si las hubiere, y ejecutará la acción.",
|
||||
@ -1384,9 +1392,9 @@
|
||||
"introduction2": "Utiliza el registro de entidades para anular el nombre, cambiar el ID de la entidad o eliminar la entrada de Home Assistant.",
|
||||
"remove_selected": {
|
||||
"button": "Eliminar seleccionadas",
|
||||
"confirm_partly_text": "Solo puede eliminar {removable} de las entidades {selected} . Las entidades solo se pueden eliminar cuando la integración ya no proporciona las entidades. En ocasiones, debe reiniciar Home Assistant antes de poder eliminar las entidades de una integración eliminada. ¿Seguro que quieres eliminar las entidades extraíbles?",
|
||||
"confirm_partly_text": "Solo puedes eliminar {removable} de las entidades {selected} seleccionadas. Las entidades solo se pueden eliminar cuando la integración ya no proporciona las entidades. En algunas ocasiones debes reiniciar Home Assistant antes de poder eliminar las entidades de una integración eliminada. ¿Seguro que quieres eliminar las entidades eliminables?",
|
||||
"confirm_partly_title": "Sólo se pueden eliminar {number} entidades seleccionadas.",
|
||||
"confirm_text": "Las entidades solo se pueden eliminar cuando la integración ya no proporciona las entidades.",
|
||||
"confirm_text": "Debes eliminarlos de la configuración y las automatizaciones de Lovelace si contienen estas entidades.",
|
||||
"confirm_title": "¿Deseas eliminar {number} entidades?"
|
||||
},
|
||||
"selected": "{number} seleccionadas",
|
||||
@ -1491,7 +1499,7 @@
|
||||
"lovelace": {
|
||||
"caption": "Paneles de Control Lovelace",
|
||||
"dashboards": {
|
||||
"cant_edit_default": "El panel de control estándar de Lovelace no se puede editar desde la interfaz de usuario. Puede ocultarlo estableciendo otro panel como predeterminado.",
|
||||
"cant_edit_default": "El panel de control estándar de Lovelace no se puede editar desde la interfaz de usuario. Puedes ocultarlo estableciendo otro panel como predeterminado.",
|
||||
"cant_edit_yaml": "Los paneles de control definidos en YAML no se pueden editar desde la interfaz de usuario. Cámbialos en configuration.yaml.",
|
||||
"caption": "Paneles de control",
|
||||
"conf_mode": {
|
||||
@ -1526,7 +1534,7 @@
|
||||
"sidebar": "Mostrar en la barra lateral",
|
||||
"title": "Título"
|
||||
},
|
||||
"open": "Abrir panel de control"
|
||||
"open": "Abrir"
|
||||
}
|
||||
},
|
||||
"description": "Configura tus Paneles de Control Lovelace",
|
||||
@ -2084,11 +2092,11 @@
|
||||
},
|
||||
"alarm-panel": {
|
||||
"available_states": "Estados disponibles",
|
||||
"description": "La tarjeta del panel de alarma le permite armar y desarmar las integraciones de su panel de control de alarma.",
|
||||
"description": "La tarjeta del Panel de Alarma te permite Armar y Desarmar las integraciones de tu panel de control de alarma.",
|
||||
"name": "Panel de alarma"
|
||||
},
|
||||
"button": {
|
||||
"description": "La tarjeta Botón le permite agregar botones para realizar tareas.",
|
||||
"description": "La tarjeta Botón te permite agregar botones para realizar tareas.",
|
||||
"name": "Botón"
|
||||
},
|
||||
"conditional": {
|
||||
@ -2116,7 +2124,7 @@
|
||||
"name": "Botón de entidad"
|
||||
},
|
||||
"entity-filter": {
|
||||
"description": "La tarjeta Filtro de entidades le permite definir una lista de entidades de las que desea realizar un seguimiento solo cuando se encuentra en un estado determinado.",
|
||||
"description": "La tarjeta Filtro de Entidades te permite definir una lista de entidades de las que deseas realizar un seguimiento solo cuando se encuentra en un estado determinado.",
|
||||
"name": "Filtro de entidad"
|
||||
},
|
||||
"gauge": {
|
||||
@ -2141,7 +2149,7 @@
|
||||
"icon_height": "Altura del icono",
|
||||
"image": "Ruta de la imagen",
|
||||
"manual": "Manual",
|
||||
"manual_description": "¿Necesita agregar una tarjeta personalizada o simplemente desea escribir manualmente el yaml?",
|
||||
"manual_description": "¿Necesitas agregar una tarjeta personalizada o simplemente deseas escribir manualmente el yaml?",
|
||||
"maximum": "Máximo",
|
||||
"minimum": "Mínimo",
|
||||
"name": "Nombre",
|
||||
@ -2162,7 +2170,7 @@
|
||||
"name": "Vistazo"
|
||||
},
|
||||
"history-graph": {
|
||||
"description": "La tarjeta de gráficos de historia permite mostrar un gráfico para cada una de las entidades enumeradas.",
|
||||
"description": "La tarjeta Historial Gráfico te permite mostrar un gráfico para cada una de las entidades enumeradas.",
|
||||
"name": "Gráfico histórico"
|
||||
},
|
||||
"horizontal-stack": {
|
||||
@ -2170,17 +2178,17 @@
|
||||
"name": "Pila horizontal"
|
||||
},
|
||||
"iframe": {
|
||||
"description": "La tarjeta de página web le permite incrustar su página web favorita directamente en Home Assistant.",
|
||||
"name": "iFrame"
|
||||
"description": "La tarjeta de página web te permite incrustar tu página web favorita directamente en Home Assistant.",
|
||||
"name": "Página web"
|
||||
},
|
||||
"light": {
|
||||
"description": "La tarjeta de luz le permite cambiar la intensidad de la luz.",
|
||||
"description": "La tarjeta de luz te permite cambiar la intensidad de la luz.",
|
||||
"name": "Luz"
|
||||
},
|
||||
"map": {
|
||||
"dark_mode": "¿Modo oscuro?",
|
||||
"default_zoom": "Zoom predeterminado",
|
||||
"description": "La tarjeta Mapa que permite mostrar entidades en un mapa.",
|
||||
"description": "La tarjeta Mapa que te permite mostrar entidades en un mapa.",
|
||||
"geo_location_sources": "Fuentes de geolocalización",
|
||||
"name": "Mapa",
|
||||
"source": "Fuente"
|
||||
@ -2195,11 +2203,11 @@
|
||||
"name": "Control Multimedia"
|
||||
},
|
||||
"picture-elements": {
|
||||
"description": "La tarjeta Elementos de imagen es uno de los tipos de tarjetas más versátiles. ¡Las tarjetas le permiten colocar iconos o texto e incluso servicios! En una imagen basada en coordenadas.",
|
||||
"description": "La tarjeta Elementos de imagen es uno de los tipos de tarjetas más versátiles. ¡Las tarjetas te permiten colocar iconos o texto e incluso servicios! En una imagen basada en coordenadas.",
|
||||
"name": "Elementos de imagen"
|
||||
},
|
||||
"picture-entity": {
|
||||
"description": "La tarjeta de Entidad de Imagen muestra una entidad en forma de imagen. En lugar de imágenes de URL, también puede mostrar la imagen de las entidades de la cámara.",
|
||||
"description": "La tarjeta de Entidad de Imagen muestra una entidad en forma de imagen. En lugar de imágenes desde una URL, también puede mostrar la imagen de las entidades de cámara.",
|
||||
"name": "Entidad de imagen"
|
||||
},
|
||||
"picture-glance": {
|
||||
@ -2215,22 +2223,22 @@
|
||||
"name": "Estado de la planta"
|
||||
},
|
||||
"sensor": {
|
||||
"description": "La tarjeta Sensor le ofrece una visión general rápida del estado de sus sensores con un gráfico opcional para visualizar los cambios a lo largo del tiempo.",
|
||||
"description": "La tarjeta Sensor te ofrece una visión general rápida del estado de tus sensores con un gráfico opcional para visualizar los cambios a lo largo del tiempo.",
|
||||
"graph_detail": "Detalle del gráfico",
|
||||
"graph_type": "Tipo de gráfico",
|
||||
"name": "Sensor"
|
||||
},
|
||||
"shopping-list": {
|
||||
"description": "La tarjeta Lista de la Compra le permite agregar, editar, marcar y borrar artículos de su lista de compras.",
|
||||
"description": "La tarjeta Lista de la Compra le permite agregar, editar, marcar y borrar artículos de tu lista de compras.",
|
||||
"integration_not_loaded": "Esta tarjeta requiere que se configure la integración 'Lista de la compra'.",
|
||||
"name": "Lista de la compra"
|
||||
},
|
||||
"thermostat": {
|
||||
"description": "La tarjeta Termostato le da el control de su entidad climática. Permitiéndole cambiar la temperatura y el modo de la entidad.",
|
||||
"description": "La tarjeta Termostato te da el control de tu entidad climática. Te permite cambiar la temperatura y el modo de la entidad.",
|
||||
"name": "Termostato"
|
||||
},
|
||||
"vertical-stack": {
|
||||
"description": "La tarjeta Pila Vertical le permite agrupar varias tarjetas para que siempre se sienten en la misma columna.",
|
||||
"description": "La tarjeta Pila Vertical te permite agrupar varias tarjetas para que siempre se sienten en la misma columna.",
|
||||
"name": "Pila vertical"
|
||||
},
|
||||
"weather-forecast": {
|
||||
@ -2337,10 +2345,10 @@
|
||||
"title": "Entidades no utilizadas"
|
||||
},
|
||||
"views": {
|
||||
"confirm_delete": "¿Seguro que quieres eliminar esta vista?",
|
||||
"confirm_delete": "¿Eliminar vista?",
|
||||
"confirm_delete_existing_cards": "Al eliminar esta vista también se eliminarán las tarjetas",
|
||||
"confirm_delete_existing_cards_text": "¿Está seguro de que desea eliminar su vista '{name}'? La vista contiene {number} tarjetas que se eliminarán. Esta acción no se puede deshacer.",
|
||||
"confirm_delete_text": "¿Está seguro de que desea eliminar su vista '{name}'?",
|
||||
"confirm_delete_existing_cards_text": "¿Estás seguro de que deseas eliminar tu vista '{name}'? La vista contiene {number} tarjetas que se eliminarán. Esta acción no se puede deshacer.",
|
||||
"confirm_delete_text": "¿Estás seguro de que deseas eliminar tu vista '{name}'?",
|
||||
"existing_cards": "No puedes eliminar una vista que tiene tarjetas. Elimina las tarjetas primero."
|
||||
},
|
||||
"warning": {
|
||||
|
@ -649,8 +649,12 @@
|
||||
"name": "Numm"
|
||||
},
|
||||
"input_datetime": {
|
||||
"date": "Datum",
|
||||
"datetime": "Datum an Zäit",
|
||||
"has_date": "Datum",
|
||||
"has_time": "Zäit"
|
||||
"has_time": "Zäit",
|
||||
"mode": "Wat soll d'Angabe sinn?",
|
||||
"time": "Zäit"
|
||||
},
|
||||
"input_number": {
|
||||
"max": "Maximale Wäert",
|
||||
@ -799,6 +803,10 @@
|
||||
"areas": {
|
||||
"caption": "Lëscht vun de Beräicher",
|
||||
"create_area": "Beräich erstellen",
|
||||
"delete": {
|
||||
"confirmation_text": "All Apparater an dësem Beräich ginn néirens zougewisen.",
|
||||
"confirmation_title": "Sécher fir dëse Beräich ze läsche?"
|
||||
},
|
||||
"description": "Iwwersiicht vun de Beräicher am Haus",
|
||||
"editor": {
|
||||
"create": "Erstellen",
|
||||
@ -1404,6 +1412,7 @@
|
||||
"add_helper": "Helper bäifügen",
|
||||
"headers": {
|
||||
"editable": "Editéierbar",
|
||||
"entity_id": "ID vun der Entitéit",
|
||||
"name": "Numm",
|
||||
"type": "Typ"
|
||||
}
|
||||
@ -1497,6 +1506,7 @@
|
||||
"require_admin": "Admin nëmmen",
|
||||
"show_sidebar": "An der Säite Läischt uweisen",
|
||||
"title": "Titel vun der Säite Läischt",
|
||||
"title_required": "Titel ass erfuerderlech.",
|
||||
"update": "Aktualiséieren",
|
||||
"url": "Url",
|
||||
"url_error_msg": "D'Url ka keen Espace oder speziell Charakteren, ausser _ an - , enthalen."
|
||||
@ -2071,10 +2081,18 @@
|
||||
"name": "Alarm Zentral"
|
||||
},
|
||||
"button": {
|
||||
"description": "Knäppchen Kaart erlaabt et Knäppchen mat Aktioune unzeweisen.",
|
||||
"name": "Knäppchen"
|
||||
},
|
||||
"conditional": {
|
||||
"name": "Bedingungen"
|
||||
"card": "Kaart",
|
||||
"change_type": "Typ änneren",
|
||||
"condition_explanation": "D'Kaart gëtt réischt ugewisen wann ALL Konditiounen erfëllt sinn.",
|
||||
"conditions": "Konditiounen",
|
||||
"current_state": "aktuell",
|
||||
"name": "Bedingungen",
|
||||
"state_equal": "Zoustand ass gläich mat",
|
||||
"state_not_equal": "Zoustand ass net gläich mat"
|
||||
},
|
||||
"config": {
|
||||
"optional": "Optional",
|
||||
@ -2111,6 +2129,7 @@
|
||||
"icon": "Ikon",
|
||||
"icon_height": "Héicht vun der Ikon",
|
||||
"image": "Wee zum Bild",
|
||||
"manual": "Manuell",
|
||||
"maximum": "Maximum",
|
||||
"minimum": "Minimum",
|
||||
"name": "Numm",
|
||||
@ -2118,6 +2137,7 @@
|
||||
"show_icon": "Ikon uweisen?",
|
||||
"show_name": "Numm uweisen?",
|
||||
"show_state": "Zoustand uweisen?",
|
||||
"state": "Zoustand",
|
||||
"tap_action": "Aktioun beim tippen",
|
||||
"theme": "Thema",
|
||||
"title": "Titel",
|
||||
@ -2132,32 +2152,39 @@
|
||||
"name": "Verlaf Diagramm"
|
||||
},
|
||||
"horizontal-stack": {
|
||||
"description": "Horizontaé Kaart erlaabt et méi Kaarten ze gruppéieren fir dass se ëmmer an der selwechter Rei ugewise ginn.",
|
||||
"name": "Horizontale Stapel"
|
||||
},
|
||||
"iframe": {
|
||||
"description": "Websäit Kaart erlaabt et eng aaner Websäit am Home Assistant unzeweisen.",
|
||||
"name": "iFrame"
|
||||
},
|
||||
"light": {
|
||||
"description": "Luucht Kaart erlaabt et d'Hellegkeet vun de Luuchten ze veränneren.",
|
||||
"name": "Luucht"
|
||||
},
|
||||
"map": {
|
||||
"dark_mode": "Däischteren Modus",
|
||||
"default_zoom": "Standard Zoom",
|
||||
"description": "Kaarte Kaart erméiglecht d'Visualisatioun vun Entitéiten op enger Kaart.",
|
||||
"geo_location_sources": "Quell vun der Geolokalisatioun",
|
||||
"name": "Kaart",
|
||||
"source": "Quell"
|
||||
},
|
||||
"markdown": {
|
||||
"content": "Contenu",
|
||||
"description": "Markdown Kaart gëtt benotzt fir Text ze formatéieren.",
|
||||
"name": "Markdown"
|
||||
},
|
||||
"media-control": {
|
||||
"description": "Medien Kontroller Kaart gëtt benotzt fir Medie Spiller Entitéiten an engem Interface mat Kontroll Knäppchen unzeweisen.",
|
||||
"name": "Medie Kontroll"
|
||||
},
|
||||
"picture-elements": {
|
||||
"name": "Biller Elementer"
|
||||
},
|
||||
"picture-entity": {
|
||||
"description": "Bild Entitéite Kaart affichéiert eng Entitéit an der Form vun engem Bild. Amplaatz vun Biller vun enger URL kënnen och Biller vun enger Kamera ugewise ginn.",
|
||||
"name": "Biller Entitéit"
|
||||
},
|
||||
"picture-glance": {
|
||||
@ -2167,24 +2194,30 @@
|
||||
"name": "Bild"
|
||||
},
|
||||
"plant-status": {
|
||||
"description": "Pflanz Kaart ass fir all Botanist geduecht.",
|
||||
"name": "Status vun der Planz"
|
||||
},
|
||||
"sensor": {
|
||||
"description": "Sensor Kaart erméiglecht eng schnell vue vun den Zoustänn vun de Sensoren mat engem optionalen Graphique fir den Verlaf ze visualiséieren.",
|
||||
"graph_detail": "Detail Diagramm",
|
||||
"graph_type": "Typ vun Graph.",
|
||||
"name": "Sensor"
|
||||
},
|
||||
"shopping-list": {
|
||||
"description": "Akafslëscht Kaart erlaabt et Saachen op eng Akafslëscht dobäizesetzen, änneren oder ofzehaken.",
|
||||
"integration_not_loaded": "Dës Kaart erfuerdert dass d'Integratioun `shopping_list ageriicht ass.",
|
||||
"name": "Akafslëscht"
|
||||
},
|
||||
"thermostat": {
|
||||
"description": "Thermostat Kaart erlaabt d'Kontroll vun den Klima Entitéiten. Souwuel Temperatur an Betriibs Modus kënnen geännert ginn.",
|
||||
"name": "Thermostat"
|
||||
},
|
||||
"vertical-stack": {
|
||||
"description": "Vertikal Kaart erlaabt et méi Kaarten ze gruppéieren fir dass se ëmmer an der selwechter Kolonne ugewise ginn.",
|
||||
"name": "Vertikale Stapel"
|
||||
},
|
||||
"weather-forecast": {
|
||||
"description": "Wieder Previsoune Kaart weist d'Météo un. Immens nëtzlech fir Interfacen déi Benotzer un d'Mauer hänken.",
|
||||
"name": "Wiederprevisioune"
|
||||
}
|
||||
},
|
||||
@ -2216,7 +2249,8 @@
|
||||
"move_left": "Usiicht no lenks réckelen",
|
||||
"move_right": "Usiicht no riets réckelen",
|
||||
"tab_badges": "Badgen",
|
||||
"tab_settings": "Astellungen"
|
||||
"tab_settings": "Astellungen",
|
||||
"tab_visibility": "Visibilitéit"
|
||||
},
|
||||
"header": "UI änneren",
|
||||
"menu": {
|
||||
|
@ -651,8 +651,12 @@
|
||||
"name": "Navn"
|
||||
},
|
||||
"input_datetime": {
|
||||
"date": "Dato",
|
||||
"datetime": "Dato og tid",
|
||||
"has_date": "Dato",
|
||||
"has_time": "Tid"
|
||||
"has_time": "Tid",
|
||||
"mode": "Hva vil du legge inn",
|
||||
"time": "Tid"
|
||||
},
|
||||
"input_number": {
|
||||
"box": "Inntastingsfelt",
|
||||
@ -679,7 +683,7 @@
|
||||
},
|
||||
"not_editable": "Kan ikke redigeres",
|
||||
"not_editable_text": "Denne enheten kan ikke endres fra brukergrensesnittet fordi den er definert i configuration.yaml.",
|
||||
"platform_not_loaded": "{platform} -komponenten er ikke lastet, legg den til konfigurasjonen din. Enten ved å legge til 'default_config:' eller '{platform}:'.",
|
||||
"platform_not_loaded": "Integrasjonen {platform} er ikke lastet, legg den til konfigurasjonen din. Enten ved å legge til 'default_config:' eller '{platform}:'.",
|
||||
"required_error_msg": "Dette feltet er påkrevd",
|
||||
"yaml_not_editable": "Innstillingene til denne enheten kan ikke redigeres fra brukergrensesnittet. Bare enheter som er konfigurert fra brukergrensesnittet, kan konfigureres fra brukergrensesnittet."
|
||||
},
|
||||
|
@ -651,6 +651,7 @@
|
||||
"name": "Nazwa"
|
||||
},
|
||||
"input_datetime": {
|
||||
"datetime": "Data i godzina",
|
||||
"has_date": "Data",
|
||||
"has_time": "Czas"
|
||||
},
|
||||
|
@ -650,8 +650,12 @@
|
||||
"name": "Название"
|
||||
},
|
||||
"input_datetime": {
|
||||
"date": "Дата",
|
||||
"datetime": "Дата и время",
|
||||
"has_date": "Дата",
|
||||
"has_time": "Время"
|
||||
"has_time": "Время",
|
||||
"mode": "Что вы хотите ввести?",
|
||||
"time": "Время"
|
||||
},
|
||||
"input_number": {
|
||||
"box": "Поле ввода",
|
||||
@ -678,7 +682,7 @@
|
||||
},
|
||||
"not_editable": "Только для чтения",
|
||||
"not_editable_text": "Этот объект нельзя изменить из пользовательского интерфейса, поскольку он был создан в файле configuration.yaml.",
|
||||
"platform_not_loaded": "Компонент {platform} не загружен. Добавьте в YAML-конфигурацию 'default_config:' или '{platform}:'.",
|
||||
"platform_not_loaded": "Интеграция {platform} не загружена. Добавьте в YAML-конфигурацию 'default_config:' или '{platform}:'.",
|
||||
"required_error_msg": "Обязательное поле",
|
||||
"yaml_not_editable": "Настройки этого объекта нельзя изменить из пользовательского интерфейса. Настраиваться из пользовательского интерфейса могут только те объекты, которые были созданы в нём."
|
||||
},
|
||||
|
@ -622,7 +622,9 @@
|
||||
"settings": "Nastavenia"
|
||||
},
|
||||
"generic": {
|
||||
"default_confirmation_title": "Ste si istý?"
|
||||
"cancel": "Zrušiť",
|
||||
"default_confirmation_title": "Ste si istý?",
|
||||
"ok": "OK"
|
||||
},
|
||||
"more_info_control": {
|
||||
"person": {
|
||||
@ -718,6 +720,9 @@
|
||||
"areas": {
|
||||
"caption": "Register oblastí",
|
||||
"create_area": "VYTVORIŤ OBLASŤ",
|
||||
"delete": {
|
||||
"confirmation_title": "Naozaj chcete odstrániť túto oblasť?"
|
||||
},
|
||||
"description": "Prehľad všetkých oblastí vo vašej domácnosti.",
|
||||
"editor": {
|
||||
"create": "VYTVORIŤ",
|
||||
@ -1004,12 +1009,15 @@
|
||||
"thank_you_note": "Ďakujeme, že ste sa stali súčasťou Home Assistant Cloudu. Vďaka ľuďom, ako ste vy, sme schopní urobiť skvelý zážitok z automatizácie domácnosti pre každého. Ďakujeme!",
|
||||
"webhooks": {
|
||||
"disable_hook_error_msg": "Nepodarilo sa deaktivovať webhook:",
|
||||
"info": "Čokoľvek, čo je nakonfigurované na spúšťanie webhookom, môže dostať verejne prístupnú adresu URL, ktorá vám umožní odosielať údaje späť Home Assistant odkiaľkoľvek bez toho, aby ste svoju inštanciu vystavili na internete.",
|
||||
"link_learn_more": "Prečítajte si viac informácií o vytváraní automatizácií na báze Webhook.",
|
||||
"loading": "Načítava sa ...",
|
||||
"manage": "Spravovať",
|
||||
"no_hooks_yet": "Zdá sa, že ešte nemáte žiadne webhooky. Začnite konfiguráciou",
|
||||
"no_hooks_yet_link_automation": "automatizácia webhookov",
|
||||
"no_hooks_yet_link_integration": "integrácia založená na webhook",
|
||||
"no_hooks_yet2": "alebo vytvorením "
|
||||
"no_hooks_yet2": "alebo vytvorením ",
|
||||
"title": "Webhooky"
|
||||
}
|
||||
},
|
||||
"alexa": {
|
||||
@ -1027,7 +1035,10 @@
|
||||
"close": "Zavrieť",
|
||||
"confirm_disable": "Naozaj chcete zakázať tento webhook?",
|
||||
"copied_to_clipboard": "Skopírované do schránky",
|
||||
"info_disable_webhook": "Ak už nechcete používať tento webhook, môžete",
|
||||
"link_disable_webhook": "zakázať to",
|
||||
"managed_by_integration": "Tento webhook je riadený integráciou a nemožno ho zakázať.",
|
||||
"view_documentation": "Pozrieť dokumentáciu",
|
||||
"webhook_for": "Webhook pre {name}"
|
||||
},
|
||||
"forgot_password": {
|
||||
@ -1055,6 +1066,7 @@
|
||||
"register": {
|
||||
"feature_amazon_alexa": "Integrácia s Amazon Alexa",
|
||||
"feature_google_home": "Integrácia s Google Assistant",
|
||||
"feature_webhook_apps": "Jednoduchá integrácia s webovými aplikáciami, ako napríklad OwnTracks",
|
||||
"password": "Heslo",
|
||||
"resend_confirm_email": "Znova odoslať potvrdzovací e-mail",
|
||||
"title": "Registrovať účet"
|
||||
@ -1206,6 +1218,9 @@
|
||||
"confirm_text": "Entity je možné odstrániť, iba ak ich integrácia už neposkytuje."
|
||||
},
|
||||
"show_disabled": "Zobraziť zakázané entity",
|
||||
"status": {
|
||||
"ok": "Ok"
|
||||
},
|
||||
"unavailable": "(nedostupné)"
|
||||
}
|
||||
},
|
||||
@ -1266,6 +1281,7 @@
|
||||
"introduction": "Tu je možné konfigurovať vaše komponenty a Home Assistant. Aktuálne sa z používateľského rozhrania nedá konfigurovať všetko, ale pracujeme na tom.",
|
||||
"lovelace": {
|
||||
"dashboards": {
|
||||
"confirm_delete": "Naozaj chcete odstrániť tento dashboard?",
|
||||
"detail": {
|
||||
"delete": "Vymazať",
|
||||
"update": "Aktualizovať"
|
||||
@ -1302,6 +1318,7 @@
|
||||
"update": "Aktualizovať"
|
||||
},
|
||||
"introduction": "Tu môžete definovať každú osobu, ktorá vás zaujíma v Home Assistant.",
|
||||
"no_persons_created_yet": "Zdá sa, že ste ešte nevytvorili žiadne osoby.",
|
||||
"note_about_persons_configured_in_yaml": "Poznámka: osoby nakonfigurované prostredníctvom configuration.yaml nie je možné upravovať pomocou používateľského rozhrania."
|
||||
},
|
||||
"scene": {
|
||||
@ -1655,6 +1672,7 @@
|
||||
"showing_entries": "Zobrazujú sa záznamy pre"
|
||||
},
|
||||
"logbook": {
|
||||
"entries_not_found": "Nenašli sa žiadne záznamy v denníku.",
|
||||
"period": "Obdobie",
|
||||
"showing_entries": "Zobrazujú sa záznamy za obdobie"
|
||||
},
|
||||
@ -1679,6 +1697,11 @@
|
||||
"toggle": "Prepnúť {name}",
|
||||
"url": "Otvoriť okno na {url_path}"
|
||||
},
|
||||
"safe-mode": {
|
||||
"description": "Pri načítaní vašej konfigurácie sa Home Assistant dostal do problémov a teraz beží v núdzovom režime. Prezrite si denník chýb a zistite, čo sa stalo.",
|
||||
"header": "Núdzový režim je aktivovaný",
|
||||
"show_errors": "Zobraziť chyby"
|
||||
},
|
||||
"shopping-list": {
|
||||
"add_item": "Pridať položku",
|
||||
"checked_items": "Označené položky",
|
||||
@ -1839,6 +1862,7 @@
|
||||
},
|
||||
"save_config": {
|
||||
"cancel": "Zrušiť",
|
||||
"close": "Zavrieť",
|
||||
"header": "Prevziať kontrolu rozhrania Lovelace",
|
||||
"para": "Štandardne bude Home Assistant udržiavať vaše používateľské rozhranie a aktualizovať ho, keď budú k dispozícii nové entity alebo komponenty rozhrania Lovelace. Ak prevezmete kontrolu, už za vás nebudeme automaticky robiť zmeny.",
|
||||
"para_sure": "Skutočne chcete prevziať kontrolu vášho používateľského rozhrania?",
|
||||
@ -1863,7 +1887,9 @@
|
||||
},
|
||||
"reload_lovelace": "Znovu načítať Lovelace",
|
||||
"views": {
|
||||
"confirm_delete": "Naozaj chcete odstrániť toto zobrazenie?"
|
||||
"confirm_delete": "Naozaj chcete odstrániť toto zobrazenie?",
|
||||
"confirm_delete_existing_cards_text": "Naozaj chcete odstrániť zobrazenie '{name}'? Toto zobrazenie obsahuje {number} kariet, ktoré budú odstránené. Túto akciu nie je možné vrátiť späť.",
|
||||
"confirm_delete_text": "Naozaj chcete odstrániť zobrazenie '{name}'?"
|
||||
},
|
||||
"warning": {
|
||||
"entity_non_numeric": "Entita je nečíselná: {entity}",
|
||||
|
@ -651,8 +651,12 @@
|
||||
"name": "名称"
|
||||
},
|
||||
"input_datetime": {
|
||||
"date": "日期",
|
||||
"datetime": "日期和时间",
|
||||
"has_date": "日期",
|
||||
"has_time": "时间"
|
||||
"has_time": "时间",
|
||||
"mode": "要输入哪种形式",
|
||||
"time": "时间"
|
||||
},
|
||||
"input_number": {
|
||||
"box": "输入框",
|
||||
@ -806,6 +810,10 @@
|
||||
"areas": {
|
||||
"caption": "区域注册表",
|
||||
"create_area": "创建区域",
|
||||
"delete": {
|
||||
"confirmation_text": "此区域中的所有设备都将取消分配。",
|
||||
"confirmation_title": "您确定要删除此区域吗?"
|
||||
},
|
||||
"description": "您家中所有区域的概览。",
|
||||
"editor": {
|
||||
"create": "创建",
|
||||
|
@ -651,8 +651,12 @@
|
||||
"name": "名稱"
|
||||
},
|
||||
"input_datetime": {
|
||||
"date": "日期",
|
||||
"datetime": "日期與時間",
|
||||
"has_date": "日期",
|
||||
"has_time": "時間"
|
||||
"has_time": "時間",
|
||||
"mode": "所要輸入的內容",
|
||||
"time": "時間"
|
||||
},
|
||||
"input_number": {
|
||||
"box": "輸入欄位",
|
||||
@ -679,7 +683,7 @@
|
||||
},
|
||||
"not_editable": "不可編輯",
|
||||
"not_editable_text": "由於 configuration.yaml 內已定義,物件編輯功能已關閉。",
|
||||
"platform_not_loaded": "{platform} 元件未載入。請於設定檔進行添加、新增「default_config:」或「{platform}:」。",
|
||||
"platform_not_loaded": "{platform} 元件未載入。請於設定檔進行添加、新增 'default_config:' 或 '{platform}:'。",
|
||||
"required_error_msg": "必填欄位",
|
||||
"yaml_not_editable": "此物件的設定無法藉由 UI 編輯、僅有透過 UI 設定的物件可於 UI 進行設定。"
|
||||
},
|
||||
|
Loading…
x
Reference in New Issue
Block a user