diff --git a/app/archive/[slug]/page.tsx b/app/archive/[slug]/page.tsx new file mode 100644 index 0000000..22358b6 --- /dev/null +++ b/app/archive/[slug]/page.tsx @@ -0,0 +1,18 @@ +"use client" +import '@/src/styles/reset.scss'; + +import NavigationBar from '@/src/components/navbar'; +import ProjectDetail from '@/src/sections/ProjectDetail'; +import Footer from '@/src/components/footer'; + +const ProjectPage = ({ params }: { params: { slug: string } }) => { + return ( +
+ + +
+ ); +}; + +export default ProjectPage; diff --git a/app/layout.tsx b/app/layout.tsx index a120171..cf01f3a 100644 --- a/app/layout.tsx +++ b/app/layout.tsx @@ -2,7 +2,7 @@ import "./globals.css"; import type { Metadata } from "next"; import { DM_Sans } from "next/font/google"; -const dm_sans = DM_Sans({ subsets: ["latin"], weight: "400" }); +const dm_sans = DM_Sans({ subsets: ["latin"], weight: ["200", "400", "500", "600", "700", "800"] }); export const metadata: Metadata = { title: "ACM at UC San Diego Projects Website", diff --git a/app/page.tsx b/app/page.tsx index d24ed3b..380f50c 100644 --- a/app/page.tsx +++ b/app/page.tsx @@ -5,12 +5,18 @@ import "../src/styles/reset.scss"; import NavigationBar from "@/src/components/navbar"; import Footer from "@/src/components/footer"; import Hero from "@/src/sections/Hero"; +import FAQ from "@/src/sections/FAQ"; +import Timeline from "@/src/sections/Timeline"; +import HomePastProjects from "@/src/sections/Home-Past-Projects"; // here we will compile all the sections of the website together const Home: NextPage = () => { return (
+ + +
); diff --git a/public/assets/chevron-down.svg b/public/assets/chevron-down.svg new file mode 100644 index 0000000..5af78b8 --- /dev/null +++ b/public/assets/chevron-down.svg @@ -0,0 +1,3 @@ + + + diff --git a/public/assets/countdown_image.png b/public/assets/countdown_image.png new file mode 100644 index 0000000..46fa833 Binary files /dev/null and b/public/assets/countdown_image.png differ diff --git a/public/assets/embeds/figma-icon.svg b/public/assets/embeds/figma-icon.svg new file mode 100644 index 0000000..cd15c45 --- /dev/null +++ b/public/assets/embeds/figma-icon.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/public/assets/embeds/github-icon.svg b/public/assets/embeds/github-icon.svg new file mode 100644 index 0000000..c097de2 --- /dev/null +++ b/public/assets/embeds/github-icon.svg @@ -0,0 +1,3 @@ + + + diff --git a/public/assets/hero-gradient-mobile.png b/public/assets/hero-gradient-mobile.png new file mode 100644 index 0000000..a3b5be6 Binary files /dev/null and b/public/assets/hero-gradient-mobile.png differ diff --git a/public/assets/hero-gradient.png b/public/assets/hero-gradient.png new file mode 100644 index 0000000..32ee658 Binary files /dev/null and b/public/assets/hero-gradient.png differ diff --git a/public/assets/navbar_proj_logo.svg b/public/assets/navbar_proj_logo.svg new file mode 100644 index 0000000..4109c05 --- /dev/null +++ b/public/assets/navbar_proj_logo.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/public/assets/proj_logo.svg b/public/assets/proj_logo.svg index 4109c05..064606e 100644 --- a/public/assets/proj_logo.svg +++ b/public/assets/proj_logo.svg @@ -1,5 +1,4 @@ - - - - + + + diff --git a/public/assets/robo.svg b/public/assets/robo.svg new file mode 100644 index 0000000..ace28cc --- /dev/null +++ b/public/assets/robo.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/public/assets/timeline_component_image.jpg b/public/assets/timeline_component_image.jpg new file mode 100644 index 0000000..a4ecc44 Binary files /dev/null and b/public/assets/timeline_component_image.jpg differ diff --git a/src/components/banner/index.tsx b/src/components/banner/index.tsx deleted file mode 100644 index 9ed6fcc..0000000 --- a/src/components/banner/index.tsx +++ /dev/null @@ -1,58 +0,0 @@ -"use client"; - -import { useState, useEffect } from "react"; -import styles from "./style.module.scss"; - -const Banner = () => { - const [days, setDays] = useState(0); - const [hours, setHours] = useState(0); - const [minutes, setMinutes] = useState(0); - const [seconds, setSeconds] = useState(0); - - useEffect(() => { - const target = new Date("04/02/2024 23:59:59"); - - const interval = setInterval(() => { - const now = new Date(); - const difference = target.getTime() - now.getTime(); - - if (difference <= 0) { - // The target date has passed, set all values to zero - setDays(0); - setHours(0); - setMinutes(0); - setSeconds(0); - clearInterval(interval); - } else { - const d = Math.floor(difference / (1000 * 60 * 60 * 24)); - setDays(d); - - const h = Math.floor( - (difference % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60) - ); - setHours(h); - - const m = Math.floor((difference % (1000 * 60 * 60)) / (1000 * 60)); - setMinutes(m); - - const s = Math.floor((difference % (1000 * 60)) / 1000); - setSeconds(s); - } - }, 1000); - - return () => clearInterval(interval); - }, []); - - return ( -
-
- Projects applications close in{" "} - - {days} days {hours} hours {minutes} minutes {seconds} seconds - -
-
- ); -}; - -export default Banner; diff --git a/src/components/banner/style.module.scss b/src/components/banner/style.module.scss deleted file mode 100644 index ae815cf..0000000 --- a/src/components/banner/style.module.scss +++ /dev/null @@ -1,18 +0,0 @@ -@use "../../styles/vars.scss" as v; // allows you to use pre-defined colors - -.bannerbg { - background-color: v.$acm-blue-30 !important; - text-align: center; - padding: 0.3rem; -} - -@media screen and (max-width: 768px) { - .bannerbg { - display: flex; - flex-direction: column; - } -} - -.date { - font-weight: 700; -} diff --git a/src/components/countdown/index.tsx b/src/components/countdown/index.tsx new file mode 100644 index 0000000..2258646 --- /dev/null +++ b/src/components/countdown/index.tsx @@ -0,0 +1,66 @@ +"use client"; + +import { useState, useEffect } from "react"; +import styles from "./style.module.scss"; + +type CountdownProps = { + className?: string; +}; + +const Countdown = ({ className = "" }: CountdownProps) => { + const [days, setDays] = useState(0); + const [hours, setHours] = useState(0); + const [minutes, setMinutes] = useState(0); + const [seconds, setSeconds] = useState(0); + let countdownComponents : number[] = [days, hours, minutes, seconds]; + + useEffect(() => { + const target = new Date("10/02/2026 23:59:59"); + + const interval = setInterval(() => { + const now = new Date(); + const difference = target.getTime() - now.getTime(); + + if (difference <= 0) { + setDays(0); + setHours(0); + setMinutes(0); + setSeconds(0); + countdownComponents = [days, hours, minutes, seconds]; + clearInterval(interval); + } else { + setDays(Math.floor(difference / (1000 * 60 * 60 * 24))); + setHours( + Math.floor( + (difference % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60) + ) + ); + setMinutes( + Math.floor((difference % (1000 * 60 * 60)) / (1000 * 60)) + ); + setSeconds(Math.floor((difference % (1000 * 60)) / 1000)); + countdownComponents = [days, hours, minutes, seconds]; + } + }, 1000); + + return () => clearInterval(interval); + }, []); + + return ( +
+ {countdownComponents.map((comp, key) => { + const digits = String(comp).padStart(2, '0').split(''); + + return ( + + {digits[0]} + {digits[1]} + {key < 3 ? : : null} + + ); + })} +
+ ); +}; + +export default Countdown; diff --git a/src/components/countdown/style.module.scss b/src/components/countdown/style.module.scss new file mode 100644 index 0000000..f519abb --- /dev/null +++ b/src/components/countdown/style.module.scss @@ -0,0 +1,13 @@ +@use "../../styles/vars.scss" as v; // allows you to use pre-defined colors + +.date { + color: black; + font-size: 1.25rem; + font-weight: 700; + + .digit { + display: inline-block; + width: 1ch; + text-align: center; + } +} diff --git a/src/components/footer/styles.module.scss b/src/components/footer/styles.module.scss index 6cd93a1..d510885 100644 --- a/src/components/footer/styles.module.scss +++ b/src/components/footer/styles.module.scss @@ -8,7 +8,7 @@ $mmmw: 375px; // medium mobile max width .footer { width: 100%; height: 100%; - background-color: vars.$footer-blue; + background-color: vars.$proj-blue; color: vars.$white; z-index: 0; position: relative; @@ -224,4 +224,4 @@ $mmmw: 375px; // medium mobile max width } } } -} +} \ No newline at end of file diff --git a/src/components/navbar/Navbar.module.scss b/src/components/navbar/Navbar.module.scss index f0c82c1..05acdd9 100644 --- a/src/components/navbar/Navbar.module.scss +++ b/src/components/navbar/Navbar.module.scss @@ -9,19 +9,40 @@ $stmw: 956px; // small tablet max width // Base styles (Regular desktop view) .navbarWrapper { + $vert-padding: 1.25rem; + position: sticky; top: 0; font-weight: 400; width: 100%; + height: auto; z-index: 10; white-space: nowrap; - background-color: vars.$white; // this is a placeholder; the navbar bg color needs to match the page's bg color (bc of the gradient on the landing page) + background-color: vars.$white; + + .gradientWrapper { + position: absolute; + z-index: -10; + width: 100%; + height: $vert-padding * 2 + 3rem; // 3rem-tall project logo + background-color: vars.$white; + overflow: hidden; + + .gradient { + width: 100%; + height: 85rem; + user-select: none; + will-change: transform; + + @media screen and (max-width: 920px) { + height: 50rem; + } + } + } // container for fixed navbar (desktop and mobile) .navbar { - $vert-padding: 1.25rem; - - background-color: vars.$white; // this is a placeholder; the navbar bg color needs to match the page's bg color (bc of the gradient on the landing page) + position: relative; z-index: 20; width: 100%; justify-content: space-between; @@ -52,7 +73,7 @@ $stmw: 956px; // small tablet max width cursor: pointer; } - // left side of navbar is just the acm logo + // left side of navbar is just the project logo .left { display: flex; flex-flow: row nowrap; @@ -66,7 +87,7 @@ $stmw: 956px; // small tablet max width .logoText { font-size: 1.375rem; font-weight: 700; - color: vars.$proj-blue; + color: vars.$proj-blue-2; margin: 0; margin-left: 0.5rem; } @@ -97,7 +118,7 @@ $stmw: 956px; // small tablet max width padding: 0.64rem 0; gap: 0.257813333rem; border: none; - background-color: vars.$white; + background-color: transparent; // the toggle icon is composed of two bars we can separately animate between a hamburger icon and an x icon (default is hamburger, we have .open class we can toggle to rotate into the shape of an x) .bar1 { @@ -135,7 +156,6 @@ $stmw: 956px; // small tablet max width .mobileNav { width: 100%; - background-color: vars.$white; position: absolute; z-index: -1; display: flex; @@ -143,11 +163,10 @@ $stmw: 956px; // small tablet max width justify-content: center; align-items: center; line-height: $mobileNav-line-height; - // mobile menu is hidden by positioning under fixed navbar by moving the top margin up; we open it by sliding it out w/ transition and changing margin-top to 0 + // mobile menu is hidden by positioning under fixed navbar by moving the top margin up; we open it by sliding it out w/ transition (in index.tsx) and changing margin-top to 0 margin-top: -1 * $num-navItems * ($mobileNav-line-height + $navItem-margin-bottom); - border-bottom: $bottom-border-width solid vars.$proj-blue; - transition: margin-top 0.3s ease-in-out; + border-bottom: $bottom-border-width solid vars.$proj-blue-2; a { text-decoration: none; @@ -155,13 +174,20 @@ $stmw: 956px; // small tablet max width &.open { margin-top: 0; + + .navItem { + color: vars.$black; + user-select: auto; + } } + .navItem { margin-bottom: $navItem-margin-bottom; text-align: center; font-size: 1.125rem; font-weight: 700; - color: vars.$black; + color: transparent; + user-select: none; &:hover { text-decoration: underline solid currentColor; @@ -173,9 +199,17 @@ $stmw: 956px; // small tablet max width // Small tablet view (956px) @media only screen and (max-width: $stmw) { .navbarWrapper { - .navbar { - $vert-padding: 0.72rem; + $vert-padding: 0.72rem; + + .gradientWrapper { + height: $vert-padding * 2 + 5.06rem; // 3rem-tall project logo + 2.06rem top padding + &.mobileNavOpen { + height: ($vert-padding * 2 + 5.06rem) + ($num-navItems * ($mobileNav-line-height + $navItem-margin-bottom)); + } + } + + .navbar { padding: calc($vert-padding + 2.06rem) 1.38rem @@ -192,4 +226,4 @@ $stmw: 956px; // small tablet max width } } } -} +} \ No newline at end of file diff --git a/src/components/navbar/index.tsx b/src/components/navbar/index.tsx index 4297c0f..b9c497b 100644 --- a/src/components/navbar/index.tsx +++ b/src/components/navbar/index.tsx @@ -1,11 +1,14 @@ "use client"; +import Image from "next/image"; import Link from "next/link"; import { useEffect, useState } from "react"; import s from "./Navbar.module.scss"; import { Size, useWindowSize } from "../../utils/general"; -const ProjLogo = "/assets/proj_logo.svg"; +const ProjLogo = "/assets/navbar_proj_logo.svg"; +const Gradient = "/assets/hero-gradient.png"; +const GradientMobile = "/assets/hero-gradient-mobile.png"; // Nav link properties const navLinks = [ @@ -16,23 +19,69 @@ const navLinks = [ { href: "/about", label: "About" }, ]; +const DESKTOP_GRADIENT_HEIGHT = 85 * 18; // 85rem for 18px font +const MOBILE_GRADIENT_HEIGHT = 50 * 18; // 50rem for 18px font + // Main navbar component const NavigationBar: React.FC = () => { const size: Size = useWindowSize(); // size.width !== undefined determines whether the viewport has rendered yet const mobile = size.width !== undefined && size.width <= 956; + const mobileGrad = size.width !== undefined && size.width <= 920; const [menuOpen, setMenuOpen] = useState(false); - const toggleMenu = () => setMenuOpen(!menuOpen); + const [gradientOffset, setGradientOffset] = useState(0); + const [isTransitioning, setIsTransitioning] = useState(false); + + const toggleMenu = () => { + setMenuOpen(!menuOpen); + setIsTransitioning(true); + + setTimeout(() => { + setIsTransitioning(false); + }, 300); + } // close the mobile menu if no longer within mobile viewport width useEffect(() => { if (!mobile) setMenuOpen(false); }, [mobile]); + useEffect(() => { + const gradientHeight = mobileGrad + ? MOBILE_GRADIENT_HEIGHT + : DESKTOP_GRADIENT_HEIGHT; + + const handleScroll = () => { + // stop scrolling once gradient image height reached + setGradientOffset(Math.min(window.scrollY, gradientHeight)); + }; + + handleScroll(); + + window.addEventListener("scroll", handleScroll, { passive: true }); + return () => window.removeEventListener("scroll", handleScroll); + }, [mobileGrad]); + return (
+
+ Gradient +
+
{/* Projects Logo */}
@@ -65,10 +114,19 @@ const NavigationBar: React.FC = () => {
{/* Mobile Menu Dropdown */} -
+
{navLinks.map((link, key) => ( -

setMenuOpen(false)}> +

setMenuOpen(false)} + style={isTransitioning ? {transition: "color 0.1s linear"} : {}} + > {link.label}

@@ -78,4 +136,4 @@ const NavigationBar: React.FC = () => { ); }; -export default NavigationBar; +export default NavigationBar; \ No newline at end of file diff --git a/src/components/project-card/highlighted.json b/src/components/project-card/highlighted.json new file mode 100644 index 0000000..7db038f --- /dev/null +++ b/src/components/project-card/highlighted.json @@ -0,0 +1,5 @@ +[ + "sp23-hack-1", + "wi23-design-1", + "fa22-ai-1" +] diff --git a/src/components/project-card/index.tsx b/src/components/project-card/index.tsx index 541c8af..c2f040b 100644 --- a/src/components/project-card/index.tsx +++ b/src/components/project-card/index.tsx @@ -1,148 +1,156 @@ +'use client' +import { useEffect, useLayoutEffect, useRef } from "react"; import s from "./style.module.scss"; +import projects_data from "./projects.json"; +import highlighted_ids from "./highlighted.json"; -// Images for embed links and other logos - -const default_pic = "/assets/proj_logo.png"; -const figma = "/assets/embeds/figma.png"; -const github = "/assets/embeds/github.png"; -const slides = "/assets/embeds/slides.png"; -const other_links = "/assets/embeds/other_links.png"; -const hack_logo = "/assets/hack.svg"; -const design_logo = "/assets/design.svg"; -const ai_logo = "/assets/ai.svg"; - -const projects_data = [ - {"quarter": "Spring 2023", - "subgroup": "Hack", - "project_title": "Word Nerd", - "team_name": "Team 1", - "logo": "/assets/project_logos/word_nerd.png", - "description": "We created a clone of the game CodeNames, except that users have the option to upload their own words so they can follow a theme or use it as a unique way to study vocab concepts with friends.", - "mentor": "Sujal", - "members": ["Greg Weber (Front-end)", "Julie Nguyen (Front-end)", "Josh Chen (Front-end)", "Tim Liu (Back-end)", "Gonzalo Allen-Perez (Back-end)", "Annie Ping (Back-end)"], - "slides": "https://docs.google.com/presentation/d/1xPRnYbfmZHW8l7_jo7gmTAxowV3PmLO39MvzfHht_Dk/edit?usp=sharing", - "project_link": "https://github.com/acmucsd-projects/sp23-hack-team-1", - "other_links": "https://codenames-acm.netlify.app/" +const SUBGROUP_CONFIG: Record = { + Design: { + logo: "/assets/design.svg", + border: s.borderDesign, + color: s.colorDesign, + repoIcon: "/assets/embeds/figma-icon.svg", + repoLabel: "Figma", }, - {"quarter": "Spring 2023", - "subgroup": "Hack", - "project_title": "GAMED", - "team_name": "Team 2", - "logo": "/assets/project_logos/gamed.png", - "description": "We created a website where UCSD students can find other players to play video games with. They can do this by creating an account, creating cards, and sending cards to people!.", - "mentor": "Shreya Nagunuri and Kevin Wu", - "members": ["Calvin Nguyen (Front-end)", "Kane Li (Full-stack)"], - "slides": "https://docs.google.com/presentation/d/1W-3JfpnNEghKXsuuCe1638ZBUkyCkntRNy6yUnFhr_4/edit?usp=sharing", - "project_link": "https://github.com/acmucsd-projects/sp23-hack-team-2", - "other_links": "https://ucsdgamed.onrender.com/" + Hack: { + logo: "/assets/hack.svg", + border: s.borderHack, + color: s.colorHack, + repoIcon: "/assets/embeds/github-icon.svg", + repoLabel: "GitHub File", }, - {"quarter": "Spring 2023", - "subgroup": "Hack", - "project_title": "Eventify", - "team_name": "Team 3", - "logo": "/assets/project_logos/eventify.png", - "description": "We created a website that can track on-campus UCSD events.", - "mentor": "Angela Hu and Charvi Shukla", - "members": ["Gavyn Ezell", "Cho Jung (Angela) Tsai", "Qijun (Mary) Hu", "Jae Whan Lee", "Rachel Chau", "Willey Zhou"], - "slides": "https://docs.google.com/presentation/d/1U93WsdyVuFDbvgWZ931oakEpL7zgzbZz8vNolmMZtFI/edit?usp=sharing", - "project_link": "https://github.com/acmucsd-projects/sp23-hack-team-3", - "other_links": "https://www.figma.com/file/KqvP7N6lLUu8NnT2ZnYK3o/Eventify?type=design&node-id=0%3A1&mode=design&t=hnFUTSx4agxe4CNT-1" + AI: { + logo: "/assets/ai.svg", + border: s.borderAI, + color: s.colorAI, + repoIcon: "/assets/embeds/github-icon.svg", + repoLabel: "GitHub File", }, - {"quarter": "Winter 2023", - "subgroup": "Hack", - "project_title": "IGFood", - "team_name": "Team 1", - "logo": "/assets/project_logos/ig_food.svg", - "description": "Yelp and Google Reviews are written by strangers that you cannot necessarily trust. Our solution is to create an application which creates a more personalized food-rating experience! The application connects you to your friends and allows you to see what/where your friends are eating via posts on a feed.", - "mentor": "Nikhil Dange", - "members": ["Angela Hu (Project Lead/Front-end)", "Nicholas Cheah (Front-end)", "Kinan Alatasi (Front-end)", "Alexis Vergnet (Back-end)", "Charvi Shukla (Back-end)", "Jason Wong (Back-end)"], - "slides": "https://docs.google.com/presentation/d/1g0pEKT7Rx_hoZDnC27zxxPs2UqipDLffgUC0Z0v5xUE/edit?usp=sharing", - "project_link": "https://github.com/acmucsd-projects/wi23-hack-team-1", - "other_links": "https://www.figma.com/file/lX9VzkvBHesJT4e2zK6LOr/IGFood-Web-App-Design?type=design&node-id=0%3A1&mode=design&t=Z6gg0vyLGspHj7r5-1" + Robotics: { + logo: "/assets/robo.svg", + border: s.borderRobotics, + color: s.colorRobotics, + repoIcon: "/assets/embeds/github-icon.svg", + repoLabel: "GitHub File", }, - {"quarter": "Winter 2023", - "subgroup": "Design", - "project_title": "Triton2Go Redesign", - "team_name": "Team 1", - "description": "Recognizing the indispensable role of food ordering apps in the UCSD students’ daily lives, our team aimed to focus on the official food ordering mobile app Triton2Go (Mobile Order) by redesigning both the visual layouts and content layouts to optimize the user interface, streamline the ordering process, incorporate engaging gamification elements in rewards store to encourage user loyalty and satisfaction. We hope to help our target users and make the end process intelligent, enjoyable, and productive.", - "mentor": "Anmol", - "members": ["Cindy Peng (Project Lead)", "Thomas Wang", "Dianne Natanauan", "Amy To"], - "slides": "https://docs.google.com/presentation/d/1eCxEr19T1yPc1zffcvXHE9n0KPUSUy6G87tE_Ub_9Fk/edit?usp=sharing", - "project_link": "https://www.figma.com/file/0r2ncVSKHqBY9pOQCGrHvq/Mobile-Order-Prototypes?type=design&node-id=0%3A1&t=33a883iMHphAA1U1-1" - }, - {"quarter": "Fall 2022", - "subgroup": "AI", - "project_title": "Supreme Court Predictor", - "team_name": "Team 1", - "description": "Using machine learning, predict the outcomes of Supreme Court Cases (whether they are conservative, liberal, or unspecifiable).", - "mentor": "Stephanie", - "members": ["Jenny Mar", "Nitya Pillai", "Ada He", "Han Hoang", "Rushil Chandrupatla", "Serena Chen"], - "slides": "https://docs.google.com/presentation/d/1qANpLZvhv5F0lOkbUxtlJU5UF4KqsDzuy0Dy6E2BG-0/edit?usp=sharing", - "project_link": "https://github.com/acmucsd-projects/fa22-ai-team-1", - "other_links": "https://deepnote.com/join-team?token=02d34e715c9e4f6" - }, - {"quarter": "Fall 2022", - "subgroup": "AI", - "project_title": "GAIN: Gamers for Artificial Intelligence and NLP", - "team_name": "Team 2", - "description": "Using NLP and Machine Learning, created a Political Sentiment Classifier that can address blocks of texts and determine whether they are politically charged and classify them as Liberal or Democratic. ", - "mentor": "Weiji Chen", - "members": ["Samvrit Srinath", "Calvin Nguyen", "Peter Gao", "Benjamin Johnson", "Skyler Goh", "Joon Kim"], - "slides": "https://docs.google.com/presentation/d/1s7W3E9Wv5RXAzmgQYjCN166xycIJuxyFnCbs_IpVBlw/edit?usp=sharing", - "project_link": "https://github.com/acmucsd-projects/fa22-ai-team-2", - "other_links": "https://colab.research.google.com/drive/1zfL2UtCyJnwAMzqeAAvfTigUU6rVxCca?usp=sharing" - }, - {"quarter": "Fall 2022", - "subgroup": "Design", - "project_title": "UCSD App Redesign", - "team_name": "Team 1", - "description": "We redesigned the UCSD mobile app to increase its functionality and aesthetic appeal, helping students navigate it with more ease, efficiency, and less confusion.", - "mentor": "Anthony Manrique", - "members": ["Tammy Ding","Khoi Nguyen", "Caitlyn Cielo", "Sashwat Nayak"], - "slides": "https://docs.google.com/presentation/d/1NBU4o8cFqalW_I9UUo_t_h7XsHVtjGcQ7hVZUzqO0qg/edit?usp=sharing", - "project_link": "https://www.figma.com/file/8kuHJXTZcIGVjm88OCYi1W/Final-Draft?type=design&node-id=1%3A2&t=K7vUmdAhPcQpWj6O-1" - }, -]; +}; + +const DEFAULT_CONFIG = { + logo: "/assets/proj_logo.png", + border: "", + color: "", + repoIcon: "/assets/embeds/github-icon.svg", + repoLabel: "GitHub File", +}; interface ProjectProps { quarter: string; + highlighted?: boolean; + subgroup?: string | null; } -const ProjectCards: React.FC = ({quarter}) => { - const filteredProjects = quarter === "All" ? projects_data : projects_data.filter((project) => - project.quarter === quarter - ); +const ProjectCards: React.FC = ({ quarter, highlighted, subgroup }) => { + let projects = quarter === "All" + ? projects_data + : projects_data.filter((project) => project.quarter === quarter); + + if (subgroup) { + projects = projects.filter((project) => project.subgroup === subgroup); + } + + if (highlighted !== undefined) { + projects = projects.filter((project) => + highlighted ? highlighted_ids.includes(project.id) : !highlighted_ids.includes(project.id) + ); + } + + projects = [...projects].sort((a, b) => a.team_name.localeCompare(b.team_name)); + + const descWrapperRefs = useRef<(HTMLDivElement | null)[]>([]); + + const updateClamps = () => { + const wrappers = descWrapperRefs.current; + if (!wrappers) return; + for (const wrapper of wrappers) { + if (!wrapper) continue; + const p = wrapper.querySelector("p") as HTMLParagraphElement | null; + if (!p) continue; + p.style.webkitLineClamp = "unset"; + const availableHeight = wrapper.clientHeight; + const lineHeight = parseFloat(getComputedStyle(p).lineHeight); + const lines = Math.max(1, Math.floor(availableHeight / lineHeight)); + p.style.webkitLineClamp = String(lines); + } + }; + + useLayoutEffect(() => { updateClamps(); }, [projects.length]); + + useEffect(() => { + window.addEventListener("resize", updateClamps); + return () => window.removeEventListener("resize", updateClamps); + }, []); + return (
- {filteredProjects && filteredProjects.map((project, index) => ( -
-
-
- Community Logo -

{project.quarter} {project.subgroup} {project.team_name}

+ {projects.map((project, index) => { + const config = SUBGROUP_CONFIG[project.subgroup] ?? DEFAULT_CONFIG; + return ( +
+
+ {`${project.subgroup} +
+ {project.quarter} + {project.subgroup} {project.team_name} +
+
+ +
+ {project.project_title} +
+ +

{project.project_title}

+ +
+

Created by: {project.members.join(", ")}

+

Mentored by: {project.mentors.join(", ")}

+ {project.technology && ( +

Technology: {project.technology}

+ )} +
+ +
{ descWrapperRefs.current[index] = el; }} + > +

{project.description}

+
+ +
+ + Explore Project + + {project.project_link && ( + + {config.repoLabel} + {config.repoLabel} + + )}
-

{project.project_title}

-
- Project Logo -
-

Project Description: {project.description}

-

Members: {project.members.join(", ")}

-

Mentor: {project.mentor}

-
-
- - Slides Logo - - Project Repo Logo - {project.other_links && ( - Other Links Logo - )}
-
- ))} + ); + })}
- ) -} + ); +}; -export default ProjectCards; \ No newline at end of file +export default ProjectCards; diff --git a/src/components/project-card/projects.json b/src/components/project-card/projects.json new file mode 100644 index 0000000..cd1e2aa --- /dev/null +++ b/src/components/project-card/projects.json @@ -0,0 +1,129 @@ +[ + { + "id": "sp23-hack-1", + "quarter": "Spring 2023", + "subgroup": "Hack", + "project_title": "Word Nerd", + "team_name": "Team 1", + "logo": "/assets/project_logos/word_nerd.png", + "description": "We created a clone of the game CodeNames, except that users have the option to upload their own words so they can follow a theme or use it as a unique way to study vocab concepts with friends.", + "mentors": ["Sujal"], + "members": ["Greg Weber", "Julie Nguyen", "Josh Chen", "Tim Liu", "Gonzalo Allen-Perez", "Annie Ping"], + "slides": "https://docs.google.com/presentation/d/1xPRnYbfmZHW8l7_jo7gmTAxowV3PmLO39MvzfHht_Dk/edit?usp=sharing", + "project_link": "https://github.com/acmucsd-projects/sp23-hack-team-1", + "other_links": "https://codenames-acm.netlify.app/", + "technology": null + }, + { + "id": "sp23-hack-2", + "quarter": "Spring 2023", + "subgroup": "Hack", + "project_title": "GAMED", + "team_name": "Team 2", + "logo": "/assets/project_logos/gamed.png", + "description": "We created a website where UCSD students can find other players to play video games with. They can do this by creating an account, creating cards, and sending cards to people!", + "mentors": ["Shreya Nagunuri", "Kevin Wu"], + "members": ["Calvin Nguyen", "Kane Li"], + "slides": "https://docs.google.com/presentation/d/1W-3JfpnNEghKXsuuCe1638ZBUkyCkntRNy6yUnFhr_4/edit?usp=sharing", + "project_link": "https://github.com/acmucsd-projects/sp23-hack-team-2", + "other_links": "https://ucsdgamed.onrender.com/", + "technology": null + }, + { + "id": "sp23-hack-3", + "quarter": "Spring 2023", + "subgroup": "Hack", + "project_title": "Eventify", + "team_name": "Team 3", + "logo": "/assets/project_logos/eventify.png", + "description": "We created a website that can track on-campus UCSD events.", + "mentors": ["Angela Hu", "Charvi Shukla"], + "members": ["Gavyn Ezell", "Cho Jung (Angela) Tsai", "Qijun (Mary) Hu", "Jae Whan Lee", "Rachel Chau", "Willey Zhou"], + "slides": "https://docs.google.com/presentation/d/1U93WsdyVuFDbvgWZ931oakEpL7zgzbZz8vNolmMZtFI/edit?usp=sharing", + "project_link": "https://github.com/acmucsd-projects/sp23-hack-team-3", + "other_links": "https://www.figma.com/file/KqvP7N6lLUu8NnT2ZnYK3o/Eventify?type=design&node-id=0%3A1&mode=design&t=hnFUTSx4agxe4CNT-1", + "technology": null + }, + { + "id": "wi23-hack-1", + "quarter": "Winter 2023", + "subgroup": "Hack", + "project_title": "IGFood", + "team_name": "Team 1", + "logo": "/assets/project_logos/ig_food.svg", + "description": "Yelp and Google Reviews are written by strangers that you cannot necessarily trust. Our solution is to create an application which creates a more personalized food-rating experience! The application connects you to your friends and allows you to see what/where your friends are eating via posts on a feed.", + "mentors": ["Nikhil Dange"], + "members": ["Angela Hu", "Nicholas Cheah", "Kinan Alatasi", "Alexis Vergnet", "Charvi Shukla", "Jason Wong"], + "slides": "https://docs.google.com/presentation/d/1g0pEKT7Rx_hoZDnC27zxxPs2UqipDLffgUC0Z0v5xUE/edit?usp=sharing", + "project_link": "https://github.com/acmucsd-projects/wi23-hack-team-1", + "other_links": "https://www.figma.com/file/lX9VzkvBHesJT4e2zK6LOr/IGFood-Web-App-Design?type=design&node-id=0%3A1&mode=design&t=Z6gg0vyLGspHj7r5-1", + "technology": null + }, + { + "id": "wi23-design-1", + "quarter": "Winter 2023", + "subgroup": "Design", + "project_title": "Triton2Go Redesign", + "team_name": "Team 1", + "description": "Recognizing the indispensable role of food ordering apps in the UCSD students' daily lives, our team aimed to focus on the official food ordering mobile app Triton2Go (Mobile Order) by redesigning both the visual layouts and content layouts to optimize the user interface, streamline the ordering process, incorporate engaging gamification elements in rewards store to encourage user loyalty and satisfaction. We hope to help our target users and make the end process intelligent, enjoyable, and productive.", + "mentors": ["Anmol"], + "members": ["Cindy Peng", "Thomas Wang", "Dianne Natanauan", "Amy To"], + "slides": "https://docs.google.com/presentation/d/1eCxEr19T1yPc1zffcvXHE9n0KPUSUy6G87tE_Ub_9Fk/edit?usp=sharing", + "project_link": "https://www.figma.com/file/0r2ncVSKHqBY9pOQCGrHvq/Mobile-Order-Prototypes?type=design&node-id=0%3A1&t=33a883iMHphAA1U1-1", + "technology": null + }, + { + "id": "fa22-ai-1", + "quarter": "Fall 2022", + "subgroup": "AI", + "project_title": "Supreme Court Predictor", + "team_name": "Team 1", + "description": "Using machine learning, predict the outcomes of Supreme Court Cases (whether they are conservative, liberal, or unspecifiable).", + "mentors": ["Stephanie"], + "members": ["Jenny Mar", "Nitya Pillai", "Ada He", "Han Hoang", "Rushil Chandrupatla", "Serena Chen"], + "slides": "https://docs.google.com/presentation/d/1qANpLZvhv5F0lOkbUxtlJU5UF4KqsDzuy0Dy6E2BG-0/edit?usp=sharing", + "project_link": "https://github.com/acmucsd-projects/fa22-ai-team-1", + "other_links": "https://deepnote.com/join-team?token=02d34e715c9e4f6", + "technology": null + }, + { + "id": "fa22-ai-2", + "quarter": "Fall 2022", + "subgroup": "AI", + "project_title": "GAIN: Gamers for Artificial Intelligence and NLP", + "team_name": "Team 2", + "description": "Using NLP and Machine Learning, created a Political Sentiment Classifier that can address blocks of texts and determine whether they are politically charged and classify them as Liberal or Democratic. ", + "mentors": ["Weiji Chen"], + "members": ["Samvrit Srinath", "Calvin Nguyen", "Peter Gao", "Benjamin Johnson", "Skyler Goh", "Joon Kim"], + "slides": "https://docs.google.com/presentation/d/1s7W3E9Wv5RXAzmgQYjCN166xycIJuxyFnCbs_IpVBlw/edit?usp=sharing", + "project_link": "https://github.com/acmucsd-projects/fa22-ai-team-2", + "other_links": "https://colab.research.google.com/drive/1zfL2UtCyJnwAMzqeAAvfTigUU6rVxCca?usp=sharing", + "technology": null + }, + { + "id": "fa22-design-1", + "quarter": "Fall 2022", + "subgroup": "Design", + "project_title": "UCSD App Redesign", + "team_name": "Team 1", + "description": "We redesigned the UCSD mobile app to increase its functionality and aesthetic appeal, helping students navigate it with more ease, efficiency, and less confusion.", + "mentors": ["Anthony Manrique"], + "members": ["Tammy Ding", "Khoi Nguyen", "Caitlyn Cielo", "Sashwat Nayak"], + "slides": "https://docs.google.com/presentation/d/1NBU4o8cFqalW_I9UUo_t_h7XsHVtjGcQ7hVZUzqO0qg/edit?usp=sharing", + "project_link": "https://www.figma.com/file/8kuHJXTZcIGVjm88OCYi1W/Final-Draft?type=design&node-id=1%3A2&t=K7vUmdAhPcQpWj6O-1", + "technology": null + }, + { + "id": "fa26-robotics-1", + "quarter": "Fall 2026", + "subgroup": "Robotics", + "project_title": "Robotics Project", + "team_name": "Team 1", + "description": "This is an example description of a robotics project.", + "mentors": ["John Doe"], + "members": ["John Doe"], + "slides": "", + "project_link": "https://github.com/acmucsd/projects-website", + "technology": null + } +] diff --git a/src/components/project-card/style.module.scss b/src/components/project-card/style.module.scss index 9efd54b..567917f 100644 --- a/src/components/project-card/style.module.scss +++ b/src/components/project-card/style.module.scss @@ -1,70 +1,215 @@ -@use "../../styles/vars.scss" as vars; // allows you to use pre-defined colors +@use "../../styles/vars.scss" as vars; .container { display: grid; - max-width: 95%; - margin: 0 auto; - grid-template-columns: repeat(auto-fit, minmax(20rem, 1fr)); - margin-top: 2rem; - margin-bottom: 2rem; - row-gap: 2rem; - column-gap: 2rem; - - .projectItem { - background-color: vars.$darker-white; - display: flex; - flex-direction: column; - justify-content: flex-start; - align-items: center; - text-decoration: none; - border-radius: 0.5rem; - padding: 1.5rem; - box-shadow: 0px 4px 6px rgba(0, 0, 0, 0.1); + width: 100%; + grid-template-columns: repeat(auto-fit, minmax(min(20rem, 100%), 1fr)); + gap: 2rem; +} + +.card { + display: flex; + flex-direction: column; + border: 2px solid; + border-radius: 0.5rem; + padding: 1.5rem; + background-color: vars.$white; + height: 42rem; +} + +.borderDesign { + border-color: vars.$pink; +} + +.borderHack { + border-color: vars.$orange; +} + +.borderAI { + border-color: vars.$red; +} + +.borderRobotics { + border-color: vars.$robotics-green; +} + +.cardHeader { + display: flex; + align-items: center; + gap: 0.75rem; + margin-bottom: 1.5rem; +} + +.teamLogo { + width: 4rem; + height: 4rem; + margin: -0.75rem 0 -0.75rem -0.5rem; +} + +.cardHeaderText { + display: flex; + flex-direction: column; + line-height: 1.2; +} + +.cardQuarter { + font-size: 0.875rem; + font-weight: 400; + color: vars.$black; +} + +.cardTeam { + font-size: 1.125rem; + font-weight: 700; + color: vars.$black; +} + +.projectImageWrapper { + width: 100%; + height: 14rem; + min-height: 14rem; + max-height: 14rem; + display: flex; + align-items: center; + justify-content: center; + border-radius: 0.5rem; + margin-bottom: 1rem; + overflow: hidden; + background-color: vars.$darker-white; + pointer-events: none; +} + +.projectImage { + width: 100%; + height: 100%; + object-fit: contain; + padding: 1rem; + margin: 0; +} + +.projectImageDefault { + width: 7rem; + height: 7rem; + object-fit: contain; + margin: 0; +} + +.projectTitle { + font-size: 1.5rem; + font-weight: 700; + margin: 0 0 0.75rem; +} + +.colorDesign { + color: vars.$pink; +} + +.colorHack { + color: vars.$orange; +} + +.colorAI { + color: vars.$red; +} + +.colorRobotics { + color: vars.$robotics-green; +} + +.projectDetails { + margin-bottom: 0.75rem; + + p { + margin: 0 0 0.25rem; + font-size: 0.875rem; + color: vars.$black; } - .header { - text-align: center; - .AI { - color: vars.$red; - font-size: 1.4rem; - } - .Hack { - color: vars.$orange; - font-size: 1.4rem; - } - .Design { - color: vars.$pink; - font-size: 1.4rem; - } - .team { - display: flex; - flex-direction: row; - align-items: center; - justify-content: center; - } - .community_logo { - width: 80px; - height: 80px; - padding-right: 1rem; - } +} + +.descriptionWrapper { + flex-grow: 1; + min-height: 0; + margin-bottom: 1.25rem; + overflow: clip; +} + +.projectDescription { + font-size: 0.875rem; + line-height: 1.5; + color: vars.$black; + margin: 0; + display: -webkit-box; + -webkit-box-orient: vertical; + overflow: hidden; + pointer-events: none; +} + +.cardActions { + display: flex; + flex-wrap: wrap; + gap: 0.75rem; + align-items: center; +} + +.exploreButton { + display: inline-flex; + align-items: center; + padding: 0.4rem 1rem; + border-radius: 0.5rem; + font-size: 0.8rem; + font-weight: 600; + white-space: nowrap; + text-decoration: none; + color: vars.$white; + transition: opacity 0.2s; + + &.colorDesign { + background-color: vars.$pink; } - .logo { - object-fit: contain; - width: 100%; - height: 200px; - border-top-left-radius: 0.5rem; - border-top-right-radius: 0.5rem; + + &.colorHack { + background-color: vars.$orange; } - .description { - flex-grow: 1; + + &.colorAI { + background-color: vars.$red; + } + + &.colorRobotics { + background-color: vars.$robotics-green; } - .project_links { - display: flex; - flex-direction: row; - gap: 1rem; + + &:hover { + opacity: 0.85; } - .links { - object-fit: contain; - width: 100%; - height: 4rem; +} + +.repoButton { + display: inline-flex; + align-items: center; + justify-content: center; + gap: 0.4rem; + padding: 0.4rem 1rem; + border-radius: 0.5rem; + box-shadow: inset 0 0 0 1.5px vars.$black; + font-size: 0.8rem; + font-weight: 600; + white-space: nowrap; + text-decoration: none; + color: vars.$black; + background-color: vars.$white; + transition: background-color 0.2s; + + &:hover { + background-color: vars.$darker-white; } -} \ No newline at end of file +} + +.repoIcon { + width: 1rem; + height: 1rem; + object-fit: contain; + display: block; + flex-shrink: 0; + margin: 0; +} diff --git a/src/sections/Archive/index.tsx b/src/sections/Archive/index.tsx index 52ce9ef..95be5de 100644 --- a/src/sections/Archive/index.tsx +++ b/src/sections/Archive/index.tsx @@ -3,23 +3,49 @@ import { useState } from 'react'; import s from './style.module.scss'; import ProjectCards from '../../components/project-card'; +const FILTERS = [ + { label: 'Design', className: s.filterDesign }, + { label: 'Hack', className: s.filterHack }, + { label: 'AI', className: s.filterAI }, + { label: 'Robotics', className: s.filterRobotics }, +]; + const Archive: React.FC = () => { const [quarter, setQuarter] = useState('All'); + const [activeFilter, setActiveFilter] = useState(null); return (
-

Past Project Archives

-
- +
+

Past Projects Archive

+ +
+
+ {FILTERS.map(({ label, className }) => ( + + ))} +
+
+

Highlighted Projects

+
+ +
+

Other Projects

- +
) } diff --git a/src/sections/Archive/style.module.scss b/src/sections/Archive/style.module.scss index 42e62de..44777ef 100644 --- a/src/sections/Archive/style.module.scss +++ b/src/sections/Archive/style.module.scss @@ -1,9 +1,140 @@ -@use "../../styles/vars.scss" as vars; // allows you to use pre-defined colors +@use "../../styles/vars.scss" as vars; .container { display: flex; flex-direction: column; align-items: center; margin-top: 2rem; - padding-top: 3rem; -} \ No newline at end of file + padding: 3rem vars.calc-relative-size(531px, 3.1875rem, 834px, 7.5rem); +} + +.headerRow { + display: flex; + align-items: center; + justify-content: space-between; + flex-wrap: wrap; + gap: 1.25rem; + width: 100%; + margin-bottom: 2rem; +} + +.header { + font-size: 2.25rem; + font-weight: 800; + margin: 0; +} + +.project_selector { + appearance: none; + background: vars.$white url("/assets/chevron-down.svg") no-repeat right 0.75rem center; + border: 1.5px solid #5777C0; + border-radius: 0.75rem; + padding: 0.625rem 2rem 0.625rem 1.25rem; + font-size: 1rem; + color: vars.$black; + cursor: pointer; + outline: none; +} + +.filters { + display: flex; + flex-wrap: wrap; + gap: 0.75rem; + align-self: flex-start; + margin-bottom: 2rem; +} + +.filterButton { + background: transparent; + border: 2px solid; + border-radius: 2rem; + padding: 0.5rem 2rem; + font-size: 1rem; + cursor: pointer; + font-weight: 500; + transition: background-color 0.2s; + white-space: nowrap; +} + +.filterDesign { + border-color: vars.$pink; + color: vars.$black; +} + +.filterHack { + border-color: vars.$orange; + color: vars.$black; +} + +.filterAI { + border-color: vars.$red; + color: vars.$black; +} + +.filterRobotics { + border-color: vars.$robotics-green; + color: vars.$black; +} + +.filterActive { + &.filterDesign { + background-color: rgba(vars.$pink, 0.15); + } + &.filterHack { + background-color: rgba(vars.$orange, 0.15); + } + &.filterAI { + background-color: rgba(vars.$red, 0.15); + } + &.filterRobotics { + background-color: rgba(vars.$robotics-green, 0.15); + } +} + +.subheadingRow { + display: flex; + align-items: baseline; + gap: 1rem; + align-self: flex-start; + margin-top: 2rem; + margin-bottom: 1.5rem; +} + +.subheading { + font-size: 1.5rem; + font-weight: 700; + margin: 0; + color: vars.$black; +} + +.dateLabel { + font-size: 1rem; + color: vars.$dark-gray; +} + +@media only screen and (max-width: 530px) { + .headerRow { + flex-direction: column; + align-items: center; + gap: 1.25rem; + } + + .header { + text-align: center; + font-size: 1.75rem; + white-space: nowrap; + } + + .filters { + flex-direction: column; + align-items: center; + align-self: center; + width: 100%; + } + + .filterButton { + width: 55%; + text-align: center; + } +} + diff --git a/src/sections/FAQ/faq.jsx b/src/sections/FAQ/faq.jsx new file mode 100644 index 0000000..e5cfb51 --- /dev/null +++ b/src/sections/FAQ/faq.jsx @@ -0,0 +1,17 @@ +import s from './style.module.scss'; + +const FAQItem = ({ question, answer, isOpen, onClick }) => { + return ( +
+ +
+
{answer}
+
+
+ ); +}; + +export default FAQItem; diff --git a/src/sections/FAQ/index.tsx b/src/sections/FAQ/index.tsx new file mode 100644 index 0000000..3b292b3 --- /dev/null +++ b/src/sections/FAQ/index.tsx @@ -0,0 +1,93 @@ +import { useState } from 'react'; +import type { ReactNode } from 'react'; +import s from './style.module.scss'; +import FAQItem from './faq'; + +// list of questions and answers +const faqs: { question: ReactNode; answer: ReactNode }[] = [ + { + question: 'Do I need to be on campus to participate in Summer Projects?', + answer: 'No! Meetings throughout the summer are 100% remote!', + }, + { + question: 'Do I need to be on campus to participate in Fall/Winter/Spring Projects?', + answer: 'Yes!', + }, + { + question: 'How long is the program?', + answer: ( + <> +

Summer: Week of June 22, 2026 to Week 1 of Fall Quarter

+

Fall: Week 3 of Fall Quarter to Week 1 of Winter Quarter

+

Winter: Week 3 of Winter Quarter to Week 1 of Spring Quarter

+

Spring: Week 1 of Spring Quarter to Week 10 of Spring Quarter

+ + ), + }, + { + question: 'What is the time commitment per week?', + answer: '5-10 hours!', + }, + { + question: "What if I've never done a project before?", + answer: ( + <> + No worries! This is a super great beginner-friendly opportunity to apply your course level knowledge on a real project and level up your resume! + + ), + }, + { + question: ( + <> + What do I actually do if I am accepted into ACM Projects? + + ), + answer: ( +
    +
  • Work with your team and mentors to come up with a project idea to complete by the end of the program
  • +
  • Meet and complete deliverables every week
  • +
  • Progress update meetings (stand-ups) with the Projects community every month
  • +
  • Showcase your project in person during Week 1 of Fall Quarter
  • +
  • Make new friends with likeminded interests!
  • +
  • Make a project you can passionately speak about!
  • +
+ ), + }, + { + question: 'What do mentors do?', + answer: ( +
    +
  • Guide team through entire project timeline, including brainstorming, research, development, testing, and improvement
  • +
  • Prepare and lead team meetings and delegate weekly tasks
  • +
  • Ensure project can and will be completed by the end of the program
  • +
+ ), + }, +]; + +const FAQ = () => { + const [openIndex, setOpenIndex] = useState(null); + + const toggle = (index: number) => { + setOpenIndex(openIndex === index ? null : index); + }; + + return ( +
+

FAQs

+
+ {faqs.map((faq, i) => ( + toggle(i)} + /> + ))} +
+
+ ); +}; + +export default FAQ; diff --git a/src/sections/FAQ/style.module.scss b/src/sections/FAQ/style.module.scss new file mode 100644 index 0000000..fe4edfe --- /dev/null +++ b/src/sections/FAQ/style.module.scss @@ -0,0 +1,110 @@ +@use "../../styles/vars.scss" as v; + +$stmw: 956px; // small tablet/mobile max width + +$faq-bg: #dce6f7; + +.faqSection { + max-width: 760px; + margin: 4rem auto; + padding: 0 1.5rem; +} + +.heading { + font-size: 2rem; + font-weight: 700; + margin-bottom: 1.5rem; + text-align: left; + color: v.$black; + + @media only screen and (max-width: $stmw) { + text-align: center; + } +} + +.faqList { + display: flex; + flex-direction: column; + gap: 0.625rem; +} + +.faqItem { + background-color: $faq-bg; + border-radius: 8px; + overflow: hidden; + overscroll-behavior: auto; //override overscroll behavior in globals.css +} + +.question { + width: 100%; + display: flex; + align-items: center; + justify-content: space-between; + gap: 1rem; + padding: 1.1rem 1.25rem; + background: none; + border: none; + cursor: pointer; + text-align: left; + font-size: 1rem; + font-weight: 700; + color: v.$black; +} + +.chevron { + flex-shrink: 0; + width: 10px; + height: 10px; + border-right: 2px solid v.$black; + border-bottom: 2px solid v.$black; + transform: rotate(45deg); + transition: transform 0.3s ease; +} + +.chevronOpen { + transform: rotate(-135deg); +} + +.answerWrapper { + display: grid; + grid-template-rows: 0fr; + transition: grid-template-rows 0.3s ease; + + .open & { + grid-template-rows: 1fr; + } +} + +.answer { + overflow: hidden; + overscroll-behavior: auto; // override overscroll-behavior in globals.css + padding: 0 1.25rem; + font-size: 0.95rem; + line-height: 1.65; + color: v.$black; + + .open & { + padding: 0 1.25rem 1.1rem; + } + + ul { + margin: 0; + padding-left: 1.25rem; + + li { + margin-bottom: 0.35rem; + + &:last-child { + margin-bottom: 0; + } + } + } + + p { + margin: 0 0 0.4rem; + + &:last-child { + margin-bottom: 0; + } + } +} diff --git a/src/sections/Hero/index.tsx b/src/sections/Hero/index.tsx index 6b8d483..43d0e04 100644 --- a/src/sections/Hero/index.tsx +++ b/src/sections/Hero/index.tsx @@ -2,45 +2,85 @@ import Image from "next/image"; import styles from "./style.module.scss"; import Description from "../description"; +import Countdown from "../../components/countdown"; +import { Size, useWindowSize } from "../../utils/general"; + +const ProjLogo = "/assets/proj_logo.svg"; +const CountdownImage = "/assets/countdown_image.png"; +const Gradient = "/assets/hero-gradient.png"; +const GradientMobile = "/assets/hero-gradient-mobile.png"; const Hero = () => { const projects_app = "https://acmurl.com/projects-app"; + const size: Size = useWindowSize(); + + // size.width !== undefined determines whether the viewport has rendered yet + const mobile = size.width !== undefined && size.width <= 920; + return ( -
-
-
-
-

ACM Projects

-

- ACM Projects is our quarterly projects program where students work - in a tight knit team. The program gives students the opportunity - to be hands-on outside of courses in fields such as AI, design, - and software engineering. The program culminates in a projects - showcase and the finished product looks great on resumes. We - welcome all skill levels to apply! -

-
- ACM Projects + Gradient +
+
+ Countdown + +
+
+
+ Projects Logo +

ACM Projects

+
+

+ ACM Projects is our quarterly projects program where students work + in a tight knit team. The program gives students the opportunity + to be hands-on outside of courses in fields such as AI, design, + and software engineering. The program culminates in a projects + showcase and the finished product looks great on resumes. We + welcome all skill levels to apply! +

-
- Applications Due April 2nd, 11:59PM! -
-
+
+ Countdown + +
+
); }; -export default Hero; +export default Hero; \ No newline at end of file diff --git a/src/sections/Hero/style.module.scss b/src/sections/Hero/style.module.scss index a0ba2dc..5428594 100644 --- a/src/sections/Hero/style.module.scss +++ b/src/sections/Hero/style.module.scss @@ -1,74 +1,229 @@ @use "../../styles/vars.scss" as v; // allows you to use pre-defined colors -.container { - min-height: 500px; +.pageContent { + position: relative; display: flex; - align-items: center; - justify-content: center; - justify-self: start; flex-direction: column; + justify-content: center; + align-items: center; + padding: 2.44rem 5.44rem; @media screen and (max-width: 768px) { align-items: flex-start; + padding-inline: 3rem; } -} -.hero { - margin: auto; - max-width: 1000px; - padding: 2rem; - font-size: 20px; - word-wrap: normal; - display: grid; - grid-template-columns: 1fr 1fr; - grid-template-areas: - "about image" - "button image"; - align-items: start; - justify-content: center; -} + @media screen and (max-width: 500px) { + padding-inline: 1.69rem; + } + + .gradient { + position: absolute; + z-index: -10; + top: calc(-5.5rem + 4px); + left: 0; + width: 100%; + height: 85rem; + user-select: none; + + @media screen and (max-width: 956px) { + top: calc(-6.5rem + 4px) + } + + @media screen and (max-width: 920px) { + height: 50rem; + } + } -@media screen and (max-width: 768px) { .hero { display: flex; - flex-direction: column; + justify-content: center; + align-items: center; + color: v.$black; + + @media screen and (max-width: 768px) { + display: flex; + flex-direction: column; + } + + .hero_main { + display: flex; + flex-direction: column; + font-size: 1.125rem; + + .title { + display: flex; + align-items: center; + gap: 1.25rem; + margin-bottom: 1.25rem; + + .titleLogo { + width: 8rem; + height: auto; + margin: 0; + } + + .titleText { + font-size: 5rem; + font-weight: 700; + margin: 0; + } + + @media screen and (max-width: 1500px) { + .titleLogo { + width: 6rem; + } + + .titleText { + font-size: 4rem; + } + } + + @media screen and (max-width: 1340px) { + gap: 0.8rem; + + .titleLogo { + width: 4rem; + } + + .titleText { + font-size: 3rem; + } + } + + @media screen and (max-width: 965px) { + gap: 0.6rem; + + .titleText { + font-size: 2.5rem; + } + } + } + + .description { + margin-bottom: 1.75rem; + } + + .button { + background-color: v.$proj-blue; + color: v.$white; + padding: 1rem 2.25rem; + border-radius: 0.625rem; + border-width: 0; + font-size: 1.2rem; + font-weight: 500; + cursor: pointer; + + @media screen and (max-width: 1340px) { + padding: 0.7rem 1.8rem; + font-size: 1rem; + } + + @media screen and (max-width: 768px) { + justify-content: center; + align-self: center; + } + } + } + + .countdownImageWrapper { + flex: 0 0 auto; + position: relative; + margin: 0 -5rem 0 -6rem; + + .countdownImage { + width: 42rem; + height: auto; + margin: -0.5rem 0 -10rem 0; + user-select: none; + } + + .countdown { + position: absolute; + top: 7.5rem; + right: 16.1rem; + transform: perspective(1000px) rotateX(-43deg) rotateY(-43deg); + transform-style: preserve-3d; + } + + @media screen and (max-width: 1190px) { + .countdownImage { + width: 35rem; + } + + .countdown { + top: 6rem; + right: 13rem; + font-size: 1.2rem; + } + } + + @media screen and (max-width: 1055px) { + .countdownImage { + width: 30rem; + } + + .countdown { + top: 4.9rem; + right: 11.2rem; + font-size: 1rem; + } + } + } + + .countdownImageWrapperMobile { + @extend .countdownImageWrapper; + display: none; + + .countdownImage { + width: 20rem; + margin: 0 0 -3rem 0; + } + + .countdown { + top: 3.4rem; + right: 7.4rem; + font-size: 0.7rem; + } + } } } -.title { - font-size: 56px; - font-weight: 200; -} +@media screen and (max-width: 920px) { + .pageContent { + .hero { + flex-direction: column; -.hero_text { - grid-area: about; -} + .hero_main { + align-items: center; -.image { - grid-area: image; - border-radius: 10px; -} + .title { + .titleLogo { + display: none; + } -.button { - background-color: v.$acm-blue; - color: v.$white; - padding: 12px 30px; - border-radius: 10px; - font-size: 16px; - cursor: pointer; - border-width: 0; - grid-area: button; -} + .titleText { + font-size: 1.875rem; + } + } -.deadline { - padding-top: 1rem; - font-size: 16px; - font-weight: 700; -} + .description { + margin-bottom: 2.5rem; + text-align: center; + } -@media screen and (max-width: 768px) { - .button { - justify-content: center; - align-self: center; + .button { + padding: 0.625rem 2.5rem; + } + } + + .countdownImageWrapper { + display: none; + } + + .countdownImageWrapperMobile { + display: inline; + } + } } -} +} \ No newline at end of file diff --git a/src/sections/Home-Past-Projects/index.tsx b/src/sections/Home-Past-Projects/index.tsx new file mode 100644 index 0000000..a5855ad --- /dev/null +++ b/src/sections/Home-Past-Projects/index.tsx @@ -0,0 +1,112 @@ +'use client' +import Link from 'next/link'; +import s from './style.module.scss'; +import projects_data from '../../components/project-card/projects.json'; +import highlighted_ids from '../../components/project-card/highlighted.json'; + +const SUBGROUP_ORDER = ['Hack', 'AI', 'Design', 'Robotics']; + +const SUBGROUP_CONFIG: Record = { + Design: { + logo: "/assets/design.svg", + border: s.borderDesign, + button: s.buttonDesign, + repoIcon: '/assets/embeds/figma-icon.svg', + repoLabel: 'Figma' + }, + Hack: { + logo: "/assets/hack.svg", + border: s.borderHack, + button: s.buttonHack, + repoIcon: '/assets/embeds/github-icon.svg', + repoLabel: 'GitHub File' + }, + AI: { + logo: "/assets/ai.svg", + border: s.borderAI, + button: s.buttonAI, + repoIcon: '/assets/embeds/github-icon.svg', + repoLabel: 'GitHub File' + }, + Robotics: { + logo: "/assets/robo.svg", + border: s.borderRobotics, + button: s.buttonRobotics, + repoIcon: '/assets/embeds/github-icon.svg', + repoLabel: 'GitHub File' + }, +}; + +const DEFAULT_CONFIG = { + logo: "/assets/proj_logo.png", + border: "", + color: "", + repoIcon: "/assets/embeds/github-icon.svg", + repoLabel: "GitHub File", +}; + +const highlightedProjects = projects_data.filter((project) => highlighted_ids.includes(project.id)); + +const displayProjects = SUBGROUP_ORDER + .map((subgroup) => + highlightedProjects.find((project) => project.subgroup === subgroup) ?? + projects_data.find((project) => project.subgroup === subgroup) + ) + .filter((project): project is typeof projects_data[number] => Boolean(project)); + +const HomePastProjects: React.FC = () => { + return ( +
+

See Past Projects

+
+ {displayProjects.map((project) => { + const config = SUBGROUP_CONFIG[project.subgroup]; + const slug = project.project_title.toLowerCase().replace(/\s+/g, '-'); + return ( +
+
+ {project.project_title} +
+
+

{project.project_title}

+

{project.members.join(', ')}

+

{project.description}

+
+ + Explore Project + + {project.project_link && ( + + {config.repoLabel} + {config.repoLabel} + + )} +
+
+
+ ); + })} +
+ + View More Projects + +
+ ); +}; + +export default HomePastProjects; diff --git a/src/sections/Home-Past-Projects/style.module.scss b/src/sections/Home-Past-Projects/style.module.scss new file mode 100644 index 0000000..87a5e61 --- /dev/null +++ b/src/sections/Home-Past-Projects/style.module.scss @@ -0,0 +1,232 @@ +@use "../../styles/vars.scss" as vars; + +.container { + width: 100%; + display: flex; + flex-direction: column; + align-items: center; + padding: 2rem 7.5rem; +} + +.header { + align-self: flex-start; + font-size: 2.25rem; + font-weight: 800; + margin: 0 0 2rem; +} + +.list { + display: flex; + flex-direction: column; + gap: 2.5rem; + width: 100%; +} + +.row { + display: flex; + align-items: center; + gap: 2.5rem; +} + +.imageWrapper { + flex: 0 0 auto; + width: 19rem; + height: 19rem; + display: flex; + align-items: center; + justify-content: center; + border: 4px solid; + border-radius: 1rem; + overflow: hidden; + padding: 1.5rem; + background-color: transparent; + pointer-events: none; +} + +.image { + width: 100%; + height: 100%; + object-fit: contain; +} + +.imageDefault { + width: 60%; + height: 60%; + object-fit: contain; + transform: translateY(6%); // svg files are slightly shifted up. need to compensate in order to center it +} + +.borderDesign { + border-color: vars.$pink; +} + +.borderHack { + border-color: vars.$orange; +} + +.borderAI { + border-color: vars.$red; +} + +.borderRobotics { + border-color: vars.$robotics-green; +} + +.details { + display: flex; + flex-direction: column; + flex: 1; + min-width: 0; +} + +.title { + font-size: 1.5rem; + font-weight: 700; + margin: 0 0 0.375rem; + color: vars.$black; +} + +.members { + font-size: 1.125rem; + // color: vars.$dark-gray; + color: vars.$black; + margin: 0 0 1.5rem; +} + +.description { + font-size: 1.125rem; + line-height: 1.5; + color: vars.$black; + margin: 0 0 1.25rem; + display: -webkit-box; + -webkit-box-orient: vertical; + -webkit-line-clamp: 3; + pointer-events: none; + overflow: hidden; +} + +.actions { + display: flex; + flex-wrap: wrap; + gap: 0.75rem; + align-items: center; +} + +.exploreButton { + display: inline-flex; + align-items: center; + padding: 0.4rem 1rem; + border-radius: 0.5rem; + font-size: 0.8rem; + font-weight: 600; + white-space: nowrap; + text-decoration: none; + color: vars.$white; + transition: opacity 0.2s; + + &:hover { + opacity: 0.85; + } +} + +.buttonDesign { + background-color: vars.$pink; +} + +.buttonHack { + background-color: vars.$orange; +} + +.buttonAI { + background-color: vars.$red; +} + +.buttonRobotics { + background-color: vars.$robotics-green; +} + +.repoButton { + display: inline-flex; + align-items: center; + justify-content: center; + gap: 0.4rem; + padding: 0.4rem 1rem; + border-radius: 0.5rem; + box-shadow: inset 0 0 0 1.5px vars.$black; + font-size: 0.8rem; + font-weight: 600; + white-space: nowrap; + text-decoration: none; + color: vars.$black; + background-color: vars.$white; + transition: background-color 0.2s; + + &:hover { + background-color: vars.$darker-white; + } +} + +.repoIcon { + width: 1rem; + height: 1rem; + object-fit: contain; + display: block; + flex-shrink: 0; + margin: 0; +} + +.viewMoreButton { + margin-top: 3rem; + background-color: vars.$proj-blue; + color: vars.$white; + padding: 1rem 2.25rem; + border-radius: 0.625rem; + border-width: 0; + font-size: 1.2rem; + font-weight: 500; + text-decoration: none; + cursor: pointer; + + &:hover { + opacity: 0.9; + } +} + +@media screen and (max-width: 834px) { + .container { + padding: 2rem 3.1875rem; + } + + .header { + font-size: 1.75rem; + } +} + +@media only screen and (max-width: 700px) { + .list { + gap: 4rem; + } + + .row { + flex-direction: column; + align-items: center; + text-align: center; + gap: 1.25rem; + } + + .imageWrapper { + width: 100%; + max-width: 24rem; + height: auto; + aspect-ratio: 1 / 1; + } + + .description { + font-size: 0.8125rem; + -webkit-line-clamp: 4; + } + + .actions { + justify-content: center; + } +} diff --git a/src/sections/ProjectDetail/index.tsx b/src/sections/ProjectDetail/index.tsx new file mode 100644 index 0000000..259c936 --- /dev/null +++ b/src/sections/ProjectDetail/index.tsx @@ -0,0 +1,126 @@ +'use client' +import Link from 'next/link'; +import s from './style.module.scss'; +import projects_data from '../../components/project-card/projects.json'; + +const SUBGROUP_CONFIG: Record = { + Design: { + logo: "/assets/design.svg", + border: s.borderDesign, + color: s.colorDesign, + repoIcon: "/assets/embeds/figma-icon.svg", + repoLabel: "Figma File", + }, + Hack: { + logo: "/assets/hack.svg", + border: s.borderHack, + color: s.colorHack, + repoIcon: "/assets/embeds/github-icon.svg", + repoLabel: "GitHub File", + }, + AI: { + logo: "/assets/ai.svg", + border: s.borderAI, + color: s.colorAI, + repoIcon: "/assets/embeds/github-icon.svg", + repoLabel: "GitHub File", + }, + Robotics: { + logo: "/assets/robo.svg", + border: s.borderRobotics, + color: s.colorRobotics, + repoIcon: "/assets/embeds/github-icon.svg", + repoLabel: "GitHub File", + }, +}; + +const DEFAULT_CONFIG = { + logo: "/assets/proj_logo.png", + border: "", + color: "", + repoIcon: "/assets/embeds/github-icon.svg", + repoLabel: "GitHub File", +}; + +interface ProjectDetailProps { + slug: string; +} + +const ProjectDetail: React.FC = ({ slug }) => { + const project = projects_data.find( + (p) => p.project_title.toLowerCase().replace(/\s+/g, "-") === slug + ); + + if (!project) { + return ( +
+ Back to Archive +

Project not found

+
+ ); + } + + const config = SUBGROUP_CONFIG[project.subgroup] ?? DEFAULT_CONFIG; + + return ( +
+ Back to Archive + +
+
+ {`${project.subgroup} +
+ {project.quarter} + {project.subgroup} {project.team_name} +
+
+ +
+ {project.project_title} +
+ +

{project.project_title}

+ +
+

Created by: {project.members.join(", ")}

+

Mentored by: {project.mentors.join(", ")}

+ {project.technology && ( +

Technology: {project.technology}

+ )} +
+ +

{project.description}

+ +
+ + {config.repoLabel} + {config.repoLabel} + + {project.slides && ( + + Slides + Slides + + )} + {project.other_links && ( + + Additional Link + + )} +
+
+
+ ); +}; + +export default ProjectDetail; diff --git a/src/sections/ProjectDetail/style.module.scss b/src/sections/ProjectDetail/style.module.scss new file mode 100644 index 0000000..d905d26 --- /dev/null +++ b/src/sections/ProjectDetail/style.module.scss @@ -0,0 +1,219 @@ +@use "../../styles/vars.scss" as vars; + +$stmw: 834px; +$mmw: 530px; + +.container { + display: flex; + flex-direction: column; + align-items: center; + padding: 3rem 7.5rem; + min-height: 60vh; +} + +@media only screen and (max-width: $stmw) { + .container { + padding: + 3rem + vars.calc-relative-size($mmw + 1px, 3.1875rem, $stmw, 7.5rem); + } +} + +@media only screen and (max-width: $mmw) { + .container { + padding: 3rem 3.1875rem; + } +} + +.backLink { + align-self: flex-start; + font-size: 1rem; + font-weight: 600; + color: vars.$proj-blue; + text-decoration: none; + margin-bottom: 2rem; + + &:hover { + text-decoration: underline; + } +} + +.notFound { + font-size: 1.5rem; + color: vars.$black; +} + +.detail { + display: flex; + flex-direction: column; + width: 100%; + max-width: 48rem; + border: 2px solid; + border-radius: 0.75rem; + padding: 2.5rem; + background-color: vars.$white; +} + +.borderDesign { + border-color: vars.$pink; +} + +.borderHack { + border-color: vars.$orange; +} + +.borderAI { + border-color: vars.$red; +} + +.borderRobotics { + border-color: vars.$robotics-green; +} + +.header { + display: flex; + align-items: center; + gap: 0.75rem; + margin-bottom: 1.5rem; +} + +.subgroupLogo { + width: 4rem; + height: 4rem; + margin: -0.75rem 0 -0.75rem -0.5rem; +} + +.headerText { + display: flex; + flex-direction: column; + line-height: 1.2; +} + +.quarter { + font-size: 0.875rem; + font-weight: 400; + color: vars.$black; +} + +.teamName { + font-size: 1.25rem; + font-weight: 700; + color: vars.$black; +} + +.imageWrapper { + width: 100%; + height: 20rem; + display: flex; + align-items: center; + justify-content: center; + border-radius: 0.5rem; + margin-bottom: 1.5rem; + overflow: hidden; + background-color: #f5f5f5; + pointer-events: none; +} + +.projectImage { + width: 100%; + height: 100%; + object-fit: contain; + padding: 1rem; + margin: 0; +} + +.projectImageDefault { + width: 8rem; + height: 8rem; + object-fit: contain; + margin: 0; +} + +.title { + font-size: 2rem; + font-weight: 700; + margin: 0 0 1rem; +} + +.colorDesign { + color: vars.$pink; +} + +.colorHack { + color: vars.$orange; +} + +.colorAI { + color: vars.$red; +} + +.colorRobotics { + color: vars.$robotics-green; +} + +.meta { + margin-bottom: 1.25rem; + + p { + margin: 0 0 0.375rem; + font-size: 1rem; + color: vars.$black; + } +} + +.description { + font-size: 1rem; + line-height: 1.6; + color: vars.$black; + margin: 0 0 2rem; +} + +.links { + display: flex; + flex-wrap: wrap; + gap: 0.75rem; +} + +.repoButton { + display: inline-flex; + align-items: center; + justify-content: center; + gap: 0.4rem; + padding: 0.5rem 1.25rem; + border-radius: 0.5rem; + box-shadow: inset 0 0 0 1.5px vars.$black; + font-size: 0.875rem; + font-weight: 600; + white-space: nowrap; + text-decoration: none; + color: vars.$black; + background-color: vars.$white; + transition: background-color 0.2s; + + &:hover { + background-color: vars.$darker-white; + } +} + +.repoIcon { + width: 1rem; + height: 1rem; + object-fit: contain; + display: block; + flex-shrink: 0; + margin: 0; +} + +@media only screen and (max-width: $mmw) { + .detail { + padding: 1.5rem; + } + + .imageWrapper { + height: 14rem; + } + + .title { + font-size: 1.5rem; + } +} diff --git a/src/sections/Timeline/index.tsx b/src/sections/Timeline/index.tsx new file mode 100644 index 0000000..a783259 --- /dev/null +++ b/src/sections/Timeline/index.tsx @@ -0,0 +1,76 @@ +"use client"; + +import { useState } from "react"; +import Image from "next/image"; +import styles from "./style.module.scss"; +import timelineData from "./timelineData.json"; + +function getInitialIndex(): number { + const now = new Date(); + const index = timelineData.events.findIndex( + (event) => new Date(event.date) >= now + ); + return index === -1 ? timelineData.events.length - 1 : index; +} + +const Timeline = () => { + const [activeIndex, setActiveIndex] = useState(getInitialIndex); + const activeEvent = timelineData.events[activeIndex]; + + return ( +
+

Projects Timeline

+ +
+
+
+ Timeline +
+
+
+

{activeEvent.date}

+

+ {activeEvent.description} +

+
+
+ +
+
+ {timelineData.events.map((event, index) => ( + + ))} +
+ + + Apply Here + +
+ ); +}; + +export default Timeline; diff --git a/src/sections/Timeline/style.module.scss b/src/sections/Timeline/style.module.scss new file mode 100644 index 0000000..945ba7d --- /dev/null +++ b/src/sections/Timeline/style.module.scss @@ -0,0 +1,199 @@ +@use "../../styles/vars.scss" as v; + +.container { + width: 100%; + padding: 2rem 7.5rem; + display: flex; + flex-direction: column; + align-items: center; +} + +.heading { + font-size: 2.25rem; + font-weight: 800; + align-self: flex-start; + margin-bottom: 2rem; +} + +.eventCard { + display: flex; + align-items: flex-start; + gap: 2rem; + margin-bottom: 2rem; + width: 100%; + padding: 0 4rem; +} + +.imageWrapper { + flex-shrink: 0; + width: 130px; + height: 130px; + display: flex; + align-items: center; + justify-content: center; +} + +.imageDiamond { + width: 100px; + height: 100px; + transform: rotate(45deg); + border: 3px solid v.$proj-blue; + border-radius: 8px; + background-color: v.$blue; + position: relative; + overflow: hidden; +} + +.diamondImage { + object-fit: cover; + transform: rotate(-45deg) scale(1.42); +} + +.eventInfo { + display: flex; + flex-direction: column; + gap: 0.7rem; +} + +.eventDate { + font-size: 1.5rem; + font-weight: 700; + margin: 0; +} + +.eventDescription { + font-size: 1.125rem; + line-height: 1.5; + color: v.$black; +} + +.timeline { + display: flex; + align-items: flex-start; + justify-content: space-between; + width: 100%; + position: relative; + margin-bottom: 2.5rem; + padding-top: 12px; +} + +.timelineLine { + position: absolute; + top: 18px; + left: 0; + right: 0; + height: 2px; + background-color: v.$proj-blue; +} + +.milestone { + display: flex; + flex-direction: column; + align-items: center; + z-index: 1; + flex: 1; + background: none; + border: none; + padding: 0; + cursor: pointer; +} + +.dot { + width: 14px; + height: 14px; + border-radius: 50%; + border: 2px solid v.$proj-blue; + background-color: v.$white; + margin-bottom: 0.5rem; +} + +.dotActive { + background-color: v.$proj-blue; + border-color: v.$proj-blue; +} + +.milestoneLabel { + font-size: 1.125rem; + text-align: center; + white-space: pre-line; + font-weight: 400; + color: v.$black; +} + +.milestoneLabelActive { + font-weight: 700; + color: v.$proj-blue; +} + +.applyButton { + display: inline-block; + background-color: v.$proj-blue; + color: v.$white; + padding: 12px 40px; + border-radius: 10px; + font-size: 1rem; + font-weight: 700; + cursor: pointer; + text-decoration: none; + margin-top: 1rem; +} + +@media screen and (max-width: 834px) { + .container { + padding: 2rem 3.1875rem; + } + + .heading { + font-size: 1.75rem; + align-self: center; + } + + .eventCard { + flex-direction: column; + align-items: center; + text-align: center; + padding: 0; + } + + .eventDescription { + min-height: unset; + } + + .timeline { + flex-direction: column; + align-items: flex-start; + padding-top: 0; + padding-left: 2rem; + gap: 0; + width: auto; + } + + .timelineLine { + top: 0; + bottom: 0; + left: calc(2rem + 9px); + right: unset; + width: 2px; + height: auto; + } + + .milestone { + flex-direction: row; + align-items: center; + gap: 1rem; + padding: 0.75rem 0; + } + + .dot { + margin-bottom: 0; + flex-shrink: 0; + width: 20px; + height: 20px; + } + + .milestoneLabel { + font-size: 1rem; + text-align: left; + white-space: nowrap; + } +} diff --git a/src/sections/Timeline/timelineData.json b/src/sections/Timeline/timelineData.json new file mode 100644 index 0000000..3caa2e4 --- /dev/null +++ b/src/sections/Timeline/timelineData.json @@ -0,0 +1,25 @@ +{ + "applyLink": "https://acmurl.com/projects-app", + "events": [ + { + "label": "Application\nOpens", + "date": "Wednesday, September 24, 2026", + "description": "Applications are now open! Submit your application to join ACM Projects for the Fall 2026 quarter." + }, + { + "label": "Application\nDeadline", + "date": "Friday, October 2, 2026", + "description": "Last day to submit your application. Make sure to apply before 11:59 PM!" + }, + { + "label": "Decisions", + "date": "Thursday, October 9, 2026", + "description": "Decisions will be released. Check your email for your acceptance status." + }, + { + "label": "Final\nShowcase", + "date": "Tuesday, January 13, 2027", + "description": "Present your completed project to the community at the Final Showcase!" + } + ] +} diff --git a/src/styles/vars.scss b/src/styles/vars.scss index d401e69..cdd7347 100644 --- a/src/styles/vars.scss +++ b/src/styles/vars.scss @@ -13,11 +13,12 @@ $dark-gray: #8d8d8d; $hover-blue: #7cbdff; $turquoise: #51c0c0; $purple: #816dff; +$robotics-green: #9EC284; $black: #333333; $acm-blue-30: #a8d3ff; $acm-blue: #62b0ff; -$proj-blue: #5777C0; -$footer-blue: #4E78C6; +$proj-blue: #4E78C6; +$proj-blue-2: #5777C0; // find the size relative to the viewport width between a min and max size // size is calculated using a linear function between two points diff --git a/tsconfig.json b/tsconfig.json index b09cc80..c196a09 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,6 +1,6 @@ { "compilerOptions": { - "target": "es5", + "target": "es6", "lib": [ "dom", "dom.iterable", @@ -15,7 +15,7 @@ "moduleResolution": "bundler", "resolveJsonModule": true, "isolatedModules": true, - "jsx": "react-jsx", + "jsx": "preserve", "incremental": true, "plugins": [ {