MAD Lab
/
Tutor > Dashboards e widgets > Widgets

Widgets

Dashboards e widgets

mad-db-steps mad-goal-ladder mad-segment-stats mad-timeline
Steps alimentados pelo banco

mad-db-steps lê a lista de estados do pedido direto do model — cor e ordem vêm da própria tabela.

Novo
Em separação
3 Enviado
4 Entregue
5 Cancelado
Novo
Em separação
3
Enviado
4
Entregue
5
Cancelado
✓ Novo ✓ Em separação Enviado Entregue Cancelado
resources/views/tutor/examples/dashboards-widgets/db-steps.blade.php
<div style="display:flex;flex-direction:column;gap:22px;">
    <mad-db-steps model="TutorDemoEstadoPedido" display="nome" color-field="cor" order-by="ordem asc"
        value="3" variant="arrows" />
    <mad-db-steps model="TutorDemoEstadoPedido" display="nome" color-field="cor" order-by="ordem asc"
        value="3" variant="dots" size="sm" />
    <mad-db-steps model="TutorDemoEstadoPedido" display="nome" color-field="cor" order-by="ordem asc"
        value="3" variant="progress" />
</div>
Escada de metas

mad-goal-ladder: Meta → Projeção → Realizado → Saldo, com a seta de variação entre degraus.

Meta x Realizado (trimestre demo)
Meta do trimestre R$ 150.000,00
396,8%
Projeção R$ 745.151,21
-7,4%
Realizado R$ 689.954,82
Meta batida
Saldo até a meta R$ 539.954,82
resources/views/tutor/examples/dashboards-widgets/goal-ladder.blade.php
@php($__component = \Mad\Component\MadRenderContext::getComponent())
<mad-goal-ladder title="Meta x Realizado (trimestre demo)" :steps="$__component->goalLadderSteps()" accent="#2F4F3F" />
app/control/Tutor/TutorDashboardsWidgets.php
/** Degraus Meta → Projeção → Realizado → Saldo, pro mad-goal-ladder. */
public function goalLadderSteps(): array
{
    $meta      = 150000.0;
    $realizado = (float) (TutorDemoPedido::query()->sum('valor_total') ?? 0);
    $projecao  = round($realizado * 1.08, 2);
    $saldo     = round($meta - $realizado, 2);

    $money = fn (float $v): string => 'R$ ' . number_format($v, 2, ',', '.');
    $pct   = fn (float $a, float $b): string => $b > 0
        ? number_format((($a - $b) / $b) * 100, 1, ',', '.') . '%'
        : '—';

    return [
        ['label' => 'Meta do trimestre', 'value' => $money($meta)],
        [
            'label' => 'Projeção', 'value' => $money($projecao),
            'delta' => ['text' => $pct($projecao, $meta), 'dir' => $projecao >= $meta ? 'up' : 'down'],
        ],
        [
            'label' => 'Realizado', 'value' => $money($realizado),
            'delta' => ['text' => $pct($realizado, $projecao), 'dir' => $realizado >= $projecao ? 'up' : 'down'],
        ],
        [
            'label' => 'Saldo até a meta', 'value' => $money(abs($saldo)), 'muted' => true,
            'delta' => ['text' => $saldo <= 0 ? 'Meta batida' : 'Falta bater', 'dir' => $saldo <= 0 ? 'up' : 'down'],
        ],
    ];
}
Contadores segmentados

mad-segment-stats resume uma distribuição em uma faixa horizontal de contadores.

Pedidos por estado
74 Entregue 49,3%
24 Enviado 16,0%
20 Em separação 13,3%
17 Cancelado 11,3%
15 Novo 10,0%
resources/views/tutor/examples/dashboards-widgets/segment-stats.blade.php
@php($__component = \Mad\Component\MadRenderContext::getComponent())
<mad-segment-stats title="Pedidos por estado" :items="$__component->segmentStatsItems()" />
app/control/Tutor/TutorDashboardsWidgets.php
/** Contagem + percentual de pedidos por estado, pro mad-segment-stats. */
public function segmentStatsItems(): array
{
    $total = TutorDemoPedido::query()->count();
    if ($total === 0) {
        return [];
    }

    return TutorDemoPedido::query()
        ->join('tutor_estados_pedido as te', 'te.id', '=', 'tutor_pedidos.estado_id')
        ->selectRaw('te.nome as estado_nome, te.cor as cor, count(*) as qtd')
        ->groupBy('te.nome', 'te.cor')
        ->orderByDesc('qtd')
        ->get()
        ->map(fn ($r) => [
            'value' => (int) $r->qtd,
            'label' => $r->estado_nome,
            'pct'   => round(($r->qtd / $total) * 100, 1),
            'color' => $r->cor,
        ])
        ->all();
}
Linha do tempo

mad-timeline com itens manuais — o ciclo de vida de um pedido, do pedido criado até a entrega.

10/08/2026
00:00
Pedido #150 criado
Recebido e aguardando separação.
00:00
Em separação
Itens conferidos no estoque.
00:00
Enviado
Despachado para a transportadora.
00:00
Entregue
Cliente confirmou o recebimento.
resources/views/tutor/examples/dashboards-widgets/timeline.blade.php
@php($__component = \Mad\Component\MadRenderContext::getComponent())
<mad-timeline :items="$__component->timelineDoPedido()" cards />
app/control/Tutor/TutorDashboardsWidgets.php
/** Linha do tempo sintética do ciclo de vida de um pedido, pro mad-timeline. */
public function timelineDoPedido(): array
{
    $pedido = TutorDemoPedido::query()->orderByDesc('id')->first();
    if (!$pedido) {
        return [];
    }

    $data = (string) $pedido->dt_pedido;

    return [
        ['title' => "Pedido #{$pedido->id} criado", 'body' => 'Recebido e aguardando separação.', 'date' => $data, 'icon' => 'shopping-cart', 'color' => 'info'],
        ['title' => 'Em separação', 'body' => 'Itens conferidos no estoque.', 'date' => $data, 'icon' => 'package-search', 'color' => 'warning'],
        ['title' => 'Enviado', 'body' => 'Despachado para a transportadora.', 'date' => $data, 'icon' => 'truck', 'color' => 'info'],
        ['title' => 'Entregue', 'body' => 'Cliente confirmou o recebimento.', 'date' => $data, 'icon' => 'check-check', 'color' => 'success'],
    ];
}
Código-fonte completo da página
app/control/Tutor/TutorDashboardsWidgets.php
<?php

namespace App\Control\Tutor;

use App\Models\TutorDemo\TutorDemoPedido;
use App\Support\Tutor\TutorDemoSeed;
use App\Support\Tutor\TutorPage;

/**
 * TutorDashboardsWidgets — página "Widgets" do catálogo.
 *
 * mad-db-steps é 100% declarativo (não precisa de PHP aqui). Os outros três
 * widgets (goal-ladder, segment-stats, timeline) recebem dados via prop
 * array — os métodos abaixo calculam esses arrays a partir da fixture
 * TutorDemo (nunca @php com query Eloquent direto no blade).
 */
class TutorDashboardsWidgets extends TutorPage
{
    protected string $catalogKey = 'dashboards_widgets';

    public function mount(array $params = []): void
    {
        TutorDemoSeed::ensure();
    }

    /** Degraus Meta → Projeção → Realizado → Saldo, pro mad-goal-ladder. */
    public function goalLadderSteps(): array
    {
        $meta      = 150000.0;
        $realizado = (float) (TutorDemoPedido::query()->sum('valor_total') ?? 0);
        $projecao  = round($realizado * 1.08, 2);
        $saldo     = round($meta - $realizado, 2);

        $money = fn (float $v): string => 'R$ ' . number_format($v, 2, ',', '.');
        $pct   = fn (float $a, float $b): string => $b > 0
            ? number_format((($a - $b) / $b) * 100, 1, ',', '.') . '%'
            : '—';

        return [
            ['label' => 'Meta do trimestre', 'value' => $money($meta)],
            [
                'label' => 'Projeção', 'value' => $money($projecao),
                'delta' => ['text' => $pct($projecao, $meta), 'dir' => $projecao >= $meta ? 'up' : 'down'],
            ],
            [
                'label' => 'Realizado', 'value' => $money($realizado),
                'delta' => ['text' => $pct($realizado, $projecao), 'dir' => $realizado >= $projecao ? 'up' : 'down'],
            ],
            [
                'label' => 'Saldo até a meta', 'value' => $money(abs($saldo)), 'muted' => true,
                'delta' => ['text' => $saldo <= 0 ? 'Meta batida' : 'Falta bater', 'dir' => $saldo <= 0 ? 'up' : 'down'],
            ],
        ];
    }

    /** Contagem + percentual de pedidos por estado, pro mad-segment-stats. */
    public function segmentStatsItems(): array
    {
        $total = TutorDemoPedido::query()->count();
        if ($total === 0) {
            return [];
        }

        return TutorDemoPedido::query()
            ->join('tutor_estados_pedido as te', 'te.id', '=', 'tutor_pedidos.estado_id')
            ->selectRaw('te.nome as estado_nome, te.cor as cor, count(*) as qtd')
            ->groupBy('te.nome', 'te.cor')
            ->orderByDesc('qtd')
            ->get()
            ->map(fn ($r) => [
                'value' => (int) $r->qtd,
                'label' => $r->estado_nome,
                'pct'   => round(($r->qtd / $total) * 100, 1),
                'color' => $r->cor,
            ])
            ->all();
    }

    /** Linha do tempo sintética do ciclo de vida de um pedido, pro mad-timeline. */
    public function timelineDoPedido(): array
    {
        $pedido = TutorDemoPedido::query()->orderByDesc('id')->first();
        if (!$pedido) {
            return [];
        }

        $data = (string) $pedido->dt_pedido;

        return [
            ['title' => "Pedido #{$pedido->id} criado", 'body' => 'Recebido e aguardando separação.', 'date' => $data, 'icon' => 'shopping-cart', 'color' => 'info'],
            ['title' => 'Em separação', 'body' => 'Itens conferidos no estoque.', 'date' => $data, 'icon' => 'package-search', 'color' => 'warning'],
            ['title' => 'Enviado', 'body' => 'Despachado para a transportadora.', 'date' => $data, 'icon' => 'truck', 'color' => 'info'],
            ['title' => 'Entregue', 'body' => 'Cliente confirmou o recebimento.', 'date' => $data, 'icon' => 'check-check', 'color' => 'success'],
        ];
    }
}
resources/views/tutor/dashboards/widgets.blade.php
<x-tutor-page page="dashboards_widgets">
    <x-tutor-demo demo="tutor.examples.dashboards-widgets.db-steps"
        title="Steps alimentados pelo banco" desc="mad-db-steps lê a lista de estados do pedido direto do model — cor e ordem vêm da própria tabela." />

    <x-tutor-demo demo="tutor.examples.dashboards-widgets.goal-ladder"
        title="Escada de metas" desc="mad-goal-ladder: Meta → Projeção → Realizado → Saldo, com a seta de variação entre degraus."
        php="TutorDashboardsWidgets::goalLadderSteps" />

    <x-tutor-demo demo="tutor.examples.dashboards-widgets.segment-stats"
        title="Contadores segmentados" desc="mad-segment-stats resume uma distribuição em uma faixa horizontal de contadores."
        php="TutorDashboardsWidgets::segmentStatsItems" />

    <x-tutor-demo demo="tutor.examples.dashboards-widgets.timeline"
        title="Linha do tempo" desc="mad-timeline com itens manuais — o ciclo de vida de um pedido, do pedido criado até a entrega."
        php="TutorDashboardsWidgets::timelineDoPedido" />
</x-tutor-page>