Files
sgse-app/apps/web/src/routes/(dashboard)/+layout.svelte

108 lines
3.0 KiB
Svelte

<script lang="ts">
import { onMount } from 'svelte';
import { Toaster } from 'svelte-sonner';
import PushNotificationManager from '$lib/components/PushNotificationManager.svelte';
import Footer from '$lib/components/Footer.svelte';
import Header from '$lib/components/Header.svelte';
import Sidebar from '$lib/components/Sidebar.svelte';
import DashboardHeaderActions from '$lib/components/dashboard/DashboardHeaderActions.svelte';
import ChatWidget from '$lib/components/chat/ChatWidget.svelte';
import PresenceManager from '$lib/components/chat/PresenceManager.svelte';
import { Menu, X } from 'lucide-svelte';
const { children } = $props();
let sidebarOpen = $state(false);
const toggleSidebar = () => (sidebarOpen = !sidebarOpen);
const closeSidebar = () => (sidebarOpen = false);
// No desktop, abrir por padrão; no mobile, começar fechado
onMount(() => {
sidebarOpen = window.matchMedia('(min-width: 1024px)').matches;
});
</script>
<div
class="bg-base-100 text-base-content selection:bg-primary selection:text-primary-content flex min-h-screen flex-col font-sans"
>
<Header>
{#snippet left()}
<button
type="button"
class="btn btn-ghost btn-sm"
aria-label={sidebarOpen ? 'Fechar menu' : 'Abrir menu'}
onclick={toggleSidebar}
>
{#if sidebarOpen}
<X class="h-5 w-5" />
{:else}
<Menu class="h-5 w-5" />
{/if}
</button>
{/snippet}
{#snippet right()}
<DashboardHeaderActions />
{/snippet}
</Header>
<div class="relative flex min-h-[calc(100vh-4rem)] flex-1">
<!-- Overlay (mobile) -->
{#if sidebarOpen}
<div
class="fixed inset-0 z-40 bg-black/30 backdrop-blur-[1px] lg:hidden"
role="button"
tabindex="0"
aria-label="Fechar menu"
onclick={closeSidebar}
onkeydown={(e) => e.key === 'Escape' && closeSidebar()}
></div>
{/if}
<!-- Sidebar -->
<aside
class="bg-base-100 border-base-200 fixed top-16 bottom-0 left-0 z-50 w-72 border-r shadow-sm transition-transform duration-200"
class:translate-x-0={sidebarOpen}
class:-translate-x-full={!sidebarOpen}
>
<div class="h-full overflow-y-auto">
<Sidebar onNavigate={closeSidebar} />
</div>
</aside>
<!-- Conteúdo -->
<div
class="min-w-0 flex-1 transition-[padding] duration-200 {sidebarOpen
? 'lg:pl-72'
: 'lg:pl-0'}"
>
<div id="container-central" class="w-full max-w-none px-3 py-4 lg:px-4">
{@render children()}
</div>
<Footer />
</div>
</div>
<!-- Componentes de Chat (gerenciam auth internamente) -->
<PresenceManager />
<ChatWidget />
</div>
<!-- Toast Notifications (Sonner) -->
<Toaster position="top-right" richColors closeButton expand={true} />
<!-- Push Notification Manager (registra subscription automaticamente) -->
<PushNotificationManager />
<style>
/* Evita “corredor” quando páginas usam `container mx-auto` */
#container-central :global(.container) {
max-width: none !important;
}
#container-central :global(.container.mx-auto) {
margin-left: 0 !important;
margin-right: 0 !important;
}
</style>