@laitszkin/apollo-toolkit 3.10.0 → 3.11.1
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/CHANGELOG.md +37 -0
- package/analyse-app-logs/scripts/__pycache__/filter_logs_by_time.cpython-312.pyc +0 -0
- package/analyse-app-logs/scripts/__pycache__/log_cli_utils.cpython-312.pyc +0 -0
- package/analyse-app-logs/scripts/__pycache__/search_logs.cpython-312.pyc +0 -0
- package/docs-to-voice/scripts/__pycache__/docs_to_voice.cpython-312.pyc +0 -0
- package/generate-spec/SKILL.md +17 -15
- package/generate-spec/agents/openai.yaml +1 -1
- package/generate-spec/references/TEMPLATE_SPEC.md +103 -84
- package/generate-spec/scripts/__pycache__/create-specscpython-312.pyc +0 -0
- package/init-project-html/SKILL.md +117 -125
- package/init-project-html/agents/openai.yaml +18 -9
- package/init-project-html/lib/atlas/assets/architecture.css +161 -0
- package/init-project-html/lib/atlas/assets/viewer.client.js +136 -0
- package/init-project-html/lib/atlas/cli.js +1023 -0
- package/init-project-html/lib/atlas/layout.js +330 -0
- package/init-project-html/lib/atlas/render.js +583 -0
- package/init-project-html/lib/atlas/schema.js +347 -0
- package/init-project-html/lib/atlas/state.js +402 -0
- package/init-project-html/references/TEMPLATE_SPEC.md +140 -83
- package/init-project-html/sample-demo/resources/project-architecture/assets/architecture.css +160 -1058
- package/init-project-html/sample-demo/resources/project-architecture/assets/viewer.client.js +136 -0
- package/init-project-html/sample-demo/resources/project-architecture/atlas/atlas.index.yaml +34 -0
- package/init-project-html/sample-demo/resources/project-architecture/atlas/features/get-invite-codes.yaml +172 -0
- package/init-project-html/sample-demo/resources/project-architecture/atlas/features/invite-code-registration.yaml +160 -0
- package/init-project-html/sample-demo/resources/project-architecture/features/get-invite-codes/index.html +67 -52
- package/init-project-html/sample-demo/resources/project-architecture/features/get-invite-codes/invite-code-generator.html +64 -163
- package/init-project-html/sample-demo/resources/project-architecture/features/get-invite-codes/invite-issuance-service.html +102 -196
- package/init-project-html/sample-demo/resources/project-architecture/features/get-invite-codes/postgresql.html +82 -163
- package/init-project-html/sample-demo/resources/project-architecture/features/get-invite-codes/public-api.html +88 -150
- package/init-project-html/sample-demo/resources/project-architecture/features/get-invite-codes/web-get-invite-ui.html +83 -138
- package/init-project-html/sample-demo/resources/project-architecture/features/invite-code-registration/index.html +61 -51
- package/init-project-html/sample-demo/resources/project-architecture/features/invite-code-registration/postgresql.html +84 -159
- package/init-project-html/sample-demo/resources/project-architecture/features/invite-code-registration/public-api.html +81 -143
- package/init-project-html/sample-demo/resources/project-architecture/features/invite-code-registration/registration-service.html +98 -188
- package/init-project-html/sample-demo/resources/project-architecture/features/invite-code-registration/web-register-ui.html +83 -138
- package/init-project-html/sample-demo/resources/project-architecture/index.html +256 -335
- package/init-project-html/scripts/architecture.js +65 -247
- package/katex/scripts/__pycache__/render_katex.cpython-312.pyc +0 -0
- package/open-github-issue/scripts/__pycache__/open_github_issue.cpython-312.pyc +0 -0
- package/package.json +6 -2
- package/read-github-issue/scripts/__pycache__/find_issues.cpython-312.pyc +0 -0
- package/read-github-issue/scripts/__pycache__/read_issue.cpython-312.pyc +0 -0
- package/resolve-review-comments/scripts/__pycache__/review_threads.cpython-312.pyc +0 -0
- package/spec-to-project-html/SKILL.md +74 -67
- package/spec-to-project-html/agents/openai.yaml +14 -8
- package/spec-to-project-html/references/TEMPLATE_SPEC.md +98 -83
- package/text-to-short-video/scripts/__pycache__/enforce_video_aspect_ratio.cpython-312.pyc +0 -0
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
/* viewer.client.js — pan/zoom for every atlas SVG on the page.
|
|
2
|
+
*
|
|
3
|
+
* Each `[data-pan-zoom-viewport]` element gets its own state and
|
|
4
|
+
* handlers, so a single page can host the macro atlas SVG AND
|
|
5
|
+
* sub-module-internal dataflow SVGs simultaneously. Toolbar buttons
|
|
6
|
+
* (`[data-pan-zoom="zoom-in|zoom-out|fit"]`) are scoped to the
|
|
7
|
+
* containing `[data-pan-zoom-container]` (falls back to the viewport's
|
|
8
|
+
* direct parent), so multiple toolbars on one page do not collide.
|
|
9
|
+
* Keyboard shortcuts (`←` / `→` / `↑` / `↓` / `+` / `−` / `0`) drive
|
|
10
|
+
* the page's first viewport — the "primary" diagram of that page
|
|
11
|
+
* (macro SVG on `index.html`; sub-dataflow SVG on a sub-module page).
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
(function () {
|
|
15
|
+
'use strict';
|
|
16
|
+
|
|
17
|
+
const viewports = Array.from(document.querySelectorAll('[data-pan-zoom-viewport]'));
|
|
18
|
+
const controllers = viewports.map(setupViewport).filter(Boolean);
|
|
19
|
+
if (controllers.length === 0) return;
|
|
20
|
+
|
|
21
|
+
const primary = controllers[0];
|
|
22
|
+
document.addEventListener('keydown', function (evt) {
|
|
23
|
+
if (evt.target && (evt.target.tagName === 'INPUT' || evt.target.tagName === 'TEXTAREA')) return;
|
|
24
|
+
if (evt.key === 'ArrowLeft') { primary.pan(-1, 0); }
|
|
25
|
+
else if (evt.key === 'ArrowRight') { primary.pan(1, 0); }
|
|
26
|
+
else if (evt.key === 'ArrowUp') { primary.pan(0, -1); }
|
|
27
|
+
else if (evt.key === 'ArrowDown') { primary.pan(0, 1); }
|
|
28
|
+
else if (evt.key === '+' || evt.key === '=') { primary.zoom(1 / 1.2); }
|
|
29
|
+
else if (evt.key === '-' || evt.key === '_') { primary.zoom(1.2); }
|
|
30
|
+
else if (evt.key === '0') { primary.fit(); }
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
function setupViewport(viewport) {
|
|
34
|
+
const svg = viewport.querySelector('[data-atlas-svg]');
|
|
35
|
+
if (!svg) return null;
|
|
36
|
+
const initial = svg.getAttribute('viewBox');
|
|
37
|
+
if (!initial) return null;
|
|
38
|
+
const [ix, iy, iw, ih] = initial.split(/\s+/).map(Number);
|
|
39
|
+
const state = { x: ix, y: iy, w: iw, h: ih };
|
|
40
|
+
|
|
41
|
+
function apply() {
|
|
42
|
+
svg.setAttribute('viewBox', `${state.x} ${state.y} ${state.w} ${state.h}`);
|
|
43
|
+
}
|
|
44
|
+
function fit() {
|
|
45
|
+
state.x = ix; state.y = iy; state.w = iw; state.h = ih;
|
|
46
|
+
apply();
|
|
47
|
+
}
|
|
48
|
+
function zoom(factor, cx, cy) {
|
|
49
|
+
const newW = Math.max(40, Math.min(state.w * factor, iw * 8));
|
|
50
|
+
const newH = newW * (state.h / state.w);
|
|
51
|
+
if (cx == null) { cx = state.x + state.w / 2; cy = state.y + state.h / 2; }
|
|
52
|
+
state.x = cx - (cx - state.x) * (newW / state.w);
|
|
53
|
+
state.y = cy - (cy - state.y) * (newH / state.h);
|
|
54
|
+
state.w = newW;
|
|
55
|
+
state.h = newH;
|
|
56
|
+
apply();
|
|
57
|
+
}
|
|
58
|
+
function pan(dirX, dirY) {
|
|
59
|
+
const stepX = state.w * 0.08;
|
|
60
|
+
const stepY = state.h * 0.08;
|
|
61
|
+
state.x += dirX * stepX;
|
|
62
|
+
state.y += dirY * stepY;
|
|
63
|
+
apply();
|
|
64
|
+
}
|
|
65
|
+
function clientToSvg(evt) {
|
|
66
|
+
const rect = svg.getBoundingClientRect();
|
|
67
|
+
const xRatio = (evt.clientX - rect.left) / rect.width;
|
|
68
|
+
const yRatio = (evt.clientY - rect.top) / rect.height;
|
|
69
|
+
return { x: state.x + xRatio * state.w, y: state.y + yRatio * state.h };
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
viewport.addEventListener('wheel', function (evt) {
|
|
73
|
+
if (!evt.ctrlKey && !evt.metaKey && Math.abs(evt.deltaY) < 4 && Math.abs(evt.deltaX) < 4) return;
|
|
74
|
+
evt.preventDefault();
|
|
75
|
+
const factor = evt.deltaY > 0 ? 1.1 : 1 / 1.1;
|
|
76
|
+
const pt = clientToSvg(evt);
|
|
77
|
+
zoom(factor, pt.x, pt.y);
|
|
78
|
+
}, { passive: false });
|
|
79
|
+
|
|
80
|
+
// Drag-pan: defer the pointer capture (and the "is-grabbing" class)
|
|
81
|
+
// until the pointer actually moves past a small threshold. Without
|
|
82
|
+
// this, a single click on an SVG <a> (sub-module link) would be
|
|
83
|
+
// captured by the viewport and never reach the link.
|
|
84
|
+
const DRAG_THRESHOLD_PX = 4;
|
|
85
|
+
let pending = null;
|
|
86
|
+
let dragging = null;
|
|
87
|
+
viewport.addEventListener('pointerdown', function (evt) {
|
|
88
|
+
if (evt.button !== 0) return;
|
|
89
|
+
pending = { x: evt.clientX, y: evt.clientY, pointerId: evt.pointerId };
|
|
90
|
+
});
|
|
91
|
+
viewport.addEventListener('pointermove', function (evt) {
|
|
92
|
+
if (!dragging && pending && pending.pointerId === evt.pointerId) {
|
|
93
|
+
const dx = evt.clientX - pending.x;
|
|
94
|
+
const dy = evt.clientY - pending.y;
|
|
95
|
+
if (Math.hypot(dx, dy) < DRAG_THRESHOLD_PX) return;
|
|
96
|
+
dragging = { x: pending.x, y: pending.y, pointerId: pending.pointerId };
|
|
97
|
+
pending = null;
|
|
98
|
+
viewport.classList.add('is-grabbing');
|
|
99
|
+
try { viewport.setPointerCapture(dragging.pointerId); } catch (e) { /* ignore */ }
|
|
100
|
+
}
|
|
101
|
+
if (!dragging || dragging.pointerId !== evt.pointerId) return;
|
|
102
|
+
evt.preventDefault();
|
|
103
|
+
const rect = svg.getBoundingClientRect();
|
|
104
|
+
const dx = ((evt.clientX - dragging.x) / rect.width) * state.w;
|
|
105
|
+
const dy = ((evt.clientY - dragging.y) / rect.height) * state.h;
|
|
106
|
+
state.x -= dx;
|
|
107
|
+
state.y -= dy;
|
|
108
|
+
dragging.x = evt.clientX;
|
|
109
|
+
dragging.y = evt.clientY;
|
|
110
|
+
apply();
|
|
111
|
+
});
|
|
112
|
+
function endDrag(evt) {
|
|
113
|
+
pending = null;
|
|
114
|
+
if (!dragging) return;
|
|
115
|
+
const draggedId = dragging.pointerId;
|
|
116
|
+
dragging = null;
|
|
117
|
+
viewport.classList.remove('is-grabbing');
|
|
118
|
+
try { viewport.releasePointerCapture(draggedId); } catch (e) { /* ignore */ }
|
|
119
|
+
// Suppress the synthetic click that would follow a drag-release
|
|
120
|
+
// on top of a sub-module <a>; only the no-movement case should
|
|
121
|
+
// navigate.
|
|
122
|
+
const swallow = (e) => { e.preventDefault(); e.stopPropagation(); };
|
|
123
|
+
viewport.addEventListener('click', swallow, { capture: true, once: true });
|
|
124
|
+
}
|
|
125
|
+
viewport.addEventListener('pointerup', endDrag);
|
|
126
|
+
viewport.addEventListener('pointercancel', endDrag);
|
|
127
|
+
viewport.addEventListener('pointerleave', endDrag);
|
|
128
|
+
|
|
129
|
+
const container = viewport.closest('[data-pan-zoom-container]') || viewport.parentElement || document;
|
|
130
|
+
container.querySelectorAll('[data-pan-zoom="zoom-in"]').forEach((btn) => btn.addEventListener('click', () => zoom(1 / 1.2)));
|
|
131
|
+
container.querySelectorAll('[data-pan-zoom="zoom-out"]').forEach((btn) => btn.addEventListener('click', () => zoom(1.2)));
|
|
132
|
+
container.querySelectorAll('[data-pan-zoom="fit"]').forEach((btn) => btn.addEventListener('click', fit));
|
|
133
|
+
|
|
134
|
+
return { zoom, fit, pan };
|
|
135
|
+
}
|
|
136
|
+
})();
|