website

source code for the ttmaths.uk website
Log | Files | Refs | README

commit e4912ef8d0f606aeb3bbc18eeed3a69869bf6e21
parent 452f9df98a1fb07a851a5921e1b6bfb847eed91b
Author: fen123456 <fenwthompson@gmail.com>
Date:   Thu, 30 Jul 2026 15:05:28 +0100

Add window class

Diffstat:
Msrc/components/App.jsx | 4++--
Dsrc/components/QuestionPanel.jsx | 86-------------------------------------------------------------------------------
Asrc/components/QuestionWindow.jsx | 77+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Dsrc/components/TestQuestionPanel.jsx | 7-------
Asrc/components/TestQuestionWindow.jsx | 7+++++++
Asrc/components/Window.jsx | 20++++++++++++++++++++
Dsrc/data/test-question-panel.js | 19-------------------
Asrc/data/test-question-window.js | 19+++++++++++++++++++
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', + }] + }] +}