Add datepicker to timeline.

This commit is contained in:
Dermot Duffy
2023-03-28 19:57:26 -07:00
parent c7cab98786
commit 8c606b296f
10 changed files with 126 additions and 21 deletions
+1
View File
@@ -31,6 +31,7 @@
"home-assistant-js-websocket": "^8.0.0", "home-assistant-js-websocket": "^8.0.0",
"keycharm": "^0.4.0", "keycharm": "^0.4.0",
"lit": "^2.3.1", "lit": "^2.3.1",
"lit-flatpickr": "^0.4.0",
"lodash-es": "^4.17.21", "lodash-es": "^4.17.21",
"moment": "^2.29.4", "moment": "^2.29.4",
"propagating-hammerjs": "^2.0.1", "propagating-hammerjs": "^2.0.1",
+3 -2
View File
@@ -91,11 +91,12 @@ const config = {
}), }),
}, },
plugins: plugins, plugins: plugins,
// These two files use this at the toplevel, which causes rollup warning // These files use this at the toplevel, which causes rollup warning
// spam on build: `this` has been rewritten to `undefined` // spam on build: `this` has been rewritten to `undefined`.
moduleContext: { moduleContext: {
'./node_modules/@formatjs/intl-utils/lib/src/diff.js': 'window', './node_modules/@formatjs/intl-utils/lib/src/diff.js': 'window',
'./node_modules/@formatjs/intl-utils/lib/src/resolve-locale.js': 'window', './node_modules/@formatjs/intl-utils/lib/src/resolve-locale.js': 'window',
'./node_modules/flatpickr/dist/esm/index.js': 'window',
}, },
}; };
+44
View File
@@ -0,0 +1,44 @@
import { CSSResultGroup, html, LitElement, TemplateResult, unsafeCSS } from 'lit';
import 'lit-flatpickr';
import { LitFlatpickr } from 'lit-flatpickr';
import { customElement } from 'lit/decorators.js';
import { createRef, ref, Ref } from 'lit/directives/ref.js';
import datePickerStyle from '../scss/date-picker.scss';
import { dispatchFrigateCardEvent } from '../utils/basic';
export interface DatePickerEvent {
date: Date;
}
@customElement('frigate-card-date-picker')
export class FrigateCardDatePicker extends LitElement {
protected _refInput: Ref<LitFlatpickr> = createRef();
public open(): void {
this._refInput.value?.open();
}
protected render(): TemplateResult {
return html` <lit-flatpickr
${ref(this._refInput)}
.onChange=${(dates: Date[]) => {
if (dates.length) {
// This is a single date picker, there should be only a single date.
dispatchFrigateCardEvent<DatePickerEvent>(this, 'date-picker:change', {
date: dates[0],
});
}
}}
></lit-flatpickr>`;
}
static get styles(): CSSResultGroup {
return unsafeCSS(datePickerStyle);
}
}
declare global {
interface HTMLElementTagNameMap {
'frigate-card-date-picker': FrigateCardDatePicker;
}
}
+44 -17
View File
@@ -59,6 +59,10 @@ import { ViewMediaClassifier } from '../view/media-classifier';
import { rangesOverlap } from '../camera-manager/range'; import { rangesOverlap } from '../camera-manager/range';
import { View } from '../view/view'; import { View } from '../view/view';
import { MediaQuery } from '../camera-manager/types'; import { MediaQuery } from '../camera-manager/types';
import './date-picker.js';
import { DatePickerEvent, FrigateCardDatePicker } from './date-picker.js';
import startOfDay from 'date-fns/startOfDay';
import endOfDay from 'date-fns/endOfDay';
interface FrigateCardGroupData { interface FrigateCardGroupData {
id: string; id: string;
@@ -191,7 +195,10 @@ export class FrigateCardTimelineCore extends LitElement {
protected _locked = false; protected _locked = false;
protected _targetBarVisible = false; protected _targetBarVisible = false;
protected _refDatePicker: Ref<FrigateCardDatePicker> = createRef();
protected _refTimeline: Ref<HTMLElement> = createRef(); protected _refTimeline: Ref<HTMLElement> = createRef();
protected _timeline?: Timeline; protected _timeline?: Timeline;
protected _timelineSource: TimelineDataSource | null = null; protected _timelineSource: TimelineDataSource | null = null;
@@ -260,6 +267,10 @@ export class FrigateCardTimelineCore extends LitElement {
} }
const capabilities = this.cameraManager?.getAggregateCameraCapabilities(cameraIDs); const capabilities = this.cameraManager?.getAggregateCameraCapabilities(cameraIDs);
const lockTitle = this._locked
? localize('timeline.unlock')
: localize('timeline.lock');
return html` ${capabilities?.supportsTimeline return html` ${capabilities?.supportsTimeline
? html` <div ? html` <div
@frigate-card:timeline:thumbnail-data-request=${this._handleThumbnailDataRequest.bind( @frigate-card:timeline:thumbnail-data-request=${this._handleThumbnailDataRequest.bind(
@@ -268,20 +279,36 @@ export class FrigateCardTimelineCore extends LitElement {
class="timeline" class="timeline"
${ref(this._refTimeline)} ${ref(this._refTimeline)}
> >
<ha-icon <div class="timeline-tools">
class="lock" <frigate-card-date-picker
.icon=${`mdi:${this._locked ? 'lock' : 'lock-open-variant'}`} ${ref(this._refDatePicker)}
@click=${() => { @frigate-card:date-picker:change=${(ev: CustomEvent<DatePickerEvent>) => {
this._locked = !this._locked; this._timeline?.setWindow(
}} startOfDay(ev.detail.date),
aria-label="${this._locked endOfDay(ev.detail.date),
? localize('timeline.unlock') );
: localize('timeline.lock')}" }}
title="${this._locked >
? localize('timeline.unlock') </frigate-card-date-picker>
: localize('timeline.lock')}" <ha-icon
> .icon=${`mdi:calendar-search`}
</ha-icon> aria-label="${localize('timeline.select_date')}"
title="${localize('timeline.select_date')}"
@click=${() => {
this._refDatePicker.value?.open();
}}
>
</ha-icon>
<ha-icon
.icon=${`mdi:${this._locked ? 'lock' : 'lock-open-variant'}`}
@click=${() => {
this._locked = !this._locked;
}}
aria-label="${lockTitle}"
title="${lockTitle}"
>
</ha-icon>
</div>
</div>` </div>`
: ''}`; : ''}`;
} }
@@ -896,9 +923,9 @@ export class FrigateCardTimelineCore extends LitElement {
const mediaEndTime = media?.getEndTime(); const mediaEndTime = media?.getEndTime();
const mediaWindow: TimelineWindow | null = const mediaWindow: TimelineWindow | null =
media && mediaStartTime media && mediaStartTime
// If this media has no end time, it's just a "point" in time so the ? // If this media has no end time, it's just a "point" in time so the
// range effectively starts/ends at the same time. // range effectively starts/ends at the same time.
? { start: mediaStartTime, end: mediaEndTime ?? mediaStartTime } { start: mediaStartTime, end: mediaEndTime ?? mediaStartTime }
: null; : null;
const context = this.view.context?.timeline; const context = this.view.context?.timeline;
+1
View File
@@ -461,6 +461,7 @@
}, },
"timeline": { "timeline": {
"lock": "Lock timeline to a single event", "lock": "Lock timeline to a single event",
"select_date": "Choose date",
"unlock": "Unlock timeline" "unlock": "Unlock timeline"
}, },
"elements": { "elements": {
+1
View File
@@ -450,6 +450,7 @@
}, },
"timeline": { "timeline": {
"lock": "", "lock": "",
"select_date": "",
"unlock": "" "unlock": ""
}, },
"elements": { "elements": {
+1
View File
@@ -450,6 +450,7 @@
}, },
"timeline": { "timeline": {
"lock": "", "lock": "",
"select_date": "",
"unlock": "" "unlock": ""
}, },
"elements": { "elements": {
+7
View File
@@ -0,0 +1,7 @@
// The lit-flatpickr element itself is hidden as we only want the popup
// calender.
lit-flatpickr {
visibility: hidden;
width: 0px;
height: 0px;
}
+4 -1
View File
@@ -141,11 +141,14 @@ div.vis-tooltip {
pointer-events: none; pointer-events: none;
} }
ha-icon.lock { .timeline-tools {
position: absolute; position: absolute;
right: 2px; right: 2px;
bottom: 2px; bottom: 2px;
color: var(--primary-color); color: var(--primary-color);
z-index: 10; z-index: 10;
}
.timeline-tools ha-icon {
cursor: pointer; cursor: pointer;
} }
+20 -1
View File
@@ -2407,6 +2407,13 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"flatpickr@npm:^4.6.13":
version: 4.6.13
resolution: "flatpickr@npm:4.6.13"
checksum: 2cca1b8dc974e7673b51174ee3f0679ae3a6b79525a0c53bf49b87455ef358354e64acfd60b312e44cef208aab9750a1a48df32a0914046a53de6d9403742304
languageName: node
linkType: hard
"flatted@npm:^3.1.0": "flatted@npm:^3.1.0":
version: 3.2.7 version: 3.2.7
resolution: "flatted@npm:3.2.7" resolution: "flatted@npm:3.2.7"
@@ -2460,6 +2467,7 @@ __metadata:
home-assistant-js-websocket: ^8.0.0 home-assistant-js-websocket: ^8.0.0
keycharm: ^0.4.0 keycharm: ^0.4.0
lit: ^2.3.1 lit: ^2.3.1
lit-flatpickr: ^0.4.0
lodash-es: ^4.17.21 lodash-es: ^4.17.21
moment: ^2.29.4 moment: ^2.29.4
prettier: ^2.6.0 prettier: ^2.6.0
@@ -3327,6 +3335,17 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"lit-flatpickr@npm:^0.4.0":
version: 0.4.0
resolution: "lit-flatpickr@npm:0.4.0"
dependencies:
flatpickr: ^4.6.13
lit: ^2.0.0
tslib: ^1.11.0
checksum: 2141902346bf3f2d291e1c3369317bb494641da48a3f69dabb891b7d065e2505b268c584cbc1859c36763374b9880399b17d93721539b2dc7d90c58988dba471
languageName: node
linkType: hard
"lit-html@npm:^2.2.0, lit-html@npm:^2.6.0": "lit-html@npm:^2.2.0, lit-html@npm:^2.6.0":
version: 2.6.1 version: 2.6.1
resolution: "lit-html@npm:2.6.1" resolution: "lit-html@npm:2.6.1"
@@ -5160,7 +5179,7 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"tslib@npm:^1.8.1": "tslib@npm:^1.11.0, tslib@npm:^1.8.1":
version: 1.14.1 version: 1.14.1
resolution: "tslib@npm:1.14.1" resolution: "tslib@npm:1.14.1"
checksum: dbe628ef87f66691d5d2959b3e41b9ca0045c3ee3c7c7b906cc1e328b39f199bb1ad9e671c39025bd56122ac57dfbf7385a94843b1cc07c60a4db74795829acd checksum: dbe628ef87f66691d5d2959b3e41b9ca0045c3ee3c7c7b906cc1e328b39f199bb1ad9e671c39025bd56122ac57dfbf7385a94843b1cc07c60a4db74795829acd