1+ // Color Picker Component for User Accent Color Selection
2+
3+ import React , { useState , useEffect } from 'react' ;
4+ import { Palette , Check } from 'lucide-react' ;
5+ import { DEFAULT_ACCENT_COLORS , updateUserAccentColor } from '../lib/userSettings' ;
6+ import { useTheme } from '../lib/theme' ;
7+ import { safeLogError } from '../lib/utils' ;
8+
9+ interface ColorPickerProps {
10+ username : string ;
11+ onColorChange ?: ( color : string ) => void ;
12+ }
13+
14+ export function ColorPicker ( { username, onColorChange } : ColorPickerProps ) {
15+ const { accentColor, setAccentColor } = useTheme ( ) ;
16+ const [ isSaving , setIsSaving ] = useState ( false ) ;
17+ const [ customColor , setCustomColor ] = useState ( accentColor ) ;
18+
19+ const handleColorSelect = async ( color : string ) => {
20+ setIsSaving ( true ) ;
21+ try {
22+ await updateUserAccentColor ( username , color ) ;
23+ setAccentColor ( color ) ;
24+ onColorChange ?.( color ) ;
25+ } catch ( error ) {
26+ safeLogError ( 'Error saving accent color:' , error ) ;
27+ alert ( 'Failed to save color preference. Please try again.' ) ;
28+ } finally {
29+ setIsSaving ( false ) ;
30+ }
31+ } ;
32+
33+ const handleCustomColorChange = ( color : string ) => {
34+ setCustomColor ( color ) ;
35+ } ;
36+
37+ const handleCustomColorApply = ( ) => {
38+ handleColorSelect ( customColor ) ;
39+ } ;
40+
41+ return (
42+ < div className = "space-y-4" >
43+ < div className = "flex items-center gap-2" >
44+ < Palette className = "w-5 h-5 text-gray-600 dark:text-gray-400" />
45+ < h3 className = "text-lg font-medium text-gray-900 dark:text-gray-100" >
46+ Accent Color
47+ </ h3 >
48+ </ div >
49+
50+ < div className = "space-y-3" >
51+ < p className = "text-sm text-gray-600 dark:text-gray-400" >
52+ Choose your accent color that will be applied throughout the interface.
53+ </ p >
54+
55+ { /* Preset colors */ }
56+ < div className = "grid grid-cols-4 gap-3" >
57+ { DEFAULT_ACCENT_COLORS . map ( ( color ) => (
58+ < button
59+ key = { color }
60+ onClick = { ( ) => handleColorSelect ( color ) }
61+ disabled = { isSaving }
62+ className = { `relative w-12 h-12 rounded-lg border-2 transition-all hover:scale-110 ${
63+ accentColor === color
64+ ? 'border-gray-900 dark:border-gray-100 shadow-lg'
65+ : 'border-gray-300 dark:border-gray-600'
66+ } `}
67+ style = { { backgroundColor : color } }
68+ title = { color }
69+ >
70+ { accentColor === color && (
71+ < Check className = "w-5 h-5 text-white absolute inset-0 m-auto drop-shadow-lg" />
72+ ) }
73+ </ button >
74+ ) ) }
75+ </ div >
76+
77+ { /* Custom color picker */ }
78+ < div className = "space-y-2" >
79+ < label className = "text-sm font-medium text-gray-700 dark:text-gray-300" >
80+ Custom Color
81+ </ label >
82+ < div className = "flex items-center gap-3" >
83+ < input
84+ type = "color"
85+ value = { customColor }
86+ onChange = { ( e ) => handleCustomColorChange ( e . target . value ) }
87+ className = "w-12 h-10 rounded border border-gray-300 dark:border-gray-600 bg-white dark:bg-gray-700"
88+ />
89+ < input
90+ type = "text"
91+ value = { customColor }
92+ onChange = { ( e ) => handleCustomColorChange ( e . target . value ) }
93+ placeholder = "rgb(59, 130, 246)"
94+ className = "flex-1 px-3 py-2 border border-gray-300 dark:border-gray-600 rounded-md bg-white dark:bg-gray-700 text-gray-900 dark:text-gray-100"
95+ />
96+ < button
97+ onClick = { handleCustomColorApply }
98+ disabled = { isSaving || customColor === accentColor }
99+ className = "px-4 py-2 btn-accent hover:opacity-90 disabled:opacity-50 text-white rounded-md transition-colors"
100+ >
101+ { isSaving ? 'Saving...' : 'Apply' }
102+ </ button >
103+ </ div >
104+ </ div >
105+
106+ { /* Current color preview */ }
107+ < div className = "flex items-center gap-3 p-3 bg-gray-50 dark:bg-gray-800 rounded-lg" >
108+ < div
109+ className = "w-8 h-8 rounded-full border-2 border-gray-300 dark:border-gray-600"
110+ style = { { backgroundColor : accentColor } }
111+ />
112+ < div >
113+ < p className = "text-sm font-medium text-gray-900 dark:text-gray-100" >
114+ Current: { accentColor }
115+ </ p >
116+ < p className = "text-xs text-gray-600 dark:text-gray-400" >
117+ This color is applied to buttons, links, and interactive elements
118+ </ p >
119+ </ div >
120+ </ div >
121+ </ div >
122+ </ div >
123+ ) ;
124+ }
0 commit comments