Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
156 changes: 154 additions & 2 deletions components/DevProjectCards.js
Original file line number Diff line number Diff line change
@@ -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
<div
style={{
position: 'absolute',
// eslint-disable-next-line quotes
left: `calc(50% + ${offset}px)`,
// eslint-disable-next-line quotes
transform: `translateX(-50%)`,
zIndex,
opacity,
transition: 'all 0.7s cubic-bezier(0.25, 0.1, 0.25, 1)',
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
}}
onClick={onClick}
>
<div
className={`${styles['diamond-wrapper']} ${isCenter ? styles['is-center'] : ''}`}
style={{ width: size, height: size }}
>
<div className={styles['diamond-inner']}>
{/* eslint-disable-next-line @next/next/no-img-element */}
<img
src={project.img}
alt={project.alt}
className={styles['diamond-img']}
/>
{isCenter && (
<div className={styles['diamond-hover-content']}>
<div className={styles['description-header']}>
{project.name !== '???' && (
<>
<span
className={`${styles['dev-badge']} ${styles[project.prim_lang]}`}
/>
&nbsp;
</>
)}
{project.prim_lang}
{project.name !== '???' && (
<>
&nbsp;•&nbsp;
<a href={project.proj_link} target="_blank" rel="noopener noreferrer">
<u>Proj</u>
</a>
&nbsp;•&nbsp;
<a href={project.repo_link} target="_blank" rel="noopener noreferrer">
<u>Repo</u>
</a>
</>
)}
</div>
<div className={styles['description-box']}>
<p dangerouslySetInnerHTML={{ __html: project.description }} />
</div>
</div>
)}
</div>
</div>
</div>
);
}

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 (
<div className={carouselStyles['carousel-section']}>
<div className={carouselStyles['carousel-track']}>
<button
className={carouselStyles['carousel-btn']}
onClick={() => setActiveIndex(getWrapped(activeIndex - 1))}
aria-label="Previous project"
style={{ position: 'absolute', left: '-4.5rem', fontSize: '0.75rem', color: 'rgba(150, 150, 150, 1)' }}
>
</button>
{visibleProjects.map(({ project, offset }, slotIndex) => (
<DiamondCard
key={project.name}
project={project}
slotIndex={slotIndex}
isCenter={offset === 0}
onClick={() => {
if (offset !== 0) setActiveIndex(getWrapped(activeIndex + offset));
}}
/>
))}
<button
className={carouselStyles['carousel-btn']}
onClick={() => setActiveIndex(getWrapped(activeIndex + 1))}
aria-label="Next project"
style={{ position: 'absolute', right: '-4.5rem', fontSize: '0.75rem', color: 'rgba(150, 150, 150, 1)' }}
>
</button>
</div>
<p className={styles['diamond-title']} style={{ position: 'relative', zIndex: 10, marginTop: '1rem' }}>
{projectList[activeIndex].name}
</p>
<div className={carouselStyles['carousel-controls']}>
<div className={carouselStyles['carousel-dots']}>
{projectList.map((p, i) => (
<button
key={p.name}
className={`${carouselStyles['carousel-dot']} ${i === activeIndex ? carouselStyles.active : ''}`}
onClick={() => setActiveIndex(i)}
aria-label={`Go to ${p.name}`}
/>
))}
</div>
</div>
</div>
);
}

function Project({
name,
Expand Down Expand Up @@ -66,8 +211,10 @@ function Project({
className={`${styles['project-card']} ${styles['grid-tablet-only-2']}`}
>
<div className={styles['project-image-container']}>
{/* eslint-disable-next-line @next/next/no-img-element */}
<img src={img} alt={alt} style={{ maxWidth: '100%' }} />
<div className={styles.rotated}>
{/* eslint-disable-next-line @next/next/no-img-element */}
<img src={img} alt={alt} style={{ maxWidth: '100%' }} />
</div>
</div>
<div>
<h3 className={styles.name}>{name}</h3>
Expand Down Expand Up @@ -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 <DiamondCarousel projects={props.projects} />;
}

return (
// TODO: more flexible mobile views
(<>
Expand Down
14 changes: 11 additions & 3 deletions pages/dev.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
/* eslint-disable linebreak-style */
import Link from 'next/link';
import { NextSeo } from 'next-seo';
import Banner from '../components/Banner';
Expand Down Expand Up @@ -41,9 +42,10 @@ function DevTeam() {
</Link>&nbsp;with the Dev Team!
</p>
<h2 className="text-center">Our Projects</h2>
<div className="grid-desktop-3 text-center-mobile">
{/* <div className="grid-desktop-3 text-center-mobile">
<Projects projects={projects} />
</div>
</div> */}
<Projects projects={projects} />
<h2 className="text-center">Our Commitment to Open Source</h2>
<p className={styles['project-info']}>
Everything we build is&nbsp;
Expand All @@ -61,11 +63,17 @@ function DevTeam() {
Github
</Link>.
</p>
<h2 className="text-center">Where We&apos;ve Worked</h2>
<p className={styles['project-info']}>
{/* 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!
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Image

could we do something like this, where we show the logos of companies rather than text?

</p>
<h2 className="text-center">Leadership</h2>
<div className="grid-desktop-3 text-center-mobile">
<Officers officers={devTeamExec} />
</div>
<h2 className="text-center">Members</h2>
{/* <h2 className="text-center">Members</h2> */}
<h2 className="text-center">People</h2>
<div className="grid-desktop-3 text-center-mobile">
<Officers officers={devTeamOfficers} />
</div>
Expand Down
77 changes: 77 additions & 0 deletions styles/components/DevProjCard.module.scss
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,75 @@
padding-bottom: 0;
}

// diamond carousel card
.diamond-wrapper {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Image

on mobile, the width is a little broken

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Image

the text is also a little too big and doesn't fit

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);
Expand Down Expand Up @@ -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 {
Expand Down
69 changes: 69 additions & 0 deletions styles/pages/Dev.module.scss
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
.grid-container {
display: grid;
grid-template-columns: 1fr 1fr 1fr;
margin-top: 2rem;
}

$navbar-breakpoint: 992px;
Expand All @@ -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;
}
}
Loading