mirror of
https://github.com/DayuanJiang/next-ai-draw-io.git
synced 2026-09-02 01:20:23 +08:00
feat(diagram-engine): design tokens + role/group composition, engine-wide theming
Paper-summary posters previously required hand-written XML: every engine box rendered identically (white, 11px), so anything whose meaning lives in visual hierarchy came out flat. This makes presentation a first-class, generalised part of the declaration - not a poster feature. Structure/presentation separation, the same split HTML and CSS settled on: - ROLE says what a node IS: banner, heading, body, callout, good, bad, metric, muted. Maps to a type scale and an emphasis (filled / tinted / outlined / ghost), never to a colour. - GROUP says which semantic zone a node belongs to. Each distinct group name gets one hue ramp (tint / base / dark), assigned in document order. Promoted from a draw_graph-only field to BoxNode and GroupNode, round-tripped via dai_group. - themedStyle(role, hue, kind) composes the two by rule - there is no per-combination table to extend, so a new diagram kind gets full theming by tagging nodes. The model never sees a hex value. A heading container plus a group yields the tinted section panel with a dark title; a grouped body box takes its zone's tint; verdict roles stay green/red regardless of zone; the banner is the page's one dark field. Also fixed, found while building the acceptance poster: - autoBoxSize only counted explicit newlines, so a long single-line label wrapped to six lines in draw.io but got a one-line-tall box, and the text overflowed the cell. - Marker stamping appended without replacing, so every render of a recovered style grew it by one duplicate dai_* token per key - unnoticed because draw.io resolves duplicates last-wins. dai_* keys are now replaced in place; mxGraph keys still append, because last-wins is load-bearing for container=1 normalisation. - Banner/heading/metric roles stretch across their container's cross axis, the way a masthead spans its page. - Prompt: a poster's banner IS its title (no set_title alongside), and sections get their colour by naming groups. 537 unit tests, 250-flowchart corpus still zero crossing arrows, 5 e2e tests in a real browser. Verified visually: the Transformer-paper poster renders with a navy masthead, three hue-coded section panels, metric, verdict and callout boxes - all engine-computed geometry.
This commit is contained in:
@@ -36,6 +36,7 @@ import {
|
||||
readList,
|
||||
readMarker,
|
||||
} from "./markers"
|
||||
import { isRole, type Role } from "./theme"
|
||||
import type {
|
||||
BoxNode,
|
||||
BoxShape,
|
||||
@@ -347,6 +348,18 @@ function looksLikeText(style: string): boolean {
|
||||
}
|
||||
|
||||
/** The flowchart outline a box is drawn with, read back from its style. */
|
||||
/** The information role stamped on a cell, if any. */
|
||||
function roleOf(style: string): Role | undefined {
|
||||
const v = readMarker(style, MARKER.role)
|
||||
return isRole(v) ? v : undefined
|
||||
}
|
||||
|
||||
/** The semantic zone stamped on a cell, if any. */
|
||||
function zoneOf(style: string): string | undefined {
|
||||
const v = readMarker(style, MARKER.group)
|
||||
return v ? decodeURIComponent(v) : undefined
|
||||
}
|
||||
|
||||
function boxShape(style: string): BoxShape | undefined {
|
||||
const shape = styleValue(style, "shape")
|
||||
if (shape === "parallelogram") return "data"
|
||||
@@ -1055,6 +1068,8 @@ export function parseDiagram(xml: string, pageIndex = 0): ParseResult {
|
||||
fill: styleValue(c.style, "fillColor"),
|
||||
stroke: styleValue(c.style, "strokeColor"),
|
||||
shape: boxShape(c.style),
|
||||
role: roleOf(c.style),
|
||||
group: zoneOf(c.style),
|
||||
// A lifeline's style is chrome the renderer rebuilds, so keeping it verbatim
|
||||
// would re-emit a lifeline that no longer matches the new message count.
|
||||
style: lifeline ? undefined : c.style,
|
||||
@@ -1204,6 +1219,8 @@ export function parseDiagram(xml: string, pageIndex = 0): ParseResult {
|
||||
kind: "group",
|
||||
...common,
|
||||
dir: dir === "col" ? "col" : "row",
|
||||
role: roleOf(c.style),
|
||||
group: zoneOf(c.style),
|
||||
}
|
||||
return node
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user