From 8c606b296ffa2283fade53d0d034b06d3f1fc002 Mon Sep 17 00:00:00 2001 From: Dermot Duffy Date: Tue, 28 Mar 2023 19:57:26 -0700 Subject: [PATCH] Add datepicker to timeline. --- package.json | 1 + rollup.config.js | 5 ++- src/components/date-picker.ts | 44 ++++++++++++++++++++++ src/components/timeline-core.ts | 61 ++++++++++++++++++++++--------- src/localize/languages/en.json | 1 + src/localize/languages/it.json | 1 + src/localize/languages/pt-BR.json | 1 + src/scss/date-picker.scss | 7 ++++ src/scss/timeline-core.scss | 5 ++- yarn.lock | 21 ++++++++++- 10 files changed, 126 insertions(+), 21 deletions(-) create mode 100644 src/components/date-picker.ts create mode 100644 src/scss/date-picker.scss diff --git a/package.json b/package.json index ffc3a4e1..84d69e84 100644 --- a/package.json +++ b/package.json @@ -31,6 +31,7 @@ "home-assistant-js-websocket": "^8.0.0", "keycharm": "^0.4.0", "lit": "^2.3.1", + "lit-flatpickr": "^0.4.0", "lodash-es": "^4.17.21", "moment": "^2.29.4", "propagating-hammerjs": "^2.0.1", diff --git a/rollup.config.js b/rollup.config.js index bc530a8f..821de314 100644 --- a/rollup.config.js +++ b/rollup.config.js @@ -91,11 +91,12 @@ const config = { }), }, plugins: plugins, - // These two files use this at the toplevel, which causes rollup warning - // spam on build: `this` has been rewritten to `undefined` + // These files use this at the toplevel, which causes rollup warning + // spam on build: `this` has been rewritten to `undefined`. moduleContext: { './node_modules/@formatjs/intl-utils/lib/src/diff.js': 'window', './node_modules/@formatjs/intl-utils/lib/src/resolve-locale.js': 'window', + './node_modules/flatpickr/dist/esm/index.js': 'window', }, }; diff --git a/src/components/date-picker.ts b/src/components/date-picker.ts new file mode 100644 index 00000000..36cdd277 --- /dev/null +++ b/src/components/date-picker.ts @@ -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 = createRef(); + + public open(): void { + this._refInput.value?.open(); + } + + protected render(): TemplateResult { + return html` { + if (dates.length) { + // This is a single date picker, there should be only a single date. + dispatchFrigateCardEvent(this, 'date-picker:change', { + date: dates[0], + }); + } + }} + >`; + } + + static get styles(): CSSResultGroup { + return unsafeCSS(datePickerStyle); + } +} + +declare global { + interface HTMLElementTagNameMap { + 'frigate-card-date-picker': FrigateCardDatePicker; + } +} diff --git a/src/components/timeline-core.ts b/src/components/timeline-core.ts index 11d53568..59bcb9ce 100644 --- a/src/components/timeline-core.ts +++ b/src/components/timeline-core.ts @@ -59,6 +59,10 @@ import { ViewMediaClassifier } from '../view/media-classifier'; import { rangesOverlap } from '../camera-manager/range'; import { View } from '../view/view'; 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 { id: string; @@ -191,7 +195,10 @@ export class FrigateCardTimelineCore extends LitElement { protected _locked = false; protected _targetBarVisible = false; + + protected _refDatePicker: Ref = createRef(); protected _refTimeline: Ref = createRef(); + protected _timeline?: Timeline; protected _timelineSource: TimelineDataSource | null = null; @@ -260,6 +267,10 @@ export class FrigateCardTimelineCore extends LitElement { } const capabilities = this.cameraManager?.getAggregateCameraCapabilities(cameraIDs); + const lockTitle = this._locked + ? localize('timeline.unlock') + : localize('timeline.lock'); + return html` ${capabilities?.supportsTimeline ? html`
- { - this._locked = !this._locked; - }} - aria-label="${this._locked - ? localize('timeline.unlock') - : localize('timeline.lock')}" - title="${this._locked - ? localize('timeline.unlock') - : localize('timeline.lock')}" - > - +
+ ) => { + this._timeline?.setWindow( + startOfDay(ev.detail.date), + endOfDay(ev.detail.date), + ); + }} + > + + { + this._refDatePicker.value?.open(); + }} + > + + { + this._locked = !this._locked; + }} + aria-label="${lockTitle}" + title="${lockTitle}" + > + +
` : ''}`; } @@ -896,9 +923,9 @@ export class FrigateCardTimelineCore extends LitElement { const mediaEndTime = media?.getEndTime(); const mediaWindow: TimelineWindow | null = media && mediaStartTime - // If this media has no end time, it's just a "point" in time so the - // range effectively starts/ends at the same time. - ? { start: mediaStartTime, end: mediaEndTime ?? mediaStartTime } + ? // If this media has no end time, it's just a "point" in time so the + // range effectively starts/ends at the same time. + { start: mediaStartTime, end: mediaEndTime ?? mediaStartTime } : null; const context = this.view.context?.timeline; diff --git a/src/localize/languages/en.json b/src/localize/languages/en.json index f1bc2bc0..daaed937 100644 --- a/src/localize/languages/en.json +++ b/src/localize/languages/en.json @@ -461,6 +461,7 @@ }, "timeline": { "lock": "Lock timeline to a single event", + "select_date": "Choose date", "unlock": "Unlock timeline" }, "elements": { diff --git a/src/localize/languages/it.json b/src/localize/languages/it.json index 802aab00..6aeec790 100644 --- a/src/localize/languages/it.json +++ b/src/localize/languages/it.json @@ -450,6 +450,7 @@ }, "timeline": { "lock": "", + "select_date": "", "unlock": "" }, "elements": { diff --git a/src/localize/languages/pt-BR.json b/src/localize/languages/pt-BR.json index 6498842a..334e16dd 100644 --- a/src/localize/languages/pt-BR.json +++ b/src/localize/languages/pt-BR.json @@ -450,6 +450,7 @@ }, "timeline": { "lock": "", + "select_date": "", "unlock": "" }, "elements": { diff --git a/src/scss/date-picker.scss b/src/scss/date-picker.scss new file mode 100644 index 00000000..4e336282 --- /dev/null +++ b/src/scss/date-picker.scss @@ -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; +} diff --git a/src/scss/timeline-core.scss b/src/scss/timeline-core.scss index 7b58c027..98b686db 100644 --- a/src/scss/timeline-core.scss +++ b/src/scss/timeline-core.scss @@ -141,11 +141,14 @@ div.vis-tooltip { pointer-events: none; } -ha-icon.lock { +.timeline-tools { position: absolute; right: 2px; bottom: 2px; color: var(--primary-color); z-index: 10; +} + +.timeline-tools ha-icon { cursor: pointer; } \ No newline at end of file diff --git a/yarn.lock b/yarn.lock index 465531ab..a2071f3b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2407,6 +2407,13 @@ __metadata: languageName: node 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": version: 3.2.7 resolution: "flatted@npm:3.2.7" @@ -2460,6 +2467,7 @@ __metadata: home-assistant-js-websocket: ^8.0.0 keycharm: ^0.4.0 lit: ^2.3.1 + lit-flatpickr: ^0.4.0 lodash-es: ^4.17.21 moment: ^2.29.4 prettier: ^2.6.0 @@ -3327,6 +3335,17 @@ __metadata: languageName: node 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": version: 2.6.1 resolution: "lit-html@npm:2.6.1" @@ -5160,7 +5179,7 @@ __metadata: languageName: node linkType: hard -"tslib@npm:^1.8.1": +"tslib@npm:^1.11.0, tslib@npm:^1.8.1": version: 1.14.1 resolution: "tslib@npm:1.14.1" checksum: dbe628ef87f66691d5d2959b3e41b9ca0045c3ee3c7c7b906cc1e328b39f199bb1ad9e671c39025bd56122ac57dfbf7385a94843b1cc07c60a4db74795829acd