From e6b93d53e991bc4761d58d74a55f0fc6794c80c5 Mon Sep 17 00:00:00 2001 From: Dermot Duffy Date: Sun, 23 Aug 2026 12:25:44 -0700 Subject: [PATCH] fix: Reduce visual clutter on startup (#2709) - Closes: #2584 --- src/components-lib/notification/media.ts | 7 +-- src/components/live/provider.ts | 4 +- src/images/README.md | 5 +- src/images/iris-background.svg | 49 ------------------- src/scss/live-provider.scss | 12 +++++ src/scss/loading.scss | 5 +- src/scss/media-background.scss | 35 ++++++++++--- .../components-lib/notification/media.test.ts | 8 +++ 8 files changed, 59 insertions(+), 66 deletions(-) delete mode 100644 src/images/iris-background.svg diff --git a/src/components-lib/notification/media.ts b/src/components-lib/notification/media.ts index c952a298..6d4095a7 100644 --- a/src/components-lib/notification/media.ts +++ b/src/components-lib/notification/media.ts @@ -9,8 +9,9 @@ export interface MediaNotificationOptions { // A short heading. A longer explanation goes in `detail`. title: string; - // The heading icon. Defaults to a generic alert icon. - icon?: string; + // The heading icon. Defaults to a generic alert icon; `null` for no icon at + // all. + icon?: string | null; // Appended to the heading to identify the media, when it has a title (e.g. the // camera title `: Front Door`). Absent for untitled media (a url or @@ -36,7 +37,7 @@ export const createMediaNotification = ( options: MediaNotificationOptions, ): Notification => ({ heading: { - icon: options.icon ?? 'mdi:alert-circle', + ...(options.icon !== null && { icon: options.icon ?? 'mdi:alert-circle' }), text: options.targetTitle ? `${options.title}: ${options.targetTitle}` : options.title, diff --git a/src/components/live/provider.ts b/src/components/live/provider.ts index 3b33c987..4c76ac81 100644 --- a/src/components/live/provider.ts +++ b/src/components/live/provider.ts @@ -292,7 +292,7 @@ export class AdvancedCameraCardLiveProvider extends LitElement implements MediaP // endpoints). Instead, simply never render uninitialized cameras. if (!this.camera?.isInitialized()) { return renderMediaNotification({ - icon: 'mdi:progress-helper', + icon: null, title: localize('error.awaiting_live'), targetTitle: this.cameraTitle, }); @@ -488,7 +488,7 @@ export class AdvancedCameraCardLiveProvider extends LitElement implements MediaP return html`
${renderMediaNotification({ - icon: 'mdi:progress-helper', + icon: null, title: localize('error.awaiting_live'), targetTitle: this.cameraTitle, })} diff --git a/src/images/README.md b/src/images/README.md index d3cbdda6..26e3d27f 100644 --- a/src/images/README.md +++ b/src/images/README.md @@ -19,7 +19,7 @@ $ convert -strip -interlace Plane -quality 85% -scale 492x277 iris-screensaver-original.jpg iris-screensaver.jpg ``` -## icons/iris.svg / iris-background.svg +## icons/iris.svg **Link**: https://pictogrammers.com/library/mdi/icon/camera-iris/ @@ -27,8 +27,7 @@ $ convert -strip -interlace Plane -quality 85% -scale 492x277 iris-screensaver-o **Image Formatting Process**: -- `icons/iris.svg`: single-path variant for the card's custom iconset -- `iris-background.svg`: outline / opacity adjusted manually +- Single-path variant for the card's custom iconset ## icons/{frigate,motioneye,reolink,tplink}.svg diff --git a/src/images/iris-background.svg b/src/images/iris-background.svg deleted file mode 100644 index 53748cb5..00000000 --- a/src/images/iris-background.svg +++ /dev/null @@ -1,49 +0,0 @@ - - - - - - - - - diff --git a/src/scss/live-provider.scss b/src/scss/live-provider.scss index 2eeda624..d41dcab1 100644 --- a/src/scss/live-provider.scss +++ b/src/scss/live-provider.scss @@ -21,6 +21,18 @@ .fill { position: absolute; inset: 0; + + // `both` holds the status invisible for the length of the delay. + animation: fade-in 0.4s ease-out 3s both; +} + +@keyframes fade-in { + from { + opacity: 0; + } + to { + opacity: 1; + } } advanced-camera-card-icon { diff --git a/src/scss/loading.scss b/src/scss/loading.scss index 5ff3e7be..7861309a 100644 --- a/src/scss/loading.scss +++ b/src/scss/loading.scss @@ -24,10 +24,9 @@ opacity: 0; } -// The hidden element stays mounted: without this the icon would rotate -// invisibly forever. :host([loaded]) advanced-camera-card-icon { - animation: none; + display: none; + transition: display 0s 1.5s allow-discrete; } advanced-camera-card-icon { diff --git a/src/scss/media-background.scss b/src/scss/media-background.scss index 13c70d65..7cfa500a 100644 --- a/src/scss/media-background.scss +++ b/src/scss/media-background.scss @@ -1,11 +1,34 @@ -// Use the outlined Iris logo since the background color is unknown. -$bg-img: url('../images/iris-background.svg'); +$bracket-length: 24px; +$bracket-thickness: 1px; +$bracket-inset: 10px; + +// Mix from text color so the brackets show against both light/dark. +$bracket-color: color-mix( + in srgb, + var(--advanced-camera-card-text-color), + transparent 90% +); + +$arm: linear-gradient($bracket-color 0 0); +$arm-horizontal: $bracket-length $bracket-thickness; +$arm-vertical: $bracket-thickness $bracket-length; :host { background-color: var(--advanced-camera-card-background); - background-position: center; + + // Corner brackets mark a media surface that is rendering nothing at all, + // which is otherwise indistinguishable from a black video frame. + background-image: $arm, $arm, $arm, $arm, $arm, $arm, $arm, $arm; + background-size: $arm-horizontal, $arm-vertical, $arm-horizontal, $arm-vertical, + $arm-horizontal, $arm-vertical, $arm-horizontal, $arm-vertical; + background-position: + left $bracket-inset top $bracket-inset, + left $bracket-inset top $bracket-inset, + right $bracket-inset top $bracket-inset, + right $bracket-inset top $bracket-inset, + left $bracket-inset bottom $bracket-inset, + left $bracket-inset bottom $bracket-inset, + right $bracket-inset bottom $bracket-inset, + right $bracket-inset bottom $bracket-inset; background-repeat: no-repeat; - background-image: $bg-img; - background-size: 10%; - background-position: center; } diff --git a/tests/components-lib/notification/media.test.ts b/tests/components-lib/notification/media.test.ts index 53307706..b347f784 100644 --- a/tests/components-lib/notification/media.test.ts +++ b/tests/components-lib/notification/media.test.ts @@ -21,6 +21,14 @@ describe('createMediaNotification', () => { expect(notification.heading?.icon).toBe('mdi:alert-circle'); }); + it('should omit the heading icon when it is null', () => { + const notification = createMediaNotification({ + icon: null, + title: 'Awaiting live view', + }); + expect(notification.heading?.icon).toBeUndefined(); + }); + it('should append the camera title to the heading', () => { const notification = createMediaNotification({ icon: 'mdi:alert-circle',