Add styling and interactivity.

This commit is contained in:
Dermot Duffy
2022-03-19 09:00:21 -07:00
parent b9cef866c9
commit 83a25e5b79
3 changed files with 131 additions and 4 deletions
+99 -2
View File
@@ -13,11 +13,13 @@ import { customElement, property } from 'lit/decorators.js';
import { createRef, ref, Ref } from 'lit/directives/ref';
import { BrowseMediaUtil } from '../browse-media-util';
import { CameraConfig, ExtendedHomeAssistant } from '../types';
import { CameraConfig, ExtendedHomeAssistant, FrigateBrowseMediaSource } from '../types';
import { View } from '../view';
import { dispatchFrigateCardEvent } from '../common.js';
import { renderProgressIndicator } from './message';
import timelineStyle from '../scss/timeline.scss';
import timelineEventStyle from '../scss/timeline-event.scss';
interface FrigateCardTimelineData {
id: string;
@@ -25,6 +27,40 @@ interface FrigateCardTimelineData {
start: number;
}
@customElement('frigate-card-timeline-event')
export class FrigateCardTimelineEvent extends LitElement {
@property({ attribute: true })
protected media_id?: string;
@property({ attribute: true })
protected thumbnail?: string;
@property({ attribute: true })
protected label?: string;
protected render(): TemplateResult | void {
if (!this.thumbnail) {
return;
}
return html`<img
@click=${() => {
// The view is not accessible from here, since this element is created
// from a string (see _buildEventContent below), so instead we emit an
// intermediate event that is caught by the timeline.
dispatchFrigateCardEvent(this, 'timeline-select', this.media_id);
}}
src="${this.thumbnail}"
title="${this.label || ''}"
aria-label="${this.label || ''}"
/>`;
}
static get styles(): CSSResultGroup {
return unsafeCSS(timelineEventStyle);
}
}
@customElement('frigate-card-timeline')
export class FrigateCardTimeline extends LitElement {
@property({ attribute: false })
@@ -38,6 +74,7 @@ export class FrigateCardTimeline extends LitElement {
protected _timelineRef: Ref<HTMLElement> = createRef();
protected _timeline?: Timeline;
protected _boundTimelineSelectHandler = this._timelineSelectHandler.bind(this);
/**
* Master render method.
@@ -70,6 +107,53 @@ export class FrigateCardTimeline extends LitElement {
return html` <div id="timeline" ${ref(this._timelineRef)}></div>`;
}
/**
* Component connected callback.
*/
connectedCallback(): void {
super.connectedCallback();
document.addEventListener(
'frigate-card:timeline-select',
this._boundTimelineSelectHandler,
);
}
/**
* Component disconnected callback.
*/
disconnectedCallback(): void {
document.removeEventListener(
'frigate-card:timeline-select',
this._boundTimelineSelectHandler,
);
super.disconnectedCallback();
}
protected _timelineSelectHandler(ev: Event): void {
const id = (ev as CustomEvent<string>).detail;
const index =
this.view?.target?.children?.findIndex((item) => item.media_content_id == id) ??
-1;
if (index >= 0) {
this.view
?.evolve({
view: 'clip',
childIndex: index,
})
.dispatchChangeEvent(this);
}
}
protected _buildEventContent(source: FrigateBrowseMediaSource): string {
return `
<frigate-card-timeline-event
media_id=${source.media_content_id}
thumbnail="${source.thumbnail}"
label="${source.title}"
>
</frigate-card-timeline-event>`;
}
protected _buildDataset(): DataSet<FrigateCardTimelineData> {
const items: FrigateCardTimelineData[] = [];
@@ -77,8 +161,9 @@ export class FrigateCardTimeline extends LitElement {
if (child.frigate) {
const item = {
id: child.media_content_id,
content: child.frigate.event.id,
content: this._buildEventContent(child),
start: child.frigate.event.start_time * 1000,
selectable: false,
};
if (child.frigate.event.end_time) {
//item['end'] = child.frigate.event.end_time * 1000;
@@ -94,6 +179,18 @@ export class FrigateCardTimeline extends LitElement {
// Configuration for the Timeline
const options = {
minHeight: '300px',
margin: {
item: 75 + 10,
axis: 75 + 10,
},
xss: {
disabled: false,
filterOptions: {
whiteList: {
'frigate-card-timeline-event': ['thumbnail', 'label', 'media_id'],
},
},
},
};
// Create a Timeline