diff --git a/next.config.mjs b/next.config.mjs index 34b7d73..c05102f 100644 --- a/next.config.mjs +++ b/next.config.mjs @@ -1,5 +1,6 @@ /** @type {import('next').NextConfig} */ const nextConfig = { + output: 'export', images: { remotePatterns: [ { @@ -7,7 +8,8 @@ const nextConfig = { hostname: '**.amazonaws.com', }, ], - }, + unoptimized: true, + }, }; export default nextConfig; diff --git a/public/images/diwali/01-banner.jpg b/public/images/diwali/01-banner.jpg new file mode 100644 index 0000000..54b9098 Binary files /dev/null and b/public/images/diwali/01-banner.jpg differ diff --git a/public/images/diwali/02-red-praline-box.jpg b/public/images/diwali/02-red-praline-box.jpg new file mode 100644 index 0000000..22ad30f Binary files /dev/null and b/public/images/diwali/02-red-praline-box.jpg differ diff --git a/public/images/diwali/03-blue-praline-box-open.jpg b/public/images/diwali/03-blue-praline-box-open.jpg new file mode 100644 index 0000000..3cd12e8 Binary files /dev/null and b/public/images/diwali/03-blue-praline-box-open.jpg differ diff --git a/public/images/diwali/04-blue-praline-box-two.jpg b/public/images/diwali/04-blue-praline-box-two.jpg new file mode 100644 index 0000000..63795f4 Binary files /dev/null and b/public/images/diwali/04-blue-praline-box-two.jpg differ diff --git a/public/images/diwali/05-gold-praline-box.jpg b/public/images/diwali/05-gold-praline-box.jpg new file mode 100644 index 0000000..b4f30b4 Binary files /dev/null and b/public/images/diwali/05-gold-praline-box.jpg differ diff --git a/public/images/diwali/06-red-bark-box.jpg b/public/images/diwali/06-red-bark-box.jpg new file mode 100644 index 0000000..00d0ac5 Binary files /dev/null and b/public/images/diwali/06-red-bark-box.jpg differ diff --git a/public/images/diwali/07-blue-spread.jpg b/public/images/diwali/07-blue-spread.jpg new file mode 100644 index 0000000..2486602 Binary files /dev/null and b/public/images/diwali/07-blue-spread.jpg differ diff --git a/src/app/(static)/about-us/page.tsx b/src/app/(static)/about-us/page.tsx index 3433425..c750c9c 100644 --- a/src/app/(static)/about-us/page.tsx +++ b/src/app/(static)/about-us/page.tsx @@ -1,3 +1,5 @@ +'use client'; +import { useRef } from 'react'; import Image from 'next/image'; import pralinePic from '/public/images/about-us/01-praline.jpg'; import prAmPic from '/public/images/about-us/02-priyanka-amritanshu.jpg'; @@ -5,8 +7,40 @@ import dryingPic from '/public/images/about-us/03-drying.jpg'; import chefPic from '/public/images/about-us/04-chef.jpg'; import barkPic from '/public/images/about-us/05-bark.jpg'; import italyPic from '/public/images/about-us/06-italy.jpg'; +import useInView from '@/hooks/useInView'; export default function AboutUsPage() { + const pralinePicRef = useRef(null); + const isPralinePic = useInView(pralinePicRef, { + threshold: 0.1, + triggerOnce: true, + }); + const prAmPicRef = useRef(null); + const isPrAmPic = useInView(prAmPicRef, { + threshold: 0.1, + triggerOnce: true, + }); + const dryingPicRef = useRef(null); + const isDryingPic = useInView(dryingPicRef, { + threshold: 0.1, + triggerOnce: true, + }); + const chefPicRef = useRef(null); + const isChefPic = useInView(chefPicRef, { + threshold: 0.1, + triggerOnce: true, + }); + const barkPicRef = useRef(null); + const isBarkPic = useInView(barkPicRef, { + threshold: 0.1, + triggerOnce: true, + }); + const italyPicRef = useRef(null); + const isItalyPic = useInView(italyPicRef, { + threshold: 0.1, + triggerOnce: true, + }); + return (
@@ -25,9 +59,10 @@ export default function AboutUsPage() {
Praline Left Side Image
Beans Drying
Beans Drying
Beans Drying
Training +
+
+ Praline +
+

+ Sweet Moments with Mozimo +

+
+ “Transforming cacao beans sourced straight from the pod into rich, + velvety smooth chocolate is pure magic. This is why we take great + pride in being called the 'Alchemists of the Chocolate + World'.” +
+
+
+ {/* Left Column - Image */} +
+ Left Side Image +
+ {/* Right Column - Text with Header */} +
+
+

+ Our journey at Mozimo has been a passionate pursuit of creating + exceptional chocolate that tantalizes the taste buds and tells the + unique story of each cocoa bean's origin. We traversed the + globe to search for the finest beans, equipment, and techniques. + We ventured deep into remote cocoa farms to select the best beans + as we cherished the stories and traditions behind every harvest. +

+

+ Beholding our vision, we started the meticulous process of + crafting rich, exquisite, delectable chocolates, ultimately + perfecting the art. As we continue our journey at Mozimo, we are + proud to be a part of the global craft chocolate revolution + celebrating the diversity of cocoa. +

+
+
+
+
+
+
+

+ Aritsan Craftmanship +

+

+ We are an atelier crafting chocolate from the finest single-source + beans. Our commitment to the art of making chocolate ensures that + each piece epitomizes supreme taste & quality. +

+

+ Ethics and Sustainability +

+

+ We are committed to sustainability and being ethical in all that + we do. From selecting ingredients from remote farmers to our + production practices, we prioritize sustainability and ethical + practices. +

+

+ Commitment to Excellence +

+

+ We are inspired to create the best-quality chocolate in our + pursuit of excellence. This involves refining ingredients, + updating processes, and continuously striving to become the best + in the game. +

+
+
+
+ Beans Drying +
+
+ {/* Fourth Three-Column Layout (Collections) */} +
+
+ Specimens of{' '} + + Exquisite Craftsmanship + +
+
+ Every creation of Mozimo's chocolate is a specimen of + craftsmanship of the highest quality by the finest chocolatiers. +
+
+
+
+ Beans Drying +
+
+ Beans Drying +
+
+
+

+ Immerse yourself in the{' '} + + Italian Chocolate Experience + +

+

+ Indulge in the authentic artistry of the Cioccolaterias of Italy with + handcrafted artisanal chocolates by Mozimo. +

+ Training +

+ Experience the art of gifting this Diwali +

+

+ It’s time to celebrate the joy of togetherness, love, and the luxury + of Mozimo’s chocolates. This Diwali, let’s embrace the sweetness of + life with our exquisite single-origin handcrafted chocolates, crafted + to elevate your festive moments. +

+

+ Let our handcrafted chocolates be a part of your Diwali rituals. + Whether you’re enjoying them during family gatherings, using them as a + centerpiece for your celebrations, or gifting them to friends or + colleagues, they are sure to bring warmth and sweetness to every + moment. +

+
+
+ ); +} diff --git a/src/app/(static)/page.tsx b/src/app/(static)/page.tsx index 6d4ce45..69dac9d 100644 --- a/src/app/(static)/page.tsx +++ b/src/app/(static)/page.tsx @@ -1,3 +1,5 @@ +'use client'; +import { useRef } from 'react'; import Image from 'next/image'; import brandStoryPic from '/public/images/homepage/brand-story.jpg'; import { HomepageVideo } from '@/components/homepage-video'; @@ -6,8 +8,16 @@ import { Collections } from '@/components/our-collection'; import { ChocolateCategories } from '@/components/category-slider'; import { InstagramFeed } from '@/components/instagram'; import { Spotlight } from '@/components/spotlight'; +import { AnimatedText } from '@/components/animated-text'; +import useInView from '@/hooks/useInView'; export default function HomePage() { + const brandStoryPicRef = useRef(null); + const isBrandStoryPic = useInView(brandStoryPicRef, { + threshold: 0.1, + triggerOnce: true, + }); + return (
@@ -16,30 +26,38 @@ export default function HomePage() { {/* Left Column - Text with Header */}
-

- Brand Story -

-

- Mozimo's journey is a passionate pursuit of crafting - exceptional chocolate that celebrates the origin of each cocoa - bean. -

-

- We meticulously roast, crack, winnow, and refine beans in-house, - using modern techniques to highlight their natural flavors. -

-

- Each chocolate is a masterpiece, capturing the essence of cocoa in - its purest form. -

+ +

+ Brand Story +

+
+ +

+ Mozimo's journey is a passionate pursuit of crafting + exceptional chocolate that celebrates the origin of each cocoa + bean. +

+

+ We meticulously roast, crack, winnow, and refine beans in-house, + using modern techniques to highlight their natural flavors. +

+

+ Each chocolate is a masterpiece, capturing the essence of cocoa + in its purest form. +

+
{/* Right Column - Image */}
Right Side Image
-

- Discover the delicate art of our -

-

- Chocolate Tempering -

-

- Crafted to perfection Mozimo delivers a sublime sensory experience - with every bite. Experience the epitome of indulgence with our - perfectly tempered chocolate: velvety smooth, exquisitely rich, - and artfully balanced. Each bite offers a symphony of nuanced - cocoa flavors, melting luxuriously! -

+ +

+ Discover the delicate art of our +

+

+ Chocolate Tempering +

+
+ +

+ Crafted to perfection Mozimo delivers a sublime sensory + experience with every bite. Experience the epitome of indulgence + with our perfectly tempered chocolate: velvety smooth, + exquisitely rich, and artfully balanced. Each bite offers a + symphony of nuanced cocoa flavors, melting luxuriously! +

+
@@ -97,6 +122,9 @@ export default function HomePage() { In the Spotlight
+ {/* + Button Text + */}
); diff --git a/src/app/(storefront)/products/[handle]/ProductDetails.tsx b/src/app/(storefront)/products/[handle]/ProductDetails.tsx index 383c2e3..b4e6238 100644 --- a/src/app/(storefront)/products/[handle]/ProductDetails.tsx +++ b/src/app/(storefront)/products/[handle]/ProductDetails.tsx @@ -24,7 +24,7 @@ const ProductDetails: FC = ({ handle }) => { } else { setProduct(product); } - } catch (err) { + } catch (err: unknown) { setError(err); } finally { setIsLoading(false); @@ -39,7 +39,8 @@ const ProductDetails: FC = ({ handle }) => { } if (error) { - return
Something went wrong: {error.message}
; + console.log(error); + return
Something went wrong
; } if (!product) { @@ -52,7 +53,7 @@ const ProductDetails: FC = ({ handle }) => {
{/* Product Images */}
- {product?.images?.length > 0 && ( + {!!product.images?.length && ( {product.title}
void; // onClick is optional +}; + +export function PillButton({ text, onClick }: PillButtonProps) { + return ( + + ); +} diff --git a/src/components/animated-image.tsx b/src/components/animated-image.tsx new file mode 100644 index 0000000..d74cd70 --- /dev/null +++ b/src/components/animated-image.tsx @@ -0,0 +1,38 @@ +// src/components/AnimatedImage.tsx +import React, { ImgHTMLAttributes, useRef } from 'react'; +import useInView from '@/hooks/useInView'; + +interface AnimatedImageProps extends ImgHTMLAttributes { + src: string; + alt: string; + className?: string; + threshold?: number; // New prop +} + +const AnimatedImage: React.FC = ({ + src, + alt, + className = '', + threshold, + ...props +}) => { + const ref = useRef(null); + const isVisible = useInView(ref, { + threshold: threshold ?? 0.1, + triggerOnce: true, + }); + + return ( + {alt} + ); +}; + +export default AnimatedImage; diff --git a/src/components/animated-text.tsx b/src/components/animated-text.tsx new file mode 100644 index 0000000..563b7d1 --- /dev/null +++ b/src/components/animated-text.tsx @@ -0,0 +1,36 @@ +// src/components/AnimatedText.tsx +import { ReactNode, useRef } from 'react'; +import useInView from '@/hooks/useInView'; + +interface AnimatedTextProps { + children: ReactNode; + className?: string; + startClass?: string; + finishClass?: string; + threshold?: number; // New prop +} + +export function AnimatedText({ + children, + className = '', + startClass, + finishClass, + threshold, +}: AnimatedTextProps) { + const ref = useRef(null); + const isVisible = useInView(ref, { + threshold: threshold ?? 0.1, + triggerOnce: true, + }); + + return ( +
+ {children} +
+ ); +} diff --git a/src/hooks/useInView.tsx b/src/hooks/useInView.tsx new file mode 100644 index 0000000..88372c8 --- /dev/null +++ b/src/hooks/useInView.tsx @@ -0,0 +1,63 @@ +import { useState, useEffect, RefObject } from 'react'; + +interface UseInViewOptions { + threshold?: number | number[]; + triggerOnce?: boolean; +} + +const useInView = ( + ref: RefObject, + options: UseInViewOptions = { threshold: 0.1, triggerOnce: true }, +): boolean => { + const { threshold = 0.1, triggerOnce = true } = options; + const [isVisible, setIsVisible] = useState(false); + + // Validate threshold + const isValidThreshold = + typeof threshold === 'number' + ? threshold >= 0 && threshold <= 1 + : Array.isArray(threshold) && threshold.every((t) => t >= 0 && t <= 1); + + if (!isValidThreshold) { + console.warn( + 'Invalid threshold value passed to useInView. It should be between 0 and 1.', + ); + } + + useEffect(() => { + const element = ref.current; + if (!element) return; + + const prefersReducedMotion = window.matchMedia( + '(prefers-reduced-motion: reduce)', + ); + if (prefersReducedMotion.matches) { + setIsVisible(true); + return; + } + + const observer = new IntersectionObserver( + (entries) => { + entries.forEach((entry) => { + if (entry.isIntersecting) { + setIsVisible(true); + if (triggerOnce) { + observer.unobserve(entry.target); + } + } + }); + }, + { threshold }, + ); + + observer.observe(element); + + return () => { + if (element) observer.unobserve(element); + }; + }, [ref, threshold, triggerOnce]); + + return isVisible; +}; + +export default useInView;