Date-range-picker Design to use Prev and Next Buttons in History and Logbook on mobiles (#23228)

* date-range-picker prev and next design

* correct width and margins

* logbook width correction

* Update src/components/ha-date-range-picker.ts

Co-authored-by: Wendelin <12148533+wendevlin@users.noreply.github.com>

* Update src/components/ha-date-range-picker.ts

Co-authored-by: Wendelin <12148533+wendevlin@users.noreply.github.com>

* Update src/components/ha-date-range-picker.ts

Co-authored-by: Wendelin <12148533+wendevlin@users.noreply.github.com>

* changes from comments

* share date-range logic for energy and history / logbook

* switch to energy-dashboard timespan-function

* changed shiftDateRange to differenceInMilliseconds

* used gap instead margin-right

---------

Co-authored-by: Wendelin <12148533+wendevlin@users.noreply.github.com>
This commit is contained in:
libe.net 2024-12-17 17:40:32 +01:00 committed by GitHub
parent ad1c32a880
commit 6f8ba6afac
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 143 additions and 234 deletions

View File

@ -1,3 +1,12 @@
import {
addMilliseconds,
addMonths,
isFirstDayOfMonth,
isLastDayOfMonth,
differenceInMilliseconds,
differenceInMonths,
endOfMonth,
} from "date-fns";
import { toZonedTime, fromZonedTime } from "date-fns-tz"; import { toZonedTime, fromZonedTime } from "date-fns-tz";
import type { HassConfig } from "home-assistant-js-websocket"; import type { HassConfig } from "home-assistant-js-websocket";
import type { FrontendLocaleData } from "../../data/translation"; import type { FrontendLocaleData } from "../../data/translation";
@ -55,3 +64,55 @@ export const calcDateDifferenceProperty = (
? toZonedTime(startDate, config.time_zone) ? toZonedTime(startDate, config.time_zone)
: startDate : startDate
); );
export const shiftDateRange = (
startDate: Date,
endDate: Date,
forward: boolean,
locale: FrontendLocaleData,
config: any
): { start: Date; end: Date } => {
let start: Date;
let end: Date;
if (
(calcDateProperty(
startDate,
isFirstDayOfMonth,
locale,
config
) as boolean) &&
(calcDateProperty(endDate, isLastDayOfMonth, locale, config) as boolean)
) {
const difference =
((calcDateDifferenceProperty(
endDate,
startDate,
differenceInMonths,
locale,
config
) as number) +
1) *
(forward ? 1 : -1);
start = calcDate(startDate, addMonths, locale, config, difference);
end = calcDate(
calcDate(endDate, addMonths, locale, config, difference),
endOfMonth,
locale,
config
);
} else {
const difference =
((calcDateDifferenceProperty(
endDate,
startDate,
differenceInMilliseconds,
locale,
config
) as number) +
1) *
(forward ? 1 : -1);
start = calcDate(startDate, addMilliseconds, locale, config, difference);
end = calcDate(endDate, addMilliseconds, locale, config, difference);
}
return { start, end };
};

View File

@ -5,8 +5,6 @@ import "@material/mwc-list/mwc-list-item";
import { mdiCalendar } from "@mdi/js"; import { mdiCalendar } from "@mdi/js";
import { import {
addDays, addDays,
addMonths,
addYears,
endOfDay, endOfDay,
endOfMonth, endOfMonth,
endOfWeek, endOfWeek,
@ -15,25 +13,23 @@ import {
startOfMonth, startOfMonth,
startOfWeek, startOfWeek,
startOfYear, startOfYear,
differenceInMilliseconds, isThisYear,
addMilliseconds,
subMilliseconds,
roundToNearestHours,
} from "date-fns"; } from "date-fns";
import type { CSSResultGroup, PropertyValues, TemplateResult } from "lit"; import type { CSSResultGroup, PropertyValues, TemplateResult } from "lit";
import { LitElement, css, html, nothing } from "lit"; import { LitElement, css, html, nothing } from "lit";
import { customElement, property, state } from "lit/decorators"; import { customElement, property, state } from "lit/decorators";
import { ifDefined } from "lit/directives/if-defined"; import { ifDefined } from "lit/directives/if-defined";
import { calcDate } from "../common/datetime/calc_date"; import { calcDate, shiftDateRange } from "../common/datetime/calc_date";
import { firstWeekdayIndex } from "../common/datetime/first_weekday"; import { firstWeekdayIndex } from "../common/datetime/first_weekday";
import { formatDate } from "../common/datetime/format_date"; import {
import { formatDateTime } from "../common/datetime/format_date_time"; formatShortDateTimeWithYear,
formatShortDateTime,
} from "../common/datetime/format_date_time";
import { useAmPm } from "../common/datetime/use_am_pm"; import { useAmPm } from "../common/datetime/use_am_pm";
import type { HomeAssistant } from "../types"; import type { HomeAssistant } from "../types";
import "./date-range-picker"; import "./date-range-picker";
import "./ha-icon-button"; import "./ha-icon-button";
import "./ha-svg-icon"; import "./ha-textarea";
import "./ha-textfield";
import "./ha-icon-button-next"; import "./ha-icon-button-next";
import "./ha-icon-button-prev"; import "./ha-icon-button-prev";
@ -141,9 +137,6 @@ export class HaDateRangePicker extends LitElement {
[this.hass.localize( [this.hass.localize(
"ui.components.date-range-picker.ranges.this_week" "ui.components.date-range-picker.ranges.this_week"
)]: [weekStart, weekEnd], )]: [weekStart, weekEnd],
[this.hass.localize(
"ui.components.date-range-picker.ranges.last_week"
)]: [addDays(weekStart, -7), addDays(weekEnd, -7)],
...(this.extendedPresets ...(this.extendedPresets
? { ? {
[this.hass.localize( [this.hass.localize(
@ -168,28 +161,6 @@ export class HaDateRangePicker extends LitElement {
} }
), ),
], ],
[this.hass.localize(
"ui.components.date-range-picker.ranges.last_month"
)]: [
calcDate(
addMonths(today, -1),
startOfMonth,
this.hass.locale,
this.hass.config,
{
weekStartsOn,
}
),
calcDate(
addMonths(today, -1),
endOfMonth,
this.hass.locale,
this.hass.config,
{
weekStartsOn,
}
),
],
[this.hass.localize( [this.hass.localize(
"ui.components.date-range-picker.ranges.this_year" "ui.components.date-range-picker.ranges.this_year"
)]: [ )]: [
@ -206,28 +177,6 @@ export class HaDateRangePicker extends LitElement {
weekStartsOn, weekStartsOn,
}), }),
], ],
[this.hass.localize(
"ui.components.date-range-picker.ranges.last_year"
)]: [
calcDate(
addYears(today, -1),
startOfYear,
this.hass.locale,
this.hass.config,
{
weekStartsOn,
}
),
calcDate(
addYears(today, -1),
endOfYear,
this.hass.locale,
this.hass.config,
{
weekStartsOn,
}
),
],
} }
: {}), : {}),
}; };
@ -261,54 +210,49 @@ export class HaDateRangePicker extends LitElement {
> >
<div slot="input" class="date-range-inputs" @click=${this._handleClick}> <div slot="input" class="date-range-inputs" @click=${this._handleClick}>
${!this.minimal ${!this.minimal
? html`<ha-svg-icon .path=${mdiCalendar}></ha-svg-icon> ? html`<ha-textarea
<ha-icon-button-prev mobile-multiline
.label=${this.hass.localize("ui.common.previous")} .value=${(isThisYear(this.startDate)
class="prev" ? formatShortDateTime(
@click=${this._handlePrev}
>
</ha-icon-button-prev>
<ha-textfield
.value=${this.timePicker
? formatDateTime(
this.startDate, this.startDate,
this.hass.locale, this.hass.locale,
this.hass.config this.hass.config
) )
: formatDate( : formatShortDateTimeWithYear(
this.startDate, this.startDate,
this.hass.locale, this.hass.locale,
this.hass.config this.hass.config
)} )) +
" - \n" +
(isThisYear(this.endDate)
? formatShortDateTime(
this.endDate,
this.hass.locale,
this.hass.config
)
: formatShortDateTimeWithYear(
this.endDate,
this.hass.locale,
this.hass.config
))}
.label=${this.hass.localize( .label=${this.hass.localize(
"ui.components.date-range-picker.start_date" "ui.components.date-range-picker.start_date"
)} ) +
.disabled=${this.disabled} " - " +
@click=${this._handleInputClick} this.hass.localize(
readonly
></ha-textfield>
<ha-textfield
.value=${this.timePicker
? formatDateTime(
this.endDate,
this.hass.locale,
this.hass.config
)
: formatDate(
this.endDate,
this.hass.locale,
this.hass.config
)}
.label=${this.hass.localize(
"ui.components.date-range-picker.end_date" "ui.components.date-range-picker.end_date"
)} )}
.disabled=${this.disabled} .disabled=${this.disabled}
@click=${this._handleInputClick} @click=${this._handleInputClick}
readonly readonly
></ha-textfield> ></ha-textarea>
<ha-icon-button-prev
.label=${this.hass.localize("ui.common.previous")}
@click=${this._handlePrev}
>
</ha-icon-button-prev>
<ha-icon-button-next <ha-icon-button-next
.label=${this.hass.localize("ui.common.next")} .label=${this.hass.localize("ui.common.next")}
class="next"
@click=${this._handleNext} @click=${this._handleNext}
> >
</ha-icon-button-next>` </ha-icon-button-next>`
@ -342,40 +286,28 @@ export class HaDateRangePicker extends LitElement {
`; `;
} }
private _handleNext(): void { private _handleNext(ev: MouseEvent): void {
const dateRange = [ if (ev && ev.stopPropagation) ev.stopPropagation();
roundToNearestHours(this.endDate), this._shift(true);
subMilliseconds(
roundToNearestHours(
addMilliseconds(
this.endDate,
Math.max(
3600000,
differenceInMilliseconds(this.endDate, this.startDate)
)
)
),
1
),
];
const dateRangePicker = this._dateRangePicker;
dateRangePicker.clickRange(dateRange);
dateRangePicker.clickedApply();
} }
private _handlePrev(): void { private _handlePrev(ev: MouseEvent): void {
const dateRange = [ if (ev && ev.stopPropagation) ev.stopPropagation();
roundToNearestHours( this._shift(false);
subMilliseconds( }
this.startDate,
Math.max( private _shift(forward: boolean) {
3600000, if (!this.startDate) return;
differenceInMilliseconds(this.endDate, this.startDate) const { start, end } = shiftDateRange(
) this.startDate,
) this.endDate,
), forward,
subMilliseconds(roundToNearestHours(this.startDate), 1), this.hass.locale,
]; this.hass.config
);
this.startDate = start;
this.endDate = end;
const dateRange = [start, end];
const dateRangePicker = this._dateRangePicker; const dateRangePicker = this._dateRangePicker;
dateRangePicker.clickRange(dateRange); dateRangePicker.clickRange(dateRange);
dateRangePicker.clickedApply(); dateRangePicker.clickedApply();
@ -430,12 +362,6 @@ export class HaDateRangePicker extends LitElement {
static get styles(): CSSResultGroup { static get styles(): CSSResultGroup {
return css` return css`
ha-svg-icon {
margin-right: 8px;
margin-inline-end: 8px;
margin-inline-start: initial;
direction: var(--direction);
}
ha-icon-button { ha-icon-button {
direction: var(--direction); direction: var(--direction);
@ -444,6 +370,7 @@ export class HaDateRangePicker extends LitElement {
.date-range-inputs { .date-range-inputs {
display: flex; display: flex;
align-items: center; align-items: center;
gap: 8px;
} }
.date-range-ranges { .date-range-ranges {
@ -457,17 +384,13 @@ export class HaDateRangePicker extends LitElement {
border-top: 1px solid var(--divider-color); border-top: 1px solid var(--divider-color);
} }
ha-textfield { ha-textarea {
display: inline-block; display: inline-block;
max-width: 250px; width: 340px;
min-width: 220px;
} }
@media only screen and (max-width: 460px) {
ha-textfield:last-child { ha-textarea {
margin-left: 8px; width: 100%
margin-inline-start: 8px;
margin-inline-end: initial;
direction: var(--direction);
} }
@media only screen and (max-width: 800px) { @media only screen and (max-width: 800px) {
@ -476,18 +399,6 @@ export class HaDateRangePicker extends LitElement {
border-bottom: 1px solid var(--divider-color); border-bottom: 1px solid var(--divider-color);
} }
} }
@media only screen and (max-width: 500px) {
ha-textfield {
min-width: inherit;
}
ha-svg-icon,
.prev,
.next {
display: none;
}
}
`; `;
} }
} }

View File

@ -53,6 +53,12 @@ export class HaTextArea extends TextAreaBase {
inset-inline-end: initial !important; inset-inline-end: initial !important;
transform-origin: var(--float-start) top; transform-origin: var(--float-start) top;
} }
@media only screen and (min-width: 459px) {
:host([mobile-multiline]) .mdc-text-field__input {
white-space: nowrap;
max-height: 16px;
}
}
`, `,
]; ];
} }

View File

@ -772,10 +772,8 @@ class HaPanelHistory extends LitElement {
flex-direction: column; flex-direction: column;
} }
ha-date-range-picker { ha-date-range-picker {
margin-right: 0;
margin-inline-end: 0;
margin-inline-start: initial;
width: 100%; width: 100%;
margin-bottom: 8px;
} }
} }

View File

@ -305,6 +305,12 @@ export class HaPanelLogbook extends LitElement {
direction: var(--direction); direction: var(--direction);
} }
@media all and (max-width: 870px) {
ha-date-range-picker {
width: 100%;
}
}
:host([narrow]) ha-date-range-picker { :host([narrow]) ha-date-range-picker {
margin-right: 0; margin-right: 0;
margin-inline-end: 0; margin-inline-end: 0;

View File

@ -2,8 +2,6 @@ import "@material/mwc-button/mwc-button";
import type { RequestSelectedDetail } from "@material/mwc-list/mwc-list-item"; import type { RequestSelectedDetail } from "@material/mwc-list/mwc-list-item";
import { mdiDotsVertical } from "@mdi/js"; import { mdiDotsVertical } from "@mdi/js";
import { import {
addDays,
addMonths,
differenceInDays, differenceInDays,
differenceInMonths, differenceInMonths,
endOfDay, endOfDay,
@ -30,6 +28,7 @@ import {
calcDate, calcDate,
calcDateProperty, calcDateProperty,
calcDateDifferenceProperty, calcDateDifferenceProperty,
shiftDateRange,
} from "../../../common/datetime/calc_date"; } from "../../../common/datetime/calc_date";
import { firstWeekdayIndex } from "../../../common/datetime/first_weekday"; import { firstWeekdayIndex } from "../../../common/datetime/first_weekday";
import { import {
@ -512,84 +511,15 @@ export class HuiEnergyPeriodSelector extends SubscribeMixin(LitElement) {
private _shift(forward: boolean) { private _shift(forward: boolean) {
if (!this._startDate) return; if (!this._startDate) return;
const { start, end } = shiftDateRange(
let start: Date; this._startDate,
let end: Date; this._endDate!,
if ( forward,
(calcDateProperty( this.hass.locale,
this._startDate, this.hass.config
isFirstDayOfMonth, );
this.hass.locale,
this.hass.config
) as boolean) &&
(calcDateProperty(
this._endDate!,
isLastDayOfMonth,
this.hass.locale,
this.hass.config
) as boolean)
) {
// Shift date range with respect to month/year selection
const difference =
((calcDateDifferenceProperty(
this._endDate!,
this._startDate,
differenceInMonths,
this.hass.locale,
this.hass.config
) as number) +
1) *
(forward ? 1 : -1);
start = calcDate(
this._startDate,
addMonths,
this.hass.locale,
this.hass.config,
difference
);
end = calcDate(
calcDate(
this._endDate!,
addMonths,
this.hass.locale,
this.hass.config,
difference
),
endOfMonth,
this.hass.locale,
this.hass.config
);
} else {
// Shift date range by period length
const difference =
((calcDateDifferenceProperty(
this._endDate!,
this._startDate,
differenceInDays,
this.hass.locale,
this.hass.config
) as number) +
1) *
(forward ? 1 : -1);
start = calcDate(
this._startDate,
addDays,
this.hass.locale,
this.hass.config,
difference
);
end = calcDate(
this._endDate!,
addDays,
this.hass.locale,
this.hass.config,
difference
);
}
this._startDate = start; this._startDate = start;
this._endDate = end; this._endDate = end;
this._updateCollectionPeriod(); this._updateCollectionPeriod();
} }

View File

@ -802,12 +802,9 @@
"today": "Today", "today": "Today",
"yesterday": "Yesterday", "yesterday": "Yesterday",
"this_week": "This week", "this_week": "This week",
"last_week": "Last week",
"this_quarter": "This quarter", "this_quarter": "This quarter",
"this_month": "This month", "this_month": "This month",
"last_month": "Last month", "this_year": "This year"
"this_year": "This year",
"last_year": "Last year"
} }
}, },
"grid-size-picker": { "grid-size-picker": {