Add drawer component and support side thumbnails.
This commit is contained in:
+3
-2
@@ -24,16 +24,17 @@
|
||||
"@types/bluebird": "^3.5.36",
|
||||
"component-emitter": "^1.3.0",
|
||||
"crypto": "^1.0.1",
|
||||
"custom-card-helpers": "^1.8.0",
|
||||
"custom-card-helpers": "^1.9.0",
|
||||
"embla-carousel": "^6.1.1",
|
||||
"home-assistant-js-websocket": "^6.1.1",
|
||||
"lit": "^2.2.1",
|
||||
"keycharm": "^0.4.0",
|
||||
"lit": "^2.2.1",
|
||||
"lodash-es": "^4.17.21",
|
||||
"moment": "^2.29.1",
|
||||
"propagating-hammerjs": "^2.0.1",
|
||||
"quick-lru": "^6.1.0",
|
||||
"screenfull": "^6.0.1",
|
||||
"side-drawer": "^3.0.0",
|
||||
"ts-toolbelt": "^9.6.0",
|
||||
"uuid": "^8.3.2",
|
||||
"vis-data": "^7.1.3",
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
import { CSSResultGroup, LitElement, unsafeCSS, PropertyValues } from 'lit';
|
||||
import { property } from 'lit/decorators.js';
|
||||
|
||||
import EmblaCarousel, {
|
||||
EmblaCarouselType,
|
||||
EmblaOptionsType,
|
||||
@@ -15,6 +17,9 @@ export interface CarouselSelect {
|
||||
}
|
||||
|
||||
export class FrigateCardCarousel extends LitElement {
|
||||
@property({ attribute: true, reflect: true })
|
||||
public direction: 'vertical' | 'horizontal' = 'horizontal';
|
||||
|
||||
protected _carousel?: EmblaCarouselType;
|
||||
protected _plugins: Record<string, EmblaPluginType> = {};
|
||||
|
||||
@@ -98,7 +103,13 @@ export class FrigateCardCarousel extends LitElement {
|
||||
return acc;
|
||||
}, {});
|
||||
|
||||
this._carousel = EmblaCarousel(carouselNode, this._getOptions(), plugins);
|
||||
this._carousel = EmblaCarousel(
|
||||
carouselNode,
|
||||
{
|
||||
axis: this.direction == 'horizontal' ? 'x' : 'y',
|
||||
...this._getOptions()
|
||||
},
|
||||
plugins);
|
||||
this._carousel.on('init', () => dispatchFrigateCardEvent(this, 'carousel:init'));
|
||||
this._carousel.on('select', () => {
|
||||
const selected = this.carouselSelected();
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
import {
|
||||
CSSResultGroup,
|
||||
LitElement,
|
||||
TemplateResult,
|
||||
html,
|
||||
unsafeCSS,
|
||||
PropertyValues,
|
||||
} from 'lit';
|
||||
import { customElement, property } from 'lit/decorators.js';
|
||||
import { createRef, ref, Ref } from 'lit/directives/ref.js';
|
||||
import 'side-drawer';
|
||||
|
||||
import drawerStyle from '../scss/drawer.scss';
|
||||
import drawerInjectStyle from '../scss/drawer-inject.scss';
|
||||
|
||||
@customElement('frigate-card-drawer')
|
||||
export class FrigateCardDrawer extends LitElement {
|
||||
@property({ attribute: true, reflect: true })
|
||||
public location: 'left' | 'right' = 'left';
|
||||
|
||||
/**
|
||||
* Set the timeline configuration.
|
||||
*/
|
||||
@property({ type: Boolean, reflect: true, attribute: true })
|
||||
set open(open: boolean) {
|
||||
if (this._drawerRef.value) {
|
||||
const old = this._drawerRef.value.open;
|
||||
this._drawerRef.value.open = open;
|
||||
this.requestUpdate('open', old);
|
||||
}
|
||||
}
|
||||
|
||||
get open(): boolean {
|
||||
return this._drawerRef.value?.open ?? false;
|
||||
}
|
||||
|
||||
protected _drawerRef: Ref<HTMLElement & { open: boolean }> = createRef();
|
||||
|
||||
/**
|
||||
* Called on the first update.
|
||||
* @param changedProps The changed properties.
|
||||
*/
|
||||
protected firstUpdated(changedProps: PropertyValues): void {
|
||||
super.firstUpdated(changedProps);
|
||||
|
||||
// The `side-drawer` component (and the material drawer for that matter)
|
||||
// only do fixed drawers (i.e. a drawer for the whole viewport). Hackily
|
||||
// override the style to customize the drawer to be absolute within the div.
|
||||
const style = document.createElement('style');
|
||||
style.innerHTML = drawerInjectStyle;
|
||||
this._drawerRef.value?.shadowRoot?.appendChild(style);
|
||||
}
|
||||
|
||||
protected render(): TemplateResult {
|
||||
return html` <side-drawer location="${this.location}" ${ref(this._drawerRef)}>
|
||||
<slot></slot>
|
||||
</side-drawer>`;
|
||||
}
|
||||
|
||||
static get styles(): CSSResultGroup {
|
||||
return unsafeCSS(drawerStyle);
|
||||
}
|
||||
}
|
||||
@@ -1,11 +1,14 @@
|
||||
import { BrowseMediaUtil } from '../browse-media-util.js';
|
||||
import { CSSResultGroup, TemplateResult, html, unsafeCSS } from 'lit';
|
||||
import { CSSResultGroup, TemplateResult, html, unsafeCSS, PropertyValues } from 'lit';
|
||||
import { EmblaOptionsType } from 'embla-carousel';
|
||||
import { customElement, property } from 'lit/decorators.js';
|
||||
|
||||
import type { FrigateBrowseMediaSource, ThumbnailsControlConfig } from '../types.js';
|
||||
import { FrigateCardCarousel } from './carousel.js';
|
||||
import { dispatchFrigateCardEvent, stopEventFromActivatingCardWideActions } from '../common.js';
|
||||
import {
|
||||
dispatchFrigateCardEvent,
|
||||
stopEventFromActivatingCardWideActions,
|
||||
} from '../common.js';
|
||||
|
||||
import thumbnailCarouselStyle from '../scss/thumbnail-carousel.scss';
|
||||
|
||||
@@ -18,7 +21,7 @@ export interface ThumbnailCarouselTap {
|
||||
@customElement('frigate-card-thumbnail-carousel')
|
||||
export class FrigateCardThumbnailCarousel extends FrigateCardCarousel {
|
||||
@property({ attribute: false })
|
||||
protected target?: FrigateBrowseMediaSource;
|
||||
public target?: FrigateBrowseMediaSource;
|
||||
|
||||
protected _tapSelected?;
|
||||
|
||||
@@ -90,6 +93,17 @@ export class FrigateCardThumbnailCarousel extends FrigateCardCarousel {
|
||||
return slides;
|
||||
}
|
||||
|
||||
/**
|
||||
* The updated lifecycle callback for this element.
|
||||
* @param changedProperties The properties that were changed in this render.
|
||||
*/
|
||||
updated(changedProperties: PropertyValues): void {
|
||||
if (this._carousel && changedProperties.has('target')) {
|
||||
this._destroyCarousel();
|
||||
}
|
||||
super.updated(changedProperties);
|
||||
}
|
||||
|
||||
/**
|
||||
* Render a given thumbnail.
|
||||
* @param mediaToRender The media item to render.
|
||||
|
||||
+14
-1
@@ -23,11 +23,19 @@ img,video {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
|
||||
flex-direction: column;
|
||||
|
||||
user-select: none;
|
||||
-webkit-touch-callout: none;
|
||||
-khtml-user-select: none;
|
||||
-webkit-tap-highlight-color: transparent;
|
||||
}
|
||||
:host([direction="vertical"]) .embla__container {
|
||||
flex-direction: column;
|
||||
}
|
||||
:host([direction="horizontal"]) .embla__container {
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
.embla__viewport {
|
||||
width: 100%;
|
||||
@@ -50,9 +58,14 @@ img,video {
|
||||
.embla__slide {
|
||||
position: relative;
|
||||
height: 100%;
|
||||
margin-right: 5px;
|
||||
overflow: visible;
|
||||
}
|
||||
:host([direction="vertical"]) .embla__slide {
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
:host([direction="horizontal"]) .embla__slide {
|
||||
margin-right: 5px;
|
||||
}
|
||||
.embla__slide img,video {
|
||||
// Letterbox media. <frigate-card-ha-hls-player> has similar added directly in
|
||||
// its element.
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
:host {
|
||||
// Drawer width sizes to contents.
|
||||
width: unset;
|
||||
};
|
||||
|
||||
#d, #fs {
|
||||
// Override width/height to be 100% instead of 100v[wh].
|
||||
height: 100%;
|
||||
|
||||
// Position absolutely.
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
:host([location=right]) #d {
|
||||
// Position to the right.
|
||||
left: unset;
|
||||
right: 0;
|
||||
transform: translateX(100%);
|
||||
};
|
||||
|
||||
:host([location=right][open]) #d {
|
||||
transform: none;
|
||||
box-shadow: 0px 0px 25px 0px rgba(0, 0, 0, 0.5);
|
||||
}
|
||||
|
||||
#fs {
|
||||
width: 100%;
|
||||
inset: 0;
|
||||
}
|
||||
|
||||
#ifs {
|
||||
// Override width/height to be 100% instead of 100v[wh].
|
||||
height: 100%;
|
||||
};
|
||||
@@ -0,0 +1,3 @@
|
||||
side-drawer {
|
||||
background-color: var(--card-background-color);
|
||||
}
|
||||
@@ -6,6 +6,9 @@
|
||||
display: block;
|
||||
background-color: var(--card-background-color);
|
||||
padding-bottom: 5px;
|
||||
|
||||
// So that absolute sidedrawer is relative to this host.
|
||||
position: relative;
|
||||
}
|
||||
|
||||
div.timeline {
|
||||
|
||||
Reference in New Issue
Block a user