Skip to content

Commit

Permalink
add page showing all course parts
Browse files Browse the repository at this point in the history
parity with ohjelmointi-22
  • Loading branch information
ConcernedHobbit committed Feb 2, 2022
1 parent 95f521d commit 3aaa2a4
Show file tree
Hide file tree
Showing 8 changed files with 281 additions and 2 deletions.
9 changes: 9 additions & 0 deletions data/all-exercises.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
---
path: '/all-exercises'
title: 'All exercises'
hidden: false
hide_in_sidebar: true
course_info_page: true
---

<exercises-in-all-sections></exercises-in-all-sections>
6 changes: 6 additions & 0 deletions gatsby-node.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ exports.createPages = ({ actions, graphql }) => {

const vocabularyTemplate = path.resolve(`src/templates/VocabularyTemplate.js`)

const courseInfoTemplate = path.resolve(`src/templates/CourseInfoTemplate.js`)

const query = `
{
allMarkdownRemark(
Expand All @@ -49,6 +51,7 @@ exports.createPages = ({ actions, graphql }) => {
hide_in_sidebar
sidebar_priority
vocabulary_page
course_info_page
}
}
}
Expand Down Expand Up @@ -77,6 +80,9 @@ exports.createPages = ({ actions, graphql }) => {
if (node.frontmatter.vocabulary_page) {
template = vocabularyTemplate
}
if (node.frontmatter.course_info_page) {
template = courseInfoTemplate
}
if (!node.frontmatter.path) {
// To prevent a bug that happens in development from time to time
return;
Expand Down
5 changes: 3 additions & 2 deletions src/components/Sidebar.js
Original file line number Diff line number Diff line change
Expand Up @@ -130,10 +130,10 @@ const Sidebar = (props) => {
}),
)

let coursePartEdges = edges.filter((o) => !o.information_page && !o.upcoming)
let coursePartEdges = edges.filter((o) => !o.information_page && !o.course_info_page && !o.upcoming)

let informationPageEdges = edges
.filter((o) => o.information_page)
.filter((o) => o.information_page || o.course_info_page)
.sort((a, b) => b.sidebar_priority - a.sidebar_priority)

let upcomingPageEdges = edges
Expand Down Expand Up @@ -210,6 +210,7 @@ const query = graphql`
frontmatter {
title
information_page
course_info_page
path
hidden
separator_after
Expand Down
124 changes: 124 additions & 0 deletions src/partials/ExercisesInAllSections/ExerciseList.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
import React from "react"
import PagesContext from "../../contexes/PagesContext"
import styled from "styled-components"
import { Paper } from "@material-ui/core"
import { Link } from "gatsby"
import withSimpleErrorBoundary from "../../util/withSimpleErrorBoundary"
import ExerciseSummary from "../ExercisesInThisSection/ExerciseSummary"
import { fetchQuizNames } from "../../services/quizzes"
import { extractPartNumberFromPath, extractSubpartNumberFromPath } from "../../util/strings"
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"
import { faLink } from "@fortawesome/free-solid-svg-icons"

const PartWrapper = styled(Paper)`
padding: 1rem;
margin: 2rem 0;
`

const Page = styled.div`
margin: 1rem 0;
`

const Title = styled.div`
margin-bottom: 0.35em;
color: rgba(0, 0, 0, 0.87);
font-size: 1.5em;
font-family: "Roboto", "Helvetica", "Arial", sans-serif;
font-weight: 800;
line-height: 1.33;
letter-spacing: 0em;
a {
margin-left: .5em;
}
`

const Subtitle = styled.div`
margin-bottom: 0.5em;
color: rgba(0, 0, 0, 0.87);
font-family: "Roboto", "Helvetica", "Arial", sans-serif;
font-weight: 400;
font-size: 1.1rem;
letter-spacing: 0em;
a {
margin-left: .5em;
}
`

class ExerciseList extends React.Component {
static contextType = PagesContext

state = {
render: false,
sectionPages: null,
quizIdToTitle: null,
}

async componentDidMount() {
const value = this.context

const overviewPages = value.all
.filter((o) => o.overview && !o.hidden)
.sort((a, b) => {
let partA = extractPartNumberFromPath(a.path.toLowerCase())
let partB = extractPartNumberFromPath(b.path.toLowerCase())

return partA > partB ? 1 : partB > partA ? -1 : 0
})

const exercisePages = value.all
.filter((o) => o.exercises?.length > 0)

const quizIdToTitle = await fetchQuizNames()
this.setState({ overviewPages, exercisePages, quizIdToTitle, render: true })
}
render() {
if (!this.state.render) {
return <div>Loading...</div>
}
return (
<div>
{this.state.overviewPages &&
this.state.overviewPages.map((page) => (
<PartWrapper key={page.title}>
<Title>
{page.title}
<Link to={page.path}>
<FontAwesomeIcon icon={faLink} size="xs" />
</Link>
</Title>

{this.state.exercisePages
.filter((o) => o.path.startsWith(`${page.path}/`))
.sort((a, b) => {
let subA = extractSubpartNumberFromPath(a.path.toLowerCase())
let subB = extractSubpartNumberFromPath(b.path.toLowerCase())

return subA > subB ? 1 : subB > subA ? -1 : 0
})
.map((page) => (
<Page key={page.title}>
<Subtitle>
{page.title}
<Link to={page.path}>
<FontAwesomeIcon icon={faLink} size="sm" />
</Link>
</Subtitle>
{page.exercises.map((exercise, i) => (
<ExerciseSummary
index={i}
exercise={exercise}
key={exercise.id}
quizIdToTitle={this.state.quizIdToTitle}
/>
))}
</Page>
))}
</PartWrapper>
))
}
</div>
)
}
}

export default withSimpleErrorBoundary(ExerciseList)
27 changes: 27 additions & 0 deletions src/partials/ExercisesInAllSections/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import React from "react"
import { withTranslation } from "react-i18next"
import withSimpleErrorBoundary from "../../util/withSimpleErrorBoundary"
import ExerciseList from "./ExerciseList"

class ExercisesInAllSections extends React.Component {
state = {
render: false,
}

componentDidMount() {
this.setState({ render: true })
}

render() {
if (!this.state.render) {
return <div>Loading...</div>
}
return (
<ExerciseList />
)
}
}

export default withTranslation("common")(
withSimpleErrorBoundary(ExercisesInAllSections),
)
2 changes: 2 additions & 0 deletions src/partials/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ import FloatImageRight from "./FloatImageRight"
import CodeStatesVisualizer from "./CodeStatesVisualizer"
import PdfSlideshow from "./PdfSlideshow"
import ExercisesInThisSection from "./ExercisesInThisSection"
import ExercisesInAllSections from "./ExercisesInAllSections"
import AbStudy from "./AbStudy"
import MoodleExercise from "./MoodleExercise"
import SqlTrainerExercise from "./SqlTrainerExercise"
Expand Down Expand Up @@ -84,6 +85,7 @@ const mapping = () => ({
"code-states-visualizer": CodeStatesVisualizer,
"pdf-slideshow": PdfSlideshow,
"exercises-in-this-section": ExercisesInThisSection,
"exercises-in-all-sections": ExercisesInAllSections,
"ab-study": AbStudy,
"only-for-ab-group": OnlyForAbGroup,
"only-for-course-variant": OnlyForCourseVariant,
Expand Down
96 changes: 96 additions & 0 deletions src/templates/CourseInfoTemplate.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
import React, { Fragment } from "react"
import { graphql } from "gatsby"
import styled from "styled-components"
import rehypeReact from "rehype-react"
import { Helmet } from "react-helmet"

import Layout from "./Layout"

import getNamedPartials from "../partials"

import "./remark.css"
import { LoginStateContextProvider } from "../contexes/LoginStateContext"
import Container from "../components/Container"
import Banner from "../components/Banner"
import PagesContext from "../contexes/PagesContext"

const ContentWrapper = styled.article``

export default class CourseInfoTemplate extends React.Component {
render() {
const { data } = this.props
const { frontmatter, htmlAst } = data.page
const allPages = data.allPages.edges.map((o) => {
const res = o.node?.frontmatter
res.exercises = o.node?.moocfiExercises
return res
})
const partials = getNamedPartials()
const renderAst = new rehypeReact({
createElement: React.createElement,
components: partials,
}).Compiler

const filePath = data.page.fileAbsolutePath.substring(
data.page.fileAbsolutePath.lastIndexOf("/data/"),
data.page.fileAbsolutePath.length,
)
return (
<Fragment>
<Helmet title={frontmatter.title} />
<PagesContext.Provider
value={{
all: allPages,
current: { frontmatter: frontmatter, filePath: filePath },
}}
>
<LoginStateContextProvider>
<Layout>
<Fragment>
{frontmatter.banner && <Banner />}
<Container>
<ContentWrapper>
<h1>{frontmatter.title}</h1>
{renderAst(htmlAst)}
</ContentWrapper>
</Container>
</Fragment>
</Layout>
</LoginStateContextProvider>
</PagesContext.Provider>
</Fragment>
)
}
}

export const pageQuery = graphql`
query ($path: String!) {
page: markdownRemark(frontmatter: { path: { eq: $path } }) {
htmlAst
html
frontmatter {
path
title
}
fileAbsolutePath
}
allPages: allMarkdownRemark {
edges {
node {
id
frontmatter {
path
title
overview
hidden
}
moocfiExercises {
id
type
parentPagePath
}
}
}
}
}
`
14 changes: 14 additions & 0 deletions src/util/strings.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,20 @@ export function nthIndex(str, pat, n) {
return i
}

export function extractPartNumberFromPath(string) {
// Assumes path is formatted /part-[num] or /part-[num]/...
const subpartSeperator = nthIndex(string, '/', 2)
if (subpartSeperator !== -1) {
string = string.substring(0, subpartSeperator)
}
return parseInt(string.substring(string.indexOf('-') + 1))
}

export function extractSubpartNumberFromPath(string) {
// Assumes path is formatted /part-[num]/[num]-...
return parseInt(string.substring(nthIndex(string, '/', 2) + 1, nthIndex(string, '-', 2)))
}

export function capitalizeFirstLetter(string) {
return string.charAt(0).toUpperCase() + string.slice(1)
}
Expand Down

0 comments on commit 3aaa2a4

Please sign in to comment.