Correcao Sidebar Classico e Rail, Correcao Layout, Ajuste de Breakpoint para Tailwind, Ajuste AppTopbar, Ajuste Menu PopOver, Recriado Paleta de Cores, Inserido algumas animações leves, Reajuste Cor items NOVOS da tabela, Drawer Ajuda Corrigido no Logout, Whatsapp, sms, email, recursos extras

This commit is contained in:
Leonardo
2026-03-24 21:26:58 -03:00
parent a89d1f5560
commit 53a4980396
453 changed files with 121427 additions and 174407 deletions

View File

@@ -15,212 +15,338 @@
|--------------------------------------------------------------------------
-->
<script setup>
import { computed, ref } from 'vue'
import { useRouter } from 'vue-router'
import { computed, nextTick, onMounted, onUnmounted, ref } from 'vue';
import { useRouter } from 'vue-router';
import Popover from 'primevue/popover'
import Popover from 'primevue/popover';
import { sessionUser, sessionRole } from '@/app/session'
import { supabase } from '@/lib/supabase/client'
import { useRoleGuard } from '@/composables/useRoleGuard'
import { sessionUser, sessionRole } from '@/app/session';
import { supabase } from '@/lib/supabase/client';
import { useRoleGuard } from '@/composables/useRoleGuard';
import { useLayout } from '@/layout/composables/layout';
import { useUserSettingsPersistence } from '@/composables/useUserSettingsPersistence';
import { useConfiguratorBar } from '@/layout/composables/useConfiguratorBar';
const props = defineProps({
variant: { type: String, default: 'sidebar' }
})
variant: { type: String, default: 'sidebar' }
});
const router = useRouter()
const pop = ref(null)
const router = useRouter();
const pop = ref(null);
const { role, canSee } = useRoleGuard()
const { role, canSee } = useRoleGuard();
const { toggleDarkMode, isDarkTheme } = useLayout();
const { init: initSettings, queuePatch } = useUserSettingsPersistence();
const { toggle: toggleThemeBar } = useConfiguratorBar();
onMounted(() => initSettings());
function isDarkNow() {
return document.documentElement.classList.contains('app-dark');
}
async function toggleDarkAndPersist() {
try {
toggleDarkMode();
await nextTick();
const theme_mode = isDarkNow() ? 'dark' : 'light';
await queuePatch({ theme_mode }, { flushNow: true });
} catch (e) {
console.error('[FooterPanel][theme] falhou:', e?.message || e);
}
}
const initials = computed(() => {
const name = sessionUser.value?.user_metadata?.full_name || sessionUser.value?.email || ''
const parts = String(name).trim().split(/\s+/).filter(Boolean)
const a = parts[0]?.[0] || 'U'
const b = parts.length > 1 ? parts[parts.length - 1][0] : ''
return (a + b).toUpperCase()
})
const name = sessionUser.value?.user_metadata?.full_name || sessionUser.value?.email || '';
const parts = String(name).trim().split(/\s+/).filter(Boolean);
const a = parts[0]?.[0] || 'U';
const b = parts.length > 1 ? parts[parts.length - 1][0] : '';
return (a + b).toUpperCase();
});
const label = computed(() => {
const name = sessionUser.value?.user_metadata?.full_name
return name || sessionUser.value?.email || 'Conta'
})
const name = sessionUser.value?.user_metadata?.full_name;
return name || sessionUser.value?.email || 'Conta';
});
const sublabel = computed(() => {
const r = role.value || sessionRole.value
if (!r) return 'Sessão'
if (r === 'clinic_admin' || r === 'tenant_admin' || r === 'admin') return 'Administrador'
if (r === 'therapist') return 'Terapeuta'
if (r === 'portal_user' || r === 'patient') return 'Portal'
return r
})
const r = role.value || sessionRole.value;
if (!r) return 'Sessão';
if (r === 'clinic_admin' || r === 'tenant_admin' || r === 'admin') return 'Administrador';
if (r === 'therapist') return 'Terapeuta';
if (r === 'portal_user' || r === 'patient') return 'Portal';
return r;
});
const avatarUrl = computed(() => sessionUser.value?.user_metadata?.avatar_url || null)
const avatarUrl = computed(() => sessionUser.value?.user_metadata?.avatar_url || null);
function toggle (e) { pop.value?.toggle(e) }
function close () { try { pop.value?.hide() } catch {} }
async function safePush (target, fallback) {
try {
const r = router.resolve(target)
if (r?.matched?.length) return await router.push(target)
} catch {}
if (fallback) { try { return await router.push(fallback) } catch {} }
return router.push('/')
function toggle(e) {
pop.value?.toggle(e);
}
function close() {
try {
pop.value?.hide();
} catch {}
}
function goMyProfile () { close(); safePush({ name: 'account-profile' }, '/account/profile') }
function goSecurity () { close(); safePush({ name: 'account-security' }, '/account/security') }
function goSettings () {
close()
if (canSee('settings.view')) return safePush({ name: 'ConfiguracoesAgenda' }, '/admin/settings')
return safePush({ name: 'portal-sessoes' }, '/portal')
}
async function signOut () {
close()
try { await supabase.auth.signOut() } catch {}
finally { router.push('/auth/login') }
async function safePush(target, fallback) {
try {
const r = router.resolve(target);
if (r?.matched?.length) return await router.push(target);
} catch {}
if (fallback) {
try {
return await router.push(fallback);
} catch {}
}
return router.push('/');
}
defineExpose({ toggle })
function goMyProfile() {
close();
safePush({ name: 'account-profile' }, '/account/profile');
}
function goSecurity() {
close();
safePush({ name: 'account-security' }, '/account/security');
}
function goSettings() {
close();
if (canSee('settings.view')) return safePush({ name: 'ConfiguracoesAgenda' }, '/admin/settings');
return safePush({ name: 'portal-sessoes' }, '/portal');
}
function goMyPlan() {
close();
const r = role.value || sessionRole.value;
if (r === 'clinic_admin' || r === 'tenant_admin' || r === 'admin') {
return safePush({ name: 'admin-meu-plano' }, '/admin/meu-plano');
}
if (r === 'supervisor') {
return safePush({ name: 'supervisor.meu-plano' }, '/supervisor/meu-plano');
}
if (r === 'editor') {
return safePush({ name: 'editor-meu-plano' }, '/editor/meu-plano');
}
if (r === 'portal_user' || r === 'patient') {
return safePush({ name: 'portal-meu-plano' }, '/portal/meu-plano');
}
return safePush({ name: 'therapist-meu-plano' }, '/therapist/meu-plano');
}
// ── Logout com confirmação ────────────────────────────────────
const signingOut = ref(false);
const dots = ref('.');
let _signOutTimer = null;
let _dotsTimer = null;
function initSignOut() {
signingOut.value = true;
dots.value = '.';
_dotsTimer = setInterval(() => {
dots.value = dots.value.length >= 3 ? '.' : dots.value + '.';
}, 400);
_signOutTimer = setTimeout(async () => {
_clearSignOutTimers();
try {
await supabase.auth.signOut();
} catch {
} finally {
router.push('/auth/login');
}
}, 3000);
}
function cancelSignOut() {
_clearSignOutTimers();
signingOut.value = false;
}
function _clearSignOutTimers() {
clearTimeout(_signOutTimer);
clearInterval(_dotsTimer);
_signOutTimer = null;
_dotsTimer = null;
}
onUnmounted(_clearSignOutTimers);
defineExpose({ toggle });
</script>
<template>
<!-- SIDEBAR: trigger + popover -->
<template v-if="variant === 'sidebar'">
<div class="sticky bottom-0 z-20 border-t border-[var(--surface-border)] bg-[var(--surface-card)]">
<button
type="button"
class="w-full px-3 py-3 flex items-center gap-3 hover:bg-[var(--surface-ground)] transition-colors duration-150"
@click="toggle"
>
<img v-if="avatarUrl" :src="avatarUrl" class="h-9 w-9 rounded-xl object-cover border border-[var(--surface-border)]" alt="avatar" />
<div v-else class="h-9 w-9 rounded-xl border border-[var(--surface-border)] bg-[var(--surface-ground)] grid place-items-center text-sm font-semibold">{{ initials }}</div>
<div class="min-w-0 flex-1 text-left">
<div class="truncate text-sm font-semibold text-[var(--text-color)]">{{ label }}</div>
<div class="truncate text-xs text-[var(--text-color-secondary)]">{{ sublabel }}</div>
</div>
<i class="pi pi-angle-up text-xs opacity-40" />
</button>
<!-- SIDEBAR: trigger + popover -->
<template v-if="variant === 'sidebar'">
<div class="sticky bottom-0 z-20 border-t border-[var(--surface-border)] bg-[var(--surface-card)]">
<button type="button" class="w-full px-3 py-3 flex items-center gap-3 hover:bg-[var(--surface-ground)] transition-colors duration-150" @click="toggle">
<img v-if="avatarUrl" :src="avatarUrl" class="h-9 w-9 rounded-xl object-cover border border-[var(--surface-border)]" alt="avatar" />
<div v-else class="h-9 w-9 rounded-xl border border-[var(--surface-border)] bg-[var(--surface-ground)] grid place-items-center text-sm font-semibold">{{ initials }}</div>
<div class="min-w-0 flex-1 text-left">
<div class="truncate text-sm font-semibold text-[var(--text-color)]">{{ label }}</div>
<div class="truncate text-xs text-[var(--text-color-secondary)]">{{ sublabel }}</div>
</div>
<i class="pi pi-angle-up text-xs opacity-40" />
</button>
<Popover ref="pop" appendTo="body">
<!-- conteúdo reutilizado via template inline -->
<template v-if="true">
<div class="w-[224px] overflow-hidden rounded-[inherit]">
<!-- Header -->
<div class="flex items-center gap-2.5 px-3.5 pt-3.5 pb-3 bg-[var(--primary-color)]/[0.06] border-b border-[var(--surface-border)]">
<div class="relative shrink-0">
<img v-if="avatarUrl" :src="avatarUrl" class="w-9 h-9 rounded-[10px] object-cover ring-[1.5px] ring-[var(--primary-color)]/30" alt="avatar" />
<div v-else class="w-9 h-9 rounded-[10px] grid place-items-center text-[1rem] font-bold text-[var(--primary-color)] bg-[var(--primary-color)]/10 ring-[1.5px] ring-[var(--primary-color)]/20">{{ initials }}</div>
<span class="absolute -bottom-0.5 -right-0.5 w-2.5 h-2.5 rounded-full bg-green-500 border-2 border-[var(--surface-card)]" />
</div>
<div class="min-w-0 flex flex-col gap-px">
<span class="text-[1rem] font-bold text-[var(--text-color)] truncate tracking-tight">{{ label }}</span>
<span class="text-[0.85rem] text-[var(--text-color-secondary)] truncate opacity-70">{{ sessionUser?.email }}</span>
</div>
<Popover ref="pop" appendTo="body">
<!-- conteúdo reutilizado via template inline -->
<template v-if="true">
<div class="w-[224px] overflow-hidden rounded-[inherit]">
<!-- Header -->
<div class="flex items-center gap-2.5 px-3.5 pt-3.5 pb-3 bg-[var(--primary-color)]/[0.06] border-b border-[var(--surface-border)]">
<div class="relative shrink-0">
<img v-if="avatarUrl" :src="avatarUrl" class="w-9 h-9 rounded-[10px] object-cover ring-[1.5px] ring-[var(--primary-color)]/30" alt="avatar" />
<div v-else class="w-9 h-9 rounded-[10px] grid place-items-center text-[1rem] font-bold text-[var(--primary-color)] bg-[var(--primary-color)]/10 ring-[1.5px] ring-[var(--primary-color)]/20">{{ initials }}</div>
<span class="absolute -bottom-0.5 -right-0.5 w-2.5 h-2.5 rounded-full bg-green-500 border-2 border-[var(--surface-card)]" />
</div>
<div class="min-w-0 flex flex-col gap-px">
<span class="text-[1rem] font-bold text-[var(--text-color)] truncate tracking-tight">{{ label }}</span>
<span class="text-[0.85rem] text-[var(--text-color-secondary)] truncate opacity-70">{{ sessionUser?.email }}</span>
</div>
</div>
<!-- Nav items -->
<div class="py-1.5">
<button class="group flex items-center gap-2.5 w-full px-3.5 py-[7px] text-[1rem] font-medium text-[var(--text-color)] hover:bg-[var(--surface-ground)] hover:pl-4 transition-all duration-150" @click="goMyProfile">
<i class="pi pi-user text-[0.72rem] opacity-40 group-hover:opacity-100 group-hover:text-[var(--primary-color)] transition-all duration-150" />
Meu perfil
</button>
<button class="group flex items-center gap-2.5 w-full px-3.5 py-[7px] text-[1rem] font-medium text-[var(--text-color)] hover:bg-[var(--surface-ground)] hover:pl-4 transition-all duration-150" @click="goMyPlan">
<i class="pi pi-credit-card text-[0.72rem] opacity-40 group-hover:opacity-100 group-hover:text-[var(--primary-color)] transition-all duration-150" />
Meu Plano
</button>
<button class="group flex items-center gap-2.5 w-full px-3.5 py-[7px] text-[1rem] font-medium text-[var(--text-color)] hover:bg-[var(--surface-ground)] hover:pl-4 transition-all duration-150" @click="goSecurity">
<i class="pi pi-shield text-[0.72rem] opacity-40 group-hover:opacity-100 group-hover:text-[var(--primary-color)] transition-all duration-150" />
Segurança
</button>
<button
v-if="canSee('settings.view')"
class="group flex items-center gap-2.5 w-full px-3.5 py-[7px] text-[1rem] font-medium text-[var(--text-color)] hover:bg-[var(--surface-ground)] hover:pl-4 transition-all duration-150"
@click="goSettings"
>
<i class="pi pi-cog text-[0.72rem] opacity-40 group-hover:opacity-100 group-hover:text-[var(--primary-color)] transition-all duration-150" />
Configurações
</button>
<div class="my-1 border-t border-[var(--surface-border)]" />
<button class="group flex items-center gap-2.5 w-full px-3.5 py-[7px] text-[1rem] font-medium text-[var(--text-color)] hover:bg-[var(--surface-ground)] hover:pl-4 transition-all duration-150" @click="toggleDarkAndPersist">
<i :class="['pi', isDarkTheme ? 'pi-sun' : 'pi-moon', 'text-[0.72rem] opacity-40 group-hover:opacity-100 group-hover:text-[var(--primary-color)] transition-all duration-150']" />
{{ isDarkTheme ? 'Modo claro' : 'Modo escuro' }}
</button>
<button class="group flex items-center gap-2.5 w-full px-3.5 py-[7px] text-[1rem] font-medium text-[var(--text-color)] hover:bg-[var(--surface-ground)] hover:pl-4 transition-all duration-150" @click="toggleThemeBar">
<i class="pi pi-palette text-[0.72rem] opacity-40 group-hover:opacity-100 group-hover:text-[var(--primary-color)] transition-all duration-150" />
Cores do tema
</button>
</div>
<!-- Footer: Sair -->
<div class="border-t border-[var(--surface-border)] py-1.5">
<button v-if="!signingOut" class="group flex items-center gap-2.5 w-full px-3.5 py-[7px] text-[1rem] font-medium text-red-500 hover:bg-red-500/[0.06] hover:pl-4 transition-all duration-150" @click="initSignOut">
<i class="pi pi-sign-out text-[0.72rem] opacity-60 group-hover:opacity-100 transition-opacity duration-150" />
Sair
</button>
<div v-else class="flex items-center gap-2 w-full px-3.5 py-[7px]">
<span class="flex items-center gap-2.5 flex-1 text-[1rem] font-medium text-red-400 select-none">
<i class="pi pi-sign-out text-[0.72rem] opacity-60" />
Saindo{{ dots }}
</span>
<button class="shrink-0 text-[0.72rem] text-[var(--text-color-secondary)] hover:text-[var(--text-color)] border border-[var(--surface-border)] rounded px-2 py-0.5 transition-colors duration-150" @click="cancelSignOut">
Cancelar
</button>
</div>
</div>
</div>
</template>
</Popover>
</div>
</template>
<!-- RAIL: o popover, trigger externo -->
<template v-else>
<Popover ref="pop" appendTo="body">
<div class="w-[224px] overflow-hidden rounded-[inherit]">
<!-- Header -->
<div class="flex items-center gap-2.5 px-3.5 pt-3.5 pb-3 bg-[var(--primary-color)]/[0.06] border-b border-[var(--surface-border)]">
<div class="relative shrink-0">
<img v-if="avatarUrl" :src="avatarUrl" class="w-9 h-9 rounded-[10px] object-cover ring-[1.5px] ring-[var(--primary-color)]/30" alt="avatar" />
<div v-else class="w-9 h-9 rounded-[10px] grid place-items-center text-[1rem] font-bold text-[var(--primary-color)] bg-[var(--primary-color)]/10 ring-[1.5px] ring-[var(--primary-color)]/20">{{ initials }}</div>
<span class="absolute -bottom-0.5 -right-0.5 w-2.5 h-2.5 rounded-full bg-green-500 border-2 border-[var(--surface-card)]" />
</div>
<div class="min-w-0 flex flex-col gap-px">
<span class="text-[1rem] font-bold text-[var(--text-color)] truncate tracking-tight">{{ label }}</span>
<span class="text-[0.85rem] text-[var(--text-color-secondary)] truncate opacity-70">{{ sessionUser?.email }}</span>
</div>
</div>
<!-- Nav items -->
<div class="py-1.5">
<button class="group flex items-center gap-2.5 w-full px-3.5 py-[7px] text-[1rem] font-medium text-[var(--text-color)] hover:bg-[var(--surface-ground)] hover:pl-4 transition-all duration-150" @click="goMyProfile">
<i class="pi pi-user text-[0.72rem] opacity-40 group-hover:opacity-100 group-hover:text-[var(--primary-color)] transition-all duration-150" />
Meu perfil
</button>
<button class="group flex items-center gap-2.5 w-full px-3.5 py-[7px] text-[1rem] font-medium text-[var(--text-color)] hover:bg-[var(--surface-ground)] hover:pl-4 transition-all duration-150" @click="goMyPlan">
<i class="pi pi-credit-card text-[0.72rem] opacity-40 group-hover:opacity-100 group-hover:text-[var(--primary-color)] transition-all duration-150" />
Meu Plano
</button>
<button class="group flex items-center gap-2.5 w-full px-3.5 py-[7px] text-[1rem] font-medium text-[var(--text-color)] hover:bg-[var(--surface-ground)] hover:pl-4 transition-all duration-150" @click="goSecurity">
<i class="pi pi-shield text-[0.72rem] opacity-40 group-hover:opacity-100 group-hover:text-[var(--primary-color)] transition-all duration-150" />
Segurança
</button>
<button
v-if="canSee('settings.view')"
class="group flex items-center gap-2.5 w-full px-3.5 py-[7px] text-[1rem] font-medium text-[var(--text-color)] hover:bg-[var(--surface-ground)] hover:pl-4 transition-all duration-150"
@click="goSettings"
>
<i class="pi pi-cog text-[0.72rem] opacity-40 group-hover:opacity-100 group-hover:text-[var(--primary-color)] transition-all duration-150" />
Configurações
</button>
<div class="my-1 border-t border-[var(--surface-border)]" />
<button class="group flex items-center gap-2.5 w-full px-3.5 py-[7px] text-[1rem] font-medium text-[var(--text-color)] hover:bg-[var(--surface-ground)] hover:pl-4 transition-all duration-150" @click="toggleDarkAndPersist">
<i :class="['pi', isDarkTheme ? 'pi-sun' : 'pi-moon', 'text-[0.72rem] opacity-40 group-hover:opacity-100 group-hover:text-[var(--primary-color)] transition-all duration-150']" />
{{ isDarkTheme ? 'Modo claro' : 'Modo escuro' }}
</button>
<div class="relative footer-theme-panel">
<button
type="button"
class="group flex items-center gap-2.5 w-full px-3.5 py-[7px] text-[1rem] font-medium text-[var(--text-color)] hover:bg-[var(--surface-ground)] hover:pl-4 transition-all duration-150"
v-styleclass="{
selector: '@next',
enterFromClass: 'hidden',
enterActiveClass: 'p-anchored-overlay-enter-active',
leaveToClass: 'hidden',
leaveActiveClass: 'p-anchored-overlay-leave-active',
hideOnOutsideClick: true
}"
>
<i class="pi pi-palette text-[0.72rem] opacity-40 group-hover:opacity-100 group-hover:text-[var(--primary-color)] transition-all duration-150" />
Cores do tema
</button>
<AppConfigurator />
</div>
</div>
<!-- Footer: Sair -->
<div class="border-t border-[var(--surface-border)] py-1.5">
<button v-if="!signingOut" class="group flex items-center gap-2.5 w-full px-3.5 py-[7px] text-[1rem] font-medium text-red-500 hover:bg-red-500/[0.06] hover:pl-4 transition-all duration-150" @click="initSignOut">
<i class="pi pi-sign-out text-[0.72rem] opacity-60 group-hover:opacity-100 transition-opacity duration-150" />
Sair
</button>
<div v-else class="flex items-center gap-2 w-full px-3.5 py-[7px]">
<span class="flex items-center gap-2.5 flex-1 text-[1rem] font-medium text-red-400 select-none">
<i class="pi pi-sign-out text-[0.72rem] opacity-60" />
Saindo{{ dots }}
</span>
<button class="shrink-0 text-[0.72rem] text-[var(--text-color-secondary)] hover:text-[var(--text-color)] border border-[var(--surface-border)] rounded px-2 py-0.5 transition-colors duration-150" @click="cancelSignOut">
Cancelar
</button>
</div>
</div>
</div>
<!-- Nav items -->
<div class="py-1.5">
<button
class="group flex items-center gap-2.5 w-full px-3.5 py-[7px] text-[1rem] font-medium text-[var(--text-color)] hover:bg-[var(--surface-ground)] hover:pl-4 transition-all duration-150"
@click="goMyProfile"
>
<i class="pi pi-user text-[0.72rem] opacity-40 group-hover:opacity-100 group-hover:text-[var(--primary-color)] transition-all duration-150" />
Meu perfil
</button>
<button
class="group flex items-center gap-2.5 w-full px-3.5 py-[7px] text-[1rem] font-medium text-[var(--text-color)] hover:bg-[var(--surface-ground)] hover:pl-4 transition-all duration-150"
@click="goSecurity"
>
<i class="pi pi-shield text-[0.72rem] opacity-40 group-hover:opacity-100 group-hover:text-[var(--primary-color)] transition-all duration-150" />
Segurança
</button>
<button
v-if="canSee('settings.view')"
class="group flex items-center gap-2.5 w-full px-3.5 py-[7px] text-[1rem] font-medium text-[var(--text-color)] hover:bg-[var(--surface-ground)] hover:pl-4 transition-all duration-150"
@click="goSettings"
>
<i class="pi pi-cog text-[0.72rem] opacity-40 group-hover:opacity-100 group-hover:text-[var(--primary-color)] transition-all duration-150" />
Configurações
</button>
</div>
<!-- Footer: Sair -->
<div class="border-t border-[var(--surface-border)] py-1.5">
<button
class="group flex items-center gap-2.5 w-full px-3.5 py-[7px] text-[1rem] font-medium text-red-500 hover:bg-red-500/[0.06] hover:pl-4 transition-all duration-150"
@click="signOut"
>
<i class="pi pi-sign-out text-[0.72rem] opacity-60 group-hover:opacity-100 transition-opacity duration-150" />
Sair
</button>
</div>
</div>
</template>
</Popover>
</div>
</template>
<!-- RAIL: o popover, trigger externo -->
<template v-else>
<Popover ref="pop" appendTo="body">
<div class="w-[224px] overflow-hidden rounded-[inherit]">
<!-- Header -->
<div class="flex items-center gap-2.5 px-3.5 pt-3.5 pb-3 bg-[var(--primary-color)]/[0.06] border-b border-[var(--surface-border)]">
<div class="relative shrink-0">
<img v-if="avatarUrl" :src="avatarUrl" class="w-9 h-9 rounded-[10px] object-cover ring-[1.5px] ring-[var(--primary-color)]/30" alt="avatar" />
<div v-else class="w-9 h-9 rounded-[10px] grid place-items-center text-[1rem] font-bold text-[var(--primary-color)] bg-[var(--primary-color)]/10 ring-[1.5px] ring-[var(--primary-color)]/20">{{ initials }}</div>
<span class="absolute -bottom-0.5 -right-0.5 w-2.5 h-2.5 rounded-full bg-green-500 border-2 border-[var(--surface-card)]" />
</div>
<div class="min-w-0 flex flex-col gap-px">
<span class="text-[1rem] font-bold text-[var(--text-color)] truncate tracking-tight">{{ label }}</span>
<span class="text-[0.85rem] text-[var(--text-color-secondary)] truncate opacity-70">{{ sessionUser?.email }}</span>
</div>
</div>
<!-- Nav items -->
<div class="py-1.5">
<button
class="group flex items-center gap-2.5 w-full px-3.5 py-[7px] text-[1rem] font-medium text-[var(--text-color)] hover:bg-[var(--surface-ground)] hover:pl-4 transition-all duration-150"
@click="goMyProfile"
>
<i class="pi pi-user text-[0.72rem] opacity-40 group-hover:opacity-100 group-hover:text-[var(--primary-color)] transition-all duration-150" />
Meu perfil
</button>
<button
class="group flex items-center gap-2.5 w-full px-3.5 py-[7px] text-[1rem] font-medium text-[var(--text-color)] hover:bg-[var(--surface-ground)] hover:pl-4 transition-all duration-150"
@click="goSecurity"
>
<i class="pi pi-shield text-[0.72rem] opacity-40 group-hover:opacity-100 group-hover:text-[var(--primary-color)] transition-all duration-150" />
Segurança
</button>
<button
v-if="canSee('settings.view')"
class="group flex items-center gap-2.5 w-full px-3.5 py-[7px] text-[1rem] font-medium text-[var(--text-color)] hover:bg-[var(--surface-ground)] hover:pl-4 transition-all duration-150"
@click="goSettings"
>
<i class="pi pi-cog text-[0.72rem] opacity-40 group-hover:opacity-100 group-hover:text-[var(--primary-color)] transition-all duration-150" />
Configurações
</button>
</div>
<!-- Footer: Sair -->
<div class="border-t border-[var(--surface-border)] py-1.5">
<button
class="group flex items-center gap-2.5 w-full px-3.5 py-[7px] text-[1rem] font-medium text-red-500 hover:bg-red-500/[0.06] hover:pl-4 transition-all duration-150"
@click="signOut"
>
<i class="pi pi-sign-out text-[0.72rem] opacity-60 group-hover:opacity-100 transition-opacity duration-150" />
Sair
</button>
</div>
</div>
</Popover>
</template>
</Popover>
</template>
</template>
<style>
/* Zero padding nativo do PrimeVue — mínimo inevitável pois não há prop pra isso */
.p-popover-content { padding: 0 !important; }
</style>
.p-popover-content {
padding: 0 !important;
}
</style>