chore: rewrite existing shared/ui stories using snippet template pattern

This commit is contained in:
Ilia Mashkov
2026-02-22 11:25:02 +03:00
parent 30bbfa7e11
commit 0c8b8e989f
15 changed files with 403 additions and 304 deletions

View File

@@ -65,9 +65,13 @@ const selectedFilter = createFilter({
</script>
<Story name="Default">
<CheckboxFilter filter={defaultFilter} displayedLabel="Zoo" />
{#snippet template(args)}
<CheckboxFilter filter={defaultFilter} displayedLabel="Zoo" {...args} />
{/snippet}
</Story>
<Story name="Selected">
<CheckboxFilter filter={selectedFilter} displayedLabel="Shopping list" />
{#snippet template(args)}
<CheckboxFilter filter={selectedFilter} displayedLabel="Shopping list" {...args} />
{/snippet}
</Story>

View File

@@ -51,7 +51,9 @@ const customLabelsControl = createTypographyControl({ value: 50, min: 0, max: 10
control: defaultControl,
}}
>
<ComboControl control={defaultControl} />
{#snippet template(args)}
<ComboControl control={defaultControl} {...args} />
{/snippet}
</Story>
<Story
@@ -60,7 +62,9 @@ const customLabelsControl = createTypographyControl({ value: 50, min: 0, max: 10
control: atMinimumControl,
}}
>
<ComboControl control={atMinimumControl} />
{#snippet template(args)}
<ComboControl control={atMinimumControl} {...args} />
{/snippet}
</Story>
<Story
@@ -69,7 +73,9 @@ const customLabelsControl = createTypographyControl({ value: 50, min: 0, max: 10
control: atMaximumControl,
}}
>
<ComboControl control={atMaximumControl} />
{#snippet template(args)}
<ComboControl control={atMaximumControl} {...args} />
{/snippet}
</Story>
<Story
@@ -78,7 +84,9 @@ const customLabelsControl = createTypographyControl({ value: 50, min: 0, max: 10
control: withFloatControl,
}}
>
<ComboControl control={withFloatControl} />
{#snippet template(args)}
<ComboControl control={withFloatControl} {...args} />
{/snippet}
</Story>
<Story
@@ -90,10 +98,13 @@ const customLabelsControl = createTypographyControl({ value: 50, min: 0, max: 10
controlLabel: 'Open font size controls',
}}
>
{#snippet template(args)}
<ComboControl
control={customLabelsControl}
decreaseLabel="Decrease font size"
increaseLabel="Increase font size"
controlLabel="Open font size controls"
{...args}
/>
{/snippet}
</Story>

View File

@@ -52,7 +52,9 @@ const largeRangeControl = createTypographyControl({ min: 0, max: 1000, step: 10,
label: 'Size',
}}
>
<ComboControlV2 control={horizontalControl} orientation="horizontal" label="Size" />
{#snippet template(args)}
<ComboControlV2 control={horizontalControl} orientation="horizontal" label="Size" {...args} />
{/snippet}
</Story>
<Story
@@ -63,7 +65,9 @@ const largeRangeControl = createTypographyControl({ min: 0, max: 1000, step: 10,
label: 'Size',
}}
>
<ComboControlV2 control={verticalControl} orientation="vertical" class="h-48" label="Size" />
{#snippet template(args)}
<ComboControlV2 control={verticalControl} orientation="vertical" class="h-48" label="Size" {...args} />
{/snippet}
</Story>
<Story
@@ -74,7 +78,9 @@ const largeRangeControl = createTypographyControl({ min: 0, max: 1000, step: 10,
label: 'Opacity',
}}
>
<ComboControlV2 control={floatControl} orientation="vertical" class="h-48" label="Opacity" />
{#snippet template(args)}
<ComboControlV2 control={floatControl} orientation="vertical" class="h-48" label="Opacity" {...args} />
{/snippet}
</Story>
<Story
@@ -85,7 +91,9 @@ const largeRangeControl = createTypographyControl({ min: 0, max: 1000, step: 10,
label: 'Size',
}}
>
<ComboControlV2 control={atMinControl} orientation="horizontal" label="Size" />
{#snippet template(args)}
<ComboControlV2 control={atMinControl} orientation="horizontal" label="Size" {...args} />
{/snippet}
</Story>
<Story
@@ -96,7 +104,9 @@ const largeRangeControl = createTypographyControl({ min: 0, max: 1000, step: 10,
label: 'Size',
}}
>
<ComboControlV2 control={atMaxControl} orientation="horizontal" label="Size" />
{#snippet template(args)}
<ComboControlV2 control={atMaxControl} orientation="horizontal" label="Size" {...args} />
{/snippet}
</Story>
<Story
@@ -107,5 +117,7 @@ const largeRangeControl = createTypographyControl({ min: 0, max: 1000, step: 10,
label: 'Scale',
}}
>
<ComboControlV2 control={largeRangeControl} orientation="horizontal" label="Scale" />
{#snippet template(args)}
<ComboControlV2 control={largeRangeControl} orientation="horizontal" label="Scale" {...args} />
{/snippet}
</Story>

View File

@@ -55,7 +55,9 @@ let longValue = $state(
letterSpacing: 0,
}}
>
<ContentEditable bind:text={value} />
{#snippet template(args)}
<ContentEditable bind:text={value} {...args} />
{/snippet}
</Story>
<Story
@@ -67,7 +69,9 @@ let longValue = $state(
letterSpacing: 0,
}}
>
<ContentEditable bind:text={smallValue} />
{#snippet template(args)}
<ContentEditable bind:text={smallValue} {...args} />
{/snippet}
</Story>
<Story
@@ -79,7 +83,9 @@ let longValue = $state(
letterSpacing: 0,
}}
>
<ContentEditable bind:text={largeValue} />
{#snippet template(args)}
<ContentEditable bind:text={largeValue} {...args} />
{/snippet}
</Story>
<Story
@@ -91,7 +97,9 @@ let longValue = $state(
letterSpacing: 0.3,
}}
>
<ContentEditable bind:text={spacedValue} />
{#snippet template(args)}
<ContentEditable bind:text={spacedValue} {...args} />
{/snippet}
</Story>
<Story
@@ -103,5 +111,7 @@ let longValue = $state(
letterSpacing: 0,
}}
>
<ContentEditable bind:text={longValue} />
{#snippet template(args)}
<ContentEditable bind:text={longValue} {...args} />
{/snippet}
</Story>

View File

@@ -59,7 +59,7 @@ const { Story } = defineMeta({
</script>
{/* @ts-ignore */ null}
<Story name="With hidden content">
{#snippet children(args)}
{#snippet template(args)}
<div class="p-12 bg-slate-100 min-h-[300px] flex justify-center items-start">
<ExpandableWrapper
{...args}
@@ -71,7 +71,7 @@ const { Story } = defineMeta({
{/* @ts-ignore */ null}
<Story name="Disabled" args={{ disabled: true }}>
{#snippet children(args)}
{#snippet template(args)}
<div class="p-12 bg-slate-100 min-h-[300px] flex justify-center items-start">
<ExpandableWrapper
{...args}
@@ -84,7 +84,7 @@ const { Story } = defineMeta({
{/* @ts-ignore */ null}
<Story name="With badge" args={{ badge: badgeSnippet }}>
{#snippet children(args)}
{#snippet template(args)}
<div class="p-12 bg-slate-100 min-h-[300px] flex justify-center items-start">
<ExpandableWrapper
{...args}

View File

@@ -17,15 +17,19 @@ const { Story } = defineMeta({
</script>
<Story name="Default">
<Footnote>
{#snippet template(args)}
<Footnote {...args}>
Footnote
</Footnote>
{/snippet}
</Story>
<Story name="With custom render">
<Footnote>
{#snippet template(args)}
<Footnote {...args}>
{#snippet render({ class: className })}
<span class={className}>Footnote</span>
{/snippet}
</Footnote>
{/snippet}
</Story>

View File

@@ -77,11 +77,13 @@ import XIcon from '@lucide/svelte/icons/x';
icon: chevronRightIcon,
}}
>
<IconButton onclick={() => console.log('Default clicked')}>
{#snippet template(args)}
<IconButton onclick={() => console.log('Default clicked')} {...args}>
{#snippet icon({ className })}
<ChevronRight class={className} />
{/snippet}
</IconButton>
{/snippet}
</Story>
<Story
@@ -91,11 +93,13 @@ import XIcon from '@lucide/svelte/icons/x';
disabled: true,
}}
>
{#snippet template(args)}
<div class="flex flex-col gap-4 items-center">
<IconButton disabled>
<IconButton disabled {...args}>
{#snippet icon({ className })}
<ChevronRight class={className} />
{/snippet}
</IconButton>
</div>
{/snippet}
</Story>

View File

@@ -50,33 +50,47 @@ const placeholder = 'Enter text';
<!-- Default Story -->
<Story name="Default" args={{ placeholder }}>
<Input bind:value={valueDefault} {placeholder} />
{#snippet template(args)}
<Input bind:value={valueDefault} {placeholder} {...args} />
{/snippet}
</Story>
<!-- Size Variants -->
<Story name="Small" args={{ placeholder }}>
<Input bind:value={valueSm} {placeholder} size="sm" />
{#snippet template(args)}
<Input bind:value={valueSm} {placeholder} size="sm" {...args} />
{/snippet}
</Story>
<Story name="Medium" args={{ placeholder }}>
<Input bind:value={valueMd} {placeholder} size="md" />
{#snippet template(args)}
<Input bind:value={valueMd} {placeholder} size="md" {...args} />
{/snippet}
</Story>
<Story name="Large" args={{ placeholder }}>
<Input bind:value={valueLg} {placeholder} size="lg" />
{#snippet template(args)}
<Input bind:value={valueLg} {placeholder} size="lg" {...args} />
{/snippet}
</Story>
<!-- Ghost Variant with Sizes -->
<Story name="Ghost Small" args={{ placeholder }}>
<Input bind:value={valueGhostSm} {placeholder} variant="ghost" size="sm" />
{#snippet template(args)}
<Input bind:value={valueGhostSm} {placeholder} variant="ghost" size="sm" {...args} />
{/snippet}
</Story>
<Story name="Ghost Medium" args={{ placeholder }}>
<Input bind:value={valueGhostMd} {placeholder} variant="ghost" size="md" />
{#snippet template(args)}
<Input bind:value={valueGhostMd} {placeholder} variant="ghost" size="md" {...args} />
{/snippet}
</Story>
<Story name="Ghost Large" args={{ placeholder }}>
<Input bind:value={valueGhostLg} {placeholder} variant="ghost" size="lg" />
{#snippet template(args)}
<Input bind:value={valueGhostLg} {placeholder} variant="ghost" size="lg" {...args} />
{/snippet}
</Story>
<!-- Size Comparison -->

View File

@@ -29,5 +29,7 @@ const { Story } = defineMeta({
</script>
<Story name="Default">
<Loader />
{#snippet template(args)}
<Loader {...args} />
{/snippet}
</Story>

View File

@@ -17,5 +17,7 @@ const { Story } = defineMeta({
</script>
<Story name="Default">
<Logo />
{#snippet template(args)}
<Logo {...args} />
{/snippet}
</Story>

View File

@@ -39,5 +39,7 @@ let defaultSearchValue = $state('');
placeholder: 'Type here...',
}}
>
<SearchBar bind:value={defaultSearchValue} placeholder="Type here..." />
{#snippet template(args)}
<SearchBar bind:value={defaultSearchValue} placeholder="Type here..." {...args} />
{/snippet}
</Story>

View File

@@ -192,21 +192,23 @@ import SettingsIcon from '@lucide/svelte/icons/settings';
content: welcomeContent,
}}
>
{#snippet template(args)}
<div class="grid grid-cols-1 lg:grid-cols-[auto_1fr] gap-x-6 sm:gap-x-8 md:gap-x-10 lg:gap-x-12 p-8 max-w-6xl mx-auto">
<Section index={1}>
<Section index={1} {...args}>
{#snippet title({ className })}
<h2 class={className}>Welcome</h2>
{/snippet}
{#snippet content({ className })}
<div class={cn(className, 'min-w-128')}>
<p class="text-lg text-text-muted">
This is the default section layout with a title and content area. The section uses a 2-column
grid layout with the title on the left and content on the right.
This is the default section layout with a title and content area. The section uses a
2-column grid layout with the title on the left and content on the right.
</p>
</div>
{/snippet}
</Section>
</div>
{/snippet}
</Story>
<Story
@@ -216,6 +218,7 @@ import SettingsIcon from '@lucide/svelte/icons/settings';
content: stickyContent,
}}
>
{#snippet template(args)}
<div class="h-[200vh]">
<div class="grid grid-cols-1 lg:grid-cols-[auto_1fr] gap-x-6 sm:gap-x-8 md:gap-x-10 lg:gap-x-12 p-8 max-w-6xl mx-auto">
<Section
@@ -223,6 +226,7 @@ import SettingsIcon from '@lucide/svelte/icons/settings';
index={1}
stickyTitle={true}
stickyOffset="20px"
{...args}
>
{#snippet title({ className })}
<h2 class={className}>Sticky Title</h2>
@@ -230,8 +234,8 @@ import SettingsIcon from '@lucide/svelte/icons/settings';
{#snippet content({ className })}
<div class={cn(className, 'min-w-128')}>
<p class="text-lg text-text-muted mb-4">
This section has a sticky title that stays fixed while you scroll through the content. Try
scrolling down to see the effect.
This section has a sticky title that stays fixed while you scroll through the content.
Try scrolling down to see the effect.
</p>
<div class="space-y-4">
<p class="text-text-muted">
@@ -239,20 +243,20 @@ import SettingsIcon from '@lucide/svelte/icons/settings';
incididunt ut labore et dolore magna aliqua.
</p>
<p class="text-text-muted">
Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea
commodo consequat.
Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip
ex ea commodo consequat.
</p>
<p class="text-text-muted">
Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat
nulla pariatur.
Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu
fugiat nulla pariatur.
</p>
<p class="text-text-muted">
Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt
mollim anim id est laborum.
</p>
<p class="text-text-muted">
Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque
laudantium.
Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium
doloremque laudantium.
</p>
</div>
</div>
@@ -260,6 +264,7 @@ import SettingsIcon from '@lucide/svelte/icons/settings';
</Section>
</div>
</div>
{/snippet}
</Story>
<Story
@@ -271,8 +276,9 @@ import SettingsIcon from '@lucide/svelte/icons/settings';
content: searchFontsContent,
}}
>
{#snippet template(args)}
<div class="grid grid-cols-1 lg:grid-cols-[auto_1fr] gap-x-6 sm:gap-x-8 md:gap-x-10 lg:gap-x-12 p-8 max-w-6xl mx-auto">
<Section index={1}>
<Section index={1} {...args}>
{#snippet title({ className })}
<h2 class={className}>Search Fonts</h2>
{/snippet}
@@ -285,21 +291,24 @@ import SettingsIcon from '@lucide/svelte/icons/settings';
{#snippet content({ className })}
<div class={cn(className, 'min-w-128')}>
<p class="text-lg text-text-muted">
Use the search bar to find fonts by name, or use the filters to browse by category, subset, or
provider.
Use the search bar to find fonts by name, or use the filters to browse by category, subset,
or provider.
</p>
</div>
{/snippet}
</Section>
</div>
{/snippet}
</Story>
<Story name="Multiple Sections" tags={['!autodocs']}>
{#snippet template(args)}
<div class="grid grid-cols-1 lg:grid-cols-[auto_1fr] gap-x-6 sm:gap-x-8 md:gap-x-10 lg:gap-x-12 p-8 max-w-6xl mx-auto">
<Section
id="section-1"
index={1}
stickyTitle={true}
{...args}
>
{#snippet title({ className })}
<h2 class={className}>Typography</h2>
@@ -324,6 +333,7 @@ import SettingsIcon from '@lucide/svelte/icons/settings';
id="section-2"
index={2}
stickyTitle={true}
{...args}
>
{#snippet title({ className })}
<h2 class={className}>Font Search</h2>
@@ -337,8 +347,8 @@ import SettingsIcon from '@lucide/svelte/icons/settings';
{#snippet content({ className })}
<div class={cn(className, 'min-w-128')}>
<p class="text-lg text-text-muted">
Search through our collection of fonts from Google Fonts and Fontshare. Use filters to narrow
down your selection.
Search through our collection of fonts from Google Fonts and Fontshare. Use filters to
narrow down your selection.
</p>
</div>
{/snippet}
@@ -348,6 +358,7 @@ import SettingsIcon from '@lucide/svelte/icons/settings';
id="section-3"
index={3}
stickyTitle={true}
{...args}
>
{#snippet title({ className })}
<h2 class={className}>Sample List</h2>
@@ -368,6 +379,7 @@ import SettingsIcon from '@lucide/svelte/icons/settings';
{/snippet}
</Section>
</div>
{/snippet}
</Story>
<Story
@@ -377,11 +389,13 @@ import SettingsIcon from '@lucide/svelte/icons/settings';
content: longContent,
}}
>
{#snippet template(args)}
<div class="grid grid-cols-1 lg:grid-cols-[auto_1fr] gap-x-6 sm:gap-x-8 md:gap-x-10 lg:gap-x-12 p-8 max-w-6xl mx-auto">
<Section
index={1}
stickyTitle={true}
stickyOffset="0px"
{...args}
>
{#snippet title({ className })}
<h2 class={className}>Long Content</h2>
@@ -390,22 +404,23 @@ import SettingsIcon from '@lucide/svelte/icons/settings';
<div class={cn(className, 'min-w-128')}>
<div class="space-y-6">
<p class="text-lg text-text-muted">
This section demonstrates how the sticky title behaves with longer content. As you scroll
through this content, the title remains visible at the top of the viewport.
This section demonstrates how the sticky title behaves with longer content. As you
scroll through this content, the title remains visible at the top of the viewport.
</p>
<div class="h-64 bg-background-40 rounded-lg flex items-center justify-center">
<span class="text-text-muted">Content block 1</span>
</div>
<p class="text-text-muted">
The sticky position is achieved using CSS position: sticky with a configurable top offset.
This is useful for long sections where you want to maintain context while scrolling.
The sticky position is achieved using CSS position: sticky with a configurable top
offset. This is useful for long sections where you want to maintain context while
scrolling.
</p>
<div class="h-64 bg-background-40 rounded-lg flex items-center justify-center">
<span class="text-text-muted">Content block 2</span>
</div>
<p class="text-text-muted">
The Intersection Observer API is used to detect when the section title scrolls out of view,
triggering the optional onTitleStatusChange callback.
The Intersection Observer API is used to detect when the section title scrolls out of
view, triggering the optional onTitleStatusChange callback.
</p>
<div class="h-64 bg-background-40 rounded-lg flex items-center justify-center">
<span class="text-text-muted">Content block 3</span>
@@ -415,6 +430,7 @@ import SettingsIcon from '@lucide/svelte/icons/settings';
{/snippet}
</Section>
</div>
{/snippet}
</Story>
<Story
@@ -424,8 +440,9 @@ import SettingsIcon from '@lucide/svelte/icons/settings';
content: minimalContent,
}}
>
{#snippet template(args)}
<div class="grid grid-cols-1 lg:grid-cols-[auto_1fr] gap-x-6 sm:gap-x-8 md:gap-x-10 lg:gap-x-12 p-8 max-w-6xl mx-auto">
<Section>
<Section {...args}>
{#snippet title({ className })}
<h2 class={className}>Minimal Section</h2>
{/snippet}
@@ -438,6 +455,7 @@ import SettingsIcon from '@lucide/svelte/icons/settings';
{/snippet}
</Section>
</div>
{/snippet}
</Story>
<Story
@@ -448,8 +466,9 @@ import SettingsIcon from '@lucide/svelte/icons/settings';
content: customContent,
}}
>
{#snippet template(args)}
<div class="grid grid-cols-1 lg:grid-cols-[auto_1fr] gap-x-6 sm:gap-x-8 md:gap-x-10 lg:gap-x-12 p-8 max-w-6xl mx-auto">
<Section index={42}>
<Section index={42} {...args}>
{#snippet title({ className })}
<h2 class={className}>Custom Content</h2>
{/snippet}
@@ -472,4 +491,5 @@ import SettingsIcon from '@lucide/svelte/icons/settings';
{/snippet}
</Section>
</div>
{/snippet}
</Story>

View File

@@ -29,13 +29,15 @@ const { Story } = defineMeta({
animate: true,
}}
>
{#snippet template(args)}
<div class="flex flex-col gap-4 p-4 w-full">
<div class="flex flex-col gap-2 p-4 border rounded-xl border-border-subtle bg-background-40">
<div class="flex items-center justify-between mb-4">
<Skeleton class="h-8 w-1/3" />
<Skeleton class="h-8 w-8 rounded-full" />
<Skeleton class="h-8 w-1/3" {...args} />
<Skeleton class="h-8 w-8 rounded-full" {...args} />
</div>
<Skeleton class="h-32 w-full" />
<Skeleton class="h-32 w-full" {...args} />
</div>
</div>
{/snippet}
</Story>

View File

@@ -44,13 +44,19 @@ let value = $state(50);
</script>
<Story name="Horizontal" args={{ orientation: 'horizontal', min: 0, max: 100, step: 1, value }}>
<Slider bind:value />
{#snippet template(args)}
<Slider bind:value {...args} />
{/snippet}
</Story>
<Story name="Vertical" args={{ orientation: 'vertical', min: 0, max: 100, step: 1, value }}>
<Slider bind:value />
{#snippet template(args)}
<Slider bind:value {...args} />
{/snippet}
</Story>
<Story name="With Label" args={{ orientation: 'horizontal', min: 0, max: 100, step: 1, value, label: 'SIZE' }}>
<Slider bind:value />
{#snippet template(args)}
<Slider bind:value {...args} />
{/snippet}
</Story>

View File

@@ -46,29 +46,35 @@ const emptyDataSet: string[] = [];
</script>
<Story name="Small Dataset">
{#snippet template(args)}
<div class="h-[400px]">
<VirtualList items={smallDataSet} itemHeight={40}>
<VirtualList items={smallDataSet} itemHeight={40} {...args}>
{#snippet children({ item })}
<div class="p-2 m-0.5 rounded-sm hover:bg-accent">{item}</div>
{/snippet}
</VirtualList>
</div>
{/snippet}
</Story>
<Story name="Medium Dataset (200 items)">
{#snippet template(args)}
<div class="h-[400px]">
<VirtualList items={mediumDataSet} itemHeight={40}>
<VirtualList items={mediumDataSet} itemHeight={40} {...args}>
{#snippet children({ item })}
<div class="p-2 m-0.5 rounded-sm hover:bg-accent">{item}</div>
{/snippet}
</VirtualList>
</div>
{/snippet}
</Story>
<Story name="Empty Dataset">
<VirtualList items={emptyDataSet} itemHeight={40}>
{#snippet template(args)}
<VirtualList items={emptyDataSet} itemHeight={40} {...args}>
{#snippet children({ item })}
<div class="p-2 m-0.5 rounded-sm hover:bg-accent">{item}</div>
{/snippet}
</VirtualList>
{/snippet}
</Story>