diff --git a/README.md b/README.md index 06ea341e..5141e6ca 100644 --- a/README.md +++ b/README.md @@ -766,6 +766,9 @@ See the [fully expanded dimensions configuration example](#config-expanded-dimen | - | - | - | - | | `aspect_ratio_mode` | `dynamic` | :white_check_mark: | The aspect ratio mode to use. Acceptable values: `dynamic`, `static`, `unconstrained`. See [aspect ratios](#aspect-ratios) below.| | `aspect_ratio` | `16:9` | :white_check_mark: | The aspect ratio to use. Acceptable values: `:` or `/`. See [aspect ratios](#aspect-ratios) below.| +| `max_height` | `100vh` | :white_check_mark: | The maximum allowable height for the card. Specified in [CSS units](https://developer.mozilla.org/en-US/docs/Learn/CSS/Building_blocks/Values_and_units). Generally users should not need to change this setting unless they have set an `unconstrained` aspect ratio. | +| `min_height` | `100px` | :white_check_mark: | The minimum allowable height for the card. Specified in [CSS units](https://developer.mozilla.org/en-US/docs/Learn/CSS/Building_blocks/Values_and_units). Generally users should not need to change this setting. | + #### `dimensions.aspect_ratio_mode`: diff --git a/src/card.ts b/src/card.ts index 906b7e5e..d8e4e049 100644 --- a/src/card.ts +++ b/src/card.ts @@ -5,7 +5,7 @@ import { LitElement, PropertyValues, TemplateResult, - unsafeCSS + unsafeCSS, } from 'lit'; import { customElement, property, state } from 'lit/decorators.js'; import { classMap } from 'lit/directives/class-map.js'; @@ -27,7 +27,7 @@ import { CardConditionManager, ConditionState, conditionStateRequestHandler, - getOverriddenConfig + getOverriddenConfig, } from './card-condition.js'; import './components/elements.js'; import { FrigateCardElements } from './components/elements.js'; @@ -48,19 +48,26 @@ import { ActionType, CameraConfig, CardWideConfig, - ExtendedHomeAssistant, FrigateCardConfig, + ExtendedHomeAssistant, + FrigateCardConfig, frigateCardConfigSchema, FrigateCardCustomAction, FrigateCardError, - FrigateCardView, FRIGATE_CARD_VIEWS_USER_SPECIFIED, FRIGATE_CARD_VIEW_DEFAULT, MediaLoadedInfo, - MenuButton, Message, MESSAGE_TYPE_PRIORITIES, RawFrigateCardConfig + FrigateCardView, + FRIGATE_CARD_VIEWS_USER_SPECIFIED, + FRIGATE_CARD_VIEW_DEFAULT, + MediaLoadedInfo, + MenuButton, + Message, + MESSAGE_TYPE_PRIORITIES, + RawFrigateCardConfig, } from './types.js'; import { convertActionToFrigateCardCustomAction, createFrigateCardCustomAction, frigateCardHandleAction, frigateCardHasAction, - getActionConfigGivenAction + getActionConfigGivenAction, } from './utils/action.js'; import { errorToConsole } from './utils/basic.js'; import { getAllDependentCameras } from './utils/camera.js'; @@ -73,7 +80,7 @@ import { isCardInPanel, isHassDifferent, isTriggeredState, - sideLoadHomeAssistantElements + sideLoadHomeAssistantElements, } from './utils/ha'; import { DeviceList, getAllDevices } from './utils/ha/device-registry.js'; import { EntityCache } from './utils/ha/entity-registry/cache.js'; @@ -828,6 +835,7 @@ class FrigateCard extends LitElement { this._generateConditionState(); this._setLightOrDarkMode(); + this._setPropertiesForMinMaxHeight(); this._untrigger(); } @@ -943,6 +951,18 @@ class FrigateCard extends LitElement { } } + protected _setPropertiesForMinMaxHeight(): void { + this.style.setProperty( + '--frigate-card-max-height', + this._getConfig().dimensions.max_height, + ); + + this.style.setProperty( + '--frigate-card-min-height', + this._getConfig().dimensions.min_height, + ); + } + /** * Get the most recent triggered camera. */ @@ -1853,9 +1873,6 @@ class FrigateCard extends LitElement { * @returns A padding percentage. */ protected _getAspectRatioStyle(): string { - // In expanded mode we must always set the aspect ratio since there are no - // constraints on the size. - if (!this._isAspectRatioEnforced()) { return 'auto'; } diff --git a/src/components/gallery.ts b/src/components/gallery.ts index 4413778d..c331be0d 100644 --- a/src/components/gallery.ts +++ b/src/components/gallery.ts @@ -1,5 +1,4 @@ import { - css, CSSResultGroup, html, LitElement, @@ -9,6 +8,7 @@ import { } from 'lit'; import { customElement, property, state } from 'lit/decorators.js'; import galleryStyle from '../scss/gallery.scss'; +import galleryCoreStyle from '../scss/gallery-core.scss'; import { CardWideConfig, ExtendedHomeAssistant, @@ -138,17 +138,8 @@ export class FrigateCardGallery extends LitElement { `; } - /** - * Get element styles. - */ static get styles(): CSSResultGroup { - return css` - :host { - display: block; - width: 100%; - height: 100%; - } - `; + return unsafeCSS(galleryStyle); } } @@ -525,11 +516,8 @@ export class FrigateCardGalleryCore extends LitElement { }); } - /** - * Get styles. - */ static get styles(): CSSResultGroup { - return unsafeCSS(galleryStyle); + return unsafeCSS(galleryCoreStyle); } } diff --git a/src/scss/card.scss b/src/scss/card.scss index b9833fa9..73244d8d 100644 --- a/src/scss/card.scss +++ b/src/scss/card.scss @@ -12,7 +12,13 @@ // keeping the background-color within the radius. border-radius: var(--ha-card-border-radius, 4px); - // The standard HA header is 56 pixels wide, so that much off the top (header) + // Necessary to ensure children adhere to height of outer container (without + // this gallery surround is not correctly positioned in the middle of the + // card, but rather the middle of the scrolling gallery container). + max-height: var(--frigate-card-max-height); + min-height: var(--frigate-card-min-height); + + // The standard HA header is 56 pixels tall, so that much off the top (header) // and bottom (to maintain center), before doing the calculation of // max-height. This matters on small mobile devices in landscape orientation. --frigate-card-expand-max-height: calc( ( 100vh - (2 * 56px) ) * 0.85 ); @@ -20,6 +26,9 @@ --frigate-card-expand-width: none; --frigate-card-expand-height: none; --frigate-card-expand-aspect-ratio: unset; + + --frigate-card-max-height: none; + --frigate-card-min-height: none; } :host([dark]) { @@ -27,7 +36,8 @@ } :host([panel]) { // Card always extends to the full allowed height in panel mode (in non-panel - // mode this would cause the card to expand to the height of a column). + // mode this would cause the card to expand to the height of a column when + // there are multiple cards in the column). height: 100%; } diff --git a/src/scss/gallery-core.scss b/src/scss/gallery-core.scss new file mode 100644 index 00000000..f6a230ec --- /dev/null +++ b/src/scss/gallery-core.scss @@ -0,0 +1,51 @@ +:host { + width: 100%; + height: 100%; + display: block; + overflow: auto; + + // Hide scrollbar: IE and Edge + -ms-overflow-style: none; + + // Hide scrollbar: Firefox + scrollbar-width: none; + + --frigate-card-gallery-gap: 3px; + --frigate-card-gallery-columns: 4; +} + +.grid { + display: grid; + grid-template-columns: repeat(var(--frigate-card-gallery-columns), minmax(0, 1fr)); + grid-auto-rows: min-content; + gap: var(--frigate-card-gallery-gap); +} + +// Hide scrollbar for Chrome, Safari and Opera +:host::-webkit-scrollbar { + display: none; +} + +frigate-card-thumbnail { + height: 100%; + max-height: var(--frigate-card-thumbnail-size); +} +frigate-card-thumbnail:not([details]) { + width: 100%; +} +frigate-card-thumbnail.selected { + border: 4px solid var(--accent-color); + // Because this is box-sizing: border-box, the border is effectively + // 'padding'. To get the curved borders to line up between the thumbnail and + // this outer border, we need to add the size of the border to the thumbnail + // image border radius. + // Related: https://www.30secondsofcode.org/articles/s/css-nested-border-radius + border-radius: calc( + var(--frigate-card-css-border-radius, var(--ha-card-border-radius, 4px)) + 4px + ); +} + +frigate-card-progress-indicator.top { + // The top loading progress indicator should span the whole width. + grid-column: 1/-1; +} diff --git a/src/scss/gallery.scss b/src/scss/gallery.scss index f6a230ec..9f12b3be 100644 --- a/src/scss/gallery.scss +++ b/src/scss/gallery.scss @@ -2,50 +2,11 @@ width: 100%; height: 100%; display: block; - overflow: auto; - - // Hide scrollbar: IE and Edge - -ms-overflow-style: none; - - // Hide scrollbar: Firefox - scrollbar-width: none; - - --frigate-card-gallery-gap: 3px; - --frigate-card-gallery-columns: 4; } -.grid { - display: grid; - grid-template-columns: repeat(var(--frigate-card-gallery-columns), minmax(0, 1fr)); - grid-auto-rows: min-content; - gap: var(--frigate-card-gallery-gap); -} - -// Hide scrollbar for Chrome, Safari and Opera -:host::-webkit-scrollbar { - display: none; -} - -frigate-card-thumbnail { - height: 100%; - max-height: var(--frigate-card-thumbnail-size); -} -frigate-card-thumbnail:not([details]) { - width: 100%; -} -frigate-card-thumbnail.selected { - border: 4px solid var(--accent-color); - // Because this is box-sizing: border-box, the border is effectively - // 'padding'. To get the curved borders to line up between the thumbnail and - // this outer border, we need to add the size of the border to the thumbnail - // image border radius. - // Related: https://www.30secondsofcode.org/articles/s/css-nested-border-radius - border-radius: calc( - var(--frigate-card-css-border-radius, var(--ha-card-border-radius, 4px)) + 4px - ); -} - -frigate-card-progress-indicator.top { - // The top loading progress indicator should span the whole width. - grid-column: 1/-1; +frigate-card-surround-basic { + // This must be re-specified (in addition to on the top card element) to + // ensure the filter 'tab' on the gallery drawer is correctly included on the + // non-scrolling part of the gallery. + max-height: var(--frigate-card-max-height); } diff --git a/src/types.ts b/src/types.ts index e6cc5324..9ef4e25f 100644 --- a/src/types.ts +++ b/src/types.ts @@ -1208,6 +1208,8 @@ export type GalleryConfig = z.infer; const dimensionsConfigDefault = { aspect_ratio_mode: 'dynamic' as const, aspect_ratio: [16, 9], + max_height: '100vh', + min_height: '100px', }; const dimensionsConfigSchema = z .object({ @@ -1225,6 +1227,8 @@ const dimensionsConfigSchema = z .transform((input) => input.split(/[:\/]/).map((d) => Number(d))), ) .default(dimensionsConfigDefault.aspect_ratio), + max_height: z.string().default(dimensionsConfigDefault.max_height), + min_height: z.string().default(dimensionsConfigDefault.min_height), }) .default(dimensionsConfigDefault);