5b7ec03973
Replace inline class clusters with the design-system utilities and tokens established in the prior two commits. No behavior changes intended beyond two real bug fixes. Bug fixes: - SampleList.svelte: 'border-border-subtle bg-background-40' was a silent no-op (both classes mis-spelled). Now 'border-subtle bg-background/40' applies as intended. - FontList.svelte: 'h-[44px]' → 'h-11' (44px = 2.75rem = spacing-11, no need for arbitrary value). Sweeps: - TypographyMenu: popover + floating bar now use surface-popover / surface-floating + shadow-popover. - FontList + FilterGroup: tertiary list buttons use the new Button layout="block-list-row" variant; skeleton fills use the skeleton-fill utility. - Footer / BreadcrumbHeader: surface-floating absorbs the bg-surface/blur/border cluster. Footer bumped to z-20 with a comment explaining the stacking against SidebarContainer (z-40/50). - FontSampler: surface-card + hover shadow-stamp-card token. - SliderArea: surface-canvas, flex-center, shadow-floating-panel tokens (light + dark variants). - Sidebar / Header / ButtonGroup / Layout / SidebarContainer: bg-surface dark:bg-dark-bg → surface-canvas (8 sites); SidebarContainer mobile panel uses shadow-overlay. - Loader / Thumb: flex items-center justify-center → flex-center; Thumb durations → duration-fast. - ComboControl: trigger uses surface-card-elevated when open, popover uses surface-card-elevated, label cluster → text-label-mono, flex-center for the trigger interior. - Slider: shadow-sm → shadow-rest, duration-150 → duration-fast. - text-secondary → text-subtle across Input, Slider, ComboControl (matches the rename in the styles commit). - Link: reverted earlier surface-floating attempt — Link's original bg-surface/80 backdrop-blur pattern was thinner than surface-floating (no border, smaller blur), and the Footer was overlaying its own border-subtle on top, fighting the utility. Kept the original style.
101 lines
2.9 KiB
Svelte
101 lines
2.9 KiB
Svelte
<!--
|
|
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}
|