70 lines
2.2 KiB
TypeScript
70 lines
2.2 KiB
TypeScript
/**
|
|
* 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<string, any>)) {
|
|
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: `<link rel="stylesheet" href="/modules/choices/choices.css">`,
|
|
body: `<folk-choices-dashboard space="${spaceSlug}"></folk-choices-dashboard>`,
|
|
scripts: `<script type="module" src="/modules/choices/folk-choices-dashboard.js"></script>`,
|
|
}));
|
|
});
|
|
|
|
export const choicesModule: RSpaceModule = {
|
|
id: "choices",
|
|
name: "rChoices",
|
|
icon: "☑",
|
|
description: "Polls, rankings, and multi-criteria scoring",
|
|
routes,
|
|
};
|