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:
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,
+ },
});