Skip to content

Commit ed08c61

Browse files
ashworks1706benjuntillaCopilot
authored
Commit that shit v2 (#85)
* commit that shit * Update src/components/Shop/CategorySection.tsx Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Signed-off-by: Ben Juntilla <ben@benjuntilla.com> * Update CategorySection component * commit that shit * Update src/components/Shop/ProductCarousel.tsx Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Signed-off-by: Ash Srivastava <85481905+ashworks1706@users.noreply.github.com> --------- Signed-off-by: Ben Juntilla <ben@benjuntilla.com> Signed-off-by: Ash Srivastava <85481905+ashworks1706@users.noreply.github.com> Co-authored-by: Ben Juntilla <ben@benjuntilla.com> Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
1 parent 9eb9f0e commit ed08c61

File tree

3 files changed

+181
-49
lines changed

3 files changed

+181
-49
lines changed
Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
import React from "react";
2+
3+
interface PointRow {
4+
activity: string;
5+
points: string;
6+
note?: string;
7+
}
8+
9+
interface PointCategory {
10+
label: string;
11+
rows: PointRow[];
12+
}
13+
14+
const categories: PointCategory[] = [
15+
{
16+
label: "Meetings",
17+
rows: [
18+
{ activity: "Attend in-person GBM", points: "10 pts" },
19+
{ activity: "Attend online GBM", points: "~5 pts" },
20+
{ activity: "Attend lounge hours", points: "5 pts" },
21+
],
22+
},
23+
{
24+
label: "Participation",
25+
rows: [
26+
{ activity: "Ask questions / interact", points: "1 pt", note: "per time" },
27+
{ activity: "Bonus participation", points: "5 pts" },
28+
{ activity: "Submit workshop challenge", points: "20 pts" },
29+
],
30+
},
31+
{
32+
label: "Discord",
33+
rows: [
34+
{ activity: "General engagement", points: "2 pts", note: "per mo · max 10/sem" },
35+
{ activity: "Helpful post / solve query", points: "5 pts", note: "max 15/sem" },
36+
],
37+
},
38+
];
39+
40+
const PointsBreakdownTable: React.FC = () => {
41+
return (
42+
<div className="bg-black/40 backdrop-blur-xl shadow-2xl text-gray-300 w-full rounded-xl overflow-hidden border border-white/10">
43+
{/* 2-D Table */}
44+
<table className="w-full text-sm border-collapse">
45+
<caption className="sr-only">
46+
Points breakdown by category, activity, and points
47+
</caption>
48+
<thead>
49+
<tr className="bg-white/[0.06]">
50+
<th
51+
scope="col"
52+
className="text-left px-3 py-2.5 text-gray-400 font-semibold uppercase tracking-widest text-[10px] border-b border-r border-white/10 w-[24%]"
53+
>
54+
Category
55+
</th>
56+
<th
57+
scope="col"
58+
className="text-left px-3 py-2.5 text-gray-400 font-semibold uppercase tracking-widest text-[10px] border-b border-r border-white/10"
59+
>
60+
Activity
61+
</th>
62+
<th
63+
scope="col"
64+
className="text-center px-3 py-2.5 text-gray-400 font-semibold uppercase tracking-widest text-[10px] border-b border-white/10 w-[20%]"
65+
>
66+
Pts
67+
</th>
68+
</tr>
69+
</thead>
70+
<tbody>
71+
{categories.map((cat, ci) =>
72+
cat.rows.map((row, ri) => (
73+
<tr
74+
key={`${ci}-${ri}`}
75+
className="border-b border-white/[0.05] last:border-0 hover:bg-white/[0.04] transition-colors"
76+
>
77+
{/* Category cell – only on first row of each category */}
78+
{ri === 0 ? (
79+
<td
80+
rowSpan={cat.rows.length}
81+
className="px-3 py-3 align-middle border-r border-white/10 text-[11px] font-semibold text-gray-400 uppercase tracking-widest leading-snug"
82+
>
83+
{cat.label}
84+
</td>
85+
) : null}
86+
87+
{/* Activity */}
88+
<td className="px-3 py-3 border-r border-white/10 text-gray-200 leading-snug">
89+
{row.activity}
90+
{row.note && (
91+
<span className="block text-gray-500 text-[11px] mt-0.5">{row.note}</span>
92+
)}
93+
</td>
94+
95+
{/* Points badge */}
96+
<td className="px-3 py-3 text-center">
97+
<span className="inline-block bg-blue-500/20 border border-blue-400/30 text-blue-300 font-bold text-xs px-2 py-1 rounded-md tabular-nums whitespace-nowrap">
98+
{row.points}
99+
</span>
100+
</td>
101+
</tr>
102+
))
103+
)}
104+
</tbody>
105+
</table>
106+
</div>
107+
);
108+
};
109+
110+
export default PointsBreakdownTable;

src/components/Shop/ProductCarousel.tsx

Lines changed: 64 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -12,16 +12,25 @@ interface ProductCarouselProps {
1212
slides: CarouselSlide[];
1313
autoplayDelay?: number;
1414
videoUrl?: string;
15+
rightPanel?: React.ReactNode;
1516
}
1617

1718
const ProductCarousel: React.FC<ProductCarouselProps> = ({
1819
slides,
1920
autoplayDelay = 5000,
2021
videoUrl = "https://framerusercontent.com/assets/sRXQsZpCuTpukMUfotGcRUuvg.mp4",
22+
rightPanel,
2123
}) => {
2224
const [currentIndex, setCurrentIndex] = useState(0);
2325
const [videoLoaded, setVideoLoaded] = useState(false);
2426
const [videoError, setVideoError] = useState(false);
27+
const [isMobile, setIsMobile] = useState(() => window.innerWidth < 1024);
28+
29+
useEffect(() => {
30+
const handleResize = () => setIsMobile(window.innerWidth < 1024);
31+
window.addEventListener("resize", handleResize);
32+
return () => window.removeEventListener("resize", handleResize);
33+
}, []);
2534

2635
useEffect(() => {
2736
if (slides.length <= 1) return;
@@ -63,57 +72,65 @@ const ProductCarousel: React.FC<ProductCarouselProps> = ({
6372
</div>
6473

6574
{/* Carousel Content */}
66-
<div className="relative w-full h-[350px] md:h-[450px] lg:h-[500px] z-10 pt-24 md:pt-32">
67-
{/* Animated Text Content */}
75+
<div className="relative w-full h-auto lg:h-[500px] z-10 pt-20 pb-8 lg:pt-32 lg:pb-0">
6876
<div className="relative z-10 h-full flex items-center">
69-
<div className="container mx-auto px-4 md:px-8 lg:px-16">
70-
<div className="max-w-3xl">
71-
<AnimatePresence mode="wait">
72-
<motion.div
73-
key={currentSlide.id}
74-
initial={{ opacity: 0, x: -60, scale: 0.95 }}
75-
animate={{ opacity: 1, x: 0, scale: 1 }}
76-
exit={{ opacity: 0, x: 60, scale: 0.95 }}
77-
transition={{ duration: 1, ease: [0.22, 1, 0.36, 1] }}
78-
>
79-
{currentSlide.subtitle && (
80-
<motion.p
81-
className="text-blue-400 font-semibold text-xs md:text-sm lg:text-base uppercase tracking-wider mb-2 md:mb-3"
82-
initial={{ opacity: 0, x: -40 }}
83-
animate={{ opacity: 1, x: 0 }}
84-
transition={{ delay: 0.2, duration: 0.8, ease: "easeOut" }}
85-
>
86-
{currentSlide.subtitle}
87-
</motion.p>
88-
)}
89-
<motion.h2
90-
className="text-3xl md:text-5xl lg:text-7xl xl:text-8xl font-bold text-white mb-2 md:mb-3 leading-tight"
91-
initial={{ opacity: 0, x: -50, rotateX: -15 }}
92-
animate={{ opacity: 1, x: 0, rotateX: 0 }}
93-
transition={{ delay: 0.3, duration: 0.9, ease: [0.22, 1, 0.36, 1] }}
77+
<div className="container mx-auto px-4 md:px-8 lg:px-16 w-full">
78+
<div className="flex flex-col items-center gap-8 lg:flex-row lg:justify-center lg:gap-24 xl:gap-48">
79+
{/* Left: animated text */}
80+
<div className="w-full lg:w-72 xl:w-[408px] lg:shrink-0">
81+
<AnimatePresence mode="wait">
82+
<motion.div
83+
key={currentSlide.id}
84+
initial={{ opacity: 0, x: isMobile ? 0 : -60, scale: 0.95 }}
85+
animate={{ opacity: 1, x: 0, scale: 1 }}
86+
exit={{ opacity: 0, x: isMobile ? 0 : 60, scale: 0.95 }}
87+
transition={{ duration: 1, ease: [0.22, 1, 0.36, 1] }}
9488
>
95-
{currentSlide.title}
96-
</motion.h2>
97-
{currentSlide.description && (
98-
<motion.p
99-
className="text-gray-300 text-sm md:text-lg lg:text-2xl mb-6 md:mb-10 max-w-2xl"
100-
initial={{ opacity: 0, x: -40 }}
101-
animate={{ opacity: 1, x: 0 }}
102-
transition={{ delay: 0.5, duration: 0.8, ease: "easeOut" }}
89+
{currentSlide.subtitle && (
90+
<motion.p
91+
className="text-blue-400 font-semibold text-xs md:text-sm uppercase tracking-wider mb-2"
92+
initial={{ opacity: 0, x: isMobile ? 0 : -40 }}
93+
animate={{ opacity: 1, x: 0 }}
94+
transition={{ delay: 0.2, duration: 0.8, ease: "easeOut" }}
95+
>
96+
{currentSlide.subtitle}
97+
</motion.p>
98+
)}
99+
<motion.h2
100+
className="text-3xl md:text-4xl lg:text-5xl xl:text-6xl font-bold text-white mb-3 leading-tight"
101+
initial={{ opacity: 0, x: isMobile ? 0 : -50, rotateX: -15 }}
102+
animate={{ opacity: 1, x: 0, rotateX: 0 }}
103+
transition={{ delay: 0.3, duration: 0.9, ease: [0.22, 1, 0.36, 1] }}
103104
>
104-
{currentSlide.description}
105-
</motion.p>
106-
)}
107-
</motion.div>
108-
</AnimatePresence>
105+
{currentSlide.title}
106+
</motion.h2>
107+
{currentSlide.description && (
108+
<motion.p
109+
className="text-gray-300 text-sm md:text-base mb-6 md:mb-8 max-w-sm"
110+
initial={{ opacity: 0, x: isMobile ? 0 : -40 }}
111+
animate={{ opacity: 1, x: 0 }}
112+
transition={{ delay: 0.5, duration: 0.8, ease: "easeOut" }}
113+
>
114+
{currentSlide.description}
115+
</motion.p>
116+
)}
117+
</motion.div>
118+
</AnimatePresence>
119+
120+
<a
121+
href="#products"
122+
className="inline-block bg-blue-500/10 backdrop-blur-xl border border-blue-400/20 hover:bg-blue-500/20 hover:border-blue-400/40 text-white font-semibold px-6 py-3 rounded-lg transition-all duration-300 hover:scale-105 shadow-lg shadow-blue-500/10 text-sm md:text-base"
123+
>
124+
Shop Now
125+
</a>
126+
</div>
109127

110-
{/* Static CTA Button */}
111-
<a
112-
href="#products"
113-
className="inline-block bg-blue-500/10 backdrop-blur-xl border border-blue-400/20 hover:bg-blue-500/20 hover:border-blue-400/40 text-white font-semibold px-6 py-3 md:px-10 md:py-4 rounded-lg md:rounded-xl transition-all duration-300 hover:scale-105 shadow-lg shadow-blue-500/10 text-sm md:text-base lg:text-lg"
114-
>
115-
Shop Now
116-
</a>
128+
{/* Right: optional panel (e.g. points table) */}
129+
{rightPanel && (
130+
<div className="w-full max-h-[45vh] overflow-y-auto lg:max-h-none lg:overflow-visible lg:w-[440px] lg:shrink-0">
131+
{rightPanel}
132+
</div>
133+
)}
117134
</div>
118135
</div>
119136
</div>

src/pages/Shop/ShopIndex.tsx

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import { CategoryLayout } from "../../components/Shop/CategoryLayout";
88
import { useProducts } from "../../hooks/useProducts";
99
import { motion, useInView } from "framer-motion";
1010
import LoadingSpinner from "../../components/LoadingSpinner";
11+
import PointsBreakdownTable from "../../components/Shop/PointsBreakdownTable";
1112
import "./styles/scrolling-text.css";
1213

1314
const ShopIndex: React.FC = () => {
@@ -62,9 +63,13 @@ const ShopIndex: React.FC = () => {
6263
</Helmet>
6364
<div className="min-h-screen bg-black text-white h-screen overflow-y-scroll snap-y snap-mandatory snap-container">
6465
{/* Hero Carousel Section - Full Screen Snap */}
65-
<div className="snap-section relative overflow-hidden flex flex-col">
66+
<div className="snap-section relative lg:overflow-hidden flex flex-col">
6667
<div className="flex-1 flex flex-col justify-center">
67-
<ProductCarousel slides={carouselSlides} autoplayDelay={5000} />
68+
<ProductCarousel
69+
slides={carouselSlides}
70+
autoplayDelay={5000}
71+
rightPanel={<PointsBreakdownTable />}
72+
/>
6873
</div>
6974

7075
{/* Scroll indicator */}

0 commit comments

Comments
 (0)