feat: enhance layout and component structure for dashboard, including responsive sidebar and header actions, and update footer styling

This commit is contained in:
2025-12-12 16:05:28 -03:00
parent b771322b24
commit 4f238022cf
6 changed files with 350 additions and 465 deletions

View File

@@ -0,0 +1,124 @@
<script lang="ts">
import { api } from '@sgse-app/backend/convex/_generated/api';
import { useQuery } from 'convex-svelte';
import type { FunctionReference } from 'convex/server';
import { goto } from '$app/navigation';
import { resolve } from '$app/paths';
import { page } from '$app/state';
import { LogIn, Settings, User, UserCog } from 'lucide-svelte';
import { authClient } from '$lib/auth';
import NotificationBell from '$lib/components/chat/NotificationBell.svelte';
let currentPath = $derived(page.url.pathname);
const currentUser = useQuery(api.auth.getCurrentUser as FunctionReference<'query'>, {});
// Função para obter a URL do avatar/foto do usuário
let avatarUrlDoUsuario = $derived.by(() => {
if (!currentUser.data) return null;
// Prioridade: fotoPerfilUrl > avatar > fallback com nome
if (currentUser.data.fotoPerfilUrl) {
return currentUser.data.fotoPerfilUrl;
}
if (currentUser.data.avatar) {
return currentUser.data.avatar;
}
// Fallback: retornar null para usar o ícone User do Lucide
return null;
});
function goToLogin(redirectTo?: string) {
const target = redirectTo || currentPath || '/';
goto(`${resolve('/login')}?redirect=${encodeURIComponent(target)}`);
}
async function handleLogout() {
const result = await authClient.signOut();
if (result.error) {
console.error('Sign out error:', result.error);
}
// Resetar tema para padrão ao fazer logout
const { aplicarTemaPadrao } = await import('$lib/utils/temas');
aplicarTemaPadrao();
goto(resolve('/home'));
}
</script>
<div class="flex items-center gap-3">
{#if currentUser.data}
<!-- Nome e Perfil -->
<div class="hidden flex-col items-end lg:flex">
<span class="text-base-content text-sm leading-tight font-semibold"
>{currentUser.data.nome}</span
>
<span class="text-base-content/60 text-xs leading-tight">{currentUser.data.role?.nome}</span>
</div>
<div class="dropdown dropdown-end">
<!-- Botão de Perfil com Avatar -->
<button
type="button"
tabindex="0"
class="btn avatar ring-base-200 hover:ring-primary/50 h-10 w-10 p-0 ring-2 ring-offset-2 transition-all"
aria-label="Menu do usuário"
>
<div class="h-full w-full overflow-hidden rounded-full">
{#if avatarUrlDoUsuario}
<img
src={avatarUrlDoUsuario}
alt={currentUser.data?.nome || 'Usuário'}
class="h-full w-full object-cover"
/>
{:else}
<div class="bg-primary/10 text-primary flex h-full w-full items-center justify-center">
<User class="h-5 w-5" />
</div>
{/if}
</div>
</button>
<!-- svelte-ignore a11y_no_noninteractive_tabindex -->
<ul
tabindex="0"
class="dropdown-content menu bg-base-100 rounded-box ring-base-content/5 z-1 mt-3 w-56 p-2 shadow-xl ring-1"
>
<li class="menu-title border-base-200 mb-2 border-b px-4 py-2">
<span class="text-base-content font-bold">{currentUser.data?.nome}</span>
<span class="text-base-content/60 text-xs font-normal">{currentUser.data.email}</span>
</li>
<li>
<a href={resolve('/perfil')} class="active:bg-primary/10 active:text-primary"
><UserCog class="mr-2 h-4 w-4" /> Meu Perfil</a
>
</li>
<li>
<a href={resolve('/alterar-senha')} class="active:bg-primary/10 active:text-primary"
><Settings class="mr-2 h-4 w-4" /> Alterar Senha</a
>
</li>
<div class="divider my-1"></div>
<li>
<button type="button" onclick={handleLogout} class="text-error hover:bg-error/10"
><LogIn class="mr-2 h-4 w-4 rotate-180" /> Sair</button
>
</li>
</ul>
</div>
<!-- Sino de notificações -->
<div class="relative">
<NotificationBell />
</div>
{:else}
<button
type="button"
class="btn btn-primary btn-sm rounded-full px-6"
onclick={() => goToLogin()}
>
Entrar
</button>
{/if}
</div>