Merge branch 'main' into feat/organized-content

This commit is contained in:
William Tran 2021-05-24 20:21:22 -04:00
commit 6099a0b337
55 changed files with 4737 additions and 111 deletions

2
.gitignore vendored
View File

@ -22,4 +22,4 @@
# debug
npm-debug.log*
yarn-debug.log*
yarn-error.log*
yarn-error.log*

View File

@ -2,7 +2,6 @@
"recommendations": [
"dbaeumer.vscode-eslint",
"humao.rest-client",
"silvenon.mdx",
"xyc.vscode-mdx-preview"
"silvenon.mdx"
]
}

View File

@ -38,4 +38,5 @@
"files.exclude": {
"node_modules": true
},
"editor.tabSize": 2
}

View File

@ -0,0 +1,47 @@
.card {
display: flex;
flex-direction: row;
max-width: calc(1000rem / 16);
box-sizing: border-box;
padding: calc(24rem / 16);
}
.card aside {
flex: 0 0 calc(144rem / 16);
margin-right: calc(24rem / 16);
}
.card aside img {
width: 100%;
margin-bottom: 1rem;
}
.spacer {
margin-top: calc(76rem / 16);
}
.registerButton {
width: 100%;
}
.content > h1 {
font-size: calc(24rem / 16);
font-weight: 700;
font-style: normal;
margin-top: 0;
margin-bottom: 0;
}
.content,
.content > h2 {
color: var(--purple-2);
font-weight: 400;
font-style: normal;
margin-top: 0;
margin-bottom: 0;
}
.content > h2 {
font-size: 1rem;
margin-bottom: calc(14rem / 16);
}

48
components/EventCard.tsx Normal file
View File

@ -0,0 +1,48 @@
import React, { ReactNode } from "react";
import styles from "./EventCard.module.css";
import { EventSetting } from "./EventSetting";
import { Image } from "./Image";
interface EventCardProps {
name: string;
short: string;
date: Date;
online: boolean;
location: string;
poster?: string;
registerLink?: string;
children: ReactNode;
}
export function EventCard({
name,
date,
online,
location,
poster,
registerLink,
children,
}: EventCardProps) {
return (
<article className={styles.card}>
<aside>
{poster && <Image alt={name} src={poster} />}
{!poster && <div className={styles.spacer}></div>}
{/* TODO: use the <Button /> component */}
{registerLink && (
<button className={styles.registerButton}>
<a href={registerLink}>Register</a>
</button>
)}
</aside>
<section className={styles.content}>
<h1>{name}</h1>
<h2>
<EventSetting date={date} online={online} location={location} />
</h2>
<div>{children}</div>
</section>
</article>
);
}

View File

@ -0,0 +1,63 @@
.card {
display: flex;
box-sizing: border-box;
max-width: calc(540rem / 16);
padding: calc(24rem / 16);
border-radius: calc(4rem / 16);
background-color: white;
}
.poster {
width: calc(150rem / 16);
height: calc(150rem / 16);
margin-right: calc(20rem / 16);
}
.details {
position: relative;
width: 100%;
}
.name {
color: var(--purple-2);
font-weight: bolder;
font-size: calc(18rem / 16);
line-height: calc(27rem / 16);
margin: 0;
}
.desc {
color: var(--purple-2);
margin-top: calc(12rem / 16);
}
.spacer {
height: calc(35rem / 16);
}
.button {
position: absolute;
bottom: 0;
left: 0;
}
.logo {
width: calc(30rem / 16);
position: absolute;
bottom: 0;
right: 0;
}
.setting {
margin: 0;
color: var(--blue-1);
font-weight: bolder;
font-size: calc(14rem / 16);
}
@media only screen and (max-width: calc(768rem / 16)) {
.card {
padding: 0;
background-color: #e1eefa;
}
}

View File

@ -0,0 +1,86 @@
import React, { ReactNode } from "react";
// import { Button } from "./Button";
import { Image } from "./Image";
import { EventSetting } from "./EventSetting";
import styles from "./EventDescriptionCard.module.css";
interface Props {
name: string;
online: boolean;
location: string;
date: Date;
poster?: string;
registerLink?: string;
children: ReactNode;
}
function getPlatformURL(platform: string) {
switch (platform) {
case "Twitch":
return "https://www.twitch.tv/uwcsclub";
case "Discord":
return "https://discord.gg/pHfYBCg";
case "Facebook":
return "https://www.facebook.com/uw.computerscienceclub";
case "Instagram":
return "https://www.instagram.com/uwcsclub/";
default:
return;
}
}
/**
* @remarks
* - Child elements will display as the event's description
* - Assuming date prop is in EST
* - poster is the event's image name, including file ending (.jpg/.png/etc)
* - If event is online, location will be the platform, with capital first letter and no trailing spaces
* - ie. location="Discord"
* @todo
* get Link component
*/
export function EventDescriptionCard({
location,
poster,
name,
date,
online,
registerLink,
children,
}: Props) {
const platformURL = getPlatformURL(location);
return (
<article className={styles.card}>
{poster && <Image className={styles.poster} src={poster} alt={name} />}
<div className={styles.details}>
<h1 className={styles.name}>{name}</h1>
<h2 className={styles.setting}>
<EventSetting date={date} online={online} location={location} />
</h2>
<div className={styles.desc}>{children}</div>
<div className={styles.spacer}></div>
<footer>
{registerLink && (
<div className={styles.button}>
<button>
<a href={registerLink}>Register</a>
</button>
</div>
)}
{online && platformURL && (
<a target="_blank" href={platformURL} rel="noreferrer">
<Image
className={styles.logo}
alt={location}
src={"logos/" + location + ".png"}
/>
</a>
)}
</footer>
</div>
</article>
);
}

View File

@ -0,0 +1,27 @@
import React from "react";
interface Props {
date: Date;
online: boolean;
location: string;
}
export function EventSetting(props: Props) {
const date = props.date.toLocaleDateString("en-US", {
day: "numeric",
month: "long",
year: "numeric",
});
const time = props.date.toLocaleTimeString("en-US", {
hour: "numeric",
minute: "numeric",
});
const location = props.online ? `Online - ${props.location}` : props.location;
return (
<div>
<time dateTime={props.date.toISOString()}>{`${date} | ${time}`}</time>
{` | ${location}`}
</div>
);
}

16
components/Image.tsx Normal file
View File

@ -0,0 +1,16 @@
import React, { ImgHTMLAttributes } from "react";
export function Image(props: ImgHTMLAttributes<HTMLImageElement>) {
const { src: relativeSrc = "" } = props;
let absoluteSrc = process.env.BASE_PATH ?? "/";
if (absoluteSrc.endsWith("/") && relativeSrc.startsWith("/")) {
absoluteSrc += relativeSrc.slice(1);
} else if (absoluteSrc.endsWith("/") || relativeSrc.startsWith("/")) {
absoluteSrc += relativeSrc;
} else {
absoluteSrc += "/" + relativeSrc;
}
return <img {...props} src={absoluteSrc} />;
}

View File

@ -1,24 +1,25 @@
.miniEventCard {
max-width: 936px;
max-width: calc(936rem / 16);
box-sizing: border-box;
position: relative;
color: var(--purple-2);
padding: 1.25rem;
font-size: 0.875rem;
padding: calc(20rem / 16);
/* FIXME: Check figma for updated size */
font-size: calc(14rem / 16);
}
.name {
display: flex;
font-size: 1.125rem;
font-size: calc(18rem / 16);
margin: 0;
}
.nameSpacer {
width: 140px;
width: calc(140rem / 16);
}
.info {
margin-top: 0;
margin-bottom: calc(12rem / 16);
}
.details {
@ -27,7 +28,7 @@
right: 0;
cursor: pointer;
color: var(--blue-2);
margin: 1.25rem;
margin: calc(20rem / 16);
}
.miniEventCard[open] .shortDescription {

View File

@ -1,13 +1,14 @@
import React, { ReactNode } from "react";
import { EventSetting } from "./EventSetting";
import styles from "./MiniEventCard.module.css";
interface Props {
name: string;
descriptionShort: string;
description: ReactNode;
short: string;
online: boolean;
location: string;
date: string;
time: string;
date: Date;
}
const dropDownIcon = (
@ -28,11 +29,11 @@ const dropDownIcon = (
export const MiniEventCard: React.FC<Props> = ({
name,
descriptionShort,
short,
description,
location,
date,
time,
online,
}) => {
return (
<details className={styles.miniEventCard}>
@ -42,10 +43,10 @@ export const MiniEventCard: React.FC<Props> = ({
<div>{name}</div>
<div className={styles.nameSpacer}></div>
</h2>
<p className={styles.info}>
{location} | {date} | {time}
</p>
<p className={styles.shortDescription}>{descriptionShort}</p>
<div className={styles.info}>
<EventSetting date={date} location={location} online={online} />
</div>
<p className={styles.shortDescription}>{short}</p>
</div>
<p className={styles.details}>View details {dropDownIcon}</p>

View File

@ -0,0 +1,151 @@
.navbar {
display: flex;
justify-content: center;
align-items: center;
background-color: var(--white);
}
.navContent {
display: flex;
flex-direction: row;
flex-wrap: none;
justify-content: space-between;
align-items: center;
width: stretch;
max-width: calc(1440rem / 16);
height: auto;
padding: calc(28rem / 16) calc(136rem / 16);
}
.logo {
display: flex;
justify-content: center;
align-items: center;
}
.logo:hover {
cursor: pointer;
}
.logo img {
width: calc(96rem / 16);
}
.navMenu {
display: inline-flex;
flex-direction: row;
flex-wrap: none;
justify-content: space-between;
align-items: baseline;
margin: 0;
padding: 0;
width: calc(512rem / 16);
}
.navMenu li {
list-style: none;
text-align: center;
}
.navMenu a {
color: var(--purple-2);
text-decoration: none;
}
.navMenu a.currentPage {
color: var(--blue-2);
}
.navMenu > li:hover > a {
color: var(--blue-2);
font-weight: 600;
}
/* Prevents the menu items from shifting when made bold on hover */
.navMenu > li > a::before {
display: block;
content: attr(title);
font-weight: 600;
height: 0;
overflow: hidden;
visibility: hidden;
}
.navMenu > li > a {
padding: 1rem;
}
.dropdownWrapper {
display: flex;
flex-direction: column;
justify-content: flex-start;
align-items: center;
}
.dropdown {
visibility: visible;
display: flex;
flex-direction: column;
justify-content: space-evenly;
align-items: center;
position: absolute;
margin: 0;
margin-top: calc(48rem / 16);
padding: 0;
border-radius: calc(8rem / 16);
background-color: var(--white);
box-shadow: 0 calc(8rem / 16) 1rem var(--blue-1-20);
font-size: calc(14rem / 16);
}
.dropdown > li {
width: 100%;
}
.dropdown > li > a {
padding: calc(8rem / 16);
width: 100%;
box-sizing: border-box;
}
.dropdown > li:hover > a,
.dropdown > li > a:focus {
background-color: var(--blue-1-20);
}
.dropdown > li:first-child > a {
padding-top: 1rem;
border-radius: calc(8rem / 16) calc(8rem / 16) 0 0;
}
.dropdown > li:last-child > a {
padding-bottom: 1rem;
border-radius: 0 0 calc(8rem / 16) calc(8rem / 16);
}
.navMenu > li .dropdown {
visibility: hidden;
}
.navMenu > li:hover .dropdown,
.navMenu > li:focus-within .dropdown {
visibility: visible;
}
/* On a smaller desktop screen, keep the same navbar layout but decrease the
* horizontal padding so it still fits
*/
@media screen and (max-width: calc(960rem / 16)) {
.navContent {
padding: calc(28rem / 16) calc(64rem / 16);
}
}

120
components/Navbar.tsx Normal file
View File

@ -0,0 +1,120 @@
import React from "react";
import Link from "next/link";
import { useRouter } from "next/router";
import { Image } from "./Image";
import styles from "./Navbar.module.css";
interface NavLink {
name: string;
route: string;
submenu?: {
name: string;
route: string;
}[];
}
const menu: NavLink[] = [
{
name: "Home",
route: "/",
},
{
name: "About",
route: "/about",
submenu: [
{
name: "About Us",
route: "/about",
},
{
name: "Meet the Team",
route: "/about/team",
},
{
name: "Constitution",
route: "/about/constitution",
},
{
name: "Code of Conduct",
route: "/about/code-of-conduct",
},
],
},
{
name: "Get Involved",
route: "/get-involved",
},
{
name: "Events",
route: "/events",
},
{
name: "Resources",
route: "/resources",
},
];
function NavItem(props: NavLink) {
const router = useRouter();
return (
<>
<Link href={props.route}>
<a
title={props.name}
className={
router.pathname === props.route ||
((props.submenu?.length ?? 0) > 0 &&
router.pathname.startsWith(props.route))
? styles.currentPage
: ""
}
onClick={() => {
if (document.activeElement instanceof HTMLElement) {
document.activeElement.blur();
}
}}
>
{props.name}
</a>
</Link>
{(props.submenu?.length ?? 0) > 0 ? (
<ul className={styles.dropdown}>
{props.submenu?.map((item) => {
return (
<li className={styles.dropdownWrapper} key={item.name}>
<NavItem name={item.name} route={item.route} />
</li>
);
})}
</ul>
) : null}
</>
);
}
export function Navbar() {
return (
<nav className={styles.navbar}>
<div className={styles.navContent}>
<Link href="/">
<a className={styles.logo}>
<Image src="/images/logo-icon.png" alt="CSC Logo" />
</a>
</Link>
<ul className={styles.navMenu}>
{menu.map((item) => {
return (
<li className={styles.dropdownWrapper} key={item.name}>
<NavItem
name={item.name}
route={item.route}
submenu={item.submenu}
/>
</li>
);
})}
</ul>
</div>
</nav>
);
}

View File

@ -0,0 +1,32 @@
.card {
padding: calc(27rem / 16) calc(39rem / 16);
max-width: calc(524rem / 16);
background-color: white;
}
.date {
color: var(--purple-2);
font-size: calc(18rem / 16);
font-weight: bold;
line-height: calc(27rem / 16);
}
.author {
color: var(--purple-1);
font-style: normal;
line-height: calc(21rem / 16);
font-size: calc(14rem / 16);
margin: calc(5rem / 16) 0 calc(7rem / 16) 0;
}
.content {
line-height: calc(21rem / 16);
color: var(--purple-2);
}
@media only screen and (max-width: calc(768rem / 16)) {
.card {
padding: 0;
background-color: transparent;
}
}

30
components/NewsCard.tsx Normal file
View File

@ -0,0 +1,30 @@
import React, { ReactNode } from "react";
import styles from "./NewsCard.module.css";
interface NewsCardProps {
date: Date;
author: string;
children: ReactNode;
}
export const NewsCard: React.FC<NewsCardProps> = ({
date,
author,
children,
}) => {
return (
<article className={styles.card}>
<h3>
<time className={styles.date} dateTime={date.toISOString()}>
{date.toLocaleDateString("en-US", {
year: "numeric",
month: "long",
day: "numeric",
})}
</time>
</h3>
<address className={styles.author}>{author}</address>
<div className={styles.content}>{children}</div>
</article>
);
};

View File

@ -0,0 +1,28 @@
.container {
max-width: calc(126rem / 16);
display: flex;
flex-direction: column;
margin: 0;
}
.img {
width: 100%;
border-radius: 50%;
margin: 0 auto;
}
.caption {
text-align: center;
margin-top: calc(24rem / 16);
}
.name {
font-weight: bold;
color: var(--blue-1);
}
.role {
font-weight: 600;
color: var(--purple-2);
line-height: 1.875;
}

29
components/TeamMember.tsx Normal file
View File

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

View File

@ -0,0 +1,112 @@
.card {
display: grid;
grid-template-columns: calc(126rem / 16) auto;
grid-template-areas:
"picture name"
"picture role"
"picture description";
column-gap: calc(32rem / 16);
row-gap: 0;
justify-items: start;
align-items: start;
max-width: calc(847rem / 16);
}
.picture {
grid-area: picture;
justify-self: center;
max-width: calc(126rem / 16);
max-height: calc(126rem / 16);
clip-path: circle(50%);
}
.image {
width: 100%;
}
.name {
grid-area: name;
margin: 0;
color: var(--blue-1);
font-size: calc(36rem / 16);
line-height: 1.1;
font-weight: 700;
}
.role {
grid-area: role;
margin: 0;
color: var(--purple-2);
font-size: calc(24rem / 16);
line-height: 1.7;
font-weight: 600;
}
.description {
grid-area: description;
margin: 0;
line-height: 1.875;
}
@media screen and (max-width: calc(768rem / 16)) {
.card {
grid-template-columns: calc(90rem / 16) auto;
column-gap: calc(22rem / 16);
max-width: calc(460rem / 16);
}
.picture {
max-width: calc(90rem / 16);
max-height: calc(90rem / 16);
}
.name,
.role,
.description {
line-height: 1.5;
}
}
/* 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);
}
.picture {
max-width: calc(70rem / 16);
max-height: calc(70rem / 16);
}
.name,
.role,
.description {
line-height: 1.5;
}
.role {
margin-bottom: calc(12rem / 16);
}
.description {
justify-self: top;
margin-top: calc(12rem / 16);
margin-left: calc(12rem / 16);
}
} */

View File

@ -0,0 +1,27 @@
import React from "react";
import { Image } from "./Image";
import styles from "./TeamMemberCard.module.css";
interface TeamMemberCardProps {
name: string;
role: string;
image?: string; // path to image of person, relative to public directory
children: React.ReactNode;
}
export function TeamMemberCard(props: TeamMemberCardProps) {
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}`}
/>
</div>
<h1 className={styles.name}>{props.name}</h1>
<h2 className={styles.role}>{props.role}</h2>
<div className={styles.description}>{props.children}</div>
</article>
);
}

View File

@ -1,3 +1,93 @@
.miniEventCardDemo > *:nth-child(odd) {
background: #E1EEFA;
}
background: #e1eefa;
}
.newsDemo {
padding: calc(50rem / 16);
background-color: var(--off-white);
display: inline-block;
}
.newsTitle {
font-style: normal;
font-weight: bold;
color: var(--purple-2);
font-size: calc(24rem / 16);
line-height: calc(36rem / 16);
margin-bottom: calc(14rem / 16);
}
.newsDesc {
font-style: normal;
font-weight: normal;
font-size: calc(14rem / 16);
line-height: calc(21rem / 16);
white-space: pre-line;
color: var(--purple-2);
vertical-align: baseline;
}
.news > hr {
border: none;
height: calc(1rem / 16);
background-color: var(--purple-2);
margin: 0 0 calc(13rem / 16) 0;
}
.eventDescriptionCardDemo {
padding: calc(50rem / 16) 0;
background-color: var(--off-white);
display: inline-block;
}
.eventDescriptionCardDemo > * {
margin: calc(12rem / 16) calc(50rem / 16);
}
.eventDescriptionCardDemo > *:first-child {
margin-top: 0;
}
.eventDescriptionCardDemo > *:last-child {
margin-bottom: 0;
}
.teamMemberDemo {
padding: calc(10rem / 16) calc(50rem / 16) calc(30rem / 16) calc(50rem / 16);
max-width: calc(847rem / 16);
}
.committee {
margin: 0;
color: var(--purple-2);
font-weight: 600;
font-size: calc(24rem / 16);
line-height: calc(36rem / 16);
}
.teamMemberDemo > hr {
border: none;
height: calc(1rem / 16);
background-color: var(--blue-2);
width: 100%;
margin-top: calc(24rem / 16);
margin-bottom: calc(46rem / 16);
}
.teamMembers {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(calc(100rem / 16), 1fr));
row-gap: calc(43rem / 16);
column-gap: calc(53rem / 16);
}
@media only screen and (max-width: calc(768rem / 16)) {
.newsDemo,
.eventDescriptionCardDemo {
background-color: #e1eefa;
}
.eventDescriptionCardDemo > * {
margin: calc(50rem / 16);
}
}

View File

@ -4,49 +4,125 @@ import styles from "./playground.module.css";
import AfterHoursContent, {
metadata as afterHoursMetadata,
} from "../content/playground/after-hours.event.mdx";
import OOTBReact, {
metadata as OOTBReactEventMetadata,
} from "../content/playground/ootb-react.event.mdx";
import AltTab, {
metadata as altTabEventMetadata,
} from "../content/playground/alt-tab.event.mdx";
import UnavailableContent, {
metadata as unavailableMetadata,
} from "../content/playground/unavailable.news.mdx";
import { metadata as dogeMetadata } from "../content/playground/doge.team-member.mdx";
import CodeyInfo, {
metadata as codeyMetadata,
} from "../content/playground/codey.team-member.mdx";
import { MiniEventCard } from "./MiniEventCard";
import { NewsCard } from "./NewsCard";
import { EventCard } from "./EventCard";
import { EventDescriptionCard } from "./EventDescriptionCard";
import { TeamMember } from "./TeamMember";
import { TeamMemberCard } from "./TeamMemberCard";
import { OrganizedContent, LinkProps } from "./OrganizedContent";
const events = [
{ Content: OOTBReact, metadata: OOTBReactEventMetadata },
{ Content: AfterHoursContent, metadata: afterHoursMetadata },
{ Content: AltTab, metadata: altTabEventMetadata },
];
export function MiniEventCardDemo() {
const { name, location, short, date } = afterHoursMetadata;
const dateString = date.toLocaleDateString("en-US", {
day: "numeric",
month: "long",
year: "numeric",
});
const timeString = date.toLocaleTimeString("en-US", {
hour: "numeric",
minute: "numeric",
});
return (
<div className={styles.miniEventCardDemo}>
<MiniEventCard
name={name}
date={dateString}
time={timeString}
descriptionShort={short}
location={location}
description={<AfterHoursContent />}
/>
<MiniEventCard
name={name}
date={dateString}
time={timeString}
descriptionShort={short}
location={location}
description={<AfterHoursContent />}
/>
<MiniEventCard
name={name}
date={dateString}
time={timeString}
descriptionShort={short}
location={location}
description={<AfterHoursContent />}
/>
{events.map(({ Content, metadata }) => (
<MiniEventCard
{...metadata}
description={<Content />}
key={metadata.name + metadata.date.toString()}
/>
))}
</div>
);
}
export function NewsCardDemo() {
return (
<div className={styles.newsDemo}>
<div className={styles.newsTitle}>News</div>
<div className={styles.newsDesc}>
Updates from our execs
<br />
<br />
</div>
<hr className={styles.newsHr} />
<NewsCard {...unavailableMetadata}>
<UnavailableContent />
</NewsCard>
</div>
);
}
export function EventDescriptionCardDemo() {
return (
<div className={styles.eventDescriptionCardDemo}>
{events.map(({ metadata }) => (
<EventDescriptionCard
{...metadata}
key={metadata.name + metadata.date.toString()}
>
{metadata.short}
</EventDescriptionCard>
))}
</div>
);
}
export function EventCardDemo() {
return (
<>
{events.map(({ Content, metadata }) => (
<EventCard
{...metadata}
key={metadata.name + metadata.date.toDateString()}
>
<Content />
</EventCard>
))}
</>
);
}
export function TeamMemberDemo() {
return (
<div className={styles.teamMemberDemo}>
<div className={styles.teamMemberHeader}>
<h1 className={styles.committee}>Programme Committee</h1>
</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} />
</div>
</div>
);
}
export function TeamMemberCardDemo() {
return (
<div className={styles.teamMemberCardDemo}>
<TeamMemberCard {...codeyMetadata}>
<CodeyInfo />
</TeamMemberCard>
</div>
);
}

View File

@ -2,7 +2,9 @@ export const metadata = {
name: "Afterhours: Personal Relationships",
short: "Learn how React works and make your own version!",
date: new Date("2021-03-02 2:00 PM"),
location: "Online - Twitch",
online: false,
location: "MC",
registerLink: "http://csclub.uwaterloo.ca/",
};
The past year has been tough for all of us, having to deal with the pandemic

View File

@ -0,0 +1,14 @@
export const metadata = {
name: "Alt-Tab",
short: "CSC is proud to present to you Alt-Tab!",
date: new Date("March 25, 2021 19:00:00"),
online: true,
location: "Twitch",
poster: "/images/playground/alt-tab.jpg",
};
CSC is proud to present to you Alt-Tab! Join us in a lightning tech talk series presented to you by our very own students. Alt-Tab consists of 10 to 15-minute talks about anything related to tech. Learn more about exciting topics that range from competitive programming to cryptography!
We will have four incredible presenters that are eager to share their insights with you. Stay tuned as we'll be introducing them and the topics that they will be discussing soon!.
Registration is not required to attend! We'll just be sending you an email reminder, as well as inviting you to our calendar even

View File

@ -0,0 +1,9 @@
export const metadata = {
name: "Codey",
role: "Mascot",
image: "/images/playground/codeyHi.png"
}
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,5 @@
export const metadata = {
name: "Woof Woof",
role: "Doge",
image: "/images/playground/doge.jpg"
}

View File

@ -0,0 +1,17 @@
export const metadata = {
name: "Out of the Box: React",
short: "Out of the Box is a series of code-along projects that explore what's under the hood of modern web frameworks.",
date: new Date("March 23, 2021 19:00:00"),
online: true,
location: "Twitch",
poster: "/images/playground/intro-ootb.jpg",
registerLink: "http://google.com/",
};
Modern web frameworks are a black-box. They're easy to use, but they have numerous minute details to master in order to apply them to truly scalable websites. Over the last few years, front-end frameworks have absorbed the responsibilities of the back-end, meaning it's become ever more important to dig their details out of the box.
Out of the Box is a series of code-along projects that explore what's under the hood of modern web frameworks. Nearly 5 million websites use React, including many of the internet's most popular websites. While its simple syntax attracts developers from all over, underneath lies a complex infrastructure of code to manage all elements from caching to hooks. Rishi will bring these ideas to light in our inaugural episode of Out of the Box. Come join him and code your own version of React!
Only basic web experience is needed. All JavaScript code will be written within a single HTML document for simplicity. Node.js will also be required to participate in the event!
Registration is not required to attend! We'll just be sending you an email reminder, as well as inviting you to our calendar event.

View File

@ -0,0 +1,14 @@
export const metadata = {
author: "merenber",
date: new Date("2021-03-19"),
}
Computer Science Club systems and services will be unavailable on Saturday, Mar. 20
due to a planned power outage in the Mathematics and Computer Building (MC) from 7am to 5pm.
The CSC will begin shutting down machines at 6am in preparation of the outage.
Please prepare for the outage by:
- Ensuring all running processes have their state saved (configuration, data, etc.)
- Any important files are backed up off-site from the CSC
- If you have any questions/concerns, please email the Systems Committee.

48
next-env.d.ts vendored
View File

@ -1,16 +1,50 @@
/// <reference types="next" />
/// <reference types="next/types/global" />
interface EventMetadata {
name: string;
short: string;
date: Date;
location: string;
}
declare module "*.event.mdx" {
import { ComponentType } from "react";
interface EventMetadata {
name: string;
short: string;
date: Date;
online: boolean;
location: string;
poster?: string;
registerLink?: string;
}
const ReactComponent: ComponentType;
export const metadata: EventMetadata;
export default ReactComponent;
}
declare module "*.news.mdx" {
import { ComponentType } from "react";
interface NewsMetadata {
author: string;
date: Date;
}
const ReactComponent: ComponentType;
export const metadata: NewsMetadata;
export default ReactComponent;
}
declare module "*.team-member.mdx" {
import { ComponentType } from "react";
interface TeamMemberMetadata {
name: string;
role: string;
image?: string;
}
const ReactComponent: ComponentType;
export const metadata: TeamMemberMetadata;
export default ReactComponent;
}

View File

@ -1,7 +1,9 @@
const withMDX = require('@next/mdx')({
extension: /\.mdx$/
})
const withMDX = require("@next/mdx")({
extension: /\.mdx$/,
});
module.exports = withMDX({
pageExtensions: ['ts', 'tsx', 'mdx']
})
pageExtensions: ["ts", "tsx", "mdx"],
trailingSlash: true,
basePath: process.env.BASE_PATH,
});

3495
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -33,6 +33,10 @@
"eslint-plugin-prettier": "^3.4.0",
"eslint-plugin-react": "^7.23.2",
"eslint-plugin-react-hooks": "^4.2.0",
"postcss": "^8.3.0",
"postcss-calc": "^8.0.0",
"postcss-flexbugs-fixes": "^5.0.2",
"postcss-preset-env": "^6.7.0",
"typescript": "^4.2.4"
}
}

View File

@ -1,18 +1,16 @@
* {
font-family: "Poppins", "sans-serif";
}
code, pre {
font-family: monospace;
}
/* Default is light theme */
body {
font-family: "Poppins", "sans-serif";
font-size: 1rem;
margin: 0;
/* Default is light theme */
--white: #ffffff;
--off-white: #fdf8f5;
--teal-1: #76ffdc;
--teal-2: #4ed4b2;
--blue-1: #5caff9;
--blue-2: #1482E3;
--blue-1-20: #5caff934;
--blue-2: #1482e3;
--purple-1: #525284;
--purple-2: #2a2a62;
--gradient-blue-green: linear-gradient(
@ -22,12 +20,15 @@ body {
);
}
/* FIXME: Dark theme is the same as light theme right now */
.dark {
--white: #ffffff;
--off-white: #fdf8f5;
--teal-1: #76ffdc;
--teal-2: #4ed4b2;
--blue-1: #5caff9;
--blue-2: #1482E3;
--blue-1-20: #5caff934;
--blue-2: #1482e3;
--purple-1: #525284;
--purple-2: #2a2a62;
--gradient-blue-green: linear-gradient(
@ -36,3 +37,9 @@ body {
#4ed4b2 172.82%
);
}
@media only screen and (max-width: calc(375rem / 16)) {
body {
font-size: calc(14rem / 16);
}
}

View File

@ -2,6 +2,7 @@ import React from "react";
import { AppProps } from "next/app";
import { MDXProvider } from "@mdx-js/react";
import { ThemeProvider } from "../components/theme";
import { Navbar } from "../components/Navbar";
import "./_app.css";
import "./font.css";
@ -9,6 +10,7 @@ export default function App({ Component, pageProps }: AppProps): JSX.Element {
return (
<ThemeProvider theme="light">
<MDXProvider components={{}<