@lernapps/app-templates 0.0.1 → 0.1.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/LICENSE +22 -0
- package/README.md +195 -2
- package/dist/appname-Bh23cUuz.mjs +12 -0
- package/dist/assessment-Dy359O1O.mjs +1696 -0
- package/dist/block-BK_ohsH1.mjs +82 -0
- package/dist/blocks-CxtCPAa5.mjs +149 -0
- package/dist/blocks.mjs +4 -0
- package/dist/check-CteIFN96.mjs +254 -0
- package/dist/content-DO6oEJxj.mjs +140 -0
- package/dist/contract-PONpxJtd.mjs +52 -0
- package/dist/e2e-CU0n_unV.mjs +89 -0
- package/dist/engine-CArxqizW.mjs +136 -0
- package/dist/explainer-e2e.mjs +1311 -0
- package/dist/explainer-islands.mjs +197 -0
- package/dist/explainer-plugin.mjs +2132 -0
- package/dist/explainer.mjs +1246 -0
- package/dist/html-mffkHGHh.mjs +89 -0
- package/dist/image-CspJVfyQ.mjs +21 -0
- package/dist/interactive-e2e.mjs +140 -0
- package/dist/interactive-plugin.mjs +242 -0
- package/dist/interactive.mjs +75 -0
- package/dist/load-RosvaPZf.mjs +16976 -0
- package/dist/needs-BzEahJ6X.mjs +97 -0
- package/dist/pages-9RaaomoO.mjs +81 -0
- package/dist/questions-e2e.mjs +1 -0
- package/dist/questions-engine.mjs +3 -0
- package/dist/questions.mjs +6 -0
- package/dist/quiz-DnW-xtCh.mjs +70 -0
- package/dist/quiz-e2e.mjs +174 -0
- package/dist/quiz-plugin.mjs +266 -0
- package/dist/quiz.mjs +246 -0
- package/dist/render-D5kwkNt1.mjs +507 -0
- package/dist/render-DqHOJyHK.mjs +146 -0
- package/dist/render-GS1Htlu8.mjs +545 -0
- package/dist/result-D_mmCVwN.mjs +180 -0
- package/dist/tasks-DADUYy52.mjs +74 -0
- package/dist/validate-BDwL7Su3.mjs +1076 -0
- package/dist/validate-Bxy9NfB8.mjs +146 -0
- package/dist/vue-DO1m6q1R.mjs +40 -0
- package/dist/vue-code-BkJjW_I_.mjs +320 -0
- package/docs/arc42/01-introduction-and-goals.arc42.md +82 -0
- package/docs/arc42/02-constraints.arc42.md +228 -0
- package/docs/arc42/03-system-context.arc42.md +118 -0
- package/docs/arc42/04-solution-strategy.arc42.md +47 -0
- package/docs/arc42/05-building-blocks.arc42.md +307 -0
- package/docs/arc42/06-runtime-view.arc42.md +98 -0
- package/docs/arc42/07-deployment-view.arc42.md +160 -0
- package/docs/arc42/08-concepts.arc42.md +123 -0
- package/docs/arc42/09-decisions.arc42.md +246 -0
- package/docs/arc42/10-quality-requirements.arc42.md +155 -0
- package/docs/arc42/11-risks.arc42.md +113 -0
- package/docs/arc42/12-glossary.arc42.md +162 -0
- package/docs/arc42/architecture-evidence.md +395 -0
- package/explainer/.arc42ignore +3 -0
- package/explainer/README.md +54 -0
- package/explainer/_gitignore +5 -0
- package/explainer/docs/arc42/03-explainer-system-context.arc42.md +35 -0
- package/explainer/docs/arc42/05-explainer-building-blocks.arc42.md +659 -0
- package/explainer/docs/arc42/06-explainer-runtime-view.arc42.md +105 -0
- package/explainer/docs/arc42/07-explainer-deployment-view.arc42.md +34 -0
- package/explainer/docs/arc42/08-explainer-concepts.arc42.md +17 -0
- package/explainer/docs/arc42/09-explainer-decisions.arc42.md +443 -0
- package/explainer/docs/arc42/10-explainer-quality-requirements.arc42.md +54 -0
- package/explainer/docs/arc42/11-explainer-risks.arc42.md +17 -0
- package/explainer/docs/arc42/12-explainer-glossary.arc42.md +185 -0
- package/explainer/e2e/explainer.e2e.ts +3 -0
- package/explainer/index.html +11 -0
- package/explainer/package.json +18 -0
- package/explainer/playwright.config.ts +1 -0
- package/explainer/src/app.yaml +20 -0
- package/explainer/src/components/ProzentFeld.test.ts +30 -0
- package/explainer/src/components/ProzentFeld.ts +121 -0
- package/explainer/src/components/ProzentFeld.vue +84 -0
- package/explainer/src/images/hunderterfeld-klammern.svg +105 -0
- package/explainer/src/main.ts +4 -0
- package/explainer/src/prozent/chapter.yaml +18 -0
- package/explainer/src/prozent/grundwert.yaml +115 -0
- package/explainer/src/prozent/prozentsatz.yaml +99 -0
- package/explainer/src/prozent/prozentwert.yaml +119 -0
- package/explainer/tsconfig.json +1 -0
- package/explainer/vite.config.ts +4 -0
- package/interactive/.arc42ignore +5 -0
- package/interactive/README.md +28 -0
- package/interactive/_gitignore +4 -0
- package/interactive/docs/arc42/05-interactive-building-blocks.arc42.md +518 -0
- package/interactive/docs/arc42/06-interactive-runtime-view.arc42.md +58 -0
- package/interactive/docs/arc42/07-interactive-deployment-view.arc42.md +35 -0
- package/interactive/docs/arc42/08-interactive-concepts.arc42.md +52 -0
- package/interactive/docs/arc42/09-interactive-decisions.arc42.md +130 -0
- package/interactive/docs/arc42/10-interactive-quality-requirements.arc42.md +45 -0
- package/interactive/docs/arc42/11-interactive-risks.arc42.md +20 -0
- package/interactive/docs/arc42/12-interactive-glossary.arc42.md +80 -0
- package/interactive/e2e/interactive.e2e.ts +3 -0
- package/interactive/index.html +11 -0
- package/interactive/package.json +18 -0
- package/interactive/playwright.config.ts +1 -0
- package/interactive/src/app.yaml +28 -0
- package/interactive/src/core/index.ts +101 -0
- package/interactive/src/data/lessons.json +4 -0
- package/interactive/src/env.d.ts +6 -0
- package/interactive/src/main.ts +6 -0
- package/interactive/src/messages/de.json +12 -0
- package/interactive/src/playthroughs/grundreihe.yaml +33 -0
- package/interactive/src/playthroughs/obere-reihe.yaml +14 -0
- package/interactive/src/ui/App.vue +85 -0
- package/interactive/tsconfig.json +1 -0
- package/interactive/vite.config.ts +4 -0
- package/package.json +143 -4
- package/quiz/README.md +31 -0
- package/quiz/_gitignore +5 -0
- package/quiz/docs/arc42/05-quiz-building-blocks.arc42.md +283 -0
- package/quiz/docs/arc42/06-quiz-runtime-view.arc42.md +21 -0
- package/quiz/docs/arc42/07-quiz-deployment-view.arc42.md +33 -0
- package/quiz/docs/arc42/09-quiz-decisions.arc42.md +36 -0
- package/quiz/docs/arc42/10-quiz-quality-requirements.arc42.md +53 -0
- package/quiz/docs/arc42/11-quiz-risks.arc42.md +19 -0
- package/quiz/docs/arc42/12-quiz-glossary.arc42.md +27 -0
- package/quiz/e2e/quiz.e2e.ts +3 -0
- package/quiz/index.html +11 -0
- package/quiz/package.json +18 -0
- package/quiz/playwright.config.ts +1 -0
- package/quiz/src/images/berge-ordnen.jpg +0 -0
- package/quiz/src/images/everest-hoehe.jpg +0 -0
- package/quiz/src/images/galapagos.jpg +0 -0
- package/quiz/src/images/grand-canyon.jpg +0 -0
- package/quiz/src/images/totes-meer.jpg +0 -0
- package/quiz/src/images/uluru.jpg +0 -0
- package/quiz/src/images/wasserfaelle-laender.jpg +0 -0
- package/quiz/src/main.ts +4 -0
- package/quiz/src/quiz.json +312 -0
- package/quiz/tsconfig.json +1 -0
- package/quiz/vite.config.ts +4 -0
- package/runtime/explainer/assessment-client.ts +478 -0
- package/runtime/explainer/assessment-page.ts +448 -0
- package/runtime/explainer/assessment.ts +393 -0
- package/runtime/explainer/check-page.ts +520 -0
- package/runtime/explainer/components/exercise.ts +409 -0
- package/runtime/explainer/components/props.ts +230 -0
- package/runtime/explainer/components/read.ts +428 -0
- package/runtime/explainer/content.ts +277 -0
- package/runtime/explainer/e2e.ts +1488 -0
- package/runtime/explainer/exercises.ts +326 -0
- package/runtime/explainer/explainer.css +1283 -0
- package/runtime/explainer/explainer.ts +838 -0
- package/runtime/explainer/explainer.v1.schema.json +1165 -0
- package/runtime/explainer/expression.ts +407 -0
- package/runtime/explainer/fraction.ts +107 -0
- package/runtime/explainer/generated/comparator.ts +31 -0
- package/runtime/explainer/generated/question.ts +165 -0
- package/runtime/explainer/generated/soundness.ts +280 -0
- package/runtime/explainer/generated/texts.ts +257 -0
- package/runtime/explainer/generated/types.ts +103 -0
- package/runtime/explainer/generated/values.ts +136 -0
- package/runtime/explainer/islands.ts +281 -0
- package/runtime/explainer/load.ts +457 -0
- package/runtime/explainer/messages/de.json +200 -0
- package/runtime/explainer/messages/en.json +200 -0
- package/runtime/explainer/messages.ts +13 -0
- package/runtime/explainer/needs.ts +122 -0
- package/runtime/explainer/open-task.ts +235 -0
- package/runtime/explainer/outline.ts +306 -0
- package/runtime/explainer/plugin.ts +488 -0
- package/runtime/explainer/position.ts +62 -0
- package/runtime/explainer/prompt.ts +75 -0
- package/runtime/explainer/render.ts +686 -0
- package/runtime/explainer/result.ts +238 -0
- package/runtime/explainer/routes.ts +119 -0
- package/runtime/explainer/schema.ts +140 -0
- package/runtime/explainer/scope.ts +87 -0
- package/runtime/explainer/stuck.ts +57 -0
- package/runtime/explainer/tasks.ts +109 -0
- package/runtime/explainer/tutor.ts +469 -0
- package/runtime/explainer/tutorpage.ts +669 -0
- package/runtime/explainer/video.ts +123 -0
- package/runtime/interactive/contract.ts +121 -0
- package/runtime/interactive/e2e.ts +190 -0
- package/runtime/interactive/interactive.css +82 -0
- package/runtime/interactive/interactive.ts +115 -0
- package/runtime/interactive/interactive.v1.schema.json +146 -0
- package/runtime/interactive/load.ts +188 -0
- package/runtime/interactive/messages/de.json +14 -0
- package/runtime/interactive/messages/en.json +14 -0
- package/runtime/interactive/messages.ts +11 -0
- package/runtime/interactive/playthrough.v1.schema.json +143 -0
- package/runtime/interactive/plugin.ts +266 -0
- package/runtime/interactive/render.ts +126 -0
- package/runtime/quiz/e2e.ts +233 -0
- package/runtime/quiz/engine.ts +242 -0
- package/runtime/quiz/messages/de.json +23 -0
- package/runtime/quiz/messages/en.json +23 -0
- package/runtime/quiz/plugin.ts +150 -0
- package/runtime/quiz/quiz.css +154 -0
- package/runtime/quiz/quiz.ts +56 -0
- package/runtime/quiz/quiz.v1.schema.json +72 -0
- package/runtime/quiz/render.ts +173 -0
- package/runtime/quiz/validate.ts +108 -0
- package/runtime/shared/appname.ts +16 -0
- package/runtime/shared/blocks/block.ts +162 -0
- package/runtime/shared/blocks/blocks.css +190 -0
- package/runtime/shared/blocks/blocks.v1.schema.json +432 -0
- package/runtime/shared/blocks/code.ts +26 -0
- package/runtime/shared/blocks/figures.ts +49 -0
- package/runtime/shared/blocks/image.ts +25 -0
- package/runtime/shared/blocks/index.ts +13 -0
- package/runtime/shared/blocks/messages/de.json +4 -0
- package/runtime/shared/blocks/messages/en.json +4 -0
- package/runtime/shared/blocks/render.ts +134 -0
- package/runtime/shared/blocks/validate.ts +165 -0
- package/runtime/shared/content.ts +197 -0
- package/runtime/shared/examples.ts +20 -0
- package/runtime/shared/html.ts +10 -0
- package/runtime/shared/languages.ts +94 -0
- package/runtime/shared/page.css +101 -0
- package/runtime/shared/pages.ts +114 -0
- package/runtime/shared/questions/e2e.ts +115 -0
- package/runtime/shared/questions/engine.ts +209 -0
- package/runtime/shared/questions/index.ts +39 -0
- package/runtime/shared/questions/messages/de.json +26 -0
- package/runtime/shared/questions/messages/en.json +26 -0
- package/runtime/shared/questions/question.ts +433 -0
- package/runtime/shared/questions/question.v1.schema.json +346 -0
- package/runtime/shared/questions/questions.css +192 -0
- package/runtime/shared/questions/render.ts +255 -0
- package/runtime/shared/questions/validate.ts +518 -0
- package/runtime/shared/schema.ts +44 -0
- package/runtime/shared/text/check.ts +68 -0
- package/runtime/shared/text/formula.ts +69 -0
- package/runtime/shared/text/markdown.ts +185 -0
- package/runtime/shared/text/speech.ts +39 -0
- package/runtime/shared/text/text.v1.schema.json +34 -0
- package/runtime/shared/vue-code.ts +395 -0
- package/runtime/shared/vue.ts +38 -0
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
/* The look of blocks that show content (text, formula, figure, labelled figure, table, quotation, code), for every
|
|
2
|
+
archetype that shows them, in the colours of the page (page.css): images that fit the page, the drawings, the
|
|
3
|
+
caption and the credit, the markers of a labelled figure, tables that scroll on their own, and code, highlighted at
|
|
4
|
+
build time (highlight.js classes), every colour with 4.5:1 on the code's background. */
|
|
5
|
+
|
|
6
|
+
:root {
|
|
7
|
+
--block-hl-keyword: #7b2382;
|
|
8
|
+
--block-hl-string: #0f5a2e;
|
|
9
|
+
--block-hl-number: #8a3b00;
|
|
10
|
+
--block-hl-comment: #50555c;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
@media (prefers-color-scheme: dark) {
|
|
14
|
+
:root {
|
|
15
|
+
--block-hl-keyword: #e0a3ff;
|
|
16
|
+
--block-hl-string: #8fe0ac;
|
|
17
|
+
--block-hl-number: #ffb77a;
|
|
18
|
+
--block-hl-comment: #a3a9b3;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
.block-figure {
|
|
23
|
+
margin: 1.25rem 0;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
.block-figure img,
|
|
27
|
+
.block-drawing {
|
|
28
|
+
display: block;
|
|
29
|
+
max-width: 100%;
|
|
30
|
+
height: auto;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
.block-hundred-grid {
|
|
34
|
+
width: 16rem;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
.block-bar {
|
|
38
|
+
width: 100%;
|
|
39
|
+
max-width: 28rem;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
figcaption {
|
|
43
|
+
margin-top: 0.5rem;
|
|
44
|
+
color: var(--page-muted);
|
|
45
|
+
font-size: 0.9375rem;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
figcaption p {
|
|
49
|
+
margin: 0;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
.block-credit {
|
|
53
|
+
display: block;
|
|
54
|
+
font-size: 0.875rem;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
.block-labelled-image {
|
|
58
|
+
position: relative;
|
|
59
|
+
display: inline-block;
|
|
60
|
+
max-width: 100%;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/* an image without a size of its own (an SVG with only a viewBox) fills the width, as in a figure */
|
|
64
|
+
.block-labelled-fill {
|
|
65
|
+
display: block;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
.block-labelled-fill img {
|
|
69
|
+
width: 100%;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/* the legend of a figure whose labels name their markers: the marker leads each line, in place of the list's number */
|
|
73
|
+
.block-legend-named {
|
|
74
|
+
list-style: none;
|
|
75
|
+
padding-left: 0;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
.block-marker {
|
|
79
|
+
position: absolute;
|
|
80
|
+
transform: translate(-50%, -50%);
|
|
81
|
+
min-width: 1.6rem;
|
|
82
|
+
padding: 0 0.3rem;
|
|
83
|
+
border-radius: 1rem;
|
|
84
|
+
background: var(--page-text);
|
|
85
|
+
color: var(--page-background);
|
|
86
|
+
font-size: 0.875rem;
|
|
87
|
+
font-weight: 700;
|
|
88
|
+
line-height: 1.6rem;
|
|
89
|
+
text-align: center;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/* a formula wider than the page scrolls on its own; vertically, MathML may overhang its box by a pixel */
|
|
93
|
+
.block-formula {
|
|
94
|
+
margin: 1rem 0;
|
|
95
|
+
padding: 0.25rem 0;
|
|
96
|
+
overflow-x: auto;
|
|
97
|
+
overflow-y: hidden;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
math {
|
|
101
|
+
font-size: 1.1em;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
.block-quote,
|
|
105
|
+
.block-code {
|
|
106
|
+
margin: 1.25rem 0;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
.block-table {
|
|
110
|
+
margin: 1rem 0;
|
|
111
|
+
overflow-x: auto;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
.block-table table {
|
|
115
|
+
border-collapse: collapse;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
.block-table caption {
|
|
119
|
+
margin-bottom: 0.25rem;
|
|
120
|
+
font-weight: 600;
|
|
121
|
+
text-align: left;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
.block-table th,
|
|
125
|
+
.block-table td {
|
|
126
|
+
padding: 0.35rem 0.6rem;
|
|
127
|
+
border: 1px solid var(--page-border);
|
|
128
|
+
text-align: left;
|
|
129
|
+
vertical-align: top;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
.block-table thead th,
|
|
133
|
+
.block-table th[scope="row"] {
|
|
134
|
+
background: var(--page-surface);
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
.block-quote blockquote {
|
|
138
|
+
margin: 0;
|
|
139
|
+
padding: 0.25rem 1rem;
|
|
140
|
+
border-left: 4px solid var(--page-border);
|
|
141
|
+
font-style: italic;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
.block-code pre {
|
|
145
|
+
margin: 0;
|
|
146
|
+
padding: 0.75rem 1rem;
|
|
147
|
+
overflow-x: auto;
|
|
148
|
+
border-radius: 0.5rem;
|
|
149
|
+
background: var(--page-surface);
|
|
150
|
+
font-size: 0.9375rem;
|
|
151
|
+
line-height: 1.45;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
/* code, highlighted at build time (highlight.js classes); every colour has 4.5:1 on the code's background */
|
|
155
|
+
.hljs-keyword,
|
|
156
|
+
.hljs-selector-tag,
|
|
157
|
+
.hljs-literal,
|
|
158
|
+
.hljs-type {
|
|
159
|
+
color: var(--block-hl-keyword);
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
.hljs-string,
|
|
163
|
+
.hljs-attr,
|
|
164
|
+
.hljs-regexp {
|
|
165
|
+
color: var(--block-hl-string);
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
.hljs-number,
|
|
169
|
+
.hljs-symbol {
|
|
170
|
+
color: var(--block-hl-number);
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
.hljs-comment,
|
|
174
|
+
.hljs-meta {
|
|
175
|
+
color: var(--block-hl-comment);
|
|
176
|
+
font-style: italic;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
.hljs-title,
|
|
180
|
+
.hljs-function,
|
|
181
|
+
.hljs-name,
|
|
182
|
+
.hljs-built_in {
|
|
183
|
+
color: var(--page-accent);
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
.hljs-variable,
|
|
187
|
+
.hljs-params,
|
|
188
|
+
.hljs-tag {
|
|
189
|
+
color: var(--page-text);
|
|
190
|
+
}
|
|
@@ -0,0 +1,432 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"$id": "urn:lernapps:schema:blocks.v1",
|
|
4
|
+
"title": "Blocks that show content",
|
|
5
|
+
"description": "The blocks the quiz shows with a question and the explainer shows on a page alike: prose, a formula, a figure (drawn from data or a bundled image), a labelled figure (a bundled image with numbered labels), a table, a quotation and program code, with the credit of an image or a quotation. An image is a file in src/images/ of the app.",
|
|
6
|
+
"$defs": {
|
|
7
|
+
"credit": {
|
|
8
|
+
"description": "Where a bundled image or a quote comes from: the source (a URL or a citation) and its licence (an SPDX identifier such as CC-BY-SA-4.0, or \"gemeinfrei\").",
|
|
9
|
+
"type": "object",
|
|
10
|
+
"properties": {
|
|
11
|
+
"source": {
|
|
12
|
+
"description": "Where it comes from: a URL, the same in every language and shown as a link, or a citation, a text like any other: a string while German is the only language of the app, else a map of texts by language with every declared language, e.g. { de: eigene Zeichnung, en: own drawing }. Each language's page shows its own.",
|
|
13
|
+
"anyOf": [
|
|
14
|
+
{
|
|
15
|
+
"type": "string",
|
|
16
|
+
"minLength": 1,
|
|
17
|
+
"pattern": "\\S"
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
"type": "object",
|
|
21
|
+
"minProperties": 1,
|
|
22
|
+
"propertyNames": {
|
|
23
|
+
"pattern": "^[a-z]{2}$"
|
|
24
|
+
},
|
|
25
|
+
"additionalProperties": {
|
|
26
|
+
"type": "string",
|
|
27
|
+
"minLength": 1,
|
|
28
|
+
"pattern": "\\S"
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
]
|
|
32
|
+
},
|
|
33
|
+
"licence": {
|
|
34
|
+
"description": "Its licence: an SPDX identifier (CC-BY-SA-4.0, CC0-1.0, …), or gemeinfrei for a work in the public domain.",
|
|
35
|
+
"type": "string",
|
|
36
|
+
"minLength": 1,
|
|
37
|
+
"pattern": "\\S"
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
},
|
|
41
|
+
"image": {
|
|
42
|
+
"description": "A bundled image file in src/images/, as a path from src/: images/<name>.svg (or .png, .jpg, .webp).",
|
|
43
|
+
"type": "string",
|
|
44
|
+
"pattern": "^images/[a-z0-9]+(-[a-z0-9]+)*\\.(svg|png|jpg|webp)$"
|
|
45
|
+
},
|
|
46
|
+
"drawing": {
|
|
47
|
+
"description": "A figure drawn from numbers at build, as inline SVG: hundred-grid (a field of 100 squares, filled of them shaded) or bar (a strip, part of whole shaded, with its percentage).",
|
|
48
|
+
"type": "object",
|
|
49
|
+
"required": ["kind"],
|
|
50
|
+
"properties": {
|
|
51
|
+
"kind": {
|
|
52
|
+
"enum": ["hundred-grid", "bar"]
|
|
53
|
+
}
|
|
54
|
+
},
|
|
55
|
+
"allOf": [
|
|
56
|
+
{
|
|
57
|
+
"if": {
|
|
58
|
+
"properties": {
|
|
59
|
+
"kind": {
|
|
60
|
+
"const": "hundred-grid"
|
|
61
|
+
}
|
|
62
|
+
},
|
|
63
|
+
"required": ["kind"],
|
|
64
|
+
"type": "object"
|
|
65
|
+
},
|
|
66
|
+
"then": {
|
|
67
|
+
"required": ["filled"],
|
|
68
|
+
"properties": {
|
|
69
|
+
"filled": {
|
|
70
|
+
"description": "How many of the 100 squares are shaded.",
|
|
71
|
+
"type": "integer",
|
|
72
|
+
"minimum": 0,
|
|
73
|
+
"maximum": 100
|
|
74
|
+
}
|
|
75
|
+
},
|
|
76
|
+
"type": "object"
|
|
77
|
+
}
|
|
78
|
+
},
|
|
79
|
+
{
|
|
80
|
+
"if": {
|
|
81
|
+
"properties": {
|
|
82
|
+
"kind": {
|
|
83
|
+
"const": "bar"
|
|
84
|
+
}
|
|
85
|
+
},
|
|
86
|
+
"required": ["kind"],
|
|
87
|
+
"type": "object"
|
|
88
|
+
},
|
|
89
|
+
"then": {
|
|
90
|
+
"required": ["part", "whole"],
|
|
91
|
+
"properties": {
|
|
92
|
+
"part": {
|
|
93
|
+
"description": "The shaded part.",
|
|
94
|
+
"type": "number",
|
|
95
|
+
"minimum": 0
|
|
96
|
+
},
|
|
97
|
+
"whole": {
|
|
98
|
+
"description": "The whole strip, 100 %.",
|
|
99
|
+
"type": "number",
|
|
100
|
+
"exclusiveMinimum": 0
|
|
101
|
+
}
|
|
102
|
+
},
|
|
103
|
+
"type": "object"
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
],
|
|
107
|
+
"unevaluatedProperties": false
|
|
108
|
+
},
|
|
109
|
+
"figure": {
|
|
110
|
+
"description": "A figure: drawn from data (draw) or a bundled image (image, with its source and licence), one of the two. It has an alternative text that says what it shows, and a caption that says what to see.",
|
|
111
|
+
"required": ["alt", "caption"],
|
|
112
|
+
"allOf": [
|
|
113
|
+
{
|
|
114
|
+
"$ref": "#/$defs/credit"
|
|
115
|
+
}
|
|
116
|
+
],
|
|
117
|
+
"properties": {
|
|
118
|
+
"draw": {
|
|
119
|
+
"$ref": "#/$defs/drawing"
|
|
120
|
+
},
|
|
121
|
+
"image": {
|
|
122
|
+
"$ref": "#/$defs/image"
|
|
123
|
+
},
|
|
124
|
+
"alt": {
|
|
125
|
+
"description": "What the figure shows, for those who cannot see it.",
|
|
126
|
+
"$ref": "urn:lernapps:schema:text.v1#/$defs/text"
|
|
127
|
+
},
|
|
128
|
+
"caption": {
|
|
129
|
+
"description": "What to see in the figure, under it.",
|
|
130
|
+
"$ref": "urn:lernapps:schema:text.v1#/$defs/markdown"
|
|
131
|
+
}
|
|
132
|
+
},
|
|
133
|
+
"dependentRequired": {
|
|
134
|
+
"image": ["source", "licence"]
|
|
135
|
+
},
|
|
136
|
+
"type": "object"
|
|
137
|
+
},
|
|
138
|
+
"labelledFigure": {
|
|
139
|
+
"description": "A bundled image with labels at positions. Each label shows its marker (A, B, 1a; else its number in order). The texts of the labels are listed beside the image (the legend), unless legend is false.",
|
|
140
|
+
"required": ["image", "alt", "labels", "source", "licence"],
|
|
141
|
+
"allOf": [
|
|
142
|
+
{
|
|
143
|
+
"$ref": "#/$defs/credit"
|
|
144
|
+
}
|
|
145
|
+
],
|
|
146
|
+
"properties": {
|
|
147
|
+
"image": {
|
|
148
|
+
"$ref": "#/$defs/image"
|
|
149
|
+
},
|
|
150
|
+
"alt": {
|
|
151
|
+
"description": "What the image shows, for those who cannot see it.",
|
|
152
|
+
"$ref": "urn:lernapps:schema:text.v1#/$defs/text"
|
|
153
|
+
},
|
|
154
|
+
"caption": {
|
|
155
|
+
"description": "What to see in the figure.",
|
|
156
|
+
"$ref": "urn:lernapps:schema:text.v1#/$defs/markdown"
|
|
157
|
+
},
|
|
158
|
+
"legend": {
|
|
159
|
+
"description": "Whether the texts of the labels are listed beside the image. Default true. With false the figure shows only the markers (for a figure the learner labels), and alt names every marker with its part.",
|
|
160
|
+
"type": "boolean"
|
|
161
|
+
},
|
|
162
|
+
"labels": {
|
|
163
|
+
"type": "array",
|
|
164
|
+
"minItems": 1,
|
|
165
|
+
"items": {
|
|
166
|
+
"type": "object",
|
|
167
|
+
"additionalProperties": false,
|
|
168
|
+
"required": ["x", "y", "text"],
|
|
169
|
+
"properties": {
|
|
170
|
+
"marker": {
|
|
171
|
+
"description": "What the label shows on the image, plain text of 1 to 3 characters (A, B, 1a), the letters of the material. Each marker is used once. Without it: the number of the label in order, from 1.",
|
|
172
|
+
"type": "string",
|
|
173
|
+
"minLength": 1,
|
|
174
|
+
"maxLength": 3
|
|
175
|
+
},
|
|
176
|
+
"x": {
|
|
177
|
+
"description": "From the left edge, in percent of the width.",
|
|
178
|
+
"type": "number",
|
|
179
|
+
"minimum": 0,
|
|
180
|
+
"maximum": 100
|
|
181
|
+
},
|
|
182
|
+
"y": {
|
|
183
|
+
"description": "From the top edge, in percent of the height.",
|
|
184
|
+
"type": "number",
|
|
185
|
+
"minimum": 0,
|
|
186
|
+
"maximum": 100
|
|
187
|
+
},
|
|
188
|
+
"text": {
|
|
189
|
+
"description": "What the label names.",
|
|
190
|
+
"$ref": "urn:lernapps:schema:text.v1#/$defs/text"
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
},
|
|
196
|
+
"type": "object"
|
|
197
|
+
},
|
|
198
|
+
"materialBlock": {
|
|
199
|
+
"description": "A block that shows content with a question: a figure or a labelled figure.",
|
|
200
|
+
"type": "object",
|
|
201
|
+
"required": ["type"],
|
|
202
|
+
"properties": {
|
|
203
|
+
"type": {
|
|
204
|
+
"description": "The kind of block.",
|
|
205
|
+
"enum": ["text", "formula", "figure", "labelled-figure", "table", "quote", "code"]
|
|
206
|
+
}
|
|
207
|
+
},
|
|
208
|
+
"allOf": [
|
|
209
|
+
{
|
|
210
|
+
"if": {
|
|
211
|
+
"properties": {
|
|
212
|
+
"type": {
|
|
213
|
+
"const": "text"
|
|
214
|
+
}
|
|
215
|
+
},
|
|
216
|
+
"required": ["type"],
|
|
217
|
+
"type": "object"
|
|
218
|
+
},
|
|
219
|
+
"then": {
|
|
220
|
+
"$ref": "#/$defs/textBlock"
|
|
221
|
+
}
|
|
222
|
+
},
|
|
223
|
+
{
|
|
224
|
+
"if": {
|
|
225
|
+
"properties": {
|
|
226
|
+
"type": {
|
|
227
|
+
"const": "formula"
|
|
228
|
+
}
|
|
229
|
+
},
|
|
230
|
+
"required": ["type"],
|
|
231
|
+
"type": "object"
|
|
232
|
+
},
|
|
233
|
+
"then": {
|
|
234
|
+
"$ref": "#/$defs/formula"
|
|
235
|
+
}
|
|
236
|
+
},
|
|
237
|
+
{
|
|
238
|
+
"if": {
|
|
239
|
+
"properties": {
|
|
240
|
+
"type": {
|
|
241
|
+
"const": "figure"
|
|
242
|
+
}
|
|
243
|
+
},
|
|
244
|
+
"required": ["type"],
|
|
245
|
+
"type": "object"
|
|
246
|
+
},
|
|
247
|
+
"then": {
|
|
248
|
+
"$ref": "#/$defs/figure"
|
|
249
|
+
}
|
|
250
|
+
},
|
|
251
|
+
{
|
|
252
|
+
"if": {
|
|
253
|
+
"properties": {
|
|
254
|
+
"type": {
|
|
255
|
+
"const": "labelled-figure"
|
|
256
|
+
}
|
|
257
|
+
},
|
|
258
|
+
"required": ["type"],
|
|
259
|
+
"type": "object"
|
|
260
|
+
},
|
|
261
|
+
"then": {
|
|
262
|
+
"$ref": "#/$defs/labelledFigure"
|
|
263
|
+
}
|
|
264
|
+
},
|
|
265
|
+
{
|
|
266
|
+
"if": {
|
|
267
|
+
"properties": {
|
|
268
|
+
"type": {
|
|
269
|
+
"const": "table"
|
|
270
|
+
}
|
|
271
|
+
},
|
|
272
|
+
"required": ["type"],
|
|
273
|
+
"type": "object"
|
|
274
|
+
},
|
|
275
|
+
"then": {
|
|
276
|
+
"$ref": "#/$defs/table"
|
|
277
|
+
}
|
|
278
|
+
},
|
|
279
|
+
{
|
|
280
|
+
"if": {
|
|
281
|
+
"properties": {
|
|
282
|
+
"type": {
|
|
283
|
+
"const": "quote"
|
|
284
|
+
}
|
|
285
|
+
},
|
|
286
|
+
"required": ["type"],
|
|
287
|
+
"type": "object"
|
|
288
|
+
},
|
|
289
|
+
"then": {
|
|
290
|
+
"$ref": "#/$defs/quote"
|
|
291
|
+
}
|
|
292
|
+
},
|
|
293
|
+
{
|
|
294
|
+
"if": {
|
|
295
|
+
"properties": {
|
|
296
|
+
"type": {
|
|
297
|
+
"const": "code"
|
|
298
|
+
}
|
|
299
|
+
},
|
|
300
|
+
"required": ["type"],
|
|
301
|
+
"type": "object"
|
|
302
|
+
},
|
|
303
|
+
"then": {
|
|
304
|
+
"$ref": "#/$defs/code"
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
],
|
|
308
|
+
"unevaluatedProperties": false
|
|
309
|
+
},
|
|
310
|
+
"textBlock": {
|
|
311
|
+
"description": "Prose in restricted Markdown.",
|
|
312
|
+
"required": ["text"],
|
|
313
|
+
"properties": {
|
|
314
|
+
"text": {
|
|
315
|
+
"$ref": "urn:lernapps:schema:text.v1#/$defs/markdown"
|
|
316
|
+
}
|
|
317
|
+
},
|
|
318
|
+
"type": "object"
|
|
319
|
+
},
|
|
320
|
+
"formula": {
|
|
321
|
+
"description": "One formula on its own line, rendered at build to MathML.",
|
|
322
|
+
"required": ["formula"],
|
|
323
|
+
"properties": {
|
|
324
|
+
"formula": {
|
|
325
|
+
"$ref": "#/$defs/latex"
|
|
326
|
+
}
|
|
327
|
+
},
|
|
328
|
+
"type": "object"
|
|
329
|
+
},
|
|
330
|
+
"latex": {
|
|
331
|
+
"description": "One formula in the LaTeX subset of the formula command list: \\frac, \\cdot, \\times, \\div, \\%, \\text, ^, _, \\sqrt, \\approx, \\pm, \\le, \\ge, \\neq, \\, (thin space), parentheses and braces; \\ce{…} for chemical equations and \\pu{…} for units (mhchem). Written without the $ signs. A map by language only when it has \\text{…} that differs by language.",
|
|
332
|
+
"$ref": "urn:lernapps:schema:text.v1#/$defs/text"
|
|
333
|
+
},
|
|
334
|
+
"table": {
|
|
335
|
+
"description": "A table with a caption. Cells are restricted Markdown without paragraphs.",
|
|
336
|
+
"required": ["caption", "rows"],
|
|
337
|
+
"properties": {
|
|
338
|
+
"caption": {
|
|
339
|
+
"description": "What the table shows.",
|
|
340
|
+
"$ref": "urn:lernapps:schema:text.v1#/$defs/text"
|
|
341
|
+
},
|
|
342
|
+
"header": {
|
|
343
|
+
"description": "The header row: one heading per column.",
|
|
344
|
+
"type": "array",
|
|
345
|
+
"minItems": 1,
|
|
346
|
+
"items": {
|
|
347
|
+
"$ref": "urn:lernapps:schema:text.v1#/$defs/markdown"
|
|
348
|
+
}
|
|
349
|
+
},
|
|
350
|
+
"rowHeaders": {
|
|
351
|
+
"description": "The first cell of each row heads the row.",
|
|
352
|
+
"type": "boolean",
|
|
353
|
+
"default": false
|
|
354
|
+
},
|
|
355
|
+
"rows": {
|
|
356
|
+
"type": "array",
|
|
357
|
+
"minItems": 1,
|
|
358
|
+
"items": {
|
|
359
|
+
"type": "array",
|
|
360
|
+
"minItems": 1,
|
|
361
|
+
"items": {
|
|
362
|
+
"$ref": "urn:lernapps:schema:text.v1#/$defs/markdown"
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
},
|
|
367
|
+
"type": "object"
|
|
368
|
+
},
|
|
369
|
+
"quote": {
|
|
370
|
+
"description": "A quotation, quoted exactly, with its origin, source and licence.",
|
|
371
|
+
"required": ["text", "origin", "source", "licence"],
|
|
372
|
+
"allOf": [
|
|
373
|
+
{
|
|
374
|
+
"$ref": "#/$defs/credit"
|
|
375
|
+
}
|
|
376
|
+
],
|
|
377
|
+
"properties": {
|
|
378
|
+
"text": {
|
|
379
|
+
"description": "The quotation itself, exactly as written.",
|
|
380
|
+
"$ref": "urn:lernapps:schema:text.v1#/$defs/markdown"
|
|
381
|
+
},
|
|
382
|
+
"origin": {
|
|
383
|
+
"description": "Who said or wrote it, where and when.",
|
|
384
|
+
"type": "object",
|
|
385
|
+
"additionalProperties": false,
|
|
386
|
+
"required": ["author"],
|
|
387
|
+
"properties": {
|
|
388
|
+
"author": {
|
|
389
|
+
"description": "Who said or wrote it. A name is the same in every language: a string, or a map by language where it differs.",
|
|
390
|
+
"$ref": "urn:lernapps:schema:text.v1#/$defs/text"
|
|
391
|
+
},
|
|
392
|
+
"work": {
|
|
393
|
+
"description": "Where it was said or written: the work, as it is called; a string, or a map by language where its title is translated.",
|
|
394
|
+
"$ref": "urn:lernapps:schema:text.v1#/$defs/text"
|
|
395
|
+
},
|
|
396
|
+
"year": {
|
|
397
|
+
"anyOf": [
|
|
398
|
+
{
|
|
399
|
+
"type": "integer"
|
|
400
|
+
},
|
|
401
|
+
{
|
|
402
|
+
"$ref": "urn:lernapps:schema:text.v1#/$defs/text"
|
|
403
|
+
}
|
|
404
|
+
],
|
|
405
|
+
"description": "When: a year, or a text such as um 500 v. Chr."
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
}
|
|
409
|
+
},
|
|
410
|
+
"type": "object"
|
|
411
|
+
},
|
|
412
|
+
"code": {
|
|
413
|
+
"description": "Program code, highlighted at build.",
|
|
414
|
+
"required": ["language", "code"],
|
|
415
|
+
"properties": {
|
|
416
|
+
"language": {
|
|
417
|
+
"enum": ["bash", "c", "css", "html", "java", "javascript", "json", "plaintext", "python", "sql", "typescript"]
|
|
418
|
+
},
|
|
419
|
+
"code": {
|
|
420
|
+
"description": "The code, as it is.",
|
|
421
|
+
"type": "string",
|
|
422
|
+
"minLength": 1
|
|
423
|
+
},
|
|
424
|
+
"caption": {
|
|
425
|
+
"description": "What the code does.",
|
|
426
|
+
"$ref": "urn:lernapps:schema:text.v1#/$defs/text"
|
|
427
|
+
}
|
|
428
|
+
},
|
|
429
|
+
"type": "object"
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
// Code blocks, highlighted at build time by highlight.js into spans with classes (blocks.css colours them): the
|
|
2
|
+
// page needs no script for it. The languages are a fixed list, the schema's $defs/code.
|
|
3
|
+
import hljs from "highlight.js/lib/core";
|
|
4
|
+
import bash from "highlight.js/lib/languages/bash";
|
|
5
|
+
import c from "highlight.js/lib/languages/c";
|
|
6
|
+
import css from "highlight.js/lib/languages/css";
|
|
7
|
+
import java from "highlight.js/lib/languages/java";
|
|
8
|
+
import javascript from "highlight.js/lib/languages/javascript";
|
|
9
|
+
import json from "highlight.js/lib/languages/json";
|
|
10
|
+
import python from "highlight.js/lib/languages/python";
|
|
11
|
+
import sql from "highlight.js/lib/languages/sql";
|
|
12
|
+
import typescript from "highlight.js/lib/languages/typescript";
|
|
13
|
+
import xml from "highlight.js/lib/languages/xml";
|
|
14
|
+
import { escapeText } from "../html.ts";
|
|
15
|
+
|
|
16
|
+
const languages = { bash, c, css, html: xml, java, javascript, json, python, sql, typescript };
|
|
17
|
+
for (const [name, language] of Object.entries(languages)) hljs.registerLanguage(name, language);
|
|
18
|
+
|
|
19
|
+
/** The languages a code block may have. */
|
|
20
|
+
export type CodeLanguage = keyof typeof languages | "plaintext";
|
|
21
|
+
|
|
22
|
+
/** The code as highlighted HTML, for inside <code>. */
|
|
23
|
+
export function highlight(code: string, language: CodeLanguage): string {
|
|
24
|
+
if (language === "plaintext") return escapeText(code);
|
|
25
|
+
return hljs.highlight(code, { language, ignoreIllegals: true }).value;
|
|
26
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
// The figures drawn from data at build time, as inline SVG with role="img" and the figure's alternative text as its
|
|
2
|
+
// name: hundred-grid (a field of 100 squares, some shaded) and bar (a strip with a shaded part and its percentage).
|
|
3
|
+
import { escape } from "../html.ts";
|
|
4
|
+
|
|
5
|
+
const ON = "#1d4ed8";
|
|
6
|
+
const OFF = "#ffffff";
|
|
7
|
+
const LINE = "#4a4a4a";
|
|
8
|
+
|
|
9
|
+
/** A field of 10 × 10 squares, the first `filled` shaded, row by row. */
|
|
10
|
+
export function hundredGrid(filled: number, alt: string): string {
|
|
11
|
+
const cells: string[] = [];
|
|
12
|
+
for (let index = 0; index < 100; index++) {
|
|
13
|
+
const x = 1 + (index % 10) * 11;
|
|
14
|
+
const y = 1 + Math.floor(index / 10) * 11;
|
|
15
|
+
cells.push(
|
|
16
|
+
`<rect x="${x}" y="${y}" width="10" height="10" class="${index < filled ? "fig-on" : "fig-off"} fig-line" fill="${index < filled ? ON : OFF}" stroke="${LINE}" stroke-width="0.5"/>`,
|
|
17
|
+
);
|
|
18
|
+
}
|
|
19
|
+
return `<svg class="block-drawing block-hundred-grid" role="img" aria-label="${escape(alt)}" viewBox="0 0 111 111" xmlns="http://www.w3.org/2000/svg">${cells.join("")}</svg>`;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* A strip for `whole`, `part` of it shaded; under it 0, part and whole, and their percentages (without them in a task
|
|
24
|
+
* that asks for the percentage: `percent` false).
|
|
25
|
+
*/
|
|
26
|
+
export function bar(part: number, whole: number, alt: string, locale: string, percent = true): string {
|
|
27
|
+
const numbers = new Intl.NumberFormat(locale, { maximumFractionDigits: 2 });
|
|
28
|
+
const share = Math.min(part / whole, 1);
|
|
29
|
+
const width = 298 * share;
|
|
30
|
+
const at = Math.min(Math.max(1 + width, 50), 250);
|
|
31
|
+
const label = (x: number, y: number, anchor: string, text: string) =>
|
|
32
|
+
`<text x="${x.toFixed(1)}" y="${y}" text-anchor="${anchor}" font-size="12" class="fig-text" fill="#1a1a1a">${escape(text)}</text>`;
|
|
33
|
+
return [
|
|
34
|
+
`<svg class="block-drawing block-bar" role="img" aria-label="${escape(alt)}" viewBox="0 0 300 ${percent ? 74 : 58}" xmlns="http://www.w3.org/2000/svg">`,
|
|
35
|
+
`<rect x="1" y="1" width="298" height="36" class="fig-off fig-line" fill="${OFF}" stroke="${LINE}"/>`,
|
|
36
|
+
`<rect x="1" y="1" width="${width.toFixed(1)}" height="36" class="fig-on" fill="${ON}"/>`,
|
|
37
|
+
label(1, 54, "start", "0"),
|
|
38
|
+
label(at, 54, "middle", numbers.format(part)),
|
|
39
|
+
label(299, 54, "end", numbers.format(whole)),
|
|
40
|
+
...(percent
|
|
41
|
+
? [
|
|
42
|
+
label(1, 70, "start", "0 %"),
|
|
43
|
+
label(at, 70, "middle", `${numbers.format(share * 100)} %`),
|
|
44
|
+
label(299, 70, "end", "100 %"),
|
|
45
|
+
]
|
|
46
|
+
: []),
|
|
47
|
+
`</svg>`,
|
|
48
|
+
].join("");
|
|
49
|
+
}
|