From fe1df0f7c7c7d8d489614beb0b3af31ed26cf333 Mon Sep 17 00:00:00 2001 From: sreenidhis29 Date: Mon, 20 Apr 2026 23:18:20 +0530 Subject: [PATCH 1/5] Fix responsiveness and added date sticker --- src/index.css | 6 +-- src/sections/Hero.tsx | 99 ++++++++++++++++++++++++++++++------------- 2 files changed, 72 insertions(+), 33 deletions(-) diff --git a/src/index.css b/src/index.css index 8e5b979..796aced 100644 --- a/src/index.css +++ b/src/index.css @@ -252,7 +252,7 @@ 0 0 0 2px rgba(243, 236, 210, 0.3), 0 4px 0 #1a1a1a, 0 0 15px rgba(249, 112, 40, 0.2); - transform: rotate(-1deg); + transform: rotate(0deg); animation: datePulse 2.5s ease-in-out infinite; } @@ -339,12 +339,12 @@ 0%, 100% { - transform: rotate(-1deg) scale(1); + transform: rotate(0deg) scale(1); opacity: 1; } 50% { - transform: rotate(-1deg) scale(1.05); + transform: rotate(0deg) scale(1.05); opacity: 0.9; } } diff --git a/src/sections/Hero.tsx b/src/sections/Hero.tsx index 7de0348..7084024 100644 --- a/src/sections/Hero.tsx +++ b/src/sections/Hero.tsx @@ -65,6 +65,7 @@ export default function DevHackHeroCompact() { const card1Ref = useRef(null); const card2Ref = useRef(null); const videoFrameRef = useRef(null); + const dateStickerRef = useRef(null); useEffect(() => { gsap.registerPlugin(ScrollTrigger); @@ -77,9 +78,10 @@ export default function DevHackHeroCompact() { const card2 = card2Ref.current; const videoFrame = videoFrameRef.current; - if (!section || !baseLayer || !imagesFrame || !reveal || !card1 || !card2 || !videoFrame) { + if (!section || !baseLayer || !imagesFrame || !reveal || !card1 || !card2 || !videoFrame || !dateStickerRef.current) { return; } + const sticker = dateStickerRef.current; @@ -96,19 +98,32 @@ export default function DevHackHeroCompact() { gsap.set(videoFrame, { opacity: 1, scale: 1, - top: isMobile ? "12vh" : "0", - height: isMobile ? "50vh" : "100vh", - width: isMobile ? "90vw" : "100vw", - left: isMobile ? "50%" : "0", - xPercent: isMobile ? -50 : 0, + top: isMobile ? "75px" : "9px", + height: isMobile ? "auto" : "100vh", + width: "100vw", + left: 0, + xPercent: 0, + borderRadius: 0, }); gsap.set(baseLayer, { opacity: 1 }); - gsap.set(reveal, { + gsap.set(reveal, { + opacity: 1, + top: isMobile ? "calc(75px + 56vw + 60px)" : "100vh" + }); + gsap.set(imagesFrame, { + opacity: 0, + }); + gsap.set([card1, card2], { opacity: isMobile ? 1 : 0, - top: isMobile ? "100vh" : "0" + y: isMobile ? 0 : 50 + }); + gsap.set(sticker, { + opacity: 1, + y: 0, + top: isMobile ? "calc(75px + 56vw)" : "auto", + bottom: isMobile ? "auto" : "2rem", }); - gsap.set([card1, card2], { opacity: 0, y: 50 }); const timeline = gsap.timeline({ defaults: { ease: "none" }, @@ -126,7 +141,7 @@ export default function DevHackHeroCompact() { .to( videoFrame, { - scale: isMobile ? 1.2 : 1.8, + scale: isMobile ? 1 : 1.8, opacity: isMobile ? 1 : 0, duration: 2.0, }, @@ -135,10 +150,9 @@ export default function DevHackHeroCompact() { .to( reveal, { - top: isMobile ? "65vh" : "0", - opacity: 1, - duration: isMobile ? 3.0 : 1.5, - ease: "power2.out", + top: isMobile ? "75px" : "0", + duration: isMobile ? 4.0 : 1.5, + ease: "power2.inOut", }, 0.5 ) @@ -167,6 +181,19 @@ export default function DevHackHeroCompact() { duration: 1.5, }, isMobile ? 1.5 : 3.4 + ) + .to( + {}, + { duration: 1 } // Adds extra scroll time at the end + ) + .to( + sticker, + { + opacity: 0, + y: 20, + duration: 0.5, + }, + 0 // Starts immediately with scroll ); }, section); @@ -189,44 +216,45 @@ export default function DevHackHeroCompact() { }, []); return ( -
+
-
+
-
-
- - - -
- +
+ + {/* Restricted Scrolling Background */} +
+
+ + + +
+ +
+
-
-
- -
-
+
01

What is DevHack?

DSU DEVHACK 2026 is a national-level hackathon pushing the boundaries of innovation in AI, ML, IoT, Blockchain, Cybersecurity, and Cloud

-
+
02

Why Participate?

@@ -235,6 +263,17 @@ export default function DevHackHeroCompact() {

+ {/* Date Sticker */} +
+
+ SEPTEMBER 18TH & 19TH, 2026 +
+
+ +
From 29bfe1486cb61849b3a1cb9b11062980636dde10 Mon Sep 17 00:00:00 2001 From: sreenidhis29 Date: Mon, 20 Apr 2026 23:20:59 +0530 Subject: [PATCH 2/5] fix scroll issue ft mobile --- src/sections/Hero.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sections/Hero.tsx b/src/sections/Hero.tsx index 7084024..8a3edfb 100644 --- a/src/sections/Hero.tsx +++ b/src/sections/Hero.tsx @@ -216,7 +216,7 @@ export default function DevHackHeroCompact() { }, []); return ( -
+
From 2ea4259af7b9d9cca605e50b3b9cf8f4a0cf4509 Mon Sep 17 00:00:00 2001 From: sreenidhis29 Date: Mon, 20 Apr 2026 23:31:36 +0530 Subject: [PATCH 3/5] added submarine for vertical timeline hehe --- src/App.tsx | 6 ++-- src/sections/Timeline.tsx | 68 ++++++++++++++++++++++++++++++--------- 2 files changed, 56 insertions(+), 18 deletions(-) diff --git a/src/App.tsx b/src/App.tsx index f8c4e9b..0910027 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -100,11 +100,11 @@ function Navbar({ onNavClick }: { onNavClick: (e: React.MouseEvent - Main - Timeline + Main Themes Prizes Sponsors + Timeline FAQ )} @@ -139,10 +139,10 @@ function Navbar({ onNavClick }: { onNavClick: (e: React.MouseEvent
Main - Timeline Themes Prizes Sponsors + Timeline FAQ )} diff --git a/src/sections/Timeline.tsx b/src/sections/Timeline.tsx index 3ce9bf9..eba3db1 100644 --- a/src/sections/Timeline.tsx +++ b/src/sections/Timeline.tsx @@ -101,6 +101,42 @@ function TrainSVG({ color }: { color: string }) { ); } +/* ───────────────────────────────────── + SVG SUBMARINE ICON (FOR MOBILE) + ───────────────────────────────────── */ +function SubmarineSVG({ color }: { color: string }) { + return ( + + {/* Submarine Body (Oval/Capsule) */} + + + {/* Conning Tower */} + + {/* Periscope */} + + + {/* Portholes */} + + + + + {/* Accent Stripe */} + + + {/* Rear Propeller Handle/Base */} + + {/* Propeller Blades */} + + + ); +} + /* ───────────────────────────────────── TRACK COMPONENT ───────────────────────────────────── */ @@ -772,46 +808,48 @@ export default function Timeline() { zIndex: 40, }} > - {/* Smoke puff animation */} + {/* Puffs or Bubbles animation */}
- {/* Train body with bounce */} + {/* Vehicle body with bounce */} - + {isMobile ? : } {/* Active station name label on train */} From eb17a587b49a7775d4f62816264ee443c333c81c Mon Sep 17 00:00:00 2001 From: BeeXD Date: Tue, 21 Apr 2026 00:35:39 +0530 Subject: [PATCH 4/5] feat: complete team section UI redesign with tabs, animations, & centered layouts --- src/App.tsx | 6 +- src/components/TeamCarousel.tsx | 520 ------------------------ src/index.css | 24 ++ src/sections/Team.tsx | 679 ++++++++++++++++++-------------- 4 files changed, 403 insertions(+), 826 deletions(-) delete mode 100644 src/components/TeamCarousel.tsx diff --git a/src/App.tsx b/src/App.tsx index 0910027..f3a3f3a 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -5,7 +5,7 @@ import Hero from './sections/Hero' import Themes from './components/Themes' import Timeline from './sections/Timeline' import FAQ from './sections/FAQ' -// import Team from './sections/Team' +import Team from './sections/Team' import Prizes from './sections/Prizes' import Sponsors from './sections/Sponsors' import Footer from './sections/Footer' @@ -105,6 +105,7 @@ function Navbar({ onNavClick }: { onNavClick: (e: React.MouseEventPrizes Sponsors Timeline + Team FAQ )} @@ -143,6 +144,7 @@ function Navbar({ onNavClick }: { onNavClick: (e: React.MouseEventPrizes Sponsors Timeline + Team FAQ )} @@ -251,7 +253,7 @@ export default function App() { - {/* */} +
diff --git a/src/components/TeamCarousel.tsx b/src/components/TeamCarousel.tsx deleted file mode 100644 index edd450e..0000000 --- a/src/components/TeamCarousel.tsx +++ /dev/null @@ -1,520 +0,0 @@ -"use client"; - -import React, { useState, useCallback, useEffect } from 'react'; -import { ChevronLeft, ChevronRight } from 'lucide-react'; -import { motion, AnimatePresence, type TargetAndTransition} from 'framer-motion'; -import { cn } from '../lib/utils'; // Assuming this utility correctly merges class names - -export interface TeamMember { - id: string; - name: string; - role: string; - image: string; - bio?: string; - linkedin?: string; -} - -export interface TeamCarouselProps { - /** Array of team members */ - members: TeamMember[]; - /** Title displayed above the carousel */ - title?: string; - /** Title font size */ - titleSize?: 'sm' | 'md' | 'lg' | 'xl' | '2xl'; - /** Title color */ - titleColor?: string; - /** Background color or gradient. Overrides the default 'bg-background' class. */ - background?: string; - /** Card width in pixels */ - cardWidth?: number; - /** Card height in pixels */ - cardHeight?: number; - /** Card border radius */ - cardRadius?: number; - /** Enable/disable navigation arrows */ - showArrows?: boolean; - /** Enable/disable dots indicator */ - showDots?: boolean; - /** Enable/disable keyboard navigation */ - keyboardNavigation?: boolean; - /** Enable/disable touch/swipe navigation */ - touchNavigation?: boolean; - /** Animation duration in milliseconds */ - animationDuration?: number; - /** Auto-play interval in milliseconds (0 to disable) */ - autoPlay?: number; - /** Pause auto-play on hover */ - pauseOnHover?: boolean; - /** Number of visible cards on each side */ - visibleCards?: number; - /** Scale factor for side cards */ - sideCardScale?: number; - /** Opacity for side cards */ - sideCardOpacity?: number; - /** Apply grayscale filter to side cards */ - grayscaleEffect?: boolean; - /** Custom className for container */ - className?: string; - /** Custom className for cards */ - cardClassName?: string; - /** Custom className for title */ - titleClassName?: string; - /** Member info position */ - infoPosition?: 'bottom' | 'overlay' | 'none'; - /** Info text color */ - infoTextColor?: string; - /** Info background */ - infoBackground?: string; - /** Callback when active member changes */ - onMemberChange?: (member: TeamMember, index: number) => void; - /** Callback when card is clicked */ - onCardClick?: (member: TeamMember, index: number) => void; - /** Initial active index */ - initialIndex?: number; -} - -export const TeamCarousel: React.FC = ({ - members, - title = "OUR TEAM", - titleSize = "2xl", - titleColor = "rgba(0, 76, 255, 1)", - background, - cardWidth = 280, - cardHeight = 380, - cardRadius = 20, - showArrows = true, - showDots = true, - keyboardNavigation = true, - touchNavigation = true, - animationDuration = 800, - autoPlay = 0, - pauseOnHover = true, - visibleCards = 2, - sideCardScale = 0.9, - sideCardOpacity = 0.8, - grayscaleEffect = true, - className, - cardClassName, - titleClassName, - infoPosition = "bottom", - infoTextColor = "rgb(8, 42, 123)", - infoBackground = "transparent", - onMemberChange, - onCardClick, - initialIndex = 0, -}) => { - const [currentIndex, setCurrentIndex] = useState(initialIndex); - const [direction, setDirection] = useState(0); // 0: no movement, 1: next, -1: prev - const [touchStart, setTouchStart] = useState(0); - const [touchEnd, setTouchEnd] = useState(0); - - const totalMembers = members.length; - - const paginate = useCallback( - (newDirection: number) => { - if (totalMembers === 0) return; - setDirection(newDirection); - const nextIndex = (currentIndex + newDirection + totalMembers) % totalMembers; - setCurrentIndex(nextIndex); - onMemberChange?.(members[nextIndex], nextIndex); - }, - [currentIndex, totalMembers, members, onMemberChange] - ); - - const wrapIndex = (index: number) => { - return (index + totalMembers) % totalMembers; - }; - - const calculatePosition = (index: number) => { - const activeIndex = currentIndex; - const diff = wrapIndex(index - activeIndex); - - if (diff === 0) return 'center'; - - const half = Math.floor(totalMembers / 2); - - if (diff <= half) { - if (diff <= visibleCards) return `right-${diff}`; - return 'hidden'; - } else { - const leftDiff = totalMembers - diff; - if (leftDiff <= visibleCards) return `left-${leftDiff}`; - return 'hidden'; - } - }; - - // Explicitly type the return of getVariantStyles to match framer-motion's expectations - const getVariantStyles = (position: string): TargetAndTransition => { - // FIX: Changed ease from number[] to an array of string presets or a valid CubicBezier type - // Using string presets for simplicity and type compatibility. - // If you need the exact cubic-bezier values, ensure they are compatible with framer-motion's Easing type. - // For custom cubic-bezier, you might need to use a type assertion like `as [number, number, number, number]` - // or import CubicBezier from 'framer-motion/types/value/types'. - const transition = { - duration: animationDuration / 1000, - // You can use a string preset like 'easeInOut' or a valid cubic-bezier array if framer-motion's types support it directly - // For the given numbers, 'easeInOut' is a close approximation or 'cubic-bezier(0.25, 0.46, 0.45, 0.94)' if framer-motion accepted it directly as string - // To strictly match [0.25, 0.46, 0.45, 0.94], framer-motion expects it as a CubicBezier tuple: - ease: [0.25, 0.46, 0.45, 0.94] as [number, number, number, number], - }; - - switch (position) { - case 'center': - return { - zIndex: 10, - opacity: 1, - scale: 1.1, - x: 0, - filter: 'grayscale(0%)', - pointerEvents: 'auto', - transition, - }; - case 'right-1': - return { - zIndex: 5, - opacity: sideCardOpacity, - scale: sideCardScale, - x: cardWidth * 0.7, - filter: grayscaleEffect ? 'grayscale(100%)' : 'grayscale(0%)', - pointerEvents: 'auto', - transition, - }; - case 'right-2': - return { - zIndex: 1, - opacity: sideCardOpacity * 0.7, - scale: sideCardScale * 0.9, - x: cardWidth * 1.4, - filter: grayscaleEffect ? 'grayscale(100%)' : 'grayscale(0%)', - pointerEvents: 'auto', - transition, - }; - case 'left-1': - return { - zIndex: 5, - opacity: sideCardOpacity, - scale: sideCardScale, - x: -cardWidth * 0.7, - filter: grayscaleEffect ? 'grayscale(100%)' : 'grayscale(0%)', - pointerEvents: 'auto', - transition, - }; - case 'left-2': - return { - zIndex: 1, - opacity: sideCardOpacity * 0.7, - scale: sideCardScale * 0.9, - x: -cardWidth * 1.4, - filter: grayscaleEffect ? 'grayscale(100%)' : 'grayscale(0%)', - pointerEvents: 'auto', - transition, - }; - default: - return { - zIndex: 0, - opacity: 0, - scale: 0.8, - x: direction > 0 ? cardWidth * (visibleCards + 1) : -cardWidth * (visibleCards + 1), - pointerEvents: 'none', - filter: grayscaleEffect ? 'grayscale(100%)' : 'grayscale(0%)', - transition, - }; - } - }; - - // Auto-play functionality - useEffect(() => { - let interval: ReturnType; - if (autoPlay > 0) { - interval = setInterval(() => { - paginate(1); - }, autoPlay); - } - - const carouselContainer = document.getElementById('team-carousel-container'); - - const handleMouseEnter = () => { - if (pauseOnHover && autoPlay > 0) clearInterval(interval); - }; - - const handleMouseLeave = () => { - if (pauseOnHover && autoPlay > 0) { - interval = setInterval(() => { - paginate(1); - }, autoPlay); - } - }; - - if (carouselContainer && pauseOnHover && autoPlay > 0) { - carouselContainer.addEventListener('mouseenter', handleMouseEnter); - carouselContainer.addEventListener('mouseleave', handleMouseLeave); - } - - return () => { - clearInterval(interval); - if (carouselContainer && pauseOnHover && autoPlay > 0) { - carouselContainer.removeEventListener('mouseenter', handleMouseEnter); - carouselContainer.removeEventListener('mouseleave', handleMouseLeave); - } - }; - }, [autoPlay, paginate, pauseOnHover]); - - // Keyboard navigation - useEffect(() => { - if (!keyboardNavigation) return; - - const handleKeyDown = (e: KeyboardEvent) => { - if (e.key === 'ArrowLeft') { - paginate(-1); - } else if (e.key === 'ArrowRight') { - paginate(1); - } - }; - - document.addEventListener('keydown', handleKeyDown); - return () => document.removeEventListener('keydown', handleKeyDown); - }, [keyboardNavigation, paginate]); - - // Touch navigation - const handleTouchStart = (e: React.TouchEvent) => { - if (!touchNavigation) return; - setTouchStart(e.targetTouches[0].clientX); - }; - - const handleTouchMove = (e: React.TouchEvent) => { - if (!touchNavigation) return; - setTouchEnd(e.targetTouches[0].clientX); - }; - - const handleTouchEnd = () => { - if (!touchNavigation) return; - - const swipeThreshold = 50; - const diff = touchStart - touchEnd; - - if (Math.abs(diff) > swipeThreshold) { - if (diff > 0) { - paginate(1); - } else { - paginate(-1); - } - } - }; - - const titleSizeClasses = { - sm: 'text-4xl', - md: 'text-5xl', - lg: 'text-6xl', - xl: 'text-7xl', - '2xl': 'text-8xl', - }; - - return ( - - ); -}; - -export default TeamCarousel; diff --git a/src/index.css b/src/index.css index 796aced..4a903fc 100644 --- a/src/index.css +++ b/src/index.css @@ -428,4 +428,28 @@ 100% { background-size: 1ch 100%, 1ch 100%, 1ch 100%, 1ch 100%, 1ch 100%, 1ch 100%, 1ch 100%, 1ch 100%, 1ch 100%, 1ch 100%, 1ch 100% } +} + +@keyframes spinY { + from { + transform: rotateY(0deg); + } + to { + transform: rotateY(360deg); + } +} + +.animate-spin-y { + animation: spinY 3s linear infinite; +} + +.coin { + width: 24px; + height: 24px; + border-radius: 50%; + border: 2px solid #1a1a1a; + background: linear-gradient(135deg, #f3a20f, #f97028); + box-shadow: inset -2px -2px 0px rgba(0,0,0,0.2), 2px 2px 0px #1a1a1a; + display: inline-block; + margin: 0 8px; } \ No newline at end of file diff --git a/src/sections/Team.tsx b/src/sections/Team.tsx index a18c19b..cf44fca 100644 --- a/src/sections/Team.tsx +++ b/src/sections/Team.tsx @@ -1,348 +1,419 @@ import { useState } from 'react'; import { motion, AnimatePresence } from 'framer-motion'; -import TeamCarousel from '../components/TeamCarousel'; +// --- Types --- interface TeamMember { id: string; name: string; role: string; bio?: string; image: string; + twitter?: string; linkedin?: string; } -// ── Main tabs ── -const mainTabs = ['Organizing Team', 'Patrons', 'Faculty', 'Judges'] as const; -type MainTab = (typeof mainTabs)[number]; - -// ── Sub-tabs (under "Meet the Entire Team") ── -const subTabs = ['Web Team', 'Design Team', 'Marketing Team', 'Sponsorship Team'] as const; -type SubTab = (typeof subTabs)[number]; - -// ── Data ── -const organizingTeam: TeamMember[] = [ - { - id: 'org-1', - name: 'Dr. Bipin Kumar Rai', - role: 'Faculty Coordinator', - bio: 'Professor, CSE', - image: - 'https://images.unsplash.com/photo-1507003211169-0a1dd7228f2d?auto=format&fit=crop&w=400&q=80', - }, - { - id: 'org-2', - name: 'Utkarsh Priye Jha', - role: 'Student Coordinator', - image: - 'https://images.unsplash.com/photo-1599566150163-29194dcaad36?auto=format&fit=crop&w=400&q=80', - }, - { - id: 'org-3', - name: 'Ritvik Vasundh', - role: 'Student Coordinator', - image: - 'https://images.unsplash.com/photo-1500648767791-00dcc994a43e?auto=format&fit=crop&w=400&q=80', - }, +// --- Data --- + +const chiefPatrons: TeamMember[] = [ + { id: 'cp1', name: 'Dr. D. Hemachandra Sagar', role: 'Chancellor, DSU', image: 'https://images.unsplash.com/photo-1556157382-97eda2d62296?auto=format&fit=crop&w=400&q=80' }, + { id: 'cp2', name: 'Dr. D. Premachandra Sagar', role: 'Pro Chancellor, DSU', image: 'https://images.unsplash.com/photo-1557862921-37829c790f19?auto=format&fit=crop&w=400&q=80' }, ]; const patrons: TeamMember[] = [ - { - id: 'pat-1', - name: 'Prof. Ramesh Gupta', - role: 'Patron', - bio: 'Director', - image: - 'https://images.unsplash.com/photo-1472099645785-5658abf4ff4e?auto=format&fit=crop&w=400&q=80', - }, - { - id: 'pat-2', - name: 'Dr. Meena Sharma', - role: 'Co-Patron', - bio: 'Dean, Engineering', - image: - 'https://images.unsplash.com/photo-1438761681033-6461ffad8d80?auto=format&fit=crop&w=400&q=80', - }, + { id: 'p1', name: 'Dr. B. S. Satyanarayana', role: 'Vice Chancellor, DSU', image: 'https://images.unsplash.com/photo-1560250097-0b93528c311a?auto=format&fit=crop&w=400&q=80' }, + { id: 'p2', name: 'Prof. R Janardhan', role: 'Pro Vice Chancellor, DSU', image: 'https://images.unsplash.com/photo-1500648767791-00dcc994a43e?auto=format&fit=crop&w=400&q=80' }, + { id: 'p3', name: 'Dr. Prakash S', role: 'Pro Vice Chancellor, DSU', image: 'https://images.unsplash.com/photo-1472099645785-5658abf4ff4e?auto=format&fit=crop&w=400&q=80' }, + { id: 'p4', name: 'Dr. C.Puttamadapappa', role: 'Registrar, DSU', image: 'https://images.unsplash.com/photo-1599566150163-29194dcaad36?auto=format&fit=crop&w=400&q=80' }, + { id: 'fac1', name: 'Dr.Udaya Kumar Reddy K.R', role: 'Professor & Dean-SoE', image: 'https://images.unsplash.com/photo-1494790108377-be9c29b29330?auto=format&fit=crop&w=400&q=80' }, + { id: 'fac2', name: 'Dr. Girisha G S', role: 'Chairperson, CSE', image: 'https://images.unsplash.com/photo-1507003211169-0a1dd7228f2d?auto=format&fit=crop&w=400&q=80' } ]; -const faculty: TeamMember[] = [ - { - id: 'fac-1', - name: 'Dr. Anjali Verma', - role: 'Faculty Advisor', - bio: 'HoD, CSE', - image: - 'https://images.unsplash.com/photo-1494790108377-be9c29b29330?auto=format&fit=crop&w=400&q=80', - }, - { - id: 'fac-2', - name: 'Dr. Vikram Patel', - role: 'Faculty Advisor', - bio: 'Associate Professor', - image: - 'https://images.unsplash.com/photo-1507003211169-0a1dd7228f2d?auto=format&fit=crop&w=400&q=80', - }, +const judges: TeamMember[] = [ + { id: 'j1', name: 'Arjun Mehta', role: 'CTO, TechCorp', image: 'https://images.unsplash.com/photo-1599566150163-29194dcaad36?auto=format&fit=crop&w=400&q=80' }, + { id: 'j2', name: 'Sneha Iyer', role: 'VP Engineering, InnoSoft', image: 'https://images.unsplash.com/photo-1494790108377-be9c29b29330?auto=format&fit=crop&w=400&q=80' }, ]; -const judges: TeamMember[] = [ - { - id: 'jud-1', - name: 'Arjun Mehta', - role: 'Industry Expert', - bio: 'CTO, TechCorp', - image: - 'https://images.unsplash.com/photo-1599566150163-29194dcaad36?auto=format&fit=crop&w=400&q=80', - }, - { - id: 'jud-2', - name: 'Sneha Iyer', - role: 'Industry Expert', - bio: 'VP Engineering, InnoSoft', - image: - 'https://images.unsplash.com/photo-1494790108377-be9c29b29330?auto=format&fit=crop&w=400&q=80', - }, +const coreTeam: TeamMember[] = [ + { id: '0', name: 'Dr. Bipin Kumar Rai', role: 'Faculty Coordinator', image: 'https://images.unsplash.com/photo-1507003211169-0a1dd7228f2d?auto=format&fit=crop&w=400&q=80' }, + { id: '1', name: 'Trisha', role: 'Student Co ordinator', image: 'https://api.dicebear.com/9.x/pixel-art/svg?seed=Trisha' }, + { id: '2', name: 'S Shreenidhi', role: 'Student Co ordinator', image: 'https://api.dicebear.com/9.x/pixel-art/svg?seed=Shreenidhi' }, ]; -const subTeams: Record = { - 'Web Team': [ - { - id: 'web-1', - name: 'Sachin Baluragi', - role: 'Web Team Co-Head', - image: - 'https://images.unsplash.com/photo-1599566150163-29194dcaad36?auto=format&fit=crop&w=400&q=80', - }, - { - id: 'web-2', - name: 'S Shreenidhi', - role: 'Web Dev', - image: - 'https://images.unsplash.com/photo-1507003211169-0a1dd7228f2d?auto=format&fit=crop&w=400&q=80', - }, - { - id: 'web-3', - name: 'G Nithesh', - role: 'Web Dev', - image: - 'https://images.unsplash.com/photo-1500648767791-00dcc994a43e?auto=format&fit=crop&w=400&q=80', - }, - { - id: 'web-4', - name: 'Manavi P', - role: 'Web Dev', - image: - 'https://images.unsplash.com/photo-1438761681033-6461ffad8d80?auto=format&fit=crop&w=400&q=80', - }, - ], - 'Design Team': [ - { - id: 'des-1', - name: 'Priya Nair', - role: 'Design Lead', - image: - 'https://images.unsplash.com/photo-1494790108377-be9c29b29330?auto=format&fit=crop&w=400&q=80', - }, - { - id: 'des-2', - name: 'Raj Kulkarni', - role: 'UI Designer', - image: - 'https://images.unsplash.com/photo-1472099645785-5658abf4ff4e?auto=format&fit=crop&w=400&q=80', - }, - ], - 'Marketing Team': [ - { - id: 'mkt-1', - name: 'Ananya Das', - role: 'Marketing Lead', - image: - 'https://images.unsplash.com/photo-1438761681033-6461ffad8d80?auto=format&fit=crop&w=400&q=80', - }, - { - id: 'mkt-2', - name: 'Karthik Rao', - role: 'Content Writer', - image: - 'https://images.unsplash.com/photo-1500648767791-00dcc994a43e?auto=format&fit=crop&w=400&q=80', - }, - ], - 'Sponsorship Team': [ - { - id: 'spo-1', - name: 'Divya Hegde', - role: 'Sponsorship Lead', - image: - 'https://images.unsplash.com/photo-1494790108377-be9c29b29330?auto=format&fit=crop&w=400&q=80', - }, - { - id: 'spo-2', - name: 'Nihal Khan', - role: 'Sponsorship Associate', - image: - 'https://images.unsplash.com/photo-1599566150163-29194dcaad36?auto=format&fit=crop&w=400&q=80', - }, - ], -}; - -// ── Helpers ── -function getMembersForMainTab(tab: MainTab): TeamMember[] { - switch (tab) { - case 'Organizing Team': - return organizingTeam; - case 'Patrons': - return patrons; - case 'Faculty': - return faculty; - case 'Judges': - return judges; - } -} +const subHeads: TeamMember[] = [ + { id: '3', name: 'Manavi P', role: 'Web Team Lead', image: 'https://api.dicebear.com/9.x/pixel-art/svg?seed=Manavi' }, + { id: '4', name: 'Raksha', role: 'Design Team Lead', image: 'https://api.dicebear.com/9.x/pixel-art/svg?seed=Raksha' }, + { id: '5', name: 'Aastha', role: 'Sponsorship Team Co Lead', image: 'https://api.dicebear.com/9.x/pixel-art/svg?seed=Aastha' }, + { id: '6', name: 'Nishchal Gowda R', role: 'Marketing and Media Lead', image: 'https://api.dicebear.com/9.x/pixel-art/svg?seed=Nishchal' }, + { id: '7', name: 'G Nithesh', role: 'Web Co Lead & Ops Lead', image: 'https://api.dicebear.com/9.x/pixel-art/svg?seed=Nithesh' }, +]; -function getMainTabTitle(tab: MainTab): string { - switch (tab) { - case 'Organizing Team': - return 'Organising Team'; - case 'Patrons': - return 'Patrons'; - case 'Faculty': - return 'Faculty'; - case 'Judges': - return 'Judges'; - } +const theOperators: TeamMember[] = [ + { id: 'w1', name: 'Omkar G K', role: 'Web Team', image: 'https://api.dicebear.com/9.x/pixel-art/svg?seed=Omkar' }, + { id: 'w2', name: 'Supraj U Sivajji', role: 'Web Team', image: 'https://api.dicebear.com/9.x/pixel-art/svg?seed=Supraj' }, + { id: 'd1', name: 'Moulika', role: 'Design Team', image: 'https://api.dicebear.com/9.x/pixel-art/svg?seed=Moulika' }, + { id: 'd2', name: 'Moulya', role: 'Design Team', image: 'https://api.dicebear.com/9.x/pixel-art/svg?seed=Moulya' }, + { id: 'd3', name: 'Hridya', role: 'Design Team', image: 'https://api.dicebear.com/9.x/pixel-art/svg?seed=Hridya' }, + { id: 's1', name: 'Naman Sharaff', role: 'Sponsorship Team', image: 'https://api.dicebear.com/9.x/pixel-art/svg?seed=Naman' }, + { id: 's2', name: 'Thathagath', role: 'Sponsorship Team', image: 'https://api.dicebear.com/9.x/pixel-art/svg?seed=Thathagath' }, +]; + +const facultyCoordinator: TeamMember[] = [ + { id: 'fc1', name: 'Dr. Bipin Kumar Rai', role: 'Faculty Coordinator - Professor, CSE', image: 'https://images.unsplash.com/photo-1507003211169-0a1dd7228f2d?auto=format&fit=crop&w=400&q=80' } +]; + +const facultyOrganizers: TeamMember[] = [ + { id: 'fo1', name: 'Dr. Meenakshi Malhotra', role: 'Associate Professor', image: 'https://images.unsplash.com/photo-1494790108377-be9c29b29330?auto=format&fit=crop&w=400&q=80' }, + { id: 'fo2', name: 'Dr. Sivananda Reddy', role: 'Associate Professor', image: 'https://images.unsplash.com/photo-1507003211169-0a1dd7228f2d?auto=format&fit=crop&w=400&q=80' }, + { id: 'fo3', name: 'Prof. Bharath M B', role: 'Assistant Professor', image: 'https://images.unsplash.com/photo-1500648767791-00dcc994a43e?auto=format&fit=crop&w=400&q=80' }, + { id: 'fo4', name: 'Prof. Dharmendra D P', role: 'Assistant Professor', image: 'https://images.unsplash.com/photo-1560250097-0b93528c311a?auto=format&fit=crop&w=400&q=80' }, + { id: 'fo5', name: 'Dr. Kumar Dilip', role: 'Associate Professor', image: 'https://images.unsplash.com/photo-1472099645785-5658abf4ff4e?auto=format&fit=crop&w=400&q=80' }, + { id: 'fo6', name: 'Prof. Yashaswini H C', role: 'Assistant Professor', image: 'https://images.unsplash.com/photo-1599566150163-29194dcaad36?auto=format&fit=crop&w=400&q=80' }, + { id: 'fo7', name: 'Dr. Shreekant Salotagi', role: 'Assistant Professor', image: 'https://images.unsplash.com/photo-1507003211169-0a1dd7228f2d?auto=format&fit=crop&w=400&q=80' }, + { id: 'fo8', name: 'Prof. Smriti Bharti', role: 'Assistant Professor', image: 'https://images.unsplash.com/photo-1494790108377-be9c29b29330?auto=format&fit=crop&w=400&q=80' }, + { id: 'fo9', name: 'Prof. Shivani', role: 'Assistant Professor', image: 'https://images.unsplash.com/photo-1556157382-97eda2d62296?auto=format&fit=crop&w=400&q=80' }, + { id: 'fo10', name: 'Dr Naitik ST', role: 'Assistant Professor', image: 'https://images.unsplash.com/photo-1500648767791-00dcc994a43e?auto=format&fit=crop&w=400&q=80' }, + { id: 'fo11', name: 'Dr. Pannangi Naresh', role: 'Assistant Professor', image: 'https://images.unsplash.com/photo-1560250097-0b93528c311a?auto=format&fit=crop&w=400&q=80' }, +]; + +// --- Sub-components --- + +function CoinDivider() { + return ( +
+
+
+ {[...Array(8)].map((_, i) => ( +
+ ))} +
+
+ ); } -// ── Pill Tab Bar ── -function TabBar({ - tabs, - active, - onChange, - accentColor, -}: { - tabs: readonly T[]; - active: T; - onChange: (tab: T) => void; - accentColor?: string; -}) { - const accent = accentColor ?? '#f97028'; +function TeamCard({ member, onClickBio }: { member: TeamMember, onClickBio: (m: TeamMember) => void }) { + const [isHovered, setIsHovered] = useState(false); + return ( -
- {tabs.map((tab) => { - const isActive = tab === active; - return ( + setIsHovered(true)} + onMouseLeave={() => setIsHovered(false)} + onClick={() => onClickBio(member)} + > + {/* Corner Rivets */} + {[ + { top: 4, left: 4 } as React.CSSProperties, + { top: 4, right: 4 } as React.CSSProperties, + { bottom: 4, left: 4 } as React.CSSProperties, + { bottom: 4, right: 4 } as React.CSSProperties, + ].map((pos, ri) => ( +
+ ))} + + {/* Image Box */} +
+ {/* Scanline overlay */} +
+ {member.name} +
+ + {/* Details Box */} +
+

+ {member.name} +

+

{member.role}

+ +
- ); - })} -
+
+
+ ); } -// ── Main Section ── export default function Team() { - const [activeMainTab, setActiveMainTab] = useState('Organizing Team'); - const [activeSubTab, setActiveSubTab] = useState('Web Team'); + const [selectedBio, setSelectedBio] = useState(null); + const [activeTab, setActiveTab] = useState('Organising Team'); - const mainMembers = getMembersForMainTab(activeMainTab); - const sectionTitle = getMainTabTitle(activeMainTab); + const TABS = ['Organising Team', 'The Board', 'Faculty', 'Jury & Experts']; + + if (selectedBio) { + if (typeof window !== 'undefined') document.body.style.overflow = 'hidden'; + } else { + if (typeof window !== 'undefined') document.body.style.overflow = 'auto'; + } return ( -
- {/* ── Main Tab Bar ── */} -
- { - setActiveMainTab(t); - // Reset sub-tab when switching - setActiveSubTab('Web Team'); - }} - accentColor="#f97028" - /> -
+
+
- {/* ── Section Title ── */} -

- {sectionTitle} -

- - {/* ── Main Tab Carousel ── */} - - - - - + {/* Header block condtionally rendered */} + + {activeTab === 'Organising Team' && ( + +
+

+ + Meet The + + + Team + +

+

+ We back the dreamers, the builders, and the rebels. The architectural minds behind DevHack 3.0. +

+
+
+ )} +
- {/* ── "Meet the Entire Team" — only under Organizing Team ── */} - {activeMainTab === 'Organizing Team' && ( - -

+ {TABS.map((tab) => ( + + ))} +

+ + {/* Tab Content */} + + + {activeTab === 'Organising Team' && ( +
+
+

Core Team

+
+ {coreTeam.map((member) => ( + + ))} +
+
+ +
+ +
+ +
+

Sub Heads

+
+ {subHeads.map((member) => ( + + ))} +
+
+ +
+ +
+ +
+

Operating Partners

+
+ {theOperators.map((member) => ( + + ))} +
+
+
+ )} + + {activeTab === 'The Board' && ( +
+
+

Chief Patrons

+
+ {chiefPatrons.map((member) => ( + + ))} +
+
+ +
+ +
+ +
+

Patrons

+
+ {patrons.map((member) => ( + + ))} +
+
+
+ )} + + {activeTab === 'Faculty' && ( +
+
+

Faculty Coordinator

+
+ {facultyCoordinator.map((member) => ( + + ))} +
+
+ +
+ +
+ +
+

Organising Team Members

+
+ {facultyOrganizers.map((member) => ( + + ))} +
+
+
+ )} + + {activeTab === 'Jury & Experts' && ( +
+

Jury & Experts

+
+ {judges.map((member) => ( + + ))} +
+
+ )} +
+
+ + {/* Decorative Divider */} +
+ +
+ +
+ + {/* Bio Modal Pop-in */} + + {selectedBio && ( + setSelectedBio(null)} > - Meet the Entire Team - - - {/* Sub-tab bar */} -
- -
- - {/* Sub-tab Carousel */} - e.stopPropagation()} > - + + +

+ {selectedBio.name} +

+

+ {selectedBio.role} +

+ +
+ +

+ {selectedBio.bio || "No bio available right now. Currently busy building the future."} +

+ + - - - )} + + )} +
); } From fd9dc1f363c9a032ac598b7ae5c4e09bdc5a78a8 Mon Sep 17 00:00:00 2001 From: BeeXD Date: Thu, 23 Apr 2026 00:50:35 +0530 Subject: [PATCH 5/5] feat: redesign themes and team sections with mobile responsiveness and groovy font --- CHANGELOG.md | 28 +++ src/components/Themes.tsx | 490 ++++++++++++++++++-------------------- src/index.css | 11 +- src/sections/Team.tsx | 285 ++++++++++++---------- 4 files changed, 429 insertions(+), 385 deletions(-) create mode 100644 CHANGELOG.md diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..4534b9e --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,28 @@ +# Changelog + +All notable changes to this project will be documented in this file. + +## [Unreleased] + +### Added +- Added `.no-scrollbar` utility class in `src/index.css` to enable smooth horizontal scrolling without visible scrollbars for mobile tab navigation. +- Added `Fredoka` font (a modern groovy font) to replace the previous display font on Theme card titles. +- Added a "Team Members" toggle button with a spring-animated chevron that smoothly reveals the "Operating Partners" grid underneath the "Sub Heads" section. + +### Changed +- **Themes Section**: + - Overhauled interaction: Replaced "click-to-view" modal system with an inline smooth dropdown (hover on desktop, tap on mobile/tablet). + - Cleaned up titles: Removed legacy "2026", "Theme XX" numbering labels. + - Renamed "IOT & Smart Cities" theme to **"IOT & Sustainability"** and updated tags (added GreenTech). + - Renamed "Web3 / Sustain" theme to **"Blockchain & Fintech"** with an updated description, updated emoji to `🔗`, and tags to `Smart Contracts`, `DeFi`, `Fintech`, `Crypto`. + - Updated card titles font-weight to `normal` (400) mapping to the `Fredoka` groovy font design. +- **Team Section Header**: Replaced the slide-in (`x: ±300`) animation with a bulletproof fade-up (`y: 30 → 0`) animation to prevent the "Meet The Team" heading from clipping completely off-screen on constrained mobile displays due to `overflow-hidden`. +- **Team Section Layout**: Integrated proper CSS grid configuration (`grid-cols-2` mobile, `grid-cols-3` tablet, `grid-cols-4` desktop) over the previous fixed-width wrapping implementation. +- **Team Section Responsiveness**: + - Adjusted container to `w-[92%]` on tablet and correctly incremented padding (`px-5`, `px-6`) so the retro shadow offsets (`10px_10px`, `16px_16px`) no longer clip via the responsive bounds. + - Sub-headings now safely `clamp` sizing alongside smaller card text metrics to avoid horizontal scrollbar lock. + - Active Tab Button CSS explicitly utilizes inline style coloring (`#f3ecd2`) overriding systemic tailwind specificity cascading rendering the default black rectangle bug. + +### Removed +- Removed the standalone "Operating Partners" tab grouping, integrating it as a sub-collapse element under "Sub Heads". +- Removed hardcoded margins and large scale fonts causing overflow clipping from mobile versions (e.g., swapped `text-6xl` to `clamp(2rem, 7vw, 6rem)`). diff --git a/src/components/Themes.tsx b/src/components/Themes.tsx index 8c0f293..20bc842 100644 --- a/src/components/Themes.tsx +++ b/src/components/Themes.tsx @@ -17,76 +17,62 @@ export type Theme = { title: string; desc: string; tags: string[]; - rotate: string; - year: string; }; const themes: Theme[] = [ { id: 1, emoji: '🤖', - color: '#f97028', // Orange - bg: '#fffdf9', // Very light cream - title: 'AI ML', + color: '#f97028', + bg: '#fffdf9', + title: 'AI / ML', desc: 'Build intelligent systems, chatbots, predictive models, and generative AI tools that think, learn, and adapt.', tags: ['LLMs', 'Computer Vision', 'NLP', 'Deep Learning'], - rotate: '-3deg', - year: '2026', }, { id: 2, emoji: '🧠', - color: '#f489a3', // Pink + color: '#f489a3', bg: '#fffdf9', title: 'Agentic AI', desc: 'Develop autonomous agents that can plan, reason, and execute complex workflows without human intervention.', tags: ['Autonomous Agents', 'Reasoning', 'Workflows', 'Multi-Agent'], - rotate: '2deg', - year: '2026', }, { id: 3, emoji: '📡', - color: '#f3a20f', // Yellow/Gold + color: '#f3a20f', bg: '#fffdf9', - title: 'IOT & Smart Cities', - desc: 'Bridge physical and digital worlds with embedded systems, sensor networks, edge intelligence, and urban tech.', - tags: ['Embedded', 'Edge AI', 'Sensors', 'Urban Tech'], - rotate: '-2deg', - year: '2026', + title: 'IOT & Sustainability', + desc: 'Bridge physical and digital worlds with embedded systems, sensor networks, edge intelligence, and sustainable tech solutions.', + tags: ['Embedded', 'Edge AI', 'Sensors', 'GreenTech'], }, { id: 4, emoji: '⚕️', - color: '#4ade80', // Green + color: '#4ade80', bg: '#fffdf9', title: 'Healthcare', desc: 'Revolutionise patient care and medical research with modern health-tech, accessibility tools, and data analysis.', tags: ['HealthAI', 'Telemed', 'Accessibility', 'Bioinformatics'], - rotate: '3deg', - year: '2026', }, { id: 5, - emoji: '🌐', - color: '#22d3ee', // Cyan + emoji: '🔗', + color: '#22d3ee', bg: '#fffdf9', - title: 'Web3 / Sustain', - desc: 'Decentralise the future and protect the planet — DeFi protocols, DAOs, green-tech, and sustainable innovation.', - tags: ['Smart Contracts', 'DeFi', 'GreenTech', 'NFTs'], - rotate: '-1deg', - year: '2026', + title: 'Blockchain & Fintech', + desc: 'Build the future of finance and trust — decentralised protocols, smart contracts, digital payments, and financial innovation.', + tags: ['Smart Contracts', 'DeFi', 'Fintech', 'Crypto'], }, { id: 6, emoji: '💡', - color: '#a855f7', // Purple + color: '#a855f7', bg: '#fffdf9', title: 'Open Innovation', - desc: 'No boundaries. Build whatever crazy, groundbreaking idea you have that doesn’t fit into a box.', + desc: 'No boundaries. Build whatever crazy, groundbreaking idea you have that doesn\'t fit into a box.', tags: ['Moonshots', 'Creative', 'Anything Goes', 'Wildcard'], - rotate: '2deg', - year: '2026', }, ]; @@ -94,202 +80,192 @@ const containerVariants: Variants = { hidden: {}, visible: { transition: { - staggerChildren: 0.1, + staggerChildren: 0.12, }, }, }; const cardVariants: Variants = { - hidden: { opacity: 0, y: 40, scale: 0.95 }, + hidden: { opacity: 0, y: 50, scale: 0.92 }, visible: { opacity: 1, y: 0, scale: 1, transition: { type: 'spring', - stiffness: 90, - damping: 15, + stiffness: 80, + damping: 16, }, }, }; -function ThemeCard({ theme, onClick }: { theme: Theme; onClick: () => void }) { +/** Returns true when viewport is below the given px width */ +function useIsMobile(breakpoint = 1024) { + const [isMobile, setIsMobile] = useState(false); + useEffect(() => { + const mql = window.matchMedia(`(max-width: ${breakpoint}px)`); + const update = () => setIsMobile(mql.matches); + update(); + mql.addEventListener('change', update); + return () => mql.removeEventListener('change', update); + }, [breakpoint]); + return isMobile; +} + +function ThemeCard({ theme, isMobile }: { theme: Theme; isMobile: boolean }) { + const [isOpen, setIsOpen] = useState(false); + + // On desktop: hover controls reveal; on mobile: tap toggles + const showContent = isMobile ? isOpen : isOpen; + return ( { if (!isMobile) setIsOpen(true); }} + onHoverEnd={() => { if (!isMobile) setIsOpen(false); }} + onClick={() => { if (isMobile) setIsOpen((v) => !v); }} + className="relative w-full cursor-pointer" > - {/* Outer wrapper provides the thick colorful border */} -
- {/* Top-left subtle branding / corner decoration if desired */} -
- - Theme {theme.id < 10 ? `0${theme.id}` : theme.id} -
- - {/* Central Graphic (Emoji) */} -
- - {theme.emoji} - -
- - {/* The bottom-right Cutout/Tab mimicking Lando Norris helmet view */} + {/* Accent stripe at top */}
- - {theme.title} {theme.year} - -
+ className="w-full h-[6px]" + style={{ backgroundColor: theme.color }} + /> - {/* Hover overlay hint */} -
- - Click to View - -
-
-
- ); -} - -// ── Shared Modal component ── -function ThemeModal({ theme, onClose }: { theme: Theme; onClose: () => void }) { - // Prevent scrolling when modal is open - useEffect(() => { - document.body.style.overflow = 'hidden'; - return () => { - document.body.style.overflow = 'unset'; - }; - }, []); - - return ( -
- {/* Backdrop */} - - - {/* Modal Content Wrapper */} - - {/* Sticky Header for Close Button on Mobile */} -
- -
- - {/* Scrollable Content Container */} -
- {/* Left Side (Visuals) */} -
+
+ {/* Emoji + Title row — always visible */} +
- {theme.emoji} + {theme.emoji} -
- 0{theme.id} +
+

+ {theme.title} +

-
- {/* Right Side (Details) */} -
-
- - Domain -
+ {/* Tap indicator on mobile/tablet */} + {isMobile && ( + + + + + + )} +
-

- {theme.title} -

+ {/* Dropdown content — smooth reveal */} + + {showContent && ( + + {/* Divider */} +
-

- {theme.desc} -

+ {/* Description */} +

+ {theme.desc} +

-
-

Key Focus Areas

-
- {theme.tags.map((tag) => ( - - {tag} - - ))} -
-
-
+ {/* Tags */} +
+ {theme.tags.map((tag) => ( + + {tag} + + ))} +
+
+ )} +
+ + {/* Bottom accent bar */} + -
+ ); } export default function Themes() { const sectionRef = useRef(null); const headingRef = useRef(null); - - const [selectedTheme, setSelectedTheme] = useState(null); + const isMobile = useIsMobile(1024); const isInView = useInView(sectionRef, { once: true, margin: '-10% 0px' }); @@ -304,90 +280,90 @@ export default function Themes() { const blobY2 = useTransform(smoothY, [0, 1], [0, 80]); return ( - <> -
+ {/* Decorative background blobs */} + - {/* Decorative background blobs */} - -
- +
+ + + +
+ +
+ {/* Section heading — more prominent */} -
- - -
- {/* Section heading */} + {/* Decorative top line */} - -
- - - - - Themes - - - + initial={{ opacity: 0, scaleX: 0 }} + whileInView={{ opacity: 1, scaleX: 1 }} + transition={{ type: "spring", stiffness: 200, delay: 0.1 }} + className="mx-auto mb-5 h-[3px] w-24 md:w-32 bg-[#1a1a1a]" + /> - {/* Theme cards grid */} - - {themes.map((theme) => ( - setSelectedTheme(theme)} - /> - ))} - + Themes + - {/* Bottom CTA */} - -
-
+ + Choose your domain. Build your vision. + - {/* Modal Overlay */} - - {selectedTheme && ( - setSelectedTheme(null)} + {/* Decorative bottom line */} + - )} - - + + + {/* Theme cards grid */} + + {themes.map((theme) => ( + + ))} + +
+
); } diff --git a/src/index.css b/src/index.css index 4a903fc..56c84bf 100644 --- a/src/index.css +++ b/src/index.css @@ -1,4 +1,4 @@ -@import url('https://fonts.googleapis.com/css2?family=Shrikhand&family=Outfit:wght@400;500;600;700&display=swap'); +@import url('https://fonts.googleapis.com/css2?family=Shrikhand&family=Outfit:wght@400;500;600;700&family=Fredoka:wght@400;500;600;700&display=swap'); @font-face { font-family: 'Wonderful Snowflake'; @@ -28,6 +28,7 @@ --font-display: "Wonderful Snowflake", "Shrikhand", serif; --font-sans: "Outfit", sans-serif; + --font-groovy: "Fredoka", "Outfit", sans-serif; } @layer base { @@ -126,6 +127,14 @@ .glow-effect { filter: drop-shadow(0 0 10px rgba(243, 162, 15, 0.6)); } + + .no-scrollbar { + -ms-overflow-style: none; + scrollbar-width: none; + } + .no-scrollbar::-webkit-scrollbar { + display: none; + } } @keyframes marquee { diff --git a/src/sections/Team.tsx b/src/sections/Team.tsx index cf44fca..00fe83b 100644 --- a/src/sections/Team.tsx +++ b/src/sections/Team.tsx @@ -79,17 +79,26 @@ const facultyOrganizers: TeamMember[] = [ function CoinDivider() { return ( -
+
-
- {[...Array(8)].map((_, i) => ( -
+
+ {[...Array(5)].map((_, i) => ( +
))}
); } +/** Reusable section sub-heading */ +function SectionSubHeading({ children }: { children: React.ReactNode }) { + return ( +

+ {children} +

+ ); +} + function TeamCard({ member, onClickBio }: { member: TeamMember, onClickBio: (m: TeamMember) => void }) { const [isHovered, setIsHovered] = useState(false); @@ -100,7 +109,7 @@ function TeamCard({ member, onClickBio }: { member: TeamMember, onClickBio: (m: viewport={{ once: true, margin: '-50px' }} transition={{ duration: 0.6, ease: [0.22, 1, 0.36, 1] }} whileHover={{ y: -8, scale: 1.02 }} - className="group relative bg-[#fff9f4] border-[3px] border-[#1a1a1a] shadow-[6px_6px_0px_#1a1a1a] hover:shadow-[8px_8px_0px_#f97028] transition-all cursor-pointer flex flex-col h-full overflow-hidden w-full max-w-[280px] sm:max-w-[300px] shrink-0" + className="group relative bg-[#fff9f4] border-[3px] border-[#1a1a1a] shadow-[4px_4px_0px_#1a1a1a] sm:shadow-[6px_6px_0px_#1a1a1a] hover:shadow-[8px_8px_0px_#f97028] transition-all cursor-pointer flex flex-col h-full overflow-hidden w-full shrink-0" onMouseEnter={() => setIsHovered(true)} onMouseLeave={() => setIsHovered(false)} onClick={() => onClickBio(member)} @@ -126,7 +135,7 @@ function TeamCard({ member, onClickBio }: { member: TeamMember, onClickBio: (m: ))} {/* Image Box */} -
+
{/* Scanline overlay */}
{/* Details Box */} -
+

{member.name}

-

{member.role}

+

{member.role}

-
+
@@ -162,9 +171,34 @@ function TeamCard({ member, onClickBio }: { member: TeamMember, onClickBio: (m: ); } +/** Responsive grid wrapper for team cards */ +function TeamGrid({ members, onClickBio }: { members: TeamMember[]; onClickBio: (m: TeamMember) => void }) { + return ( +
+ {members.map((member) => ( + + ))} +
+ ); +} + +/** Small grid for 1-3 items — centers them */ +function TeamGridSmall({ members, onClickBio }: { members: TeamMember[]; onClickBio: (m: TeamMember) => void }) { + return ( +
+ {members.map((member) => ( +
+ +
+ ))} +
+ ); +} + export default function Team() { const [selectedBio, setSelectedBio] = useState(null); const [activeTab, setActiveTab] = useState('Organising Team'); + const [showOperators, setShowOperators] = useState(false); const TABS = ['Organising Team', 'The Board', 'Faculty', 'Jury & Experts']; @@ -175,61 +209,59 @@ export default function Team() { } return ( -
-
+
+
- {/* Header block condtionally rendered */} + {/* Header block conditionally rendered */} {activeTab === 'Organising Team' && (
-

- - Meet The - - - Team - -

-

+ + Meet The + Team + + We back the dreamers, the builders, and the rebels. The architectural minds behind DevHack 3.0. -

+
)}
- {/* Tab Navigation */} -
- {TABS.map((tab) => ( - - ))} + {/* Tab Navigation — scrollable on mobile */} +
+
+ {TABS.map((tab) => ( + + ))} +
{/* Tab Content */} @@ -240,42 +272,65 @@ export default function Team() { animate={{ opacity: 1, y: 0 }} exit={{ opacity: 0, y: -10 }} transition={{ duration: 0.3 }} - className="min-h-[40vh]" + className="min-h-[30vh] sm:min-h-[40vh]" > {activeTab === 'Organising Team' && (
-

Core Team

-
- {coreTeam.map((member) => ( - - ))} -
+ Core Team +
-
- -
+
-

Sub Heads

-
- {subHeads.map((member) => ( - - ))} -
-
- -
- -
- -
-

Operating Partners

-
- {theOperators.map((member) => ( - - ))} + Sub Heads + + + {/* Dropdown toggle for Operating Partners */} +
+ + + + {showOperators && ( + +
+

+ Operating Partners +

+ +
+
+ )} +
@@ -284,25 +339,15 @@ export default function Team() { {activeTab === 'The Board' && (
-

Chief Patrons

-
- {chiefPatrons.map((member) => ( - - ))} -
+ Chief Patrons +
-
- -
+
-

Patrons

-
- {patrons.map((member) => ( - - ))} -
+ Patrons +
)} @@ -310,44 +355,30 @@ export default function Team() { {activeTab === 'Faculty' && (
-

Faculty Coordinator

-
- {facultyCoordinator.map((member) => ( - - ))} -
+ Faculty Coordinator +
-
- -
+
-

Organising Team Members

-
- {facultyOrganizers.map((member) => ( - - ))} -
+ Organising Team Members +
)} {activeTab === 'Jury & Experts' && (
-

Jury & Experts

-
- {judges.map((member) => ( - - ))} -
+ Jury & Experts +
)} {/* Decorative Divider */} -
+
@@ -360,7 +391,7 @@ export default function Team() { initial={{ opacity: 0 }} animate={{ opacity: 1 }} exit={{ opacity: 0 }} - className="fixed inset-0 z-50 flex items-center justify-center bg-[rgba(26,26,26,0.8)] backdrop-blur-sm p-4" + className="fixed inset-0 z-50 flex items-center justify-center bg-[rgba(26,26,26,0.8)] backdrop-blur-sm p-3 sm:p-4" onClick={() => setSelectedBio(null)} > e.stopPropagation()} > -

+

{selectedBio.name}

-

+

{selectedBio.role}

-
+
-

+

{selectedBio.bio || "No bio available right now. Currently busy building the future."}

-
+
Twitter/X @@ -405,7 +436,7 @@ export default function Team() { href={selectedBio.linkedin || '#'} target="_blank" rel="noreferrer" - className="flex-1 py-3 border-2 border-[#1a1a1a] text-center font-bold uppercase tracking-widest hover:bg-[#1a1a1a] hover:text-[#f3ecd2] transition-colors" + className="flex-1 py-2.5 sm:py-3 border-2 border-[#1a1a1a] text-center font-bold uppercase tracking-wider sm:tracking-widest hover:bg-[#1a1a1a] hover:text-[#f3ecd2] transition-colors text-xs sm:text-sm md:text-base" > LinkedIn