Compare commits

...

6 Commits

Author SHA1 Message Date
Paul Bottein
6745a97f86 Set energy selector position to fixed 2025-12-15 15:52:25 +01:00
Petar Petrov
a8286e31a0 Use dialog backdrop and define default 2025-12-11 12:47:10 +02:00
Petar Petrov
4fa7274fbe fix scrollbar 2025-12-10 12:24:03 +02:00
Petar Petrov
414c1315a4 move to hui-root via slot 2025-12-10 12:08:44 +02:00
Petar Petrov
04bfc350ea Blur view when date picker is open 2025-12-09 15:25:09 +02:00
Petar Petrov
75ec9404ce Sticky period selector for energy dashboard 2025-12-09 13:15:12 +02:00
10 changed files with 139 additions and 54 deletions

View File

@@ -101,6 +101,10 @@ const Component = Vue.extend({
type: String,
default: "en",
},
opensVertical: {
type: String,
default: undefined,
},
},
render(createElement) {
// @ts-expect-error
@@ -129,6 +133,11 @@ const Component = Vue.extend({
},
expression: "dateRange",
},
on: {
toggle: (open: boolean) => {
fireEvent(this.$el as HTMLElement, "toggle", { open });
},
},
scopedSlots: {
input() {
return createElement("slot", {
@@ -309,6 +318,10 @@ class DateRangePickerElement extends WrappedElement {
min-width: unset !important;
display: block !important;
}
:host([opens-vertical="up"]) .daterangepicker {
bottom: 100%;
top: auto !important;
}
`;
if (mainWindow.document.dir === "rtl") {
style.innerHTML += `
@@ -340,4 +353,7 @@ declare global {
interface HTMLElementTagNameMap {
"date-range-picker": DateRangePickerElement;
}
interface HASSDomEvents {
toggle: { open: boolean };
}
}

View File

@@ -74,6 +74,9 @@ export class HaDateRangePicker extends LitElement {
@property({ attribute: "extended-presets", type: Boolean })
public extendedPresets = false;
@property({ attribute: "vertical-opening-direction" })
public verticalOpeningDirection?: "up" | "down";
@property({ attribute: false }) public openingDirection?:
| "right"
| "left"
@@ -127,6 +130,7 @@ export class HaDateRangePicker extends LitElement {
opening-direction=${ifDefined(
this.openingDirection || this._calcedOpeningDirection
)}
opens-vertical=${ifDefined(this.verticalOpeningDirection)}
first-day=${firstWeekdayIndex(this.hass.locale)}
language=${this.hass.locale.language}
@change=${this._handleChange}

View File

@@ -2,7 +2,9 @@ import { mdiDownload } from "@mdi/js";
import type { CSSResultGroup, PropertyValues } from "lit";
import { LitElement, css, html, nothing } from "lit";
import { customElement, property, state } from "lit/decorators";
import { classMap } from "lit/directives/class-map";
import { navigate } from "../../common/navigate";
import type { LocalizeKeys } from "../../common/translations/localize";
import "../../components/ha-alert";
import "../../components/ha-icon-button-arrow-prev";
import "../../components/ha-menu-button";
@@ -22,7 +24,10 @@ import {
getSummedData,
} from "../../data/energy";
import type { LovelaceConfig } from "../../data/lovelace/config/types";
import type { LovelaceViewConfig } from "../../data/lovelace/config/view";
import {
isStrategyView,
type LovelaceViewConfig,
} from "../../data/lovelace/config/view";
import type { StatisticValue } from "../../data/recorder";
import { haStyle } from "../../resources/styles";
import type { HomeAssistant, PanelInfo } from "../../types";
@@ -33,7 +38,6 @@ import type { ExtraActionItem } from "../lovelace/hui-root";
import type { Lovelace } from "../lovelace/types";
import "../lovelace/views/hui-view";
import "../lovelace/views/hui-view-container";
import type { LocalizeKeys } from "../../common/translations/localize";
export const DEFAULT_ENERGY_COLLECTION_KEY = "energy_dashboard";
@@ -48,6 +52,7 @@ const OVERVIEW_VIEW = {
strategy: {
type: "energy-overview",
collection_key: DEFAULT_ENERGY_COLLECTION_KEY,
show_period_selector: true,
},
} as LovelaceViewConfig;
@@ -56,6 +61,7 @@ const ENERGY_VIEW = {
strategy: {
type: "energy",
collection_key: DEFAULT_ENERGY_COLLECTION_KEY,
show_period_selector: true,
},
} as LovelaceViewConfig;
@@ -64,6 +70,7 @@ const WATER_VIEW = {
strategy: {
type: "water",
collection_key: DEFAULT_ENERGY_COLLECTION_KEY,
show_period_selector: true,
},
} as LovelaceViewConfig;
@@ -72,6 +79,7 @@ const GAS_VIEW = {
strategy: {
type: "gas",
collection_key: DEFAULT_ENERGY_COLLECTION_KEY,
show_period_selector: true,
},
} as LovelaceViewConfig;
@@ -223,6 +231,16 @@ class PanelEnergy extends LitElement {
return nothing;
}
const routePath = this.route?.path?.split("/")[1] || "";
const currentView = this._lovelace.config.views.find(
(view) => view.path === routePath
);
const showEnergySelector =
currentView &&
isStrategyView(currentView) &&
currentView.strategy?.show_period_selector;
return html`
<hui-root
.hass=${this.hass}
@@ -232,7 +250,20 @@ class PanelEnergy extends LitElement {
.panel=${this.panel}
.extraActionItems=${this._extraActionItems}
@reload-energy-panel=${this._reloadConfig}
></hui-root>
class=${classMap({ "has-period-selector": showEnergySelector })}
>
</hui-root>
${showEnergySelector
? html`
<ha-card raised class="period-selector">
<hui-energy-period-selector
.hass=${this.hass}
.collectionKey=${DEFAULT_ENERGY_COLLECTION_KEY}
vertical-opening-direction="up"
></hui-energy-period-selector>
</ha-card>
`
: nothing}
`;
}
@@ -631,24 +662,6 @@ class PanelEnergy extends LitElement {
-webkit-user-select: none;
-moz-user-select: none;
}
.toolbar {
height: var(--header-height);
display: flex;
flex: 1;
align-items: center;
font-size: var(--ha-font-size-xl);
padding: 0px 12px;
font-weight: var(--ha-font-weight-normal);
box-sizing: border-box;
}
:host([narrow]) .toolbar {
padding: 0 4px;
}
.main-title {
margin: var(--margin-title);
line-height: var(--ha-line-height-normal);
flex-grow: 1;
}
.centered {
width: 100%;
height: 100%;
@@ -656,6 +669,28 @@ class PanelEnergy extends LitElement {
align-items: center;
justify-content: center;
}
hui-root.has-period-selector {
--view-container-padding-bottom: var(--ha-space-16);
}
.period-selector {
position: fixed;
bottom: calc(var(--ha-space-2) + var(--safe-area-inset-bottom, 0px));
left: var(--mdc-drawer-width, 0);
right: var(--safe-area-inset-right, 0px);
inset-inline-start: var(--mdc-drawer-width, 0);
inset-inline-end: var(--safe-area-inset-right, 0px);
margin: var(--ha-space-2) auto;
max-width: calc(min(450px, 100% - var(--ha-space-4)));
box-sizing: border-box;
padding-left: calc(
var(--ha-space-4) + var(--safe-area-inset-left, 0px)
);
padding-right: 0;
padding-inline-start: calc(
var(--ha-space-4) + var(--safe-area-inset-left, 0px)
);
padding-inline-end: 0;
}
`,
];
}

View File

@@ -5,7 +5,6 @@ import { getEnergyDataCollection } from "../../../data/energy";
import type { HomeAssistant } from "../../../types";
import type { LovelaceViewConfig } from "../../../data/lovelace/config/view";
import type { LovelaceStrategyConfig } from "../../../data/lovelace/config/strategy";
import type { LovelaceSectionConfig } from "../../../data/lovelace/config/section";
import { DEFAULT_ENERGY_COLLECTION_KEY } from "../ha-panel-energy";
@customElement("energy-overview-view-strategy")
@@ -64,24 +63,20 @@ export class EnergyOverviewViewStrategy extends ReactiveElement {
(source.type === "grid" && source.power?.length)
);
const overviewSection: LovelaceSectionConfig = {
type: "grid",
cards: [
{
type: "energy-date-selection",
collection_key: collectionKey,
allow_compare: false,
},
],
};
if (hasGrid || hasBattery || hasSolar) {
overviewSection.cards!.push({
title: hass.localize("ui.panel.energy.cards.energy_distribution_title"),
type: "energy-distribution",
collection_key: collectionKey,
view.sections!.push({
type: "grid",
cards: [
{
title: hass.localize(
"ui.panel.energy.cards.energy_distribution_title"
),
type: "energy-distribution",
collection_key: collectionKey,
},
],
});
}
view.sections!.push(overviewSection);
if (prefs.energy_sources.length) {
view.sections!.push({

View File

@@ -53,10 +53,6 @@ export class EnergyViewStrategy extends ReactiveElement {
(d) => d.included_in_stat
);
view.cards!.push({
type: "energy-date-selection",
collection_key: collectionKey,
});
view.cards!.push({
type: "energy-compare",
collection_key: "energy_dashboard",

View File

@@ -40,10 +40,6 @@ export class GasViewStrategy extends ReactiveElement {
const section = view.sections![0] as LovelaceSectionConfig;
section.cards!.push({
type: "energy-date-selection",
collection_key: collectionKey,
});
section.cards!.push({
type: "energy-compare",
collection_key: collectionKey,

View File

@@ -41,10 +41,6 @@ export class WaterViewStrategy extends ReactiveElement {
const section = view.sections![0] as LovelaceSectionConfig;
section.cards!.push({
type: "energy-date-selection",
collection_key: collectionKey,
});
section.cards!.push({
type: "energy-compare",
collection_key: collectionKey,

View File

@@ -17,6 +17,7 @@ import type { PropertyValues } from "lit";
import { LitElement, css, html, nothing } from "lit";
import { customElement, property, state } from "lit/decorators";
import memoizeOne from "memoize-one";
import { classMap } from "lit/directives/class-map";
import {
calcDate,
calcDateProperty,
@@ -69,6 +70,11 @@ export class HuiEnergyPeriodSelector extends SubscribeMixin(LitElement) {
@property({ type: Boolean, attribute: "allow-compare" }) public allowCompare =
true;
@property({ attribute: "vertical-opening-direction" })
public verticalOpeningDirection?: "up" | "down";
@state() _datepickerOpen = false;
@state() _startDate?: Date;
@state() _endDate?: Date;
@@ -150,7 +156,13 @@ export class HuiEnergyPeriodSelector extends SubscribeMixin(LitElement) {
);
return html`
<div class="row">
<div
class=${classMap({
row: true,
"datepicker-open": this._datepickerOpen,
})}
>
<div class="backdrop"></div>
<div class="label">
${simpleRange === "day"
? this.narrow
@@ -202,8 +214,10 @@ export class HuiEnergyPeriodSelector extends SubscribeMixin(LitElement) {
.ranges=${this._ranges}
@value-changed=${this._dateRangeChanged}
@preset-selected=${this._presetSelected}
@toggle=${this._handleDatepickerToggle}
minimal
header-position
.verticalOpeningDirection=${this.verticalOpeningDirection}
></ha-date-range-picker>
</div>
@@ -446,6 +460,10 @@ export class HuiEnergyPeriodSelector extends SubscribeMixin(LitElement) {
this._endDate = energyData.end || endOfToday();
}
private _handleDatepickerToggle(ev: CustomEvent<{ open: boolean }>) {
this._datepickerOpen = ev.detail.open;
}
private _toggleCompare(ev: CustomEvent<RequestSelectedDetail>) {
if (ev.detail.source !== "interaction") {
return;
@@ -496,6 +514,29 @@ export class HuiEnergyPeriodSelector extends SubscribeMixin(LitElement) {
flex-shrink: 0;
--ha-button-theme-color: currentColor;
}
.backdrop {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
z-index: var(--dialog-z-index, 8);
-webkit-backdrop-filter: var(
--ha-dialog-scrim-backdrop-filter,
var(--dialog-backdrop-filter)
);
backdrop-filter: var(
--ha-dialog-scrim-backdrop-filter,
var(--dialog-backdrop-filter)
);
pointer-events: none;
opacity: 0;
transition: opacity var(--ha-animation-base-duration) ease-in-out;
}
.datepicker-open .backdrop {
opacity: 1;
pointer-events: auto;
}
`;
}

View File

@@ -26,6 +26,7 @@ import { classMap } from "lit/directives/class-map";
import { ifDefined } from "lit/directives/if-defined";
import memoizeOne from "memoize-one";
import { isComponentLoaded } from "../../common/config/is_component_loaded";
import { UndoRedoController } from "../../common/controllers/undo-redo-controller";
import { fireEvent } from "../../common/dom/fire_event";
import { shouldHandleRequestSelectedEvent } from "../../common/mwc/handle-request-selected-event";
import { goBack, navigate } from "../../common/navigate";
@@ -37,8 +38,8 @@ import {
removeSearchParam,
} from "../../common/url/search-params";
import { debounce } from "../../common/util/debounce";
import { isMobileClient } from "../../util/is_mobile";
import { afterNextRender } from "../../common/util/render-status";
import { withViewTransition } from "../../common/util/view-transition";
import "../../components/ha-button";
import "../../components/ha-button-menu";
import "../../components/ha-icon";
@@ -81,6 +82,7 @@ import { showVoiceCommandDialog } from "../../dialogs/voice-command-dialog/show-
import { haStyle } from "../../resources/styles";
import type { HomeAssistant, PanelInfo } from "../../types";
import { documentationUrl } from "../../util/documentation-url";
import { isMobileClient } from "../../util/is_mobile";
import { showToast } from "../../util/toast";
import { showAreaRegistryDetailDialog } from "../config/areas/show-dialog-area-registry-detail";
import { showNewAutomationDialog } from "../config/automation/show-dialog-new-automation";
@@ -98,8 +100,6 @@ import "./views/hui-view";
import type { HUIView } from "./views/hui-view";
import "./views/hui-view-background";
import "./views/hui-view-container";
import { UndoRedoController } from "../../common/controllers/undo-redo-controller";
import { withViewTransition } from "../../common/util/view-transition";
interface ActionItem {
icon: string;
@@ -1546,7 +1546,10 @@ class HUIRoot extends LitElement {
padding-top: calc(var(--header-height) + var(--safe-area-inset-top));
padding-right: var(--safe-area-inset-right);
padding-inline-end: var(--safe-area-inset-right);
padding-bottom: var(--safe-area-inset-bottom);
padding-bottom: calc(
var(--safe-area-inset-bottom) +
var(--view-container-padding-bottom, 0px)
);
}
.narrow hui-view-container {
padding-left: var(--safe-area-inset-left);

View File

@@ -48,6 +48,9 @@ export const mainStyles = css`
*/
--safe-width: calc(100vw - var(--safe-area-inset-left) - var(--safe-area-inset-right));
--safe-height: calc(100vh - var(--safe-area-inset-top) - var(--safe-area-inset-bottom));
/* dialog backdrop filter */
--ha-dialog-scrim-backdrop-filter: brightness(68%);
}
`;