UX/UI — Componentes
Loading states, tooltips, breadcrumbs, stepper, animações, patterns de layout, empty states, inputs avançados, dark mode, data visualization e mais.
Loading e Skeleton States
Estados de carregamento mantêm o usuário informado enquanto dados são processados. Skeletons preservam o layout, spinners indicam processamento, e botões com loading previnem cliques duplicados.
Skeleton Screens
<!-- Skeleton Card -->
<div class="skeleton-card">
<div class="skel" style="height: 12px; width: 40%;"></div>
<div class="skel" style="height: 24px; width: 60%; margin-top: 8px;"></div>
<div class="skel" style="height: 12px; width: 100%; margin-top: 16px;"></div>
<div class="skel" style="height: 12px; width: 80%; margin-top: 6px;"></div>
<div class="skel" style="height: 36px; width: 120px; margin-top: 16px; border-radius: 8px;"></div>
</div>
<!-- Skeleton Table Row -->
<tr class="skeleton-row">
<td><div class="skel" style="height: 16px; width: 16px; border-radius: 4px;"></div></td>
<td><div class="skel" style="height: 14px; width: 70px;"></div></td>
<td><div class="skel" style="height: 14px; width: 150px;"></div></td>
<td><div class="skel" style="height: 14px; width: 90px;"></div></td>
<td><div class="skel" style="height: 22px; width: 60px; border-radius: 99px;"></div></td>
</tr>
<!-- Spinner -->
<div class="spinner" role="status" aria-label="Carregando">
<div class="spinner-ring"></div>
</div>
<!-- Button Loading -->
<button class="btn-primary btn-loading" disabled>
<span class="btn-spinner"></span>
Salvando...
</button>
<!-- Progress Bar -->
<div class="progress-track">
<div class="progress-fill" style="width: 65%;"></div>
</div>
/* Skeleton Base */
.skel {
background: linear-gradient(90deg,
#E2E8F0 25%, #EDF2F7 50%, #E2E8F0 75%);
background-size: 200% 100%;
animation: skeletonShimmer 1.5s ease infinite;
border-radius: 6px;
}
@keyframes skeletonShimmer {
0% { background-position: 200% 0; }
100% { background-position: -200% 0; }
}
/* Skeleton Card Container */
.skeleton-card {
padding: 24px;
border: 1px solid #E2E8F0;
border-radius: 16px;
background: #FFFFFF;
}
/* Spinner */
.spinner-ring {
width: 32px; height: 32px;
border: 3px solid #E2E8F0;
border-top-color: #2B6CB0;
border-radius: 50%;
animation: spinnerRotate 0.7s linear infinite;
}
@keyframes spinnerRotate {
to { transform: rotate(360deg); }
}
/* Tamanhos de Spinner */
.spinner-sm .spinner-ring { width: 16px; height: 16px; border-width: 2px; }
.spinner-md .spinner-ring { width: 32px; height: 32px; border-width: 3px; }
.spinner-lg .spinner-ring { width: 48px; height: 48px; border-width: 4px; }
/* Button Loading */
.btn-loading {
position: relative;
opacity: 0.8;
pointer-events: none;
}
.btn-spinner {
display: inline-block;
width: 14px; height: 14px;
border: 2px solid rgba(255,255,255,0.3);
border-top-color: #FFFFFF;
border-radius: 50%;
animation: spinnerRotate 0.6s linear infinite;
margin-right: 6px;
vertical-align: middle;
}
/* Progress Bar */
.progress-track {
width: 100%;
height: 6px;
background: #E2E8F0;
border-radius: 99px;
overflow: hidden;
}
.progress-fill {
height: 100%;
background: linear-gradient(90deg, #2B6CB0, #3A8FD6);
border-radius: 99px;
transition: width 0.3s ease;
}
/* Dark Mode */
[data-theme="dark"] .skel {
background: linear-gradient(90deg,
#2D3748 25%, #4A5568 50%, #2D3748 75%);
background-size: 200% 100%;
}
[data-theme="dark"] .spinner-ring {
border-color: #4A5568;
border-top-color: #3A8FD6;
}
[data-theme="dark"] .progress-track {
background: #2D3748;
}
Skeleton Cards
Skeleton Table Rows
| Código | Produto | Categoria | Estoque | Status | |
|---|---|---|---|---|---|
Spinners
Tamanhos
Botões com Loading
Progress Bars
Diretrizes de Uso
| Diretriz | Descrição |
|---|---|
| Skeleton vs Spinner | Usar skeleton quando o layout final é conhecido (cards, tabelas, listas). Usar spinner para ações pontuais (submit, processar). |
| Shimmer Direction | Animação shimmer sempre da esquerda para direita. Duração: 1.5s, easing: ease, loop infinito. |
| Skeleton Shapes | Respeitar a forma do conteúdo final: retângulos para texto, círculos para avatares, retângulos arredondados para badges/botões. |
| Button Loading | Desabilitar o botão (pointer-events: none), exibir spinner inline + texto "Salvando...", opacidade 0.8. |
| Progress Bar | Determinada: exibir porcentagem. Indeterminada: animação loop. Concluída: trocar cor para #059669 (success). |
| Duração | < 1s: nenhum indicador. 1-3s: spinner. > 3s: skeleton ou progress bar. > 10s: progress bar com estimativa. |
| ARIA | Spinners: role="status" + aria-label="Carregando". Progress: role="progressbar" + aria-valuenow. |
| Dark Mode | Skeleton usa #2D3748 → #4A5568. Spinner track: #4A5568. Progress track: #2D3748. |
Especificações
| Componente | Propriedade | Valor |
|---|---|---|
| Skeleton | Background | #E2E8F0 → #EDF2F7 (gradient shimmer) |
| Animation | 1.5s ease infinite | |
| Border Radius | 6px (texto), 8px (botão), 50% (avatar), 99px (badge) | |
| Spinner | Border | Track: #E2E8F0, Active: #2B6CB0 |
| Sizes | SM: 16px/2px · MD: 32px/3px · LG: 48px/4px · XL: 64px/4px | |
| Animation | rotate 0.7s linear infinite | |
| Button Spinner | 14px/2px, track rgba(255,255,255,0.3) | |
| Progress | Track | Height 6px, bg #E2E8F0, radius 99px |
| Fill | linear-gradient(90deg, #2B6CB0, #3A8FD6) | |
| Complete | Fill: #059669 |
Tooltips, Popovers e Dropdowns
Componentes flutuantes exibem informações contextuais sem sair da tela atual. Tooltips são rápidos e textuais, popovers trazem conteúdo rico, e dropdowns listam ações ou opções.
Tooltips
<!-- Tooltip (CSS-only, sem JS) -->
<span class="tooltip-wrapper">
<button class="btn-icon" aria-describedby="tip1">
<svg>...</svg>
</button>
<span class="tooltip tooltip-top" id="tip1"
role="tooltip">Editar produto</span>
</span>
<!-- Posições: tooltip-top | tooltip-bottom
tooltip-left | tooltip-right -->
<!-- Popover (click) -->
<div class="popover-wrapper">
<button class="btn-secondary-sm"
onclick="this.parentElement.classList.toggle('open')">
Mais info
</button>
<div class="popover popover-bottom">
<div class="popover-header">Detalhes do Produto</div>
<div class="popover-body">
<p>SKU: LED-001</p>
<p>Última atualização: 05/03/2026</p>
</div>
</div>
</div>
<!-- Dropdown Menu -->
<div class="dropdown-wrapper">
<button class="btn-icon"
onclick="this.parentElement.classList.toggle('open')">
•••
</button>
<div class="dropdown-menu">
<button class="dropdown-item">
<svg>...</svg> Editar
</button>
<button class="dropdown-item">
<svg>...</svg> Duplicar
</button>
<div class="dropdown-divider"></div>
<button class="dropdown-item dropdown-danger">
<svg>...</svg> Excluir
</button>
</div>
</div>
/* ============ TOOLTIP ============ */
.tooltip-wrapper {
position: relative;
display: inline-flex;
}
.tooltip {
position: absolute;
padding: 6px 12px;
background: #0F172A;
color: #FFFFFF;
font-family: 'Inter', sans-serif;
font-size: 0.75rem;
font-weight: 500;
border-radius: 8px;
white-space: nowrap;
pointer-events: none;
opacity: 0;
transform: translateY(4px);
transition: opacity 0.15s, transform 0.15s;
z-index: 200;
}
/* Posições */
.tooltip-top { bottom: calc(100% + 8px); left: 50%; transform: translateX(-50%) translateY(4px); }
.tooltip-bottom { top: calc(100% + 8px); left: 50%; transform: translateX(-50%) translateY(-4px); }
.tooltip-left { right: calc(100% + 8px); top: 50%; transform: translateY(-50%) translateX(4px); }
.tooltip-right { left: calc(100% + 8px); top: 50%; transform: translateY(-50%) translateX(-4px); }
/* Show on hover */
.tooltip-wrapper:hover .tooltip,
.tooltip-wrapper:focus-within .tooltip {
opacity: 1;
transform: translateX(-50%) translateY(0);
}
.tooltip-wrapper:hover .tooltip-left,
.tooltip-wrapper:focus-within .tooltip-left {
transform: translateY(-50%) translateX(0);
}
.tooltip-wrapper:hover .tooltip-right,
.tooltip-wrapper:focus-within .tooltip-right {
transform: translateY(-50%) translateX(0);
}
/* Arrow (optional) */
.tooltip::after {
content: '';
position: absolute;
border: 5px solid transparent;
}
.tooltip-top::after {
top: 100%; left: 50%;
transform: translateX(-50%);
border-top-color: #0F172A;
}
.tooltip-bottom::after {
bottom: 100%; left: 50%;
transform: translateX(-50%);
border-bottom-color: #0F172A;
}
/* ============ POPOVER ============ */
.popover-wrapper {
position: relative;
display: inline-flex;
}
.popover {
position: absolute;
min-width: 240px;
background: #FFFFFF;
border: 1px solid #E2E8F0;
border-radius: 12px;
box-shadow: 0 4px 20px rgba(0,0,0,0.12);
opacity: 0;
visibility: hidden;
transform: translateY(4px);
transition: all 0.2s ease;
z-index: 100;
}
.popover-wrapper.open .popover {
opacity: 1;
visibility: visible;
transform: translateY(0);
}
.popover-bottom { top: calc(100% + 8px); left: 0; }
.popover-top { bottom: calc(100% + 8px); left: 0; }
.popover-header {
padding: 0.75rem 1rem;
font-family: 'Montserrat', sans-serif;
font-size: 0.8rem;
font-weight: 700;
color: #0F172A;
border-bottom: 1px solid #F1F5F9;
}
.popover-body {
padding: 0.75rem 1rem;
font-family: 'Inter', sans-serif;
font-size: 0.8rem;
color: #475569;
}
/* ============ DROPDOWN ============ */
.dropdown-wrapper {
position: relative;
display: inline-flex;
}
.dropdown-menu {
position: absolute;
top: calc(100% + 6px);
right: 0;
min-width: 180px;
background: #FFFFFF;
border: 1px solid #E2E8F0;
border-radius: 10px;
box-shadow: 0 4px 20px rgba(0,0,0,0.12);
padding: 4px;
opacity: 0;
visibility: hidden;
transform: translateY(-4px);
transition: all 0.15s ease;
z-index: 100;
}
.dropdown-wrapper.open .dropdown-menu {
opacity: 1;
visibility: visible;
transform: translateY(0);
}
.dropdown-item {
display: flex;
align-items: center;
gap: 0.5rem;
width: 100%;
padding: 0.5rem 0.75rem;
font-family: 'Inter', sans-serif;
font-size: 0.8rem;
color: #334155;
background: none;
border: none;
border-radius: 6px;
cursor: pointer;
transition: background 0.1s;
}
.dropdown-item:hover { background: #F8FAFC; }
.dropdown-item svg { width: 16px; height: 16px; color: #64748B; }
.dropdown-danger { color: #DC2626; }
.dropdown-danger:hover { background: #FEF2F2; }
.dropdown-danger svg { color: #DC2626; }
.dropdown-divider {
height: 1px;
background: #F1F5F9;
margin: 4px 0;
}
Tooltips (hover nos ícones)
Popover
Exibem conteúdo rico ao clicar. Diferente do tooltip, o popover tem header, body e pode conter links e botões.
Dropdown Menu
Listam ações contextuais. Abrem ao clicar e fecham ao selecionar uma opção ou clicar fora.
Diretrizes de Uso
| Diretriz | Descrição |
|---|---|
| Tooltip vs Popover | Tooltip: texto curto, trigger hover, sem interação. Popover: conteúdo rico, trigger click, permite links e botões. |
| Tooltip Texto | Máximo 1 linha, ~60 caracteres. Sem HTML, sem links. Capitalização: sentence case. |
| Delay | Tooltip: aparecer após 200ms de hover, desaparecer após 100ms. Evitar flash em movimentos rápidos do mouse. |
| Posição | Padrão: top. Auto-flip se sair da viewport. Manter 8px de gap entre trigger e flutuante. |
| Dropdown Fechar | Fechar ao: clicar em um item, clicar fora, pressionar Escape. Não fechar ao scroll. |
| Dropdown Ações | Máximo 6 itens. Agrupar com dividers. Ação destrutiva (excluir) sempre por último, em vermelho. |
| ARIA | Tooltip: role="tooltip" + aria-describedby. Dropdown: aria-expanded + aria-haspopup. |
| Mobile | Tooltips não funcionam com touch — usar long-press ou substituir por label. Dropdowns: bottom sheet em mobile. |
Especificações
| Propriedade | Tooltip | Popover | Dropdown |
|---|---|---|---|
| Background | #0F172A | #FFFFFF | #FFFFFF |
| Border | Nenhum | 1px #E2E8F0 | 1px #E2E8F0 |
| Radius | 8px | 12px | 10px |
| Shadow | Nenhum | 0 4px 20px rgba(0,0,0,0.12) | 0 4px 20px rgba(0,0,0,0.12) |
| Padding | 6px 12px | 0.75rem 1rem | 4px (container) |
| Font | Inter, 0.75rem, 500 | Inter, 0.8rem | Inter, 0.8rem |
| Min Width | Auto | 240px | 180px |
| Gap (trigger) | 8px | 8px | 6px |
| Z-Index | 200 (--z-tooltip) | 100 (--z-dropdown) | 100 (--z-dropdown) |
| Animation | opacity + translate 0.15s | opacity + translate 0.2s | opacity + translate 0.15s |
| Trigger | Hover / Focus | Click | Click |
| Arrow | Sim (5px border) | Opcional | Não |
Breadcrumbs e Navegação Estrutural
Breadcrumbs mostram a localização do usuário na hierarquia do sistema, permitindo navegar para níveis anteriores. Essenciais para aplicações com múltiplos níveis de profundidade como catálogo de produtos, configurações e relatórios.
Variantes de Breadcrumb
<!-- Breadcrumb com separador › -->
<nav class="breadcrumb" aria-label="Navegação estrutural">
<ol>
<li><a href="/">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor"
stroke-width="2" width="14" height="14">
<path d="M3 9l9-7 9 7v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z"/>
<polyline points="9 22 9 12 15 12 15 22"/>
</svg>
Início
</a></li>
<li><a href="/produtos">Produtos</a></li>
<li><a href="/produtos/iluminacao">Iluminação</a></li>
<li aria-current="page">Painel Solar 200W</li>
</ol>
</nav>
<!-- Breadcrumb com separador / -->
<nav class="breadcrumb breadcrumb-slash" aria-label="Navegação">
<ol>
<li><a href="/">Início</a></li>
<li><a href="/config">Configurações</a></li>
<li aria-current="page">Integrações</li>
</ol>
</nav>
<!-- Breadcrumb com truncamento -->
<nav class="breadcrumb" aria-label="Navegação">
<ol>
<li><a href="/">Início</a></li>
<li class="breadcrumb-ellipsis">
<button aria-label="Mostrar caminhos ocultos">…</button>
</li>
<li><a href="/cat">Iluminação</a></li>
<li aria-current="page">LED-001</li>
</ol>
</nav>
/* Breadcrumb */
.breadcrumb ol {
display: flex;
align-items: center;
gap: 0;
list-style: none;
padding: 0;
margin: 0;
flex-wrap: wrap;
}
.breadcrumb li {
display: inline-flex;
align-items: center;
font-family: 'Inter', sans-serif;
font-size: 0.8rem;
color: #64748B;
}
/* Separador › (padrão) */
.breadcrumb li + li::before {
content: '›';
margin: 0 0.5rem;
color: #CBD5E1;
font-size: 0.9rem;
}
/* Separador / */
.breadcrumb-slash li + li::before {
content: '/';
margin: 0 0.4rem;
color: #CBD5E1;
font-size: 0.8rem;
}
/* Links */
.breadcrumb a {
display: inline-flex;
align-items: center;
gap: 0.3rem;
color: #64748B;
text-decoration: none;
transition: color 0.15s;
}
.breadcrumb a:hover { color: #2B6CB0; }
/* Página atual */
.breadcrumb li[aria-current="page"] {
color: #0F172A;
font-weight: 600;
}
/* Ícone Home */
.breadcrumb svg {
width: 14px; height: 14px;
flex-shrink: 0;
}
/* Ellipsis para caminhos longos */
.breadcrumb-ellipsis button {
background: none; border: none;
font-size: 1rem; color: #94A3B8;
cursor: pointer; padding: 0 2px;
letter-spacing: 2px;
}
.breadcrumb-ellipsis button:hover {
color: #2B6CB0;
}
/* Breadcrumb com background (variante card) */
.breadcrumb-card {
background: #F8FAFC;
border: 1px solid #E2E8F0;
border-radius: 10px;
padding: 0.6rem 1rem;
}
/* Responsivo */
@media (max-width: 640px) {
.breadcrumb li { font-size: 0.75rem; }
.breadcrumb li + li::before { margin: 0 0.35rem; }
}
Separador › (Padrão)
Separador /
Com Truncamento (…)
Variante Card (com fundo)
Paginação
Componente complementar para navegar entre páginas de resultados em listagens e tabelas.
Paginação Numérica
Paginação Simples (Prev / Next)
Mini Paginação (compacta)
Diretrizes de Uso
| Diretriz | Descrição |
|---|---|
| Quando Usar | Breadcrumbs: hierarquias com ≥ 3 níveis. Não usar em fluxos lineares (wizard) — para esses, use stepper. |
| Home | Primeiro item sempre é "Início" ou ícone de casa. Nunca omitir o ponto de partida. |
| Página Atual | Último item sem link, com font-weight: 600 e aria-current="page". Cor #0F172A. |
| Truncamento | Se > 4 níveis, colapsar intermediários com "…" (ellipsis). Manter primeiro, penúltimo e atual visíveis. |
| Separador | Padrão: › (chevron). Alternativa: / (slash). Consistente em toda a aplicação. |
| Paginação | Exibir "Mostrando X–Y de Z". Numérica para ≤ 10 páginas visíveis. Simples (Prev/Next) para mobile ou listagens menores. |
| ARIA | Breadcrumb: aria-label="Navegação estrutural". Paginação: aria-label="Paginação", aria-current="page" no ativo. |
| Mobile | Breadcrumbs: mostrar apenas último nível + botão "← Voltar". Paginação: versão mini (compacta) ou prev/next. |
Especificações
| Propriedade | Breadcrumb | Paginação |
|---|---|---|
| Font | Inter, 0.8rem | Inter, 0.8rem |
| Link Color | #64748B → hover #2B6CB0 | #475569 → hover border #2B6CB0 |
| Active Color | #0F172A, weight 600 | Background #2B6CB0, cor #FFFFFF |
| Separador | › ou /, cor #CBD5E1 | N/A |
| Gap | 0.5rem (entre separador) | 4px (entre botões) |
| Icon Size | 14px (home) | 14px (setas) |
| Button Size | N/A | 36px × 36px, radius 8px |
| Disabled | N/A | Cor #CBD5E1, cursor: not-allowed |
| Card Variant | Background #F8FAFC, border #E2E8F0, radius 10px | N/A |
Stepper / Wizard
Steppers guiam o usuário por fluxos de múltiplas etapas como cadastros, configurações e processos de importação. Cada etapa mostra o progresso e permite navegação controlada entre fases.
Stepper Horizontal
<!-- Stepper Horizontal -->
<nav class="stepper" aria-label="Progresso do cadastro">
<ol>
<li class="step step-complete">
<div class="step-indicator">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3">
<polyline points="20 6 9 17 4 12"/>
</svg>
</div>
<div class="step-content">
<span class="step-title">Dados Básicos</span>
<span class="step-desc">Nome, categoria</span>
</div>
</li>
<li class="step step-active">
<div class="step-indicator">2</div>
<div class="step-content">
<span class="step-title">Especificações</span>
<span class="step-desc">Dimensões, peso</span>
</div>
</li>
<li class="step step-pending">
<div class="step-indicator">3</div>
<div class="step-content">
<span class="step-title">Preço e Estoque</span>
</div>
</li>
<li class="step step-pending">
<div class="step-indicator">4</div>
<div class="step-content">
<span class="step-title">Revisão</span>
</div>
</li>
</ol>
</nav>
<!-- Stepper Vertical -->
<nav class="stepper stepper-vertical">
<ol>
<li class="step step-complete">...</li>
<li class="step step-active">...</li>
<li class="step step-error">
<div class="step-indicator">!</div>
<div class="step-content">
<span class="step-title">Validação</span>
<span class="step-desc step-error-msg">Campo obrigatório</span>
</div>
</li>
<li class="step step-pending">...</li>
</ol>
</nav>
/* Stepper Horizontal */
.stepper ol {
display: flex;
align-items: flex-start;
list-style: none;
padding: 0;
margin: 0;
counter-reset: step;
}
.step {
flex: 1;
display: flex;
flex-direction: column;
align-items: center;
position: relative;
text-align: center;
}
/* Connector line */
.step + .step::before {
content: '';
position: absolute;
top: 18px;
right: 50%;
width: 100%;
height: 2px;
background: #E2E8F0;
z-index: 0;
}
.step-complete + .step::before,
.step-complete + .step-active::before {
background: #2B6CB0;
}
/* Step Indicator (circle) */
.step-indicator {
width: 36px; height: 36px;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
font-family: 'Montserrat', sans-serif;
font-size: 0.8rem;
font-weight: 700;
position: relative;
z-index: 1;
transition: all 0.2s;
}
.step-indicator svg {
width: 16px; height: 16px;
}
/* States */
.step-complete .step-indicator {
background: #2B6CB0;
color: #FFFFFF;
}
.step-active .step-indicator {
background: #FFFFFF;
color: #2B6CB0;
border: 2px solid #2B6CB0;
box-shadow: 0 0 0 4px rgba(43,108,176,0.15);
}
.step-pending .step-indicator {
background: #F1F5F9;
color: #94A3B8;
border: 2px solid #E2E8F0;
}
.step-error .step-indicator {
background: #FEE2E2;
color: #DC2626;
border: 2px solid #DC2626;
}
/* Step Content */
.step-content { margin-top: 0.75rem; }
.step-title {
display: block;
font-family: 'Montserrat', sans-serif;
font-size: 0.75rem;
font-weight: 600;
color: #334155;
}
.step-active .step-title { color: #2B6CB0; }
.step-pending .step-title { color: #94A3B8; }
.step-error .step-title { color: #DC2626; }
.step-desc {
display: block;
font-family: 'Inter', sans-serif;
font-size: 0.7rem;
color: #94A3B8;
margin-top: 2px;
}
.step-error-msg { color: #DC2626; }
/* Stepper Vertical */
.stepper-vertical ol { flex-direction: column; gap: 0; }
.stepper-vertical .step {
flex-direction: row;
align-items: flex-start;
text-align: left;
padding-left: 0;
min-height: 72px;
}
.stepper-vertical .step + .step::before {
top: 0; left: 17px; right: auto;
width: 2px; height: 100%;
}
.stepper-vertical .step-content {
margin-top: 0; margin-left: 1rem; padding-top: 6px;
}
/* Responsive */
@media (max-width: 640px) {
.stepper:not(.stepper-vertical) .step-content { display: none; }
.stepper:not(.stepper-vertical) .step-active .step-content { display: block; }
}
Horizontal — Cadastro de Produto
Vertical — Importação de Dados
Minimal (Dots) — Onboarding
Barra de Ações do Step
Diretrizes de Uso
| Diretriz | Descrição |
|---|---|
| Quando Usar | Processos com 3-7 etapas sequenciais. Para > 7 etapas, agrupar em fases. Para 2 etapas, usar apenas botões Voltar/Próximo. |
| Horizontal vs Vertical | Horizontal: até 5 etapas, desktop. Vertical: > 5 etapas ou quando há descrições longas. Dots: onboarding simples. |
| Navegação | Permitir voltar para steps completos (clicáveis). Não permitir pular para steps futuros pendentes. |
| Estado de Erro | Indicador vermelho com "!" no step. Mensagem de erro na descrição. Bloquear avanço até resolver. |
| Barra de Ações | Fixa no rodapé: "Voltar" (esquerda), "Salvar Rascunho" + "Próximo" (direita). Último step: "Concluir" ou "Enviar". |
| Persistência | Salvar dados parciais ao sair. Ao retornar, restaurar o último step ativo com dados preenchidos. |
| ARIA | aria-label no nav, aria-current="step" no ativo. Steps completos: aria-label="Concluído". |
| Mobile | Horizontal: ocultar labels dos steps pendentes, mostrar apenas o ativo. Ou converter para variante dots com label abaixo. |
Especificações
| Propriedade | Valor |
|---|---|
| Indicator Size | 36px × 36px, border-radius 50% |
| Indicator Font | Montserrat, 0.8rem, weight 700 |
| Check Icon | SVG 16px, stroke-width 3 |
| Connector Line | 2px height (h) / width (v) |
| Complete | Indicator: bg #2B6CB0, cor #FFFFFF. Line: #2B6CB0 |
| Active | Indicator: bg #FFFFFF, border 2px #2B6CB0, shadow 0 0 0 4px rgba(43,108,176,0.15) |
| Pending | Indicator: bg #F1F5F9, border 2px #E2E8F0, cor #94A3B8 |
| Error | Indicator: bg #FEE2E2, border 2px #DC2626, cor #DC2626 |
| Title Font | Montserrat, 0.75rem, weight 600 |
| Description Font | Inter, 0.7rem, cor #94A3B8 |
| Dots Size | Normal: 10px, Active: 12px + border + shadow |
| Transition | all 0.2s ease |
Animações e Micro-interações
Animações comunicam mudanças de estado, guiam a atenção e tornam a interface mais fluida. Devem ser sutis, rápidas e com propósito — nunca decorativas. Todas as animações respeitam prefers-reduced-motion para acessibilidade.
Tokens de Motion
<!-- Aplicando tokens de motion -->
<button class="btn-primary"
style="transition: all var(--duration-normal) var(--ease-out);">
Salvar
</button>
<!-- Animação de entrada -->
<div class="animate-fade-in">Conteúdo</div>
<div class="animate-slide-up">Conteúdo</div>
<div class="animate-scale-in">Conteúdo</div>
<!-- Staggered animation (delay escalonado) -->
<div class="animate-slide-up" style="--delay: 0ms">Item 1</div>
<div class="animate-slide-up" style="--delay: 50ms">Item 2</div>
<div class="animate-slide-up" style="--delay: 100ms">Item 3</div>
/* ============ MOTION TOKENS ============ */
:root {
--duration-instant: 100ms;
--duration-fast: 150ms;
--duration-normal: 250ms;
--duration-slow: 350ms;
--duration-slower: 500ms;
--ease-in: cubic-bezier(0.4, 0, 1, 1);
--ease-out: cubic-bezier(0, 0, 0.2, 1);
--ease-in-out: cubic-bezier(0.4, 0, 0.2, 1);
--ease-spring: cubic-bezier(0.34, 1.56, 0.64, 1);
}
/* ============ ENTRADA (APPEAR) ============ */
@keyframes fadeIn {
from { opacity: 0; }
to { opacity: 1; }
}
@keyframes slideUp {
from { opacity: 0; transform: translateY(16px); }
to { opacity: 1; transform: translateY(0); }
}
@keyframes slideDown {
from { opacity: 0; transform: translateY(-16px); }
to { opacity: 1; transform: translateY(0); }
}
@keyframes slideLeft {
from { opacity: 0; transform: translateX(16px); }
to { opacity: 1; transform: translateX(0); }
}
@keyframes scaleIn {
from { opacity: 0; transform: scale(0.95); }
to { opacity: 1; transform: scale(1); }
}
/* Classes utilitárias */
.animate-fade-in { animation: fadeIn var(--duration-normal) var(--ease-out) var(--delay, 0ms) both; }
.animate-slide-up { animation: slideUp var(--duration-normal) var(--ease-out) var(--delay, 0ms) both; }
.animate-slide-down { animation: slideDown var(--duration-normal) var(--ease-out) var(--delay, 0ms) both; }
.animate-scale-in { animation: scaleIn var(--duration-fast) var(--ease-spring) var(--delay, 0ms) both; }
/* ============ HOVER EFFECTS ============ */
.hover-lift {
transition: transform var(--duration-normal) var(--ease-out),
box-shadow var(--duration-normal) var(--ease-out);
}
.hover-lift:hover {
transform: translateY(-2px);
box-shadow: 0 8px 32px rgba(0,0,0,0.08);
}
.hover-glow {
transition: box-shadow var(--duration-fast) var(--ease-out);
}
.hover-glow:hover {
box-shadow: 0 0 0 4px rgba(43,108,176,0.15);
}
.hover-scale {
transition: transform var(--duration-instant) var(--ease-spring);
}
.hover-scale:hover {
transform: scale(1.05);
}
/* ============ FOCUS RING ============ */
.focus-ring:focus-visible {
outline: none;
box-shadow: 0 0 0 3px rgba(58,143,214,0.3);
transition: box-shadow var(--duration-instant) var(--ease-out);
}
/* ============ REDUCED MOTION ============ */
@media (prefers-reduced-motion: reduce) {
*, *::before, *::after {
animation-duration: 0.01ms !important;
animation-iteration-count: 1 !important;
transition-duration: 0.01ms !important;
}
}
Escala de Duração
Easing Curves
Hover Effects (interaja com os cards)
Animações de Entrada (clique para replay)
Focus Ring
Ring visível ao navegar com teclado (Tab). Usa :focus-visible para não aparecer em cliques.
Diretrizes de Uso
| Diretriz | Descrição |
|---|---|
| Propósito | Toda animação deve ter um motivo: feedback, orientação ou continuidade. Se remover a animação e nada se perde, ela é desnecessária. |
| Duração Máx | Interfaces: máx 500ms. Hover: 100-150ms. Modais/pages: 250-350ms. Usuários percebem > 400ms como lento. |
| Easing Padrão | Usar ease-out para entradas (elemento aparecendo), ease-in para saídas. linear apenas para spinners. |
| Stagger | Para listas/grids, atrasar cada item em 50ms. Máximo 10 items com stagger, depois aparecer junto. |
| Reduced Motion | Obrigatório: @media (prefers-reduced-motion: reduce) desativa todas as animações. |
| Performance | Animar apenas transform e opacity (GPU-accelerated). Evitar animar width, height, top, left, margin. |
| Consistência | Mesma ação = mesma animação em toda a aplicação. Modal sempre fadeIn + scaleIn. Dropdown sempre slideDown. |
| Mobile | Reduzir duração em 20% em mobile. Desativar hover effects. Preferir animações mais curtas. |
Mapa de Animações por Componente
| Componente | Animação | Duração | Easing |
|---|---|---|---|
| Botão (hover) | background + shadow | 150ms | ease-out |
| Botão (focus) | box-shadow ring | 100ms | ease-out |
| Card (hover) | translateY(-2px) + shadow | 250ms | ease-out |
| Tooltip | opacity + translateY | 150ms | ease-out |
| Dropdown | opacity + translateY | 150ms | ease-out |
| Modal (overlay) | fadeIn | 200ms | ease |
| Modal (container) | scaleIn + fadeIn | 250ms | spring |
| Toast | slideLeft (from right) | 300ms | ease-out |
| Page transition | fadeIn + slideUp | 350ms | ease-out |
| Skeleton | shimmer gradient | 1500ms | ease (loop) |
| Spinner | rotate | 700ms | linear (loop) |
Patterns de Layout
Patterns são composições recorrentes de componentes que formam páginas completas. Definem a estrutura visual de dashboards, listagens, detalhes e configurações — garantindo consistência entre módulos.
Dashboard
Visão geral com métricas, gráficos e ações rápidas. Layout: sidebar fixa + header + grid de cards.
Master-Detail (Lista-Detalhe)
Lista à esquerda, detalhe à direita. Para catálogos, e-mails, mensagens e gestão de pedidos.
Página de Configurações
Tabs laterais ou superiores com formulários agrupados por categoria.
Catálogo de Patterns
Diretrizes de Composição
| Diretriz | Descrição |
|---|---|
| Hierarquia Visual | Métricas principais no topo (cards). Conteúdo detalhado no centro. Ações secundárias na sidebar ou footer. |
| Sidebar | Desktop: fixa, 240-280px expandida ou 56-64px colapsada (ícones). Mobile: drawer com overlay. |
| Header | Altura: 56-64px. Contém: título da página, breadcrumb, ações primárias (botões). Sticky em scroll. |
| Content Area | Max-width: 1200px. Padding: 24-32px. Background: #F8FAFC. |
| Master-Detail | Lista: 280-320px fixa. Detalhe: flex. Em mobile: tela cheia alternando entre lista e detalhe. |
| Configurações | Nav lateral: 180-220px. Conteúdo: max-width 600px para formulários. |
| Empty State | Toda listagem deve ter empty state com ilustração + mensagem + CTA. Nunca exibir página vazia. |
| Responsivo | Dashboard: cards empilham em 1-2 colunas. Master-Detail: stack vertical. Settings: nav vira tabs. |
Especificações de Estrutura
| Elemento | Desktop | Tablet | Mobile |
|---|---|---|---|
| Sidebar | 240px fixa / 56px colapsada | 56px ícones | Drawer overlay |
| Header | 64px sticky | 56px sticky | 56px sticky |
| Content Padding | 32px | 24px | 16px |
| Content Max Width | 1200px | 100% | 100% |
| Card Grid | 3-4 colunas | 2 colunas | 1 coluna |
| Master List | 280-320px fixa | 240px | Tela cheia |
| Settings Nav | 180px lateral | Tabs superiores | Tabs superiores |
| Metric Cards | 4 em linha | 2 em linha | 1 por linha (stack) |
Empty States e Feedback Visual
Empty states comunicam quando não há dados para exibir e guiam o próximo passo. Telas de erro informam problemas. Ambos devem ser visuais, claros e conter uma ação.
Empty States
Telas de Erro
| Diretriz | Descrição |
|---|---|
| Estrutura | Ícone SVG outline + título + descrição (1-2 linhas) + CTA primário. Centralizado verticalmente. |
| Tom | Empático e construtivo. Nunca culpar o usuário. Sugerir próximo passo concreto. |
| CTA | Sempre incluir pelo menos 1 ação. Primeiro uso: 2 opções (importar ou manual). Busca vazia: "Limpar filtros". |
| Ilustrações | SVGs outline (Lucide/Heroicons) com stroke #94A3B8. Tamanho 48px. |
Inputs Avançados
Componentes de formulário além do básico: toggles, file upload com drag & drop, date picker, search autocomplete e inputs com máscara.
Toggle Switch
File Upload (Drag & Drop)
Search Autocomplete
| Componente | Specs |
|---|---|
| Toggle | Track: 44×24px, radius 99px. Thumb: 20×20px. On: bg #2B6CB0. Off: bg #E2E8F0. Transition: 150ms. |
| File Upload | Border: 2px dashed #CBD5E1. Hover: border #2B6CB0, bg #EFF6FF. Radius: 12px. |
| Autocomplete | Input padrão + dropdown de resultados. Highlight do match em <strong>. Debounce: 300ms. |
| Disabled | Opacidade 0.5, cursor not-allowed. Mesmo visual mas sem interação. |
Sidebars e Navegação Principal
A sidebar é o principal elemento de navegação da aplicação Sysled. Contém logo, menu de módulos, atalhos e acesso ao perfil. Suporta modo expandido e colapsado.
Sidebar Expandida vs Colapsada
| Propriedade | Expandida | Colapsada | Mobile |
|---|---|---|---|
| Largura | 240px | 56px | Drawer 280px |
| Background | #0F172A (dark primary) | ||
| Item Ativo | rgba(43,108,176,0.2) + ícone azul | Idem | |
| Item Padding | 0.5rem 0.75rem | center 36×36px | Idem expandida |
| Item Font | Inter, 0.75rem | Tooltip no hover | Idem expandida |
| Divider | 1px rgba(255,255,255,0.08) | ||
| Badge | 18px pill vermelho | 8px dot | Idem expandida |
| Overlay (mobile) | N/A | rgba(0,0,0,0.5) | |
Tipografia Aplicada e Hierarquia
Exemplos práticos de como a tipografia Montserrat + Inter cria hierarquia visual em contextos reais: página de produto, dashboard e artigo.
Página de Produto
Luminária Industrial LED 150W
Alta performance para galpões e áreas industriais. IP65, 120lm/W, vida útil 50.000h.
Especificações
Escala Tipográfica em Contexto
Truncamento de Texto
| Regra | Descrição |
|---|---|
| Heading Font | Montserrat para títulos, labels de seção, badges, botões, overlines. |
| Body Font | Inter para parágrafos, inputs, descrições, tabelas, tooltips. |
| Mono Font | JetBrains Mono para código, SKUs, IDs, valores técnicos. |
| Line Height | Headings: 1.2-1.3. Body: 1.5-1.6. Compact (tables, labels): 1.3-1.4. |
| Truncamento | 1 linha: text-overflow: ellipsis. Multi-linha: -webkit-line-clamp. Sempre com title para hover. |
| Responsivo | Page title: 2rem → 1.5rem (mobile). Section: 1.5rem → 1.25rem. Body: mantém 1rem. |
Dark Mode e Temas
O sistema de cores da Sysled suporta troca de tema via variáveis CSS. Cada cor semântica possui mapeamento light e dark, garantindo contraste WCAG AA (4.5:1 texto, 3:1 elementos UI) em ambos os modos.
Mapeamento de Cores Light / Dark
Componentes: Light vs Dark
Implementacao com CSS Variables
/* Light theme (default) */ :root { --bg-primary: #FFFFFF; --bg-secondary: #F8FAFC; --bg-elevated: #FFFFFF; --text-primary: #0F172A; --text-secondary: #64748B; --border-color: #E2E8F0; --accent: #2B6CB0; --accent-hover: #2C5282; --shadow: 0 1px 3px rgba(0,0,0,0.1); } /* Dark theme */ [data-theme="dark"] { --bg-primary: #0F172A; --bg-secondary: #1E293B; --bg-elevated: #334155; --text-primary: #F1F5F9; --text-secondary: #94A3B8; --border-color: #334155; --accent: #5BB8F5; --accent-hover: #3A8FD6; --shadow: 0 1px 3px rgba(0,0,0,0.4); }
Regras de Contraste
| Diretriz | Descricao |
|---|---|
| Ativacao | Usar data-theme="dark" no <html>. Detectar prefers-color-scheme do sistema como padrao. |
| Contraste minimo | Texto: 4.5:1 (AA). Elementos UI (bordas, icones): 3:1. Texto grande (≥18px bold): 3:1. |
| Cores de accent | Light: #2B6CB0. Dark: #5BB8F5 (mais claro para manter contraste em fundo escuro). |
| Sombras | Light: opacity 0.1. Dark: opacity 0.4 (sombras mais fortes em fundos escuros para manter profundidade). |
| Badges/Tags | Light: background solido suave (#EBF8FF). Dark: background com rgba() a 15% de opacidade. |
| Imagens/Icones | Icones SVG com currentColor adaptam automaticamente. Imagens: usar filter: brightness(0.9) no dark mode para evitar brilho excessivo. |
| Transicao | Aplicar transition: background-color 0.2s, color 0.2s, border-color 0.2s para troca suave entre temas. |
| Nunca fazer | Nunca usar preto puro (#000000) como fundo. Usar #0F172A (Slate 900). Evitar branco puro (#FFFFFF) como texto — usar #F1F5F9. |
Data Visualization — Graficos e Dashboards
Graficos traduzem dados complexos em insights visuais. A paleta Sysled para data viz usa cores distintas com contraste suficiente entre si e segue ordem semantica consistente.
Paleta para Graficos
Grafico de Barras
KPI Cards
Grafico Donut
| Diretriz | Descricao |
|---|---|
| Paleta | Maximo 6 cores por grafico. Usar a sequencia definida (Primary → Cyan → Light Blue → Yellow → Red → Purple). |
| Legendas | Posicionar acima ou ao lado do grafico. Usar dot (10px) + label. Nunca sobrepor ao grafico. |
| KPI Cards | Valor principal em font-weight: 800, tamanho 1.5rem. Indicador de tendencia com seta SVG + percentual colorido (verde/vermelho). |
| Tooltips | Ao passar o mouse em barras/fatias, mostrar tooltip com valor exato. Background #0F172A, texto branco, border-radius 8px. |
| Eixos | Labels em Inter 0.6rem #94A3B8. Gridlines em #F1F5F9 (light) ou #1E293B (dark). Sem bordas nos eixos. |
| Responsivo | Graficos devem usar width: 100% e viewBox SVG. Em mobile, legendas abaixo do grafico. |
Paginacao e Infinite Scroll
Paginacao divide resultados em paginas discretas. Cada padrão serve um caso de uso diferente: numerico para navegacao precisa, compact para mobile, load more para feeds, e infinite scroll para galerias.
Paginacao Numerica
Paginacao Compact (Mobile)
Load More Button
| Padrao | Quando usar |
|---|---|
| Numerico | Tabelas de dados, listagens com busca. Quando o usuario precisa navegar para pagina especifica. Desktop. |
| Compact | Mobile e espacos restritos. Anterior/Proximo com indicador de pagina atual. |
| Load More | Feeds, catalogos de produtos. Barra de progresso mostra quanto ja foi carregado. Max 3 cliques antes de sugerir filtros. |
| Infinite Scroll | Galerias de imagens, timelines. Usar sentinel element + Intersection Observer. Mostrar spinner ao carregar. |
| Items por pagina | Padrao: 20. Opcoes: 10, 20, 50, 100. Dropdown ao lado da paginacao. |
Alertas Inline e Banners
Alertas inline e banners sao mensagens persistentes (diferente de toasts que desaparecem). Banners ficam no topo da pagina; alertas inline aparecem dentro do contexto do conteudo.
Banners de Topo
Alertas Inline em Formularios
Callouts de Destaque
| Tipo | Especificacao |
|---|---|
| Banner | Topo da pagina, largura total. Icone SVG (18px) + texto + botao fechar (X). Border-radius 10px. Dismissable com X. |
| Inline (form) | Abaixo do input com erro/warning. Icone 12px + texto 0.65rem. Borda do input muda para a cor do estado. |
| Callout | Border-left 4px + background suave. Titulo bold + descricao. Nao e dismissable — sempre visivel. |
| Cores | Info: azul (#2B6CB0/#EBF8FF). Warning: amarelo (#D97706/#FFFBEB). Error: vermelho (#DC2626/#FFF5F5). Success: verde (#059669/#D1FAE5). |
| Persistencia | Banners de sistema (manutencao): persistem ate o usuario fechar. Erros criticos: nao podem ser fechados ate resolver. |
Drag & Drop e Reordenacao
Drag & drop permite que usuarios reorganizem elementos visualmente. Os indicadores visuais (grab cursor, ghost, drop zone) devem ser claros para comunicar o que esta acontecendo.
Lista Reordenavel
Kanban Board — Drag entre Colunas
| Estado | Visual |
|---|---|
| Default | Handle com icone grip (6 dots). Cursor grab. Border normal #E2E8F0. |
| Dragging | Cursor grabbing. Border dashed #2B6CB0. Background #EBF8FF. Shadow elevada. transform: scale(1.02). Opacity 0.85. |
| Drop Zone | Border dashed #48C9B0. Background rgba(72,201,176,0.08). Texto "Soltar aqui". |
| Drop Zone inativa | Border dashed #CBD5E0. Texto "Arraste cards aqui" em #CBD5E0. |
| Acessibilidade | Suporte a teclado: Space para pegar, setas para mover, Space para soltar, Esc para cancelar. aria-grabbed, aria-dropeffect. |
| Feedback | Apos soltar: toast de confirmacao "Ordem atualizada". Animacao suave de reposicionamento (200ms ease). |
Shortcuts e Atalhos de Teclado
Atalhos de teclado aceleram o fluxo de trabalho de usuarios avancados. Todos os atalhos devem ser descobriveis via modal de ajuda (?) e documentados.
Modal de Atalhos
| Diretriz | Descricao |
|---|---|
| Descoberta | Tecla ? abre modal de atalhos. Tooltip em hover mostra atalho do botao. |
| Padroes | Navegacao: G + letra. Acoes: Cmd/Ctrl + letra. Acoes rapidas: letra unica (N = novo). |
| Kbd style | Background branco, border #E2E8F0, border-radius 5px, box-shadow para efeito 3D sutil, font JetBrains Mono 0.6rem. |
| Acessibilidade | Nunca substituir atalhos nativos do browser. Atalhos nao podem ser a unica forma de acesso — sempre ter equivalente clicavel. |
Onboarding e Tour Guiado
O onboarding guia novos usuarios pelos recursos principais do sistema. Usa spotlight (destaque) em elementos da interface com tooltips explicativos e progresso visual.
Tour Step — Spotlight
| Diretriz | Descricao |
|---|---|
| Spotlight | Overlay escurecido rgba(15,23,42,0.6). Elemento alvo elevado com z-index + ring glow box-shadow: 0 0 0 4px rgba(43,108,176,0.3). |
| Tooltip | Max 260px. Titulo em Montserrat bold + descricao em Inter. Arrow CSS apontando para o elemento. Sombra forte. |
| Progresso | Dots (6px) com estado ativo. Contador "N de N" alinhado a direita. Maximo 5-7 steps. |
| Acoes | "Pular tour" (text button, cinza). "Anterior" (secondary). "Proximo" / "Concluir" (primary). Ultimo step: "Comecar a usar!". |
| Persistencia | Salvar progresso em localStorage. Nao mostrar novamente apos completar. Oferecer replay em Configuracoes. |
Filtros e Busca Avancada
Filtros permitem refinar resultados. Devem ser visiveis, facilmente removiveis, e mostrar quantos resultados foram encontrados. A busca com sugestoes acelera a descoberta.
Barra de Filtros com Chips
| Diretriz | Descricao |
|---|---|
| Filter Chips | Background #EBF8FF, border #BEE3F8, pill shape. Icone X para remover. white-space: nowrap. |
| Contagem | Badge circular no botao Filtros mostrando quantidade ativa. Badge no resultado: "47 resultados encontrados". |
| Limpar | Botao "Limpar todos" em vermelho (#DC2626), text-only. Aparece so quando ha filtros ativos. |
| Busca | Input com icone lupa. Placeholder "Buscar...". Sugestoes em dropdown apos 2 caracteres. Highlight do match em bold. |
| View Toggle | Grid / Lista — botoes icone com estado ativo (borda azul, bg #EBF8FF). |
Centro de Notificacoes
O centro de notificacoes agrega todas as mensagens do sistema em um painel acessivel pelo icone de sino. Notificacoes nao lidas sao destacadas visualmente.
Notification Bell + Dropdown
| Diretriz | Descricao |
|---|---|
| Badge | Circulo vermelho (#DC2626) com borda branca 2px. Max "9+". Desaparece quando nao ha novas. |
| Nao lida | Background #F8FAFC, border-left 3px azul, titulo bold, dot azul 8px a direita. |
| Lida | Background branco, sem border-left, titulo cinza (#64748B), sem dot. |
| Icones | Por tipo: info (azul), warning (amarelo), error (vermelho), success (verde). Icones SVG outline em fundo colorido suave 32x32. |
| Timestamp | Relativo: "2 min atras", "1 hora atras". Apos 24h: "Ontem 14:30". Apos 7 dias: data completa. |
| Agrupamento | Agrupar por "Hoje", "Ontem", "Esta semana" com divisor + label cinza. Max 20 itens no dropdown, link "Ver todas" no footer. |
Tabelas Avancadas — Selecao e Bulk Actions
Tabelas avancadas permitem selecionar multiplos itens e executar acoes em lote (bulk actions). A barra de acoes aparece quando ha selecao ativa.
Tabela com Selecao e Bulk Actions
| Diretriz | Descricao |
|---|---|
| Checkbox | 18x18px, border-radius 4px. Checked: bg #2B6CB0 + checkmark branco. Indeterminate (parcial): bg azul + dash branco. |
| Linha selecionada | Background #EBF8FF, border-bottom #BEE3F8. Transicao suave 150ms. |
| Bulk Bar | Aparece no topo da tabela quando 1+ itens selecionados. Sticky para ficar visivel ao scrollar. Background #EBF8FF. |
| Acoes em lote | Exportar CSV, Editar (preco, categoria, status), Excluir (vermelho, com confirmacao modal). Max 4 acoes visiveis. |
| Selecao | Click no checkbox da linha seleciona/deseleciona. Checkbox do header: seleciona todos da pagina. Shift+Click para selecao em range. |
| Feedback | Contador "N itens selecionados" atualiza em tempo real. Apos acao em lote: toast de confirmacao + deselecionar. |
File Upload & Attachment
Componentes de upload de arquivos para contextos industriais — drag & drop, progress bar, preview, validação de tipo/tamanho e galeria de anexos em ordens de manutenção e inspeções.
| Propriedade | Valor | Nota |
|---|---|---|
| Drop Zone | Border 2px dashed, radius 12px, padding 2rem | Active = primary dashed + shadow ring |
| Icon Upload | 40×40px, radius 10px | Background gray-100 (default) / primary/10% (active) |
| File Row | Padding 12px 16px, radius 10px | Icon 36×36 + info + actions |
| Progress Bar | 4px height, radius 2px | Primary color + pulse animation |
| Thumbnail Grid | 4 colunas, gap 10px | Image height 80px, object-fit cover |
| File Size Limit | 10MB por arquivo (configurável) | Validar antes do upload |
| Tipos Aceitos | PNG, JPG, PDF, XLSX, CSV, DWG | Configurável por contexto |
| Action Buttons | 28×28px, radius 6px | Preview, delete, retry |
- Validar tipo e tamanho antes do upload
- Mostrar progresso com % e tempo restante
- Permitir cancelar upload em andamento
- Preview inline para imagens e PDFs
- Feedback visual claro no drag over
- Upload sem indicação de progresso
- Aceitar qualquer tipo de arquivo silenciosamente
- Deletar arquivo sem confirmação
- Drop zone menor que 200px de altura
- Bloquear UI durante upload (usar async)
Breadcrumbs & Page Header
Breadcrumbs fornecem contexto de navegação hierárquica e o Page Header combina título, ações e breadcrumbs em um bloco coeso no topo de cada tela.
Variantes de Breadcrumb
Page Header
Ordens de Serviço
148 registrosGerencie ordens de serviço de manutenção preventiva e corretiva de equipamentos industriais.
OS-2024-0847
Em AndamentoTroca de rolamento — Bomba Centrífuga BC-12
Anatomia do Page Header
Comportamento Responsivo
Specs
| Propriedade | Valor |
|---|---|
| Separador | Chevron-right · 14 × 14 · stroke 1.5 · color text-tertiary |
| Link font | Inter 0.85rem / 400 · color text-secondary · hover: underline |
| Current item | Inter 0.85rem / 600 · color text-primary · sem link |
| Home icon | Lucide Home · 16 × 16 · stroke 1.5 |
| Collapse trigger | ••• pill · bg gray-100 · border · border-radius 6px · padding 2px 8px |
| Header padding | 24px (desktop) · 16px (mobile) |
| Title font | Montserrat 1.25–1.35rem / 700 |
| Meta bar | border-top 1px · padding-top 1rem · gap 1.5rem · font 0.78rem / 400 |
| Max depth visible | 4 níveis (Home + 2 intermediários + current) — colapsar se > 4 |
Do
- Sempre incluir Home como primeiro nível do breadcrumb
- Colapsar níveis intermediários em hierarquias profundas (> 4)
- Alinhar ações primárias à direita no Page Header
- Usar meta bar para informações contextuais da entidade
Don't
- Não usar breadcrumbs em páginas de primeiro nível (Dashboard)
- Não tornar o item atual clicável — ele é a página corrente
- Não exceder 3 botões de ação no Page Header
- Não omitir o botão de voltar em páginas de detalhe
Tooltip & Popover
Tooltips fornecem informações contextuais breves ao hover/focus sobre ícones de status e ações. Popovers são overlays ricos para detalhes de equipamentos, confirmações e cards de técnicos.
Tooltip — Variantes
Tooltip — Estilos
Popover — Variantes
A manutenção preventiva reduz em até 40% os custos operacionais e aumenta a vida útil do equipamento.
Saiba mais →Isso marcará a ordem como concluída e notificará o solicitante. Peças utilizadas serão debitadas do estoque.
Timing & Comportamento
Tooltip
200ms
0ms
fade 150ms ease
Popover
0ms
scale 200ms ease-out
Specs
| Propriedade | Tooltip | Popover |
|---|---|---|
| Background | #1e293b (dark) ou #fff (light) | var(--bg-card) |
| Border radius | 6px | 12px |
| Padding | 6px 12px | 16px |
| Font size | 0.72rem / 500 | 0.8rem / 400 (body) |
| Max width | 240px | 320px |
| Shadow | Nenhuma | 0 4px 16px rgba(0,0,0,0.1) |
| Z-index | 1070 | 1060 |
| Arrow size | 8 × 8px rotated 45° | Opcional, 10 × 10px |
| Offset do trigger | 8px | 8px |
Do
- Usar tooltip para labels curtos de icon buttons (max 1 linha)
- Incluir atalhos de teclado no tooltip quando aplicável
- Fechar popover ao pressionar Esc ou clicar fora
- Manter popover visível enquanto o cursor estiver dentro dele
Don't
- Não colocar conteúdo interativo dentro de tooltips
- Não usar tooltip para informações essenciais — não são acessíveis em touch
- Não abrir mais de um popover simultaneamente
- Não usar tooltip em elementos já descritivos (texto visível)
Stepper & Multi-Step Wizard
Steppers indicam progresso em fluxos multi-etapa. Wizards guiam o usuário por processos complexos divididos em passos sequenciais com validação progressiva.
Stepper Horizontal
Stepper Vertical
Wizard — Exemplo Completo
Estados do Step
Stepper Compacto (Mobile)
Specs
| Propriedade | Valor |
|---|---|
| Step circle | 36 × 36px (default) · 32px (vertical) · border-radius 50% |
| Active ring | box-shadow 0 0 0 4px var(--primary-light) |
| Completed bg | #16a34a · check icon stroke 2.5 · color #fff |
| Connector | height 2px · completed: #16a34a · pending: var(--border) |
| Label font | Inter 0.72rem / 600 (active/completed) · 500 (pending) |
| Wizard header | padding 20px 24px · border-bottom 1px |
| Wizard footer | bg gray-100 · padding 16px 24px · sticky bottom |
| Progress bar | height 6px · border-radius 100px · bg primary |
| Max steps recomendado | 3–7 steps · colapsar se > 5 em mobile |
Do
- Validar cada etapa antes de permitir avançar
- Permitir navegação livre entre etapas já concluídas
- Oferecer "Salvar rascunho" em wizards longos
- Usar dot indicator ou progress bar em mobile
Don't
- Não exceder 7 etapas — divida em sub-fluxos
- Não permitir pular etapas obrigatórias
- Não perder dados preenchidos ao navegar entre etapas
- Não esconder o progresso — sempre indicar a etapa atual