<!--
    Component: SidebarContainer
    Wraps <Sidebar> and handles show/hide behaviour for both breakpoints.
-->
<script lang="ts">
import type { ResponsiveManager } from '$shared/lib';
import { cn } from '$shared/lib';
import type { Snippet } from 'svelte';
import { getContext } from 'svelte';
import { cubicOut } from 'svelte/easing';
import {
    fade,
    fly,
} from 'svelte/transition';

interface Props {
    /**
     * Sidebar open state
     */
    isOpen: boolean;
    /**
     * Sidebar snippet
     */
    sidebar?: Snippet<[{ onClose: () => void }]>;
    /**
     * CSS classes
     */
    class?: string;
}

let {
    isOpen = $bindable(false),
    sidebar,
    class: className,
}: Props = $props();

const responsive = getContext<ResponsiveManager>('responsive');

function close() {
    isOpen = false;
}
</script>

{#if responsive.isMobile}
    <!--
        ── MOBILE: fixed overlay ─────────────────────────────────────────────
        Only rendered when open. Both backdrop and panel use Svelte transitions
        so they animate in and out independently.
    -->
    {#if isOpen}
        <!-- Backdrop -->
        <div
            class="fixed inset-0 bg-black/40 backdrop-blur-sm z-40"
            transition:fade={{ duration: 200 }}
            onclick={close}
            aria-hidden="true"
        >
        </div>

        <!-- Panel -->
        <div
            class="fixed left-0 top-0 bottom-0 w-80 z-50 shadow-overlay"
            in:fly={{ x: -320, duration: 300, easing: cubicOut }}
            out:fly={{ x: -320, duration: 250, easing: cubicOut }}
        >
            {#if sidebar}
                {@render sidebar({ onClose: close })}
            {/if}
        </div>
    {/if}
{:else}
    <!--
        ── DESKTOP: collapsible column ───────────────────────────────────────
        Always in the DOM — width transitions between 320px and 0.
        overflow-hidden clips the w-80 inner div during the collapse.

        transition-[width] is on the outer shell.
        duration-300 + ease-out approximates the spring(300, 30) feel.
        The inner div stays w-80 so Sidebar layout never reflows mid-animation.
    -->
    <div
        class={cn(
            'shrink-0 z-30 h-full relative',
            'overflow-hidden',
            'will-change-[width]',
            'border-r border-subtle',
            'surface-canvas',
            isOpen ? 'w-80 opacity-100' : 'w-0 opacity-0',
            'transition-[width,opacity] duration-slow ease-out',
            className,
        )}
    >
        <!-- Fixed-width inner so content never reflows during width animation -->
        <div class="w-80 h-full">
            {#if sidebar}
                {@render sidebar({ onClose: close })}
            {/if}
        </div>
    </div>
{/if}
