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