Merge pull request #3 from ABasral/fix/minor-changes

minor changes
This commit is contained in:
Ayush
2025-08-20 13:41:25 +05:30
committed by GitHub
5 changed files with 234 additions and 149 deletions

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 24 KiB

After

Width:  |  Height:  |  Size: 22 KiB

View File

@ -281,13 +281,13 @@ export default function Home() {
<motion.h3 <motion.h3
className="text-4xl md:text-5xl lg:text-7xl font-bold text-[#8B4513] font-samantha" className="text-4xl md:text-5xl lg:text-7xl font-bold text-[#8B4513] font-samantha"
style={{ style={{
fontWeight: 300, fontWeight: 400,
fontSize: "clamp(36px, 6vw, 60px)", fontSize: "clamp(36px, 6vw, 60px)",
lineHeight: "120%", lineHeight: "120%",
letterSpacing: "0%", letterSpacing: "0%",
fontStyle: "italic", fontStyle: "italic",
color: "#703133", color: "#703133",
fontFamily: "Renner*", fontFamily: "Samantha Signature",
}} }}
whileHover={{ scale: 1.02 }} whileHover={{ scale: 1.02 }}
transition={{ duration: 0.3 }} transition={{ duration: 0.3 }}

View File

@ -161,7 +161,6 @@ export default function BannerSlider() {
}} }}
> >
<span className="relative z-10">Shop Now</span> <span className="relative z-10">Shop Now</span>
<div className="absolute inset-0 bg-gradient-to-r from-transparent via-white/20 to-transparent -translate-x-full hover:translate-x-full transition-transform duration-700 ease-out rounded-full" />
</motion.button> </motion.button>
</div> </div>
)} )}

View File

@ -119,9 +119,10 @@ export default function Header() {
transition={{ duration: 0.6 }} transition={{ duration: 0.6 }}
> >
<motion.div <motion.div
className="relative w-10 h-10" className="relative"
animate={{ animate={{
scale: isScrolled ? 1.1 : 1, width: isScrolled ? 40 : 60, // shrink on scroll
height: isScrolled ? 40 : 60,
}} }}
transition={{ duration: 0.5, ease: "easeInOut" }} transition={{ duration: 0.5, ease: "easeInOut" }}
whileHover={{ whileHover={{
@ -136,7 +137,7 @@ export default function Header() {
fill fill
className="object-contain drop-shadow-lg" className="object-contain drop-shadow-lg"
priority priority
sizes="60px" sizes="(max-width: 768px) 40px, 96px"
quality={95} quality={95}
placeholder="blur" placeholder="blur"
blurDataURL="data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAYEBQYFBAYGBQYHBwYIChAKCgkJChQODwwQFxQYGBcUFhYaHSUfGhsjHBYWICwgIyYnKSopGR8tMC0oMCUoKSj/2wBDAQcHBwoIChMKChMoGhYaKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCj/wAARCAAIAAoDASIAAhEBAxEB/8QAFQABAQAAAAAAAAAAAAAAAAAAAAv/xAAhEAACAQMDBQAAAAAAAAAAAAABAgMABAUGIWGRkqGx0f/EABUBAQEAAAAAAAAAAAAAAAAAAAMF/8QAGhEAAgIDAAAAAAAAAAAAAAAAAAECEgMRkf/aAAwDAQACEQMRAD8AltJagyeH0AthI5xdrLcNM91BF5pX2HaH9bcfaSXWGaRmknyJckliyjqTzSlT54b6bk+h0R//2Q==" blurDataURL="data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAYEBQYFBAYGBQYHBwYIChAKCgkJChQODwwQFxQYGBcUFhYaHSUfGhsjHBYWICwgIyYnKSopGR8tMC0oMCUoKSj/2wBDAQcHBwoIChMKChMoGhYaKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCj/wAARCAAIAAoDASIAAhEBAxEB/8QAFQABAQAAAAAAAAAAAAAAAAAAAAv/xAAhEAACAQMDBQAAAAAAAAAAAAABAgMABAUGIWGRkqGx0f/EABUBAQEAAAAAAAAAAAAAAAAAAAMF/8QAGhEAAgIDAAAAAAAAAAAAAAAAAAECEgMRkf/aAAwDAQACEQMRAD8AltJagyeH0AthI5xdrLcNM91BF5pX2HaH9bcfaSXWGaRmknyJckliyjqTzSlT54b6bk+h0R//2Q=="
@ -272,35 +273,28 @@ export default function Header() {
{/* Center Logo */} {/* Center Logo */}
<motion.div <motion.div
className="flex items-center justify-center absolute left-1/2 transform -translate-x-1/2" className="relative"
initial={{ opacity: 0, y: -20 }} animate={{
animate={{ opacity: 1, y: 0 }} width: isScrolled ? 75 : 96, // shrink logo when scrolled
transition={{ duration: 0.6 }} height: isScrolled ? 75 : 96,
scale: isScrolled ? 1 : 1, // optional subtle scaling
}}
transition={{ duration: 0.5, ease: "easeInOut" }}
whileHover={{
scale: 1.15,
rotate: 5,
transition: { duration: 0.3 },
}}
> >
<motion.div <Image
className="relative w-12 h-12" src="/logo/logo.svg"
animate={{ alt="Mozimo Logo"
scale: isScrolled ? 1.1 : 1, fill
}} className="object-contain drop-shadow-lg"
transition={{ duration: 0.5, ease: "easeInOut" }} priority
whileHover={{ sizes="(max-width: 768px) 40px, 96px"
scale: 1.15, quality={95}
rotate: 5, />
transition: { duration: 0.3 },
}}
>
<Image
src="/logo/logo.svg"
alt="Mozimo Logo"
fill
className="object-contain drop-shadow-lg"
priority
sizes="48px"
quality={95}
placeholder="blur"
blurDataURL="data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAYEBQYFBAYGBQYHBwYIChAKCgkJChQODwwQFxQYGBcUFhYaHSUfGhsjHBYWICwgIyYnKSopGR8tMC0oMCUoKSj/2wBDAQcHBwoIChMKChMoGhYaKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCj/wAARCAAIAAoDASIAAhEBAxEB/8QAFQABAQAAAAAAAAAAAAAAAAAAAAv/xAAhEAACAQMDBQAAAAAAAAAAAAABAgMABAUGIWGRkqGx0f/EABUBAQEAAAAAAAAAAAAAAAAAAAMF/8QAGhEAAgIDAAAAAAAAAAAAAAAAAAECEgMRkf/aAAwDAQACEQMRAD8AltJagyeH0AthI5xdrLcNM91BF5pX2HaH9bcfaSXWGaRmknyJckliyjqTzSlT54b6bk+h0R//2Q=="
/>
</motion.div>
</motion.div> </motion.div>
{/* Right Icons */} {/* Right Icons */}

View File

@ -1,6 +1,5 @@
"use client"; "use client";
import { useState, useRef, useCallback, useMemo } from "react"; import { useState, useRef, useCallback, useMemo, useEffect } from "react";
import { AnimatePresence } from "framer-motion";
import { motion } from "framer-motion"; import { motion } from "framer-motion";
import Section from "@/components/Section"; import Section from "@/components/Section";
import Image from "next/image"; import Image from "next/image";
@ -8,17 +7,8 @@ import Image from "next/image";
export default function ProductCategory() { export default function ProductCategory() {
const [currentCategory, setCurrentCategory] = useState(0); const [currentCategory, setCurrentCategory] = useState(0);
const categoriesSectionRef = useRef<HTMLDivElement>(null); const categoriesSectionRef = useRef<HTMLDivElement>(null);
const fadeInLeft = { const imageCache = useRef<{ [key: string]: HTMLImageElement }>({});
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 = [ const categories = [
"Bars", "Bars",
"Barks", "Barks",
@ -36,117 +26,176 @@ export default function ProductCategory() {
"/categories/c6.svg", "/categories/c6.svg",
]; ];
// Memoize category change handler for better performance // Preload all images on component mount
useEffect(() => {
const preloadImages = async () => {
const loadPromises = categoryImages.map((src) => {
return new Promise<void>((resolve) => {
if (imageCache.current[src]) {
resolve();
return;
}
const img = new window.Image();
img.onload = () => {
imageCache.current[src] = img;
resolve();
};
img.onerror = () => resolve(); // Continue even if one fails
img.src = src;
});
});
await Promise.all(loadPromises);
};
preloadImages();
}, []);
// Ultra-fast animation variants (no delays)
const fadeInLeft = {
initial: { opacity: 0, x: -20 },
animate: { opacity: 1, x: 0 },
transition: { duration: 0.3, ease: [0.23, 1, 0.32, 1] },
};
const fadeInRight = {
initial: { opacity: 0, x: 20 },
animate: { opacity: 1, x: 0 },
transition: { duration: 0.3, ease: [0.23, 1, 0.32, 1] },
};
// Instant category change with no debouncing
const handleCategoryChange = useCallback((idx: number) => { const handleCategoryChange = useCallback((idx: number) => {
setCurrentCategory(idx); setCurrentCategory(idx);
}, []); }, []);
// Memoize category buttons to prevent unnecessary re-renders // Optimized category buttons
const categoryButtons = useMemo(() => { const categoryButtons = useMemo(() => {
return categories.map((category, idx) => ( return categories.map((category, idx) => {
<motion.li const isActive = idx === currentCategory;
key={category}
initial={{ opacity: 0, x: -20 }} return (
whileInView={{ opacity: 1, x: 0 }} <motion.li
transition={{ duration: 0.4, delay: idx * 0.05 }} // Reduced delay key={category}
viewport={{ once: true }} initial={{ opacity: 0, y: 10 }}
> whileInView={{ opacity: 1, y: 0 }}
<button transition={{ duration: 0.2, delay: idx * 0.02 }}
className={`group flex items-center gap-4 transition-all duration-200 ease-out w-full text-left font-moneta hover:scale-105 viewport={{ once: true }}
${ >
idx === currentCategory <button
? "text-[#703133] font-normal" className={`group flex items-center gap-4 w-full text-left font-moneta transition-all duration-100 ease-out will-change-transform
: "text-[#703133] opacity-60 font-light" ${
} isActive
`} ? "text-[#703133] font-normal"
style={{ : "text-[#703133] opacity-70 font-light hover:opacity-90"
fontFamily: "MonetaSans-Regular", }
fontWeight: idx === currentCategory ? 400 : 300, `}
fontSize: style={{
idx === currentCategory fontFamily: "MonetaSans-Regular",
fontWeight: isActive ? 400 : 300,
fontSize: isActive
? "clamp(22px, 5vw, 64px)" ? "clamp(22px, 5vw, 64px)"
: "clamp(18px, 4vw, 56px)", : "clamp(18px, 4vw, 56px)",
lineHeight: "120%", lineHeight: "120%",
letterSpacing: "0%", letterSpacing: "0%",
transition: "all 0.2s cubic-bezier(0.4, 0.0, 0.2, 1)", // Even faster transition transform: isActive ? "translateX(4px)" : "translateX(0)",
}} }}
onClick={() => handleCategoryChange(idx)} onClick={() => handleCategoryChange(idx)}
onMouseEnter={() => handleCategoryChange(idx)} onMouseEnter={() => handleCategoryChange(idx)}
onTouchStart={() => handleCategoryChange(idx)} // Add this for mobile touch onTouchStart={() => handleCategoryChange(idx)}
tabIndex={-1} >
> {/* Mobile optimized thumbnail */}
{/* Show only on mobile */} <div className="block lg:hidden w-16 h-16 rounded-full overflow-hidden shrink-0 will-change-transform">
<div className="block lg:hidden w-16 h-16 rounded-full overflow-hidden shrink-0"> <Image
<Image src={categoryImages[idx]}
src={categoryImages[idx]} alt={category}
alt={category} width={64}
width={56} height={64}
height={56} className={`w-full h-full object-cover transition-transform duration-100 ${
className="w-full h-full object-cover" isActive ? "scale-110" : "scale-100"
draggable={false} }`}
quality={85} draggable={false}
sizes="(max-width: 375px) 40px, (max-width: 640px) 44px, (max-width: 768px) 48px, 56px" quality={60}
/> priority={idx < 2}
</div> loading={idx < 2 ? "eager" : "lazy"}
{/* Category name */} />
<span className="text-left">{category}</span> </div>
</button> <span className="will-change-transform">{category}</span>
</motion.li> </button>
)); </motion.li>
);
});
}, [currentCategory, handleCategoryChange]); }, [currentCategory, handleCategoryChange]);
// Memoize the category image component // Ultra-optimized image switcher with instant transitions
const categoryImageComponent = useMemo( const categoryImageComponent = useMemo(
() => ( () => (
<AnimatePresence mode="wait"> <div className="relative w-full h-full overflow-hidden rounded-2xl">
<motion.img {/* Render all images but show only active one */}
key={currentCategory} {categoryImages.map((src, idx) => (
src={categoryImages[currentCategory]} <motion.div
alt={categories[currentCategory]} key={idx}
initial={{ opacity: 0, scale: 1.01 }} initial={false}
animate={{ opacity: 1, scale: 1 }} animate={{
exit={{ opacity: 0, scale: 0.99 }} opacity: idx === currentCategory ? 1 : 0,
transition={{ duration: 0.25, ease: [0.4, 0.0, 0.2, 1] }} // Super fast transition scale: idx === currentCategory ? 1 : 0.95,
className="w-full h-full object-cover rounded-2xl shadow-premium hover:shadow-premium-hover transition-all duration-200 img-premium" // Faster shadow }}
draggable={false} transition={{
style={{ maxHeight: "600px", maxWidth: "100%" }} duration: 0.15,
/> ease: [0.23, 1, 0.32, 1],
</AnimatePresence> }}
className="absolute inset-0 will-change-transform"
style={{
zIndex: idx === currentCategory ? 2 : 1,
}}
>
<Image
src={src}
alt={categories[idx]}
fill
className="object-cover"
draggable={false}
quality={85}
priority={idx < 3}
loading={idx < 3 ? "eager" : "lazy"}
sizes="(max-width: 768px) 100vw, 50vw"
/>
</motion.div>
))}
</div>
), ),
[currentCategory] [currentCategory]
); );
return ( return (
<div className="min-h-screen bg-white font-renner"> <Section background="white" id="categories">
{/* Product Categories Section */} <div
<Section background="white" id="categories"> ref={categoriesSectionRef}
<div className="grid grid-cols-1 lg:grid-cols-2 gap-0 items-stretch min-h-[400px] md:min-h-[500px]"
ref={categoriesSectionRef} >
className="grid grid-cols-1 lg:grid-cols-2 gap-0 items-stretch min-h-[400px] md:min-h-[500px]" {/* Left Column - Categories List */}
<motion.div
initial="initial"
whileInView="animate"
viewport={{ once: true, margin: "-100px" }}
variants={fadeInLeft}
className="flex flex-col justify-center h-full bg-white px-4 md:px-8 py-6 md:py-12 order-2 lg:order-1"
> >
{/* Left Column - Categories List */} <ul className="space-y-4 md:space-y-6">{categoryButtons}</ul>
<motion.div </motion.div>
initial="initial"
whileInView="animate"
viewport={{ once: true, margin: "-50px" }}
variants={fadeInLeft}
className="flex flex-col justify-center h-full bg-white px-4 md:px-8 py-6 md:py-12 order-2 lg:order-1"
>
<ul className="space-y-4 md:space-y-6">{categoryButtons}</ul>
</motion.div>
{/* Right Column - Large Category Image (desktop only) */} {/* Right Column - Large Category Image */}
<motion.div <motion.div
initial="initial" initial="initial"
whileInView="animate" whileInView="animate"
viewport={{ once: true, margin: "-50px" }} viewport={{ once: true, margin: "-100px" }}
variants={fadeInRight} variants={fadeInRight}
className="relative hidden lg:flex items-center justify-center h-full min-h-[300px] md:min-h-[400px] bg-white order-1 lg:order-2" className="relative hidden lg:flex items-center justify-center h-full min-h-[300px] md:min-h-[400px] bg-white order-1 lg:order-2 p-4"
> >
{categoryImageComponent} {categoryImageComponent}
</motion.div> </motion.div>
</div> </div>
</Section> </Section>
</div>
); );
} }