From f0bdefaa53d4b4dfbd2cd136955320dddcfc2909 Mon Sep 17 00:00:00 2001 From: Jake Date: Tue, 16 Sep 2025 03:40:44 +0200 Subject: [PATCH 1/3] Scrollable carousels --- src/app/globals.css | 10 ++++ src/components/Carousel.tsx | 109 +++++++++++++++++++++++++++++++----- 2 files changed, 105 insertions(+), 14 deletions(-) diff --git a/src/app/globals.css b/src/app/globals.css index cc2537f..ab06696 100644 --- a/src/app/globals.css +++ b/src/app/globals.css @@ -26,3 +26,13 @@ body { color: var(--foreground); font-family: var(--font-outfit-sans), sans-serif; } + +/* Utility to hide scrollbars while maintaining functionality */ +.scrollbar-hide { + -ms-overflow-style: none; /* IE and Edge */ + scrollbar-width: none; /* Firefox */ +} + +.scrollbar-hide::-webkit-scrollbar { + display: none; /* Chrome, Safari and Opera */ +} diff --git a/src/components/Carousel.tsx b/src/components/Carousel.tsx index d084541..cbc59bb 100644 --- a/src/components/Carousel.tsx +++ b/src/components/Carousel.tsx @@ -1,32 +1,113 @@ 'use client'; -import {useState, createContext, useContext} from 'react'; +import {useState, createContext, useRef, useEffect} from 'react'; const PageContext = createContext({page: 1,size:1}); function Carousel({children, pages, size, className}:{children: Array, pages:number, size:number, className?:string}) { const [page, setPage] = useState(0); + const scrollContainerRef = useRef(null); + function setter (p: number) { setPage(p); + // Scroll to the corresponding page + if (scrollContainerRef.current) { + const scrollContainer = scrollContainerRef.current; + const pageWidth = scrollContainer.offsetWidth; + scrollContainer.scrollTo({ + left: pageWidth * p, + behavior: 'smooth' + }); + } } + + // Handle scroll events to update active dot + useEffect(() => { + const scrollContainer = scrollContainerRef.current; + if (!scrollContainer || pages <= 1) return; + + const handleScroll = () => { + const scrollLeft = scrollContainer.scrollLeft; + const pageWidth = scrollContainer.offsetWidth; + const currentPage = Math.round(scrollLeft / pageWidth); + if (currentPage !== page && currentPage >= 0 && currentPage < pages) { + setPage(currentPage); + } + }; + + scrollContainer.addEventListener('scroll', handleScroll); + return () => scrollContainer.removeEventListener('scroll', handleScroll); + }, [pages, page]); + + // Create pages with items + const createPages = () => { + const pageElements = []; + for (let i = 0; i < pages; i++) { + const pageItems = []; + for (let j = i * size; j < Math.min((i + 1) * size, children.length); j++) { + const childElement = children[j] as React.ReactElement<{className?: string, children: React.ReactNode}>; + pageItems.push( + + {childElement.props.children} + + ); + } + + pageElements.push( +
    + + {pageItems} + +
+ ); + } + return pageElements; + }; + let dots; - if (pages>1){ - dots = (
- {[...Array(pages).keys()].map(i => ({setter(i)}} className={`${(page==i)?'opacity-100':'opacity-50'} select-none m-0.5 hover:opacity-70`}>●))} -
) + if (pages > 1) { + dots = ( +
+
+ {[...Array(pages).keys()].map(i => ( + + ))} +
+
+ ); } + return ( -
    - {children} - {dots} -
-); +
+
+ {createPages()} +
+ {dots} +
+ ); } -function CI ({children, className, index}:{children: Array, className:string, index:number}) { - const context = useContext(PageContext); - const visible = (index>=(context.size*context.page))&&(index<(context.size*(context.page+1))); +function CI ({children, className}:{children: React.ReactNode, className:string}) { return ( -
  • +
  • {children}
  • ); From 6a28a935b9101d9edaab6b065890aadb1f1e7c27 Mon Sep 17 00:00:00 2001 From: Jake Date: Tue, 16 Sep 2025 03:46:19 +0200 Subject: [PATCH 2/3] Rm index prop --- src/app/volunteers/CarouselAssignments.tsx | 2 +- src/app/volunteers/CarouselTestimony.tsx | 2 +- src/app/volunteers/CarouselVolunteer.tsx | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/app/volunteers/CarouselAssignments.tsx b/src/app/volunteers/CarouselAssignments.tsx index f15fb11..f5d72cb 100644 --- a/src/app/volunteers/CarouselAssignments.tsx +++ b/src/app/volunteers/CarouselAssignments.tsx @@ -13,7 +13,7 @@ async function AssignmentsCarousel() { return ( {assignments.map((e, i) => ( - +
    {e.title}{i}

    {e.description}

    {/*Unused code from Figma:*/}

    {e.id}

    diff --git a/src/app/volunteers/CarouselTestimony.tsx b/src/app/volunteers/CarouselTestimony.tsx index c46dc44..0711cf1 100644 --- a/src/app/volunteers/CarouselTestimony.tsx +++ b/src/app/volunteers/CarouselTestimony.tsx @@ -14,7 +14,7 @@ async function TestimonyCarousel() { return ( {testimony.map((e, i) => ( - + {/*Unused code from Figma design
    {e.title}{i}
    */}

    {e.quote}

    diff --git a/src/app/volunteers/CarouselVolunteer.tsx b/src/app/volunteers/CarouselVolunteer.tsx index 0873ccb..d882ada 100644 --- a/src/app/volunteers/CarouselVolunteer.tsx +++ b/src/app/volunteers/CarouselVolunteer.tsx @@ -15,7 +15,7 @@ async function VolunteerCarousel() { return ( {volunteers.map((e, i) => ( - + {e.name}
    From e3c8b665bcf65e525c78a8cc1fb3de05aacd3ef2 Mon Sep 17 00:00:00 2001 From: Jake Date: Tue, 16 Sep 2025 03:55:24 +0200 Subject: [PATCH 3/3] Rm unused var --- src/app/volunteers/CarouselTestimony.tsx | 2 +- src/app/volunteers/CarouselVolunteer.tsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/app/volunteers/CarouselTestimony.tsx b/src/app/volunteers/CarouselTestimony.tsx index 0711cf1..b35b523 100644 --- a/src/app/volunteers/CarouselTestimony.tsx +++ b/src/app/volunteers/CarouselTestimony.tsx @@ -13,7 +13,7 @@ async function TestimonyCarousel() { }/**/ return ( - {testimony.map((e, i) => ( + {testimony.map((e) => ( {/*Unused code from Figma design
    {e.title}{i}
    */} diff --git a/src/app/volunteers/CarouselVolunteer.tsx b/src/app/volunteers/CarouselVolunteer.tsx index d882ada..a4e00a4 100644 --- a/src/app/volunteers/CarouselVolunteer.tsx +++ b/src/app/volunteers/CarouselVolunteer.tsx @@ -14,7 +14,7 @@ async function VolunteerCarousel() { } return ( - {volunteers.map((e, i) => ( + {volunteers.map((e) => ( {e.name}