diff --git a/components/course-revision/CourseRevisionMiniCard.tsx b/components/course-revision/CourseRevisionMiniCard.tsx
index 4e11e00..bd3a3d9 100644
--- a/components/course-revision/CourseRevisionMiniCard.tsx
+++ b/components/course-revision/CourseRevisionMiniCard.tsx
@@ -1,10 +1,10 @@
import { styled } from "@stitches/react";
import { Text } from "components/Text";
-import { CourseRevisionOffering } from "contentlayer/generated";
+import { CourseRevisionOffering, WorkshopsOffering } from "contentlayer/generated";
type PropTypes = {
- courseOffering: CourseRevisionOffering
+ courseOffering: CourseRevisionOffering | WorkshopsOffering
}
const CourseRevisionMiniCardStyled = styled('div', {
diff --git a/components/course-revision/CourseRevisionSidebar.tsx b/components/course-revision/CourseRevisionSidebar.tsx
index 9c059b8..e889892 100644
--- a/components/course-revision/CourseRevisionSidebar.tsx
+++ b/components/course-revision/CourseRevisionSidebar.tsx
@@ -1,5 +1,5 @@
import { styled } from "@stitches/react"
-import { CourseRevisionExercise, CourseRevisionOffering } from "contentlayer/generated"
+import { CourseRevisionExercise, CourseRevisionOffering, WorkshopsOffering, WorkshopsExercise } from "contentlayer/generated"
import Link from "next/link"
import { ArrowLeft, CaretDown, CaretUp } from "phosphor-react"
import { useState } from "react"
@@ -11,10 +11,10 @@ type PropTypes = {
courseOfferingTitle: string,
/* Home page for this course offering e.g. 1511 22T3 */
- courseOfferingContent: CourseRevisionOffering,
+ courseOfferingContent: CourseRevisionOffering | WorkshopsOffering,
/* List of exercises content */
- contentList: CourseRevisionExercise[],
+ contentList: CourseRevisionExercise[] | WorkshopsExercise[]
/* Index of the currently selected content in contentList */
currentContentIdx: number,
@@ -111,6 +111,16 @@ const ExerciseButton = styled("button", {
},
})
+const determineCourseRevisionOrWorkshopsOffering = (toBeDetermined: WorkshopsOffering | CourseRevisionOffering) => {
+
+ if (toBeDetermined.type === "WorkshopsOffering") {
+ return true;
+ }
+
+ return false;
+
+}
+
const CourseRevisionSidebar = ({ courseOfferingTitle, courseOfferingContent, contentList, currentContentIdx }: PropTypes) => {
/* ONLY applies when width < 768px (in mobile view) */
const [showContent, setShowContent] = useState(false)
@@ -120,11 +130,23 @@ const CourseRevisionSidebar = ({ courseOfferingTitle, courseOfferingContent, con
justifyContent: "space-between",
alignItems: "center",
}}>
-
+ {determineCourseRevisionOrWorkshopsOffering(courseOfferingContent) ?
+
+
+ Other Workshops
+
+ :
+
+
+ Other Courses
+
+
+ }
+ {/*
Other Courses
-
+ */}
setShowContent((val) => !val)}>
{showContent ? (<>Hide Exercises>) : <>Show Exercises>}
diff --git a/components/workshops/WorkshopsContainerHomePage.tsx b/components/workshops/WorkshopsContainerHomePage.tsx
new file mode 100644
index 0000000..88cd3e2
--- /dev/null
+++ b/components/workshops/WorkshopsContainerHomePage.tsx
@@ -0,0 +1,40 @@
+import { styled } from "@stitches/react"
+import { WorkshopsOffering } from "contentlayer/generated"
+import Link from "next/link"
+import CourseRevisionMiniCard from "../course-revision/CourseRevisionMiniCard"
+
+type PropTypes = {
+ allWorkshopsOffering: WorkshopsOffering[]
+}
+
+const CourseRevisionsContainer = styled('div', {
+ width: "100%",
+ display: 'flex',
+ flexFlow: "row wrap",
+ justifyContent: "center",
+ rowGap: '$1',
+ columnGap: '$4',
+})
+
+const WorkshopsContainerHomePage = (props: PropTypes) => {
+ return (
+
+ {
+ props.allWorkshopsOffering?.map((offering) => (
+
+
+
+
+
+ ))
+
+ }
+ )
+}
+
+export default WorkshopsContainerHomePage
+
diff --git a/contentlayer.config.js b/contentlayer.config.js
index 2774da6..f2067eb 100644
--- a/contentlayer.config.js
+++ b/contentlayer.config.js
@@ -69,22 +69,26 @@ export const CourseRevisionOffering = defineDocumentType(() => ({
fields: {
title: {
type: 'string',
- description: 'The title of the exercise set e.g. COMP1511 22T3 Revision Session',
+ description:
+ 'The title of the exercise set e.g. COMP1511 22T3 Revision Session',
required: true
},
desc: {
type: 'string',
- description: 'A brief 1-2 sentence description of what this course revision contains',
+ description:
+ 'A brief 1-2 sentence description of what this course revision contains',
required: true
},
course: {
type: 'string',
- description: 'The course that the revision set relates to (COMP1511, COMP2521, ...)',
+ description:
+ 'The course that the revision set relates to (COMP1511, COMP2521, ...)',
required: true
},
offering: {
type: 'string',
- description: 'The offering of the course that the revision set is intended for (22T3, 23T1, ...)',
+ description:
+ 'The offering of the course that the revision set is intended for (22T3, 23T1, ...)',
required: true
}
},
@@ -108,7 +112,71 @@ export const CourseRevisionExercise = defineDocumentType(() => ({
},
class: {
type: 'string',
- description: 'The class the exercise relates to (COMP1511, COMP2521, etc)',
+ description:
+ 'The class the exercise relates to (COMP1511, COMP2521, etc)',
+ required: true
+ },
+ difficulty: {
+ type: 'number',
+ description: 'The difficulty of the exercise (1=Easy, 2=Medium, 3=Hard)',
+ required: true
+ }
+ },
+ computedFields
+}))
+
+export const WorkshopsOffering = defineDocumentType(() => ({
+ name: 'WorkshopsOffering',
+ filePathPattern: `workshops/*.mdx`,
+ contentType: 'mdx',
+ fields: {
+ title: {
+ type: 'string',
+ description:
+ 'The title of the exercise set e.g. COMP2521 Fundamentals Workshop',
+ required: true
+ },
+ desc: {
+ type: 'string',
+ description:
+ 'A brief 1-2 sentence description of what this workshop contains',
+ required: true
+ },
+ course: {
+ type: 'string',
+ description:
+ 'The course that the revision set relates to (COMP1511, COMP2521, ...)',
+ required: true
+ },
+ offering: {
+ type: 'string',
+ description:
+ 'The offering of the course that the revision set is intended for (22T3, 23T1, ...)',
+ required: true
+ }
+ },
+ computedFields
+}))
+
+export const WorkshopsExercise = defineDocumentType(() => ({
+ name: 'WorkshopsExercise',
+ filePathPattern: `workshops/**/*.mdx`,
+ contentType: 'mdx',
+ fields: {
+ title: {
+ type: 'string',
+ description: 'The title of the exercise',
+ required: true
+ },
+ desc: {
+ type: 'string',
+ description: 'One sentence that summarises the exercise objective.',
+ required: true
+ },
+ class: {
+ type: 'string',
+ description:
+ 'The class the exercise relates to (COMP1511, COMP2521, etc)',
required: true
},
difficulty: {
@@ -122,7 +190,13 @@ export const CourseRevisionExercise = defineDocumentType(() => ({
export default makeSource({
contentDirPath: 'data',
- documentTypes: [ArticleType, CourseRevisionOffering, CourseRevisionExercise],
+ documentTypes: [
+ ArticleType,
+ CourseRevisionOffering,
+ CourseRevisionExercise,
+ WorkshopsOffering,
+ WorkshopsExercise
+ ],
mdx: {
remarkPlugins: [remarkGfm],
rehypePlugins: [
diff --git a/pages/articles.tsx b/pages/articles.tsx
index 1db11a7..e7df9d4 100644
--- a/pages/articles.tsx
+++ b/pages/articles.tsx
@@ -3,7 +3,7 @@ import { Flex } from 'components/Flex'
import { Text } from 'components/Text'
import { Button } from 'components/Button'
import ArticleCard from 'components/ArticleCard'
-import { ArticleType, allArticleTypes, allCourseRevisionOfferings } from 'contentlayer/generated'
+import { ArticleType, allArticleTypes, allCourseRevisionOfferings, allWorkshopsOfferings } from 'contentlayer/generated'
import { compareDesc } from 'date-fns'
import { NextPage } from 'next'
import Head from 'next/head'
@@ -13,6 +13,7 @@ import { MagnifyingGlass } from 'phosphor-react'
import { ArticleRow } from '../components/ArticleRow'
import { ArticlesCarousel } from 'components/ArticlesCarousel'
import CourseRevisionContainerHomePage from 'components/course-revision/CourseRevisionContainerHomePage'
+import WorkshopsContainerHomePage from 'components/workshops/WorkshopsContainerHomePage'
export async function getStaticProps() {
const articles = allArticleTypes.sort((a, b) => {
@@ -23,7 +24,7 @@ export async function getStaticProps() {
)
const flattenedTags = tagLists.flat(1)
const allTags = [...['All Topics'], ...new Set(flattenedTags)]
- return { props: { articles, allTags, courseOfferingContent: allCourseRevisionOfferings } }
+ return { props: { articles, allTags, courseOfferingContent: allCourseRevisionOfferings, workshopOfferingContent: allWorkshopsOfferings } }
}
const SearchBar = styled('input', {
@@ -43,7 +44,7 @@ const TagsContainer = styled('div', {
})
// I'm tired, I didn't type this properly ok
-const Articles: NextPage = ({ articles, allTags, courseOfferingContent }: any) => {
+const Articles: NextPage = ({ articles, allTags, courseOfferingContent, workshopOfferingContent }: any) => {
const [currentTag, setCurrentTag] = useState('All Topics')
const [currentSearch, setCurrentSearch] = useState('')
const [filteredArticles, setFilteredArticles] = useState(articles)
@@ -135,6 +136,29 @@ const Articles: NextPage = ({ articles, allTags, courseOfferingContent }: any) =
+ {/* Uncomment once we have content for workshops */}
+
+ {/*
+
+ Workshops
+
+
+ Explore the many workshops our Education Team has curated to become big brain.
+
+
+ */}
+
diff --git a/pages/index.tsx b/pages/index.tsx
index 1bd1c91..8fe70bb 100644
--- a/pages/index.tsx
+++ b/pages/index.tsx
@@ -3,7 +3,7 @@ import { Button } from 'components/Button'
import { Card } from 'components/Card'
import { Flex } from 'components/Flex'
import { Text } from 'components/Text'
-import { allArticleTypes, allCourseRevisionOfferings, ArticleType, CourseRevisionOffering } from 'contentlayer/generated'
+import { allArticleTypes, allCourseRevisionOfferings, ArticleType, CourseRevisionOffering, WorkshopsOffering, allWorkshopsOfferings } from 'contentlayer/generated'
import { compareAsc, compareDesc } from 'date-fns'
import type { NextPage } from 'next'
import Head from 'next/head'
@@ -15,20 +15,22 @@ import CourseRevisionCard from 'components/course-revision/CourseRevisionCard'
import { styled } from '@stitches/react'
import CourseRevisionMiniCard from 'components/course-revision/CourseRevisionMiniCard'
import CourseRevisionContainerHomePage from 'components/course-revision/CourseRevisionContainerHomePage'
+import WorkshopsContainerHomePage from 'components/workshops/WorkshopsContainerHomePage'
type PropTypes = {
articles: ArticleType[],
courseOfferingContent: CourseRevisionOffering[],
+ workshopOfferingContent: WorkshopsOffering[]
}
export async function getStaticProps() {
const articles = allArticleTypes.sort((a, b) => {
return compareAsc(new Date(b.date), new Date(a.date))
})
- return { props: { articles, courseOfferingContent: allCourseRevisionOfferings } }
+ return { props: { articles, courseOfferingContent: allCourseRevisionOfferings, workshopOfferingContent: allWorkshopsOfferings } }
}
-const Home: NextPage = ({ articles, courseOfferingContent }: PropTypes) => {
+const Home: NextPage = ({ articles, courseOfferingContent, workshopOfferingContent }: PropTypes) => {
return (
@@ -87,6 +89,28 @@ const Home: NextPage = ({ articles, courseOfferingContent }: PropTypes) => {
+ {/* Uncomment once we have content for workshops */}
+
+ {/*
+
+ Workshops
+
+
+ Explore the many workshops our Education Team has curated to become big brain.
+
+
+ */}
{
+ allWorkshopsExercises.forEach((e) => {
+ if (e._raw.sourceFileDir.endsWith(o.slug)) {
+ paths.push({ params: { course_offering: o.slug, exercise: e.slug } })
+ }
+ })
+ })
+
+ return {
+ paths,
+ fallback: false
+ }
+}
+
+export async function getStaticProps({ params }) {
+ const exercisesContent = allWorkshopsExercises.filter((e) => e._raw.sourceFileDir.endsWith(params.course_offering)).sort((a, b) => a.difficulty - b.difficulty)
+ const exerciseIdx = exercisesContent.findIndex((e) => e.slug === params.exercise)
+ return {
+ props: {
+ courseOfferingContent: allWorkshopsOfferings.find((c) => c.slug === params.course_offering),
+ exercisesContent,
+ exerciseIdx,
+ }
+ }
+}
+
+const ExercisePage = ({ courseOfferingContent, exercisesContent, exerciseIdx }: PropTypes) => {
+ const MDXContent = useMDXComponent(exercisesContent[exerciseIdx].body.code)
+
+ return (
+
+
+
+ {MDXContent && }
+
+
+
+ )
+}
+
+export default ExercisePage
diff --git a/pages/workshops/[course_offering]/index.tsx b/pages/workshops/[course_offering]/index.tsx
new file mode 100644
index 0000000..c294862
--- /dev/null
+++ b/pages/workshops/[course_offering]/index.tsx
@@ -0,0 +1,69 @@
+import { Card } from '@modulz/design-system'
+import { styled } from '@stitches/react'
+import ArticleLayout from 'components/ArticleLayout'
+import { Button } from 'components/Button'
+import ContentContainer from 'components/course-revision/ContentContainer'
+import CourseRevisionSidebar from 'components/course-revision/CourseRevisionSidebar'
+import { ProblemCard } from 'components/ProblemCard'
+import { Tag } from 'components/Tag'
+import { Text } from 'components/Text'
+import { allCourseRevisionOfferings, allCourseRevisionExercises, CourseRevisionOffering, WorkshopsOffering, allWorkshopsOfferings, allWorkshopsExercises } from 'contentlayer/generated'
+import { InferGetStaticPropsType } from 'next'
+import { useMDXComponent } from 'next-contentlayer/hooks'
+import Link from 'next/link'
+import Router, { useRouter } from 'next/router'
+import { ArrowLeft } from 'phosphor-react'
+import { useEffect, useState } from 'react'
+
+export async function getStaticPaths() {
+ const paths = allWorkshopsOfferings.map((o) => ({ params: { course_offering: o.slug } }))
+ return {
+ paths,
+ fallback: false
+ }
+}
+
+export const getStaticProps = async ({ params }) => {
+ const courseOfferingContent = allWorkshopsOfferings.find(
+ (c) => c.slug === params.course_offering
+ )
+
+ return {
+ props: {
+ exercisesContent: allWorkshopsExercises.filter((e) => e._raw.sourceFileDir.endsWith(params.course_offering)).sort((a, b) => a.difficulty - b.difficulty),
+ courseOfferingContent
+ }
+ }
+}
+
+const ExercisesPage = ({
+ exercisesContent,
+ courseOfferingContent
+}: InferGetStaticPropsType) => {
+ const MDXContent = useMDXComponent(courseOfferingContent.body.code)
+
+ return (
+
+
+
+
+ {MDXContent && }
+ {/* {exercisesContent?.map((exercise) => (
+
+
+ {exercise.title}
+ Pain score: {exercise.difficulty} 💀
+ {exercise.desc}
+
+
+ ))} */}
+
+
+
+
+ )
+}
+
+export default ExercisesPage
diff --git a/pages/workshops/index.tsx b/pages/workshops/index.tsx
new file mode 100644
index 0000000..c8a2927
--- /dev/null
+++ b/pages/workshops/index.tsx
@@ -0,0 +1,58 @@
+import { Card } from '@modulz/design-system'
+import { styled } from '@stitches/react'
+import ArticleLayout from 'components/ArticleLayout'
+import CourseRevisionCard from 'components/course-revision/CourseRevisionCard'
+import { Tag } from 'components/Tag'
+import { allWorkshopsOfferings } from 'contentlayer/generated'
+import { InferGetStaticPropsType } from 'next'
+import { useMDXComponent } from 'next-contentlayer/hooks'
+import Link from 'next/link'
+import Router, { useRouter } from 'next/router'
+
+export const getStaticProps = async ({ params }) => {
+ return {
+ props: {
+ allWorkshopsOfferings,
+ }
+ }
+}
+
+const ExercisesPage = ({
+ allWorkshopsOfferings,
+}: InferGetStaticPropsType) => {
+ const router = useRouter()
+ return (
+
+
+ Workshops
+ {allWorkshopsOfferings?.map((offering) => (
+
+
+
+ {offering.title}
+ {offering.desc}
+
+
+
+ ))}
+
+
+ )
+}
+
+export default ExercisesPage
+
+const H1 = styled('h1', {
+ fontSize: "1.4rem",
+ marginBottom: "0.2rem",
+ lineHeight: "1.6rem",
+ '@media (min-width: 640px)': {
+ fontSize: "1.8rem",
+ marginBottom: "0.2rem",
+ lineHeight: "2.2rem",
+ },
+})
\ No newline at end of file
diff --git a/yarn.lock b/yarn.lock
index 995ab14..e7d2ce7 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -5398,4 +5398,4 @@ zod@^3.21.4:
zwitch@^2.0.0, zwitch@^2.0.4:
version "2.0.4"
resolved "https://registry.npmjs.org/zwitch/-/zwitch-2.0.4.tgz"
- integrity sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==
+ integrity sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==
\ No newline at end of file