Compare commits
124 Commits
version_10
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| 8186ca87bd | |||
| f09797c81f | |||
| df897af0cb | |||
| 6645a29157 | |||
| a1db576e69 | |||
| 0c3889534c | |||
| 16ff4ba558 | |||
| c4cf684ec2 | |||
| 6a3320444a | |||
| c7759c2bb5 | |||
| e329f755a6 | |||
| de15dcefc2 | |||
| 9c6bdd8c45 | |||
| 644f78d536 | |||
| bca2c66751 | |||
| d4f2914ac8 | |||
| 15c55dc458 | |||
| 1c171ed1b1 | |||
| dc7adc5c98 | |||
| c147799589 | |||
| 76d9e12897 | |||
| feb138eedc | |||
| 28241e5df1 | |||
| a1937549ed | |||
| fdf4547d57 | |||
| 8b30b26c01 | |||
| 5b1f2eae47 | |||
| e390ee971e | |||
| eb04b57a29 | |||
| df02d9f8c7 | |||
| bb6f9c0657 | |||
| 15f3759b8d | |||
| 1120992fc1 | |||
| d8fc391dd1 | |||
| 33222485f9 | |||
| 175337d9fe | |||
| db72fecd40 | |||
| 8039db447b | |||
| ae0bdfce63 | |||
| db6c589753 | |||
| f413388ce2 | |||
| a5e06e87b9 | |||
| c9abf24b7b | |||
| f3be5a11fe | |||
| 7068ae76b5 | |||
| e2506c3a66 | |||
| b260ab6f15 | |||
| a5c834f9fc | |||
| 1aa9788a4a | |||
| 150f2b254c | |||
| 3aa7e33948 | |||
| 340716fe3e | |||
| 537601ee19 | |||
| 9c23776465 | |||
| d68a1badc9 | |||
| 5854c172f5 | |||
| 19f25d0b8f | |||
| 65db121ec6 | |||
| 290ecbdf18 | |||
| cf284f4bc6 | |||
| e812a41272 | |||
| 6ec05e6497 | |||
| 0847c98641 | |||
| 574e17251e | |||
| 82edf03cf2 | |||
| 7569facec5 | |||
| daab93c9f3 | |||
| a2228ca537 | |||
| 68094e5592 | |||
| 6dd47629e6 | |||
| ab485b0d30 | |||
| 651cc9427b | |||
| 7f18332905 | |||
| b0360b5784 | |||
| b6a8015b5a | |||
| c74227ca00 | |||
| 34667b3e39 | |||
| 3f4359dd46 | |||
| 30c0b01057 | |||
| 0b84fe33a3 | |||
| 970fa3fbea | |||
| 9807ee790c | |||
| b5994e8235 | |||
| e3f129208b | |||
| 1560f38543 | |||
| b835383e2a | |||
| c6ecfb010e | |||
| 64f3c3869b | |||
| 846aa84155 | |||
| 81a68f5e71 | |||
| ef67dd7d0c | |||
| 0de13d4ccc | |||
| fcc0441f5a | |||
| 452b4d00c9 | |||
| 53b6683972 | |||
| e94914d0ba | |||
| 5796afa7d7 | |||
| c91a752f88 | |||
| c295bceaa4 | |||
| e56e865f1a | |||
| a16cb96315 | |||
| 08852338d6 | |||
| e396880075 | |||
| 7a662c5872 | |||
| dd69bdcbb8 | |||
| 35c9cd39b9 | |||
| 3eec907d94 | |||
| ac8cb3c24e | |||
| 8af2e7629e | |||
| abcce974ad | |||
| 0636e0dc0c | |||
| da50567492 | |||
| 2db5bc271e | |||
| 30e0b609f0 | |||
| fe82627870 | |||
| 0625be4861 | |||
| 80a742ed82 | |||
| 1fcebf8494 | |||
| a0ed68e3ad | |||
| 776702551e | |||
| 46a552fc6b | |||
| a0eab5e329 | |||
| 83b6ce08af | |||
| 28267be8d7 |
@@ -3,7 +3,6 @@ import { Halant } from "next/font/google";
|
|||||||
import { Inter } from "next/font/google";
|
import { Inter } from "next/font/google";
|
||||||
import "./globals.css";
|
import "./globals.css";
|
||||||
import { ServiceWrapper } from "@/components/ServiceWrapper";
|
import { ServiceWrapper } from "@/components/ServiceWrapper";
|
||||||
import Tag from "@/tag/Tag";
|
|
||||||
import { getVisualEditScript } from "@/utils/visual-edit-script";
|
import { getVisualEditScript } from "@/utils/visual-edit-script";
|
||||||
import { Lato } from "next/font/google";
|
import { Lato } from "next/font/google";
|
||||||
|
|
||||||
@@ -28,7 +27,7 @@ export default function RootLayout({
|
|||||||
<html lang="en" suppressHydrationWarning>
|
<html lang="en" suppressHydrationWarning>
|
||||||
<ServiceWrapper>
|
<ServiceWrapper>
|
||||||
<body className={`${lato.variable} antialiased`}>
|
<body className={`${lato.variable} antialiased`}>
|
||||||
<Tag />
|
|
||||||
{children}
|
{children}
|
||||||
<script
|
<script
|
||||||
dangerouslySetInnerHTML={{
|
dangerouslySetInnerHTML={{
|
||||||
|
|||||||
431
src/app/page.tsx
431
src/app/page.tsx
@@ -1,346 +1,157 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import { ThemeProvider } from "@/providers/themeProvider/ThemeProvider";
|
import { ThemeProvider } from "@/providers/themeProvider/ThemeProvider";
|
||||||
import NavbarStyleCentered from "@/components/navbar/NavbarStyleCentered/NavbarStyleCentered";
|
|
||||||
import HeroSplitDoubleCarousel from "@/components/sections/hero/HeroSplitDoubleCarousel";
|
import HeroSplitDoubleCarousel from "@/components/sections/hero/HeroSplitDoubleCarousel";
|
||||||
import FeatureCardSixteen from "@/components/sections/feature/FeatureCardSixteen";
|
import FeatureCardSixteen from "@/components/sections/feature/FeatureCardSixteen";
|
||||||
import TestimonialCardSixteen from "@/components/sections/testimonial/TestimonialCardSixteen";
|
|
||||||
import ProductCardFour from "@/components/sections/product/ProductCardFour";
|
import ProductCardFour from "@/components/sections/product/ProductCardFour";
|
||||||
import ContactCTA from "@/components/sections/contact/ContactCTA";
|
import ContactCTA from "@/components/sections/contact/ContactCTA";
|
||||||
import FooterSimple from "@/components/sections/footer/FooterSimple";
|
import FooterSimple from "@/components/sections/footer/FooterSimple";
|
||||||
import TestimonialAboutCard from "@/components/sections/about/TestimonialAboutCard";
|
import TestimonialAboutCard from "@/components/sections/about/TestimonialAboutCard";
|
||||||
import BlogCardThree from "@/components/sections/blog/BlogCardThree";
|
import BlogCardThree from "@/components/sections/blog/BlogCardThree";
|
||||||
import { Star, Heart, Users, Camera, Sparkles, Crown, Phone, MessageCircle, User, Play } from "lucide-react";
|
import { Star, Heart, Camera, Sparkles, Crown, Phone, User, Play, ChevronRight, X, Instagram, MapPin } from "lucide-react";
|
||||||
|
import { useState, useEffect, useRef } from "react";
|
||||||
|
|
||||||
export default function LandingPage() {
|
export default function LandingPage() {
|
||||||
|
const [showModal, setShowModal] = useState(false);
|
||||||
|
const [showGalleryViewMore, setShowGalleryViewMore] = useState(false);
|
||||||
|
const [showShoesViewMore, setShowShoesViewMore] = useState(false);
|
||||||
|
const [showVeilsViewMore, setShowVeilsViewMore] = useState(false);
|
||||||
|
const [modalType, setModalType] = useState<'gallery' | 'shoes' | 'veils' | null>(null);
|
||||||
|
const galleryRef = useRef<HTMLDivElement>(null);
|
||||||
|
const shoesRef = useRef<HTMLDivElement>(null);
|
||||||
|
const veilsRef = useRef<HTMLDivElement>(null);
|
||||||
|
const galleryContainerRef = useRef<HTMLDivElement>(null);
|
||||||
|
const shoesContainerRef = useRef<HTMLDivElement>(null);
|
||||||
|
const veilsContainerRef = useRef<HTMLDivElement>(null);
|
||||||
|
const galleryButtonContainerRef = useRef<HTMLDivElement>(null);
|
||||||
|
const shoesButtonContainerRef = useRef<HTMLDivElement>(null);
|
||||||
|
const veilsButtonContainerRef = useRef<HTMLDivElement>(null);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
let ticking = false;
|
||||||
|
const handleScroll = () => {
|
||||||
|
if (!ticking && !showModal) {
|
||||||
|
window.requestAnimationFrame(() => {
|
||||||
|
if (galleryButtonContainerRef.current) {
|
||||||
|
const rect = galleryButtonContainerRef.current.getBoundingClientRect();
|
||||||
|
setShowGalleryViewMore(rect.top < window.innerHeight && rect.bottom > 0);
|
||||||
|
}
|
||||||
|
if (shoesButtonContainerRef.current) {
|
||||||
|
const rect = shoesButtonContainerRef.current.getBoundingClientRect();
|
||||||
|
setShowShoesViewMore(rect.top < window.innerHeight && rect.bottom > 0);
|
||||||
|
}
|
||||||
|
if (veilsButtonContainerRef.current) {
|
||||||
|
const rect = veilsButtonContainerRef.current.getBoundingClientRect();
|
||||||
|
setShowVeilsViewMore(rect.top < window.innerHeight && rect.bottom > 0);
|
||||||
|
}
|
||||||
|
ticking = false;
|
||||||
|
});
|
||||||
|
ticking = true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
window.addEventListener('scroll', handleScroll);
|
||||||
|
return () => window.removeEventListener('scroll', handleScroll);
|
||||||
|
}, [showModal]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
document.body.style.overflow = showModal ? 'hidden' : 'unset';
|
||||||
|
return () => { document.body.style.overflow = 'unset'; };
|
||||||
|
}, [showModal]);
|
||||||
|
|
||||||
|
const allDresses = [{ id: "dress-1", name: "Classic Elegance", price: "Starting at $1,200", variant: "White", imageSrc: "https://webuild-dev.s3.eu-north-1.amazonaws.com/users/user_3B5MJh3BJx339lVFA4KYjFzlzMX/uploaded-1773897612811-03t85tl3.jpg?_wi=1", imageAlt: "Elegant white wedding dress" }, { id: "dress-2", name: "Blush Romance", price: "Starting at $1,400", variant: "Blush Pink", imageSrc: "https://webuild-dev.s3.eu-north-1.amazonaws.com/users/user_3B5MJh3BJx339lVFA4KYjFzlzMX/uploaded-1773897625910-hax1y5k9.jpg?_wi=1", imageAlt: "Beautiful blush pink wedding gown" }, { id: "dress-3", name: "Modern Sophistication", price: "Starting at $1,300", variant: "Off-White", imageSrc: "https://webuild-dev.s3.eu-north-1.amazonaws.com/users/user_3B5MJh3BJx339lVFA4KYjFzlzMX/uploaded-1773898154508-5owc9z0t.jpg?_wi=1", imageAlt: "Modern off-shoulder wedding dress" }, { id: "dress-4", name: "Intricate Lace", price: "Starting at $1,500", variant: "White", imageSrc: "https://webuild-dev.s3.eu-north-1.amazonaws.com/users/user_3B5MJh3BJx339lVFA4KYjFzlzMX/uploaded-1773898173007-a5wime2i.jpg?_wi=1", imageAlt: "Detailed lace wedding dress" }, { id: "dress-5", name: "Minimalist Chic", price: "Starting at $1,100", variant: "White", imageSrc: "https://webuild-dev.s3.eu-north-1.amazonaws.com/users/user_3B5MJh3BJx339lVFA4KYjFzlzMX/uploaded-1773898188020-nldykyrf.jpg?_wi=1", imageAlt: "Sleek minimalist wedding dress" }, { id: "dress-6", name: "Royal Drama", price: "Starting at $1,600", variant: "White", imageSrc: "https://webuild-dev.s3.eu-north-1.amazonaws.com/users/user_3B5MJh3BJx339lVFA4KYjFzlzMX/uploaded-1773898205862-ka8mspzk.jpg?_wi=1", imageAlt: "Dramatic train wedding dress" }];
|
||||||
|
const allShoes = [{ id: "shoe-1", name: "Classic Satin Heels", price: "Starting at $250", variant: "White", imageSrc: "http://img.b2bpic.net/free-photo/elegant-beautiful-fashionable-woman-blonde-long-white-dre_7502-4897.jpg?_wi=2", imageAlt: "Classic white satin bridal heels" }, { id: "shoe-2", name: "Jeweled Flats", price: "Starting at $280", variant: "Ivory", imageSrc: "http://img.b2bpic.net/free-photo/beautiful-bridal-dress-hanger_23-2149640924.jpg?_wi=2", imageAlt: "Comfortable jeweled flat bridal shoes" }, { id: "shoe-3", name: "Pearl Embellished Pumps", price: "Starting at $320", variant: "Champagne", imageSrc: "http://img.b2bpic.net/free-photo/morning-bride-when-she-wears-beautiful-dress_1328-2238.jpg?_wi=2", imageAlt: "Pearl decorated champagne bridal pumps" }];
|
||||||
|
const allVeils = [{ id: "veil-1", name: "Cathedral Length Veil", price: "Starting at $180", variant: "White Tulle", imageSrc: "http://img.b2bpic.net/free-photo/woman-looking-herself_1157-187.jpg?_wi=2", imageAlt: "Elegant cathedral length bridal veil" }, { id: "veil-2", name: "Lace Embellished Veil", price: "Starting at $220", variant: "Ivory Lace", imageSrc: "http://img.b2bpic.net/free-photo/woman-checking-two-shirts_23-2147601332.jpg?_wi=2", imageAlt: "Beautiful lace embellished bridal veil" }, { id: "veil-3", name: "Dramatic Detachable Veil", price: "Starting at $250", variant: "Ivory", imageSrc: "http://img.b2bpic.net/free-photo/beautiful-bride-posing-medium-shot_23-2149860841.jpg?_wi=1", imageAlt: "Dramatic detachable bridal veil" }];
|
||||||
|
const allReels = [{ id: "r1", category: "Behind the Scenes", title: "Our Studio Tour", excerpt: "Take a peek behind the curtain at Irentall.", imageSrc: "https://webuild-dev.s3.eu-north-1.amazonaws.com/users/user_3B5MJh3BJx339lVFA4KYjFzlzMX/uploaded-1773898154508-5owc9z0t.jpg?_wi=1", authorName: "Iren Ulikhanova", authorAvatar: "https://webuild-dev.s3.eu-north-1.amazonaws.com/users/user_3B5MJh3BJx339lVFA4KYjFzlzMX/uploaded-1773894327718-8nx4sc9p.jpg", date: "2024-05-20" }, { id: "r2", category: "BTS", title: "Fitting Process", excerpt: "See how we tailor every gown to perfection.", imageSrc: "https://webuild-dev.s3.eu-north-1.amazonaws.com/users/user_3B5MJh3BJx339lVFA4KYjFzlzMX/uploaded-1773897612811-03t85tl3.jpg?_wi=1", authorName: "Iren Ulikhanova", authorAvatar: "https://webuild-dev.s3.eu-north-1.amazonaws.com/users/user_3B5MJh3BJx339lVFA4KYjFzlzMX/uploaded-1773894327718-8nx4sc9p.jpg", date: "2024-05-18" }];
|
||||||
|
|
||||||
|
const renderModal = () => {
|
||||||
|
if (!showModal || !modalType) return null;
|
||||||
|
const items = modalType === 'gallery' ? allDresses : modalType === 'shoes' ? allShoes : allVeils;
|
||||||
|
return (
|
||||||
|
<div className="fixed inset-0 z-[9999] flex items-center justify-center bg-black/60 backdrop-blur-sm p-4">
|
||||||
|
<div className="relative w-full max-w-6xl max-h-[90vh] bg-[var(--background)] rounded-2xl shadow-2xl overflow-hidden flex flex-col">
|
||||||
|
<div className="flex items-center justify-between p-6 border-b border-[var(--accent)]/20">
|
||||||
|
<h2 className="text-2xl font-semibold text-[var(--foreground)]">Collection</h2>
|
||||||
|
<button onClick={() => setShowModal(false)} className="p-2 hover:bg-[var(--accent)]/10 rounded-lg"><X className="w-6 h-6" /></button>
|
||||||
|
</div>
|
||||||
|
<div className="overflow-y-auto flex-1 p-6">
|
||||||
|
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-6">
|
||||||
|
{items.map((item) => (
|
||||||
|
<div key={item.id} className="group relative overflow-hidden rounded-lg bg-[var(--card)] shadow-md">
|
||||||
|
<img src={item.imageSrc} alt={item.imageAlt} className="w-full h-64 object-cover" />
|
||||||
|
<div className="p-4">
|
||||||
|
<h3 className="font-semibold text-[var(--foreground)]">{item.name}</h3>
|
||||||
|
<p className="text-sm text-[var(--foreground)]/70">{item.variant}</p>
|
||||||
|
<p className="font-bold text-[var(--primary-cta)] mt-2">{item.price}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ThemeProvider
|
<ThemeProvider defaultButtonVariant="shift-hover" defaultTextAnimation="background-highlight" borderRadius="rounded" contentWidth="small" sizing="medium" background="grid" cardStyle="inset" primaryButtonStyle="radial-glow" secondaryButtonStyle="glass" headingFontWeight="light">
|
||||||
defaultButtonVariant="shift-hover"
|
<div className="fixed top-0 left-0 right-0 z-50 bg-[#D4AF37] text-black py-3 px-4 flex items-center justify-center gap-6">
|
||||||
defaultTextAnimation="background-highlight"
|
<a href="https://instagram.com/irentall.usa" target="_blank" rel="noopener noreferrer"><Instagram className="w-6 h-6" /></a>
|
||||||
borderRadius="rounded"
|
<a href="tel:747-800-7770"><Phone className="w-6 h-6" /></a>
|
||||||
contentWidth="small"
|
<a href="https://www.google.com/maps/search/Irentall" target="_blank" rel="noopener noreferrer"><MapPin className="w-6 h-6" /></a>
|
||||||
sizing="medium"
|
|
||||||
background="grid"
|
|
||||||
cardStyle="inset"
|
|
||||||
primaryButtonStyle="radial-glow"
|
|
||||||
secondaryButtonStyle="glass"
|
|
||||||
headingFontWeight="light"
|
|
||||||
>
|
|
||||||
<div id="nav" data-section="nav">
|
|
||||||
<NavbarStyleCentered
|
|
||||||
brandName="Irentall"
|
|
||||||
navItems={[
|
|
||||||
{ name: "Home", id: "home" },
|
|
||||||
{ name: "About", id: "about" },
|
|
||||||
{ name: "Gallery", id: "gallery" },
|
|
||||||
{ name: "Contact", id: "contact" }
|
|
||||||
]}
|
|
||||||
button={{
|
|
||||||
text: "Call Now", href: "tel:747-800-7770"
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="hero" data-section="hero">
|
<div id="hero" data-section="hero" className="relative z-10 mt-16">
|
||||||
<HeroSplitDoubleCarousel
|
<HeroSplitDoubleCarousel title="Find Your Perfect Wedding Dress in Los Angeles" description="Personalized bridal styling with a curated collection of stunning gowns. Our expert team will guide you through every moment of your journey to find the dress of your dreams." background={{ variant: "plain" }} leftCarouselItems={allDresses.slice(0, 3).map(d => ({ imageSrc: d.imageSrc, imageAlt: d.imageAlt }))} rightCarouselItems={allDresses.slice(3, 6).map(d => ({ imageSrc: d.imageSrc, imageAlt: d.imageAlt }))} tag="5.0 ★ Loved by Local Brides" tagIcon={Star} tagAnimation="slide-up" buttons={[{ text: "Call Now", href: "tel:747-800-7770" }, { text: "Browse Dresses", onClick: () => galleryRef.current?.scrollIntoView({ behavior: 'smooth' }) }]} buttonAnimation="slide-up" carouselPosition="right" />
|
||||||
title="Find Your Perfect Wedding Dress in Los Angeles"
|
|
||||||
description="Personalized bridal styling with a curated collection of stunning gowns. Our expert team will guide you through every moment of your journey to find the dress of your dreams."
|
|
||||||
background={{ variant: "plain" }}
|
|
||||||
tag="5.0 ★ Loved by Local Brides"
|
|
||||||
tagIcon={Star}
|
|
||||||
tagAnimation="slide-up"
|
|
||||||
buttons={[
|
|
||||||
{ text: "Call Now", href: "tel:747-800-7770" }
|
|
||||||
]}
|
|
||||||
buttonAnimation="slide-up"
|
|
||||||
leftCarouselItems={[
|
|
||||||
{
|
|
||||||
imageSrc: "http://img.b2bpic.net/free-photo/woman-looking-herself_1157-187.jpg?_wi=1", imageAlt: "Bride in beautiful wedding dress at Irentall boutique"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
imageSrc: "http://img.b2bpic.net/free-photo/woman-checking-two-shirts_23-2147601332.jpg?_wi=1", imageAlt: "Elegant Irentall bridal boutique interior"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
imageSrc: "http://img.b2bpic.net/free-photo/beautiful-bride-posing-medium-shot_23-2149860841.jpg?_wi=1", imageAlt: "Happy bride smiling in wedding dress"
|
|
||||||
}
|
|
||||||
]}
|
|
||||||
rightCarouselItems={[
|
|
||||||
{
|
|
||||||
imageSrc: "http://img.b2bpic.net/free-photo/young-women-enjoying-bachelorette-party_23-2149278361.jpg?_wi=1", imageAlt: "Bride with friends at bridal boutique"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
imageSrc: "http://img.b2bpic.net/free-photo/elegant-beautiful-fashionable-woman-blonde-long-white-dre_7502-4897.jpg?_wi=1", imageAlt: "Elegant white wedding dress on display"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
imageSrc: "http://img.b2bpic.net/free-photo/elegant-bride-posing_23-2148105871.jpg?_wi=1", imageAlt: "Bride in perfect wedding dress moment"
|
|
||||||
}
|
|
||||||
]}
|
|
||||||
carouselPosition="right"
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="features" data-section="features">
|
<div id="features" data-section="features" className="relative z-10">
|
||||||
<FeatureCardSixteen
|
<FeatureCardSixteen title="What Makes Irentall Different" description="At Irentall, we believe every bride deserves a personalized, stress-free experience. Here's what sets us apart." textboxLayout="default" useInvertedBackground={false} tag="Our Promise" tagIcon={Heart} tagAnimation="slide-up" negativeCard={{ items: ["Impersonal big-box store experience", "Limited dress selection", "Rushed appointments", "Generic styling advice"] }} positiveCard={{ items: ["Personalized one-on-one attention", "Curated collection of stunning gowns", "Unhurried, comfortable fittings", "Expert styling guidance"] }} animationType="slide-up" />
|
||||||
title="What Makes Us Different"
|
|
||||||
description="At Irentall, we believe every bride deserves a personalized, stress-free experience. Here's what sets us apart from other boutiques."
|
|
||||||
textboxLayout="default"
|
|
||||||
useInvertedBackground={false}
|
|
||||||
tag="Our Promise"
|
|
||||||
tagIcon={Heart}
|
|
||||||
tagAnimation="slide-up"
|
|
||||||
negativeCard={{
|
|
||||||
items: [
|
|
||||||
"Impersonal big-box store experience", "Limited dress selection", "Rushed appointments", "Generic styling advice"
|
|
||||||
]
|
|
||||||
}}
|
|
||||||
positiveCard={{
|
|
||||||
items: [
|
|
||||||
"Personalized one-on-one attention", "Curated collection of stunning gowns", "Unhurried, comfortable fittings", "Expert styling guidance tailored to you"
|
|
||||||
]
|
|
||||||
}}
|
|
||||||
animationType="slide-up"
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="about" data-section="about">
|
<div id="about" data-section="about" className="relative z-10">
|
||||||
<TestimonialAboutCard
|
<TestimonialAboutCard tag="Meet Our Founder" tagIcon={User} tagAnimation="slide-up" title="Iren Ulikhanova" description="Iren Ulikhanova is an accomplished professional in the wedding and dance industry, with years of experience as a dancer, choreographer, and wedding coach. Known for her professionalism and attention to detail, Iren has helped countless couples bring their wedding visions to life." subdescription="" icon={Heart} imageSrc="https://webuild-dev.s3.eu-north-1.amazonaws.com/users/user_3B5MJh3BJx339lVFA4KYjFzlzMX/uploaded-1773894327718-8nx4sc9p.jpg" mediaAnimation="slide-up" useInvertedBackground={true} />
|
||||||
tag="Meet Our Founder"
|
|
||||||
tagIcon={User}
|
|
||||||
tagAnimation="slide-up"
|
|
||||||
title="Iren Ulikhanova "
|
|
||||||
description="Iren Ulikhanova is an accomplished professional in the wedding and dance industry, with years of experience as a dancer, choreographer, and wedding coach. As the owner of a refined wedding dress rental boutique, she combines artistic vision with deep understanding of bridal elegance, delivering a polished and personalized experience for every client. Known for her professionalism and attention to detail, Iren has helped countless couples bring their wedding visions to life, both through exquisite bridal styling and beautifully choreographed first dances."
|
|
||||||
subdescription=""
|
|
||||||
icon={Heart}
|
|
||||||
imageSrc="https://webuild-dev.s3.eu-north-1.amazonaws.com/users/user_3B5MJh3BJx339lVFA4KYjFzlzMX/uploaded-1773894327718-8nx4sc9p.jpg"
|
|
||||||
imageAlt="Irentall owner with bride"
|
|
||||||
mediaAnimation="slide-up"
|
|
||||||
useInvertedBackground={true}
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="testimonials" data-section="testimonials">
|
<div id="gallery" data-section="gallery" className="relative z-10" ref={galleryRef}>
|
||||||
<TestimonialCardSixteen
|
<div ref={galleryContainerRef}>
|
||||||
title="Real Brides, Real Love"
|
<ProductCardFour title="Our Dress Collection" description="Handpicked dresses for every bride, every style, every story." textboxLayout="default" useInvertedBackground={false} tag="Gallery" tagIcon={Camera} tagAnimation="slide-up" gridVariant="bento-grid" animationType="slide-up" products={allDresses} />
|
||||||
description="See what brides in Los Angeles are saying about their Irentall experience."
|
</div>
|
||||||
textboxLayout="default"
|
<div ref={galleryButtonContainerRef} className="flex justify-end px-8 pt-8 pb-4">
|
||||||
useInvertedBackground={false}
|
{showGalleryViewMore && <button onClick={() => { setModalType('gallery'); setShowModal(true); }} className="inline-flex items-center gap-2 px-6 py-3 bg-[#D4AF37] text-black rounded-lg font-semibold hover:shadow-lg transition-all">View More <ChevronRight className="w-5 h-5" /></button>}
|
||||||
tag="Customer Stories"
|
</div>
|
||||||
tagIcon={Users}
|
|
||||||
tagAnimation="slide-up"
|
|
||||||
kpiItems={[
|
|
||||||
{ value: "50+", label: "Happy Brides" },
|
|
||||||
{ value: "5.0★", label: "Average Rating" },
|
|
||||||
{ value: "4.5+", label: "Month of Excellence" }
|
|
||||||
]}
|
|
||||||
testimonials={[
|
|
||||||
{
|
|
||||||
id: "1", name: "Marina Farhardyan ", role: "Bride", company: "Irentall Boutique", rating: 5,
|
|
||||||
imageSrc: "http://img.b2bpic.net/free-photo/beautiful-bride-posing-medium-shot_23-2149860841.jpg?_wi=2", imageAlt: "Sarah Johnson - Happy bride"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "2", name: "Jessica Martinez", role: "Bride", company: "Irentall Boutique", rating: 5,
|
|
||||||
imageSrc: "http://img.b2bpic.net/free-photo/young-women-enjoying-bachelorette-party_23-2149278361.jpg?_wi=2", imageAlt: "Jessica Martinez - Bride with friends"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "3", name: "Emily Chen", role: "Bride", company: "Irentall Boutique", rating: 5,
|
|
||||||
imageSrc: "http://img.b2bpic.net/free-photo/reflection-senior-mother-mature-daughter-mirror-home_23-2148202921.jpg", imageAlt: "Emily Chen - Bride in mirror"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "4", name: "Michelle Rodriguez", role: "Bride", company: "Irentall Boutique", rating: 5,
|
|
||||||
imageSrc: "http://img.b2bpic.net/free-photo/elegant-bride-posing_23-2148105871.jpg?_wi=2", imageAlt: "Michelle Rodriguez - Happy bride moment"
|
|
||||||
}
|
|
||||||
]}
|
|
||||||
animationType="slide-up"
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="gallery" data-section="gallery">
|
<div id="reels" data-section="reels" className="relative z-10">
|
||||||
<ProductCardFour
|
<BlogCardThree title="Behind the Beauty" description="See our latest bridal stories and inspirations." textboxLayout="default" useInvertedBackground={true} tag="Behind the Scenes" tagIcon={Play} tagAnimation="slide-up" animationType="slide-up" blogs={allReels} />
|
||||||
title="Our Dress Collection"
|
|
||||||
description="Handpicked dresses for every bride, every style, every story. From classic elegance to modern minimalism. Some of these dresses are exquisitely and elegantly sewed and crafted by MARAL."
|
|
||||||
textboxLayout="default"
|
|
||||||
useInvertedBackground={false}
|
|
||||||
tag="Gallery"
|
|
||||||
tagIcon={Camera}
|
|
||||||
tagAnimation="slide-up"
|
|
||||||
gridVariant="bento-grid"
|
|
||||||
animationType="slide-up"
|
|
||||||
products={[
|
|
||||||
{
|
|
||||||
id: "dress-1", name: "Classic Elegance", price: "Starting at $1,200", variant: "White", imageSrc: "http://img.b2bpic.net/free-photo/elegant-beautiful-fashionable-woman-blonde-long-white-dre_7502-4897.jpg?_wi=2", imageAlt: "Elegant white wedding dress"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "dress-2", name: "Blush Romance", price: "Starting at $1,400", variant: "Blush Pink", imageSrc: "http://img.b2bpic.net/free-photo/beautiful-bridal-dress-hanger_23-2149640924.jpg?_wi=1", imageAlt: "Beautiful blush pink wedding gown"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "dress-3", name: "Modern Sophistication", price: "Starting at $1,300", variant: "Off-White", imageSrc: "http://img.b2bpic.net/free-vector/hand-drawn-wedding-clothes-collection_1236-88.jpg", imageAlt: "Modern off-shoulder wedding dress"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "dress-4", name: "Intricate Lace", price: "Starting at $1,500", variant: "White", imageSrc: "http://img.b2bpic.net/free-photo/morning-bride-when-she-wears-beautiful-dress_1328-2238.jpg?_wi=1", imageAlt: "Detailed lace wedding dress"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "dress-5", name: "Minimalist Chic", price: "Starting at $1,100", variant: "White", imageSrc: "http://img.b2bpic.net/free-photo/front-view-beautiful-bride-indoors_23-2149640909.jpg?_wi=1", imageAlt: "Sleek minimalist wedding dress"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "dress-6", name: "Royal Drama", price: "Starting at $1,600", variant: "White", imageSrc: "http://img.b2bpic.net/free-photo/bride-playing-with-her-skirt_1157-725.jpg?_wi=1", imageAlt: "Dramatic train wedding dress"
|
|
||||||
}
|
|
||||||
]}
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="reels" data-section="reels">
|
<div id="shoes" data-section="shoes" className="relative z-10" ref={shoesRef}>
|
||||||
<BlogCardThree
|
<div ref={shoesContainerRef}>
|
||||||
title="Behind the Beauty"
|
<ProductCardFour title="Bridal Shoes" description="Complete your look with stunning shoes." textboxLayout="default" useInvertedBackground={true} tag="Accessory Collection" tagIcon={Sparkles} tagAnimation="slide-up" gridVariant="three-columns-all-equal-width" animationType="slide-up" products={allShoes} />
|
||||||
description="Watch our stunning Instagram reels showcasing real brides, styling tips, and magical moments from the Irentall boutique."
|
</div>
|
||||||
textboxLayout="default"
|
<div ref={shoesButtonContainerRef} className="flex justify-end px-8 pt-8 pb-4">
|
||||||
useInvertedBackground={true}
|
{showShoesViewMore && <button onClick={() => { setModalType('shoes'); setShowModal(true); }} className="inline-flex items-center gap-2 px-6 py-3 bg-[#D4AF37] text-black rounded-lg font-semibold hover:shadow-lg transition-all">View More <ChevronRight className="w-5 h-5" /></button>}
|
||||||
tag="Featured Content"
|
</div>
|
||||||
tagIcon={Play}
|
|
||||||
tagAnimation="slide-up"
|
|
||||||
animationType="slide-up"
|
|
||||||
blogs={[
|
|
||||||
{
|
|
||||||
id: "reel-1", category: "Styling", title: "The Perfect First Look", excerpt: "Watch this emotional moment as the groom sees his bride for the first time in her Irentall dress.", imageSrc: "http://img.b2bpic.net/free-photo/beautiful-bride-posing-medium-shot_23-2149860841.jpg?_wi=2", imageAlt: "Bride and groom first look moment", authorName: "Irentall Team", authorAvatar: "https://webuild-dev.s3.eu-north-1.amazonaws.com/users/user_3B5MJh3BJx339lVFA4KYjFzlzMX/uploaded-1773894327718-8nx4sc9p.jpg", date: "Latest"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "reel-2", category: "Dress Reveal", title: "Twirl & Smile", excerpt: "The joy of finding THE dress - captured in this beautiful twirl moment at our boutique.", imageSrc: "http://img.b2bpic.net/free-photo/young-women-enjoying-bachelorette-party_23-2149278361.jpg?_wi=2", imageAlt: "Bride twirling in wedding dress", authorName: "Irentall Team", authorAvatar: "https://webuild-dev.s3.eu-north-1.amazonaws.com/users/user_3B5MJh3BJx339lVFA4KYjFzlzMX/uploaded-1773894327718-8nx4sc9p.jpg", date: "Latest"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "reel-3", category: "Styling Tips", title: "Accessory Magic", excerpt: "See how the right veil and shoes complete the perfect bridal look in seconds.", imageSrc: "http://img.b2bpic.net/free-photo/elegant-beautiful-fashionable-woman-blonde-long-white-dre_7502-4897.jpg?_wi=2", imageAlt: "Bride with complete bridal accessories", authorName: "Irentall Team", authorAvatar: "https://webuild-dev.s3.eu-north-1.amazonaws.com/users/user_3B5MJh3BJx339lVFA4KYjFzlzMX/uploaded-1773894327718-8nx4sc9p.jpg", date: "Latest"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "reel-4", category: "Fashion", title: "Lace Details Up Close", excerpt: "Discover the intricate craftsmanship of our most popular lace wedding dress collection.", imageSrc: "http://img.b2bpic.net/free-photo/elegant-bride-posing_23-2148105871.jpg?_wi=2", imageAlt: "Close-up of wedding dress lace details", authorName: "Irentall Team", authorAvatar: "https://webuild-dev.s3.eu-north-1.amazonaws.com/users/user_3B5MJh3BJx339lVFA4KYjFzlzMX/uploaded-1773894327718-8nx4sc9p.jpg", date: "Latest"
|
|
||||||
}
|
|
||||||
]}
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="shoes" data-section="shoes">
|
<div id="veils" data-section="veils" className="relative z-10" ref={veilsRef}>
|
||||||
<ProductCardFour
|
<div ref={veilsContainerRef}>
|
||||||
title="Bridal Shoes"
|
<ProductCardFour title="Veils & Crowns" description="Enhance your bridal beauty." textboxLayout="default" useInvertedBackground={false} tag="Veil Collection" tagIcon={Crown} tagAnimation="slide-up" gridVariant="three-columns-all-equal-width" animationType="slide-up" products={allVeils} />
|
||||||
description="Complete your wedding day look with stunning shoes designed for comfort and elegance. From classic heels to modern designs."
|
</div>
|
||||||
textboxLayout="default"
|
<div ref={veilsButtonContainerRef} className="flex justify-end px-8 pt-8 pb-4">
|
||||||
useInvertedBackground={true}
|
{showVeilsViewMore && <button onClick={() => { setModalType('veils'); setShowModal(true); }} className="inline-flex items-center gap-2 px-6 py-3 bg-[#D4AF37] text-black rounded-lg font-semibold hover:shadow-lg transition-all">View More <ChevronRight className="w-5 h-5" /></button>}
|
||||||
tag="Accessory Collection"
|
</div>
|
||||||
tagIcon={Sparkles}
|
|
||||||
tagAnimation="slide-up"
|
|
||||||
gridVariant="three-columns-all-equal-width"
|
|
||||||
animationType="slide-up"
|
|
||||||
products={[
|
|
||||||
{
|
|
||||||
id: "shoe-1", name: "Classic Satin Heels", price: "Starting at $250", variant: "White", imageSrc: "http://img.b2bpic.net/free-photo/elegant-beautiful-fashionable-woman-blonde-long-white-dre_7502-4897.jpg?_wi=2", imageAlt: "Classic white satin bridal heels"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "shoe-2", name: "Jeweled Flats", price: "Starting at $280", variant: "Ivory", imageSrc: "http://img.b2bpic.net/free-photo/beautiful-bridal-dress-hanger_23-2149640924.jpg?_wi=2", imageAlt: "Comfortable jeweled flat bridal shoes"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "shoe-3", name: "Pearl Embellished Pumps", price: "Starting at $320", variant: "Champagne", imageSrc: "http://img.b2bpic.net/free-photo/morning-bride-when-she-wears-beautiful-dress_1328-2238.jpg?_wi=2", imageAlt: "Pearl decorated champagne bridal pumps"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "shoe-4", name: "Delicate Strappy Sandals", price: "Starting at $200", variant: "Silver", imageSrc: "http://img.b2bpic.net/free-photo/elegant-bride-posing_23-2148105871.jpg?_wi=2", imageAlt: "Delicate silver strappy bridal sandals"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "shoe-5", name: "Vintage Lace Pumps", price: "Starting at $290", variant: "White", imageSrc: "http://img.b2bpic.net/free-photo/front-view-beautiful-bride-indoors_23-2149640909.jpg?_wi=2", imageAlt: "Vintage lace wedding pumps"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "shoe-6", name: "Minimalist Ballet Flats", price: "Starting at $220", variant: "Ivory", imageSrc: "http://img.b2bpic.net/free-photo/bride-playing-with-her-skirt_1157-725.jpg?_wi=2", imageAlt: "Minimalist ivory ballet flat shoes"
|
|
||||||
}
|
|
||||||
]}
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="veils" data-section="veils">
|
<div id="contact" data-section="contact" className="relative z-10">
|
||||||
<ProductCardFour
|
<ContactCTA tag="Get in Touch" tagIcon={Phone} tagAnimation="slide-up" title="Ready to Find Your Dream Dress?" description="Book your free 30-minute styling session today! Call or text (747) 800-7770." buttons={[{ text: "Call (747) 800-7770", href: "tel:747-800-7770" }, { text: "Text (747) 800-7770", href: "sms:747-800-7770" }]} background={{ variant: "plain" }} useInvertedBackground={false} />
|
||||||
title="Veils & Crowns"
|
|
||||||
description="Enhance your bridal beauty with our exquisite collection of veils and headpieces. Each piece is carefully selected to complement your gown perfectly."
|
|
||||||
textboxLayout="default"
|
|
||||||
useInvertedBackground={false}
|
|
||||||
tag="Veil Collection"
|
|
||||||
tagIcon={Crown}
|
|
||||||
tagAnimation="slide-up"
|
|
||||||
gridVariant="three-columns-all-equal-width"
|
|
||||||
animationType="slide-up"
|
|
||||||
products={[
|
|
||||||
{
|
|
||||||
id: "veil-1", name: "Cathedral Length Veil", price: "Starting at $180", variant: "White Tulle", imageSrc: "http://img.b2bpic.net/free-photo/woman-looking-herself_1157-187.jpg?_wi=2", imageAlt: "Elegant cathedral length bridal veil"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "veil-2", name: "Lace Embellished Veil", price: "Starting at $220", variant: "Ivory Lace", imageSrc: "http://img.b2bpic.net/free-photo/woman-checking-two-shirts_23-2147601332.jpg?_wi=2", imageAlt: "Beautiful lace embellished bridal veil"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "veil-3", name: "Dramatic Detachable Veil", price: "Starting at $250", variant: "Ivory", imageSrc: "http://img.b2bpic.net/free-photo/beautiful-bride-posing-medium-shot_23-2149860841.jpg?_wi=1", imageAlt: "Dramatic detachable bridal veil"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "veil-4", name: "Short Birdcage Veil", price: "Starting at $120", variant: "Black Netting", imageSrc: "http://img.b2bpic.net/free-photo/young-women-enjoying-bachelorette-party_23-2149278361.jpg?_wi=1", imageAlt: "Modern short birdcage veil"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "veil-5", name: "Pearl Trimmed Veil", price: "Starting at $200", variant: "Champagne", imageSrc: "http://img.b2bpic.net/free-photo/elegant-beautiful-fashionable-woman-blonde-long-white-dre_7502-4897.jpg?_wi=1", imageAlt: "Pearl trimmed champagne bridal veil"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "veil-6", name: "Crystal Beaded Veil", price: "Starting at $270", variant: "White with Crystals", imageSrc: "http://img.b2bpic.net/free-photo/elegant-bride-posing_23-2148105871.jpg?_wi=1", imageAlt: "Sparkling crystal beaded bridal veil"
|
|
||||||
}
|
|
||||||
]}
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="contact" data-section="contact">
|
<div id="footer" data-section="footer" className="relative z-10">
|
||||||
<ContactCTA
|
<FooterSimple columns={[]} bottomLeftText="© 2024 Irentall Bridal Boutique." bottomRightText="3106 Los Feliz Blvd, Los Angeles, CA 90039" />
|
||||||
tag="Get in Touch"
|
|
||||||
tagIcon={Phone}
|
|
||||||
tagAnimation="slide-up"
|
|
||||||
title="Ready to Find Your Dream Dress?"
|
|
||||||
description="Call or text us at 747-800-7770 to schedule your personal styling appointment. Our team is here to make your bridal journey unforgettable."
|
|
||||||
buttons={[
|
|
||||||
{ text: "Call (747) 800-7770", href: "tel:747-800-7770" },
|
|
||||||
{ text: "Text (747) 800-7770", href: "sms:747-800-7770" }
|
|
||||||
]}
|
|
||||||
buttonAnimation="slide-up"
|
|
||||||
background={{ variant: "plain" }}
|
|
||||||
useInvertedBackground={false}
|
|
||||||
buttonContainerClassName="flex flex-col sm:flex-row gap-3 justify-center"
|
|
||||||
buttonClassName="first:order-first second:order-last"
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="footer" data-section="footer">
|
{renderModal()}
|
||||||
<FooterSimple
|
|
||||||
columns={[
|
|
||||||
{
|
|
||||||
title: "Irentall", items: [
|
|
||||||
{ label: "Home", href: "#home" },
|
|
||||||
{ label: "About", href: "#about" },
|
|
||||||
{ label: "Gallery", href: "#gallery" },
|
|
||||||
{ label: "Contact", href: "#contact" }
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "Services", items: [
|
|
||||||
{ label: "Bridal Gowns", href: "#gallery" },
|
|
||||||
{ label: "Dress Fittings", href: "#appointment" },
|
|
||||||
{ label: "Personal Styling", href: "#appointment" },
|
|
||||||
{ label: "Consultations", href: "#appointment" }
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "Accessories", items: [
|
|
||||||
{ label: "Shoes", href: "#shoes" },
|
|
||||||
{ label: "Veils & Headpieces", href: "#veils" },
|
|
||||||
{ label: "Complete Looks", href: "#appointment" }
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "Contact", items: [
|
|
||||||
{ label: "Phone", href: "tel:747-800-7770" },
|
|
||||||
{ label: "Email", href: "mailto:info@irentall.com" },
|
|
||||||
{ label: "Address", href: "#contact" },
|
|
||||||
{ label: "Book Online", href: "#appointment" }
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]}
|
|
||||||
bottomLeftText="© 2024 Irentall Bridal Boutique. All rights reserved."
|
|
||||||
bottomRightText="3106 Los Feliz Blvd, Los Angeles, CA 90039 | (747) 800-7770"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</ThemeProvider>
|
</ThemeProvider>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
78
src/hooks/useScrollDetection.ts
Normal file
78
src/hooks/useScrollDetection.ts
Normal file
@@ -0,0 +1,78 @@
|
|||||||
|
import { useEffect, useRef, useState } from 'react';
|
||||||
|
|
||||||
|
interface UseScrollDetectionOptions {
|
||||||
|
targetElementId: string;
|
||||||
|
scrollThreshold?: number;
|
||||||
|
onStateChange?: (state: {
|
||||||
|
isScrollingPastTarget: boolean;
|
||||||
|
isScrollingBack: boolean;
|
||||||
|
scrollProgress: number;
|
||||||
|
}) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface UseScrollDetectionReturn {
|
||||||
|
isScrollingPastTarget: boolean;
|
||||||
|
isScrollingBack: boolean;
|
||||||
|
scrollProgress: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function useScrollDetection({
|
||||||
|
targetElementId,
|
||||||
|
scrollThreshold = 0.3,
|
||||||
|
onStateChange,
|
||||||
|
}: UseScrollDetectionOptions): UseScrollDetectionReturn {
|
||||||
|
const [isScrollingPastTarget, setIsScrollingPastTarget] = useState(false);
|
||||||
|
const [isScrollingBack, setIsScrollingBack] = useState(false);
|
||||||
|
const [scrollProgress, setScrollProgress] = useState(0);
|
||||||
|
const lastScrollYRef = useRef(0);
|
||||||
|
const targetElementRef = useRef<HTMLElement | null>(null);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
// Get target element
|
||||||
|
targetElementRef.current = document.getElementById(targetElementId);
|
||||||
|
|
||||||
|
const handleScroll = () => {
|
||||||
|
if (!targetElementRef.current) return;
|
||||||
|
|
||||||
|
const targetRect = targetElementRef.current.getBoundingClientRect();
|
||||||
|
const windowHeight = window.innerHeight;
|
||||||
|
const scrollY = window.scrollY;
|
||||||
|
const currentScrollDirection = scrollY > lastScrollYRef.current ? 'down' : 'up';
|
||||||
|
|
||||||
|
// Calculate if we've scrolled past the target element
|
||||||
|
const targetTop = targetRect.top + scrollY;
|
||||||
|
const thresholdDistance = window.innerHeight * scrollThreshold;
|
||||||
|
const isPastTarget = scrollY > targetTop - thresholdDistance;
|
||||||
|
|
||||||
|
// Determine scroll direction
|
||||||
|
const isScrollingBackward = currentScrollDirection === 'up';
|
||||||
|
|
||||||
|
// Calculate scroll progress (0 to 1)
|
||||||
|
const progress = Math.min(scrollY / (targetTop + thresholdDistance), 1);
|
||||||
|
|
||||||
|
setIsScrollingPastTarget(isPastTarget);
|
||||||
|
setIsScrollingBack(isScrollingBackward);
|
||||||
|
setScrollProgress(progress);
|
||||||
|
|
||||||
|
// Call callback if provided
|
||||||
|
if (onStateChange) {
|
||||||
|
onStateChange({
|
||||||
|
isScrollingPastTarget: isPastTarget,
|
||||||
|
isScrollingBack: isScrollingBackward,
|
||||||
|
scrollProgress: progress,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
lastScrollYRef.current = scrollY;
|
||||||
|
};
|
||||||
|
|
||||||
|
window.addEventListener('scroll', handleScroll, { passive: true });
|
||||||
|
return () => window.removeEventListener('scroll', handleScroll);
|
||||||
|
}, [targetElementId, scrollThreshold, onStateChange]);
|
||||||
|
|
||||||
|
return {
|
||||||
|
isScrollingPastTarget,
|
||||||
|
isScrollingBack,
|
||||||
|
scrollProgress,
|
||||||
|
};
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user