Skip to content

Commit 57a76ad

Browse files
committed
exercises sidebar
1 parent 1a53182 commit 57a76ad

File tree

12 files changed

+161
-55
lines changed

12 files changed

+161
-55
lines changed

README.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
A place for the CSESoc community to learn and share their knowledge and expertise.
88

9-
> 🌈 **Status update:**<br> Finessing the front-end!
9+
> 🌈 **Status update:**<br> Creating a generic system for publishing course revision exercises
1010
1111
> 🎨 **Design system**:<br> CSESoc Learn has its own design system with components + tokens. The Figma file is [here](https://www.figma.com/file/l5z96D2EHE5VNz3nayZ9Ht/Design-System?node-id=11%3A4381).
1212
@@ -15,7 +15,8 @@ A place for the CSESoc community to learn and share their knowledge and expertis
1515
- Support for a wide variety of content types via Contentlayer
1616
- Beautiful UI/UX inspired by Medium and technical sites
1717
- Spotlight-style search via Stork
18-
- Ergonomic content creation workflow
18+
- Ergonomic content creation workflow powered by MDX
19+
- Convenient content sorting and filtering options
1920

2021
## Getting Started
2122
> For detailed instructions, see [here](https://github.com/csesoc/learning-platform/wiki/Getting-started).

components/CourseRevisionSidebar.tsx

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
import { styled } from "@stitches/react"
2+
import { CourseRevisionExercise, CourseRevisionOffering } from "contentlayer/generated"
3+
import Link from "next/link"
4+
import { ArrowLeft } from "phosphor-react"
5+
import { Button } from "./Button"
6+
7+
type PropTypes = {
8+
/* First in list must be the course offering, the rest are exercises */
9+
contentList: (CourseRevisionOffering | CourseRevisionExercise)[],
10+
11+
/* Index of the currently selected content in contentList*/
12+
currentContentIdx: number,
13+
}
14+
15+
const CourseRevisionSidebarStyled = styled("div", {
16+
position: "fixed",
17+
top: "66px",
18+
width: "250px",
19+
height: "calc(100vh - 62px)",
20+
overflowY: "scroll",
21+
scrollbarGutter: "auto",
22+
})
23+
24+
const ExerciseButton = styled("button", {
25+
padding: "0.9rem 1.2rem",
26+
color: "#edf8ff",
27+
backgroundColor: "#0d86d6",
28+
borderRadius: "0.6rem",
29+
cursor: "pointer",
30+
border: "none",
31+
width: "100%",
32+
textAlign: "left",
33+
'&:hover': {
34+
backgroundColor: "#31a7f5",
35+
},
36+
})
37+
38+
39+
const CourseRevisionSidebar = ({ contentList, currentContentIdx }: PropTypes) => {
40+
return (<CourseRevisionSidebarStyled>
41+
<Link href={`/course-revision`}>
42+
<Button css={{ padding: '3px 14px', borderRadius: '100vh', width: "fit-content" }}>
43+
<ArrowLeft />Other Courses
44+
</Button>
45+
</Link>
46+
47+
<ul style={{
48+
padding: "0",
49+
}}>
50+
{contentList.map((content, idx) => (
51+
<li
52+
key={content.slug}
53+
style={{
54+
listStyle: "none",
55+
margin: "0.9rem 0",
56+
}}>
57+
<Link href={`/${content._raw.flattenedPath}`} passHref>
58+
<ExerciseButton key={content.slug} css={{
59+
backgroundColor: idx === currentContentIdx ? "#31a7f5" : "#2285c7",
60+
fontWeight: idx === currentContentIdx ? "bold" : "normal",
61+
}}>
62+
{content.title}
63+
</ExerciseButton>
64+
</Link>
65+
</li>
66+
67+
)
68+
)}
69+
</ul>
70+
</CourseRevisionSidebarStyled>)
71+
}
72+
73+
export default CourseRevisionSidebar

components/Navbar.tsx

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,8 @@ const NavContainer = styled('div', {
5454
}
5555
}
5656
},
57-
backgroundColor: '#e8ebed',
57+
backgroundColor: 'rgb(232, 235, 237, 0.87)',
58+
backdropFilter: 'blur(8px)',
5859
boxShadow: "0px 0px 31px -19px rgba(0,0,0,0.54)",
5960
width: '100vw',
6061
maxWidth: '548px',
@@ -134,7 +135,8 @@ export default function Navbar() {
134135
zIndex: '1',
135136
position: 'fixed',
136137
width: "100%",
137-
background: "linear-gradient(180deg, rgba(244,244,244,1) 0%, rgba(244,244,244,1) 90%, rgba(244,244,244,0.8084599921043882) 96%, rgba(244,244,244,0) 100%)",
138+
background: "rgba(244,244,244,0.78)",
139+
backdropFilter: "blur(7px)",
138140
}}>
139141
<Flex css={{ flex: 1, justifyContent: 'flex-start' }}>
140142
<Link href="/">

data/course-revision/1511/billys_books.mdx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ class: COMP1511
55
difficulty: 2
66
---
77

8+
# Billy's Books
9+
810
For this exercise, you’ll be working with the following scenario.
911

1012
Everyday Billy places a book on his floor, with each book being stacked on top of the previous book. On every third day, in addition to stacking a book to the top, Billy also places another book on top of his bookstack (after placing the new book). If there are an odd number of books, then Billy will move the book in the middle of his bookstack to the top. If there an even number of books, then Billy will take the book at the bottom of his bookstack, and move that to the top. He continues this for all `n` books.

data/course-revision/1511/letter_pairs.mdx

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ class: COMP1511
55
difficulty: 1
66
---
77

8+
# Letter Pairs
9+
810
A letter pair is two of the same character appearing next to each other in a string. E.g. in the string "terrifically" there are 2 letter pairs "rr" and "ll".
911

1012
Write a program that reads a lowercase string as input, counts and prints out the number of letter pairs in a word.
@@ -18,7 +20,9 @@ Write a program that reads a lowercase string as input, counts and prints out th
1820
- No letters will appear consecutively more than twice (e.g. "aaa" will not be an input).
1921

2022

21-
### Examples
23+
## Examples
24+
25+
### Example 1
2226

2327
Input:
2428

@@ -36,6 +40,8 @@ Output:
3640

3741
Explanation: The double letter pair “ee” occurs twice in this word.
3842

43+
### Example 2
44+
3945
Input:
4046

4147
```bash:~/1511-revision/letter_pairs
@@ -52,6 +58,8 @@ Output:
5258

5359
Explanation: The double letter pairs “ll” and “oo” each appear once in this word, so there are two double letter pairs.
5460

61+
### Example 3
62+
5563
Input:
5664

5765
```bash:~/1511-revision/letter_pairs

data/course-revision/2521/bstree_difference.mdx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ class: COMP2521
55
difficulty: 4
66
---
77

8+
# Binary Search Tree Difference
9+
810
Given a binary search tree, determine the minimum difference between any two
911
different values in it. You may assume that the BST has at least two nodes.
1012

data/course-revision/2521/bstree_kth_largest.mdx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ class: COMP2521
55
difficulty: 3
66
---
77

8+
# Kth Largest in Binary Search Tree
9+
810
Given a BST and a number `k`, find the `k`th largest element in the BST.
911

1012
Implement the function `kthlargest` in `bstree_kth_largest.c`. This function will then be called by the `main` function in `test_bstree_kth_largest.c`.

data/course-revision/2521/exact_price_or_not.mdx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ class: COMP2521
55
difficulty: 2
66
---
77

8+
# Exact Price or Not
9+
810
Jack wants to pay for an item at the convenient store. However, this particular store does not give change, i.e., the amount you pay must be the exact amount of the item you are buying, and only takes exactly three coins. Luckily, Jack brought a lot of coins. See if Jack can get the exact price for a given item price `p` he wants using exactly three coins.
911

1012
Complete the `sumCoins` function and return `1` if it's possible and `0` is it isn't.

data/course-revision/2521/graph_detect_cycle.mdx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ class: COMP2521
55
difficulty: 5
66
---
77

8+
# Graph Detect Cycle
9+
810
Given an undirected, unweighted graph with at least one edge, write a function that returns true if the graph contains a cycle, and false otherwise.
911

1012
Implement the function `graphDetectCycle` in `graph_detect_cycle.c`. This function will then be called by the `main` function in `test_graph_detect_cycle.c`.

data/course-revision/2521/sort_the_trio.mdx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ class: COMP2521
55
difficulty: 1
66
---
77

8+
# Sort the Trio
9+
810
Given an array of only 0's, 1's, or 2's, write a O(n) function which sorts this array in ascending order.
911

1012
Implement the function `sort` in `sort_the_trio.c`. This function will be then be called by the `main` function in

pages/course-revision/[course_offering]/[exercise]/index.tsx

Lines changed: 17 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import { ArrowDown, ArrowLeft } from 'phosphor-react'
1616
import ArticleLayout from 'components/ArticleLayout'
1717
import { Button } from 'components/Button'
1818
import { useRouter } from 'next/router'
19+
import CourseRevisionSidebar from 'components/CourseRevisionSidebar'
1920

2021
const defaultComponents = {
2122
Image,
@@ -48,43 +49,30 @@ export async function getStaticPaths() {
4849
}
4950

5051
export async function getStaticProps({ params }) {
51-
const exercise = allCourseRevisionExercises.find((e) => e.slug === params.exercise)
52+
const exercisesContent = allCourseRevisionExercises.filter((e) => e._raw.sourceFileDir.endsWith(params.course_offering)).sort((a, b) => a.difficulty - b.difficulty)
53+
const exerciseIdx = exercisesContent.findIndex((e) => e.slug === params.exercise)
5254
return {
5355
props: {
54-
exercise
56+
courseOfferingContent: allCourseRevisionOfferings.find((c) => c.slug === params.course_offering),
57+
exercisesContent,
58+
exerciseIdx,
5559
}
5660
}
5761
}
5862

59-
const ExercisePage = ({ exercise }) => {
60-
const router = useRouter();
61-
const MDXContent = useMDXComponent(exercise.body.code)
63+
const ExercisePage = ({ courseOfferingContent, exercisesContent, exerciseIdx }) => {
64+
const MDXContent = useMDXComponent(exercisesContent[exerciseIdx].body.code)
6265

6366
return (
64-
<ArticleLayout>
65-
<Head>
66-
<title>{exercise.title}</title>
67-
</Head>
68-
<Link href={`/course-revision/${router.query.course_offering}`}>
69-
<Button css={{ padding: '3px 14px', borderRadius: '100vh', width: "fit-content" }}>
70-
<ArrowLeft />Back
71-
</Button>
72-
</Link>
73-
<Text
74-
size="headline"
75-
css={{
76-
color: '$slate12',
77-
fontWeight: '600',
78-
paddingTop: '$2',
79-
alignSelf: 'center'
80-
}}>
81-
{exercise.title}
82-
</Text>
83-
<Box css={{ paddingTop: '$2' }}>
84-
<Text>
85-
<MDXContent components={components} />
86-
</Text>
87-
</Box>
67+
<ArticleLayout style={{
68+
maxWidth: '1018px',
69+
}}>
70+
<CourseRevisionSidebar contentList={[courseOfferingContent, ...exercisesContent]} currentContentIdx={exerciseIdx + 1} />
71+
<div style={{
72+
marginLeft: "266px",
73+
}}>
74+
<MDXContent components={components} />
75+
</div>
8876
</ArticleLayout >
8977
)
9078
}

pages/course-revision/[course_offering]/index.tsx

Lines changed: 43 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,19 @@
11
import { Card } from '@modulz/design-system'
22
import ArticleLayout from 'components/ArticleLayout'
33
import { Button } from 'components/Button'
4+
import CourseRevisionSidebar from 'components/CourseRevisionSidebar'
45
import { ProblemCard } from 'components/ProblemCard'
56
import { Tag } from 'components/Tag'
6-
import { allCourseRevisionOfferings, allCourseRevisionExercises } from 'contentlayer/generated'
7+
import { allCourseRevisionOfferings, allCourseRevisionExercises, CourseRevisionOffering } from 'contentlayer/generated'
78
import { InferGetStaticPropsType } from 'next'
89
import { useMDXComponent } from 'next-contentlayer/hooks'
910
import Link from 'next/link'
1011
import Router, { useRouter } from 'next/router'
1112
import { ArrowLeft } from 'phosphor-react'
13+
import { useEffect, useState } from 'react'
1214

1315
export async function getStaticPaths() {
14-
const paths = allCourseRevisionOfferings.map((o) => ({ params: { course_offering: o.slug, course: o.course } }))
16+
const paths = allCourseRevisionOfferings.map((o) => ({ params: { course_offering: o.slug } }))
1517
return {
1618
paths,
1719
fallback: false
@@ -23,41 +25,61 @@ export const getStaticProps = async ({ params }) => {
2325
(c) => c.slug === params.course_offering
2426
)
2527

26-
// const courseRevisionExercises = allCourseRevisionExercises.filter((e) => e.course === params.course_offering)
27-
2828
return {
2929
props: {
30-
exercises: allCourseRevisionExercises.sort((a, b) => a.difficulty - b.difficulty),
30+
exercisesContent: allCourseRevisionExercises.filter((e) => e._raw.sourceFileDir.endsWith(params.course_offering)).sort((a, b) => a.difficulty - b.difficulty),
3131
courseOfferingContent
3232
}
3333
}
3434
}
3535

3636
const ExercisesPage = ({
37-
exercises,
37+
exercisesContent,
3838
courseOfferingContent
3939
}: InferGetStaticPropsType<typeof getStaticProps>) => {
4040
const router = useRouter()
4141
const MDXContent = useMDXComponent(courseOfferingContent.body.code)
42+
// const exercisesMDXContent = [useMDXComponent(courseOfferingContent.body.code), ...exercisesContent.map((e) => useMDXComponent(e.body.code))]
43+
// const [content, setContent] = useState(0)
44+
// const [MDXContent, setMDXContent] = useState(null)
45+
46+
// useEffect(() => {
47+
// const content = exercisesMDXContent[0]
48+
// setMDXContent(content)
49+
// }, [])
50+
51+
// const switchExercise = (path: string) => {
52+
// const exerciseContent = allCourseRevisionExercises.find((e) => e._raw.flattenedPath === path)
53+
// // setContent(exerciseContent.body.code)
54+
// setMDXContent(useMDXComponent(exerciseContent.body.code))
55+
// router.push(path, undefined, { shallow: true })
56+
// }
4257

4358
return (
4459
<main>
45-
<ArticleLayout>
46-
<Link href={`/course-revision`}>
47-
<Button css={{ padding: '3px 14px', borderRadius: '100vh', width: "fit-content" }}>
48-
<ArrowLeft />Back
49-
</Button>
50-
</Link>
51-
<MDXContent />
52-
{exercises?.map((exercise) => (
53-
<Link href={`${router.query.course_offering}/${exercise.slug}`} passHref key={exercise.slug}>
60+
<ArticleLayout style={{
61+
maxWidth: '1018px',
62+
}}>
63+
<CourseRevisionSidebar contentList={[courseOfferingContent, ...exercisesContent]} currentContentIdx={0} />
64+
<div style={{
65+
marginLeft: "266px",
66+
}}>
67+
<div style={{
68+
marginLeft: '1.4rem',
69+
}}>
70+
{MDXContent && <MDXContent />}
71+
</div>
72+
{/* {exercisesContent?.map((exercise) => (
73+
<Link href={`${router.query.course_offering}/${exercise.slug}`} passHref key={exercise.slug}>
5474
<ProblemCard>
55-
<h1>{exercise.title}</h1>
56-
<Tag>Pain score: {exercise.difficulty} 💀</Tag>
57-
<p>{exercise.desc}</p>
58-
</ProblemCard>
59-
</Link>
60-
))}
75+
<h1>{exercise.title}</h1>
76+
<Tag>Pain score: {exercise.difficulty} 💀</Tag>
77+
<p>{exercise.desc}</p>
78+
</ProblemCard>
79+
</Link>
80+
))} */}
81+
82+
</div>
6183
</ArticleLayout>
6284
</main>
6385
)

0 commit comments

Comments
 (0)