Pular para o conteúdo

Primitivas de UI — Um Guia de Campo

Se alguma vez olhou para uma aplicação moderna e pensou “como é que chamam àquela coisa?” — esta página é para si.

Todas as interfaces que utiliza são construídas a partir de um conjunto surpreendentemente pequeno de blocos reutilizáveis chamados primitivas de UI. Têm nomes. Nomes estranhos, por vezes. Mas assim que se percebe a metáfora, nunca mais se deixa de a ver.

O En Parlant~ utiliza o Mantine, uma biblioteca de componentes React que fornece todas estas primitivas prontas a usar. Aqui está o seu guia de campo.


Um toast é uma pequena notificação que surge a partir do canto do ecrã, permanece uns segundos e depois desliza para fora. Como uma fatia de pão a saltar da torradeira — só que a gravidade funciona ao contrário e acaba por voltar para dentro.

No En Parlant~, os toasts aparecem no canto inferior direito (via @mantine/notifications do Mantine) para coisas como:

  • “Base de dados carregada com sucesso” — pop
  • “Voz TTS não configurada” — pop
  • “Falha ao ligar ao Lichess” — pop, e sentimos uma certa tristeza

Nunca os pedimos. Simplesmente aparecem, entregam a mensagem e vão-se embora. São os pombos-correio do mundo das interfaces.

Um card é um contentor retangular com um contorno ou sombra que agrupa conteúdo relacionado. Imagine um cartão de índice pousado numa secretária — tem um limite definido, contém uma coisa, e pode ser pegado e movido.

No En Parlant~, encontrará cards para:

  • Pré-visualizações de jogos no navegador de bases de dados (GameCard) — nomes dos jogadores, resultado, data
  • Editor de posição no tabuleiro (EditingCard) — o card que se vira ao configurar uma posição personalizada
  • Entradas de bases de dados na página de bases de dados — cada base de dados tem o seu próprio card numa grelha

Os cards têm um primo próximo chamado Paper, que é basicamente um card que andou numa escola de artes. Mesma ideia — um contentor com contorno ou sombra — mas com menos significado semântico. O Paper diz apenas “sou uma superfície.” Aparece como fundo por detrás dos painéis de análise e dos displays de informação das bases de dados.

Não é utilizado atualmente no En Parlant~, mas vale a pena conhecer: um drawer é um painel que desliza a partir do canto do ecrã, como uma gaveta de secretária. (É isso. É toda a metáfora. Os designers de UI foram muito literais nesse dia.)


Um modal é um diálogo popup que exige a sua atenção. Escurece o fundo e obriga-o a lidar com ele antes de fazer qualquer outra coisa. É a criança de dois anos dos padrões de UI — “OLHA PARA MIM AGORA MESMO.”

O En Parlant~ usa modais para momentos que genuinamente precisam do seu foco:

  • “Tem a certeza de que quer limpar todos os dados?” (ClearDataModal) — com checkboxes para poder escolher quais dados obliterar
  • “Está disponível uma atualização” (UpdateModal) — com uma barra de progresso enquanto faz o download
  • “Importar um jogo” (ImportModal) — cole um PGN, introduza um FEN ou largue um link
  • “Criar um novo repertório” (CreateRepertoireModal) — dê-lhe um nome, configure-o, avance
  • “Acerca do En Parlant~” (About) — informação da versão, créditos, o habitual passe dos bastidores

Os modais dizem: “Isto é uma conversa. Vamos tê-la agora.”

Um dialog é o primo educado do modal. No Mantine, são essencialmente o mesmo componente, mas na teoria de design de UI, um dialog é mais pequeno e mais focado — uma única pergunta e resposta. “Guardar alterações?” Sim / Não. Feito.

O En Parlant~ usa ConfirmModal para estes momentos rápidos de sim-ou-não, como confirmar que quer descartar alterações não guardadas.


Um tooltip é uma pequena etiqueta que aparece quando se passa o rato sobre algo. É o estranho prestável que sussurra a resposta quando parecemos confusos.

Os tooltips estão por todo o lado no En Parlant~. Passe o rato sobre quase qualquer botão com ícone e receberá um:

  • Passe sobre o botão ↻ → “Recarregar”
  • Passe sobre um caminho de ficheiro truncado → o caminho completo aparece
  • Passe sobre um símbolo de anotação → o significado desse símbolo
  • Passe sobre um lance no painel de análise → surge uma pré-visualização em miniatura do tabuleiro

Os tooltips são o “manual não necessário” original.

Um popover é um tooltip que foi para a pós-graduação. Em vez de mostrar apenas uma etiqueta de texto, pode conter qualquer coisa — botões, imagens, até um tabuleiro de xadrez em miniatura.

No En Parlant~, quando se passa o rato sobre um lance na análise do motor, um popover renderiza uma pré-visualização do tabuleiro nessa posição. É um tooltip, mas trouxe apoio visual.

Um menu é uma lista de ações que aparece quando se clica (ou clica com o botão direito) em algo. Utiliza-os desde os primórdios da informática — Ficheiro, Editar, Ver. Sabe como funciona.

O En Parlant~ tem duas variantes:

  • Menus da barra superior — a clássica barra de menu Ficheiro / Editar / Ver, construída com o componente Menu do Mantine. Atalhos de teclado listados à direita. Um padrão de design tão antigo que já tem reforma.
  • Menus de contexto — clique com o botão direito num lance na árvore de jogo e obtém opções como Promover Variante, Eliminar a Partir Daqui e Copiar Linha. Estes usam a biblioteca mantine-contextmenu para maior polimento.

Os menus têm o seu próprio sub-vocabulário: Menu.Target (a coisa em que se clica), Menu.Dropdown (a lista que aparece), Menu.Item (cada opção) e Menu.Divider (a linha fina que diz “secção diferente agora”).


São a manteiga de amendoim e a geleia do layout.

  • Stack organiza as coisas verticalmente — uma em cima da outra. Como empilhar livros.
  • Group organiza as coisas horizontalmente — lado a lado. Como alinhar peças de xadrez numa prateleira.

Aparecem literalmente em mais de 100 ficheiros cada. São os componentes mais comuns em toda a aplicação. Sempre que as coisas estão bem arrumadas, um Stack ou Group é o responsável.

Flex é o primo canivete suíço do Stack e do Group. Quando as coisas precisam de envolver, esticar, encolher, inverter ou comportar-se de forma inusitada, o Flex entra em ação com controlo total sobre o modelo CSS Flexbox.

Usado na lista de lances do painel de análise — aquelas sequências de lances que envolvem e fluem como texto? É o Flex a fazer o trabalho pesado.

Uma Box é uma <div> a usar cartola. Não faz nada sozinha — é apenas um contentor genérico. Mas aceita as propriedades de estilização do Mantine, o que a torna num invólucro incrivelmente prático para “preciso de uma coisa à volta desta outra coisa.”

A Box aparece em mais de 150 ficheiros. É a fita adesiva da biblioteca de componentes.

Faz exatamente o que o nome indica. Coloca algo no centro. Horizontalmente. Verticalmente. Ambos. Pronto.

Aparece em estados vazios — quando não há contas ligadas, bases de dados carregadas, dados ainda. Um ícone grande, uma mensagem, e o Center a certificar-se de que está perfeitamente posicionado. Ninguém gosta de um estado vazio descentrado.

Uma grelha que é simples. Indica-se quantas colunas e ela organiza os cards numa grelha arrumada que se reorganiza à medida que a janela é redimensionada. A página de bases de dados usa-a para dispor os cards das bases de dados numa grelha responsiva.

Um contentor que faz scroll quando o conteúdo transborda. Poder-se-ia pensar que isto é gratuito — e de certa forma é, com CSS overflow: auto — mas a ScrollArea adiciona barras de scroll estilizadas, scroll com momentum e deteção de transbordamento. Envolve o painel da árvore de jogo, as linhas de análise, e qualquer lugar onde o conteúdo possa crescer mais do que a sua caixa.

O AppShell é o layout principal — o esqueleto de toda a aplicação. Define onde fica o cabeçalho, onde fica a barra lateral e onde vive o conteúdo principal. Tudo o resto se encaixa dentro dele.

Usa-se apenas uma vez. É a fundação da casa.

Um Portal é um buraco de minhoca mágico. Renderiza um componente fora da sua posição normal na árvore do DOM e coloca-o noutro lugar — normalmente na raiz do documento. É assim que os popovers e as pré-visualizações do tabuleiro evitam ser cortados por contentores-pai com overflow: hidden.

Nunca se vê um Portal. Veem-se apenas os seus efeitos. É a equipa de bastidores dos componentes de UI.


Um retângulo clicável com texto. Este já conhece. No Mantine, os botões vêm em variantes:

  • filled — cor sólida, grande ênfase. “Clica em mim, sou importante.”
  • outline — apenas um contorno. “Sou uma opção, mas sem pressão.”
  • subtle — quase invisível. “Estou aqui se precisares.”
  • default — um meio-termo neutro.

O En Parlant~ usa todas estas variantes em mais de 150 ficheiros. O padrão mais comum: um Group de botões no fundo de um modal — “Cancelar” (subtle) e “Confirmar” (filled). Clássico.

Um ActionIcon é um botão que abdicou da sua etiqueta de texto e se comprometeu totalmente com o estilo de vida dos ícones. É compacto, quadrado e depende do seu ícone (mais um tooltip) para comunicar o seu propósito.

Botões de barra de ferramentas, controlos de painéis, botões de fechar — todos ActionIcons. São a forma mais eficiente em termos de espaço de oferecer uma ação.

Um Switch é um interruptor que parece um pequeno interruptor de luz. Mexe-se para a esquerda, mexe-se para a direita. Ligado. Desligado.

Nas definições, os switches controlam escolhas binárias:

  • Som ligado/desligado
  • Narração TTS ativada/desativada
  • Modo escuro / modo claro

A metáfora física é tão boa que até os avós a compreendem.

Um Slider é uma pista com uma alça que se arrasta para trás e para a frente para selecionar um valor. Como um botão de volume que foi achatado.

O En Parlant~ usa sliders para:

  • Tamanho da fonte — arraste para ajustar
  • Volume — arraste para ajustar (claro)
  • Núcleos de CPU — quantos núcleos deve o motor usar?
  • Memória hash — quanta RAM para a tabela hash do motor?

Existe também um RangeSlider com duas alças para selecionar um intervalo — usado para filtrar jogos por classificação Elo (por exemplo, 2000–2200) e períodos de tempo.

Uma fila de botões onde exatamente um está selecionado de cada vez. É como os botões de preset de um rádio de carro — carrega-se num, os outros saltam para fora.

Usado para alternar entre:

  • Avaliação em centipeões vs. percentagens de Vitória/Empate/Derrota no gráfico de análise
  • Diferentes formatos de notação de lances
  • Contagem de linhas do motor

Estes já conhece. Checkboxes para “selecione todos os que se apliquem,” dropdowns Select para “escolha um desta lista.” Aparecem nas definições, filtros e formulários por toda a aplicação. O modal Limpar Dados tem um conjunto particularmente satisfatório de checkboxes onde se pode escolher a própria destruição.

Um campo de texto que sugere completações à medida que se escreve. A pesquisa de jogadores no navegador de bases de dados usa isto — comece a escrever um nome e os jogadores correspondentes aparecem por baixo.

O FileInput abre um seletor de ficheiros quando clicado — usado no modal de importação para carregar ficheiros PGN. O DateInput abre um calendário para selecionar uma data — usado para filtrar jogos por data. Existem também o MonthPickerInput e o YearPickerInput para quando se precisa de menos precisão (filtragem de bases de dados do Lichess por mês, filtragem de bases de dados Masters por ano).


Uma barra horizontal que se preenche da esquerda para a direita para mostrar o quão longe algo está. Usada durante atualizações da aplicação (progresso do download) e — de forma mais criativa — para mostrar probabilidades de Vitória/Empate/Derrota no painel de análise. Três secções coloridas (branco, cinzento, preto) preenchem a barra proporcionalmente. É um pequeno gráfico de barras disfarçado de indicador de progresso.

Um Loader é uma animação giratória que diz “estou a trabalhar nisso, dá-me um segundo.” Aparece enquanto as bases de dados estão a carregar, as estatísticas de jogadores estão a ser obtidas, ou qualquer coisa assíncrona está a acontecer.

Um Skeleton é um espaço reservado cinzento que imita a forma do conteúdo que ainda não carregou. Em vez de um ecrã em branco ou um spinner, veem-se contornos fantasma de onde os cards e o texto irão estar. É a planta arquitetónica de um estado de carregamento — “a mobília verdadeira está a caminho.”

A página de bases de dados usa skeletons enquanto a grelha de cards carrega. Muito mais elegante do que um spinner sozinho.

Um manto semi-transparente lançado sobre um componente enquanto está a carregar. O gráfico de análise usa isto — ainda se pode ver o gráfico por detrás da sobreposição, mas está escurecido, e há um spinner por cima. “Ainda estou aqui, só a atualizar.”


Um Badge é uma pequena etiqueta colorida — como um crachá numa conferência. No En Parlant~, o componente SpeedBadge usa badges para exibir controlos de tempo com código de cores:

  • 🩷 Rosa — UltraBullet
  • 🔴 Vermelho — Bullet
  • 🟠 Laranja — Blitz
  • 🟢 Verde — Rapid
  • 🔵 Azul — Classical
  • 🟣 Roxo — Correspondence

Cada badge é pequeno, colorido e comunica instantaneamente a velocidade do jogo num relance.

Abreviatura de keyboard. Exibe uma tecla de teclado com aquele estilo característico de tecla em relevo. Usado nas definições de atalhos de teclado para mostrar coisas como Ctrl + Z. É uma recriação em CSS de uma tecla física real do teclado. Deliciosamente esqueomórfico.


Uma linha horizontal que separa secções. É isso. É uma linha. Mas é uma linha estilizada, e pode opcionalmente ter uma etiqueta de texto no meio — como o divisor ”— OU —” no modal de importação que separa “cole um PGN” de “introduza um FEN.”

Mais de trinta ficheiros usam Divider. Acontece que as coisas precisam de ser separadas bastante.

Um Collapse é uma secção que expande e contrai com uma animação suave. Clique para revelar, clique para esconder. As opções de filtro da base de dados usam isto — nem sempre se precisa de ver todos os filtros, por isso ficam escondidos atrás de um Collapse até serem necessários.


Um editor de texto completo do tipo o-que-se-vê-é-o-que-se-obtém, construído sobre o TipTap. Negrito, itálico, listas, tudo. Usado para escrever anotações de jogos — aquelas notas de comentário que se adicionam para explicar porque é que um lance foi brilhante ou terrível.

Esta é a única primitiva que é mais um organismo composto do que uma célula única. Por baixo, é TipTap + ProseMirror + estilização Mantine. Mas da perspetiva do utilizador, é apenas uma caixa de texto onde a formatação funciona.

De @mantine/charts (que envolve o Recharts), o AreaChart alimenta o gráfico de avaliação — aquela forma de onda que corre ao longo da parte inferior do painel de análise. Área branca acima da linha média significa que as Brancas estão a ganhar; área preta abaixo significa que as Negras estão a ganhar.

Pode clicar em qualquer ponto do gráfico para saltar para esse lance. Visualização interativa de dados encontra análise de xadrez. Tem até tooltips personalizados e linhas de referência que marcam as fases do jogo (abertura → meio-jogo → final).

Através da biblioteca mantine-datatable — uma tabela de dados completa com ordenação, paginação, seleção de linhas e filtragem. Alimenta a lista de jogos, a lista de jogadores e a lista de torneios do navegador de bases de dados. É uma folha de cálculo que sabe que está numa aplicação de xadrez.


Algumas primitivas não renderizam nada visível por si próprias, mas fazem tudo o resto funcionar:

  • MantineProvider — envolve toda a aplicação e fornece o tema (cores, modo escuro, valores por defeito dos componentes)
  • Portal — teletransporta conteúdo renderizado para uma parte diferente do DOM
  • useHotkeys — um hook (não um componente) que liga os atalhos de teclado
  • useForm — gere o estado do formulário, validação e tratamento de erros
  • useDebouncedValue — espera que se pare de escrever antes de lançar uma pesquisa. O hook educado.

Para referência, eis todas as famílias de primitivas usadas no En Parlant~, agrupadas pelo que fazem:

CategoriaPrimitivas
LayoutAppShell, Box, Center, Flex, Group, Stack, SimpleGrid, ScrollArea, Portal
SuperfíciesCard, Paper
SobreposiçõesModal, Tooltip, Popover, Menu, ContextMenu, LoadingOverlay
NotificaçõesToast (via @mantine/notifications)
BotõesButton, ActionIcon, CloseButton, ThemeIcon
InputsTextInput, Textarea, NumberInput, Select, Autocomplete, Checkbox, Switch, Slider, RangeSlider, SegmentedControl, FileInput, DateInput, MonthPickerInput, YearPickerInput
Exibição de dadosTable, DataTable, Badge, Code, Kbd, Rating, Image
TipografiaText, Title, Anchor
ProgressoProgress, Loader, Skeleton
EstruturaDivider, Collapse
Conteúdo ricoRichTextEditor (TipTap), AreaChart (Recharts)
TemasMantineProvider, createTheme, useColorScheme
HooksuseForm, useHotkeys, useToggle, useDebouncedValue, useClickOutside, useElementSize

Todos provenientes do Mantine v8 e dos seus pacotes do ecossistema: @mantine/core, @mantine/notifications, @mantine/dates, @mantine/charts, @mantine/form, @mantine/tiptap, mantine-datatable e mantine-contextmenu.


Da próxima vez que vir uma pequena mensagem a deslizar a partir do canto do ecrã — é um toast. O retângulo à volta de uma pré-visualização de jogo — é um card. Os borrões cinzentos a cintilar antes do conteúdo carregar — são skeletons.

Assim que se aprendem os nomes, começam a ver-se por todo o lado. Em todas as aplicações. Em todos os websites. As mesmas duas dúzias de primitivas, reorganizadas de mil formas diferentes.

É Lego, até ao fundo.