slidemind 0.3.19 → 0.4.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/.claude-plugin/plugin.json +1 -1
- package/.codex-plugin/plugin.json +1 -1
- package/AGENTS.md +591 -15
- package/README.md +202 -7
- package/bin/slidemind.mjs +50 -2
- package/package.json +2 -2
- package/skills/create-slides/SKILL.md +484 -886
- package/skills/search/SKILL.md +46 -23
- package/src/bridge/build-and-push.mjs +548 -73
- package/src/bridge/bundle.mjs +100 -31
- package/src/bridge/capture.mjs +14 -17
- package/src/bridge/client/brands.mjs +157 -18
- package/src/bridge/client/engine-routing.mjs +48 -13
- package/src/bridge/client/engine-search.mjs +24 -1
- package/src/bridge/client/engine-slides.mjs +1 -1
- package/src/bridge/client/render.mjs +27 -1
- package/src/bridge/client/transport.mjs +499 -23
- package/src/bridge/client.mjs +10 -0
- package/src/bridge/config.mjs +67 -6
- package/src/bridge/engine-download.mjs +0 -10
- package/src/bridge/graph-auth.mjs +55 -3
- package/src/bridge/image-intent-envelope.mjs +239 -0
- package/src/bridge/package-preview.mjs +67 -0
- package/src/bridge/sharepoint.mjs +914 -0
- package/src/builders/asset-fetch.mjs +203 -0
- package/src/builders/block-dividers.mjs +83 -0
- package/src/builders/build.mjs +171 -87
- package/src/builders/card-height.mjs +294 -0
- package/src/builders/chart-hole.mjs +183 -0
- package/src/builders/chart-jsx.mjs +410 -0
- package/src/builders/chart-labels.mjs +326 -0
- package/src/builders/concept-geometry.mjs +370 -0
- package/src/builders/concept-intent.mjs +200 -0
- package/src/builders/concept-layout.mjs +79 -0
- package/src/builders/concept-lines.mjs +509 -0
- package/src/builders/concept-lists.mjs +270 -0
- package/src/builders/concept-marks.mjs +84 -0
- package/src/builders/concept-relationships.mjs +12 -0
- package/src/builders/concept-spec.mjs +645 -0
- package/src/builders/concept-text.mjs +140 -0
- package/src/builders/concept-waves.mjs +57 -0
- package/src/builders/copy-fit.mjs +139 -0
- package/src/builders/design-tokens.mjs +347 -0
- package/src/builders/draft-check.mjs +552 -340
- package/src/builders/draft-lines.mjs +369 -0
- package/src/builders/edit-route.mjs +29 -0
- package/src/builders/figure-sketch.mjs +375 -0
- package/src/builders/fold-sets.mjs +639 -0
- package/src/builders/gate-server.mjs +9 -4
- package/src/builders/gate-session.js +273 -12
- package/src/builders/gate-shell.js +1494 -0
- package/src/builders/image-intent-check.mjs +308 -0
- package/src/builders/image-use-reconcile.mjs +107 -0
- package/src/builders/kit-helpers.mjs +121 -0
- package/src/builders/layout-names.mjs +32 -0
- package/src/builders/legacy-reference-uses.mjs +179 -0
- package/src/builders/line-fit.mjs +224 -0
- package/src/builders/line-native.mjs +895 -0
- package/src/builders/line-relations.mjs +230 -0
- package/src/builders/lint-fix.mjs +117 -9
- package/src/builders/lint.mjs +25 -20
- package/src/builders/list-jsx.mjs +88 -0
- package/src/builders/placement.mjs +133 -0
- package/src/builders/plan-checks.mjs +135 -0
- package/src/builders/plan-comments.mjs +19 -0
- package/src/builders/plan-handlers.mjs +95 -0
- package/src/builders/plan-markdown-edit.mjs +3 -3
- package/src/builders/plan-overlay.js +1530 -1608
- package/src/builders/plan.mjs +689 -186
- package/src/builders/preset-definitions.json +1 -0
- package/src/builders/preset-eval.mjs +244 -0
- package/src/builders/preview.html +51 -120
- package/src/builders/red-thread-backbone.mjs +135 -36
- package/src/builders/repair.mjs +205 -0
- package/src/builders/repeat-groups.mjs +540 -0
- package/src/builders/resolve-skill.mjs +5 -4
- package/src/builders/review-overlay.js +296 -293
- package/src/builders/review.mjs +305 -84
- package/src/builders/rule-shift.mjs +96 -0
- package/src/builders/seat.mjs +354 -0
- package/src/builders/settle-driver.mjs +236 -0
- package/src/builders/settle.mjs +1448 -0
- package/src/builders/slide-prep.mjs +67 -0
- package/src/builders/spec-assets.mjs +236 -0
- package/src/builders/spec-match.mjs +56 -0
- package/src/builders/stack.mjs +413 -0
- package/src/builders/storyboard-markdown.mjs +70 -27
- package/src/builders/storyboard-schema.mjs +54 -114
- package/src/builders/text-blocks.mjs +212 -0
- package/src/builders/text-card-fit.mjs +552 -0
- package/src/builders/text-stack.mjs +276 -0
- package/src/builders/transcribe.mjs +1069 -0
- package/src/cli/assets.mjs +164 -0
- package/src/cli/common.mjs +173 -12
- package/src/cli/concept-spec-support.mjs +76 -0
- package/src/cli/concepts.mjs +1002 -103
- package/src/cli/deck.mjs +401 -65
- package/src/cli/diagnose.mjs +4 -2
- package/src/cli/engine-helpers.mjs +17 -10
- package/src/cli/engine-results.mjs +76 -3
- package/src/cli/help.mjs +232 -28
- package/src/cli/install.mjs +9 -0
- package/src/cli/maintenance.mjs +104 -0
- package/src/cli/read.mjs +2 -1
- package/src/cli/ready.mjs +6 -3
- package/src/cli/record.mjs +522 -0
- package/src/cli/remote.mjs +818 -0
- package/src/cli/revision.mjs +686 -0
- package/src/cli/search.mjs +30 -11
- package/src/cli/session.mjs +56 -13
- package/src/cli/setup.mjs +46 -2
- package/src/cli/status.mjs +142 -33
- package/src/cli/tasks.mjs +246 -0
- package/src/cli/transcribe.mjs +854 -0
- package/src/cli/workspace-ui.mjs +260 -0
- package/src/cli/workspace.mjs +212 -34
- package/src/install-channel.mjs +64 -7
- package/src/lib/adopt.mjs +346 -25
- package/src/lib/concept-spec-binding.mjs +96 -0
- package/src/lib/conversions.mjs +70 -6
- package/src/lib/convert-folded.mjs +107 -0
- package/src/lib/deck-paths.mjs +418 -0
- package/src/lib/durable-ids.mjs +47 -0
- package/src/lib/edit-operations.mjs +316 -0
- package/src/lib/edit-state.mjs +1244 -0
- package/src/lib/edit-transitions.mjs +120 -0
- package/src/lib/extensions.mjs +501 -0
- package/src/lib/image-assets.mjs +465 -0
- package/src/lib/image-derivatives.mjs +234 -0
- package/src/lib/image-intent-fingerprint.mjs +70 -0
- package/src/lib/image-intent-tags.mjs +176 -0
- package/src/lib/image-intent.mjs +802 -0
- package/src/lib/image-use-overrides.mjs +279 -0
- package/src/lib/inline-components.mjs +613 -0
- package/src/lib/lint-converted.mjs +68 -4
- package/src/lib/merge-json.mjs +163 -0
- package/src/lib/overwrite-guard.mjs +3 -3
- package/src/lib/presentation-context.mjs +531 -0
- package/src/lib/preservation-tags.mjs +157 -0
- package/src/lib/preservation-verdict.mjs +1342 -0
- package/src/lib/publish.mjs +1557 -0
- package/src/lib/rebase.mjs +945 -0
- package/src/lib/reconcile-ack.mjs +4 -6
- package/src/lib/reconcile.mjs +62 -24
- package/src/lib/record-client.mjs +175 -0
- package/src/lib/record-state.mjs +151 -0
- package/src/lib/remote.mjs +661 -0
- package/src/lib/revision.mjs +1210 -0
- package/src/lib/slide-guids.mjs +4 -6
- package/src/lib/slide-preservation.mjs +423 -0
- package/src/lib/slide-selection.mjs +9 -0
- package/src/lib/workspace-transaction.mjs +117 -0
- package/src/pptx/content-digest.mjs +334 -0
- package/src/pptx/deck-assemble.mjs +1278 -0
- package/src/pptx/fill/engine.mjs +2 -3
- package/src/pptx/fill/freeform.mjs +6 -3
- package/src/pptx/ooxml.mjs +20 -0
- package/src/pptx/package-evidence.mjs +383 -0
- package/src/pptx/tags.mjs +163 -11
- package/src/update-check.mjs +22 -4
- package/src/workspace/adapters.mjs +222 -0
- package/src/workspace/auth.mjs +256 -0
- package/src/workspace/autostart.mjs +204 -0
- package/src/workspace/daemon.mjs +360 -0
- package/src/workspace/discovery.mjs +180 -0
- package/src/workspace/edit.mjs +167 -0
- package/src/workspace/events.mjs +52 -0
- package/src/workspace/gate-client.mjs +290 -0
- package/src/workspace/handback.mjs +73 -0
- package/src/workspace/lifecycle.mjs +635 -0
- package/src/workspace/operations.mjs +200 -0
- package/src/workspace/pick-folder.mjs +152 -0
- package/src/workspace/registry.mjs +359 -0
- package/src/workspace/remote-links.mjs +397 -0
- package/src/workspace/remote-status.mjs +359 -0
- package/src/workspace/routes.mjs +1331 -0
- package/src/workspace/server.mjs +159 -0
- package/src/workspace/sync.mjs +1119 -0
- package/src/workspace/task-actions.mjs +215 -0
- package/src/workspace/tasks.mjs +507 -0
- package/src/workspace/ui/app.js +1886 -0
- package/src/workspace/ui/index.html +141 -0
- package/src/workspace/ui/plan-bridge.js +120 -0
- package/src/workspace/ui/sharepoint.svg +59 -0
- package/src/workspace/ui/styles.css +423 -0
- package/src/builders/visual-families.mjs +0 -46
|
@@ -0,0 +1,244 @@
|
|
|
1
|
+
// ECMA-376 preset geometry evaluator: the one place that knows what a
|
|
2
|
+
// `prstGeom` looks like and where its connection sites are.
|
|
3
|
+
//
|
|
4
|
+
// `preset-definitions.json` (generated by scripts/convert-preset-definitions.mjs
|
|
5
|
+
// from the POI/ECMA `presetShapeDefinitions.xml`) carries all 187 presets:
|
|
6
|
+
// adjust defaults, guide formulas, path commands and the `cxnLst`. This module
|
|
7
|
+
// binds the guides for one box and returns
|
|
8
|
+
//
|
|
9
|
+
// - `paths`: per `<a:path>` the evaluated ops (shape-local px, arc angles in
|
|
10
|
+
// degrees — the add-in's `PathOp` shape) and the outline sampled into a
|
|
11
|
+
// polyline in slide space (arcs and Béziers flattened);
|
|
12
|
+
// - `sites`: the connection sites in slide space, in `cxnLst` order, so a
|
|
13
|
+
// site's array index IS the `stCxn`/`endCxn` idx PowerPoint glues to.
|
|
14
|
+
//
|
|
15
|
+
// Canonical in the CLI; the add-in carries a byte-identical mirror
|
|
16
|
+
// (scripts/sync-transcription-runtime.mjs). Nothing here throws: an unknown
|
|
17
|
+
// preset evaluates to no paths and no sites.
|
|
18
|
+
|
|
19
|
+
import definitions from "./preset-definitions.json" with { type: "json" };
|
|
20
|
+
|
|
21
|
+
const PRESETS = definitions.presets;
|
|
22
|
+
|
|
23
|
+
/** Every preset the definitions carry — the full ECMA-376 set. */
|
|
24
|
+
export const PRESET_NAMES = Object.keys(PRESETS);
|
|
25
|
+
|
|
26
|
+
/** OOXML angle unit: 60000ths of a degree. */
|
|
27
|
+
const DEG = 60000;
|
|
28
|
+
const CIRCLE = 360 * DEG;
|
|
29
|
+
|
|
30
|
+
// Flattening density: an arc gets one chord per ARC_STEP of sweep (never
|
|
31
|
+
// fewer than 4), a Bézier BEZ_STEPS chords. Both keep the chord error well
|
|
32
|
+
// under 0.5 px for any box a slide can hold.
|
|
33
|
+
const ARC_STEP = Math.PI / 64;
|
|
34
|
+
const BEZ_STEPS = 24;
|
|
35
|
+
|
|
36
|
+
/** ECMA-376 §20.1.9.11 built-in guides, for a box whose top-left is the origin. */
|
|
37
|
+
function builtin(name, w, h) {
|
|
38
|
+
switch (name) {
|
|
39
|
+
case "w": case "r": return w;
|
|
40
|
+
case "h": case "b": return h;
|
|
41
|
+
case "l": case "t": return 0;
|
|
42
|
+
case "hc": return w / 2;
|
|
43
|
+
case "vc": return h / 2;
|
|
44
|
+
case "ss": return Math.min(w, h);
|
|
45
|
+
case "ls": return Math.max(w, h);
|
|
46
|
+
case "3cd4": return 270 * DEG;
|
|
47
|
+
case "3cd8": return 135 * DEG;
|
|
48
|
+
case "5cd8": return 225 * DEG;
|
|
49
|
+
case "7cd8": return 315 * DEG;
|
|
50
|
+
}
|
|
51
|
+
const m = /^(wd|hd|ssd|cd)(\d+)$/.exec(name);
|
|
52
|
+
if (!m) return undefined;
|
|
53
|
+
const n = Number(m[2]);
|
|
54
|
+
if (n === 0) return 0;
|
|
55
|
+
return { wd: w, hd: h, ssd: Math.min(w, h), cd: CIRCLE }[m[1]] / n;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
const toRad = (a) => (a / DEG) * Math.PI / 180;
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Guide scope for one box: adjusts first (the caller's `av` by name, else the
|
|
62
|
+
* definition's default), then `gdLst` in document order. An unknown name reads
|
|
63
|
+
* as 0 rather than throwing.
|
|
64
|
+
*/
|
|
65
|
+
function bindGuides(def, w, h, av = {}) {
|
|
66
|
+
const values = new Map();
|
|
67
|
+
const value = (token) => {
|
|
68
|
+
if (token === undefined || token === "") return 0;
|
|
69
|
+
const literal = Number(token);
|
|
70
|
+
if (Number.isFinite(literal)) return literal;
|
|
71
|
+
return values.get(token) ?? builtin(token, w, h) ?? 0;
|
|
72
|
+
};
|
|
73
|
+
const formula = (fmla) => {
|
|
74
|
+
const [op, a, b, c] = String(fmla).trim().split(/\s+/);
|
|
75
|
+
const x = value(a), y = value(b), z = value(c);
|
|
76
|
+
switch (op) {
|
|
77
|
+
case "*/": return z === 0 ? 0 : (x * y) / z;
|
|
78
|
+
case "+-": return x + y - z;
|
|
79
|
+
case "+/": return z === 0 ? 0 : (x + y) / z;
|
|
80
|
+
case "?:": return x > 0 ? y : z;
|
|
81
|
+
case "val": return x;
|
|
82
|
+
case "abs": return Math.abs(x);
|
|
83
|
+
case "sqrt": return Math.sqrt(x);
|
|
84
|
+
case "max": return Math.max(x, y);
|
|
85
|
+
case "min": return Math.min(x, y);
|
|
86
|
+
case "pin": return Math.max(x, Math.min(y, z));
|
|
87
|
+
case "mod": return Math.sqrt(x * x + y * y + z * z);
|
|
88
|
+
case "at2": return Math.atan2(y, x) * 180 / Math.PI * DEG;
|
|
89
|
+
case "sin": return x * Math.sin(toRad(y));
|
|
90
|
+
case "cos": return x * Math.cos(toRad(y));
|
|
91
|
+
case "tan": return x * Math.tan(toRad(y));
|
|
92
|
+
// The arctan here is a plain radian angle, not an OOXML one.
|
|
93
|
+
case "cat2": return x * Math.cos(Math.atan2(z, y));
|
|
94
|
+
case "sat2": return x * Math.sin(Math.atan2(z, y));
|
|
95
|
+
default: return 0;
|
|
96
|
+
}
|
|
97
|
+
};
|
|
98
|
+
// An adjust may be passed as a number (the OOXML value) or as a fmla string.
|
|
99
|
+
const adjust = (v) => (typeof v === "number" ? v : formula(v));
|
|
100
|
+
for (const [name, fmla] of def.av ?? []) values.set(name, name in av ? adjust(av[name]) : formula(fmla));
|
|
101
|
+
for (const [name, v] of Object.entries(av)) if (!values.has(name)) values.set(name, adjust(v));
|
|
102
|
+
for (const [name, fmla] of def.gd ?? []) values.set(name, formula(fmla));
|
|
103
|
+
return value;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* `arcTo` angles are VISUAL angles on the ellipse (the direction from the
|
|
108
|
+
* centre); the ellipse is traced by its parametric angle. This maps one onto
|
|
109
|
+
* the other continuously, so a sweep past ±90° keeps its sign and length
|
|
110
|
+
* (Apache POI's ArcToCommand does the same).
|
|
111
|
+
*/
|
|
112
|
+
function parametric(theta, rx, ry) {
|
|
113
|
+
if (!(rx > 0 && ry > 0)) return theta;
|
|
114
|
+
const t = Math.atan2(rx * Math.sin(theta), ry * Math.cos(theta));
|
|
115
|
+
return t + 2 * Math.PI * Math.round((theta - t) / (2 * Math.PI));
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/** Shape-local ops for one path, `PathOp`-shaped (arc angles in degrees). */
|
|
119
|
+
function pathOps(path, value, w, h) {
|
|
120
|
+
const sx = path.w ? w / path.w : 1;
|
|
121
|
+
const sy = path.h ? h / path.h : 1;
|
|
122
|
+
const pt = (x, y) => ({ x: value(x) * sx, y: value(y) * sy });
|
|
123
|
+
return path.ops.map(([code, ...a]) => {
|
|
124
|
+
switch (code) {
|
|
125
|
+
case "m": return { op: "moveTo", ...pt(a[0], a[1]) };
|
|
126
|
+
case "l": return { op: "lnTo", ...pt(a[0], a[1]) };
|
|
127
|
+
case "c": return { op: "cubicBezTo", c1: pt(a[0], a[1]), c2: pt(a[2], a[3]), end: pt(a[4], a[5]) };
|
|
128
|
+
case "q": return { op: "quadBezTo", c: pt(a[0], a[1]), end: pt(a[2], a[3]) };
|
|
129
|
+
case "a": return { op: "arcTo", wR: value(a[0]) * sx, hR: value(a[1]) * sy, stAng: value(a[2]) / DEG, swAng: value(a[3]) / DEG };
|
|
130
|
+
default: return { op: "close" };
|
|
131
|
+
}
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/** Flatten ops into polylines (one per moveTo), shape-local. */
|
|
136
|
+
function flatten(ops) {
|
|
137
|
+
const lines = [];
|
|
138
|
+
let line = null;
|
|
139
|
+
let cur = { x: 0, y: 0 };
|
|
140
|
+
const push = (p) => {
|
|
141
|
+
if (!line) { line = { points: [{ ...cur }], closed: false }; lines.push(line); }
|
|
142
|
+
line.points.push(p);
|
|
143
|
+
cur = p;
|
|
144
|
+
};
|
|
145
|
+
for (const o of ops) {
|
|
146
|
+
if (o.op === "moveTo") {
|
|
147
|
+
cur = { x: o.x, y: o.y };
|
|
148
|
+
line = { points: [{ ...cur }], closed: false };
|
|
149
|
+
lines.push(line);
|
|
150
|
+
} else if (o.op === "lnTo") push({ x: o.x, y: o.y });
|
|
151
|
+
else if (o.op === "cubicBezTo" || o.op === "quadBezTo") {
|
|
152
|
+
const p0 = cur;
|
|
153
|
+
const cs = o.op === "cubicBezTo" ? [o.c1, o.c2] : [o.c];
|
|
154
|
+
for (let i = 1; i <= BEZ_STEPS; i++) {
|
|
155
|
+
const t = i / BEZ_STEPS, u = 1 - t;
|
|
156
|
+
const at = cs.length === 2
|
|
157
|
+
? (k) => u * u * u * p0[k] + 3 * u * u * t * cs[0][k] + 3 * u * t * t * cs[1][k] + t * t * t * o.end[k]
|
|
158
|
+
: (k) => u * u * p0[k] + 2 * u * t * cs[0][k] + t * t * o.end[k];
|
|
159
|
+
push({ x: at("x"), y: at("y") });
|
|
160
|
+
}
|
|
161
|
+
} else if (o.op === "arcTo") {
|
|
162
|
+
const st = o.stAng * Math.PI / 180;
|
|
163
|
+
const t0 = parametric(st, o.wR, o.hR);
|
|
164
|
+
const t1 = parametric(st + o.swAng * Math.PI / 180, o.wR, o.hR);
|
|
165
|
+
const cx = cur.x - o.wR * Math.cos(t0);
|
|
166
|
+
const cy = cur.y - o.hR * Math.sin(t0);
|
|
167
|
+
const n = Math.max(4, Math.ceil(Math.abs(t1 - t0) / ARC_STEP));
|
|
168
|
+
for (let i = 1; i <= n; i++) {
|
|
169
|
+
const t = t0 + (t1 - t0) * i / n;
|
|
170
|
+
push({ x: cx + o.wR * Math.cos(t), y: cy + o.hR * Math.sin(t) });
|
|
171
|
+
}
|
|
172
|
+
} else if (o.op === "close" && line) {
|
|
173
|
+
line.closed = true;
|
|
174
|
+
const first = line.points[0];
|
|
175
|
+
cur = { ...first };
|
|
176
|
+
line = null;
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
return lines;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
/**
|
|
183
|
+
* Local box point -> slide point. OOXML order: flip inside the box, rotate
|
|
184
|
+
* clockwise about the box centre, then offset. `rot` is in 60000ths of a degree.
|
|
185
|
+
*/
|
|
186
|
+
function transformer(w, h, { x = 0, y = 0, rot = 0, flipH = false, flipV = false } = {}) {
|
|
187
|
+
const a = toRad(rot), cos = Math.cos(a), sin = Math.sin(a);
|
|
188
|
+
const cx = w / 2, cy = h / 2;
|
|
189
|
+
const point = (p) => {
|
|
190
|
+
const dx = (flipH ? w - p.x : p.x) - cx;
|
|
191
|
+
const dy = (flipV ? h - p.y : p.y) - cy;
|
|
192
|
+
return { x: x + cx + dx * cos - dy * sin, y: y + cy + dx * sin + dy * cos };
|
|
193
|
+
};
|
|
194
|
+
// A site's outward angle: a flip mirrors it, rot turns it (degrees, 0 = +x, clockwise).
|
|
195
|
+
const angle = (deg) => {
|
|
196
|
+
let d = flipH ? 180 - deg : deg;
|
|
197
|
+
if (flipV) d = -d;
|
|
198
|
+
return ((d + rot / DEG) % 360 + 360) % 360;
|
|
199
|
+
};
|
|
200
|
+
return { point, angle };
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
/**
|
|
204
|
+
* Evaluate a preset for a `w` x `h` box.
|
|
205
|
+
*
|
|
206
|
+
* av: adjust overrides by name — `{ adj1: 25000 }` (OOXML value) or a fmla
|
|
207
|
+
* string (`"val 25000"`); anything omitted keeps the definition default.
|
|
208
|
+
* xf: optional `{ x, y, rot, flipH, flipV }` placing the box on the slide;
|
|
209
|
+
* `rot` in 60000ths of a degree. Without it the box sits at the origin.
|
|
210
|
+
*
|
|
211
|
+
* Returns `{ paths: [{ ops, polylines, fill, stroke }], sites: [{ idx, x, y, angle }] }`.
|
|
212
|
+
* `ops` stay box-local and untransformed; `polylines` and `sites` are placed by `xf`.
|
|
213
|
+
* A site's `angle` is the outward direction in degrees (0 = +x, 90 = +y/down).
|
|
214
|
+
*/
|
|
215
|
+
export function evalPreset(prst, w, h, av = {}, xf = {}) {
|
|
216
|
+
const def = Object.hasOwn(PRESETS, prst) ? PRESETS[prst] : null;
|
|
217
|
+
if (!def) return { paths: [], sites: [] };
|
|
218
|
+
const value = bindGuides(def, w, h, av ?? {});
|
|
219
|
+
const { point, angle } = transformer(w, h, xf ?? {});
|
|
220
|
+
const paths = def.paths.map((path) => {
|
|
221
|
+
const ops = pathOps(path, value, w, h);
|
|
222
|
+
const polylines = flatten(ops).map((l) => ({ points: l.points.map(point), closed: l.closed }));
|
|
223
|
+
return { ops, polylines, fill: path.fill !== false, stroke: path.stroke !== false };
|
|
224
|
+
});
|
|
225
|
+
const sites = (def.cxn ?? []).map(([ang, px, py], idx) => ({
|
|
226
|
+
idx,
|
|
227
|
+
...point({ x: value(px), y: value(py) }),
|
|
228
|
+
angle: angle(value(ang) / DEG),
|
|
229
|
+
}));
|
|
230
|
+
return { paths, sites };
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
/** A preset's adjust handles and their defaults, `{ adj1: 50000, … }` in `av` order ({} for none or an unknown preset). */
|
|
234
|
+
export function presetAdjusts(prst) {
|
|
235
|
+
const def = Object.hasOwn(PRESETS, prst) ? PRESETS[prst] : null;
|
|
236
|
+
if (!def) return {};
|
|
237
|
+
const value = bindGuides(def, 100, 100);
|
|
238
|
+
return Object.fromEntries((def.av ?? []).map(([name]) => [name, value(name)]));
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
/** The connection sites alone (same placement and indices as `evalPreset`). */
|
|
242
|
+
export function presetSites(prst, w, h, av, xf) {
|
|
243
|
+
return evalPreset(prst, w, h, av, xf).sites;
|
|
244
|
+
}
|
|
@@ -13,8 +13,12 @@
|
|
|
13
13
|
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
|
14
14
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
|
15
15
|
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Arimo:ital,wght@0,400..700;1,400..700&display=swap" />
|
|
16
|
-
<
|
|
17
|
-
|
|
16
|
+
<!-- The page lives in <workspace>/preview/, the deck's own media in
|
|
17
|
+
<workspace>/assets/. One <base> keeps every "./assets/…" a slide author
|
|
18
|
+
writes resolving to the deck's assets dir, off disk and over the review
|
|
19
|
+
server alike. -->
|
|
20
|
+
<base href="../" />
|
|
21
|
+
<style id="design-system">__DESIGN_CSS__</style>
|
|
18
22
|
<style>
|
|
19
23
|
/* Compatibility aliases for decks/slides authored against the older
|
|
20
24
|
statworx token names. New materialized bundles expose semantic tokens
|
|
@@ -40,6 +44,7 @@
|
|
|
40
44
|
bundle's corporate-design.css carries; repeated here so a preview
|
|
41
45
|
against an older bundle lays out like the render will. */
|
|
42
46
|
[data-connector] { position: absolute; width: 0; height: 0; padding: 0; margin: 0; border-color: transparent; pointer-events: none; }
|
|
47
|
+
[data-sm-line] { border-color: transparent !important; background: none !important; pointer-events: none; }
|
|
43
48
|
[data-sm-connector-overlay] { position: absolute; left: 0; top: 0; width: 1280px; height: 720px; overflow: visible; pointer-events: none; z-index: 2147483000; }
|
|
44
49
|
</style>
|
|
45
50
|
<style>
|
|
@@ -197,6 +202,24 @@
|
|
|
197
202
|
text-overflow: ellipsis;
|
|
198
203
|
white-space: nowrap;
|
|
199
204
|
}
|
|
205
|
+
/* Small screens: the rail becomes a horizontal filmstrip along the bottom
|
|
206
|
+
so the slide keeps the full width; fit() reads the rail's live size. */
|
|
207
|
+
@media (max-width: 760px) {
|
|
208
|
+
:root { --deck-rail-w: 0px; }
|
|
209
|
+
.deck { inset: 0 0 var(--deck-rail-h, 112px) 0; }
|
|
210
|
+
.deck__rail {
|
|
211
|
+
top: auto;
|
|
212
|
+
right: 0;
|
|
213
|
+
width: 100%;
|
|
214
|
+
height: var(--deck-rail-h, 112px);
|
|
215
|
+
border-right: 0;
|
|
216
|
+
border-top: 1px solid var(--deck-chrome-border);
|
|
217
|
+
}
|
|
218
|
+
.deck__thumbs { display: flex; gap: 10px; padding: 10px 12px; overflow-x: auto; overflow-y: hidden; }
|
|
219
|
+
.deck__thumb { width: 132px; flex: none; margin: 0; }
|
|
220
|
+
.deck__thumb-preview, .deck__thumb-frame { width: 114px; height: 64px; }
|
|
221
|
+
.deck__nav { bottom: calc(var(--deck-rail-h, 112px) + 10px); }
|
|
222
|
+
}
|
|
200
223
|
.deck__error {
|
|
201
224
|
padding: 32px;
|
|
202
225
|
color: #ff6b6b;
|
|
@@ -484,7 +507,13 @@ __RUNTIME_APPLIER__
|
|
|
484
507
|
var Chart = window.SlidemindChart
|
|
485
508
|
? window.SlidemindChart.createComponent(React)
|
|
486
509
|
: function () { return null; };
|
|
487
|
-
|
|
510
|
+
// <Figure>: a drawn shape as a structural sketch, compiled to its exact
|
|
511
|
+
// outline by the add-in's figure runtime (the same module this CLI's
|
|
512
|
+
// transcriber expands sketches with), inlined with the chart scripts.
|
|
513
|
+
var Figure = window.SlidemindFigure
|
|
514
|
+
? window.SlidemindFigure.createComponent(React)
|
|
515
|
+
: function () { return null; };
|
|
516
|
+
var slideScope = Object.assign({ Chart: Chart, Figure: Figure }, LAYOUTS);
|
|
488
517
|
|
|
489
518
|
var slides = [];
|
|
490
519
|
document.querySelectorAll('script[data-kind="slide"]').forEach(function (s) {
|
|
@@ -517,125 +546,20 @@ __RUNTIME_APPLIER__
|
|
|
517
546
|
|
|
518
547
|
smInlineSvgAssets();
|
|
519
548
|
|
|
520
|
-
//
|
|
521
|
-
//
|
|
522
|
-
// engine
|
|
523
|
-
//
|
|
524
|
-
//
|
|
525
|
-
// measured output at view-draft / in the .pptx stays the truth.
|
|
549
|
+
// Native line overlay — the preview's stand-in for the native lines the
|
|
550
|
+
// render exports from every data-connector / data-sm-line directive. The
|
|
551
|
+
// bundle's capture engine draws them with the exporter's own preset
|
|
552
|
+
// evaluator (drawLineDirectives), so the preview shows what PowerPoint
|
|
553
|
+
// draws; view-draft / the .pptx stay the truth.
|
|
526
554
|
function smDrawConnectors(container) {
|
|
527
555
|
if (!container) return;
|
|
528
|
-
var
|
|
529
|
-
if (
|
|
530
|
-
|
|
531
|
-
if (!dirs.length) return;
|
|
532
|
-
var derive = window.SlidemindConnectorDerive;
|
|
533
|
-
if (!derive || typeof derive.resolveConnector !== "function") {
|
|
534
|
-
console.warn("connector overlay skipped: the bundle's capture engine exports no connector geometry — the connected add-in predates it; view-draft / build-pptx still derive the real connectors server-side");
|
|
556
|
+
var d = window.SlidemindConnectorDerive;
|
|
557
|
+
if (!d || typeof d.drawLineDirectives !== "function") {
|
|
558
|
+
console.warn("line overlay skipped: the bundle's capture engine has no drawLineDirectives — the connected add-in predates native lines; view-draft / build-pptx still export them");
|
|
535
559
|
return;
|
|
536
560
|
}
|
|
537
|
-
var
|
|
538
|
-
|
|
539
|
-
var NS = "http://www.w3.org/2000/svg";
|
|
540
|
-
var svg = document.createElementNS(NS, "svg");
|
|
541
|
-
svg.setAttribute("data-sm-connector-overlay", "1");
|
|
542
|
-
svg.setAttribute("viewBox", "0 0 1280 720");
|
|
543
|
-
var defs = document.createElementNS(NS, "defs");
|
|
544
|
-
svg.appendChild(defs);
|
|
545
|
-
var rectOf = function (el) {
|
|
546
|
-
var r = el.getBoundingClientRect();
|
|
547
|
-
return { x: (r.left - cRect.left) / scale, y: (r.top - cRect.top) / scale, w: r.width / scale, h: r.height / scale };
|
|
548
|
-
};
|
|
549
|
-
var resolveRef = function (ref) {
|
|
550
|
-
if (!ref) return null;
|
|
551
|
-
try { return container.querySelector(ref.charAt(0) === "#" ? ref : "#" + ref); } catch (e) { return null; }
|
|
552
|
-
};
|
|
553
|
-
var sideOrNull = function (raw) {
|
|
554
|
-
var s = (raw || "").toLowerCase();
|
|
555
|
-
return (s === "top" || s === "bottom" || s === "left" || s === "right") ? s : null;
|
|
556
|
-
};
|
|
557
|
-
// Computed CSS colour ("rgb(a)(...)") → { hex, alpha } as the serialiser reports it.
|
|
558
|
-
var colorOf = function (css) {
|
|
559
|
-
var m = /rgba?(([^)]+))/.exec(css || "");
|
|
560
|
-
if (!m) return { hex: "000000", alpha: 1 };
|
|
561
|
-
var p = m[1].split(",").map(function (v) { return parseFloat(v); });
|
|
562
|
-
var hex = p.slice(0, 3).map(function (v) {
|
|
563
|
-
var h = Math.max(0, Math.min(255, Math.round(v))).toString(16);
|
|
564
|
-
return h.length < 2 ? "0" + h : h;
|
|
565
|
-
}).join("").toUpperCase();
|
|
566
|
-
return { hex: hex, alpha: p.length > 3 && isFinite(p[3]) ? p[3] : 1 };
|
|
567
|
-
};
|
|
568
|
-
dirs.forEach(function (el, idx) {
|
|
569
|
-
var fromEl = resolveRef(el.getAttribute("data-from"));
|
|
570
|
-
var toEl = resolveRef(el.getAttribute("data-to"));
|
|
571
|
-
var route = (el.getAttribute("data-route") || "straight").toLowerCase();
|
|
572
|
-
var centerEl = route === "arc" ? resolveRef(el.getAttribute("data-center")) : null;
|
|
573
|
-
var arrowRaw = (el.getAttribute("data-arrow") || "none").toLowerCase();
|
|
574
|
-
var cs = getComputedStyle(el);
|
|
575
|
-
var stroke = colorOf(cs.color);
|
|
576
|
-
// The same payload the serialiser hands the exporter; resolveConnector
|
|
577
|
-
// derives endpoints, route, bends, arc, and arrowhead size from it.
|
|
578
|
-
var r = derive.resolveConnector({
|
|
579
|
-
from: el.getAttribute("data-from") || "",
|
|
580
|
-
to: el.getAttribute("data-to") || "",
|
|
581
|
-
arrow: (arrowRaw === "start" || arrowRaw === "end" || arrowRaw === "both") ? arrowRaw : "none",
|
|
582
|
-
route: route,
|
|
583
|
-
fromSide: sideOrNull(el.getAttribute("data-from-side")),
|
|
584
|
-
toSide: sideOrNull(el.getAttribute("data-to-side")),
|
|
585
|
-
center: el.getAttribute("data-center") || null,
|
|
586
|
-
fromRect: fromEl ? rectOf(fromEl) : null,
|
|
587
|
-
toRect: toEl ? rectOf(toEl) : null,
|
|
588
|
-
centerRect: centerEl ? rectOf(centerEl) : null,
|
|
589
|
-
strokeHex: stroke.hex,
|
|
590
|
-
strokeAlpha: stroke.alpha,
|
|
591
|
-
strokeWidthPx: parseFloat(cs.borderTopWidth) || 0,
|
|
592
|
-
dashed: /dashed|dotted/.test(cs.borderTopStyle || ""),
|
|
593
|
-
missing: [],
|
|
594
|
-
});
|
|
595
|
-
if (!r) return;
|
|
596
|
-
var color = "#" + r.strokeHex;
|
|
597
|
-
var d;
|
|
598
|
-
if (r.arc) {
|
|
599
|
-
var large = Math.abs(r.arc.sweepDeg) > 180 ? 1 : 0;
|
|
600
|
-
var sweep = r.arc.sweepDeg > 0 ? 1 : 0;
|
|
601
|
-
d = "M" + r.start.x + " " + r.start.y + " A" + r.arc.r + " " + r.arc.r + " 0 " + large + " " + sweep + " " + r.end.x + " " + r.end.y;
|
|
602
|
-
} else {
|
|
603
|
-
d = r.points.map(function (p, i) { return (i ? "L" : "M") + p.x + " " + p.y; }).join(" ");
|
|
604
|
-
}
|
|
605
|
-
var path = document.createElementNS(NS, "path");
|
|
606
|
-
path.setAttribute("d", d);
|
|
607
|
-
path.setAttribute("fill", "none");
|
|
608
|
-
path.setAttribute("stroke", color);
|
|
609
|
-
path.setAttribute("stroke-opacity", String(r.strokeAlpha));
|
|
610
|
-
path.setAttribute("stroke-width", String(r.strokeWidthPx));
|
|
611
|
-
if (r.dashed) {
|
|
612
|
-
var dash = Math.max(4, r.strokeWidthPx * 3);
|
|
613
|
-
path.setAttribute("stroke-dasharray", dash + " " + dash);
|
|
614
|
-
}
|
|
615
|
-
if (r.arrowStart || r.arrowEnd) {
|
|
616
|
-
// Marker sized to the head PowerPoint renders (r.arrowheadPx).
|
|
617
|
-
var markerId = "sm-conn-arrow-" + idx;
|
|
618
|
-
var marker = document.createElementNS(NS, "marker");
|
|
619
|
-
marker.setAttribute("id", markerId);
|
|
620
|
-
marker.setAttribute("viewBox", "0 0 10 10");
|
|
621
|
-
marker.setAttribute("refX", "9");
|
|
622
|
-
marker.setAttribute("refY", "5");
|
|
623
|
-
marker.setAttribute("markerWidth", String(r.arrowheadPx));
|
|
624
|
-
marker.setAttribute("markerHeight", String(r.arrowheadPx));
|
|
625
|
-
marker.setAttribute("orient", "auto-start-reverse");
|
|
626
|
-
marker.setAttribute("markerUnits", "userSpaceOnUse");
|
|
627
|
-
var tri = document.createElementNS(NS, "path");
|
|
628
|
-
tri.setAttribute("d", "M0,0 L10,5 L0,10 z");
|
|
629
|
-
tri.setAttribute("fill", color);
|
|
630
|
-
tri.setAttribute("fill-opacity", String(r.strokeAlpha));
|
|
631
|
-
marker.appendChild(tri);
|
|
632
|
-
defs.appendChild(marker);
|
|
633
|
-
if (r.arrowStart) path.setAttribute("marker-start", "url(#" + markerId + ")");
|
|
634
|
-
if (r.arrowEnd) path.setAttribute("marker-end", "url(#" + markerId + ")");
|
|
635
|
-
}
|
|
636
|
-
svg.appendChild(path);
|
|
637
|
-
});
|
|
638
|
-
if (svg.childNodes.length > 1) container.appendChild(svg);
|
|
561
|
+
var r = d.drawLineDirectives(container);
|
|
562
|
+
r.refused.forEach(function (x) { console.warn("line " + (x.id || "(no id)") + ": " + x.message); });
|
|
639
563
|
}
|
|
640
564
|
function smScheduleConnectors(container) {
|
|
641
565
|
requestAnimationFrame(function () { requestAnimationFrame(function () { smDrawConnectors(container); }); });
|
|
@@ -727,6 +651,7 @@ __RUNTIME_APPLIER__
|
|
|
727
651
|
} else if (bottom > thumbs.scrollTop + thumbs.clientHeight) {
|
|
728
652
|
thumbs.scrollTop = bottom - thumbs.clientHeight + 12;
|
|
729
653
|
}
|
|
654
|
+
if (btn.scrollIntoView) btn.scrollIntoView({ block: "nearest", inline: "nearest" });
|
|
730
655
|
}
|
|
731
656
|
});
|
|
732
657
|
}
|
|
@@ -764,9 +689,15 @@ __RUNTIME_APPLIER__
|
|
|
764
689
|
stage.style.transform = "none";
|
|
765
690
|
return;
|
|
766
691
|
}
|
|
767
|
-
|
|
692
|
+
// The rail sits left (its width) or, on small screens, along the
|
|
693
|
+
// bottom (its height) — read whichever edge it occupies.
|
|
694
|
+
var railShown = rail && getComputedStyle(rail).display !== "none";
|
|
695
|
+
var railBottom = railShown && rail.offsetWidth >= window.innerWidth - 1;
|
|
696
|
+
var railW = railShown && !railBottom ? rail.offsetWidth : 0;
|
|
697
|
+
var railH = railBottom ? rail.offsetHeight : 0;
|
|
698
|
+
var chromeH = parseFloat(getComputedStyle(document.documentElement).getPropertyValue("--deck-chrome-h")) || 0;
|
|
768
699
|
var sx = Math.max(1, window.innerWidth - railW) / 1280;
|
|
769
|
-
var sy = window.innerHeight / 720;
|
|
700
|
+
var sy = Math.max(1, window.innerHeight - railH - (railBottom ? chromeH : 0)) / 720;
|
|
770
701
|
var s = Math.min(sx, sy) * (thumbMode ? 1 : 0.95);
|
|
771
702
|
stage.style.transform = "scale(" + s + ")";
|
|
772
703
|
}
|