feat(Stat): Label wrapper for statistics
This commit is contained in:
136
src/shared/ui/Stat/Stat.stories.svelte
Normal file
136
src/shared/ui/Stat/Stat.stories.svelte
Normal file
@@ -0,0 +1,136 @@
|
|||||||
|
<script module>
|
||||||
|
import { defineMeta } from '@storybook/addon-svelte-csf';
|
||||||
|
import Stat from './Stat.svelte';
|
||||||
|
|
||||||
|
const { Story } = defineMeta({
|
||||||
|
title: 'Shared/Stat',
|
||||||
|
component: Stat,
|
||||||
|
tags: ['autodocs'],
|
||||||
|
parameters: {
|
||||||
|
docs: {
|
||||||
|
description: {
|
||||||
|
component: 'A single key:value pair in Space Mono. Optional trailing divider.',
|
||||||
|
},
|
||||||
|
story: { inline: false },
|
||||||
|
},
|
||||||
|
layout: 'centered',
|
||||||
|
},
|
||||||
|
argTypes: {
|
||||||
|
label: {
|
||||||
|
control: 'text',
|
||||||
|
description: 'Stat label/key',
|
||||||
|
defaultValue: 'Label',
|
||||||
|
},
|
||||||
|
value: {
|
||||||
|
control: 'text',
|
||||||
|
description: 'Stat value',
|
||||||
|
defaultValue: 'Value',
|
||||||
|
},
|
||||||
|
variant: {
|
||||||
|
control: 'select',
|
||||||
|
options: ['default', 'accent', 'muted', 'success', 'warning', 'error'],
|
||||||
|
description: 'Value variant',
|
||||||
|
defaultValue: 'default',
|
||||||
|
},
|
||||||
|
separator: {
|
||||||
|
control: 'boolean',
|
||||||
|
description: 'Show trailing divider',
|
||||||
|
defaultValue: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<Story
|
||||||
|
name="Default/Basic"
|
||||||
|
args={{ label: 'Label', value: 'Value' }}
|
||||||
|
parameters={{ docs: { description: { story: 'Standard stat with label and value' } } }}
|
||||||
|
>
|
||||||
|
{#snippet template()}
|
||||||
|
<Stat label="Label" value="Value" />
|
||||||
|
{/snippet}
|
||||||
|
</Story>
|
||||||
|
|
||||||
|
<Story
|
||||||
|
name="With string value"
|
||||||
|
args={{ label: 'Font', value: 'Inter' }}
|
||||||
|
>
|
||||||
|
{#snippet template()}
|
||||||
|
<Stat label="Font" value="Inter" />
|
||||||
|
{/snippet}
|
||||||
|
</Story>
|
||||||
|
|
||||||
|
<Story
|
||||||
|
name="With number value"
|
||||||
|
args={{ label: 'Weight', value: 400 }}
|
||||||
|
>
|
||||||
|
{#snippet template()}
|
||||||
|
<Stat label="Weight" value={400} />
|
||||||
|
{/snippet}
|
||||||
|
</Story>
|
||||||
|
|
||||||
|
<Story
|
||||||
|
name="With separator"
|
||||||
|
args={{ label: 'Size', value: '16px', separator: true }}
|
||||||
|
>
|
||||||
|
{#snippet template()}
|
||||||
|
<div class="flex items-center">
|
||||||
|
<Stat label="Size" value="16px" separator />
|
||||||
|
<Stat label="Line" value="1.5" />
|
||||||
|
</div>
|
||||||
|
{/snippet}
|
||||||
|
</Story>
|
||||||
|
|
||||||
|
<Story
|
||||||
|
name="Default variant"
|
||||||
|
args={{ variant: 'default', label: 'Status', value: 'Active' }}
|
||||||
|
>
|
||||||
|
{#snippet template()}
|
||||||
|
<Stat label="Status" value="Active" variant="default" />
|
||||||
|
{/snippet}
|
||||||
|
</Story>
|
||||||
|
|
||||||
|
<Story
|
||||||
|
name="Accent variant"
|
||||||
|
args={{ variant: 'accent', label: 'Status', value: 'Active' }}
|
||||||
|
>
|
||||||
|
{#snippet template()}
|
||||||
|
<Stat label="Status" value="Active" variant="accent" />
|
||||||
|
{/snippet}
|
||||||
|
</Story>
|
||||||
|
|
||||||
|
<Story
|
||||||
|
name="Muted variant"
|
||||||
|
args={{ variant: 'muted', label: 'Status', value: 'Inactive' }}
|
||||||
|
>
|
||||||
|
{#snippet template()}
|
||||||
|
<Stat label="Status" value="Inactive" variant="muted" />
|
||||||
|
{/snippet}
|
||||||
|
</Story>
|
||||||
|
|
||||||
|
<Story
|
||||||
|
name="Success variant"
|
||||||
|
args={{ variant: 'success', label: 'Status', value: 'Success' }}
|
||||||
|
>
|
||||||
|
{#snippet template()}
|
||||||
|
<Stat label="Status" value="Success" variant="success" />
|
||||||
|
{/snippet}
|
||||||
|
</Story>
|
||||||
|
|
||||||
|
<Story
|
||||||
|
name="Warning variant"
|
||||||
|
args={{ variant: 'warning', label: 'Status', value: 'Warning' }}
|
||||||
|
>
|
||||||
|
{#snippet template()}
|
||||||
|
<Stat label="Status" value="Warning" variant="warning" />
|
||||||
|
{/snippet}
|
||||||
|
</Story>
|
||||||
|
|
||||||
|
<Story
|
||||||
|
name="Error variant"
|
||||||
|
args={{ variant: 'error', label: 'Status', value: 'Error' }}
|
||||||
|
>
|
||||||
|
{#snippet template()}
|
||||||
|
<Stat label="Status" value="Error" variant="error" />
|
||||||
|
{/snippet}
|
||||||
|
</Story>
|
||||||
34
src/shared/ui/Stat/Stat.svelte
Normal file
34
src/shared/ui/Stat/Stat.svelte
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
<!--
|
||||||
|
Component: Stat
|
||||||
|
A single key:value pair in Space Mono. Optional trailing divider.
|
||||||
|
-->
|
||||||
|
<script lang="ts">
|
||||||
|
import { cn } from '$shared/shadcn/utils/shadcn-utils';
|
||||||
|
import { Label } from '$shared/ui';
|
||||||
|
import type { ComponentProps } from 'svelte';
|
||||||
|
|
||||||
|
interface Props extends Pick<ComponentProps<typeof Label>, 'variant'> {
|
||||||
|
label: string;
|
||||||
|
value: string | number;
|
||||||
|
/** Renders a 1px vertical divider after the stat. */
|
||||||
|
separator?: boolean;
|
||||||
|
class?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
let {
|
||||||
|
label,
|
||||||
|
value,
|
||||||
|
variant = 'default',
|
||||||
|
separator = false,
|
||||||
|
class: className,
|
||||||
|
}: Props = $props();
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div class={cn('flex items-center gap-1', className)}>
|
||||||
|
<Label variant="muted" size="xs">{label}:</Label>
|
||||||
|
<Label {variant} size="xs" bold>{value}</Label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{#if separator}
|
||||||
|
<div class="w-px h-2 bg-black/10 dark:bg-white/10"></div>
|
||||||
|
{/if}
|
||||||
Reference in New Issue
Block a user