Merge version_5_1776255067449 into main #5

Merged
bender merged 1 commits from version_5_1776255067449 into main 2026-04-15 12:16:03 +00:00
5 changed files with 52 additions and 47 deletions

View File

@@ -35,7 +35,11 @@ export default function App() {
text: "Browse Menu", href: "#features"}}
secondaryButton={{
text: "Visit Us", href: "#contact"}}
imageSrc="https://images.unsplash.com/photo-1681838675911-625ee52549f5?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3w4Mzc5ODl8MHwxfHNlYXJjaHwxNHx8YmFrZXJ5JTIwd2luZG93JTIwd2l0aCUyMHdhcm0lMjBsaWdodGluZ3xlbnwxfDB8fHwxNzc2MjUzMTMzfDA&ixlib=rb-4.1.0&q=80&w=1080"
images={[
"https://images.unsplash.com/photo-1681838675911-625ee52549f5?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3w4Mzc5ODl8MHwxfHNlYXJjaHwxNHx8YmFrZXJ5JTIwd2luZG93JTIwd2l0aCUyMHdhcm0lMjBsaWdodGluZ3xlbnwxfDB8fHwxNzc2MjUzMTMzfDA&ixlib=rb-4.1.0&q=80&w=1080",
"https://images.unsplash.com/photo-1555507036-ab1f4038808a?q=80&w=2070&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D",
"https://images.unsplash.com/photo-1568254183919-78a4f43a2877?q=80&w=2070&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D"
]}
/>
</div>

View File

@@ -1,7 +1,7 @@
import { motion } from "motion/react";
import Button from "@/components/ui/Button";
import TextAnimation from "@/components/ui/TextAnimation";
import ImageOrVideo from "@/components/ui/ImageOrVideo";
import ImageSlider from "@/components/ui/ImageSlider";
type HeroSplitProps = {
tag: string;
@@ -9,7 +9,8 @@ type HeroSplitProps = {
description: string;
primaryButton: { text: string; href: string };
secondaryButton: { text: string; href: string };
} & ({ imageSrc: string; videoSrc?: never } | { videoSrc: string; imageSrc?: never });
images: string[];
};
const HeroSplit = ({
tag,
@@ -17,8 +18,7 @@ const HeroSplit = ({
description,
primaryButton,
secondaryButton,
imageSrc,
videoSrc,
images,
}: HeroSplitProps) => {
return (
<section aria-label="Hero section" className="flex items-center h-fit md:h-svh pt-25 pb-20 md:py-0">
@@ -54,7 +54,7 @@ const HeroSplit = ({
transition={{ duration: 0.6, ease: "easeOut", delay: 0.2 }}
className="w-full md:w-1/2 h-100 md:h-[65vh] md:max-h-[75svh] p-5 card rounded overflow-hidden"
>
<ImageOrVideo imageSrc={imageSrc} videoSrc={videoSrc} />
<ImageSlider images={images} />
</motion.div>
</div>
</section>

View File

@@ -0,0 +1,30 @@
import { useCarouselControls } from "@/hooks/useCarouselControls";
import { ChevronLeft, ChevronRight } from "lucide-react";
type ImageSliderProps = {
images: string[];
};
const ImageSlider = ({ images }: ImageSliderProps) => {
const { currentIndex, prev, next } = useCarouselControls(images.length);
return (
<div className="image-slider">
<div className="slides-container" style={{ transform: `translateX(-${currentIndex * 100}%)` }}>
{images.map((src, index) => (
<div className="slide" key={index}>
<img src={src} alt={`Slide ${index + 1}`} className="w-full h-full object-cover" />
</div>
))}
</div>
<button onClick={prev} className="slider-control prev">
<ChevronLeft />
</button>
<button onClick={next} className="slider-control next">
<ChevronRight />
</button>
</div>
);
};
export default ImageSlider;

View File

@@ -1,45 +1,15 @@
import { useCallback, useEffect, useState } from "react";
import type { EmblaCarouselType } from "embla-carousel";
import { useState } from "react";
export const useCarouselControls = (emblaApi: EmblaCarouselType | undefined) => {
const [prevDisabled, setPrevDisabled] = useState(true);
const [nextDisabled, setNextDisabled] = useState(true);
const [scrollProgress, setScrollProgress] = useState(0);
export const useCarouselControls = (totalSlides: number) => {
const [currentIndex, setCurrentIndex] = useState(0);
const scrollPrev = useCallback(() => {
if (!emblaApi) return;
emblaApi.scrollPrev();
}, [emblaApi]);
const next = () => {
setCurrentIndex((prevIndex) => (prevIndex + 1) % totalSlides);
};
const scrollNext = useCallback(() => {
if (!emblaApi) return;
emblaApi.scrollNext();
}, [emblaApi]);
const prev = () => {
setCurrentIndex((prevIndex) => (prevIndex - 1 + totalSlides) % totalSlides);
};
const onSelect = useCallback((api: EmblaCarouselType) => {
setPrevDisabled(!api.canScrollPrev());
setNextDisabled(!api.canScrollNext());
}, []);
const onScroll = useCallback((api: EmblaCarouselType) => {
const progress = Math.max(0, Math.min(1, api.scrollProgress()));
setScrollProgress(progress * 100);
}, []);
useEffect(() => {
if (!emblaApi) return;
onSelect(emblaApi);
onScroll(emblaApi);
emblaApi.on("reInit", onSelect).on("select", onSelect);
emblaApi.on("reInit", onScroll).on("scroll", onScroll);
return () => {
emblaApi.off("reInit", onSelect).off("select", onSelect);
emblaApi.off("reInit", onScroll).off("scroll", onScroll);
};
}, [emblaApi, onSelect, onScroll]);
return { prevDisabled, nextDisabled, scrollPrev, scrollNext, scrollProgress };
};
return { currentIndex, next, prev };
};

View File

@@ -1,6 +1,7 @@
@import "tailwindcss";
@import "./styles/masks.css";
@import "./styles/animations.css";
@import "./styles/slider.css";
:root {
/* @colorThemes/lightTheme/grayBlueAccent */