Files
banner/web/src/routes/+layout.svelte
Xevion fa28f13a45 feat: add interactive timeline visualization for class times
Implements a canvas-based timeline view with D3 scales showing class
counts across subjects. Features drag-to-pan, mouse wheel zoom, subject
filtering, hover tooltips, and smooth animations. Timeline auto-follows
current time and supports keyboard navigation.
2026-01-29 23:19:39 -06:00

59 lines
1.8 KiB
Svelte

<script lang="ts">
import "overlayscrollbars/overlayscrollbars.css";
import "./layout.css";
import { page } from "$app/state";
import PageTransition from "$lib/components/PageTransition.svelte";
import NavBar from "$lib/components/NavBar.svelte";
import { useOverlayScrollbars } from "$lib/composables/useOverlayScrollbars.svelte";
import { initNavigation } from "$lib/stores/navigation.svelte";
import { themeStore } from "$lib/stores/theme.svelte";
import { Tooltip } from "bits-ui";
import ErrorBoundaryFallback from "$lib/components/ErrorBoundaryFallback.svelte";
import { onMount } from "svelte";
let { children } = $props();
const APP_PREFIXES = ["/profile", "/settings", "/admin"];
/**
* Coarsened key so sub-route navigation within the (app) layout group
* doesn't re-trigger the root page transition — the shared layout handles its own.
*/
let transitionKey = $derived(
APP_PREFIXES.some((p) => page.url.pathname.startsWith(p)) ? "/app" : page.url.pathname
);
initNavigation();
useOverlayScrollbars(() => document.body, {
scrollbars: {
autoHide: "leave",
autoHideDelay: 800,
},
});
onMount(() => {
themeStore.init();
});
</script>
<Tooltip.Provider>
<div class="relative flex min-h-screen flex-col">
<!-- pointer-events-none so the navbar doesn't block canvas interactions;
NavBar re-enables pointer-events on its own container. -->
<div class="absolute inset-x-0 top-0 z-50 pointer-events-none">
<NavBar />
</div>
<svelte:boundary onerror={(e) => console.error("[root boundary]", e)}>
<PageTransition key={transitionKey}>
{@render children()}
</PageTransition>
{#snippet failed(error, reset)}
<ErrorBoundaryFallback {error} {reset} />
{/snippet}
</svelte:boundary>
</div>
</Tooltip.Provider>