Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 | 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x | 'use client';
/**
* ConnectionIndicator Component
*
* Visual indicator for real-time connection status.
* Shows whether the client is connected via WebSocket or using polling fallback.
*/
import { cn } from '@/lib/core';
import type { NotificationMode } from '@/hooks/useNotificationsWithFallback';
export interface ConnectionIndicatorProps {
/** Whether connected to real-time server */
isConnected: boolean;
/** Current notification mode */
mode: NotificationMode;
/** Additional CSS classes */
className?: string;
/** Whether to show the label text */
showLabel?: boolean;
/** Size variant */
size?: 'sm' | 'md' | 'lg';
/** Whether to show animation when connected */
animated?: boolean;
/** Whether to show tooltip on hover */
showTooltip?: boolean;
/** Custom tooltip content */
tooltipContent?: string;
}
const sizeClasses = {
sm: 'h-1.5 w-1.5',
md: 'h-2 w-2',
lg: 'h-2.5 w-2.5',
};
const labelSizeClasses = {
sm: 'text-[10px]',
md: 'text-xs',
lg: 'text-sm',
};
export function ConnectionIndicator({
isConnected,
mode,
className,
showLabel = false,
size = 'md',
animated = true,
showTooltip = true,
tooltipContent,
}: ConnectionIndicatorProps) {
const dotClasses = cn(
'rounded-full flex-shrink-0',
sizeClasses[size],
isConnected
? 'bg-green-500 dark:bg-green-400'
: 'bg-yellow-500 dark:bg-yellow-400',
animated && isConnected && 'animate-pulse'
);
const labelText = mode === 'realtime' ? 'Live' : 'Polling';
const tooltip =
tooltipContent ||
(mode === 'realtime'
? 'Connected - Real-time updates active'
: 'Polling mode - Updates every 30 seconds');
return (
<div
className={cn('flex items-center gap-1.5', className)}
role="status"
aria-live="polite"
aria-label={`Connection status: ${mode === 'realtime' ? 'connected' : 'polling mode'}`}
title={showTooltip ? tooltip : undefined}
>
<span className={dotClasses} aria-hidden="true" />
{showLabel && (
<span
className={cn(
'text-gray-500 dark:text-gray-400 font-medium',
labelSizeClasses[size]
)}
>
{labelText}
</span>
)}
{/* Screen reader text */}
<span className="sr-only">
{mode === 'realtime'
? 'Connected to real-time updates'
: 'Using polling for updates'}
</span>
</div>
);
}
export default ConnectionIndicator;
|