@nowline/renderer 0.8.5 → 0.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/image-size.d.ts +9 -0
- package/dist/image-size.d.ts.map +1 -0
- package/dist/image-size.js +104 -0
- package/dist/image-size.js.map +1 -0
- package/dist/index.d.ts +4 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -1
- package/dist/index.js.map +1 -1
- package/dist/logo.d.ts +24 -0
- package/dist/logo.d.ts.map +1 -0
- package/dist/logo.js +60 -0
- package/dist/logo.js.map +1 -0
- package/dist/stage.d.ts +78 -0
- package/dist/stage.d.ts.map +1 -0
- package/dist/stage.js +88 -0
- package/dist/stage.js.map +1 -0
- package/dist/svg/edges.d.ts +3 -0
- package/dist/svg/edges.d.ts.map +1 -0
- package/dist/svg/edges.js +144 -0
- package/dist/svg/edges.js.map +1 -0
- package/dist/svg/footnotes.d.ts +4 -0
- package/dist/svg/footnotes.d.ts.map +1 -0
- package/dist/svg/footnotes.js +81 -0
- package/dist/svg/footnotes.js.map +1 -0
- package/dist/svg/header.d.ts +6 -0
- package/dist/svg/header.d.ts.map +1 -0
- package/dist/svg/header.js +215 -0
- package/dist/svg/header.js.map +1 -0
- package/dist/svg/ids.d.ts.map +1 -1
- package/dist/svg/ids.js.map +1 -1
- package/dist/svg/include-region.d.ts +4 -0
- package/dist/svg/include-region.d.ts.map +1 -0
- package/dist/svg/include-region.js +157 -0
- package/dist/svg/include-region.js.map +1 -0
- package/dist/svg/item.d.ts +36 -0
- package/dist/svg/item.d.ts.map +1 -0
- package/dist/svg/item.js +549 -0
- package/dist/svg/item.js.map +1 -0
- package/dist/svg/markers.d.ts +7 -0
- package/dist/svg/markers.d.ts.map +1 -0
- package/dist/svg/markers.js +151 -0
- package/dist/svg/markers.js.map +1 -0
- package/dist/svg/nowline.d.ts +4 -0
- package/dist/svg/nowline.d.ts.map +1 -0
- package/dist/svg/nowline.js +133 -0
- package/dist/svg/nowline.js.map +1 -0
- package/dist/svg/primitives.d.ts +7 -0
- package/dist/svg/primitives.d.ts.map +1 -0
- package/dist/svg/primitives.js +70 -0
- package/dist/svg/primitives.js.map +1 -0
- package/dist/svg/render.d.ts +13 -7
- package/dist/svg/render.d.ts.map +1 -1
- package/dist/svg/render.js +64 -1701
- package/dist/svg/render.js.map +1 -1
- package/dist/svg/sanitize.d.ts +10 -0
- package/dist/svg/sanitize.d.ts.map +1 -1
- package/dist/svg/sanitize.js +264 -16
- package/dist/svg/sanitize.js.map +1 -1
- package/dist/svg/swimlanes.d.ts +5 -0
- package/dist/svg/swimlanes.d.ts.map +1 -0
- package/dist/svg/swimlanes.js +228 -0
- package/dist/svg/swimlanes.js.map +1 -0
- package/dist/svg/timeline.d.ts +24 -0
- package/dist/svg/timeline.d.ts.map +1 -0
- package/dist/svg/timeline.js +284 -0
- package/dist/svg/timeline.js.map +1 -0
- package/dist/svg/waves.d.ts +62 -0
- package/dist/svg/waves.d.ts.map +1 -0
- package/dist/svg/waves.js +397 -0
- package/dist/svg/waves.js.map +1 -0
- package/package.json +7 -7
- package/src/image-size.ts +113 -0
- package/src/index.ts +10 -1
- package/src/logo.ts +82 -0
- package/src/stage.ts +191 -0
- package/src/svg/edges.ts +154 -0
- package/src/svg/footnotes.ts +115 -0
- package/src/svg/header.ts +285 -0
- package/src/svg/include-region.ts +201 -0
- package/src/svg/item.ts +672 -0
- package/src/svg/markers.ts +178 -0
- package/src/svg/nowline.ts +152 -0
- package/src/svg/primitives.ts +86 -0
- package/src/svg/render.ts +94 -2110
- package/src/svg/sanitize.ts +286 -16
- package/src/svg/swimlanes.ts +317 -0
- package/src/svg/timeline.ts +343 -0
- package/src/svg/waves.ts +502 -0
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
// The footnotes layer: the panel at the bottom of the chart that lists each
|
|
2
|
+
// footnote's number, title and description, drawn only when the roadmap has
|
|
3
|
+
// footnotes.
|
|
4
|
+
import { FOOTNOTE_HEADER_BASELINE_OFFSET_PX, FOOTNOTE_PANEL_PADDING_PX } from '@nowline/layout';
|
|
5
|
+
import { num, tag, textTag } from './xml.js';
|
|
6
|
+
export function renderFootnotes(f, idPrefix, palette, fonts) {
|
|
7
|
+
if (f.entries.length === 0)
|
|
8
|
+
return '';
|
|
9
|
+
const panelFill = palette.footnotePanel.fill;
|
|
10
|
+
const borderColor = palette.footnotePanel.border;
|
|
11
|
+
const headerColor = palette.footnotePanel.header;
|
|
12
|
+
const titleColor = palette.footnotePanel.title;
|
|
13
|
+
const descColor = palette.footnotePanel.description;
|
|
14
|
+
const numberColor = palette.footnotePanel.number;
|
|
15
|
+
const parts = [];
|
|
16
|
+
parts.push(tag('rect', {
|
|
17
|
+
x: num(f.box.x),
|
|
18
|
+
y: num(f.box.y),
|
|
19
|
+
width: num(f.box.width),
|
|
20
|
+
height: num(f.box.height),
|
|
21
|
+
rx: 6,
|
|
22
|
+
ry: 6,
|
|
23
|
+
fill: panelFill,
|
|
24
|
+
stroke: borderColor,
|
|
25
|
+
'stroke-width': 1,
|
|
26
|
+
filter: `url(#${idPrefix}-shadow-subtle)`,
|
|
27
|
+
}));
|
|
28
|
+
parts.push(textTag({
|
|
29
|
+
x: num(f.box.x + FOOTNOTE_PANEL_PADDING_PX),
|
|
30
|
+
y: num(f.box.y + FOOTNOTE_HEADER_BASELINE_OFFSET_PX),
|
|
31
|
+
'font-family': fonts.sans,
|
|
32
|
+
'font-size': 12,
|
|
33
|
+
'font-weight': 700,
|
|
34
|
+
fill: headerColor,
|
|
35
|
+
}, 'Footnotes'));
|
|
36
|
+
// Layout places every row: the entry's number on its first row, the
|
|
37
|
+
// title and description lines (wrapped ones included) at their own
|
|
38
|
+
// baselines, and a region's heading row above its first entry.
|
|
39
|
+
const numberX = f.box.x + FOOTNOTE_PANEL_PADDING_PX;
|
|
40
|
+
for (const e of f.entries) {
|
|
41
|
+
if (e.region !== undefined && e.regionHeadingY !== undefined) {
|
|
42
|
+
parts.push(textTag({
|
|
43
|
+
x: num(numberX),
|
|
44
|
+
y: num(e.regionHeadingY),
|
|
45
|
+
'font-family': fonts.sans,
|
|
46
|
+
'font-size': 10,
|
|
47
|
+
'font-weight': 700,
|
|
48
|
+
fill: headerColor,
|
|
49
|
+
}, e.region));
|
|
50
|
+
}
|
|
51
|
+
parts.push(textTag({
|
|
52
|
+
x: num(numberX),
|
|
53
|
+
y: num(e.y),
|
|
54
|
+
'font-family': fonts.sans,
|
|
55
|
+
'font-size': 10,
|
|
56
|
+
'font-weight': 700,
|
|
57
|
+
fill: numberColor,
|
|
58
|
+
}, String(e.number)));
|
|
59
|
+
for (const line of e.titleLines) {
|
|
60
|
+
parts.push(textTag({
|
|
61
|
+
x: num(line.x),
|
|
62
|
+
y: num(line.y),
|
|
63
|
+
'font-family': fonts.sans,
|
|
64
|
+
'font-size': 11,
|
|
65
|
+
'font-weight': 600,
|
|
66
|
+
fill: titleColor,
|
|
67
|
+
}, line.text));
|
|
68
|
+
}
|
|
69
|
+
for (const line of e.descriptionLines ?? []) {
|
|
70
|
+
parts.push(textTag({
|
|
71
|
+
x: num(line.x),
|
|
72
|
+
y: num(line.y),
|
|
73
|
+
'font-family': fonts.sans,
|
|
74
|
+
'font-size': 11,
|
|
75
|
+
fill: descColor,
|
|
76
|
+
}, line.text));
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
return tag('g', { 'data-layer': 'footnotes' }, parts.join(''));
|
|
80
|
+
}
|
|
81
|
+
//# sourceMappingURL=footnotes.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"footnotes.js","sourceRoot":"","sources":["../../src/svg/footnotes.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { PositionedHeader, PositionedLogo, PositionedRoadmap, Theme } from '@nowline/layout';
|
|
2
|
+
import type { AssetResolver, FontFamilies, RenderOptions } from './render.js';
|
|
3
|
+
export declare function renderHeader(h: PositionedHeader, idPrefix: string, palette: Theme, fonts: FontFamilies): string;
|
|
4
|
+
export declare function renderAttributionMark(model: PositionedRoadmap, fonts: FontFamilies): string;
|
|
5
|
+
export declare function embedLogo(logo: PositionedLogo, resolver: AssetResolver | undefined, idPrefix: string, options: RenderOptions): Promise<string>;
|
|
6
|
+
//# sourceMappingURL=header.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"header.d.ts","sourceRoot":"","sources":["../../src/svg/header.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,gBAAgB,EAAE,cAAc,EAAE,iBAAiB,EAAE,KAAK,EAAE,MAAM,iBAAiB,CAAC;AAmBlG,OAAO,KAAK,EAAc,aAAa,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAI1F,wBAAgB,YAAY,CACxB,CAAC,EAAE,gBAAgB,EACnB,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,KAAK,EACd,KAAK,EAAE,YAAY,GACpB,MAAM,CA6ER;AAQD,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,iBAAiB,EAAE,KAAK,EAAE,YAAY,GAAG,MAAM,CAkE3F;AAMD,wBAAsB,SAAS,CAC3B,IAAI,EAAE,cAAc,EACpB,QAAQ,EAAE,aAAa,GAAG,SAAS,EACnC,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,aAAa,GACvB,OAAO,CAAC,MAAM,CAAC,CA2EjB"}
|
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
// The header layers: the title card, the "Powered by nowline" attribution mark,
|
|
2
|
+
// and the embedded logo that sits in the card, plus the base64 helper the logo
|
|
3
|
+
// path uses.
|
|
4
|
+
import { ATTRIBUTION_BAR_LOGICAL_WIDTH, ATTRIBUTION_BAR_LOGICAL_X, ATTRIBUTION_INE_LOGICAL_X, ATTRIBUTION_LINK, ATTRIBUTION_NOW_LOGICAL_X, ATTRIBUTION_PREFIX_FONT_SIZE, ATTRIBUTION_SCALE, ATTRIBUTION_TEXT, ATTRIBUTION_WORDMARK_FONT_SIZE, HEADER_AUTHOR_FONT_SIZE_PX, HEADER_AUTHOR_LINE_HEIGHT_PX, HEADER_CARD_PADDING_TOP, HEADER_CARD_PADDING_X, HEADER_TITLE_FONT_SIZE_PX, HEADER_TITLE_LINE_HEIGHT_PX, HEADER_TITLE_TO_AUTHOR_GAP_PX, } from '@nowline/layout';
|
|
5
|
+
import { sanitizeSvg, svgIntrinsicSize } from './sanitize.js';
|
|
6
|
+
import { num, tag, textTag } from './xml.js';
|
|
7
|
+
export function renderHeader(h, idPrefix, palette, fonts) {
|
|
8
|
+
// The layout has already sized the card to its (wrapped) text content
|
|
9
|
+
// and stashed the bounds in `h.cardBox`, with `h.titleLines` /
|
|
10
|
+
// `h.authorLines` ready to render line-by-line. See sizeBesideHeader
|
|
11
|
+
// in @nowline/layout.
|
|
12
|
+
const cardX = h.box.x + h.cardBox.x;
|
|
13
|
+
const cardY = h.box.y + h.cardBox.y;
|
|
14
|
+
const cardWidth = h.cardBox.width;
|
|
15
|
+
const cardHeight = h.cardBox.height;
|
|
16
|
+
const cardFill = h.style.bg === 'none' ? palette.surface.headerBox : h.style.bg;
|
|
17
|
+
const borderColor = palette.header.cardBorder;
|
|
18
|
+
const card = tag('rect', {
|
|
19
|
+
x: num(cardX),
|
|
20
|
+
y: num(cardY),
|
|
21
|
+
width: num(cardWidth),
|
|
22
|
+
height: num(cardHeight),
|
|
23
|
+
rx: 6,
|
|
24
|
+
ry: 6,
|
|
25
|
+
fill: cardFill,
|
|
26
|
+
stroke: borderColor,
|
|
27
|
+
'stroke-width': 1,
|
|
28
|
+
filter: `url(#${idPrefix}-shadow-subtle)`,
|
|
29
|
+
});
|
|
30
|
+
// Title and author baselines come from `@nowline/layout`'s
|
|
31
|
+
// `header-card-geometry` module so the renderer paints with the
|
|
32
|
+
// exact metrics `sizeBesideHeader` sized the card to.
|
|
33
|
+
// A logo in the card shifts the text right of it (and down, to center
|
|
34
|
+
// it, when the logo made the card taller); see `h.textInset`.
|
|
35
|
+
const textX = cardX + HEADER_CARD_PADDING_X + (h.textInset?.x ?? 0);
|
|
36
|
+
const textTopY = cardY + (h.textInset?.y ?? 0);
|
|
37
|
+
const titleParts = [];
|
|
38
|
+
h.titleLines.forEach((line, i) => {
|
|
39
|
+
titleParts.push(textTag({
|
|
40
|
+
x: num(textX),
|
|
41
|
+
y: num(textTopY + HEADER_CARD_PADDING_TOP + i * HEADER_TITLE_LINE_HEIGHT_PX),
|
|
42
|
+
'font-family': fonts[h.style.font],
|
|
43
|
+
'font-size': HEADER_TITLE_FONT_SIZE_PX,
|
|
44
|
+
'font-weight': 600,
|
|
45
|
+
fill: h.style.text,
|
|
46
|
+
}, line));
|
|
47
|
+
});
|
|
48
|
+
const titleText = titleParts.join('');
|
|
49
|
+
const lastTitleY = textTopY +
|
|
50
|
+
HEADER_CARD_PADDING_TOP +
|
|
51
|
+
Math.max(0, h.titleLines.length - 1) * HEADER_TITLE_LINE_HEIGHT_PX;
|
|
52
|
+
const authorColor = palette.header.author;
|
|
53
|
+
const authorParts = [];
|
|
54
|
+
h.authorLines.forEach((line, j) => {
|
|
55
|
+
authorParts.push(textTag({
|
|
56
|
+
x: num(textX),
|
|
57
|
+
y: num(lastTitleY +
|
|
58
|
+
HEADER_TITLE_TO_AUTHOR_GAP_PX +
|
|
59
|
+
j * HEADER_AUTHOR_LINE_HEIGHT_PX),
|
|
60
|
+
'font-family': fonts[h.style.font],
|
|
61
|
+
'font-size': HEADER_AUTHOR_FONT_SIZE_PX,
|
|
62
|
+
fill: authorColor,
|
|
63
|
+
}, line));
|
|
64
|
+
});
|
|
65
|
+
const authorText = authorParts.join('');
|
|
66
|
+
return tag('g', { 'data-layer': 'header', 'data-id': `${idPrefix}-header` }, card + titleText + authorText);
|
|
67
|
+
}
|
|
68
|
+
// Paint the "Powered by nowline" attribution mark inside the
|
|
69
|
+
// layout-supplied `attributionBox`. The whole mark — prefix text,
|
|
70
|
+
// "now", red "l" bar, and "ine" — sits inside one <a href> so the
|
|
71
|
+
// entire string is clickable. Glyph anatomy (positions, widths, scale)
|
|
72
|
+
// lives in `themes/shared.ts` (`ATTRIBUTION_*`); the layout reserves a
|
|
73
|
+
// box of exactly that size at canvas-bottom-right.
|
|
74
|
+
export function renderAttributionMark(model, fonts) {
|
|
75
|
+
const muted = model.palette.attribution.mark;
|
|
76
|
+
const accent = model.palette.attribution.link;
|
|
77
|
+
if (model.swimlanes.length === 0)
|
|
78
|
+
return '';
|
|
79
|
+
const tx = model.header.attributionBox.x;
|
|
80
|
+
const ty = model.header.attributionBox.y;
|
|
81
|
+
// Both texts share the wordmark's baseline (y = wordmark font size)
|
|
82
|
+
// so the smaller "Powered by" sits visually above the wordmark's
|
|
83
|
+
// baseline without bumping the bar's bottom up.
|
|
84
|
+
const baselineY = ATTRIBUTION_WORDMARK_FONT_SIZE;
|
|
85
|
+
const inner = textTag({
|
|
86
|
+
x: '0',
|
|
87
|
+
y: baselineY,
|
|
88
|
+
'font-family': fonts.sans,
|
|
89
|
+
'font-size': ATTRIBUTION_PREFIX_FONT_SIZE,
|
|
90
|
+
'font-weight': 400,
|
|
91
|
+
fill: muted,
|
|
92
|
+
}, ATTRIBUTION_TEXT) +
|
|
93
|
+
textTag({
|
|
94
|
+
x: ATTRIBUTION_NOW_LOGICAL_X,
|
|
95
|
+
y: baselineY,
|
|
96
|
+
'font-family': fonts.sans,
|
|
97
|
+
'font-size': ATTRIBUTION_WORDMARK_FONT_SIZE,
|
|
98
|
+
'font-weight': 700,
|
|
99
|
+
fill: muted,
|
|
100
|
+
}, 'now') +
|
|
101
|
+
tag('rect', {
|
|
102
|
+
x: ATTRIBUTION_BAR_LOGICAL_X,
|
|
103
|
+
y: 12,
|
|
104
|
+
width: ATTRIBUTION_BAR_LOGICAL_WIDTH,
|
|
105
|
+
height: ATTRIBUTION_WORDMARK_FONT_SIZE,
|
|
106
|
+
fill: accent,
|
|
107
|
+
}) +
|
|
108
|
+
textTag({
|
|
109
|
+
x: ATTRIBUTION_INE_LOGICAL_X,
|
|
110
|
+
y: baselineY,
|
|
111
|
+
'font-family': fonts.sans,
|
|
112
|
+
'font-size': ATTRIBUTION_WORDMARK_FONT_SIZE,
|
|
113
|
+
'font-weight': 400,
|
|
114
|
+
fill: muted,
|
|
115
|
+
}, 'ine');
|
|
116
|
+
const group = tag('g', { transform: `translate(${num(tx)} ${num(ty)}) scale(${num(ATTRIBUTION_SCALE)})` }, inner);
|
|
117
|
+
return tag('a', {
|
|
118
|
+
href: ATTRIBUTION_LINK,
|
|
119
|
+
target: '_blank',
|
|
120
|
+
rel: 'noopener',
|
|
121
|
+
'aria-label': 'Powered by nowline',
|
|
122
|
+
}, tag('g', { 'data-layer': 'attribution' }, group));
|
|
123
|
+
}
|
|
124
|
+
// Draws the logo into its layout box. Layout sized the box to the asset's
|
|
125
|
+
// aspect ratio, so scaling the asset to the box fills it exactly whether
|
|
126
|
+
// the source is larger or smaller; `meet` (fit) only matters if the two
|
|
127
|
+
// disagree, and then it letterboxes rather than cropping or distorting.
|
|
128
|
+
export async function embedLogo(logo, resolver, idPrefix, options) {
|
|
129
|
+
const logoRef = logo.assetRef ?? '';
|
|
130
|
+
const { x, y, width, height } = logo.box;
|
|
131
|
+
let asset;
|
|
132
|
+
try {
|
|
133
|
+
if (options.logo && options.logo.ref === logoRef) {
|
|
134
|
+
asset = options.logo.asset;
|
|
135
|
+
}
|
|
136
|
+
else if (resolver) {
|
|
137
|
+
asset = await resolver(logoRef);
|
|
138
|
+
}
|
|
139
|
+
else {
|
|
140
|
+
return '';
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
catch (err) {
|
|
144
|
+
const msg = `logo file not found: ${logoRef} (${err instanceof Error ? err.message : String(err)})`;
|
|
145
|
+
if (options.strict)
|
|
146
|
+
throw err;
|
|
147
|
+
options.warn?.(msg);
|
|
148
|
+
return '';
|
|
149
|
+
}
|
|
150
|
+
const mime = (asset.mime ?? '').toLowerCase();
|
|
151
|
+
if (mime === 'image/svg+xml') {
|
|
152
|
+
const raw = new TextDecoder().decode(asset.bytes);
|
|
153
|
+
const intrinsic = logo.intrinsic ?? svgIntrinsicSize(raw) ?? { width, height };
|
|
154
|
+
// The root loses its own size so it fills this viewport; the
|
|
155
|
+
// viewport's viewBox then scales the asset's units to the box.
|
|
156
|
+
// One warning per logo listing what the sanitizer removed, not one
|
|
157
|
+
// per attribute; editor metadata it removes silently.
|
|
158
|
+
const removed = new Set();
|
|
159
|
+
const cleaned = sanitizeSvg(raw, {
|
|
160
|
+
idPrefix: `${idPrefix}-logo`,
|
|
161
|
+
onWarn: (msg) => removed.add(msg.replace(/^sanitizer: dropping /, '')),
|
|
162
|
+
stripRootSize: true,
|
|
163
|
+
});
|
|
164
|
+
// A warning even under strict: callers promote warnings themselves
|
|
165
|
+
// (the export kernel throws, the browser pipeline returns rows).
|
|
166
|
+
if (removed.size > 0) {
|
|
167
|
+
options.warn?.(`logo ${logoRef}: removed unsupported SVG content: ${[...removed].join(', ')}`);
|
|
168
|
+
}
|
|
169
|
+
return tag('svg', {
|
|
170
|
+
'data-layer': 'logo',
|
|
171
|
+
x: num(x),
|
|
172
|
+
y: num(y),
|
|
173
|
+
width: num(width),
|
|
174
|
+
height: num(height),
|
|
175
|
+
viewBox: `0 0 ${num(intrinsic.width)} ${num(intrinsic.height)}`,
|
|
176
|
+
preserveAspectRatio: 'xMidYMid meet',
|
|
177
|
+
overflow: 'hidden',
|
|
178
|
+
}, cleaned);
|
|
179
|
+
}
|
|
180
|
+
if (mime === 'image/png' ||
|
|
181
|
+
mime === 'image/jpeg' ||
|
|
182
|
+
mime === 'image/jpg' ||
|
|
183
|
+
mime === 'image/webp') {
|
|
184
|
+
const b64 = bytesToBase64(asset.bytes);
|
|
185
|
+
return tag('image', {
|
|
186
|
+
'data-layer': 'logo',
|
|
187
|
+
href: `data:${mime};base64,${b64}`,
|
|
188
|
+
x: num(x),
|
|
189
|
+
y: num(y),
|
|
190
|
+
width: num(width),
|
|
191
|
+
height: num(height),
|
|
192
|
+
preserveAspectRatio: 'xMidYMid meet',
|
|
193
|
+
});
|
|
194
|
+
}
|
|
195
|
+
const msg = `unsupported logo format: ${mime} (${logoRef})`;
|
|
196
|
+
if (options.strict)
|
|
197
|
+
throw new Error(msg);
|
|
198
|
+
options.warn?.(msg);
|
|
199
|
+
return '';
|
|
200
|
+
}
|
|
201
|
+
// Base64 without depending on Node's Buffer (renderer stays browser-safe).
|
|
202
|
+
function bytesToBase64(bytes) {
|
|
203
|
+
if (typeof btoa !== 'undefined') {
|
|
204
|
+
let bin = '';
|
|
205
|
+
for (let i = 0; i < bytes.length; i++)
|
|
206
|
+
bin += String.fromCharCode(bytes[i]);
|
|
207
|
+
return btoa(bin);
|
|
208
|
+
}
|
|
209
|
+
// Node fallback without importing Buffer directly; use lazy dynamic require.
|
|
210
|
+
const g = globalThis;
|
|
211
|
+
if (g.Buffer)
|
|
212
|
+
return g.Buffer.from(bytes).toString('base64');
|
|
213
|
+
throw new Error('renderer: no base64 encoder available');
|
|
214
|
+
}
|
|
215
|
+
//# sourceMappingURL=header.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"header.js","sourceRoot":"","sources":["../../src/svg/header.ts"],"names":[],"mappings":"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"}
|
package/dist/svg/ids.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ids.d.ts","sourceRoot":"","sources":["../../src/svg/ids.ts"],"names":[],"mappings":"AAIA,qBAAa,WAAW;IAER,OAAO,CAAC,QAAQ,CAAC,MAAM;IADnC,OAAO,CAAC,OAAO,CAAK;
|
|
1
|
+
{"version":3,"file":"ids.d.ts","sourceRoot":"","sources":["../../src/svg/ids.ts"],"names":[],"mappings":"AAIA,qBAAa,WAAW;IAER,OAAO,CAAC,QAAQ,CAAC,MAAM;IADnC,OAAO,CAAC,OAAO,CAAK;IACpB,YAA6B,MAAM,GAAE,MAAa,EAAI;IACtD,IAAI,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,CAG3B;CACJ"}
|
package/dist/svg/ids.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ids.js","sourceRoot":"","sources":["../../src/svg/ids.ts"],"names":[],"mappings":"AAAA,2EAA2E;AAC3E,wEAAwE;AACxE,sDAAsD;AAEtD,MAAM,OAAO,WAAW;IAES;
|
|
1
|
+
{"version":3,"file":"ids.js","sourceRoot":"","sources":["../../src/svg/ids.ts"],"names":[],"mappings":"AAAA,2EAA2E;AAC3E,wEAAwE;AACxE,sDAAsD;AAEtD,MAAM,OAAO,WAAW;IAES,MAAM;IAD3B,OAAO,GAAG,CAAC,CAAC;IACpB,YAA6B,MAAM,GAAW,IAAI;sBAArB,MAAM;IAAkB,CAAC;IACtD,IAAI,CAAC,KAAc;QACf,MAAM,EAAE,GAAG,GAAG,IAAI,CAAC,MAAM,IAAI,IAAI,CAAC,OAAO,EAAE,EAAE,CAAC;QAC9C,OAAO,KAAK,CAAC,CAAC,CAAC,GAAG,EAAE,IAAI,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;IACzC,CAAC;CACJ"}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { PositionedIncludeRegion, PositionedRoadmap, Theme } from '@nowline/layout';
|
|
2
|
+
import type { FontFamilies, RenderOptions } from './render.js';
|
|
3
|
+
export declare function renderIncludeRegion(r: PositionedIncludeRegion, options: RenderOptions, idPrefix: string, palette: Theme, fonts: FontFamilies, model?: PositionedRoadmap): string;
|
|
4
|
+
//# sourceMappingURL=include-region.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"include-region.d.ts","sourceRoot":"","sources":["../../src/svg/include-region.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAER,uBAAuB,EACvB,iBAAiB,EACjB,KAAK,EACR,MAAM,iBAAiB,CAAC;AAczB,OAAO,KAAK,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAM/D,wBAAgB,mBAAmB,CAC/B,CAAC,EAAE,uBAAuB,EAC1B,OAAO,EAAE,aAAa,EACtB,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,KAAK,EACd,KAAK,EAAE,YAAY,EACnB,KAAK,CAAC,EAAE,iBAAiB,GAC1B,MAAM,CAoKR"}
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
// The include-region layer: the dashed border, frame tab, badge and source
|
|
2
|
+
// label drawn around the roadmap an `include` pulls in, with that roadmap's own
|
|
3
|
+
// swimlanes, edges, markers, non-working bands and wave layers nested inside.
|
|
4
|
+
import { ACCENT_DASH_PATTERN, FRAME_TAB_HEIGHT_PX, FRAME_TAB_LABEL_BASELINE_OFFSET_PX, includeChromeGeometry, } from '@nowline/layout';
|
|
5
|
+
import { renderEdge } from './edges.js';
|
|
6
|
+
import { renderAnchor, renderAnchorCutLine, renderMilestone, renderMilestoneCutLine, } from './markers.js';
|
|
7
|
+
import { renderSwimlane } from './swimlanes.js';
|
|
8
|
+
import { renderNonWorkingBands } from './timeline.js';
|
|
9
|
+
import { renderWaveBoundaries, renderWaveCrossings, renderWaveTints } from './waves.js';
|
|
10
|
+
import { num, tag, textTag } from './xml.js';
|
|
11
|
+
export function renderIncludeRegion(r, options, idPrefix, palette, fonts, model) {
|
|
12
|
+
const border = palette.includeRegion.border;
|
|
13
|
+
const fill = palette.includeRegion.fill;
|
|
14
|
+
const tabFill = palette.includeRegion.tabFill;
|
|
15
|
+
const tabStroke = palette.includeRegion.tabStroke;
|
|
16
|
+
const tabText = palette.includeRegion.tabText;
|
|
17
|
+
const badgeFill = palette.includeRegion.badgeFill;
|
|
18
|
+
const badgeStroke = palette.includeRegion.badgeStroke;
|
|
19
|
+
const badgeText = palette.includeRegion.badgeText;
|
|
20
|
+
const rx = r.box.x + 8;
|
|
21
|
+
const ry = r.box.y;
|
|
22
|
+
const rw = r.box.width - 16;
|
|
23
|
+
const rh = r.box.height;
|
|
24
|
+
const region = tag('rect', {
|
|
25
|
+
x: num(rx),
|
|
26
|
+
y: num(ry),
|
|
27
|
+
width: num(rw),
|
|
28
|
+
height: num(rh),
|
|
29
|
+
rx: 8,
|
|
30
|
+
ry: 8,
|
|
31
|
+
fill,
|
|
32
|
+
stroke: border,
|
|
33
|
+
'stroke-width': 1,
|
|
34
|
+
'stroke-dasharray': ACCENT_DASH_PATTERN,
|
|
35
|
+
});
|
|
36
|
+
// Chrome geometry — single source of truth shared with the layout
|
|
37
|
+
// (`buildIncludeRegions` calls the same helper to size the dashed
|
|
38
|
+
// bracket so the chrome always fits inside it). All placement Xs
|
|
39
|
+
// come from the helper directly so the renderer stays declarative.
|
|
40
|
+
const tabHeight = FRAME_TAB_HEIGHT_PX;
|
|
41
|
+
const chrome = includeChromeGeometry(r.box.x, r.label, r.sourcePath);
|
|
42
|
+
const tabY = ry - tabHeight / 2;
|
|
43
|
+
const tab = tag('rect', {
|
|
44
|
+
x: num(chrome.tabX),
|
|
45
|
+
y: num(tabY),
|
|
46
|
+
width: num(chrome.tabWidth),
|
|
47
|
+
height: tabHeight,
|
|
48
|
+
rx: 4,
|
|
49
|
+
ry: 4,
|
|
50
|
+
fill: tabFill,
|
|
51
|
+
stroke: tabStroke,
|
|
52
|
+
'stroke-width': 1,
|
|
53
|
+
});
|
|
54
|
+
const tabLabel = textTag({
|
|
55
|
+
x: num(chrome.tabLabelX),
|
|
56
|
+
y: num(tabY + FRAME_TAB_LABEL_BASELINE_OFFSET_PX),
|
|
57
|
+
'font-family': fonts.sans,
|
|
58
|
+
'font-size': 11,
|
|
59
|
+
'font-weight': 600,
|
|
60
|
+
fill: tabText,
|
|
61
|
+
}, r.label);
|
|
62
|
+
// Content badge to the right of the tab. The glyph here is the
|
|
63
|
+
// stacked-sheets icon, distinct from the item-level link-icon
|
|
64
|
+
// outbound-arrow: an `include` is a content pull (one document
|
|
65
|
+
// brings in another), conceptually different from a `link:` that
|
|
66
|
+
// navigates somewhere.
|
|
67
|
+
const badgeX = chrome.badgeX;
|
|
68
|
+
const badgeSize = chrome.badgeSize;
|
|
69
|
+
const badgeY = ry - badgeSize / 2;
|
|
70
|
+
const badge = tag('rect', {
|
|
71
|
+
x: num(badgeX),
|
|
72
|
+
y: num(badgeY),
|
|
73
|
+
width: badgeSize,
|
|
74
|
+
height: badgeSize,
|
|
75
|
+
rx: 4,
|
|
76
|
+
ry: 4,
|
|
77
|
+
fill: badgeFill,
|
|
78
|
+
stroke: badgeStroke,
|
|
79
|
+
'stroke-width': 1,
|
|
80
|
+
});
|
|
81
|
+
// Glyph: stacked sheets — back rectangle peeking behind front
|
|
82
|
+
// rectangle. Sized for the 18×18 badge tile.
|
|
83
|
+
const glyph = tag('path', {
|
|
84
|
+
d: `M${num(badgeX + 7)} ${num(badgeY + 4)} H${num(badgeX + 14)} V${num(badgeY + 11)}` +
|
|
85
|
+
` M${num(badgeX + 4)} ${num(badgeY + 7)} H${num(badgeX + 11)} V${num(badgeY + 14)} H${num(badgeX + 4)} Z`,
|
|
86
|
+
stroke: badgeText,
|
|
87
|
+
'stroke-width': 1.4,
|
|
88
|
+
fill: 'none',
|
|
89
|
+
'stroke-linecap': 'round',
|
|
90
|
+
'stroke-linejoin': 'round',
|
|
91
|
+
});
|
|
92
|
+
// Halo behind the source-path text. The text's baseline at `ry + 4`
|
|
93
|
+
// straddles the dashed region border (drawn at y = ry); without a
|
|
94
|
+
// backing rect the dashed stroke cuts through the text body. Matches
|
|
95
|
+
// how the tab and badge already mask the border where they cross it.
|
|
96
|
+
// Fill is `includeRegion.fill` — same cream/tint as the region, near
|
|
97
|
+
// the canvas surface above, so the halo disappears into both.
|
|
98
|
+
const sourceFontSize = 9;
|
|
99
|
+
const sourceTextY = ry + 4;
|
|
100
|
+
const sourceHalo = tag('rect', {
|
|
101
|
+
x: num(chrome.sourceHaloX),
|
|
102
|
+
y: num(sourceTextY - sourceFontSize),
|
|
103
|
+
width: num(chrome.sourceHaloWidth),
|
|
104
|
+
height: sourceFontSize + 6,
|
|
105
|
+
fill,
|
|
106
|
+
});
|
|
107
|
+
const sourceText = textTag({
|
|
108
|
+
x: num(chrome.sourceTextX),
|
|
109
|
+
y: num(sourceTextY),
|
|
110
|
+
'font-family': fonts.mono,
|
|
111
|
+
'font-size': sourceFontSize,
|
|
112
|
+
fill: badgeText,
|
|
113
|
+
}, r.sourcePath);
|
|
114
|
+
// The opaque region fill hides the global wave layers, so a roadmap
|
|
115
|
+
// with waves re-emits its styled tints and boundaries over it, clipped
|
|
116
|
+
// to the painted region rect by rect intersection (no clipPath, no new
|
|
117
|
+
// defs), and the region's own crossings over its nested lanes
|
|
118
|
+
// (specs/waves.md §9.8). The strip stays global.
|
|
119
|
+
const clip = { x: rx, y: ry, width: rw, height: rh };
|
|
120
|
+
// The same opaque fill hides the global non-working bands, so they are
|
|
121
|
+
// re-emitted over it the same way, under the wave layers.
|
|
122
|
+
const bandsUnder = model
|
|
123
|
+
? renderNonWorkingBands(model.timeline, model.chartBox.y, palette, clip)
|
|
124
|
+
: '';
|
|
125
|
+
const waveUnder = model?.waves
|
|
126
|
+
? renderWaveTints(model.waves, clip) + renderWaveBoundaries(model.waveBoundaries, clip)
|
|
127
|
+
: '';
|
|
128
|
+
const waveOver = model?.waves ? renderWaveCrossings(r.waveCrossings) : '';
|
|
129
|
+
// Nested swimlanes (laid out by buildIncludeRegions against the parent's timeline).
|
|
130
|
+
const nested = r.nestedSwimlanes
|
|
131
|
+
.map((s) => renderSwimlane(s, options, idPrefix, palette, fonts))
|
|
132
|
+
.join('');
|
|
133
|
+
// The region's own dependency edges, behind its bars as on the host.
|
|
134
|
+
const edges = (r.edges ?? []).map((e) => renderEdge(e, palette)).join('');
|
|
135
|
+
// The region's own anchors and milestones: cut lines over its lanes,
|
|
136
|
+
// then the diamonds and labels of its marker row, as on the host.
|
|
137
|
+
const anchors = r.anchors ?? [];
|
|
138
|
+
const milestones = r.milestones ?? [];
|
|
139
|
+
const markers = anchors.map((a) => renderAnchorCutLine(a, palette)).join('') +
|
|
140
|
+
milestones.map((m) => renderMilestoneCutLine(m, idPrefix, palette)).join('') +
|
|
141
|
+
anchors.map((a) => renderAnchor(a, palette, fonts)).join('') +
|
|
142
|
+
milestones.map((m) => renderMilestone(m, palette, fonts)).join('');
|
|
143
|
+
return tag('g', { 'data-layer': 'include' }, region +
|
|
144
|
+
bandsUnder +
|
|
145
|
+
waveUnder +
|
|
146
|
+
edges +
|
|
147
|
+
nested +
|
|
148
|
+
waveOver +
|
|
149
|
+
markers +
|
|
150
|
+
tab +
|
|
151
|
+
tabLabel +
|
|
152
|
+
badge +
|
|
153
|
+
glyph +
|
|
154
|
+
sourceHalo +
|
|
155
|
+
sourceText);
|
|
156
|
+
}
|
|
157
|
+
//# sourceMappingURL=include-region.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"include-region.js","sourceRoot":"","sources":["../../src/svg/include-region.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import type { InlineDatePin, PositionedCapacity, PositionedItem, Theme } from '@nowline/layout';
|
|
2
|
+
import type { FontFamilies, RenderOptions } from './render.js';
|
|
3
|
+
/**
|
|
4
|
+
* Paint an item / lane capacity suffix starting at `(x0, baselineY)`. The
|
|
5
|
+
* capacity model arrives pre-resolved from layout (`PositionedCapacity`):
|
|
6
|
+
* `text` is the formatted number, `icon` is either `null` (no glyph), a
|
|
7
|
+
* built-in name, or an inline literal string, and `iconDxTerms` places a
|
|
8
|
+
* built-in SVG icon.
|
|
9
|
+
*
|
|
10
|
+
* Three rendering paths:
|
|
11
|
+
*
|
|
12
|
+
* 1. `icon === null` (the resolved `capacity-icon` was `'none'`): paint
|
|
13
|
+
* the bare number as a single `<text>` node.
|
|
14
|
+
* 2. `icon.kind === 'builtin'` and `name === 'multiplier'`: paint
|
|
15
|
+
* `5×` as a single `<text>` node — the multiplication sign is a
|
|
16
|
+
* typographic operator with consistent rendering across system
|
|
17
|
+
* fonts and built-in side bearing, so no `<tspan dx>` separator.
|
|
18
|
+
* 3. `icon.kind === 'builtin'` and `name` ∈ {person, people, points,
|
|
19
|
+
* time}: paint the number as `<text>`, then drop the curated SVG
|
|
20
|
+
* icon at `x0` plus `iconDxTerms` (layout's `capacityIconDxTerms`:
|
|
21
|
+
* the number's estimated width and a `0.25em` gap, sized to one em). The
|
|
22
|
+
* icon's `style="color:..."` propagates through the
|
|
23
|
+
* `currentColor`-bound paths in the icon library.
|
|
24
|
+
* 4. `icon.kind === 'literal'` (inline Unicode literal or
|
|
25
|
+
* dereferenced custom `symbol`): paint number + glyph in a single
|
|
26
|
+
* `<text>`, with a `<tspan dx="0.1em">` separator before the
|
|
27
|
+
* glyph payload.
|
|
28
|
+
*
|
|
29
|
+
* The number always starts the run at `x0`: an item with meta text paints
|
|
30
|
+
* its suffix through `renderItemMetaLine` instead.
|
|
31
|
+
*/
|
|
32
|
+
export declare function renderCapacitySuffix(capacity: PositionedCapacity, x0: number, baselineY: number, fontSize: number, fontFamily: string, color: string): string;
|
|
33
|
+
export declare function renderInlineDatePins(pins: InlineDatePin[] | undefined, color: string): string;
|
|
34
|
+
export declare function hasAfterPin(pins: InlineDatePin[] | undefined): boolean;
|
|
35
|
+
export declare function renderItem(i: PositionedItem, options: RenderOptions, idPrefix: string, palette: Theme, fonts: FontFamilies): string;
|
|
36
|
+
//# sourceMappingURL=item.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"item.d.ts","sourceRoot":"","sources":["../../src/svg/item.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,aAAa,EAAE,kBAAkB,EAAE,cAAc,EAAE,KAAK,EAAE,MAAM,iBAAiB,CAAC;AA0BhG,OAAO,KAAK,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAgB/D;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,wBAAgB,oBAAoB,CAChC,QAAQ,EAAE,kBAAkB,EAC5B,EAAE,EAAE,MAAM,EACV,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,MAAM,EAChB,UAAU,EAAE,MAAM,EAClB,KAAK,EAAE,MAAM,GACd,MAAM,CA0CR;AA8HD,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,aAAa,EAAE,GAAG,SAAS,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAG7F;AAED,wBAAgB,WAAW,CAAC,IAAI,EAAE,aAAa,EAAE,GAAG,SAAS,GAAG,OAAO,CAEtE;AAsYD,wBAAgB,UAAU,CACtB,CAAC,EAAE,cAAc,EACjB,OAAO,EAAE,aAAa,EACtB,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,KAAK,EACd,KAAK,EAAE,YAAY,GACpB,MAAM,CAiBR"}
|