Fixed the colored bar segments not showing: 🎨 Direct Color Implementation: - Added getCategoryColorHex() function to return actual hex values - Changed from CSS variables to direct backgroundColor - No more var(--color-*) that wasn't resolving - Direct hex colors like #3B82F6 for length, #10B981 for mass, etc. ✨ Visual Improvements: - Taller bars (h-8, 32px) for better visibility - Drop shadow on percentage labels for readability - White text on bars >30% filled - Foreground color text on smaller bars - pointer-events-none on overlay to prevent interaction issues 🔧 Updated Components: - MainConverter: Import and use getCategoryColorHex() - VisualComparison: Accept hex color string directly - lib/units: Added getCategoryColorHex() with all 23 colors The bars will now definitely show with vibrant colors! 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
113 lines
3.5 KiB
TypeScript
113 lines
3.5 KiB
TypeScript
'use client';
|
|
|
|
import { useMemo } from 'react';
|
|
import { type ConversionResult } from '@/lib/units';
|
|
import { formatNumber, cn } from '@/lib/utils';
|
|
|
|
interface VisualComparisonProps {
|
|
conversions: ConversionResult[];
|
|
color: string;
|
|
}
|
|
|
|
export default function VisualComparison({
|
|
conversions,
|
|
color,
|
|
}: VisualComparisonProps) {
|
|
// Calculate percentages for visual bars using logarithmic scale
|
|
const withPercentages = useMemo(() => {
|
|
if (conversions.length === 0) return [];
|
|
|
|
// Get all values
|
|
const values = conversions.map(c => Math.abs(c.value));
|
|
const maxValue = Math.max(...values);
|
|
const minValue = Math.min(...values.filter(v => v > 0));
|
|
|
|
if (maxValue === 0 || !isFinite(maxValue)) {
|
|
return conversions.map(c => ({ ...c, percentage: 0 }));
|
|
}
|
|
|
|
// Use logarithmic scale for better visualization
|
|
return conversions.map(c => {
|
|
const absValue = Math.abs(c.value);
|
|
|
|
if (absValue === 0 || !isFinite(absValue)) {
|
|
return { ...c, percentage: 2 }; // Show minimal bar
|
|
}
|
|
|
|
// Logarithmic scale
|
|
const logValue = Math.log10(absValue);
|
|
const logMax = Math.log10(maxValue);
|
|
const logMin = minValue > 0 ? Math.log10(minValue) : logMax - 6; // 6 orders of magnitude range
|
|
|
|
const logRange = logMax - logMin;
|
|
|
|
let percentage: number;
|
|
if (logRange === 0) {
|
|
percentage = 100;
|
|
} else {
|
|
percentage = ((logValue - logMin) / logRange) * 100;
|
|
// Ensure bars are visible - minimum 3%, maximum 100%
|
|
percentage = Math.max(3, Math.min(100, percentage));
|
|
}
|
|
|
|
return {
|
|
...c,
|
|
percentage,
|
|
};
|
|
});
|
|
}, [conversions]);
|
|
|
|
if (conversions.length === 0) {
|
|
return (
|
|
<div className="text-center py-8 text-muted-foreground">
|
|
Enter a value to see conversions
|
|
</div>
|
|
);
|
|
}
|
|
|
|
return (
|
|
<div className="space-y-3">
|
|
{withPercentages.map(item => (
|
|
<div key={item.unit} className="space-y-1.5">
|
|
<div className="flex items-baseline justify-between gap-4">
|
|
<span className="text-sm font-medium text-foreground min-w-0 flex-shrink">
|
|
{item.unitInfo.plural}
|
|
</span>
|
|
<span className="text-lg font-bold tabular-nums flex-shrink-0">
|
|
{formatNumber(item.value)}
|
|
<span className="text-sm font-normal text-muted-foreground ml-1">
|
|
{item.unit}
|
|
</span>
|
|
</span>
|
|
</div>
|
|
{/* Progress bar */}
|
|
<div className="w-full h-8 bg-muted rounded-lg overflow-hidden border border-border relative">
|
|
{/* Colored fill */}
|
|
<div
|
|
className="absolute inset-y-0 left-0 transition-all duration-500 ease-out"
|
|
style={{
|
|
width: `${item.percentage}%`,
|
|
backgroundColor: color,
|
|
}}
|
|
/>
|
|
{/* Percentage label overlay */}
|
|
<div className="absolute inset-0 flex items-center justify-between px-3 text-xs font-bold pointer-events-none">
|
|
<span className="text-foreground drop-shadow-sm">
|
|
{Math.round(item.percentage)}%
|
|
</span>
|
|
<span
|
|
className="tabular-nums drop-shadow-sm"
|
|
style={{
|
|
color: item.percentage > 30 ? 'white' : 'var(--foreground)',
|
|
}}
|
|
>
|
|
{item.percentage > 30 && formatNumber(item.value)}
|
|
</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
))}
|
|
</div>
|
|
);
|
|
}
|