/** * Choices module — voting, ranking, and multi-criteria scoring tools. * * The folk-choice-* web components live in lib/ (shared with canvas). * This module provides: * - A page listing choice shapes in the current space * - API to query choice shapes from the Automerge store * - Links to create new choices on the canvas */ import { Hono } from "hono"; import { renderShell } from "../../server/shell"; import type { RSpaceModule } from "../../shared/module"; import { getModuleInfoList } from "../../shared/module"; import { getDocumentData } from "../../server/community-store"; const routes = new Hono(); // GET /api/choices — list choice shapes in the current space routes.get("/api/choices", async (c) => { const space = c.req.param("space") || c.req.query("space") || "demo"; const docData = getDocumentData(space); if (!docData?.shapes) { return c.json({ choices: [], total: 0 }); } const choiceTypes = ["folk-choice-vote", "folk-choice-rank", "folk-choice-spider"]; const choices: any[] = []; for (const [id, shape] of Object.entries(docData.shapes as Record)) { if (shape.forgotten) continue; if (choiceTypes.includes(shape.type)) { choices.push({ id, type: shape.type, title: shape.title || "Untitled", mode: shape.mode, optionCount: (shape.options || []).length, voteCount: (shape.votes || shape.rankings || shape.scores || []).length, createdAt: shape.createdAt, }); } } return c.json({ choices, total: choices.length }); }); // GET / — choices page routes.get("/", (c) => { const spaceSlug = c.req.param("space") || "demo"; return c.html(renderShell({ title: `${spaceSlug} — Choices | rSpace`, moduleId: "choices", spaceSlug, modules: getModuleInfoList(), theme: "light", styles: ``, body: ``, scripts: ``, })); }); export const choicesModule: RSpaceModule = { id: "choices", name: "rChoices", icon: "☑", description: "Polls, rankings, and multi-criteria scoring", routes, standaloneDomain: "rchoices.online", };