Pular para o conteúdo
OmniRoute source

OmniRoute — Design System & Visual Identity (Português (Brasil))

O site de marketing (viral.omniroute.online, why.omniroute.online, omniroute.online) e o dashboard do produto devem parecer um único produto. O site já adotou sua paleta do dashboard — seu css/tokens.css inclusive diz “A paleta espelha o dashboard do OmniRoute (src/app/globals.css)”. Portanto, ambos já estão cerca de 80% alinhados no nível das cores. O que falta no dashboard:

  1. O papel de parede quadriculado de papel milimetrado que o site utiliza em todas as páginas.
  2. Alguns tokens de design compartilhados que o site possui, mas o dashboard não (escala de raios, gradiente da marca, surface-2, fonte mono).
  3. Consistência no nível dos componentes — vários componentes do dashboard ignoram os tokens do tema e usam valores hex/rgba codificados diretamente.

Este documento apresenta a análise e o plano.


  • Fonte única da verdade = src/app/globals.css. O site espelha o dashboard, nunca o contrário. Novos tokens são adicionados primeiro ao globals.css.
  • Tokens, nunca literais. Os componentes consomem tokens semânticos (bg-surface, text-primary, border-border), nunca valores #hex brutos.
  • Sutil, não chamativo. A grade é um papel de parede discreto que fica atrás do conteúdo — ela jamais deve reduzir o contraste do texto ou competir com a interface.
  • Ciente do tema. Tudo funciona tanto no modo .dark (a aparência característica do produto) quanto no modo claro.
  • Implementação cirúrgica. Primeiro, entregue a grade + os tokens (baixo risco, alta visibilidade); depois, faça a limpeza dos componentes em etapas.

3. Estado atual — o que já está alinhado e o que não está

Seção intitulada “3. Estado atual — o que já está alinhado e o que não está”

Todas as cores da marca e superfícies já correspondem às do site em valor (apenas os nomes diferem — o dashboard usa o prefixo --color-). Verificado em src/app/globals.css:30-128:

Conceito Token do site (tokens.css) Token do dashboard (globals.css) Correspondência
primária --primary #e54d5e --color-primary #e54d5e ✅
primária-hover --primary-hover #c93d4e --color-primary-hover #c93d4e ✅
destaque --accent #6366f1 --color-accent #6366f1 ✅
destaque-2 --accent-2 #8b5cf6 --color-accent-hover #8b5cf6 ✅ (renomeado)
destaque-3 --accent-3 #a855f7 --color-accent-light #a855f7 ✅ (renomeado)
sucesso / aviso / erro #22c55e / #f59e0b / #ef4444 idênticos ✅
luzes de status #ff5f56 / #ffbd2e / #27c93f idênticas ✅
fundo / superfície / borda escuros #0b0e14 / #161b22 / rgba(255,255,255,.08) idênticos ✅
fundo / superfície / texto claros #f9f9fb / #fff / #1a1a2e idênticos ✅

Conclusão: não há nenhuma migração de cores a ser feita. A identidade já é compartilhada; estamos concluindo sua implementação, não a reconstruindo.

Lacuna O site possui Dashboard Ação
Papel de parede quadriculado Papel milimetrado em body::before, --grid-line, --grid-size 32px, --section-alt ✅ adicionado (Fase 1) Parte A
Escala de raio --radius 14px, --radius-sm 9px --radius 14px adicionado; -sm + redirecionamento dos componentes pendentes Parte B / Fase 2
Gradiente da marca --grad-brand 135deg primary→accent-3 ✅ token adicionado (Fase 1); utilizado na Fase 2 Parte B
Superfície aninhada --surface-2 #1c2230 ✅ adicionado (Fase 1) Parte B
Fonte monoespaçada --font-mono (pilha ui-monospace) pendente (Fase 4, com os consumidores) Parte B
text-muted (escuro) #8b8b9e #a1a1aa (zinc-400) reconciliar — Parte B

3.3 Mecânica de temas (para não quebrarmos nada)

Seção intitulada “3.3 Mecânica de temas (para não quebrarmos nada)”
  • Tailwind v4, CSS-first (sem tailwind.config.*). Os tokens são definidos em :root/.dark e disponibilizados aos utilitários por meio de @theme inline (globals.css:130-179).
  • Modo escuro via classe .dark em <html> (@custom-variant dark em globals.css:22), alternado por uma store Zustand personalizada (src/store/themeStore.ts), tema padrão = system (src/shared/constants/appConfig.ts:11). O site usa html[data-theme="light"] em vez disso — os mecanismos são diferentes, mas nunca se encontram (origens separadas), portanto não há conflito. Mantemos o mecanismo .dark do dashboard.
  • Existe uma substituição da cor primária em tempo de execução (themeStore.ts:85-97, predefinições em COLOR_THEMES) — os usuários podem trocar --color-primary. Qualquer novo token (gradiente etc.) que faça referência a --color-primary herda essas substituições sem nenhum esforço adicional. ✅
  • Nomes de raio reservados do Tailwind v4: --radius-sm/md/lg/... são a base dos utilitários rounded-*. Redefini-los altera retroativamente todos os rounded-* existentes (por exemplo, rounded-sm é usado em 12 arquivos). Portanto, o valor do raio pequeno e o redirecionamento dos componentes foram deliberadamente adiados para a Fase 2, quando os consumidores serão alterados em conjunto.

4. Parte A — O fundo de grade quadriculada (solicitação principal) — IMPLEMENTADO (Fase 1)

Seção intitulada “4. Parte A — O fundo de grade quadriculada (solicitação principal) — IMPLEMENTADO (Fase 1)”

A receita exata do site (_mono_repo/omnirouteSite/css/base.css): um pseudo-elemento fixo, ocupando toda a viewport, que desenha dois gradientes de linhas de 1px e fica em z-index:-1 atrás de todo o conteúdo.

body::before {
content: "";
position: fixed;
inset: 0;
z-index: -1;
pointer-events: none;
background-image:
linear-gradient(to right, var(--grid-line) 1px, transparent 1px),
linear-gradient(to bottom, var(--grid-line) 1px, transparent 1px);
background-size: var(--grid-size) var(--grid-size);
}

Por que isso funciona mesmo que body tenha um background-color opaco: um ::before com z-index:-1 é renderizado acima do fundo do próprio elemento, mas abaixo do conteúdo dele que está no fluxo. Portanto, --color-bg é o preenchimento base, a grade é sobreposta a ele e o aplicativo é renderizado acima da grade.

src/app/landing/page.tsx:16-26 já implementa essa mesma grade por página — mas com linhas vermelhas (#E54D5E, opacidade 0.06) a cada 50px, além de orbes animados. Portanto, o padrão já foi validado no produto; este trabalho o promove a um papel de parede global e adaptado ao tema.

:root {
/* claro — opacidade da grade aumentada em relação aos 0.045 do site para que o papel de parede
seja realmente visível no dashboard denso (cards/interface cobrem a maior parte da viewport) */
--grid-line: rgba(0, 0, 0, 0.07);
--grid-size: 32px;
--section-alt: rgba(0, 0, 0, 0.022);
}
.dark {
/* escuro — aumentada em relação a 0.035 pelo mesmo motivo */
--grid-line: rgba(255, 255, 255, 0.06);
--section-alt: rgba(255, 255, 255, 0.018);
}

A grade é global por definição (ela cobre o painel, auth/login, páginas de erro — todas as rotas — de uma só vez). Exatamente um elemento a ocultava dentro do painel:

  • src/shared/components/layouts/DashboardLayout.tsx — o wrapper externo desenhava um bg-bg opaco. Tudo abaixo dele já é transparente (<main>, o contêiner de rolagem e o elemento interno max-w-7xl), portanto, remover bg-bg permite que a grade do body apareça através da área de conteúdo (o --color-bg do body continua sendo o preenchimento base).

    <div className="flex h-dvh min-h-0 w-full overflow-hidden bg-bg">
    <div className="flex h-dvh min-h-0 w-full overflow-hidden">

4.5 Interação com a interface (barra lateral / cabeçalho)

Seção intitulada “4.5 Interação com a interface (barra lateral / cabeçalho)”
  • Header (Header.tsx:207, bg-bg) e Sidebar (Sidebar.tsx:430, bg-sidebar) permanecem opacos → a grade aparece somente na área de conteúdo, emoldurada por uma interface sólida. É um padrão visual discreto e corresponde à maneira como o site separa a interface da área de trabalho (decisão D3 = sólida).

Essas páginas são renderizadas diretamente sob &lt;body&gt; (sem a interface do painel), portanto, a grade global deve aparecer atrás delas automaticamente. Fase 5 — CONCLUÍDA: os wrappers independentes de tela cheia eram, de fato, opacos (min-h-screen … bg-bg, em que bg-bg é o mesmo preenchimento sólido de &lt;body&gt;), o que ocultava a grade em todas as telas fora do dashboard — não apenas no login. Agora, todos eles são transparentes para que o papel de parede compartilhado apareça: login, forgot-password, callback, maintenance, offline, status, terms, privacy, onboarding e ErrorPageScaffold (abrange 400/401). Isso conclui a D4 (ampliada de apenas login para todas as telas independentes). Protegido por tests/unit/design-grid-background.test.ts.

landing/page.tsx mantém seu fundo animado mais elaborado (orbes + vinheta) — sua própria apresentação de marketing (decisão D5 = manter como está).


A Fase 1 adiciona os tokens de identidade inertes e sem colisões (--surface-2/--color-surface-2, --grad-brand, --radius). A Fase 2 integra a escala de raios ao Tailwind e redireciona os componentes; a Fase 4 adiciona --font-mono e seus consumidores.

Token Motivo Fase
--radius / --radius-sm Uma escala de raios (14/9) em vez de valores ad hoc de 6/8/12 1 (valor) / 2 (integrar + redirecionar)
--grad-brand Gradiente da marca para CTAs primários (vermelho→violeta), igual ao site 1 (token) / 2 (Button)
--surface-2 Painéis aninhados / cabeçalhos de tabela / linhas recuadas 1
--font-mono Blocos de código, terminal, IDs, endpoints 4
reconciliar --text-muted Escolher um único valor para site↔painel (#a1a1aa recomendado) 2

D2 (text-muted): site #8b8b9e vs. dashboard #a1a1aa. Recomenda-se manter o #a1a1aa do dashboard e atualizar o site para corresponder. Alteração cosmética.


6. Parte C — Padronização de componentes (Fases 2–4)

Seção intitulada “6. Parte C — Padronização de componentes (Fases 2–4)”

Componentes personalizados (sem shadcn/Radix), Tailwind v4, tokens semânticos majoritariamente adotados (195 arquivos importam o barrel compartilhado). O trabalho consiste em remover os desvios. Local: src/shared/components/.

# Item Arquivo(s) Problema → Objetivo Fase
C1 Alinhamento dos raios Button.tsx:14-18, Card.tsx:39, Modal.tsx, Input.tsx, Select.tsx mistura de 6/8/12px → --radius/--radius-sm (14/9) 2
C2 Gradiente do Button + variante accent Button.tsx:5-12 primário é vermelho→vermelho chapado; alinhar a --grad-brand; adicionar a variante accent ausente. ~195 importadores — maior visibilidade 2
C3 Tabelas DataTable.tsx:122-176, logTableStyles.ts, globals.css:405-414 100% de rgba hardcoded inline + variáveis inexistentes; migrar para tokens e descontinuar estilos divergentes 3
C4 Centralizar cores de status flow/edgeStyles.ts, TokenHealthBadge.tsx, DegradationBadge.tsx, ProviderCascadeNode.tsx, Badge.tsx + 5 helpers mais de 6 cópias dos mesmos valores hex → um único módulo baseado em --color-success/warning/error 3
C5 Borda do Card Card.tsx:39 border-white/5 → marca /8 2
C6 Reconciliar anel de foco ✅ CONCLUÍDO globals.css --focus-ring (accent) vs. ring-primary/30 dos controles de formulário unificado em accent (violeta) para corresponder ao anel global + diferenciar do anel vermelho de erro; o erro permanece vermelho 4
C7 Adicionar Checkbox + Textarea &lt;input&gt;/&lt;textarea&gt; brutos com accentColor:#6366f1 inline primitivas orientadas por tokens 4
C8 Varredura de hex hardcoded ConsoleLogViewer.tsx:240, ComboLiveStudio.tsx:306, pontos do Modal, ~14 arquivos de gráficos literais → tokens 4
C9 cn() → clsx + tailwind-merge src/shared/utils/cn.ts classes conflitantes se acumulam; necessário para sobrescritas de C1 2

Já alinhados à marca (orientados por tokens, precisam apenas de raio): Badge, Toggle, SegmentedControl, Input, Select.


  • Fase 1 — Grid + tokens de identidade (ESTE PR). Grid no globals.css + tokens --surface-2/--grad-brand/--radius; wallpaper em body::before; remover o bloqueador bg-bg; teste de proteção estático. Baixo risco, reversível em um único commit.
  • Fase 2 — Primitivos (C1, C2, C5) — CONCLUÍDA neste PR. Utilitários semânticos de raio rounded-card (14px) / rounded-control (9px) adicionados via @theme (nomes personalizados, portanto os padrões rounded-sm/md/lg/xl permanecem intactos — sem impacto em 400 arquivos); Card/Modal → 14px, Button/Input/Select → 9px; Button primário → --grad-brand (vermelho→violeta) + nova variante accent; bordas de Card → o token border-border (0.08). Adiado: cn()→tailwind-merge (C9) precisa de novas dependências; a varredura pontual de rounded-lg (326 arquivos) foi mantida como está, pois os primitivos cobrem a maior parte da superfície.
  • Fase 3 — Cores de status + tabelas (C3, C4) — CONCLUÍDA neste PR. ✅ C4 (src/shared/constants/statusColors.ts — STATUS_HEX como fonte única; flow/edgeStyles.ts + TokenHealthBadge redirecionados, fiéis/mesmo valor hexadecimal). ✅ Token --font-mono. ✅ C3 (DataTable) — substituídos todos os rgba inline + os fallbacks inativos var(--bg-table-header) / var(--text-secondary) por um conjunto de tokens --table-* (--table-header-bg/-row-zebra/-row-hover/-cell-border/-row-selected), cujos valores no tema escuro são exatamente iguais aos antigos rgba codificados diretamente (tema escuro idêntico byte a byte) e cujos valores no tema claro corrigem o tema claro que antes era sempre escuro. Borda do cabeçalho → --color-border, texto secundário → --color-text-muted. Requer uma revisão visual antes do merge. (Não alterados: logTableStyles.ts e as regras legadas .ant-table do Ant — separados, com prioridade menor.)
  • Fase 4 — Limpeza (C6, C7, C9 concluídos; C8 pendente). ✅ C9 cn() → twMerge(clsx(...)) (clsx + tailwind-merge adicionados como dependências) — agora o className de quem chama substitui corretamente uma classe conflitante do primitivo, em vez de empilhá-la. ✅ C7 novos primitivos Checkbox + Textarea (orientados por tokens, exportados pelo barrel; aditivos — a adoção dos 32 checkboxes brutos / 41 textareas brutas pode ocorrer de forma incremental). ✅ C6 conciliação do anel de foco — os controles de formulário (Input/Select/Textarea/Toggle/Checkbox) agora usam o anel de accent (violeta) no foco para corresponder ao --focus-ring global e evitar conflito com o anel vermelho de erro; o estado vermelho de erro permanece inalterado. ⏳ A varredura de valores hexadecimais da C8 NÃO é um localizar/substituir indiscriminado — ocorrências confirmadas como intencionais e que devem permanecer: ConsoleLogViewer.tsx:240 (terminal sempre escuro), popover de TokenHealthBadge, traços SVG do ReactFlow. Migrar apenas valores hexadecimais que realmente devam responder ao tema.

Em cada fase: npm run lint + npm run typecheck:core + uma revisão visual.


  • D1 — Button primário: manter vermelho→vermelho ou mudar para vermelho→violeta --grad-brand? Recomendação: vermelho→violeta (Fase 2).
  • D2 — Cor das linhas do grid: neutra (estilo do site) — escolhida — em vez de vermelho da marca. Tamanho 32px (reduzido em ~30% em relação aos 46px originais após feedback do responsável — células de 46px pareciam grandes demais no layout do dashboard).
  • D3 — Vivacidade do chrome: sidebar/header sólidos — escolhido.
  • D4 — Grid de autenticação/login: ✅ CONCLUÍDO (Fase 5) — bg-bg opaco removido de todos os wrappers independentes de tela cheia (não apenas do login), para que o grid apareça em todas as telas. Consulte §4.6.
  • D5 — Landing page: manter a splash animada como está. Escolhido.
  • D6 — Raio 14/9 em todo o produto: Recomendação: sim (Fase 2).
  • D7 — Fase 1 enviada primeiro: Escolhido.
  • D8 — Largura do layout (Fase 5): o contêiner de conteúdo do dashboard estava limitado a max-w-7xl (1280px), ficando centralizado com amplas margens laterais vazias em monitores grandes. ✅ CONCLUÍDO — aumentado para um max-w-[3840px] fluido (4K real): agora o conteúdo acompanha a viewport até ~4K e só é centralizado além desse ponto (DashboardLayout.tsx). Páginas deliberadamente estreitas continuam estreitas por design (ProviderOnboardingWizard max-w-5xl, Rtk/CavemanContextPageClient max-w-6xl).
  • D9 — Tabelas de dados opacas (Fase 6): com a área de conteúdo do dashboard agora transparente (para que o wallpaper de grid apareça através dela, Fase 5), tabelas de dados cujo contêiner não era uma superfície opaca deixavam o grid vazar por suas linhas pares transparentes / zebra de baixa opacidade. ✅ CONCLUÍDO — agora toda tabela sem card aplica bg-surface (ou, no caso do primitivo <DataTable>, background: var(--color-surface) em seu contêiner de rolagem). Corrigidos: DataTable (primitivo), ProxyLogger/RequestLoggerV2 (o tom bg-black/5 dark:bg-black/20 de seus <Card> estava prevalecendo sobre o bg-surface do Card via tailwind-merge → ~95% transparente), BatchListTab/FilesListTab/CacheEntriesTab/ReasoningCacheTab/cache page/FreePoolTab/ModelMappingTable/HeaderTable, além das duas “tabelas” em CSS grid nas visualizações de cache (bg-surface/35 → bg-surface). As tabelas que já estavam dentro de um <Card>/Modal foram verificadas como opacas e deliberadamente mantidas intactas (bg-surface seria redundante e não teria efeito ali). O grid em si não precisou de nenhuma alteração — o body::before do dashboard é idêntico byte a byte ao do site (--grid-size: 32px); qualquer “grid maior” visto em uma instância em execução é um build antigo anterior ao #4143, não o código atual. Protegido por tests/unit/design-grid-background.test.ts (bloco da Fase 6).

  • Nenhuma alteração na paleta — as cores já correspondem; adicionamos apenas os tokens ausentes. Risco zero de alterar as cores do produto.
  • Nenhuma alteração no mecanismo de temas — manter .dark + store Zustand.
  • A mudança de raio (Fase 2) é abrangente — afeta todos os cards/botões/inputs; inspecione visualmente telas densas (tabelas, modais) antes do merge.
  • As tabelas (C3) concentram a maior quantidade de estilos hardcoded e a maior superfície de regressão — isole-as em seu próprio PR.

Área Caminho
Tokens do dashboard src/app/globals.css (:root, .dark, @theme inline, body, body::before)
Store de tema src/store/themeStore.ts, src/shared/components/ThemeProvider.tsx, src/shared/constants/appConfig.ts:9-11
Estrutura do painel (grid desbloqueado aqui) src/shared/components/layouts/DashboardLayout.tsx
Chrome src/shared/components/Header.tsx:207, src/shared/components/Sidebar.tsx:430
Precedente do grid src/app/landing/page.tsx:16-26
Primitivos src/shared/components/{Button,Card,Input,Select,Badge,Modal,Toggle,SegmentedControl,Loading,Tooltip,DataTable}.tsx
Fontes de cores de status flow/edgeStyles.ts, TokenHealthBadge.tsx, DegradationBadge.tsx, logTableStyles.ts
Utilitário cn src/shared/utils/cn.ts
Teste de proteção da Fase 1 tests/unit/design-grid-background.test.ts
Referência do site _mono_repo/omnirouteSite/css/tokens.css, css/base.css

Código-fonte do OmniRoute (a58000c7685f)

HagiCode

HagiCode é um ambiente de programação com agentes, fluxos estruturados, execução multiagente e visualizações Hero Dungeon.

Transforme ideias em software útil com um fluxo de trabalho com agentes mais inteligente, rápido e agradável.

Interface principal do HagiCode no tema claro
  • SmartFluxos estruturados transformam intenções em um caminho executável da ideia à entrega.
  • EfficientFluxos multiagente mantêm pesquisa, implementação e revisão em andamento simultaneamente.
  • FunO Hero Dungeon torna longas sessões de programação mais visuais e colaborativas.
Acessar HagiCode