- 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>
49 lines
1.8 KiB
TypeScript
49 lines
1.8 KiB
TypeScript
/** 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) })),
|
|
]);
|