diff --git a/src/card.ts b/src/card.ts index c92c33b2..2a32c48c 100644 --- a/src/card.ts +++ b/src/card.ts @@ -963,10 +963,8 @@ export class FrigateCard extends LitElement { * Get the most recent triggered camera. */ protected _getMostRecentTrigger(): string | null { - const sorted = ( - [...this._triggers.entries()].sort( - (a: [string, Date], b: [string, Date]) => b[1].getTime() - a[1].getTime(), - ) + const sorted = [...this._triggers.entries()].sort( + (a: [string, Date], b: [string, Date]) => b[1].getTime() - a[1].getTime(), ); return sorted.length ? sorted[0][0] : null; } @@ -1009,7 +1007,10 @@ export class FrigateCard extends LitElement { changedCamera = true; } else { const targetCamera = this._getMostRecentTrigger(); - if (targetCamera && (this._view.camera !== targetCamera || !this._view.is('live'))) { + if ( + targetCamera && + (this._view.camera !== targetCamera || !this._view.is('live')) + ) { this._changeView({ view: new View({ view: 'live', camera: targetCamera }) }); changedCamera = true; } @@ -1510,21 +1511,21 @@ export class FrigateCard extends LitElement { * required). * @returns A padding percentage. */ - protected _getAspectRatioPadding(): number | null { + protected _getAspectRatioStyle(): string { if (!this._isAspectRatioEnforced()) { - return null; + return 'auto'; } const aspectRatioMode = this._getConfig().dimensions.aspect_ratio_mode; if (aspectRatioMode == 'dynamic' && this._mediaShowInfo) { - return (this._mediaShowInfo.height / this._mediaShowInfo.width) * 100; + return `${this._mediaShowInfo.width} / ${this._mediaShowInfo.height}`; } const defaultAspectRatio = this._getConfig().dimensions.aspect_ratio; if (defaultAspectRatio) { - return (defaultAspectRatio[1] / defaultAspectRatio[0]) * 100; + return `${defaultAspectRatio[0]} / ${defaultAspectRatio[1]}`; } else { - return (9 / 16) * 100; + return '16 / 9'; } } @@ -1557,26 +1558,15 @@ export class FrigateCard extends LitElement { return; } - const padding = this._getAspectRatioPadding(); - const outerStyle = {}; - - // Padding to force a particular aspect ratio. - if (padding != null) { - outerStyle['padding-top'] = `${padding}%`; - } - - const outerClasses = { - container: true, - outer: true, + const cardStyle = { + 'aspect-ratio': this._getAspectRatioStyle(), + }; + const mainClasses = { + main: true, triggered: !!this._triggers.size && this._getConfig().view.scan.show_trigger_status, }; - const contentClasses = { - 'frigate-card-contents': true, - absolute: padding != null, - }; - const actions = this._getMergedActions(); const renderMenuAbove = this._getConfig().menu.style === 'outside' && @@ -1587,6 +1577,7 @@ export class FrigateCard extends LitElement { hasHold: frigateCardHasAction(actions.hold_action), hasDoubleClick: frigateCardHasAction(actions.double_tap_action), })} + style="${styleMap(cardStyle)}" @action=${(ev: CustomEvent) => this._actionHandler(ev, actions)} @ll-custom=${this._cardActionHandler.bind(this)} @frigate-card:message=${this._messageHandler} @@ -1595,49 +1586,47 @@ export class FrigateCard extends LitElement { @frigate-card:render=${() => this.requestUpdate()} > ${renderMenuAbove ? this._renderMenu() : ''} -
-
- ${this._cameras === undefined - ? until( - (async () => { - await this._loadCameras(); - // Don't reset messages as errors may have been generated - // during the camera load. - this._changeView({ resetMessage: false }); - return this._render(); - })(), - renderProgressIndicator(), - ) - : // Always want to call render even if there's a message, to - // ensure live preload is always present (even if not displayed). - this._render()} - ${this._getConfig().elements - ? // Always show elements to allow for custom menu items (etc.) to - // be present even if a particular view has an error. Elements - // need to render after the main views so it can render 'on top'. - html` { - this._addDynamicMenuButton(e.detail); - }} - @frigate-card:menu-remove=${(e) => { - this._removeDynamicMenuButton(e.detail); - }} - @frigate-card:condition-state-request=${(ev) => { - conditionStateRequestHandler(ev, this._conditionState); - }} - > - ` - : ``} - ${ - // Keep message rendering to last to show messages that may have - // been generated during the render. - this._message ? renderMessage(this._message) : '' - } -
+
+ ${this._cameras === undefined + ? until( + (async () => { + await this._loadCameras(); + // Don't reset messages as errors may have been generated + // during the camera load. + this._changeView({ resetMessage: false }); + return this._render(); + })(), + renderProgressIndicator(), + ) + : // Always want to call render even if there's a message, to + // ensure live preload is always present (even if not displayed). + this._render()} + ${this._getConfig().elements + ? // Always show elements to allow for custom menu items (etc.) to + // be present even if a particular view has an error. Elements + // need to render after the main views so it can render 'on top'. + html` { + this._addDynamicMenuButton(e.detail); + }} + @frigate-card:menu-remove=${(e) => { + this._removeDynamicMenuButton(e.detail); + }} + @frigate-card:condition-state-request=${(ev) => { + conditionStateRequestHandler(ev, this._conditionState); + }} + > + ` + : ``} + ${ + // Keep message rendering to last to show messages that may have + // been generated during the render. + this._message ? renderMessage(this._message) : '' + }
${!renderMenuAbove ? this._renderMenu() : ''} `; diff --git a/src/scss/card.scss b/src/scss/card.scss index 989b85f9..f3ccbbdd 100644 --- a/src/scss/card.scss +++ b/src/scss/card.scss @@ -9,21 +9,31 @@ filter: brightness(50%); } -.container { +div.main { position: relative; overflow: auto; width: 100%; height: 100%; margin: auto; display: flex; + align-items: center; justify-content: center; // Need to apply the border radius on the container level, as the ha-card has // overflow visible in order to allow a submenu to extend beyond the card // boundary. border-radius: var(--ha-card-border-radius, 4px); + + // Include the borders in the sizing (to keep the triggered warning pulse + // visible in fullscreen). + box-sizing: border-box; + + // Hide scrollbar: Firefox + scrollbar-width: none; + // Hide scrollbar: IE and Edge + -ms-overflow-style: none; } -.container.triggered { +div.main.triggered { @keyframes warning-pulse { 0% { border: solid 1px rgba(0,0,0,0); @@ -38,39 +48,11 @@ animation: warning-pulse 5s infinite; } -.frigate-card-contents { - width: inherit; - height: inherit; - margin: auto; - overflow: auto; - display: flex; - align-items: center; - justify-content: center; - - // Include the borders in the sizing (to keep the triggered warning pulse - // visible in fullscreen). - box-sizing: border-box; - - // Hide scrollbar: Firefox - scrollbar-width: none; - // Hide scrollbar: IE and Edge - -ms-overflow-style: none; -} - /* Hide scrollbar for Chrome, Safari and Opera */ -.frigate-card-contents::-webkit-scrollbar { +div.main::-webkit-scrollbar { display: none; } -/* When forcing aspect ratio absolute positioning is required */ -.frigate-card-contents.absolute { - position: absolute; - top: 0px; - right: 0px; - bottom: 0px; - left: 0px; -} - /* The 'hover' menu mode is styling applied outside of the menu itself */ frigate-card-menu[data-style='hover'] { z-index: 1;