/**
* domain-viewers.ts — the v1 viewer palette's actual rendering (musehub#117 DOM_09/DOM_10).
*
* Each viewer takes only a `viewerType` string and the domain's declared
* `dimensions` list (schema-validated server-side — see
* musehub/api/routes/musehub/domains.py's DomainCapabilities model) and
* renders real SVG. No per-domain executable code runs here — a domain
* manifest can only *select* one of these built-in, reviewed viewers and
* supply the dimension names/descriptions that parameterize it.
*
* Hand-rolled SVG via template strings, matching the existing pattern in
* src/ts/pages/timeline.ts and the sparkline in src/ts/pages/symbols.ts —
* no charting library dependency needed or added.
*/
import { domainColor } from './domain-palette.ts';
export interface DimensionSpec {
name: string;
description?: string;
}
function escapeXml(s: string): string {
return s
.replace(/&/g, '&')
.replace(//g, '>')
.replace(/"/g, '"');
}
/** Deterministic pseudo-activity seed from a dimension's name — gives each
* track a stable, distinct-looking pattern without any real commit data. */
function hashStr(s: string): number {
let h = 0;
for (let i = 0; i < s.length; i++) h = (h * 31 + s.charCodeAt(i)) | 0;
return Math.abs(h);
}
/**
* symbol_graph — a central "repo" node radiating to one node per dimension,
* styled like a lightweight commit/symbol graph (see code-demo.html for the
* full-scale reference this palette entry is modeled after).
*/
export function renderSymbolGraphViewer(container: HTMLElement, dimensions: DimensionSpec[]): void {
const color = domainColor('symbol_graph');
const dims = dimensions.length ? dimensions : [{ name: 'state' }];
const W = Math.max(container.clientWidth || 600, 360);
const H = Math.max(160, dims.length * 32 + 40);
const cx = 56;
const cy = H / 2;
const nodeX = Math.min(W - 80, 220);
const nodes = dims.map((d, i) => {
const y = dims.length === 1 ? cy : 24 + (i / (dims.length - 1)) * (H - 48);
return { x: nodeX, y, name: d.name };
});
const edges = nodes
.map(n => `
No dimensions declared for this domain yet.
`; return; } const items = dimensions .map(d => `