@pagenary/publisher 2026.5.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/LICENSE +661 -0
- package/README.md +337 -0
- package/bin/pagenary.mjs +116 -0
- package/build.config.json +5 -0
- package/package.json +66 -0
- package/scripts/build-site.js +87 -0
- package/scripts/build-tenants.js +3569 -0
- package/scripts/build.js +99 -0
- package/scripts/generate-sections.js +41 -0
- package/scripts/lib/seo-generator.js +558 -0
- package/scripts/lint-content.js +62 -0
- package/scripts/seo-smoke.js +94 -0
- package/scripts/serve.js +142 -0
- package/site/app.js +1 -0
- package/site/index.html +57 -0
- package/site/lib/categories.js +1 -0
- package/site/lib/export.js +1 -0
- package/site/lib/manifest-utils.js +1 -0
- package/site/lib/router.js +1 -0
- package/site/lib/search.js +1 -0
- package/site/llms.txt +22 -0
- package/site/manifest.js +132 -0
- package/site/mermaid-init.js +1 -0
- package/site/pages/api.html +339 -0
- package/site/pages/architecture.html +303 -0
- package/site/pages/deployment.html +282 -0
- package/site/pages/developer-guide.html +157 -0
- package/site/pages/extending.html +135 -0
- package/site/pages/quickstart.html +318 -0
- package/site/pages/seo-strategy.html +121 -0
- package/site/pages/tenant-config.html +519 -0
- package/site/pages/welcome.html +116 -0
- package/site/robots.txt +10 -0
- package/site/sections/api.js +3 -0
- package/site/sections/architecture.js +3 -0
- package/site/sections/deployment.js +3 -0
- package/site/sections/developer-guide.js +3 -0
- package/site/sections/extending.js +3 -0
- package/site/sections/quickstart.js +3 -0
- package/site/sections/section-templates.js +1 -0
- package/site/sections/seo-strategy.js +3 -0
- package/site/sections/tenant-config.js +3 -0
- package/site/sections/welcome.js +3 -0
- package/site/seo.js +1 -0
- package/site/sitemap.xml +63 -0
- package/site/styles.css +1982 -0
- package/site/syntax-highlight.js +1 -0
- package/src/app.js +988 -0
- package/src/index.html +56 -0
- package/src/lib/categories.js +55 -0
- package/src/lib/export.js +195 -0
- package/src/lib/manifest-utils.js +69 -0
- package/src/lib/router.js +44 -0
- package/src/lib/search.js +151 -0
- package/src/manifest.js +246 -0
- package/src/mermaid-init.js +207 -0
- package/src/sections/archive-future-roadmap.js +7 -0
- package/src/sections/archive-initiative-alpha.js +7 -0
- package/src/sections/archive-milestone-records.js +7 -0
- package/src/sections/archive-timeline-overview.js +7 -0
- package/src/sections/core-technology-compliance-frameworks.js +7 -0
- package/src/sections/core-technology-coordination-model.js +7 -0
- package/src/sections/core-technology-data-definitions.js +7 -0
- package/src/sections/core-technology-hardware-integration.js +7 -0
- package/src/sections/core-technology-integrity-controls.js +7 -0
- package/src/sections/core-technology-network-topology.js +7 -0
- package/src/sections/core-technology-operator-requirements.js +7 -0
- package/src/sections/core-technology-overview.js +7 -0
- package/src/sections/core-technology-service-interfaces.js +7 -0
- package/src/sections/core-technology-synchronization-strategy.js +7 -0
- package/src/sections/core-technology-system-foundation.js +7 -0
- package/src/sections/developers-api-credentials.js +7 -0
- package/src/sections/developers-api-operations.js +7 -0
- package/src/sections/developers-api-reference.js +7 -0
- package/src/sections/developers-api-websocket.js +7 -0
- package/src/sections/developers-automation-blueprints.js +7 -0
- package/src/sections/developers-automation-modules.js +7 -0
- package/src/sections/developers-automation-patterns.js +7 -0
- package/src/sections/developers-deployment-playbook.js +7 -0
- package/src/sections/developers-overview.js +7 -0
- package/src/sections/developers-scheduling-patterns.js +7 -0
- package/src/sections/developers-sdk-go.js +7 -0
- package/src/sections/developers-sdk-javascript.js +7 -0
- package/src/sections/developers-sdk-python.js +7 -0
- package/src/sections/developers-sdk-rust.js +7 -0
- package/src/sections/developers-sdks.js +7 -0
- package/src/sections/developers-solution-examples.js +7 -0
- package/src/sections/developers-testing-framework.js +7 -0
- package/src/sections/getting-started-architecture-basics.js +7 -0
- package/src/sections/getting-started-introduction.js +7 -0
- package/src/sections/getting-started-performance-overview.js +7 -0
- package/src/sections/governance-community-initiatives.js +7 -0
- package/src/sections/governance-dao-overview.js +7 -0
- package/src/sections/governance-multi-token.js +7 -0
- package/src/sections/governance-overview.js +7 -0
- package/src/sections/governance-proposal-process.js +7 -0
- package/src/sections/governance-proposals.js +7 -0
- package/src/sections/governance-structure.js +7 -0
- package/src/sections/governance-token-distribution.js +7 -0
- package/src/sections/governance-treasury.js +7 -0
- package/src/sections/operations-environment-prep.js +7 -0
- package/src/sections/operations-getting-started.js +7 -0
- package/src/sections/operations-incentives-guide.js +7 -0
- package/src/sections/operations-incentives-strategies.js +7 -0
- package/src/sections/operations-incentives.js +7 -0
- package/src/sections/operations-infrastructure.js +7 -0
- package/src/sections/operations-monitoring.js +7 -0
- package/src/sections/operations-overview.js +7 -0
- package/src/sections/operations-performance.js +7 -0
- package/src/sections/operations-power-infrastructure.js +7 -0
- package/src/sections/operations-setup-guide.js +7 -0
- package/src/sections/operations-sync-setup.js +7 -0
- package/src/sections/products-flagship-solution.js +7 -0
- package/src/sections/products-solution-library.js +7 -0
- package/src/sections/resources-brand-assets.js +7 -0
- package/src/sections/resources-faq.js +7 -0
- package/src/sections/resources-glossary.js +7 -0
- package/src/sections/resources-research-papers.js +7 -0
- package/src/sections/section-templates.js +873 -0
- package/src/sections/security-audits.js +7 -0
- package/src/sections/security-best-practices.js +7 -0
- package/src/sections/security-bug-bounty.js +7 -0
- package/src/sections/security-incident-response.js +7 -0
- package/src/sections/security-overview.js +7 -0
- package/src/sections/technical-architecture.js +7 -0
- package/src/sections/technical-whitepaper.js +7 -0
- package/src/sections/tutorial-automation-bot.js +7 -0
- package/src/sections/tutorial-build-first-integration.js +7 -0
- package/src/sections/tutorial-deploy-automation.js +7 -0
- package/src/sections/tutorial-event-driven-experience.js +7 -0
- package/src/sections/tutorial-operations-onboarding.js +7 -0
- package/src/sections/tutorial-systems-integration.js +7 -0
- package/src/sections/tutorials-overview.js +7 -0
- package/src/sections/use-case-connected-devices.js +7 -0
- package/src/sections/use-case-digital-auctions.js +7 -0
- package/src/sections/use-case-financial-automation.js +7 -0
- package/src/sections/use-case-interactive-media.js +7 -0
- package/src/sections/use-case-realtime-execution.js +7 -0
- package/src/sections/use-case-research-analytics.js +7 -0
- package/src/sections/use-case-supply-operations.js +7 -0
- package/src/sections/use-cases-overview.js +7 -0
- package/src/sections/welcome-overview.js +7 -0
- package/src/seo.js +90 -0
- package/src/styles.css +1982 -0
- package/src/syntax-highlight.js +90 -0
- package/tenants.json.example +68 -0
- package/tenants.schema.json +231 -0
package/src/manifest.js
ADDED
|
@@ -0,0 +1,246 @@
|
|
|
1
|
+
import { getSectionMetadata } from './sections/section-templates.js';
|
|
2
|
+
|
|
3
|
+
function sectionEntry(input) {
|
|
4
|
+
const sectionId = typeof input === 'string' ? input : input.id;
|
|
5
|
+
const overrides = typeof input === 'string' ? {} : { title: input.title, summary: input.summary };
|
|
6
|
+
const meta = getSectionMetadata(sectionId, overrides);
|
|
7
|
+
return {
|
|
8
|
+
id: sectionId,
|
|
9
|
+
title: meta.title,
|
|
10
|
+
summary: meta.summary,
|
|
11
|
+
module: `./sections/${sectionId}.js`
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
function groupEntry({ id, title, summary, sections }) {
|
|
16
|
+
return {
|
|
17
|
+
id,
|
|
18
|
+
title,
|
|
19
|
+
summary,
|
|
20
|
+
subsections: sections.map(sectionEntry)
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export const MANIFEST = [
|
|
25
|
+
sectionEntry({ id: 'welcome-overview', title: 'Welcome', summary: 'Landing hub for introducing each tenant experience.' }),
|
|
26
|
+
groupEntry({
|
|
27
|
+
id: 'getting-started',
|
|
28
|
+
title: 'Getting Started',
|
|
29
|
+
summary: 'Orientation guides that prepare new teams to launch quickly.',
|
|
30
|
+
sections: [
|
|
31
|
+
{ id: 'getting-started-introduction', title: 'Introduction' },
|
|
32
|
+
{ id: 'getting-started-architecture-basics', title: 'Platform Fundamentals' },
|
|
33
|
+
{ id: 'getting-started-performance-overview', title: 'Why Precision Matters' }
|
|
34
|
+
]
|
|
35
|
+
}),
|
|
36
|
+
groupEntry({
|
|
37
|
+
id: 'core-technology',
|
|
38
|
+
title: 'Core Systems',
|
|
39
|
+
summary: 'Reference templates describing foundational infrastructure and consensus patterns.',
|
|
40
|
+
sections: [
|
|
41
|
+
{ id: 'core-technology-overview', title: 'Overview' },
|
|
42
|
+
'core-technology-system-foundation',
|
|
43
|
+
'core-technology-compliance-frameworks',
|
|
44
|
+
'core-technology-synchronization-strategy',
|
|
45
|
+
'core-technology-hardware-integration',
|
|
46
|
+
'core-technology-data-definitions',
|
|
47
|
+
'core-technology-coordination-model',
|
|
48
|
+
'core-technology-service-interfaces',
|
|
49
|
+
'core-technology-integrity-controls',
|
|
50
|
+
'core-technology-network-topology',
|
|
51
|
+
'core-technology-operator-requirements'
|
|
52
|
+
]
|
|
53
|
+
}),
|
|
54
|
+
groupEntry({
|
|
55
|
+
id: 'technical',
|
|
56
|
+
title: 'Technical Papers',
|
|
57
|
+
summary: 'Deep dives and formal descriptions ready for adaptation.',
|
|
58
|
+
sections: [
|
|
59
|
+
'technical-architecture',
|
|
60
|
+
'technical-whitepaper'
|
|
61
|
+
]
|
|
62
|
+
}),
|
|
63
|
+
groupEntry({
|
|
64
|
+
id: 'developers',
|
|
65
|
+
title: 'Developers',
|
|
66
|
+
summary: 'SDKs, APIs, and engineering workflows captured as reusable templates.',
|
|
67
|
+
sections: [
|
|
68
|
+
{ id: 'developers-overview', title: 'Developer Hub' },
|
|
69
|
+
'developers-sdks',
|
|
70
|
+
'developers-sdk-javascript',
|
|
71
|
+
'developers-sdk-python',
|
|
72
|
+
'developers-sdk-rust',
|
|
73
|
+
'developers-sdk-go',
|
|
74
|
+
'developers-api-reference',
|
|
75
|
+
'developers-api-operations',
|
|
76
|
+
'developers-api-websocket',
|
|
77
|
+
'developers-api-credentials',
|
|
78
|
+
'developers-solution-examples',
|
|
79
|
+
'developers-automation-blueprints',
|
|
80
|
+
'developers-automation-modules',
|
|
81
|
+
'developers-automation-patterns',
|
|
82
|
+
'developers-scheduling-patterns',
|
|
83
|
+
'developers-testing-framework',
|
|
84
|
+
'developers-deployment-playbook'
|
|
85
|
+
]
|
|
86
|
+
}),
|
|
87
|
+
groupEntry({
|
|
88
|
+
id: 'tutorials',
|
|
89
|
+
title: 'Tutorials',
|
|
90
|
+
summary: 'Hands-on walkthroughs that demonstrate end-to-end tenant scenarios.',
|
|
91
|
+
sections: [
|
|
92
|
+
'tutorials-overview',
|
|
93
|
+
'tutorial-build-first-integration',
|
|
94
|
+
'tutorial-deploy-automation',
|
|
95
|
+
'tutorial-event-driven-experience',
|
|
96
|
+
'tutorial-systems-integration',
|
|
97
|
+
'tutorial-automation-bot',
|
|
98
|
+
'tutorial-operations-onboarding'
|
|
99
|
+
]
|
|
100
|
+
}),
|
|
101
|
+
groupEntry({
|
|
102
|
+
id: 'use-cases',
|
|
103
|
+
title: 'Use Cases',
|
|
104
|
+
summary: 'Story-driven templates that connect personas, workflows, and measurable impact.',
|
|
105
|
+
sections: [
|
|
106
|
+
'use-cases-overview',
|
|
107
|
+
'use-case-digital-auctions',
|
|
108
|
+
'use-case-financial-automation',
|
|
109
|
+
'use-case-interactive-media',
|
|
110
|
+
'use-case-realtime-execution',
|
|
111
|
+
'use-case-connected-devices',
|
|
112
|
+
'use-case-research-analytics',
|
|
113
|
+
'use-case-supply-operations'
|
|
114
|
+
]
|
|
115
|
+
}),
|
|
116
|
+
groupEntry({
|
|
117
|
+
id: 'products',
|
|
118
|
+
title: 'Products',
|
|
119
|
+
summary: 'Packaging and positioning templates for offerings built on the platform.',
|
|
120
|
+
sections: [
|
|
121
|
+
'products-solution-library',
|
|
122
|
+
'products-flagship-solution'
|
|
123
|
+
]
|
|
124
|
+
}),
|
|
125
|
+
groupEntry({
|
|
126
|
+
id: 'governance',
|
|
127
|
+
title: 'Governance',
|
|
128
|
+
summary: 'Policy and decision-making templates that scale across tenants.',
|
|
129
|
+
sections: [
|
|
130
|
+
'governance-overview',
|
|
131
|
+
'governance-structure',
|
|
132
|
+
'governance-dao-overview',
|
|
133
|
+
'governance-proposal-process',
|
|
134
|
+
'governance-proposals',
|
|
135
|
+
'governance-token-distribution',
|
|
136
|
+
'governance-treasury',
|
|
137
|
+
'governance-community-initiatives',
|
|
138
|
+
'governance-multi-token'
|
|
139
|
+
]
|
|
140
|
+
}),
|
|
141
|
+
groupEntry({
|
|
142
|
+
id: 'resources',
|
|
143
|
+
title: 'Resources',
|
|
144
|
+
summary: 'Reference libraries, glossaries, and asset collections ready for reuse.',
|
|
145
|
+
sections: [
|
|
146
|
+
'resources-faq',
|
|
147
|
+
'resources-glossary',
|
|
148
|
+
'resources-brand-assets',
|
|
149
|
+
'resources-research-papers'
|
|
150
|
+
]
|
|
151
|
+
}),
|
|
152
|
+
groupEntry({
|
|
153
|
+
id: 'security',
|
|
154
|
+
title: 'Security',
|
|
155
|
+
summary: 'Risk management templates spanning posture, controls, and incident response.',
|
|
156
|
+
sections: [
|
|
157
|
+
'security-overview',
|
|
158
|
+
'security-best-practices',
|
|
159
|
+
'security-incident-response',
|
|
160
|
+
'security-bug-bounty',
|
|
161
|
+
'security-audits'
|
|
162
|
+
]
|
|
163
|
+
}),
|
|
164
|
+
groupEntry({
|
|
165
|
+
id: 'operations',
|
|
166
|
+
title: 'Operations',
|
|
167
|
+
summary: 'Runbooks and checklists for service operators and tenant teams.',
|
|
168
|
+
sections: [
|
|
169
|
+
'operations-overview',
|
|
170
|
+
'operations-getting-started',
|
|
171
|
+
'operations-setup-guide',
|
|
172
|
+
'operations-environment-prep',
|
|
173
|
+
'operations-infrastructure',
|
|
174
|
+
'operations-sync-setup',
|
|
175
|
+
'operations-power-infrastructure',
|
|
176
|
+
'operations-monitoring',
|
|
177
|
+
'operations-performance',
|
|
178
|
+
'operations-incentives',
|
|
179
|
+
'operations-incentives-guide',
|
|
180
|
+
'operations-incentives-strategies'
|
|
181
|
+
]
|
|
182
|
+
}),
|
|
183
|
+
groupEntry({
|
|
184
|
+
id: 'archive',
|
|
185
|
+
title: 'Archive',
|
|
186
|
+
summary: 'Historical timelines and context for major initiatives.',
|
|
187
|
+
sections: [
|
|
188
|
+
'archive-timeline-overview',
|
|
189
|
+
'archive-milestone-records',
|
|
190
|
+
'archive-initiative-alpha',
|
|
191
|
+
'archive-future-roadmap'
|
|
192
|
+
]
|
|
193
|
+
})
|
|
194
|
+
];
|
|
195
|
+
|
|
196
|
+
export const DEFAULT_SECTION = 'welcome-overview';
|
|
197
|
+
|
|
198
|
+
const SECTION_INDEX = new Map();
|
|
199
|
+
|
|
200
|
+
function registerEntry(entry, parentId = null) {
|
|
201
|
+
if (parentId) entry.parentId = parentId;
|
|
202
|
+
SECTION_INDEX.set(entry.id, entry);
|
|
203
|
+
if (Array.isArray(entry.subsections)) {
|
|
204
|
+
entry.subsections.forEach((subsection) => registerEntry(subsection, entry.id));
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
MANIFEST.forEach((entry) => registerEntry(entry));
|
|
209
|
+
|
|
210
|
+
export function findSection(id) {
|
|
211
|
+
return SECTION_INDEX.get(id) || null;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
// Build flat list of navigable sections for prev/next navigation
|
|
215
|
+
function buildFlatNav() {
|
|
216
|
+
const flat = [];
|
|
217
|
+
MANIFEST.forEach((entry) => {
|
|
218
|
+
if (entry.subsections && entry.subsections.length) {
|
|
219
|
+
entry.subsections.forEach((sub) => flat.push(sub));
|
|
220
|
+
} else {
|
|
221
|
+
flat.push(entry);
|
|
222
|
+
}
|
|
223
|
+
});
|
|
224
|
+
return flat;
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
const FLAT_NAV = buildFlatNav();
|
|
228
|
+
|
|
229
|
+
/**
|
|
230
|
+
* Get previous and next sections for bottom navigation
|
|
231
|
+
* @param {string} currentId - Current section ID
|
|
232
|
+
* @returns {{ prev: object|null, next: object|null }}
|
|
233
|
+
*/
|
|
234
|
+
export function getAdjacentSections(currentId) {
|
|
235
|
+
const index = FLAT_NAV.findIndex((s) => s.id === currentId);
|
|
236
|
+
if (index === -1) return { prev: null, next: null };
|
|
237
|
+
return {
|
|
238
|
+
prev: index > 0 ? FLAT_NAV[index - 1] : null,
|
|
239
|
+
next: index < FLAT_NAV.length - 1 ? FLAT_NAV[index + 1] : null
|
|
240
|
+
};
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
// Site configuration (can be overridden by tenant manifest)
|
|
244
|
+
export const SITE_CONFIG = {
|
|
245
|
+
bottomNav: 'mobile' // 'always' | 'mobile' | 'never'
|
|
246
|
+
};
|
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Mermaid.js lazy-loading and rendering module
|
|
3
|
+
* Only loads mermaid when diagrams are detected on the page
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
let mermaidPromise = null;
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Lazily load mermaid.js from CDN
|
|
10
|
+
* @returns {Promise<object>} The mermaid module
|
|
11
|
+
*/
|
|
12
|
+
async function loadMermaid() {
|
|
13
|
+
if (mermaidPromise) return mermaidPromise;
|
|
14
|
+
|
|
15
|
+
mermaidPromise = (async () => {
|
|
16
|
+
const { default: mermaid } = await import('https://esm.sh/mermaid@10/dist/mermaid.esm.min.mjs');
|
|
17
|
+
mermaid.initialize({
|
|
18
|
+
startOnLoad: false,
|
|
19
|
+
theme: 'neutral',
|
|
20
|
+
securityLevel: 'strict',
|
|
21
|
+
flowchart: {
|
|
22
|
+
htmlLabels: true,
|
|
23
|
+
curve: 'basis',
|
|
24
|
+
nodeSpacing: 30,
|
|
25
|
+
rankSpacing: 50,
|
|
26
|
+
padding: 15,
|
|
27
|
+
useMaxWidth: true
|
|
28
|
+
},
|
|
29
|
+
themeVariables: {
|
|
30
|
+
fontFamily: 'system-ui, -apple-system, sans-serif',
|
|
31
|
+
fontSize: '14px'
|
|
32
|
+
}
|
|
33
|
+
});
|
|
34
|
+
return mermaid;
|
|
35
|
+
})();
|
|
36
|
+
|
|
37
|
+
return mermaidPromise;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Generate a unique ID for mermaid diagrams
|
|
42
|
+
* @returns {string} A unique identifier
|
|
43
|
+
*/
|
|
44
|
+
function generateId() {
|
|
45
|
+
return 'mermaid-' + Math.random().toString(36).slice(2, 10);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Render all mermaid code blocks within a container
|
|
50
|
+
* @param {HTMLElement} container - The container to search for mermaid blocks
|
|
51
|
+
*/
|
|
52
|
+
export async function renderMermaidBlocks(container) {
|
|
53
|
+
const codeBlocks = container.querySelectorAll('code.language-mermaid');
|
|
54
|
+
if (codeBlocks.length === 0) return;
|
|
55
|
+
|
|
56
|
+
const mermaid = await loadMermaid();
|
|
57
|
+
|
|
58
|
+
for (const codeBlock of codeBlocks) {
|
|
59
|
+
const pre = codeBlock.parentElement;
|
|
60
|
+
const definition = codeBlock.textContent;
|
|
61
|
+
const id = generateId();
|
|
62
|
+
|
|
63
|
+
try {
|
|
64
|
+
const { svg } = await mermaid.render(id, definition);
|
|
65
|
+
const wrapper = document.createElement('div');
|
|
66
|
+
wrapper.className = 'mermaid-diagram';
|
|
67
|
+
|
|
68
|
+
// Create controls
|
|
69
|
+
const controls = document.createElement('div');
|
|
70
|
+
controls.className = 'mermaid-controls';
|
|
71
|
+
controls.innerHTML = `
|
|
72
|
+
<button type="button" class="mermaid-btn mermaid-zoom-out" aria-label="Zoom out">−</button>
|
|
73
|
+
<button type="button" class="mermaid-btn mermaid-zoom-reset" aria-label="Reset zoom">⊙</button>
|
|
74
|
+
<button type="button" class="mermaid-btn mermaid-zoom-in" aria-label="Zoom in">+</button>
|
|
75
|
+
`;
|
|
76
|
+
|
|
77
|
+
// Create scrollable content area
|
|
78
|
+
const content = document.createElement('div');
|
|
79
|
+
content.className = 'mermaid-content';
|
|
80
|
+
content.innerHTML = svg;
|
|
81
|
+
|
|
82
|
+
wrapper.appendChild(controls);
|
|
83
|
+
wrapper.appendChild(content);
|
|
84
|
+
|
|
85
|
+
// Initialize zoom and pan state
|
|
86
|
+
let scale = 1;
|
|
87
|
+
const svgEl = content.querySelector('svg');
|
|
88
|
+
let isDragging = false;
|
|
89
|
+
let startX, startY, scrollLeft, scrollTop;
|
|
90
|
+
|
|
91
|
+
const updateZoom = () => {
|
|
92
|
+
if (svgEl) {
|
|
93
|
+
svgEl.style.transform = `scale(${scale})`;
|
|
94
|
+
svgEl.style.transformOrigin = 'top left';
|
|
95
|
+
}
|
|
96
|
+
};
|
|
97
|
+
|
|
98
|
+
// Zoom controls
|
|
99
|
+
controls.querySelector('.mermaid-zoom-in').addEventListener('click', () => {
|
|
100
|
+
scale = Math.min(scale + 0.25, 3);
|
|
101
|
+
updateZoom();
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
controls.querySelector('.mermaid-zoom-out').addEventListener('click', () => {
|
|
105
|
+
scale = Math.max(scale - 0.25, 0.5);
|
|
106
|
+
updateZoom();
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
controls.querySelector('.mermaid-zoom-reset').addEventListener('click', () => {
|
|
110
|
+
scale = 1;
|
|
111
|
+
updateZoom();
|
|
112
|
+
content.scrollLeft = 0;
|
|
113
|
+
content.scrollTop = 0;
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
// Click and drag to pan
|
|
117
|
+
content.addEventListener('mousedown', (e) => {
|
|
118
|
+
isDragging = true;
|
|
119
|
+
content.style.cursor = 'grabbing';
|
|
120
|
+
startX = e.pageX - content.offsetLeft;
|
|
121
|
+
startY = e.pageY - content.offsetTop;
|
|
122
|
+
scrollLeft = content.scrollLeft;
|
|
123
|
+
scrollTop = content.scrollTop;
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
content.addEventListener('mouseleave', () => {
|
|
127
|
+
isDragging = false;
|
|
128
|
+
content.style.cursor = 'grab';
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
content.addEventListener('mouseup', () => {
|
|
132
|
+
isDragging = false;
|
|
133
|
+
content.style.cursor = 'grab';
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
content.addEventListener('mousemove', (e) => {
|
|
137
|
+
if (!isDragging) return;
|
|
138
|
+
e.preventDefault();
|
|
139
|
+
const x = e.pageX - content.offsetLeft;
|
|
140
|
+
const y = e.pageY - content.offsetTop;
|
|
141
|
+
content.scrollLeft = scrollLeft - (x - startX);
|
|
142
|
+
content.scrollTop = scrollTop - (y - startY);
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
// Touch gesture support
|
|
146
|
+
let lastTouchDistance = 0;
|
|
147
|
+
|
|
148
|
+
content.addEventListener('touchstart', (e) => {
|
|
149
|
+
if (e.touches.length === 1) {
|
|
150
|
+
isDragging = true;
|
|
151
|
+
startX = e.touches[0].pageX - content.offsetLeft;
|
|
152
|
+
startY = e.touches[0].pageY - content.offsetTop;
|
|
153
|
+
scrollLeft = content.scrollLeft;
|
|
154
|
+
scrollTop = content.scrollTop;
|
|
155
|
+
} else if (e.touches.length === 2) {
|
|
156
|
+
// Pinch zoom start
|
|
157
|
+
lastTouchDistance = Math.hypot(
|
|
158
|
+
e.touches[0].pageX - e.touches[1].pageX,
|
|
159
|
+
e.touches[0].pageY - e.touches[1].pageY
|
|
160
|
+
);
|
|
161
|
+
}
|
|
162
|
+
}, { passive: true });
|
|
163
|
+
|
|
164
|
+
content.addEventListener('touchmove', (e) => {
|
|
165
|
+
if (e.touches.length === 1 && isDragging) {
|
|
166
|
+
const x = e.touches[0].pageX - content.offsetLeft;
|
|
167
|
+
const y = e.touches[0].pageY - content.offsetTop;
|
|
168
|
+
content.scrollLeft = scrollLeft - (x - startX);
|
|
169
|
+
content.scrollTop = scrollTop - (y - startY);
|
|
170
|
+
} else if (e.touches.length === 2) {
|
|
171
|
+
// Pinch zoom
|
|
172
|
+
const distance = Math.hypot(
|
|
173
|
+
e.touches[0].pageX - e.touches[1].pageX,
|
|
174
|
+
e.touches[0].pageY - e.touches[1].pageY
|
|
175
|
+
);
|
|
176
|
+
if (lastTouchDistance > 0) {
|
|
177
|
+
const delta = distance - lastTouchDistance;
|
|
178
|
+
if (Math.abs(delta) > 10) {
|
|
179
|
+
scale = Math.max(0.5, Math.min(3, scale + (delta > 0 ? 0.1 : -0.1)));
|
|
180
|
+
updateZoom();
|
|
181
|
+
lastTouchDistance = distance;
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
}, { passive: true });
|
|
186
|
+
|
|
187
|
+
content.addEventListener('touchend', () => {
|
|
188
|
+
isDragging = false;
|
|
189
|
+
lastTouchDistance = 0;
|
|
190
|
+
}, { passive: true });
|
|
191
|
+
|
|
192
|
+
// Set initial cursor
|
|
193
|
+
content.style.cursor = 'grab';
|
|
194
|
+
|
|
195
|
+
pre.replaceWith(wrapper);
|
|
196
|
+
} catch (err) {
|
|
197
|
+
console.error('Mermaid render error:', err);
|
|
198
|
+
// Add error class but keep original code visible for debugging
|
|
199
|
+
pre.classList.add('mermaid-error');
|
|
200
|
+
// Add error message before the code block
|
|
201
|
+
const errorMsg = document.createElement('div');
|
|
202
|
+
errorMsg.className = 'mermaid-error-message';
|
|
203
|
+
errorMsg.textContent = 'Diagram failed to render: ' + err.message;
|
|
204
|
+
pre.insertAdjacentElement('beforebegin', errorMsg);
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
}
|