1
+ "use client" ;
2
+ import React , { useState , useEffect } from "react" ;
3
+ import NavBar from "../NavBar/page" ;
4
+ import Footer from "../Footer/page" ;
5
+ import { motion , AnimatePresence } from "framer-motion" ;
6
+ import { sanity } from "@/lib/sanity" ; // adjust path as needed
7
+
8
+ // GROQ query for your event schema
9
+ const query = `*[_type == "event"]{
10
+ _id,
11
+ title,
12
+ date,
13
+ location,
14
+ description,
15
+ images[]{
16
+ asset->{
17
+ _id,
18
+ url
19
+ }
20
+ }
21
+ }` ;
22
+
23
+ const EventCard = ( { event } : { event : any } ) => (
24
+ < motion . div
25
+ className = "bg-white/20 dark:bg-neutral-900/70 rounded-2xl shadow-xl overflow-hidden backdrop-blur-md border border-white/10 flex flex-col"
26
+ initial = { { opacity : 0 , y : 40 , scale : 0.95 } }
27
+ animate = { { opacity : 1 , y : 0 , scale : 1 } }
28
+ transition = { { duration : 0.5 , type : "spring" , stiffness : 120 } }
29
+ whileHover = { {
30
+ scale : 1.03 ,
31
+ boxShadow : "0 8px 32px 0 rgba(0,0,0,0.18)" ,
32
+ } }
33
+ >
34
+ { event . images && event . images [ 0 ] ?. asset ?. url && (
35
+ < img
36
+ src = { event . images [ 0 ] . asset . url }
37
+ alt = { event . title }
38
+ className = "w-full h-48 object-cover"
39
+ />
40
+ ) }
41
+ < div className = "p-6 flex flex-col flex-1" >
42
+ < h3 className = "text-2xl font-bold text-gray-800 dark:text-white mb-2" >
43
+ { event . title }
44
+ </ h3 >
45
+ < div className = "text-sm text-gray-500 dark:text-gray-300 mb-2" >
46
+ < span >
47
+ { event . date ? new Date ( event . date ) . toLocaleDateString ( ) : "" }
48
+ </ span >
49
+ · < span > { event . location } </ span >
50
+ </ div >
51
+ < p className = "text-gray-700 dark:text-gray-200 flex-1" >
52
+ { event . description }
53
+ </ p >
54
+ </ div >
55
+ </ motion . div >
56
+ ) ;
57
+
58
+ const EventsPage = ( ) => {
59
+ const [ search , setSearch ] = useState ( "" ) ;
60
+ const [ events , setEvents ] = useState < any [ ] > ( [ ] ) ;
61
+
62
+ useEffect ( ( ) => {
63
+ sanity . fetch ( query ) . then ( setEvents ) ;
64
+ } , [ ] ) ;
65
+
66
+ const filteredEvents = events . filter ( ( event ) => {
67
+ const searchText = search . toLowerCase ( ) ;
68
+ return (
69
+ event . title ?. toLowerCase ( ) . includes ( searchText ) ||
70
+ event . description ?. toLowerCase ( ) . includes ( searchText ) ||
71
+ event . location ?. toLowerCase ( ) . includes ( searchText )
72
+ ) ;
73
+ } ) ;
74
+
75
+ return (
76
+ < div className = "flex flex-col min-h-screen bg-black" >
77
+ < NavBar />
78
+ < main className = "flex-1 container mx-auto px-4 py-24" >
79
+ < motion . div
80
+ initial = { { opacity : 0 , y : 30 } }
81
+ animate = { { opacity : 1 , y : 0 } }
82
+ transition = { { duration : 0.7 } }
83
+ className = "text-center mb-12"
84
+ >
85
+ < h1 className = "text-4xl md:text-5xl font-extrabold text-white mb-3" >
86
+ Upcoming < span className = "text-primary" > Events</ span >
87
+ </ h1 >
88
+ < p className = "text-gray-200 max-w-2xl mx-auto" >
89
+ Stay updated with our latest events, workshops, and meetups.
90
+ </ p >
91
+ </ motion . div >
92
+ < div className = "flex justify-center mb-10" >
93
+ < input
94
+ type = "text"
95
+ placeholder = "Search events..."
96
+ value = { search }
97
+ onChange = { ( e ) => setSearch ( e . target . value ) }
98
+ className = "w-full max-w-md px-4 py-2 rounded-lg border border-gray-300 focus:outline-none focus:ring-2 focus:ring-primary text-black"
99
+ />
100
+ </ div >
101
+ < AnimatePresence >
102
+ < div className = "grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-8" >
103
+ { filteredEvents . length > 0 ? (
104
+ filteredEvents . map ( ( event ) => (
105
+ < EventCard key = { event . _id } event = { event } />
106
+ ) )
107
+ ) : (
108
+ < motion . div
109
+ className = "col-span-full text-center text-gray-400 py-20"
110
+ initial = { { opacity : 0 } }
111
+ animate = { { opacity : 1 } }
112
+ >
113
+ No events found.
114
+ </ motion . div >
115
+ ) }
116
+ </ div >
117
+ </ AnimatePresence >
118
+ </ main >
119
+ < Footer />
120
+ </ div >
121
+ ) ;
122
+ } ;
123
+
124
+ export default EventsPage ;
0 commit comments