Merge remote-tracking branch 'origin/main' into feat/events-page
continuous-integration/drone/push Build is passing Details

This commit is contained in:
Aditya Thakral 2021-08-27 17:53:58 -04:00
commit f3d9a08a73
449 changed files with 6377 additions and 707 deletions

View File

@ -4,8 +4,15 @@ type: docker
name: node16
steps:
- name: check-lockfile
image: node:16
commands:
- node ./check-lockfile.js
- name: install-deps
image: node:16
depends_on:
- check-lockfile
commands:
- npm install
@ -30,6 +37,16 @@ steps:
commands:
- npm run export
- name: deploy (staging)
image: node:16
depends_on:
- export
environment:
TOKEN:
from_secret: STAGING_TOKEN
commands:
- 'curl -XPOST -H "Authorization: $TOKEN" -H "X-Branch: $DRONE_BRANCH" "https://csclub.uwaterloo.ca/~a3thakra/update-csc/"'
trigger:
event:
exclude:

11
.vscode/settings.json vendored
View File

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

10
check-lockfile.js Normal file
View File

@ -0,0 +1,10 @@
const lockfile = require('./package-lock.json')
if (lockfile.lockfileVersion !== 2) {
console.error(`
Please upgrade to npm v7 and revert changes to the lockfile.
- \`npm i -g npm\` to upgrade.
`.trim())
process.exit(1)
}

View File

@ -1,7 +1,71 @@
.bubble {
.container {
position: relative;
padding: calc(36rem / 16) 0;
overflow-x: clip;
}
.bubble:nth-child(odd) {
.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;
}
.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);
}
}

View File

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

View File

@ -0,0 +1,6 @@
.code {
padding: 0 calc(4rem / 16);
background: var(--code-background);
border-radius: calc(5rem / 16);
word-wrap: break-word;
}

9
components/Code.tsx Normal file
View File

@ -0,0 +1,9 @@
import React, { HTMLAttributes } from "react";
import styles from "./Code.module.css";
export function Code(props: HTMLAttributes<HTMLElement>) {
const classes = [styles.code, props.className ?? ""];
return <code {...props} className={classes.join(" ")} />;
}

View File

@ -18,9 +18,9 @@ export function ConnectWithUs() {
<SocialLinks color="gradient" size="big" />
</div>
{/* TODO: fix feedback form link */}
<p>
Send feedback through our <Link href="#">Feedback Form</Link>
Send feedback through our{" "}
<Link href="https://bit.ly/uwcsclub-feedback-form">Feedback Form</Link>
</p>
</section>
);

View File

@ -1,7 +1,3 @@
.container form {
box-sizing: border-box;
}
.header {
color: var(--primary-accent);
font-weight: 600;
@ -9,8 +5,9 @@
}
.button {
margin-top: calc(34rem / 16);
margin-top: calc(26rem / 16);
display: block;
width: fit-content;
}
@media only screen and (max-width: calc(768rem / 16)) {

View File

@ -1,21 +1,24 @@
import React from "react";
import { Button } from "./Button";
import { Input } from "./Input";
import styles from "./EmailSignup.module.css";
export function EmailSignup() {
return (
<section className={styles.container}>
<h1 className={styles.header}>Join Our Mailing List!</h1>
<form className={styles.form} action="">
<Input type="text" placeholder="Full Name*" required />
<Input type="email" placeholder="Email*" required />
<Button type="submit" className={styles.button}>
<h1 className={styles.header}>Join our mailing list!</h1>
<p>
Join our mailing list to receive email notifications about important
news and upcoming events!
</p>
<Button
isLink={true}
href="https://mailman.csclub.uwaterloo.ca/postorius/lists/csc-general.csclub.uwaterloo.ca/"
className={styles.button}
>
Subscribe
</Button>
</form>
</section>
);
}

View File

@ -23,6 +23,11 @@
text-align: center;
}
.email {
color: unset;
text-decoration: unset;
}
@media only screen and (max-width: calc(768rem / 16)) {
.footer {
height: calc(120rem / 16);

View File

@ -1,3 +1,4 @@
import Link from "next/link";
import React from "react";
import { SocialLinks } from "./SocialLinks";
@ -9,7 +10,10 @@ export function Footer() {
<footer className={styles.footer}>
<div className={styles.container}>
<div className={styles.text}>
Have questions? Email us at XX@XXX.COM
Have questions? Email us at{" "}
<Link href="mailto:exec@csclub.uwaterloo.ca">
<a className={styles.email}>exec@csclub.uwaterloo.ca</a>
</Link>
</div>
<SocialLinks color="white" size="small" />
</div>

View File

@ -0,0 +1,7 @@
.line {
display: block;
margin: calc(34rem / 16) 0;
height: calc(1rem / 16);
border: none;
background-color: var(--primary-heading);
}

View File

@ -0,0 +1,7 @@
import React from "react";
import styles from "./HorizontalLine.module.css";
export function HorizontalLine() {
return <hr className={styles.line} />;
}

View File

@ -1,6 +1,10 @@
import React, { ImgHTMLAttributes } from "react";
export function Image(props: ImgHTMLAttributes<HTMLImageElement>) {
if (props.src?.startsWith("http://") || props.src?.startsWith("https://")) {
return <img {...props} />;
}
const { src: relativeSrc = "" } = props;
let absoluteSrc = process.env.NEXT_PUBLIC_BASE_PATH ?? "/";

View File

@ -1,15 +1,16 @@
.card {
.card > a {
display: flex;
flex-direction: row;
box-sizing: border-box;
padding: calc(16rem / 16);
color: var(--purple-2);
font-size: 1rem;
color: inherit;
text-decoration: inherit;
}
.card aside {
max-width: calc(142rem / 16);
margin-right: calc(45rem / 16);
margin-right: 1rem;
display: flex;
justify-content: center;
align-items: center;
@ -29,6 +30,7 @@
margin: 0;
margin-top: calc(4rem / 16);
font-size: calc(18rem / 16);
color: var(--primary-heading);
}
.card section {

View File

@ -1,3 +1,4 @@
import Link from "next/link";
import React from "react";
import { Image } from "./Image";
@ -5,19 +6,36 @@ import { Image } from "./Image";
import styles from "./MiniTechTalkCard.module.css";
interface MiniTechTalkProps {
name: string;
short: string;
poster?: string;
slug: string;
title: string;
presentors: string[];
poster: string;
}
export function MiniTechTalkCard({ name, poster, short }: MiniTechTalkProps) {
export function MiniTechTalkCard({
slug,
title,
presentors,
poster,
}: MiniTechTalkProps) {
const presentorsStr = presentors.join(", ");
return (
<article className={styles.card}>
<aside>{poster && <Image alt={name} src={poster} />}</aside>
<Link href={`/resources/tech-talks/${slug}`}>
<a>
<aside>
<Image
alt={`Thumbnail of tech talk by ${presentorsStr}: ${title}`}
src={poster}
/>
</aside>
<div className={styles.content}>
<h1>{name}</h1>
<p>{short}</p>
<h1>{title}</h1>
<p>{presentorsStr}</p>
</div>
</a>
</Link>
</article>
);
}

View File

@ -62,6 +62,10 @@ const menu: Menu = [
name: "Services",
route: "/resources/services",
},
{
name: "Machine Usage",
route: "/resources/machine-usage-agreement",
},
{
name: "Tech Talks",
route: "/resources/tech-talks",
@ -70,6 +74,14 @@ const menu: Menu = [
name: "CS Club Wiki",
route: "https://wiki.csclub.uwaterloo.ca",
},
{
name: "Advice",
route: "/resources/advice/coop",
},
{
name: "Internships",
route: "https://github.com/uwcsc/winter2022-internships",
},
],
},
];

View File

@ -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;
}
@ -41,7 +49,7 @@
}
.selected {
background-color: var(--primary-accent-dim);
background-color: var(--primary-accent-lightest);
color: var(--primary-accent);
font-weight: 700;
}
@ -110,8 +118,113 @@
padding-left: calc(8rem / 16);
}
@media only screen and (max-width: calc(768rem / 16)) {
.nav {
.link,
.link:visited {
color: inherit;
text-decoration: none;
}
.burger {
display: none;
}
.mobileNavTitle {
display: none;
}
@media only screen and (max-width: calc(768rem / 16)) {
.burger {
display: flex;
position: fixed;
border: none;
bottom: calc(32rem / 16);
left: calc(16rem / 16);
width: calc(62rem / 16);
height: calc(57rem / 16);
cursor: pointer;
z-index: 9;
background: var(--primary-accent-light);
border-radius: calc(5rem / 16);
transition: transform 0.3s ease-in-out;
transform: translateY(calc(94rem / 16));
padding: calc(11rem / 16) calc(9rem / 16);
}
.burgerVisible {
transform: translateY(0);
}
.burger > svg {
width: 100%;
height: 100%;
stroke: var(--primary-accent);
}
.navItem {
width: auto;
padding: 0 calc(16rem / 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 {
position: fixed;
top: 0;
left: 0;
overflow-y: auto;
z-index: 30;
margin: 0;
background: var(--primary-accent-lighter);
width: calc(288rem / 16);
transform: translateX(-100vw);
transition: 0.5s;
}
.navMobileBackground {
position: fixed;
visibility: hidden;
width: 100%;
height: 100%;
top: 0;
left: 0;
z-index: 20;
background-color: var(--navbar-page-overlay);
opacity: 0;
transition: 0.5s;
}
.mobileNavOpen {
transform: translateX(0);
}
.mobileNavTitle {
display: flex;
font-size: calc(24rem / 16);
font-weight: 700;
margin: calc(14rem / 16);
margin-top: calc(39rem / 16);
}
.show.navMobileBackground {
visibility: visible;
opacity: 100%;
}
}

View File

@ -1,19 +1,20 @@
import React, { ReactNode, ComponentType } from "react";
import NextLink from "next/link";
import React, {
ReactNode,
ComponentType,
useState,
useRef,
useEffect,
useCallback,
} 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,41 +22,83 @@ export const READ_ALL_ID = "read-all";
interface Props {
sections: Section[];
currentId: string;
id: string;
children: ReactNode;
pageTitle: string;
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,
pageTitle,
link: Link,
}: Props) {
const [mobileNavOpen, setMobileNavOpen] = useState(false);
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];
const isReadAll = section.id === READ_ALL_ID;
const ref = useRef<HTMLDivElement>(null);
const isVisible = useOnScreen(ref.current);
const burgerVisible = useBurger(isVisible);
useEffect(() => {
mobileNavOpen
? (document.body.style.overflow = "hidden")
: (document.body.style.overflow = "visible");
}, [mobileNavOpen]);
return (
<div className={styles.wrapper}>
<Nav sections={sections} currentIndex={currentIndex} link={props.link} />
<div className={styles.wrapper} ref={ref}>
<div
className={
mobileNavOpen
? `${styles.navMobileBackground} ${styles.show}`
: styles.navMobileBackground
}
onClick={() => setMobileNavOpen(false)}
/>
<Nav
sections={sections}
currentIndex={currentIndex}
link={Link}
pageTitle={pageTitle}
mobileNavOpen={mobileNavOpen}
setMobileNavOpen={setMobileNavOpen}
/>
<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}
/>
</>
)}
</div>
<button
className={`${styles.burger} ${
burgerVisible ? styles.burgerVisible : ""
}`}
onClick={() => setMobileNavOpen(!mobileNavOpen)}
>
<Burger />
</button>
</div>
);
}
@ -64,11 +107,29 @@ interface NavProps {
sections: Section[];
currentIndex: number;
link: Link;
pageTitle: string;
mobileNavOpen: boolean;
setMobileNavOpen: (mobileNavOpen: boolean) => void;
}
function Nav({ sections, currentIndex, link: Link }: NavProps) {
function Nav({
sections,
currentIndex,
link: Link,
pageTitle,
mobileNavOpen,
setMobileNavOpen,
}: NavProps) {
const navStyles = mobileNavOpen
? [styles.nav, styles.mobileNavOpen]
: [styles.nav];
return (
<div className={styles.nav}>
<nav
className={navStyles.join(" ")}
onClick={(event) => event.stopPropagation()}
>
<h1 className={styles.mobileNavTitle}>{pageTitle}</h1>
{sections.map((section, index) => {
const classNames = [styles.navItem];
@ -81,17 +142,20 @@ function Nav({ sections, currentIndex, link: Link }: NavProps) {
}
return (
<Link
className={classNames.join(" ")}
id={section.id}
<div
onClick={() => {
setMobileNavOpen(false);
}}
key={section.id}
>
<Link className={classNames.join(" ")} id={section.id}>
<span className={styles.marker} />
<div>{section.title}</div>
</Link>
</div>
);
})}
</div>
</nav>
);
}
@ -136,26 +200,82 @@ function Footer({ sections, currentIndex, link: Link }: FooterProps) {
);
}
function createSections(sections: Section[]) {
return [
{
function useDebounce(func: () => void, delay = 300) {
const timerRef = useRef<number | undefined>(undefined);
return useCallback(() => {
if (timerRef.current != null) {
return;
}
timerRef.current = window.setTimeout(() => {
func();
timerRef.current = undefined;
}, delay);
}, [func, delay]);
}
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,
Content() {
};
return content
? {
section: readAllSection,
Content: function ReadAllContent() {
return (
<>
{sections.map(({ id, title, Content: SectionContent }) => (
<div key={id}>
{(sections as SectionWithContent[]).map(
({ section: { id, title }, Content }) => (
<section key={id}>
<h1>{title}</h1>
<SectionContent />
</div>
))}
<Content />
</section>
)
)}
</>
);
},
},
...sections,
];
}
: 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" }) {
@ -173,3 +293,91 @@ function Arrow({ direction }: { direction: "left" | "right" }) {
</svg>
);
}
function useOnScreen(element: HTMLDivElement | null) {
const [isIntersecting, setIntersecting] = useState(false);
useEffect(() => {
const observer = new IntersectionObserver(([entry]) =>
setIntersecting(entry.isIntersecting)
);
if (element) {
observer.observe(element);
}
// Remove the observer as soon as the component is unmounted
return () => {
observer.disconnect();
};
}, [element]);
return isIntersecting;
}
function useBurger(componentIsVisible: boolean): boolean {
const [prevScrollPos, setPrevScrollPos] = useState(0);
const [burgerVisible, setBurgerVisible] = useState(true);
const handleScroll = useDebounce(() => {
// find current scroll position
const currentScrollPos = window.pageYOffset;
setBurgerVisible(
componentIsVisible &&
((prevScrollPos > currentScrollPos &&
prevScrollPos - currentScrollPos > 70) ||
currentScrollPos < 10)
);
// set state to new scroll position
setPrevScrollPos(currentScrollPos);
});
useEffect(() => {
window.addEventListener("scroll", handleScroll);
return () => window.removeEventListener("scroll", handleScroll);
}, [handleScroll]);
return burgerVisible;
}
// Inlining this svg because we want to fill in colors using css variables
function Burger() {
return (
<svg
width="30"
height="23"
viewBox="0 0 30 23"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<line
x1="28"
y1="2"
x2="2"
y2="2"
strokeWidth="4"
strokeLinecap="round"
strokeLinejoin="round"
/>
<line
x1="28"
y1="11.375"
x2="2"
y2="11.375"
strokeWidth="4"
strokeLinecap="round"
strokeLinejoin="round"
/>
<line
x1="28"
y1="20.75"
x2="2"
y2="20.75"
strokeWidth="4"
strokeLinecap="round"
strokeLinejoin="round"
/>
</svg>
);
}

View File

@ -0,0 +1,50 @@
.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;
}
.imageRight {
flex-direction: row-reverse;
}
.imageRight .header {
text-align: left;
margin-left: 0;
}
@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);
}
.description {
display: none;
}
}

View File

@ -0,0 +1,38 @@
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;
description?: string;
imagePosition?: "left" | "right";
}
export function Header({
title,
image,
children,
description,
imagePosition,
}: Props) {
return (
<main className={styles.page}>
<header
className={`${styles.headerContainer} ${
imagePosition === "right" ? styles.imageRight : ""
}`}
>
<Image src={image} className={styles.headerImage} />
<div>
<h1 className={styles.header}>{title}</h1>
{description && <p className={styles.description}>{description}</p>}
</div>
</header>
{children}
</main>
);
}

View File

@ -0,0 +1,84 @@
import { MDXRemote, MDXRemoteSerializeResult } from "next-mdx-remote";
import React, { ComponentType } from "react";
import {
createLink,
createReadAllSection,
LinkProps,
OrganizedContent,
} from "@/components/OrganizedContent";
import { GetShapesConfig } from "../ShapesBackground";
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;
getShapesConfig?: GetShapesConfig;
imagePosition?: "left" | "right";
link?: ComponentType<LinkProps>;
description?: string;
}
export function createReadAllPage({
title,
image,
pagePath,
getShapesConfig,
link,
description,
imagePosition,
}: Options) {
const Link = link ?? createLink(pagePath);
function Page({ sections }: Props) {
const readAllSection = createReadAllSection(
sections.map(({ section, content }) => ({
section,
Content() {
return <MDXRemote {...content} />;
},
})),
true
);
return (
<Header
title={title}
image={image}
description={description}
imagePosition={imagePosition}
>
<OrganizedContent
id={readAllSection.section.id}
sections={[
readAllSection.section,
...sections.map(({ section }) => section),
]}
pageTitle={title}
link={Link}
>
<readAllSection.Content />
</OrganizedContent>
</Header>
);
}
Page.getShapesConfig = getShapesConfig;
return Page;
}

View File

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

View File

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

View File

@ -0,0 +1,6 @@
.pre {
padding: calc(10rem / 16);
background: var(--code-background);
overflow-x: auto;
border-radius: calc(5rem / 16);
}

9
components/Pre.tsx Normal file
View File

@ -0,0 +1,9 @@
import React, { HTMLAttributes } from "react";
import styles from "./Pre.module.css";
export function Pre(props: HTMLAttributes<HTMLPreElement>) {
const classes = [styles.pre, props.className ?? ""];
return <pre {...props} className={classes.join(" ")} />;
}

View File

@ -0,0 +1,20 @@
.shapesContainer {
position: absolute;
overflow: hidden;
top: 0;
left: 0;
right: 0;
bottom: 0;
z-index: -10;
}
.shape {
--blue: invert(53%) sepia(80%) saturate(4689%) hue-rotate(189deg)
brightness(92%) contrast(93%);
--teal: invert(76%) sepia(39%) saturate(578%) hue-rotate(110deg)
brightness(91%) contrast(88%);
position: absolute;
filter: var(--blue);
opacity: 20%;
}

View File

@ -0,0 +1,308 @@
import { useWindowDimension } from "hooks/useWindowDimension";
import { useRouter } from "next/router";
import React, { CSSProperties, useEffect, useRef, useState } from "react";
import { Image } from "./Image";
import styles from "./ShapesBackground.module.css";
const MOBILE_WIDTH = 768;
interface Props {
getConfig?: GetShapesConfig;
}
export function ShapesBackground({ getConfig }: Props) {
const [config, setConfig] = useState<ShapesConfig>({});
const [prevWidth, setPrevWidth] = useState<number>(-1);
const [prevRoute, setPrevRoute] = useState<string>("");
const { width, height } = useWindowDimension();
const shapesContainerRef = useRef<HTMLDivElement>(null);
const router = useRouter();
useEffect(() => {
const containerWidth = shapesContainerRef.current?.offsetWidth;
const containerHeight = shapesContainerRef.current?.offsetHeight;
// In general, rerun getShapesConfig() if the screen size changes from desktop to mobile (or vice versa)
if (
containerWidth == null ||
containerHeight == null ||
!(
router.asPath === "/" ||
router.asPath !== prevRoute ||
prevWidth < 0 ||
(prevWidth <= MOBILE_WIDTH && MOBILE_WIDTH < width) ||
(prevWidth > MOBILE_WIDTH && MOBILE_WIDTH >= width)
)
) {
return;
}
setPrevWidth(width);
setPrevRoute(router.asPath);
setConfig(getConfig?.(containerWidth, containerHeight) ?? {});
}, [getConfig, width, height, prevWidth, prevRoute, router.asPath]);
return (
<div className={styles.shapesContainer} ref={shapesContainerRef}>
{Object.entries(config).map(([type, instances]) =>
instances.map((attributes, idx) => (
<Shape
key={idx.toString() + type}
type={type as ShapeType}
style={attributes}
/>
))
)}
</div>
);
}
function Shape(props: { type: ShapeType; style: CSSProperties }) {
return (
<Image
src={`/images/shapes/${props.type}.svg`}
className={styles.shape}
style={props.style}
/>
);
}
export type ShapeType =
| "asterisk"
| "circle"
| "cross"
| "dots"
| "hash"
| "plus"
| "ring"
| "triangle"
| "triangleBig"
| "waves"
| "wavesBig";
export type ShapesConfig = {
[key in ShapeType]?: CSSProperties[];
};
export type GetShapesConfig = (width: number, height: number) => ShapesConfig;
type ShapeSize = {
[key in ShapeType]: {
size: "big" | "small";
width: number;
height: number;
// 0 <= minAngle, maxAngle <= 180
minAngle?: number;
maxAngle?: number;
};
};
const shapeTypes: ShapeType[] = [
"asterisk",
"circle",
"cross",
"dots",
"hash",
"plus",
"ring",
"triangle",
"triangleBig",
"waves",
"wavesBig",
];
const shapesSizes: ShapeSize = {
asterisk: {
size: "big",
width: 168,
height: 168,
},
circle: {
size: "big",
width: 132,
height: 132,
},
cross: {
size: "big",
width: 150,
height: 150,
},
dots: {
size: "big",
width: 232,
height: 250,
},
hash: {
size: "small",
width: 60,
height: 60,
},
plus: {
size: "small",
width: 48,
height: 48,
},
ring: {
size: "small",
width: 70,
height: 70,
},
triangle: {
size: "small",
width: 68,
height: 68,
minAngle: 15,
maxAngle: 26,
},
triangleBig: {
size: "big",
width: 138,
height: 138,
minAngle: 15,
maxAngle: 26,
},
waves: {
size: "small",
width: 102,
height: 50,
},
wavesBig: {
size: "big",
width: 252,
height: 132,
},
};
const shapesBySize = {
big: shapeTypes.filter((shape) => shapesSizes[shape]["size"] == "big"),
small: shapeTypes.filter((shape) => shapesSizes[shape]["size"] == "small"),
};
// Used to generate random shapes in the margins
export const defaultGetShapesConfig = ((pageWidth, pageHeight) => {
if (window.innerWidth <= MOBILE_WIDTH) {
return mobileShapesConfig;
}
const defaultConfig: ShapesConfig = {};
const gap = 20;
const minBoxWidth = 150;
const boxWidth = Math.max(minBoxWidth, (pageWidth - 800 - 2 * gap) / 2);
const boxHeight = 400;
const shapeGenerationProbability = 0.85;
for (let y = 0; y + boxHeight <= pageHeight; y += gap + boxHeight) {
for (let x = 0; x <= 1; ++x) {
if (Math.random() > shapeGenerationProbability) {
continue;
}
const size =
boxWidth > minBoxWidth && (y == 0 || y + 2 * boxHeight > pageHeight)
? "big"
: "small";
const shape: ShapeType = getRandomShape(size);
const verticalOffset = getVerticalOffset(boxHeight, shape);
const horizontalOffset = getHorizontalOffset(boxWidth - 2 * gap, shape);
const shapeWidth = shapesSizes[shape]["width"];
const shapeHeight = shapesSizes[shape]["height"];
const angle = getRandomAngle(shape);
const colour = getRandomColour();
const opacity = getRandomOpacity(colour);
defaultConfig[shape] ??= [];
defaultConfig[shape]?.push({
top: `${((y + verticalOffset) / 16).toFixed(5)}rem`,
left:
x == 0
? `${(((horizontalOffset + gap) / window.innerWidth) * 100).toFixed(
5
)}vw`
: "unset",
right:
x == 1
? `${(((horizontalOffset + gap) / window.innerWidth) * 100).toFixed(
5
)}vw`
: "unset",
width: `${(shapeWidth / 16).toFixed(5)}rem`,
height: `${(shapeHeight / 16).toFixed(5)}rem`,
transform: `rotate(${angle}deg)`,
filter: `var(--${colour})`,
opacity: `${opacity}%`,
});
}
}
return defaultConfig;
}) as GetShapesConfig;
function getRandomShape(size: "big" | "small"): ShapeType {
const idx = Math.floor(Math.random() * shapesBySize[size].length);
return shapesBySize[size][idx];
}
function getVerticalOffset(boxHeight: number, shape: ShapeType): number {
const padding = shapesSizes[shape]["height"];
return Math.floor(Math.random() * (boxHeight - padding));
}
function getHorizontalOffset(boxWidth: number, shape: ShapeType): number {
const padding = shapesSizes[shape]["width"];
return shapesSizes[shape]["size"] == "big"
? Math.floor(Math.random() * (boxWidth - padding / 2) - padding / 2)
: Math.floor(Math.random() * (boxWidth - padding));
}
function getRandomAngle(shape: ShapeType): number {
const minAngle = shapesSizes[shape]["minAngle"] ?? 0;
const maxAngle = shapesSizes[shape]["maxAngle"] ?? 0;
const direction = Math.random() < 0.5 ? 1 : -1;
return (
(minAngle + Math.floor(Math.random() * (maxAngle - minAngle + 1))) *
direction
);
}
function getRandomColour(): "blue" | "teal" {
return Math.random() < 0.7 ? "blue" : "teal";
}
function getRandomOpacity(colour: "blue" | "teal"): number {
if (colour === "blue") {
return Math.random() < 0.8 ? 20 : 25;
} else {
return Math.random() < 0.8 ? 25 : 30;
}
}
// Used for most mobile pages
export const mobileShapesConfig = {
dots: [
{
top: "calc(-6rem / 16)",
left: "calc(-95rem / 16)",
width: "calc(166rem / 16)",
height: "calc(150rem / 16)",
},
],
hash: [
{
top: "calc(88rem / 16)",
right: "15vw",
width: "calc(40rem / 16)",
height: "calc(40rem / 16)",
},
],
triangle: [
{
top: "calc(20rem / 16)",
right: "1vw",
width: "calc(45rem / 16)",
height: "calc(45rem / 16)",
transform: "rotate(17deg)",
},
],
};

View File

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

View File

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

View File

@ -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;
/* Popup */
max-width: calc(190rem / 16);
@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%;
}
}
.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,
.description {
line-height: 1.5;
}
.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;
}
}
} */

View File

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

View File

@ -24,11 +24,31 @@
font-style: normal;
margin-top: 0;
margin-bottom: 0;
color: var(--blue-2);
color: var(--primary-accent);
}
.content h2,
.content h3,
.content h4 {
font-size: calc(18rem / 16);
}
@media only screen and (max-width: calc(768rem / 16)) {
.card {
flex-direction: column;
}
.card aside {
margin: 0;
margin-bottom: 1rem;
flex: unset;
}
.card aside img {
margin: 0;
}
.content ul {
padding-left: 1rem;
}
}

View File

@ -1,26 +1,57 @@
import React, { ReactNode } from "react";
import { Image } from "./Image";
import { Link } from "./Link";
import styles from "./TechTalkCard.module.css";
interface DownloadLink {
file: string;
type: string;
size?: string;
}
interface TechTalkProps {
name: string;
poster?: string;
title: string;
presentors: string[];
poster: string;
links: DownloadLink[];
children: ReactNode;
}
export function TechTalkCard({ name, poster, children }: TechTalkProps) {
export function TechTalkCard({
title,
poster,
presentors,
links,
children,
}: TechTalkProps) {
return (
<article className={styles.card}>
<aside>
{poster && <Image alt={name} src={poster} />}
{!poster && <div className={styles.spacer}></div>}
<Image
alt={`Thumbnail of tech talk by ${presentors.join(", ")}: ${title}`}
src={poster}
/>
</aside>
<section className={styles.content}>
<h1>{name}</h1>
<h1>{title}</h1>
<div>{children}</div>
<h2>Download:</h2>
<ul>
{links.map((link) => (
<li key={link.file + link.type}>
<DownloadLink {...link} />
</li>
))}
</ul>
</section>
</article>
);
}
function DownloadLink({ file, type, size }: DownloadLink) {
const text = size ? `${type} (${size})` : type;
return <Link href={file}>{text}</Link>;
}

View File

@ -22,7 +22,8 @@ export const PALETTE_NAMES = [
"--primary-accent",
"--primary-accent-soft",
"--primary-accent-light",
"--primary-accent-dim",
"--primary-accent-lighter",
"--primary-accent-lightest",
"--secondary-accent",
"--secondary-accent-light",
@ -38,6 +39,8 @@ export const PALETTE_NAMES = [
"--input-placeholder-text",
"--input-text",
"--code-background",
"--navbar-page-overlay",
] as const;

View File

@ -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,15 +232,31 @@ 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}
pageTitle="Playground"
>
<Content />
</OrganizedContent>
);
}
export function TechTalkDemo() {
const poster =
tempTechTalkMetadata.thumbnails.large ??
tempTechTalkMetadata.thumbnails.small;
return (
<div>
<TechTalkCard {...tempTechTalkMetadata}>
<TechTalkCard {...tempTechTalkMetadata} poster={poster}>
<TempTechTalk />
</TechTalkCard>
</div>
@ -235,15 +266,18 @@ export function TechTalkDemo() {
export function MiniTechTalkDemo() {
return (
<div className={styles.miniTechTalkDemo}>
<MiniTechTalkCard {...tempTechTalkMetadata}>
<TempTechTalk />
</MiniTechTalkCard>
<MiniTechTalkCard {...tempTechTalkMetadata}>
<TempTechTalk />
</MiniTechTalkCard>
<MiniTechTalkCard {...tempTechTalkMetadata}>
<TempTechTalk />
</MiniTechTalkCard>
<MiniTechTalkCard
{...tempTechTalkMetadata}
poster={tempTechTalkMetadata.thumbnails.small}
/>
<MiniTechTalkCard
{...tempTechTalkMetadata}
poster={tempTechTalkMetadata.thumbnails.small}
/>
<MiniTechTalkCard
{...tempTechTalkMetadata}
poster={tempTechTalkMetadata.thumbnails.small}
/>
</div>
);
}

View File

@ -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](/about/constitution).

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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](/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](/about#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.

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -0,0 +1,8 @@
---
title: 12. Code of Conduct
index: 12
---
1. The Club has a [Code of Conduct](/about/code-of-conduct).
2. The [scope of the Code of Conduct](/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.

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -0,0 +1,10 @@
---
title: 3. Membership
index: 3
---
1. In compliance with MathSoc regulations and in recognition of the club being primarily targeted at undergraduate students, full membership is open to all Social Members of the Mathematics Society and restricted to the same.
2. Affiliate membership in this Club shall be open to all members of the University community, including alumni. Affiliate members shall have all the rights of full members except for the rights of voting and holding executive office.
3. Membership shall be accounted for on a termly basis, where a term begins at the start of lectures in Winter or Spring, and at the start of Orientation Week in Fall.
4. A person is not a member until he or she has paid the current membership fee and has been enrolled in the member database. The termly membership fee is set from time to time by the Executive. Under conditions approved by the Executive, a member who purchases a membership at the end of the current term may be given membership for both the current term and the next term. If the membership fee changes, then this does not affect the validity of any membership terms already paid for.
5. The Club may grant access to its systems, either free of charge or for a fee, to members of the University community in order to offer them services. This does not constitute membership.

View File

@ -0,0 +1,6 @@
---
title: 1. Name
index: 1
---
The name of this organization shall be the "Computer Science Club of the University of Waterloo".

View File

@ -0,0 +1,30 @@
---
title: 4. Officers
index: 4
---
1. The officers of the Club shall be:
a. President
a. Vice-President
a. Secretary
a. Treasurer
a. System Administrator
1. There shall additionally be a Faculty Advisor, selected by the Executive from time to time from among the faculty of the School of Computer Science. The Faculty Advisor shall be an ex-officio affiliate member of the Club.
1. The choice of officers shall be limited to full members of the Club.
1. All officers, other than the System Administrator, shall be elected at a meeting to be held no later than two weeks after the start of lectures in each term.
1. The election of officers shall be accomplished by the following procedure:
a. Before the end of the prior term, the then-Executive shall choose a willing Chief Returning Officer, who is responsible for carrying out elections according to this procedure.
a. The CRO shall set the date and time of the election meeting, and set the nomination period. The nomination shall be at least one week long and shall end at least 24 hours before the start of the election meeting.
a. Announcements of the election and the nomination procedure must be distributed to all members by the members' mailing list, and should also be advertised by posters in the MC building.
a. During the nomination period, the Chief Returning Officer (CRO) shall be available to receive nominations for the posts of officers of the club, either in person, by email, by depositing nomination forms in the CSC's mailbox in the MathSoc office, or by writing the nomination in a place in the CSC office to be specified by the CRO.
a. A nomination shall consist of the nominee's userid, and post(s) nominated for. Nominees must be full members of the Computer Science Club. A member may decline a nomination at any point prior to the taking of the vote.
a. The election shall commence with the offering of memberships for sale. After a reasonable time, control of the meeting is given to the CRO who will preside over the election of the President, Vice-President, Treasurer, and Secretary, in that order.
a. During each election, if the position has no nominees, the CRO will take nominations from the floor. Any present, eligible member can be nominated.
a. Each election shall be carried out by secret vote, in a manner to be decided on by the CRO, with the approval of the members at the meeting. A simple heads-down-hands-up method is considered acceptable.
a. The CRO shall not vote except to break a tie.
a. The CRO may, if feasible, accept absentee ballots from full members. No absentee vote from a member shall be counted if the member is present at the time the vote is taken. The CRO shall make a best effort to ensure that absentee ballots are compatible with the method of voting chosen; if this is not possible (for instance, if the CRO is overruled by the membership), then the absentee votes shall not be counted.
a. Immediately after the vote is taken, the CRO will announce the results of the election and the winner will be removed from subsequent contests. If, due to lack of candidates (because there were no nominations, or candidates withdrew or were eliminated), there is no one elected to an office, then the members at the meeting will decide whether or not to hold extra elections in accordance with the procedure for vacancies. If they choose not to, this does not prevent the Executive or a group of members from calling extra elections later in the term in accordance with the usual vacancy provisions.
1. Following the elections, it is the responsibility of the new executive to select a System Administrator. The selection of System Administrator must then be ratified by the members at the meeting. If a suitable System Administrator is not available, then the executive may delay their selection until one becomes available. In this case the selection of System Administrator must be ratified at the next meeting of the Club.
1. Any two offices may be held by a single person with the approval of the President (if any), and the explicit approval of the members.
1. In the case of a resignation of an officer or officers, including the President, or if a vacancy occurs for any other reason, the Executive, members at a meeting, or any ten (10) members may call extra elections to replace such officer(s). If extra elections are held, they are held for all vacant offices.
1. Whenever extra elections are held, they shall follow the usual election procedure. If they are held after elections failed to elect an officer, then the nomination period may be shortened to less than a week in order to allow the extra elections to take place at the same date and time in the following week. The Executive (or the ten (10) members who called the election) may appoint a replacement CRO if the previous CRO is unwilling or unable to fulfill their duties.

View File

@ -0,0 +1,10 @@
---
title: 2. Purpose
index: 2
---
1. The Club is organized and will be operated exclusively for educational and scientific purposes in furtherance of:
a. promoting an increased knowledge of computer science and its applications;
a. providing a means of communication between persons having interest in computer science.
a. promoting a greater interest in computer science and its applications; and
1. The above purposes will be fulfilled by the organization of discussions and lectures with professionals and academics in the field of computer science and related fields, the maintenance of a library of materials related to computer science, the maintenance of an office containing the library as an aid to aim (1.c) above, and such other means as decided by the club membership.

View File

@ -0,0 +1,6 @@
---
title: Revision
index: 14
---
The constitution was last revised on 25 January 2018.

View File

@ -0,0 +1,10 @@
---
title: 13. Use of Club Resources
index: 13
---
1. All resources under control of the Club are to be used in accordance with the aims of the Club.
2. The President and Vice-President are jointly responsible for the proper use of all Club resources, except as otherwise specified by the Executive or this Constitution.
3. The Systems Administrator is responsible for the proper use of all administrative access to Club computing resources.
4. The Executive, via the Systems Administrator and the Systems Committee, are responsible for the proper use of all Club computing resources.
5. Permission to use a resource is automatically granted to someone responsible for that resource, and optionally as determined by those responsible for a resource. Granting permission to someone to use a resource does not make that person responsible for the proper use of the resource, although the user is, of course, responsible to the person granting permission.

View File

@ -1,4 +1,4 @@
import Bubble from "@/components/Bubble";
import { Bubble } from "@/components/Bubble";
<Bubble>
@ -85,5 +85,3 @@ Our office phone number is [(519) 888-4567 x33870](tel:+15198884567,33870)
</address>
</Bubble>

View File

@ -0,0 +1,16 @@
## Academic Advice
Find a nice group of people that you study well with and meet every once in a while to work on things together,
you can do that generally by asking around via messaging platforms/office hours. To avoid plagiarism, avoid discussing
intricate details of the solution but rather bounce ideas off one another, and leave yourself 30 minutes after the meeting
before you write up a solution
Try to complete your assignments without consulting your notes. It will be very challenging to do if you are not very confident
in the content and is a good indicator that you need to understand the content better! Try to review it again and do the
assignment without referring back to it.
Try to manage your pace when it comes to work. Its really easy to burn out and lose motivation in the middle to end of the term,
when you need it the most. Give yourself a breather and take breaks!
Assignments can be pretty endless, so make sure you celebrate your small wins. Modularize your tasks and reflect on all the
work youve done over a period of time. Its often much more than you think.

View File

@ -0,0 +1,98 @@
## Coop Advice
Although WaterlooWorks is quite reliable, there are many more opportunities outside of the job board.
Being able to apply for jobs externally not only prepares you to look for jobs full time but it also
provides a way to start your study term without having to worry about looking for a co-op.
Create rituals for starting your day and ending your day. Studies have shown that not having a post work activity
makes it harder to not think about work which leads to burn out and reduced productivity. Start your day by thinking
about what you want to achieve and how you want to feel. End your day by doing an activity i.e exercising, listing
todos for tomorrow, or even reflecting about the work day! This may help you have a more balanced lifestyle.
To make the best use of your time, set a time limit on how long you spend on the problem (e.g. 1 hour before
you ask for help). Asking for help on an issue youve been stuck on for some time can be beneficial. Its much
better to take an hour of your mentor/boss time than to be stuck for days without any results. The solution
may be team/organization specific and asking can save a lot of time. Be sure to try your best to solve the
problem on your own first to maximize your ability to learn.
If you have spent time diving into the codebase but you still are confused, schedule time with your mentor/coworkers
to have a code base walk through. Write up questions to ask during the meeting and take notes of unclear parts of the code.
Check over your code at least twice before submitting your code review. Reviewing the code a second time may
help you catch minor issues and/or problematic code that your reviewers may or may not comment on. If you are
unable to figure out a solution to an issue, then reach out to someone for help rather than implementing a
hacky solution. You will be more aware of your coding quality, less prone to ignoring issues, and overall
be a more responsible developer.
Asking for feedback from your manager/mentor throughout the term can go a long way. You can ask about your
performance in certain areas and ways you can improve. These feedbacks can help determine what you should continue
and/or change. For example, you can ask about their expectations and how you can achieve a specific rating on
the employer co-op rating to set up specific goals.
Around the middle of the term, ask to go over your co-op evaluation form with your manager. In doing so, you will
be able to modify your current goals to match/exceed your managers expectations. This is especially helpful for
you to determine how you can achieve the co-op rating you want.
Meeting and networking with people in and outside your team is an amazing way to learn and meet new people.
Coffee chats are a great way to learn about interesting roles and tasks others around the company perform.
Try to set up coffee chats with others at your company as you might meet an amazing connection or learn about
a really neat topic. This may lead to an idea of what you want to do in your future co-ops. A format you can
use is: “Hey, I'm the new intern of \<manager\> and I was wondering if I could put something on your calendar
so I can get to know you and your work a little better.”
Aim to make most/all of your code testable. This will ensure the code is functioning properly and will save
time debugging in the future. This is a useful skill to have as a developer.
Each push request (PR) should focus on a very specific change/feature. Modularizing the changes will make
reviewing the PR easier and quicker.
Set up a system to stay on top of your work. This can be as simple as setting up a to-do list ready for the day.
The important thing is to be clear and intentional with your goals each day so you can optimize your focus on getting things done.
Document any blockers you faced during onboarding, and how you overcame them because chances are others will face them too.
These can be tips/advice you would give new hires. Feel free to share these findings with your team, because they want to make
the onboarding process more efficient and up to date for future hires. Some examples of things to take note of are
outdated/incorrect/missing documentation and the way the team does a specific task.
Negotiating compensation for an offer when you already have competing offers can be very beneficial for you and its normal
to do. For a general guide, you can use the format:
-------------------------------------------------------------------------------------------------------------------------------
Hello [Name of recruiter],
I am very interested in working \[company name\]. I have been given an opportunity at \[another company name\] that is offering \[compensation\].
Would it be possible for [the company name] to match/increase the compensation.
Thank you,
[Name]
-------------------------------------------------------------------------------------------------------------------------------
If you do not have competing offers you can still try to negotiate using the format:
-------------------------------------------------------------------------------------------------------------------------------
Hello \[Name of recruiter\],
Given my experiences, would it be possible to increase the compensation to [compensation]?
Thank you,
[Name]
-------------------------------------------------------------------------------------------------------------------------------
Either way, it does not hurt to try as the worst they can say is no.

View File

@ -0,0 +1,42 @@
## Social Advice
If youre looking to watch movies with friends then you can either buy cheaper (Tuesday prices)
at the Student Life Center or Waterloo has a list of streaming sites where you can watch free movies.
Join different clubs or societies! Theyre a great way to make friends and manage your time better.
Plus, it makes going through a school term much more fun.
Take up the opportunities for meeting people. You never know who you might meet. If you dont put
yourself out there and take chances, its much harder to find a relationship, friendships, or even study buddies.
Be kind. Celebrate your friends successes when they get a co-op job and support them when theyre struggling
too. Waterloo is so competitive and sometimes it can be hard to navigate through, so make sure youre giving
and getting a good support network.
Additional Resources
Along with your tuition fees, part of your library fees grant you access to a database of [free movies](https://media3-criterionpic-com.proxy.lib.uwaterloo.ca/htbin/wwform/006/wwk770?&kw=zkcode%7C000005%7C)
SE servers:
[discord.gg/ZtmRPc59](https://discord.gg/ZtmRPc59)
[discord.gg/XyQtsfe5](https://discord.gg/XyQtsfe5)
Group Leetcode server:
[discord.gg/kwCsCNb3](https://discord.gg/kwCsCNb3)
There are many online resources for interview preparation including https://evykassirer.github.io/playing-the-internship-game/ and https://github.com/viraptor/reverse-interview
If you have issues regarding courses, there are MathSoc class representatives who can help voice your concerns to involved faculty members.
Access to eBooks: https://subjectguides.uwaterloo.ca/compsci/books
More specifically O'Reilly Higher education: https://learning-oreilly-com.proxy.lib.uwaterloo.ca/home
There are a lot of helpful books/videos that can teach you a variety of things from finance to leadership to a variety of cs topics! (With recommendations, case studies and playlist to help you get started)
We have GPUs: https://uwaterloo.ca/math-faculty-computing-facility/services/service-catalogue-teaching-linux/access-teaching-gpu-cluster
List of math faculty services: https://uwaterloo.ca/math-faculty-computing-facility/services
Internship/Interview advice
https://www.techintern.io/

View File

@ -14,10 +14,10 @@ a bunch of ways you can join and help out.
1. Drop by our office in **MC 3036/3037** with
- your WatCard, and
- $2 for term that you would like to pay for
2. Sign our [Machine Usage Agreement](https://csclub.uwaterloo.ca/services/machine_usage)
2. Sign our [Machine Usage Agreement](/resources/machine-usage-agreement)
That's all! After your account created, you'll have access to all the
[services](https://csclub.uwaterloo.ca/services/) available to members.
[services](/resources/services) available to members.
#### Membership Renewal
@ -36,7 +36,7 @@ University of Waterloo email address with the following:
1. a scan or photograph copy of your **WatCard**,
2. your **WatIAM userid**, and
3. your acknowledgement of having read, understood, and agreeing with our 
[Machine Usage Agreement](https://csclub.uwaterloo.ca/services/machine_usage).
[Machine Usage Agreement](/resources/machine-usage-agreement).
#### Membership Renewal
@ -82,4 +82,4 @@ Each term the CSC holds elections to determine the executive council.
To find out when and where the next elections will be held, keep an eye on on the [News](/).
For details on the elections, see the [Constitution](https://csclub.uwaterloo.ca/about/constitution).
For details on the elections, see the [Constitution](/about/constitution).

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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"
}
]

View File

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

View File

@ -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"
}
]

View File

@ -0,0 +1,6 @@
---
author: 'sjdutoit'
date: 'Mon Sep 16 2002 01:00:00 GMT-0400 (Eastern Daylight Time)'
---
The Fall elections have occured and the [results](</about/exec>) are in.

View File

@ -1,6 +0,0 @@
---
author: "sjdutoit"
date: "2002-09-16"
---
The Fall elections have occured and the [results](</about/exec>) are in.

View File

@ -1,6 +1,6 @@
---
author: "sjdutoit"
date: "2002-09-18"
author: 'sjdutoit'
date: 'Wed Sep 18 2002 01:00:00 GMT-0400 (Eastern Daylight Time)'
---
We've changed to the new site! Please send your comments to the [webmaster](<mailto:webmaster@csclub.uwaterloo.ca>). The [old site](</old/>) is still available. A few things may not be working quite right yet, but I'm working on it.

View File

@ -1,6 +1,6 @@
---
author: "sjdutoit"
date: "2002-09-30"
author: 'sjdutoit'
date: 'Mon Sep 30 2002 01:00:00 GMT-0400 (Eastern Daylight Time)'
---
The business meeting of 2002-09-30 was concluded and the [constitutional change](</about/constitution-change-20020920>) was approved with a 14:2 majority (and one spoiled ballot). See the new [constitution](</about/constitution>).

View File

@ -1,6 +1,6 @@
---
author: "sjdutoit"
date: "2002-10-29"
author: 'sjdutoit'
date: 'Tue Oct 29 2002 00:00:00 GMT-0500 (Eastern Standard Time)'
---
Due to lack of time for preparation, the Romp Through The Linux Kernel talks were cancelled. Sorry for the inconvenience. Hopefully these talks will happen next term.

View File

@ -0,0 +1,6 @@
---
author: 'sjdutoit'
date: 'Sun Feb 03 2002 00:00:00 GMT-0500 (Eastern Standard Time)'
---
XML goodness.

View File

@ -1,6 +0,0 @@
---
author: "sjdutoit"
date: "2002-02-03"
---
XML goodness.

View File

@ -0,0 +1,6 @@
---
author: 'sjdutoit'
date: 'Mon Feb 04 2002 00:00:00 GMT-0500 (Eastern Standard Time)'
---
About/Memberlist stub up. Made the CSC logo gold. Isn't it nifty?

View File

@ -1,6 +0,0 @@
---
author: "sjdutoit"
date: "2002-02-04"
---
About/Memberlist stub up. Made the CSC logo gold. Isn't it nifty?

View File

@ -1,6 +1,6 @@
---
author: "sjdutoit"
date: "2002-04-15"
author: 'sjdutoit'
date: 'Mon Apr 15 2002 01:00:00 GMT-0400 (Eastern Daylight Time)'
---
Added the [membership list](</about/members>). [Old events](</events/old>) are working. Event terms, as well as the current term are determined automagically now. Lots of work done. Some more stubs up (office etc.). And I introduce cow - that is, the CSC Ontological Webalizer - which is just a wrapper around libxslt with some extra xpath functions. It is now what is being used to build the site, instead of xsltproc.

View File

@ -1,6 +1,6 @@
---
author: "sjdutoit"
date: "2002-04-22"
author: 'sjdutoit'
date: 'Mon Apr 22 2002 01:00:00 GMT-0400 (Eastern Daylight Time)'
---
Added [books](<http://library.csclub.uwaterloo.ca/>)! About 2.5 shelves are there, minus a whole lot that weren't readily accessible from the Library of Congress. Getting all of the books on there is going to be a tough job. These are, by the way, managed by good-old (or new?) CEO. Thanks to Ryan Golbeck and Petio for their hard work getting ISBN numbers onto disc.

View File

@ -0,0 +1,6 @@
---
author: 'sfllaw'
date: 'Wed Sep 17 2003 01:00:00 GMT-0400 (Eastern Daylight Time)'
---
The CSC elections took place and we have a new [executive](</about/exec>) for Fall 2003.

View File

@ -1,6 +0,0 @@
---
author: "sfllaw"
date: "2003-09-17"
---
The CSC elections took place and we have a new [executive](</about/exec>) for Fall 2003.

View File

@ -0,0 +1,6 @@
---
author: 'sjdutoit'
date: 'Wed May 14 2003 01:00:00 GMT-0400 (Eastern Daylight Time)'
---
The CSC elections took place and we have a new [executive](</about/exec>) for Spring 2003.

View File

@ -1,6 +0,0 @@
---
author: "sjdutoit"
date: "2003-05-14"
---
The CSC elections took place and we have a new [executive](</about/exec>) for Spring 2003.

View File

@ -1,6 +1,6 @@
---
author: "sfllaw"
date: "2003-06-05"
author: 'sfllaw'
date: 'Thu Jun 05 2003 01:00:00 GMT-0400 (Eastern Daylight Time)'
---
We have a new computer called `glucose-fructose`, or `sugar` for short. As a result, `carbonated-water` is temporarily out of service, although it should return within a month.

View File

@ -0,0 +1,6 @@
---
author: 'sfllaw'
date: 'Thu Jul 03 2003 01:00:00 GMT-0400 (Eastern Daylight Time)'
---
We have been notified by the Guelph Computer Club that they are unable to host our group event. Sorry for the inconvenience.

View File

@ -1,6 +0,0 @@
---
author: "sfllaw"
date: "2003-07-03"
---
We have been notified by the Guelph Computer Club that they are unable to host our group event. Sorry for the inconvenience.

View File

@ -1,6 +1,6 @@
---
author: "ja2morri"
date: "2003-07-09"
author: 'ja2morri'
date: 'Wed Jul 09 2003 01:00:00 GMT-0400 (Eastern Daylight Time)'
---
Jim Elliott gave a great talk for the CSC yesterday and has put his slides online.

View File

@ -1,6 +1,6 @@
---
author: "ja2morri"
date: "2003-08-06"
author: 'ja2morri'
date: 'Wed Aug 06 2003 01:00:00 GMT-0400 (Eastern Daylight Time)'
---
We've finally gotten around to disabling accounts. If you find your account has been improperly disabled please email [the executive](<mailto:exec@csclub.uwaterloo.ca>). We are keeping a back up of the files and mail for each disabled account for a short period of time.

View File

@ -1,6 +1,6 @@
---
author: "ja2morri"
date: "2003-08-12"
author: 'ja2morri'
date: 'Tue Aug 12 2003 01:00:00 GMT-0400 (Eastern Daylight Time)'
---
The [CSC Procedures manual](<http://wiki.csclub.uwaterloo.ca/wiki/Exec_Manual>) has been added to the website. Thanks go to Shannon Mann for reminding us of this document.

View File

@ -0,0 +1,6 @@
---
author: 'sfllaw'
date: 'Mon Jan 13 2003 00:00:00 GMT-0500 (Eastern Standard Time)'
---
The CSC elections took place and we have a new [executive](</about/exec>) for Winter 2003.

View File

@ -1,6 +0,0 @@
---
author: "sfllaw"
date: "2003-01-13"
---
The CSC elections took place and we have a new [executive](</about/exec>) for Winter 2003.

Some files were not shown because too many files have changed in this diff Show More