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,141 @@
|
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="utf-8">
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
6
|
+
<title>slidemind workspace</title>
|
|
7
|
+
<link rel="icon" href="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 32 32'%3E%3Crect width='32' height='32' rx='7' fill='%2310131b'/%3E%3Crect x='6.5' y='9.5' width='19' height='13' rx='3' fill='none' stroke='%23a9c2ff' stroke-width='2'/%3E%3C/svg%3E">
|
|
8
|
+
<link rel="preconnect" href="https://fonts.googleapis.com">
|
|
9
|
+
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
|
10
|
+
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;500;600&family=Urbanist:wght@300;400&display=swap">
|
|
11
|
+
<link rel="stylesheet" href="/ui/styles.css">
|
|
12
|
+
</head>
|
|
13
|
+
<body>
|
|
14
|
+
<header class="top">
|
|
15
|
+
<button type="button" class="icon" id="side-toggle" data-tip="Menu" aria-label="Show the navigation" aria-controls="side" aria-expanded="false">
|
|
16
|
+
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"><path d="M4 7h16M4 12h16M4 17h16"/></svg>
|
|
17
|
+
</button>
|
|
18
|
+
<a href="/" data-nav class="brand" data-tip="Inbox">
|
|
19
|
+
<span class="logo"><!-- the add-in's embossed slide mark, as in the review and plan gates -->
|
|
20
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="160 160 960 540" preserveAspectRatio="none"><defs><linearGradient id="rimTop" gradientUnits="userSpaceOnUse" x1="160" y1="0" x2="1120" y2="0"><stop offset="0%" stop-color="#d0e4ff" stop-opacity="0.85"/><stop offset="35%" stop-color="#fff" stop-opacity="0.5"/><stop offset="100%" stop-color="#fff" stop-opacity="0"/></linearGradient><linearGradient id="rimLeft" gradientUnits="userSpaceOnUse" x1="0" y1="160" x2="0" y2="700"><stop offset="0%" stop-color="#d0e4ff" stop-opacity="0.6"/><stop offset="40%" stop-color="#fff" stop-opacity="0.28"/><stop offset="100%" stop-color="#fff" stop-opacity="0"/></linearGradient><linearGradient id="rimBottom" gradientUnits="userSpaceOnUse" x1="1120" y1="0" x2="160" y2="0"><stop offset="0%" stop-color="#000" stop-opacity="0.55"/><stop offset="60%" stop-color="#000" stop-opacity="0.2"/><stop offset="100%" stop-color="#000" stop-opacity="0"/></linearGradient><linearGradient id="rimRight" gradientUnits="userSpaceOnUse" x1="0" y1="700" x2="0" y2="160"><stop offset="0%" stop-color="#000" stop-opacity="0.45"/><stop offset="60%" stop-color="#000" stop-opacity="0.16"/><stop offset="100%" stop-color="#000" stop-opacity="0"/></linearGradient><linearGradient id="faceFill" gradientUnits="userSpaceOnUse" x1="160" y1="160" x2="1120" y2="700"><stop offset="0%" stop-color="#fff" stop-opacity="0.08"/><stop offset="50%" stop-color="#808080" stop-opacity="0.02"/><stop offset="100%" stop-color="#000" stop-opacity="0.10"/></linearGradient></defs><rect x="160" y="160" width="960" height="540" rx="40" ry="40" fill="url(#faceFill)"/><path d="M 160,200 A 40,40 0 0 1 200,160 L 1080,160 A 40,40 0 0 1 1120,200" fill="none" stroke="url(#rimTop)" stroke-width="3" stroke-linecap="round"/><path d="M 160,200 L 160,660 A 40,40 0 0 0 200,700" fill="none" stroke="url(#rimLeft)" stroke-width="2.4" stroke-linecap="round"/><path d="M 1120,660 A 40,40 0 0 1 1080,700 L 200,700 A 40,40 0 0 1 160,660" fill="none" stroke="url(#rimBottom)" stroke-width="3" stroke-linecap="round"/><path d="M 1120,660 L 1120,200 A 40,40 0 0 0 1080,160" fill="none" stroke="url(#rimRight)" stroke-width="2.4" stroke-linecap="round"/><rect x="160" y="160" width="960" height="540" rx="40" ry="40" fill="none" stroke="#fff" stroke-opacity="0.14" stroke-width="1.4"/></svg>
|
|
21
|
+
</span>
|
|
22
|
+
<span class="word"><b class="t">slide</b><b class="b">mind</b></span>
|
|
23
|
+
</a>
|
|
24
|
+
<span class="sep"></span>
|
|
25
|
+
<!-- the page's one header: its name, the line under it, its own buttons and chips (app.js setMeta) -->
|
|
26
|
+
<span class="meta"><span class="t" id="meta-title">Workspace</span><span class="h" id="meta-sub">Your decks, plans and open questions</span></span>
|
|
27
|
+
<span class="top-actions" id="top-actions"></span>
|
|
28
|
+
<span class="grow"></span>
|
|
29
|
+
<nav>
|
|
30
|
+
<span id="conn" class="chip">Connecting…</span>
|
|
31
|
+
</nav>
|
|
32
|
+
</header>
|
|
33
|
+
<div id="conn-banner" class="conn-banner" role="status" aria-live="polite" hidden></div>
|
|
34
|
+
<div class="shell">
|
|
35
|
+
<aside id="side" aria-label="Workspace navigation">
|
|
36
|
+
<div class="side-search">
|
|
37
|
+
<svg class="side-search-ico" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="11" cy="11" r="7"/><path d="m20 20-3.5-3.5"/></svg>
|
|
38
|
+
<input type="search" id="library-search" placeholder="Search decks" autocomplete="off" aria-label="Search decks" aria-keyshortcuts="Meta+K Control+K /">
|
|
39
|
+
<kbd class="side-kbd" aria-hidden="true">⌘K</kbd>
|
|
40
|
+
</div>
|
|
41
|
+
<div class="side-nav">
|
|
42
|
+
<a href="/" data-nav class="side-link" id="inbox-link" data-side-item>
|
|
43
|
+
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M22 12h-6l-2 3h-4l-2-3H2"/><path d="M5.45 5.11 2 12v6a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2v-6l-3.45-6.89A2 2 0 0 0 16.76 4H7.24a2 2 0 0 0-1.79 1.11z"/></svg>
|
|
44
|
+
<span class="side-link-txt">Inbox</span><span class="badge" id="inbox-count" data-tip="Questions your agent is waiting on"></span>
|
|
45
|
+
</a>
|
|
46
|
+
</div>
|
|
47
|
+
<div class="side-sec">
|
|
48
|
+
<h2 id="library-heading">Decks</h2>
|
|
49
|
+
<div class="side-filter seg" id="library-filter" role="group" aria-label="Show"><button type="button" data-filter="all" aria-pressed="true">All</button><button type="button" data-filter="unfinished" aria-pressed="false" data-tip="Decks without a .pptx yet">Unfinished</button></div>
|
|
50
|
+
</div>
|
|
51
|
+
<div class="side-body"><ul class="list" id="library" aria-labelledby="library-heading"></ul><button id="more" hidden>Load more</button></div>
|
|
52
|
+
<div class="side-foot"><button type="button" class="btn" id="add-folder">
|
|
53
|
+
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M20 20a2 2 0 0 0 2-2V8a2 2 0 0 0-2-2h-7.9a2 2 0 0 1-1.69-.9L9.6 3.9A2 2 0 0 0 7.93 3H4a2 2 0 0 0-2 2v13a2 2 0 0 0 2 2Z"/><path d="M12 10v6"/><path d="M9 13h6"/></svg>
|
|
54
|
+
Add local folder
|
|
55
|
+
</button></div>
|
|
56
|
+
<div id="side-grip" data-tip="Drag to resize · double-click to reset"></div>
|
|
57
|
+
</aside>
|
|
58
|
+
<main id="app"><div class="page"><p class="muted">Signing in…</p></div></main>
|
|
59
|
+
</div>
|
|
60
|
+
<script>
|
|
61
|
+
// The shell is served without a credential; everything under /ui/ needs one.
|
|
62
|
+
// A browser that already holds this workspace's session (the cookie survives
|
|
63
|
+
// daemon restarts) is simply signed in; otherwise the one-time fragment token
|
|
64
|
+
// is exchanged for it. The token leaves the address bar first, whatever
|
|
65
|
+
// happens next: it is spent (or dead) either way.
|
|
66
|
+
(function () {
|
|
67
|
+
const $app = document.getElementById("app");
|
|
68
|
+
const $conn = document.getElementById("conn");
|
|
69
|
+
// A browser signs in through a link the CLI made: the agent's, or the tab it opens.
|
|
70
|
+
const ASK = "Ask your agent to open the slidemind workspace, or open the workspace link it gave you — either signs this browser in.";
|
|
71
|
+
const m = location.hash.match(/[#&]bootstrap=([^&]+)/);
|
|
72
|
+
const token = m ? decodeURIComponent(m[1]) : null;
|
|
73
|
+
if (m) history.replaceState(null, "", location.pathname + location.search);
|
|
74
|
+
const say = (cls, msg, sub) => {
|
|
75
|
+
const page = document.createElement("div");
|
|
76
|
+
page.className = "page";
|
|
77
|
+
const p = document.createElement("p");
|
|
78
|
+
p.className = cls;
|
|
79
|
+
p.id = "signed-out";
|
|
80
|
+
p.textContent = msg;
|
|
81
|
+
page.append(p);
|
|
82
|
+
if (sub) {
|
|
83
|
+
const q = document.createElement("p");
|
|
84
|
+
q.className = "muted";
|
|
85
|
+
q.textContent = sub;
|
|
86
|
+
page.append(q);
|
|
87
|
+
}
|
|
88
|
+
$app.replaceChildren(page);
|
|
89
|
+
};
|
|
90
|
+
// a sign-in in another tab of this browser sets the same cookie: pick it up
|
|
91
|
+
const signedOut = (msg) => {
|
|
92
|
+
say("error", msg, ASK);
|
|
93
|
+
$conn.textContent = "Signed out";
|
|
94
|
+
$conn.className = "chip bad";
|
|
95
|
+
const tick = () => fetch("/api/v1/session", { credentials: "same-origin", cache: "no-store" }).then((r) => (r.ok ? signIn() : setTimeout(tick, 6000)), () => setTimeout(tick, 6000));
|
|
96
|
+
setTimeout(tick, 6000);
|
|
97
|
+
};
|
|
98
|
+
// Not up (yet): say so once, poll /health, sign in again when it answers.
|
|
99
|
+
const offline = () => {
|
|
100
|
+
say("banner", "The workspace stopped. This page reconnects by itself.");
|
|
101
|
+
$conn.textContent = "Workspace offline — reconnecting…";
|
|
102
|
+
$conn.className = "chip warn";
|
|
103
|
+
const tick = () => fetch("/health", { cache: "no-store" }).then((r) => r.json()).then((h) => (h && !h.draining ? signIn() : setTimeout(tick, 3000)), () => setTimeout(tick, 3000));
|
|
104
|
+
setTimeout(tick, 3000);
|
|
105
|
+
};
|
|
106
|
+
async function signIn() {
|
|
107
|
+
let csrf = null;
|
|
108
|
+
let r;
|
|
109
|
+
try {
|
|
110
|
+
r = await fetch("/api/v1/session", { credentials: "same-origin", cache: "no-store" });
|
|
111
|
+
} catch {
|
|
112
|
+
return offline();
|
|
113
|
+
}
|
|
114
|
+
if (r.ok) csrf = (await r.json().catch(() => null))?.csrfToken ?? null;
|
|
115
|
+
else if (r.status !== 401) return offline(); // a workspace on its way out
|
|
116
|
+
else if (!token) return signedOut("You're not signed in to this workspace yet.");
|
|
117
|
+
else {
|
|
118
|
+
let x;
|
|
119
|
+
try {
|
|
120
|
+
x = await fetch("/api/v1/session", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ bootstrap: token }) });
|
|
121
|
+
} catch {
|
|
122
|
+
return offline();
|
|
123
|
+
}
|
|
124
|
+
const j = await x.json().catch(() => null);
|
|
125
|
+
// a link signs in every time it is clicked; only one from a reset workspace (a new session.key) fails
|
|
126
|
+
if (!x.ok || !j?.csrfToken) return signedOut("This link is not from this workspace — it was reset since the link was made.");
|
|
127
|
+
csrf = j.csrfToken;
|
|
128
|
+
}
|
|
129
|
+
window.SLIDEMIND_CSRF = csrf ?? undefined;
|
|
130
|
+
try {
|
|
131
|
+
if (csrf) sessionStorage.setItem("slidemind.csrf", csrf);
|
|
132
|
+
} catch {}
|
|
133
|
+
const load = (src) => new Promise((ok, no) => { const s = document.createElement("script"); s.src = src; s.onload = ok; s.onerror = no; document.body.append(s); });
|
|
134
|
+
await load("/ui/plan-bridge.js").catch(() => {}); // optional: the plan transport lane ships it
|
|
135
|
+
await load("/ui/app.js").catch(() => offline());
|
|
136
|
+
}
|
|
137
|
+
signIn();
|
|
138
|
+
})();
|
|
139
|
+
</script>
|
|
140
|
+
</body>
|
|
141
|
+
</html>
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
// Parent side of the plan-view transport (contracts §7).
|
|
2
|
+
//
|
|
3
|
+
// The plan page runs in a sandboxed iframe without allow-same-origin, so it has
|
|
4
|
+
// an opaque origin and no credentials. After the frame has loaded, the parent
|
|
5
|
+
// hands it exactly one MessagePort; from then on every request the child makes
|
|
6
|
+
// is `{id, method, payload}` on that port and every answer `{id, ok, result?,
|
|
7
|
+
// error?}`. Which deck, view and task those requests touch is bound HERE, from
|
|
8
|
+
// the options `connect` was given — ids inside the child's payload are ignored.
|
|
9
|
+
//
|
|
10
|
+
// PlanBridge.connect(iframe, { viewId, deckId, taskId?, api, allow?, loaded?, onChrome? })
|
|
11
|
+
// → { close(), notify(message) }
|
|
12
|
+
// PlanBridge.notify(iframe, { type: "invalidate" }) — an advisory nudge on the
|
|
13
|
+
// port (the page re-reads; it ignores types it does not know). Any other
|
|
14
|
+
// field of the message rides along: `{ type: "chrome-event", event }`.
|
|
15
|
+
//
|
|
16
|
+
// The page keeps its own navigation but says nothing to the user itself. Its
|
|
17
|
+
// status line, its notices and its one dialog it posts on the port as
|
|
18
|
+
// `{ type: "slidemind-view-chrome", chrome }`, and the parent's
|
|
19
|
+
// `onChrome(chrome)` renders them (every post replaces the last). A click on
|
|
20
|
+
// any of it comes back as `{ type: "slidemind-view-chrome-event", event: { kind:
|
|
21
|
+
// "action" | "dismiss", id } }`. While the page holds an edit it has not saved
|
|
22
|
+
// yet (its own debounce) it posts `{ type: "slidemind-view-dirty", dirty }`, and
|
|
23
|
+
// the parent's `onDirty(dirty)` shows the save state accordingly.
|
|
24
|
+
//
|
|
25
|
+
// `api` is the parent's own, already-authenticated client:
|
|
26
|
+
// read(scope) · save({base, value}, scope) · validate(payload, scope)
|
|
27
|
+
// action(name, payload, scope) · respondTask(taskId, {action, payload}, scope)
|
|
28
|
+
// Anything an api call throws with `.code` / `.details` reaches the child as
|
|
29
|
+
// `{code, message, details}`; a `local_conflict` with its details is how the
|
|
30
|
+
// page shows both sides.
|
|
31
|
+
(function (global) {
|
|
32
|
+
"use strict";
|
|
33
|
+
var METHODS = ["read", "save", "validate", "workbook.open", "workbook.import", "task.respond"];
|
|
34
|
+
var live = new WeakMap();
|
|
35
|
+
|
|
36
|
+
function connect(iframe, options) {
|
|
37
|
+
options = options || {};
|
|
38
|
+
var api = options.api || {};
|
|
39
|
+
var allow = METHODS.filter(function (m) { return !options.allow || options.allow.indexOf(m) >= 0; });
|
|
40
|
+
var previous = live.get(iframe);
|
|
41
|
+
if (previous) previous.close();
|
|
42
|
+
var channel = new MessageChannel();
|
|
43
|
+
var closed = false;
|
|
44
|
+
var scope = { deckId: options.deckId, viewId: options.viewId, taskId: options.taskId || null };
|
|
45
|
+
var session = { close: close, notify: notify };
|
|
46
|
+
live.set(iframe, session);
|
|
47
|
+
function notify(message) {
|
|
48
|
+
if (closed || !message || typeof message.type !== "string") return false;
|
|
49
|
+
var out = {};
|
|
50
|
+
for (var k in message) if (Object.prototype.hasOwnProperty.call(message, k) && k !== "type") out[k] = message[k];
|
|
51
|
+
out.type = "slidemind-view-" + message.type;
|
|
52
|
+
channel.port1.postMessage(out);
|
|
53
|
+
return true;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function reply(id, ok, body) {
|
|
57
|
+
if (closed) return;
|
|
58
|
+
channel.port1.postMessage(ok ? { id: id, ok: true, result: body === undefined ? null : body } : { id: id, ok: false, error: body });
|
|
59
|
+
}
|
|
60
|
+
function refuse(code, message) { var e = new Error(message); e.code = code; return e; }
|
|
61
|
+
function run(method, payload) {
|
|
62
|
+
switch (method) {
|
|
63
|
+
case "read": return api.read(scope);
|
|
64
|
+
case "save": return api.save({ base: payload.base, value: payload.value }, scope);
|
|
65
|
+
case "validate": return api.validate(payload, scope);
|
|
66
|
+
case "workbook.open":
|
|
67
|
+
case "workbook.import": return api.action(method, payload, scope);
|
|
68
|
+
case "task.respond":
|
|
69
|
+
if (!scope.taskId) throw refuse("stale_subject", "no task is bound to this view");
|
|
70
|
+
return api.respondTask(scope.taskId, { action: payload.action, payload: payload.payload }, scope);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
function dispatch(msg) {
|
|
74
|
+
if (msg && msg.type === "slidemind-view-chrome") {
|
|
75
|
+
if (typeof options.onChrome === "function") options.onChrome(msg.chrome && typeof msg.chrome === "object" ? msg.chrome : null);
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
if (msg && msg.type === "slidemind-view-dirty") {
|
|
79
|
+
if (typeof options.onDirty === "function") options.onDirty(!!msg.dirty);
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
if (!msg || typeof msg.id !== "string" || typeof msg.method !== "string") return;
|
|
83
|
+
var payload = msg.payload && typeof msg.payload === "object" ? msg.payload : {};
|
|
84
|
+
if (allow.indexOf(msg.method) < 0) { reply(msg.id, false, { code: "method_not_allowed", message: msg.method + " is not granted to this view" }); return; }
|
|
85
|
+
if (typeof api[{ "workbook.open": "action", "workbook.import": "action", "task.respond": "respondTask" }[msg.method] || msg.method] !== "function") { reply(msg.id, false, { code: "not_implemented", message: msg.method + " is not available here" }); return; }
|
|
86
|
+
Promise.resolve().then(function () { return run(msg.method, payload); }).then(
|
|
87
|
+
function (result) { reply(msg.id, true, result); },
|
|
88
|
+
function (error) { reply(msg.id, false, { code: (error && error.code) || "error", message: (error && error.message) || String(error), details: (error && error.details) || null }); }
|
|
89
|
+
);
|
|
90
|
+
}
|
|
91
|
+
channel.port1.onmessage = function (event) { dispatch(event.data); };
|
|
92
|
+
|
|
93
|
+
function start() {
|
|
94
|
+
if (closed) return;
|
|
95
|
+
// targetOrigin must be "*": a sandboxed frame has an opaque origin that no
|
|
96
|
+
// string can name. This is the only message that crosses the window
|
|
97
|
+
// boundary, and it carries nothing but the port — all trust afterwards
|
|
98
|
+
// is bound to that port, which only the frame it was transferred to holds.
|
|
99
|
+
// The parent must only ever connect a frame whose content it wrote itself.
|
|
100
|
+
iframe.contentWindow.postMessage({ type: "slidemind-view-connect", version: 1, viewId: options.viewId }, "*", [channel.port2]);
|
|
101
|
+
}
|
|
102
|
+
if (options.loaded) start(); else iframe.addEventListener("load", start, { once: true });
|
|
103
|
+
|
|
104
|
+
function close() {
|
|
105
|
+
if (closed) return;
|
|
106
|
+
closed = true;
|
|
107
|
+
try { channel.port1.postMessage({ type: "slidemind-view-close" }); } catch (_) {}
|
|
108
|
+
channel.port1.close();
|
|
109
|
+
if (live.get(iframe) === session) live.delete(iframe);
|
|
110
|
+
}
|
|
111
|
+
return session;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
function notify(iframe, message) {
|
|
115
|
+
var session = live.get(iframe);
|
|
116
|
+
return session ? session.notify(message) : false;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
global.PlanBridge = { connect: connect, notify: notify, METHODS: METHODS.slice() };
|
|
120
|
+
})(typeof window !== "undefined" ? window : globalThis);
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="utf-8"?>
|
|
2
|
+
<!-- Generator: Adobe Illustrator 23.0.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
|
3
|
+
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" [
|
|
4
|
+
<!ENTITY ns_extend "http://ns.adobe.com/Extensibility/1.0/">
|
|
5
|
+
<!ENTITY ns_ai "http://ns.adobe.com/AdobeIllustrator/10.0/">
|
|
6
|
+
<!ENTITY ns_graphs "http://ns.adobe.com/Graphs/1.0/">
|
|
7
|
+
<!ENTITY ns_vars "http://ns.adobe.com/Variables/1.0/">
|
|
8
|
+
<!ENTITY ns_imrep "http://ns.adobe.com/ImageReplacement/1.0/">
|
|
9
|
+
<!ENTITY ns_sfw "http://ns.adobe.com/SaveForWeb/1.0/">
|
|
10
|
+
<!ENTITY ns_custom "http://ns.adobe.com/GenericCustomNamespace/1.0/">
|
|
11
|
+
<!ENTITY ns_adobe_xpath "http://ns.adobe.com/XPath/1.0/">
|
|
12
|
+
]>
|
|
13
|
+
<svg version="1.1" id="Livello_1" xmlns:x="&ns_extend;" xmlns:i="&ns_ai;" xmlns:graph="&ns_graphs;"
|
|
14
|
+
xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 1992.333 1946"
|
|
15
|
+
enable-background="new 0 0 1992.333 1946" xml:space="preserve">
|
|
16
|
+
<metadata>
|
|
17
|
+
<sfw xmlns="&ns_sfw;">
|
|
18
|
+
<slices></slices>
|
|
19
|
+
<sliceSourceBounds bottomLeftOrigin="true" height="1946" width="1992.333" x="-995.333" y="-949"></sliceSourceBounds>
|
|
20
|
+
</sfw>
|
|
21
|
+
</metadata>
|
|
22
|
+
<circle fill="#036C70" cx="1019.333" cy="556" r="556"/>
|
|
23
|
+
<circle fill="#1A9BA1" cx="1482.667" cy="1065.667" r="509.667"/>
|
|
24
|
+
<circle fill="#37C6D0" cx="1088.833" cy="1552.167" r="393.833"/>
|
|
25
|
+
<path opacity="0.1" enable-background="new " d="M1112,501.79v988.753c-0.23,34.357-21.05,65.222-52.82,78.303
|
|
26
|
+
c-10.116,4.279-20.987,6.484-31.97,6.487H695.463c-0.463-7.877-0.463-15.29-0.463-23.167c-0.154-7.734,0.155-15.47,0.927-23.167
|
|
27
|
+
c8.48-148.106,99.721-278.782,235.837-337.77v-86.18c-302.932-48.005-509.592-332.495-461.587-635.427
|
|
28
|
+
c0.333-2.098,0.677-4.195,1.034-6.289c2.306-15.626,5.556-31.099,9.73-46.333h546.27C1073.964,417.178,1111.822,455.036,1112,501.79
|
|
29
|
+
z"/>
|
|
30
|
+
<path opacity="0.2" enable-background="new " d="M980.877,463.333H471.21c-51.486,302.386,151.908,589.256,454.293,640.742
|
|
31
|
+
c9.156,1.559,18.35,2.888,27.573,3.986c-143.633,68.11-248.3,261.552-257.196,420.938c-0.771,7.697-1.081,15.433-0.927,23.167
|
|
32
|
+
c0,7.877,0,15.29,0.463,23.167c0.836,15.574,2.85,31.063,6.023,46.333h279.39c34.357-0.23,65.222-21.05,78.303-52.82
|
|
33
|
+
c4.279-10.115,6.485-20.987,6.487-31.97V548.123C1065.443,501.387,1027.613,463.537,980.877,463.333z"/>
|
|
34
|
+
<path opacity="0.2" enable-background="new " d="M980.877,463.333H471.21c-51.475,302.414,151.95,589.297,454.364,640.773
|
|
35
|
+
c6.186,1.053,12.389,2.001,18.607,2.844c-139,73.021-239.543,266-248.254,422.05h284.95c46.681-0.353,84.437-38.109,84.79-84.79
|
|
36
|
+
V548.123C1065.489,501.369,1027.631,463.511,980.877,463.333z"/>
|
|
37
|
+
<path opacity="0.2" enable-background="new " d="M934.543,463.333H471.21c-48.606,285.482,130.279,560.404,410.977,631.616
|
|
38
|
+
C775.901,1216.384,710.711,1368.301,695.927,1529h238.617c46.754-0.178,84.612-38.036,84.79-84.79V548.123
|
|
39
|
+
C1019.308,501.306,981.361,463.359,934.543,463.333z"/>
|
|
40
|
+
<linearGradient id="SVGID_1_" gradientUnits="userSpaceOnUse" x1="177.0788" y1="1551.0284" x2="842.2545" y2="398.9716" gradientTransform="matrix(1 0 0 -1 0 1948)">
|
|
41
|
+
<stop offset="0" style="stop-color:#058F92"/>
|
|
42
|
+
<stop offset="0.5" style="stop-color:#038489"/>
|
|
43
|
+
<stop offset="1" style="stop-color:#026D71"/>
|
|
44
|
+
</linearGradient>
|
|
45
|
+
<path fill="url(#SVGID_1_)" d="M84.929,463.333h849.475c46.905,0,84.929,38.024,84.929,84.929v849.475
|
|
46
|
+
c0,46.905-38.024,84.929-84.929,84.929H84.929c-46.905,0-84.929-38.024-84.929-84.929V548.262
|
|
47
|
+
C0,501.357,38.024,463.333,84.929,463.333z"/>
|
|
48
|
+
<path fill="#FFFFFF" d="M379.331,962.621c-19.903-13.202-36.528-30.777-48.604-51.384c-11.701-21.542-17.533-45.781-16.912-70.288
|
|
49
|
+
c-1.042-33.181,10.155-65.586,31.46-91.045c22.388-25.49,51.326-44.366,83.678-54.581c36.871-12.136,75.49-18.116,114.304-17.699
|
|
50
|
+
c51.043-1.865,102.015,5.272,150.583,21.082v106.567c-21.103-12.784-44.088-22.166-68.11-27.8
|
|
51
|
+
c-26.065-6.392-52.81-9.597-79.647-9.545c-28.3-1.039-56.419,4.913-81.871,17.329c-19.65,8.475-32.392,27.807-32.433,49.206
|
|
52
|
+
c-0.08,12.981,4.907,25.481,13.9,34.843c10.622,11.037,23.187,20.021,37.067,26.503c15.444,7.691,38.611,17.916,69.5,30.673
|
|
53
|
+
c3.401,1.075,6.716,2.407,9.915,3.985c30.401,11.881,59.729,26.344,87.663,43.229c21.154,13.043,38.908,30.924,51.801,52.171
|
|
54
|
+
c13.218,24.085,19.625,51.315,18.533,78.767c1.509,34.066-8.913,67.591-29.468,94.798c-20.488,25.012-47.88,43.446-78.767,53.005
|
|
55
|
+
c-36.329,11.387-74.245,16.892-112.312,16.309c-34.154,0.155-68.258-2.635-101.933-8.34c-28.434-4.653-56.182-12.807-82.612-24.279
|
|
56
|
+
v-112.358c25.264,18.043,53.489,31.529,83.4,39.847c29.81,9.289,60.798,14.251,92.018,14.734c28.895,1.83,57.739-4.291,83.4-17.699
|
|
57
|
+
c17.976-10.144,28.909-29.358,28.449-49.994c0.12-14.359-5.56-28.158-15.753-38.271c-12.676-12.444-27.352-22.671-43.414-30.256
|
|
58
|
+
c-18.533-9.267-45.824-21.483-81.871-36.65C432.618,993.951,405.161,979.594,379.331,962.621z"/>
|
|
59
|
+
</svg>
|