Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
502b076
updated past sponsor logos
bhuvana108 Nov 3, 2025
8413d63
update logos
bhuvana108 Nov 3, 2025
7d2f4d4
added nvidia
bhuvana108 Nov 4, 2025
d60f8ae
mobile view for Intro (who are we)
AbhiramTadepalli Nov 9, 2025
95cf61c
smaller icons in SponsorCarousel
AbhiramTadepalli Nov 9, 2025
1bbb569
make pastHackathons 3 columns
AbhiramTadepalli Nov 9, 2025
dbe2002
make openSource mobile-friendly
AbhiramTadepalli Nov 9, 2025
508e327
mess with some spacing up above in openSource
AbhiramTadepalli Nov 9, 2025
7f5a4c6
moves arrows better in into file
AbhiramTadepalli Nov 9, 2025
9251cca
Merge branch 'icons' into mobile-abhi
AbhiramTadepalli Nov 9, 2025
f69c50c
Add gradual fade mask between sections
AbhiramTadepalli Nov 9, 2025
5a90db4
Past Sponsors seemd too far away from the carousel
AbhiramTadepalli Nov 9, 2025
f82c1d4
mask fade out on intro
AbhiramTadepalli Nov 9, 2025
5723143
mb on SponsorCarousel for spacing
AbhiramTadepalli Nov 9, 2025
de2607a
Mobile NavBar v1
AbhiramTadepalli Nov 21, 2025
aeca438
feat: Make website more mobile friendly
raywa04 Nov 21, 2025
2f0f46b
feat: Revert intro comp
raywa04 Nov 21, 2025
0fbc369
feat: Add clean transitions to horizontal scroll comp
raywa04 Nov 21, 2025
9706d5c
add home screen animation
AbhiramTadepalli Jan 4, 2026
0f1a5d0
mobile hero comet animation
AbhiramTadepalli Jan 5, 2026
abe5be1
mobile alignment of hero
AbhiramTadepalli Jan 5, 2026
c12a342
generate stars based on window width
AbhiramTadepalli Jan 5, 2026
99d9fe0
mobile star distribution
AbhiramTadepalli Jan 5, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
242 changes: 186 additions & 56 deletions app/components/SponsorCarousel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,107 +2,233 @@

import { useEffect, useRef } from "react";
import Image from "next/image";
import { FaEnvelope } from "react-icons/fa";

export default function SponsorCarousel() {
const scrollRef = useRef<HTMLDivElement>(null);
const scrollRefTop = useRef<HTMLDivElement>(null);
const scrollRefBottom = useRef<HTMLDivElement>(null);
const intervalRefTop = useRef<NodeJS.Timeout | null>(null);
const intervalRefBottom = useRef<NodeJS.Timeout | null>(null);

const sponsors = [
{ name: "Snowflake", logo: "/logo.svg" },
{ name: "Intel", logo: "/logo.svg" },
{ name: "AWS", logo: "/logo.svg" },
{ name: "Oracle", logo: "/logo.svg" },
{ name: "SK Telecom", logo: "/logo.svg" },
{ name: "NVIDIA", logo: "/logo.svg" },
{ name: "Meta", logo: "/logo.svg" },
{ name: "Google", logo: "/logo.svg" },
{ name: "Microsoft", logo: "/logo.svg" },
{ name: "Apple", logo: "/logo.svg" },
{ name: "Capital One", logo: "/Logos/CapitalOne/cap1.png", url: "https://www.capitalone.com/" },
{ name: "NVIDIA", logo: "/Logos/NVIDIA/nvidia.png", url: "https://www.nvidia.com/en-us/" },
{ name: "CBRE", logo: "/Logos/CBRE/CBRE_green.png", url: "https://www.cbre.com/" },
{ name: "Cognizant", logo: "/Logos/Cognizant/CognizantLogo.png", url: "https://www.cognizant.com/us/en" },
{ name: "EOG", logo: "/Logos/EOG/EOGLogo.png", url: "https://www.eogresources.com/" },
{ name: "Goldman", logo: "/Logos/Goldman/GS_white.svg", url: "https://www.goldmansachs.com/" },
{ name: "NMC^2", logo: "/Logos/NMC^2/NMC2 Logo from HackUTD.png", url:"https://nmc2.com/" },
{ name: "PNC", logo: "/Logos/PNC/PNC Bank_OrangeGray_650x200 1.png", url: "https://www.pnc.com/en/personal-banking.html" },
{ name: "Scale", logo: "/Logos/Scale/scalelogo.png", url: "https://scale.com/" },
{ name: "State Farm", logo: "/Logos/Statefarm/SFLogo.png", url: "https://www.statefarm.com/" },
{ name: "T-Mobile", logo: "/Logos/T-Mobile/T-Badge_Icon_Ltd-Use_RGB_K_2025-03-06.png", url: "https://www.t-mobile.com/" },
{ name: "Toyota", logo: "/Logos/Toyota/Toyota Logo 2.png", url: "https://www.toyotafinancial.com/us/en.html" },
{ name: "Nord_Protect", logo: "/Logos/Nord/Color=Orange, Type=Horizontal, On=Black.png", url: "https://nordprotect.com/" },
{ name: "Nord_Incogni", logo: "/Logos/Nord/Incogni_logo_white_better_quality.png", url: "https://nordvpn.com/incogni/?srsltid=AfmBOooyevCgYKIT5Kr1xutxSdD0_cJV4WnOFErberJRV0g4-9aZroPl" },
{ name: "Nord_Pass", logo: "/Logos/Nord/NordPass-white-horizontal (2).png", url: "https://nordpass.com/" },
{ name: "Nord_Saily", logo: "/Logos/Nord/saily-logo-white (3).png", url: "https://saily.com/" },
{ name: "Nord_VPN", logo: "/Logos/Nord/NordVPN_Logo_RGB_Primary_Blue_White (1).png", url: "https://nordvpn.com/?srsltid=AfmBOopu6SjzTP8a7CtPx1NanVbn9qjjyOS0hFM_tzDs4qTSdNlyFyoF" },
];
// Duplicate the sponsors array for seamless infinite scroll
const duplicatedSponsors = [...sponsors, ...sponsors, ...sponsors];

// Split sponsors into two groups
const topRowSponsors = sponsors.slice(0, Math.ceil(sponsors.length / 2));
const bottomRowSponsors = sponsors.slice(Math.ceil(sponsors.length / 2));

// Duplicate for seamless infinite scroll
const duplicatedTopSponsors = [...topRowSponsors, ...topRowSponsors, ...topRowSponsors];
const duplicatedBottomSponsors = [...bottomRowSponsors, ...bottomRowSponsors, ...bottomRowSponsors];

// Top row - scrolls left (normal direction)
useEffect(() => {
const scrollContainer = scrollRef.current;
const scrollContainer = scrollRefTop.current;
if (!scrollContainer) return;

let animationFrameId: number;
let scrollPosition = 0;
const scrollSpeed = 0.5; // Adjust speed here (lower = slower)
const scrollSpeed = 1.0;

const animate = () => {
intervalRefTop.current = setInterval(() => {
scrollPosition += scrollSpeed;

// Reset position for infinite scroll
const maxScroll = scrollContainer.scrollWidth / 3;
if (scrollPosition >= maxScroll) {
scrollPosition = 0;
}

scrollContainer.scrollLeft = scrollPosition;
animationFrameId = requestAnimationFrame(animate);
};
}, 16);

animationFrameId = requestAnimationFrame(animate);

// Pause on hover
const handleMouseEnter = () => {
cancelAnimationFrame(animationFrameId);
return () => {
if (intervalRefTop.current !== null) {
clearInterval(intervalRefTop.current);
}
};
}, []);

const handleMouseLeave = () => {
animationFrameId = requestAnimationFrame(animate);
};
// Bottom row - scrolls right (opposite direction)
useEffect(() => {
const scrollContainer = scrollRefBottom.current;
if (!scrollContainer) return;

scrollContainer.addEventListener("mouseenter", handleMouseEnter);
scrollContainer.addEventListener("mouseleave", handleMouseLeave);
let scrollPosition = 0;
const scrollSpeed = 1.0;

intervalRefBottom.current = setInterval(() => {
scrollPosition += scrollSpeed;

const maxScroll = scrollContainer.scrollWidth / 3;
if (scrollPosition >= maxScroll) {
scrollPosition = 0;
}

// With scaleX(-1), increasing scrollLeft will make it appear to scroll right
scrollContainer.scrollLeft = scrollPosition;
}, 16);

return () => {
cancelAnimationFrame(animationFrameId);
scrollContainer.removeEventListener("mouseenter", handleMouseEnter);
scrollContainer.removeEventListener("mouseleave", handleMouseLeave);
if (intervalRefBottom.current !== null) {
clearInterval(intervalRefBottom.current);
}
};
}, []);

return (
<section className="relative py-16 md:py-24 bg-black overflow-hidden">
<div className="max-w-7xl mx-auto px-4">
<div className="flex justify-center mb-12">
<span className="inline-block px-4 py-1.5 text-xs md:text-sm font-medium text-gray-400 border border-gray-700 rounded-full uppercase tracking-wider">
<section
className="relative py-8 md:py-12 pb-20 md:pb-24 mb-0 bg-black overflow-hidden"
style={{
backgroundColor: '#000000',
zIndex: 10,
position: 'relative',
marginTop: 0,
marginBottom: 0,
}}
>
<div className="max-w-7xl mx-auto px-4 md:px-8 relative z-20" style={{ backgroundColor: '#000000' }}>
<div className="flex justify-center mb-6 md:mb-8">
<h2
className="font-inter text-xl md:text-2xl text-center font-medium text-white/60 px-4 tracking-wider uppercase"
>
Past Sponsors
</span>
</h2>
</div>

<div className="relative mb-4 md:mb-6">
<div className="absolute left-0 top-0 bottom-0 w-24 md:w-32 bg-gradient-to-r from-black via-black to-transparent z-10 pointer-events-none" />
<div className="absolute right-0 top-0 bottom-0 w-24 md:w-32 bg-gradient-to-l from-black via-black to-transparent z-10 pointer-events-none" />

<div
ref={scrollRefTop}
className="flex gap-12 md:gap-20 overflow-x-hidden scrollbar-hide py-6 md:py-8"
style={{ scrollBehavior: "auto", willChange: "scroll-position" }}
>
{duplicatedTopSponsors.map((sponsor, index) => (
<div
key={`top-${sponsor.name}-${index}`}
className="flex-shrink-0 flex items-center justify-center group"
>
<div className="relative w-56 md:w-72 h-32 md:h-40 flex items-center justify-center transition-all duration-300 group-hover:scale-110">
<div className="w-[180px] md:w-full h-full flex items-center justify-center">
<a
href={sponsor.url}
target="_blank"
rel="noopener noreferrer"
className="inline-block"
>
<Image
src={sponsor.logo}
alt={sponsor.name}
width={240}
height={120}
className="object-contain max-h-24 md:max-h-32 opacity-70 group-hover:opacity-100 transition-opacity duration-300 sponsor-logo"
style={{ maxWidth: "100%", height: "auto" }}
/>
</a>
</div>
</div>
</div>
))}
</div>
</div>

<div className="relative">
<div className="absolute left-0 top-0 bottom-0 w-24 md:w-32 bg-gradient-to-r from-black to-transparent z-10 pointer-events-none" />
<div className="absolute right-0 top-0 bottom-0 w-24 md:w-32 bg-gradient-to-l from-black to-transparent z-10 pointer-events-none" />
<div className="relative mt-4 md:mt-6">
<div className="absolute left-0 top-0 bottom-0 w-24 md:w-32 bg-gradient-to-r from-black via-black to-transparent z-10 pointer-events-none" />
<div className="absolute right-0 top-0 bottom-0 w-24 md:w-32 bg-gradient-to-l from-black via-black to-transparent z-10 pointer-events-none" />

<div
ref={scrollRef}
className="flex gap-12 md:gap-16 overflow-x-hidden scrollbar-hide py-8 md:py-12"
style={{ scrollBehavior: "auto" }}
ref={scrollRefBottom}
className="flex gap-12 md:gap-20 overflow-x-hidden scrollbar-hide py-6 md:py-8"
style={{ scrollBehavior: "auto", willChange: "scroll-position" }}
>
{duplicatedSponsors.map((sponsor, index) => (
{duplicatedBottomSponsors.map((sponsor, index) => (
<div
key={`${sponsor.name}-${index}`}
key={`bottom-${sponsor.name}-${index}`}
className="flex-shrink-0 flex items-center justify-center group"
>
<div className="relative w-40 md:w-48 h-24 md:h-32 flex items-center justify-center transition-all duration-300 group-hover:scale-110">
<div className="w-full h-full flex items-center justify-center">
<Image
src={sponsor.logo}
alt={sponsor.name}
width={160}
height={80}
className="object-contain opacity-60 group-hover:opacity-100 transition-opacity duration-300 filter grayscale group-hover:grayscale-0"
style={{ maxWidth: "100%", height: "auto" }}
/>
<div className="relative w-56 md:w-72 h-32 md:h-40 flex items-center justify-center transition-all duration-300 group-hover:scale-110">
<div className="w-[180px] md:w-full h-full flex items-center justify-center">
<a
href={sponsor.url}
target="_blank"
rel="noopener noreferrer"
className="inline-block"
>
<Image
src={sponsor.logo}
alt={sponsor.name}
width={240}
height={120}
className="object-contain max-h-24 md:max-h-32 opacity-70 group-hover:opacity-100 transition-opacity duration-300 sponsor-logo"
style={{ maxWidth: "100%", height: "auto" }}
/>
</a>
</div>
</div>
</div>
))}
</div>
</div>

<div className="mt-12 md:mt-16 flex flex-col items-center relative z-40">
<div className="max-w-2xl text-center px-4">
<h3
className="font-inter text-2xl md:text-3xl font-bold mb-4 bg-clip-text text-transparent"
style={{ backgroundImage: 'linear-gradient(to bottom right, #FF56D6 0%, #FF7AA2 35%, #FF9167 70%)' }}
>
Sponsor
</h3>
<p className="text-white/80 text-sm md:text-base leading-relaxed mb-6">
Interested in sponsoring HackUTD for our next hackathon and beyond? Get in touch with our Industry Team and learn how supporting HackUTD will benefit you!
</p>
<a
href="mailto:hello@hackutd.co?subject=HackUTD Sponsorship Inquiry&body="
className="inline-block px-6 py-3 rounded-full font-medium text-sm md:text-base transition-all duration-300 hover:scale-105 relative z-50"
style={{
background: 'linear-gradient(to right, #FF56D6, #FF9167)',
color: '#FFFFFF',
boxShadow: '0 4px 15px rgba(255, 86, 214, 0.3)',
filter: 'brightness(1)',
}}
onMouseEnter={(e) => {
e.currentTarget.style.boxShadow = '0 8px 30px rgba(255, 86, 214, 0.8), 0 0 40px rgba(255, 86, 214, 0.5)';
e.currentTarget.style.filter = 'brightness(1.2)';
e.currentTarget.style.background = 'linear-gradient(to right, #FF6FE5, #FFA67F)';
}}
onMouseLeave={(e) => {
e.currentTarget.style.boxShadow = '0 4px 15px rgba(255, 86, 214, 0.3)';
e.currentTarget.style.filter = 'brightness(1)';
e.currentTarget.style.background = 'linear-gradient(to right, #FF56D6, #FF9167)';
}}
>
<span className="flex items-center justify-center gap-2">
Get in Touch
<FaEnvelope className="w-4 h-4" />
</span>
</a>
</div>
</div>
</div>

<div className="absolute bottom-0 left-0 right-0 h-48 md:h-64 bg-gradient-to-b from-transparent via-black/40 to-black pointer-events-none z-30" />
<div className="absolute bottom-0 left-0 right-0 h-[2px] bg-gradient-to-r from-transparent via-pink-500/70 to-transparent pointer-events-none z-30 shadow-[0_0_20px_rgba(255,86,214,0.5)]" />

<style jsx>{`
.scrollbar-hide::-webkit-scrollbar {
Expand All @@ -112,6 +238,10 @@ export default function SponsorCarousel() {
-ms-overflow-style: none;
scrollbar-width: none;
}
.sponsor-logo {
filter: brightness(0) invert(1);
transition: opacity 0.3s ease;
}
`}</style>
</section>
);
Expand Down
Loading