@curio-sd/e-module-builder 0.6.0 → 0.6.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,308 +1,313 @@
1
- # `@curio-sd/e-module-builder`
2
-
3
- A CLI build tool for creating interactive e-learning modules. It processes a structured `content/` directory of Markdown files and produces a Vite-powered, single-page-style site with theory pages, quizzes, exercises, and assignments — one per week.
4
-
5
- ## Installation
6
-
7
- ```bash
8
- npm install --save-dev @curio-sd/e-module-builder
9
- ```
10
-
11
- Add these scripts to your project's `package.json`:
12
-
13
- ```json
14
- {
15
- "scripts": {
16
- "dev": "e-module-builder dev",
17
- "build": "e-module-builder build",
18
- "preview": "e-module-builder preview"
19
- }
20
- }
21
- ```
22
-
23
- ## Commands
24
-
25
- | Command | Description |
26
- | ------- | ----------- |
27
- | `dev` | Start dev server at `localhost:5173`, watches `content/` and hot-reloads |
28
- | `build` | Production build to `dist/` |
29
- | `preview` | Locally preview the `dist/` build |
30
-
31
- ## Project structure
32
-
33
- Your project only needs a `content/` directory. Everything else (`src/data/`, `pages/`, `index.html`) is generated automatically.
34
-
35
- ```txt
36
- content/
37
- module.md ← module metadata (name, weeks, language, exercise mode)
38
- week1/
39
- theory.md ← theory content (Markdown + YAML frontmatter)
40
- quiz.md ← mid-week quiz questions
41
- assignment.md ← hand-in assignment
42
- exercises/
43
- _meta.md ← exercise set metadata (week, title, color)
44
- 1.md exercise 1
45
- 2.md exercise 2
46
-
47
- week2/ … weekN/ ← same structure
48
- assessments/
49
- theory-assessment.md final theory assessment (optional)
50
- practical-assessment.md final practical assessment (optional)
51
- ```
52
-
53
- ## Content file formats
54
-
55
- ### `content/module.md`
56
-
57
- ```yaml
58
- ---
59
- name: CSS Grid
60
- subtitle: E-module
61
- weeks: 4
62
- language: nl
63
- exerciseMode: interactive # or: external
64
- description: Learn CSS Grid from the ground up.
65
- youtube: https://www.youtube.com/watch?v=...
66
- logoAlt: My module logo
67
- algemeen:
68
- - I can explain the difference between Flexbox and Grid
69
- ---
70
- ```
71
-
72
- | Field | Required | Description |
73
- | ----- | -------- | ----------- |
74
- | `name` | yes | Module title |
75
- | `weeks` | yes | Number of weeks to include (limits which `weekN/` dirs are processed) |
76
- | `exerciseMode` | yes | `interactive` (Monaco editor) or `external` (link-out) |
77
- | `language` | no | UI language, default `nl` |
78
- | `subtitle` | no | Shown below the title |
79
- | `description` | no | Short module description |
80
- | `youtube` | no | Intro video URL |
81
- | `algemeen` | no | General learning outcomes added to the checklist |
82
-
83
- ---
84
-
85
- ### `content/weekN/theory.md`
86
-
87
- YAML frontmatter + Markdown body. The body supports standard Markdown, syntax-highlighted code blocks, and custom block-level elements (see [Custom elements](#custom-elements)).
88
-
89
- ```yaml
90
- ---
91
- week: 1
92
- title: The building blocks
93
- goal: You understand what CSS Grid is and when to use it.
94
- accent: indigo # Tailwind color name used as the week's accent color
95
- summary: Short summary shown on the home page.
96
- leeruitkomsten:
97
- - I can explain what a grid container is
98
- - I can define columns with grid-template-columns
99
- ---
100
-
101
- Markdown content here…
102
- ```
103
-
104
- ---
105
-
106
- ### `content/weekN/quiz.md`
107
-
108
- ```yaml
109
- ---
110
- title: Mid-week quiz — Week 1
111
- passScore: 70
112
- questions:
113
- - id: q1
114
- question: What does display:grid do?
115
- options:
116
- - Creates a flex container
117
- - Activates CSS Grid on the element
118
- correct: 1
119
- explanation: display:grid activates CSS Grid.
120
- ---
121
- ```
122
-
123
- ---
124
-
125
- ### `content/weekN/assignment.md`
126
-
127
- The Markdown **body** is split on blank lines: the first paragraph becomes the `case`, the rest becomes the `assignment` description.
128
-
129
- ```yaml
130
- ---
131
- week: 1
132
- title: Build a page layout
133
- subtitle: Practical assignment
134
- deliverables:
135
- - A working HTML/CSS page
136
- criteria:
137
- - Grid is used for the overall layout
138
- maxPoints: 10
139
- tips:
140
- - Start with the grid container
141
- ---
142
-
143
- Case description paragraph.
144
-
145
- Assignment instructions paragraph.
146
- ```
147
-
148
- ---
149
-
150
- ### `content/weekN/exercises/_meta.md`
151
-
152
- ```yaml
153
- ---
154
- week: 1
155
- title: CSS Grid exercises
156
- color: indigo
157
- mode: interactive # optional, overrides module-level exerciseMode for this set
158
- ---
159
- ```
160
-
161
- ---
162
-
163
- ### `content/weekN/exercises/N.md`
164
-
165
- Each file is a single exercise. The YAML frontmatter holds metadata; for text exercises the markdown **body** (content below the frontmatter) is rendered as the exercise content.
166
-
167
- **Text exercise with markdown body (recommended for rich content):**
168
-
169
- ```markdown
170
- ---
171
- id: 1
172
- difficulty: 1
173
- title: Columns
174
- type: text
175
- ---
176
-
177
- Create a grid with **two equal columns** using `grid-template-columns`.
178
-
179
- ## Tips
180
-
181
- - Use `repeat(2, 1fr)` for equal columns.
182
- - `fr` stands for _fractional unit_.
183
- ```
184
-
185
- The body can contain any markdown: headings, bold/italic, lists, images, code blocks, and [custom elements](#custom-elements-in-markdown). No CSS playground or external link is needed — teachers can write the full exercise content as plain markdown.
186
-
187
- **Shorthand (inline description in YAML, for very short exercises):**
188
-
189
- ```yaml
190
- ---
191
- type: text
192
- title: Columns
193
- description: Create a grid with two equal columns.
194
- ---
195
- ```
196
-
197
- When both a body and a `description` field are present the body takes precedence.
198
-
199
- **Linking theory pages (optional):**
200
-
201
- Use `linked_theory` to attach one or more theory pages to an exercise. A collapsible panel slides in from the right with a tab per week, embedding the theory page so students can look up content without leaving the exercise.
202
-
203
- ```yaml
204
- ---
205
- id: 3
206
- type: text
207
- title: Columns
208
- linked_theory:
209
- - week1
210
- - week2
211
- ---
212
- ```
213
-
214
- | Field | Required | Description |
215
- | ----- | -------- | ----------- |
216
- | `linked_theory` | no | List of week identifiers (e.g. `week1`). Renders a collapsible right-side panel with tabbed iframes — one per linked week. When absent, no panel or toggle button is shown. Theory pages load without their own navbar inside the panel. |
217
-
218
- ---
219
-
220
- **Interactive (Monaco editor) exercise:**
221
-
222
- ```yaml
223
- ---
224
- type: interactive
225
- title: Add a gap
226
- starterHtml: "<div class='grid'>…</div>"
227
- starterCss: ".grid { display: grid; }"
228
- solution: ".grid { display: grid; gap: 16px; }"
229
- ---
230
- ```
231
-
232
- **External exercise (link-out):**
233
-
234
- ```yaml
235
- ---
236
- type: external
237
- title: Grid Garden
238
- url: https://cssgridgarden.com
239
- ---
240
- ```
241
-
242
- ---
243
-
244
- ### `content/assessments/theory-assessment.md` and `practical-assessment.md`
245
-
246
- Same structure as `quiz.md`. Practical assessment questions may include a `preview` field with `css` and `html` for a live CSS preview alongside the question.
247
-
248
- ---
249
-
250
- ## Custom elements in Markdown
251
-
252
- Theory pages support these custom block elements in Markdown:
253
-
254
- | Element | Purpose |
255
- | ------- | ------- |
256
- | `<x-callout>` | Highlighted note block. Add `type="warning"` for warnings. |
257
- | `<x-card title="…">` | Content card with a title. |
258
- | `<x-compare>` / `<x-compare-item title="…">` | Side-by-side comparison columns. |
259
- | `<x-nav label="…">` | Bottom navigation links (one Markdown link per line). |
260
-
261
- Example:
262
-
263
- ```markdown
264
- <x-callout type="warning">
265
- Watch out: only **direct children** of the grid container become grid items.
266
- </x-callout>
267
-
268
- <x-compare>
269
- <x-compare-item title="Flexbox — one direction">
270
-
271
- Use for components: navbars, button rows.
272
-
273
- </x-compare-item>
274
- <x-compare-item title="Gridtwo directions">
275
-
276
- Use for full page layouts.
277
-
278
- </x-compare-item>
279
- </x-compare>
280
- ```
281
-
282
- ---
283
-
284
- ## What gets generated
285
-
286
- The build pipeline runs before Vite and produces:
287
-
288
- | Output | Source |
289
- | ------ | ------ |
290
- | `src/data/manifest.json` | `module.md` + all week frontmatter |
291
- | `src/data/theory-weekN.json` | `weekN/theory.md` |
292
- | `src/data/meetmoment-quiz-weekN.json` | `weekN/quiz.md` |
293
- | `src/data/exercises/weekN.json` | `weekN/exercises/` |
294
- | `src/data/inleveropdracht-weekN.json` | `weekN/assignment.md` |
295
- | `src/data/checklist.json` | `leeruitkomsten` from all weeks |
296
- | `src/data/meetmoment-theorie.json` | `assessments/theory-assessment.md` |
297
- | `src/data/meetmoment-praktijk.json` | `assessments/practical-assessment.md` |
298
- | `pages/weekN-theorie.html` | generated from template |
299
- | `pages/weekN-oefeningen.html` | generated from template |
300
- | `pages/weekN-meetmoment.html` | generated from template |
301
- | `pages/weekN-oefening.html` | generated from template |
302
- | `pages/weekN-inleveropdracht.html` | generated from template |
303
- | `pages/checklist.html` | generated from template |
304
- | `pages/meetmoment-theorie.html` | generated from template |
305
- | `pages/meetmoment-praktijk.html` | generated from template |
306
- | `index.html` | generated from template |
307
-
308
- In `dev` mode, changes to `content/` trigger an automatic rebuild and browser reload.
1
+ # `@curio-sd/e-module-builder`
2
+
3
+ A CLI build tool for creating interactive e-learning modules. It processes a structured `content/` directory of Markdown files and produces a Vite-powered, single-page-style site with theory pages, quizzes, exercises, and assignments — one per week.
4
+
5
+
6
+ > [!IMPORTANT]
7
+ > If you want to use the template for your own e-module, please go to https://github.com/curio-team/e-module-template and press 'Use this template' on the right.
8
+
9
+
10
+ ## Installation
11
+
12
+ ```bash
13
+ npm install --save-dev @curio-sd/e-module-builder
14
+ ```
15
+
16
+ Add these scripts to your project's `package.json`:
17
+
18
+ ```json
19
+ {
20
+ "scripts": {
21
+ "dev": "e-module-builder dev",
22
+ "build": "e-module-builder build",
23
+ "preview": "e-module-builder preview"
24
+ }
25
+ }
26
+ ```
27
+
28
+ ## Commands
29
+
30
+ | Command | Description |
31
+ | ------- | ----------- |
32
+ | `dev` | Start dev server at `localhost:5173`, watches `content/` and hot-reloads |
33
+ | `build` | Production build to `dist/` |
34
+ | `preview` | Locally preview the `dist/` build |
35
+
36
+ ## Project structure
37
+
38
+ Your project only needs a `content/` directory. Everything else (`src/data/`, `pages/`, `index.html`) is generated automatically.
39
+
40
+ ```txt
41
+ content/
42
+ module.md ← module metadata (name, weeks, language, exercise mode)
43
+ week1/
44
+ theory.md theory content (Markdown + YAML frontmatter)
45
+ quiz.md mid-week quiz questions
46
+ assignment.md ← hand-in assignment
47
+ exercises/
48
+ _meta.md ← exercise set metadata (week, title, color)
49
+ 1.md exercise 1
50
+ 2.md exercise 2
51
+
52
+ week2/ … weekN/ ← same structure
53
+ assessments/
54
+ theory-assessment.md ← final theory assessment (optional)
55
+ practical-assessment.md ← final practical assessment (optional)
56
+ ```
57
+
58
+ ## Content file formats
59
+
60
+ ### `content/module.md`
61
+
62
+ ```yaml
63
+ ---
64
+ name: CSS Grid
65
+ subtitle: E-module
66
+ weeks: 4
67
+ language: nl
68
+ exerciseMode: interactive # or: external
69
+ description: Learn CSS Grid from the ground up.
70
+ youtube: https://www.youtube.com/watch?v=...
71
+ logoAlt: My module logo
72
+ algemeen:
73
+ - I can explain the difference between Flexbox and Grid
74
+ ---
75
+ ```
76
+
77
+ | Field | Required | Description |
78
+ | ----- | -------- | ----------- |
79
+ | `name` | yes | Module title |
80
+ | `weeks` | yes | Number of weeks to include (limits which `weekN/` dirs are processed) |
81
+ | `exerciseMode` | yes | `interactive` (Monaco editor) or `external` (link-out) |
82
+ | `language` | no | UI language, default `nl` |
83
+ | `subtitle` | no | Shown below the title |
84
+ | `description` | no | Short module description |
85
+ | `youtube` | no | Intro video URL |
86
+ | `algemeen` | no | General learning outcomes added to the checklist |
87
+
88
+ ---
89
+
90
+ ### `content/weekN/theory.md`
91
+
92
+ YAML frontmatter + Markdown body. The body supports standard Markdown, syntax-highlighted code blocks, and custom block-level elements (see [Custom elements](#custom-elements)).
93
+
94
+ ```yaml
95
+ ---
96
+ week: 1
97
+ title: The building blocks
98
+ goal: You understand what CSS Grid is and when to use it.
99
+ accent: indigo # Tailwind color name used as the week's accent color
100
+ summary: Short summary shown on the home page.
101
+ leeruitkomsten:
102
+ - I can explain what a grid container is
103
+ - I can define columns with grid-template-columns
104
+ ---
105
+
106
+ Markdown content here…
107
+ ```
108
+
109
+ ---
110
+
111
+ ### `content/weekN/quiz.md`
112
+
113
+ ```yaml
114
+ ---
115
+ title: Mid-week quiz — Week 1
116
+ passScore: 70
117
+ questions:
118
+ - id: q1
119
+ question: What does display:grid do?
120
+ options:
121
+ - Creates a flex container
122
+ - Activates CSS Grid on the element
123
+ correct: 1
124
+ explanation: display:grid activates CSS Grid.
125
+ ---
126
+ ```
127
+
128
+ ---
129
+
130
+ ### `content/weekN/assignment.md`
131
+
132
+ The Markdown **body** is split on blank lines: the first paragraph becomes the `case`, the rest becomes the `assignment` description.
133
+
134
+ ```yaml
135
+ ---
136
+ week: 1
137
+ title: Build a page layout
138
+ subtitle: Practical assignment
139
+ deliverables:
140
+ - A working HTML/CSS page
141
+ criteria:
142
+ - Grid is used for the overall layout
143
+ maxPoints: 10
144
+ tips:
145
+ - Start with the grid container
146
+ ---
147
+
148
+ Case description paragraph.
149
+
150
+ Assignment instructions paragraph.
151
+ ```
152
+
153
+ ---
154
+
155
+ ### `content/weekN/exercises/_meta.md`
156
+
157
+ ```yaml
158
+ ---
159
+ week: 1
160
+ title: CSS Grid exercises
161
+ color: indigo
162
+ mode: interactive # optional, overrides module-level exerciseMode for this set
163
+ ---
164
+ ```
165
+
166
+ ---
167
+
168
+ ### `content/weekN/exercises/N.md`
169
+
170
+ Each file is a single exercise. The YAML frontmatter holds metadata; for text exercises the markdown **body** (content below the frontmatter) is rendered as the exercise content.
171
+
172
+ **Text exercise with markdown body (recommended for rich content):**
173
+
174
+ ```markdown
175
+ ---
176
+ id: 1
177
+ difficulty: 1
178
+ title: Columns
179
+ type: text
180
+ ---
181
+
182
+ Create a grid with **two equal columns** using `grid-template-columns`.
183
+
184
+ ## Tips
185
+
186
+ - Use `repeat(2, 1fr)` for equal columns.
187
+ - `fr` stands for _fractional unit_.
188
+ ```
189
+
190
+ The body can contain any markdown: headings, bold/italic, lists, images, code blocks, and [custom elements](#custom-elements-in-markdown). No CSS playground or external link is needed — teachers can write the full exercise content as plain markdown.
191
+
192
+ **Shorthand (inline description in YAML, for very short exercises):**
193
+
194
+ ```yaml
195
+ ---
196
+ type: text
197
+ title: Columns
198
+ description: Create a grid with two equal columns.
199
+ ---
200
+ ```
201
+
202
+ When both a body and a `description` field are present the body takes precedence.
203
+
204
+ **Linking theory pages (optional):**
205
+
206
+ Use `linked_theory` to attach one or more theory pages to an exercise. A collapsible panel slides in from the right with a tab per week, embedding the theory page so students can look up content without leaving the exercise.
207
+
208
+ ```yaml
209
+ ---
210
+ id: 3
211
+ type: text
212
+ title: Columns
213
+ linked_theory:
214
+ - week1
215
+ - week2
216
+ ---
217
+ ```
218
+
219
+ | Field | Required | Description |
220
+ | ----- | -------- | ----------- |
221
+ | `linked_theory` | no | List of week identifiers (e.g. `week1`). Renders a collapsible right-side panel with tabbed iframes — one per linked week. When absent, no panel or toggle button is shown. Theory pages load without their own navbar inside the panel. |
222
+
223
+ ---
224
+
225
+ **Interactive (Monaco editor) exercise:**
226
+
227
+ ```yaml
228
+ ---
229
+ type: interactive
230
+ title: Add a gap
231
+ starterHtml: "<div class='grid'>…</div>"
232
+ starterCss: ".grid { display: grid; }"
233
+ solution: ".grid { display: grid; gap: 16px; }"
234
+ ---
235
+ ```
236
+
237
+ **External exercise (link-out):**
238
+
239
+ ```yaml
240
+ ---
241
+ type: external
242
+ title: Grid Garden
243
+ url: https://cssgridgarden.com
244
+ ---
245
+ ```
246
+
247
+ ---
248
+
249
+ ### `content/assessments/theory-assessment.md` and `practical-assessment.md`
250
+
251
+ Same structure as `quiz.md`. Practical assessment questions may include a `preview` field with `css` and `html` for a live CSS preview alongside the question.
252
+
253
+ ---
254
+
255
+ ## Custom elements in Markdown
256
+
257
+ Theory pages support these custom block elements in Markdown:
258
+
259
+ | Element | Purpose |
260
+ | ------- | ------- |
261
+ | `<x-callout>` | Highlighted note block. Add `type="warning"` for warnings. |
262
+ | `<x-card title="…">` | Content card with a title. |
263
+ | `<x-compare>` / `<x-compare-item title="…">` | Side-by-side comparison columns. |
264
+ | `<x-nav label="">` | Bottom navigation links (one Markdown link per line). |
265
+
266
+ Example:
267
+
268
+ ```markdown
269
+ <x-callout type="warning">
270
+ Watch out: only **direct children** of the grid container become grid items.
271
+ </x-callout>
272
+
273
+ <x-compare>
274
+ <x-compare-item title="Flexboxone direction">
275
+
276
+ Use for components: navbars, button rows.
277
+
278
+ </x-compare-item>
279
+ <x-compare-item title="Grid — two directions">
280
+
281
+ Use for full page layouts.
282
+
283
+ </x-compare-item>
284
+ </x-compare>
285
+ ```
286
+
287
+ ---
288
+
289
+ ## What gets generated
290
+
291
+ The build pipeline runs before Vite and produces:
292
+
293
+ | Output | Source |
294
+ | ------ | ------ |
295
+ | `src/data/manifest.json` | `module.md` + all week frontmatter |
296
+ | `src/data/theory-weekN.json` | `weekN/theory.md` |
297
+ | `src/data/meetmoment-quiz-weekN.json` | `weekN/quiz.md` |
298
+ | `src/data/exercises/weekN.json` | `weekN/exercises/` |
299
+ | `src/data/inleveropdracht-weekN.json` | `weekN/assignment.md` |
300
+ | `src/data/checklist.json` | `leeruitkomsten` from all weeks |
301
+ | `src/data/meetmoment-theorie.json` | `assessments/theory-assessment.md` |
302
+ | `src/data/meetmoment-praktijk.json` | `assessments/practical-assessment.md` |
303
+ | `pages/weekN-theorie.html` | generated from template |
304
+ | `pages/weekN-oefeningen.html` | generated from template |
305
+ | `pages/weekN-meetmoment.html` | generated from template |
306
+ | `pages/weekN-oefening.html` | generated from template |
307
+ | `pages/weekN-inleveropdracht.html` | generated from template |
308
+ | `pages/checklist.html` | generated from template |
309
+ | `pages/meetmoment-theorie.html` | generated from template |
310
+ | `pages/meetmoment-praktijk.html` | generated from template |
311
+ | `index.html` | generated from template |
312
+
313
+ In `dev` mode, changes to `content/` trigger an automatic rebuild and browser reload.
package/build-pdf.mjs CHANGED
@@ -1,6 +1,6 @@
1
1
  import fs from 'fs'
2
2
  import path from 'path'
3
- import matter from 'gray-matter'
3
+ import matter from '@11ty/gray-matter'
4
4
  import { Marked } from 'marked'
5
5
  import PDFDocument from 'pdfkit'
6
6
 
package/build.mjs CHANGED
@@ -1,7 +1,7 @@
1
1
  import fs from 'fs'
2
2
  import path from 'path'
3
3
  import { fileURLToPath } from 'url'
4
- import matter from 'gray-matter'
4
+ import matter from '@11ty/gray-matter'
5
5
  import { Marked } from 'marked'
6
6
  import { markedHighlight } from "marked-highlight";
7
7
  import hljs from 'highlight.js';
@@ -167,8 +167,8 @@ for (const weekDir of activeWeeks) {
167
167
  }
168
168
  ex.descriptionInlineHtml = marked.parseInline(ex.description ?? '')
169
169
  if (ex.type === 'external') {
170
- if (ex.task) ex.taskHtml = marked.parseInline(ex.task)
171
- if (ex.hint) ex.hintHtml = marked.parse(ex.hint)
170
+ if (ex.task) ex.taskHtml = marked.parseInline(ex.task)
171
+ if (ex.hint) ex.hintHtml = marked.parse(ex.hint)
172
172
  if (ex.solution) ex.solutionHtml = marked.parse(ex.solution)
173
173
  }
174
174
  return ex
@@ -242,7 +242,7 @@ function buildPracticalAssessmentData(filePath, fallbackTitle, fallbackNavLabel)
242
242
  title: md.data.title ?? fallbackTitle,
243
243
  navLabel: md.data.navLabel ?? fallbackNavLabel,
244
244
  description: marked.parseInline(md.data.description ?? ''),
245
- html: marked.parse(md.content ?? ''),
245
+ html: rewriteAssetPaths(marked.parse(md.content ?? ''), 'assessments'),
246
246
  }
247
247
  }
248
248
  return { title: fallbackTitle, navLabel: fallbackNavLabel, description: '', html: '' }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@curio-sd/e-module-builder",
3
- "version": "0.6.0",
3
+ "version": "0.6.1",
4
4
  "type": "module",
5
5
  "description": "A tool for building e-modules for Curio SD",
6
6
  "license": "MIT",
@@ -25,8 +25,8 @@
25
25
  "test:watch": "vitest"
26
26
  },
27
27
  "dependencies": {
28
+ "@11ty/gray-matter": "^2.1.0",
28
29
  "@tailwindcss/vite": "^4.1.8",
29
- "gray-matter": "^4.0.3",
30
30
  "highlight.js": "^11.11.1",
31
31
  "marked": "^18.0.5",
32
32
  "marked-highlight": "^2.2.4",