From 7638b780d5e28bdaecb9f924d621d4820fed0ef0 Mon Sep 17 00:00:00 2001 From: Caden Cheng Date: Wed, 5 Aug 2026 16:36:38 -0700 Subject: [PATCH] redesign home page, nav, and footer --- frontend/public/index.html | 2 +- frontend/src/components/Events/Events.tsx | 520 --------------- frontend/src/components/Events/styles.ts | 42 -- frontend/src/components/Footer/Footer.tsx | 117 +--- frontend/src/components/Home/Home.tsx | 546 ++++----------- .../components/Home/SlideShow/SlideShow.tsx | 59 -- .../src/components/Home/SlideShow/styles.ts | 16 - frontend/src/components/Home/styles.ts | 621 +++++------------- frontend/src/components/Home/teamData.ts | 63 ++ .../components/Membership/EventsDashboard.tsx | 15 +- frontend/src/components/NavBar/NavBar.tsx | 140 ++-- frontend/src/components/NavBar/styles.ts | 47 +- .../src/components/common/SegmentedTabs.tsx | 53 ++ frontend/src/index.css | 2 +- frontend/src/theme.ts | 26 + frontend/src/utils/types.tsx | 34 + 16 files changed, 640 insertions(+), 1663 deletions(-) delete mode 100644 frontend/src/components/Events/Events.tsx delete mode 100644 frontend/src/components/Events/styles.ts delete mode 100644 frontend/src/components/Home/SlideShow/SlideShow.tsx delete mode 100644 frontend/src/components/Home/SlideShow/styles.ts create mode 100644 frontend/src/components/Home/teamData.ts create mode 100644 frontend/src/components/common/SegmentedTabs.tsx create mode 100644 frontend/src/theme.ts diff --git a/frontend/public/index.html b/frontend/public/index.html index e88c2b8d..50796120 100644 --- a/frontend/public/index.html +++ b/frontend/public/index.html @@ -24,7 +24,7 @@ CSE Society @ UCSD diff --git a/frontend/src/components/Events/Events.tsx b/frontend/src/components/Events/Events.tsx deleted file mode 100644 index 9f3dc730..00000000 --- a/frontend/src/components/Events/Events.tsx +++ /dev/null @@ -1,520 +0,0 @@ -import React, { useState, useEffect } from 'react'; -import { Container, Grid } from '@mui/material'; -import bgTop from '../../images/shape.svg'; -import bgBtm from '../../images/shape.svg'; -import { event_style } from './styles'; -import EventBox from '../Event/Event'; -import MobileEventBox from '../Event/MobileEvent'; -import Button from '../Button/Button'; -import useMediaQuery from '../../hooks/useMediaQuery'; -import { CircularProgress } from '@mui/material'; - -interface EventData { - calendar_link: string; - description: string; - end_time: string; - instagram_link: string; - location: string; - start_time: string; - title: string; - _id: string; -} - -const Events = () => { - // add state for page number - const [pageNumberUpcoming, setPageNumberUpcoming] = useState(1); - const [pageNumberPast, setPageNumberPast] = useState(1); - - // add state for the total number of pages - const [totalPagesUpcoming, setTotalPagesUpcoming] = useState(1); - const [totalPagesPast, setTotalPagesPast] = useState(1); - - // add state for the number of events per page - const eventsPerPage = 6; - - const styles = event_style(); - const eventsContainerStyle: any = styles.eventsContainer; - - const [upcomingEvents, setUpcomingEvents] = useState([]); - const [pastEvents, setPastEvents] = useState([]); - const [selectedYear, setSelectedYear] = useState(new Date().getFullYear()); // Default to current year - const [selectedMonth] = useState(null); - const [pastEventYears, setPastEventYears] = useState([]); - - - const [displayedFutureEvents, setDisplayedFutureEvents] = useState(upcomingEvents); - const [displayedPastEvents, setDisplayedPastEvents] = useState(pastEvents); - const [isThisWeekClicked, setIsThisWeekClicked] = useState(false); - const [isThisMonthClicked, setIsThisMonthClicked] = useState(false); - // add state to keep track of the total pages based on the filtered events - const [filteredTotalPagesPast, setFilteredTotalPagesPast] = useState(totalPagesPast); - - - const [isLoading, setIsLoading] = useState(true); - - const paginate = ( - events: Array, - pageNumber: number, - totalPages: number, - type: string, - ) => { - let filteredEvents = events; - if (type === 'past' && selectedYear !== null) { - // If a year filter is applied, use the filtered past events - filteredEvents = pastEvents.filter(event => new Date(event.end_time).getFullYear() === selectedYear); - - } - - if (type === 'upcoming') { - setPageNumberUpcoming(pageNumber); - setDisplayedFutureEvents( - filteredEvents.slice((pageNumber - 1) * eventsPerPage, pageNumber * eventsPerPage), - ); - } else { - setPageNumberPast(pageNumber); - setDisplayedPastEvents( - filteredEvents.slice((pageNumber - 1) * eventsPerPage, pageNumber * eventsPerPage), - ); - } - }; - - const isDesktop = useMediaQuery('(min-width: 1024px)'); - const isIpad = useMediaQuery('(min-width: 768px) and (max-width: 1023px)'); - const isMobile = useMediaQuery('(max-width: 767px)'); - - if (isDesktop) { - // if desktop view set styles for desktop - eventsContainerStyle.maxWidth = '100vw'; - eventsContainerStyle.overflowX = 'hidden'; - eventsContainerStyle.flexWrap = 'wrap' as 'wrap'; - } - - if (isIpad) { - // if ipad view set styles for ipad - eventsContainerStyle.maxWidth = '100vw'; - eventsContainerStyle.overflowX = 'hidden'; - eventsContainerStyle.alignItems = 'flex-start'; - eventsContainerStyle.flexWrap = 'wrap' as 'wrap'; - } - - if (isMobile) { - // if mobile view set styles for mobile - eventsContainerStyle.width = '100%'; // Set width to 100% of the parent container - eventsContainerStyle.padding = '0'; // Remove any padding - eventsContainerStyle.overflowX = 'auto'; - eventsContainerStyle.overflowY = 'auto'; - eventsContainerStyle.flexWrap = 'wrap' as 'wrap'; - eventsContainerStyle.alignItems = 'flex-start'; - } - - useEffect(() => { - // Set media queries - let upcomingEventsEndpoint = `${process.env.REACT_APP_BACKEND_URL}/api/v1/events?type=upcoming`; - let pastEventsEndpoint = `${process.env.REACT_APP_BACKEND_URL}/api/v1/events?type=past`; - - const fetchUpcomingEvents = async () => { - try { - const response = await fetch(upcomingEventsEndpoint); - const data = await response.json(); - setTotalPagesUpcoming(Math.ceil(data.length / 6)); - setUpcomingEvents(data); - paginate(data, 1, totalPagesUpcoming, 'upcoming'); - } catch (error) { - console.error('Error fetching upcoming events:', error); - } - }; - - const fetchPastEvents = async () => { - try { - const response = await fetch(pastEventsEndpoint); - const data = await response.json(); - setTotalPagesPast(Math.ceil(data.length / 6)); - setPastEvents(data); - - // Extract years from past events and sort in descending order - const years = Array.from(new Set(data.map((event: EventData) => new Date(event.end_time).getFullYear()))) - .sort((a, b) => (b as number) - (a as number)); // Explicit type casting for 'a' and 'b' - setPastEventYears(years as number[]); - - - paginate(data, 1, totalPagesPast, 'past'); - } catch (error) { - console.error('Error fetching past events:', error); - } - }; - - async function fetchData() { - try { - await Promise.all([fetchUpcomingEvents(), fetchPastEvents()]); - setIsLoading(false); - } catch (error) { - console.error(error); - setIsLoading(false); - } - } - - fetchData(); - }, [selectedYear, selectedMonth, totalPagesUpcoming, totalPagesPast, setTotalPagesUpcoming, setTotalPagesPast]); - - - const handleThisWeekClick = () => { - if (isThisWeekClicked) { - setDisplayedFutureEvents(upcomingEvents); - setIsThisWeekClicked(false); - } else { - const now = new Date().getTime(); - const oneWeekAfter = now + 7 * 24 * 60 * 60 * 1000; - - const thisWeekEvents = upcomingEvents.filter( - (event) => - new Date(event.start_time).getTime() >= now && - new Date(event.start_time).getTime() <= oneWeekAfter, - ); - - setDisplayedFutureEvents(thisWeekEvents); - setIsThisWeekClicked(true); - setIsThisMonthClicked(false); - } - }; - - const handleThisMonthClick = () => { - if (isThisMonthClicked) { - setDisplayedFutureEvents(upcomingEvents); - setIsThisMonthClicked(false); - } else { - const now = new Date().getTime(); - const oneMonthAfter = now + 30 * 24 * 60 * 60 * 1000; - - const thisMonthEvents = upcomingEvents.filter( - (event) => - new Date(event.start_time).getTime() >= now && - new Date(event.start_time).getTime() <= oneMonthAfter, - ); - - setDisplayedFutureEvents(thisMonthEvents); - setIsThisWeekClicked(false); - setIsThisMonthClicked(true); - } - }; - - const handleYearClick = (year: number) => { - if (selectedYear === year) { - setSelectedYear(null); - } else { - setSelectedYear(year); - } - }; - - useEffect(() => { - // Filter events based on selected year - const filterEventsByYear = (year: number, events: EventData[]) => { - return events.filter((event) => { - const eventYear = new Date(event.end_time).getFullYear(); - return eventYear === year; - }); - }; - - if (selectedYear !== null) { - const filteredPastEvents = filterEventsByYear(selectedYear, pastEvents); - setDisplayedPastEvents(filteredPastEvents); - setFilteredTotalPagesPast(Math.ceil(filteredPastEvents.length / eventsPerPage)); - paginate(filteredPastEvents, 1, totalPagesPast, 'past'); - } else { - setDisplayedPastEvents(pastEvents); - setFilteredTotalPagesPast(Math.ceil(pastEvents.length / eventsPerPage)); - paginate(pastEvents, 1, totalPagesPast, 'past'); - } - }, [selectedYear, pastEvents]); - - - // Render EventBoxes using map - const renderEventBoxes = (events: EventData[]) => { - return events.map((eventData) => { - if (isMobile) { - return ( - - ); - } else { - return ( - - - - ); - } - }); - }; - - const renderPastEventBoxes = (events: EventData[]) => { - return events.map((eventData) => { - if (isMobile) { - return ( - - ); - } else { - return ( - - - - ); - } - }); - }; - - return ( -
- bg1 - bg2 - - - EVENTS - - - {isLoading && ( -
- -
- )} - - {/* Buttons for filtering events */} - {displayedFutureEvents.length >= 0 && ( - - - - - )} - {/* Render EventBoxes for future events */} -
- {(displayedFutureEvents.length === 0 && ( - - No upcoming events - - )) || - renderEventBoxes(displayedFutureEvents)} -
- - {displayedFutureEvents.length > 0 && ( - - Page {pageNumberUpcoming} of {totalPagesUpcoming} - - )} - {totalPagesUpcoming > 1 && ( -
-
- )} - - {/* Render EventBoxes for past events */} - - PAST EVENTS - - - {isLoading && ( -
- -
- )} - {/* Buttons for filtering past events */} - {displayedPastEvents.length > 0 && ( - - {/* */} - - {/*Buttons that handle general year */} - {Array.from(pastEventYears).sort().reverse().map(year => ( - - -
- )} - - - ); -}; - -export default Events; diff --git a/frontend/src/components/Events/styles.ts b/frontend/src/components/Events/styles.ts deleted file mode 100644 index a29f9e91..00000000 --- a/frontend/src/components/Events/styles.ts +++ /dev/null @@ -1,42 +0,0 @@ -export const event_style = () => ({ - bg1: { - width: '100%', - margin: '10% 0%', - transform: 'rotate(-25deg)', - scale: '120%', - top: '0%', - marginTop: '-10%', - opacity: '0.5', - }, - bg2: { - opacity: '0.5', - width: '100%', - scale: '120%', - transform: 'scaleX(-1) scaleY(-1)', - margin: '30% 0%', - marginTop: '100%', - }, - eventsContainer: { - color: 'white', - fontSize: '20px', - fontFamily: 'Chakra Petch', - fontWeight: '700', - display: 'flex', - flexDirection: 'row' as 'row', - flexWrap: 'wrap' as 'wrap' | 'nowrap' | 'wrap-reverse', - marginLeft: '39px', - maxWidth: '1024px', - overflowX: 'scroll' as - | 'scroll' - | 'auto' - | 'hidden' - | 'visible' - | 'inherit' - | 'initial' - | 'revert' - | 'unset', - gridTemplateColumns: 'repeat(auto-fill, minmax(200px, 1fr)', - gap: '40px', - }, - body: { position: 'relative', top: '93px', marginBottom: '200px' }, -}); diff --git a/frontend/src/components/Footer/Footer.tsx b/frontend/src/components/Footer/Footer.tsx index c652700d..deb660a2 100644 --- a/frontend/src/components/Footer/Footer.tsx +++ b/frontend/src/components/Footer/Footer.tsx @@ -1,129 +1,80 @@ import React from 'react'; import { Box, Typography, Link } from '@mui/material'; import InstagramIcon from '../../images/instagram-icon.svg'; -import FacebookIcon from '../../images/facebook-icon.svg'; import LinkedInIcon from '../../images/linkedin-icon.svg'; -import DiscordIcon from '../../images/discord-icon.svg'; -import csesLogo from '../../images/footer-logo.png'; +import csesLogo from '../../images/logo.png'; +import { colors, fonts } from '../../theme'; const links = [ - { logo: InstagramIcon, link: 'https://www.instagram.com/cses_ucsd/' }, - { logo: DiscordIcon, link: 'https://discord.gg/UkdACyy2h8' }, - { logo: FacebookIcon, link: 'https://www.facebook.com/csesucsd' }, - { logo: LinkedInIcon, link: 'https://www.linkedin.com/in/csesucsd/' }, + { logo: InstagramIcon, link: 'https://www.instagram.com/cses_ucsd/', label: 'Instagram' }, + { logo: LinkedInIcon, link: 'https://www.linkedin.com/in/csesucsd/', label: 'LinkedIn' }, ]; +const COPYRIGHT = '© 2026 UC San Diego Computer Science and Engineering Society. All rights reserved.'; + const Footer = () => { return ( - {/* Desktop Layout */} {/* Logo */} - - - - - {/* Center Contact Info */} - - For all inquiries, contact{' '} - - cses@ucsd.edu - - . - + {/* Social Icons */} - - {links.map(({ logo, link }, idx) => ( + + {links.map(({ logo, link, label }) => ( - social + {label} ))} - {/* Mobile Layout */} - - {/* Logo */} - - - - - {/* Social Icons */} - - {links.map(({ logo, link }, idx) => ( - - social - - ))} - - + {COPYRIGHT} + ); }; diff --git a/frontend/src/components/Home/Home.tsx b/frontend/src/components/Home/Home.tsx index a29816f9..ef97f764 100644 --- a/frontend/src/components/Home/Home.tsx +++ b/frontend/src/components/Home/Home.tsx @@ -1,447 +1,169 @@ -import React, { useState, useEffect } from 'react'; +import { useMemo, useState } from 'react'; import { useNavigate } from 'react-router-dom'; -import { Container, Box, Grid, Button as MuiButton } from '@mui/material'; +import { Box, Button, Container, Grid } from '@mui/material'; +import { motion } from 'framer-motion'; import { homeStyles } from './styles'; +import { colors } from '../../theme'; +import SegmentedTabs from '../common/SegmentedTabs'; +import { TEAM_MEMBERS } from './teamData'; import DevLogo from '../../images/ourCommunitiesImages/DevLogo.png'; import InnovateLogo from '../../images/ourCommunitiesImages/InnovateLogo.png'; import OpenSourceLogo from '../../images/ourCommunitiesImages/OpenSourceLogo.png'; -import HomeLogo from '../../images/HomeLogo.png'; -import ASLogo from '../../images/sponsors/AS_Logo.png'; -import CSEDeptLogo from '../../images/sponsors/CSEDept_Logo.png'; -import BasementLogo from '../../images/sponsors/Basement_Logo.jpeg'; -import EyePopAILogo from '../../images/sponsors/EyePopAI_Logo.png'; -import GoogleLogo from '../../images/sponsors/Google_Logo.webp'; -import BSLLogo from '../../images/sponsors/BSL.png' -import IGELogo from '../../images/sponsors/IGE_Logo.png'; -import LinuxLogo from '../../images/sponsors/Linux_Logo.png'; -import LovableLogo from '../../images/sponsors/Lovable_Logo.png'; -import OSPOLogo from '../../images/sponsors/OSPO_Logo.png'; -import PersonaLogo from '../../images/sponsors/Persona_Logo.png'; -import RobloxLogo from '../../images/sponsors/Roblox_Logo.png'; -import Sithu from '../../images/homepage/sithu.jpg'; -import axios from 'axios'; -import CountUp from 'react-countup'; -import { motion } from "framer-motion"; -import jesusgonzalez from '../../images/homepage/jesusgonzalez.png'; -import shreevenkatesh from '../../images/homepage/shreevenkatesh.jpg'; -import pranavsoma from '../../images/homepage/pranavsoma.jpg'; -import nikithamaderamitla from '../../images/homepage/nikithaM.jpg'; -import westonzong from '../../images/homepage/westonzong.jpg'; -import vanditajain from '../../images/homepage/vanditajain.jpg'; -import EventCard from '../NewEvents/EventCard'; - -interface EventData { - calendar_link: string; - description: string; - end_time: string; - instagram_link: string; - location: string; - start_time: string; - title: string; - _id: string; -} +const WHAT_IS_CSES_COPY = `For over 21 years, CSES has been at the forefront of undergraduate computing, growing the largest student-led tech community on campus. Through our Dev, OpenSource, and Innovate divisions, we give students the chance to build real-world software, contribute to open-source projects, and explore cutting-edge research. We celebrate curiosity, foster innovation, and empower the next generation of tech leaders.`; + +const COMMUNITIES = [ + { + name: 'Open-Source', + logo: OpenSourceLogo, + accent: colors.lightBlue, + description: 'Contribute to real projects and learn collaborative development practices', + path: '/opensourcecommunity', + }, + { + name: 'Innovate', + logo: InnovateLogo, + accent: colors.purple, + description: 'Turn ideas into reality through hackathons and entrepreneurial ventures', + path: '/innovatecommunity', + }, + { + name: 'Dev', + logo: DevLogo, + accent: colors.mint, + description: 'Build industry-ready skills and connect with mentors in tech', + path: '/devcommunity', + }, +]; + +const TEAM_TABS = ['General', 'Open-Source', 'Innovate', 'Dev']; +const MEMBERS_PER_PAGE = { xs: 1, sm: 2, md: 4 }; const Home = () => { const navigate = useNavigate(); const styles = homeStyles(); - const [totalEvents, setTotalEvents] = useState(0); - const [totalUsers, setTotalUsers] = useState(0); - const [currentPersonIndex, setCurrentPersonIndex] = useState(0); - const [displayedFutureEvents, setDisplayedFutureEvents] = useState([]); - const [allFutureEvents, setAllFutureEvents] = useState([]); - const [eventsToShow, setEventsToShow] = useState(4); - const [currentEventPage, setCurrentEventPage] = useState(0); - - - const teamMembers = [ - { - name: "Jesus Gonzalez", - position: "Software Engineer Intern", - company: "Intuit", - photo: jesusgonzalez // placeholder for now - }, - { - name: "Shree Venkatesh", - position: "Software Development Engineer Intern", - company: "Amazon Web Services", - photo: shreevenkatesh // placeholder for now - }, - { - name: "Pranav Soma", - position: "Associate Software Engineer", - company: "ServiceNow", - photo: pranavsoma // placeholder for now - }, - { - name: "Nikitha Maderamitla", - position: "Software Engineer", - company: "Curanostics", - photo: nikithamaderamitla // placeholder for now - }, - { - name: "Weston Zong", - position: "Software Engineer", - company: "Roblox", - photo: westonzong // placeholder for now - }, - { - name: "Vandita Jain", - position: "AL and ML Intern", - company: "Global Impact Assessment", - photo: vanditajain // placeholder for now - }, - - { - name: "Sithu Soe", - position: "Associate Software Engineer Intern", - company: "ServiceNow", - // classOf: "2026", - photo: Sithu - }, - /*{ - name: "Michael Chen", - position: "Full Stack Developer", - company: "Microsoft", - classOf: "2019", - photo: null - }, - { - name: "Emily Rodriguez", - position: "Product Manager", - company: "Apple", - classOf: "2021", - photo: null - }, - { - name: "David Kim", - position: "DevOps Engineer", - company: "Amazon", - classOf: "2018", - photo: null - }, - { - name: "Lisa Wang", - position: "Frontend Developer", - company: "Meta", - classOf: "2022", - photo: null - }*/ - ]; - - - const currentMember = teamMembers[currentPersonIndex]; + const [teamTab, setTeamTab] = useState('General'); + const [teamPage, setTeamPage] = useState(0); - const handlePrevPerson = () => { - setCurrentPersonIndex((prev) => - prev === 0 ? teamMembers.length - 1 : prev - 1 - ); - }; - - const handleNextPerson = () => { - setCurrentPersonIndex((prev) => - prev === teamMembers.length - 1 ? 0 : prev + 1 - ); - }; + const filteredMembers = useMemo( + () => TEAM_MEMBERS.filter((member) => member.community === teamTab), + [teamTab], + ); - const handlePrevEvent = () => { - setCurrentEventPage((prev) => { - const maxPage = Math.max(0, Math.ceil(allFutureEvents.length / eventsToShow) - 1); - return prev > 0 ? prev - 1 : maxPage; - }); - }; + // Page size follows the md layout; smaller breakpoints wrap within the grid. + const pageSize = MEMBERS_PER_PAGE.md; + const pageCount = Math.ceil(filteredMembers.length / pageSize); + const visibleMembers = filteredMembers.slice(teamPage * pageSize, (teamPage + 1) * pageSize); - const handleNextEvent = () => { - setCurrentEventPage((prev) => { - const maxPage = Math.max(0, Math.ceil(allFutureEvents.length / eventsToShow) - 1); - return prev < maxPage ? prev + 1 : 0; - }); + const handleTeamTabChange = (tab: string) => { + setTeamTab(tab); + setTeamPage(0); }; - useEffect(() => { - axios - .get(`${process.env.REACT_APP_BACKEND_URL}/api/v1/events`) - .then((response) => { - setTotalEvents(response.data.length); - }) - .catch((error) => { - console.error('Error fetching total events:', error); - }); - - axios - .get(`${process.env.REACT_APP_BACKEND_URL}/api/v1/users/usersCount`) - .then((response) => { - setTotalUsers(response.data); - }) - .catch((error) => { - console.error('Error fetching total users:', error); - }); - }, []); - - useEffect(() => { - const handleResize = () => { - const isMobile = window.innerWidth <= 600; - setEventsToShow(isMobile ? 1 : 4); - }; - - // Set initial value - handleResize(); - - // Add event listener - window.addEventListener('resize', handleResize); - - // Cleanup - return () => window.removeEventListener('resize', handleResize); - }, []); - - useEffect(() => { - const fetchRecentEvents = async () => { - try { - console.log('Fetching events from:', `${process.env.REACT_APP_BACKEND_URL}/api/v1/events?type=upcoming`); - const response = await fetch( - `${process.env.REACT_APP_BACKEND_URL}/api/v1/events?type=upcoming` - ); - let mostRecentEvents = await response.json(); - console.log('Events received:', mostRecentEvents); - setAllFutureEvents(mostRecentEvents); - } catch (error) { - console.error('Error fetching upcoming events:', error); - } - }; - - fetchRecentEvents(); - }, []); - - // Update displayed events when page or eventsToShow changes - useEffect(() => { - const startIndex = currentEventPage * eventsToShow; - const endIndex = startIndex + eventsToShow; - setDisplayedFutureEvents(allFutureEvents.slice(startIndex, endIndex)); - }, [allFutureEvents, currentEventPage, eventsToShow]); - return ( -
- - - {/* Hero Section */} - - - - - Create. - - - - Solve. - - - - Evolve. - - - - We're CSES, the largest student-led tech community at UCSD. - - - - - - - CSE Society Logo - - - - - {/* Scroll Down Arrow */} - - + + {/* Hero */} + + + + CSE Society + at UC San Diego + + Empowering students through technology, innovation, and community + + + + + + + - {/* Join Section */} - - Join UCSD's largest computing organisation! - - - - - - + - - Members - - - - - - - + + + {/* What is CSES? */} + + + What is CSES? + + {WHAT_IS_CSES_COPY} + + + {/* Communities */} + + + {COMMUNITIES.map((community) => ( + + navigate(community.path)}> + + + {community.description} - Annual Events + ))} + + - - - 12+ - Annual Projects - - - - - {/* navigate('/membership')} - sx={styles.ctaButton} - > - Become a member now! - */} + {/* Meet the Team! */} + + + Meet the Team! + The people who make CSE Society possible - {/* Events Section REDO THE WHOLE THING*/} - - {"{Events}"} - - - - - {displayedFutureEvents.length > 0 ? ( - displayedFutureEvents.map((event, index) => ( - - - - )) - ) : ( - // Fallback for when no events are available - Array.from({ length: eventsToShow }, (_, index) => index + 1).map((event, index) => ( - - - - [Event {event}] - - - )) - )} - - - - - - - navigate('/events')} - sx={styles.ctaButton} - > - See Events Page - - + + - {/* Communities Section */} - - {"{Communities}"} - - navigate('/opensourcecommunity')} style={{ cursor: 'pointer' }}> - Open Source - - navigate('/innovatecommunity')} style={{ cursor: 'pointer' }}> - Innovate - - navigate('/devcommunity')} style={{ cursor: 'pointer' }}> - Dev - - - - - navigate('/about')} - sx={styles.ctaButton} - > - About us - - - - - {/* Where We Are Section */} - - {"{Where We Are}"} - - - - - - - {currentMember.photo ? ( - {currentMember.name} - ) : ( - '' - )} + {visibleMembers.length > 0 ? ( + + {visibleMembers.map((member) => ( + + + + {member.name} + {member.role} - - - {currentMember.position} | {currentMember.company} - {/* {currentMember.classOf} */} - {currentMember.name} - - - - - + + ))} + + ) : ( + Team members coming soon. + )} + {pageCount > 1 && ( - {teamMembers.map((_, index) => ( - setCurrentPersonIndex(index)} /> + {Array.from({ length: pageCount }, (_, index) => ( + setTeamPage(index)} + /> ))} - - navigate('/about')} - sx={styles.ctaButton} - > - Meet the Team - - - - {/* Current Sponsors */} - - {"{Current Sponsors}"} - - Interested in how CSES can help you? Contact csed@ucsd.edu or view our sponsorship package here. - - - - Associated Student - CSE Department - Big Strategy Lab - Roblox - Persona - Lovable - EyePop AI - IGE - Linux Foundation - OSPO - Basement - - - - -
+ )} +
+ +
); }; diff --git a/frontend/src/components/Home/SlideShow/SlideShow.tsx b/frontend/src/components/Home/SlideShow/SlideShow.tsx deleted file mode 100644 index e11e7d3b..00000000 --- a/frontend/src/components/Home/SlideShow/SlideShow.tsx +++ /dev/null @@ -1,59 +0,0 @@ -import React from 'react'; -import { slideShowStyles } from './styles'; -import desktop from '../../../images/desktop.png'; -import { Box } from '@mui/material'; - -const images = require.context('../../../images/slideshowImages', true); -const styles = slideShowStyles(); -const delay = 10000; - -const SlideShow = () => { - const imageList = images.keys().map((image: any) => images(image)); - const [index, setIndex] = React.useState(0); - const indexRef = React.useRef(index); - - // Update the ref whenever the index changes (without triggering re-renders) - React.useEffect(() => { - indexRef.current = index; - }, [index]); - - // Use setInterval to handle periodic updates - React.useEffect(() => { - const intervalId = setInterval(() => { - setIndex((prevIndex) => (prevIndex === imageList.length - 1 ? 0 : prevIndex + 1)); - }, delay); - return () => clearInterval(intervalId); - }, [imageList]); - - return ( -
- img - -
- {imageList.map((img: any, idx: React.Key | null | undefined) => ( -
- ))} -
- -
- ); -}; - -export default SlideShow; diff --git a/frontend/src/components/Home/SlideShow/styles.ts b/frontend/src/components/Home/SlideShow/styles.ts deleted file mode 100644 index 8da0b27d..00000000 --- a/frontend/src/components/Home/SlideShow/styles.ts +++ /dev/null @@ -1,16 +0,0 @@ -export const slideShowStyles = () => ({ - slideshow: { - margin: '0 auto', - overflow: 'hidden', - maxWidth: '64.6%', - }, - slide: { - display: 'inline-block', - height: '100%', - width: '100%', - clipPath: 'polygon(3% 9.5% , 98% 2.5%, 98% 97%, 3% 97%)', - paddingTop: '86.6%', - backgroundSize: 'cover', - backgroundPosition: 'center center', - }, -}); diff --git a/frontend/src/components/Home/styles.ts b/frontend/src/components/Home/styles.ts index 339e815d..428852b0 100644 --- a/frontend/src/components/Home/styles.ts +++ b/frontend/src/components/Home/styles.ts @@ -1,514 +1,227 @@ +import { colors, fonts, radii } from '../../theme'; + export const homeStyles = () => ({ - /* ===== Page Wrapper ===== */ pageWrapper: { - position: 'relative' as const, - paddingBottom: '80px', - paddingLeft: '20px', - paddingRight: '20px', - overflow: 'hidden' as const, - background: '#020F5D ', + backgroundColor: colors.background, minHeight: '100vh', - '@media (min-width: 600px)': { - paddingLeft: '40px', - paddingRight: '40px' - }, - '@media (min-width: 900px)': { - paddingLeft: '60px', - paddingRight: '60px' - }, - '@media (min-width: 1200px)': { - paddingLeft: '80px', - paddingRight: '80px' - } - }, - - /* ===== Root Container ===== */ - root: { - position: 'relative', + overflowX: 'hidden' as const, }, - container: { - position: 'relative', - }, - - /* ===== Hero Section ===== */ - heroGrid: { - minHeight: '80vh', - paddingTop: '100px', - '@media (max-width: 600px)': { - paddingTop: '150px' - }, - '@media (min-width: 900px)': { - paddingTop: '120px' - } + display: 'flex', + flexDirection: 'column', + alignItems: 'center', + px: { xs: 3, md: 6 }, }, - heroTextContainer: { - textAlign: 'left', - paddingLeft: '0', - '@media (max-width: 600px)': { - textAlign: 'center', - paddingLeft: '0' - }, - '@media (min-width: 900px)': { - paddingLeft: '2rem' - }, - '@media (min-width: 1200px)': { - paddingLeft: '4rem' - } + // Hero + hero: { + width: '100%', + minHeight: { xs: '70vh', md: '85vh' }, + display: 'flex', + flexDirection: 'column', + alignItems: 'center', + justifyContent: 'center', + textAlign: 'center', + pt: { xs: 16, md: 18 }, + pb: { xs: 8, md: 10 }, }, - - heroTitleWhite: { - fontSize: { xs: '3rem', md: '5rem' }, - fontWeight: 'bold', - color: 'white', - fontFamily: 'Chakra Petch', - lineHeight: 1.1, - marginBottom: '0.5rem' + heroTitle: { + fontFamily: fonts.heading, + fontWeight: 700, + fontSize: { xs: '2.6rem', sm: '3.5rem', md: '4.5rem' }, + color: colors.textPrimary, + letterSpacing: '0.02em', }, - - heroTitleGold: { - fontSize: { xs: '3rem', md: '5rem' }, - fontWeight: 'bold', - color: '#FFD700', - fontFamily: 'Chakra Petch', - lineHeight: 1.1, - marginBottom: '2rem' - }, - heroSubtitle: { - color: 'white', - fontSize: '1.2rem', - marginBottom: '1rem', - fontFamily: 'Arial', - '@media (min-width: 1200px)': { - fontSize: '1.4rem' - } - }, - - logoContainer: { + fontFamily: fonts.heading, + fontSize: { xs: '1.2rem', md: '1.75rem' }, + color: colors.textPrimary, + mt: 1, + }, + heroTagline: { + fontFamily: fonts.heading, + fontSize: { xs: '0.85rem', md: '1rem' }, + color: colors.textSecondary, + mt: 4, + px: 2, + }, + heroButtons: { display: 'flex', + gap: 2, + mt: 5, + flexWrap: 'wrap', justifyContent: 'center', - alignItems: 'center', - minHeight: { xs: '300px', sm: '350px', md: '400px' } - }, - - logoImage: { - width: "80%", - height: "80%", - objectFit: "contain" as const, - filter: "brightness(1.1)" - }, - - /* ===== Motion Animation Props ===== */ - motionInitialLeft: { x: -100, opacity: 0 }, - motionAnimate: { x: 0, opacity: 1 }, - motionTransition: (delay: number) => ({ type: 'spring', stiffness: 50, delay }), - - /* ===== Scroll Arrow ===== */ - scrollArrowWrapper: { - textAlign: 'center', - marginTop: '2rem' }, - - scrollArrow: { - color: 'white', - fontSize: '2rem', - cursor: 'pointer' + primaryButton: { + fontFamily: fonts.body, + fontSize: '0.95rem', + fontWeight: 500, + textTransform: 'none', + color: colors.textPrimary, + backgroundColor: colors.purpleButton, + borderRadius: '8px', + px: 3, + py: 1.2, + '&:hover': { backgroundColor: colors.purpleBright }, + }, + secondaryButton: { + fontFamily: fonts.body, + fontSize: '0.95rem', + fontWeight: 500, + textTransform: 'none', + color: colors.textPrimary, + border: `1px solid ${colors.purple}`, + borderRadius: '8px', + px: 3, + py: 1.2, + '&:hover': { borderColor: colors.purpleBright, backgroundColor: 'rgba(114, 93, 240, 0.1)' }, }, - /* ===== Section Wrapper ===== */ + // Shared section pieces sectionWrapper: { - textAlign: 'center', - marginTop: '8rem', - marginBottom: '4rem' + width: '100%', + maxWidth: '1100px', + py: { xs: 6, md: 9 }, + display: 'flex', + flexDirection: 'column', + alignItems: 'center', }, - sectionTitle: { - fontSize: { xs: '2.5rem', md: '3.5rem' }, - fontWeight: 'bold', - color: 'white', - marginBottom: '3rem', - fontFamily: 'Chakra Petch' - }, - - /* ===== Statistics Cards ===== */ - statsGrid: { - marginBottom: '3rem' - }, - - statsCard: { - background: 'white', - borderRadius: '8px', - padding: '2rem 1rem', + fontFamily: fonts.heading, + fontWeight: 700, + fontSize: { xs: '1.8rem', md: '2.4rem' }, + color: colors.textPrimary, textAlign: 'center', - border: '3px solid #FFD700' - }, - - statsNumber: { - fontSize: '4rem', - fontWeight: 'bold', - color: 'black', - marginBottom: '0.5rem', - lineHeight: 1 - }, - - statsLabel: { - fontSize: '1.2rem', - color: 'black', - fontWeight: '400', - '@media (min-width: 1200px)': { - fontSize: '1.4rem' - } - }, - - /* ===== CTA Button ===== */ - ctaButton: { - borderRadius: '40px', - border: '2px solid transparent', - backgroundImage: - 'linear-gradient(#0b0b0b, #0b0b0b), linear-gradient(to right, #FFCE00, #00F0FF)', - backgroundOrigin: 'border-box', - backgroundClip: 'padding-box, border-box', - paddingX: '20px', - paddingY: '11px', - color: 'white', - fontSize: '20px', - textTransform: 'none', - '&:hover': { - backgroundImage: - 'linear-gradient(rgba(255,255,255,0.05), rgba(255,255,255,0.05)), linear-gradient(to right, #FFCE00, #00F0FF)', - color: 'black' - }, - '@media (max-width: 600px)': { - fontSize: '18px', - paddingX: '16px', - paddingY: '9px' - }, - '@media (min-width: 1200px)': { - fontSize: '22px', - paddingX: '24px', - paddingY: '13px' - } - }, - - ctaButtonText: { - color: 'white', - fontSize: '1.1rem', - fontWeight: '500', - '@media (min-width: 1200px)': { - fontSize: '1.3rem' - } }, - - /* ===== Events Section ===== */ - eventsWrapper: { - position: 'relative', - display: 'flex', - alignItems: 'center', - justifyContent: 'center', - paddingLeft: '60px', - paddingRight: '60px', - '@media (max-width: 600px)': { - paddingLeft: '40px', - paddingRight: '40px' - } + sectionSubtitle: { + fontFamily: fonts.heading, + fontSize: { xs: '0.85rem', md: '0.95rem' }, + color: colors.textSecondary, + textAlign: 'center', + mt: 1.5, }, - eventsGrid: { - maxWidth: '1200px' + // What is CSES? + aboutParagraph: { + fontFamily: fonts.heading, + fontSize: { xs: '0.85rem', md: '1rem' }, + lineHeight: 1.9, + color: colors.textSecondary, + textAlign: 'center', + maxWidth: '850px', + mt: 4, }, - eventCard: { - background: 'white', - borderRadius: '8px', - padding: '0', - textAlign: 'center', - height: '300px', + // Communities + communityColumn: { display: 'flex', flexDirection: 'column', - justifyContent: 'flex-end', alignItems: 'center', - border: '2px solid transparent', - backgroundImage: 'linear-gradient(white, white), linear-gradient(45deg, #FF6B35, #00E5FF)', - backgroundOrigin: 'border-box', - backgroundClip: 'content-box, border-box', - position: 'relative', - overflow: 'hidden' + textDecoration: 'none', + cursor: 'pointer', + transition: 'transform 0.2s ease', + '&:hover': { transform: 'translateY(-4px)' }, }, - - eventCardContent: { + communityLogo: { width: '100%', - height: '100%', - background: 'white', + maxWidth: '220px', + height: 'auto', + }, + communityCard: (accent: string) => ({ + backgroundColor: colors.surface, + border: `1px solid ${accent}55`, + borderRadius: radii.card, + p: 3, + mt: 3, + width: '100%', + minHeight: '96px', display: 'flex', alignItems: 'center', justifyContent: 'center', - padding: '1rem' - }, - - eventDetails: { + }), + communityCardText: { + fontFamily: fonts.body, + fontSize: '0.95rem', + color: colors.textSecondary, textAlign: 'center', - color: 'black', - width: '100%' - }, - - eventTitle: { - fontSize: { xs: '1.1rem', sm: '1.3rem' }, - fontWeight: 'bold', - marginBottom: '0.5rem', - color: '#020F5D', - lineHeight: 1.2 - }, - - eventDescription: { - fontSize: { xs: '0.9rem', sm: '1rem' }, - marginBottom: '0.8rem', - color: '#666', - lineHeight: 1.3, - display: '-webkit-box', - WebkitLineClamp: 3, - WebkitBoxOrient: 'vertical', - overflow: 'hidden' - }, - - eventLocation: { - fontSize: { xs: '0.8rem', sm: '0.9rem' }, - marginBottom: '0.5rem', - color: '#333', - fontWeight: '500' - }, - - eventTime: { - fontSize: { xs: '0.8rem', sm: '0.9rem' }, - color: '#666', - fontWeight: '400' - }, - - eventLabel: { - position: 'absolute', - bottom: '20px', - left: '20px', - fontSize: '1.2rem', - fontWeight: 'bold', - color: 'black', - textShadow: '0 2px 4px rgba(0,0,0,0.3)' - }, - - arrowLeft: { - position: 'absolute', - left: '10px', - top: '50%', - transform: 'translateY(-50%)', - fontSize: '2rem', - color: 'white', - cursor: 'pointer', - zIndex: 2, - '@media (max-width: 600px)': { - left: '5px', - fontSize: '1.5rem' - }, - '&:hover': { - opacity: 0.7 - } - }, - - arrowRight: { - position: 'absolute', - right: '10px', - top: '50%', - transform: 'translateY(-50%)', - fontSize: '2rem', - color: 'white', - cursor: 'pointer', - zIndex: 2, - '@media (max-width: 600px)': { - right: '5px', - fontSize: '1.5rem' - }, - '&:hover': { - opacity: 0.7 - } }, - /* ===== Community Logos ===== */ - communityLogo: { - width: "300px", - height: "300px", - objectFit: "contain" as const, - filter: "brightness(1.1)", - '@media (max-width: 600px)': { - width: "150px", - height: "150px" - }, - '@media (min-width: 601px) and (max-width: 900px)': { - width: "200px", - height: "200px" - }, - '@media (min-width: 1200px)': { - width: "350px", - height: "350px" - } - }, - - /* ===== Where We Are Section ===== */ - carouselWrapper: { - position: 'relative', - display: 'flex', - alignItems: 'center', - justifyContent: 'center', + // Meet the Team! + teamTabsWrapper: { + width: '100%', maxWidth: '800px', - margin: '0 auto' + mt: 5, }, - - carouselContent: { - display: 'flex', - alignItems: 'center', - justifyContent: 'center', - gap: { xs: '2rem', md: '4rem' }, - flexDirection: { xs: 'column', md: 'row' }, + teamGrid: { + mt: 4, width: '100%', - maxWidth: '600px' }, - - photoContainer: { - width: { xs: '250px', md: '300px' }, - height: { xs: '250px', md: '300px' }, - background: 'linear-gradient(45deg, #FFD700 0%, #00E676 100%)', - borderRadius: '15px', - padding: '3px', + teamCard: { + backgroundColor: colors.surface, + border: `1px solid ${colors.border}`, + borderRadius: radii.card, + p: 2.5, display: 'flex', + flexDirection: 'column', alignItems: 'center', - justifyContent: 'center' - }, - - photoInner: { - width: '100%', + textAlign: 'center', height: '100%', - background: '#f0f0f0', - borderRadius: '12px', - display: 'flex', - alignItems: 'center', - justifyContent: 'center', - color: '#666', - fontSize: '1.1rem', - fontWeight: 'bold' }, - - carouselText: { - textAlign: { xs: 'center', md: 'left' }, - color: 'white' - }, - - carouselPosition: { - fontSize: { xs: '1rem', md: '1.4rem' }, - marginBottom: '1rem', - lineHeight: 1.2 + teamPhoto: { + width: '96px', + height: '96px', + borderRadius: '50%', + objectFit: 'cover' as const, }, - - carouselClass: { - fontSize: { xs: '1.4rem', md: '1.6rem' }, - marginBottom: '1rem', - opacity: 0.9 + teamName: { + fontFamily: fonts.body, + fontWeight: 600, + fontSize: '1rem', + color: colors.textPrimary, + mt: 2, }, - - carouselName: { - fontSize: { xs: '1.4rem', md: '2rem' }, - lineHeight: 1.2 + teamRole: { + fontFamily: fonts.body, + fontSize: '0.85rem', + color: colors.textSecondary, + mt: 0.5, }, - - /* ===== Navigation Dots ===== */ dotsWrapper: { display: 'flex', - justifyContent: 'center', - gap: '0.5rem', - marginTop: '2rem', - marginBottom: '3rem' + gap: 1.2, + mt: 4, }, - dot: { - width: '12px', - height: '12px', + width: '10px', + height: '10px', borderRadius: '50%', - background: 'rgba(255, 255, 255, 0.5)', + backgroundColor: 'rgba(255, 255, 255, 0.25)', cursor: 'pointer', - transition: 'all 0.3s ease', - '&:hover': { - background: 'rgba(255, 255, 255, 0.8)' - } }, - dotActive: { - width: '12px', - height: '12px', + width: '10px', + height: '10px', borderRadius: '50%', - background: '#FFD700', + backgroundColor: colors.purpleBright, cursor: 'pointer', - transition: 'all 0.3s ease' - }, - - /* ===== Sponsors Section ===== */ - sponsorSubtitle: { - color: 'white', - fontSize: '1rem', - marginBottom: '3rem', - maxWidth: '600px', - margin: '0 auto 3rem', - '@media (min-width: 1200px)': { - fontSize: '1.2rem' - } - }, - - sponsorLogo: { - width: "150px", - height: "150px", - objectFit: "contain" as const, - filter: "brightness(1.1)", - background: "white", - borderRadius: "12px", - boxShadow: "0 4px 6px rgba(0,0,0,0.2)", - padding: "10px", - '@media (max-width: 600px)': { - width: "100px", - height: "100px" - }, - '@media (min-width: 601px) and (max-width: 900px)': { - width: "120px", - height: "120px" - }, - '@media (min-width: 1200px)': { - width: "180px", - height: "180px" - } }, - - sponsorLogoTall: { - width: "250px", - height: "350px", - objectFit: "contain" as const, - filter: "brightness(1.1)", - '@media (max-width: 600px)': { - width: "200px", - height: "300px" - }, - '@media (min-width: 601px) and (max-width: 900px)': { - width: "220px", - height: "320px" - }, - '@media (min-width: 1200px)': { - width: "280px", - height: "400px" - } + emptyText: { + fontFamily: fonts.body, + color: colors.textSecondary, + mt: 4, }, - emptySponsorCard: { - background: 'white', - borderRadius: '15px', - padding: '1.5rem', - display: 'flex', - justifyContent: 'center', - alignItems: 'center', - height: '120px' + // Kept for consumers outside Home (e.g. About/HowToJoin). + ctaButton: { + fontFamily: fonts.body, + fontSize: '0.95rem', + fontWeight: 500, + textTransform: 'none', + color: colors.textPrimary, + border: `1px solid ${colors.purple}`, + borderRadius: '8px', + px: 3, + py: 1.2, + '&:hover': { borderColor: colors.purpleBright, backgroundColor: 'rgba(114, 93, 240, 0.1)' }, }, - -}); \ No newline at end of file +}); diff --git a/frontend/src/components/Home/teamData.ts b/frontend/src/components/Home/teamData.ts new file mode 100644 index 00000000..9f78300f --- /dev/null +++ b/frontend/src/components/Home/teamData.ts @@ -0,0 +1,63 @@ +// Team members shown in the "Meet the Team!" section on the Home page. +// Edit this file to update the people displayed — no other code changes needed. +import { EventCategory } from '../../utils/types'; +import Sithu from '../../images/meettheteamImages/sithu.jpg'; +import Yashil from '../../images/meettheteamImages/yashil vora.jpg'; +import Mishka from '../../images/meettheteamImages/mishka.jpeg'; +import Angelina from '../../images/meettheteamImages/angelina yee.jpg'; +import Shreya from '../../images/meettheteamImages/shreya gupta.jpg'; +import Michael from '../../images/meettheteamImages/michael he.png'; +import Pranav_Soma from '../../images/meettheteamImages/Pranav_Soma.jpeg'; +import Nikitha_Maderamitla from '../../images/meettheteamImages/Nikitha_Maderamitla.jpg'; +import Hillary_Chang from '../../images/meettheteamImages/Hillary_Chang.webp'; +import Aditya_Kakarla from '../../images/meettheteamImages/Aditya_Kakarla.jpg'; +import Steven_Shi from '../../images/meettheteamImages/Steven_Shi.jpg'; +import Bhavik_Chandna from '../../images/meettheteamImages/Bhavik_Chandna.jpg'; +import Aryamun_Das from '../../images/meettheteamImages/Ryan_Das.jpeg'; +import Lucas_Hlaing from '../../images/meettheteamImages/Lucas_Hiaing.jpeg'; +import Yash_Ravipati from '../../images/meettheteamImages/Yash_Ravipati.jpg'; +import Jake from '../../images/meettheteamImages/jake villaseno.jpeg'; + +export interface TeamMember { + name: string; + role: string; + photo: string; + community: EventCategory; +} + +export const TEAM_MEMBERS: TeamMember[] = [ + // General + { name: 'Pranav Soma', role: 'President', photo: Pranav_Soma, community: 'General' }, + { name: 'Michael He', role: 'VP External', photo: Michael, community: 'General' }, + { name: 'Sithu Soe', role: 'VP Operations', photo: Sithu, community: 'General' }, + { name: 'Lucas Hlaing', role: 'Finance Director', photo: Lucas_Hlaing, community: 'General' }, + { name: 'Angelina Yee', role: 'Marketing Chair', photo: Angelina, community: 'General' }, + { + name: 'Hillary Chang', + role: 'Corporate Connections Director', + photo: Hillary_Chang, + community: 'General', + }, + + // Open-Source + { name: 'Yashil Vora', role: 'President', photo: Yashil, community: 'Open-Source' }, + { name: 'Mishka Jethwani', role: 'VP Operations', photo: Mishka, community: 'Open-Source' }, + { name: 'Yash Ravipati', role: 'VP Tech', photo: Yash_Ravipati, community: 'Open-Source' }, + + // Innovate + { name: 'Pranav Soma', role: 'President', photo: Pranav_Soma, community: 'Innovate' }, + { name: 'Aryamun Das', role: 'Founder', photo: Aryamun_Das, community: 'Innovate' }, + { + name: 'Nikitha Maderamitla', + role: 'Internal Director', + photo: Nikitha_Maderamitla, + community: 'Innovate', + }, + { name: 'Aditya Kakarla', role: 'External Director', photo: Aditya_Kakarla, community: 'Innovate' }, + { name: 'Bhavik Chandna', role: 'Project Lead', photo: Bhavik_Chandna, community: 'Innovate' }, + + // Dev + { name: 'Shreya Gupta', role: 'President', photo: Shreya, community: 'Dev' }, + { name: 'Steven Shi', role: 'VP Products', photo: Steven_Shi, community: 'Dev' }, + { name: 'Jake Villasenor', role: 'VP Design', photo: Jake, community: 'Dev' }, +]; diff --git a/frontend/src/components/Membership/EventsDashboard.tsx b/frontend/src/components/Membership/EventsDashboard.tsx index 5d3ed87f..5fcfb9f6 100644 --- a/frontend/src/components/Membership/EventsDashboard.tsx +++ b/frontend/src/components/Membership/EventsDashboard.tsx @@ -22,20 +22,9 @@ import { LocalizationProvider } from '@mui/x-date-pickers/LocalizationProvider'; import { DateTimePicker } from '@mui/x-date-pickers/DateTimePicker'; import { useState, useEffect } from 'react'; import { eventListAPI, eventCreateAPI, eventDeleteAPI, eventUpdateAPI } from '../../api'; +import { MongoEvent } from '../../utils/types'; -interface Event { - title: string; - start_time: string; - end_time: string; - location: string; - major_event: boolean; - description: string; - calendar_link: string; - instagram_link: string; - _id: string; - code: string; - qrCode: string; -} +type Event = MongoEvent; const style = { position: 'absolute' as 'absolute', diff --git a/frontend/src/components/NavBar/NavBar.tsx b/frontend/src/components/NavBar/NavBar.tsx index 0438ec50..7a44d668 100644 --- a/frontend/src/components/NavBar/NavBar.tsx +++ b/frontend/src/components/NavBar/NavBar.tsx @@ -11,17 +11,26 @@ import { Button, Toolbar, Avatar, + Menu, + MenuItem, } from '@mui/material'; -import { Menu as MenuIcon, Close as CloseIcon } from '@mui/icons-material'; +import { Menu as MenuIcon, Close as CloseIcon, ExpandMore } from '@mui/icons-material'; import { Link, useNavigate, useLocation } from 'react-router-dom'; -import csesLogo from '../../images/CSES-logo.png'; -import MuiButton from '../Button/Button'; +import csesLogo from '../../images/logo.png'; import { navBarStyles } from './styles'; import { AuthContext } from '../../context/AuthContext'; import ProfileDropdown from './ProfileDropdown'; import { User } from '../../utils/types'; import axios from 'axios'; +const COMMUNITY_ITEMS = [ + { text: 'Open-Source', link: '/opensourcecommunity' }, + { text: 'Innovate', link: '/innovatecommunity' }, + { text: 'Dev', link: '/devcommunity' }, +]; + +const CONTACT_EMAIL = 'mailto:cses@ucsd.edu'; + const NavBar = () => { const location = useLocation(); const styles = navBarStyles(); @@ -29,16 +38,17 @@ const NavBar = () => { const [isDrawerOpen, setIsDrawerOpen] = useState(false); const [userData, setUserData] = useState(null); + const [communitiesAnchor, setCommunitiesAnchor] = useState(null); const { user, isLoggedIn } = useContext(AuthContext); const navItems = [ - { text: 'About', link: '/about' }, + { text: 'Home', link: '/' }, { text: 'Events', link: '/events' }, - { text: 'Sponsors', link: '/sponsorships' }, - { text: 'Initiatives', link: '/initiatives' }, ]; + const isCommunityRoute = COMMUNITY_ITEMS.some(({ link }) => location.pathname === link); + const clickItem = (link: string) => { setIsDrawerOpen(false); navigate(link); @@ -63,61 +73,67 @@ const NavBar = () => { return (
- + - + logo + at UC San Diego
{navItems.map(({ text, link }) => ( - ))} - {/* Gradient Join Us Button */} - {/* {!isLoggedIn && location.pathname !== '/login' && ( - navigate('/login')} - sx={{ - cursor: 'pointer', - background: 'linear-gradient(to left, #725DEF, #63CDDB, #EBB211)', - padding: '2px', - borderRadius: '999px', - display: 'inline-flex', - marginLeft: '12px', - }} - > - } + onClick={(e) => setCommunitiesAnchor(e.currentTarget)} + sx={{ + ...styles.button, + ...(isCommunityRoute ? styles.buttonActive : {}), + }} + > + Communities + + setCommunitiesAnchor(null)} + sx={styles.menu} + > + {COMMUNITY_ITEMS.map(({ text, link }) => ( + { + setCommunitiesAnchor(null); + navigate(link); }} > - - Join Us - - - - )} */} + {text} + + ))} + + + {isLoggedIn && userData && ( @@ -139,17 +155,10 @@ const NavBar = () => { - - setIsDrawerOpen(false)}> - + { ))} - {/* {!isLoggedIn && location.pathname !== '/login' && ( - clickItem('/login')}> + {COMMUNITY_ITEMS.map(({ text, link }) => ( + clickItem(link)}> - Join Us + {text} } /> - )} */} + ))} + + setIsDrawerOpen(false)} + > + + Contact Us + + } + /> +
diff --git a/frontend/src/components/NavBar/styles.ts b/frontend/src/components/NavBar/styles.ts index 61ea67d0..8e348e41 100644 --- a/frontend/src/components/NavBar/styles.ts +++ b/frontend/src/components/NavBar/styles.ts @@ -1,15 +1,52 @@ +import { colors, fonts, radii } from '../../theme'; + export const navBarStyles = () => ({ + appBar: { + backgroundColor: colors.background, + borderBottom: `1px solid ${colors.border}`, + }, + logoText: { + fontFamily: fonts.heading, + fontSize: { xs: '0.8rem', md: '0.95rem' }, + color: colors.textPrimary, + ml: 1, + display: { xs: 'none', sm: 'block' }, + }, button: { - fontSize: '20px', + fontSize: '1rem', color: 'white', textTransform: 'none', - fontFamily: 'Inter, sans-serif', - fontWeight: 'medium', - margin: '10px', + fontFamily: fonts.body, + fontWeight: 500, + margin: '10px 4px', + px: 2.5, + borderRadius: radii.pill, + }, + buttonActive: { + backgroundColor: colors.purpleBright, + '&:hover': { backgroundColor: colors.purpleBright }, + }, + menu: { + '& .MuiPaper-root': { + backgroundColor: colors.surface, + border: `1px solid ${colors.border}`, + color: colors.textPrimary, + }, + }, + menuItem: { + fontFamily: fonts.body, + fontSize: '0.95rem', + '&:hover': { backgroundColor: 'rgba(114, 93, 240, 0.15)' }, + }, + drawerList: { + background: colors.background, + }, + drawerSubItem: { + pl: 6, }, listitem: { '&:hover': { - background: 'rgba(255, 255, 255, 0.1)', + background: 'rgba(114, 93, 240, 0.15)', }, }, menuicon: { fontSize: '35px', margin: '10px' }, diff --git a/frontend/src/components/common/SegmentedTabs.tsx b/frontend/src/components/common/SegmentedTabs.tsx new file mode 100644 index 00000000..ffed56c7 --- /dev/null +++ b/frontend/src/components/common/SegmentedTabs.tsx @@ -0,0 +1,53 @@ +import { Box, ButtonBase } from '@mui/material'; +import { colors, fonts, radii } from '../../theme'; + +interface SegmentedTabsProps { + options: string[]; + value: string; + onChange: (value: string) => void; +} + +const SegmentedTabs = ({ options, value, onChange }: SegmentedTabsProps) => { + return ( + + {options.map((option) => ( + onChange(option)} + sx={{ + flex: 1, + minWidth: 'fit-content', + px: { xs: 2, md: 4 }, + py: 1, + borderRadius: radii.pill, + fontFamily: fonts.body, + fontSize: { xs: '0.8rem', md: '0.95rem' }, + fontWeight: 500, + whiteSpace: 'nowrap', + color: colors.textPrimary, + backgroundColor: option === value ? colors.purpleBright : 'transparent', + transition: 'background-color 0.2s ease', + '&:hover': { + backgroundColor: option === value ? colors.purpleBright : 'rgba(114, 93, 240, 0.15)', + }, + }} + > + {option} + + ))} + + ); +}; + +export default SegmentedTabs; diff --git a/frontend/src/index.css b/frontend/src/index.css index 92553ef4..c28b7781 100644 --- a/frontend/src/index.css +++ b/frontend/src/index.css @@ -4,7 +4,7 @@ html { font-family: Inter, Chakra Petch, sans-serif; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; - background-color:#020f5d; + background-color: #07070f; } code { diff --git a/frontend/src/theme.ts b/frontend/src/theme.ts new file mode 100644 index 00000000..cb3c0894 --- /dev/null +++ b/frontend/src/theme.ts @@ -0,0 +1,26 @@ +// Design tokens for the 2026 redesign (Figma: "CSES Website 2026 Redesign"). +export const colors = { + background: '#07070F', + surface: '#0A0A10', + border: 'rgba(114, 93, 240, 0.35)', + purple: '#725DF0', + // Filled buttons use a brighter purple than outlines and accents do. + purpleButton: '#8650F0', + purpleBright: '#8B2BF0', + navy: '#020F5D', + gold: '#EBB111', + mint: '#5DF0C4', + lightBlue: '#64C3E3', + textPrimary: '#FFFFFF', + textSecondary: 'rgba(255, 255, 255, 0.7)', +}; + +export const fonts = { + heading: `'Space Mono', 'Chakra Petch', monospace`, + body: `'Space Grotesk', 'Inter', sans-serif`, +}; + +export const radii = { + card: '12px', + pill: '999px', +}; diff --git a/frontend/src/utils/types.tsx b/frontend/src/utils/types.tsx index 6637d43a..5d6a75a7 100644 --- a/frontend/src/utils/types.tsx +++ b/frontend/src/utils/types.tsx @@ -1,3 +1,37 @@ +export type EventCategory = 'General' | 'Open-Source' | 'Innovate' | 'Dev'; + +// Event stored in MongoDB (admin dashboard / QR check-in system). +export interface MongoEvent { + _id: string; + title: string; + start_time: string; + end_time: string; + location: string; + description: string; + calendar_link: string; + instagram_link: string; + event_type?: string; + major_event: boolean; + code: string; + qrCode: string; +} + +// Event synced from the cses@ucsd.edu Google Calendar. +export interface CalendarEvent { + id: string; + title: string; + description: string; + location: string; + start: string; + end: string; + allDay: boolean; + htmlLink: string; + category: EventCategory; + // Free-form label shown under the title (e.g. "Social", "Career"), set on the + // calendar event itself. Empty when the organizer didn't tag the event. + type: string; +} + export interface User { name: string; email: string;