diff --git a/src/app/page.tsx b/src/app/page.tsx
index 5f01fd5..98a5d35 100644
--- a/src/app/page.tsx
+++ b/src/app/page.tsx
@@ -7,9 +7,9 @@ import Section from "@/components/Section";
import Button from "@/components/Button";
import BannerSlider from "@/components/BannerSlider";
import Image from "next/image";
-import { useState, useEffect, useRef, useCallback, useMemo } from "react";
-import { AnimatePresence } from "framer-motion";
-import { useInstagram } from "@/hooks/useInstagram";
+import { useState, useEffect, useRef, useCallback } from "react";
+import ProductCategory from "@/components/ProductCategory";
+import SocialMedia from "@/components/SocialMedia";
// Premium animation variants
const fadeInUp = {
@@ -46,14 +46,6 @@ const categories = [
"Dragees",
"Gelatos",
];
-const categoryImages = [
- "/categories/c1.svg",
- "/categories/c2.svg",
- "/categories/c3.svg",
- "/categories/c4.svg",
- "/categories/c5.svg",
- "/categories/c6.svg",
-];
const partnerImages = [
"/partners/p1.svg",
@@ -127,14 +119,18 @@ export default function Home() {
return () => clearInterval(timer);
}, []);
- const { posts, loading, error, isTokenExpired } = useInstagram();
-
// Memoize expensive components
- const BrandStorySection = useMemo(
- () => (
+
+ return (
+
+
+
+
+ {/* Brand Story */}
+
-
- {/* Left Column - Text */}
+
+ {/* Brand Story - Left Text */}
-
- {/* Right Column - Image */}
+ {/* Brand Story - Right Image */}
- {/* Premium overlay for depth */}
-
-
- ),
- []
- );
- return (
-
-
-
-
- {BrandStorySection}
-
- {/* Chocolate Tempering Section */}
-
-
- {/* Left Column - Image */}
+ {/* Chocolate Tempering - Left Video */}
- {/* Premium overlay for depth */}
- {/* Right Column - Text */}
+ {/* Chocolate Tempering - Right Text */}
- {/* Premium decorative line */}
- {/* Product Categories Section */}
-
-
- {/* Left Column - Categories List */}
-
-
- {categories.map((category, idx) => (
-
- setCurrentCategory(idx)}
- onMouseEnter={() => setCurrentCategory(idx)}
- tabIndex={-1}
- >
- {/* Show only on mobile */}
-
-
-
-
- {/* Category name */}
- {category}
-
-
- ))}
-
-
-
- {/* Right Column - Large Category Image (desktop only) */}
-
-
-
-
-
-
-
-
+
{/* Social Media Call to Action */}
-
-
-
- Follow us on Instagram
-
-
-
-
- {loading ? (
- <>
- {[1, 2, 3].map((i) => (
-
- ))}
- >
- ) : error ? (
- isTokenExpired ? (
-
-
-
- 🔗
-
-
- Instagram Connection Expired
-
-
- Our Instagram connection needs to be refreshed. We're
- working on getting it back up!
-
-
- In the meantime, follow us @mozimo_chocolate
-
-
-
- ) : (
- <>
- {/* Left Block - Chocolate Spread Jar */}
-
-
-
-
- 🍫
-
-
-
- MOZIMO
-
-
- SINGLE ORIGIN HAZELNUT SPREAD 45%
-
-
-
-
-
-
- {/* Middle Block - Magazine Article */}
-
-
-
- 🍫
-
-
-
-
- By RUPALI DEAN
-
-
-
- MOZIMO'S CHOCOLATE PIE BY PRIYANKA GUPTA
-
-
-
- isolat[ing] beans to not only single ori- but also to
- single farms so as to express unique complexity.
-
-
-
-
-
- {/* Right Block - World Chocolate Day */}
-
-
-
-
- World Chocolate Day
-
-
- Celebrating the art of chocolate making
-
-
-
-
🍫
-
- Join us in celebrating the world's favorite treat
-
-
-
-
- >
- )
- ) : (
- posts?.slice(0, 3).map((post, index) => (
-
-
-
-
{
- const target = e.target as HTMLImageElement;
- target.src = "/bst/bs1.svg";
- }}
- />
-
- {post.mediaType === "VIDEO" && (
-
- )}
-
-
-
- {post.caption?.slice(0, 100)}...
-
-
-
-
-
-
- ))
- )}
-
-
+
{/* In the Spotlight Section */}
@@ -785,7 +447,6 @@ export default function Home() {
animate={{ x: `-${spotlightIndex * 152}px` }}
transition={{ type: "spring", stiffness: 80, damping: 18 }}
>
- {/* Create 12 tiles (3 sets of 4 logos) */}
{Array(12)
.fill(0)
.map((_, i) => {
@@ -795,7 +456,10 @@ export default function Home() {
(null);
-
+
// Auto-advance slider
useEffect(() => {
const timer = setInterval(() => {
@@ -37,7 +37,7 @@ export default function BannerSlider() {
const goToPrevious = () => {
setDirection(-1);
- setCurrentIndex((prevIndex) =>
+ setCurrentIndex((prevIndex) =>
prevIndex === 0 ? banners.length - 1 : prevIndex - 1
);
};
@@ -49,7 +49,7 @@ export default function BannerSlider() {
const slideVariants = {
enter: (direction: number) => ({
- x: direction > 0 ? '100%' : '-100%',
+ x: direction > 0 ? "100%" : "-100%",
opacity: 1,
}),
center: {
@@ -57,9 +57,9 @@ export default function BannerSlider() {
opacity: 1,
},
exit: (direction: number) => ({
- x: direction < 0 ? '100%' : '-100%',
+ x: direction < 0 ? "100%" : "-100%",
opacity: 1,
- })
+ }),
};
const swipeConfidenceThreshold = 10000;
@@ -76,7 +76,7 @@ export default function BannerSlider() {
};
return (
- {
@@ -105,7 +105,7 @@ export default function BannerSlider() {
exit="exit"
transition={{
x: { type: "spring", stiffness: 300, damping: 30 },
- duration: 0.4
+ duration: 0.4,
}}
drag="x"
dragConstraints={{ left: 0, right: 0 }}
@@ -128,41 +128,43 @@ export default function BannerSlider() {
className="object-cover img-premium"
draggable={false}
priority={currentIndex === 0}
- loading={currentIndex === 0 ? 'eager' : 'lazy'}
+ loading={currentIndex === 0 ? "eager" : "lazy"}
sizes="100vw"
quality={85}
/>
-
+
{/* Premium overlay with gradient */}
{/* Premium Shop Now Button */}
-
+ {currentIndex === 0 && (
+
+ )}
{/* Premium Navigation Arrows - Hidden on mobile */}
@@ -179,8 +181,18 @@ export default function BannerSlider() {
whileTap={{ scale: 0.95 }}
aria-label="Previous banner"
>
-
-
+
+
@@ -195,8 +207,18 @@ export default function BannerSlider() {
whileTap={{ scale: 0.95 }}
aria-label="Next banner"
>
-
-
+
+
>
@@ -212,8 +234,18 @@ export default function BannerSlider() {
whileTap={{ scale: 0.95 }}
aria-label="Previous banner"
>
-
-
+
+
@@ -224,22 +256,32 @@ export default function BannerSlider() {
whileTap={{ scale: 0.95 }}
aria-label="Next banner"
>
-
-
+
+
{/* Premium Dots Indicator */}
-
+
{banners.map((_, index) => (
goToSlide(index)}
className={`w-2 h-2 md:w-3 md:h-3 rounded-full transition-all duration-300 ${
index === currentIndex
- ? 'bg-white scale-110 shadow-glow'
- : 'bg-white/50 hover:bg-white/70 hover:scale-110'
+ ? "bg-white scale-110 shadow-glow"
+ : "bg-white/50 hover:bg-white/70 hover:scale-110"
}`}
whileHover={{ scale: 1.2 }}
whileTap={{ scale: 0.9 }}
@@ -260,4 +302,4 @@ export default function BannerSlider() {
);
-}
\ No newline at end of file
+}
diff --git a/src/components/Header.tsx b/src/components/Header.tsx
index cf3ac80..8702853 100644
--- a/src/components/Header.tsx
+++ b/src/components/Header.tsx
@@ -60,7 +60,7 @@ export default function Header() {
<>
{/* Mobile Header - Only visible on mobile */}
-
+
{/* Left: Hamburger Menu */}
(null);
+ const fadeInLeft = {
+ initial: { opacity: 0, x: -30 },
+ animate: { opacity: 1, x: 0 },
+ transition: { duration: 0.8, ease: [0.25, 0.46, 0.45, 0.94] },
+ };
+
+ const fadeInRight = {
+ initial: { opacity: 0, x: 30 },
+ animate: { opacity: 1, x: 0 },
+ transition: { duration: 0.8, ease: [0.25, 0.46, 0.45, 0.94] },
+ };
+ const categories = [
+ "Bars",
+ "Barks",
+ "Pralines",
+ "Spreads",
+ "Dragees",
+ "Gelatos",
+ ];
+ const categoryImages = [
+ "/categories/c1.svg",
+ "/categories/c2.svg",
+ "/categories/c3.svg",
+ "/categories/c4.svg",
+ "/categories/c5.svg",
+ "/categories/c6.svg",
+ ];
+
+ // Memoize category change handler for better performance
+ const handleCategoryChange = useCallback((idx: number) => {
+ setCurrentCategory(idx);
+ }, []);
+
+ // Memoize category buttons to prevent unnecessary re-renders
+ const categoryButtons = useMemo(() => {
+ return categories.map((category, idx) => (
+
+ handleCategoryChange(idx)}
+ onMouseEnter={() => handleCategoryChange(idx)}
+ onTouchStart={() => handleCategoryChange(idx)} // Add this for mobile touch
+ tabIndex={-1}
+ >
+ {/* Show only on mobile */}
+
+
+
+ {/* Category name */}
+ {category}
+
+
+ ));
+ }, [currentCategory, handleCategoryChange]);
+
+ // Memoize the category image component
+ const categoryImageComponent = useMemo(
+ () => (
+
+
+
+ ),
+ [currentCategory]
+ );
+
+ return (
+
+ {/* Product Categories Section */}
+
+
+ {/* Left Column - Categories List */}
+
+
+
+
+ {/* Right Column - Large Category Image (desktop only) */}
+
+ {categoryImageComponent}
+
+
+
+
+ );
+}
diff --git a/src/components/SocialMedia.tsx b/src/components/SocialMedia.tsx
new file mode 100644
index 0000000..eb2fc30
--- /dev/null
+++ b/src/components/SocialMedia.tsx
@@ -0,0 +1,284 @@
+"use client";
+import { useEffect, useRef } from "react";
+import { motion } from "framer-motion";
+import Image from "next/image";
+import Section from "./Section";
+import { useInstagram } from "@/hooks/useInstagram";
+
+export default function SocialMedia() {
+ const { posts, loading, error, isTokenExpired } = useInstagram();
+ const scrollRef = useRef(null);
+ const fadeInUp = {
+ initial: { opacity: 0, y: 30 },
+ animate: { opacity: 1, y: 0 },
+ transition: { duration: 0.8, ease: [0.25, 0.46, 0.45, 0.94] },
+ };
+
+ const fadeInLeft = {
+ initial: { opacity: 0, x: -30 },
+ animate: { opacity: 1, x: 0 },
+ transition: { duration: 0.8, ease: [0.25, 0.46, 0.45, 0.94] },
+ };
+
+ const fadeInRight = {
+ initial: { opacity: 0, x: 30 },
+ animate: { opacity: 1, x: 0 },
+ transition: { duration: 0.8, ease: [0.25, 0.46, 0.45, 0.94] },
+ };
+
+ useEffect(() => {
+ // Only auto-scroll on mobile (<768px)
+ if (window.innerWidth >= 768) return;
+
+ const container = scrollRef.current;
+ if (!container) return;
+
+ let scrollAmount = 0;
+ const cardWidth = container.firstElementChild?.clientWidth || 300;
+ const scrollStep = cardWidth + 16; // 16px gap between items
+ let direction = 1; // 1 = right, -1 = left
+
+ const interval = setInterval(() => {
+ if (!container) return;
+ scrollAmount += scrollStep * direction;
+
+ // Reverse direction if hitting ends
+ if (
+ scrollAmount >= container.scrollWidth - container.clientWidth ||
+ scrollAmount <= 0
+ ) {
+ direction *= -1;
+ }
+
+ container.scrollTo({
+ left: scrollAmount,
+ behavior: "smooth",
+ });
+ }, 3000); // scroll every 3s
+
+ return () => clearInterval(interval);
+ }, []);
+
+ return (
+
+
+
+ Follow us on Instagram
+
+
+
+
+ {loading ? (
+ <>
+ {[1, 2, 3].map((i) => (
+
+ ))}
+ >
+ ) : error ? (
+ isTokenExpired ? (
+
+
+
+ 🔗
+
+
+ Instagram Connection Expired
+
+
+ Our Instagram connection needs to be refreshed. We're
+ working on getting it back up!
+
+
+ In the meantime, follow us @mozimo_chocolate
+
+
+
+ ) : (
+ <>
+ {/* Left Block - Chocolate Spread Jar */}
+
+
+
+
+ 🍫
+
+
+
+ MOZIMO
+
+
+ SINGLE ORIGIN HAZELNUT SPREAD 45%
+
+
+
+
+
+
+ {/* Middle Block - Magazine Article */}
+
+
+
+ 🍫
+
+
+
+
+ By RUPALI DEAN
+
+
+
+ MOZIMO'S CHOCOLATE PIE BY PRIYANKA GUPTA
+
+
+
+ isolat[ing] beans to not only single ori- but also to
+ single farms so as to express unique complexity.
+
+
+
+
+
+ {/* Right Block - World Chocolate Day */}
+
+
+
+
+ World Chocolate Day
+
+
+ Celebrating the art of chocolate making
+
+
+
+
🍫
+
+ Join us in celebrating the world's favorite treat
+
+
+
+
+ >
+ )
+ ) : (
+ posts?.slice(0, 3).map((post, index) => (
+
+
+
+
{
+ const target = e.target as HTMLImageElement;
+ target.src = "/bst/bs1.svg";
+ }}
+ />
+
+ {post.mediaType === "VIDEO" && (
+
+ )}
+
+
+
+ {post.caption?.slice(0, 100)}...
+
+
+
+
+
+
+ ))
+ )}
+
+
+ );
+}