feat(StatusIndicator): Label wrapper for status display
This commit is contained in:
80
src/shared/ui/StatusIndicator/StatusIndicator.stories.svelte
Normal file
80
src/shared/ui/StatusIndicator/StatusIndicator.stories.svelte
Normal file
@@ -0,0 +1,80 @@
|
||||
<script module>
|
||||
import { defineMeta } from '@storybook/addon-svelte-csf';
|
||||
import StatusIndicator from './StatusIndicator.svelte';
|
||||
|
||||
const { Story } = defineMeta({
|
||||
title: 'Shared/StatusIndicator',
|
||||
component: StatusIndicator,
|
||||
tags: ['autodocs'],
|
||||
parameters: {
|
||||
docs: {
|
||||
description: {
|
||||
component: 'Coloured dot with optional label. Dot can pulse for live states.',
|
||||
},
|
||||
story: { inline: false },
|
||||
},
|
||||
layout: 'centered',
|
||||
},
|
||||
argTypes: {
|
||||
status: {
|
||||
control: 'select',
|
||||
options: ['active', 'inactive', 'warning', 'error'],
|
||||
description: 'Status type',
|
||||
},
|
||||
label: {
|
||||
control: 'text',
|
||||
description: 'Optional label text',
|
||||
},
|
||||
pulse: {
|
||||
control: 'boolean',
|
||||
description: 'Enable pulsing animation',
|
||||
defaultValue: false,
|
||||
},
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
<Story
|
||||
name="Active status"
|
||||
args={{ status: 'active', label: 'Active' }}
|
||||
>
|
||||
{#snippet template()}
|
||||
<StatusIndicator status="active" label="Active" />
|
||||
{/snippet}
|
||||
</Story>
|
||||
|
||||
<Story
|
||||
name="Inactive status"
|
||||
args={{ status: 'inactive', label: 'Inactive' }}
|
||||
>
|
||||
{#snippet template()}
|
||||
<StatusIndicator status="inactive" label="Inactive" />
|
||||
{/snippet}
|
||||
</Story>
|
||||
|
||||
<Story
|
||||
name="Warning status"
|
||||
args={{ status: 'warning', label: 'Warning' }}
|
||||
>
|
||||
{#snippet template()}
|
||||
<StatusIndicator status="warning" label="Warning" />
|
||||
{/snippet}
|
||||
</Story>
|
||||
|
||||
<Story
|
||||
name="Error status"
|
||||
args={{ status: 'error', label: 'Error' }}
|
||||
>
|
||||
{#snippet template()}
|
||||
<StatusIndicator status="error" label="Error" />
|
||||
{/snippet}
|
||||
</Story>
|
||||
|
||||
<Story
|
||||
name="With pulse"
|
||||
args={{ status: 'active', label: 'Connected', pulse: true }}
|
||||
>
|
||||
{#snippet template()}
|
||||
<StatusIndicator status="active" label="Connected" pulse={true} />
|
||||
{/snippet}
|
||||
</Story>
|
||||
45
src/shared/ui/StatusIndicator/StatusIndicator.svelte
Normal file
45
src/shared/ui/StatusIndicator/StatusIndicator.svelte
Normal file
@@ -0,0 +1,45 @@
|
||||
<!--
|
||||
Component: StatusIndicator
|
||||
Coloured dot with optional label. Dot can pulse for live states.
|
||||
-->
|
||||
<script lang="ts">
|
||||
import { cn } from '$shared/shadcn/utils/shadcn-utils';
|
||||
import { Label } from '$shared/ui';
|
||||
|
||||
type Status = 'active' | 'inactive' | 'warning' | 'error';
|
||||
|
||||
const statusConfig: Record<Status, string> = {
|
||||
active: 'bg-green-500',
|
||||
inactive: 'bg-neutral-400',
|
||||
warning: 'bg-yellow-500',
|
||||
error: 'bg-brand',
|
||||
};
|
||||
|
||||
interface Props {
|
||||
status: Status;
|
||||
label?: string;
|
||||
pulse?: boolean;
|
||||
class?: string;
|
||||
}
|
||||
|
||||
let {
|
||||
status,
|
||||
label,
|
||||
pulse = false,
|
||||
class: className,
|
||||
}: Props = $props();
|
||||
</script>
|
||||
|
||||
<div class={cn('flex items-center gap-2', className)}>
|
||||
<span
|
||||
class={cn(
|
||||
'w-1.5 h-1.5 rounded-full',
|
||||
statusConfig[status],
|
||||
pulse && 'animate-pulse',
|
||||
)}
|
||||
></span>
|
||||
|
||||
{#if label}
|
||||
<Label variant="muted" size="xs">{label}</Label>
|
||||
{/if}
|
||||
</div>
|
||||
Reference in New Issue
Block a user