feat(rgov): standalone n8n-style GovMod circuit canvas
Add <folk-gov-circuit> component with interactive SVG canvas pre-loaded with 3 demo governance circuits. 8 node types (signoff, threshold, knob, project, quadratic, conviction, multisig, sankey) with pan/zoom, node dragging, Bezier wiring, palette sidebar, and detail panel. Compatible with rspace canvas shape types for rapplet integration. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
5b4ab00a2d
commit
2e2fbae8bf
File diff suppressed because it is too large
Load Diff
|
|
@ -8,7 +8,6 @@
|
|||
*/
|
||||
|
||||
import { Hono } from "hono";
|
||||
import { resolve } from "path";
|
||||
import { renderShell } from "../../server/shell";
|
||||
import { getModuleInfoList } from "../../shared/module";
|
||||
import type { RSpaceModule } from "../../shared/module";
|
||||
|
|
@ -17,53 +16,10 @@ import { addShapes, getDocumentData } from "../../server/community-store";
|
|||
|
||||
const routes = new Hono();
|
||||
|
||||
// ── Canvas content loader (same approach as rspace module) ──
|
||||
// ── Module page — renders standalone GovMod circuit canvas ──
|
||||
|
||||
const DIST_DIR = resolve(import.meta.dir, "../../dist");
|
||||
let canvasCache: { body: string; styles: string; scripts: string } | null = null;
|
||||
|
||||
function extractCanvasContent(html: string) {
|
||||
const bodyMatch = html.match(/<body[^>]*>([\s\S]*?)<\/body>/i);
|
||||
const styleMatches = [...html.matchAll(/<style[^>]*>([\s\S]*?)<\/style>/gi)];
|
||||
const scriptMatches = [...html.matchAll(/<script[^>]*>[\s\S]*?<\/script>/gi)];
|
||||
return {
|
||||
body: bodyMatch?.[1] || "",
|
||||
styles: styleMatches.map(m => m[0]).join("\n"),
|
||||
scripts: scriptMatches.map(m => m[0]).join("\n"),
|
||||
};
|
||||
}
|
||||
|
||||
async function getCanvasContent() {
|
||||
if (canvasCache) return canvasCache;
|
||||
|
||||
const moduleFile = Bun.file(resolve(DIST_DIR, "canvas-module.html"));
|
||||
if (await moduleFile.exists()) {
|
||||
canvasCache = {
|
||||
body: await moduleFile.text(),
|
||||
styles: "",
|
||||
scripts: `<script type="module" src="/canvas-module.js"></script>`,
|
||||
};
|
||||
return canvasCache;
|
||||
}
|
||||
|
||||
const fullFile = Bun.file(resolve(DIST_DIR, "canvas.html"));
|
||||
if (await fullFile.exists()) {
|
||||
canvasCache = extractCanvasContent(await fullFile.text());
|
||||
return canvasCache;
|
||||
}
|
||||
|
||||
return {
|
||||
body: `<div style="padding:2rem;text-align:center;color:#64748b;">Canvas loading...</div>`,
|
||||
styles: "",
|
||||
scripts: "",
|
||||
};
|
||||
}
|
||||
|
||||
// ── Module page (within a space) — renders canvas directly ──
|
||||
|
||||
routes.get("/", async (c) => {
|
||||
routes.get("/", (c) => {
|
||||
const space = c.req.param("space") || "demo";
|
||||
const canvas = await getCanvasContent();
|
||||
|
||||
return c.html(renderShell({
|
||||
title: `${space} — rGov | rSpace`,
|
||||
|
|
@ -71,9 +27,8 @@ routes.get("/", async (c) => {
|
|||
spaceSlug: space,
|
||||
modules: getModuleInfoList(),
|
||||
theme: "dark",
|
||||
body: canvas.body,
|
||||
styles: canvas.styles,
|
||||
scripts: canvas.scripts,
|
||||
body: `<folk-gov-circuit space="${space}" style="width:100%;height:100%;display:block;"></folk-gov-circuit>`,
|
||||
scripts: `<script type="module" src="/modules/rgov/folk-gov-circuit.js"></script>`,
|
||||
}));
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -1394,6 +1394,27 @@ export default defineConfig({
|
|||
}
|
||||
}
|
||||
|
||||
// ── Build rGov circuit canvas component ──
|
||||
mkdirSync(resolve(__dirname, "dist/modules/rgov"), { recursive: true });
|
||||
await wasmBuild({
|
||||
configFile: false,
|
||||
root: resolve(__dirname, "modules/rgov/components"),
|
||||
build: {
|
||||
emptyOutDir: false,
|
||||
outDir: resolve(__dirname, "dist/modules/rgov"),
|
||||
lib: {
|
||||
entry: resolve(__dirname, "modules/rgov/components/folk-gov-circuit.ts"),
|
||||
formats: ["es"],
|
||||
fileName: () => "folk-gov-circuit.js",
|
||||
},
|
||||
rollupOptions: {
|
||||
output: {
|
||||
entryFileNames: "folk-gov-circuit.js",
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
// ── Generate content hashes for cache-busting ──
|
||||
const { readdirSync, readFileSync, writeFileSync, statSync: statSync2 } = await import("node:fs");
|
||||
const { createHash } = await import("node:crypto");
|
||||
|
|
|
|||
Loading…
Reference in New Issue