/** * Canvas module — the collaborative infinite canvas. * * This is the original rSpace canvas restructured as an rSpace module. * Routes are relative to the mount point (/:space/canvas in unified mode, * / in standalone mode). */ import { Hono } from "hono"; import { resolve } from "node:path"; import { renderShell } from "../../server/shell"; import { getModuleInfoList } from "../../shared/module"; import type { RSpaceModule } from "../../shared/module"; const DIST_DIR = resolve(import.meta.dir, "../../dist"); const routes = new Hono(); // GET / — serve the canvas page wrapped in shell routes.get("/", async (c) => { const spaceSlug = c.req.param("space") || c.req.query("space") || "demo"; // Read the canvas page template from dist const canvasFile = Bun.file(resolve(DIST_DIR, "canvas-module.html")); let canvasBody = ""; if (await canvasFile.exists()) { canvasBody = await canvasFile.text(); } else { // Fallback: serve full canvas.html directly if module template not built yet const fallbackFile = Bun.file(resolve(DIST_DIR, "canvas.html")); if (await fallbackFile.exists()) { return new Response(fallbackFile, { headers: { "Content-Type": "text/html" }, }); } canvasBody = `
Canvas loading...
`; } const html = renderShell({ title: `${spaceSlug} — Canvas | rSpace`, moduleId: "canvas", spaceSlug, body: canvasBody, modules: getModuleInfoList(), theme: "light", scripts: ``, }); return c.html(html); }); export const canvasModule: RSpaceModule = { id: "canvas", name: "Canvas", icon: "🎨", description: "Collaborative infinite canvas", routes, };