feat(Label): component redesign with complete storybook coverage
This commit is contained in:
213
src/shared/ui/Label/Label.stories.svelte
Normal file
213
src/shared/ui/Label/Label.stories.svelte
Normal file
@@ -0,0 +1,213 @@
|
|||||||
|
<script module>
|
||||||
|
import { defineMeta } from '@storybook/addon-svelte-csf';
|
||||||
|
import Label from './Label.svelte';
|
||||||
|
|
||||||
|
const { Story } = defineMeta({
|
||||||
|
title: 'Shared/Label',
|
||||||
|
component: Label,
|
||||||
|
tags: ['autodocs'],
|
||||||
|
parameters: {
|
||||||
|
docs: {
|
||||||
|
description: {
|
||||||
|
component: 'Inline monospace label. The base primitive for all micrographic text.',
|
||||||
|
},
|
||||||
|
story: { inline: false },
|
||||||
|
},
|
||||||
|
layout: 'centered',
|
||||||
|
},
|
||||||
|
argTypes: {
|
||||||
|
variant: {
|
||||||
|
control: 'select',
|
||||||
|
options: ['default', 'accent', 'muted', 'success', 'warning', 'error'],
|
||||||
|
defaultValue: 'default',
|
||||||
|
},
|
||||||
|
size: {
|
||||||
|
control: 'select',
|
||||||
|
options: ['xs', 'sm', 'md'],
|
||||||
|
defaultValue: 'sm',
|
||||||
|
},
|
||||||
|
uppercase: {
|
||||||
|
control: 'boolean',
|
||||||
|
defaultValue: true,
|
||||||
|
},
|
||||||
|
bold: {
|
||||||
|
control: 'boolean',
|
||||||
|
defaultValue: false,
|
||||||
|
},
|
||||||
|
iconPosition: {
|
||||||
|
control: 'select',
|
||||||
|
options: ['left', 'right'],
|
||||||
|
defaultValue: 'left',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
import AlertTriangleIcon from '@lucide/svelte/icons/alert-triangle';
|
||||||
|
import CheckIcon from '@lucide/svelte/icons/check';
|
||||||
|
import CircleIcon from '@lucide/svelte/icons/circle';
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<Story
|
||||||
|
name="Default/Basic"
|
||||||
|
parameters={{ docs: { description: { story: 'Standard label with default styling' } } }}
|
||||||
|
>
|
||||||
|
{#snippet template(args)}
|
||||||
|
<Label {...args}>Default Label</Label>
|
||||||
|
{/snippet}
|
||||||
|
</Story>
|
||||||
|
|
||||||
|
<Story name="All sizes">
|
||||||
|
{#snippet template()}
|
||||||
|
<div class="flex flex-col gap-4">
|
||||||
|
<Label size="xs">Size XS Label</Label>
|
||||||
|
<Label size="sm">Size SM Label</Label>
|
||||||
|
<Label size="md">Size MD Label</Label>
|
||||||
|
</div>
|
||||||
|
{/snippet}
|
||||||
|
</Story>
|
||||||
|
|
||||||
|
<Story
|
||||||
|
name="Default variant"
|
||||||
|
args={{ variant: 'default', size: 'sm' }}
|
||||||
|
>
|
||||||
|
{#snippet template(args)}
|
||||||
|
<Label {...args}>Default Label</Label>
|
||||||
|
{/snippet}
|
||||||
|
</Story>
|
||||||
|
|
||||||
|
<Story
|
||||||
|
name="Accent variant"
|
||||||
|
args={{ variant: 'accent', size: 'sm' }}
|
||||||
|
>
|
||||||
|
{#snippet template(args)}
|
||||||
|
<Label {...args}>Accent Label</Label>
|
||||||
|
{/snippet}
|
||||||
|
</Story>
|
||||||
|
|
||||||
|
<Story
|
||||||
|
name="Muted variant"
|
||||||
|
args={{ variant: 'muted', size: 'sm' }}
|
||||||
|
>
|
||||||
|
{#snippet template(args)}
|
||||||
|
<Label {...args}>Muted Label</Label>
|
||||||
|
{/snippet}
|
||||||
|
</Story>
|
||||||
|
|
||||||
|
<Story
|
||||||
|
name="Success variant"
|
||||||
|
args={{ variant: 'success', size: 'sm' }}
|
||||||
|
>
|
||||||
|
{#snippet template(args)}
|
||||||
|
<Label {...args}>Success Label</Label>
|
||||||
|
{/snippet}
|
||||||
|
</Story>
|
||||||
|
|
||||||
|
<Story
|
||||||
|
name="Warning variant"
|
||||||
|
args={{ variant: 'warning', size: 'sm' }}
|
||||||
|
>
|
||||||
|
{#snippet template(args)}
|
||||||
|
<Label {...args}>Warning Label</Label>
|
||||||
|
{/snippet}
|
||||||
|
</Story>
|
||||||
|
|
||||||
|
<Story
|
||||||
|
name="Error variant"
|
||||||
|
args={{ variant: 'error', size: 'sm' }}
|
||||||
|
>
|
||||||
|
{#snippet template(args)}
|
||||||
|
<Label {...args}>Error Label</Label>
|
||||||
|
{/snippet}
|
||||||
|
</Story>
|
||||||
|
|
||||||
|
<Story name="All variants">
|
||||||
|
{#snippet template()}
|
||||||
|
<div class="flex flex-col gap-4">
|
||||||
|
<Label variant="default">Default</Label>
|
||||||
|
<Label variant="accent">Accent</Label>
|
||||||
|
<Label variant="muted">Muted</Label>
|
||||||
|
<Label variant="success">Success</Label>
|
||||||
|
<Label variant="warning">Warning</Label>
|
||||||
|
<Label variant="error">Error</Label>
|
||||||
|
</div>
|
||||||
|
{/snippet}
|
||||||
|
</Story>
|
||||||
|
|
||||||
|
<Story
|
||||||
|
name="Uppercase"
|
||||||
|
args={{ uppercase: true, size: 'sm' }}
|
||||||
|
>
|
||||||
|
{#snippet template(args)}
|
||||||
|
<Label {...args}>Uppercase Label</Label>
|
||||||
|
{/snippet}
|
||||||
|
</Story>
|
||||||
|
|
||||||
|
<Story
|
||||||
|
name="Lowercase"
|
||||||
|
args={{ uppercase: false, size: 'sm' }}
|
||||||
|
>
|
||||||
|
{#snippet template(args)}
|
||||||
|
<Label {...args}>lowercase label</Label>
|
||||||
|
{/snippet}
|
||||||
|
</Story>
|
||||||
|
|
||||||
|
<Story
|
||||||
|
name="Bold"
|
||||||
|
args={{ bold: true, size: 'sm' }}
|
||||||
|
>
|
||||||
|
{#snippet template(args)}
|
||||||
|
<Label {...args}>Bold Label</Label>
|
||||||
|
{/snippet}
|
||||||
|
</Story>
|
||||||
|
|
||||||
|
<Story
|
||||||
|
name="With icon (left)"
|
||||||
|
args={{ variant: 'default', size: 'sm', iconPosition: 'left' }}
|
||||||
|
>
|
||||||
|
{#snippet template(args)}
|
||||||
|
<Label {...args}>
|
||||||
|
{#snippet icon()}
|
||||||
|
<CircleIcon size={10} />
|
||||||
|
{/snippet}
|
||||||
|
Label with icon
|
||||||
|
</Label>
|
||||||
|
{/snippet}
|
||||||
|
</Story>
|
||||||
|
|
||||||
|
<Story
|
||||||
|
name="With icon (right)"
|
||||||
|
args={{ variant: 'default', size: 'sm', iconPosition: 'right' }}
|
||||||
|
>
|
||||||
|
{#snippet template(args)}
|
||||||
|
<Label {...args}>
|
||||||
|
Label with icon
|
||||||
|
{#snippet icon()}
|
||||||
|
<CircleIcon size={10} />
|
||||||
|
{/snippet}
|
||||||
|
</Label>
|
||||||
|
{/snippet}
|
||||||
|
</Story>
|
||||||
|
|
||||||
|
<Story name="Success with check icon">
|
||||||
|
{#snippet template()}
|
||||||
|
<Label variant="success" size="sm">
|
||||||
|
{#snippet icon()}
|
||||||
|
<CheckIcon size={10} />
|
||||||
|
{/snippet}
|
||||||
|
Completed
|
||||||
|
</Label>
|
||||||
|
{/snippet}
|
||||||
|
</Story>
|
||||||
|
|
||||||
|
<Story name="Warning with alert icon">
|
||||||
|
{#snippet template()}
|
||||||
|
<Label variant="warning" size="sm">
|
||||||
|
{#snippet icon()}
|
||||||
|
<AlertTriangleIcon size={10} />
|
||||||
|
{/snippet}
|
||||||
|
Attention Required
|
||||||
|
</Label>
|
||||||
|
{/snippet}
|
||||||
|
</Story>
|
||||||
@@ -1,45 +1,60 @@
|
|||||||
|
<!--
|
||||||
|
Component: Label
|
||||||
|
Inline monospace label. The base primitive for all micrographic text.
|
||||||
|
-->
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { cn } from '$shared/shadcn/utils/shadcn-utils';
|
import { cn } from '$shared/shadcn/utils/shadcn-utils';
|
||||||
|
import type { Snippet } from 'svelte';
|
||||||
|
import {
|
||||||
|
type LabelSize,
|
||||||
|
type LabelVariant,
|
||||||
|
labelSizeConfig,
|
||||||
|
labelVariantConfig,
|
||||||
|
} from './config';
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
text?: string;
|
variant?: LabelVariant;
|
||||||
align?: 'left' | 'right' | 'center';
|
size?: LabelSize;
|
||||||
size?: 'sm' | 'md' | 'lg';
|
uppercase?: boolean;
|
||||||
onlyText?: boolean;
|
bold?: boolean;
|
||||||
|
icon?: Snippet;
|
||||||
|
iconPosition?: 'left' | 'right';
|
||||||
|
children?: Snippet;
|
||||||
class?: string;
|
class?: string;
|
||||||
}
|
}
|
||||||
const {
|
|
||||||
text,
|
let {
|
||||||
align = 'left',
|
variant = 'default',
|
||||||
size = 'md',
|
size = 'sm',
|
||||||
onlyText = false,
|
uppercase = true,
|
||||||
|
bold = false,
|
||||||
|
icon,
|
||||||
|
iconPosition = 'left',
|
||||||
|
children,
|
||||||
class: className,
|
class: className,
|
||||||
}: Props = $props();
|
}: Props = $props();
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div
|
<span
|
||||||
class={cn(
|
class={cn(
|
||||||
'grid grid-rows-1 gap-2 items-center w-auto',
|
"font-['Space_Mono'] tracking-widest leading-none",
|
||||||
align === 'left' && 'grid-cols-[max-content_1fr]',
|
'inline-flex items-center gap-1.5',
|
||||||
align === 'center' && 'grid-cols-[1fr_max-content_1fr]',
|
labelSizeConfig[size],
|
||||||
align === 'right' && 'grig-cols-[1fr_max-content]',
|
labelVariantConfig[variant],
|
||||||
|
uppercase && 'uppercase',
|
||||||
|
bold && 'font-bold',
|
||||||
className,
|
className,
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
{#if align !== 'left'}
|
{#if icon && iconPosition === 'left'}
|
||||||
<div class={cn('h-px w-full bg-gray-400/50', onlyText && 'bg-transparent')}></div>
|
<span class="inline-flex">{@render icon()}</span>
|
||||||
{/if}
|
{/if}
|
||||||
<div
|
|
||||||
class={cn(
|
{#if children}
|
||||||
'text-gray-400 uppercase',
|
<span>{@render children()}</span>
|
||||||
size === 'sm' && 'text-[0.5rem]',
|
|
||||||
size === 'md' && 'text-[0.625rem]',
|
|
||||||
size === 'lg' && 'text-[0.75rem]',
|
|
||||||
)}
|
|
||||||
>
|
|
||||||
{text}
|
|
||||||
</div>
|
|
||||||
{#if align !== 'right'}
|
|
||||||
<div class={cn('h-px w-full bg-gray-400/50', onlyText && 'bg-transparent')}></div>
|
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
|
||||||
|
{#if icon && iconPosition === 'right'}
|
||||||
|
<span class="inline-flex">{@render icon()}</span>
|
||||||
|
{/if}
|
||||||
|
</span>
|
||||||
|
|||||||
Reference in New Issue
Block a user