feat(DotIndicator): create DotIndicator ui component
This commit is contained in:
189
src/shared/ui/DotIndicator/DotIndicator.stories.svelte
Normal file
189
src/shared/ui/DotIndicator/DotIndicator.stories.svelte
Normal file
@@ -0,0 +1,189 @@
|
||||
<script module>
|
||||
import { defineMeta } from '@storybook/addon-svelte-csf';
|
||||
import DotIndicator from './DotIndicator.svelte';
|
||||
|
||||
const { Story } = defineMeta({
|
||||
title: 'Shared/DotIndicator',
|
||||
component: DotIndicator,
|
||||
tags: ['autodocs'],
|
||||
parameters: {
|
||||
docs: {
|
||||
description: {
|
||||
component:
|
||||
'Circular status indicator with size options and pulse animation. Use for showing online/offline status, loading states, or feedback indicators.',
|
||||
},
|
||||
story: { inline: false },
|
||||
},
|
||||
layout: 'centered',
|
||||
},
|
||||
argTypes: {
|
||||
variant: {
|
||||
control: 'select',
|
||||
options: ['online', 'offline', 'busy', 'away', 'success', 'warning', 'error'],
|
||||
description: 'Status variant of the indicator',
|
||||
},
|
||||
size: {
|
||||
control: 'select',
|
||||
options: ['sm', 'md', 'lg'],
|
||||
description: 'Size of the indicator',
|
||||
},
|
||||
pulse: {
|
||||
control: 'boolean',
|
||||
description: 'Enable pulse animation',
|
||||
},
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
<script lang="ts">
|
||||
import type { Snippet } from 'svelte';
|
||||
</script>
|
||||
|
||||
<Story name="Default">
|
||||
{#snippet template(args)}
|
||||
<DotIndicator {...args} />
|
||||
{/snippet}
|
||||
</Story>
|
||||
|
||||
<Story name="Variants">
|
||||
{#snippet template(args)}
|
||||
<div class="flex gap-4 items-center">
|
||||
<div class="flex items-center gap-2">
|
||||
<DotIndicator variant="online" {...args} />
|
||||
<span class="text-sm">Online</span>
|
||||
</div>
|
||||
<div class="flex items-center gap-2">
|
||||
<DotIndicator variant="offline" {...args} />
|
||||
<span class="text-sm">Offline</span>
|
||||
</div>
|
||||
<div class="flex items-center gap-2">
|
||||
<DotIndicator variant="busy" {...args} />
|
||||
<span class="text-sm">Busy</span>
|
||||
</div>
|
||||
<div class="flex items-center gap-2">
|
||||
<DotIndicator variant="away" {...args} />
|
||||
<span class="text-sm">Away</span>
|
||||
</div>
|
||||
<div class="flex items-center gap-2">
|
||||
<DotIndicator variant="success" {...args} />
|
||||
<span class="text-sm">Success</span>
|
||||
</div>
|
||||
<div class="flex items-center gap-2">
|
||||
<DotIndicator variant="warning" {...args} />
|
||||
<span class="text-sm">Warning</span>
|
||||
</div>
|
||||
<div class="flex items-center gap-2">
|
||||
<DotIndicator variant="error" {...args} />
|
||||
<span class="text-sm">Error</span>
|
||||
</div>
|
||||
</div>
|
||||
{/snippet}
|
||||
</Story>
|
||||
|
||||
<Story name="Sizes">
|
||||
{#snippet template(args)}
|
||||
<div class="flex gap-4 items-center">
|
||||
<div class="flex items-center gap-2">
|
||||
<DotIndicator size="sm" {...args} />
|
||||
<span class="text-sm text-xs">Small</span>
|
||||
</div>
|
||||
<div class="flex items-center gap-2">
|
||||
<DotIndicator size="md" {...args} />
|
||||
<span class="text-sm">Medium</span>
|
||||
</div>
|
||||
<div class="flex items-center gap-2">
|
||||
<DotIndicator size="lg" {...args} />
|
||||
<span class="text-sm">Large</span>
|
||||
</div>
|
||||
</div>
|
||||
{/snippet}
|
||||
</Story>
|
||||
|
||||
<Story name="With Pulse">
|
||||
{#snippet template(args)}
|
||||
<div class="flex gap-4 items-center">
|
||||
<div class="flex items-center gap-2">
|
||||
<DotIndicator variant="online" pulse {...args} />
|
||||
<span class="text-sm">Online</span>
|
||||
</div>
|
||||
<div class="flex items-center gap-2">
|
||||
<DotIndicator variant="busy" pulse {...args} />
|
||||
<span class="text-sm">Busy</span>
|
||||
</div>
|
||||
<div class="flex items-center gap-2">
|
||||
<DotIndicator variant="away" pulse {...args} />
|
||||
<span class="text-sm">Away</span>
|
||||
</div>
|
||||
</div>
|
||||
{/snippet}
|
||||
</Story>
|
||||
|
||||
<Story name="All Combinations">
|
||||
{#snippet template(args)}
|
||||
<div class="space-y-3">
|
||||
<h3 class="text-sm font-semibold">Sizes</h3>
|
||||
<div class="flex gap-4 items-center">
|
||||
<div class="flex items-center gap-2">
|
||||
<DotIndicator variant="online" size="sm" {...args} />
|
||||
<span class="text-sm text-xs">Small</span>
|
||||
</div>
|
||||
<div class="flex items-center gap-2">
|
||||
<DotIndicator variant="online" size="md" {...args} />
|
||||
<span class="text-sm">Medium</span>
|
||||
</div>
|
||||
<div class="flex items-center gap-2">
|
||||
<DotIndicator variant="online" size="lg" {...args} />
|
||||
<span class="text-sm">Large</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h3 class="text-sm font-semibold mt-4">Status Variants</h3>
|
||||
<div class="flex gap-4 items-center">
|
||||
<div class="flex items-center gap-2">
|
||||
<DotIndicator variant="online" {...args} />
|
||||
<span class="text-sm">Online</span>
|
||||
</div>
|
||||
<div class="flex items-center gap-2">
|
||||
<DotIndicator variant="offline" {...args} />
|
||||
<span class="text-sm">Offline</span>
|
||||
</div>
|
||||
<div class="flex items-center gap-2">
|
||||
<DotIndicator variant="busy" {...args} />
|
||||
<span class="text-sm">Busy</span>
|
||||
</div>
|
||||
<div class="flex items-center gap-2">
|
||||
<DotIndicator variant="away" {...args} />
|
||||
<span class="text-sm">Away</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h3 class="text-sm font-semibold mt-4">Feedback Variants</h3>
|
||||
<div class="flex gap-4 items-center">
|
||||
<div class="flex items-center gap-2">
|
||||
<DotIndicator variant="success" {...args} />
|
||||
<span class="text-sm">Success</span>
|
||||
</div>
|
||||
<div class="flex items-center gap-2">
|
||||
<DotIndicator variant="warning" {...args} />
|
||||
<span class="text-sm">Warning</span>
|
||||
</div>
|
||||
<div class="flex items-center gap-2">
|
||||
<DotIndicator variant="error" {...args} />
|
||||
<span class="text-sm">Error</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h3 class="text-sm font-semibold mt-4">With Pulse Animation</h3>
|
||||
<div class="flex gap-4 items-center">
|
||||
<div class="flex items-center gap-2">
|
||||
<DotIndicator variant="online" pulse {...args} />
|
||||
<span class="text-sm">Online</span>
|
||||
</div>
|
||||
<div class="flex items-center gap-2">
|
||||
<DotIndicator variant="busy" pulse {...args} />
|
||||
<span class="text-sm">Busy</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{/snippet}
|
||||
</Story>
|
||||
60
src/shared/ui/DotIndicator/DotIndicator.svelte
Normal file
60
src/shared/ui/DotIndicator/DotIndicator.svelte
Normal file
@@ -0,0 +1,60 @@
|
||||
<!--
|
||||
Component: DotIndicator
|
||||
Circular status indicator with size options and pulse animation
|
||||
-->
|
||||
<script lang="ts">
|
||||
interface Props {
|
||||
/**
|
||||
* Status variant of the indicator
|
||||
* @default online
|
||||
*/
|
||||
variant?: 'online' | 'offline' | 'busy' | 'away' | 'success' | 'warning' | 'error';
|
||||
/**
|
||||
* Size of the indicator
|
||||
* @default md
|
||||
*/
|
||||
size?: 'sm' | 'md' | 'lg';
|
||||
/**
|
||||
* Enable pulse animation
|
||||
* @default false
|
||||
*/
|
||||
pulse?: boolean;
|
||||
}
|
||||
|
||||
const {
|
||||
variant = 'online',
|
||||
size = 'md',
|
||||
pulse = false,
|
||||
}: Props = $props();
|
||||
|
||||
const baseClasses = 'rounded-full';
|
||||
|
||||
const variantClasses = $derived(
|
||||
variant === 'online' || variant === 'success'
|
||||
? 'bg-green-500'
|
||||
: variant === 'offline'
|
||||
? 'bg-gray-400'
|
||||
: variant === 'busy' || variant === 'error'
|
||||
? 'bg-red-500'
|
||||
: variant === 'away'
|
||||
? 'bg-yellow-500'
|
||||
: variant === 'warning'
|
||||
? 'bg-yellow-500'
|
||||
: 'bg-gray-400',
|
||||
);
|
||||
|
||||
const sizeClasses = $derived(
|
||||
size === 'sm'
|
||||
? 'w-1.5 h-1.5'
|
||||
: size === 'lg'
|
||||
? 'w-3 h-3'
|
||||
: 'w-2 h-2',
|
||||
);
|
||||
|
||||
const pulseAnimation = $derived(pulse && 'animate-pulse');
|
||||
</script>
|
||||
|
||||
<span
|
||||
class="{baseClasses} {variantClasses} {sizeClasses} {pulseAnimation}"
|
||||
aria-label="Status indicator"
|
||||
></span>
|
||||
Reference in New Issue
Block a user