Building
With every module we build, we are moving toward a clear picture of how content will be managed in our learning management system (LMS).
Currently, this documentation uses Module 101 as an example. In the weeks to come, this documentation will be updated as we continue to iterate on Lesson components and content structures.
Getting Started
Clone the PPBL Front End Template 2023
git clone https://gitlab.com/gimbalabs/ppbl-2023/ppbl-front-end-template-2023
git branch -la
Look for a module-[number]-plannning
branch and use git checkout <branch name>
. If the branch you need does not exist, create it, and then push updates to GitLab. For example:
git checkout -b module-101-planning
git push --set-upstream origin module-101-planning
Make updates to these files:
Data
In slts-english.json
, each Module includes some identifying data, a list of slts
and a list of lessons
.
When you are building a Module, please only make changes to the list of lessons
for that Module.
Example:
"lessons": [
{
"slug": "slts",
"name": "Student Learning Targets",
"video": ""
},
{
"slug": "1011",
"name": "Lesson 1: Compiling Plutus Scripts",
"video": ""
},
...
]
slug
is used in the page route, as inplutuspbl.io/modules/101/slts
orplutuspbl.io/modules/101/1011
name
is used to populate the Sidebar in each Module. Make changes here to update the lesson names listed in the Sidebar.video
is not yet implemented. Stay tuned!
After a module is complete,
lessons
arrays can be copied from a sourceslts-language.json
file into those of the other languages and translated.
Pages
For each module, you'll find two files: [lesson].tsx
and index.tsx
, located in the corresponding directory:
/src/pages/modules/[module_id]
You might not have to change these files at all.
[lesson].tsx
includes all imports of lesson components. If a new component is added (for example, a 'Summary' component), it can be added to [lesson].tsx
. See Module 101 for an example.
In [lesson].tsx
you will find another lessons
list. Each key
must have a corresponding lesson slug
in the slts-language.json
(mentioned earlier).
Example:
const lessons = [
{ key:"slts", component:<SLTs101 />},
{ key:"1011", component:<Lesson1011 />},
{ key:"1012", component:<Lesson1012 />},
{ key:"1013", component:<Lesson1013 />},
{ key:"1014", component:<Lesson1014 />},
{ key:"1015", component:<Lesson1015 />},
{ key:"1016", component:<Lesson1016 />},
{ key:"summary", component:<Summary101 />},
]
The
lessons
list defines which routes are valid in site navigation. Eachcomponent
defines a Lesson component fromsrc/components/course-modules
as imported at the top of[lesson].tsx
. If you want to add new page routes, do so here.
Components
Most of the Module content will be added to the src/components/course-modules/
directory. For example, take a look at /src/components/course-modules/101
.
You will find three types of files:
.tsx files
.mdx files
module.json
Component Details
Let's take an in-depth look at each of the file types in course-modules/[module_id]
:
.tsx files:
Each .tsx
file is imported into /src/pages/modules/[module_id]/[lesson].tsx
as described above. See example.
Here is an example of a Lesson-[slug].tsx
component:
import LessonLayout from "@/src/components/lms/Lesson/LessonLayout";
import LessonIntroAndVideo from "@/src/components/lms/Lesson/LessonIntroAndVideo";
import YouWillKnowYouAreSuccessfulIf from "@/src/components/lms/Lesson/YouWillKnowYouAreSuccessfulIf";
import Docs1014 from "@/src/components/course-modules/101/Docs1014.mdx";
import module from "./module101.json";
export default function Lesson1014() {
const slug = "1014";
const lessonDetails = module.lessons.find((lesson) => lesson.slug === slug);
return (
<LessonLayout moduleNumber={101} sltId="101.4" slug="1014">
<LessonIntroAndVideo lessonData={lessonDetails} />
{lessonDetails?.success && (
<YouWillKnowYouAreSuccessfulIf criteria={lessonDetails?.success?.criteria} text={lessonDetails?.success.text} />
)}
<Docs1014 />
</LessonLayout>
);
}
🎉 Note that in this example, there is no lesson text! 🎉
We are moving toward the design of a full-fledged content-management system, and by separating content from components, we make it easier for everyone who is translating the course. However, there are still exceptions to this goal, for example see Lesson 101.1. With each iteration, we get closer to our CMS.
Note the imports at the top of each Lesson-[slug].tsx
file.
- First, we import the
LessonLayout
,LessonIntroAndVideo
andYouWillKnowYouAreSuccesfulIf
components. Please review each of these files to get familiar with the current project architecture. - Then, we import
Docs1014
andmodule101.json
. Keep reading to learn more.
.mdx files:
Docs1014
is a .mdx
file. Learn more about .mdx
here. In each .mdx
file, we can include documentation and embedded React components.
Whenever we need to embed extended documentation, we can follow this approach. Note how each .mdx
file is imported into its corresponding .tsx
file. Hopefully, this approach makes it easier for translation - let's test it.
module.json
To the extent possible, each .tsx file should be populated by data from slts-language.json
and module.json
. The module.json
file consists of a list of lessons
. Each object in lessons
looks like this:
{
"slug": "1011",
"introduction": [
"In this course, you will learn how to write smart contracts that can be used on the Cardano blockchain. In this module, we will take our first look at some of the smart contract languages on Cardano.",
"All of these languages share some basic design patterns, even though each language looks a little different.",
"All of these languages compile to Untyped Plutus Core (UPLC). UPLC can be encoded in Concise Binary Object Representation (CBOR), and this CBOR can be used on the blockchain.",
"To see what this CBOR looks like, watch this video."
],
"links": [
{ "url": "https://well-typed.com/blog/2022/08/plutus-cores/", "linkText": "Well-Typed Blog: The Plutus Compilation Pipeline" },
{ "url": "https://cbor.io/", "linkText": "About CBOR" }
],
"videoHeading": "What does it mean to \"compile a Plutus script\"?",
"youtubeId": "dDkAdzvzrbg",
"successComponent": false,
"success": {
"criteria": "you can compile a contract to UPLC from the language of your choice.",
"text": "To master this learning target, you must attempt at least one of the approaches suggested in Lessons 101.3 through 101.6. Are you ready? If so, move on to Lesson 2."
},
"assignmentComponent": true,
"markdownComponent": false
},
Let's take a look at each:
slug
: matches theslug
inslts-langugage.json
introduction
: a list of strings. Each maps to a<Text>
element in/src/components/lms/Lesson/LessonIntroAndVideo.tsx
links
: a list of objects withurl
andlinkText
params. Each maps to a<ListItem>
in/src/components/lms/Lesson/LessonIntroAndVideo.tsx
videoHeading
: a string. The<Heading>
in/src/components/lms/Lesson/VideoComponent.tsx
youtubeId
: string. The Youtube id passed to<LiteYouTubeEmbed>
in/src/components/lms/Lesson/VideoComponent.tsx
successComponent
: boolean - not yet usedsuccess
: object withcriteria
andtext
params used in/src/components/lms/Lesson/YouWillKnowYouAreSuccessfulIf.tsx
. This component is used when there is no automated mastery check.assignmentComponent
: boolean - not yet usedmarkdownComponent
: boolean - not yet used
Next Steps:
- add documentation for component in
/src/components/lms/
- if you are looking at this now, please get to know each of these. There is some good work ahead in fine tuning each, and creating new ones as needed. See Abstraction
Creating new subdirectories:
When you build lesson-specific demo components, you can create new subdirectories as needed. It was unnecessary to create any such components (yet?) in Module 101. Instead, see ContributorMinter
in Module 100