Add past execs page (Close #370) #417
|
@ -13,7 +13,7 @@ import { Title } from "./Title";
|
|||
import styles from "./ArchivePage.module.css";
|
||||
|
||||
export interface Props {
|
||||
type: "news" | "events";
|
||||
type: "news" | "events" | "executives";
|
||||
items: {
|
||||
year: string;
|
||||
terms: Term[];
|
||||
|
@ -28,13 +28,19 @@ export function ArchivePage({ items, type }: Props) {
|
|||
<h1>{capitalize(type)} Archive</h1>
|
||||
<ul className={styles.list}>
|
||||
{items.map(({ year, terms }) =>
|
||||
terms.map((term) => (
|
||||
<li key={`/${type}/${year}/${term}`}>
|
||||
<Link href={`/${type}/${year}/${term}`}>
|
||||
{capitalize(term)} {year}
|
||||
</Link>
|
||||
</li>
|
||||
))
|
||||
terms.map((term) => {
|
||||
const url =
|
||||
type !== "executives"
|
||||
? `/${type}/${year}/${term}`
|
||||
: `/about/${type}/${year}/${term}`;
|
||||
return (
|
||||
<li key={url}>
|
||||
<Link href={url}>
|
||||
{capitalize(term)} {year}
|
||||
</Link>
|
||||
</li>
|
||||
);
|
||||
})
|
||||
)}
|
||||
</ul>
|
||||
</div>
|
||||
|
|
|
@ -36,6 +36,10 @@ const menu: Menu = [
|
|||
name: "Members",
|
||||
route: "/about/members",
|
||||
},
|
||||
{
|
||||
name: "Past Executives",
|
||||
route: "/about/executives",
|
||||
},
|
||||
{
|
||||
name: "Constitution",
|
||||
route: "/about/constitution",
|
||||
|
|
|
@ -10,7 +10,7 @@ export interface TeamMemberCardProps {
|
|||
name: string;
|
||||
role: string;
|
||||
image: string;
|
||||
children: React.ReactNode;
|
||||
children?: React.ReactNode;
|
||||
}
|
||||
|
||||
export function TeamMemberCard({
|
||||
|
|
|
@ -0,0 +1,26 @@
|
|||
[
|
||||
{
|
||||
"name": "Dora Su",
|
||||
"role": "President"
|
||||
},
|
||||
{
|
||||
"name": "Jason Sang",
|
||||
"role": "Vice President"
|
||||
},
|
||||
{
|
||||
"name": "Anjing Li",
|
||||
"role": "Assistant Vice President"
|
||||
},
|
||||
{
|
||||
"name": "Yanni Wang",
|
||||
"role": "Treasurer"
|
||||
},
|
||||
{
|
||||
"name": "Max Erenberg",
|
||||
"role": "Systems Administrator"
|
||||
},
|
||||
{
|
||||
"name": "Neil Parikh",
|
||||
"role": "Advisor"
|
||||
}
|
||||
]
|
|
@ -0,0 +1,22 @@
|
|||
[
|
||||
{
|
||||
"name": "Kallen Tu",
|
||||
"role": "President"
|
||||
},
|
||||
{
|
||||
"name": "Gordon Le",
|
||||
"role": "Vice President"
|
||||
},
|
||||
{
|
||||
"name": "Ravindu Angammana",
|
||||
"role": "Assistant Vice President"
|
||||
},
|
||||
{
|
||||
"name": "Neil Parikh",
|
||||
"role": "Treasurer"
|
||||
},
|
||||
{
|
||||
"name": "Max Erenberg",
|
||||
"role": "Systems Administrator"
|
||||
}
|
||||
]
|
|
@ -0,0 +1,22 @@
|
|||
[
|
||||
{
|
||||
"name": "Kallen Tu",
|
||||
"role": "President"
|
||||
},
|
||||
{
|
||||
"name": "Gordon Le",
|
||||
"role": "Vice President"
|
||||
},
|
||||
{
|
||||
"name": "Nakul Vijhani",
|
||||
"role": "Assistant Vice President"
|
||||
},
|
||||
{
|
||||
"name": "Neil Parikh",
|
||||
"role": "Treasurer"
|
||||
},
|
||||
{
|
||||
"name": "Max Erenberg",
|
||||
"role": "Systems Administrator"
|
||||
}
|
||||
]
|
|
@ -0,0 +1,30 @@
|
|||
[
|
||||
{
|
||||
"name": "Juthika Hoque",
|
||||
"role": "President"
|
||||
},
|
||||
{
|
||||
"name": "Eric Huang",
|
||||
"role": "Vice President"
|
||||
},
|
||||
{
|
||||
"name": "Dina Orucevic",
|
||||
"role": "Assistant Vice President"
|
||||
},
|
||||
{
|
||||
"name": "Eden Chan",
|
||||
"role": "Treasurer"
|
||||
},
|
||||
{
|
||||
"name": "Raymond Li",
|
||||
"role": "Systems Administrator"
|
||||
},
|
||||
{
|
||||
"name": "Amy Wang",
|
||||
"role": "Web Master"
|
||||
},
|
||||
{
|
||||
"name": "Neil Parikh",
|
||||
"role": "Office Manager"
|
||||
}
|
||||
]
|
After Width: | Height: | Size: 52 KiB |
After Width: | Height: | Size: 205 KiB |
After Width: | Height: | Size: 2.2 MiB |
After Width: | Height: | Size: 10 KiB |
After Width: | Height: | Size: 1.2 MiB |
After Width: | Height: | Size: 733 KiB |
After Width: | Height: | Size: 461 KiB |
After Width: | Height: | Size: 277 KiB |
After Width: | Height: | Size: 1012 KiB |
After Width: | Height: | Size: 51 KiB |
After Width: | Height: | Size: 177 KiB |
After Width: | Height: | Size: 897 KiB |
After Width: | Height: | Size: 4.6 MiB |
After Width: | Height: | Size: 320 KiB |
|
@ -274,7 +274,10 @@ export function getCurrentTerm(): { year: string; term: Term } {
|
|||
return { year, term };
|
||||
}
|
||||
|
||||
function getPastTerm(year: string, term: Term): { year: string; term: Term } {
|
||||
export function getPastTerm(
|
||||
year: string,
|
||||
term: Term
|
||||
): { year: string; term: Term } {
|
||||
const index = TERMS.indexOf(term);
|
||||
|
||||
if (index === -1) {
|
||||
|
@ -292,7 +295,10 @@ function getPastTerm(year: string, term: Term): { year: string; term: Term } {
|
|||
};
|
||||
}
|
||||
|
||||
function getFutureTerm(year: string, term: Term): { year: string; term: Term } {
|
||||
export function getFutureTerm(
|
||||
year: string,
|
||||
term: Term
|
||||
): { year: string; term: Term } {
|
||||
const index = TERMS.indexOf(term);
|
||||
|
||||
if (index === -1) {
|
||||
|
|
|
@ -0,0 +1,98 @@
|
|||
.headerContainer {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
padding-bottom: calc(24rem / 16);
|
||||
border-bottom: calc(1rem / 16) var(--primary-heading);
|
||||
margin-bottom: calc(32rem / 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(32rem / 16);
|
||||
margin-top: calc(46rem / 16);
|
||||
}
|
||||
|
||||
.codey {
|
||||
width: calc(360rem / 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;
|
||||
}
|
||||
|
||||
.info {
|
||||
margin: 6rem 0;
|
||||
}
|
||||
|
||||
.infoSubheading {
|
||||
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;
|
||||
margin-top: calc(30rem / 16);
|
||||
}
|
||||
|
||||
.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);
|
||||
}
|
||||
|
||||
.members {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fill, minmax(calc(130rem / 16), 1fr));
|
||||
justify-items: center;
|
||||
column-gap: 0;
|
||||
}
|
||||
|
||||
.infoSubheading {
|
||||
font-size: calc(24rem / 16);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,141 @@
|
|||
import { GetStaticProps } from "next";
|
||||
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 { Title } from "@/components/Title";
|
||||
import { Metadata, getMemberImagePath } from "@/lib/team";
|
||||
|
||||
import F21ExecData from "../../content/past-execs/2021/fall.json";
|
||||
import S21ExecData from "../../content/past-execs/2021/spring.json";
|
||||
import W21ExecData from "../../content/past-execs/2021/winter.json";
|
||||
import W22ExecData from "../../content/past-execs/2022/winter.json";
|
||||
|
||||
import styles from "./executives.module.css";
|
||||
|
||||
interface Props {
|
||||
F21Exec: Metadata[];
|
||||
S21Exec: Metadata[];
|
||||
W21Exec: Metadata[];
|
||||
W22Exec: Metadata[];
|
||||
}
|
||||
|
||||
export default function Executives({
|
||||
F21Exec,
|
||||
S21Exec,
|
||||
W21Exec,
|
||||
W22Exec,
|
||||
}: Props) {
|
||||
const teams = [
|
||||
{
|
||||
id: "W22Exec",
|
||||
name: "Winter 2022",
|
||||
members: W22Exec,
|
||||
},
|
||||
{
|
||||
id: "F21Exec",
|
||||
name: "Fall 2021",
|
||||
members: F21Exec,
|
||||
},
|
||||
{
|
||||
id: "S21Exec",
|
||||
name: "Spring 2021",
|
||||
members: S21Exec,
|
||||
},
|
||||
{
|
||||
id: "W21Exec",
|
||||
name: "Winter 2021",
|
||||
members: W21Exec,
|
||||
},
|
||||
];
|
||||
return (
|
||||
<>
|
||||
<Title>Team</Title>
|
||||
<DefaultLayout>
|
||||
<div className={styles.headerContainer}>
|
||||
<div className={styles.headerTextContainer}>
|
||||
<h1 className={styles.header}>Meet the Past Executives!</h1>
|
||||
<div className={styles.nav}>
|
||||
<Link href="#F21Exec">Fall 2021</Link>
|
||||
<Link href="#S21Exec">Spring 2021</Link>
|
||||
<Link href="#W21Exec">Winter 2021</Link>
|
||||
</div>
|
||||
</div>
|
||||
<Image src="images/team/team-codey.svg" className={styles.codey} />
|
||||
</div>
|
||||
{teams.map((team) => {
|
||||
return (
|
||||
<div id={team.id} key={team.id}>
|
||||
<h2 className={styles.subheading}>{team.name}</h2>
|
||||
<MembersList team={team.members} />
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</DefaultLayout>
|
||||
<div className={styles.info}>
|
||||
<Bubble>
|
||||
<h2 className={styles.infoSubheading}>More information</h2>
|
||||
To learn more about our past executives, see our{" "}
|
||||
<Link href="https://wiki.csclub.uwaterloo.ca/Past_Executive">
|
||||
Wikipedia
|
||||
</Link>
|
||||
.
|
||||
</Bubble>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
Executives.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>
|
||||
);
|
||||
}
|
||||
|
||||
type TeamMember = Omit<Metadata, "image"> & { image?: string };
|
||||
|
||||
async function getTeamWithImages(team: TeamMember[]) {
|
||||
return await Promise.all(
|
||||
team.map(async (member) => {
|
||||
const image =
|
||||
member.image ?? (await getMemberImagePath(member.name, false));
|
||||
return {
|
||||
...member,
|
||||
image,
|
||||
};
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
export const getStaticProps: GetStaticProps<Props> = async () => {
|
||||
const [F21Exec, S21Exec, W21Exec, W22Exec] = await Promise.all([
|
||||
getTeamWithImages(F21ExecData),
|
||||
getTeamWithImages(S21ExecData),
|
||||
getTeamWithImages(W21ExecData),
|
||||
getTeamWithImages(W22ExecData),
|
||||
]);
|
||||
|
||||
return {
|
||||
props: {
|
||||
F21Exec,
|
||||
S21Exec,
|
||||
W21Exec,
|
||||
W22Exec,
|
||||
},
|
||||
};
|
||||
};
|
|
@ -103,4 +103,4 @@
|
|||
.electionSubheading {
|
||||
font-size: calc(24rem / 16);
|
||||
}
|
||||
}
|
||||
}
|