'use client'; import { forwardRef, HTMLAttributes } from 'react'; export interface TensionBarProps extends HTMLAttributes { value: number; max?: number; labelLeft?: string; labelRight?: string; showPercentage?: boolean; showMarkers?: boolean; markerCount?: number; variant?: 'default' | 'gold' | 'danger' | 'segmented' | 'dramatic'; size?: 'sm' | 'md' | 'lg'; innerText?: string; animated?: boolean; dangerThreshold?: number; } const sizeHeights: Record = { sm: 'h-1', md: 'h-2', lg: 'h-4', }; const variantColors: Record = { default: { fill: 'bg-red-500', text: 'text-red-500' }, gold: { fill: 'bg-gradient-to-r from-amber-700 to-amber-500', text: 'text-amber-500' }, danger: { fill: 'bg-red-500', text: 'text-red-500' }, segmented: { fill: 'bg-red-500', text: 'text-red-500' }, dramatic: { fill: 'bg-red-500', text: 'text-red-500' }, }; export const TensionBar = forwardRef( ({ value, max = 100, labelLeft, labelRight, showPercentage = false, showMarkers = false, markerCount = 10, variant = 'default', size = 'md', innerText, animated = false, dangerThreshold = 80, className, ...props }, ref) => { const percentage = Math.min(100, Math.max(0, (value / max) * 100)); const isHigh = variant === 'danger' && percentage >= dangerThreshold; const colors = variantColors[variant]; const height = sizeHeights[size]; const renderSegmented = () => { const filledCount = Math.floor((percentage / 100) * markerCount); return (
{Array.from({ length: markerCount }).map((_, i) => (
))}
); }; return (
{(labelLeft || labelRight) && (
{labelLeft} {labelRight}
)}
{innerText && ( {innerText} )} {variant === 'segmented' ? ( renderSegmented() ) : (
)} {showPercentage && ( {Math.round(percentage)}% )}
{showMarkers && variant !== 'segmented' && (
{Array.from({ length: markerCount + 1 }).map((_, i) => { const markerPercent = (i / markerCount) * 100; return (
); })}
)}
); } ); TensionBar.displayName = 'TensionBar'; export default TensionBar;