+ Menu Hover no Layout Rail, Twilio, Sms, Email, Templates, LNovo Layout Configurações

This commit is contained in:
Leonardo
2026-03-25 08:39:45 -03:00
parent 53a4980396
commit 3f1786c9bf
59 changed files with 2553 additions and 1106 deletions
@@ -564,11 +564,11 @@ defineExpose({ fillRandomPatient, onSubmit, confirmDelete, saving, deleting, can
<div class="absolute w-72 h-72 top-0 -left-16 rounded-full blur-[60px] bg-emerald-400/[0.08]" />
</div>
<div class="relative z-[1] flex items-center gap-3">
<div class="relative z-1 flex items-center gap-3">
<!-- Brand -->
<div class="flex items-center gap-2 flex-shrink-0">
<div class="grid place-items-center w-9 h-9 rounded-md flex-shrink-0 bg-indigo-500/10 text-indigo-500">
<div class="flex items-center gap-2 shrink-0">
<div class="grid place-items-center w-9 h-9 rounded-md shrink-0 bg-indigo-500/10 text-indigo-500">
<i class="pi pi-user-plus text-base" />
</div>
<div class="min-w-0 hidden lg:block">
@@ -586,7 +586,7 @@ defineExpose({ fillRandomPatient, onSubmit, confirmDelete, saving, deleting, can
<div class="flex-1" />
<!-- Ações (ocultas no modo dialog o Dialog tem seu próprio footer) -->
<div v-if="!dialogMode" class="flex items-center gap-1.5 flex-shrink-0">
<div v-if="!dialogMode" class="flex items-center gap-1.5 shrink-0">
<Button
v-if="canSee('testMODE')"
label="Preencher tudo"
@@ -634,7 +634,7 @@ defineExpose({ fillRandomPatient, onSubmit, confirmDelete, saving, deleting, can
<!-- Avatar -->
<div class="flex items-center gap-3 pb-3.5 mb-3.5 border-b border-[var(--surface-border,#e2e8f0)] xl:flex-col xl:items-center xl:gap-2">
<!-- Foto -->
<div class="w-16 h-16 xl:w-20 xl:h-20 rounded-full overflow-hidden border border-[var(--surface-border,#e2e8f0)] bg-[var(--surface-ground,#f8fafc)] flex-shrink-0">
<div class="w-16 h-16 xl:w-20 xl:h-20 rounded-full overflow-hidden border border-[var(--surface-border,#e2e8f0)] bg-[var(--surface-ground,#f8fafc)] shrink-0">
<img
v-if="avatarPreviewUrl || form.avatar_url"
:src="avatarPreviewUrl || form.avatar_url"
@@ -676,7 +676,7 @@ defineExpose({ fillRandomPatient, onSubmit, confirmDelete, saving, deleting, can
: 'border-transparent text-[var(--text-color)] hover:bg-[var(--surface-ground,#f8fafc)] font-medium'"
@click="openPanel(Number(item.value))"
>
<i :class="item.icon" class="text-[1rem] opacity-70 flex-shrink-0" />
<i :class="item.icon" class="text-[1rem] opacity-70 shrink-0" />
<span>{{ item.label }}</span>
</button>
</div>
@@ -705,7 +705,7 @@ defineExpose({ fillRandomPatient, onSubmit, confirmDelete, saving, deleting, can
:class="activeValue === item.value ? 'bg-indigo-500/8 border-indigo-300/40 text-indigo-700 font-semibold' : 'text-[var(--text-color)] hover:bg-[var(--surface-ground,#f8fafc)] font-medium'"
@click="selectNav(item)"
>
<i :class="item.icon" class="text-[1rem] opacity-70 flex-shrink-0" />
<i :class="item.icon" class="text-[1rem] opacity-70 shrink-0" />
<span>{{ item.label }}</span>
</button>
</div>
@@ -802,7 +802,7 @@ defineExpose({ fillRandomPatient, onSubmit, confirmDelete, saving, deleting, can
</FloatLabel>
<div class="mt-1 text-[0.72rem] text-[var(--text-color-secondary)] opacity-70">Usado para puxar um modelo de anamnese.</div>
</div>
<Button icon="pi pi-plus" severity="secondary" outlined class="flex-shrink-0" @click="openGroupDlg" />
<Button icon="pi pi-plus" severity="secondary" outlined class="shrink-0" @click="openGroupDlg" />
</div>
</div>
<!-- Tags -->
@@ -814,7 +814,7 @@ defineExpose({ fillRandomPatient, onSubmit, confirmDelete, saving, deleting, can
<label for="f_tags">Tags</label>
</FloatLabel>
</div>
<Button icon="pi pi-plus" severity="secondary" outlined class="flex-shrink-0" @click="openTagDlg" />
<Button icon="pi pi-plus" severity="secondary" outlined class="shrink-0" @click="openTagDlg" />
</div>
</div>
<div>
@@ -928,11 +928,11 @@ defineExpose({ fillRandomPatient, onSubmit, confirmDelete, saving, deleting, can
<div class="flex flex-col gap-4 pt-1">
<span class="text-[1rem] text-[var(--text-color-secondary)]">Crie um grupo para organizar seus pacientes.</span>
<div class="flex items-center gap-3">
<label for="group-name" class="w-20 text-[1rem] font-semibold flex-shrink-0">Nome</label>
<label for="group-name" class="w-20 text-[1rem] font-semibold shrink-0">Nome</label>
<InputText id="group-name" v-model="newGroup.name" class="flex-1" autocomplete="off" placeholder="Ex: Crianças" />
</div>
<div class="flex items-center gap-3">
<label class="w-20 text-[1rem] font-semibold flex-shrink-0">Cor</label>
<label class="w-20 text-[1rem] font-semibold shrink-0">Cor</label>
<div class="flex flex-1 items-center gap-2.5">
<input v-model="newGroup.color" type="color" class="h-9 w-12 cursor-pointer rounded-md border border-[var(--surface-border,#e2e8f0)] bg-transparent" />
<Chip :label="newGroup.color || '#—'" class="font-semibold" :style="{ backgroundColor: newGroup.color, color: '#fff' }" />
@@ -963,11 +963,11 @@ defineExpose({ fillRandomPatient, onSubmit, confirmDelete, saving, deleting, can
<div class="flex flex-col gap-4 pt-1">
<span class="text-[1rem] text-[var(--text-color-secondary)]">Crie uma tag para facilitar filtros e organização.</span>
<div class="flex items-center gap-3">
<label for="tag-name" class="w-20 text-[1rem] font-semibold flex-shrink-0">Nome</label>
<label for="tag-name" class="w-20 text-[1rem] font-semibold shrink-0">Nome</label>
<InputText id="tag-name" v-model="newTag.name" class="flex-1" autocomplete="off" placeholder="Ex: Ansiedade" />
</div>
<div class="flex items-center gap-3">
<label class="w-20 text-[1rem] font-semibold flex-shrink-0">Cor</label>
<label class="w-20 text-[1rem] font-semibold shrink-0">Cor</label>
<div class="flex flex-1 items-center gap-2.5">
<input v-model="newTag.color" type="color" class="h-9 w-12 cursor-pointer rounded-md border border-[var(--surface-border,#e2e8f0)] bg-transparent" />
<Chip :label="newTag.color || '#—'" class="font-semibold" :style="{ backgroundColor: newTag.color, color: '#fff' }" />
@@ -190,10 +190,10 @@ onBeforeUnmount(() => {
<div class="absolute w-72 h-72 top-0 -left-16 rounded-full blur-[60px] bg-emerald-400/[0.08]" />
</div>
<div class="relative z-[1] flex items-center gap-3">
<div class="relative z-1 flex items-center gap-3">
<!-- Brand -->
<div class="flex items-center gap-2 flex-shrink-0">
<div class="grid place-items-center w-9 h-9 rounded-md flex-shrink-0 bg-indigo-500/10 text-indigo-500">
<div class="flex items-center gap-2 shrink-0">
<div class="grid place-items-center w-9 h-9 rounded-md shrink-0 bg-indigo-500/10 text-indigo-500">
<i class="pi pi-link text-base" />
</div>
<div class="min-w-0 hidden lg:block">
@@ -206,7 +206,7 @@ onBeforeUnmount(() => {
<div class="hidden xl:flex flex-1 min-w-0 mx-2 items-center gap-3">
<!-- Badge de status -->
<span
class="inline-flex items-center gap-1.5 text-[0.75rem] px-2.5 py-1 rounded-full border flex-shrink-0 transition-colors"
class="inline-flex items-center gap-1.5 text-[0.75rem] px-2.5 py-1 rounded-full border shrink-0 transition-colors"
:class="inviteToken ? 'border-emerald-200 text-emerald-700 bg-emerald-50' : 'border-[var(--surface-border)] text-[var(--text-color-secondary)] bg-[var(--surface-ground)]'"
>
<span class="h-1.5 w-1.5 rounded-full" :class="inviteToken ? 'bg-emerald-500 animate-pulse' : 'bg-[var(--text-color-secondary)]'" />
@@ -224,12 +224,12 @@ onBeforeUnmount(() => {
</div>
<!-- Ações desktop -->
<div class="hidden xl:flex items-center gap-1 flex-shrink-0">
<div class="hidden xl:flex items-center gap-1 shrink-0">
<Button label="Gerar novo link" icon="pi pi-refresh" severity="secondary" outlined class="rounded-full" :loading="rotating" @click="rotateLink" />
</div>
<!-- Mobile -->
<div class="flex xl:hidden items-center gap-1 flex-shrink-0 ml-auto">
<div class="flex xl:hidden items-center gap-1 shrink-0 ml-auto">
<Button label="Ações" icon="pi pi-ellipsis-v" severity="secondary" size="small" class="rounded-full" @click="(e) => mobileMenuRef.toggle(e)" />
<Menu ref="mobileMenuRef" :model="mobileMenuItems" :popup="true" />
</div>
@@ -251,7 +251,7 @@ onBeforeUnmount(() => {
<div class="text-[1rem] text-[var(--text-color-secondary)] mt-0.5">Envie ao paciente por WhatsApp, e-mail ou mensagem direta</div>
</div>
<span
class="inline-flex items-center gap-1.5 text-[0.75rem] px-2.5 py-1 rounded-full border flex-shrink-0"
class="inline-flex items-center gap-1.5 text-[0.75rem] px-2.5 py-1 rounded-full border shrink-0"
:class="inviteToken ? 'border-emerald-200 text-emerald-700 bg-emerald-50' : 'border-[var(--surface-border)] text-[var(--text-color-secondary)] bg-[var(--surface-ground)]'"
>
<span class="h-1.5 w-1.5 rounded-full" :class="inviteToken ? 'bg-emerald-500 animate-pulse' : 'bg-[var(--text-color-secondary)]'" />
@@ -286,7 +286,7 @@ onBeforeUnmount(() => {
class="flex items-center gap-3 px-3.5 py-3 rounded-md border border-[var(--surface-border,#e2e8f0)] bg-[var(--surface-ground,#f8fafc)] cursor-pointer text-left transition-[background,box-shadow,transform] duration-150 hover:bg-[var(--surface-hover,#f1f5f9)] hover:shadow-[0_2px_12px_rgba(0,0,0,0.06)] hover:-translate-y-px active:translate-y-0"
@click="copyLink"
>
<div class="grid place-items-center w-9 h-9 rounded-md flex-shrink-0 bg-indigo-500/10 text-indigo-500">
<div class="grid place-items-center w-9 h-9 rounded-md shrink-0 bg-indigo-500/10 text-indigo-500">
<i class="pi pi-copy" />
</div>
<div class="min-w-0">
@@ -300,7 +300,7 @@ onBeforeUnmount(() => {
class="flex items-center gap-3 px-3.5 py-3 rounded-md border border-[var(--surface-border,#e2e8f0)] bg-[var(--surface-ground,#f8fafc)] cursor-pointer text-left transition-[background,box-shadow,transform] duration-150 hover:bg-[var(--surface-hover,#f1f5f9)] hover:shadow-[0_2px_12px_rgba(0,0,0,0.06)] hover:-translate-y-px active:translate-y-0"
@click="copyInviteMessage"
>
<div class="grid place-items-center w-9 h-9 rounded-md flex-shrink-0 bg-emerald-500/10 text-emerald-600">
<div class="grid place-items-center w-9 h-9 rounded-md shrink-0 bg-emerald-500/10 text-emerald-600">
<i class="pi pi-comment" />
</div>
<div class="min-w-0">
@@ -336,11 +336,11 @@ onBeforeUnmount(() => {
</div>
<!-- DIREITA: instruções -->
<div class="w-full lg:w-[272px] lg:flex-shrink-0 flex flex-col gap-3">
<div class="w-full lg:w-[272px] lg:shrink-0 flex flex-col gap-3">
<!-- Como funciona -->
<div class="rounded-md border border-[var(--surface-border,#e2e8f0)] bg-[var(--surface-card,#fff)] overflow-hidden">
<div class="flex items-center gap-2.5 px-3.5 pt-3 pb-2.5 border-b border-[var(--surface-border,#f1f5f9)]">
<div class="w-8 h-8 rounded-md flex items-center justify-center flex-shrink-0 bg-indigo-500/10 text-indigo-500">
<div class="w-8 h-8 rounded-md flex items-center justify-center shrink-0 bg-indigo-500/10 text-indigo-500">
<i class="pi pi-list-check text-[0.9rem]" />
</div>
<div class="min-w-0">
@@ -351,7 +351,7 @@ onBeforeUnmount(() => {
<ol class="flex flex-col divide-y divide-[var(--surface-border,#f1f5f9)]">
<li v-for="step in howItWorks" :key="step.n" class="flex items-start gap-3 px-3.5 py-3">
<div class="grid place-items-center w-7 h-7 rounded-md flex-shrink-0 bg-indigo-500/10 text-indigo-500 text-[0.75rem] font-bold mt-px">
<div class="grid place-items-center w-7 h-7 rounded-md shrink-0 bg-indigo-500/10 text-indigo-500 text-[0.75rem] font-bold mt-px">
{{ step.n }}
</div>
<div class="min-w-0">
@@ -365,7 +365,7 @@ onBeforeUnmount(() => {
<!-- Boas práticas -->
<div class="rounded-md border border-[var(--surface-border,#e2e8f0)] bg-[var(--surface-card,#fff)] overflow-hidden">
<div class="flex items-center gap-2.5 px-3.5 pt-3 pb-2.5 border-b border-[var(--surface-border,#f1f5f9)]">
<div class="w-8 h-8 rounded-md flex items-center justify-center flex-shrink-0 bg-emerald-500/10 text-emerald-600">
<div class="w-8 h-8 rounded-md flex items-center justify-center shrink-0 bg-emerald-500/10 text-emerald-600">
<i class="pi pi-shield text-[0.9rem]" />
</div>
<div class="min-w-0">
@@ -376,7 +376,7 @@ onBeforeUnmount(() => {
<ul class="flex flex-col divide-y divide-[var(--surface-border,#f1f5f9)]">
<li v-for="tip in goodPractices" :key="tip" class="flex items-start gap-2.5 px-3.5 py-2.5">
<i class="pi pi-check text-emerald-500 mt-0.5 flex-shrink-0 text-[1rem]" />
<i class="pi pi-check text-emerald-500 mt-0.5 shrink-0 text-[1rem]" />
<span class="text-[1rem] text-[var(--text-color-secondary)] leading-relaxed">{{ tip }}</span>
</li>
</ul>
@@ -495,10 +495,10 @@ onBeforeUnmount(() => {
<div class="absolute w-72 h-72 top-0 -left-16 rounded-full blur-[60px] bg-indigo-500/[0.09]" />
</div>
<div class="relative z-[1] flex items-center gap-3">
<div class="relative z-1 flex items-center gap-3">
<!-- Brand -->
<div class="flex items-center gap-2 flex-shrink-0">
<div class="grid place-items-center w-9 h-9 rounded-md flex-shrink-0 bg-indigo-500/10 text-indigo-500">
<div class="flex items-center gap-2 shrink-0">
<div class="grid place-items-center w-9 h-9 rounded-md shrink-0 bg-indigo-500/10 text-indigo-500">
<i class="pi pi-inbox text-base" />
</div>
<div class="min-w-0 hidden lg:block">
@@ -537,12 +537,12 @@ onBeforeUnmount(() => {
</div>
<!-- Ações desktop -->
<div class="hidden xl:flex items-center gap-1 flex-shrink-0">
<div class="hidden xl:flex items-center gap-1 shrink-0">
<Button icon="pi pi-refresh" severity="secondary" outlined class="h-9 w-9 rounded-full" :loading="loading" title="Atualizar" @click="fetchIntakes" />
</div>
<!-- Mobile -->
<div class="flex xl:hidden items-center gap-1 flex-shrink-0 ml-auto">
<div class="flex xl:hidden items-center gap-1 shrink-0 ml-auto">
<Button icon="pi pi-search" severity="secondary" outlined class="h-9 w-9 rounded-full" @click="recSearchDlgOpen = true" />
<Button label="Ações" icon="pi pi-ellipsis-v" severity="secondary" size="small" class="rounded-full" @click="(e) => recMobileMenuRef.toggle(e)" />
<Menu ref="recMobileMenuRef" :model="recMobileMenuItems" :popup="true" />