diff --git a/system/netlify/functions/crm.mjs b/system/netlify/functions/crm.mjs index 037078f8c7..f2bd509421 100644 --- a/system/netlify/functions/crm.mjs +++ b/system/netlify/functions/crm.mjs @@ -64,7 +64,7 @@ async function rightsFor(database, handle) { const ld = doc.linkedData; if (ld?.enabled === false) return null; const license = isLicense(ld?.license) ? ld.license : DEFAULT_RIGHTS; - return { handle: doc.handle, license }; + return { handle: doc.handle, license, colors: doc.colors || [] }; } // In dev, ?preview=CC-BY-4.0 bypasses the gate so we can validate serialization @@ -89,17 +89,69 @@ function jsonld(doc) { return respond(200, doc, { "Content-Type": JSONLD }); } -// A minimal human view that points at both the JSON-LD and the apex page. -function htmlView(doc, webUrl) { - const body = `
Linked Art (CIDOC CRM) identity on data.aesthetic.computer.
+// Render a handle as its AC sigil: each glyph of "@handle" tinted by the +// per-character colors stored in @handles.colors. +function sigil(handle, colors) { + if (!handle) return ""; + const clean = handle.replace(/^@/, ""); + const glyphs = [...`@${clean}`] + .map((ch, i) => { + const c = colors?.[i]; + const col = c ? `rgb(${c.r},${c.g},${c.b})` : "var(--accent)"; + return `${esc(ch)}`; + }) + .join(""); + return `${glyphs}`; +} + +// A rich human view of a record — the handle sigil, the painting image, rights, +// and links to the JSON-LD / IIIF / apex. Styled to match the landing (auto +// light/dark). Machines still get JSON-LD via content negotiation. +function htmlView(doc, webUrl, extras = {}) { + const { kind, handle, colors, imageUrl, code } = extras; + const rights = doc.subject_to?.[0]; + const rightsHtml = rights + ? `Rights: ${esc(rights._label)}
` + : ""; + const img = imageUrl + ? `“${esc(doc.content)}”` : ""; + const iiif = + kind === "painting" + ? `
${JSON.stringify(doc, null, 2).replace(/`;
+`;
return respond(200, body, { "Content-Type": "text/html; charset=utf-8" });
}
@@ -137,7 +189,9 @@ export async function handler(event) {
.findOne({ user: await subForHandle(database, consent.handle), deleted: { $ne: true } }, { sort: { when: -1 } });
const doc = personToLinkedArt({ handle: consent.handle, latestMood });
- return finish(event, doc, `${WEB_BASE}/@${consent.handle}`);
+ return finish(event, doc, `${WEB_BASE}/@${consent.handle}`, {
+ kind: "person", handle: consent.handle, colors: consent.colors,
+ });
}
// Painting: /painting/{code}
@@ -145,7 +199,9 @@ export async function handler(event) {
const pt = await loadPainting(database, segs[1], event);
if (!pt) return respond(404, { message: "Not found" });
const doc = paintingToLinkedArt({ code: pt.code, handle: pt.handle, when: pt.when, imageUrl: pt.imageUrl, license: pt.license });
- return finish(event, doc, `${WEB_BASE}/painting/${pt.code}`);
+ return finish(event, doc, `${WEB_BASE}/painting/${pt.code}`, {
+ kind: "painting", handle: pt.handle, colors: pt.colors, imageUrl: pt.imageUrl, code: pt.code,
+ });
}
// IIIF surfaces: /iiif/{code}/manifest | /info.json | /full/max/0/default.png
@@ -187,7 +243,9 @@ export async function handler(event) {
hash: piece.hash,
license: consent.license,
});
- return finish(event, doc, `${WEB_BASE}/${piece.code}`);
+ return finish(event, doc, `${WEB_BASE}/${piece.code}`, {
+ kind: "piece", handle, colors: consent.colors, code: piece.code,
+ });
}
// Mood: /mood/{handle}/{rkey}
@@ -211,7 +269,9 @@ export async function handler(event) {
blueskyUri: mood.bluesky?.uri,
license: consent.license,
});
- return finish(event, doc, `${WEB_BASE}/moods~${consent.handle}~${rkey}`);
+ return finish(event, doc, `${WEB_BASE}/moods~${consent.handle}~${rkey}`, {
+ kind: "mood", handle: consent.handle, colors: consent.colors,
+ });
}
return respond(404, { message: "Not found" });
@@ -245,6 +305,7 @@ async function loadPainting(database, code, event) {
handle,
when: p.when,
license: consent.license,
+ colors: consent.colors,
imageUrl: paintingImageUrl(handle, p.slug, p.user),
};
}
@@ -282,8 +343,8 @@ async function sitemap(database) {
return respond(200, body, { "Content-Type": "application/xml; charset=utf-8" });
}
-function finish(event, doc, webUrl) {
- return wantsHtml(event) ? htmlView(doc, webUrl) : jsonld(doc);
+function finish(event, doc, webUrl, extras = {}) {
+ return wantsHtml(event) ? htmlView(doc, webUrl, extras) : jsonld(doc);
}
function voidDoc() {