diff --git a/src/components/timeline.ts b/src/components/timeline.ts
index 43f8be2e..88562e37 100644
--- a/src/components/timeline.ts
+++ b/src/components/timeline.ts
@@ -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`
{
+ // 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 = createRef();
protected _timeline?: Timeline;
+ protected _boundTimelineSelectHandler = this._timelineSelectHandler.bind(this);
/**
* Master render method.
@@ -70,6 +107,53 @@ export class FrigateCardTimeline extends LitElement {
return html` `;
}
+ /**
+ * 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).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 `
+
+ `;
+ }
+
protected _buildDataset(): DataSet {
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
diff --git a/src/scss/timeline-event.scss b/src/scss/timeline-event.scss
new file mode 100644
index 00000000..3f974d39
--- /dev/null
+++ b/src/scss/timeline-event.scss
@@ -0,0 +1,18 @@
+:host {
+ display: block;
+ width: 100%;
+ height: 100%;
+}
+
+img {
+ width: 75px;
+ height: 75px;
+ box-shadow: 0px 0px 20px 5px var(--primary-background-color);
+ display: block;
+ border-radius: 5px;
+ transition: transform 0.2s linear;
+}
+
+img:hover {
+ transform: scale(1.04);
+}
diff --git a/src/scss/timeline.scss b/src/scss/timeline.scss
index eb7759dd..423ac747 100644
--- a/src/scss/timeline.scss
+++ b/src/scss/timeline.scss
@@ -1,7 +1,19 @@
-@use "vis-timeline/dist/vis-timeline-graph2d.css";
+@use 'vis-timeline/dist/vis-timeline-graph2d.css';
:host {
width: 100%;
height: 100%;
display: block;
-}
\ No newline at end of file
+}
+
+.vis-item {
+ border-color: var(--primary-color);
+}
+
+.vis-item.vis-box {
+ border-style: hidden;
+}
+
+.vis-item .vis-item-content {
+ padding: 0px;
+}