feat: orgaos page integrated with real API
This commit is contained in:
1
back-end
Submodule
1
back-end
Submodule
Submodule back-end added at 6480a285f5
@@ -1,43 +1,426 @@
|
|||||||
<!-- front-end/app/pages/gestao/orgaos.vue -->
|
<!-- front-end/app/pages/gestao/orgaos.vue -->
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { orgaos } from '~/data/mock/orgaos'
|
const { apiFetch } = useApi()
|
||||||
|
|
||||||
const esferaLabel = { federal: 'Federal', estadual: 'Estadual', municipal: 'Municipal' }
|
interface ApiOrgan {
|
||||||
const columns = [
|
ID: string
|
||||||
{ id: 'nome', accessorKey: 'nome', header: 'Órgão' },
|
Nome: string
|
||||||
{ id: 'esfera', accessorKey: 'esfera', header: 'Esfera' },
|
Esfera: string
|
||||||
{ id: 'estado', accessorKey: 'estado', header: 'UF' },
|
Estado: string
|
||||||
{ id: 'totalParticipacoes', accessorKey: 'totalParticipacoes', header: 'Participações' },
|
Site: string
|
||||||
{ id: 'totalVitorias', accessorKey: 'totalVitorias', header: 'Vitórias' },
|
Telefone: string
|
||||||
{ id: 'taxaVitoria', accessorKey: 'taxaVitoria', header: 'Taxa' },
|
Email: string
|
||||||
]
|
Observacoes: string
|
||||||
|
CreatedAt: string
|
||||||
|
}
|
||||||
|
|
||||||
const dados = computed(() => orgaos.map(o => ({
|
const { data: orgaos, refresh } = await useAsyncData('orgaos', () =>
|
||||||
...o,
|
apiFetch<ApiOrgan[]>('/organs')
|
||||||
taxaVitoria: o.totalParticipacoes > 0 ? `${Math.round((o.totalVitorias / o.totalParticipacoes) * 100)}%` : '0%',
|
)
|
||||||
})))
|
|
||||||
|
// --- Menu dropdown ---
|
||||||
|
const openMenuId = ref<string | null>(null)
|
||||||
|
const menuPos = ref({ top: 0, right: 0 })
|
||||||
|
|
||||||
|
function toggleMenu(id: string, event: MouseEvent) {
|
||||||
|
if (openMenuId.value === id) {
|
||||||
|
openMenuId.value = null
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const btn = event.currentTarget as HTMLElement
|
||||||
|
const rect = btn.getBoundingClientRect()
|
||||||
|
menuPos.value = {
|
||||||
|
top: rect.bottom + window.scrollY + 4,
|
||||||
|
right: window.innerWidth - rect.right,
|
||||||
|
}
|
||||||
|
openMenuId.value = id
|
||||||
|
}
|
||||||
|
const closeMenu = () => { openMenuId.value = null }
|
||||||
|
onMounted(() => document.addEventListener('click', closeMenu))
|
||||||
|
onUnmounted(() => document.removeEventListener('click', closeMenu))
|
||||||
|
|
||||||
|
// --- Modal Criar ---
|
||||||
|
const showCreate = ref(false)
|
||||||
|
const createForm = reactive({
|
||||||
|
nome: '', esfera: 'federal', estado: '',
|
||||||
|
site: '', telefone: '', email: '', observacoes: '',
|
||||||
|
})
|
||||||
|
const createError = ref('')
|
||||||
|
const createLoading = ref(false)
|
||||||
|
|
||||||
|
async function criarOrgao() {
|
||||||
|
createError.value = ''
|
||||||
|
createLoading.value = true
|
||||||
|
try {
|
||||||
|
await apiFetch('/organs', { method: 'POST', body: { ...createForm } })
|
||||||
|
showCreate.value = false
|
||||||
|
Object.assign(createForm, { nome: '', esfera: 'federal', estado: '', site: '', telefone: '', email: '', observacoes: '' })
|
||||||
|
await refresh()
|
||||||
|
} catch (err: any) {
|
||||||
|
createError.value = err?.data?.error || 'Erro ao criar órgão.'
|
||||||
|
} finally {
|
||||||
|
createLoading.value = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- Modal Editar ---
|
||||||
|
const showEdit = ref(false)
|
||||||
|
const editOrgao = ref<ApiOrgan | null>(null)
|
||||||
|
const editForm = reactive({
|
||||||
|
nome: '', esfera: 'federal', estado: '',
|
||||||
|
site: '', telefone: '', email: '', observacoes: '',
|
||||||
|
})
|
||||||
|
const editError = ref('')
|
||||||
|
const editLoading = ref(false)
|
||||||
|
|
||||||
|
function abrirEditar(o: ApiOrgan) {
|
||||||
|
editOrgao.value = o
|
||||||
|
Object.assign(editForm, {
|
||||||
|
nome: o.Nome, esfera: o.Esfera, estado: o.Estado,
|
||||||
|
site: o.Site, telefone: o.Telefone, email: o.Email, observacoes: o.Observacoes,
|
||||||
|
})
|
||||||
|
editError.value = ''
|
||||||
|
showEdit.value = true
|
||||||
|
}
|
||||||
|
|
||||||
|
async function salvarEdicao() {
|
||||||
|
if (!editOrgao.value) return
|
||||||
|
editError.value = ''
|
||||||
|
editLoading.value = true
|
||||||
|
try {
|
||||||
|
await apiFetch(`/organs/${editOrgao.value.ID}`, { method: 'PUT', body: { ...editForm } })
|
||||||
|
showEdit.value = false
|
||||||
|
await refresh()
|
||||||
|
} catch (err: any) {
|
||||||
|
editError.value = err?.data?.error || 'Erro ao salvar.'
|
||||||
|
} finally {
|
||||||
|
editLoading.value = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- Modal Confirmação Exclusão ---
|
||||||
|
const showDeleteConfirm = ref(false)
|
||||||
|
const deleteTarget = ref<ApiOrgan | null>(null)
|
||||||
|
const deletingId = ref<string | null>(null)
|
||||||
|
|
||||||
|
function pedirExclusao(o: ApiOrgan) {
|
||||||
|
deleteTarget.value = o
|
||||||
|
showDeleteConfirm.value = true
|
||||||
|
}
|
||||||
|
|
||||||
|
async function confirmarExclusao() {
|
||||||
|
if (!deleteTarget.value) return
|
||||||
|
deletingId.value = deleteTarget.value.ID
|
||||||
|
try {
|
||||||
|
await apiFetch(`/organs/${deleteTarget.value.ID}`, { method: 'DELETE' })
|
||||||
|
showDeleteConfirm.value = false
|
||||||
|
deleteTarget.value = null
|
||||||
|
await refresh()
|
||||||
|
} catch {}
|
||||||
|
deletingId.value = null
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- Helpers ---
|
||||||
|
const esferaLabel: Record<string, string> = {
|
||||||
|
federal: 'Federal',
|
||||||
|
estadual: 'Estadual',
|
||||||
|
municipal: 'Municipal',
|
||||||
|
}
|
||||||
|
const esferaBadgeClass: Record<string, string> = {
|
||||||
|
federal: 'badge-federal',
|
||||||
|
estadual: 'badge-estadual',
|
||||||
|
municipal: 'badge-municipal',
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="page">
|
<div class="page">
|
||||||
<AppTopbar title="Órgãos Públicos" breadcrumb="Gestão · Órgãos">
|
<AppTopbar title="Órgãos Públicos" breadcrumb="Gestão · Órgãos">
|
||||||
<template #actions>
|
<template #actions>
|
||||||
<UButton size="sm" class="btn-primary">+ Adicionar Órgão</UButton>
|
<UButton size="sm" class="btn-primary" @click="showCreate = true">+ Adicionar Órgão</UButton>
|
||||||
</template>
|
</template>
|
||||||
</AppTopbar>
|
</AppTopbar>
|
||||||
|
|
||||||
<div class="content">
|
<div class="content">
|
||||||
<div class="card">
|
<div class="card">
|
||||||
<UTable :data="dados" :columns="columns">
|
<table class="table">
|
||||||
<template #esfera-cell="{ row }">{{ esferaLabel[row.original.esfera] }}</template>
|
<thead>
|
||||||
</UTable>
|
<tr>
|
||||||
|
<th>Órgão</th>
|
||||||
|
<th>Esfera</th>
|
||||||
|
<th>UF</th>
|
||||||
|
<th>Contato</th>
|
||||||
|
<th style="width:48px"></th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr v-if="!orgaos?.length">
|
||||||
|
<td colspan="5" class="empty">Nenhum órgão cadastrado.</td>
|
||||||
|
</tr>
|
||||||
|
<tr v-for="o in orgaos" :key="o.ID">
|
||||||
|
<td class="td-nome">{{ o.Nome }}</td>
|
||||||
|
<td><span :class="['badge', esferaBadgeClass[o.Esfera]]">{{ esferaLabel[o.Esfera] }}</span></td>
|
||||||
|
<td>{{ o.Estado }}</td>
|
||||||
|
<td class="td-contato">
|
||||||
|
<span v-if="o.Email">{{ o.Email }}</span>
|
||||||
|
<span v-else-if="o.Telefone">{{ o.Telefone }}</span>
|
||||||
|
<span v-else class="muted">—</span>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<button class="menu-btn" @click.stop="toggleMenu(o.ID, $event)">⋯</button>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- Dropdown menu (Teleport para escapar do overflow da tabela) -->
|
||||||
|
<Teleport to="body">
|
||||||
|
<div
|
||||||
|
v-if="openMenuId"
|
||||||
|
class="dropdown-fixed"
|
||||||
|
:style="{ top: menuPos.top + 'px', right: menuPos.right + 'px' }"
|
||||||
|
@click.stop
|
||||||
|
>
|
||||||
|
<button @click="abrirEditar(orgaos!.find(o => o.ID === openMenuId)!); closeMenu()">Editar</button>
|
||||||
|
<button class="danger" @click="pedirExclusao(orgaos!.find(o => o.ID === openMenuId)!); closeMenu()">Excluir</button>
|
||||||
|
</div>
|
||||||
|
</Teleport>
|
||||||
|
|
||||||
|
<!-- Modal Criar -->
|
||||||
|
<Teleport to="body">
|
||||||
|
<div v-if="showCreate" class="modal-overlay" @click.self="showCreate = false">
|
||||||
|
<div class="modal">
|
||||||
|
<div class="modal-header">
|
||||||
|
<h2>Novo Órgão</h2>
|
||||||
|
<button class="close-btn" @click="showCreate = false">✕</button>
|
||||||
|
</div>
|
||||||
|
<div class="modal-body">
|
||||||
|
<div class="form-row">
|
||||||
|
<div class="form-group full">
|
||||||
|
<label>Nome *</label>
|
||||||
|
<input v-model="createForm.nome" placeholder="Ex: Ministério da Saúde" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-row">
|
||||||
|
<div class="form-group">
|
||||||
|
<label>Esfera *</label>
|
||||||
|
<select v-model="createForm.esfera">
|
||||||
|
<option value="federal">Federal</option>
|
||||||
|
<option value="estadual">Estadual</option>
|
||||||
|
<option value="municipal">Municipal</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label>UF *</label>
|
||||||
|
<input v-model="createForm.estado" placeholder="Ex: DF" maxlength="2" style="text-transform:uppercase" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-row">
|
||||||
|
<div class="form-group">
|
||||||
|
<label>Telefone</label>
|
||||||
|
<input v-model="createForm.telefone" placeholder="(61) 3000-0000" />
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label>E-mail</label>
|
||||||
|
<input v-model="createForm.email" type="email" placeholder="contato@orgao.gov.br" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-row">
|
||||||
|
<div class="form-group full">
|
||||||
|
<label>Site</label>
|
||||||
|
<input v-model="createForm.site" placeholder="https://www.orgao.gov.br" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-row">
|
||||||
|
<div class="form-group full">
|
||||||
|
<label>Observações</label>
|
||||||
|
<textarea v-model="createForm.observacoes" rows="3" placeholder="Informações adicionais..."></textarea>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<p v-if="createError" class="error-msg">{{ createError }}</p>
|
||||||
|
</div>
|
||||||
|
<div class="modal-footer">
|
||||||
|
<button class="btn-cancel" @click="showCreate = false">Cancelar</button>
|
||||||
|
<button class="btn-save" :disabled="createLoading" @click="criarOrgao">
|
||||||
|
{{ createLoading ? 'Salvando...' : 'Criar Órgão' }}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</Teleport>
|
||||||
|
|
||||||
|
<!-- Modal Editar -->
|
||||||
|
<Teleport to="body">
|
||||||
|
<div v-if="showEdit" class="modal-overlay" @click.self="showEdit = false">
|
||||||
|
<div class="modal">
|
||||||
|
<div class="modal-header">
|
||||||
|
<h2>Editar Órgão</h2>
|
||||||
|
<button class="close-btn" @click="showEdit = false">✕</button>
|
||||||
|
</div>
|
||||||
|
<div class="modal-body">
|
||||||
|
<div class="form-row">
|
||||||
|
<div class="form-group full">
|
||||||
|
<label>Nome *</label>
|
||||||
|
<input v-model="editForm.nome" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-row">
|
||||||
|
<div class="form-group">
|
||||||
|
<label>Esfera *</label>
|
||||||
|
<select v-model="editForm.esfera">
|
||||||
|
<option value="federal">Federal</option>
|
||||||
|
<option value="estadual">Estadual</option>
|
||||||
|
<option value="municipal">Municipal</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label>UF *</label>
|
||||||
|
<input v-model="editForm.estado" maxlength="2" style="text-transform:uppercase" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-row">
|
||||||
|
<div class="form-group">
|
||||||
|
<label>Telefone</label>
|
||||||
|
<input v-model="editForm.telefone" />
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label>E-mail</label>
|
||||||
|
<input v-model="editForm.email" type="email" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-row">
|
||||||
|
<div class="form-group full">
|
||||||
|
<label>Site</label>
|
||||||
|
<input v-model="editForm.site" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-row">
|
||||||
|
<div class="form-group full">
|
||||||
|
<label>Observações</label>
|
||||||
|
<textarea v-model="editForm.observacoes" rows="3"></textarea>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<p v-if="editError" class="error-msg">{{ editError }}</p>
|
||||||
|
</div>
|
||||||
|
<div class="modal-footer">
|
||||||
|
<button class="btn-cancel" @click="showEdit = false">Cancelar</button>
|
||||||
|
<button class="btn-save" :disabled="editLoading" @click="salvarEdicao">
|
||||||
|
{{ editLoading ? 'Salvando...' : 'Salvar' }}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</Teleport>
|
||||||
|
|
||||||
|
<!-- Modal Confirmação Exclusão -->
|
||||||
|
<Teleport to="body">
|
||||||
|
<div v-if="showDeleteConfirm" class="modal-overlay" @click.self="showDeleteConfirm = false">
|
||||||
|
<div class="modal modal-sm">
|
||||||
|
<div class="modal-header">
|
||||||
|
<h2>Excluir Órgão</h2>
|
||||||
|
<button class="close-btn" @click="showDeleteConfirm = false">✕</button>
|
||||||
|
</div>
|
||||||
|
<div class="modal-body">
|
||||||
|
<p>Tem certeza que deseja excluir <strong>{{ deleteTarget?.Nome }}</strong>?</p>
|
||||||
|
<p class="muted" style="margin-top:8px">Esta ação não pode ser desfeita.</p>
|
||||||
|
</div>
|
||||||
|
<div class="modal-footer">
|
||||||
|
<button class="btn-cancel" @click="showDeleteConfirm = false">Cancelar</button>
|
||||||
|
<button class="btn-danger" :disabled="!!deletingId" @click="confirmarExclusao">
|
||||||
|
{{ deletingId ? 'Excluindo...' : 'Excluir' }}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</Teleport>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
.page { display: flex; flex-direction: column; height: 100vh; }
|
.page { display: flex; flex-direction: column; height: 100vh; }
|
||||||
.content { padding: 20px 22px; flex: 1; overflow-y: auto; }
|
.content { padding: 20px 22px; flex: 1; overflow-y: auto; }
|
||||||
.card { background: white; border-radius: 11px; border: 1px solid #e2e8f0; overflow: hidden; }
|
.card { background: white; border-radius: 11px; border: 1px solid #e2e8f0; overflow: visible; }
|
||||||
.btn-primary { background: linear-gradient(135deg, #667eea, #764ba2) !important; }
|
.btn-primary { background: linear-gradient(135deg, #667eea, #764ba2) !important; }
|
||||||
|
|
||||||
|
.table { width: 100%; border-collapse: collapse; font-size: 14px; }
|
||||||
|
.table th { padding: 12px 16px; text-align: left; font-size: 12px; font-weight: 600; color: #64748b; text-transform: uppercase; letter-spacing: .05em; border-bottom: 1px solid #e2e8f0; background: #f8fafc; }
|
||||||
|
.table td { padding: 13px 16px; border-bottom: 1px solid #f1f5f9; color: #1e293b; vertical-align: middle; }
|
||||||
|
.table tr:last-child td { border-bottom: none; }
|
||||||
|
.table tr:hover td { background: #f8fafc; }
|
||||||
|
|
||||||
|
.td-nome { font-weight: 500; }
|
||||||
|
.td-contato { color: #64748b; font-size: 13px; }
|
||||||
|
.muted { color: #94a3b8; }
|
||||||
|
.empty { text-align: center; color: #94a3b8; padding: 40px; }
|
||||||
|
|
||||||
|
.badge { display: inline-block; padding: 3px 10px; border-radius: 99px; font-size: 12px; font-weight: 500; }
|
||||||
|
.badge-federal { background: #dbeafe; color: #1d4ed8; }
|
||||||
|
.badge-estadual { background: #dcfce7; color: #16a34a; }
|
||||||
|
.badge-municipal{ background: #ffedd5; color: #c2410c; }
|
||||||
|
|
||||||
|
.menu-btn { background: none; border: none; cursor: pointer; font-size: 18px; color: #94a3b8; padding: 4px 8px; border-radius: 6px; line-height: 1; }
|
||||||
|
.menu-btn:hover { background: #f1f5f9; color: #475569; }
|
||||||
|
|
||||||
|
/* Modais */
|
||||||
|
.modal-overlay { position: fixed; inset: 0; background: rgba(0,0,0,.45); display: flex; align-items: center; justify-content: center; z-index: 1000; }
|
||||||
|
.modal { background: white; border-radius: 12px; width: 560px; max-width: 95vw; box-shadow: 0 20px 60px rgba(0,0,0,.2); }
|
||||||
|
.modal-sm { width: 400px; }
|
||||||
|
.modal-header { display: flex; align-items: center; justify-content: space-between; padding: 20px 24px 16px; border-bottom: 1px solid #e2e8f0; }
|
||||||
|
.modal-header h2 { font-size: 17px; font-weight: 600; margin: 0; color: #1e293b; }
|
||||||
|
.close-btn { background: none; border: none; font-size: 16px; cursor: pointer; color: #94a3b8; padding: 4px; }
|
||||||
|
.close-btn:hover { color: #475569; }
|
||||||
|
.modal-body { padding: 20px 24px; }
|
||||||
|
.modal-footer { padding: 16px 24px 20px; display: flex; justify-content: flex-end; gap: 10px; border-top: 1px solid #f1f5f9; }
|
||||||
|
|
||||||
|
.form-row { display: flex; gap: 14px; margin-bottom: 14px; }
|
||||||
|
.form-group { display: flex; flex-direction: column; gap: 5px; flex: 1; }
|
||||||
|
.form-group.full { flex: 1 1 100%; }
|
||||||
|
.form-group label { font-size: 13px; font-weight: 500; color: #374151; }
|
||||||
|
.form-group input, .form-group select, .form-group textarea {
|
||||||
|
border: 1px solid #d1d5db; border-radius: 7px; padding: 8px 11px;
|
||||||
|
font-size: 14px; color: #1e293b; outline: none; width: 100%; box-sizing: border-box;
|
||||||
|
font-family: inherit;
|
||||||
|
}
|
||||||
|
.form-group input:focus, .form-group select:focus, .form-group textarea:focus { border-color: #667eea; box-shadow: 0 0 0 3px rgba(102,126,234,.15); }
|
||||||
|
.form-group textarea { resize: vertical; }
|
||||||
|
.error-msg { color: #ef4444; font-size: 13px; margin-top: 8px; }
|
||||||
|
|
||||||
|
.btn-cancel { padding: 8px 18px; border: 1px solid #e2e8f0; border-radius: 7px; background: white; cursor: pointer; font-size: 14px; color: #64748b; }
|
||||||
|
.btn-cancel:hover { background: #f8fafc; }
|
||||||
|
.btn-save { padding: 8px 20px; border: none; border-radius: 7px; background: linear-gradient(135deg,#667eea,#764ba2); color: white; cursor: pointer; font-size: 14px; font-weight: 500; }
|
||||||
|
.btn-save:hover:not(:disabled) { opacity: .9; }
|
||||||
|
.btn-save:disabled { opacity: .6; cursor: not-allowed; }
|
||||||
|
.btn-danger { padding: 8px 20px; border: none; border-radius: 7px; background: #ef4444; color: white; cursor: pointer; font-size: 14px; font-weight: 500; }
|
||||||
|
.btn-danger:hover:not(:disabled) { background: #dc2626; }
|
||||||
|
.btn-danger:disabled { opacity: .6; cursor: not-allowed; }
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<!-- CSS global para o dropdown teleportado (não pode ser scoped) -->
|
||||||
|
<style>
|
||||||
|
.dropdown-fixed {
|
||||||
|
position: fixed;
|
||||||
|
z-index: 9999;
|
||||||
|
background: white;
|
||||||
|
border: 1px solid #e2e8f0;
|
||||||
|
border-radius: 8px;
|
||||||
|
box-shadow: 0 4px 20px rgba(0,0,0,.12);
|
||||||
|
min-width: 140px;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
.dropdown-fixed button {
|
||||||
|
display: block;
|
||||||
|
width: 100%;
|
||||||
|
padding: 9px 16px;
|
||||||
|
text-align: left;
|
||||||
|
background: none;
|
||||||
|
border: none;
|
||||||
|
cursor: pointer;
|
||||||
|
font-size: 14px;
|
||||||
|
color: #1e293b;
|
||||||
|
}
|
||||||
|
.dropdown-fixed button:hover { background: #f8fafc; }
|
||||||
|
.dropdown-fixed button.danger { color: #ef4444; }
|
||||||
|
.dropdown-fixed button.danger:hover { background: #fef2f2; }
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
Reference in New Issue
Block a user