@curio-sd/e-module-builder 0.1.0
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/LICENSE +7 -0
- package/bin/cli.js +83 -0
- package/build.mjs +339 -0
- package/package.json +29 -0
- package/public/Logo Schaalbaar (1).svg +293 -0
- package/public/favicon.svg +6 -0
- package/public/logo.svg +293 -0
- package/src/css/main.css +283 -0
- package/src/js/checklist.js +99 -0
- package/src/js/exercises/exercise-runner.js +184 -0
- package/src/js/exercises/exercise-shared.js +37 -0
- package/src/js/exercises/external-exercise.js +71 -0
- package/src/js/exercises/hub.js +57 -0
- package/src/js/exercises/load-exercise.js +309 -0
- package/src/js/exercises/validators.js +53 -0
- package/src/js/home.js +86 -0
- package/src/js/layout.js +42 -0
- package/src/js/monaco-setup.js +49 -0
- package/src/js/nav.js +165 -0
- package/src/js/quiz.js +111 -0
- package/src/js/site-path.js +18 -0
- package/src/js/storage.js +51 -0
- package/src/js/theory.js +41 -0
- package/src/js/thuiswerk.js +161 -0
- package/src/partials/head.html +6 -0
- package/templates/index.html +181 -0
- package/templates/page.html +29 -0
- package/templates/pages/checklist.html +37 -0
- package/templates/pages/inleveropdracht.html +28 -0
- package/templates/pages/oefening.html +158 -0
- package/templates/pages/oefeningen.html +44 -0
- package/templates/pages/theorie.html +22 -0
- package/templates/pages/toets-praktijk.html +25 -0
- package/templates/pages/toets-theorie.html +25 -0
- package/templates/pages/toets.html +33 -0
- package/vite-plugin-html-includes.js +23 -0
- package/vite.config.js +42 -0
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="nl">
|
|
3
|
+
|
|
4
|
+
<head>
|
|
5
|
+
<!-- include:head -->
|
|
6
|
+
|
|
7
|
+
<title data-home-document-title>{{pageTitle}}</title>
|
|
8
|
+
</head>
|
|
9
|
+
|
|
10
|
+
<body class="font-sans antialiased">
|
|
11
|
+
<div data-page-content>
|
|
12
|
+
<main class="px-4 py-10 md:px-10 md:py-14">
|
|
13
|
+
<div class="mx-auto max-w-5xl">
|
|
14
|
+
<div class="mb-12 max-w-2xl">
|
|
15
|
+
<p class="text-[11px] font-semibold uppercase tracking-[0.2em] text-zinc-400"
|
|
16
|
+
data-home-label>E-module</p>
|
|
17
|
+
|
|
18
|
+
<h1 class="mt-3 text-4xl font-semibold tracking-tight text-zinc-900 md:text-5xl"
|
|
19
|
+
data-home-title>
|
|
20
|
+
{{pageTitle}}
|
|
21
|
+
</h1>
|
|
22
|
+
|
|
23
|
+
<p class="mt-4 text-lg leading-relaxed text-zinc-500"
|
|
24
|
+
data-home-description>
|
|
25
|
+
Welkom bij deze e-module.
|
|
26
|
+
</p>
|
|
27
|
+
</div>
|
|
28
|
+
|
|
29
|
+
<div data-home-setup
|
|
30
|
+
class="mb-12 space-y-8">
|
|
31
|
+
<div class="card border-l-4 border-l-zinc-300 bg-zinc-50">
|
|
32
|
+
<p class="text-[11px] font-semibold uppercase tracking-[0.18em] text-zinc-400">Aan de slag</p>
|
|
33
|
+
|
|
34
|
+
<h2 class="mt-1 text-xl font-medium text-zinc-900">Content toevoegen</h2>
|
|
35
|
+
|
|
36
|
+
<p class="mt-3 text-sm leading-relaxed text-zinc-600">
|
|
37
|
+
Vul de map <code class="rounded bg-zinc-100 px-1.5 py-0.5 font-mono text-xs">content/</code> met jouw module-inhoud en bouw de site opnieuw.
|
|
38
|
+
</p>
|
|
39
|
+
|
|
40
|
+
<ol class="mt-6 space-y-6">
|
|
41
|
+
<li class="flex gap-4">
|
|
42
|
+
<span class="flex h-7 w-7 shrink-0 items-center justify-center rounded-full bg-zinc-900 font-mono text-xs text-white">1</span>
|
|
43
|
+
|
|
44
|
+
<div>
|
|
45
|
+
<p class="font-medium text-zinc-900">Module-metadata instellen</p>
|
|
46
|
+
|
|
47
|
+
<p class="mt-1 text-sm text-zinc-500">
|
|
48
|
+
Bewerk <code class="font-mono text-xs">content/module.md</code> — stel naam, aantal weken, taal en oefenmodus in.
|
|
49
|
+
</p>
|
|
50
|
+
</div>
|
|
51
|
+
</li>
|
|
52
|
+
|
|
53
|
+
<li class="flex gap-4">
|
|
54
|
+
<span class="flex h-7 w-7 shrink-0 items-center justify-center rounded-full bg-zinc-900 font-mono text-xs text-white">2</span>
|
|
55
|
+
|
|
56
|
+
<div>
|
|
57
|
+
<p class="font-medium text-zinc-900">Weekcontent schrijven</p>
|
|
58
|
+
|
|
59
|
+
<p class="mt-1 text-sm text-zinc-500">
|
|
60
|
+
Maak per week een map <code class="font-mono text-xs">content/week1/</code> enz. met
|
|
61
|
+
<code class="font-mono text-xs">theory.md</code>,
|
|
62
|
+
<code class="font-mono text-xs">quiz.md</code>,
|
|
63
|
+
<code class="font-mono text-xs">exercises.md</code> en
|
|
64
|
+
<code class="font-mono text-xs">homework.md</code>.
|
|
65
|
+
</p>
|
|
66
|
+
</div>
|
|
67
|
+
</li>
|
|
68
|
+
|
|
69
|
+
<li class="flex gap-4">
|
|
70
|
+
<span class="flex h-7 w-7 shrink-0 items-center justify-center rounded-full bg-zinc-900 font-mono text-xs text-white">3</span>
|
|
71
|
+
|
|
72
|
+
<div>
|
|
73
|
+
<p class="font-medium text-zinc-900">Eindtoetsen toevoegen (optioneel)</p>
|
|
74
|
+
|
|
75
|
+
<p class="mt-1 text-sm text-zinc-500">
|
|
76
|
+
Plaats <code class="font-mono text-xs">content/exams/theory-exam.md</code> en
|
|
77
|
+
<code class="font-mono text-xs">practical-exam.md</code> met vragen in YAML frontmatter.
|
|
78
|
+
</p>
|
|
79
|
+
</div>
|
|
80
|
+
</li>
|
|
81
|
+
|
|
82
|
+
<li class="flex gap-4">
|
|
83
|
+
<span class="flex h-7 w-7 shrink-0 items-center justify-center rounded-full bg-zinc-900 font-mono text-xs text-white">4</span>
|
|
84
|
+
|
|
85
|
+
<div>
|
|
86
|
+
<p class="font-medium text-zinc-900">Bouwen en bekijken</p>
|
|
87
|
+
|
|
88
|
+
<pre class="code-block mt-2 text-sm"><code>npm run dev # ontwikkelserver
|
|
89
|
+
npm run build # productie-build
|
|
90
|
+
npm run preview # preview van dist/</code></pre>
|
|
91
|
+
</div>
|
|
92
|
+
</li>
|
|
93
|
+
</ol>
|
|
94
|
+
</div>
|
|
95
|
+
</div>
|
|
96
|
+
|
|
97
|
+
<div data-home-ready
|
|
98
|
+
class="hidden">
|
|
99
|
+
<div class="card mb-12">
|
|
100
|
+
<div class="mb-4 flex items-end justify-between">
|
|
101
|
+
<div>
|
|
102
|
+
<p class="text-[11px] font-semibold uppercase tracking-[0.18em] text-zinc-400">Voortgang</p>
|
|
103
|
+
|
|
104
|
+
<h2 class="mt-1 font-medium text-zinc-900">Skills checklist</h2>
|
|
105
|
+
</div>
|
|
106
|
+
|
|
107
|
+
<span data-progress-label
|
|
108
|
+
class="font-mono text-sm text-zinc-900">0%</span>
|
|
109
|
+
</div>
|
|
110
|
+
|
|
111
|
+
<div class="progress-track">
|
|
112
|
+
<div data-progress-bar
|
|
113
|
+
class="progress-fill"
|
|
114
|
+
style="width: 0%"></div>
|
|
115
|
+
</div>
|
|
116
|
+
|
|
117
|
+
<p class="mt-3 text-sm text-zinc-500">
|
|
118
|
+
<a href="pages/checklist.html"
|
|
119
|
+
class="text-link">Bekijk checklist</a>
|
|
120
|
+
</p>
|
|
121
|
+
</div>
|
|
122
|
+
|
|
123
|
+
<p class="mb-6 text-[11px] font-semibold uppercase tracking-[0.18em] text-zinc-400">Curriculum</p>
|
|
124
|
+
|
|
125
|
+
<div class="mb-14 grid gap-px bg-zinc-200 sm:grid-cols-2"
|
|
126
|
+
data-home-curriculum></div>
|
|
127
|
+
|
|
128
|
+
<p class="mb-6 text-[11px] font-semibold uppercase tracking-[0.18em] text-zinc-400">Eindtoets</p>
|
|
129
|
+
|
|
130
|
+
<div class="grid gap-px bg-zinc-200 sm:grid-cols-3">
|
|
131
|
+
<a href="pages/checklist.html"
|
|
132
|
+
class="card-interactive block bg-white">
|
|
133
|
+
|
|
134
|
+
<h3 class="font-medium text-zinc-900">Skills checklist</h3>
|
|
135
|
+
|
|
136
|
+
<p class="mt-1 text-sm text-zinc-500">Houd je voortgang bij</p>
|
|
137
|
+
</a>
|
|
138
|
+
|
|
139
|
+
<a href="pages/toets-theorie.html"
|
|
140
|
+
class="card-interactive block bg-white">
|
|
141
|
+
<h3 class="font-medium text-zinc-900">Eindtoets theorie</h3>
|
|
142
|
+
|
|
143
|
+
<p class="mt-1 text-sm text-zinc-500">Meerkeuzevragen</p>
|
|
144
|
+
</a>
|
|
145
|
+
|
|
146
|
+
<a href="pages/toets-praktijk.html"
|
|
147
|
+
class="card-interactive block bg-white">
|
|
148
|
+
<h3 class="font-medium text-zinc-900">Eindtoets praktijk</h3>
|
|
149
|
+
|
|
150
|
+
<p class="mt-1 text-sm text-zinc-500">Praktijkvragen</p>
|
|
151
|
+
</a>
|
|
152
|
+
</div>
|
|
153
|
+
</div>
|
|
154
|
+
</div>
|
|
155
|
+
</main>
|
|
156
|
+
</div>
|
|
157
|
+
|
|
158
|
+
<script type="module">
|
|
159
|
+
import { initPage } from '/src/js/nav.js'
|
|
160
|
+
import { initHome } from '/src/js/home.js'
|
|
161
|
+
import { getChecklistProgress } from '/src/js/storage.js'
|
|
162
|
+
import checklistData from '/src/data/checklist.json'
|
|
163
|
+
import manifest from '/src/data/manifest.json'
|
|
164
|
+
|
|
165
|
+
document.title = `${manifest.module.name} ${manifest.module.subtitle}`
|
|
166
|
+
|
|
167
|
+
initPage({ breadcrumbs: [{ label: 'Home' }] })
|
|
168
|
+
initHome()
|
|
169
|
+
|
|
170
|
+
const ready = manifest.content?.status === 'generated'
|
|
171
|
+
|
|
172
|
+
if (ready) {
|
|
173
|
+
const { percent } = getChecklistProgress(checklistData)
|
|
174
|
+
|
|
175
|
+
document.querySelector('[data-progress-bar]').style.width = `${percent}%`
|
|
176
|
+
document.querySelector('[data-progress-label]').textContent = `${percent}%`
|
|
177
|
+
}
|
|
178
|
+
</script>
|
|
179
|
+
</body>
|
|
180
|
+
|
|
181
|
+
</html>
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="nl">
|
|
3
|
+
<head>
|
|
4
|
+
<!-- include:head -->
|
|
5
|
+
<title>Paginatitel — CSS Grid E-module</title>
|
|
6
|
+
</head>
|
|
7
|
+
<body class="font-sans antialiased">
|
|
8
|
+
<div data-page-content>
|
|
9
|
+
<main class="px-4 py-10 md:px-10">
|
|
10
|
+
<div class="mx-auto max-w-3xl">
|
|
11
|
+
<!-- Pagina-inhoud -->
|
|
12
|
+
</div>
|
|
13
|
+
</main>
|
|
14
|
+
</div>
|
|
15
|
+
|
|
16
|
+
<script type="module">
|
|
17
|
+
import { initPage } from '/src/js/nav.js'
|
|
18
|
+
|
|
19
|
+
initPage({
|
|
20
|
+
breadcrumbs: [
|
|
21
|
+
{ label: 'Home', href: '/index.html' },
|
|
22
|
+
{ label: 'Titel' },
|
|
23
|
+
],
|
|
24
|
+
})
|
|
25
|
+
|
|
26
|
+
// Optioneel: pagina-specifieke JS importeren
|
|
27
|
+
</script>
|
|
28
|
+
</body>
|
|
29
|
+
</html>
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="nl">
|
|
3
|
+
<head>
|
|
4
|
+
<!-- include:head -->
|
|
5
|
+
<title>{{pageTitle}}</title>
|
|
6
|
+
</head>
|
|
7
|
+
<body class="font-sans antialiased">
|
|
8
|
+
<div data-page-content>
|
|
9
|
+
<main class="px-4 py-10 md:px-10">
|
|
10
|
+
<div class="mx-auto max-w-3xl">
|
|
11
|
+
<div class="mb-8">
|
|
12
|
+
<h1 class="text-3xl font-semibold tracking-tight text-zinc-900">Skills Checklist</h1>
|
|
13
|
+
<p class="mt-2 text-zinc-600">Vink af wat je beheerst. Je voortgang wordt lokaal opgeslagen in je browser.</p>
|
|
14
|
+
</div>
|
|
15
|
+
<div class="card mb-8">
|
|
16
|
+
<div class="mb-2 flex items-center justify-between">
|
|
17
|
+
<span class="text-sm font-medium text-zinc-700">Voortgang</span>
|
|
18
|
+
<span data-checklist-progress-label class="text-sm font-mono text-zinc-900">0 / 0 (0%)</span>
|
|
19
|
+
</div>
|
|
20
|
+
<div class="progress-track">
|
|
21
|
+
<div data-checklist-progress class="progress-fill" style="width: 0%"></div>
|
|
22
|
+
</div>
|
|
23
|
+
<button data-export-checklist type="button" class="btn-secondary mt-4">Exporteer naar klembord</button>
|
|
24
|
+
</div>
|
|
25
|
+
<div data-checklist class="space-y-6"></div>
|
|
26
|
+
</div>
|
|
27
|
+
</main>
|
|
28
|
+
</div>
|
|
29
|
+
<script type="module">
|
|
30
|
+
import { initPage } from '/src/js/nav.js'
|
|
31
|
+
import { initChecklist, initChecklistExport } from '/src/js/checklist.js'
|
|
32
|
+
initPage({ breadcrumbs: [{ label: 'Home', href: '/index.html' }, { label: 'Checklist' }] })
|
|
33
|
+
initChecklist()
|
|
34
|
+
initChecklistExport()
|
|
35
|
+
</script>
|
|
36
|
+
</body>
|
|
37
|
+
</html>
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="nl">
|
|
3
|
+
<head>
|
|
4
|
+
<!-- include:head -->
|
|
5
|
+
<title>{{pageTitle}}</title>
|
|
6
|
+
</head>
|
|
7
|
+
<body class="font-sans antialiased">
|
|
8
|
+
<div data-page-content>
|
|
9
|
+
<main class="px-4 py-10 md:px-10">
|
|
10
|
+
<div class="mx-auto max-w-3xl">
|
|
11
|
+
<span class="week-label">Week {{weekPadded}} — Inleveropdracht</span>
|
|
12
|
+
<h1 class="text-3xl font-semibold tracking-tight text-zinc-900" data-thuiswerk-title></h1>
|
|
13
|
+
<p class="mt-2 text-zinc-600">Werk de casus uit en lever in via het kanaal van je docent.</p>
|
|
14
|
+
<div data-thuiswerk class="mt-8"></div>
|
|
15
|
+
</div>
|
|
16
|
+
</main>
|
|
17
|
+
</div>
|
|
18
|
+
<script type="module">
|
|
19
|
+
import { initPage } from '/src/js/nav.js'
|
|
20
|
+
import { initThuiswerk } from '/src/js/thuiswerk.js'
|
|
21
|
+
import thuiswerkData from '/src/data/thuiswerk-week{{week}}.json'
|
|
22
|
+
initPage({ breadcrumbs: [{ label: 'Home', href: '/index.html' }, { label: 'Week {{week}}', href: '/pages/week{{week}}-theorie.html' }, { label: 'Inleveropdracht' }] })
|
|
23
|
+
const titleEl = document.querySelector('[data-thuiswerk-title]')
|
|
24
|
+
if (titleEl) titleEl.textContent = thuiswerkData.title
|
|
25
|
+
initThuiswerk(thuiswerkData)
|
|
26
|
+
</script>
|
|
27
|
+
</body>
|
|
28
|
+
</html>
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="nl">
|
|
3
|
+
|
|
4
|
+
<head>
|
|
5
|
+
<!-- include:head -->
|
|
6
|
+
<title>{{pageTitle}}</title>
|
|
7
|
+
</head>
|
|
8
|
+
|
|
9
|
+
<body class="font-sans antialiased">
|
|
10
|
+
<div data-page-content>
|
|
11
|
+
<main class="px-4 py-10 md:px-10"
|
|
12
|
+
data-exercise-content>
|
|
13
|
+
<div class="mx-auto max-w-6xl">
|
|
14
|
+
<div class="mb-6 flex flex-wrap items-center justify-between gap-4">
|
|
15
|
+
<div>
|
|
16
|
+
<span data-difficulty
|
|
17
|
+
class="badge mb-2 block"></span>
|
|
18
|
+
<h1 data-exercise-title
|
|
19
|
+
class="text-2xl font-bold text-zinc-900 md:text-3xl"></h1>
|
|
20
|
+
<p data-exercise-desc
|
|
21
|
+
class="mt-2 text-zinc-600"></p>
|
|
22
|
+
</div>
|
|
23
|
+
|
|
24
|
+
<div class="flex gap-2">
|
|
25
|
+
<a data-prev-exercise
|
|
26
|
+
href="#"
|
|
27
|
+
class="btn-secondary hidden">← Vorige</a>
|
|
28
|
+
<a href="week{{week}}-oefeningen.html"
|
|
29
|
+
class="btn-secondary">Overzicht</a>
|
|
30
|
+
<a data-next-exercise
|
|
31
|
+
href="#"
|
|
32
|
+
class="btn-primary hidden">Volgende →</a>
|
|
33
|
+
</div>
|
|
34
|
+
</div>
|
|
35
|
+
|
|
36
|
+
<div data-exercise-description
|
|
37
|
+
class="prose-theory hidden"></div>
|
|
38
|
+
|
|
39
|
+
<div data-exercise-external
|
|
40
|
+
class="hidden space-y-4">
|
|
41
|
+
<div class="card border-l-4 border-l-indigo-500">
|
|
42
|
+
<p class="text-[11px] font-semibold uppercase tracking-[0.18em] text-zinc-400">Opdracht</p>
|
|
43
|
+
|
|
44
|
+
<div data-external-task
|
|
45
|
+
class="mt-3 text-sm leading-relaxed text-zinc-700"></div>
|
|
46
|
+
|
|
47
|
+
<div data-external-steps></div>
|
|
48
|
+
</div>
|
|
49
|
+
|
|
50
|
+
<div class="card bg-zinc-50">
|
|
51
|
+
<p class="text-sm font-medium text-zinc-900">Waar werk je?</p>
|
|
52
|
+
|
|
53
|
+
<p data-external-environment
|
|
54
|
+
class="mt-2 text-sm text-zinc-600"></p>
|
|
55
|
+
|
|
56
|
+
<div data-external-deliverables></div>
|
|
57
|
+
</div>
|
|
58
|
+
|
|
59
|
+
<p class="text-sm text-zinc-500">Deze opdracht voer je uit buiten deze website — in je editor, op je machine of in de aangegeven tool.</p>
|
|
60
|
+
</div>
|
|
61
|
+
|
|
62
|
+
<div data-exercise-interactive>
|
|
63
|
+
<div data-responsive-bar
|
|
64
|
+
class="mb-4 hidden flex flex-wrap items-center gap-2">
|
|
65
|
+
|
|
66
|
+
<span class="text-sm text-zinc-500">Viewport:</span>
|
|
67
|
+
|
|
68
|
+
<button data-viewport="desktop"
|
|
69
|
+
type="button"
|
|
70
|
+
class="btn-primary">Desktop</button>
|
|
71
|
+
|
|
72
|
+
<button data-viewport="tablet"
|
|
73
|
+
type="button"
|
|
74
|
+
class="btn-secondary">Tablet</button>
|
|
75
|
+
|
|
76
|
+
<button data-viewport="mobile"
|
|
77
|
+
type="button"
|
|
78
|
+
class="btn-secondary">Mobiel</button>
|
|
79
|
+
|
|
80
|
+
<span data-viewport-label
|
|
81
|
+
class="text-sm text-zinc-500"></span>
|
|
82
|
+
</div>
|
|
83
|
+
|
|
84
|
+
<div data-exercise-css-panel
|
|
85
|
+
class="grid gap-4 lg:grid-cols-2">
|
|
86
|
+
<div class="editor-panel">
|
|
87
|
+
<div class="panel-header">CSS Editor</div>
|
|
88
|
+
|
|
89
|
+
<div data-editor
|
|
90
|
+
class="monaco-container"></div>
|
|
91
|
+
</div>
|
|
92
|
+
|
|
93
|
+
<div class="preview-panel">
|
|
94
|
+
<div class="panel-header">Preview</div>
|
|
95
|
+
|
|
96
|
+
<iframe data-preview
|
|
97
|
+
class="preview-frame"
|
|
98
|
+
title="Preview"></iframe>
|
|
99
|
+
</div>
|
|
100
|
+
</div>
|
|
101
|
+
|
|
102
|
+
<div data-exercise-areas-panel
|
|
103
|
+
class="hidden space-y-4">
|
|
104
|
+
<div class="card">
|
|
105
|
+
<label class="block text-sm font-medium text-zinc-700">grid-template-areas</label>
|
|
106
|
+
|
|
107
|
+
<textarea data-areas-container
|
|
108
|
+
class="mt-2 w-full border border-zinc-200 p-3 font-mono text-sm"
|
|
109
|
+
rows="5"></textarea>
|
|
110
|
+
|
|
111
|
+
<div data-area-selects
|
|
112
|
+
class="space-y-2"></div>
|
|
113
|
+
</div>
|
|
114
|
+
|
|
115
|
+
<div class="card">
|
|
116
|
+
<h3 class="mb-4 text-sm font-medium text-zinc-500">Live preview</h3>
|
|
117
|
+
|
|
118
|
+
<div data-areas-preview></div>
|
|
119
|
+
</div>
|
|
120
|
+
</div>
|
|
121
|
+
</div>
|
|
122
|
+
|
|
123
|
+
<div data-exercise-actions
|
|
124
|
+
class="mb-4 mt-6 flex flex-wrap gap-2">
|
|
125
|
+
<button data-hint
|
|
126
|
+
type="button"
|
|
127
|
+
class="btn-secondary">Toon hint</button>
|
|
128
|
+
|
|
129
|
+
<button data-solution
|
|
130
|
+
type="button"
|
|
131
|
+
class="btn-secondary"
|
|
132
|
+
data-solution-label>Toon oplossing</button>
|
|
133
|
+
|
|
134
|
+
<button data-check
|
|
135
|
+
type="button"
|
|
136
|
+
class="btn-primary"
|
|
137
|
+
data-check-label>Controleer</button>
|
|
138
|
+
</div>
|
|
139
|
+
|
|
140
|
+
<div data-feedback
|
|
141
|
+
class="mb-4 feedback-box hidden"></div>
|
|
142
|
+
</div>
|
|
143
|
+
</main>
|
|
144
|
+
</div>
|
|
145
|
+
|
|
146
|
+
<script type="module">
|
|
147
|
+
import { initPage } from '/src/js/nav.js'
|
|
148
|
+
import { initExercisePage } from '/src/js/exercises/load-exercise.js'
|
|
149
|
+
|
|
150
|
+
const id = new URLSearchParams(location.search).get('id') || '1'
|
|
151
|
+
|
|
152
|
+
initPage({ breadcrumbs: [{ label: 'Home', href: '/index.html' }, { label: 'Week {{week}}', href: '/pages/week{{week}}-oefeningen.html' }, { label: `Oefening ${id}` }] })
|
|
153
|
+
|
|
154
|
+
initExercisePage({{ week }})
|
|
155
|
+
</script>
|
|
156
|
+
</body>
|
|
157
|
+
|
|
158
|
+
</html>
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="nl">
|
|
3
|
+
<head>
|
|
4
|
+
<!-- include:head -->
|
|
5
|
+
<title>{{pageTitle}}</title>
|
|
6
|
+
</head>
|
|
7
|
+
<body class="font-sans antialiased">
|
|
8
|
+
<div data-page-content>
|
|
9
|
+
<main class="px-4 py-10 md:px-10">
|
|
10
|
+
<div class="mx-auto max-w-3xl">
|
|
11
|
+
<span class="week-label">Week {{week}}</span>
|
|
12
|
+
<h1 class="text-3xl font-semibold tracking-tight text-zinc-900">Oefeningen</h1>
|
|
13
|
+
<p class="mt-2 text-zinc-600" data-hub-subtitle>{{weekTitle}} — 8 oefeningen.</p>
|
|
14
|
+
<div class="card mt-8">
|
|
15
|
+
<div class="mb-4 flex items-end justify-between">
|
|
16
|
+
<div>
|
|
17
|
+
<p class="text-[11px] font-semibold uppercase tracking-[0.18em] text-zinc-400">Voortgang</p>
|
|
18
|
+
<p class="mt-1 text-sm text-zinc-500"><span data-hub-progress-text>0 / 8</span> afgerond</p>
|
|
19
|
+
</div>
|
|
20
|
+
</div>
|
|
21
|
+
<div class="progress-track">
|
|
22
|
+
<div data-hub-progress-bar class="progress-fill" style="width:0%"></div>
|
|
23
|
+
</div>
|
|
24
|
+
</div>
|
|
25
|
+
<div data-exercise-list class="mt-8 space-y-4"></div>
|
|
26
|
+
<div class="card mt-10 flex flex-col gap-4 sm:flex-row sm:items-center sm:justify-between">
|
|
27
|
+
<div>
|
|
28
|
+
<p class="font-medium text-zinc-900">Klaar met de oefeningen?</p>
|
|
29
|
+
<p class="mt-1 text-sm text-zinc-500">Test je kennis met de tussentoets.</p>
|
|
30
|
+
</div>
|
|
31
|
+
<a href="week{{week}}-toets.html" class="btn-primary shrink-0">Naar de toets</a>
|
|
32
|
+
</div>
|
|
33
|
+
</div>
|
|
34
|
+
</main>
|
|
35
|
+
</div>
|
|
36
|
+
<script type="module">
|
|
37
|
+
import { initPage } from '/src/js/nav.js'
|
|
38
|
+
import { initExerciseHub } from '/src/js/exercises/hub.js'
|
|
39
|
+
import weekData from '/src/data/exercises/week{{week}}.json'
|
|
40
|
+
initPage({ breadcrumbs: [{ label: 'Home', href: '/index.html' }, { label: 'Week {{week}}' }, { label: 'Oefeningen' }] })
|
|
41
|
+
initExerciseHub(weekData, {{week}})
|
|
42
|
+
</script>
|
|
43
|
+
</body>
|
|
44
|
+
</html>
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="nl">
|
|
3
|
+
<head>
|
|
4
|
+
<!-- include:head -->
|
|
5
|
+
<title>{{pageTitle}}</title>
|
|
6
|
+
</head>
|
|
7
|
+
<body class="font-sans antialiased">
|
|
8
|
+
<div data-page-content>
|
|
9
|
+
<main class="px-4 py-10 md:px-10">
|
|
10
|
+
<div class="mx-auto max-w-3xl">
|
|
11
|
+
<div data-theory data-week="{{week}}"></div>
|
|
12
|
+
</div>
|
|
13
|
+
</main>
|
|
14
|
+
</div>
|
|
15
|
+
<script type="module">
|
|
16
|
+
import { initPage } from '/src/js/nav.js'
|
|
17
|
+
import { initTheory } from '/src/js/theory.js'
|
|
18
|
+
initPage({ breadcrumbs: [{ label: 'Home', href: '/index.html' }, { label: 'Week {{week}}', href: '/pages/week{{week}}-theorie.html' }, { label: 'Theorie' }] })
|
|
19
|
+
initTheory({{week}})
|
|
20
|
+
</script>
|
|
21
|
+
</body>
|
|
22
|
+
</html>
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="nl">
|
|
3
|
+
<head>
|
|
4
|
+
<!-- include:head -->
|
|
5
|
+
<title>{{pageTitle}}</title>
|
|
6
|
+
</head>
|
|
7
|
+
<body class="font-sans antialiased">
|
|
8
|
+
<div data-page-content>
|
|
9
|
+
<main class="px-4 py-10 md:px-10">
|
|
10
|
+
<div class="mx-auto max-w-3xl">
|
|
11
|
+
<h1 class="text-3xl font-semibold tracking-tight text-zinc-900">Eindtoets praktijk</h1>
|
|
12
|
+
<p class="mt-2 text-zinc-600">Praktijkvragen over de module. Minimaal 70% om te slagen.</p>
|
|
13
|
+
<div data-quiz class="mt-8"></div>
|
|
14
|
+
</div>
|
|
15
|
+
</main>
|
|
16
|
+
</div>
|
|
17
|
+
<script type="module">
|
|
18
|
+
import { initPage } from '/src/js/nav.js'
|
|
19
|
+
import { initQuiz } from '/src/js/quiz.js'
|
|
20
|
+
import quizData from '/src/data/toets-praktijk.json'
|
|
21
|
+
initPage({ breadcrumbs: [{ label: 'Home', href: '/index.html' }, { label: 'Eindtoets praktijk' }] })
|
|
22
|
+
initQuiz(quizData)
|
|
23
|
+
</script>
|
|
24
|
+
</body>
|
|
25
|
+
</html>
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="nl">
|
|
3
|
+
<head>
|
|
4
|
+
<!-- include:head -->
|
|
5
|
+
<title>{{pageTitle}}</title>
|
|
6
|
+
</head>
|
|
7
|
+
<body class="font-sans antialiased">
|
|
8
|
+
<div data-page-content>
|
|
9
|
+
<main class="px-4 py-10 md:px-10">
|
|
10
|
+
<div class="mx-auto max-w-3xl">
|
|
11
|
+
<h1 class="text-3xl font-semibold tracking-tight text-zinc-900">Eindtoets theorie</h1>
|
|
12
|
+
<p class="mt-2 text-zinc-600">Meerkeuzevragen over de module. Minimaal 70% om te slagen.</p>
|
|
13
|
+
<div data-quiz class="mt-8"></div>
|
|
14
|
+
</div>
|
|
15
|
+
</main>
|
|
16
|
+
</div>
|
|
17
|
+
<script type="module">
|
|
18
|
+
import { initPage } from '/src/js/nav.js'
|
|
19
|
+
import { initQuiz } from '/src/js/quiz.js'
|
|
20
|
+
import quizData from '/src/data/toets-theorie.json'
|
|
21
|
+
initPage({ breadcrumbs: [{ label: 'Home', href: '/index.html' }, { label: 'Eindtoets theorie' }] })
|
|
22
|
+
initQuiz(quizData)
|
|
23
|
+
</script>
|
|
24
|
+
</body>
|
|
25
|
+
</html>
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="nl">
|
|
3
|
+
<head>
|
|
4
|
+
<!-- include:head -->
|
|
5
|
+
<title>{{pageTitle}}</title>
|
|
6
|
+
</head>
|
|
7
|
+
<body class="font-sans antialiased">
|
|
8
|
+
<div data-page-content>
|
|
9
|
+
<main class="px-4 py-10 md:px-10">
|
|
10
|
+
<div class="mx-auto max-w-3xl">
|
|
11
|
+
<span class="week-label">Week {{weekPadded}} — Tussentoets</span>
|
|
12
|
+
<h1 class="text-3xl font-semibold tracking-tight text-zinc-900">{{weekTitle}}</h1>
|
|
13
|
+
<p class="mt-2 text-zinc-600">Test je kennis van week {{week}}. Minimaal 70% om te slagen.</p>
|
|
14
|
+
<div data-quiz class="mt-8"></div>
|
|
15
|
+
<div class="card mt-10 flex flex-col gap-4 sm:flex-row sm:items-center sm:justify-between">
|
|
16
|
+
<div>
|
|
17
|
+
<p class="font-medium text-zinc-900">Toets afgerond?</p>
|
|
18
|
+
<p class="mt-1 text-sm text-zinc-500">Werk de inleveropdracht uit.</p>
|
|
19
|
+
</div>
|
|
20
|
+
<a href="week{{week}}-thuiswerk.html" class="btn-primary shrink-0">Naar inleveropdracht</a>
|
|
21
|
+
</div>
|
|
22
|
+
</div>
|
|
23
|
+
</main>
|
|
24
|
+
</div>
|
|
25
|
+
<script type="module">
|
|
26
|
+
import { initPage } from '/src/js/nav.js'
|
|
27
|
+
import { initQuiz } from '/src/js/quiz.js'
|
|
28
|
+
import quizData from '/src/data/tussentoets-week{{week}}.json'
|
|
29
|
+
initPage({ breadcrumbs: [{ label: 'Home', href: '/index.html' }, { label: 'Week {{week}}', href: '/pages/week{{week}}-theorie.html' }, { label: 'Tussentoets' }] })
|
|
30
|
+
initQuiz(quizData)
|
|
31
|
+
</script>
|
|
32
|
+
</body>
|
|
33
|
+
</html>
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import fs from 'fs'
|
|
2
|
+
import { resolve } from 'path'
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Vervangt <!-- include:naam --> door src/partials/naam.html (dev + build).
|
|
6
|
+
*/
|
|
7
|
+
export function htmlIncludes({ partialsDir }) {
|
|
8
|
+
return {
|
|
9
|
+
name: 'html-includes',
|
|
10
|
+
transformIndexHtml: {
|
|
11
|
+
order: 'pre',
|
|
12
|
+
handler(html) {
|
|
13
|
+
return html.replace(/<!-- include:(\w+) -->/g, (_, name) => {
|
|
14
|
+
const file = resolve(partialsDir, `${name}.html`)
|
|
15
|
+
if (!fs.existsSync(file)) {
|
|
16
|
+
throw new Error(`HTML partial ontbreekt: ${file}`)
|
|
17
|
+
}
|
|
18
|
+
return fs.readFileSync(file, 'utf8').trim()
|
|
19
|
+
})
|
|
20
|
+
},
|
|
21
|
+
},
|
|
22
|
+
}
|
|
23
|
+
}
|
package/vite.config.js
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { fileURLToPath } from 'url'
|
|
2
|
+
import path from 'path'
|
|
3
|
+
import { readdirSync, existsSync } from 'fs'
|
|
4
|
+
import { defineConfig } from 'vite'
|
|
5
|
+
import tailwindcss from '@tailwindcss/vite'
|
|
6
|
+
import { htmlIncludes } from './vite-plugin-html-includes.js'
|
|
7
|
+
|
|
8
|
+
export function createConfig({ projectDir, pkgDir }) {
|
|
9
|
+
return defineConfig({
|
|
10
|
+
root: projectDir,
|
|
11
|
+
base: './',
|
|
12
|
+
publicDir: path.join(pkgDir, 'public'),
|
|
13
|
+
plugins: [
|
|
14
|
+
htmlIncludes({ partialsDir: path.join(pkgDir, 'src', 'partials') }),
|
|
15
|
+
tailwindcss(),
|
|
16
|
+
],
|
|
17
|
+
build: {
|
|
18
|
+
outDir: path.join(projectDir, 'dist'),
|
|
19
|
+
emptyOutDir: true,
|
|
20
|
+
rollupOptions: {
|
|
21
|
+
input: buildInputs(projectDir),
|
|
22
|
+
},
|
|
23
|
+
},
|
|
24
|
+
})
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function buildInputs(projectDir) {
|
|
28
|
+
const entries = { index: path.join(projectDir, 'index.html') }
|
|
29
|
+
const pagesDir = path.join(projectDir, 'pages')
|
|
30
|
+
if (existsSync(pagesDir)) {
|
|
31
|
+
readdirSync(pagesDir)
|
|
32
|
+
.filter(f => f.endsWith('.html'))
|
|
33
|
+
.forEach(f => {
|
|
34
|
+
entries[f.replace('.html', '')] = path.join(pagesDir, f)
|
|
35
|
+
})
|
|
36
|
+
}
|
|
37
|
+
return entries
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// Default export so the config can be used directly if needed
|
|
41
|
+
const _pkgDir = path.dirname(fileURLToPath(import.meta.url))
|
|
42
|
+
export default createConfig({ projectDir: process.cwd(), pkgDir: _pkgDir })
|