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',