11/**
22 * ModuleHub Component
3- * Topic selection grid for the main hub page
3+ * Topic selection grid with search and filtering
44 */
55
6- import { useNavigation } from '../../contexts' ;
6+ import { useMemo } from 'react' ;
7+ import { useNavigation , useSearch } from '../../contexts' ;
78import { MODULE_REGISTRY } from '../../types' ;
89import styles from './ModuleHub.module.css' ;
910
1011export function ModuleHub ( ) {
1112 const { navigateTo } = useNavigation ( ) ;
12- const modules = Object . values ( MODULE_REGISTRY ) ;
13+ const { searchQuery, filterBadge } = useSearch ( ) ;
14+ const allModules = Object . values ( MODULE_REGISTRY ) ;
15+
16+ // Filter modules based on search and badge
17+ const filteredModules = useMemo ( ( ) => {
18+ return allModules . filter ( ( module ) => {
19+ // Search filter
20+ const matchesSearch = searchQuery === '' ||
21+ module . title . toLowerCase ( ) . includes ( searchQuery . toLowerCase ( ) ) ||
22+ module . description . toLowerCase ( ) . includes ( searchQuery . toLowerCase ( ) ) ||
23+ module . subtitle . toLowerCase ( ) . includes ( searchQuery . toLowerCase ( ) ) ;
24+
25+ // Badge filter
26+ const matchesBadge = filterBadge === 'all' || module . badge === filterBadge ;
27+
28+ return matchesSearch && matchesBadge ;
29+ } ) ;
30+ } , [ allModules , searchQuery , filterBadge ] ) ;
1331
1432 return (
1533 < div className = { styles . hubContainer } >
@@ -21,35 +39,48 @@ export function ModuleHub() {
2139 </ p >
2240 </ div >
2341
24- < div className = { styles . grid } >
25- { modules . map ( ( module ) => (
26- < div
27- key = { module . id }
28- className = { styles . card }
29- onClick = { ( ) => navigateTo ( module . id ) }
30- >
31- < div className = { styles . cardHeader } >
42+ { filteredModules . length === 0 ? (
43+ < div className = { styles . noResults } >
44+ < span className = { styles . noResultsIcon } > 🔍</ span >
45+ < p > No modules found matching your search.</ p >
46+ < p className = { styles . noResultsHint } > Try a different search term or filter.</ p >
47+ </ div >
48+ ) : (
49+ < div className = { styles . grid } >
50+ { filteredModules . map ( ( module ) => (
51+ < div
52+ key = { module . id }
53+ className = { styles . card }
54+ onClick = { ( ) => navigateTo ( module . id ) }
55+ >
56+ < div className = { styles . cardHeader } >
57+ < span
58+ className = { styles . indicator }
59+ style = { {
60+ backgroundColor : module . accentColor ,
61+ boxShadow : `0 0 10px ${ module . glowColor } ` ,
62+ } }
63+ />
64+ < h3 className = { styles . cardTitle } > { module . title } </ h3 >
65+ </ div >
66+ < p className = { styles . cardDescription } > { module . description } </ p >
3267 < span
33- className = { styles . indicator }
68+ className = { styles . badge }
3469 style = { {
35- backgroundColor : module . accentColor ,
36- boxShadow : `0 0 10px ${ module . glowColor } ` ,
70+ color : module . accentColor ,
3771 } }
38- />
39- < h3 className = { styles . cardTitle } > { module . title } </ h3 >
72+ >
73+ { module . badge }
74+ </ span >
4075 </ div >
41- < p className = { styles . cardDescription } > { module . description } </ p >
42- < span
43- className = { styles . badge }
44- style = { {
45- color : module . accentColor ,
46- } }
47- >
48- { module . badge }
49- </ span >
50- </ div >
51- ) ) }
52- </ div >
76+ ) ) }
77+ </ div >
78+ ) }
79+
80+ { /* Module Count */ }
81+ < p className = { styles . moduleCount } >
82+ Showing { filteredModules . length } of { allModules . length } modules
83+ </ p >
5384 </ div >
5485 </ div >
5586 ) ;
0 commit comments