import { CSSResultGroup, html, LitElement, PropertyValues, TemplateResult, unsafeCSS, } from 'lit'; import { customElement, property } from 'lit/decorators.js'; import { classMap } from 'lit/directives/class-map.js'; import { CameraManager } from '../camera-manager/manager.js'; import { ThumbnailsControlConfig } from '../config/types.js'; import thumbnailCarouselStyle from '../scss/thumbnail-carousel.scss'; import { ExtendedHomeAssistant } from '../types.js'; import { stopEventFromActivatingCardWideActions } from '../utils/action.js'; import { dispatchFrigateCardEvent } from '../utils/basic.js'; import { CarouselDirection } from '../utils/embla/carousel-controller.js'; import AutoSize from '../utils/embla/plugins/auto-size/auto-size.js'; import { MediaQueriesResults } from '../view/media-queries-results'; import { View } from '../view/view.js'; import './carousel.js'; import './thumbnail.js'; export interface ThumbnailCarouselTap { queryResults: MediaQueriesResults; } @customElement('frigate-card-thumbnail-carousel') export class FrigateCardThumbnailCarousel extends LitElement { @property({ attribute: false }) public hass?: ExtendedHomeAssistant; @property({ attribute: false }) public view?: Readonly; @property({ attribute: false }) public cameraManager?: CameraManager; @property({ attribute: false }) public config?: ThumbnailsControlConfig; @property({ attribute: false }) public fadeThumbnails = false; protected _thumbnailSlides: TemplateResult[] = []; protected _plugins = [AutoSize()]; protected willUpdate(changedProps: PropertyValues): void { if (changedProps.has('config')) { if (this.config?.size) { this.style.setProperty('--frigate-card-thumbnail-size', `${this.config.size}px`); } const direction = this._getDirection(); if (direction) { this.setAttribute('direction', direction); } else { this.removeAttribute('direction'); } } const renderProperties = [ 'cameraManager', 'config', 'transitionEffect', 'view', ] as const; if (renderProperties.some((prop) => changedProps.has(prop))) { this._thumbnailSlides = this._renderSlides(); } if (changedProps.has('view')) { this.style.setProperty( '--frigate-card-carousel-thumbnail-opacity', !this.fadeThumbnails || this._getSelectedSlide() === null ? '1.0' : '0.4', ); } } protected _getSelectedSlide(view?: View): number | null { return (view ?? this.view)?.queryResults?.getSelectedIndex() ?? null; } protected _renderSlides(): TemplateResult[] { const slides: TemplateResult[] = []; const seekTarget = this.view?.context?.mediaViewer?.seek; const selectedIndex = this._getSelectedSlide(); for (const media of this.view?.queryResults?.getResults() ?? []) { const index = slides.length; const classes = { embla__slide: true, 'slide-selected': selectedIndex === index, }; slides.push(html` { if (this.view && this.view.queryResults) { dispatchFrigateCardEvent( this, 'thumbnail-carousel:tap', { queryResults: this.view.queryResults.clone().selectIndex(index), }, ); } stopEventFromActivatingCardWideActions(ev); }} > `); } return slides; } protected _getDirection(): CarouselDirection | null { if (this.config?.mode === 'left' || this.config?.mode === 'right') { return 'vertical'; } else if (this.config?.mode === 'above' || this.config?.mode === 'below') { return 'horizontal'; } return null; } protected render(): TemplateResult | void { const direction = this._getDirection(); if (!this._thumbnailSlides.length || !this.config || !direction) { return; } return html` ${this._thumbnailSlides} `; } static get styles(): CSSResultGroup { return unsafeCSS(thumbnailCarouselStyle); } } declare global { interface HTMLElementTagNameMap { 'frigate-card-thumbnail-carousel': FrigateCardThumbnailCarousel; } }