Módulos visuais
mad-tree-view
mad-tree-actions
mad-tree-context-menu
Básico
mad-tree-view com auto-query no model, expand/collapse e clique por nó.
Diretoria
Financeiro
Contas a pagar
Contas a receber
Tesouraria
Comercial
Vendas
Marketing
Operações
Logística
Produção
resources/views/tutor/examples/modulos-tree-view/basico.blade.php
<mad-tree-view name="departamentos" model="TutorDemoTreeNode" display="nome"
parent-field="parent_id" icon="folder" active-icon="folder-open"
order-by="ordem" mad:click="onSelectTreeNode" persist />
app/control/Tutor/TutorModulosTreeView.php
public function onSelectTreeNode(int $id): MadResponse
{
$nome = TutorDemoTreeNode::query()->find($id)?->nome ?? "#{$id}";
return (new MadResponse())->toast("Selecionado: {$nome}", 'info');
}
Dados manuais
Árvore declarativa via :items — dispensa model quando os dados já existem em memória.
Categorias
Eletrônicos
Papelaria
Fornecedores
resources/views/tutor/examples/modulos-tree-view/itens-manuais.blade.php
@php
$arvore = [
['id' => 1, 'name' => 'Categorias', 'icon' => 'folder', '_count' => 2, 'children' => [
['id' => 2, 'name' => 'Eletrônicos', 'icon' => 'file', '_count' => 12, 'children' => []],
['id' => 3, 'name' => 'Papelaria', 'icon' => 'file', '_count' => 5, 'children' => []],
]],
['id' => 4, 'name' => 'Fornecedores', 'icon' => 'file', '_count' => 0, 'children' => []],
];
@endphp
<mad-tree-view name="categorias-estaticas" :items="$arvore" display="name"
icon="folder" count-field="_count" expanded="all" />
Ações e menu de contexto
mad-tree-actions (botão global acima da árvore) + mad-tree-context-menu (ações por nó).
Diretoria
Financeiro
Contas a pagar
Contas a receber
Tesouraria
Comercial
Vendas
Marketing
Operações
Logística
Produção
resources/views/tutor/examples/modulos-tree-view/acoes-contexto.blade.php
<mad-tree-view name="departamentos-acoes" model="TutorDemoTreeNode" display="nome"
parent-field="parent_id" icon="folder" order-by="ordem" mad:click="onSelectTreeNode">
<mad-tree-actions position="top">
<mad-btn variant="ghost" size="sm" icon="plus" mad:click="onNovoDepartamento">Novo departamento</mad-btn>
</mad-tree-actions>
<mad-tree-context-menu>
<mad-menu-item icon="pencil" mad:click="onRenomearNode({id})">Renomear</mad-menu-item>
<mad-menu-separator />
<mad-menu-item icon="trash-2" variant="danger" mad:click="onExcluirNode({id})">Excluir</mad-menu-item>
</mad-tree-context-menu>
</mad-tree-view>
app/control/Tutor/TutorModulosTreeView.php
public function onExcluirNode(int $id): MadResponse
{
$nome = TutorDemoTreeNode::query()->find($id)?->nome ?? "#{$id}";
return (new MadResponse())->toast("Excluir \"{$nome}\" — ação de exemplo (nada foi apagado).", 'warning');
}
Ícones dinâmicos e contagem
icon-field por nó, active/expanded-icon e badge de contagem via count-field.
Diretoria
Financeiro3
Contas a pagar
Contas a receber
Tesouraria
Comercial2
Vendas
Marketing
Operações2
Logística
Produção
resources/views/tutor/examples/modulos-tree-view/icones-contagem.blade.php
<mad-tree-view name="departamentos-badges" model="TutorDemoTreeNode" display="nome"
parent-field="parent_id" icon="folder" icon-field="icone" active-icon="folder-open"
expanded-icon="folder-open" count-field="itens_count" order-by="ordem" expanded="first" />
Código-fonte completo da página
app/control/Tutor/TutorModulosTreeView.php
<?php
namespace App\Control\Tutor;
use App\Models\TutorDemo\TutorDemoTreeNode;
use App\Support\Tutor\TutorPage;
use Illuminate\Support\Facades\Schema;
use Mad\Http\MadResponse;
/**
* TutorModulosTreeView — <mad-tree-view> + <mad-tree-actions> +
* <mad-tree-context-menu>.
*
* Fixture própria (tutor_tree_nodes, molde KanbanDevView::ensureFixture) —
* nenhuma tabela do TutorDemoSeed compartilhado é hierárquica (parent_id),
* então esta página tem seu próprio model+seed, só para hierarquia.
*/
class TutorModulosTreeView extends TutorPage
{
protected string $catalogKey = 'modulos_tree_view';
public function mount(array $params = []): void
{
$this->ensureFixture();
}
// ── Ações do menu de contexto / toolbar (ilustrativas — não persistem) ──
public function onSelectTreeNode(int $id): MadResponse
{
$nome = TutorDemoTreeNode::query()->find($id)?->nome ?? "#{$id}";
return (new MadResponse())->toast("Selecionado: {$nome}", 'info');
}
public function onNovoDepartamento(): MadResponse
{
return (new MadResponse())
->toast('Ação de exemplo — normalmente abriria um form de novo departamento.', 'info');
}
public function onRenomearNode(int $id): MadResponse
{
$nome = TutorDemoTreeNode::query()->find($id)?->nome ?? "#{$id}";
return (new MadResponse())->toast("Renomear \"{$nome}\" — ação de exemplo.", 'info');
}
public function onExcluirNode(int $id): MadResponse
{
$nome = TutorDemoTreeNode::query()->find($id)?->nome ?? "#{$id}";
return (new MadResponse())->toast("Excluir \"{$nome}\" — ação de exemplo (nada foi apagado).", 'warning');
}
// ── Fixture ──────────────────────────────────────────────────────────
private function ensureFixture(): void
{
$schema = Schema::connection('business');
if (!$schema->hasTable('tutor_tree_nodes')) {
$schema->create('tutor_tree_nodes', function ($t) {
$t->increments('id');
$t->unsignedInteger('parent_id')->nullable();
$t->string('nome');
$t->string('icone')->nullable();
$t->unsignedInteger('itens_count')->default(0);
$t->unsignedInteger('ordem')->default(0);
});
}
if (TutorDemoTreeNode::query()->count() > 0) {
return;
}
$ordem = 0;
$raizId = TutorDemoTreeNode::query()->create([
'parent_id' => null, 'nome' => 'Diretoria', 'icone' => 'building-2',
'itens_count' => 0, 'ordem' => $ordem++,
])->id;
$departamentos = [
'Financeiro' => ['Contas a pagar', 'Contas a receber', 'Tesouraria'],
'Comercial' => ['Vendas', 'Marketing'],
'Operações' => ['Logística', 'Produção'],
];
foreach ($departamentos as $nome => $filhos) {
$depId = TutorDemoTreeNode::query()->create([
'parent_id' => $raizId, 'nome' => $nome, 'icone' => 'folder',
'itens_count' => count($filhos), 'ordem' => $ordem++,
])->id;
foreach ($filhos as $filho) {
TutorDemoTreeNode::query()->create([
'parent_id' => $depId, 'nome' => $filho, 'icone' => 'file-text',
'itens_count' => 0, 'ordem' => $ordem++,
]);
}
}
}
}
resources/views/tutor/modulos/tree-view.blade.php
<x-tutor-page page="modulos_tree_view">
<x-tutor-demo demo="tutor.examples.modulos-tree-view.basico"
title="Básico" desc="mad-tree-view com auto-query no model, expand/collapse e clique por nó."
php="TutorModulosTreeView::onSelectTreeNode" />
<x-tutor-demo demo="tutor.examples.modulos-tree-view.itens-manuais"
title="Dados manuais" desc="Árvore declarativa via :items — dispensa model quando os dados já existem em memória." />
<x-tutor-demo demo="tutor.examples.modulos-tree-view.acoes-contexto"
title="Ações e menu de contexto" desc="mad-tree-actions (botão global acima da árvore) + mad-tree-context-menu (ações por nó)."
php="TutorModulosTreeView::onExcluirNode" />
<x-tutor-demo demo="tutor.examples.modulos-tree-view.icones-contagem"
title="Ícones dinâmicos e contagem" desc="icon-field por nó, active/expanded-icon e badge de contagem via count-field." />
</x-tutor-page>