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:
@@ -0,0 +1,48 @@
|
||||
/** Registro da command palette (Ctrl+K): cada parte do painel contribui com itens. */
|
||||
import { cor, CORES, gesto, GESTOS_INFO, gestosDisponiveis, pararTudo, rearmar, recarregarCelular, rosto } from './comandos.svelte';
|
||||
import { estado } from './estado.svelte';
|
||||
import { nav, ROTAS } from './rotas.svelte';
|
||||
|
||||
export interface ItemPaleta {
|
||||
id: string;
|
||||
grupo: string;
|
||||
titulo: string;
|
||||
dica?: string;
|
||||
fazer: () => unknown;
|
||||
}
|
||||
|
||||
type Fonte = () => ItemPaleta[];
|
||||
const fontes = new Set<Fonte>();
|
||||
|
||||
export function registrarNaPaleta(fonte: Fonte): () => void {
|
||||
fontes.add(fonte);
|
||||
return () => fontes.delete(fonte);
|
||||
}
|
||||
|
||||
class Paleta {
|
||||
aberta = $state(false);
|
||||
abrir = () => (this.aberta = true);
|
||||
fechar = () => (this.aberta = false);
|
||||
}
|
||||
export const paleta = new Paleta();
|
||||
|
||||
export function itensDaPaleta(): ItemPaleta[] {
|
||||
return [...fontes].flatMap((f) => f());
|
||||
}
|
||||
|
||||
// Itens base: navegação, ações gerais, gestos, rostos e cores.
|
||||
registrarNaPaleta(() => [
|
||||
...ROTAS.map((r) => ({ id: 'ir-' + r.id, grupo: 'Ir para', titulo: r.titulo, fazer: () => nav.ir(r.id) })),
|
||||
estado.estop.ativo
|
||||
? { id: 'rearmar', grupo: 'Ações', titulo: 'Rearmar motores', fazer: rearmar }
|
||||
: { id: 'estop', grupo: 'Ações', titulo: 'Parar tudo (E-Stop)', dica: 'Shift+Espaço', fazer: pararTudo },
|
||||
{ id: 'recarregar', grupo: 'Ações', titulo: 'Recarregar tela do celular', fazer: recarregarCelular },
|
||||
...gestosDisponiveis().map((g) => ({
|
||||
id: 'gesto-' + g,
|
||||
grupo: 'Gestos',
|
||||
titulo: `${GESTOS_INFO[g].emoji} ${GESTOS_INFO[g].nome}`,
|
||||
fazer: () => gesto(g),
|
||||
})),
|
||||
...estado.rostos.map((r) => ({ id: 'rosto-' + r, grupo: 'Rosto', titulo: 'Rosto ' + r, fazer: () => rosto(r) })),
|
||||
...CORES.map((c) => ({ id: 'cor-' + c.nome, grupo: 'Cor dos olhos', titulo: c.nome, fazer: () => cor(c.rgb) })),
|
||||
]);
|
||||
Reference in New Issue
Block a user