diff --git a/README.md b/README.md index 56d1763a..a8ca4491 100644 --- a/README.md +++ b/README.md @@ -23,8 +23,9 @@ A full-featured Frigate Lovelace card: * Automatic updating to continually show latest clip / snapshot. * Support for filtering events by zone and label. * Arbitrary entity access via menu (e.g. motion sensor access). -* Fullscreen event gallery & media viewing. -* Full Lovelace editing support. +* Fullscreen mode. +* Lovelace visual editing support. +* Full [Picture Elements](https://www.home-assistant.io/lovelace/picture-elements/) support. * Theme friendly. * **Advanced**: Support for [WebRTC](https://github.com/AlexxIT/WebRTC) live viewing by embedding the WebRTC card. @@ -100,6 +101,7 @@ lovelace: | `controls.nextprev` | `thumbnails` | When viewing media, what kind of controls to show to move to the previous/next media item. Acceptable values: `thumbnails`, `chevrons`, `none` . | | `dimensions.aspect_ratio_mode` | `dynamic` | The aspect ratio mode to use. Acceptable values: `dynamic`, `static`, `unconstrained`. See [aspect ratios](#aspect-ratios) below.| | `dimensions.aspect_ratio` | `16:9` | The aspect ratio to use. Acceptable values: `:` or `/`. See [aspect ratios](#aspect-ratios) below.| +| `image` | [embedded image](https://www.flickr.com/photos/dianasch/47543120431) | A static image URL for use with the `image` [view](#views).| @@ -417,6 +419,7 @@ This card supports several different views. |`snapshot`|Shows the most recent snapshot for this camera/zone/label.| |`clips`|Shows the clip gallery for this camera/zone/label.| |`clip`|Shows the most recent clip for this camera/zone/label.| +|`image`|Shows a static image specified by the `image` parameter, can be used as a discrete default view or a screensaver (via `view_timeout`).| ### Automatic updates in the `clip` or `snapshot` view diff --git a/package.json b/package.json index 0610e5ae..b8eb4e09 100644 --- a/package.json +++ b/package.json @@ -21,12 +21,13 @@ "home-assistant-js-websocket": "^5.11.1", "lit": "^2.0.2", "screenfull": "^5.1.0", - "zod": "^3.9.8" + "zod": "^3.10.0-beta.1" }, "devDependencies": { "@babel/core": "^7.15.8", "@babel/plugin-proposal-class-properties": "^7.14.5", "@babel/plugin-proposal-decorators": "^7.15.8", + "@rollup/plugin-image": "^2.1.1", "@rollup/plugin-json": "^4.1.0", "@typescript-eslint/eslint-plugin": "^4.33.0", "@typescript-eslint/parser": "^4.33.0", diff --git a/rollup.config.js b/rollup.config.js index 30276be4..fcc97cab 100644 --- a/rollup.config.js +++ b/rollup.config.js @@ -6,6 +6,7 @@ import { terser } from 'rollup-plugin-terser'; import serve from 'rollup-plugin-serve'; import json from '@rollup/plugin-json'; import styles from 'rollup-plugin-styles'; +import image from '@rollup/plugin-image'; const dev = process.env.ROLLUP_WATCH; @@ -29,6 +30,7 @@ const plugins = [ includePaths: ['./node_modules/'], }, }), + image(), nodeResolve({}), commonjs(), typescript(), diff --git a/src/card.ts b/src/card.ts index 73e4d38d..27cc6ce1 100644 --- a/src/card.ts +++ b/src/card.ts @@ -31,6 +31,7 @@ import type { } from './types'; import { CARD_VERSION, REPO_URL } from './const'; +import { FrigateCardElements } from './components/elements'; import { FrigateCardMenu, MENU_HEIGHT } from './components/menu'; import { View } from './view'; import { homeAssistantWSRequest, shouldUpdateBasedOnHass } from './common'; @@ -40,6 +41,7 @@ import { renderMessage, renderProgressIndicator } from './components/message'; import './editor'; import './components/elements'; import './components/gallery'; +import './components/image'; import './components/live'; import './components/menu'; import './components/message'; @@ -48,7 +50,6 @@ import './patches/ha-camera-stream'; import './patches/ha-hls-player'; import cardStyle from './scss/card.scss'; -import { FrigateCardElements } from './components/elements'; const MEDIA_HEIGHT_CUTOFF = 50; const MEDIA_WIDTH_CUTOFF = MEDIA_HEIGHT_CUTOFF; @@ -112,7 +113,7 @@ export class FrigateCard extends LitElement { // A small cache to avoid needing to create a new list of entities every time // a hass update arrives. - protected _entitiesToMonitor: string[] | null = null; + protected _entitiesToMonitor: string[] = []; // Information about the most recently loaded media item. protected _mediaInfo: MediaLoadInfo | null = null; @@ -197,6 +198,15 @@ export class FrigateCard extends LitElement { emphasize: this._view.is('snapshots'), }); } + if (this.config.menu_buttons?.image ?? false) { + buttons.push({ + type: 'internal-menu-icon', + card_action: 'image', + title: localize('menu.image'), + icon: 'mdi:image', + emphasize: this._view.is('image'), + }); + } if ((this.config.menu_buttons?.frigate_ui ?? true) && this.config.frigate_url) { buttons.push({ type: 'internal-menu-icon', @@ -357,6 +367,7 @@ export class FrigateCard extends LitElement { case 'frigate': this._changeView(); break; + case 'image': case 'live': case 'clips': case 'snapshots': @@ -625,10 +636,22 @@ export class FrigateCard extends LitElement { const liveClasses = { hidden: this.config.live_preload && this._view.view != 'live', }; + const imageClasses = { + hidden: this.config.live_preload && this._view.view != 'image', + }; return html`
${this._message ? renderMessage(this._message) : ``} + ${!this._message && this._view.is('image') + ? html` + ` + : ``} ${!this._message && this._view.isGalleryView() ? html` { + dispatchMediaLoadEvent(this, e); + }} + >`; + } + + static get styles(): CSSResultGroup { + return unsafeCSS(imageStyle); + } +} diff --git a/src/declarations.d.ts b/src/declarations.d.ts index d5cf927a..59c79d0c 100644 --- a/src/declarations.d.ts +++ b/src/declarations.d.ts @@ -1 +1,2 @@ declare module '*.scss'; +declare module '*.jpg'; diff --git a/src/editor.ts b/src/editor.ts index b2a2b615..d1795c9f 100644 --- a/src/editor.ts +++ b/src/editor.ts @@ -102,6 +102,7 @@ export class FrigateCardEditor extends LitElement implements LovelaceCardEditor snapshots: localize('menu.snapshots'), clip: localize('menu.clip'), snapshot: localize('menu.snapshot'), + image: localize('menu.image'), }; const menuModes = { @@ -338,6 +339,15 @@ export class FrigateCardEditor extends LitElement implements LovelaceCardEditor .configValue=${'dimensions.aspect_ratio'} @value-changed=${this._valueChanged} > +
+ + + +