commit 36c7430ca5bf7cbe258333b852af89cf334ffb61
parent e18fcd315136bcad4b76036293c13650aabe630d
Author: hrryt <harry@mayesfield.uk>
Date: Mon, 17 Aug 2026 12:53:34 +0100
Read questions index structure from /src/data file structure
Diffstat:
8 files changed, 102 insertions(+), 108 deletions(-)
diff --git a/src/components/QuestionWindow.jsx b/src/components/QuestionWindow.jsx
@@ -34,7 +34,7 @@ function shuffleArray(arr, n, seed) {
return Array.from({ length: n }).map(() => getRandomChoice(arr, ++seed));
}
-export default function QuestionWindow({ data, title }) {
+export default function QuestionWindow({ data }) {
const dataVariables = data.variables ?? [];
@@ -73,7 +73,7 @@ export default function QuestionWindow({ data, title }) {
});
return (
- <Window title={title}>
+ <Window title={data.title}>
{fields}
<fieldset>
<legend>Options</legend>
diff --git a/src/data/questions/GCSE/adding-fractions.js b/src/data/questions/GCSE/adding-fractions.js
@@ -0,0 +1,24 @@
+import AddingFractionsQuestion from '/src/components/questions/AddingFractionsQuestion.jsx';
+
+export const data = {
+ title: 'Adding Fractions',
+ questionLists: [{
+ id: 0,
+ n: 10,
+ questions: [{
+ type: AddingFractionsQuestion,
+ }]
+ }, {
+ id: 1,
+ n: 10,
+ questions: [{
+ type: AddingFractionsQuestion,
+ }]
+ }, {
+ id: 2,
+ n: 10,
+ questions: [{
+ type: AddingFractionsQuestion,
+ }]
+ }]
+}
diff --git a/src/data/questions/GCSE/double-transformations.js b/src/data/questions/GCSE/double-transformations.js
@@ -0,0 +1,16 @@
+import DoubleReflectionQuestion from "../../../components/questions/DoubleReflectionQuestion";
+import RotationTranslationQuestion from "../../../components/questions/RotationTranslationQuestion";
+
+export const data = {
+ title: 'Double Transformations',
+ questionLists: [{
+ id: 0,
+ n: 3,
+ questions: [{
+ type: RotationTranslationQuestion,
+ },
+ {
+ type: DoubleReflectionQuestion,
+ }]
+ }]
+}
diff --git a/src/data/questions/GCSE/quadratic-equations.js b/src/data/questions/GCSE/quadratic-equations.js
@@ -0,0 +1,31 @@
+import QuadraticEquationQuestion from '/src/components/questions/QuadraticEquationQuestion.jsx';
+import MultipleSelection from '/src/components/MultipleSelection.jsx';
+
+export const data = {
+ title: 'Quadratic Equations',
+ variables: [{
+ id: 'framing',
+ legend: 'Framing',
+ type: MultipleSelection,
+ values: ["Solve", "Factorise"],
+ }, {
+ id: 'aPlurality',
+ legend: 'Coefficient a',
+ type: MultipleSelection,
+ values: ["a=1", "a>1"],
+ default: ["a=1"],
+ }, {
+ id: 'cSigns',
+ legend: 'Coefficient c',
+ type: MultipleSelection,
+ values: ["Positive", "Negative"],
+ }],
+ questionLists: [{
+ id: 0,
+ n: 10,
+ questions: [{
+ type: QuadraticEquationQuestion,
+ variables: { aPlurality: 'aPlurality', framing: 'framing', cSigns: 'cSigns' },
+ }]
+ }]
+}
diff --git a/src/data/questions/gcse/adding-fractions.js b/src/data/questions/gcse/adding-fractions.js
@@ -1,23 +0,0 @@
-import AddingFractionsQuestion from '/src/components/questions/AddingFractionsQuestion.jsx';
-
-export const data = {
- questionLists: [{
- id: 0,
- n: 10,
- questions: [{
- type: AddingFractionsQuestion,
- }]
- }, {
- id: 1,
- n: 10,
- questions: [{
- type: AddingFractionsQuestion,
- }]
- }, {
- id: 2,
- n: 10,
- questions: [{
- type: AddingFractionsQuestion,
- }]
- }]
-}
diff --git a/src/data/questions/gcse/double-transformations.js b/src/data/questions/gcse/double-transformations.js
@@ -1,15 +0,0 @@
-import DoubleReflectionQuestion from "../../../components/questions/DoubleReflectionQuestion";
-import RotationTranslationQuestion from "../../../components/questions/RotationTranslationQuestion";
-
-export const data = {
- questionLists: [{
- id: 0,
- n: 3,
- questions: [{
- type: RotationTranslationQuestion,
- },
- {
- type: DoubleReflectionQuestion,
- }]
- }]
-}
diff --git a/src/data/questions/gcse/quadratic-equations.js b/src/data/questions/gcse/quadratic-equations.js
@@ -1,30 +0,0 @@
-import QuadraticEquationQuestion from '/src/components/questions/QuadraticEquationQuestion.jsx';
-import MultipleSelection from '/src/components/MultipleSelection.jsx';
-
-export const data = {
- variables: [{
- id: 'framing',
- legend: 'Framing',
- type: MultipleSelection,
- values: ["Solve", "Factorise"],
- }, {
- id: 'aPlurality',
- legend: 'Coefficient a',
- type: MultipleSelection,
- values: ["a=1", "a>1"],
- default: ["a=1"],
- }, {
- id: 'cSigns',
- legend: 'Coefficient c',
- type: MultipleSelection,
- values: ["Positive", "Negative"],
- }],
- questionLists: [{
- id: 0,
- n: 10,
- questions: [{
- type: QuadraticEquationQuestion,
- variables: { aPlurality: 'aPlurality', framing: 'framing', cSigns: 'cSigns' },
- }]
- }]
-}
diff --git a/src/pages/QuestionIndex.jsx b/src/pages/QuestionIndex.jsx
@@ -1,70 +1,61 @@
import { Route, Switch, Link } from 'wouter-preact';
-
import QuestionWindow from '../components/QuestionWindow.jsx';
+const data = import.meta.glob('./*/*.js', {
+ eager: true, import: 'data', base: '../data/questions'
+});
-const allQuestions = [{
- id: 'gcse',
- label: 'GCSE',
- questions: [{
- id: 'quadratic-equations',
- label: 'Quadratic Equations'
- }, {
- id: 'adding-fractions',
- label: 'Adding Fractions'
- }, {
- id: 'double-transformations',
- label: 'Double Transformations'
- }]
-}, {
- id: 'a-level',
- label: 'A-Level',
- questions: []
-}]
+function getHref(path) {
+ const relative = path.match(/\.\/(.+).js/)[1];
+ return `/questions/${relative}`;
+}
-function QuestionItem({ id, question }) {
+function QuestionLink({ href, title }) {
return (
<li>
- <Link href={`/questions/${id}/${question.id}`}>
- {question.label}
+ <Link href={href}>
+ {title}
</Link>
</li>
);
}
-function QuestionsItem({ id, label, questions }) {
+const tree = { };
+for (const path in data) {
+ const category = path.match(/^\.\/(.+)\//)[1];
+ tree[category] ??= [];
+ tree[category].push(
+ <QuestionLink href={getHref(path)} title={data[path].title} />
+ );
+}
+
+function Category({ category, questionLinks }) {
return (
<li>
<details open>
- <summary>{label}</summary>
+ <summary>{category}</summary>
<ul>
- {questions.map(question =>
- <QuestionItem id={id} question={question} />
- )}
+ {questionLinks}
</ul>
</details>
</li>
);
}
-const items = allQuestions.map(({ id, label, questions }) =>
- <QuestionsItem id={id} label={label} questions={questions} />
+const categories = Object.keys(tree).map(category =>
+ <Category category={category} questionLinks={tree[category]} />
);
-const arr = await Promise.all(allQuestions.map(async ({ id, questions }) =>
- await Promise.all(questions.map( async question => {
- const m = await import(`../data/questions/${id}/${question.id}.js`);
- function Component() { return <QuestionWindow data={m.data} title={question.label} />; }
- return <Route path={`/questions/${id}/${question.id}`} component={Component} />;
- }))
-));
-const routes = arr.flat();
+const routes = Object.keys(data).map(path => {
+ function Component() { return <QuestionWindow data={data[path]} />; }
+ return <Route path={getHref(path)} component={Component} />;
+})
export default function QuestionIndex() {
return (
<main>
<nav class="sidebar">
<ul class="tree-view">
- {items}
+ {categories}
</ul>
</nav>
<Switch>