feat(ao-vivo): pontinho do PIR sobre a imagem do palco
Verde pulsando por 8 s depois de cada disparo, cinza sem presença; some quando o sensor não está disponível. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -48,6 +48,8 @@
|
|||||||
});
|
});
|
||||||
|
|
||||||
const cfg = $derived(estado.appConfig);
|
const cfg = $derived(estado.appConfig);
|
||||||
|
// Pontinho do PIR sobre a imagem: verde pulsando nos 8 s depois de cada disparo.
|
||||||
|
const pirAtivo = $derived(!!estado.pir?.ultimo && estado.agora - estado.pir.ultimo * 1000 < 8000);
|
||||||
const transmitindo = $derived(!!cfg?.preview);
|
const transmitindo = $derived(!!cfg?.preview);
|
||||||
const hora = (t: number) => new Date(t).toLocaleTimeString('pt-BR', { hour: '2-digit', minute: '2-digit', second: '2-digit' });
|
const hora = (t: number) => new Date(t).toLocaleTimeString('pt-BR', { hour: '2-digit', minute: '2-digit', second: '2-digit' });
|
||||||
|
|
||||||
@@ -70,6 +72,12 @@
|
|||||||
<div class="ao-vivo">
|
<div class="ao-vivo">
|
||||||
<!-- Palco fixo: a câmera continua visível enquanto a lista rola -->
|
<!-- Palco fixo: a câmera continua visível enquanto a lista rola -->
|
||||||
<section class="palco" aria-label="Câmera e rosto">
|
<section class="palco" aria-label="Câmera e rosto">
|
||||||
|
{#if estado.pir?.disponivel}
|
||||||
|
<span class="ponto-pir" class:ativo={pirAtivo} title="Sensor de presença (PIR)" aria-live="polite">
|
||||||
|
<span class="luz" aria-hidden="true"></span>
|
||||||
|
PIR{pirAtivo ? ' · presença' : ''}
|
||||||
|
</span>
|
||||||
|
{/if}
|
||||||
<div class="quadro camera" class:mini={rostoGrande}>
|
<div class="quadro camera" class:mini={rostoGrande}>
|
||||||
<!-- svelte-ignore a11y_media_has_caption -->
|
<!-- svelte-ignore a11y_media_has_caption -->
|
||||||
<video bind:this={elVideo} muted playsinline autoplay hidden={!video?.exibindo}></video>
|
<video bind:this={elVideo} muted playsinline autoplay hidden={!video?.exibindo}></video>
|
||||||
@@ -300,6 +308,41 @@
|
|||||||
.espaco {
|
.espaco {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
}
|
}
|
||||||
|
.ponto-pir {
|
||||||
|
position: absolute;
|
||||||
|
z-index: 3;
|
||||||
|
left: var(--e-3);
|
||||||
|
top: var(--e-3);
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 6px;
|
||||||
|
padding: 4px 10px 4px 7px;
|
||||||
|
border-radius: var(--raio-pill);
|
||||||
|
background: rgb(0 0 0 / 0.55);
|
||||||
|
color: #c7cdd4;
|
||||||
|
font: 600 11px var(--fonte);
|
||||||
|
letter-spacing: 0.04em;
|
||||||
|
pointer-events: none;
|
||||||
|
transition: color var(--transicao);
|
||||||
|
}
|
||||||
|
.ponto-pir .luz {
|
||||||
|
width: 10px;
|
||||||
|
height: 10px;
|
||||||
|
border-radius: 50%;
|
||||||
|
background: #6b7280;
|
||||||
|
transition: background var(--transicao);
|
||||||
|
}
|
||||||
|
.ponto-pir.ativo {
|
||||||
|
color: #b8f5c9;
|
||||||
|
}
|
||||||
|
.ponto-pir.ativo .luz {
|
||||||
|
background: #34c759;
|
||||||
|
animation: pulsoPir 1s ease-in-out infinite;
|
||||||
|
}
|
||||||
|
@keyframes pulsoPir {
|
||||||
|
0%, 100% { box-shadow: 0 0 0 0 rgb(52 199 89 / 0.7); }
|
||||||
|
50% { box-shadow: 0 0 0 7px rgb(52 199 89 / 0); }
|
||||||
|
}
|
||||||
/* ---------- lista */
|
/* ---------- lista */
|
||||||
.lista {
|
.lista {
|
||||||
display: grid;
|
display: grid;
|
||||||
|
|||||||
Reference in New Issue
Block a user