feat(ui): badge "sem dispositivo virtual" deixa de ser beco sem saída — leva ao passo a passo do rodapé - #67
Conversation
…pe (#65) Nos estados amarelo (VB-CABLE nao renomeado) e vermelho (sem device virtual) o badge dizia o problema e escondia a solucao num <details> fechado a tres rolagens de distancia. Agora o badge inteiro e clicavel nesses estados e revela um CTA "como resolver ->" que abre o guia, rola ate ele e move o foco pro <summary>. - <details> do rodape ganha id="setup-guide" - badge segue <span> informativo; a semantica de botao vive num <button> interno, so visivel nos estados acionaveis (no verde nao ha role de botao nem cursor de acao, e o tooltip continua intacto) - aria-expanded do CTA reflete o <details> nos dois sentidos (abrir pelo badge e abrir/fechar direto no rodape) - rotulo do badge passa a guardar a chave em data-i18n, mesma convencao do conn-badge, para o toggle PT/EN reaplicar o estado - novas chaves badge.setup_cta e aria.setup_cta em PT e EN
Parecer do PR Doctor — aprovadaClassificação: HANDBOOK §7.3 (autonomia total) — diff 100% em Acceptance criteria da #65 — todos atendidos, por isso o
Dois pontos que verifiquei por serem os que quebrariam em silêncio:
Gate rodado por mim na worktree ( Gate também sobre a união com a main nova (a #64 entrou entre a abertura desta PR e este parecer, e as duas tocam Ressalva (não bloqueia): o CTA acrescenta largura ao badge nos estados amarelo/vermelho — em janela estreita o header quebra antes do que quebrava. O próprio corpo da PR declara isso; é visual, reversível, e só aparece justamente quando o usuário precisa da instrução. Squash-merge. |
Contexto
O badge de dispositivos é o primeiro diagnóstico que o usuário novo vê. Nos estados amarelo (
badge.laguna_cable— VB-CABLE detectado, não renomeado) e vermelho (badge.laguna_none— nenhum device virtual) ele dizia o que está errado e escondia como resolver: a receita mora no<details>fechado do rodapé, semide sem nenhum link apontando pra lá. Mesmo padrão de "erro visível mas não acionável" já pago na #33 e na #26 — aqui, no ponto de entrada.O que mudou (só
static/)<details>do rodapé ganhouid="setup-guide".<span>informativo; a semântica de botão vive num<button id="setup-guide-cta">interno, exibido apenas nos estados acionáveis. Isso atende ao critério "no verde não é anunciado como acionável" sem depender dedisabled(que arriscaria o tooltipdata-tipdo estado verde)..is-actionableestá presente. Ao acionar:details.open = true,scrollIntoView({behavior:'smooth', block:'start'})e foco no<summary>.aria-expandeddo CTA reflete o<details>nos dois sentidos: sincronizado no mesmo tick ao abrir pelo badge (o eventotoggleé assíncrono) e via listenertogglequando o usuário abre/fecha direto no rodapé.data-i18n— mesma convenção já usada emsetConnState()para oconn-badge— de modo que o toggle PT/EN reaplique o estado atual.badge.setup_cta("como resolver →" / "how to fix →") earia.setup_cta..badge.is-actionable { cursor: pointer }e.badge-ctacom reset de<button>(font/cor/borda/fundo) +:focus-visiblevisível.Gate (resultado real, rodado na worktree
i65)compileall -q .→COMPILE_OK; import-smoke defase0_poc, laguna_core, laguna_server→IMPORTS_OK.node --check static/app.js static/i18n.js→JS_OK;pytest tests_unit/test_i18n_parity.py -q→2 passed.static/).Além do gate, smoke funcional no navegador com o servidor da worktree (encerrado ao fim da rodada, porta 7531 livre), simulando os três estados:
has_laguna_name)class="badge ok", elementoSPAN,roleausente, CTAhidden,data-tippresentevirtual_outpresente)badge warn is-actionable, CTA visível; clique →details.open=true,activeElement=SUMMARY,aria-expanded="true"badge err is-actionable, CTA visível e focável (tabIndex=0), mesmo comportamento no cliquearia-label= "Open the setup step by step"aria-expandedacompanha (true→false)Riscos
Baixos e contidos em
static/: nenhum contrato REST/WS tocado, nenhum caminho quente de áudio, nenhuma chamada de rede nova. O único ponto de atenção é visual — o CTA acrescenta ~90px ao badge nos estados amarelo/vermelho, dentro do.badgesem flex; em janelas estreitas o header pode quebrar antes do que quebrava.Classificação HANDBOOK §7.3 (UI/i18n — autonomia total).
Closes #65