website

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

commit 0b8a54cfa756993abb1b96c239e31d40fe0dbdde
parent 39283bf94f7bab05a72ca0351a6e26aa0e1c7d36
Author: hrryt <harry@mayesfield.uk>
Date:   Sun, 16 Aug 2026 23:43:53 +0100

Fix question flashing, remove prerendering, remove lazy loading, remove preact vite preset, use wouter

Diffstat:
MTODO.md | 2--
Mindex.html | 18+++++++++---------
Djsconfig.json | 20--------------------
Mpackage.json | 5++---
Msrc/components/Header.jsx | 26++++++++++++++------------
Msrc/index.jsx | 35++++++++++++++++-------------------
Msrc/pages/QuestionIndex.jsx | 27++++++++++++++-------------
Msrc/styles/main.css | 9+++------
Mvite.config.js | 21++++++++-------------
9 files changed, 66 insertions(+), 97 deletions(-)

diff --git a/TODO.md b/TODO.md @@ -1,7 +1,6 @@ # Fixes - Match SVG IDs in production - Hide components outside graph bounds (with mask?) due to preserveAspectRatio -- Stop question windows rerendering when following links to different question windows - Adjust spacing for adding fractions # Questions @@ -13,7 +12,6 @@ - Drop-down for finer controls - tricky parallel lines / internal angles etc questions - automate allQuestions using file exploration -- move away from prerendered questions? # Other stuff - minesweeper / youtube video. diff --git a/index.html b/index.html @@ -1,12 +1,12 @@ <!DOCTYPE html> <html lang="en"> - <head> - <meta charset="UTF-8" /> - <meta name="viewport" content="width=device-width, initial-scale=1.0" /> - <title>TTMaths</title> - </head> - <body> - <div id="app"></div> - <script prerender type="module" src="/src/index.jsx"></script> - </body> + <head> + <meta charset="UTF-8" /> + <meta name="viewport" content="width=device-width, initial-scale=1.0" /> + <title>TTMaths</title> + </head> + <body> + <div id="app"></div> + <script type="module" src="/src/index.jsx"></script> + </body> </html> diff --git a/jsconfig.json b/jsconfig.json @@ -1,20 +0,0 @@ -{ - "compilerOptions": { - "target": "ES2020", - "module": "ESNext", - "moduleResolution": "bundler", - "noEmit": true, - "allowJs": true, - "checkJs": true, - - /* Preact Config */ - "jsx": "react-jsx", - "jsxImportSource": "preact", - "skipLibCheck": true, - "paths": { - "react": ["./node_modules/preact/compat/"], - "react-dom": ["./node_modules/preact/compat/"] - } - }, - "include": ["node_modules/vite/client.d.ts", "**/*"] -} diff --git a/package.json b/package.json @@ -10,10 +10,9 @@ "98.css": "^0.1.21", "katex": "^0.18.4", "preact": "^10.26.9", - "preact-iso": "^2.12.1" + "wouter-preact": "^3.10.0" }, "devDependencies": { - "@preact/preset-vite": "^2.10.2", - "vite": "^7.0.4" + "vite": "^8.2.1" } } diff --git a/src/components/Header.jsx b/src/components/Header.jsx @@ -1,21 +1,23 @@ -import { useLocation } from 'preact-iso'; +import { Link } from 'wouter-preact'; -export default function Header() { - const { url } = useLocation(); +function getActiveClass(active) { + return active ? "active" : ""; +} - return ( - <header> - <nav class="window taskbar"> - <a href="/"> - <button class={'taskbar-element' + (url == '/' ? ' active' : '')}> +export default function Header() { + return ( + <header> + <nav class="window taskbar"> + <Link href="/" className={getActiveClass}> + <button class="taskbar-element"> Home </button> - </a> - <a href="/questions"> - <button class={'taskbar-element' + (url.startsWith('/questions') ? ' active' : '')}> + </Link> + <Link href="/questions" className={getActiveClass}> + <button class="taskbar-element"> Questions </button> - </a> + </Link> </nav> </header> ); diff --git a/src/index.jsx b/src/index.jsx @@ -1,29 +1,26 @@ -import { LocationProvider, Router, hydrate, prerender as ssr } from 'preact-iso'; +import { render } from 'preact'; +import { Route, Switch } from 'wouter-preact'; import Header from './components/Header.jsx'; + import Home from './pages/Home.jsx'; import QuestionIndex from './pages/QuestionIndex.jsx'; import NotFound from './pages/NotFound.jsx'; + import './styles/index.css'; export function App() { - return ( - <LocationProvider> - <Header /> - <Router> - <Home path="/" /> - <QuestionIndex path="/questions" /> - <QuestionIndex path="/questions/*" /> - <NotFound default /> - </Router> - </LocationProvider> - ); + return ( + <> + <Header /> + <Switch> + <Route path="/" component={Home} /> + <Route path="/questions" component={QuestionIndex} /> + <Route path="/questions/*" component={QuestionIndex} /> + <Route component={NotFound} /> + </Switch> + </> + ); } -if (typeof window !== 'undefined') { - hydrate(<App />, document.getElementById('app')); -} - -export async function prerender(data) { - return await ssr(<App {...data} />); -} +render(<App />, document.getElementById('app')); diff --git a/src/pages/QuestionIndex.jsx b/src/pages/QuestionIndex.jsx @@ -1,4 +1,5 @@ -import { lazy, Router, Route } from 'preact-iso'; +import { Route, Switch, Link } from 'wouter-preact'; + import QuestionWindow from '../components/QuestionWindow.jsx'; const allQuestions = [{ @@ -23,9 +24,9 @@ const allQuestions = [{ function QuestionItem({ id, question }) { return ( <li> - <a href={`/questions/${id}/${question.id}`}> + <Link href={`/questions/${id}/${question.id}`}> {question.label} - </a> + </Link> </li> ); } @@ -49,14 +50,14 @@ const items = allQuestions.map(({ id, label, questions }) => <QuestionsItem id={id} label={label} questions={questions} /> ); -const routes = allQuestions.flatMap(({ id, questions }) => questions.map(question => { - const Component = lazy(() => - import(`../data/questions/${id}/${question.id}.js`).then(m => - () => <QuestionWindow data={m.data} title={question.label} /> - ) - ); - return <Route path={`/${id}/${question.id}`} component={Component} />; -})); +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(); export default function QuestionIndex() { return ( @@ -66,9 +67,9 @@ export default function QuestionIndex() { {items} </ul> </nav> - <Router> + <Switch> {routes} - </Router> + </Switch> </main> ); } diff --git a/src/styles/main.css b/src/styles/main.css @@ -19,8 +19,10 @@ nav.taskbar { width: 100vw; } -button.taskbar-element.active { +a.active > button.taskbar-element { font-weight: bold; + box-shadow: inset -1px -1px #ffffff, inset 1px 1px #0a0a0a, + inset -2px -2px #dfdfdf, inset 2px 2px #808080; } .window { @@ -68,11 +70,6 @@ button.window-button { margin-right: 0; } -button.active { - box-shadow: inset -1px -1px #ffffff, inset 1px 1px #0a0a0a, - inset -2px -2px #dfdfdf, inset 2px 2px #808080; -} - img.http-error { max-width: 400px; } diff --git a/vite.config.js b/vite.config.js @@ -1,17 +1,12 @@ import { defineConfig } from 'vite'; -import preact from '@preact/preset-vite'; -// https://vitejs.dev/config/ export default defineConfig({ - plugins: [ - preact({ - prerender: { - enabled: true, - renderTarget: '#app', - additionalPrerenderRoutes: ['/404'], - previewMiddlewareEnabled: true, - previewMiddlewareFallback: '/404', - }, - }), - ], + oxc: { + jsx: { + importSource: 'preact', + } + }, + build: { + cssMinify: false, + }, });