From 166d5ecc11772cd30a1a1370dbeb6497b01ca392 Mon Sep 17 00:00:00 2001 From: Chris Chen Date: Sun, 14 Apr 2024 23:41:58 -0400 Subject: [PATCH] Add team page hero and about --- new-dti-website/components/blob.tsx | 10 + new-dti-website/components/team/TeamAbout.tsx | 260 ++++++++++++++++++ new-dti-website/components/team/TeamHero.tsx | 183 ++++++++++++ .../components/team/data/carousel.json | 39 +++ new-dti-website/src/app/team/page.tsx | 13 + 5 files changed, 505 insertions(+) create mode 100644 new-dti-website/components/blob.tsx create mode 100644 new-dti-website/components/team/TeamAbout.tsx create mode 100644 new-dti-website/components/team/TeamHero.tsx create mode 100644 new-dti-website/components/team/data/carousel.json create mode 100644 new-dti-website/src/app/team/page.tsx diff --git a/new-dti-website/components/blob.tsx b/new-dti-website/components/blob.tsx new file mode 100644 index 00000000..ef08bffa --- /dev/null +++ b/new-dti-website/components/blob.tsx @@ -0,0 +1,10 @@ +const RedBlob: React.FC<{ className: string; intensity: number }> = ({ className, intensity }) => ( +
+); + +export default RedBlob; diff --git a/new-dti-website/components/team/TeamAbout.tsx b/new-dti-website/components/team/TeamAbout.tsx new file mode 100644 index 00000000..69daf55c --- /dev/null +++ b/new-dti-website/components/team/TeamAbout.tsx @@ -0,0 +1,260 @@ +import { Dispatch, SetStateAction, useState } from 'react'; +import Image from 'next/image'; +import { ibm_plex_mono } from '../../src/app/layout'; +import FA23Members from '../../../backend/src/members-archive/fa23.json'; +import useScreenSize from '../../src/hooks/useScreenSize'; +import RedBlob from '../blob'; + +type roleStatistics = { + [key: string]: { + name: string; + color: string; + people: number; + majors: Set; + colleges: Set; + }; +}; + +type PieChartProps = { + width: number; + height: number; + chartSection: string | undefined; + setChartSection: Dispatch>; + roleStats: roleStatistics; + allMembers: IdolMember[]; +}; + +const PieChart: React.FC = ({ + width, + height, + chartSection, + setChartSection, + roleStats, + allMembers +}) => { + const radius = 175; + const hoverRadius = 190; + let previousPoint = [0, -radius]; + let totalAngle = 0; + + const polarToRect = (angle: number, radius: number) => { + const newX = -radius * Math.cos(angle + Math.PI / 2); + const newY = -radius * Math.sin(angle + Math.PI / 2); + return [newX, newY]; + }; + + const pointAsString = (point: number[]) => point.join(' '); + const scale = (point: number[], scalar: number) => point.map((x) => scalar * x); + + return ( + + {Object.keys(roleStats).map((role) => { + const percentage = roleStats[role].people / allMembers.length; + const theta = 2 * Math.PI * percentage; + + const arcPoint1 = + role === chartSection ? scale(previousPoint, hoverRadius / radius) : previousPoint; + const currentRadius = role === chartSection ? hoverRadius : radius; + + totalAngle += theta; + const arcPoint2 = polarToRect(totalAngle, role === chartSection ? hoverRadius : radius); + + const nextPoint = polarToRect(totalAngle, radius); + const textLocation = polarToRect((2 * totalAngle - theta) / 2, (3 * radius) / 4); + previousPoint = nextPoint; + + return ( + setChartSection(role)} + onMouseLeave={() => setChartSection(undefined)} + > + Math.PI ? `1` : `0` + } 1 ${pointAsString(arcPoint2)} L 0 0`} + fill={roleStats[role].color} + /> + + {`${Math.round(percentage * 100)}%`} + + + ); + })} + + ); +}; + +const TeamStatistics = () => { + const [chartSection, setChartSection] = useState(undefined); + const { width } = useScreenSize(); + + const allMembers = FA23Members.members as IdolMember[]; + + const roleStats: roleStatistics = { + designer: { + name: 'Design', + color: '#FFBCBC', + people: 0, + majors: new Set(), + colleges: new Set() + }, + developer: { + name: 'Development', + color: '#D63D3D', + people: 0, + majors: new Set(), + colleges: new Set() + }, + pm: { name: 'Product', color: '#FFFFFF', people: 0, majors: new Set(), colleges: new Set() }, + business: { + name: 'Business', + color: '#B7B7B7', + people: 0, + majors: new Set(), + colleges: new Set() + }, + lead: { name: 'Leads', color: '#484848', people: 0, majors: new Set(), colleges: new Set() } + }; + + allMembers.forEach((member: IdolMember) => { + const fullRoleName = + member.role === 'tpm' || member.role === 'dev-advisor' ? 'developer' : member.role; + roleStats[fullRoleName].people += 1; + if (member.major) roleStats[fullRoleName].majors.add(member.major.trim()); + if (member.doubleMajor) roleStats[fullRoleName].majors.add(member.doubleMajor.trim()); + }); + + return ( +
+
+
+
+

+ {chartSection ? roleStats[chartSection].people : allMembers.length} +

+

Members

+
+
+

+ {chartSection + ? roleStats[chartSection].majors.size + : allMembers.reduce((acc, val) => { + if (val.major) acc.add(val.major); + if (val.doubleMajor) acc.add(val.doubleMajor); + return acc; + }, new Set()).size} +

+

Different majors

+
+
+

7

+

+ Represented colleges +

+
+
+
+
+ = 1024 ? 400 : 300} + height={width >= 1024 ? 400 : 300} + chartSection={chartSection} + setChartSection={setChartSection} + allMembers={allMembers} + roleStats={roleStats} + /> +
+
+ {Object.keys(roleStats).map((role) => { + if (role === 'tpm' || role === 'dev-advisor') return <>; + return ( +
setChartSection(role)} + onMouseLeave={() => setChartSection(undefined)} + > +
= 728 ? 40 : 24}} + /> +

+ {roleStats[role].name} +

+
+ ); + })} +
+
+ ); +}; + +const TeamAbout = () => ( +
+ +
+
+
+
+

We are Cornell DTI

+

+ Founded in 2017, DTI is a project team of{' '} + + 80+ designers, developers, product managers, and business members + {' '} + passionate about making change on campus and beyond. +

+
+
+

@2022

+ 2022 DTI Team +
+
+
+

@2017

+ 2022 DTI Team +
+
+ +
+

Who we are

+

+ More than just being inclusive, our team strives to{' '} + bring many backgrounds and perspectives together to + solve community problems. These statistics come from recruiting across campus and seeking + applicants with the best skills and potential for growth on the team. Updated Fall 2023. +

+
+ + +
+
+); +export default TeamAbout; diff --git a/new-dti-website/components/team/TeamHero.tsx b/new-dti-website/components/team/TeamHero.tsx new file mode 100644 index 00000000..6d74b04f --- /dev/null +++ b/new-dti-website/components/team/TeamHero.tsx @@ -0,0 +1,183 @@ +import { Dispatch, SetStateAction, useEffect, useState } from 'react'; +import Autoplay from 'embla-carousel-autoplay'; +import { ibm_plex_mono } from '../../src/app/layout'; +import { Carousel, CarouselContent, CarouselItem, type CarouselApi } from '../ui/carousel'; +import carouselImages from './data/carousel.json'; +import useScreenSize from '../../src/hooks/useScreenSize'; +import RedBlob from '../blob'; + +type ImageModalProps = { + onClose: () => void; + carouselIndex: number; + setCarouselIndex: Dispatch>; + carouselApi: CarouselApi; +}; + +const ImageModal: React.FC = ({ onClose, carouselIndex, carouselApi }) => { + const handleNext = () => carouselApi?.scrollNext(); + const handlePrev = () => carouselApi?.scrollPrev(); + return ( +
+
+ left arrow + + + {carouselImages.images.map((image) => ( + +
+
+ {image.alt} +
+ close + icon +

+ {`${carouselImages.images[carouselIndex % 5].alt}.jpg`} +

+
+
+ ))} +
+
+ right arrow +
+
+ ); +}; + +const TeamHero = () => { + const [carouselApi, setCarouselApi] = useState(); + const [carouselIndex, setCarouselIndex] = useState(0); + const [modalShown, setModalShown] = useState(false); + + const { width } = useScreenSize(); + const offsetIndex = width >= 768 ? 1 : 0; + + useEffect(() => { + if (carouselApi) { + carouselApi.on('select', () => { + setCarouselIndex(carouselApi.selectedScrollSnap()); + }); + } + }, [carouselIndex, carouselApi]); + + return ( +
+ {modalShown && ( + setModalShown(false)} + carouselIndex={carouselIndex + offsetIndex} + setCarouselIndex={setCarouselIndex} + carouselApi={carouselApi} + /> + )} + +
+
+
+

+ OUR TEAM +

+
+
+

+ Working{' '} + together +

+

+ We are Cornell DTI. But individually, we are a{' '} + talented, diverse group of students from different + colleges and countries striving to make a difference in the Cornell community and + beyond. +

+
+
+
+
+
+
+
+

+ {`${carouselImages.images[(carouselIndex + offsetIndex) % 5].alt}.jpg`} +

+
+
+ + + {carouselImages.images.map((image, index) => ( + +
{ + if (index === (carouselIndex + offsetIndex) % 5 && width >= 768) setModalShown(true); + }} + > +
+ {image.alt} +
+ icon +
+
+ ))} +
+
+
+
+ ); +}; + +export default TeamHero; diff --git a/new-dti-website/components/team/data/carousel.json b/new-dti-website/components/team/data/carousel.json new file mode 100644 index 00000000..405de5dc --- /dev/null +++ b/new-dti-website/components/team/data/carousel.json @@ -0,0 +1,39 @@ +{ + "images": [ + { + "src": "/images/business.png", + "alt": "business", + "icon": "/icons/business_sticker.svg", + "iconWidth": 50, + "iconHeight": 50 + }, + { + "src": "/images/full-team.png", + "alt": "full-team", + "icon": "/icons/full-team_sticker.svg", + "iconWidth": 50, + "iconHeight": 50 + }, + { + "src": "/images/design.png", + "alt": "design", + "icon": "/icons/design_sticker.svg", + "iconWidth": 50, + "iconHeight": 50 + }, + { + "src": "/images/development.png", + "alt": "development", + "icon": "/icons/dev_sticker.svg", + "iconWidth": 53, + "iconHeight": 50 + }, + { + "src": "/images/product.png", + "alt": "product", + "icon": "/icons/product_sticker.svg", + "iconWidth": 50, + "iconHeight": 50 + } + ] +} diff --git a/new-dti-website/src/app/team/page.tsx b/new-dti-website/src/app/team/page.tsx new file mode 100644 index 00000000..1961d983 --- /dev/null +++ b/new-dti-website/src/app/team/page.tsx @@ -0,0 +1,13 @@ +'use client'; + +import TeamHero from '../../../components/team/TeamHero'; +import TeamAbout from '../../../components/team/TeamAbout'; + +const TeamPage = () => ( + <> + + + +); + +export default TeamPage;