CrudLayout
Visão geral
O componente LxCrudLayout fornece uma estrutura completa para páginas de listagem e cadastro (CRUD). Ele encapsula o cabeçalho com título e área de ações, uma toolbar com campo de busca e botão de cadastrar, gerenciamento de estado vazio e de carregamento (skeleton), e uma área de extras (modais, sidebars) integrada.
Todos os blocos estruturais possuem slots de override total: ao fornecer o slot correspondente (header, content, toolbar, extra), o conteúdo padrão é completamente substituído pelo fornecido.
Usuários
Gerencie os usuários do sistema.
Clique para visualizar o código
vue
<script setup lang="ts">
import { ref, computed } from 'vue';
import { LxCrudLayout, LxDataTable, LxDataTableColumn, LxInputText, LxComboBox, LxModal } from '@lde/lxcomponents';
import type { User, RoleOption, FormData } from './types';
const loading = ref(false);
const modalLoading = ref(false);
const searchQuery = ref('');
const allUsers = ref<User[]>([
{ id: 1, name: 'Ana Souza', email: 'ana.souza@exemplo.com', role: 'Administrador' },
{ id: 2, name: 'Bruno Costa', email: 'bruno.costa@exemplo.com', role: 'Editor' },
{ id: 3, name: 'Carla Mendes', email: 'carla.mendes@exemplo.com', role: 'Visualizador' }
]);
const filteredUsers = computed(() => {
if (!searchQuery.value) return allUsers.value;
const lower = searchQuery.value.toLowerCase();
return allUsers.value.filter((u) => u.name.toLowerCase().includes(lower) || u.email.toLowerCase().includes(lower) || u.role.toLowerCase().includes(lower));
});
const isEmpty = computed(() => filteredUsers.value.length === 0);
const roleOptions = ref<RoleOption[]>([{ label: 'Administrador' }, { label: 'Editor' }, { label: 'Visualizador' }]);
const form = ref<FormData>({ name: '', email: '', role: { label: 'Visualizador' } });
const simulateLoading = () => {
loading.value = true;
setTimeout(() => {
loading.value = false;
}, 2000);
};
const handleSearch = (value: string) => {
searchQuery.value = value;
};
const handleModalConfirm = (closeModal: () => void) => {
modalLoading.value = true;
setTimeout(() => {
if (form.value.name && form.value.email) {
allUsers.value.push({ id: Date.now(), name: form.value.name, email: form.value.email, role: form.value.role?.label ?? '' });
}
form.value = { name: '', email: '', role: { label: 'Visualizador' } };
modalLoading.value = false;
closeModal();
}, 1000);
};
</script>
<template>
<LxCrudLayout
id="example-crud"
title="Usuários"
description="Gerencie os usuários do sistema."
add-label="Novo usuário"
:loading="loading"
:is-empty="isEmpty"
:search-config="{ placeholder: 'Buscar por nome, e-mail ou papel...' }"
:empty-state-config="{
icon: 'fas fa-users',
title: 'Nenhum usuário encontrado.',
description: 'Cadastre o primeiro usuário ou revise o filtro de busca.'
}"
@search="handleSearch"
>
<template #header-actions>
<button class="btn btn-secondary btn-sm" @click="simulateLoading">Simular carregamento</button>
</template>
<template #table>
<LxDataTable id="users-table" :value="filteredUsers" data-key="id">
<LxDataTableColumn field="name" header="Nome" />
<LxDataTableColumn field="email" header="E-mail" />
<LxDataTableColumn field="role" header="Papel" />
</LxDataTable>
</template>
<template #modal="{ modalVisible, closeModal }">
<LxModal
v-if="modalVisible"
title="Novo usuário"
:loading="modalLoading"
:btn-confirm="{ label: 'Salvar usuário' }"
@close="closeModal"
@confirm="handleModalConfirm(closeModal)"
>
<template #content>
<LxInputText id="form-name" v-model="form.name" label="Nome" placeholder="Nome completo" />
<LxInputText id="form-email" v-model="form.email" label="E-mail" placeholder="email@exemplo.com" />
<LxComboBox id="form-role" v-model="form.role" label="Papel" :options="roleOptions" options-label="label" open-direction="top" />
</template>
</LxModal>
</template>
</LxCrudLayout>
</template>Propriedades
| Nome | Descrição | Tipo | Padrão |
|---|---|---|---|
| id | ID raiz do componente | String | 'lx-crud-layout' |
| title | Título exibido no cabeçalho. Obrigatório. | String | — |
| description | Descrição exibida abaixo do título | String | undefined |
| docsUrl | URL da documentação — quando informado, exibe um botão de atalho para a documentação | String | undefined |
| loading | Indica estado de carregamento; exibe o skeleton LxGridLoading | Boolean | false |
| addLabel | Rótulo do botão de adicionar na toolbar e no estado vazio | String | 'Cadastrar' |
| addIcon | Ícone FontAwesome do botão de adicionar | String | 'fas fa-plus' |
| showAddButton | Exibe ou oculta o botão de adicionar na toolbar e no estado vazio | Boolean | true |
| isEmpty | Quando true, exibe o estado vazio em lugar da tabela | Boolean | false |
| searchConfig | Configuração do campo de busca. Ver SearchConfig | SearchConfig | {} |
| emptyStateConfig | Configuração do estado vazio. Ver EmptyStateConfig | EmptyStateConfig | {} |
SearchConfig
| Nome | Descrição | Tipo | Padrão |
|---|---|---|---|
| placeholder | Placeholder do input de busca | String | 'Buscar...' |
| label | Rótulo (label) do input de busca | String | '' |
| show | Exibe ou oculta o campo de busca | Boolean | true |
EmptyStateConfig
| Nome | Descrição | Tipo | Padrão |
|---|---|---|---|
| icon | Classe do ícone FontAwesome | String | 'fas fa-inbox' |
| title | Título exibido no estado vazio | String | 'Nenhum registro encontrado.' |
| description | Descrição exibida abaixo do título no estado vazio | String | undefined |
| buttonLabel | Rótulo do botão de CTA no estado vazio. Padrão: igual ao addLabel | String | undefined |
| showButton | Exibe ou oculta o botão de CTA no estado vazio | Boolean | true |
Eventos
| Nome | Descrição | Payload |
|---|---|---|
| add:click | Emitido quando o botão de adicionar é clicado | — |
| search | Emitido quando o usuário realiza uma busca | string |
Slots
Slots de override total
Quando fornecidos, substituem completamente o bloco padrão correspondente do LxBaseLayout.
| Nome | Escopo | Descrição |
|---|---|---|
| header | — | Substitui todo o cabeçalho padrão (título + ações) |
| content | — | Substitui toda a área de conteúdo (toolbar + body) |
| footer | — | Substitui o rodapé padrão. Só é renderizado quando o slot é fornecido |
| extra | — | Substitui a área de extras (modais, sidebars). Fallback: slot modal |
Slots de composição interna
Funcionam quando os slots de override acima não são fornecidos, permitindo customização pontual dentro do layout padrão.
| Nome | Escopo | Descrição |
|---|---|---|
| header-actions | — | Ações extras à direita do cabeçalho, ao lado do botão de docs |
| toolbar | — | Override total da toolbar; substitui busca + botão adicionar quando fornecido |
| toolbar-start | — | Conteúdo inserido no início da toolbar, antes do campo de busca |
| toolbar-actions | — | Ações extras no final da toolbar, após o botão de adicionar |
| table | { loading } | Slot principal para a tabela ou lista de registros |
| empty-state | — | Substitui completamente o estado vazio padrão |
| modal | { modalVisible: boolean, openModal: () => void, closeModal: () => void } | Área de extras para modais. Usa v-if="modalVisible" para exibir a modal e chama closeModal() para fechá-la. O estado é controlado internamente — aberto ao clicar em "Cadastrar" e fechado via closeModal. |
Classes Padrão
| Classe | Descrição |
|---|---|
| lx-crud-layout | Classe raiz do componente |
| lx-crud-layout__header | Contêiner do cabeçalho (título + ações) |
| lx-crud-layout__header-info | Área de título e descrição |
| lx-crud-layout__header-actions | Área de ações do cabeçalho |
| lx-crud-layout__title | Elemento <h1> do título |
| lx-crud-layout__description | Parágrafo de descrição |
| lx-crud-layout__toolbar | Contêiner da toolbar (busca + botão adicionar) |
| lx-crud-layout__search | Elemento do campo de busca |
| lx-crud-layout__content | Área de conteúdo principal (tabela / skeleton / estado vazio) |
| lx-crud-layout__content--empty | Modificador aplicado à área de conteúdo quando isEmpty é true |
| lx-crud-layout__empty-state | Contêiner do estado vazio padrão |
| lx-crud-layout__empty-icon | Ícone do estado vazio |
| lx-crud-layout__empty-title | Título do estado vazio |
| lx-crud-layout__empty-description | Descrição do estado vazio |
| lx-crud-layout__footer | Contêiner do rodapé |
LxComponents