Merge in new pages

pull/164/head
Amy 2 years ago
commit f184310083
  1. 13
      .vscode/settings.json
  2. 68
      components/Bubble.module.css
  3. 17
      components/Bubble.tsx
  4. 42
      components/OrganizedContent.module.css
  5. 123
      components/OrganizedContent.tsx
  6. 37
      components/OrganizedContent/Header.module.css
  7. 23
      components/OrganizedContent/Header.tsx
  8. 61
      components/OrganizedContent/ReadAll.tsx
  9. 46
      components/OrganizedContent/Section.tsx
  10. 69
      components/OrganizedContent/static.ts
  11. 13
      components/TeamMember.module.css
  12. 8
      components/TeamMember.tsx
  13. 122
      components/TeamMemberCard.module.css
  14. 93
      components/TeamMemberCard.tsx
  15. 50
      components/playground.tsx
  16. 8
      content/about/code-of-conduct/additional-information.md
  17. 9
      content/about/code-of-conduct/addressing-grievances.md
  18. 13
      content/about/code-of-conduct/confidentiality.md
  19. 13
      content/about/code-of-conduct/consequences-of-inappropriate-behaviour.md
  20. 6
      content/about/code-of-conduct/contact-information.md
  21. 10
      content/about/code-of-conduct/expected-behaviour.md
  22. 19
      content/about/code-of-conduct/experiencing-unacceptable-behaviour.md
  23. 6
      content/about/code-of-conduct/license-information-and-attribution.md
  24. 13
      content/about/code-of-conduct/purpose.md
  25. 6
      content/about/code-of-conduct/revision.md
  26. 12
      content/about/code-of-conduct/scope-and-spaces.md
  27. 16
      content/about/code-of-conduct/unacceptable-behaviour.md
  28. 10
      content/about/constitution/amendments-and-procedures.md
  29. 8
      content/about/constitution/code-of-conduct.md
  30. 27
      content/about/constitution/committees.md
  31. 6
      content/about/constitution/dissolution.md
  32. 27
      content/about/constitution/duties-of-officers.md
  33. 10
      content/about/constitution/executive-council.md
  34. 9
      content/about/constitution/finances.md
  35. 13
      content/about/constitution/meetings.md
  36. 10
      content/about/constitution/membership.md
  37. 6
      content/about/constitution/name.md
  38. 30
      content/about/constitution/officers.md
  39. 10
      content/about/constitution/purpose.md
  40. 6
      content/about/constitution/revision.md
  41. 10
      content/about/constitution/use-of-club-resources.md
  42. 16
      content/about/index.mdx
  43. 6
      content/meet-the-team/execs/01-kallen-tu.md
  44. 6
      content/meet-the-team/execs/02-gordon-le.md
  45. 6
      content/meet-the-team/execs/03-nakul-vijhani.md
  46. 6
      content/meet-the-team/execs/04-neil-parikh.md
  47. 6
      content/meet-the-team/execs/05-max-erenberg.md
  48. 6
      content/meet-the-team/execs/06-codey.md
  49. 114
      content/meet-the-team/programme-committee.json
  50. 18
      content/meet-the-team/systems-committee.json
  51. 38
      content/meet-the-team/website-committee.json
  52. 40
      lib/organized-content.ts
  53. 55
      lib/team.ts
  54. 4
      package.json
  55. 4
      pages/_app.css
  56. 1
      pages/about/code-of-conduct.mdx
  57. 14
      pages/about/code-of-conduct.tsx
  58. 16
      pages/about/code-of-conduct/[section].tsx
  59. 1
      pages/about/constitution.mdx
  60. 14
      pages/about/constitution.tsx
  61. 16
      pages/about/constitution/[section].tsx
  62. 2
      pages/about/index.module.css
  63. 5
      pages/about/our-supporters.module.css
  64. 1
      pages/about/team.mdx
  65. 105
      pages/about/team.module.css
  66. 139
      pages/about/team.tsx
  67. 2
      pages/index.tsx
  68. 5
      public/images/bubble-decoration.svg
  69. 9
      public/images/code-of-conduct.svg
  70. 43
      public/images/constitution.svg
  71. 3
      public/images/team-member-placeholder.svg
  72. BIN
      public/images/team/AaronChoo.jpg
  73. BIN
      public/images/team/AdityaThakral.jpg
  74. BIN
      public/images/team/AlexZhang.jpg
  75. BIN
      public/images/team/AndrewWang.jpg
  76. BIN
      public/images/team/AnjingLi.jpg
  77. BIN
      public/images/team/AnnaWang.jpg
  78. BIN
      public/images/team/AthenaLiu.jpg
  79. BIN
      public/images/team/BettyGuo.jpg
  80. BIN
      public/images/team/BonniePeng.jpg
  81. BIN
      public/images/team/BrendanWong.jpg
  82. BIN
      public/images/team/CatherineWan.jpg
  83. BIN
      public/images/team/CharlesZhang.jpg
  84. BIN
      public/images/team/ChrisXie.jpg
  85. BIN
      public/images/team/Codey.jpg
  86. BIN
      public/images/team/DoraSu.jpg
  87. BIN
      public/images/team/EdenChan.jpg
  88. BIN
      public/images/team/EdwinYang.jpg
  89. BIN
      public/images/team/FelixYang.jpg
  90. BIN
      public/images/team/GordonLe.jpg
  91. BIN
      public/images/team/GuneetBola.jpg
  92. BIN
      public/images/team/JaredHe.jpg
  93. BIN
      public/images/team/JasonSang.jpg
  94. BIN
      public/images/team/JuthikaHoque.jpg
  95. BIN
      public/images/team/KailinChan.jpg
  96. BIN
      public/images/team/KallenTu.jpg
  97. BIN
      public/images/team/KarenLee.jpg
  98. BIN
      public/images/team/LinnaLuo.jpg
  99. BIN
      public/images/team/MarkChen.jpg
  100. BIN
      public/images/team/MaxErenberg.jpg
  101. Some files were not shown because too many files have changed in this diff Show More

@ -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]": {
@ -38,5 +36,10 @@
"files.exclude": {
"node_modules": true
},
"editor.tabSize": 2
}
"editor.tabSize": 2,
"files.eol": "\n",
"[markdown]": {
"editor.wordWrap": "on",
"editor.quickSuggestions": false
}
}

@ -1,7 +1,71 @@
.bubble {
.container {
position: relative;
padding: calc(36rem / 16) 0;
overflow-x: clip;
}
.bubble {
--border-radius: calc(5000rem / 16);
display: flex;
flex-direction: row;
position: absolute;
top: 0;
height: 100%;
width: 100%;
justify-content: center;
align-items: flex-start;
}
.bubble:nth-child(odd) {
.bar {
height: 100%;
width: 100%;
}
.decoration {
display: none;
width: calc(128rem / 16);
}
.margin {
display: none;
}
.content {
position: relative;
z-index: 1;
}
.container:nth-child(odd) .bar {
background-color: var(--primary-accent-light);
}
@media only screen and (min-width: calc(1350rem / 16)) {
.container:nth-child(odd) .decoration {
display: block;
position: absolute;
}
.container:nth-child(4n + 1) .bar {
border-top-right-radius: var(--border-radius);
border-bottom-right-radius: var(--border-radius);
transform: translateX(-12.5vw);
}
.container:nth-child(4n + 1) .decoration {
top: calc(-50rem / 16);
right: 8vw;
}
.container:nth-child(4n + 3) .bar {
border-top-left-radius: var(--border-radius);
border-bottom-left-radius: var(--border-radius);
transform: translateX(12.5vw);
}
.container:nth-child(4n + 3) .decoration {
top: calc(-50rem / 16);
left: 8vw;
transform: rotateY(180deg);
}
}

@ -1,13 +1,24 @@
import React from "react";
import { Image } from "@/components/Image";
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.bubble}>
<DefaultLayout>{props.children}</DefaultLayout>
<div className={styles.container}>
<div className={styles.bubble} aria-hidden>
<div className={styles.bar} />
<Image
className={styles.decoration}
src="/images/bubble-decoration.svg"
/>
</div>
<div className={styles.content}>
<DefaultLayout>{props.children}</DefaultLayout>
</div>
</div>
);
}

@ -2,20 +2,28 @@
display: flex;
}
.wrapper h1 {
margin: 1rem 0;
font-size: calc(24rem / 16);
font-weight: 600;
color: var(--primary-accent);
}
.content {
display: flex;
flex-direction: column;
width: 100%;
}
.content h1 {
font-size: calc(24rem / 16);
color: var(--primary-accent);
}
.content h2,
.content h3 {
font-size: calc(18rem / 16);
margin-top: calc(24rem / 16);
margin-bottom: calc(16rem / 16);
}
.nav {
top: calc(20rem / 16);
position: sticky;
height: 100%;
margin: calc(8rem / 16) calc(32rem / 16) 0 0;
color: var(--primary-heading);
font-weight: 500;
@ -29,7 +37,7 @@
border-bottom: calc(1rem / 16) solid var(--primary-accent-light);
align-items: center;
height: calc(40rem / 16);
width: calc(284rem / 16);
width: calc(200rem / 16);
padding: 0 calc(14rem / 16);
cursor: pointer;
}
@ -110,7 +118,25 @@
padding-left: calc(8rem / 16);
}
.link,
.link:visited {
color: inherit;
text-decoration: none;
}
@media only screen and (max-width: calc(768rem / 16)) {
.content h1 {
font-size: calc(18rem / 16);
}
.content h2,
.content h3,
.content h4 {
font-size: calc(18rem / 16);
margin-top: calc(24rem / 16);
margin-bottom: calc(8rem / 16);
}
.nav {
display: none;
}

@ -1,19 +1,13 @@
import NextLink from "next/link";
import React, { ReactNode, ComponentType } from "react";
import styles from "./OrganizedContent.module.css";
export interface LinkProps {
className?: string;
id: string;
children: ReactNode;
}
type Link = ComponentType<LinkProps>;
interface Section {
id: string;
title: string;
Content: ComponentType;
}
const READ_ALL_TITLE = "Read All";
@ -21,16 +15,23 @@ export const READ_ALL_ID = "read-all";
interface Props {
sections: Section[];
currentId: string;
id: string;
children: ReactNode;
link: Link;
}
export function OrganizedContent(props: Props) {
const sections = createSections(props.sections);
const currentIndex = sections.findIndex(({ id }) => id === props.currentId);
export function OrganizedContent({
sections,
id,
children,
link: Link,
}: Props) {
const currentIndex = sections.findIndex(
({ id: sectionId }) => sectionId === id
);
if (currentIndex < 0) {
throw new Error(`Section with ID ${props.currentId} was not found`);
throw new Error(`Section with ID ${id} was not found`);
}
const section = sections[currentIndex];
@ -38,20 +39,20 @@ export function OrganizedContent(props: Props) {
return (
<div className={styles.wrapper}>
<Nav sections={sections} currentIndex={currentIndex} link={props.link} />
<Nav sections={sections} currentIndex={currentIndex} link={Link} />
<div className={styles.content}>
{isReadAll ? (
<section.Content />
children
) : (
<>
<div>
<section>
<h1>{section.title}</h1>
<section.Content />
</div>
{children}
</section>
<Footer
sections={sections}
currentIndex={currentIndex}
link={props.link}
link={Link}
/>
</>
)}
@ -68,7 +69,7 @@ interface NavProps {
function Nav({ sections, currentIndex, link: Link }: NavProps) {
return (
<div className={styles.nav}>
<nav className={styles.nav}>
{sections.map((section, index) => {
const classNames = [styles.navItem];
@ -91,7 +92,7 @@ function Nav({ sections, currentIndex, link: Link }: NavProps) {
</Link>
);
})}
</div>
</nav>
);
}
@ -136,26 +137,68 @@ function Footer({ sections, currentIndex, link: Link }: FooterProps) {
);
}
function createSections(sections: Section[]) {
return [
{
id: READ_ALL_ID,
title: READ_ALL_TITLE,
Content() {
return (
<>
{sections.map(({ id, title, Content: SectionContent }) => (
<div key={id}>
<h1>{title}</h1>
<SectionContent />
</div>
))}
</>
);
},
},
...sections,
];
export interface SectionWithContent {
section: Section;
Content: ComponentType;
}
export function createReadAllSection(
sections: Section[],
content: false
): Section;
export function createReadAllSection(
sections: SectionWithContent[],
content: true
): SectionWithContent;
export function createReadAllSection(
sections: SectionWithContent[] | Section[],
content = true
): SectionWithContent | Section {
const readAllSection = {
id: READ_ALL_ID,
title: READ_ALL_TITLE,
};
return content
? {
section: readAllSection,
Content: function ReadAllContent() {
return (
<>
{(sections as SectionWithContent[]).map(
({ section: { id, title }, Content }) => (
<section key={id}>
<h1>{title}</h1>
<Content />
</section>
)
)}
</>
);
},
}
: readAllSection;
}
export interface LinkProps {
className?: string;
id: string;
children: ReactNode;
}
export function createLink(page: string) {
let base = page.startsWith("/") ? page : `/${page}`;
base = base.endsWith("/") ? base : `${base}/`;
return function Link({ className, id, children }: LinkProps) {
const href = id === READ_ALL_ID ? base : base + id;
return (
<NextLink href={href}>
<a className={`${styles.link} ${className ?? ""}`}>{children}</a>
</NextLink>
);
};
}
function Arrow({ direction }: { direction: "left" | "right" }) {

@ -0,0 +1,37 @@
.page {
margin-top: calc(60rem / 16);
margin-bottom: calc(40rem / 16);
}
.headerContainer {
display: flex;
flex-direction: row;
align-items: flex-end;
padding-bottom: 1rem;
border-bottom: calc(1rem / 16) solid var(--primary-heading);
}
.header {
line-height: 1;
color: var(--primary-heading);
font-size: calc(48rem / 16);
margin: 0 0 0 calc(36rem / 16);
text-align: center;
}
@media only screen and (max-width: calc(768rem / 16)) {
.headerContainer {
flex-direction: column;
align-items: center;
border: none;
}
.header {
font-size: calc(24rem / 16);
margin: 1.5rem 0 0 0;
}
.headerImage {
width: calc(100rem / 16);
}
}

@ -0,0 +1,23 @@
import React, { ReactNode } from "react";
import { Image } from "@/components/Image";
import styles from "./Header.module.css";
export interface Props {
title: string;
image: string;
children: ReactNode;
}
export function Header({ title, image, children }: Props) {
return (
<main className={styles.page}>
<header className={styles.headerContainer}>
<Image src={image} className={styles.headerImage} />
<h1 className={styles.header}>{title}</h1>
</header>
{children}
</main>
);
}

@ -0,0 +1,61 @@
import { MDXRemote, MDXRemoteSerializeResult } from "next-mdx-remote";
import React, { ComponentType } from "react";
import {
createLink,
createReadAllSection,
LinkProps,
OrganizedContent,
} from "@/components/OrganizedContent";
import { Header } from "./Header";
export interface SerializedSection {
section: {
id: string;
title: string;
};
content: MDXRemoteSerializeResult;
}
export interface Props {
sections: SerializedSection[];
}
export interface Options {
pagePath: string;
title: string;
image: string;
link?: ComponentType<LinkProps>;
}
export function createReadAllPage({ title, image, pagePath, link }: Options) {
const Link = link ?? createLink(pagePath);
return function Page({ sections }: Props) {
const readAllSection = createReadAllSection(
sections.map(({ section, content }) => ({
section,
Content() {
return <MDXRemote {...content} />;
},
})),
true
);
return (
<Header title={title} image={image}>
<OrganizedContent
id={readAllSection.section.id}
sections={[
readAllSection.section,
...sections.map(({ section }) => section),
]}
link={Link}
>
<readAllSection.Content />
</OrganizedContent>
</Header>
);
};
}

@ -0,0 +1,46 @@
import { MDXRemote, MDXRemoteSerializeResult } from "next-mdx-remote";
import React, { ComponentType } from "react";
import {
createLink,
LinkProps,
OrganizedContent,
} from "@/components/OrganizedContent";
import { Header } from "./Header";
interface Section {
id: string;
title: string;
}
export interface Props {
content: MDXRemoteSerializeResult;
sections: Section[];
current: number;
}
export interface Options {
title: string;
pagePath: string;
image: string;
link?: ComponentType<LinkProps>;
}
export function createSectionPage({ title, image, pagePath, link }: Options) {
const Link = link ?? createLink(pagePath);
return function Page(this: void, { content, sections, current }: Props) {
return (
<Header title={title} image={image}>
<OrganizedContent
sections={sections}
id={sections[current].id}
link={Link}
>
<MDXRemote {...content} />
</OrganizedContent>
</Header>
);
};
}

@ -0,0 +1,69 @@
import { ParsedUrlQuery } from "querystring";
import { GetStaticPaths, GetStaticProps, GetStaticPropsContext } from "next";
import { createReadAllSection } from "@/components/OrganizedContent";
import {
getSectionNamesForPage,
getSectionsForPage,
} from "@/lib/organized-content";
import { Props as ReadAllProps } from "./ReadAll";
import { Props as SectionProps } from "./Section";
export function createReadAllGetStaticProps(pagePath: string) {
return (async () => {
const sections = await getSectionsForPage(pagePath);
return {
props: {
sections: sections.map(({ name: id, data: { title, content } }) => ({
section: {
id,
title,
},
content,
})),
},
};
}) as GetStaticProps<ReadAllProps>;
}
interface SectionParams extends ParsedUrlQuery {
section: string;
}
export function createSectionGetStaticProps(pagePath: string) {
return async function getStaticProps(
context: GetStaticPropsContext<SectionParams>
) {
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
const currentName = context.params!.section;
const fullSections = await getSectionsForPage(pagePath);
const current = fullSections.findIndex(({ name }) => name === currentName);
const sections = fullSections.map(({ name, data: { title } }) => ({
id: name,
title,
}));
return {
props: {
content: fullSections[current].data.content,
current: current + 1,
sections: [createReadAllSection(sections, false), ...sections],
},
};
} as GetStaticProps<SectionProps, SectionParams>;
}
export function createSectionGetStaticPaths(pagePath: string) {
return async function getStaticPaths() {
const names = await getSectionNamesForPage(pagePath);
return {
paths: names.map((section) => ({ params: { section } })),
fallback: false,
};
} as GetStaticPaths<SectionParams>;
}

@ -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;
}
}

@ -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>

@ -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;
}
} */
}

@ -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>
</>
);
}

@ -45,7 +45,11 @@ import { Link } from "./Link";
import { MiniEventCard } from "./MiniEventCard";
import { MiniTechTalkCard } from "./MiniTechTalkCard";
import { NewsCard } from "./NewsCard";
import { OrganizedContent, LinkProps } from "./OrganizedContent";
import {
OrganizedContent,
LinkProps,
createReadAllSection,
} from "./OrganizedContent";
import { TeamMember } from "./TeamMember";
import { TeamMemberCard } from "./TeamMemberCard";
import { TechTalkCard } from "./TechTalkCard";
@ -162,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>
);
@ -180,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>
@ -205,7 +209,18 @@ export function LinkDemo() {
}
export function OrganizedContentDemo() {
const sections = constitution;
const sections = [...constitution];
const readAllSection = createReadAllSection(
constitution.map(({ id, title, Content }) => ({
Content,
section: { id, title },
})),
true
);
sections.unshift({
...readAllSection.section,
Content: readAllSection.Content,
});
const [id, setId] = useState(sections[0].id);
@ -217,8 +232,15 @@ export function OrganizedContentDemo() {
);
}
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
const Content = sections.find(
({ id: sectionId }) => sectionId === id
)!.Content;
return (
<OrganizedContent sections={sections} currentId={id} link={FakeLink} />
<OrganizedContent sections={sections} id={id} link={FakeLink}>
<Content />
</OrganizedContent>
);
}

@ -0,0 +1,8 @@
---
title: Additional Information
index: 10
---
Additionally, the Executive Council are available to help Club members engage with local law enforcement or to otherwise help those experiencing unacceptable behaviour feel safe. In the context of in-person events, organizers will also provide escorts as desired by the person experiencing distress.
Changes to the Code of Conduct are governed by the Club's [constitution](https://csclub.uwaterloo.ca/about/constitution).

@ -0,0 +1,9 @@
---
title: Addressing Grievances
index: 6
---
If either the complainant or the subject disagree with the decision made by the Handling Officer, they can appeal to the Officers, who can overturn the decision with a majority vote of all the Officers.
No Officer who was personally involved in the complaint, or is in a close relationship with someone involved in the complaint, shall participate in the Officers deliberation or vote on the appeal.
If the subject of a complaint is expelled from the Club, then at their request, but no more often than once a year, the Officers will review the decision to expel them from the Club. The Officers can reinstate the subject with a two-thirds vote of the Officers.

@ -0,0 +1,13 @@
---
title: Confidentiality
index: 7
---
The Club recognizes that all members have a right to privacy, and will handle complaints confidentially.
As such, proceedings will be kept confidential as described below, to the extent allowed by whichever University policy applies to the complaint. Relevant policies include Policy 42 (Prevention and Response to Sexual Violence), Policy 33 (Ethical Behaviour), or Policy 34 (Health, Safety, and Environment).
Information will only be reported to Police Services when directly required to by applicable policy. In such a case, only the required information will be provided, anonymized if possible.
**Information that will be kept in Club records and be available to Officers in the future will be limited to**: the date the complaint was made, the name of the subject of the complaint, the name of the Handling Officer, the decision made on the complaint, the date the decision on the complaint was made, and if applicable, the date of the appeal, the party making the appeal (Complainant or Subject), the decision made on the appeal by the Officers, and the date of the Officers decision on the appeal.
**The information the Handling Officer and Faculty Advisor will jointly keep records of, in addition to the information kept in the Club records, will be limited to** : the name of the complainant, and a summary of the complaint. This information will be available to Officers that are handling future complaints if it is requested and the Handling Officer deems it relevant to the new complaint.

@ -0,0 +1,13 @@
---
title: Consequences of Inappropriate Behaviour
index: 5
---
After having done so, the Handling Officer shall use their best judgment to determine if the complaint is valid and, if so, determine with the relevant Officers the appropriate action to ensure that the complainant feels welcome in the Computer Science Club and to avoid a subsequent incident:
- A warning.
- A suspension from the events and spaces governed by the Code of Conduct until the beginning of the next term. If the suspension would come into effect less than two full weeks from the end of classes in the current term, then the suspension applies to the subsequent term as well.
- If the incident is very serious, or the subject has a pattern of similar offences, expulsion from the Club.
- A formal complaint through University policy, such as 33, 34, and 42.
The Handling Officer shall inform the complainant of the resolution of the issue and inform both the complainant and the subject of their right to appeal the decision.

@ -0,0 +1,6 @@
---
title: Contact Information
index: 9
---
- The Computer Science Club [Officers can be contacted as a whole](https://csclub.uwaterloo.ca/about/).

@ -0,0 +1,10 @@
---
title: Expected Behaviour
index: 2
---
- Participate in an authentic and active way. In doing so, you contribute to the health and longevity of this Club.
- Exercise consideration and respect in your speech and actions.
- Attempt collaboration before conflict.
- Refrain from demeaning, discriminatory, or harassing behaviour and speech.
- Be mindful of your surroundings and of your fellow participants.

@ -0,0 +1,19 @@
---
title: Experiencing Unacceptable Behaviour
index: 4
---
_The Executive Council and Faculty Advisor are herein referred to as the Officers, or singularly as Officer._
If you notice a dangerous situation, someone in distress, or violations of this Code of Conduct, [contact an Officer](https://csclub.uwaterloo.ca/about/). No situation is considered inconsequential. If you do not feel comfortable contacting an Executive Council member due to the nature of the incident, you may contact the [Faculty Advisor](https://csclub.uwaterloo.ca/about/exec#advisor).
Upon receiving a complaint the Officer will inform the first of the following people who is not personally involved in the situation, or in a close relationship with the someone involved in the situation and is available, and this person shall handle the complaint and shall here after be referred to as the Handling Officer.
1. The President
2. The Vice President
3. Any other Executive Council Member
4. The Faculty Advisor
The Handling Officer will interview the subject of the complaint and any witnesses and consult with other relevant Officers. The Handling Officer shall chair a handling committee of the Faculty Advisor and one other officer chosen in the same way. This committee shall be familiar with University Policies 33, 34, and 42.
The Faculty Advisor will make sure that all applicable University policies, laws, and bylaws are followed. The Faculty Advisor must always be notified of all complaints and decisions.

@ -0,0 +1,6 @@
---
title: License Information and Attribution
index: 11
---
- The Code of Conduct is distributed under a [Creative Commons Attribution-ShareAlike License](http://creativecommons.org/licenses/by-sa/3.0/) , derived from the [Women in Computer Science Code of Conduct](http://wics.uwaterloo.ca/code-of-conduct/) , the [UW Amateur Radio Club Code of Conduct](http://uwarc.uwaterloo.ca/policies-procedures/code-of-conduct/) , and the [FASS Code of Conduct (Article 2, Section 16)](http://fass.uwaterloo.ca/wp-content/uploads/2015/03/constitution.pdf) .

@ -0,0 +1,13 @@
---
title: Purpose
index: 1
---
One of the primary goals of the Computer Science Club of the University of Waterloo is the inclusion and support of all members of the University of Waterloo community who are interested in Computer Science. As such, we are committed to providing a friendly, safe and welcoming environment for all, regardless of gender, sex, sexual orientation, ability, ethnicity, socioeconomic status, age, and religion or lack thereof.
We invite all those who participate in our events and who communicate with our Club at large to help us create a safe and positive experience for everyone involved.
- The Code of Conduct highlights our expectations for all individuals who participate in our Club, as well as the steps to handle unacceptable behaviour.
- The Code of Conduct should be signed by new Club members.
- The Code of Conduct is in addition to existing University Policies, such as [policies 33](https://uwaterloo.ca/secretariat/policies-procedures-guidelines/policy-33), [34](https://uwaterloo.ca/secretariat/policies-procedures-guidelines/policy-34), and [42](https://uwaterloo.ca/secretariat/policies-procedures-guidelines/policies/policy-42-prevention-and-response-sexual-violence).
- The Code of Conduct does not cover criminal matters. Initiating a Code of Conduct complaint does not exclude other paths, such as going to Police Services. For criminal matters, threats or acts of physical violence, immediately contact directly UW Police at (519) 888-4911, or use the On Campus Extension x22222.

@ -0,0 +1,6 @@
---
title: Revision
index: 12
---
Revision 1.3, adopted by the Computer Science Club of the University of Waterloo on 25 January 2018.

@ -0,0 +1,12 @@
---
title: Scope and Spaces
index: 8
---
In cases where the Code of Conduct contradicts University policies, or applicable laws and bylaws, the Code of Conduct does not apply to the extent to which it conflicts.
We expect all Club participants (participants, organizers, sponsors, and other guests) to abide by this Code of Conduct in all community venues (online and in-person) as well as in all one-on-one communications pertaining to Club business.
- The Code of Conduct applies in the office, where office staff are responsible for enforcing it.
- The Code of Conduct applies in the IRC channel, where channel operators are responsible for enforcing it.
- The Code of Conduct applies at events the CSC organizes or co-organizes, where a designated organizer is responsible for enforcing it.

@ -0,0 +1,16 @@
---
title: Unacceptable Behaviour
index: 3
---
**Unacceptable behaviours include:**
Intimidating, harassing, abusive, discriminatory, derogatory or demeaning speech or actions by any participant in our community online, at all related events and in one-on-one communications carried out in the context of Club business.
- Club event venues may be shared; please be respectful to all patrons of these locations.
**Harassment includes**:
Harmful or prejudicial verbal or written comments related to gender, sexual orientation, race, religion, disability; inappropriate use of nudity and/or sexual images in public spaces (including presentation slides); deliberate intimidation, stalking or following; harassing photography or recording; sustained disruption of talks or other events; inappropriate physical contact, and unwelcome sexual attention.
- Also refer to [Policy 33](https://uwaterloo.ca/secretariat/policies-procedures-guidelines/policy-33) for the definitions of discrimination and harassment.

@ -0,0 +1,10 @@
---
title: 10. Amendments and Procedures
index: 10
---
1. A proposed constitutional amendment can be initiated by the Executive Council or any ten (10) members.
2. The proposed amendment shall be announced to all members by email to the members' mailing list.
3. The proposed amendment shall be made available for viewing by all members in the Computer Science Club office.
4. A general meeting shall be held to consider the amendment at least seven (7) days after the announcement and no more than thirty (30) days after, which may be the regular meeting for the term, or a special meeting.
5. A constitutional amendment requires a 2/3 vote for adoption.

@ -0,0 +1,8 @@
---
title: 12. Code of Conduct
index: 12
---
1. The Club has a [Code of Conduct](https://csclub.uwaterloo.ca/about/code-of-conduct).
2. The [scope of the Code of Conduct](https://csclub.uwaterloo.ca/about/code-of-conduct/scopes-and-spaces) is specified by the Code of Conduct.
3. Changes to the Code of Conduct are governed by the same rules as changes to the Constitution.

@ -0,0 +1,27 @@
---
title: 7. Committees
index: 7
---
## Programme Committee
1. The Programme Committee shall be a standing committee chaired by the Vice-President.
2. The Vice-President shall appoint and remove members to and from the Programme Committee as needed.
3. The Programme Committee shall plan and arrange the events of the Club.
4. The Programme committee shall be responsible to the Executive Council and to the Vice-President.
## Systems Committee
1. The Systems Committee will be a standing committee, chaired by the Systems Administrator.
2. The Systems Administrator shall appoint and remove members to and from the Systems Committee.
3. Members should only be appointed to the Systems Committee if they show interest and some existing ability in systems administration.
4. Members should only be removed from the Systems Committee with cause, or when they no longer show interest in systems administration.
5. The Systems Committee will collectively, under the leadership of the Systems Administrator,
a. operate any and all equipment in the possession of the Club.
a. maintain and upgrade the software on equipment that is operated by the Club.
a. facilitate the use of equipment that is operated by the Club.
6. Members of the Systems Committee shall have root access to the machines operated by the Club.
## Other Committees
1. The President, with approval of the executive council, may appoint such special committees as are deemed necessary.

@ -0,0 +1,6 @@
---
title: 11. Dissolution
index: 11
---
1. In the event of dissolution of the Club, all assets of the Club shall be transferred to the Mathematics Society of the University of Waterloo.

@ -0,0 +1,27 @@
---
title: 5. Duties of Officers
index: 5
---
1. The duties of the President shall be:
a. to call and preside at all general, special, and executive meetings of the Club, except during the election of officers;
a. to appoint special committees of the Club and the membership and chairs of such committees, with the approval of the Executive Council; and
a. to audit, or to appoint a representative to audit, the financial records of the club at the end of each academic term.
a. with the approval of the Faculty Advisor, rule on any point of procedure under the constitution that arises outside of a meeting.
1. The duties of the Vice-President shall be:
a. to assume the duties of the President in the event of the President's absence;
a. to chair the Programme Committee;
a. to appoint members to and remove members from the Programme Committee;
a. to ensure that Club events are held regularly; and
a. to assume those duties of the President that are delegated to them by the President.
1. The duties of the Secretary shall be:
a. to keep minutes of all Club meetings;
a. to care for all Club correspondence; and
a. manage any persons appointed to internal positions by the Executive.
1. The duties of the Treasurer shall be:
a. to collect dues and maintain all financial and membership records;
a. to produce a financial or membership statement when requested.
1. The duties of the System Administrator shall be:
a. to chair the Systems Committee;
a. to appoint members to and remove members from the Systems Committee.
a. to ensure that the duties of the Systems Committee are performed.

@ -0,0 +1,10 @@
---
title: 6. Executive Council
index: 6
---
1. The Executive Council shall consist of the present officers of the Club and the Faculty Advisor (as a non-voting member) and has the power to run the affairs of this club within the limits of this constitution. This includes the power to overrule or issue directions to any officer.
2. The Executive Council may appoint people to various positions to help manage the Club.
3. The Executive Council must obey any instructions given to it by the members at a meeting and can be overruled by them.
4. The Executive Council can act by consensus achieved on their mailing list.
5. Minutes of the Executive Council meetings shall be available for inspection by any member of the Club and shall be filed with the Club records. On request, a member shall be shown the archive of any thread on the Executive Council mailing list which resulted in a decision being made.

@ -0,0 +1,9 @@
---
title: 9. Finances
index: 9
---
1. The Treasurer shall, each term, present to the Executive a financial statement for the previous term. They shall, before the end of the current term, ensure that the records are in a good condition to make this task as easy as possible for the next Treasurer.
2. The Treasurer shall prepare a budget each term, to be presented to MathSoc, and shall be responsible to ensure that the Club is represented at the MathSoc budget meeting.
3. The signing officers shall be the Treasurer, and one of the President or Vice-President.
4. At the end of each term, the President or his/her representative shall ensure that the financial records are complete and accurate.

@ -0,0 +1,13 @@
---
title: 8. Meetings
index: 8
---
1. A regular meeting of the Club shall be held each term. This meeting shall be called by the CRO and shall be the election meeting for that term.
2. Special meetings may be called at any time deemed necessary by the Executive Council, by the Faculty Advisor, or by any ten (10) members.
3. All members shall be notified at least two days prior to a forthcoming meeting of the meeting and of the business to be considered at that meeting. A message to the members' mailing list will be considered sufficient notification, though other forms of notification are also encouraged.
4. The Club shall hold meetings only in places that are open to all members of the Club.
5. The Club membership cannot act except at a general meeting.
6. A quorum necessary for the conduct of business is defined as fifteen (15) full members or 2/3 of the full membership, whichever is smaller. If an election meeting lacks quorum, then the inquorate meeting can set a date and time for the elections, and can choose to either run the new elections with the same nominations or with a new nomination period (which does not need to meet the usual minimum requirement).
7. A motion to remove an officer, or to call new elections (except at an election meeting), requires a 2/3 vote and at least a week's notice. Any other motion requires a majority vote.
8. If a motion is defeated, it cannot be brought again for sixty (60) days.

@ -0,0 +1,10 @@
---
title: 3. Membership