import { Context, Next, send } from "@oak/oak"; import { OG_SITE_NAME, SITE_EMOJI } from "../config.ts"; import { emojiToCodepoint } from "./site-icons.ts"; const ICON_VERSION = emojiToCodepoint(SITE_EMOJI); async function serveIndexHtml( context: Context>, root: string, ) { const filePath = `${root}/index.html`; const raw = await Deno.readTextFile(filePath); const html = raw .replaceAll("__SITE_NAME__", OG_SITE_NAME) .replaceAll("__SITE_EMOJI__", SITE_EMOJI) .replaceAll("__ICON_VERSION__", ICON_VERSION); context.response.type = "text/html"; context.response.body = html; } export function routeStaticFilesFrom(staticPaths: string[]) { return async (context: Context>, next: Next) => { const pathname = context.request.url.pathname; // Serve index.html with runtime placeholder replacement if (pathname === "/" || pathname === "/index.html") { await serveIndexHtml(context, staticPaths[0]); return; } for (const path of staticPaths) { try { await send(context, pathname, { root: path }); return; } catch { continue; } } // SPA fallback: serve index.html so client-side routes work on direct navigation await serveIndexHtml(context, staticPaths[0]); await next(); }; }