@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.
Files changed (232) hide show
  1. package/LICENSE +22 -0
  2. package/README.md +195 -2
  3. package/dist/appname-Bh23cUuz.mjs +12 -0
  4. package/dist/assessment-Dy359O1O.mjs +1696 -0
  5. package/dist/block-BK_ohsH1.mjs +82 -0
  6. package/dist/blocks-CxtCPAa5.mjs +149 -0
  7. package/dist/blocks.mjs +4 -0
  8. package/dist/check-CteIFN96.mjs +254 -0
  9. package/dist/content-DO6oEJxj.mjs +140 -0
  10. package/dist/contract-PONpxJtd.mjs +52 -0
  11. package/dist/e2e-CU0n_unV.mjs +89 -0
  12. package/dist/engine-CArxqizW.mjs +136 -0
  13. package/dist/explainer-e2e.mjs +1311 -0
  14. package/dist/explainer-islands.mjs +197 -0
  15. package/dist/explainer-plugin.mjs +2132 -0
  16. package/dist/explainer.mjs +1246 -0
  17. package/dist/html-mffkHGHh.mjs +89 -0
  18. package/dist/image-CspJVfyQ.mjs +21 -0
  19. package/dist/interactive-e2e.mjs +140 -0
  20. package/dist/interactive-plugin.mjs +242 -0
  21. package/dist/interactive.mjs +75 -0
  22. package/dist/load-RosvaPZf.mjs +16976 -0
  23. package/dist/needs-BzEahJ6X.mjs +97 -0
  24. package/dist/pages-9RaaomoO.mjs +81 -0
  25. package/dist/questions-e2e.mjs +1 -0
  26. package/dist/questions-engine.mjs +3 -0
  27. package/dist/questions.mjs +6 -0
  28. package/dist/quiz-DnW-xtCh.mjs +70 -0
  29. package/dist/quiz-e2e.mjs +174 -0
  30. package/dist/quiz-plugin.mjs +266 -0
  31. package/dist/quiz.mjs +246 -0
  32. package/dist/render-D5kwkNt1.mjs +507 -0
  33. package/dist/render-DqHOJyHK.mjs +146 -0
  34. package/dist/render-GS1Htlu8.mjs +545 -0
  35. package/dist/result-D_mmCVwN.mjs +180 -0
  36. package/dist/tasks-DADUYy52.mjs +74 -0
  37. package/dist/validate-BDwL7Su3.mjs +1076 -0
  38. package/dist/validate-Bxy9NfB8.mjs +146 -0
  39. package/dist/vue-DO1m6q1R.mjs +40 -0
  40. package/dist/vue-code-BkJjW_I_.mjs +320 -0
  41. package/docs/arc42/01-introduction-and-goals.arc42.md +82 -0
  42. package/docs/arc42/02-constraints.arc42.md +228 -0
  43. package/docs/arc42/03-system-context.arc42.md +118 -0
  44. package/docs/arc42/04-solution-strategy.arc42.md +47 -0
  45. package/docs/arc42/05-building-blocks.arc42.md +307 -0
  46. package/docs/arc42/06-runtime-view.arc42.md +98 -0
  47. package/docs/arc42/07-deployment-view.arc42.md +160 -0
  48. package/docs/arc42/08-concepts.arc42.md +123 -0
  49. package/docs/arc42/09-decisions.arc42.md +246 -0
  50. package/docs/arc42/10-quality-requirements.arc42.md +155 -0
  51. package/docs/arc42/11-risks.arc42.md +113 -0
  52. package/docs/arc42/12-glossary.arc42.md +162 -0
  53. package/docs/arc42/architecture-evidence.md +395 -0
  54. package/explainer/.arc42ignore +3 -0
  55. package/explainer/README.md +54 -0
  56. package/explainer/_gitignore +5 -0
  57. package/explainer/docs/arc42/03-explainer-system-context.arc42.md +35 -0
  58. package/explainer/docs/arc42/05-explainer-building-blocks.arc42.md +659 -0
  59. package/explainer/docs/arc42/06-explainer-runtime-view.arc42.md +105 -0
  60. package/explainer/docs/arc42/07-explainer-deployment-view.arc42.md +34 -0
  61. package/explainer/docs/arc42/08-explainer-concepts.arc42.md +17 -0
  62. package/explainer/docs/arc42/09-explainer-decisions.arc42.md +443 -0
  63. package/explainer/docs/arc42/10-explainer-quality-requirements.arc42.md +54 -0
  64. package/explainer/docs/arc42/11-explainer-risks.arc42.md +17 -0
  65. package/explainer/docs/arc42/12-explainer-glossary.arc42.md +185 -0
  66. package/explainer/e2e/explainer.e2e.ts +3 -0
  67. package/explainer/index.html +11 -0
  68. package/explainer/package.json +18 -0
  69. package/explainer/playwright.config.ts +1 -0
  70. package/explainer/src/app.yaml +20 -0
  71. package/explainer/src/components/ProzentFeld.test.ts +30 -0
  72. package/explainer/src/components/ProzentFeld.ts +121 -0
  73. package/explainer/src/components/ProzentFeld.vue +84 -0
  74. package/explainer/src/images/hunderterfeld-klammern.svg +105 -0
  75. package/explainer/src/main.ts +4 -0
  76. package/explainer/src/prozent/chapter.yaml +18 -0
  77. package/explainer/src/prozent/grundwert.yaml +115 -0
  78. package/explainer/src/prozent/prozentsatz.yaml +99 -0
  79. package/explainer/src/prozent/prozentwert.yaml +119 -0
  80. package/explainer/tsconfig.json +1 -0
  81. package/explainer/vite.config.ts +4 -0
  82. package/interactive/.arc42ignore +5 -0
  83. package/interactive/README.md +28 -0
  84. package/interactive/_gitignore +4 -0
  85. package/interactive/docs/arc42/05-interactive-building-blocks.arc42.md +518 -0
  86. package/interactive/docs/arc42/06-interactive-runtime-view.arc42.md +58 -0
  87. package/interactive/docs/arc42/07-interactive-deployment-view.arc42.md +35 -0
  88. package/interactive/docs/arc42/08-interactive-concepts.arc42.md +52 -0
  89. package/interactive/docs/arc42/09-interactive-decisions.arc42.md +130 -0
  90. package/interactive/docs/arc42/10-interactive-quality-requirements.arc42.md +45 -0
  91. package/interactive/docs/arc42/11-interactive-risks.arc42.md +20 -0
  92. package/interactive/docs/arc42/12-interactive-glossary.arc42.md +80 -0
  93. package/interactive/e2e/interactive.e2e.ts +3 -0
  94. package/interactive/index.html +11 -0
  95. package/interactive/package.json +18 -0
  96. package/interactive/playwright.config.ts +1 -0
  97. package/interactive/src/app.yaml +28 -0
  98. package/interactive/src/core/index.ts +101 -0
  99. package/interactive/src/data/lessons.json +4 -0
  100. package/interactive/src/env.d.ts +6 -0
  101. package/interactive/src/main.ts +6 -0
  102. package/interactive/src/messages/de.json +12 -0
  103. package/interactive/src/playthroughs/grundreihe.yaml +33 -0
  104. package/interactive/src/playthroughs/obere-reihe.yaml +14 -0
  105. package/interactive/src/ui/App.vue +85 -0
  106. package/interactive/tsconfig.json +1 -0
  107. package/interactive/vite.config.ts +4 -0
  108. package/package.json +143 -4
  109. package/quiz/README.md +31 -0
  110. package/quiz/_gitignore +5 -0
  111. package/quiz/docs/arc42/05-quiz-building-blocks.arc42.md +283 -0
  112. package/quiz/docs/arc42/06-quiz-runtime-view.arc42.md +21 -0
  113. package/quiz/docs/arc42/07-quiz-deployment-view.arc42.md +33 -0
  114. package/quiz/docs/arc42/09-quiz-decisions.arc42.md +36 -0
  115. package/quiz/docs/arc42/10-quiz-quality-requirements.arc42.md +53 -0
  116. package/quiz/docs/arc42/11-quiz-risks.arc42.md +19 -0
  117. package/quiz/docs/arc42/12-quiz-glossary.arc42.md +27 -0
  118. package/quiz/e2e/quiz.e2e.ts +3 -0
  119. package/quiz/index.html +11 -0
  120. package/quiz/package.json +18 -0
  121. package/quiz/playwright.config.ts +1 -0
  122. package/quiz/src/images/berge-ordnen.jpg +0 -0
  123. package/quiz/src/images/everest-hoehe.jpg +0 -0
  124. package/quiz/src/images/galapagos.jpg +0 -0
  125. package/quiz/src/images/grand-canyon.jpg +0 -0
  126. package/quiz/src/images/totes-meer.jpg +0 -0
  127. package/quiz/src/images/uluru.jpg +0 -0
  128. package/quiz/src/images/wasserfaelle-laender.jpg +0 -0
  129. package/quiz/src/main.ts +4 -0
  130. package/quiz/src/quiz.json +312 -0
  131. package/quiz/tsconfig.json +1 -0
  132. package/quiz/vite.config.ts +4 -0
  133. package/runtime/explainer/assessment-client.ts +478 -0
  134. package/runtime/explainer/assessment-page.ts +448 -0
  135. package/runtime/explainer/assessment.ts +393 -0
  136. package/runtime/explainer/check-page.ts +520 -0
  137. package/runtime/explainer/components/exercise.ts +409 -0
  138. package/runtime/explainer/components/props.ts +230 -0
  139. package/runtime/explainer/components/read.ts +428 -0
  140. package/runtime/explainer/content.ts +277 -0
  141. package/runtime/explainer/e2e.ts +1488 -0
  142. package/runtime/explainer/exercises.ts +326 -0
  143. package/runtime/explainer/explainer.css +1283 -0
  144. package/runtime/explainer/explainer.ts +838 -0
  145. package/runtime/explainer/explainer.v1.schema.json +1165 -0
  146. package/runtime/explainer/expression.ts +407 -0
  147. package/runtime/explainer/fraction.ts +107 -0
  148. package/runtime/explainer/generated/comparator.ts +31 -0
  149. package/runtime/explainer/generated/question.ts +165 -0
  150. package/runtime/explainer/generated/soundness.ts +280 -0
  151. package/runtime/explainer/generated/texts.ts +257 -0
  152. package/runtime/explainer/generated/types.ts +103 -0
  153. package/runtime/explainer/generated/values.ts +136 -0
  154. package/runtime/explainer/islands.ts +281 -0
  155. package/runtime/explainer/load.ts +457 -0
  156. package/runtime/explainer/messages/de.json +200 -0
  157. package/runtime/explainer/messages/en.json +200 -0
  158. package/runtime/explainer/messages.ts +13 -0
  159. package/runtime/explainer/needs.ts +122 -0
  160. package/runtime/explainer/open-task.ts +235 -0
  161. package/runtime/explainer/outline.ts +306 -0
  162. package/runtime/explainer/plugin.ts +488 -0
  163. package/runtime/explainer/position.ts +62 -0
  164. package/runtime/explainer/prompt.ts +75 -0
  165. package/runtime/explainer/render.ts +686 -0
  166. package/runtime/explainer/result.ts +238 -0
  167. package/runtime/explainer/routes.ts +119 -0
  168. package/runtime/explainer/schema.ts +140 -0
  169. package/runtime/explainer/scope.ts +87 -0
  170. package/runtime/explainer/stuck.ts +57 -0
  171. package/runtime/explainer/tasks.ts +109 -0
  172. package/runtime/explainer/tutor.ts +469 -0
  173. package/runtime/explainer/tutorpage.ts +669 -0
  174. package/runtime/explainer/video.ts +123 -0
  175. package/runtime/interactive/contract.ts +121 -0
  176. package/runtime/interactive/e2e.ts +190 -0
  177. package/runtime/interactive/interactive.css +82 -0
  178. package/runtime/interactive/interactive.ts +115 -0
  179. package/runtime/interactive/interactive.v1.schema.json +146 -0
  180. package/runtime/interactive/load.ts +188 -0
  181. package/runtime/interactive/messages/de.json +14 -0
  182. package/runtime/interactive/messages/en.json +14 -0
  183. package/runtime/interactive/messages.ts +11 -0
  184. package/runtime/interactive/playthrough.v1.schema.json +143 -0
  185. package/runtime/interactive/plugin.ts +266 -0
  186. package/runtime/interactive/render.ts +126 -0
  187. package/runtime/quiz/e2e.ts +233 -0
  188. package/runtime/quiz/engine.ts +242 -0
  189. package/runtime/quiz/messages/de.json +23 -0
  190. package/runtime/quiz/messages/en.json +23 -0
  191. package/runtime/quiz/plugin.ts +150 -0
  192. package/runtime/quiz/quiz.css +154 -0
  193. package/runtime/quiz/quiz.ts +56 -0
  194. package/runtime/quiz/quiz.v1.schema.json +72 -0
  195. package/runtime/quiz/render.ts +173 -0
  196. package/runtime/quiz/validate.ts +108 -0
  197. package/runtime/shared/appname.ts +16 -0
  198. package/runtime/shared/blocks/block.ts +162 -0
  199. package/runtime/shared/blocks/blocks.css +190 -0
  200. package/runtime/shared/blocks/blocks.v1.schema.json +432 -0
  201. package/runtime/shared/blocks/code.ts +26 -0
  202. package/runtime/shared/blocks/figures.ts +49 -0
  203. package/runtime/shared/blocks/image.ts +25 -0
  204. package/runtime/shared/blocks/index.ts +13 -0
  205. package/runtime/shared/blocks/messages/de.json +4 -0
  206. package/runtime/shared/blocks/messages/en.json +4 -0
  207. package/runtime/shared/blocks/render.ts +134 -0
  208. package/runtime/shared/blocks/validate.ts +165 -0
  209. package/runtime/shared/content.ts +197 -0
  210. package/runtime/shared/examples.ts +20 -0
  211. package/runtime/shared/html.ts +10 -0
  212. package/runtime/shared/languages.ts +94 -0
  213. package/runtime/shared/page.css +101 -0
  214. package/runtime/shared/pages.ts +114 -0
  215. package/runtime/shared/questions/e2e.ts +115 -0
  216. package/runtime/shared/questions/engine.ts +209 -0
  217. package/runtime/shared/questions/index.ts +39 -0
  218. package/runtime/shared/questions/messages/de.json +26 -0
  219. package/runtime/shared/questions/messages/en.json +26 -0
  220. package/runtime/shared/questions/question.ts +433 -0
  221. package/runtime/shared/questions/question.v1.schema.json +346 -0
  222. package/runtime/shared/questions/questions.css +192 -0
  223. package/runtime/shared/questions/render.ts +255 -0
  224. package/runtime/shared/questions/validate.ts +518 -0
  225. package/runtime/shared/schema.ts +44 -0
  226. package/runtime/shared/text/check.ts +68 -0
  227. package/runtime/shared/text/formula.ts +69 -0
  228. package/runtime/shared/text/markdown.ts +185 -0
  229. package/runtime/shared/text/speech.ts +39 -0
  230. package/runtime/shared/text/text.v1.schema.json +34 -0
  231. package/runtime/shared/vue-code.ts +395 -0
  232. package/runtime/shared/vue.ts +38 -0
@@ -0,0 +1,346 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "urn:lernapps:schema:question.v1",
4
+ "title": "A question of a lernapps app",
5
+ "description": "One question of the six types (single-choice, multiple-choice, true-false, number, ordering, matching) as the quiz's question bank and the explainer's exercises write it. Use #/$defs/question for one question; the schemas of the quiz and of the explainer refer to it.",
6
+ "$defs": {
7
+ "question": {
8
+ "type": "object",
9
+ "required": ["id", "type", "text", "explanation", "links"],
10
+ "properties": {
11
+ "id": {
12
+ "description": "Stable name of the question, used in its address (#frage-<id>): lower-case letters, digits and hyphens. Keep it when the text changes, so links to the question keep working.",
13
+ "type": "string",
14
+ "pattern": "^[a-z0-9]+(-[a-z0-9]+)*$"
15
+ },
16
+ "type": {
17
+ "description": "The kind of question.",
18
+ "enum": ["single-choice", "multiple-choice", "true-false", "number", "ordering", "matching"]
19
+ },
20
+ "text": {
21
+ "description": "The question, complete in itself.",
22
+ "$ref": "urn:lernapps:schema:text.v1#/$defs/text"
23
+ },
24
+ "material": {
25
+ "description": "Optional: content that the question shows, between its text and its answers: prose, formulas, figures and labelled figures (bundled images in src/images/, or drawn from data), tables, quotations and code. A figure has an alternative text and a caption, and an image its source and licence. A question that asks about what the content shows needs it; one that merely looks nicer with an image should not have one.",
26
+ "type": "array",
27
+ "minItems": 1,
28
+ "items": {
29
+ "$ref": "urn:lernapps:schema:blocks.v1#/$defs/materialBlock"
30
+ }
31
+ },
32
+ "explanation": {
33
+ "description": "Why the right answer is right, in one to three sentences. For number, ordering and matching questions also the background knowledge, as their options carry none.",
34
+ "$ref": "urn:lernapps:schema:text.v1#/$defs/text"
35
+ },
36
+ "links": {
37
+ "description": "Further reading on the question, at least one link, e.g. to the article in the German Wikipedia; in a quiz or on a page in several languages to the article in each language's Wikipedia, with url as a map by language.",
38
+ "type": "array",
39
+ "minItems": 1,
40
+ "items": {
41
+ "$ref": "#/$defs/link"
42
+ }
43
+ },
44
+ "hint": {
45
+ "description": "Optional: what to look at again after a wrong answer, in one sentence, without giving the answer away, e.g. \"Schau dir noch einmal an, wie hoch die Spannung im Haushalt ist.\" Shown with the feedback of a wrong answer when nothing more specific applies: a chosen option's info or a number's typical mistake come first. In an explainer, a wrong answer can be tried again, with this hint, before the solution shows.",
46
+ "$ref": "urn:lernapps:schema:text.v1#/$defs/text"
47
+ },
48
+ "examples": {
49
+ "$ref": "#/$defs/examples"
50
+ }
51
+ },
52
+ "allOf": [
53
+ {
54
+ "if": {
55
+ "type": "object",
56
+ "properties": {
57
+ "type": {
58
+ "const": "single-choice"
59
+ }
60
+ },
61
+ "required": ["type"]
62
+ },
63
+ "then": {
64
+ "$ref": "#/$defs/choice"
65
+ }
66
+ },
67
+ {
68
+ "if": {
69
+ "type": "object",
70
+ "properties": {
71
+ "type": {
72
+ "const": "multiple-choice"
73
+ }
74
+ },
75
+ "required": ["type"]
76
+ },
77
+ "then": {
78
+ "$ref": "#/$defs/choice"
79
+ }
80
+ },
81
+ {
82
+ "if": {
83
+ "type": "object",
84
+ "properties": {
85
+ "type": {
86
+ "const": "true-false"
87
+ }
88
+ },
89
+ "required": ["type"]
90
+ },
91
+ "then": {
92
+ "$ref": "#/$defs/trueFalse"
93
+ }
94
+ },
95
+ {
96
+ "if": {
97
+ "type": "object",
98
+ "properties": {
99
+ "type": {
100
+ "const": "number"
101
+ }
102
+ },
103
+ "required": ["type"]
104
+ },
105
+ "then": {
106
+ "$ref": "#/$defs/number"
107
+ }
108
+ },
109
+ {
110
+ "if": {
111
+ "type": "object",
112
+ "properties": {
113
+ "type": {
114
+ "const": "ordering"
115
+ }
116
+ },
117
+ "required": ["type"]
118
+ },
119
+ "then": {
120
+ "$ref": "#/$defs/ordering"
121
+ }
122
+ },
123
+ {
124
+ "if": {
125
+ "type": "object",
126
+ "properties": {
127
+ "type": {
128
+ "const": "matching"
129
+ }
130
+ },
131
+ "required": ["type"]
132
+ },
133
+ "then": {
134
+ "$ref": "#/$defs/matching"
135
+ }
136
+ }
137
+ ],
138
+ "unevaluatedProperties": false
139
+ },
140
+ "examples": {
141
+ "description": "Optional: test cases for the build, never shown to learners. Before you write the question, note which answers fulfil its text and which typical wrong answers there are; write the other correct answers the text allows (also those other than the one you marked) into accepted, the typical wrong ones into rejected. The build runs each through the same check the page uses and fails when it accepts a rejected answer or rejects an accepted one: then the question checks something other than what its text asks (e.g. an ordering whose text says the order does not matter), so change the question or its text. An answer as the learner gives it, by the type: single-choice an option; multiple-choice a list of options, e.g. [0, 2]; true-false true or false; number a number, or the text as a learner types it, e.g. \"12,5\"; ordering every item in the learner's order; matching a list of pairs [left, right], one for each left entry. An option, item or entry is its index from 0 in the order written, or its text as written (in German). A number's mistakes and the info of wrong options already count as rejected.",
142
+ "type": "object",
143
+ "additionalProperties": false,
144
+ "minProperties": 1,
145
+ "properties": {
146
+ "accepted": {
147
+ "description": "Answers the text allows, each of which the check must accept.",
148
+ "type": "array",
149
+ "minItems": 1,
150
+ "items": {
151
+ "$ref": "#/$defs/exampleAnswer"
152
+ }
153
+ },
154
+ "rejected": {
155
+ "description": "Typical wrong answers, each of which the check must reject.",
156
+ "type": "array",
157
+ "minItems": 1,
158
+ "items": {
159
+ "$ref": "#/$defs/exampleAnswer"
160
+ }
161
+ }
162
+ }
163
+ },
164
+ "exampleAnswer": {
165
+ "description": "An answer as the learner gives it, in the shape of the question's type (see examples); the build checks its shape."
166
+ },
167
+ "choice": {
168
+ "type": "object",
169
+ "description": "Single choice: exactly one option is correct. Multiple choice: at least one option is correct, and the learner selects every correct one.",
170
+ "required": ["options"],
171
+ "properties": {
172
+ "options": {
173
+ "type": "array",
174
+ "minItems": 2,
175
+ "maxItems": 8,
176
+ "items": {
177
+ "type": "object",
178
+ "additionalProperties": false,
179
+ "required": ["text", "correct", "info"],
180
+ "properties": {
181
+ "text": {
182
+ "description": "The option as the learner reads it.",
183
+ "$ref": "urn:lernapps:schema:text.v1#/$defs/text"
184
+ },
185
+ "correct": {
186
+ "description": "Whether this option is correct.",
187
+ "type": "boolean"
188
+ },
189
+ "info": {
190
+ "description": "One to three sentences of background on this option itself, true whether or not it is the right answer, e.g. \"Der Uluru ist ein Inselberg in der Wüste Zentralaustraliens ...\". After an answer it shows for every option. For a wrong option it is also the reason a learner who chose it reads with the feedback, so say there why it does not fit.",
191
+ "$ref": "urn:lernapps:schema:text.v1#/$defs/text"
192
+ },
193
+ "alt": {
194
+ "description": "Optional: the option as it is spoken, for the name of its radio button or checkbox, when its text is only a formula, e.g. \"zwei hoch sieben\" for \"$2^7$\". Without it the name is made from the formula in the page's language (\"2 hoch 7\"); write it where that reads badly, e.g. for a chemical formula. Not needed when the text has words.",
195
+ "$ref": "urn:lernapps:schema:text.v1#/$defs/text"
196
+ },
197
+ "link": {
198
+ "description": "Further reading on this option.",
199
+ "$ref": "#/$defs/link"
200
+ }
201
+ }
202
+ }
203
+ }
204
+ }
205
+ },
206
+ "trueFalse": {
207
+ "type": "object",
208
+ "description": "A statement the learner judges as true or false; the background goes into the explanation.",
209
+ "required": ["answer"],
210
+ "properties": {
211
+ "answer": {
212
+ "description": "Whether the statement is true.",
213
+ "type": "boolean"
214
+ }
215
+ }
216
+ },
217
+ "number": {
218
+ "type": "object",
219
+ "description": "The learner types a number; it counts when it is within the tolerance of the answer. A comma or a point both work as the decimal sign. The background goes into the explanation.",
220
+ "required": ["answer", "tolerance"],
221
+ "properties": {
222
+ "answer": {
223
+ "description": "The right number.",
224
+ "type": "number"
225
+ },
226
+ "tolerance": {
227
+ "description": "How far the learner's number may be from the answer and still count; 0 for an exact answer. Match it to the rounding the question asks for.",
228
+ "type": "number",
229
+ "minimum": 0
230
+ },
231
+ "unit": {
232
+ "description": "The unit, shown next to the input, e.g. \"cm\"; the learner does not type it.",
233
+ "$ref": "urn:lernapps:schema:text.v1#/$defs/text"
234
+ },
235
+ "mistakes": {
236
+ "description": "Optional: typical wrong numbers, each with a message that says what went wrong, e.g. { \"answer\": 2300, \"message\": \"Du hast mit 10 statt mit 100 multipliziert.\" }. A learner's number within the tolerance of a mistake's answer gets its message with the feedback. A mistake's answer must not count as right, and each is listed once.",
237
+ "type": "array",
238
+ "minItems": 1,
239
+ "items": {
240
+ "type": "object",
241
+ "additionalProperties": false,
242
+ "required": ["answer", "message"],
243
+ "properties": {
244
+ "answer": {
245
+ "description": "The wrong number, as the mistake gives it.",
246
+ "type": "number"
247
+ },
248
+ "message": {
249
+ "description": "What went wrong, in one or two sentences, without giving the right number away.",
250
+ "$ref": "urn:lernapps:schema:text.v1#/$defs/text"
251
+ }
252
+ }
253
+ }
254
+ }
255
+ }
256
+ },
257
+ "ordering": {
258
+ "type": "object",
259
+ "description": "The learner puts the items in order, e.g. by height. Write them in the right order: the page shows them mixed. The background goes into the explanation.",
260
+ "required": ["items"],
261
+ "properties": {
262
+ "items": {
263
+ "type": "array",
264
+ "minItems": 2,
265
+ "maxItems": 8,
266
+ "items": {
267
+ "$ref": "urn:lernapps:schema:text.v1#/$defs/text"
268
+ }
269
+ }
270
+ }
271
+ },
272
+ "matching": {
273
+ "type": "object",
274
+ "description": "The learner matches each left entry with its right entry. Write the pairs as they belong together: the page shows the right entries mixed. The background goes into the explanation. Instead of the pairs, a question about a figure to label takes them from the figure (pairsFrom).",
275
+ "properties": {
276
+ "pairsFrom": {
277
+ "description": "material: the pairs are the labels of the labelled figure in the material, each marker (A, B, 1) on the left with its text on the right, so that they are written once. The figure must have legend: false, as its legend would give the answers away; the solution lists them. Write either the pairs or pairsFrom.",
278
+ "const": "material"
279
+ },
280
+ "distractors": {
281
+ "description": "Optional: right entries that match none of the left entries, wrong answers the learner may choose, shown mixed with the right entries. Use them for plausible mistakes, or for entries that have nothing to do with the task; 1 to 4 of them.",
282
+ "type": "array",
283
+ "minItems": 1,
284
+ "maxItems": 4,
285
+ "items": {
286
+ "$ref": "urn:lernapps:schema:text.v1#/$defs/text"
287
+ }
288
+ },
289
+ "pairs": {
290
+ "description": "The pairs, written out. Without pairsFrom they are required.",
291
+ "type": "array",
292
+ "minItems": 2,
293
+ "maxItems": 8,
294
+ "items": {
295
+ "type": "object",
296
+ "additionalProperties": false,
297
+ "required": ["left", "right"],
298
+ "properties": {
299
+ "left": {
300
+ "$ref": "urn:lernapps:schema:text.v1#/$defs/text"
301
+ },
302
+ "right": {
303
+ "$ref": "urn:lernapps:schema:text.v1#/$defs/text"
304
+ }
305
+ }
306
+ }
307
+ }
308
+ }
309
+ },
310
+ "link": {
311
+ "type": "object",
312
+ "additionalProperties": false,
313
+ "required": ["title", "url"],
314
+ "properties": {
315
+ "title": {
316
+ "description": "The link's text: what the learner finds there, e.g. \"Uluru (Wikipedia)\".",
317
+ "$ref": "urn:lernapps:schema:text.v1#/$defs/text"
318
+ },
319
+ "url": {
320
+ "description": "The address, https only: one for every language, or, in a quiz or on a page in several languages where the page to read differs by language (the article in each language's Wikipedia), a map of addresses by language ({ \"de\": \"https://de.wikipedia.org/wiki/Uluru\", \"en\": \"https://en.wikipedia.org/wiki/Uluru\" }) with every declared language, as a text's map. Each language's page links the address of its language. Check that each opens the page you mean.",
321
+ "$ref": "#/$defs/address"
322
+ }
323
+ }
324
+ },
325
+ "address": {
326
+ "description": "An address, https only: a string, the same in every language, or a map of addresses by language ({ de: …, en: … }) in a quiz or on a page in several languages. The quiz or page checks that a map has every language it declares, and no other.",
327
+ "anyOf": [
328
+ {
329
+ "type": "string",
330
+ "pattern": "^https://[^\\s]+$"
331
+ },
332
+ {
333
+ "type": "object",
334
+ "minProperties": 1,
335
+ "propertyNames": {
336
+ "pattern": "^[a-z]{2}$"
337
+ },
338
+ "additionalProperties": {
339
+ "type": "string",
340
+ "pattern": "^https://[^\\s]+$"
341
+ }
342
+ }
343
+ ]
344
+ }
345
+ }
346
+ }
@@ -0,0 +1,192 @@
1
+ /* The look of a question, for every archetype that has questions; the stylesheets of the quiz and of the explainer
2
+ import it. Its fieldset, its controls, the button to check it, its feedback and the background of its options, in the
3
+ colours of the page (page.css). */
4
+
5
+ .question {
6
+ margin: 0 0 1.5rem;
7
+ }
8
+
9
+ .question fieldset {
10
+ margin: 0;
11
+ padding: 0.75rem 1rem;
12
+ border: 1px solid var(--page-border);
13
+ border-radius: 0.5rem;
14
+ background: var(--page-surface);
15
+ min-width: 0;
16
+ }
17
+
18
+ .question legend {
19
+ padding: 0 0.25rem;
20
+ font-weight: 600;
21
+ }
22
+
23
+ .question-material {
24
+ margin: 0.75rem 0;
25
+ }
26
+
27
+ .question-material > :first-child {
28
+ margin-top: 0;
29
+ }
30
+
31
+ .question-material > :last-child {
32
+ margin-bottom: 0;
33
+ }
34
+
35
+ .question-option {
36
+ display: flex;
37
+ gap: 0.5rem;
38
+ align-items: flex-start;
39
+ padding: 0.375rem 0;
40
+ }
41
+
42
+ .question-option input {
43
+ margin-top: 0.3rem;
44
+ flex: none;
45
+ }
46
+
47
+ .question-number input,
48
+ .question-pairs select {
49
+ font: inherit;
50
+ padding: 0.25rem 0.5rem;
51
+ border: 1px solid var(--page-border);
52
+ border-radius: 0.25rem;
53
+ background: var(--page-background);
54
+ color: var(--page-text);
55
+ max-width: 100%;
56
+ }
57
+
58
+ .question-number input {
59
+ width: 8rem;
60
+ }
61
+
62
+ .question-pairs {
63
+ list-style: none;
64
+ padding: 0;
65
+ margin: 0;
66
+ }
67
+
68
+ .question-pairs li {
69
+ padding: 0.375rem 0;
70
+ }
71
+
72
+ .question-pairs label {
73
+ display: flex;
74
+ flex-wrap: wrap;
75
+ gap: 0.5rem;
76
+ align-items: center;
77
+ }
78
+
79
+ .question-hint {
80
+ margin: 0 0 0.5rem;
81
+ color: var(--page-muted);
82
+ }
83
+
84
+ .question-actions {
85
+ display: flex;
86
+ flex-wrap: wrap;
87
+ gap: 0.5rem;
88
+ }
89
+
90
+ .question-feedback:not(:empty) {
91
+ margin: 0.75rem 0;
92
+ padding: 0.5rem 1rem;
93
+ border-radius: 0.375rem;
94
+ border: 1px solid var(--page-border);
95
+ }
96
+
97
+ .question-feedback p {
98
+ margin: 0.25rem 0;
99
+ }
100
+
101
+ .question-right {
102
+ background: var(--page-right-background);
103
+ color: var(--page-right);
104
+ }
105
+
106
+ .question-wrong {
107
+ background: var(--page-wrong-background);
108
+ color: var(--page-wrong);
109
+ }
110
+
111
+ .question-infos,
112
+ .question-links {
113
+ padding-left: 0;
114
+ list-style: none;
115
+ }
116
+
117
+ .question-info {
118
+ margin: 0.5rem 0;
119
+ padding: 0.5rem 0.75rem;
120
+ border: 1px solid var(--page-border);
121
+ border-left-width: 4px;
122
+ border-radius: 0.375rem;
123
+ }
124
+
125
+ .question-info p {
126
+ margin: 0.25rem 0;
127
+ }
128
+
129
+ .question-info-right {
130
+ border-left-color: var(--page-right);
131
+ }
132
+
133
+ .question-info-chosen:not(.question-info-right) {
134
+ border-left-color: var(--page-wrong);
135
+ }
136
+
137
+ .question-badge {
138
+ display: inline-block;
139
+ margin-left: 0.25rem;
140
+ padding: 0 0.5rem;
141
+ border-radius: 999px;
142
+ font-size: 0.875rem;
143
+ font-weight: 600;
144
+ }
145
+
146
+ .question-badge-right {
147
+ background: var(--page-right-background);
148
+ color: var(--page-right);
149
+ }
150
+
151
+ .question-badge-chosen {
152
+ background: var(--page-surface);
153
+ color: var(--page-text);
154
+ border: 1px solid var(--page-border);
155
+ }
156
+
157
+ .question-links li {
158
+ margin: 0.25rem 0;
159
+ }
160
+
161
+ .question-more {
162
+ margin-bottom: 0;
163
+ font-weight: 600;
164
+ }
165
+
166
+ .question button {
167
+ font: inherit;
168
+ padding: 0.5rem 1rem;
169
+ border: 2px solid var(--page-accent);
170
+ border-radius: 0.375rem;
171
+ background: var(--page-accent);
172
+ color: var(--page-on-accent);
173
+ cursor: pointer;
174
+ }
175
+
176
+ .question button.question-solve {
177
+ background: var(--page-background);
178
+ color: var(--page-accent);
179
+ }
180
+
181
+ .question button:focus-visible,
182
+ .question a:focus-visible,
183
+ .question input:focus-visible,
184
+ .question select:focus-visible,
185
+ .question summary:focus-visible {
186
+ outline: 3px solid var(--page-text);
187
+ outline-offset: 2px;
188
+ }
189
+
190
+ .question-diagnosis {
191
+ margin: 0.25rem 0 0;
192
+ }