website

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

commit 6d0548512000970d2cc2a91324d7dc40de088d57
parent ac571718ef71218b477cc68775093dcb8793f16e
Author: hrryt <harry@mayesfield.uk>
Date:   Thu, 30 Jul 2026 14:19:22 +0100

Use 98.css, begin implementing question parameter inputs

Diffstat:
M.gitignore | 2++
Mesbuild.json | 6+++++-
Mpackage.json | 1+
Asrc/components/App.jsx | 6++++++
Msrc/components/Equation.jsx | 6+++---
Asrc/components/MultipleSelection.jsx | 15+++++++++++++++
Msrc/components/Question.jsx | 2+-
Msrc/components/QuestionList.jsx | 2+-
Msrc/components/QuestionPanel.jsx | 42++++++++++++++++++++++++++++++------------
Msrc/components/TestQuestionPanel.jsx | 4++--
Msrc/data/test-question-panel.js | 34++++++++++++++++++----------------
Msrc/scripts/react-roots.js | 4++--
Msrc/styles/index.css | 19++-----------------
Mwww/index.html | 15+--------------
14 files changed, 89 insertions(+), 69 deletions(-)

diff --git a/.gitignore b/.gitignore @@ -2,3 +2,5 @@ node_modules package-lock.json www/js www/css +www/*.woff +www/*.woff2 diff --git a/esbuild.json b/esbuild.json @@ -4,5 +4,9 @@ { "out": "css/index", "in": "src/styles/index.css" } ], "bundle": true, - "outdir": "www" + "outdir": "www", + "loader": { + ".woff": "file", + ".woff2": "file" + } } diff --git a/package.json b/package.json @@ -1,5 +1,6 @@ { "dependencies": { + "98.css": "^0.1.21", "kern-typ": "^0.2.0", "react": "^19.2.8", "react-dom": "^19.2.8" diff --git a/src/components/App.jsx b/src/components/App.jsx @@ -0,0 +1,6 @@ +import * as React from 'react'; +import TestQuestionPanel from './TestQuestionPanel.jsx'; + +export default function App() { + return <TestQuestionPanel />; +} diff --git a/src/components/Equation.jsx b/src/components/Equation.jsx @@ -2,11 +2,11 @@ import * as React from 'react'; import { render } from 'kern-typ'; export default function Equation({ equation, displayMode = false }) { - const elementRef = React.useRef(); + const ref = React.useRef(null); React.useEffect(() => { - render(equation, elementRef.current, { displayMode: displayMode }); + render(equation, ref.current, { displayMode: displayMode }); }, [equation]); - return <div className="Equation" ref={elementRef} />; + return <div ref={ref} />; } diff --git a/src/components/MultipleSelection.jsx b/src/components/MultipleSelection.jsx @@ -0,0 +1,15 @@ +import * as React from 'react'; + +export default function MultipleSelection({ legend, values, labels = values, defaults = values.map(() => true) }) { + return ( + <fieldset ref={ref}> + <legend>{legend}</legend> + {values.map((value, i) => ( + <div className="field-row"> + <input type="checkbox" name={value} defaultChecked={defaults[i]}></input> + <label for={value}>{labels[i]}</label> + </div> + ))} + </fieldset> + ); +} diff --git a/src/components/Question.jsx b/src/components/Question.jsx @@ -3,7 +3,7 @@ import Equation from './Equation.jsx'; export default function Question({ question, answer, showAnswer }) { return ( - <li className={"Question" + (showAnswer ? " Answer" : "")}> + <li> <Equation equation={showAnswer ? answer : question} /> </li> ); diff --git a/src/components/QuestionList.jsx b/src/components/QuestionList.jsx @@ -1,5 +1,5 @@ import * as React from 'react'; export default function QuestionList({ children }) { - return <ol className="QuestionList">{children}</ol>; + return <ol>{children}</ol>; } diff --git a/src/components/QuestionPanel.jsx b/src/components/QuestionPanel.jsx @@ -34,7 +34,7 @@ function shuffleArray(arr, n, seed) { return Array.from({ length: n }).map(() => arr[getRandomInt(0, max, ++seed)]); } -export default function QuestionPanel({ questionLists }) { +export default function QuestionPanel({ data }) { const [showAnswers, setShowAnswers] = React.useState(false); const [seed , setSeed ] = React.useState(Math.random()); @@ -42,7 +42,7 @@ export default function QuestionPanel({ questionLists }) { function triggerRefresh() { setSeed(getRandomNumber(seed)); } let current_seed = seed; - const questions = questionLists.map(questionList => { + 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); @@ -50,18 +50,36 @@ export default function QuestionPanel({ questionLists }) { return randomQuestionList; }); + const formRef = React.useRef(); + function submitForm() { formRef.current.submit(); } + function handleSubmit(e) { e.preventDefault(); } + return ( - <div className="QuestionPanel"> - <div className="ButtonPanel"> - <button className="RevealButton" onClick={revealAnswers}> - {showAnswers ? "Hide" : "Show"} Answers - </button> - <button className="RefreshButton" onClick={triggerRefresh}> - Refresh Questions - </button> + <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="QuestionSet"> - {questions} + <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"> + {questions} + </div> </div> </div> ); diff --git a/src/components/TestQuestionPanel.jsx b/src/components/TestQuestionPanel.jsx @@ -1,7 +1,7 @@ import * as React from 'react'; import QuestionPanel from './QuestionPanel.jsx'; -import { questionLists } from '../data/test-question-panel.js'; +import { questionPanel } from '../data/test-question-panel.js'; export default function TestQuestionPanel() { - return <QuestionPanel questionLists={questionLists} />; + return <QuestionPanel data={questionPanel} />; } diff --git a/src/data/test-question-panel.js b/src/data/test-question-panel.js @@ -1,17 +1,19 @@ -export const questionLists = [{ - id: 0, - n: 10, - questions: [{ - type: 'quadratic-equation', - parameters: { factorise: false } - }, { - type: 'quadratic-equation', - parameters: { a: 1, factorise: true } +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', + }] }] -}, { - id: 1, - n: 5, - questions: [{ - type: 'adding-fractions', - }] -}] +} diff --git a/src/scripts/react-roots.js b/src/scripts/react-roots.js @@ -1,7 +1,7 @@ import { createElement } from 'react'; import { createRoot } from 'react-dom/client'; -import TestQuestionPanel from '../components/TestQuestionPanel.jsx'; +import App from '../components/App.jsx'; function renderComponent(id, component) { node = document.getElementById(id); @@ -9,4 +9,4 @@ function renderComponent(id, component) { root.render(createElement(component)); } -renderComponent('test-question-panel', TestQuestionPanel); +renderComponent('app', App); diff --git a/src/styles/index.css b/src/styles/index.css @@ -1,21 +1,6 @@ @import 'kern-typ/kern.css'; +@import '98.css'; -html { - display: table; - margin: 0 auto; - background-color: #008080; -} - -body { - display: table-cell; - vertical-align: middle; - width: 100vw; +.window { max-width: 800px; - background-color: #202020; - color: #c5c5c5; - padding: 0 1em; -} - -.QuestionSet { - display: flex; } diff --git a/www/index.html b/www/index.html @@ -5,20 +5,7 @@ <link rel="stylesheet" href="css/index.css" /> </head> <body> - <h1>Hello world!</h1> - <section> - <h2>Introduction</h2> - <p>$ x^2 + 5x + 6 $ is an expression.</p> - $$ x^2 + 5x + 6 = 0 $$ - $$ x = -3 "or" x = -2 $$ - </section> - <section> - <h2>Random questions</h2> - <div id="test-question-panel"></div> - </section> - <footer> - <p>Fin</p> - </footer> + <div id="app"></div> <script src="js/index.js"></script> </body> </html>