1+ "use client" ;
2+
3+ import { useState , useEffect } from "react" ;
4+ import { Button } from "@serp-tools/ui/components/button" ;
5+ import { Badge } from "@serp-tools/ui/components/badge" ;
6+ import { ExtensionCard } from "@/components/ExtensionCard" ;
7+ import { ExtensionsSearchBar } from "@/components/ExtensionsSearchBar" ;
8+ import {
9+ Sparkles ,
10+ ArrowRight ,
11+ Shield ,
12+ Lock ,
13+ Eye ,
14+ ShoppingCart ,
15+ Coins ,
16+ Moon ,
17+ CheckSquare ,
18+ Bookmark ,
19+ Palette ,
20+ Code ,
21+ Video ,
22+ Clipboard ,
23+ Gauge ,
24+ Globe ,
25+ Puzzle
26+ } from "lucide-react" ;
27+ import extensionsData from '@serp-tools/app-core/data/extensions.json' ;
28+
29+ // Icon mapping for extensions
30+ const iconMap : { [ key : string ] : any } = {
31+ 'ublock-origin' : Shield ,
32+ 'lastpass' : Lock ,
33+ 'grammarly' : CheckSquare ,
34+ 'honey' : ShoppingCart ,
35+ 'metamask' : Coins ,
36+ 'dark-reader' : Moon ,
37+ 'todoist' : CheckSquare ,
38+ 'pocket' : Bookmark ,
39+ 'colorpick-eyedropper' : Palette ,
40+ 'wappalyzer' : Code ,
41+ 'json-formatter' : Code ,
42+ 'ghostery' : Shield ,
43+ 'loom' : Video ,
44+ 'notion-web-clipper' : Clipboard ,
45+ 'momentum' : Gauge ,
46+ } ;
47+
48+ // Process extensions from JSON data
49+ const processedExtensions = extensionsData
50+ . filter ( ( extension : any ) => extension . isActive )
51+ . map ( ( extension : any ) => ( {
52+ id : extension . id ,
53+ name : extension . name ,
54+ description : extension . description ,
55+ category : extension . category || 'other' ,
56+ icon : iconMap [ extension . id ] || Puzzle ,
57+ href : extension . chromeStoreUrl || extension . firefoxAddonUrl || extension . url ,
58+ tags : extension . tags || [ ] ,
59+ isNew : extension . isNew || false ,
60+ isPopular : extension . isPopular || false ,
61+ rating : extension . rating ,
62+ users : extension . users ,
63+ } ) ) ;
64+
65+
66+ export default function HomePage ( ) {
67+ const [ selectedCategory , setSelectedCategory ] = useState ( "all" ) ;
68+ const [ searchQuery , setSearchQuery ] = useState ( "" ) ;
69+ const [ extensions , setExtensions ] = useState ( processedExtensions ) ;
70+ const [ categories , setCategories ] = useState < any [ ] > ( [ ] ) ;
71+
72+ useEffect ( ( ) => {
73+ // Create categories from extensions
74+ const categoryMap = new Map ( ) ;
75+ categoryMap . set ( 'all' , { id : 'all' , name : 'All Extensions' , count : extensions . length } ) ;
76+
77+ extensions . forEach ( extension => {
78+ if ( ! categoryMap . has ( extension . category ) ) {
79+ // Use proper category names
80+ let catName = extension . category . charAt ( 0 ) . toUpperCase ( ) + extension . category . slice ( 1 ) ;
81+ if ( extension . category === 'privacy' ) catName = 'Privacy & Security' ;
82+ else if ( extension . category === 'productivity' ) catName = 'Productivity' ;
83+ else if ( extension . category === 'developer' ) catName = 'Developer Tools' ;
84+ else if ( extension . category === 'shopping' ) catName = 'Shopping' ;
85+ else if ( extension . category === 'crypto' ) catName = 'Crypto & Web3' ;
86+ else if ( extension . category === 'accessibility' ) catName = 'Accessibility' ;
87+ else if ( extension . category === 'other' ) catName = 'Other' ;
88+
89+ categoryMap . set ( extension . category , {
90+ id : extension . category ,
91+ name : catName ,
92+ count : 0
93+ } ) ;
94+ }
95+ categoryMap . get ( extension . category ) . count ++ ;
96+ } ) ;
97+
98+ setCategories ( Array . from ( categoryMap . values ( ) ) ) ;
99+ } , [ extensions ] ) ;
100+
101+ // Filter extensions based on category and search
102+ const filteredExtensions = extensions . filter ( extension => {
103+ const matchesCategory = selectedCategory === "all" || extension . category === selectedCategory ;
104+ const matchesSearch = extension . name . toLowerCase ( ) . includes ( searchQuery . toLowerCase ( ) ) ||
105+ extension . description . toLowerCase ( ) . includes ( searchQuery . toLowerCase ( ) ) ||
106+ extension . tags . some ( ( tag : string ) => tag ?. toLowerCase ( ) . includes ( searchQuery . toLowerCase ( ) ) ) ;
107+ return matchesCategory && matchesSearch ;
108+ } ) ;
109+
110+ return (
111+ < main className = "min-h-screen" >
112+ { /* Hero Section */ }
113+ < section className = "relative overflow-hidden border-b" >
114+ < div className = "absolute inset-0 bg-grid-black/[0.02] dark:bg-grid-white/[0.02]" />
115+ < div className = "container relative py-16 md:py-24" >
116+ < div className = "mx-auto max-w-2xl text-center" >
117+ < Badge className = "mb-4" variant = "secondary" >
118+ < Sparkles className = "mr-1 h-3 w-3" />
119+ Discover...
120+ </ Badge >
121+ < h1 className = "mb-4 text-4xl font-bold tracking-tight sm:text-5xl md:text-6xl" >
122+ Browser extensions that supercharge your productivity
123+ </ h1 >
124+ </ div >
125+ </ div >
126+ </ section >
127+
128+ { /* Main Content */ }
129+ < section className = "container py-12" >
130+ { /* Search and Filter Bar */ }
131+ < ExtensionsSearchBar
132+ searchQuery = { searchQuery }
133+ setSearchQuery = { setSearchQuery }
134+ categories = { categories }
135+ selectedCategory = { selectedCategory }
136+ setSelectedCategory = { setSelectedCategory }
137+ />
138+
139+ { /* Extensions Grid */ }
140+ < div className = "grid gap-5 sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-4" >
141+ { filteredExtensions . map ( ( extension ) => (
142+ < ExtensionCard key = { extension . id } extension = { extension } />
143+ ) ) }
144+ </ div >
145+
146+ { filteredExtensions . length === 0 && (
147+ < div className = "py-12 text-center" >
148+ < p className = "text-lg text-muted-foreground" >
149+ No extensions found matching your criteria.
150+ </ p >
151+ </ div >
152+ ) }
153+ </ section >
154+
155+ { /* CTA Section */ }
156+ < section className = "border-t bg-muted/30" >
157+ < div className = "container py-16" >
158+ < div className = "mx-auto max-w-2xl text-center" >
159+ < h2 className = "mb-4 text-3xl font-bold" >
160+ Missing an extension?
161+ </ h2 >
162+ < p className = "mb-8 text-lg text-muted-foreground" >
163+ We're constantly adding new extensions to our directory. Let us know what you're looking for!
164+ </ p >
165+ < Button size = "lg" className = "group" >
166+ Suggest an Extension
167+ < ArrowRight className = "ml-2 h-4 w-4 transition-transform group-hover:translate-x-1" />
168+ </ Button >
169+ </ div >
170+ </ div >
171+ </ section >
172+ </ main >
173+ ) ;
174+ }
0 commit comments