Skip to content

Commit 30bc500

Browse files
committed
product-page-revamp
1 parent 7c4206e commit 30bc500

File tree

8 files changed

+176
-45
lines changed

8 files changed

+176
-45
lines changed
33 KB
Loading
48.6 KB
Loading
42.6 KB
Loading
28.7 KB
Loading
165 KB
Binary file not shown.
Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
'use client';
2+
3+
import { useState } from 'react';
4+
import { ChevronLeft, ChevronRight } from 'lucide-react';
5+
6+
interface ProductDisplayProps {
7+
name: string;
8+
description: string;
9+
images: string[];
10+
buyNowLink: string;
11+
}
12+
13+
// Simple markdown parser for basic formatting
14+
const parseMarkdown = (text: string) => {
15+
return text
16+
.replace(/\*\*(.*?)\*\*/g, '<strong>$1</strong>')
17+
.replace(/\*(.*?)\*/g, '<em>$1</em>')
18+
.replace(/\n/g, '<br />');
19+
};
20+
21+
export const ProductDisplay = ({
22+
name,
23+
description,
24+
images = [], // Provide default empty array
25+
buyNowLink,
26+
}: ProductDisplayProps) => {
27+
const [currentIndex, setCurrentIndex] = useState(0);
28+
29+
const nextImage = () => {
30+
if (!images || images.length <= 1) return;
31+
setCurrentIndex((prevIndex) =>
32+
prevIndex === images.length - 1 ? 0 : prevIndex + 1,
33+
);
34+
};
35+
36+
const prevImage = () => {
37+
if (!images || images.length <= 1) return;
38+
setCurrentIndex((prevIndex) =>
39+
prevIndex === 0 ? images.length - 1 : prevIndex - 1,
40+
);
41+
};
42+
43+
return (
44+
<div className="w-full mx-auto p-4 sm:p-6 max-h-[800px]">
45+
<div className="grid grid-cols-1 md:grid-cols-2 gap-6 md:gap-8 lg:gap-12">
46+
{/* Product Image */}
47+
<div className="relative w-full">
48+
<div className="relative aspect-square overflow-hidden rounded-2xl border">
49+
<img
50+
src={
51+
images && images.length > 0
52+
? images[currentIndex]
53+
: '/placeholder.svg'
54+
}
55+
alt={`${name} - View ${currentIndex + 1}`}
56+
className={`object-cover transition-all duration-300 p-4`}
57+
/>
58+
{images.length > 1 && (
59+
<>
60+
<button
61+
onClick={prevImage}
62+
className="absolute left-3 top-1/2 -translate-y-1/2 bg-white/80 hover:bg-white rounded-full p-1 shadow-md transition-all duration-200"
63+
aria-label="Previous image"
64+
>
65+
<ChevronLeft className="size-4 text-gray-700" />
66+
</button>
67+
<button
68+
onClick={nextImage}
69+
className="absolute right-3 top-1/2 -translate-y-1/2 bg-white/80 hover:bg-white rounded-full p-1 shadow-md transition-all duration-200"
70+
aria-label="Next image"
71+
>
72+
<ChevronRight className="size-4 text-gray-700" />
73+
</button>
74+
</>
75+
)}
76+
{images.length > 1 && (
77+
<div className="absolute bottom-3 left-0 right-0 flex justify-center gap-2 py-2">
78+
{images.map((_, index) => (
79+
<button
80+
key={index}
81+
onClick={() => setCurrentIndex(index)}
82+
className={`w-3 h-3 rounded-full transition-colors border ${
83+
currentIndex === index
84+
? 'bg-black border-black'
85+
: 'bg-white border-gray-700 hover:bg-gray-200'
86+
}`}
87+
aria-label={`View image ${index + 1}`}
88+
/>
89+
))}
90+
</div>
91+
)}
92+
</div>
93+
</div>
94+
95+
{/* Product Details */}
96+
<div className="flex flex-col justify-between h-full">
97+
<div>
98+
<h1 className="text-2xl sm:text-3xl md:text-4xl font-bold text-gray-900">
99+
{name}
100+
</h1>
101+
{/* Description */}
102+
<div className="mt-4">
103+
<h2 className="text-md font-medium text-gray-900 text-wrap">
104+
Description
105+
</h2>
106+
<div
107+
className="mt-2 text-gray-600 text-sm sm:text-md overflow-auto prose prose-sm max-w-none"
108+
dangerouslySetInnerHTML={{ __html: parseMarkdown(description) }}
109+
/>
110+
</div>
111+
</div>
112+
{/* Buy Now Button */}
113+
<div className="mt-6 md:mt-8">
114+
<a
115+
href={buyNowLink}
116+
target="_blank"
117+
rel="noopener noreferrer"
118+
className="inline-block w-full md:w-[150px] px-6 py-3 text-center text-base font-medium bg-blue-700 text-white rounded-full hover:bg-blue-800 transition-colors shadow-sm hover:shadow-md"
119+
>
120+
Buy Now
121+
</a>
122+
</div>
123+
</div>
124+
</div>
125+
</div>
126+
);
127+
};

src/pages/Products.tsx

Lines changed: 44 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -1,57 +1,56 @@
1+
import { ProductDisplay } from '@/components/Products/ProductDisplay';
12
import Header from '@/sections/Header';
2-
import Footer from '@/sections/Footer';
3+
import { subtleRise } from '@/styles/Animations';
4+
import { motion } from 'framer-motion';
5+
6+
const products = [
7+
{
8+
name: 'Product Name',
9+
description:
10+
'*This is a mock description* Our premium cotton t-shirt offers exceptional comfort and durability. Made from 100% organic cotton, this versatile piece features a classic fit, reinforced seams, and a tagless collar for maximum comfort. Perfect for everyday wear, this t-shirt maintains its shape and softness even after multiple washes.',
11+
images: ['/assets/Images/sugarTshirtBlue.jpeg'],
12+
buyNowLink: 'https://www.bonfire.com/sugar-labs-education/',
13+
},
14+
{
15+
name: 'Product Name',
16+
description:
17+
'*This is a mock description* Our classic hoodie is made from ultra-soft fleece, providing warmth and comfort. Featuring a relaxed fit, a spacious front pocket, and an adjustable drawstring hood, it is perfect for casual outings or lounging at home.',
18+
images: [
19+
'/assets/Images/sugarTshirtWhite.jpeg',
20+
'/assets/Images/sugarTshirtWhite.jpeg',
21+
],
22+
buyNowLink: 'https://www.example.com/classic-hoodie',
23+
},
24+
];
325

426
const Products = () => {
527
return (
628
<div>
729
<Header />
830
<main className="container mx-auto p-4">
9-
<h1 className="text-4xl font-bold text-center my-8">Products</h1>
10-
<p className="text-lg text-gray-700 text-center">
11-
Explore our range of products designed to enhance learning and
12-
education.
13-
</p>
14-
<div className="mt-8 grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
15-
<div className="bg-blue-100 p-6 rounded-lg shadow-md">
16-
<h2 className="text-2xl font-semibold">Sugar Desktop</h2>
17-
<p className="mt-2 text-gray-700">
18-
A free and open-source desktop environment for learning.
19-
</p>
20-
<a
21-
href="#"
22-
className="mt-4 inline-block text-blue-600 hover:underline"
23-
>
24-
Learn More →
25-
</a>
26-
</div>
27-
<div className="bg-green-100 p-6 rounded-lg shadow-md">
28-
<h2 className="text-2xl font-semibold">Sugar Learning Platform</h2>
29-
<p className="mt-2 text-gray-700">
30-
A web-based platform for learning and collaboration.
31-
</p>
32-
<a
33-
href="#"
34-
className="mt-4 inline-block text-green-600 hover:underline"
35-
>
36-
Learn More →
37-
</a>
38-
</div>
39-
<div className="bg-yellow-100 p-6 rounded-lg shadow-md">
40-
<h2 className="text-2xl font-semibold">Sugar Activities</h2>
41-
<p className="mt-2 text-gray-700">
42-
A collection of educational activities for Sugar Desktop and the
43-
Sugar Learning Platform.
44-
</p>
45-
<a
46-
href="#"
47-
className="mt-4 inline-block text-yellow-600 hover:underline"
48-
>
49-
Learn More →
50-
</a>
51-
</div>
31+
<motion.div
32+
initial="hidden"
33+
whileInView="visible"
34+
viewport={{ once: true }}
35+
variants={subtleRise}
36+
>
37+
<h1 className="text-5xl md:text-9xl text-center my-8 py-4 md:py-10 font-Oswald font-thin tracking-[0.05em]">
38+
OUR <span className="text-[#FF4F01]">PRODUCTS</span>
39+
</h1>
40+
</motion.div>
41+
<div className="flex flex-col items-center w-full">
42+
{products.map((product, index) => (
43+
<div key={index} className="w-full max-w-5xl">
44+
<ProductDisplay
45+
name={product.name}
46+
description={product.description}
47+
images={product.images}
48+
buyNowLink={product.buyNowLink}
49+
/>
50+
</div>
51+
))}
5252
</div>
5353
</main>
54-
<Footer />
5554
</div>
5655
);
5756
};

src/styles/globals.css

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,10 @@
2222
font-family: 'Inter';
2323
src: url('/fonts/Inter_28pt-Regular.ttf');
2424
}
25+
@font-face {
26+
font-family: 'Oswald';
27+
src: url('/fonts/Oswald-VariableFont_wght.ttf')
28+
}
2529

2630
@import 'tailwindcss';
2731

@@ -31,6 +35,7 @@
3135
--font-Pacifico: 'Pacifico', sans-serif;
3236
--font-AnonymousPro: 'AnonymousPro', sans-serif;
3337
--font-Inter: 'Inter', sans-serif;
38+
--font-Oswald: 'Oswald', sans-serif;
3439
}
3540

3641
:root {

0 commit comments

Comments
 (0)