diff --git a/components/DevProjectCards.js b/components/DevProjectCards.js index 367d0731..6eae4b4a 100644 --- a/components/DevProjectCards.js +++ b/components/DevProjectCards.js @@ -1,5 +1,150 @@ +/* eslint-disable linebreak-style */ import Image from 'next/image'; +import { useState } from 'react'; import styles from '../styles/components/DevProjCard.module.scss'; +import carouselStyles from '../styles/pages/Dev.module.scss'; + +// Slot config: position offset -> { scale, zIndex, offset from center in px } +const SLOT_CONFIG = [ + { scale: 0.52, zIndex: 1, offset: -320, opacity: 0.8 }, + { scale: 0.70, zIndex: 2, offset: -175, opacity: 0.9 }, + { scale: 1.00, zIndex: 5, offset: 0, opacity: 1 }, + { scale: 0.70, zIndex: 2, offset: 175, opacity: 0.9 }, + { scale: 0.52, zIndex: 1, offset: 320, opacity: 0.8 }, +]; + +const BASE_SIZE = 280; // px, for the center diamond + +function DiamondCard({ project, slotIndex, isCenter, onClick }) { + const { scale, zIndex, offset, opacity } = SLOT_CONFIG[slotIndex]; + const size = BASE_SIZE * scale; + + return ( + // eslint-disable-next-line jsx-a11y/click-events-have-key-events, jsx-a11y/no-static-element-interactions +
+
+
+ {/* eslint-disable-next-line @next/next/no-img-element */} + {project.alt} + {isCenter && ( +
+
+ {project.name !== '???' && ( + <> + +   + + )} + {project.prim_lang} + {project.name !== '???' && ( + <> +  •  + + Proj + +  •  + + Repo + + + )} +
+
+

+

+
+ )} +
+
+
+ ); +} + +function DiamondCarousel({ projects: projectList }) { + const [activeIndex, setActiveIndex] = useState(0); + const total = projectList.length; + + const getWrapped = (i) => ((i % total) + total) % total; + + // The 5 visible projects, centered on activeIndex + const visibleProjects = [-2, -1, 0, 1, 2].map((offset) => ({ + project: projectList[getWrapped(activeIndex + offset)], + offset, + })); + + return ( +
+
+ + {visibleProjects.map(({ project, offset }, slotIndex) => ( + { + if (offset !== 0) setActiveIndex(getWrapped(activeIndex + offset)); + }} + /> + ))} + +
+

+ {projectList[activeIndex].name} +

+
+
+ {projectList.map((p, i) => ( +
+
+
+ ); +} function Project({ name, @@ -66,8 +211,10 @@ function Project({ className={`${styles['project-card']} ${styles['grid-tablet-only-2']}`} >
- {/* eslint-disable-next-line @next/next/no-img-element */} - {alt} +
+ {/* eslint-disable-next-line @next/next/no-img-element */} + {alt} +

{name}

@@ -108,6 +255,11 @@ function Project({ } function projects(props) { + // Use the diamond carousel for the default (no size/style) case + if (!props.size && !props.style) { + return ; + } + return ( // TODO: more flexible mobile views (<> diff --git a/pages/dev.js b/pages/dev.js index 6c820107..e1a944ac 100644 --- a/pages/dev.js +++ b/pages/dev.js @@ -1,3 +1,4 @@ +/* eslint-disable linebreak-style */ import Link from 'next/link'; import { NextSeo } from 'next-seo'; import Banner from '../components/Banner'; @@ -41,9 +42,10 @@ function DevTeam() {  with the Dev Team!

Our Projects

-
+ {/*
-
+
*/} +

Our Commitment to Open Source

Everything we build is  @@ -61,11 +63,17 @@ function DevTeam() { Github .

+

Where We've Worked

+

+ {/* eslint-disable-next-line max-len */} + Our ACM Dev officers and alumni have interned and worked at companies including Google, Amazon, Viasat, Apple, TikTok, Coinbase, and Oracle! +

Leadership

-

Members

+ {/*

Members

*/} +

People

diff --git a/styles/components/DevProjCard.module.scss b/styles/components/DevProjCard.module.scss index 74b7bcd0..097ef154 100644 --- a/styles/components/DevProjCard.module.scss +++ b/styles/components/DevProjCard.module.scss @@ -33,6 +33,75 @@ padding-bottom: 0; } +// diamond carousel card +.diamond-wrapper { + border-radius: 1.75rem; + box-shadow: 0 0 12px 6px rgba(255, 255, 255, 0.8), 0 8px 24px rgba(0, 0, 0, 0.15); + cursor: pointer; + flex-shrink: 0; + overflow: hidden; + position: relative; + transform: rotate(45deg); + transition: transform 0.3s cubic-bezier(0.25, 0.1, 0.25, 1); + + &:hover { + transform: rotate(45deg) scale(1.07); + } +} + +.diamond-inner { + border-radius: 1.75rem; + height: 100%; + left: 0; + overflow: hidden; + position: absolute; + top: 0; + width: 100%; +} + +.diamond-img { + height: 100%; + object-fit: cover; + object-position: center; + transform: rotate(-45deg) scale(1.42); + transform-origin: center; + width: 100%; +} + +.diamond-hover-content { + align-items: center; + background-color: rgba(255, 255, 255, 0.92); + bottom: 0; + color: black; + display: flex; + flex-direction: column; + font-family: variables.$font-body; + font-size: 0.8em; + justify-content: center; + left: 0; + opacity: 0; + padding: 12%; + position: absolute; + right: 0; + text-align: center; + top: 0; + transform: rotate(-45deg) scale(1.42); + transition: opacity 0.3s ease-in-out; +} + +.diamond-wrapper.is-center:hover .diamond-hover-content { + opacity: 1; +} + +.diamond-title { + font-family: variables.$font-display; + color: inherit; + font-size: 1.25rem !important; + font-weight: 600; + margin-top: 0.6em; + text-align: center; +} + .card-hover-content { align-items: center; background-color: rgba(255, 255, 255, 0.9); @@ -175,6 +244,14 @@ margin: 0 auto; max-width: 300px; width: 100%; + overflow: hidden; +} + +.rotated { + width: 100%; + height: 100%; + transform: rotate(-45deg) scale(1.42); + transform-origin: center; } .project-image-container img { diff --git a/styles/pages/Dev.module.scss b/styles/pages/Dev.module.scss index 105504e2..7599901f 100644 --- a/styles/pages/Dev.module.scss +++ b/styles/pages/Dev.module.scss @@ -17,6 +17,7 @@ .grid-container { display: grid; grid-template-columns: 1fr 1fr 1fr; + margin-top: 2rem; } $navbar-breakpoint: 992px; @@ -28,3 +29,71 @@ $tablet-breakpoint: 768px; grid-template-columns: 1fr 1fr; } } + +.project-spacing { + margin-top: 2rem; +} + +// diamond carousel container +.carousel-section { + align-items: center; + display: flex; + flex-direction: column; + margin: 0.75rem 0 2rem; + width: 100%; +} + +.carousel-track { + align-items: center; + display: flex; + justify-content: center; + min-height: 400px; // enough height for the largest diamond + its title beneath + position: relative; + width: 100%; +} + +.carousel-controls { + align-items: center; + display: flex; + gap: 1.5rem; + justify-content: center; + margin-top: 0.8rem; +} + +.carousel-btn { + background: none; + border: 0; + border-radius: 50%; + box-shadow: 0 0 0 1.5px rgba(150, 150, 150, 0.2), 0 0 8px 1px rgba(150, 150, 150, 0.1); + cursor: pointer; + font-size: 1.2rem; + height: 2.5rem; + line-height: 1; + transition: box-shadow 0.2s, color 0.2s; + width: 2.5rem; + + &:hover { + box-shadow: 0 0 0 1.5px #10A0D4, 0 0 8px 1px rgba(16, 160, 212, 0.3); + color: #10A0D4; + } +} + +.carousel-dots { + display: flex; + gap: 0.5rem; +} + +.carousel-dot { + background: #61616140; + border: 0; + border-radius: 50%; + cursor: pointer; + height: 0.5rem; + padding: 0; + transition: background 0.2s; + width: 0.5rem; + + &.active { + background: #10A0D4; + } +}