Skip to content

Commit 506c6ad

Browse files
committed
refactor: Render an MPA instead of an SPA
Also look into Nunjucks...
1 parent e91e5e5 commit 506c6ad

File tree

15 files changed

+155
-69
lines changed

15 files changed

+155
-69
lines changed

src/Page.tsx

Lines changed: 0 additions & 47 deletions
This file was deleted.

src/index.html

Lines changed: 2 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -5,18 +5,8 @@
55
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
66
<link rel="icon" type="image/svg+xml" href="@/assets/logo.png" />
77
<title>TypeScript Exercises</title>
8-
<style>
9-
:root {
10-
--background: hsla(0 0% 100%);
11-
}
12-
.dark {
13-
--background: hsla(240 10% 3.9%);
14-
}
15-
body {
16-
background-color: var(--background);
17-
}
18-
</style>
19-
<script type="module" src="./Page.tsx" async></script>
8+
<link rel="stylesheet" href="@/preload-theme.css" />
9+
<script type="module" src="@/Page.tsx" async></script>
2010
</head>
2111
<body>
2212
<script>

src/index.tsx

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,26 @@
11
import { serve, type ServerWebSocket } from 'bun';
22
import z from 'zod';
33
import path from 'path';
4-
import index from '@/index.html';
54
import { readdir } from 'fs/promises';
65
import { validate } from '@/checker';
76
import { getCurrentLogs, log } from '@/logger/logs.ts';
87

8+
import exercises from '@/pages/exercises.html';
9+
import exercise from '@/pages/exercise.html';
10+
import logs from '@/pages/logs.html';
11+
import page404 from '@/pages/404.html';
12+
913
const connectedSockets: Set<ServerWebSocket<any>> = new Set();
1014

1115
const server = serve({
1216
routes: {
13-
// Serve index.html for all unmatched routes.
14-
'/*': index,
17+
'/': exercises,
18+
'/exercise/:exercise': exercise,
19+
'/logs': logs,
1520

16-
'/api/*': () => Response.json({ message: 'API not found!' }, { status: 404 }),
17-
18-
'/socket': (req, server) => {
19-
if (!server.upgrade(req)) return new Response('Could not open socket.', { status: 500 });
20-
},
21+
'/*': page404,
2122

23+
'/api/*': () => Response.json({ message: 'API not found!' }, { status: 404 }),
2224
'/api/templates/:template': async req => {
2325
const template = req.params.template;
2426
try {
@@ -28,15 +30,13 @@ const server = serve({
2830
return Response.json({ message: 'Not found' }, { status: 404 });
2931
}
3032
},
31-
3233
'/api/exercises': async () => {
3334
const files = await readdir(path.join(__dirname, '..', 'templates'));
3435
const exercises = files
3536
.filter(file => file.endsWith('.template.ts'))
3637
.map(file => file.replace('.template.ts', ''));
3738
return Response.json({ exercises });
3839
},
39-
4040
'/api/submit/:exercise': {
4141
POST: async req => {
4242
const exercise = req.params.exercise;
@@ -68,6 +68,10 @@ const server = serve({
6868
headers: { 'Content-Type': 'image/x-icon' },
6969
}),
7070
'/robots.txt': new Response(await Bun.file(path.join(__dirname, '..', 'assets', 'robots.txt')).bytes()),
71+
72+
'/socket': (req, server) => {
73+
if (!server.upgrade(req)) return new Response('Could not open socket.', { status: 500 });
74+
},
7175
},
7276

7377
websocket: {

src/pages/404.html

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
<!doctype html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="UTF-8" />
5+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
6+
<link rel="icon" type="image/svg+xml" href="@/assets/logo.png" />
7+
<title>Page not found</title>
8+
<link rel="stylesheet" href="@/preload-theme.css" />
9+
<script type="module" src="404.render.tsx" async></script>
10+
</head>
11+
<body>
12+
<script>
13+
const pref = localStorage.getItem('theme');
14+
if (pref === 'light') document.body.classList.add('light');
15+
else document.body.classList.add('dark');
16+
setTimeout(() => document.body.classList.add('duration-400'), 0);
17+
</script>
18+
<div id="root" class="overflow-x-hidden"></div>
19+
</body>
20+
</html>

src/pages/404.render.tsx

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
import { render } from '@/render';
2+
import { Page404 } from './404';
3+
4+
render(<Page404 />);

src/pages/exercise.html

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
<!doctype html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="UTF-8" />
5+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
6+
<link rel="icon" type="image/svg+xml" href="@/assets/logo.png" />
7+
<title>TypeScript Exercises</title>
8+
<link rel="stylesheet" href="@/preload-theme.css" />
9+
<script type="module" src="exercise.render.tsx" async></script>
10+
</head>
11+
<body>
12+
<script>
13+
const pref = localStorage.getItem('theme');
14+
if (pref === 'light') document.body.classList.add('light');
15+
else document.body.classList.add('dark');
16+
setTimeout(() => document.body.classList.add('duration-400'), 0);
17+
</script>
18+
<div id="root" class="overflow-x-hidden"></div>
19+
</body>
20+
</html>

src/pages/exercise.render.tsx

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
import { render } from '@/render';
2+
import { Exercise } from '@/pages/Exercise';
3+
4+
const template = window.location.pathname.split('/').pop();
5+
6+
render(<Exercise template={template} />);

src/pages/exercises.html

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
<!doctype html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="UTF-8" />
5+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
6+
<link rel="icon" type="image/svg+xml" href="@/assets/logo.png" />
7+
<title>TypeScript Exercises</title>
8+
<link rel="stylesheet" href="@/preload-theme.css" />
9+
<script type="module" src="exercises.render.tsx" async></script>
10+
</head>
11+
<body>
12+
<script>
13+
const pref = localStorage.getItem('theme');
14+
if (pref === 'light') document.body.classList.add('light');
15+
else document.body.classList.add('dark');
16+
setTimeout(() => document.body.classList.add('duration-400'), 0);
17+
</script>
18+
<div id="root" class="overflow-x-hidden"></div>
19+
</body>
20+
</html>

src/pages/exercises.render.tsx

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
import { render } from '@/render';
2+
import { Exercises } from '@/pages/Exercises';
3+
4+
render(<Exercises />);

src/pages/logs.html

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
<!doctype html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="UTF-8" />
5+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
6+
<link rel="icon" type="image/svg+xml" href="@/assets/logo.png" />
7+
<title>Logs!</title>
8+
<link rel="stylesheet" href="@/preload-theme.css" />
9+
<script type="module" src="logs.render.tsx" async></script>
10+
</head>
11+
<body>
12+
<script>
13+
const pref = localStorage.getItem('theme');
14+
if (pref === 'light') document.body.classList.add('light');
15+
else document.body.classList.add('dark');
16+
setTimeout(() => document.body.classList.add('duration-400'), 0);
17+
</script>
18+
<div id="root" class="overflow-x-hidden"></div>
19+
</body>
20+
</html>

0 commit comments

Comments
 (0)