Browse Source

Meet the Team page (#94)

Includes mobile Team Member Card

Closes #9
Closes #42

Co-authored-by: Bonnie <bonniepeng2002@gmail.com>
Reviewed-on: #94
Reviewed-by: Aditya Thakral <a3thakra@csclub.uwaterloo.ca>
Co-authored-by: b38peng <b38peng@uwaterloo.ca>
Co-committed-by: b38peng <b38peng@uwaterloo.ca>
pull/171/head
b38peng 12 months ago
parent
commit
a8cae99c11
  1. 7
      .vscode/settings.json
  2. 2
      components/Bubble.tsx
  3. 13
      components/TeamMember.module.css
  4. 8
      components/TeamMember.tsx
  5. 122
      components/TeamMemberCard.module.css
  6. 93
      components/TeamMemberCard.tsx
  7. 22
      components/playground.tsx
  8. 16
      content/about/index.mdx
  9. 6
      content/meet-the-team/execs/01-kallen-tu.md
  10. 6
      content/meet-the-team/execs/02-gordon-le.md
  11. 6
      content/meet-the-team/execs/03-nakul-vijhani.md
  12. 6
      content/meet-the-team/execs/04-neil-parikh.md
  13. 6
      content/meet-the-team/execs/05-max-erenberg.md
  14. 6
      content/meet-the-team/execs/06-codey.md
  15. 114
      content/meet-the-team/programme-committee.json
  16. 18
      content/meet-the-team/systems-committee.json
  17. 38
      content/meet-the-team/website-committee.json
  18. 37
      hooks/useWindowDimension.tsx
  19. 55
      lib/team.ts
  20. 4
      package.json
  21. 4
      pages/_app.css
  22. 5
      pages/about/our-supporters.module.css
  23. 1
      pages/about/team.mdx
  24. 105
      pages/about/team.module.css
  25. 139
      pages/about/team.tsx
  26. 2
      pages/index.tsx
  27. 3
      public/images/team-member-placeholder.svg
  28. BIN
      public/images/team/AaronChoo.jpg
  29. BIN
      public/images/team/AdityaThakral.jpg
  30. BIN
      public/images/team/AlexZhang.jpg
  31. BIN
      public/images/team/AndrewWang.jpg
  32. BIN
      public/images/team/AnjingLi.jpg
  33. BIN
      public/images/team/AnnaWang.jpg
  34. BIN
      public/images/team/AthenaLiu.jpg
  35. BIN
      public/images/team/BettyGuo.jpg
  36. BIN
      public/images/team/BonniePeng.jpg
  37. BIN
      public/images/team/BrendanWong.jpg
  38. BIN
      public/images/team/CatherineWan.jpg
  39. BIN
      public/images/team/CharlesZhang.jpg
  40. BIN
      public/images/team/ChrisXie.jpg
  41. BIN
      public/images/team/Codey.jpg
  42. BIN
      public/images/team/DoraSu.jpg
  43. BIN
      public/images/team/EdenChan.jpg
  44. BIN
      public/images/team/EdwinYang.jpg
  45. BIN
      public/images/team/FelixYang.jpg
  46. BIN
      public/images/team/GordonLe.jpg
  47. BIN
      public/images/team/GuneetBola.jpg
  48. BIN
      public/images/team/JaredHe.jpg
  49. BIN
      public/images/team/JasonSang.jpg
  50. BIN
      public/images/team/JuthikaHoque.jpg
  51. BIN
      public/images/team/KailinChan.jpg
  52. BIN
      public/images/team/KallenTu.jpg
  53. BIN
      public/images/team/KarenLee.jpg
  54. BIN
      public/images/team/LinnaLuo.jpg
  55. BIN
      public/images/team/MarkChen.jpg
  56. BIN
      public/images/team/MaxErenberg.jpg
  57. BIN
      public/images/team/NeilParikh.jpg
  58. BIN
      public/images/team/PatrickHe.jpg
  59. BIN
      public/images/team/RavinduAngammana.jpg
  60. BIN
      public/images/team/RaymondLi.jpg
  61. BIN
      public/images/team/RichaDalal.jpg
  62. BIN
      public/images/team/SamHonoridez.jpg
  63. BIN
      public/images/team/SherryLev.jpg
  64. BIN
      public/images/team/ShiHan.jpg
  65. BIN
      public/images/team/StephanieXu.jpg
  66. BIN
      public/images/team/WilliamTran.jpg
  67. BIN
      public/images/team/YanniWang.jpg
  68. 4
      public/images/team/popup-close.svg
  69. 12
      public/images/team/team-codey.svg
  70. 3
      public/images/team/team-member-placeholder.svg
  71. 20
      tsconfig.json
  72. 1
      types.d.ts

7
.vscode/settings.json vendored

@ -4,9 +4,7 @@
"eslint.codeActionsOnSave.mode": "all",
"[css]": {
"editor.suggest.insertMode": "replace",
"gitlens.codeLens.scopes": [
"document"
],
"gitlens.codeLens.scopes": ["document"],
"editor.formatOnSave": true
},
"[javascript]": {
@ -39,8 +37,9 @@
"node_modules": true
},
"editor.tabSize": 2,
"files.eol": "\n",
"[markdown]": {
"editor.wordWrap": "on",
"editor.quickSuggestions": false
}
}
}

2
components/Bubble.tsx

@ -6,7 +6,7 @@ import { DefaultLayout } from "./DefaultLayout";
import styles from "./Bubble.module.css";
export default function Bubble(props: { children: React.ReactNode }) {
export function Bubble(props: { children: React.ReactNode }) {
return (
<div className={styles.container}>
<div className={styles.bubble} aria-hidden>

13
components/TeamMember.module.css

@ -9,6 +9,7 @@
width: 100%;
border-radius: 50%;
margin: 0 auto;
object-fit: cover;
}
.caption {
@ -25,3 +26,15 @@
font-weight: 600;
color: var(--primary-heading);
}
@media only screen and (max-width: calc(768rem / 16)) {
.img {
width: 100%;
}
.caption {
text-align: center;
font-size: calc(14rem / 16);
margin-top: 1rem;
}
}

8
components/TeamMember.tsx

@ -7,7 +7,7 @@ import styles from "./TeamMember.module.css";
interface TeamMemberProps {
name: string;
role: string;
image?: string;
image: string;
}
export const TeamMember: React.FC<TeamMemberProps> = ({
@ -17,11 +17,7 @@ export const TeamMember: React.FC<TeamMemberProps> = ({
}) => {
return (
<div className={styles.container}>
<Image
className={styles.img}
src={image ?? "/images/team-member-placeholder.svg"}
alt={`Picture of ${name}`}
/>
<Image className={styles.img} src={image} alt={`Picture of ${name}`} />
<div className={styles.caption}>
<div className={styles.name}>{name}</div>
<div className={styles.role}>{role}</div>

122
components/TeamMemberCard.module.css

@ -38,6 +38,7 @@
grid-area: role;
margin: 0;
color: var(--primary-heading);
font-size: calc(24rem / 16);
line-height: calc(40 / 24);
font-weight: 600;
@ -51,39 +52,110 @@
margin-top: 0;
}
/* TODO: Use the correct mobile styles from figma
@media only screen and (max-width: calc(375rem / 16)) {
.card {
grid-template-columns: calc(70rem / 16) auto;
grid-template-rows: auto calc(calc(14rem / 16) * 1.5 + calc(12rem / 16)) auto;
grid-template-areas:
"picture name"
"picture role"
"description description";
column-gap: 1.4375rem;
align-items: end;
max-width: calc(190rem / 16);
/* Popup */
@keyframes popup {
0% {
transform: scale(0.4) translate(0, -50%);
}
100% {
transform: scale(1) translate(0, -50%);
}
}
.picture {
max-width: calc(70rem / 16);
max-height: calc(70rem / 16);
@keyframes revealBg {
0% {
opacity: 0;
}
100% {
opacity: 100%;
}
}
.name,
.role,
.description {
line-height: 1.5;
.popupBackground {
position: fixed;
z-index: 11;
background-color: var(--navbar-page-overlay);
width: 100%;
height: 100%;
top: 0;
left: 0;
animation: revealBg 0.2s forwards;
}
.popupContainer {
position: fixed;
display: flex;
z-index: 12;
flex-direction: column;
background-color: var(--secondary-background);
padding: calc(20rem / 16) calc(40rem / 16);
left: 0;
top: 50%;
animation: popup 0.7s forwards;
}
.closeBtn {
align-self: flex-end;
/* reset default button styling */
width: min-content;
background: transparent;
border: 0px solid transparent;
padding: 0;
font-family: inherit;
line-height: inherit;
}
.popupContent {
display: flex;
flex-direction: column;
align-items: center;
}
.popupImage {
width: 100%;
}
.popupName {
color: var(--primary-accent);
margin: calc(24rem / 16) 0 0 0;
font-size: calc(18rem / 16);
font-weight: 600;
}
.popupRole {
color: var(--primary-heading);
margin: 0 0 1rem 0;
text-align: center;
font-size: calc(18rem / 16);
font-weight: 600;
}
.popupDescription {
font-size: calc(14rem / 16);
}
@media only screen and (max-width: calc(768rem / 16)) {
.card {
display: flex;
flex-direction: column;
align-items: center;
max-width: calc(135rem / 16);
margin: 0;
}
.name {
margin-top: calc(24rem / 16);
font-weight: 700;
}
.name,
.role {
margin-bottom: calc(12rem / 16);
text-align: center;
font-size: calc(14rem / 16);
}
.description {
justify-self: top;
margin-top: calc(12rem / 16);
margin-left: calc(12rem / 16);
display: none;
}
} */
}

93
components/TeamMemberCard.tsx

@ -1,29 +1,98 @@
import React from "react";
import React, { useState } from "react";
import { useWindowDimension } from "@/hooks/useWindowDimension";
import { Image } from "./Image";
import styles from "./TeamMemberCard.module.css";
interface TeamMemberCardProps {
export interface TeamMemberCardProps {
name: string;
role: string;
image?: string; // path to image of person, relative to public directory
image: string;
children: React.ReactNode;
}
export function TeamMemberCard(props: TeamMemberCardProps) {
interface TeamMemberInfoProps extends TeamMemberCardProps {
isPopup?: boolean;
}
function TeamMemberInfo({
name,
role,
image,
children,
isPopup = false,
}: TeamMemberInfoProps) {
return (
<article className={styles.card}>
<>
<div className={styles.picture}>
<Image
className={styles.image}
src={props.image ?? "/images/team-member-placeholder.svg"}
alt={`Picture of ${props.name}`}
className={isPopup ? styles.popupImage : styles.image}
src={image}
alt={`Picture of ${name}`}
/>
</div>
<h1 className={styles.name}>{props.name}</h1>
<h2 className={styles.role}>{props.role}</h2>
<div className={styles.description}>{props.children}</div>
</article>
<h1 className={isPopup ? styles.popupName : styles.name}>{name}</h1>
<h2 className={isPopup ? styles.popupRole : styles.role}>{role}</h2>
<div className={isPopup ? styles.popupDescription : styles.description}>
{children}
</div>
</>
);
}
export function TeamMemberCard({
name,
role,
image,
children,
}: TeamMemberCardProps) {
const { width } = useWindowDimension();
const [isOpen, setIsOpen] = useState(false);
const handleClick = () => {
if (isOpen || width <= 768) {
setIsOpen(!isOpen);
}
};
return (
<>
<article className={styles.card} onClick={handleClick}>
<TeamMemberInfo {...{ name, role, image }}>{children}</TeamMemberInfo>
</article>
{isOpen && (
<ExecPopup
name={name}
role={role}
image={image}
handleClick={handleClick}
>
{children}
</ExecPopup>
)}
</>
);
}
interface Propup extends TeamMemberCardProps {
handleClick: () => void;
}
function ExecPopup({ name, role, image, children, handleClick }: Propup) {
return (
<>
<div className={styles.popupBackground} onClick={handleClick} />
<div className={styles.popupContainer}>
<button className={styles.closeBtn} onClick={handleClick}>
<Image src="images/team/popup-close.svg" />
</button>
<div className={styles.popupContent}>
<TeamMemberInfo {...{ name, role, image }} isPopup={true}>
{children}
</TeamMemberInfo>
</div>
</div>
</>
);
}

22
components/playground.tsx

@ -166,16 +166,16 @@ export function TeamMemberDemo() {
</div>
<hr />
<div className={styles.teamMembers}>
<TeamMember {...dogeMetadata} />
<TeamMember {...dogeMetadata} />
<TeamMember {...dogeMetadata} />
<TeamMember {...dogeMetadata} />
<TeamMember {...dogeMetadata} />
<TeamMember {...dogeMetadata} />
<TeamMember {...dogeMetadata} />
<TeamMember {...dogeMetadata} />
<TeamMember {...dogeMetadata} />
<TeamMember {...dogeMetadata} />
<TeamMember {...dogeMetadata} image="/images/playground/doge.jpg" />
<TeamMember {...dogeMetadata} image="/images/playground/doge.jpg" />
<TeamMember {...dogeMetadata} image="/images/playground/doge.jpg" />
<TeamMember {...dogeMetadata} image="/images/playground/doge.jpg" />
<TeamMember {...dogeMetadata} image="/images/playground/doge.jpg" />
<TeamMember {...dogeMetadata} image="/images/playground/doge.jpg" />
<TeamMember {...dogeMetadata} image="/images/playground/doge.jpg" />
<TeamMember {...dogeMetadata} image="/images/playground/doge.jpg" />
<TeamMember {...dogeMetadata} image="/images/playground/doge.jpg" />
<TeamMember {...dogeMetadata} image="/images/playground/doge.jpg" />
</div>
</div>
);
@ -184,7 +184,7 @@ export function TeamMemberDemo() {
export function TeamMemberCardDemo() {
return (
<div className={styles.teamMemberCardDemo}>
<TeamMemberCard {...codeyMetadata}>
<TeamMemberCard {...codeyMetadata} image="/images/playground/doge.jpg">
<CodeyInfo />
</TeamMemberCard>
</div>

16
content/about/index.mdx

@ -1,4 +1,4 @@
import Bubble from "@/components/Bubble";
import { Bubble } from "@/components/Bubble";
<Bubble>
@ -17,13 +17,13 @@ growth.
## Our <span>Vision</span>
1. Academic: Promoting the knowledge and interest of Computer Science, as well
as supporting students throughout their academic experiences.
as supporting students throughout their academic experiences.
2. Career: Providing career guidance and resources to help students gain
experience and knowledge for their own job search.
experience and knowledge for their own job search.
3. Community: Encouraging interpersonal relationships through community building
and social events for all computing students.
and social events for all computing students.
</Bubble>
@ -64,9 +64,9 @@ The CS Club office is located at room **MC 3036/3037**, in the Math & Computer
Building of the University of Waterloo.
- An office favorite is our $0.50 pop for members. We have a fridge in the
office which is stocked with many different kinds of pop.
office which is stocked with many different kinds of pop.
- We have lots of informative books, 5 computer terminals, and an array of
knowledgeable people to talk to.
knowledgeable people to talk to.
Come visit us on campus in our office! Meet new members and find out what's new
in the club.
@ -77,7 +77,7 @@ Computer Science Club <br />
Math & Computer 3036/3037 <br />
University of Waterloo <br />
200 University Avenue West <br />
Waterloo, ON N2L 3G1 <br />
Waterloo, ON N2L 3G1 <br />
Canada
Our office phone number is [(519) 888-4567 x33870](tel:+15198884567,33870)
@ -85,5 +85,3 @@ Our office phone number is [(519) 888-4567 x33870](tel:+15198884567,33870)
</address>
</Bubble>

6
content/meet-the-team/execs/01-kallen-tu.md

@ -0,0 +1,6 @@
---
name: Kallen Tu
role: President
---
words words words codey words words words words codey words words words words codey words words words words codey words words words words codey words words words words words codey words words words words codey words words words words codey words words words words codey words words words

6
content/meet-the-team/execs/02-gordon-le.md

@ -0,0 +1,6 @@
---
name: Gordon Le
role: Vice President
---
words words words codey words words words words codey words words words words codey words words words words codey words words words words codey words words words words words codey words words words words codey words words words words codey words words words words codey words words words

6
content/meet-the-team/execs/03-nakul-vijhani.md

@ -0,0 +1,6 @@
---
name: Nakul Vijhani
role: Assistant Vice President
---
words words words codey words words words words codey words words words words codey words words words words codey words words words words codey words words words words words codey words words words words codey words words words words codey words words words words codey words words words

6
content/meet-the-team/execs/04-neil-parikh.md

@ -0,0 +1,6 @@
---
name: Neil Parikh
role: Treasurer
---
words words words codey words words words words codey words words words words codey words words words words codey words words words words codey words words words words words codey words words words words codey words words words words codey words words words words codey words words words

6
content/meet-the-team/execs/05-max-erenberg.md

@ -0,0 +1,6 @@
---
name: Max Erenberg
role: Systems Administrator
---
words words words codey words words words words codey words words words words codey words words words words codey words words words words codey words words words words words codey words words words words codey words words words words codey words words words words codey words words words

6
content/meet-the-team/execs/06-codey.md

@ -0,0 +1,6 @@
---
name: Codey
role: Mascot
---
The one, the only, Codey! Codey is ecstatic to be your mascot for this term. Codey loves programming and playing on their laptop. You can often find Codey posing for event promo graphics, or chilling in the CSC discord.

114
content/meet-the-team/programme-committee.json

@ -0,0 +1,114 @@
[
{
"name": "Brendan Wong",
"role": "Designer"
},
{
"name": "Kailin Chan",
"role": "Designer"
},
{
"name": "Karen Lee",
"role": "Designer"
},
{
"name": "Sam Honoridez",
"role": "Designer"
},
{
"name": "Anna Wang",
"role": "Events"
},
{
"name": "Jason Sang",
"role": "Events"
},
{
"name": "Ravindu Angammana",
"role": "Events"
},
{
"name": "Shi Han",
"role": "Events"
},
{
"name": "Stephanie Xu",
"role": "Events"
},
{
"name": "Yanni Wang",
"role": "Events"
},
{
"name": "Anjing Li",
"role": "Marketing"
},
{
"name": "Patrick He",
"role": "Marketing"
},
{
"name": "Richa Dalal",
"role": "Marketing"
},
{
"name": "Sherry Lev",
"role": "Marketing"
},
{
"name": "Alex Zhang",
"role": "Discord Mod"
},
{
"name": "Andrew Wang",
"role": "Discord Mod"
},
{
"name": "Charles Zhang",
"role": "Discord Mod"
},
{
"name": "Edwin Yang",
"role": "Discord Mod"
},
{
"name": "Mark Chen",
"role": "Discord Mod"
},
{
"name": "Aaron Choo",
"role": "Representative"
},
{
"name": "Athena Liu",
"role": "Representative"
},
{
"name": "Betty Guo",
"role": "Representative"
},
{
"name": "Chris Xie",
"role": "Representative"
},
{
"name": "Dora Su",
"role": "Representative"
},
{
"name": "Eden Chan",
"role": "Representative"
},
{
"name": "Felix Yang",
"role": "Representative"
},
{
"name": "Guneet Bola",
"role": "Representative"
},
{
"name": "Juthika Hoque",
"role": "Representative"
}
]

18
content/meet-the-team/systems-committee.json

@ -0,0 +1,18 @@
[
{
"name": "Max Erenberg",
"role": "Admin"
},
{
"name": "Andrew Wang",
"role": "Member"
},
{
"name": "Bill Xiang",
"role": "Member"
},
{
"name": "Raymond Li",
"role": "Member"
}
]

38
content/meet-the-team/website-committee.json

@ -0,0 +1,38 @@
[
{
"name": "Aditya Thakral",
"role": "Team Lead"
},
{
"name": "Neil Parikh",
"role": "Team Lead"
},
{
"name": "Amy Wang",
"role": "Developer"
},
{
"name": "Bonnie Peng",
"role": "Developer"
},
{
"name": "Catherine Wan",
"role": "Developer"
},
{
"name": "Dora Su",
"role": "Developer"
},
{
"name": "Jared He",
"role": "Developer"
},
{
"name": "Linna Luo",
"role": "Developer"
},
{
"name": "William Tran",
"role": "Developer"
}
]

37
hooks/useWindowDimension.tsx

@ -0,0 +1,37 @@
import { useEffect, useState } from "react";
interface WindowDimension {
width: number;
height: number;
}
function getWindowDimension() {
const { innerWidth: width, innerHeight: height } = window;
return {
width,
height,
};
}
export function useWindowDimension(): WindowDimension {
const [windowSize, setWindowDimension] = useState<WindowDimension>({
width: 0,
height: 0,
});
useEffect(() => {
const handleResize = () => {
setWindowDimension(getWindowDimension());
};
// Set size at the first client-side load
handleResize();
window.addEventListener("resize", handleResize);
return () => {
window.removeEventListener("resize", handleResize);
};
}, []);
return windowSize;
}

55
lib/team.ts

@ -0,0 +1,55 @@
import { readFile, readdir, access } from "fs/promises";
import path from "path";
import matter from "gray-matter";
import { serialize } from "next-mdx-remote/serialize";
const EXECS_PATH = path.join("content", "meet-the-team", "execs");
const fileType = ".md";
export interface Metadata {
name: string;
role: string;
image: string;
}
export async function getExecNames() {
return (await readdir(EXECS_PATH))
.filter((name) => name.endsWith(fileType))
.map((name) => name.slice(0, -1 * fileType.length));
}
export async function getExec(fileName: string, convert = true) {
const raw = await readFile(path.join(EXECS_PATH, `${fileName}${fileType}`));
const { content, data: metadata } = matter(raw);
const image = await getMemberImagePath(metadata.name);
return {
content: convert ? await serialize(content) : content,
metadata: { ...metadata, image } as Metadata,
};
}
async function getImage(imgPath: string) {
try {
await access(path.join("public", imgPath));
return imgPath;
} catch {
return undefined;
}
}
export async function getMemberImagePath(name: string) {
const imgPath = path.join("images", "team", name.replace(" ", ""));
const placeholder = path.join(
"images",
"team",
"team-member-placeholder.svg"
);
const img =
(await getImage(imgPath + ".jpg")) ??
(await getImage(imgPath + ".png")) ??
(await getImage(imgPath + ".gif")) ??
placeholder;
return img;
}

4
package.json

@ -10,8 +10,8 @@
"build": "next build",
"start": "next start",
"export": "next export",
"lint": "eslint \"{pages,components,lib}/**/*.{js,ts,tsx,jsx}\" --quiet",
"lint:fix": "eslint \"{pages,components,lib}/**/*.{js,ts,tsx,jsx}\" --quiet --fix"
"lint": "eslint \"{pages,components,lib,hooks}/**/*.{js,ts,tsx,jsx}\" --quiet",
"lint:fix": "eslint \"{pages,components,lib,hooks}/**/*.{js,ts,tsx,jsx}\" --quiet --fix"
},
"dependencies": {
"@mdx-js/loader": "^1.6.22",

4
pages/_app.css

@ -1,3 +1,7 @@
html {
scroll-behavior: smooth;
}
body {
/* Default is light theme */
--primary-background: #ffffff;

5
pages/about/our-supporters.module.css

@ -24,6 +24,11 @@
border: none;
}
.header {
font-size: calc(24rem / 16);
margin: 0;
}
.codey {
width: calc(100rem / 16);
}

1
pages/about/team.mdx

@ -1 +0,0 @@
# Meet the Team page

105
pages/about/team.module.css

@ -0,0 +1,105 @@
.headerContainer {
display: flex;
flex-direction: row;
padding-bottom: calc(24rem / 16);
border-bottom: calc(1rem / 16) solid var(--primary-heading);
margin-bottom: calc(46rem / 16);
}
.nav {
display: none;
}
.headerTextContainer {
margin: auto 0 0 0;
}
.header {
color: var(--primary-heading);
font-size: calc(48rem / 16);
margin: 0 calc(53rem / 16) 0 0;
}
.subheading {
color: var(--primary-heading);
font-size: calc(36rem / 16);
font-weight: 600;
padding-bottom: calc(22rem / 16);
border-bottom: calc(1rem / 16) solid var(--primary-heading);
margin-bottom: calc(46rem / 16);
margin-top: calc(86rem / 16);
}
.codey {
width: calc(360rem / 16);
}
.execs {
display: flex;
flex-direction: column;
gap: calc(26rem / 16);
margin-bottom: calc(86rem / 16);
}
.members {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(calc(100rem / 16), 1fr));
row-gap: calc(43rem / 16);
column-gap: calc(53rem / 16);
justify-items: center;
}
.elections {
margin: 6rem 0;
}
.electionSubheading {
color: var(--primary-accent);
font-size: calc(36rem / 16);
font-weight: 600;
margin-top: 0;
}
@media only screen and (max-width: calc(768rem / 16)) {
.headerContainer {
flex-direction: column-reverse;
padding-bottom: 1rem;
}
.nav {
margin-top: calc(24rem / 16);
margin-bottom: calc(46rem / 16);
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
}
.codey {
width: calc(140rem / 16);
align-self: center;
}
.header {
font-size: calc(24rem / 16);
margin: calc(10rem / 16) 0 0 0;
text-align: center;
}
.subheading {
font-size: calc(24rem / 16);
padding-bottom: calc(15rem / 16);
}
.execs,
.members {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(calc(130rem / 16), 1fr));
justify-items: center;
column-gap: 0;
}
.electionSubheading {
font-size: calc(24rem / 16);
}
}

139
pages/about/team.tsx

@ -0,0 +1,139 @@
import { GetStaticProps } from "next";
import { MDXRemote, MDXRemoteSerializeResult } from "next-mdx-remote";
import React from "react";
import { Bubble } from "@/components/Bubble";
import { DefaultLayout } from "@/components/DefaultLayout";
import { Image } from "@/components/Image";
import { Link } from "@/components/Link";
import { TeamMember } from "@/components/TeamMember";
import { TeamMemberCard } from "@/components/TeamMemberCard";
import {
getExec,
getExecNames,
Metadata,
getMemberImagePath,
} from "@/lib/team";
import programmeData from "../../content/meet-the-team/programme-committee.json";
import systemsData from "../../content/meet-the-team/systems-committee.json";
import websiteData from "../../content/meet-the-team/website-committee.json";
import styles from "./team.module.css";
interface SerializedExec {
content: MDXRemoteSerializeResult;
metadata: Metadata;
}
interface Props {
execs: SerializedExec[];
programme: Metadata[];
website: Metadata[];
systems: Metadata[];
}
export default function Team({ execs, programme, website, systems }: Props) {
return (
<>
<DefaultLayout>
<div className={styles.headerContainer}>
<div className={styles.headerTextContainer}>
<h1 className={styles.header}>Meet the Team!</h1>
<div className={styles.nav}>
<Link href="#execs">The Executives</Link>
<Link href="#programme">Programme Committee</Link>
<Link href="#website">Website Committee</Link>
<Link href="#system">Systems Committee</Link>
</div>
<h2
className={styles.subheading}
style={{ borderBottom: "none", margin: 0, padding: 0 }}
>
The Executives
</h2>
</div>
<Image src="images/team/team-codey.svg" className={styles.codey} />
</div>
<div className={styles.execs} id="execs">
{execs.map((exec) => {
return (
<div key={exec.metadata.name}>
<TeamMemberCard {...exec.metadata}>
<MDXRemote {...exec.content} />
</TeamMemberCard>
</div>
);
})}
</div>
<div id="programme">
<h2 className={styles.subheading}>Programme Committee</h2>
<MembersList team={programme} />
</div>
<div id="website">
<h2 className={styles.subheading}>Website Committee</h2>
<MembersList team={website} />
</div>
<div id="system">
<h2 className={styles.subheading}>Systems Committee</h2>
<MembersList team={systems} />
</div>
</DefaultLayout>
<div className={styles.elections}>
<Bubble>
<h2 className={styles.electionSubheading}>Elections</h2>
To find out when and where the next elections will be held, keep an
eye on on the <Link href="/#news">News</Link>. <br />
For details on the elections, read our
<Link href="/about/constitution"> Constitution</Link>
</Bubble>
</div>
</>
);
}
Team.Layout = function TeamLayout(props: { children: React.ReactNode }) {
return <div>{props.children}</div>;
};
interface MembersProps {
team: Metadata[];
}
function MembersList(props: MembersProps) {
return (
<div className={styles.members}>
{props.team.map((member) => (
<TeamMember {...member} key={member.name} />
))}
</div>
);
}
async function getTeamWithImages(team: Omit<Metadata, "image">[]) {
return await Promise.all(
team.map(async (member) => {
const image = await getMemberImagePath(member.name);
return {
...member,
image,
};
})
);
}
export const getStaticProps: GetStaticProps<Props> = async () => {
const execNames = await getExecNames();
const execs = (await Promise.all(
execNames.map((name) => getExec(name))
)) as SerializedExec[];
const [programme, website, systems] = await Promise.all([
getTeamWithImages(programmeData),
getTeamWithImages(websiteData),
getTeamWithImages(systemsData),
]);
return {
props: { execs, programme, website, systems },
};
};

2
pages/index.tsx

@ -68,7 +68,7 @@ export default function Home() {
))}
</div>
</section>
<section className={styles.news}>
<section className={styles.news} id="news">
<h1 className={styles.cardsHeading}>News</h1>
<p className={styles.cardsDescription}>
Updates from our execs! <br />

3
public/images/team-member-placeholder.svg

@ -1,3 +0,0 @@
<svg width="512" height="512" viewBox="0 0 512 512" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect width="512" height="512" fill="#5CAFF9" fill-opacity="0.2"/>
</svg>

Before

Width:  |  Height:  |  Size: 174 B

BIN
public/images/team/AaronChoo.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 323 KiB

BIN
public/images/team/AdityaThakral.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 74 KiB

BIN
public/images/team/AlexZhang.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 877 KiB

BIN
public/images/team/AndrewWang.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 57 KiB

BIN
public/images/team/AnjingLi.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 52 KiB

BIN
public/images/team/AnnaWang.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 246 KiB

BIN
public/images/team/AthenaLiu.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 183 KiB

BIN
public/images/team/BettyGuo.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 87 KiB

BIN
public/images/team/BonniePeng.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 119 KiB

BIN
public/images/team/BrendanWong.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 MiB

BIN
public/images/team/CatherineWan.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 786 KiB

BIN
public/images/team/CharlesZhang.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 200 KiB

BIN
public/images/team/ChrisXie.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 218 KiB

BIN
public/images/team/Codey.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

BIN
public/images/team/DoraSu.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 MiB

BIN
public/images/team/EdenChan.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

BIN
public/images/team/EdwinYang.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 847 KiB

BIN
public/images/team/FelixYang.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 968 KiB

BIN
public/images/team/GordonLe.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 733 KiB

BIN
public/images/team/GuneetBola.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 MiB

BIN
public/images/team/JaredHe.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 336 KiB

BIN
public/images/team/JasonSang.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 461 KiB

BIN
public/images/team/JuthikaHoque.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 277 KiB

BIN
public/images/team/KailinChan.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 862 KiB

BIN
public/images/team/KallenTu.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 1012 KiB

BIN
public/images/team/KarenLee.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 MiB

BIN
public/images/team/LinnaLuo.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 526 KiB

BIN
public/images/team/MarkChen.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 454 KiB

BIN
public/images/team/MaxErenberg.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 51 KiB

BIN
public/images/team/NeilParikh.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 177 KiB

BIN
public/images/team/PatrickHe.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

BIN
public/images/team/RavinduAngammana.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 897 KiB

BIN
public/images/team/RaymondLi.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 785 KiB

BIN
public/images/team/RichaDalal.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 114 KiB

BIN
public/images/team/SamHonoridez.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 341 KiB

BIN
public/images/team/SherryLev.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 223 KiB

BIN
public/images/team/ShiHan.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 69 KiB

BIN
public/images/team/StephanieXu.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 MiB

BIN
public/images/team/WilliamTran.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 738 KiB

BIN
public/images/team/YanniWang.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 320 KiB

4
public/images/team/popup-close.svg

@ -0,0 +1,4 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect width="2.57333" height="30.8317" rx="1.28666" transform="matrix(0.795101 -0.606477 0.710338 0.703861 0 1.83057)" fill="#C4C4C4"/>
<rect width="2.58854" height="30.6416" rx="1.29427" transform="matrix(-0.820223 -0.572044 0.67815 -0.734924 2.87207 24)" fill="#C4C4C4"/>
</svg>

After

Width:  |  Height:  |  Size: 377 B

12
public/images/team/team-codey.svg

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 44 KiB

3
public/images/team/team-member-placeholder.svg

@ -0,0 +1,3 @@
<svg width="126" height="126" viewBox="0 0 126 126" fill="none" xmlns="http://www.w3.org/2000/svg">
<circle cx="63" cy="63" r="63" fill="#5CAFF9" fill-opacity="0.09"/>
</svg>

After

Width:  |  Height:  |  Size: 175 B

20
tsconfig.json

@ -2,11 +2,7 @@
"compilerOptions": {
"baseUrl": ".",
"target": "es5",
"lib": [
"dom",
"dom.iterable",
"esnext"
],
"lib": ["dom", "dom.iterable", "esnext"],
"allowJs": true,
"skipLibCheck": true,
"strict": false,
@ -26,16 +22,10 @@
"strictFunctionTypes": true,
"paths": {
"@/components/*": ["components/*"],
"@/lib/*": ["lib/*"]
"@/lib/*": ["lib/*"],
"@/hooks/*": ["hooks/*"]
}