diff --git a/app/(home)/components/Footer.tsx b/app/(home)/components/Footer.tsx index 7c17201..e935861 100644 --- a/app/(home)/components/Footer.tsx +++ b/app/(home)/components/Footer.tsx @@ -42,7 +42,12 @@ const socialLinks = [ const links = [ { label: 'Home', href: '/' }, - { label: 'SIGs', href: '/sigs' }, + // { label: 'SIGs', href: '/sigs' }, + { + label: 'Code of Conduct', + href: '/code-of-conduct', + external: false, + }, { label: 'About', href: 'https://www.meetup.com/durianpy/', external: true }, { label: 'Speak', diff --git a/app/(home)/components/Sponsors.tsx b/app/(home)/components/Sponsors.tsx new file mode 100644 index 0000000..91c0f87 --- /dev/null +++ b/app/(home)/components/Sponsors.tsx @@ -0,0 +1,73 @@ +import { Container } from '@/components/ui/container'; +import dynamic from 'next/dynamic'; +const SponsorsDesktop = dynamic(() => import('./SponsorsDesktop')); +const SponsorsMobile = dynamic(() => import('./SponsorsMobile')); + +interface SponsorshipProps { + name: string; + logo: string; + logoMobile: string; + description: string; + url: string; +} + +export function Sponsors() { + const sponsors: SponsorshipProps[] = [ + { + name: 'Mugna Tech', + logo: '/sponsor-logos/mugna-logo.png', + logoMobile: '/sponsor-logos/mugna-logo.png', + description: + 'Mugna Tech specializes in Web, Software, and Mobile Development, UI/UX Design, and more, with 75+ projects for diverse businesses.', + url: 'https://mugna.tech', + }, + { + name: 'Codev', + logo: '/sponsor-logos/codev-logo.png', + logoMobile: '/sponsor-logos/codev-logo.png', + description: + 'Hire top offshore developers with CoDev—skilled professionals dedicated to your success.', + url: 'https://codev.com', + }, + { + name: 'Ingenuity Software', + logo: '/sponsor-logos/ingenuity-logo.png', + logoMobile: '/sponsor-logos/ingenuity-logo-mobile.png', + description: + 'Ingenuity Software is a Davao-based software development company that turns ideas into impactful digital solutions. ', + url: 'https://ingenuity.ph', + }, + { + name: 'PythonPH', + logo: '/sponsor-logos/pythonph-logo.png', + logoMobile: '/sponsor-logos/pythonph-logo-mobile.png', + description: + 'Python Philippines is a volunteer-run non-profit supporting the growth of the Python community in the country.', + url: 'https://python.ph', + }, + { + name: 'Stace', + logo: '/sponsor-logos/stace-logo.svg', + logoMobile: '/sponsor-logos/stace-logo.svg', + description: + 'Stace is a comprehensive platform designed to enhance and simplify the rental experience for both renters and landlords.', + url: 'https://www.stace.app', + }, + ]; + + return ( +
+ + {/* Desktop View (768px and up) */} +
+ +
+ + {/* Mobile View (Below 768px) */} +
+ +
+
+
+ ); +} diff --git a/app/(home)/components/SponsorsDesktop.tsx b/app/(home)/components/SponsorsDesktop.tsx new file mode 100644 index 0000000..7c50d52 --- /dev/null +++ b/app/(home)/components/SponsorsDesktop.tsx @@ -0,0 +1,246 @@ +'use client'; + +import { useEffect, useState, useRef } from 'react'; +import { cn } from '@/lib/utils'; +import Autoplay from 'embla-carousel-autoplay'; +import { + Carousel, + CarouselApi, + CarouselContent, + CarouselItem, + CarouselNext, + CarouselPrevious, +} from '@/components/ui/carousel'; +import Image from 'next/image'; +import Link from 'next/link'; +import { Button } from '@/components/ui/button'; + +interface SponsorshipProps { + name: string; + logo: string; + logoMobile: string; + description: string; + url: string; +} + +const SponsorsDesktop = ({ sponsors }: { sponsors: SponsorshipProps[] }) => { + const [api, setApi] = useState(); + const [current, setCurrent] = useState(0); + const [count, setCount] = useState(0); + + // State to hold the featured sponsor + const [featuredSponsor, setfeaturedSponsor] = useState( + sponsors[0] + ); + + useEffect(() => { + if (!api) { + return; + } + setCount(api.scrollSnapList().length); + + // Set the current index to the first item + api.scrollTo(2); + + api.on('select', () => { + const currentIndex = api.selectedScrollSnap(); + const correctedCurrentIndex = (currentIndex + 3) % sponsors.length; + setCurrent(correctedCurrentIndex); + setfeaturedSponsor(sponsors[correctedCurrentIndex]); + }); + }, [api, sponsors]); + + const plugin = useRef(Autoplay({ delay: 5000, stopOnInteraction: true })); + + const autoPlayInteraction = () => { + plugin.current.stop(); + // Wait for 5 seconds before resuming autoplay but when the user clicks it cancel the autoplay + setTimeout(() => { + if (api) { + plugin.current.play(); + } + }, 5000); + }; + + const carouselFeaturedAnimation = ( + sponsor: SponsorshipProps, + index: number + ) => { + setfeaturedSponsor(sponsor); + api?.scrollTo(index + 2); + updateButton(index); + autoPlayInteraction(); + }; + + const updateButton = (index: number) => { + setCurrent(index); + api?.scrollTo(index + 2); + setfeaturedSponsor(sponsors[index]); + autoPlayInteraction(); + }; + + return ( +
+ {/* Description Section */} +
+
+

+ Our Sponsors +

+

+ A big thank you to our generous sponsors whose support makes our + work possible and helps us create lasting impact. +

+ +
+ +
+
+
+
+
+
+ +
+ {/* Featured Section */} + {featuredSponsor && ( +
+ +
+ {featuredSponsor.name} +
+
+ {/* Icon */} +
+ + + + +
+ {/* Horizontal Line */} +
+
+

+ {featuredSponsor.description} +

+

— {featuredSponsor.name} +

+ +
+ )} + + {/* Carousel Section */} +
+ {/*Carousel Body*/} + + {/* Previous Button */} + + + + + {/* Carousel Content */} + + {sponsors.map((sponsor, index) => ( + +
carouselFeaturedAnimation(sponsor, index)} + > + {/* Gradient Overlay */} +
+ +
+ {/* Logo Container */} +
+
+ {sponsor.name} +
+
+
+
+
+ ))} +
+ + {/* Next Button */} + + + +
+
+ {/* Dots Navigation */} +
+ {Array.from({ length: count }).map((_, index) => ( + + ))} +
+
+
+ ); +}; + +export default SponsorsDesktop; diff --git a/app/(home)/components/SponsorsMobile.tsx b/app/(home)/components/SponsorsMobile.tsx new file mode 100644 index 0000000..3fff45b --- /dev/null +++ b/app/(home)/components/SponsorsMobile.tsx @@ -0,0 +1,230 @@ +'use client'; + +import { + Carousel, + CarouselContent, + CarouselItem, +} from '@/components/ui/carousel'; +import React, { useState, useEffect, useRef } from 'react'; +import Image from 'next/image'; +import Link from 'next/link'; +import { Button } from '@/components/ui/button'; +import { cn } from '@/lib/utils'; + +interface SponsorsProps { + name: string; + logoMobile: string; + description: string; + url: string; +} + +const SponsorsMobile = ({ sponsors }: { sponsors: SponsorsProps[] }) => { + const [activeIndex, setActiveIndex] = useState(0); + const [showAll, setShowAll] = useState(false); + const [isVisible, setIsVisible] = useState(false); + const sectionRef = useRef(null); + + useEffect(() => { + const handleScroll = () => { + const container = document.getElementById('sponsors-carousel-container'); + if (!container) return; + + const cardHeight = 250; + const scrollTop = container.scrollTop; + const maxScroll = container.scrollHeight - container.clientHeight; + let index = Math.round(scrollTop / cardHeight); + + if (scrollTop <= 5) { + index = 0; + } else if (scrollTop >= maxScroll - 5) { + index = sponsors.length - 1; + } + + setActiveIndex(index); + }; + + const container = document.getElementById('sponsors-carousel-container'); + if (container) { + container.addEventListener('scroll', handleScroll); + } + + return () => { + if (container) { + container.removeEventListener('scroll', handleScroll); + } + }; + }, [sponsors.length]); + + useEffect(() => { + const observer = new IntersectionObserver( + ([entry]) => { + setIsVisible(entry.isIntersecting); + }, + { threshold: 0.2 } + ); + + const currentRef = sectionRef.current; + if (currentRef) { + observer.observe(currentRef); + } + + return () => { + if (currentRef) { + observer.unobserve(currentRef); + } + }; + }, []); + + return ( +
+

+ Our Sponsors +

+

+ A big thank you to our generous sponsors whose support makes our work + possible and helps us create lasting impact. +

+ +
+ +
+ +
+ {/* Carousel or Full View */} +
+ +
+ + {/* Dot Indicators */} + {!showAll && ( +
+ {sponsors.map((_, index) => ( + + ))} +
+ )} + + {/* Show All Button */} +
setShowAll(!showAll)} + > + {showAll ? 'Collapse' : 'Show all'} +
+
+
+ ); +}; + +export default SponsorsMobile; diff --git a/app/(home)/page.tsx b/app/(home)/page.tsx index b64309e..66c407f 100644 --- a/app/(home)/page.tsx +++ b/app/(home)/page.tsx @@ -4,7 +4,7 @@ import { CTASection } from './components/CTASection'; import { StatsAndReviews } from './components/StatsAndReviews'; import { PythonFoundation } from './components//PythonFoundation'; import { Partners } from './components//Partners'; -import { Footer } from './components//Footer'; +import { Sponsors } from './components/Sponsors'; export default function HomePage() { return ( @@ -15,7 +15,7 @@ export default function HomePage() { -