feat: Allow per-camera customization of grid width (#2273)
- Closes #2271
This commit is contained in:
@@ -2,7 +2,11 @@ import { isEqual, throttle } from 'lodash-es';
|
||||
import Masonry from 'masonry-layout';
|
||||
import { ViewDisplayConfig } from '../config/schema/common/display';
|
||||
import { MediaLoadedInfo } from '../types';
|
||||
import { getChildrenFromElement, setOrRemoveAttribute } from '../utils/basic';
|
||||
import {
|
||||
getChildrenFromElement,
|
||||
setOrRemoveAttribute,
|
||||
setOrRemoveStyleProperty,
|
||||
} from '../utils/basic';
|
||||
import { fireAdvancedCameraCardEvent } from '../utils/fire-advanced-camera-card-event';
|
||||
import {
|
||||
AdvancedCameraCardMediaLoadedEventTarget,
|
||||
@@ -30,6 +34,7 @@ export interface MediaGridSelected {
|
||||
export interface MediaGridConstructorOptions {
|
||||
selected?: GridID;
|
||||
idAttribute?: string;
|
||||
widthFactorAttribute?: string;
|
||||
displayConfig?: ViewDisplayConfig;
|
||||
}
|
||||
|
||||
@@ -51,6 +56,7 @@ export class MediaGridController {
|
||||
protected _displayConfig: ViewDisplayConfig | null = null;
|
||||
protected _hostWidth: number;
|
||||
protected _idAttribute: string;
|
||||
protected _widthFactorAttribute: string;
|
||||
|
||||
protected _throttledLayout = throttle(
|
||||
() => this._masonry?.layout?.(),
|
||||
@@ -79,6 +85,7 @@ export class MediaGridController {
|
||||
this._host = host;
|
||||
this._selected = options?.selected ?? null;
|
||||
this._idAttribute = options?.idAttribute ?? 'grid-id';
|
||||
this._widthFactorAttribute = options?.widthFactorAttribute ?? 'grid-width-factor';
|
||||
this._hostWidth = this._host.getBoundingClientRect().width;
|
||||
this._hostResizeObserver.observe(host);
|
||||
this._displayConfig = options?.displayConfig ?? null;
|
||||
@@ -233,7 +240,7 @@ export class MediaGridController {
|
||||
this._cellResizeObserver.disconnect();
|
||||
for (const child of gridContents.values()) {
|
||||
this._cellMutationObserver.observe(child, {
|
||||
attributeFilter: [this._idAttribute],
|
||||
attributeFilter: [this._idAttribute, this._widthFactorAttribute],
|
||||
attributes: true,
|
||||
});
|
||||
this._cellResizeObserver.observe(child);
|
||||
@@ -241,6 +248,7 @@ export class MediaGridController {
|
||||
|
||||
this._sortItemsInGrid();
|
||||
this._updateSelectedStylesOnElements();
|
||||
this._updateWidthFactorStyles();
|
||||
this._setColumnSizeStyles();
|
||||
}
|
||||
|
||||
@@ -343,6 +351,18 @@ export class MediaGridController {
|
||||
}
|
||||
}
|
||||
|
||||
protected _updateWidthFactorStyles(): void {
|
||||
for (const element of this._gridContents.values()) {
|
||||
const widthFactor = element.getAttribute(this._widthFactorAttribute);
|
||||
setOrRemoveStyleProperty(
|
||||
element,
|
||||
!!widthFactor,
|
||||
'--advanced-camera-card-grid-width-factor',
|
||||
widthFactor ?? undefined,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
protected _getColumnSize(): number {
|
||||
const columns = this._getColumns();
|
||||
if (columns === 1) {
|
||||
|
||||
@@ -45,9 +45,16 @@ export class AdvancedCameraCardLiveGrid extends LitElement {
|
||||
const view = this.viewManagerEpoch?.manager.getView();
|
||||
const triggeredCameraID = cameraID ?? view?.camera;
|
||||
|
||||
// Get the camera's grid width factor from its dimensions config.
|
||||
const gridWidthFactor = cameraID
|
||||
? this.cameraManager?.getStore().getCameraConfig(cameraID)?.dimensions?.grid
|
||||
?.width_factor
|
||||
: undefined;
|
||||
|
||||
return html`
|
||||
<advanced-camera-card-live-carousel
|
||||
grid-id=${ifDefined(cameraID)}
|
||||
grid-width-factor=${ifDefined(gridWidthFactor)}
|
||||
.hass=${this.hass}
|
||||
.viewManagerEpoch=${this.viewManagerEpoch}
|
||||
.viewFilterCameraID=${cameraID}
|
||||
|
||||
@@ -41,9 +41,17 @@ export class AdvancedCameraCardViewerGrid extends LitElement {
|
||||
|
||||
protected _renderCarousel(filterCamera?: string): TemplateResult {
|
||||
const selectedCameraID = this.viewManagerEpoch?.manager.getView()?.camera;
|
||||
|
||||
// Get the camera's grid width factor from its dimensions config.
|
||||
const gridWidthFactor = filterCamera
|
||||
? this.cameraManager?.getStore().getCameraConfig(filterCamera)?.dimensions?.grid
|
||||
?.width_factor
|
||||
: undefined;
|
||||
|
||||
return html`
|
||||
<advanced-camera-card-viewer-carousel
|
||||
grid-id=${ifDefined(filterCamera)}
|
||||
grid-width-factor=${ifDefined(gridWidthFactor)}
|
||||
.hass=${this.hass}
|
||||
.viewManagerEpoch=${this.viewManagerEpoch}
|
||||
.viewFilterCameraID=${filterCamera}
|
||||
|
||||
@@ -161,10 +161,15 @@ const rotationSchema = z
|
||||
.or(z.literal(270));
|
||||
export type Rotation = z.infer<typeof rotationSchema>;
|
||||
|
||||
const cameraDimensionsGridSchema = z.object({
|
||||
width_factor: z.number().min(0.1).optional(),
|
||||
});
|
||||
|
||||
const cameraDimensionsSchema = z.object({
|
||||
aspect_ratio: aspectRatioSchema.optional(),
|
||||
layout: mediaLayoutConfigSchema.optional(),
|
||||
rotation: rotationSchema.optional(),
|
||||
grid: cameraDimensionsGridSchema.optional(),
|
||||
});
|
||||
export type CameraDimensionsConfig = z.infer<typeof cameraDimensionsSchema>;
|
||||
|
||||
|
||||
@@ -23,7 +23,14 @@
|
||||
|
||||
::slotted(*) {
|
||||
box-sizing: border-box;
|
||||
width: var(--advanced-camera-card-grid-column-size);
|
||||
|
||||
// Support multi-column cells via --advanced-camera-card-grid-width-factor CSS variable.
|
||||
// Default to 1 column if not specified.
|
||||
--advanced-camera-card-grid-width-factor: 1;
|
||||
width: calc(
|
||||
var(--advanced-camera-card-grid-width-factor) *
|
||||
var(--advanced-camera-card-grid-column-size)
|
||||
);
|
||||
|
||||
// Unselected items included a transparent border to act as the effective
|
||||
// gutter between elements, and to ensure when the item is selected it does
|
||||
@@ -35,10 +42,13 @@
|
||||
::slotted([selected]) {
|
||||
border: var(--advanced-camera-card-grid-border-size) solid
|
||||
var(--advanced-camera-card-grid-selected-border-color);
|
||||
|
||||
// Selected width = columns × selection factor, capped at 100%.
|
||||
width: min(
|
||||
100%,
|
||||
calc(
|
||||
var(--advanced-camera-card-grid-selected-width-factor) *
|
||||
var(--advanced-camera-card-grid-width-factor) *
|
||||
var(--advanced-camera-card-grid-selected-width-factor) *
|
||||
var(--advanced-camera-card-grid-column-size)
|
||||
)
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user