11import { useCallback , useRef } from 'react' ;
22import { useTranslation } from 'react-i18next' ;
3+ import type { ClassNamesConfig , StylesConfig } from 'react-select' ;
34import AsyncSelect from 'react-select/async' ;
45import { OptionProps } from 'react-select/dist/declarations/src' ;
56import { fetchSearchCompetition } from '@/lib/api' ;
7+ import { useUserSettings } from '@/providers/UserSettingsProvider' ;
68import { CompetitionListItem } from '../CompetitionListItem' ;
79
810export interface CompetitionSelectProps {
@@ -12,6 +14,8 @@ export interface CompetitionSelectProps {
1214
1315export const CompetitionSelect = ( { onSelect, className } : CompetitionSelectProps ) => {
1416 const { t } = useTranslation ( ) ;
17+ const { effectiveTheme } = useUserSettings ( ) ;
18+ const isDark = effectiveTheme === 'dark' ;
1519
1620 const loadOptions = useDebounced ( async ( inputValue : string ) => {
1721 try {
@@ -32,16 +36,92 @@ export const CompetitionSelect = ({ onSelect, className }: CompetitionSelectProp
3236 [ onSelect ] ,
3337 ) ;
3438
39+ const classNames : ClassNamesConfig < ApiCompetition , false > = {
40+ control : ( state ) =>
41+ [
42+ // Base sizing and rounded look
43+ 'min-h-[38px] rounded-md' ,
44+ // Backgrounds
45+ 'bg-white dark:bg-gray-800' ,
46+ // Borders + focus
47+ 'border border-gray-200 dark:border-gray-700' ,
48+ state . isFocused
49+ ? 'ring-1 ring-blue-500 dark:ring-blue-400 border-blue-500 dark:border-blue-400'
50+ : '' ,
51+ ] . join ( ' ' ) ,
52+ valueContainer : ( ) => 'text-gray-900 dark:text-white' ,
53+ singleValue : ( ) => 'text-gray-900 dark:text-white' ,
54+ input : ( ) => 'text-gray-900 dark:text-white' ,
55+ placeholder : ( ) => 'text-gray-600 dark:text-gray-400' ,
56+ indicatorsContainer : ( ) => 'text-gray-500 dark:text-gray-400' ,
57+ dropdownIndicator : ( state ) =>
58+ [
59+ 'text-gray-500 dark:text-gray-400' ,
60+ state . isFocused ? 'text-blue-600 dark:text-blue-400' : '' ,
61+ ] . join ( ' ' ) ,
62+ clearIndicator : ( ) =>
63+ 'text-gray-500 dark:text-gray-400 hover:text-gray-700 dark:hover:text-gray-300' ,
64+ menu : ( ) => 'bg-white dark:bg-gray-800 border border-gray-200 dark:border-gray-700 shadow-md' ,
65+ menuList : ( ) => 'bg-white dark:bg-gray-800' ,
66+ option : ( state ) =>
67+ [
68+ 'text-gray-900 dark:text-white' ,
69+ state . isFocused ? 'bg-gray-100 dark:bg-gray-700' : '' ,
70+ state . isSelected ? 'bg-blue-100 dark:bg-blue-900' : '' ,
71+ ] . join ( ' ' ) ,
72+ noOptionsMessage : ( ) => 'text-gray-600 dark:text-gray-400' ,
73+ } ;
74+
75+ const styles : StylesConfig < ApiCompetition , false > = {
76+ control : ( base , state ) => ( {
77+ ...base ,
78+ backgroundColor : 'transparent' ,
79+ borderColor : state . isFocused ? ( isDark ? '#60a5fa' : '#3b82f6' ) : base . borderColor ,
80+ boxShadow : state . isFocused ? `0 0 0 1px ${ isDark ? '#60a5fa' : '#3b82f6' } ` : 'none' ,
81+ ':hover' : {
82+ ...base [ ':hover' ] ,
83+ borderColor : state . isFocused ? ( isDark ? '#60a5fa' : '#3b82f6' ) : base . borderColor ,
84+ } ,
85+ } ) ,
86+ menu : ( base ) => ( {
87+ ...base ,
88+ backgroundColor : 'transparent' ,
89+ } ) ,
90+ menuList : ( base ) => ( {
91+ ...base ,
92+ backgroundColor : 'transparent' ,
93+ } ) ,
94+ option : ( base ) => ( {
95+ ...base ,
96+ backgroundColor : 'transparent' ,
97+ } ) ,
98+ input : ( base ) => ( {
99+ ...base ,
100+ color : isDark ? '#ffffff' : '#111827' , // gray-900
101+ } ) ,
102+ singleValue : ( base ) => ( {
103+ ...base ,
104+ color : isDark ? '#ffffff' : '#111827' , // gray-900
105+ } ) ,
106+ placeholder : ( base ) => ( {
107+ ...base ,
108+ color : isDark ? '#9ca3af' : '#4b5563' , // dark: gray-400, light: gray-600
109+ } ) ,
110+ } ;
111+
35112 return (
36113 < AsyncSelect < ApiCompetition >
37114 className = { className }
115+ classNamePrefix = "cg-select"
38116 cacheOptions
39117 loadOptions = { loadOptions }
40118 placeholder = { t ( 'common.competitionSelect.placeholder' ) }
41119 noOptionsMessage = { ( ) => t ( 'common.competitionSelect.noOptions' ) }
42120 components = { {
43121 Option : CompetitionOption ,
44122 } }
123+ classNames = { classNames }
124+ styles = { styles }
45125 onChange = { handleSelectOption }
46126 />
47127 ) ;
0 commit comments