feature/project-redesign #28

Merged
ilia merged 88 commits from feature/project-redesign into main 2026-03-02 19:46:39 +00:00
2 changed files with 257 additions and 29 deletions
Showing only changes of commit 12d57c59c1 - Show all commits

View 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>

View File

@@ -1,45 +1,60 @@
<!--
Component: Label
Inline monospace label. The base primitive for all micrographic text.
-->
<script lang="ts">
import { cn } from '$shared/shadcn/utils/shadcn-utils';
import type { Snippet } from 'svelte';
import {
type LabelSize,
type LabelVariant,
labelSizeConfig,
labelVariantConfig,
} from './config';
interface Props {
text?: string;
align?: 'left' | 'right' | 'center';
size?: 'sm' | 'md' | 'lg';
onlyText?: boolean;
variant?: LabelVariant;
size?: LabelSize;
uppercase?: boolean;
bold?: boolean;
icon?: Snippet;
iconPosition?: 'left' | 'right';
children?: Snippet;
class?: string;
}
const {
text,
align = 'left',
size = 'md',
onlyText = false,
let {
variant = 'default',
size = 'sm',
uppercase = true,
bold = false,
icon,
iconPosition = 'left',
children,
class: className,
}: Props = $props();
</script>
<div
<span
class={cn(
'grid grid-rows-1 gap-2 items-center w-auto',
align === 'left' && 'grid-cols-[max-content_1fr]',
align === 'center' && 'grid-cols-[1fr_max-content_1fr]',
align === 'right' && 'grig-cols-[1fr_max-content]',
"font-['Space_Mono'] tracking-widest leading-none",
'inline-flex items-center gap-1.5',
labelSizeConfig[size],
labelVariantConfig[variant],
uppercase && 'uppercase',
bold && 'font-bold',
className,
)}
>
{#if align !== 'left'}
<div class={cn('h-px w-full bg-gray-400/50', onlyText && 'bg-transparent')}></div>
{#if icon && iconPosition === 'left'}
<span class="inline-flex">{@render icon()}</span>
{/if}
<div
class={cn(
'text-gray-400 uppercase',
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 children}
<span>{@render children()}</span>
{/if}
</div>
{#if icon && iconPosition === 'right'}
<span class="inline-flex">{@render icon()}</span>
{/if}
</span>