fix: Improve visual styling for transmitting/triggering (#2490)
This commit is contained in:
committed by
dermotduffy
parent
090138a01e
commit
f21a46297a
@@ -114,6 +114,8 @@ Allows overriding of any CSS value, can be used to tweak theming parameters.
|
|||||||
| --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------ |
|
| --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------ |
|
||||||
| Any CSS key. Overriding the [Advanced Camera Card](https://github.com/dermotduffy/advanced-camera-card/blob/main/src/scss/themes/base.scss) CSS variables allows changing individual theming parameters, e.g. `--advanced-camera-card-menu-override-background` | Any CSS value, e.g. `red` or `rgba(10, 11, 12, 0.64)`. |
|
| Any CSS key. Overriding the [Advanced Camera Card](https://github.com/dermotduffy/advanced-camera-card/blob/main/src/scss/themes/base.scss) CSS variables allows changing individual theming parameters, e.g. `--advanced-camera-card-menu-override-background` | Any CSS value, e.g. `red` or `rgba(10, 11, 12, 0.64)`. |
|
||||||
|
|
||||||
|
> [!WARNING] Changes to CSS keys are not considered breaking changes and may not have an associated [major version change](../developing.md?id=release-philosophy).
|
||||||
|
|
||||||
## `triggers`
|
## `triggers`
|
||||||
|
|
||||||
The `triggers` block controls how the card reacts when a camera is triggered
|
The `triggers` block controls how the card reacts when a camera is triggered
|
||||||
|
|||||||
@@ -445,6 +445,8 @@ export class AdvancedCameraCardLiveCarousel extends LitElement {
|
|||||||
<!-- -->
|
<!-- -->
|
||||||
${this._renderNextPrevious('right', neighbors)}
|
${this._renderNextPrevious('right', neighbors)}
|
||||||
</advanced-camera-card-carousel>
|
</advanced-camera-card-carousel>
|
||||||
|
<div class="status-glow status-glow--trigger"></div>
|
||||||
|
<div class="status-glow status-glow--transmitting"></div>
|
||||||
<advanced-camera-card-ptz
|
<advanced-camera-card-ptz
|
||||||
.hass=${this.hass}
|
.hass=${this.hass}
|
||||||
.config=${this.liveConfig.controls.ptz}
|
.config=${this.liveConfig.controls.ptz}
|
||||||
|
|||||||
@@ -35,3 +35,82 @@
|
|||||||
|
|
||||||
flex: 0 0 100%;
|
flex: 0 0 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Triggered and transmitting cameras are highlighted with a soft inset glow,
|
||||||
|
// drawn by an overlay stacked above the camera feed. The overlays come before
|
||||||
|
// the carousel controls in source order, so they stack above the feed but
|
||||||
|
// below the controls; `pointer-events: none` keeps them inert. The glow is an
|
||||||
|
// interior effect, so it coexists with the grid selection border (see
|
||||||
|
// media-grid.scss) without competing for the `border` property.
|
||||||
|
//
|
||||||
|
// The two states differ by colour and rhythm: triggered is an amber glow that
|
||||||
|
// pulses fully out and back (a "something happened" beacon), transmitting is a
|
||||||
|
// red glow that breathes gently without ever fully fading ("you are live").
|
||||||
|
// Transmitting wins: while it is active the trigger overlay is faded out.
|
||||||
|
|
||||||
|
// Triggered: pulse from nothing to a full amber glow and back.
|
||||||
|
@keyframes trigger-vignette-pulse {
|
||||||
|
0%,
|
||||||
|
100% {
|
||||||
|
box-shadow: inset 0 0 var(--advanced-camera-card-trigger-glow-size) transparent;
|
||||||
|
}
|
||||||
|
50% {
|
||||||
|
box-shadow: inset 0 0 var(--advanced-camera-card-trigger-glow-size)
|
||||||
|
var(--advanced-camera-card-trigger-glow-color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Transmitting: breathe between a softer and a fuller glow — never fully fades,
|
||||||
|
// so the camera always reads as live.
|
||||||
|
@keyframes transmitting-vignette-pulse {
|
||||||
|
0%,
|
||||||
|
100% {
|
||||||
|
box-shadow: inset 0 0 calc(var(--advanced-camera-card-transmitting-glow-size) * 0.55)
|
||||||
|
var(--advanced-camera-card-transmitting-glow-color);
|
||||||
|
}
|
||||||
|
50% {
|
||||||
|
box-shadow: inset 0 0 var(--advanced-camera-card-transmitting-glow-size)
|
||||||
|
var(--advanced-camera-card-transmitting-glow-color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-glow {
|
||||||
|
position: absolute;
|
||||||
|
inset: 0;
|
||||||
|
pointer-events: none;
|
||||||
|
|
||||||
|
// Hidden by default; activation/deactivation is a plain opacity fade. Each
|
||||||
|
// overlay carries its own static box-shadow (not scoped to the
|
||||||
|
// `[triggered]`/`[transmitting]` selectors) so the glow stays painted in its
|
||||||
|
// own colour throughout the fade-out, after its animation has been removed.
|
||||||
|
opacity: 0;
|
||||||
|
transition: opacity 0.5s ease-in-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-glow--trigger {
|
||||||
|
box-shadow: inset 0 0 var(--advanced-camera-card-trigger-glow-size)
|
||||||
|
var(--advanced-camera-card-trigger-glow-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-glow--transmitting {
|
||||||
|
box-shadow: inset 0 0 var(--advanced-camera-card-transmitting-glow-size)
|
||||||
|
var(--advanced-camera-card-transmitting-glow-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
:host([triggered]) .status-glow--trigger {
|
||||||
|
opacity: 1;
|
||||||
|
animation: trigger-vignette-pulse 5s infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Transmitting takes precedence: while it is active the trigger overlay is
|
||||||
|
// faded out. This rule follows the `[triggered]` rule with equal specificity,
|
||||||
|
// so it wins the cascade.
|
||||||
|
:host([transmitting]) .status-glow--trigger {
|
||||||
|
opacity: 0;
|
||||||
|
animation: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
:host([transmitting]) .status-glow--transmitting {
|
||||||
|
opacity: 1;
|
||||||
|
animation: transmitting-vignette-pulse 4s ease-in-out infinite;
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,61 +1,8 @@
|
|||||||
@use 'basic-block.scss';
|
@use 'basic-block.scss';
|
||||||
@use 'locked.scss';
|
@use 'locked.scss';
|
||||||
|
|
||||||
@keyframes warning-pulse {
|
|
||||||
0% {
|
|
||||||
border-color: var(--trigger-border-color-base);
|
|
||||||
}
|
|
||||||
50% {
|
|
||||||
border-color: var(--trigger-border-color);
|
|
||||||
}
|
|
||||||
100% {
|
|
||||||
border-color: var(--trigger-border-color-base);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
advanced-camera-card-live-carousel {
|
|
||||||
--trigger-border-color: var(--advanced-camera-card-trigger-border-color);
|
|
||||||
--trigger-border-color-base: var(
|
|
||||||
--advanced-camera-card-trigger-border-color-base,
|
|
||||||
black
|
|
||||||
);
|
|
||||||
|
|
||||||
transition: border-color 0.3s ease-out;
|
|
||||||
}
|
|
||||||
|
|
||||||
// `:host >` matches the carousel only in single display mode (in grid mode it
|
|
||||||
// is nested inside `media-grid`). The single-mode carousel has no border of its
|
|
||||||
// own, so reserve a transparent one so border changes (e.g. trigger) only
|
|
||||||
// recolour. In grid mode the border is supplied (already width-reserved) by
|
|
||||||
// `media-grid`.
|
|
||||||
:host > advanced-camera-card-live-carousel {
|
|
||||||
box-sizing: border-box;
|
|
||||||
border: solid 2px transparent;
|
|
||||||
}
|
|
||||||
|
|
||||||
advanced-camera-card-live-carousel[triggered] {
|
|
||||||
animation: warning-pulse 5s infinite;
|
|
||||||
}
|
|
||||||
// The `:host` prefix raises specificity to (0,2,1), above `media-grid`'s
|
|
||||||
// `::slotted([selected])` border (0,1,1). In grid mode that rule lives in an
|
|
||||||
// inner shadow tree and would otherwise win the cross-tree cascade tie,
|
|
||||||
// leaving the transmitting border the wrong colour. `[triggered]` needs no
|
|
||||||
// such treatment — animated values always beat the regular cascade.
|
|
||||||
:host advanced-camera-card-live-carousel[transmitting] {
|
|
||||||
// `animation: none` cancels any concurrent trigger pulse to ensure
|
|
||||||
// transmitting takes precedence.
|
|
||||||
animation: none;
|
|
||||||
border-color: var(--advanced-camera-card-transmitting-border-color);
|
|
||||||
}
|
|
||||||
// While locked, dim and disable interaction on the non-selected cameras in the
|
// While locked, dim and disable interaction on the non-selected cameras in the
|
||||||
// grid so input stays on the selected camera (e.g. during a call).
|
// grid so input stays on the selected camera (e.g. during a call).
|
||||||
:host([locked]) advanced-camera-card-live-carousel[unselected] {
|
:host([locked]) advanced-camera-card-live-carousel[unselected] {
|
||||||
@include locked.style;
|
@include locked.style;
|
||||||
}
|
}
|
||||||
|
|
||||||
advanced-camera-card-live-carousel[selected] {
|
|
||||||
--trigger-border-color-base: var(
|
|
||||||
--advanced-camera-card-trigger-border-color-base,
|
|
||||||
var(--advanced-camera-card-foreground-primary)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -245,15 +245,16 @@
|
|||||||
/*********
|
/*********
|
||||||
* Trigger
|
* Trigger
|
||||||
*********/
|
*********/
|
||||||
--advanced-camera-card-trigger-border-color: var(--advanced-camera-card-warning-color);
|
--advanced-camera-card-trigger-glow-color: var(--advanced-camera-card-active-color);
|
||||||
--advanced-camera-card-trigger-border-color-base: unset;
|
--advanced-camera-card-trigger-glow-size: 16px;
|
||||||
|
|
||||||
/**************
|
/**************
|
||||||
* Transmitting
|
* Transmitting
|
||||||
**************/
|
**************/
|
||||||
--advanced-camera-card-transmitting-border-color: var(
|
--advanced-camera-card-transmitting-glow-color: var(
|
||||||
--advanced-camera-card-warning-color
|
--advanced-camera-card-warning-color
|
||||||
);
|
);
|
||||||
|
--advanced-camera-card-transmitting-glow-size: 28px;
|
||||||
|
|
||||||
/*****
|
/*****
|
||||||
* Grid
|
* Grid
|
||||||
|
|||||||
Reference in New Issue
Block a user