gsferro / filament-stat-plus-easy
Stat cards with a corner icon and a colored accent border for Filament v3, v4 and v5 — animated counter included, plus a matching lazy-loading skeleton.
Package info
github.com/gsferro/filament-stat-plus-easy
pkg:composer/gsferro/filament-stat-plus-easy
Fund package maintenance!
Requires
- php: ^8.2
- filament/filament: ^3.2|^4.0|^5.0
- gsferro/filament-odometer-easy: ^1.1
- spatie/laravel-package-tools: ^1.15.0
Requires (Dev)
- larastan/larastan: ^3.0
- laravel/pint: ^1.0
- nunomaduro/collision: ^8.0
- orchestra/testbench: ^9.0|^10.0|^11.0
- pestphp/pest: ^3.7|^4.0
- pestphp/pest-plugin-arch: ^3.0|^4.0
- pestphp/pest-plugin-laravel: ^3.0|^4.0
- pestphp/pest-plugin-livewire: ^3.0|^4.0
This package is auto-updated.
Last update: 2026-08-01 15:23:51 UTC
README
Filament Stat Plus Easy
🇧🇷 Português · 🇺🇸 English
O Stat do Filament v3, v4 e v5 com o visual que todo dashboard acaba pedindo: ícone no canto superior direito, borda de acento colorida à esquerda e contador animado — mais um esqueleto de carregamento com a mesma forma do card.
Troque Stat::make(...) por StatPlus::make(...), acrescente ->icon(...) e pronto. Nenhuma view publicada, nenhum CSS no seu tema.
use Gsferro\FilamentStatPlusEasy\Widgets\StatPlus; protected function getStats(): array { return [ StatPlus::make('Projetos em andamento', Projeto::emAndamento()->count()) ->icon('heroicon-o-folder-open'), StatPlus::make('SLA estourado', Ticket::atrasados()->count()) ->icon('heroicon-o-exclamation-triangle') ->iconColor('danger'), ]; }
🎬 Demo
StatPlus no dashboard — ícone no canto, borda de acento e contador animado:
Cores independentes — o ícone numa cor, a borda em outra (ou sem borda):
Esqueleto do carregamento lazy — mesma forma do card real, então nada salta na troca:
O que o pacote entrega
| Recurso | O que faz |
|---|---|
StatPlus |
Stat com ícone no canto, borda de acento e contador animado |
HasStatPlus |
O mesmo acento em qualquer Stat seu, sem o contador |
HasStatPlusPlaceholder |
Esqueleto de carregamento com a forma do card, para widget lazy |
FilamentStatPlusEasyPlugin |
Padrões por painel (cor de ícone, borda ligada/desligada) |
Compatibilidade
| Filament | Suportado |
|---|---|
v3 (^3.2) |
✅ |
v4 (^4.0) |
✅ |
v5 (^5.0) |
✅ |
PHP 8.2+. O pacote não publica nem substitui a view nativa do Stat: ele injeta classes e CSS custom properties no elemento raiz que a view já imprime nas três versões. Upgrade de Filament não pede nada daqui.
Instalação
composer require gsferro/filament-stat-plus-easy php artisan filament:assets
filament:assets copia o CSS do pacote para public/ — é o passo que faz o visual aparecer. Rode-o também no deploy.
Registro do plugin (opcional, só para trocar padrões):
use Gsferro\FilamentStatPlusEasy\FilamentStatPlusEasyPlugin; public function panel(Panel $panel): Panel { return $panel ->plugin(FilamentStatPlusEasyPlugin::make()); }
Publicar a config (opcional):
php artisan vendor:publish --tag=filament-stat-plus-easy-config
Uso
O básico
->icon() é o gatilho: com ícone, o card ganha o quadrado no canto e a borda à esquerda, ambos na cor do stat.
StatPlus::make('Entidades', 42) ->icon('heroicon-o-building-library');
Sem ->icon() e sem ->accentColor(), o StatPlus renderiza exatamente como o stat nativo. É o que torna a migração incremental segura: troque a classe hoje, acrescente o ícone quando quiser.
Cores — ícone e borda são independentes
// os dois na cor do ícone StatPlus::make('Entidades', 42)->icon('heroicon-o-building-library')->iconColor('success'); // só o ícone, sem borda StatPlus::make('Entidades', 42)->icon('heroicon-o-building-library')->accentColor(false); // ícone numa cor, borda em outra StatPlus::make('SLA', 3)->icon('heroicon-o-clock')->iconColor('gray')->accentColor('danger'); // só a borda, sem ícone StatPlus::make('Receita', 'R$ 1,2M')->accentColor('success');
Resolução da cor do ícone:
->iconColor('success')— vence sempre- senão,
->color('danger')(o método nativo, que também pinta description e chart) - senão,
config('filament-stat-plus-easy.icon_color')(padrão:primary)
Resolução da cor da borda:
->accentColor(false)— sem borda->accentColor('danger')— cor própria- senão, a cor do ícone — e, sem ícone, não há borda
As cores são nomes de cores registradas no painel (
->colors([...])), não hex. O CSS lê a escala pela variável--{cor}-500, que é o que faz o card seguir o tema e o modo escuro. Cor passada como array de 11 tons cai no padrão.
Tudo do Stat nativo continua valendo
StatPlus::make('Projetos', 128) ->icon('heroicon-o-folder-open') ->description('12% neste mês') ->descriptionIcon('heroicon-m-arrow-trending-up') ->chart([7, 12, 9, 14, 18, 22]) ->url(ProjetoResource::getUrl()) ->extraAttributes(['class' => 'minha-classe']);
Chart, description, url, polling, extraAttributes — nada é substituído. O que o pacote acrescenta é somado ao que você já passou (classe e style concatenam, não sobrescrevem).
Contador animado
StatPlus estende o OdometerStat do filament-odometer-easy — que vem junto como dependência —, então o valor anima sozinho:
StatPlus::make('Receita', 1250000) ->icon('heroicon-o-banknotes') ->format(['style' => 'currency', 'currency' => 'BRL']) ->duration(1500);
Quer o acento sem o contador? Aplique o trait na sua própria classe:
use Filament\Widgets\StatsOverviewWidget\Stat; use Gsferro\FilamentStatPlusEasy\Concerns\HasStatPlus; class MeuStat extends Stat { use HasStatPlus; }
Esqueleto de carregamento (widget lazy)
Widget lazy pinta um placeholder até hidratar. O padrão do Filament é um card liso — quando o widget real entra com ícone e borda, o layout mexe. O trait resolve:
use Filament\Widgets\StatsOverviewWidget; use Gsferro\FilamentStatPlusEasy\Concerns\HasStatPlusPlaceholder; class VisaoGeralStats extends StatsOverviewWidget { use HasStatPlusPlaceholder; protected static bool $isLazy = true; }
Por padrão o esqueleto desenha 4 cards, todos com acento, e não executa getStats() — o placeholder roda antes da hidratação, e chamar os stats ali executaria justamente as queries que o lazy adia.
Ajustes, todos opcionais:
// outra quantidade de cards protected function getPlaceholderStatsCount(): int { return 3; } // widget misto (alguns stats com acento, outros não): lê os stats reais e // espelha card a card — custa as queries no placeholder protected bool $placeholderReadsStats = true;
O esqueleto usa as mesmas classes do card real (fi-wi-stats-overview-stat, fi-stat-plus, fi-stat-plus-bordered), só que em cinza — é o que garante que a troca não desloque nada. E respeita o columnSpan do widget.
Configuração
Fluente, por painel
->plugin( FilamentStatPlusEasyPlugin::make() ->iconColor('info') // cor padrão do ícone quando o stat não define ->accent(false) // borda desligada por padrão neste painel )
Ou pelo arquivo de config
// config/filament-stat-plus-easy.php return [ 'icon_color' => 'primary', 'accent' => true, ];
Medidas, via CSS
Tamanho do ícone, raio, deslocamento, espessura da borda e opacidade do fundo são custom properties com valor padrão. Sobrescreva onde fizer sentido — no tema (global), por painel ou num card só:
/* no seu theme.css */ .fi-wi-stats-overview-stat.fi-stat-plus { --stat-plus-icon-size: 3rem; --stat-plus-icon-radius: 9999px; /* ícone redondo */ --stat-plus-border-width: 6px; }
// ou só neste card StatPlus::make('Projetos', 12) ->icon('heroicon-o-folder-open') ->extraAttributes(['style' => '--stat-plus-border-width: 8px']);
| Custom property | Padrão | O que controla |
|---|---|---|
--stat-plus-icon-size |
2.5rem |
Lado da caixa do ícone |
--stat-plus-icon-padding |
0.5rem |
Respiro entre a caixa e o desenho |
--stat-plus-icon-offset |
1.25rem |
Distância do canto do card |
--stat-plus-icon-radius |
0.625rem |
Arredondamento da caixa |
--stat-plus-icon-opacity |
12% |
Opacidade do fundo da caixa (claro) |
--stat-plus-icon-opacity-dark |
22% |
Opacidade do fundo da caixa (escuro) |
--stat-plus-border-width |
4px |
Espessura da borda de acento |
Como funciona por baixo dos panos
- Nada de view publicada. A view nativa do
Statjá imprime$getExtraAttributeBag()no elemento raiz em v3, v4 e v5. O pacote injeta ali duas classes (fi-stat-plus,fi-stat-plus-bordered) e duas custom properties (--stat-plus-icon,--stat-plus-accent). O CSS faz o resto: o card já érelativeem todas as versões, então o ícone só precisa ser posicionado. - CSS estático, registrado como asset. Nada de
@apply, utilitário do Tailwind ou@layer— o arquivo não passa pelo build do app consumidor. Por isso o pacote dispensa qualquer edição de tema;filament:assetscopia e o Filament injeta em todos os painéis. - Uma diferença real entre as versões: o formato das variáveis de cor. O v3 guarda canais RGB (
--primary-500: 217 119 6) e o v4/v5 guardam a cor pronta (oklch(...)). Quem resolve é o PHP, escrevendorgb(var(--primary-500))ouvar(--primary-500)conforme a versão instalada. O CSS fica igual para todo mundo. - O ícone mudou de markup entre as versões (
.fi-wi-stats-overview-stat-iconno v3,.fi-icondentro de.fi-wi-stats-overview-stat-label-ctnno v4/v5), então a regra cobre os dois seletores. Nenhum dos dois alcança o ícone da description. - Nome de cor é validado antes de entrar na string de
style(o Filament não escapa valores de atributo extra): só slug[a-z0-9-]passa, o resto cai no padrão. Importa quando a cor vem de dado, como identidade visual por tenant.
Desenvolvimento
composer install composer test # Pest composer analyse # PHPStan composer lint # Pint
O CSS é plain CSS versionado em resources/dist/filament-stat-plus-easy.css — não há passo de build. Editou, testou, commitou.
Os GIFs do README saem de art/demo/index.html (a página carrega o CSS real do pacote) com bash art/make-gifs.sh — Chrome headless para os quadros, ffmpeg para montar. Cada quadro é um screenshot com um ?t= diferente, então a captura é determinística. A capa da página de plugins (art/thumbnail.jpg, 1280x720) sai da mesma página com bash art/make-thumbnail.sh.
Testes
composer test
Changelog
Veja o CHANGELOG.
Contributing
Veja o CONTRIBUTING.
Security Vulnerabilities
Veja a política de segurança.
Credits
- gsferro
- Todos os contribuidores
- filament-odometer-easy — o contador animado que vem junto
License
MIT. Veja o arquivo de licença.



