Add media title popups.
This commit is contained in:
+2
-2
@@ -143,10 +143,10 @@ export class FrigateCard extends LitElement {
|
||||
protected _conditionState?: ConditionState;
|
||||
|
||||
@query('frigate-card-menu')
|
||||
_menu!: FrigateCardMenu;
|
||||
protected _menu!: FrigateCardMenu;
|
||||
|
||||
@query('frigate-card-elements')
|
||||
_elements?: FrigateCardElements;
|
||||
protected _elements?: FrigateCardElements;
|
||||
|
||||
// user interaction timer ("screensaver" functionality, return to default
|
||||
// view after user interaction).
|
||||
|
||||
+15
-2
@@ -21,6 +21,7 @@ import {
|
||||
} from '../types.js';
|
||||
import { EmblaOptionsType, EmblaPluginType } from 'embla-carousel';
|
||||
import { HomeAssistant } from 'custom-card-helpers';
|
||||
import JSMpeg from '@cycjimmy/jsmpeg-player';
|
||||
import { Ref, createRef, ref } from 'lit/directives/ref.js';
|
||||
import { Task } from '@lit-labs/task';
|
||||
import { customElement, property, state } from 'lit/decorators.js';
|
||||
@@ -47,7 +48,8 @@ import {
|
||||
} from '../common.js';
|
||||
import { renderProgressIndicator } from '../components/message.js';
|
||||
|
||||
import JSMpeg from '@cycjimmy/jsmpeg-player';
|
||||
import './next-prev-control.js';
|
||||
import './title-control.js';
|
||||
|
||||
import liveStyle from '../scss/live.scss';
|
||||
import liveFrigateStyle from '../scss/live-frigate.scss';
|
||||
@@ -471,7 +473,7 @@ export class FrigateCardLiveCarousel extends FrigateCardMediaCarousel {
|
||||
protected render(): TemplateResult | void {
|
||||
const [slides, cameraToSlide] = this._getSlides();
|
||||
this._cameraToSlide = cameraToSlide;
|
||||
if (!slides || !this.liveConfig) {
|
||||
if (!slides || !this.liveConfig || !this.cameras || !this.view) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -482,6 +484,8 @@ export class FrigateCardLiveCarousel extends FrigateCardMediaCarousel {
|
||||
) as LiveConfig;
|
||||
|
||||
const [prev, next] = this._getCameraNeighbors();
|
||||
const title = getCameraTitle(this.hass, this.cameras.get(this.view.camera));
|
||||
|
||||
return html`
|
||||
<div class="embla">
|
||||
<frigate-card-next-previous-control
|
||||
@@ -512,6 +516,15 @@ export class FrigateCardLiveCarousel extends FrigateCardMediaCarousel {
|
||||
>
|
||||
</frigate-card-next-previous-control>
|
||||
</div>
|
||||
<frigate-card-title-control
|
||||
${ref(this._titleControlRef)}
|
||||
.config=${config.controls.title}
|
||||
.text="${title
|
||||
? `${localize('common.live')}: ${title}`
|
||||
: ''}"
|
||||
.fitInto=${this as HTMLElement}
|
||||
>
|
||||
</frigate-card-title-control>
|
||||
`;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,6 +15,7 @@ import './next-prev-control.js';
|
||||
import mediaCarouselStyle from '../scss/media-carousel.scss';
|
||||
|
||||
import { FrigateCardNextPreviousControl } from './next-prev-control.js';
|
||||
import { FrigateCardTitleControl } from './title-control.js';
|
||||
import { MediaAutoPlayPauseType } from './embla-plugins/media-autoplay.js';
|
||||
|
||||
const getEmptyImageSrc = (width: number, height: number) =>
|
||||
@@ -27,7 +28,8 @@ export class FrigateCardMediaCarousel extends FrigateCardCarousel {
|
||||
protected _mediaShowInfo: Record<number, MediaShowInfo> = {};
|
||||
protected _nextControlRef: Ref<FrigateCardNextPreviousControl> = createRef();
|
||||
protected _previousControlRef: Ref<FrigateCardNextPreviousControl> = createRef();
|
||||
|
||||
protected _titleControlRef: Ref<FrigateCardTitleControl> = createRef();
|
||||
protected _titleTimerID: number | null = null;
|
||||
/**
|
||||
* Play the media on the selected slide. May be overridden to control when
|
||||
* autoplay should happen.
|
||||
@@ -36,6 +38,32 @@ export class FrigateCardMediaCarousel extends FrigateCardCarousel {
|
||||
(this._plugins['MediaAutoPlayPause'] as MediaAutoPlayPauseType | undefined)?.play();
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the media title after the media loads.
|
||||
*/
|
||||
protected _titleHandler(): void {
|
||||
const show = () => {
|
||||
this._titleTimerID = null;
|
||||
this._titleControlRef.value?.show();
|
||||
};
|
||||
|
||||
if (this._titleTimerID) {
|
||||
window.clearTimeout(this._titleTimerID);
|
||||
}
|
||||
if (this._titleControlRef.value?.isVisible()) {
|
||||
// If it's already visible, update it immediately (but also update it
|
||||
// after the timer expires to ensure it re-positions if necessary, see
|
||||
// comment below).
|
||||
show();
|
||||
}
|
||||
|
||||
// Allow a brief pause after the media loads, but before the title is
|
||||
// displayed. This allows for a pleasant appearance/disappear of the title,
|
||||
// and allows for the browser to finish rendering the carousel (inc.
|
||||
// adaptive height which has `0.5s ease`, see `media-carousel.scss`).
|
||||
this._titleTimerID = window.setTimeout(show, 0.5 * 1000);
|
||||
}
|
||||
|
||||
/**
|
||||
* Component connected callback.
|
||||
*/
|
||||
@@ -43,6 +71,7 @@ export class FrigateCardMediaCarousel extends FrigateCardCarousel {
|
||||
super.connectedCallback();
|
||||
this.addEventListener('frigate-card:media-show', this._autoplayHandler);
|
||||
this.addEventListener('frigate-card:media-show', this._adaptiveHeightHandler);
|
||||
this.addEventListener('frigate-card:media-show', this._titleHandler);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -52,6 +81,7 @@ export class FrigateCardMediaCarousel extends FrigateCardCarousel {
|
||||
super.disconnectedCallback();
|
||||
this.removeEventListener('frigate-card:media-show', this._autoplayHandler);
|
||||
this.removeEventListener('frigate-card:media-show', this._adaptiveHeightHandler);
|
||||
this.removeEventListener('frigate-card:media-show', this._titleHandler);
|
||||
}
|
||||
|
||||
protected _destroyCarousel(): void {
|
||||
@@ -93,7 +123,7 @@ export class FrigateCardMediaCarousel extends FrigateCardCarousel {
|
||||
* actually the media load/show that will change the dimensions, and that is
|
||||
* async from carousel actions (e.g. lazy-loaded media).
|
||||
*/
|
||||
protected _adaptiveHeightHandler(): void {
|
||||
protected _adaptiveHeightHandler(): void {
|
||||
const adaptCarouselHeight = (): void => {
|
||||
if (!this._carousel) {
|
||||
return;
|
||||
|
||||
@@ -0,0 +1,85 @@
|
||||
import { CSSResultGroup, LitElement, TemplateResult, html, unsafeCSS } from 'lit';
|
||||
import { createRef, ref, Ref } from 'lit/directives/ref';
|
||||
import { customElement, property } from 'lit/decorators.js';
|
||||
|
||||
import { TitleControlConfig } from '../types.js';
|
||||
|
||||
import titleStyle from '../scss/title-control.scss';
|
||||
|
||||
type PaperToast = HTMLElement & {
|
||||
opened: boolean;
|
||||
};
|
||||
|
||||
@customElement('frigate-card-title-control')
|
||||
export class FrigateCardTitleControl extends LitElement {
|
||||
@property({ attribute: false })
|
||||
public config?: TitleControlConfig;
|
||||
|
||||
@property({ attribute: false })
|
||||
public text?: string;
|
||||
|
||||
@property({ attribute: false })
|
||||
public fitInto?: HTMLElement;
|
||||
|
||||
protected _toastRef: Ref<PaperToast> = createRef();
|
||||
|
||||
/**
|
||||
* Master render method.
|
||||
* @returns A rendered template.
|
||||
*/
|
||||
protected render(): TemplateResult {
|
||||
if (!this.text || !this.config || this.config.mode == 'none' || !this.fitInto) {
|
||||
return html``;
|
||||
}
|
||||
|
||||
const verticalAlign = this.config.mode.match(/-top-/) ? 'top' : 'bottom';
|
||||
const horizontalAlign = this.config.mode.match(/-left$/) ? 'left' : 'right';
|
||||
|
||||
return html` <paper-toast
|
||||
${ref(this._toastRef)}
|
||||
class="capsule"
|
||||
.duration=${this.config.duration_seconds * 1000}
|
||||
.verticalAlign=${verticalAlign}
|
||||
.horizontalAlign=${horizontalAlign}
|
||||
.text="${this.text}"
|
||||
.fitInto=${this.fitInto}
|
||||
>
|
||||
</paper-toast>`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the toast is visible.
|
||||
* @returns `true` if the toast is visible, `false` otherwise.
|
||||
*/
|
||||
public isVisible(): boolean {
|
||||
return this._toastRef.value?.opened ?? false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the toast.
|
||||
*/
|
||||
public hide(): void {
|
||||
if (this._toastRef.value) {
|
||||
// Set it to false first, to ensure the timer resets.
|
||||
this._toastRef.value.opened = false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the toast.
|
||||
*/
|
||||
public show(): void {
|
||||
if (this._toastRef.value) {
|
||||
// Set it to false first, to ensure the timer resets.
|
||||
this._toastRef.value.opened = false;
|
||||
this._toastRef.value.opened = true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get element styles.
|
||||
*/
|
||||
static get styles(): CSSResultGroup {
|
||||
return unsafeCSS(titleStyle);
|
||||
}
|
||||
}
|
||||
+35
-25
@@ -41,6 +41,7 @@ import {
|
||||
import { renderProgressIndicator } from '../components/message.js';
|
||||
|
||||
import './next-prev-control.js';
|
||||
import './title-control.js';
|
||||
|
||||
import viewerStyle from '../scss/viewer.scss';
|
||||
import viewerCoreStyle from '../scss/viewer-core.scss';
|
||||
@@ -628,32 +629,41 @@ export class FrigateCardViewerCarousel extends FrigateCardMediaCarousel {
|
||||
const [prev, next] = [neighbors?.previous, neighbors?.next];
|
||||
|
||||
return html`<div class="embla">
|
||||
<frigate-card-next-previous-control
|
||||
${ref(this._previousControlRef)}
|
||||
.direction=${'previous'}
|
||||
.controlConfig=${this.viewerConfig?.controls.next_previous}
|
||||
.thumbnail=${prev && prev.thumbnail ? prev.thumbnail : undefined}
|
||||
.label=${prev ? prev.title : ''}
|
||||
?disabled=${!prev}
|
||||
@click=${() => {
|
||||
this._nextPreviousHandler('previous');
|
||||
}}
|
||||
></frigate-card-next-previous-control>
|
||||
<div class="embla__viewport">
|
||||
<div class="embla__container">${slides}</div>
|
||||
<frigate-card-next-previous-control
|
||||
${ref(this._previousControlRef)}
|
||||
.direction=${'previous'}
|
||||
.controlConfig=${this.viewerConfig?.controls.next_previous}
|
||||
.thumbnail=${prev && prev.thumbnail ? prev.thumbnail : undefined}
|
||||
.label=${prev ? prev.title : ''}
|
||||
?disabled=${!prev}
|
||||
@click=${() => {
|
||||
this._nextPreviousHandler('previous');
|
||||
}}
|
||||
></frigate-card-next-previous-control>
|
||||
<div class="embla__viewport">
|
||||
<div class="embla__container">${slides}</div>
|
||||
</div>
|
||||
<frigate-card-next-previous-control
|
||||
${ref(this._nextControlRef)}
|
||||
.direction=${'next'}
|
||||
.controlConfig=${this.viewerConfig?.controls.next_previous}
|
||||
.thumbnail=${next && next.thumbnail ? next.thumbnail : undefined}
|
||||
.label=${next ? next.title : ''}
|
||||
?disabled=${!next}
|
||||
@click=${() => {
|
||||
this._nextPreviousHandler('next');
|
||||
}}
|
||||
></frigate-card-next-previous-control>
|
||||
</div>
|
||||
<frigate-card-next-previous-control
|
||||
${ref(this._nextControlRef)}
|
||||
.direction=${'next'}
|
||||
.controlConfig=${this.viewerConfig?.controls.next_previous}
|
||||
.thumbnail=${next && next.thumbnail ? next.thumbnail : undefined}
|
||||
.label=${next ? next.title : ''}
|
||||
?disabled=${!next}
|
||||
@click=${() => {
|
||||
this._nextPreviousHandler('next');
|
||||
}}
|
||||
></frigate-card-next-previous-control>
|
||||
</div>`;
|
||||
${this.view?.media
|
||||
? html` <frigate-card-title-control
|
||||
${ref(this._titleControlRef)}
|
||||
.config=${this.viewerConfig?.controls.title}
|
||||
.text="${this.view.media.title}"
|
||||
.fitInto=${this as HTMLElement}
|
||||
>
|
||||
</frigate-card-title-control>`
|
||||
: ``} `;
|
||||
}
|
||||
|
||||
protected _renderMediaItem(
|
||||
|
||||
@@ -43,6 +43,10 @@ export const CONF_EVENT_VIEWER_CONTROLS_THUMBNAILS_MODE =
|
||||
`${CONF_EVENT_VIEWER}.controls.thumbnails.mode` as const;
|
||||
export const CONF_EVENT_VIEWER_CONTROLS_THUMBNAILS_SIZE =
|
||||
`${CONF_EVENT_VIEWER}.controls.thumbnails.size` as const;
|
||||
export const CONF_EVENT_VIEWER_CONTROLS_TITLE_MODE =
|
||||
`${CONF_EVENT_VIEWER}.controls.title.mode` as const;
|
||||
export const CONF_EVENT_VIEWER_CONTROLS_TITLE_DURATION_SECONDS =
|
||||
`${CONF_EVENT_VIEWER}.controls.title.duration_seconds` as const;
|
||||
|
||||
export const CONF_LIVE = 'live' as const;
|
||||
export const CONF_LIVE_CONTROLS_NEXT_PREVIOUS_STYLE =
|
||||
@@ -55,6 +59,10 @@ export const CONF_LIVE_CONTROLS_THUMBNAILS_MODE =
|
||||
`${CONF_LIVE}.controls.thumbnails.mode` as const;
|
||||
export const CONF_LIVE_CONTROLS_THUMBNAILS_SIZE =
|
||||
`${CONF_LIVE}.controls.thumbnails.size` as const;
|
||||
export const CONF_LIVE_CONTROLS_TITLE_MODE =
|
||||
`${CONF_LIVE}.controls.title.mode` as const;
|
||||
export const CONF_LIVE_CONTROLS_TITLE_DURATION_SECONDS =
|
||||
`${CONF_LIVE}.controls.title.duration_seconds` as const;
|
||||
export const CONF_LIVE_DRAGGABLE = `${CONF_LIVE}.draggable` as const;
|
||||
export const CONF_LIVE_JSMPEG = `${CONF_LIVE}.jsmpeg` as const;
|
||||
export const CONF_LIVE_LAZY_LOAD = `${CONF_LIVE}.lazy_load` as const;
|
||||
|
||||
+36
-1
@@ -33,6 +33,8 @@ import {
|
||||
CONF_EVENT_VIEWER_CONTROLS_NEXT_PREVIOUS_STYLE,
|
||||
CONF_EVENT_VIEWER_CONTROLS_THUMBNAILS_MODE,
|
||||
CONF_EVENT_VIEWER_CONTROLS_THUMBNAILS_SIZE,
|
||||
CONF_EVENT_VIEWER_CONTROLS_TITLE_DURATION_SECONDS,
|
||||
CONF_EVENT_VIEWER_CONTROLS_TITLE_MODE,
|
||||
CONF_EVENT_VIEWER_DRAGGABLE,
|
||||
CONF_EVENT_VIEWER_LAZY_LOAD,
|
||||
CONF_IMAGE_REFRESH_SECONDS,
|
||||
@@ -42,6 +44,8 @@ import {
|
||||
CONF_LIVE_CONTROLS_THUMBNAILS_MEDIA,
|
||||
CONF_LIVE_CONTROLS_THUMBNAILS_MODE,
|
||||
CONF_LIVE_CONTROLS_THUMBNAILS_SIZE,
|
||||
CONF_LIVE_CONTROLS_TITLE_DURATION_SECONDS,
|
||||
CONF_LIVE_CONTROLS_TITLE_MODE,
|
||||
CONF_LIVE_DRAGGABLE,
|
||||
CONF_LIVE_LAZY_LOAD,
|
||||
CONF_LIVE_LAZY_UNLOAD,
|
||||
@@ -233,6 +237,21 @@ export class FrigateCardEditor extends LitElement implements LovelaceCardEditor
|
||||
['snapshots', localize('config.live.controls.thumbnails.medias.snapshots')],
|
||||
]);
|
||||
|
||||
protected _titleModes = new Map([
|
||||
['', ''],
|
||||
['none', localize('config.event_viewer.controls.title.modes.none')],
|
||||
['popup-top-left', localize('config.event_viewer.controls.title.modes.popup-top-left')],
|
||||
['popup-top-right', localize('config.event_viewer.controls.title.modes.popup-top-right')],
|
||||
[
|
||||
'popup-bottom-left',
|
||||
localize('config.event_viewer.controls.title.modes.popup-bottom-left'),
|
||||
],
|
||||
[
|
||||
'popup-bottom-right',
|
||||
localize('config.event_viewer.controls.title.modes.popup-bottom-right'),
|
||||
],
|
||||
]);
|
||||
|
||||
public setConfig(config: RawFrigateCardConfig): void {
|
||||
// Note: This does not use Zod to parse the configuration, so it may be
|
||||
// partially or completely invalid. It's more useful to have a partially
|
||||
@@ -752,6 +771,14 @@ export class FrigateCardEditor extends LitElement implements LovelaceCardEditor
|
||||
this._thumbnailMedias,
|
||||
)}
|
||||
${this._renderStringInput(CONF_LIVE_CONTROLS_THUMBNAILS_SIZE)}
|
||||
${this._renderDropdown(
|
||||
CONF_LIVE_CONTROLS_TITLE_MODE,
|
||||
this._titleModes,
|
||||
)}
|
||||
${this._renderStringInput(
|
||||
CONF_LIVE_CONTROLS_TITLE_DURATION_SECONDS,
|
||||
'number',
|
||||
)}
|
||||
</div>
|
||||
`
|
||||
: ''}
|
||||
@@ -792,6 +819,14 @@ export class FrigateCardEditor extends LitElement implements LovelaceCardEditor
|
||||
this._thumbnailModes,
|
||||
)}
|
||||
${this._renderStringInput(CONF_EVENT_VIEWER_CONTROLS_THUMBNAILS_SIZE)}
|
||||
${this._renderDropdown(
|
||||
CONF_EVENT_VIEWER_CONTROLS_TITLE_MODE,
|
||||
this._titleModes,
|
||||
)}
|
||||
${this._renderStringInput(
|
||||
CONF_EVENT_VIEWER_CONTROLS_TITLE_DURATION_SECONDS,
|
||||
'number',
|
||||
)}
|
||||
</div>`
|
||||
: ''}
|
||||
${this._renderOptionSetHeader('image')}
|
||||
@@ -889,7 +924,7 @@ export class FrigateCardEditor extends LitElement implements LovelaceCardEditor
|
||||
value = target.checked;
|
||||
} else if (typeof target.value === 'string') {
|
||||
value = target.value?.trim();
|
||||
if (target['type'] === 'number') {
|
||||
if (target['type'] === 'number' && value != '') {
|
||||
value = Number(value);
|
||||
}
|
||||
} else {
|
||||
|
||||
@@ -6,7 +6,8 @@
|
||||
"no_snapshots": "No snapshots",
|
||||
"no_clips": "No clips",
|
||||
"no_snapshot": "No recent snapshot",
|
||||
"no_clip": "No recent clip"
|
||||
"no_clip": "No recent clip",
|
||||
"live": "Live"
|
||||
},
|
||||
"config": {
|
||||
"cameras": {
|
||||
@@ -73,6 +74,17 @@
|
||||
"above": "Thumbnails above the media",
|
||||
"none": "No thumbnails"
|
||||
}
|
||||
},
|
||||
"title": {
|
||||
"mode": "Event Viewer media title display mode",
|
||||
"modes": {
|
||||
"none": "No title display",
|
||||
"popup-top-left": "Popup on the top left",
|
||||
"popup-top-right": "Popup on the top right",
|
||||
"popup-bottom-left": "Popup on the bottom left",
|
||||
"popup-bottom-right": "Popup on the bottom right"
|
||||
},
|
||||
"duration_seconds": "Seconds to display popup title in Event Viewer (0=forever)"
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -99,6 +111,10 @@
|
||||
"clips": "Clip thumbnails",
|
||||
"snapshots": "Snapshot thumbnails"
|
||||
}
|
||||
},
|
||||
"title": {
|
||||
"mode": "Live media title display mode",
|
||||
"duration_seconds": "Seconds to display popup title in Live view (0=forever)"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
--video-max-height: none;
|
||||
}
|
||||
|
||||
|
||||
.embla__container {
|
||||
// To support adaptive height animations.
|
||||
transition: max-height 0.5s ease;
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
:host {
|
||||
--paper-toast-background-color: rgba(0,0,0,0.6);
|
||||
--paper-toast-color: white;
|
||||
}
|
||||
|
||||
paper-toast {
|
||||
max-width: unset;
|
||||
}
|
||||
+68
-28
@@ -436,6 +436,21 @@ const nextPreviousControlConfigSchema = z.object({
|
||||
});
|
||||
export type NextPreviousControlConfig = z.infer<typeof nextPreviousControlConfigSchema>;
|
||||
|
||||
/**
|
||||
* Title Control configuration section.
|
||||
*/
|
||||
const titleControlConfigSchema = z.object({
|
||||
mode: z.enum([
|
||||
'none',
|
||||
'popup-top-right',
|
||||
'popup-top-left',
|
||||
'popup-bottom-right',
|
||||
'popup-bottom-left',
|
||||
]),
|
||||
duration_seconds: z.number().min(0),
|
||||
});
|
||||
export type TitleControlConfig = z.infer<typeof titleControlConfigSchema>;
|
||||
|
||||
/**
|
||||
* Live view configuration section.
|
||||
*/
|
||||
@@ -454,6 +469,10 @@ const liveConfigDefault = {
|
||||
size: '100px',
|
||||
mode: 'none' as const,
|
||||
},
|
||||
title: {
|
||||
mode: 'popup-bottom-right' as const,
|
||||
duration_seconds: 2,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
@@ -483,40 +502,47 @@ const jsmpegConfigSchema = z
|
||||
.optional();
|
||||
export type JSMPEGConfig = z.infer<typeof jsmpegConfigSchema>;
|
||||
|
||||
const liveNextPreviousControlConfigSchema = nextPreviousControlConfigSchema.extend({
|
||||
// Live cannot show thumbnails, remove that option.
|
||||
style: z
|
||||
.enum(['none', 'chevrons', 'icons'])
|
||||
.default(liveConfigDefault.controls.next_previous.style),
|
||||
size: nextPreviousControlConfigSchema.shape.size.default(
|
||||
liveConfigDefault.controls.next_previous.size,
|
||||
),
|
||||
});
|
||||
|
||||
const liveThumbnailControlConfigSchema = thumbnailsControlSchema.extend({
|
||||
mode: thumbnailsControlSchema.shape.mode.default(
|
||||
liveConfigDefault.controls.thumbnails.mode,
|
||||
),
|
||||
size: thumbnailsControlSchema.shape.size.default(
|
||||
liveConfigDefault.controls.thumbnails.size,
|
||||
),
|
||||
media: z
|
||||
.enum(['clips', 'snapshots'])
|
||||
.default(liveConfigDefault.controls.thumbnails.media),
|
||||
});
|
||||
|
||||
const liveOverridableConfigSchema = z
|
||||
.object({
|
||||
webrtc: webrtcConfigSchema,
|
||||
jsmpeg: jsmpegConfigSchema,
|
||||
controls: z
|
||||
.object({
|
||||
next_previous: liveNextPreviousControlConfigSchema.default(
|
||||
liveConfigDefault.controls.next_previous,
|
||||
),
|
||||
thumbnails: liveThumbnailControlConfigSchema.default(
|
||||
liveConfigDefault.controls.thumbnails,
|
||||
),
|
||||
next_previous: nextPreviousControlConfigSchema
|
||||
.extend({
|
||||
// Live cannot show thumbnails, remove that option.
|
||||
style: z
|
||||
.enum(['none', 'chevrons', 'icons'])
|
||||
.default(liveConfigDefault.controls.next_previous.style),
|
||||
size: nextPreviousControlConfigSchema.shape.size.default(
|
||||
liveConfigDefault.controls.next_previous.size,
|
||||
),
|
||||
})
|
||||
.default(liveConfigDefault.controls.next_previous),
|
||||
thumbnails: thumbnailsControlSchema
|
||||
.extend({
|
||||
mode: thumbnailsControlSchema.shape.mode.default(
|
||||
liveConfigDefault.controls.thumbnails.mode,
|
||||
),
|
||||
size: thumbnailsControlSchema.shape.size.default(
|
||||
liveConfigDefault.controls.thumbnails.size,
|
||||
),
|
||||
media: z
|
||||
.enum(['clips', 'snapshots'])
|
||||
.default(liveConfigDefault.controls.thumbnails.media),
|
||||
})
|
||||
|
||||
.default(liveConfigDefault.controls.thumbnails),
|
||||
title: titleControlConfigSchema
|
||||
.extend({
|
||||
mode: titleControlConfigSchema.shape.mode.default(
|
||||
liveConfigDefault.controls.title.mode,
|
||||
),
|
||||
duration_seconds: titleControlConfigSchema.shape.duration_seconds.default(
|
||||
liveConfigDefault.controls.title.duration_seconds,
|
||||
),
|
||||
})
|
||||
.default(liveConfigDefault.controls.title),
|
||||
})
|
||||
.default(liveConfigDefault.controls),
|
||||
})
|
||||
@@ -589,6 +615,10 @@ const viewerConfigDefault = {
|
||||
size: '100px',
|
||||
mode: 'none' as const,
|
||||
},
|
||||
title: {
|
||||
mode: 'popup-bottom-right' as const,
|
||||
duration_seconds: 2,
|
||||
},
|
||||
},
|
||||
};
|
||||
const viewerNextPreviousControlConfigSchema = nextPreviousControlConfigSchema.extend({
|
||||
@@ -621,6 +651,16 @@ const viewerConfigSchema = z
|
||||
),
|
||||
})
|
||||
.default(viewerConfigDefault.controls.thumbnails),
|
||||
title: titleControlConfigSchema
|
||||
.extend({
|
||||
mode: titleControlConfigSchema.shape.mode.default(
|
||||
viewerConfigDefault.controls.title.mode,
|
||||
),
|
||||
duration_seconds: titleControlConfigSchema.shape.duration_seconds.default(
|
||||
viewerConfigDefault.controls.title.duration_seconds,
|
||||
),
|
||||
})
|
||||
.default(viewerConfigDefault.controls.title),
|
||||
})
|
||||
.default(viewerConfigDefault.controls),
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user