Tag Enhancement + bugfixes

This commit is contained in:
Stefan Hardegger
2025-08-17 17:16:40 +02:00
parent 6b83783381
commit 1a99d9830d
34 changed files with 2996 additions and 97 deletions

View File

@@ -0,0 +1,171 @@
'use client';
import { useState } from 'react';
import Button from './Button';
interface ColorPickerProps {
value?: string;
onChange: (color: string | undefined) => void;
disabled?: boolean;
label?: string;
}
// Theme-compatible color palette
const THEME_COLORS = [
// Primary blues
{ hex: '#3B82F6', name: 'Theme Blue' },
{ hex: '#1D4ED8', name: 'Deep Blue' },
{ hex: '#60A5FA', name: 'Light Blue' },
// Greens
{ hex: '#10B981', name: 'Emerald' },
{ hex: '#059669', name: 'Forest Green' },
{ hex: '#34D399', name: 'Light Green' },
// Purples
{ hex: '#8B5CF6', name: 'Purple' },
{ hex: '#7C3AED', name: 'Deep Purple' },
{ hex: '#A78BFA', name: 'Light Purple' },
// Warm tones
{ hex: '#F59E0B', name: 'Amber' },
{ hex: '#D97706', name: 'Orange' },
{ hex: '#F97316', name: 'Bright Orange' },
// Reds/Pinks
{ hex: '#EF4444', name: 'Red' },
{ hex: '#F472B6', name: 'Pink' },
{ hex: '#EC4899', name: 'Hot Pink' },
// Neutrals
{ hex: '#6B7280', name: 'Gray' },
{ hex: '#4B5563', name: 'Dark Gray' },
{ hex: '#9CA3AF', name: 'Light Gray' }
];
export default function ColorPicker({ value, onChange, disabled, label }: ColorPickerProps) {
const [showCustomPicker, setShowCustomPicker] = useState(false);
const [customColor, setCustomColor] = useState(value || '#3B82F6');
const handleThemeColorSelect = (color: string) => {
onChange(color);
setShowCustomPicker(false);
};
const handleCustomColorChange = (color: string) => {
setCustomColor(color);
onChange(color);
};
const handleRemoveColor = () => {
onChange(undefined);
setShowCustomPicker(false);
};
return (
<div className="space-y-3">
{label && (
<label className="block text-sm font-medium theme-header">
{label}
</label>
)}
{/* Current Color Display */}
{value && (
<div className="flex items-center gap-2 p-2 border theme-border rounded-lg">
<div
className="w-6 h-6 rounded border border-gray-300 dark:border-gray-600"
style={{ backgroundColor: value }}
/>
<span className="text-sm theme-text font-mono">{value}</span>
<Button
variant="ghost"
size="sm"
onClick={handleRemoveColor}
disabled={disabled}
className="ml-auto text-xs"
>
Remove
</Button>
</div>
)}
{/* Theme Color Palette */}
<div className="space-y-2">
<h4 className="text-sm font-medium theme-header">Theme Colors</h4>
<div className="grid grid-cols-6 gap-2 p-3 border theme-border rounded-lg">
{THEME_COLORS.map((color) => (
<button
key={color.hex}
type="button"
className={`
w-8 h-8 rounded-md border-2 transition-all hover:scale-110 focus:outline-none focus:ring-2 focus:ring-theme-accent
${value === color.hex ? 'border-gray-800 dark:border-white scale-110' : 'border-gray-300 dark:border-gray-600'}
`}
style={{ backgroundColor: color.hex }}
onClick={() => handleThemeColorSelect(color.hex)}
disabled={disabled}
title={color.name}
/>
))}
</div>
</div>
{/* Custom Color Section */}
<div className="space-y-2">
<div className="flex items-center justify-between">
<h4 className="text-sm font-medium theme-header">Custom Color</h4>
<Button
variant="ghost"
size="sm"
onClick={() => setShowCustomPicker(!showCustomPicker)}
disabled={disabled}
className="text-xs"
>
{showCustomPicker ? 'Hide' : 'Show'} Custom
</Button>
</div>
{showCustomPicker && (
<div className="p-3 border theme-border rounded-lg space-y-3">
<div className="flex items-center gap-3">
<input
type="color"
value={customColor}
onChange={(e) => handleCustomColorChange(e.target.value)}
disabled={disabled}
className="w-12 h-8 rounded border border-gray-300 dark:border-gray-600 cursor-pointer disabled:cursor-not-allowed"
/>
<input
type="text"
value={customColor}
onChange={(e) => {
const color = e.target.value;
if (/^#[0-9A-Fa-f]{6}$/.test(color)) {
setCustomColor(color);
onChange(color);
}
}}
disabled={disabled}
className="flex-1 px-3 py-1 text-sm border theme-border rounded font-mono"
placeholder="#3B82F6"
/>
<Button
variant="primary"
size="sm"
onClick={() => onChange(customColor)}
disabled={disabled}
className="text-xs"
>
Apply
</Button>
</div>
<p className="text-xs theme-text-muted">
Enter a hex color code or use the color picker
</p>
</div>
)}
</div>
</div>
);
}