11"use client" ;
22
3+ import { useState } from "react" ;
34import { AppShell , Header , Content , Footer } from "@appshell/react" ;
4- import { ShoppingCart , Search } from "lucide-react" ;
5+ import { ShoppingCart , Search , Star } from "lucide-react" ;
6+
7+ const products = [
8+ {
9+ id : 1 ,
10+ name : "Linen Relaxed Blazer" ,
11+ price : 149 ,
12+ rating : 4.5 ,
13+ reviews : 234 ,
14+ gradient : "bg-gradient-to-br from-amber-200 to-orange-300" ,
15+ colors : [ "#c4a882" , "#2c2c2c" , "#e8ddd3" ] ,
16+ tag : "Best Seller" as const ,
17+ } ,
18+ {
19+ id : 2 ,
20+ name : "Cropped Wide-Leg Trousers" ,
21+ price : 89 ,
22+ rating : 4.0 ,
23+ reviews : 187 ,
24+ gradient : "bg-gradient-to-br from-stone-300 to-zinc-400" ,
25+ colors : [ "#1a1a1a" , "#d4c5b0" ] ,
26+ tag : "New" as const ,
27+ } ,
28+ {
29+ id : 3 ,
30+ name : "Silk Camisole Top" ,
31+ price : 59 ,
32+ rating : 4.5 ,
33+ reviews : 312 ,
34+ gradient : "bg-gradient-to-br from-rose-200 to-pink-300" ,
35+ colors : [ "#e8c4c4" , "#1a1a1a" , "#f5f0eb" ] ,
36+ tag : null ,
37+ } ,
38+ {
39+ id : 4 ,
40+ name : "Oversized Wool Coat" ,
41+ price : 189 ,
42+ rating : 5.0 ,
43+ reviews : 156 ,
44+ gradient : "bg-gradient-to-br from-slate-400 to-gray-600" ,
45+ colors : [ "#3d3d3d" , "#8b7d6b" ] ,
46+ tag : "Best Seller" as const ,
47+ } ,
48+ {
49+ id : 5 ,
50+ name : "Ribbed Knit Cardigan" ,
51+ price : 79 ,
52+ rating : 4.0 ,
53+ reviews : 98 ,
54+ gradient : "bg-gradient-to-br from-emerald-200 to-teal-300" ,
55+ colors : [ "#6b8f71" , "#f5f0eb" , "#2c2c2c" ] ,
56+ tag : null ,
57+ } ,
58+ {
59+ id : 6 ,
60+ name : "High-Rise Slim Jeans" ,
61+ price : 98 ,
62+ rating : 4.5 ,
63+ reviews : 421 ,
64+ gradient : "bg-gradient-to-br from-blue-300 to-indigo-400" ,
65+ colors : [ "#3b5998" , "#1a1a1a" ] ,
66+ tag : "Sale" as const ,
67+ } ,
68+ {
69+ id : 7 ,
70+ name : "Cotton Poplin Shirt" ,
71+ price : 65 ,
72+ rating : 4.0 ,
73+ reviews : 276 ,
74+ gradient : "bg-gradient-to-br from-sky-200 to-cyan-300" ,
75+ colors : [ "#f5f5f5" , "#a8c8e0" , "#1a1a1a" ] ,
76+ tag : "New" as const ,
77+ } ,
78+ {
79+ id : 8 ,
80+ name : "Leather Crossbody Bag" ,
81+ price : 129 ,
82+ rating : 4.5 ,
83+ reviews : 189 ,
84+ gradient : "bg-gradient-to-br from-yellow-200 to-amber-400" ,
85+ colors : [ "#8b6914" , "#1a1a1a" , "#c4a882" ] ,
86+ tag : null ,
87+ } ,
88+ {
89+ id : 9 ,
90+ name : "Pleated Midi Skirt" ,
91+ price : 75 ,
92+ rating : 3.5 ,
93+ reviews : 143 ,
94+ gradient : "bg-gradient-to-br from-violet-200 to-purple-300" ,
95+ colors : [ "#7c5cbf" , "#1a1a1a" ] ,
96+ tag : null ,
97+ } ,
98+ {
99+ id : 10 ,
100+ name : "Cashmere Crewneck Sweater" ,
101+ price : 165 ,
102+ rating : 5.0 ,
103+ reviews : 208 ,
104+ gradient : "bg-gradient-to-br from-red-200 to-rose-400" ,
105+ colors : [ "#c45c5c" , "#f5f0eb" , "#2c2c2c" ] ,
106+ tag : "Best Seller" as const ,
107+ } ,
108+ {
109+ id : 11 ,
110+ name : "Quilted Puffer Vest" ,
111+ price : 119 ,
112+ rating : 4.0 ,
113+ reviews : 87 ,
114+ gradient : "bg-gradient-to-br from-lime-200 to-green-400" ,
115+ colors : [ "#4a6741" , "#1a1a1a" ] ,
116+ tag : "Sale" as const ,
117+ } ,
118+ {
119+ id : 12 ,
120+ name : "Woven Straw Sun Hat" ,
121+ price : 45 ,
122+ rating : 4.5 ,
123+ reviews : 64 ,
124+ gradient : "bg-gradient-to-br from-orange-200 to-yellow-300" ,
125+ colors : [ "#d4a76a" , "#f5f0eb" ] ,
126+ tag : "New" as const ,
127+ } ,
128+ ] ;
129+
130+ const categories = [ "All" , "Tops" , "Bottoms" , "Outerwear" , "Accessories" , "Sale" ] ;
131+
132+ function tagColor ( tag : string ) {
133+ switch ( tag ) {
134+ case "Best Seller" :
135+ return "bg-amber-500 text-white" ;
136+ case "New" :
137+ return "bg-emerald-500 text-white" ;
138+ case "Sale" :
139+ return "bg-destructive text-white" ;
140+ default :
141+ return "bg-muted text-muted-foreground" ;
142+ }
143+ }
144+
145+ function StarRating ( { rating, reviews } : { rating : number ; reviews : number } ) {
146+ return (
147+ < div className = "flex items-center gap-1" >
148+ < div className = "flex" >
149+ { Array . from ( { length : 5 } , ( _ , i ) => {
150+ const filled = i < Math . floor ( rating ) ;
151+ const half = ! filled && i < rating ;
152+ return (
153+ < Star
154+ key = { i }
155+ className = { `size-3 ${
156+ filled || half
157+ ? "fill-amber-400 text-amber-400"
158+ : "fill-none text-muted-foreground/40"
159+ } `}
160+ />
161+ ) ;
162+ } ) }
163+ </ div >
164+ < span className = "text-xs text-muted-foreground" > ({ reviews } )</ span >
165+ </ div >
166+ ) ;
167+ }
5168
6169export default function EcommerceExample ( ) {
170+ const [ activeCategory , setActiveCategory ] = useState ( "All" ) ;
171+
7172 return (
8173 < AppShell safeArea >
9174 < Header
10175 behavior = "fixed"
11176 theme = "light"
12- logo = { < span className = "text-lg font-bold tracking-tight" > ShopNow</ span > }
177+ logo = {
178+ < span className = "text-lg font-bold tracking-tight" > ShopNow</ span >
179+ }
13180 title = "New Arrivals"
14181 subtitle = "Spring Collection"
15182 searchContent = {
@@ -24,31 +191,80 @@ export default function EcommerceExample() {
24191 </ div >
25192 }
26193 actions = {
27- < button aria-label = "Cart (3 items)" className = "relative p-2 rounded-lg hover:bg-accent transition-colors" >
194+ < button
195+ aria-label = "Cart (3 items)"
196+ className = "relative p-2 rounded-lg hover:bg-accent transition-colors"
197+ >
28198 < ShoppingCart className = "size-5" />
29- < span aria-hidden = "true" className = "absolute -top-0.5 -right-0.5 flex h-4 min-w-4 items-center justify-center rounded-full bg-destructive px-1 text-[10px] font-bold text-white" >
199+ < span
200+ aria-hidden = "true"
201+ className = "absolute -top-0.5 -right-0.5 flex h-4 min-w-4 items-center justify-center rounded-full bg-destructive px-1 text-[10px] font-bold text-white"
202+ >
30203 3
31204 </ span >
32205 </ button >
33206 }
34207 />
35208
36209 < Content className = "pb-24" >
37- < div className = "mx-auto max-w-7xl px-4 py-6" >
210+ < div className = "mx-auto max-w-7xl px-4 py-6 space-y-6" >
211+ { /* Category chips */ }
212+ < div className = "flex gap-2 overflow-x-auto no-scrollbar" >
213+ { categories . map ( ( category ) => (
214+ < button
215+ key = { category }
216+ onClick = { ( ) => setActiveCategory ( category ) }
217+ className = { `rounded-full px-4 py-1.5 text-sm whitespace-nowrap transition-colors ${
218+ activeCategory === category
219+ ? "bg-primary text-primary-foreground"
220+ : "bg-muted text-muted-foreground"
221+ } `}
222+ >
223+ { category }
224+ </ button >
225+ ) ) }
226+ </ div >
227+
228+ { /* Product grid */ }
38229 < div className = "grid grid-cols-2 md:grid-cols-3 gap-4" >
39- { Array . from ( { length : 12 } , ( _ , i ) => (
40- < div key = { i } className = "rounded-xl border bg-card overflow-hidden" >
41- < div className = "aspect-square bg-muted" />
42- < div className = "p-3 space-y-2" >
43- < div className = "h-3.5 w-3/4 rounded bg-muted" />
44- < div className = "h-3 w-1/2 rounded bg-muted" />
45- < div className = "flex items-center justify-between mt-2" >
46- < div className = "h-4 w-16 rounded bg-muted" />
47- < div className = "flex gap-1" >
48- { Array . from ( { length : 5 } , ( _ , j ) => (
49- < div key = { j } className = "size-2.5 rounded-full bg-muted" />
50- ) ) }
51- </ div >
230+ { products . map ( ( product ) => (
231+ < div
232+ key = { product . id }
233+ className = "rounded-xl border bg-card overflow-hidden"
234+ >
235+ { /* Image placeholder */ }
236+ < div className = { `relative aspect-square ${ product . gradient } ` } >
237+ { product . tag && (
238+ < span
239+ className = { `absolute top-2 left-2 rounded-full px-2 py-0.5 text-[11px] font-semibold ${ tagColor ( product . tag ) } ` }
240+ >
241+ { product . tag }
242+ </ span >
243+ ) }
244+ </ div >
245+
246+ { /* Product info */ }
247+ < div className = "p-3 space-y-1.5" >
248+ < h3 className = "text-sm font-medium text-foreground leading-snug line-clamp-1" >
249+ { product . name }
250+ </ h3 >
251+
252+ < StarRating rating = { product . rating } reviews = { product . reviews } />
253+
254+ < p className = "text-sm font-bold text-foreground" >
255+ ${ product . price }
256+ </ p >
257+
258+ { /* Color swatches */ }
259+ < div className = "flex items-center gap-1.5 pt-0.5" >
260+ { product . colors . map ( ( color ) => (
261+ < span
262+ key = { color }
263+ className = "size-4 rounded-full border border-border"
264+ style = { { backgroundColor : color } }
265+ aria-label = { `Color ${ color } ` }
266+ />
267+ ) ) }
52268 </ div >
53269 </ div >
54270 </ div >
@@ -58,8 +274,11 @@ export default function EcommerceExample() {
58274 </ Content >
59275
60276 < Footer variant = "floating" position = "right" >
61- < button aria-label = "Add to cart" className = "flex items-center justify-center size-14 rounded-full bg-primary text-primary-foreground shadow-xl hover:scale-105 transition-transform" >
277+ < button className = "relative flex items-center justify-center size-14 rounded-full bg-primary text-primary-foreground shadow-xl hover:scale-105 transition-transform" >
62278 < ShoppingCart className = "size-6" />
279+ < span className = "absolute -top-1 -right-1 flex h-5 min-w-5 items-center justify-center rounded-full bg-destructive px-1 text-[11px] font-bold text-white" >
280+ 3
281+ </ span >
63282 </ button >
64283 </ Footer >
65284 </ AppShell >
0 commit comments