feat(web): cria painel Svelte com shell, Ao vivo e Ajustes

- web/ com Vite + Svelte 5 + TypeScript; servidor entrega web/dist em "/"
  (telas antigas seguem em /dashboard, /painel, /braco...)
- design system em tokens CSS, tema escuro e claro, fontes locais
- estado unico: foto de /estado + um EventSource em /eventos, sem polling
- shell com navegacao lateral/inferior, selos de status reais e E-Stop fixo
- command palette (Ctrl+K), gestos favoritos com atalhos 1-9, g+letra navega
- Ao vivo: camera WebRTC e rastreamento portados para TS, rosto, aparencia,
  sensores do celular, IA local e feed de acontecimentos
- Ajustes: campos do celular agrupados com busca, salvamento otimista e
  restaurar padrao (GET /app/padrao); motor da conversa, Gemini e token
- carinha.html ganha modo ?painel=1 dirigido por postMessage (sem polling)
- teste Playwright de ponta a ponta do painel novo

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
julio
2026-10-05 19:47:18 -03:00
co-authored by Claude Opus 5.5
parent 35d443a358
commit c4b53a8976
40 changed files with 4710 additions and 3 deletions
+56
View File
@@ -0,0 +1,56 @@
<script lang="ts">
import { KeyRound } from '@lucide/svelte';
import { gravarToken } from '../api';
import { conectar } from '../estado.svelte';
let token = $state('');
async function entrar(e: SubmitEvent) {
e.preventDefault();
gravarToken(token.trim());
await conectar();
}
</script>
<div class="fundo">
<form class="caixa" onsubmit={entrar}>
<KeyRound size={28} />
<h1>Token do Carinha</h1>
<p class="fraco pequeno-texto">
Este servidor exige um token para controlar o robô. Ele fica em <span class="mono">CARINHA_TOKEN</span> ou
<span class="mono">seguranca.json</span> na placa e é guardado só neste navegador.
</p>
<label class="campo">
<span>Token</span>
<!-- svelte-ignore a11y_autofocus -->
<input type="password" bind:value={token} autocomplete="current-password" required minlength="8" autofocus />
</label>
<button class="btn primario" type="submit">Entrar</button>
</form>
</div>
<style>
.fundo {
position: fixed;
inset: 0;
z-index: 100;
display: grid;
place-items: center;
padding: var(--e-4);
background: var(--fundo);
}
.caixa {
width: min(400px, 100%);
display: grid;
gap: var(--e-4);
padding: var(--e-6);
border-radius: var(--raio-lg);
background: var(--superficie);
border: 1px solid var(--borda);
color: var(--destaque);
}
h1,
p,
label {
color: var(--texto);
}
</style>