Major restructure: Remove Confluence, add V2 data structure, organize for dev/prod
- Import real data from PDF (35 Bambu Lab filaments) - Remove all Confluence integration and dependencies - Implement new V2 data structure with proper inventory tracking - Add backwards compatibility for existing data - Create enhanced UI components (ColorSwatch, InventoryBadge, MaterialBadge) - Add advanced filtering with quick filters and multi-criteria search - Organize codebase for dev/prod environments - Update Lambda functions to support both V1/V2 formats - Add inventory summary dashboard - Clean up project structure and documentation 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
79
src/components/ColorSwatch.tsx
Normal file
79
src/components/ColorSwatch.tsx
Normal file
@@ -0,0 +1,79 @@
|
||||
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-6 h-6',
|
||||
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-full border-2 ${isLight ? 'border-gray-300' : 'border-gray-700'} shadow-sm`}
|
||||
style={{ backgroundColor }}
|
||||
title={name}
|
||||
>
|
||||
{name.toLowerCase().includes('transparent') && (
|
||||
<div className="w-full h-full rounded-full 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>
|
||||
);
|
||||
};
|
||||
Reference in New Issue
Block a user