commit e4912ef8d0f606aeb3bbc18eeed3a69869bf6e21
parent 452f9df98a1fb07a851a5921e1b6bfb847eed91b
Author: fen123456 <fenwthompson@gmail.com>
Date: Thu, 30 Jul 2026 15:05:28 +0100
Add window class
Diffstat:
8 files changed, 125 insertions(+), 114 deletions(-)
diff --git a/src/components/App.jsx b/src/components/App.jsx
@@ -1,6 +1,6 @@
import * as React from 'react';
-import TestQuestionPanel from './TestQuestionPanel.jsx';
+import TestQuestionWindow from './TestQuestionWindow.jsx';
export default function App() {
- return <TestQuestionPanel />;
+ return <TestQuestionWindow />;
}
diff --git a/src/components/QuestionPanel.jsx b/src/components/QuestionPanel.jsx
@@ -1,86 +0,0 @@
-import * as React from 'react';
-import QuestionList from './QuestionList.jsx';
-import { getRandomInt, getRandomNumber } from '../scripts/utils.js';
-
-import AddingFractionsQuestion from './questions/AddingFractionsQuestion.jsx';
-import QuadraticEquationQuestion from './questions/QuadraticEquationQuestion.jsx';
-
-function chooseQuestionComponent(type) {
- switch (type) {
- case 'quadratic-equation':
- return QuadraticEquationQuestion;
- case 'adding-fractions':
- return AddingFractionsQuestion;
- }
-}
-
-function renderQuestion(seed, showAnswer) {
- return (question, i) => {
- const QuestionComponent = chooseQuestionComponent(question.type);
- return <QuestionComponent key={i} seed={seed+i} showAnswer={showAnswer} parameters={question.parameters || {}} />;
- };
-}
-
-function getQuestionList(id, questions, showAnswers, seed) {
- return (
- <QuestionList key={id}>
- {questions.map(renderQuestion(seed, showAnswers))}
- </QuestionList>
- );
-}
-
-function shuffleArray(arr, n, seed) {
- const max = arr.length - 1;
- return Array.from({ length: n }).map(() => arr[getRandomInt(0, max, ++seed)]);
-}
-
-export default function QuestionPanel({ data }) {
- const [showAnswers, setShowAnswers] = React.useState(false);
- const [seed , setSeed ] = React.useState(Math.random());
-
- function revealAnswers() { setShowAnswers(!showAnswers); }
- function triggerRefresh() { setSeed(getRandomNumber(seed)); }
-
- let current_seed = seed;
- const questions = data.questionLists.map(questionList => {
- const { id: id, n: n, questions: unique_questions } = questionList;
- const questions = shuffleArray(unique_questions, n, current_seed);
- const randomQuestionList = getQuestionList(id, questions, showAnswers, current_seed);
- current_seed += n;
- return randomQuestionList;
- });
-
- const formRef = React.useRef();
- function submitForm() { formRef.current.submit(); }
- function handleSubmit(e) { e.preventDefault(); }
-
- return (
- <div className="window">
- <div className="title-bar">
- <div className="title-bar-text">Questions</div>
- <div className="title-bar-controls">
- <button aria-label="Minimize" />
- <button aria-label="Maximize" />
- <button aria-label="Close" />
- </div>
- </div>
- <div className="window-body">
- <form ref={formRef} onChange={submitForm} onSubmit={handleSubmit}>
- <fieldset>
- <legend>Options</legend>
- <button onClick={revealAnswers}>
- {showAnswers ? "Hide" : "Show"} Answers
- </button>
- <button onClick={triggerRefresh}>
- Refresh Questions
- </button>
- </fieldset>
- </form>
- <br />
- <div className="field-border kern">
- {questions}
- </div>
- </div>
- </div>
- );
-}
diff --git a/src/components/QuestionWindow.jsx b/src/components/QuestionWindow.jsx
@@ -0,0 +1,77 @@
+import * as React from 'react';
+import QuestionList from './QuestionList.jsx';
+import { getRandomInt, getRandomNumber } from '../scripts/utils.js';
+
+import AddingFractionsQuestion from './questions/AddingFractionsQuestion.jsx';
+import QuadraticEquationQuestion from './questions/QuadraticEquationQuestion.jsx';
+import Window from './Window.jsx';
+
+function chooseQuestionComponent(type) {
+ switch (type) {
+ case 'quadratic-equation':
+ return QuadraticEquationQuestion;
+ case 'adding-fractions':
+ return AddingFractionsQuestion;
+ }
+}
+
+function renderQuestion(seed, showAnswer) {
+ return (question, i) => {
+ const QuestionComponent = chooseQuestionComponent(question.type);
+ return <QuestionComponent key={i} seed={seed+i} showAnswer={showAnswer} parameters={question.parameters || {}} />;
+ };
+}
+
+function getQuestionList(id, questions, showAnswers, seed) {
+ return (
+ <QuestionList key={id}>
+ {questions.map(renderQuestion(seed, showAnswers))}
+ </QuestionList>
+ );
+}
+
+function shuffleArray(arr, n, seed) {
+ const max = arr.length - 1;
+ return Array.from({ length: n }).map(() => arr[getRandomInt(0, max, ++seed)]);
+}
+
+export default function QuestionWindow({ data }) {
+ const [showAnswers, setShowAnswers] = React.useState(false);
+ const [seed , setSeed ] = React.useState(Math.random());
+
+ function revealAnswers() { setShowAnswers(!showAnswers); }
+ function triggerRefresh() { setSeed(getRandomNumber(seed)); }
+
+ let current_seed = seed;
+ const questions = data.questionLists.map(questionList => {
+ const { id: id, n: n, questions: unique_questions } = questionList;
+ const questions = shuffleArray(unique_questions, n, current_seed);
+ const randomQuestionList = getQuestionList(id, questions, showAnswers, current_seed);
+ current_seed += n;
+ return randomQuestionList;
+ });
+
+ const formRef = React.useRef();
+ function submitForm() { formRef.current.submit(); }
+ function handleSubmit(e) { e.preventDefault(); }
+
+ return (
+ <Window title="Questions">
+ <form ref={formRef} onChange={submitForm} onSubmit={handleSubmit}>
+ <fieldset>
+ <legend>Options</legend>
+ <button onClick={revealAnswers}>
+ {showAnswers ? "Hide" : "Show"} Answers
+ </button>
+ <button onClick={triggerRefresh}>
+ Refresh Questions
+ </button>
+ </fieldset>
+ </form>
+ <br />
+ <div className="field-border kern">
+ {questions}
+ </div>
+ </Window>
+ );
+}
diff --git a/src/components/TestQuestionPanel.jsx b/src/components/TestQuestionPanel.jsx
@@ -1,7 +0,0 @@
-import * as React from 'react';
-import QuestionPanel from './QuestionPanel.jsx';
-import { questionPanel } from '../data/test-question-panel.js';
-
-export default function TestQuestionPanel() {
- return <QuestionPanel data={questionPanel} />;
-}
diff --git a/src/components/TestQuestionWindow.jsx b/src/components/TestQuestionWindow.jsx
@@ -0,0 +1,7 @@
+import * as React from 'react';
+import QuestionWindow from './QuestionWindow.jsx';
+import { questionWindow } from '../data/test-question-window.js';
+
+export default function TestQuestionPanel() {
+ return <QuestionWindow data={questionWindow} />;
+}
diff --git a/src/components/Window.jsx b/src/components/Window.jsx
@@ -0,0 +1,19 @@
+import * as React from 'react'
+
+export default function Window({ children, title, maximised }){
+ return (
+ <div className="window">
+ <div className="title-bar">
+ <div className="title-bar-text">{title}</div>
+ <div className="title-bar-controls">
+ <button aria-label="Minimize" />
+ <button aria-label={maximised ? "Restore" : "Maximize"} />
+ <button aria-label="Close" />
+ </div>
+ </div>
+ <div className="window-body">
+ {children}
+ </div>
+ </div>
+ )
+}
+\ No newline at end of file
diff --git a/src/data/test-question-panel.js b/src/data/test-question-panel.js
@@ -1,19 +0,0 @@
-export const questionPanel = {
- inputs: [{
- id: 'a',
- legend: 'Quadratic Equations: a',
- type: 'multiple-selection',
- values: [1, 2, 3],
- }],
- questionLists: [{
- id: 0,
- n: 10,
- questions: [{
- type: 'quadratic-equation',
- controlledParameters: { a: 'a' },
- lockedParameters: { factorise: false },
- }, {
- type: 'adding-fractions',
- }]
- }]
-}
diff --git a/src/data/test-question-window.js b/src/data/test-question-window.js
@@ -0,0 +1,19 @@
+export const questionWindow = {
+ inputs: [{
+ id: 'a',
+ legend: 'Quadratic Equations: a',
+ type: 'multiple-selection',
+ values: [1, 2, 3],
+ }],
+ questionLists: [{
+ id: 0,
+ n: 10,
+ questions: [{
+ type: 'quadratic-equation',
+ controlledParameters: { a: 'a' },
+ lockedParameters: { factorise: false },
+ }, {
+ type: 'adding-fractions',
+ }]
+ }]
+}