feat: Modernize the visual card editor. (#2586)
This commit is contained in:
@@ -0,0 +1,159 @@
|
||||
// A single namespace shadowing the main config: anything the upgrade cannot
|
||||
// faithfully convert is recorded here as a failure, intact, at the same path it
|
||||
// came from (e.g. top-level `automations` -> `__UPGRADE_FAILURE__.automations`)
|
||||
// for the user to migrate by hand.
|
||||
export const CONF_UPGRADE_FAILURE = '__UPGRADE_FAILURE__' as const;
|
||||
|
||||
// ===========================================================================
|
||||
// Configuration path constants
|
||||
// ===========================================================================
|
||||
|
||||
export const CONF_AUTOMATIONS = 'automations' as const;
|
||||
|
||||
export const CONF_CAMERAS = 'cameras' as const;
|
||||
|
||||
const CONF_CAMERAS_GLOBAL = 'cameras_global' as const;
|
||||
export const CONF_CAMERAS_GLOBAL_LIVE_PROVIDER =
|
||||
`${CONF_CAMERAS_GLOBAL}.live_provider` as const;
|
||||
export const CONF_CAMERAS_GLOBAL_TRIGGERS_DOORBELL =
|
||||
`${CONF_CAMERAS_GLOBAL}.triggers.doorbell` as const;
|
||||
export const CONF_CAMERAS_GLOBAL_IMAGE_REFRESH_SECONDS =
|
||||
`${CONF_CAMERAS_GLOBAL}.image.refresh_seconds` as const;
|
||||
export const CONF_CAMERAS_GLOBAL_DIMENSIONS_LAYOUT =
|
||||
`${CONF_CAMERAS_GLOBAL}.dimensions.layout` as const;
|
||||
export const CONF_CAMERAS_GLOBAL_PTZ = `${CONF_CAMERAS_GLOBAL}.ptz` as const;
|
||||
|
||||
export const CONF_ELEMENTS = 'elements' as const;
|
||||
|
||||
export const CONF_FOLDERS = 'folders' as const;
|
||||
|
||||
const CONF_VIEW = 'view' as const;
|
||||
export const CONF_VIEW_DIM = `${CONF_VIEW}.dim` as const;
|
||||
export const CONF_VIEW_INTERACTION_SECONDS = `${CONF_VIEW}.interaction_seconds` as const;
|
||||
export const CONF_VIEW_DEFAULT_CYCLE_CAMERA =
|
||||
`${CONF_VIEW}.default_cycle_camera` as const;
|
||||
const CONF_VIEW_DEFAULT_RESET = `${CONF_VIEW}.default_reset` as const;
|
||||
export const CONF_VIEW_DEFAULT_RESET_INTERACTION_MODE =
|
||||
`${CONF_VIEW_DEFAULT_RESET}.interaction_mode` as const;
|
||||
export const CONF_VIEW_DEFAULT_RESET_EVERY_SECONDS =
|
||||
`${CONF_VIEW_DEFAULT_RESET}.every_seconds` as const;
|
||||
export const CONF_VIEW_DEFAULT_RESET_ENTITIES =
|
||||
`${CONF_VIEW_DEFAULT_RESET}.entities` as const;
|
||||
export const CONF_VIEW_KEYBOARD_SHORTCUTS = `${CONF_VIEW}.keyboard_shortcuts` as const;
|
||||
export const CONF_VIEW_TRIGGERS = `${CONF_VIEW}.triggers` as const;
|
||||
export const CONF_VIEW_TRIGGERS_SHOW_TRIGGER_STATUS =
|
||||
`${CONF_VIEW_TRIGGERS}.show_trigger_status` as const;
|
||||
export const CONF_VIEW_TRIGGERS_FILTER_SELECTED_CAMERA =
|
||||
`${CONF_VIEW_TRIGGERS}.filter_selected_camera` as const;
|
||||
export const CONF_VIEW_TRIGGERS_UNTRIGGER_DELAY_SECONDS =
|
||||
`${CONF_VIEW_TRIGGERS}.untrigger_delay_seconds` as const;
|
||||
const CONF_VIEW_TRIGGERS_ACTIONS = `${CONF_VIEW_TRIGGERS}.actions` as const;
|
||||
export const CONF_VIEW_TRIGGERS_ACTIONS_INTERACTION_MODE =
|
||||
`${CONF_VIEW_TRIGGERS_ACTIONS}.interaction_mode` as const;
|
||||
export const CONF_VIEW_TRIGGERS_ACTIONS_TRIGGER =
|
||||
`${CONF_VIEW_TRIGGERS_ACTIONS}.trigger` as const;
|
||||
export const CONF_VIEW_TRIGGERS_ACTIONS_UNTRIGGER =
|
||||
`${CONF_VIEW_TRIGGERS_ACTIONS}.untrigger` as const;
|
||||
|
||||
const CONF_MEDIA_GALLERY = 'media_gallery' as const;
|
||||
export const CONF_MEDIA_GALLERY_CONTROLS_THUMBNAILS_SHOW_DETAILS =
|
||||
`${CONF_MEDIA_GALLERY}.controls.thumbnails.show_details` as const;
|
||||
export const CONF_MEDIA_GALLERY_CONTROLS_THUMBNAILS_SHOW_FAVORITE_CONTROL =
|
||||
`${CONF_MEDIA_GALLERY}.controls.thumbnails.show_favorite_control` as const;
|
||||
|
||||
const CONF_MEDIA_VIEWER = 'media_viewer' as const;
|
||||
export const CONF_MEDIA_VIEWER_AUTO_PLAY = `${CONF_MEDIA_VIEWER}.auto_play` as const;
|
||||
export const CONF_MEDIA_VIEWER_AUTO_PAUSE = `${CONF_MEDIA_VIEWER}.auto_pause` as const;
|
||||
export const CONF_MEDIA_VIEWER_AUTO_MUTE = `${CONF_MEDIA_VIEWER}.auto_mute` as const;
|
||||
export const CONF_MEDIA_VIEWER_DRAGGABLE = `${CONF_MEDIA_VIEWER}.draggable` as const;
|
||||
export const CONF_MEDIA_VIEWER_SNAPSHOT_CLICK_PLAYS_CLIP =
|
||||
`${CONF_MEDIA_VIEWER}.snapshot_click_plays_clip` as const;
|
||||
export const CONF_MEDIA_VIEWER_TRANSITION_EFFECT =
|
||||
`${CONF_MEDIA_VIEWER}.transition_effect` as const;
|
||||
export const CONF_MEDIA_VIEWER_CONTROLS_BUILTIN =
|
||||
`${CONF_MEDIA_VIEWER}.controls.builtin` as const;
|
||||
export const CONF_MEDIA_VIEWER_CONTROLS_NEXT_PREVIOUS_STYLE =
|
||||
`${CONF_MEDIA_VIEWER}.controls.next_previous.style` as const;
|
||||
export const CONF_MEDIA_VIEWER_CONTROLS_THUMBNAILS_MODE =
|
||||
`${CONF_MEDIA_VIEWER}.controls.thumbnails.mode` as const;
|
||||
export const CONF_MEDIA_VIEWER_CONTROLS_THUMBNAILS_SHOW_DETAILS =
|
||||
`${CONF_MEDIA_VIEWER}.controls.thumbnails.show_details` as const;
|
||||
export const CONF_MEDIA_VIEWER_CONTROLS_THUMBNAILS_SHOW_FAVORITE_CONTROL =
|
||||
`${CONF_MEDIA_VIEWER}.controls.thumbnails.show_favorite_control` as const;
|
||||
|
||||
export const CONF_MEDIA_VIEWER_CONTROLS_TIMELINE_MODE =
|
||||
`${CONF_MEDIA_VIEWER}.controls.timeline.mode` as const;
|
||||
export const CONF_MEDIA_VIEWER_CONTROLS_TIMELINE_PAN_MODE =
|
||||
`${CONF_MEDIA_VIEWER}.controls.timeline.pan_mode` as const;
|
||||
export const CONF_MEDIA_VIEWER_CONTROLS_TIMELINE_SHOW_RECORDINGS =
|
||||
`${CONF_MEDIA_VIEWER}.controls.timeline.show_recordings` as const;
|
||||
export const CONF_MEDIA_VIEWER_CONTROLS_TIMELINE_STYLE =
|
||||
`${CONF_MEDIA_VIEWER}.controls.timeline.style` as const;
|
||||
|
||||
const CONF_LIVE = 'live' as const;
|
||||
export const CONF_LIVE_AUTO_MUTE = `${CONF_LIVE}.auto_mute` as const;
|
||||
export const CONF_LIVE_AUTO_UNMUTE = `${CONF_LIVE}.auto_unmute` as const;
|
||||
export const CONF_LIVE_CONTROLS_BUILTIN = `${CONF_LIVE}.controls.builtin` as const;
|
||||
|
||||
export const CONF_LIVE_CONTROLS_THUMBNAILS_MODE =
|
||||
`${CONF_LIVE}.controls.thumbnails.mode` as const;
|
||||
export const CONF_LIVE_CONTROLS_THUMBNAILS_SHOW_DETAILS =
|
||||
`${CONF_LIVE}.controls.thumbnails.show_details` as const;
|
||||
export const CONF_LIVE_CONTROLS_THUMBNAILS_SHOW_FAVORITE_CONTROL =
|
||||
`${CONF_LIVE}.controls.thumbnails.show_favorite_control` as const;
|
||||
export const CONF_LIVE_CONTROLS_TIMELINE_MODE =
|
||||
`${CONF_LIVE}.controls.timeline.mode` as const;
|
||||
export const CONF_LIVE_CONTROLS_TIMELINE_PAN_MODE =
|
||||
`${CONF_LIVE}.controls.timeline.pan_mode` as const;
|
||||
export const CONF_LIVE_CONTROLS_TIMELINE_SHOW_RECORDINGS =
|
||||
`${CONF_LIVE}.controls.timeline.show_recordings` as const;
|
||||
export const CONF_LIVE_CONTROLS_TIMELINE_STYLE =
|
||||
`${CONF_LIVE}.controls.timeline.style` as const;
|
||||
export const CONF_LIVE_DRAGGABLE = `${CONF_LIVE}.draggable` as const;
|
||||
export const CONF_LIVE_LAZY_UNLOAD = `${CONF_LIVE}.lazy_unload` as const;
|
||||
export const CONF_LIVE_TRANSITION_EFFECT = `${CONF_LIVE}.transition_effect` as const;
|
||||
export const CONF_LIVE_SHOW_IMAGE_DURING_LOAD =
|
||||
`${CONF_LIVE}.show_image_during_load` as const;
|
||||
|
||||
const CONF_TIMELINE = 'timeline' as const;
|
||||
export const CONF_TIMELINE_SHOW_RECORDINGS = `${CONF_TIMELINE}.show_recordings` as const;
|
||||
export const CONF_TIMELINE_CONTROLS_THUMBNAILS_MODE =
|
||||
`${CONF_TIMELINE}.controls.thumbnails.mode` as const;
|
||||
export const CONF_TIMELINE_CONTROLS_THUMBNAILS_SHOW_DETAILS =
|
||||
`${CONF_TIMELINE}.controls.thumbnails.show_details` as const;
|
||||
export const CONF_TIMELINE_CONTROLS_THUMBNAILS_SHOW_FAVORITE_CONTROL =
|
||||
`${CONF_TIMELINE}.controls.thumbnails.show_favorite_control` as const;
|
||||
|
||||
const CONF_MENU = 'menu' as const;
|
||||
export const CONF_MENU_STYLE = `${CONF_MENU}.style` as const;
|
||||
const CONF_MENU_BUTTONS = `${CONF_MENU}.buttons` as const;
|
||||
|
||||
export const CONF_MENU_BUTTONS_FULLSCREEN = `${CONF_MENU_BUTTONS}.fullscreen` as const;
|
||||
export const CONF_MENU_BUTTONS_IRIS = `${CONF_MENU_BUTTONS}.iris` as const;
|
||||
export const CONF_MENU_BUTTONS_PLAY = `${CONF_MENU_BUTTONS}.play` as const;
|
||||
export const CONF_MENU_BUTTONS_MUTE = `${CONF_MENU_BUTTONS}.mute` as const;
|
||||
export const CONF_MENU_BUTTONS_MEDIA_PLAYER =
|
||||
`${CONF_MENU_BUTTONS}.media_player` as const;
|
||||
export const CONF_MENU_BUTTONS_TIMELINE = `${CONF_MENU_BUTTONS}.timeline` as const;
|
||||
|
||||
export const CONF_STATUS_BAR = 'status_bar' as const;
|
||||
export const CONF_STATUS_BAR_STYLE = `${CONF_STATUS_BAR}.style` as const;
|
||||
|
||||
const CONF_DIMENSIONS = 'dimensions' as const;
|
||||
export const CONF_DIMENSIONS_ASPECT_RATIO = `${CONF_DIMENSIONS}.aspect_ratio` as const;
|
||||
export const CONF_DIMENSIONS_ASPECT_RATIO_MODE =
|
||||
`${CONF_DIMENSIONS}.aspect_ratio_mode` as const;
|
||||
export const CONF_DIMENSIONS_HEIGHT = `${CONF_DIMENSIONS}.height` as const;
|
||||
|
||||
export const CONF_OVERRIDES = 'overrides' as const;
|
||||
|
||||
const CONF_PERFORMANCE = 'performance' as const;
|
||||
export const CONF_PERFORMANCE_FEATURES_ANIMATED_PROGRESS_INDICATOR = `${CONF_PERFORMANCE}.features.animated_progress_indicator`;
|
||||
export const CONF_PERFORMANCE_FEATURES_CARD_LOADING_EFFECTS = `${CONF_PERFORMANCE}.features.card_loading_effects`;
|
||||
export const CONF_PERFORMANCE_FEATURES_CARD_LOADING_INDICATOR = `${CONF_PERFORMANCE}.features.card_loading_indicator`;
|
||||
export const CONF_PERFORMANCE_FEATURES_MEDIA_CHUNK_SIZE = `${CONF_PERFORMANCE}.features.media_chunk_size`;
|
||||
export const CONF_PERFORMANCE_FEATURES_MAX_SIMULTANEOUS_ENGINE_REQUESTS = `${CONF_PERFORMANCE}.features.max_simultaneous_engine_requests`;
|
||||
export const CONF_PERFORMANCE_STYLE_BOX_SHADOW = `${CONF_PERFORMANCE}.style.box_shadow`;
|
||||
export const CONF_PERFORMANCE_STYLE_BORDER_RADIUS = `${CONF_PERFORMANCE}.style.border_radius`;
|
||||
|
||||
export const CONF_PROFILES = 'profiles' as const;
|
||||
+97
-16
@@ -1,5 +1,6 @@
|
||||
import { cloneDeep, get, isEqual, set, unset } from 'lodash-es';
|
||||
|
||||
import { arrayify, arrayMove, isRecord } from '../utils/basic';
|
||||
import {
|
||||
CONF_AUTOMATIONS,
|
||||
CONF_CAMERAS,
|
||||
@@ -22,8 +23,7 @@ import {
|
||||
CONF_VIEW_TRIGGERS_ACTIONS_UNTRIGGER,
|
||||
CONF_VIEW_TRIGGERS_FILTER_SELECTED_CAMERA,
|
||||
CONF_VIEW_TRIGGERS_UNTRIGGER_DELAY_SECONDS,
|
||||
} from '../const';
|
||||
import { arrayify, isRecord } from '../utils/basic';
|
||||
} from './const';
|
||||
import type { Condition } from './schema/condition-trigger/conditions/types';
|
||||
import type {
|
||||
RawAdvancedCameraCardConfig,
|
||||
@@ -70,7 +70,7 @@ export const getConfigValue = (
|
||||
*/
|
||||
export const deleteConfigValue = (
|
||||
obj: RawAdvancedCameraCardConfig,
|
||||
path: string,
|
||||
path: string | (string | number)[],
|
||||
): void => {
|
||||
unset(obj, path);
|
||||
};
|
||||
@@ -84,16 +84,89 @@ export const copyConfig = <T>(obj: T): T => {
|
||||
return cloneDeep(obj);
|
||||
};
|
||||
|
||||
/**
|
||||
* Given an array path, return a true path.
|
||||
* @param path The array path (should have a '#').
|
||||
* @param index The numeric array index to use.
|
||||
* @returns The true config path.
|
||||
*/
|
||||
export const getArrayConfigPath = (path: string, index: number): string => {
|
||||
return path.replace('#', `[${index.toString()}]`);
|
||||
// Apply an in-place mutation to the array at `arrayPath`, returning whether the
|
||||
// mutation reported a change.
|
||||
const mutateConfigArray = (
|
||||
obj: RawAdvancedCameraCardConfig,
|
||||
arrayPath: string | (string | number)[],
|
||||
mutator: (array: unknown[]) => boolean,
|
||||
): boolean => {
|
||||
const array = getConfigValue(obj, arrayPath);
|
||||
return Array.isArray(array) && mutator(array);
|
||||
};
|
||||
|
||||
/**
|
||||
* Append an item to a configuration array. The array is created when the
|
||||
* configuration does not have one at that path yet.
|
||||
* @param obj The configuration to modify.
|
||||
* @param arrayPath The configuration path of the array.
|
||||
* @param item The item to append.
|
||||
* @returns `true` if the configuration was modified.
|
||||
*/
|
||||
export const addConfigArrayItem = (
|
||||
obj: RawAdvancedCameraCardConfig,
|
||||
arrayPath: string | (string | number)[],
|
||||
item: unknown,
|
||||
): boolean => {
|
||||
const array = getConfigValue(obj, arrayPath);
|
||||
if (!Array.isArray(array)) {
|
||||
setConfigValue(obj, arrayPath, [item]);
|
||||
return true;
|
||||
}
|
||||
array.push(item);
|
||||
return true;
|
||||
};
|
||||
|
||||
/**
|
||||
* Move an item within a configuration array.
|
||||
* @param obj The configuration to modify.
|
||||
* @param arrayPath The configuration path of the array.
|
||||
* @param fromIndex The index of the item to move.
|
||||
* @param toIndex The index to move the item to.
|
||||
* @returns `true` if the configuration was modified.
|
||||
*/
|
||||
export const moveConfigArrayItem = (
|
||||
obj: RawAdvancedCameraCardConfig,
|
||||
arrayPath: string | (string | number)[],
|
||||
fromIndex: number,
|
||||
toIndex: number,
|
||||
): boolean =>
|
||||
mutateConfigArray(obj, arrayPath, (array) => {
|
||||
if (
|
||||
!Number.isInteger(fromIndex) ||
|
||||
!Number.isInteger(toIndex) ||
|
||||
fromIndex === toIndex ||
|
||||
fromIndex < 0 ||
|
||||
toIndex < 0 ||
|
||||
fromIndex >= array.length ||
|
||||
toIndex >= array.length
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
arrayMove(array, fromIndex, toIndex);
|
||||
return true;
|
||||
});
|
||||
|
||||
/**
|
||||
* Delete an item from a configuration array.
|
||||
* @param obj The configuration to modify.
|
||||
* @param arrayPath The configuration path of the array.
|
||||
* @param index The index of the item to delete.
|
||||
* @returns `true` if the configuration was modified.
|
||||
*/
|
||||
export const deleteConfigArrayItem = (
|
||||
obj: RawAdvancedCameraCardConfig,
|
||||
arrayPath: string | (string | number)[],
|
||||
index: number,
|
||||
): boolean =>
|
||||
mutateConfigArray(obj, arrayPath, (array) => {
|
||||
if (!Number.isInteger(index) || index < 0 || index >= array.length) {
|
||||
return false;
|
||||
}
|
||||
array.splice(index, 1);
|
||||
return true;
|
||||
});
|
||||
|
||||
// *************************************************************************
|
||||
// Upgrade Related Functions
|
||||
// *************************************************************************
|
||||
@@ -1424,16 +1497,24 @@ const frigateCardToAdvancedCameraCardStyleTransform = (data: unknown): unknown =
|
||||
// Legacy `triggers.events: string[]` (Frigate engine media-availability filter)
|
||||
// was renamed to `triggers.media_events` to free up `triggers.events` for the
|
||||
// new HA-bus-event trigger list (object shape). Distinguish old from new by
|
||||
// element type: an all-string array is legacy; any non-string element marks
|
||||
// the new shape and must not be touched. If `media_events` already exists we
|
||||
// refuse to overwrite it -- but we still drop the legacy `events` (otherwise
|
||||
// it would fail the new schema, which expects objects).
|
||||
// element type: an array holding at least one string is legacy; any non-string
|
||||
// element marks the new shape and must not be touched. An empty list says
|
||||
// nothing about which of the two it is, and is valid under the new schema, so
|
||||
// it is left alone -- a user who deletes their last event trigger is not
|
||||
// offered an upgrade that would rename the key underneath them. If
|
||||
// `media_events` already exists we refuse to overwrite it -- but we still drop
|
||||
// the legacy `events` (otherwise it would fail the new schema, which expects
|
||||
// objects).
|
||||
const triggersEventsToMediaEventsTransform = (triggers: unknown): unknown => {
|
||||
if (!isRecord(triggers)) {
|
||||
return undefined;
|
||||
}
|
||||
const events = triggers['events'];
|
||||
if (!Array.isArray(events) || events.some((x) => typeof x !== 'string')) {
|
||||
if (
|
||||
!Array.isArray(events) ||
|
||||
!events.length ||
|
||||
events.some((x) => typeof x !== 'string')
|
||||
) {
|
||||
return undefined;
|
||||
}
|
||||
const result = { ...triggers };
|
||||
|
||||
@@ -10,7 +10,7 @@ import {
|
||||
CONF_MENU_BUTTONS_MEDIA_PLAYER,
|
||||
CONF_MENU_BUTTONS_MUTE,
|
||||
CONF_MENU_BUTTONS_PLAY,
|
||||
} from '../../const.js';
|
||||
} from '../const.js';
|
||||
|
||||
export const CASTING_PROFILE = {
|
||||
[CONF_LIVE_CONTROLS_BUILTIN]: false,
|
||||
|
||||
@@ -4,7 +4,7 @@ import {
|
||||
CONF_VIEW_TRIGGERS_ACTIONS_TRIGGER,
|
||||
CONF_VIEW_TRIGGERS_ACTIONS_UNTRIGGER,
|
||||
CONF_VIEW_TRIGGERS_SHOW_TRIGGER_STATUS,
|
||||
} from '../../const.js';
|
||||
} from '../const.js';
|
||||
|
||||
export const DOORBELL_PROFILE = {
|
||||
// Auto-discover HA `event.*` entities with `device_class: doorbell` on each
|
||||
|
||||
@@ -40,7 +40,7 @@ import {
|
||||
CONF_TIMELINE_CONTROLS_THUMBNAILS_SHOW_FAVORITE_CONTROL,
|
||||
CONF_TIMELINE_SHOW_RECORDINGS,
|
||||
CONF_VIEW_TRIGGERS_ACTIONS_TRIGGER,
|
||||
} from '../../const.js';
|
||||
} from '../const.js';
|
||||
|
||||
export const LOW_PERFORMANCE_PROFILE = {
|
||||
// Disable thumbnail carousels.
|
||||
|
||||
@@ -5,7 +5,7 @@ import {
|
||||
CONF_MEDIA_VIEWER_CONTROLS_TIMELINE_MODE,
|
||||
CONF_MEDIA_VIEWER_CONTROLS_TIMELINE_PAN_MODE,
|
||||
CONF_MEDIA_VIEWER_CONTROLS_TIMELINE_STYLE,
|
||||
} from '../../const.js';
|
||||
} from '../const.js';
|
||||
|
||||
export const SCRUBBING_PROFILE = {
|
||||
[CONF_LIVE_CONTROLS_TIMELINE_MODE]: 'below' as const,
|
||||
|
||||
@@ -5,7 +5,6 @@ export const timelineCoreConfigDefault = {
|
||||
window_seconds: 60 * 60,
|
||||
show_recordings: true,
|
||||
style: 'stack' as const,
|
||||
pan_mode: 'pan' as const,
|
||||
format: {
|
||||
'24h': true,
|
||||
},
|
||||
@@ -34,21 +33,31 @@ export const timelineCoreConfigSchema = z.object({
|
||||
.optional()
|
||||
.default(timelineCoreConfigDefault.show_recordings),
|
||||
style: z.enum(['stack', 'ribbon']).optional().default(timelineCoreConfigDefault.style),
|
||||
pan_mode: timelinePanModeSchema.optional().default(timelineCoreConfigDefault.pan_mode),
|
||||
format: timelineFormatSchema.optional().default(timelineCoreConfigDefault.format),
|
||||
});
|
||||
export type TimelineCoreConfig = z.infer<typeof timelineCoreConfigSchema>;
|
||||
type TimelineCoreConfig = z.infer<typeof timelineCoreConfigSchema>;
|
||||
|
||||
export const miniTimelineConfigDefault = {
|
||||
...timelineCoreConfigDefault,
|
||||
mode: 'none' as const,
|
||||
|
||||
// The non-`pan` modes seek within playing media, so `pan_mode` only applies
|
||||
// to a mini timeline shown alongside media.
|
||||
pan_mode: 'pan' as const,
|
||||
|
||||
// Mini-timeline defaults to ribbon style.
|
||||
style: 'ribbon' as const,
|
||||
};
|
||||
|
||||
export const miniTimelineConfigSchema = timelineCoreConfigSchema.extend({
|
||||
mode: z.enum(['none', 'above', 'below']).default(miniTimelineConfigDefault.mode),
|
||||
pan_mode: timelinePanModeSchema.optional().default(miniTimelineConfigDefault.pan_mode),
|
||||
style: timelineCoreConfigSchema.shape.style.default(miniTimelineConfigDefault.style),
|
||||
});
|
||||
export type MiniTimelineControlConfig = z.infer<typeof miniTimelineConfigSchema>;
|
||||
|
||||
// The config consumed by the shared `timeline-core` component: the core fields,
|
||||
// plus the mini-only extras (`pan_mode` etc.) made optional since the full
|
||||
// timeline omits them.
|
||||
export type TimelineCoreComponentConfig = TimelineCoreConfig &
|
||||
Partial<MiniTimelineControlConfig>;
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
import { z } from 'zod';
|
||||
|
||||
import { MEDIA_CHUNK_SIZE_DEFAULT, MEDIA_CHUNK_SIZE_MAX } from '../../const';
|
||||
import { MEDIA_CHUNK_SIZE_DEFAULT } from '../../const';
|
||||
|
||||
// The largest media fetch chunk size the configuration accepts.
|
||||
export const MEDIA_CHUNK_SIZE_MAX = 1000;
|
||||
|
||||
export const performanceConfigDefault = {
|
||||
features: {
|
||||
|
||||
@@ -37,14 +37,17 @@ const keyboardShortcutsSchema = z.object({
|
||||
});
|
||||
export type KeyboardShortcuts = z.infer<typeof keyboardShortcutsSchema>;
|
||||
|
||||
export type PTZKeyboardShortcutName =
|
||||
| 'ptz_down'
|
||||
| 'ptz_home'
|
||||
| 'ptz_left'
|
||||
| 'ptz_right'
|
||||
| 'ptz_up'
|
||||
| 'ptz_zoom_in'
|
||||
| 'ptz_zoom_out';
|
||||
export type PTZKeyboardShortcutName = Exclude<keyof KeyboardShortcuts, 'enabled'>;
|
||||
|
||||
export const PTZ_KEYBOARD_SHORTCUTS: readonly PTZKeyboardShortcutName[] = [
|
||||
'ptz_left',
|
||||
'ptz_right',
|
||||
'ptz_up',
|
||||
'ptz_down',
|
||||
'ptz_zoom_in',
|
||||
'ptz_zoom_out',
|
||||
'ptz_home',
|
||||
];
|
||||
|
||||
const interactionModeDefault = 'inactive' as const;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user