feat: color picker panel with 18 preset colors + native color input + hex field

This commit is contained in:
Agent Zero
2026-07-27 17:31:42 +02:00
parent c670084420
commit 9a922f8abb
@@ -226,6 +226,7 @@ export function ContactFolderTree({
const { t } = useTranslation();
const [tagsOpen, setTagsOpen] = useState(true);
const [dropdown, setDropdown] = useState<DropdownState | null>(null);
const [colorPicker, setColorPicker] = useState<{ folderId: string; color: string } | null>(null);
const [dragOverFolderId, setDragOverFolderId] = useState<string | null>(null);
const { data: folders, isLoading: foldersLoading } = useContactFolders();
@@ -273,9 +274,13 @@ export function ContactFolderTree({
};
const handleColor = (id: string) => {
const color = prompt('Farbe (Hex-Code, z.B. #ff0000):', '#3b82f6');
if (!color) return;
updateFolderMut.mutate({ id, data: { color } as any });
setColorPicker({ folderId: id, color: folderList.find((f) => f.id === id && (f as any).color) ? (folderList.find((f) => f.id === id) as any).color : '#3b82f6' });
};
const handleColorSelect = (color: string) => {
if (!colorPicker) return;
updateFolderMut.mutate({ id: colorPicker.folderId, data: { color } as any });
setColorPicker(null);
};
const handlePin = (id: string) => {
@@ -444,6 +449,48 @@ export function ContactFolderTree({
onPin={handlePin}
/>
)}
{colorPicker && createPortal(
<>
<div className="fixed inset-0 z-[9998]" onClick={() => setColorPicker(null)} />
<div className="fixed z-[9999] bg-white border border-secondary-200 rounded-lg shadow-lg p-3 min-w-[200px]" style={{ top: '50%', left: '50%', transform: 'translate(-50%, -50%)' }}>
<div className="text-sm font-semibold text-secondary-700 mb-2">Farbe wählen</div>
<div className="grid grid-cols-6 gap-1.5 mb-3">
{['#ef4444', '#f97316', '#f59e0b', '#eab308', '#84cc16', '#22c55e', '#10b981', '#14b8a6', '#06b6d4', '#3b82f6', '#6366f1', '#8b5cf6', '#a855f7', '#d946ef', '#ec4899', '#f43f5e', '#64748b', '#475569'].map((c) => (
<button
key={c}
type="button"
onClick={() => handleColorSelect(c)}
className="w-7 h-7 rounded-md border-2 border-white shadow-sm hover:scale-110 transition-transform"
style={{ backgroundColor: c, outline: colorPicker.color === c ? '2px solid #3b82f6' : 'none' }}
/>
))}
</div>
<div className="flex items-center gap-2">
<input
type="color"
value={colorPicker.color}
onChange={(e) => setColorPicker({ ...colorPicker, color: e.target.value })}
className="w-8 h-8 rounded cursor-pointer border border-secondary-200"
/>
<input
type="text"
value={colorPicker.color}
onChange={(e) => setColorPicker({ ...colorPicker, color: e.target.value })}
className="flex-1 px-2 py-1 text-sm border border-secondary-200 rounded-md"
/>
<button
type="button"
onClick={() => handleColorSelect(colorPicker.color)}
className="px-3 py-1 text-sm bg-primary-600 text-white rounded-md hover:bg-primary-700"
>
OK
</button>
</div>
</div>
</>,
document.body
)}
</nav>
);
}