O que é WmnUI?
Biblioteca PHP para geração de HTML com o design system WMN. O CSS já está embutido no servidor — nenhuma tag <link> é necessária.
Requisitos: PHP 8.0+ | Arquivo: pacote/wmnui.php
Como incluir
<?php require_once __DIR__ . '/pacote/wmnui.php';
Estrutura mínima de uma página
<?php
require_once __DIR__ . '/pacote/wmnui.php';
WmnUI::pagina('Título da Página', 'Nome do Usuário', function() {
WmnUI::cabecalho('Título', 'Subtítulo opcional', function() {
WmnUI::botao('Ação principal', '#', 'primary');
});
WmnUI::conteudo(function() {
WmnUI::card('Seção', function() {
echo 'Conteúdo da página aqui.';
});
});
});Referência rápida de métodos
| Método | Descrição |
|---|---|
pagina($titulo, $usuario, fn) | Página completa (DOCTYPE + shellbar + body) |
shellbar($titulo, $usuario, fn?) | Barra superior com logo e avatar |
cabecalho($titulo, $sub?, fn?) | Cabeçalho com título, subtítulo e ações |
conteudo(fn) | Área de conteúdo principal |
card($titulo, fn) | Card com cabeçalho e corpo |
secao($titulo) | Título de seção com linha separadora |
divisor() | Linha horizontal divisória |
botao($rotulo, $href?, $tipo?, $extra?) | Botão ou link |
botaoEnviar($rotulo, $tipo?, $extra?) | Submit button para formulários |
grupoBotoes(fn) | Botões agrupados lado a lado |
form($action, $method, fn) | Tag <form> |
formGrid(fn) | Grid de 4 colunas responsivo |
campo($label, $html, $obrig?, $ajuda?, $erro?) | Campo com label e mensagens |
input($nome, $tipo?, $valor?, $extra?, $comErro?) | Retorna <input> |
select($nome, $opcoes, $sel?, $extra?, $comErro?) | Retorna <select> |
textarea($nome, $valor?, $linhas?, $extra?, $comErro?) | Retorna <textarea> |
checkbox($nome, $label, $marcado?) | Checkbox com label |
radio($nome, $label, $valor, $marcado?) | Radio button com label |
formAcoes(fn) | Botões alinhados à direita |
abas(['Aba' => fn, ...], $abaAtiva?) | Abas com painéis |
tabela($cols, $linhas, $titulo?, fn?) | Tabela com toolbar opcional |
tileGrid($tiles) | Grade de tiles para home/menu |
badge($texto, $tipo?) | Badge: '' | 'success' | 'error' | 'warning' |
erro($mensagem) | Bloco de erro visível |
muted($texto) | Texto com cor reduzida |
Página e layout
pagina()
Gera o DOCTYPE, head com CSS, shellbar e fecha o body automaticamente. O avatar exibe as iniciais do usuário (ex.: MS para Maria Silva).
WmnUI::pagina('Meu App', 'Maria Silva', function() {
// todo o conteúdo aqui dentro
});cabecalho() — com botões de ação
WmnUI::cabecalho('Ordens de Serviço', 'Lista de OS abertas', function() {
WmnUI::botao('Nova OS', '#', 'primary');
WmnUI::botao('Exportar', '#', 'ghost');
});card(), secao() e divisor()
WmnUI::card('Título do Card', function() {
echo '<p>Conteúdo do card.</p>';
});
WmnUI::card('', function() { // string vazia = card sem cabeçalho
echo '<p>Conteúdo.</p>';
});
WmnUI::secao('Título de Seção'); // título + linha separadora
WmnUI::divisor(); // apenas a linhaBotões
botao() — tipos e tamanhos
WmnUI::botao('Padrão');
WmnUI::botao('Primary', '#', 'primary');
WmnUI::botao('Accept', '#', 'accept');
WmnUI::botao('Reject', '#', 'reject');
WmnUI::botao('Warning', '#', 'warning');
WmnUI::botao('Ghost', '#', 'ghost');
// Tamanhos
WmnUI::botao('Small', '#', 'small');
WmnUI::botao('Large', '#', 'large');
// href preenchido → gera <a href> em vez de <button>
WmnUI::botao('Abrir documentação', '/wmnui-docs.php', 'primary');botaoEnviar() — submit de formulário
Diferença: botao() gera type="button"; botaoEnviar() gera type="submit" e envia o formulário.
WmnUI::botaoEnviar('Salvar'); // primary por padrão
WmnUI::botaoEnviar('Confirmar', 'accept');
WmnUI::botaoEnviar('Excluir', 'reject');grupoBotoes(), speedbar() e onclick JS
WmnUI::grupoBotoes(function() {
WmnUI::botao('Editar', '#', 'primary');
WmnUI::botao('Excluir', '#', 'reject');
});
// Botões de ícone compactos
WmnUI::speedbar(function() {
WmnUI::speedButton('💾', 'Salvar');
WmnUI::speedButton('🗑️', 'Excluir');
});
// O 4º parâmetro é injetado literalmente na tag (onclick, id, data-*, disabled...)
WmnUI::botao('Dizer Olá', '', 'primary', 'onclick="dizOla()"');Formulários
input(), select(), textarea(), checkbox(), radio()
WmnUI::formGrid(function() {
WmnUI::campo('Texto', WmnUI::input('nome', 'text', '', 'placeholder="Digite..."'));
WmnUI::campo('Número', WmnUI::input('qtd', 'number', '0'));
WmnUI::campo('Data', WmnUI::input('dt', 'date'));
WmnUI::campo('Senha', WmnUI::input('senha', 'password'));
});
// Chave => Rótulo (a chave é o valor enviado no POST)
WmnUI::select('status', ['' => 'Selecione...', 'ativo' => 'Ativo', 'inativo' => 'Inativo']);
WmnUI::textarea('obs', '', 3, 'placeholder="..."');
WmnUI::checkbox('aceito', 'Aceito os termos', true);
WmnUI::radio('sexo', 'Masculino', 'M', true);campo() — label, obrigatório, ajuda e erro
// Normal
WmnUI::campo('Nome', WmnUI::input('nome', 'text'));
// Obrigatório (asterisco vermelho no label)
WmnUI::campo('E-mail', WmnUI::input('email', 'email'), true);
// Com texto de ajuda
WmnUI::campo('CPF', WmnUI::input('cpf'), false, 'Somente números.');
// Com erro (borda vermelha + mensagem)
WmnUI::campo('Campo',
WmnUI::input('campo', 'text', $valor, '', isset($erros['campo'])),
true, '', $erros['campo'] ?? '');Formulário completo com validação
<?php
require_once __DIR__ . '/pacote/wmnui.php';
$erros = [];
$dados = [];
$salvo = null;
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$dados = ['nome' => trim($_POST['nome'] ?? ''), 'email' => trim($_POST['email'] ?? '')];
if ($dados['nome'] === '') $erros['nome'] = 'Informe o nome.';
if ($dados['email'] === '') $erros['email'] = 'Informe o e-mail.';
if (empty($erros)) { $salvo = $dados; $dados = []; }
}
WmnUI::pagina('Cadastro', 'Usuário', function() use ($erros, $dados, $salvo) {
WmnUI::cabecalho('Novo Cadastro');
WmnUI::conteudo(function() use ($erros, $dados, $salvo) {
if ($salvo !== null) { WmnUI::badge('Cadastro realizado!', 'success'); return; }
if (!empty($erros)) { WmnUI::erro(count($erros) . ' campo(s) com erro.'); }
WmnUI::card('Dados', function() use ($erros, $dados) {
WmnUI::form($_SERVER['PHP_SELF'], 'post', function() use ($erros, $dados) {
WmnUI::formGrid(function() use ($erros, $dados) {
WmnUI::campo('Nome',
WmnUI::input('nome', 'text', $dados['nome'] ?? '', '', isset($erros['nome'])),
true, '', $erros['nome'] ?? '');
WmnUI::campo('E-mail',
WmnUI::input('email', 'email', $dados['email'] ?? '', '', isset($erros['email'])),
true, '', $erros['email'] ?? '');
});
WmnUI::formAcoes(function() {
WmnUI::botaoEnviar('Salvar');
WmnUI::botao('Cancelar', '#', 'ghost');
});
});
});
});
});Abas
abas() — painéis e aba ativa
O segundo parâmetro define o rótulo da aba que deve abrir (útil para manter a aba ativa após um POST).
WmnUI::abas([
'Dados' => function() { echo '<p>Conteúdo da aba Dados.</p>'; },
'Histórico' => function() { echo '<p>Conteúdo do Histórico.</p>'; },
'Anexos' => function() { echo '<p>Nenhum anexo.</p>'; },
]);
// Abrir numa aba específica
WmnUI::abas([ /* ... */ ], 'Histórico');Tabelas
Assinatura
| Parâmetro | Tipo | Obrigatório | Descrição |
|---|---|---|---|
$colunas | string[] | Sim | Rótulos do cabeçalho |
$linhas | array[] | Sim | Cada célula pode ser string ou callable |
$titulo | string | Não | Texto exibido na toolbar acima da tabela |
$toolbar | callable|null | Não | Botões/ações à direita do título |
fn()), é executado e seu output vai direto para a célula — assim você insere badges, botões ou qualquer HTML.Tabela simples + coluna com badge (fn)
WmnUI::tabela(
['ID', 'Nome', 'Status'],
[
['1', 'João Silva', fn() => WmnUI::badge('Ativo', 'success')],
['2', 'Maria Souza', fn() => WmnUI::badge('Inativo', 'error')],
['3', 'Pedro Costa', fn() => WmnUI::badge('Pendente','warning')],
]
);Coluna de ações por linha
Use fn() use ($r) para capturar o ID/dados da linha e gerar botões com onclick dinâmico.
$linhas = array_map(function($r) {
return [
$r['ID'],
$r['NOME'],
fn() => WmnUI::badge($r['STATUS'] === 'A' ? 'Ativo' : 'Inativo',
$r['STATUS'] === 'A' ? 'success' : 'error'),
fn() => WmnUI::grupoBotoes(function() use ($r) {
WmnUI::botao('Editar', '', 'small', 'onclick="abrirForm(' . $r['ID'] . ')"');
WmnUI::botao('Excluir', '', 'small reject', 'onclick="excluir(' . $r['ID'] . ')"');
}),
];
}, $registros);
WmnUI::tabela(['ID', 'Nome', 'Status', 'Ações'], $linhas);Toolbar com título e botões + exemplo com banco
<?php
require_once __DIR__ . '/pacote/wmn.php';
require_once __DIR__ . '/pacote/wmnui.php';
$db = Wmn::instancia();
$linhas = $db->buscar("SELECT ID, DESCRICAO, ATIVO FROM OS_TIPO ORDER BY DESCRICAO");
WmnUI::tabela(
['ID', 'Descrição', 'Ativo', 'Ações'],
array_map(fn($r) => [
$r['ID'],
$r['DESCRICAO'],
fn() => WmnUI::badge($r['ATIVO'] === 'S' ? 'Sim' : 'Não',
$r['ATIVO'] === 'S' ? 'success' : 'error'),
fn() => WmnUI::grupoBotoes(function() use ($r) {
WmnUI::botao('Editar', '', 'small', 'onclick="abrirForm(' . $r['ID'] . ')"');
WmnUI::botao('Excluir', '', 'small reject', 'onclick="excluir(' . $r['ID'] . ')"');
}),
], $linhas),
'Tipos (' . count($linhas) . ')', // título da toolbar
fn() => WmnUI::botao('+ Novo', '', 'primary', 'onclick="abrirForm(0)"') // botões
);Tiles
tileGrid() — menu/home com tiles
WmnUI::tileGrid([
[
'titulo' => 'Ordens de Serviço',
'url' => '/os',
'numero' => '24', // número grande (opcional)
'subtitulo' => 'abertas' // texto abaixo do número (opcional)
],
[
'titulo' => 'Relatórios',
'url' => '/relatorios',
'icone' => '📊', // emoji ou SVG (opcional)
],
]);Badges e utilitários
badge(), erro(), muted()
WmnUI::badge('Padrão');
WmnUI::badge('Sucesso', 'success');
WmnUI::badge('Erro', 'error');
WmnUI::badge('Atenção', 'warning');
WmnUI::erro('Não foi possível salvar o registro.');
echo 'Texto normal — ';
WmnUI::muted('texto secundário com cor reduzida.');Variáveis CSS (design tokens)
Definidas no CSS embutido do servidor — não devem ser sobrescritas, para manter a consistência visual.
| Variável CSS | Uso |
|---|---|
--wmn-blue | Cor primária (botões, links, foco) |
--wmn-green | Cor de sucesso / aceitar |
--wmn-red | Cor de erro / rejeitar |
--wmn-orange | Cor de aviso |
--wmn-text | Cor do texto principal |
--wmn-subtext | Cor de texto secundário |
--wmn-border | Borda padrão de campos |
--wmn-bg | Fundo da página |
--wmn-content-bg | Fundo de cards e tabelas |
--wmn-radius | Border-radius padrão (2px) |
--wmn-shadow | Sombra padrão de cards |
Campo de texto → variável PHP → tela
O fluxo mais básico do PHP com formulário: o usuário envia, o PHP lê $_POST e a página é gerada com o valor.
Código completo (arquivo único)
<?php
require_once __DIR__ . '/pacote/wmnui.php';
// 1. Ler e sanitizar o valor enviado
$nome = trim($_POST['nome'] ?? '');
$enviado = isset($_POST['enviar']);
$erroNome = '';
// 2. Validar (só quando submetido)
if ($enviado && $nome === '') {
$erroNome = 'Digite seu nome.';
}
// 3. Gerar a página — repasse as variáveis via use()
WmnUI::pagina('Olá!', '', function() use ($nome, $enviado, $erroNome) {
WmnUI::cabecalho('Exemplo de formulário');
WmnUI::conteudo(function() use ($nome, $enviado, $erroNome) {
if ($enviado && $erroNome === '') {
echo '<p style="font-size:20px">👋 Olá, <strong>'
. htmlspecialchars($nome) . '</strong>!</p>';
}
WmnUI::card('Informe seu nome', function() use ($nome, $erroNome) {
WmnUI::form($_SERVER['PHP_SELF'], 'post', function() use ($nome, $erroNome) {
WmnUI::formGrid(function() use ($nome, $erroNome) {
WmnUI::campo('Seu nome',
WmnUI::input('nome', 'text', $nome, 'placeholder="Ex: João"', $erroNome !== ''),
true, '', $erroNome);
});
WmnUI::formAcoes(function() {
WmnUI::botaoEnviar('Enviar', 'primary', 'name="enviar"');
});
});
});
});
});Conceitos-chave
| Conceito | Explicação |
|---|---|
$_POST['campo'] | Lê o valor enviado pelo formulário (string ou null) |
trim() | Remove espaços em branco extras |
?? '' | Null-coalescing: retorna '' se a chave não existe (GET inicial) |
isset($_POST['enviar']) | Detecta se o botão foi clicado (o botão precisa ter name=) |
htmlspecialchars() | Converte caracteres especiais para HTML seguro (evita XSS) |
use($var) | Injeta variáveis PHP dentro de closures (callbacks) |
$_POST['x'] diretamente — sempre passe por htmlspecialchars() ou pelo WmnUI::input(..., $valor), que já faz o escape.