@@ -5,6 +5,8 @@ import { KeyboardSelector, KeyboardType } from '../Keyboards';
55import { KeyboardLayoutType } from '../Keyboards/keyboardTypes' ;
66import RolloverTest from '../RolloverTest/RolloverTest' ;
77import TypingTest from '../TypingTest/TypingTest' ;
8+ import { ThemeName , themeMetadata } from '../../styles/themeTypes' ;
9+ import { useTheme } from '../../styles/ThemeContext' ;
810
911interface TestContainerProps {
1012 onKeyPress ?: ( key : string ) => void ;
@@ -120,6 +122,81 @@ const ResetButton = styled(Tab)`
120122 }
121123` ;
122124
125+ const ThemeGrid = styled . div `
126+ display: grid;
127+ grid-template-columns: repeat(7, 1fr);
128+ gap: 0.75rem;
129+ width: 100%;
130+ max-width: 1000px;
131+ margin: 0 auto;
132+ ` ;
133+
134+ const ThemeCard = styled . div < { active : boolean } > `
135+ padding: 0.75rem;
136+ border-radius: 8px;
137+ border: 1px solid ${ props => props . active ? props . theme . colors . primary : props . theme . colors . primary + '40' } ;
138+ background: ${ props => props . active ? props . theme . colors . primary + '20' : 'transparent' } ;
139+ cursor: pointer;
140+ transition: all 0.2s ease;
141+ display: flex;
142+ flex-direction: column;
143+ align-items: center;
144+
145+ &:hover {
146+ background: ${ props => props . active ? props . theme . colors . primary + '30' : props . theme . colors . primary + '10' } ;
147+ transform: translateY(-2px);
148+ box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
149+ }
150+ ` ;
151+
152+ const ThemePreview = styled . div < { colors : { background : string , primary : string , text : string } } > `
153+ width: 100%;
154+ height: 50px;
155+ border-radius: 6px;
156+ margin-bottom: 0.75rem;
157+ background: ${ props => props . colors . background } ;
158+ position: relative;
159+ overflow: hidden;
160+ box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
161+
162+ &::before {
163+ content: '';
164+ position: absolute;
165+ top: 50%;
166+ left: 50%;
167+ transform: translate(-50%, -50%);
168+ width: 30px;
169+ height: 30px;
170+ border-radius: 50%;
171+ background: ${ props => props . colors . primary } ;
172+ }
173+
174+ &::after {
175+ content: 'Aa';
176+ position: absolute;
177+ top: 50%;
178+ left: 50%;
179+ transform: translate(-50%, -50%);
180+ color: ${ props => props . colors . text } ;
181+ font-weight: bold;
182+ font-size: 12px;
183+ }
184+ ` ;
185+
186+ const ThemeLabel = styled . h4 `
187+ margin: 0;
188+ font-size: 0.8rem;
189+ text-align: center;
190+ color: ${ props => props . theme . colors . text } ;
191+ ` ;
192+
193+ const ThemeContainer = styled . div `
194+ width: 100%;
195+ display: flex;
196+ flex-direction: column;
197+ align-items: center;
198+ ` ;
199+
123200const slideVariants = {
124201 enter : ( direction : number ) => ( {
125202 x : direction > 0 ? 1000 : - 1000 ,
@@ -152,9 +229,10 @@ const TestContainer: React.FC<TestContainerProps> = ({ onKeyPress, onReset, onTa
152229 const [ currentLayout , setCurrentLayout ] = useState < KeyboardType > ( '75%' ) ;
153230 const [ currentType , setCurrentType ] = useState < KeyboardLayoutType > ( 'qwerty' ) ;
154231 const [ keyboardKey , setKeyboardKey ] = useState ( 0 ) ;
232+ const { currentTheme, setTheme } = useTheme ( ) ;
155233
156234 const handleTabClick = ( tabId : string ) => {
157- const tabOrder = [ 'keyTest' , 'rolloverTest' , 'typingTest' , 'layout' , 'type' , 'themes' , 'language' ] ;
235+ const tabOrder = [ 'keyTest' , 'rolloverTest' , 'typingTest' , 'layout' , 'type' , 'themes' ] ;
158236 const currentIndex = tabOrder . indexOf ( activeTab ) ;
159237 const newIndex = tabOrder . indexOf ( tabId ) ;
160238 setDirection ( newIndex > currentIndex ? 1 : - 1 ) ;
@@ -179,6 +257,10 @@ const TestContainer: React.FC<TestContainerProps> = ({ onKeyPress, onReset, onTa
179257 setKeyboardKey ( prevKey => prevKey + 1 ) ;
180258 } ;
181259
260+ const handleThemeChange = ( themeName : ThemeName ) => {
261+ setTheme ( themeName ) ;
262+ } ;
263+
182264 const handleReset = ( ) => {
183265 if ( onReset ) {
184266 onReset ( ) ;
@@ -310,9 +392,40 @@ const TestContainer: React.FC<TestContainerProps> = ({ onKeyPress, onReset, onTa
310392 </ LayoutPreview >
311393 ) ;
312394 case 'themes' :
313- return < div > Themes Content</ div > ;
314- case 'language' :
315- return < div > Language Content</ div > ;
395+ // Get all themes including original
396+ const allThemes = ( Object . keys ( themeMetadata ) as ThemeName [ ] ) ;
397+
398+ // Sort themes alphabetically (excluding original)
399+ const sortedThemes = [
400+ 'original' as ThemeName ,
401+ ...allThemes
402+ . filter ( name => name !== 'original' )
403+ . sort ( ( a , b ) => themeMetadata [ a ] . name . localeCompare ( themeMetadata [ b ] . name ) )
404+ ] ;
405+
406+ // Limit to 35 themes (7x5 grid)
407+ const displayThemes = sortedThemes . slice ( 0 , 35 ) ;
408+
409+ return (
410+ < LayoutPreview >
411+ < h3 > Select a Theme</ h3 >
412+
413+ < ThemeContainer >
414+ < ThemeGrid >
415+ { displayThemes . map ( ( themeName : ThemeName ) => (
416+ < ThemeCard
417+ key = { themeName }
418+ active = { currentTheme === themeName }
419+ onClick = { ( ) => handleThemeChange ( themeName ) }
420+ >
421+ < ThemePreview colors = { themeMetadata [ themeName ] . colors } />
422+ < ThemeLabel > { themeMetadata [ themeName ] . name } </ ThemeLabel >
423+ </ ThemeCard >
424+ ) ) }
425+ </ ThemeGrid >
426+ </ ThemeContainer >
427+ </ LayoutPreview >
428+ ) ;
316429 default :
317430 return < div > Select a tab</ div > ;
318431 }
@@ -347,11 +460,6 @@ const TestContainer: React.FC<TestContainerProps> = ({ onKeyPress, onReset, onTa
347460 label : 'Type' ,
348461 onClick : ( ) => handleTabClick ( 'type' )
349462 } ,
350- {
351- id : 'language' ,
352- label : 'Language' ,
353- onClick : ( ) => handleTabClick ( 'language' )
354- } ,
355463 {
356464 id : 'themes' ,
357465 label : 'Themes' ,
0 commit comments