Files
salam e687b4437b
linter / quality (push) Canceled after 0s
tests / ci (8.3) (push) Canceled after 0s
tests / ci (8.4) (push) Canceled after 0s
tests / ci (8.5) (push) Canceled after 0s
first commit
2026-10-06 18:53:03 +02:00

106 lines
2.9 KiB
Svelte

<script lang="ts">
import type { Snippet } from 'svelte';
import { derived, readable, writable } from 'svelte/store';
import { onMount, setContext } from 'svelte';
import { cn } from '@/lib/utils';
import { TooltipProvider } from '@/components/ui/tooltip';
import {
SIDEBAR_CONTEXT,
SIDEBAR_COOKIE_MAX_AGE,
SIDEBAR_COOKIE_NAME,
SIDEBAR_KEYBOARD_SHORTCUT,
SIDEBAR_WIDTH,
SIDEBAR_WIDTH_ICON,
type SidebarContext,
} from './context';
let {
defaultOpen = true,
class: className = '',
children,
}: {
defaultOpen?: boolean;
class?: string;
children?: Snippet;
} = $props();
const initialOpen = () => {
if (typeof document === 'undefined') return defaultOpen;
const hasCookie = document.cookie.includes(`${SIDEBAR_COOKIE_NAME}=false`);
return hasCookie ? false : defaultOpen;
};
const open = writable(initialOpen());
const openMobile = writable(false);
const isMobile = readable(false, (set) => {
if (typeof window === 'undefined') {
return () => {};
}
const media = window.matchMedia('(max-width: 768px)');
const update = () => set(media.matches);
update();
media.addEventListener('change', update);
return () => media.removeEventListener('change', update);
});
const state = derived(open, ($open) => ($open ? 'expanded' : 'collapsed'));
const setOpen = (value: boolean) => {
open.set(value);
if (typeof document !== 'undefined') {
document.cookie = `${SIDEBAR_COOKIE_NAME}=${value}; path=/; max-age=${SIDEBAR_COOKIE_MAX_AGE}`;
}
};
const setOpenMobile = (value: boolean) => {
openMobile.set(value);
};
const toggleSidebar = () => {
if ($isMobile) {
setOpenMobile(!$openMobile);
} else {
setOpen(!$open);
}
};
onMount(() => {
const handler = (event: KeyboardEvent) => {
if (event.key === SIDEBAR_KEYBOARD_SHORTCUT && (event.metaKey || event.ctrlKey)) {
event.preventDefault();
toggleSidebar();
}
};
window.addEventListener('keydown', handler);
return () => window.removeEventListener('keydown', handler);
});
const context: SidebarContext = {
state,
open,
setOpen,
isMobile,
openMobile,
setOpenMobile,
toggleSidebar,
};
setContext(SIDEBAR_CONTEXT, context);
</script>
<TooltipProvider>
<div
data-slot="sidebar-wrapper"
style={`--sidebar-width: ${SIDEBAR_WIDTH}; --sidebar-width-icon: ${SIDEBAR_WIDTH_ICON};`}
class={cn(
'group/sidebar-wrapper has-data-[variant=inset]:bg-sidebar flex min-h-svh w-full',
className,
)}
>
{@render children?.()}
</div>
</TooltipProvider>