josenildotiago / crud
Modern CRUD generator with a color palette layer for Laravel 12 and 13 + React.js
Requires
- php: >=8.2.0
- illuminate/console: ^12.0|^13.0
- illuminate/database: ^12.0|^13.0
- illuminate/filesystem: ^12.0|^13.0
- illuminate/support: ^12.0|^13.0
- illuminate/validation: ^12.0|^13.0
- laravel/prompts: ^0.3.0
- symfony/console: ^7.0|^8.0
- symfony/process: ^7.0|^8.0
Requires (Dev)
- orchestra/testbench: ^10.0|^11.0
- pestphp/pest: ^3.0|^4.0
- pestphp/pest-plugin-laravel: ^3.0|^4.0
- phpstan/phpstan: ^2.0
- phpunit/phpunit: ^11.5.50|^12.0
This package is auto-updated.
Last update: 2026-07-31 12:33:37 UTC
README
Um pacote moderno para Laravel que gera operações CRUD completas com integração React.js e uma camada de paleta de cores.
🚀 Características Principais
✨ Compatibilidade Laravel 12 e 13
- Arquitetura Moderna: Laravel 12 e 13, com suporte PHP 8.2+
- Wayfinder: em projetos com
laravel/wayfinder, as rotas viram funções TypeScript importadas de@/routes/{recurso}no lugar do helper globalroute() - Link na Sidebar: o CRUD gerado entra no menu do projeto numa região que o pacote gerencia sozinho
- Integração AppLayout: Usa AppLayout (ao invés do AuthenticatedLayout descontinuado)
- Sistema de Breadcrumbs: Navegação hierárquica abrangente
- Campos Inteligentes: Detecção automática de campos fillable para React useForm
- Organização de Rotas: Arquivos de rota separados por modelo com middleware adequado
- Suporte Multi-Database: Compatível com MySQL, PostgreSQL, SQLite e SQL Server
- Design RESTful: Gera controllers e rotas RESTful limpos
🎨 Camada de Paleta de Cores
- Sistema de Cores OKLCH: Suporte ao espaço de cor moderno para paletas vibrantes e consistentes
- CSS Custom Properties: Troca de paleta em tempo real, sem reload da página
- React, Vue e Svelte: Um seletor por stack, instalado dentro da página de aparência do starter kit
- Persistente: Preferência salva em
localStorage - Criação Automática: Comando para acrescentar novas paletas
⚛️ Integração React.js + shadcn/ui
- Suporte Inertia.js: SSR sem complicações com backend Laravel
- TypeScript Pronto: Suporte completo ao TypeScript para type safety
- Componentes Modernos: AppLayout com navegação breadcrumb
- shadcn/ui Integration: Uso completo de Button, Card, Input, Label
- Formulários Inteligentes: Integração fillableColumns com useForm
- Design Responsivo: Padrões mobile-first
🛠️ Funcionalidades CRUD Avançadas
- Operações em Lote: Ações multi-select para gerenciamento eficiente de dados
- Busca Avançada: Busca em tempo real com debouncing
- Paginação Inteligente: Paginação otimizada com preservação de estado
- Validação de Formulários: Validação client e server-side
- Upload de Arquivos: Manipulação integrada de arquivos com preview
- Export/Import: Exportação CSV com colunas customizáveis
📦 Instalação
composer require josenildotiago/crud
🎯 Início Rápido
1. Instalar a Camada de Paleta (Opcional)
php artisan crud:install-palette
Este comando irá:
- Detectar seu stack frontend (
react,vueousvelte— pela página de aparência do projeto; ou aceita--stack=explícito) - Escrever
resources/css/crud-palettes.csseresources/js/lib/crud-palette.ts - Gerar o seletor de paleta da stack detectada
- Editar
resources/css/app.css, o arquivo de entrada da stack e a página de aparência, sempre de forma idempotente — rodar de novo não duplica nada
2. Criar Sua Primeira Paleta (Opcional)
php artisan crud:create-palette minha-paleta
Prompts interativos irão guiá-lo através de:
- Nome da paleta (o identificador sai sozinho do nome, via slug — não há prompt separado para ele)
- Matiz OKLCH (0 a 360)
- Geração automática dos dois modos, claro e escuro
3. Gerar Recursos CRUD
php artisan getic:install users
Este comando gera:
- Model:
app/Models/User.phpcom relacionamentos - Controller:
app/Http/Controllers/UserController.phpotimizado para Inertia.js - Componentes React: Interface CRUD completa em TypeScript
Create.tsx- Formulário de criação com shadcn/uiEdit.tsx- Formulário de ediçãoIndex.tsx- Listagem com paginação e buscaShow.tsx- Visualização de registro
- Routes:
routes/user.phpcom middleware auth e verified
Opções Avançadas
# Com relacionamentos automáticos php artisan getic:install orders --relationship # Stack específico php artisan getic:install categories --stack=react # Escolhendo o helper de rotas dos componentes React php artisan getic:install clientes --routes=wayfinder php artisan getic:install clientes --routes=ziggy
Helper de rotas (--routes=)
Sem a flag, vale crud.inertia.route_helper — que por padrão é auto e detecta se o
laravel/wayfinder está instalado no projeto. Em wayfinder, os componentes importam
funções de @/routes/{recurso}; em ziggy, usam o helper global route().
Link na sidebar
Na stack react, o pacote acrescenta o CRUD gerado ao menu do projeto
(resources/js/components/app-sidebar.tsx), dentro de uma região delimitada pelos
comentários crud:nav:start / crud:nav:end — o resto do seu menu nunca é tocado, e
regerar a mesma tabela substitui o item em vez de duplicar. Na primeira geração o pacote
pergunta antes de criar a região. Para desligar:
// config/crud.php 'navigation' => [ 'sidebar' => false, ],
Pré-voo da tabela
Antes de escrever qualquer arquivo do CRUD, o pacote confere se a tabela tem o que o código
gerado assume: created_at e/ou updated_at, chave primária chamada id, e nomes de coluna
que sejam identificadores válidos. Se algo falta, ele lista os avisos e pergunta se você
quer gerar mesmo assim — avisa, não bloqueia, porque gerar em cima de uma tabela
legada e ajustar o Model à mão depois é caso legítimo. Numa tabela criada pelas migrations
do Laravel ele não diz nada.
Em modo não interativo (--no-interaction, script, CI) ele imprime os avisos, segue, e
repete o resumo no fim — por sua conta e risco. O padrão da pergunta é gerar (apertar Enter
continua).
getic:install não instala a paleta — os dois comandos são independentes; rode
crud:install-palette quando quiser.
🎨 Paleta de Cores
As paletas mudam só o acento da interface: --primary, --primary-foreground,
--ring, --sidebar-primary, --sidebar-primary-foreground, --sidebar-ring,
--chart-1, --chart-2 e --chart-3. Nenhuma variável de superfície entra — cor de fundo
e de texto continuam do starter kit, que já acerta o contraste nos dois modos.
O claro/escuro não é do pacote: continua sendo a classe .dark que o starter kit já
gerencia. A paleta escreve só o atributo data-crud-palette no <html> e guarda a escolha
em localStorage — as duas dimensões, cor e modo, são independentes uma da outra.
Instalação
php artisan crud:install-palette
O comando escreve três arquivos e edita três:
| Arquivo | O que acontece |
|---|---|
resources/css/crud-palettes.css |
Criado — as paletas, como seletores :root[data-crud-palette='x'] |
resources/js/lib/crud-palette.ts |
Criado — a lista de paletas e a função que aplica o atributo |
Seletor da stack — crud-palette-selector.tsx (react), CrudPaletteSelector.vue (vue) ou CrudPaletteSelector.svelte (svelte) |
Criado |
resources/css/app.css |
Editado — acrescenta o @import das paletas |
Arquivo de entrada da stack (app.tsx ou app.ts) |
Editado — chama initializeCrudPalette() |
Página de aparência (settings/appearance) |
Editado — insere <CrudPaletteSelector /> numa região marcada |
Rodar de novo é seguro: cada edição é idempotente, e nada é duplicado. Quando o comando não reconhece o arquivo (versão do starter kit fora do padrão, edição manual que mudou a âncora esperada), ele não escreve — avisa e imprime o trecho para você colar à mão.
Desligue a inserção automática do seletor na página de aparência com:
// config/crud.php 'palette' => [ 'settings_page' => false, ],
O pacote guarda a escolha só em localStorage. A paleta é aplicada no arquivo de entrada
(initializeCrudPalette(), chamado no mesmo ponto onde o starter kit já chama
initializeTheme()), então pode haver um piscar breve da paleta padrão no primeiro
carregamento — só o acento muda de cor por um instante, o fundo e o texto não invertem.
Se isso incomodar, dá para eliminar gravando a preferência também num cookie e renderizando
o atributo data-crud-palette direto no HTML inicial (app.blade.php), mas isso é por sua
conta: o pacote não grava cookie nenhum hoje.
Criar uma paleta nova
php artisan crud:create-palette minha-paleta
📋 Comandos Disponíveis
# Instalar a camada de paleta php artisan crud:install-palette # Criar uma paleta nova php artisan crud:create-palette {nome} # Gerar CRUD completo php artisan getic:install {tabela} # Com relacionamentos php artisan getic:install {tabela} --relationship # Escolhendo o helper de rotas dos componentes React (default: auto) php artisan getic:install {tabela} --routes=wayfinder
🎯 Exemplo de Uso Completo
1. Instalação e Configuração
# Instalar pacote composer require josenildotiago/crud # Instalar a camada de paleta php artisan crud:install-palette # Criar uma paleta personalizada php artisan crud:create-palette corporativo
2. Gerar CRUD para Produtos
php artisan getic:install products
3. Resultado Gerado
Controller (app/Http/Controllers/ProductController.php)
class ProductController extends Controller { public function index(Request $request): InertiaResponse { $products = Product::query() ->when($request->search, function ($query, $search) { $query->where('name', 'like', "%{$search}%") ->orWhere('description', 'like', "%{$search}%"); }) ->orderBy('created_at', 'desc') ->paginate(10) ->withQueryString() ->through(fn ($product) => [ 'id' => $product->id, 'name' => $product->name, 'description' => $product->description, 'price' => $product->price, 'created_at' => $product->created_at->format('d/m/Y H:i'), 'updated_at' => $product->updated_at->format('d/m/Y H:i'), ]); return Inertia::render('Product/Index', [ 'products' => $products, 'filters' => ['search' => $request->search], ]); } }
Componente React (resources/js/pages/Product/Create.tsx)
export default function Create() { const { data, setData, post, processing, errors } = useForm({ name: "", description: "", price: "", }); return ( <AppLayout breadcrumbs={breadcrumbs}> <Head title="Criar Produto" /> <form onSubmit={handleSubmit}> <Card className="container mx-auto py-8"> <CardHeader> <CardTitle className="uppercase">Cadastrar novo produto</CardTitle> <CardDescription>Cadastre um novo produto</CardDescription> </CardHeader> <CardContent className="container"> <div className="mt-2 grid grid-cols-1 gap-2 sm:grid-cols-12"> <div className="sm:col-span-12"> <Label htmlFor="name">Nome:</Label> <Input placeholder="Digite o nome" value={data.name} onChange={(e) => setData("name", e.target.value)} required /> {errors.name && ( <p className="text-sm text-red-500 mt-1">{errors.name}</p> )} </div> {/* Outros campos gerados automaticamente */} </div> </CardContent> <CardFooter className="flex-col gap-2"> <Button disabled={processing} className="w-full"> {processing && <LoaderCircle className="h-4 w-4 animate-spin" />} Cadastrar </Button> </CardFooter> </Card> </form> </AppLayout> ); }
Rotas (routes/product.php)
<?php use App\Http\Controllers\ProductController; use Illuminate\Support\Facades\Route; Route::middleware(['auth', 'verified'])->group(function () { Route::get('/products', [ProductController::class, 'index'])->name('products.index'); Route::get('/products/create', [ProductController::class, 'create'])->name('products.create'); Route::post('/products', [ProductController::class, 'store'])->name('products.store'); // Precisa vir antes da rota curinga abaixo, senão `bulk-destroy` é lido como {product}. Route::delete('/products/bulk-destroy', [ProductController::class, 'bulkDestroy'])->name('products.bulk-destroy'); Route::get('/products/{product}', [ProductController::class, 'show'])->name('products.show'); Route::get('/products/{product}/edit', [ProductController::class, 'edit'])->name('products.edit'); Route::put('/products/{product}', [ProductController::class, 'update'])->name('products.update'); Route::delete('/products/{product}', [ProductController::class, 'destroy'])->name('products.destroy'); });
🔧 Configuração Avançada
Arquivo de Configuração
Publique e customize as configurações:
php artisan vendor:publish --provider="Crud\CrudServiceProvider" --tag="crud-config"
Arquivo config/crud.php:
Um recorte das chaves que mais se mexe — o arquivo publicado traz todas, comentadas:
return [ 'frontend' => 'react', // blade, react, vue 'inertia' => [ 'enabled' => true, 'components_path' => 'js/pages', 'layout_component' => 'Layouts/AuthenticatedLayout', // 'auto' usa wayfinder se estiver instalado, senão o route() do Ziggy. // Também aceita 'wayfinder' e 'ziggy'. A flag --routes= sobrepõe. 'route_helper' => 'auto', ], // Em false, o pacote nunca toca no arquivo de navegação do projeto. 'navigation' => [ 'sidebar' => true, ], // Em false, `crud:install-palette` não insere o seletor na página de aparência. 'palette' => [ 'settings_page' => true, ], ];
📱 Características da Interface
Componentes shadcn/ui
- Cards: Layout moderno com header, content e footer
- Buttons: Com estados de loading e ícones
- Inputs: Com labels e validação integrada
- Tables: Responsivas com paginação
- Forms: Grid responsivo e validação em tempo real
Design Responsivo
- Mobile-first: Otimizado para dispositivos móveis
- Grid System: sm:grid-cols-12 para layout flexível
- Breakpoints: Tailwind CSS responsivo
- Touch-friendly: Interface amigável ao toque
🚀 Performance
Otimizações
- Lazy Loading: Componentes carregados sob demanda
- Code Splitting: Divisão automática de código
- CSS Optimization: Custom properties para a paleta de cores
- Database Queries: Queries otimizadas com Eloquent
Caching
- Template Caching: Stubs em cache durante desenvolvimento
- Query Caching: Colunas de banco em cache
- Asset Optimization: CSS e JS otimizados para produção
🧪 Testes
Execute os testes do pacote:
vendor/bin/phpunit
# ou
vendor/bin/pest
Cobertura
- Unit Tests: Commands, Manager, Generator
- Integration Tests: Geração completa de CRUD
- Component Tests: Paleta e componentes React
📚 Documentação Adicional
- Documentação Técnica: Arquitetura detalhada do sistema
- Changelog: Histórico de versões e mudanças
- Contribuição: Como contribuir para o projeto
🤝 Contribuição
Contribuições são bem-vindas! Por favor, leia o guia de contribuição para detalhes sobre nosso código de conduta e o processo para enviar pull requests.
📄 Licença
Este projeto está licenciado sob a Licença MIT - veja o arquivo LICENSE para detalhes.
🆘 Suporte
Se você encontrar algum problema ou tiver dúvidas:
- Issues: Abra uma issue no GitHub
- Discussões: Use as discussões do GitHub para perguntas
- Email: josenildo.tiago.designer@gmail.com
🎉 Créditos
Desenvolvido com ❤️ por Josenildo Tiago
Tecnologias Utilizadas
- Laravel 12: Framework PHP moderno
- React.js: Biblioteca JavaScript para UI
- Inertia.js: Stack moderno sem API
- TypeScript: JavaScript tipado
- shadcn/ui: Componentes React modernos
- Tailwind CSS: Framework CSS utility-first
- OKLCH: Espaço de cor moderno