108 lines
3.0 KiB
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>
|