@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.
@@ -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 })