Frontend changes: - Removed brand filter and column from table - Removed inventory summary grid - Removed stanje (state) and težina (weight) columns - Reorganized filters: Material → Finish → Color - Updated EnhancedFilters component with new filter structure - Removed legend section for storage conditions Admin dashboard changes: - Removed sidebar navigation (Boje option) - Made dashboard full screen - Removed brand column from table - Removed brand field from add/edit form - Updated all boolean columns to use checkmark/X icons - Made color tiles 40% bigger - Added sortable columns functionality - Auto-fill price: 3499 for refill, 3999 for regular Other improvements: - Added BackToTop button component on all pages - Fixed Next.js dialog backdrop CSS error - Updated tests to match new UI structure - Removed obsolete FilamentTable.tsx component - Ensured proper synchronization between admin and frontend 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
79 lines
2.2 KiB
TypeScript
79 lines
2.2 KiB
TypeScript
import React from 'react';
|
|
|
|
interface ColorSwatchProps {
|
|
name: string;
|
|
hex?: string;
|
|
size?: 'sm' | 'md' | 'lg';
|
|
showLabel?: boolean;
|
|
className?: string;
|
|
}
|
|
|
|
export const ColorSwatch: React.FC<ColorSwatchProps> = ({
|
|
name,
|
|
hex,
|
|
size = 'md',
|
|
showLabel = true,
|
|
className = ''
|
|
}) => {
|
|
const sizeClasses = {
|
|
sm: 'w-7 h-7',
|
|
md: 'w-8 h-8',
|
|
lg: 'w-10 h-10'
|
|
};
|
|
|
|
// Default color mappings if hex is not provided
|
|
const defaultColors: Record<string, string> = {
|
|
'Black': '#000000',
|
|
'White': '#FFFFFF',
|
|
'Gray': '#808080',
|
|
'Red': '#FF0000',
|
|
'Blue': '#0000FF',
|
|
'Green': '#00FF00',
|
|
'Yellow': '#FFFF00',
|
|
'Transparent': 'rgba(255, 255, 255, 0.1)'
|
|
};
|
|
|
|
const getColorFromName = (colorName: string): string => {
|
|
// Check exact match first
|
|
if (defaultColors[colorName]) return defaultColors[colorName];
|
|
|
|
// Check if color name contains a known color
|
|
const lowerName = colorName.toLowerCase();
|
|
for (const [key, value] of Object.entries(defaultColors)) {
|
|
if (lowerName.includes(key.toLowerCase())) {
|
|
return value;
|
|
}
|
|
}
|
|
|
|
// Generate a color from the name hash
|
|
let hash = 0;
|
|
for (let i = 0; i < colorName.length; i++) {
|
|
hash = colorName.charCodeAt(i) + ((hash << 5) - hash);
|
|
}
|
|
const hue = hash % 360;
|
|
return `hsl(${hue}, 70%, 50%)`;
|
|
};
|
|
|
|
const backgroundColor = hex || getColorFromName(name);
|
|
const isLight = backgroundColor.startsWith('#') &&
|
|
parseInt(backgroundColor.slice(1, 3), 16) > 200 &&
|
|
parseInt(backgroundColor.slice(3, 5), 16) > 200 &&
|
|
parseInt(backgroundColor.slice(5, 7), 16) > 200;
|
|
|
|
return (
|
|
<div className={`flex items-center gap-2 ${className}`}>
|
|
<div
|
|
className={`${sizeClasses[size]} rounded border border-gray-300 dark:border-gray-600`}
|
|
style={{ backgroundColor }}
|
|
title={name}
|
|
>
|
|
{name.toLowerCase().includes('transparent') && (
|
|
<div className="w-full h-full rounded bg-gradient-to-br from-gray-200 to-gray-300 opacity-50" />
|
|
)}
|
|
</div>
|
|
{showLabel && (
|
|
<span className="text-sm text-gray-700 dark:text-gray-300">{name}</span>
|
|
)}
|
|
</div>
|
|
);
|
|
}; |