mirror of
https://github.com/home-assistant/frontend.git
synced 2026-01-14 11:17:26 +00:00
Compare commits
1 Commits
clock-date
...
fix-issue-
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b24ef59718 |
@@ -216,7 +216,7 @@
|
||||
"ts-lit-plugin": "2.0.2",
|
||||
"typescript": "5.9.3",
|
||||
"typescript-eslint": "8.52.0",
|
||||
"vite-tsconfig-paths": "6.0.4",
|
||||
"vite-tsconfig-paths": "6.0.3",
|
||||
"vitest": "4.0.16",
|
||||
"webpack-stats-plugin": "1.1.3",
|
||||
"webpackbar": "7.0.0",
|
||||
|
||||
@@ -1364,9 +1364,6 @@ export class HaDataTable extends LitElement {
|
||||
.mdc-data-table__header-cell > * {
|
||||
transition: var(--float-start) 0.2s ease;
|
||||
}
|
||||
.mdc-data-table__header-cell--numeric > span {
|
||||
transition: none;
|
||||
}
|
||||
.mdc-data-table__header-cell ha-svg-icon {
|
||||
top: -3px;
|
||||
position: absolute;
|
||||
|
||||
@@ -14,6 +14,7 @@ import "./ha-icon-button";
|
||||
import "./ha-label";
|
||||
import "./ha-list";
|
||||
import "./ha-list-item";
|
||||
import "./search-input-outlined";
|
||||
import "./voice-assistant-brand-icon";
|
||||
import { voiceAssistants } from "../data/expose";
|
||||
import "../panels/config/voice-assistants/expose/expose-assistant-icon";
|
||||
|
||||
@@ -52,6 +52,8 @@ import "./ha-spinner";
|
||||
import "./ha-svg-icon";
|
||||
import "./user/ha-user-badge";
|
||||
|
||||
const SUPPORT_SCROLL_IF_NEEDED = "scrollIntoViewIfNeeded" in document.body;
|
||||
|
||||
const SORT_VALUE_URL_PATHS = {
|
||||
energy: 1,
|
||||
map: 2,
|
||||
@@ -342,6 +344,17 @@ class HaSidebar extends SubscribeMixin(LitElement) {
|
||||
}
|
||||
|
||||
this._calculateCounts();
|
||||
|
||||
if (!SUPPORT_SCROLL_IF_NEEDED) {
|
||||
return;
|
||||
}
|
||||
if (oldHass?.panelUrl !== this.hass.panelUrl) {
|
||||
const selectedEl = this.shadowRoot!.querySelector(".selected");
|
||||
if (selectedEl) {
|
||||
// @ts-ignore
|
||||
selectedEl.scrollIntoViewIfNeeded();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private _calculateCounts = throttle(() => {
|
||||
|
||||
@@ -57,7 +57,6 @@ import "../../../components/ha-filter-devices";
|
||||
import "../../../components/ha-filter-entities";
|
||||
import "../../../components/ha-filter-floor-areas";
|
||||
import "../../../components/ha-filter-labels";
|
||||
import "../../../components/ha-filter-voice-assistants";
|
||||
import "../../../components/ha-icon-button";
|
||||
import "../../../components/ha-md-divider";
|
||||
import "../../../components/ha-md-menu";
|
||||
@@ -661,15 +660,6 @@ class HaAutomationPicker extends SubscribeMixin(LitElement) {
|
||||
.narrow=${this.narrow}
|
||||
@expanded-changed=${this._filterExpanded}
|
||||
></ha-filter-categories>
|
||||
<ha-filter-voice-assistants
|
||||
.hass=${this.hass}
|
||||
.value=${this._filters["ha-filter-voice-assistants"]?.value}
|
||||
@data-table-filter-changed=${this._filterChanged}
|
||||
slot="filter-pane"
|
||||
.expanded=${this._expandedFilter === "ha-filter-voice-assistants"}
|
||||
.narrow=${this.narrow}
|
||||
@expanded-changed=${this._filterExpanded}
|
||||
></ha-filter-voice-assistants>
|
||||
<ha-filter-blueprints
|
||||
.hass=${this.hass}
|
||||
.type=${"automation"}
|
||||
@@ -1040,7 +1030,8 @@ class HaAutomationPicker extends SubscribeMixin(LitElement) {
|
||||
? // @ts-ignore
|
||||
items.intersection(categoryItems)
|
||||
: new Set([...items].filter((x) => categoryItems!.has(x)));
|
||||
} else if (
|
||||
}
|
||||
if (
|
||||
key === "ha-filter-labels" &&
|
||||
Array.isArray(filter.value) &&
|
||||
filter.value.length
|
||||
@@ -1062,29 +1053,6 @@ class HaAutomationPicker extends SubscribeMixin(LitElement) {
|
||||
? // @ts-ignore
|
||||
items.intersection(labelItems)
|
||||
: new Set([...items].filter((x) => labelItems!.has(x)));
|
||||
} else if (
|
||||
key === "ha-filter-voice-assistants" &&
|
||||
Array.isArray(filter.value) &&
|
||||
filter.value.length
|
||||
) {
|
||||
const assistItems = new Set<string>();
|
||||
this.automations
|
||||
.filter((automation) =>
|
||||
getEntityVoiceAssistantsIds(
|
||||
this._entityReg,
|
||||
automation.entity_id
|
||||
).some((va) => (filter.value as string[]).includes(va))
|
||||
)
|
||||
.forEach((automation) => assistItems.add(automation.entity_id));
|
||||
if (!items) {
|
||||
items = assistItems;
|
||||
continue;
|
||||
}
|
||||
items =
|
||||
"intersection" in items
|
||||
? // @ts-ignore
|
||||
items.intersection(assistItems)
|
||||
: new Set([...items].filter((x) => assistItems!.has(x)));
|
||||
}
|
||||
}
|
||||
this._filteredAutomations = items ? [...items] : undefined;
|
||||
|
||||
@@ -206,8 +206,8 @@ class HaBlueprintOverview extends LitElement {
|
||||
sortable: true,
|
||||
valueColumn: "usageCount",
|
||||
type: "numeric",
|
||||
minWidth: "90px",
|
||||
maxWidth: "90px",
|
||||
minWidth: "100px",
|
||||
maxWidth: "120px",
|
||||
template: (blueprint) => {
|
||||
const count = blueprint.usageCount ?? 0;
|
||||
return html`
|
||||
|
||||
@@ -1,16 +1,19 @@
|
||||
import {
|
||||
mdiDotsVertical,
|
||||
mdiLocationEnter,
|
||||
mdiLocationExit,
|
||||
mdiRefresh,
|
||||
} from "@mdi/js";
|
||||
import type { RequestSelectedDetail } from "@material/mwc-list/mwc-list-item";
|
||||
import { mdiDotsVertical, mdiRefresh } from "@mdi/js";
|
||||
import type { HassEntities } from "home-assistant-js-websocket";
|
||||
import type { TemplateResult } from "lit";
|
||||
import { LitElement, css, html, nothing } from "lit";
|
||||
import { customElement, property, state } from "lit/decorators";
|
||||
import memoizeOne from "memoize-one";
|
||||
import { isComponentLoaded } from "../../../common/config/is_component_loaded";
|
||||
import { shouldHandleRequestSelectedEvent } from "../../../common/mwc/handle-request-selected-event";
|
||||
import "../../../components/ha-alert";
|
||||
import "../../../components/ha-bar";
|
||||
import "../../../components/ha-button-menu";
|
||||
import "../../../components/ha-card";
|
||||
import "../../../components/ha-check-list-item";
|
||||
import "../../../components/ha-list-item";
|
||||
import "../../../components/ha-metric";
|
||||
import { extractApiErrorMessage } from "../../../data/hassio/common";
|
||||
import type {
|
||||
HassioSupervisorInfo,
|
||||
@@ -30,9 +33,6 @@ import "../../../layouts/hass-subpage";
|
||||
import type { HomeAssistant } from "../../../types";
|
||||
import "../dashboard/ha-config-updates";
|
||||
import { showJoinBetaDialog } from "./updates/show-dialog-join-beta";
|
||||
import "../../../components/ha-dropdown";
|
||||
import "../../../components/ha-dropdown-item";
|
||||
import "@home-assistant/webawesome/dist/components/divider/divider";
|
||||
|
||||
@customElement("ha-config-section-updates")
|
||||
class HaConfigSectionUpdates extends LitElement {
|
||||
@@ -77,45 +77,35 @@ class HaConfigSectionUpdates extends LitElement {
|
||||
.path=${mdiRefresh}
|
||||
@click=${this._checkUpdates}
|
||||
></ha-icon-button>
|
||||
<ha-dropdown @wa-select=${this._handleOverflowAction}>
|
||||
<ha-button-menu multi>
|
||||
<ha-icon-button
|
||||
slot="trigger"
|
||||
.label=${this.hass.localize("ui.common.menu")}
|
||||
.path=${mdiDotsVertical}
|
||||
></ha-icon-button>
|
||||
|
||||
<ha-dropdown-item
|
||||
type="checkbox"
|
||||
.checked=${this._showSkipped}
|
||||
value="show_skipped"
|
||||
<ha-check-list-item
|
||||
left
|
||||
@request-selected=${this._toggleSkipped}
|
||||
.selected=${this._showSkipped}
|
||||
>
|
||||
${this.hass.localize("ui.panel.config.updates.show_skipped")}
|
||||
</ha-dropdown-item>
|
||||
</ha-check-list-item>
|
||||
${this._supervisorInfo
|
||||
? html`
|
||||
<wa-divider></wa-divider>
|
||||
<ha-dropdown-item
|
||||
value="toggle_beta"
|
||||
<li divider role="separator"></li>
|
||||
<ha-list-item
|
||||
@request-selected=${this._toggleBeta}
|
||||
.disabled=${this._supervisorInfo.channel === "dev"}
|
||||
>
|
||||
<ha-svg-icon
|
||||
.path=${this._supervisorInfo.channel === "stable"
|
||||
? mdiLocationEnter
|
||||
: mdiLocationExit}
|
||||
slot="icon"
|
||||
></ha-svg-icon>
|
||||
${this.hass.localize(
|
||||
`ui.panel.config.updates.${this._supervisorInfo.channel === "stable" ? "join" : "leave"}_beta`
|
||||
)}
|
||||
${this._supervisorInfo.channel === "stable"
|
||||
? this.hass.localize("ui.panel.config.updates.join_beta")
|
||||
: this.hass.localize(
|
||||
"ui.panel.config.updates.leave_beta"
|
||||
)}
|
||||
</ha-dropdown-item>
|
||||
</ha-list-item>
|
||||
`
|
||||
: nothing}
|
||||
</ha-dropdown>
|
||||
</ha-button-menu>
|
||||
</div>
|
||||
<div class="content">
|
||||
${canInstallUpdates.length
|
||||
@@ -166,19 +156,27 @@ class HaConfigSectionUpdates extends LitElement {
|
||||
this._supervisorInfo = await fetchHassioSupervisorInfo(this.hass);
|
||||
}
|
||||
|
||||
private _handleOverflowAction(
|
||||
ev: CustomEvent<{ item: { value: string } }>
|
||||
): void {
|
||||
if (ev.detail.item.value === "toggle_beta") {
|
||||
if (this._supervisorInfo!.channel === "stable") {
|
||||
showJoinBetaDialog(this, {
|
||||
join: () => this._setChannel("beta"),
|
||||
});
|
||||
} else {
|
||||
this._setChannel("stable");
|
||||
}
|
||||
} else if (ev.detail.item.value === "show_skipped") {
|
||||
this._showSkipped = !this._showSkipped;
|
||||
private _toggleSkipped(ev: CustomEvent<RequestSelectedDetail>): void {
|
||||
if (ev.detail.source !== "property") {
|
||||
return;
|
||||
}
|
||||
|
||||
this._showSkipped = !this._showSkipped;
|
||||
}
|
||||
|
||||
private async _toggleBeta(
|
||||
ev: CustomEvent<RequestSelectedDetail>
|
||||
): Promise<void> {
|
||||
if (!shouldHandleRequestSelectedEvent(ev)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this._supervisorInfo!.channel === "stable") {
|
||||
showJoinBetaDialog(this, {
|
||||
join: async () => this._setChannel("beta"),
|
||||
});
|
||||
} else {
|
||||
this._setChannel("stable");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -51,7 +51,6 @@ import "../../../components/ha-filter-devices";
|
||||
import "../../../components/ha-filter-entities";
|
||||
import "../../../components/ha-filter-floor-areas";
|
||||
import "../../../components/ha-filter-labels";
|
||||
import "../../../components/ha-filter-voice-assistants";
|
||||
import "../../../components/ha-icon";
|
||||
import "../../../components/ha-icon-overflow-menu";
|
||||
import "../../../components/ha-md-divider";
|
||||
@@ -208,7 +207,7 @@ export class HaConfigHelpers extends SubscribeMixin(LitElement) {
|
||||
})
|
||||
private _activeHiddenColumns?: string[];
|
||||
|
||||
@state() private _helperEntities: HassEntity[] = [];
|
||||
@state() private _stateItems: HassEntity[] = [];
|
||||
|
||||
@state() private _disabledEntityEntries?: EntityRegistryEntry[];
|
||||
|
||||
@@ -250,7 +249,7 @@ export class HaConfigHelpers extends SubscribeMixin(LitElement) {
|
||||
@consume({ context: fullEntitiesContext, subscribe: true })
|
||||
_entityReg!: EntityRegistryEntry[];
|
||||
|
||||
@state() private _filteredHelperEntityIds?: string[] | null;
|
||||
@state() private _filteredStateItems?: string[] | null;
|
||||
|
||||
private _sizeController = new ResizeController(this, {
|
||||
callback: (entries) => entries[0]?.contentRect.width,
|
||||
@@ -641,7 +640,7 @@ export class HaConfigHelpers extends SubscribeMixin(LitElement) {
|
||||
protected render(): TemplateResult {
|
||||
if (
|
||||
!this.hass ||
|
||||
this._helperEntities === undefined ||
|
||||
this._stateItems === undefined ||
|
||||
this._entityEntries === undefined ||
|
||||
this._configEntries === undefined
|
||||
) {
|
||||
@@ -716,14 +715,14 @@ export class HaConfigHelpers extends SubscribeMixin(LitElement) {
|
||||
(!this._sizeController.value && this.hass.dockedSidebar === "docked");
|
||||
const helpers = this._getItems(
|
||||
this.hass.localize,
|
||||
this._helperEntities,
|
||||
this._stateItems,
|
||||
this._disabledEntityEntries || [],
|
||||
this._entityEntries,
|
||||
this._configEntries,
|
||||
this._entityReg,
|
||||
this._categories,
|
||||
this._labels,
|
||||
this._filteredHelperEntityIds
|
||||
this._filteredStateItems
|
||||
);
|
||||
return html`
|
||||
<hass-tabs-subpage-data-table
|
||||
@@ -810,15 +809,6 @@ export class HaConfigHelpers extends SubscribeMixin(LitElement) {
|
||||
.narrow=${this.narrow}
|
||||
@expanded-changed=${this._filterExpanded}
|
||||
></ha-filter-categories>
|
||||
<ha-filter-voice-assistants
|
||||
.hass=${this.hass}
|
||||
.value=${this._filters["ha-filter-voice-assistants"]}
|
||||
@data-table-filter-changed=${this._filterChanged}
|
||||
slot="filter-pane"
|
||||
.expanded=${this._expandedFilter === "ha-filter-voice-assistants"}
|
||||
.narrow=${this.narrow}
|
||||
@expanded-changed=${this._filterExpanded}
|
||||
></ha-filter-voice-assistants>
|
||||
|
||||
${!this.narrow
|
||||
? html`<ha-md-button-menu slot="selection-bar">
|
||||
@@ -981,7 +971,7 @@ export class HaConfigHelpers extends SubscribeMixin(LitElement) {
|
||||
filter.length
|
||||
) {
|
||||
const labelItems = new Set<string>();
|
||||
this._helperEntities
|
||||
this._stateItems
|
||||
.filter((stateItem) =>
|
||||
entityRegistryByEntityId(this._entityReg)[
|
||||
stateItem.entity_id
|
||||
@@ -1000,13 +990,14 @@ export class HaConfigHelpers extends SubscribeMixin(LitElement) {
|
||||
? // @ts-ignore
|
||||
items.intersection(labelItems)
|
||||
: new Set([...items].filter((x) => labelItems!.has(x)));
|
||||
} else if (
|
||||
}
|
||||
if (
|
||||
key === "ha-filter-categories" &&
|
||||
Array.isArray(filter) &&
|
||||
filter.length
|
||||
) {
|
||||
const categoryItems = new Set<string>();
|
||||
this._helperEntities
|
||||
this._stateItems
|
||||
.filter(
|
||||
(stateItem) =>
|
||||
filter[0] ===
|
||||
@@ -1026,39 +1017,10 @@ export class HaConfigHelpers extends SubscribeMixin(LitElement) {
|
||||
? // @ts-ignore
|
||||
items.intersection(categoryItems)
|
||||
: new Set([...items].filter((x) => categoryItems!.has(x)));
|
||||
} else if (
|
||||
key === "ha-filter-voice-assistants" &&
|
||||
Array.isArray(filter) &&
|
||||
filter.length
|
||||
) {
|
||||
const assistItems = new Set<string>();
|
||||
this._helperEntities
|
||||
.filter((stateItem) =>
|
||||
getEntityVoiceAssistantsIds(
|
||||
this._entityReg,
|
||||
stateItem.entity_id
|
||||
).some((va) => (filter as string[]).includes(va))
|
||||
)
|
||||
.forEach((stateItem) => assistItems.add(stateItem.entity_id));
|
||||
(this._disabledEntityEntries || [])
|
||||
.filter((entry) =>
|
||||
getEntityVoiceAssistantsIds(this._entityReg, entry.entity_id).some(
|
||||
(va) => (filter as string[]).includes(va)
|
||||
)
|
||||
)
|
||||
.forEach((entry) => assistItems.add(entry.entity_id));
|
||||
if (!items) {
|
||||
items = assistItems;
|
||||
continue;
|
||||
}
|
||||
items =
|
||||
"intersection" in items
|
||||
? // @ts-ignore
|
||||
items.intersection(assistItems)
|
||||
: new Set([...items].filter((x) => assistItems!.has(x)));
|
||||
}
|
||||
}
|
||||
this._filteredHelperEntityIds = items ? [...items] : undefined;
|
||||
|
||||
this._filteredStateItems = items ? [...items] : undefined;
|
||||
}
|
||||
|
||||
public connectedCallback() {
|
||||
@@ -1091,7 +1053,6 @@ export class HaConfigHelpers extends SubscribeMixin(LitElement) {
|
||||
const device = this._searchParms.get("device");
|
||||
const label = this._searchParms.get("label");
|
||||
const category = this._searchParms.get("category");
|
||||
const voiceAssistant = this._searchParms.get("voice_assistant");
|
||||
|
||||
if (!category && !label && !device) {
|
||||
return;
|
||||
@@ -1103,7 +1064,6 @@ export class HaConfigHelpers extends SubscribeMixin(LitElement) {
|
||||
"ha-filter-devices": device ? [device] : [],
|
||||
"ha-filter-labels": label ? [label] : [],
|
||||
"ha-filter-categories": category ? [category] : [],
|
||||
"ha-filter-voice-assistants": voiceAssistant ? [voiceAssistant] : [],
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1343,7 +1303,7 @@ ${rejected
|
||||
}
|
||||
|
||||
let changed =
|
||||
!this._helperEntities ||
|
||||
!this._stateItems ||
|
||||
changedProps.has("_entityEntries") ||
|
||||
changedProps.has("_configEntries") ||
|
||||
changedProps.has("_entitySource");
|
||||
@@ -1358,17 +1318,17 @@ ${rejected
|
||||
|
||||
const entityIds = Object.keys(this._entitySource);
|
||||
|
||||
const newHelpers = Object.values(this.hass!.states).filter(
|
||||
const newStates = Object.values(this.hass!.states).filter(
|
||||
(entity) =>
|
||||
entityIds.includes(entity.entity_id) ||
|
||||
isHelperDomain(computeStateDomain(entity))
|
||||
);
|
||||
|
||||
if (
|
||||
this._helperEntities.length !== newHelpers.length ||
|
||||
!this._helperEntities.every((val, idx) => newHelpers[idx] === val)
|
||||
this._stateItems.length !== newStates.length ||
|
||||
!this._stateItems.every((val, idx) => newStates[idx] === val)
|
||||
) {
|
||||
this._helperEntities = newHelpers;
|
||||
this._stateItems = newStates;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -51,7 +51,6 @@ import "../../../components/ha-filter-devices";
|
||||
import "../../../components/ha-filter-entities";
|
||||
import "../../../components/ha-filter-floor-areas";
|
||||
import "../../../components/ha-filter-labels";
|
||||
import "../../../components/ha-filter-voice-assistants";
|
||||
import "../../../components/ha-icon-button";
|
||||
import "../../../components/ha-icon-overflow-menu";
|
||||
import "../../../components/ha-md-divider";
|
||||
@@ -680,15 +679,6 @@ class HaSceneDashboard extends SubscribeMixin(LitElement) {
|
||||
.narrow=${this.narrow}
|
||||
@expanded-changed=${this._filterExpanded}
|
||||
></ha-filter-categories>
|
||||
<ha-filter-voice-assistants
|
||||
.hass=${this.hass}
|
||||
.value=${this._filters["ha-filter-voice-assistants"]?.value}
|
||||
@data-table-filter-changed=${this._filterChanged}
|
||||
slot="filter-pane"
|
||||
.expanded=${this._expandedFilter === "ha-filter-voice-assistants"}
|
||||
.narrow=${this.narrow}
|
||||
@expanded-changed=${this._filterExpanded}
|
||||
></ha-filter-voice-assistants>
|
||||
|
||||
${!this.narrow
|
||||
? html`<ha-md-button-menu slot="selection-bar">
|
||||
@@ -924,7 +914,8 @@ class HaSceneDashboard extends SubscribeMixin(LitElement) {
|
||||
? // @ts-ignore
|
||||
items.intersection(categoryItems)
|
||||
: new Set([...items].filter((x) => categoryItems!.has(x)));
|
||||
} else if (
|
||||
}
|
||||
if (
|
||||
key === "ha-filter-labels" &&
|
||||
Array.isArray(filter.value) &&
|
||||
filter.value.length
|
||||
@@ -946,28 +937,6 @@ class HaSceneDashboard extends SubscribeMixin(LitElement) {
|
||||
? // @ts-ignore
|
||||
items.intersection(labelItems)
|
||||
: new Set([...items].filter((x) => labelItems!.has(x)));
|
||||
} else if (
|
||||
key === "ha-filter-voice-assistants" &&
|
||||
Array.isArray(filter.value) &&
|
||||
filter.value.length
|
||||
) {
|
||||
const assistItems = new Set<string>();
|
||||
this.scenes
|
||||
.filter((scene) =>
|
||||
getEntityVoiceAssistantsIds(this._entityReg, scene.entity_id).some(
|
||||
(va) => (filter.value as string[]).includes(va)
|
||||
)
|
||||
)
|
||||
.forEach((scene) => assistItems.add(scene.entity_id));
|
||||
if (!items) {
|
||||
items = assistItems;
|
||||
continue;
|
||||
}
|
||||
items =
|
||||
"intersection" in items
|
||||
? // @ts-ignore
|
||||
items.intersection(assistItems)
|
||||
: new Set([...items].filter((x) => assistItems!.has(x)));
|
||||
}
|
||||
}
|
||||
this._filteredScenes = items ? [...items] : undefined;
|
||||
@@ -1189,13 +1158,19 @@ ${rejected
|
||||
private async _duplicate(scene) {
|
||||
if (scene.attributes.id) {
|
||||
const config = await getSceneConfig(this.hass, scene.attributes.id);
|
||||
showSceneEditor({
|
||||
...config,
|
||||
id: undefined,
|
||||
name: `${config?.name} (${this.hass.localize(
|
||||
"ui.panel.config.scene.picker.duplicate"
|
||||
)})`,
|
||||
});
|
||||
const entityRegEntry = this._entityReg.find(
|
||||
(reg) => reg.entity_id === scene.entity_id
|
||||
);
|
||||
showSceneEditor(
|
||||
{
|
||||
...config,
|
||||
id: undefined,
|
||||
name: `${config?.name} (${this.hass.localize(
|
||||
"ui.panel.config.scene.picker.duplicate"
|
||||
)})`,
|
||||
},
|
||||
entityRegEntry?.area_id || undefined
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -53,7 +53,6 @@ import "../../../components/ha-filter-devices";
|
||||
import "../../../components/ha-filter-entities";
|
||||
import "../../../components/ha-filter-floor-areas";
|
||||
import "../../../components/ha-filter-labels";
|
||||
import "../../../components/ha-filter-voice-assistants";
|
||||
import "../../../components/ha-icon-button";
|
||||
import "../../../components/ha-icon-overflow-menu";
|
||||
import "../../../components/ha-md-divider";
|
||||
@@ -662,15 +661,6 @@ class HaScriptPicker extends SubscribeMixin(LitElement) {
|
||||
.narrow=${this.narrow}
|
||||
@expanded-changed=${this._filterExpanded}
|
||||
></ha-filter-categories>
|
||||
<ha-filter-voice-assistants
|
||||
.hass=${this.hass}
|
||||
.value=${this._filters["ha-filter-voice-assistants"]?.value}
|
||||
@data-table-filter-changed=${this._filterChanged}
|
||||
slot="filter-pane"
|
||||
.expanded=${this._expandedFilter === "ha-filter-voice-assistants"}
|
||||
.narrow=${this.narrow}
|
||||
@expanded-changed=${this._filterExpanded}
|
||||
></ha-filter-voice-assistants>
|
||||
<ha-filter-blueprints
|
||||
.hass=${this.hass}
|
||||
.type=${"script"}
|
||||
@@ -929,7 +919,8 @@ class HaScriptPicker extends SubscribeMixin(LitElement) {
|
||||
? // @ts-ignore
|
||||
items.intersection(categoryItems)
|
||||
: new Set([...items].filter((x) => categoryItems!.has(x)));
|
||||
} else if (
|
||||
}
|
||||
if (
|
||||
key === "ha-filter-labels" &&
|
||||
Array.isArray(filter.value) &&
|
||||
filter.value.length
|
||||
@@ -951,28 +942,6 @@ class HaScriptPicker extends SubscribeMixin(LitElement) {
|
||||
? // @ts-ignore
|
||||
items.intersection(labelItems)
|
||||
: new Set([...items].filter((x) => labelItems!.has(x)));
|
||||
} else if (
|
||||
key === "ha-filter-voice-assistants" &&
|
||||
Array.isArray(filter.value) &&
|
||||
filter.value.length
|
||||
) {
|
||||
const assistItems = new Set<string>();
|
||||
this.scripts
|
||||
.filter((script) =>
|
||||
getEntityVoiceAssistantsIds(this._entityReg, script.entity_id).some(
|
||||
(va) => (filter.value as string[]).includes(va)
|
||||
)
|
||||
)
|
||||
.forEach((script) => assistItems.add(script.entity_id));
|
||||
if (!items) {
|
||||
items = assistItems;
|
||||
continue;
|
||||
}
|
||||
items =
|
||||
"intersection" in items
|
||||
? // @ts-ignore
|
||||
items.intersection(assistItems)
|
||||
: new Set([...items].filter((x) => assistItems!.has(x)));
|
||||
}
|
||||
}
|
||||
this._filteredScripts = items ? [...items] : undefined;
|
||||
|
||||
@@ -2,8 +2,6 @@ import type { PropertyValues } from "lit";
|
||||
import { css, html, LitElement, nothing } from "lit";
|
||||
import { customElement, property, state } from "lit/decorators";
|
||||
import { classMap } from "lit/directives/class-map";
|
||||
import { styleMap } from "lit/directives/style-map";
|
||||
import memoizeOne from "memoize-one";
|
||||
import { resolveTimeZone } from "../../../../common/datetime/resolve-time-zone";
|
||||
import type { HomeAssistant } from "../../../../types";
|
||||
import type { ClockCardConfig } from "../types";
|
||||
@@ -28,11 +26,6 @@ function romanize12HourClock(num: number) {
|
||||
return numerals[num];
|
||||
}
|
||||
|
||||
const INTERVAL = 1000;
|
||||
const QUARTER_TICKS = Array.from({ length: 4 }, (_, i) => i);
|
||||
const HOUR_TICKS = Array.from({ length: 12 }, (_, i) => i);
|
||||
const MINUTE_TICKS = Array.from({ length: 60 }, (_, i) => i);
|
||||
|
||||
@customElement("hui-clock-card-analog")
|
||||
export class HuiClockCardAnalog extends LitElement {
|
||||
@property({ attribute: false }) public hass?: HomeAssistant;
|
||||
@@ -47,49 +40,6 @@ export class HuiClockCardAnalog extends LitElement {
|
||||
|
||||
@state() private _secondOffsetSec?: number;
|
||||
|
||||
@state() private _year = "";
|
||||
|
||||
@state() private _month = "";
|
||||
|
||||
@state() private _day = "";
|
||||
|
||||
private _tickInterval?: undefined | number;
|
||||
|
||||
private _currentDate = new Date();
|
||||
|
||||
public connectedCallback() {
|
||||
super.connectedCallback();
|
||||
document.addEventListener("visibilitychange", this._handleVisibilityChange);
|
||||
this._computeDateTime();
|
||||
if (this.config?.date && this.config.date !== "none") {
|
||||
this._startTick();
|
||||
}
|
||||
}
|
||||
|
||||
public disconnectedCallback() {
|
||||
super.disconnectedCallback();
|
||||
document.removeEventListener(
|
||||
"visibilitychange",
|
||||
this._handleVisibilityChange
|
||||
);
|
||||
this._stopTick();
|
||||
}
|
||||
|
||||
protected updated(changedProps: PropertyValues) {
|
||||
if (changedProps.has("hass")) {
|
||||
const oldHass = changedProps.get("hass") as HomeAssistant | undefined;
|
||||
if (!oldHass || oldHass.locale !== this.hass?.locale) {
|
||||
this._initDate();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private _handleVisibilityChange = () => {
|
||||
if (!document.hidden) {
|
||||
this._computeDateTime();
|
||||
}
|
||||
};
|
||||
|
||||
private _initDate() {
|
||||
if (!this.config || !this.hass) {
|
||||
return;
|
||||
@@ -101,27 +51,6 @@ export class HuiClockCardAnalog extends LitElement {
|
||||
}
|
||||
|
||||
this._dateTimeFormat = new Intl.DateTimeFormat(this.hass.locale.language, {
|
||||
...(this.config.date && this.config.date !== "none"
|
||||
? this.config.date === "day"
|
||||
? {
|
||||
day: "numeric",
|
||||
}
|
||||
: this.config.date === "day-month"
|
||||
? {
|
||||
month: "short",
|
||||
day: "numeric",
|
||||
}
|
||||
: this.config.date === "day-month-long"
|
||||
? {
|
||||
month: "long",
|
||||
day: "numeric",
|
||||
}
|
||||
: {
|
||||
year: "numeric",
|
||||
month: this.config.date === "long" ? "long" : "short",
|
||||
day: "numeric",
|
||||
}
|
||||
: {}),
|
||||
hour: "2-digit",
|
||||
minute: "2-digit",
|
||||
second: "2-digit",
|
||||
@@ -131,31 +60,42 @@ export class HuiClockCardAnalog extends LitElement {
|
||||
resolveTimeZone(locale.time_zone, this.hass.config?.time_zone),
|
||||
});
|
||||
|
||||
this._computeDateTime();
|
||||
this._computeOffsets();
|
||||
}
|
||||
|
||||
private _startTick() {
|
||||
this._tick();
|
||||
this._tickInterval = window.setInterval(() => this._tick(), INTERVAL);
|
||||
}
|
||||
|
||||
private _stopTick() {
|
||||
if (this._tickInterval) {
|
||||
clearInterval(this._tickInterval);
|
||||
this._tickInterval = undefined;
|
||||
protected updated(changedProps: PropertyValues) {
|
||||
if (changedProps.has("hass")) {
|
||||
const oldHass = changedProps.get("hass") as HomeAssistant | undefined;
|
||||
if (!oldHass || oldHass.locale !== this.hass?.locale) {
|
||||
this._initDate();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private _updateDate() {
|
||||
this._currentDate = new Date();
|
||||
public connectedCallback() {
|
||||
super.connectedCallback();
|
||||
document.addEventListener("visibilitychange", this._handleVisibilityChange);
|
||||
this._computeOffsets();
|
||||
}
|
||||
|
||||
private _computeDateTime() {
|
||||
public disconnectedCallback() {
|
||||
super.disconnectedCallback();
|
||||
document.removeEventListener(
|
||||
"visibilitychange",
|
||||
this._handleVisibilityChange
|
||||
);
|
||||
}
|
||||
|
||||
private _handleVisibilityChange = () => {
|
||||
if (!document.hidden) {
|
||||
this._computeOffsets();
|
||||
}
|
||||
};
|
||||
|
||||
private _computeOffsets() {
|
||||
if (!this._dateTimeFormat) return;
|
||||
|
||||
this._updateDate();
|
||||
|
||||
const parts = this._dateTimeFormat.formatToParts(this._currentDate);
|
||||
const parts = this._dateTimeFormat.formatToParts();
|
||||
const hourStr = parts.find((p) => p.type === "hour")?.value;
|
||||
const minuteStr = parts.find((p) => p.type === "minute")?.value;
|
||||
const secondStr = parts.find((p) => p.type === "second")?.value;
|
||||
@@ -163,7 +103,7 @@ export class HuiClockCardAnalog extends LitElement {
|
||||
const hour = hourStr ? parseInt(hourStr, 10) : 0;
|
||||
const minute = minuteStr ? parseInt(minuteStr, 10) : 0;
|
||||
const second = secondStr ? parseInt(secondStr, 10) : 0;
|
||||
const ms = this._currentDate.getMilliseconds();
|
||||
const ms = new Date().getMilliseconds();
|
||||
const secondsWithMs = second + ms / 1000;
|
||||
|
||||
const hour12 = hour % 12;
|
||||
@@ -171,38 +111,18 @@ export class HuiClockCardAnalog extends LitElement {
|
||||
this._secondOffsetSec = secondsWithMs;
|
||||
this._minuteOffsetSec = minute * 60 + secondsWithMs;
|
||||
this._hourOffsetSec = hour12 * 3600 + minute * 60 + secondsWithMs;
|
||||
|
||||
// Also update date parts if date is shown
|
||||
if (this.config?.date && this.config.date !== "none") {
|
||||
this._year = parts.find((p) => p.type === "year")?.value ?? "";
|
||||
this._month = parts.find((p) => p.type === "month")?.value ?? "";
|
||||
this._day = parts.find((p) => p.type === "day")?.value ?? "";
|
||||
}
|
||||
}
|
||||
|
||||
private _tick() {
|
||||
this._computeDateTime();
|
||||
}
|
||||
|
||||
private _computeClock = memoizeOne((config: ClockCardConfig) => {
|
||||
const faceParts = config.face_style?.split("_");
|
||||
const isLongDate =
|
||||
config.date === "day-month-long" || config.date === "long";
|
||||
|
||||
return {
|
||||
sizeClass: config.clock_size ? `size-${config.clock_size}` : "",
|
||||
isNumbers: faceParts?.includes("numbers") ?? false,
|
||||
isRoman: faceParts?.includes("roman") ?? false,
|
||||
isUpright: faceParts?.includes("upright") ?? false,
|
||||
isLongDate,
|
||||
};
|
||||
});
|
||||
|
||||
render() {
|
||||
if (!this.config) return nothing;
|
||||
|
||||
const { sizeClass, isNumbers, isRoman, isUpright, isLongDate } =
|
||||
this._computeClock(this.config);
|
||||
const sizeClass = this.config.clock_size
|
||||
? `size-${this.config.clock_size}`
|
||||
: "";
|
||||
|
||||
const isNumbers = this.config?.face_style?.startsWith("numbers");
|
||||
const isRoman = this.config?.face_style?.startsWith("roman");
|
||||
const isUpright = this.config?.face_style?.endsWith("upright");
|
||||
|
||||
const indicator = (number?: number) => html`
|
||||
<div
|
||||
@@ -243,14 +163,14 @@ export class HuiClockCardAnalog extends LitElement {
|
||||
})}
|
||||
>
|
||||
${this.config.ticks === "quarter"
|
||||
? QUARTER_TICKS.map(
|
||||
? Array.from({ length: 4 }, (_, i) => i).map(
|
||||
(i) =>
|
||||
// 4 ticks (12, 3, 6, 9) at 0°, 90°, 180°, 270°
|
||||
html`
|
||||
<div
|
||||
aria-hidden="true"
|
||||
class="tick hour"
|
||||
style=${styleMap({ "--tick-rotation": `${i * 90}deg` })}
|
||||
style=${`--tick-rotation: ${i * 90}deg;`}
|
||||
>
|
||||
${indicator([12, 3, 6, 9][i])}
|
||||
</div>
|
||||
@@ -258,30 +178,28 @@ export class HuiClockCardAnalog extends LitElement {
|
||||
)
|
||||
: !this.config.ticks || // Default to hour ticks
|
||||
this.config.ticks === "hour"
|
||||
? HOUR_TICKS.map(
|
||||
? Array.from({ length: 12 }, (_, i) => i).map(
|
||||
(i) =>
|
||||
// 12 ticks (1-12)
|
||||
html`
|
||||
<div
|
||||
aria-hidden="true"
|
||||
class="tick hour"
|
||||
style=${styleMap({ "--tick-rotation": `${i * 30}deg` })}
|
||||
style=${`--tick-rotation: ${i * 30}deg;`}
|
||||
>
|
||||
${indicator(((i + 11) % 12) + 1)}
|
||||
</div>
|
||||
`
|
||||
)
|
||||
: this.config.ticks === "minute"
|
||||
? MINUTE_TICKS.map(
|
||||
? Array.from({ length: 60 }, (_, i) => i).map(
|
||||
(i) =>
|
||||
// 60 ticks (1-60)
|
||||
html`
|
||||
<div
|
||||
aria-hidden="true"
|
||||
class="tick ${i % 5 === 0 ? "hour" : "minute"}"
|
||||
style=${styleMap({
|
||||
"--tick-rotation": `${i * 6}deg`,
|
||||
})}
|
||||
style=${`--tick-rotation: ${i * 6}deg;`}
|
||||
>
|
||||
${i % 5 === 0
|
||||
? indicator(((i / 5 + 11) % 12) + 1)
|
||||
@@ -290,33 +208,14 @@ export class HuiClockCardAnalog extends LitElement {
|
||||
`
|
||||
)
|
||||
: nothing}
|
||||
${this.config?.date && this.config.date !== "none"
|
||||
? html`<div
|
||||
class=${classMap({
|
||||
"date-parts": true,
|
||||
[sizeClass]: true,
|
||||
"long-date": isLongDate,
|
||||
})}
|
||||
>
|
||||
<span class="date-part day-month"
|
||||
>${this._day} ${this._month}</span
|
||||
>
|
||||
<span class="date-part year">${this._year}</span>
|
||||
</div>`
|
||||
: nothing}
|
||||
|
||||
<div class="center-dot"></div>
|
||||
<div
|
||||
class="hand hour"
|
||||
style=${styleMap({
|
||||
"animation-delay": `-${this._hourOffsetSec ?? 0}s`,
|
||||
})}
|
||||
style=${`animation-delay: -${this._hourOffsetSec ?? 0}s;`}
|
||||
></div>
|
||||
<div
|
||||
class="hand minute"
|
||||
style=${styleMap({
|
||||
"animation-delay": `-${this._minuteOffsetSec ?? 0}s`,
|
||||
})}
|
||||
style=${`animation-delay: -${this._minuteOffsetSec ?? 0}s;`}
|
||||
></div>
|
||||
${this.config.show_seconds
|
||||
? html`<div
|
||||
@@ -325,13 +224,11 @@ export class HuiClockCardAnalog extends LitElement {
|
||||
second: true,
|
||||
step: this.config.seconds_motion === "tick",
|
||||
})}
|
||||
style=${styleMap({
|
||||
"animation-delay": `-${
|
||||
(this.config.seconds_motion === "tick"
|
||||
? Math.floor(this._secondOffsetSec ?? 0)
|
||||
: (this._secondOffsetSec ?? 0)) as number
|
||||
}s`,
|
||||
})}
|
||||
style=${`animation-delay: -${
|
||||
(this.config.seconds_motion === "tick"
|
||||
? Math.floor(this._secondOffsetSec ?? 0)
|
||||
: (this._secondOffsetSec ?? 0)) as number
|
||||
}s;`}
|
||||
></div>`
|
||||
: nothing}
|
||||
</div>
|
||||
@@ -373,14 +270,6 @@ export class HuiClockCardAnalog extends LitElement {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
/* Modern browsers: Use container queries for responsive font sizing */
|
||||
@supports (container-type: inline-size) {
|
||||
.dial {
|
||||
container-type: inline-size;
|
||||
container-name: clock;
|
||||
}
|
||||
}
|
||||
|
||||
.dial-border {
|
||||
border: 2px solid var(--divider-color);
|
||||
border-radius: var(--ha-border-radius-circle);
|
||||
@@ -518,78 +407,6 @@ export class HuiClockCardAnalog extends LitElement {
|
||||
transform: translate(-50%, 0) rotate(360deg);
|
||||
}
|
||||
}
|
||||
|
||||
.date-parts {
|
||||
position: absolute;
|
||||
top: 68%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
display: grid;
|
||||
align-items: center;
|
||||
grid-template-areas:
|
||||
"day-month"
|
||||
"year";
|
||||
direction: ltr;
|
||||
color: var(--primary-text-color);
|
||||
font-size: var(--ha-font-size-s);
|
||||
font-weight: var(--ha-font-weight-medium);
|
||||
line-height: var(--ha-line-height-condensed);
|
||||
text-align: center;
|
||||
opacity: 0.8;
|
||||
max-width: 87%;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
/* Modern browsers: Use container queries for responsive font sizing */
|
||||
@supports (container-type: inline-size) {
|
||||
/* Small clock with long date: reduce to xs */
|
||||
@container clock (max-width: 139px) {
|
||||
.date-parts.long-date {
|
||||
font-size: var(--ha-font-size-xs);
|
||||
}
|
||||
}
|
||||
|
||||
/* Medium clock: scale up */
|
||||
@container clock (min-width: 140px) {
|
||||
.date-parts {
|
||||
font-size: var(--ha-font-size-l);
|
||||
}
|
||||
}
|
||||
|
||||
/* Large clock: scale up more */
|
||||
@container clock (min-width: 200px) {
|
||||
.date-parts {
|
||||
font-size: var(--ha-font-size-xl);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Legacy browsers: Use existing size classes */
|
||||
@supports not (container-type: inline-size) {
|
||||
/* Small clock (no size class) with long date */
|
||||
.date-parts.long-date:not(.size-medium):not(.size-large) {
|
||||
font-size: var(--ha-font-size-xs);
|
||||
}
|
||||
|
||||
.date-parts.size-medium {
|
||||
font-size: var(--ha-font-size-l);
|
||||
}
|
||||
|
||||
.date-parts.size-large {
|
||||
font-size: var(--ha-font-size-xl);
|
||||
}
|
||||
}
|
||||
|
||||
.date-part.day-month {
|
||||
grid-area: day-month;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.date-part.year {
|
||||
grid-area: year;
|
||||
overflow: hidden;
|
||||
}
|
||||
`;
|
||||
}
|
||||
|
||||
|
||||
@@ -24,8 +24,6 @@ export class HuiClockCardDigital extends LitElement {
|
||||
|
||||
@state() private _timeAmPm?: string;
|
||||
|
||||
@state() private _date?: string;
|
||||
|
||||
private _tickInterval?: undefined | number;
|
||||
|
||||
private _initDate() {
|
||||
@@ -41,27 +39,6 @@ export class HuiClockCardDigital extends LitElement {
|
||||
|
||||
const h12 = useAmPm(locale);
|
||||
this._dateTimeFormat = new Intl.DateTimeFormat(this.hass.locale.language, {
|
||||
...(this.config.date && this.config.date !== "none"
|
||||
? this.config.date === "day"
|
||||
? {
|
||||
day: "numeric",
|
||||
}
|
||||
: this.config.date === "day-month"
|
||||
? {
|
||||
month: "short",
|
||||
day: "numeric",
|
||||
}
|
||||
: this.config.date === "day-month-long"
|
||||
? {
|
||||
month: "long",
|
||||
day: "numeric",
|
||||
}
|
||||
: {
|
||||
year: "numeric",
|
||||
month: this.config.date === "long" ? "long" : "short",
|
||||
day: "numeric",
|
||||
}
|
||||
: {}),
|
||||
hour: h12 ? "numeric" : "2-digit",
|
||||
minute: "2-digit",
|
||||
second: "2-digit",
|
||||
@@ -116,16 +93,6 @@ export class HuiClockCardDigital extends LitElement {
|
||||
? parts.find((part) => part.type === "second")?.value
|
||||
: undefined;
|
||||
this._timeAmPm = parts.find((part) => part.type === "dayPeriod")?.value;
|
||||
|
||||
this._date = this.config?.date
|
||||
? [
|
||||
parts.find((part) => part.type === "day")?.value,
|
||||
parts.find((part) => part.type === "month")?.value,
|
||||
parts.find((part) => part.type === "year")?.value,
|
||||
]
|
||||
.filter(Boolean)
|
||||
.join(" ")
|
||||
: undefined;
|
||||
}
|
||||
|
||||
render() {
|
||||
@@ -146,9 +113,6 @@ export class HuiClockCardDigital extends LitElement {
|
||||
? html`<div class="time-part am-pm">${this._timeAmPm}</div>`
|
||||
: nothing}
|
||||
</div>
|
||||
${this.config.date && this.config.date !== "none"
|
||||
? html`<div class="date ${sizeClass}">${this._date}</div>`
|
||||
: nothing}
|
||||
`;
|
||||
}
|
||||
|
||||
@@ -224,20 +188,6 @@ export class HuiClockCardDigital extends LitElement {
|
||||
content: ":";
|
||||
margin: 0 2px;
|
||||
}
|
||||
|
||||
.date {
|
||||
text-align: center;
|
||||
opacity: 0.8;
|
||||
font-size: var(--ha-font-size-s);
|
||||
}
|
||||
|
||||
.date.size-medium {
|
||||
font-size: var(--ha-font-size-l);
|
||||
}
|
||||
|
||||
.date.size-large {
|
||||
font-size: var(--ha-font-size-2xl);
|
||||
}
|
||||
`;
|
||||
}
|
||||
|
||||
|
||||
@@ -421,7 +421,6 @@ export interface ClockCardConfig extends LovelaceCardConfig {
|
||||
time_format?: TimeFormat;
|
||||
time_zone?: string;
|
||||
no_background?: boolean;
|
||||
date?: "none" | "short" | "long" | "day" | "day-month" | "day-month-long";
|
||||
// Analog clock options
|
||||
border?: boolean;
|
||||
ticks?: "none" | "quarter" | "hour" | "minute";
|
||||
|
||||
@@ -39,19 +39,6 @@ const cardConfigStruct = assign(
|
||||
time_zone: optional(enums(Object.keys(timezones))),
|
||||
show_seconds: optional(boolean()),
|
||||
no_background: optional(boolean()),
|
||||
date: optional(
|
||||
defaulted(
|
||||
union([
|
||||
literal("none"),
|
||||
literal("short"),
|
||||
literal("long"),
|
||||
literal("day"),
|
||||
literal("day-month"),
|
||||
literal("day-month-long"),
|
||||
]),
|
||||
literal("none")
|
||||
)
|
||||
),
|
||||
// Analog clock options
|
||||
border: optional(defaulted(boolean(), false)),
|
||||
ticks: optional(
|
||||
@@ -106,7 +93,7 @@ export class HuiClockCardEditor
|
||||
name: "clock_style",
|
||||
selector: {
|
||||
select: {
|
||||
mode: "box",
|
||||
mode: "dropdown",
|
||||
options: ["digital", "analog"].map((value) => ({
|
||||
value,
|
||||
label: localize(
|
||||
@@ -132,27 +119,6 @@ export class HuiClockCardEditor
|
||||
},
|
||||
{ name: "show_seconds", selector: { boolean: {} } },
|
||||
{ name: "no_background", selector: { boolean: {} } },
|
||||
{
|
||||
name: "date",
|
||||
selector: {
|
||||
select: {
|
||||
mode: "dropdown",
|
||||
options: [
|
||||
"none",
|
||||
"short",
|
||||
"long",
|
||||
"day",
|
||||
"day-month",
|
||||
"day-month-long",
|
||||
].map((value) => ({
|
||||
value,
|
||||
label: localize(
|
||||
`ui.panel.lovelace.editor.card.clock.dates.${value}`
|
||||
),
|
||||
})),
|
||||
},
|
||||
},
|
||||
},
|
||||
...(clockStyle === "digital"
|
||||
? ([
|
||||
{
|
||||
@@ -294,14 +260,13 @@ export class HuiClockCardEditor
|
||||
] as const satisfies readonly HaFormSchema[]
|
||||
);
|
||||
|
||||
private _data = memoizeOne((config: ClockCardConfig) => ({
|
||||
private _data = memoizeOne((config) => ({
|
||||
clock_style: "digital",
|
||||
clock_size: "small",
|
||||
time_zone: "auto",
|
||||
time_format: "auto",
|
||||
show_seconds: false,
|
||||
no_background: false,
|
||||
date: "none",
|
||||
// Analog clock options
|
||||
border: false,
|
||||
ticks: "hour",
|
||||
@@ -325,9 +290,8 @@ export class HuiClockCardEditor
|
||||
.data=${this._data(this._config)}
|
||||
.schema=${this._schema(
|
||||
this.hass.localize,
|
||||
this._data(this._config)
|
||||
.clock_style as ClockCardConfig["clock_style"],
|
||||
this._data(this._config).ticks as ClockCardConfig["ticks"],
|
||||
this._data(this._config).clock_style,
|
||||
this._data(this._config).ticks,
|
||||
this._data(this._config).show_seconds
|
||||
)}
|
||||
.computeLabel=${this._computeLabelCallback}
|
||||
@@ -403,10 +367,6 @@ export class HuiClockCardEditor
|
||||
return this.hass!.localize(
|
||||
`ui.panel.lovelace.editor.card.clock.no_background`
|
||||
);
|
||||
case "date":
|
||||
return this.hass!.localize(
|
||||
`ui.panel.lovelace.editor.card.clock.date.label`
|
||||
);
|
||||
case "border":
|
||||
return this.hass!.localize(
|
||||
`ui.panel.lovelace.editor.card.clock.border.label`
|
||||
@@ -432,10 +392,6 @@ export class HuiClockCardEditor
|
||||
schema: SchemaUnion<ReturnType<typeof this._schema>>
|
||||
) => {
|
||||
switch (schema.name) {
|
||||
case "date":
|
||||
return this.hass!.localize(
|
||||
`ui.panel.lovelace.editor.card.clock.date.description`
|
||||
);
|
||||
case "border":
|
||||
return this.hass!.localize(
|
||||
`ui.panel.lovelace.editor.card.clock.border.description`
|
||||
|
||||
@@ -8241,18 +8241,6 @@
|
||||
"large": "Large"
|
||||
},
|
||||
"show_seconds": "Display seconds",
|
||||
"date": {
|
||||
"label": "Date",
|
||||
"description": "Whether to show the date on the clock. Can also be a custom date format."
|
||||
},
|
||||
"dates": {
|
||||
"none": "No date",
|
||||
"short": "Short",
|
||||
"long": "Long",
|
||||
"day": "Day only",
|
||||
"day-month": "Day and month",
|
||||
"day-month-long": "Day and month (long)"
|
||||
},
|
||||
"time_format": "[%key:ui::panel::profile::time_format::dropdown_label%]",
|
||||
"time_formats": {
|
||||
"auto": "Use user settings",
|
||||
|
||||
19
yarn.lock
19
yarn.lock
@@ -9175,7 +9175,7 @@ __metadata:
|
||||
typescript: "npm:5.9.3"
|
||||
typescript-eslint: "npm:8.52.0"
|
||||
ua-parser-js: "npm:2.0.7"
|
||||
vite-tsconfig-paths: "npm:6.0.4"
|
||||
vite-tsconfig-paths: "npm:6.0.3"
|
||||
vitest: "npm:4.0.16"
|
||||
vue: "npm:2.7.16"
|
||||
vue2-daterange-picker: "npm:0.6.8"
|
||||
@@ -14426,26 +14426,25 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"vite-tsconfig-paths@npm:6.0.4":
|
||||
version: 6.0.4
|
||||
resolution: "vite-tsconfig-paths@npm:6.0.4"
|
||||
"vite-tsconfig-paths@npm:6.0.3":
|
||||
version: 6.0.3
|
||||
resolution: "vite-tsconfig-paths@npm:6.0.3"
|
||||
dependencies:
|
||||
debug: "npm:^4.1.1"
|
||||
globrex: "npm:^0.1.2"
|
||||
tsconfck: "npm:^3.0.3"
|
||||
vite: "npm:*"
|
||||
peerDependencies:
|
||||
vite: "*"
|
||||
peerDependenciesMeta:
|
||||
vite:
|
||||
optional: true
|
||||
checksum: 10/85f871cd5e321f2865972559b01c518664e6e34f9039b630dd77c2f379f8fdc386e15f7237aa5c108d813030c6e9bc8edfbf61687df7684803111a2495edadac
|
||||
checksum: 10/271cdc040a03181d13e4253e99ec6deec1cbe4ec4cb2a1377d46dba403483f8e38a5c2ed29ad0493ed51c2cfd658847cb1cdc73e438d6a8bcdd2b52df19d72e2
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"vite@npm:*, vite@npm:^6.0.0 || ^7.0.0":
|
||||
version: 7.3.1
|
||||
resolution: "vite@npm:7.3.1"
|
||||
"vite@npm:^6.0.0 || ^7.0.0":
|
||||
version: 7.3.0
|
||||
resolution: "vite@npm:7.3.0"
|
||||
dependencies:
|
||||
esbuild: "npm:^0.27.0"
|
||||
fdir: "npm:^6.5.0"
|
||||
@@ -14494,7 +14493,7 @@ __metadata:
|
||||
optional: true
|
||||
bin:
|
||||
vite: bin/vite.js
|
||||
checksum: 10/62e48ffa4283b688f0049005405a004447ad38ffc99a0efea4c3aa9b7eed739f7402b43f00668c0ee5a895b684dc953d62f0722d8a92c5b2f6c95f051bceb208
|
||||
checksum: 10/044490133aaf4cc024700995edaac10ff182262c721a44a8ac7839207b3e5af435c8b9dd8ee4658dc0f47147fa4211632cca3120177aa4bab99a7cb095e5149e
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
|
||||
Reference in New Issue
Block a user