@eventcatalog/core 3.2.1 → 3.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/analytics/analytics.cjs +1 -1
- package/dist/analytics/analytics.js +2 -2
- package/dist/analytics/log-build.cjs +1 -1
- package/dist/analytics/log-build.js +3 -3
- package/dist/{chunk-VBEYXPR5.js → chunk-I4CMEOEN.js} +1 -1
- package/dist/{chunk-SYOF3QEG.js → chunk-NGKYYZZP.js} +1 -1
- package/dist/{chunk-SFQ3BU4M.js → chunk-OAUYXPXT.js} +1 -1
- package/dist/{chunk-7PHTRC72.js → chunk-QZF5ZYJB.js} +1 -1
- package/dist/{chunk-LWUJQOCC.js → chunk-UPSN5H7S.js} +1 -1
- package/dist/constants.cjs +1 -1
- package/dist/constants.js +1 -1
- package/dist/eventcatalog.cjs +1 -1
- package/dist/eventcatalog.js +5 -5
- package/dist/generate.cjs +1 -1
- package/dist/generate.js +3 -3
- package/dist/utils/cli-logger.cjs +1 -1
- package/dist/utils/cli-logger.js +2 -2
- package/eventcatalog/src/components/ChatPanel/ChatPanel.tsx +9 -0
- package/eventcatalog/src/components/ChatPanel/ChatPanelButton.tsx +11 -1
- package/eventcatalog/src/components/CopyAsMarkdown.tsx +47 -28
- package/eventcatalog/src/content.config.ts +18 -0
- package/eventcatalog/src/enterprise/ai/chat-api.ts +24 -2
- package/eventcatalog/src/pages/diagrams/[id]/[version]/_index.data.ts +57 -0
- package/eventcatalog/src/pages/diagrams/[id]/[version]/embed.astro +267 -0
- package/eventcatalog/src/pages/diagrams/[id]/[version]/index.astro +411 -0
- package/eventcatalog/src/pages/diagrams/[id]/[version].mdx.ts +47 -0
- package/eventcatalog/src/pages/docs/[type]/[id]/[version]/changelog/index.astro +28 -33
- package/eventcatalog/src/pages/docs/[type]/[id]/[version]/index.astro +1 -0
- package/eventcatalog/src/pages/docs/[type]/[id]/[version].md.ts +3 -2
- package/eventcatalog/src/pages/docs/[type]/[id]/[version].mdx.ts +5 -1
- package/eventcatalog/src/pages/docs/[type]/[id]/language.mdx.ts +2 -1
- package/eventcatalog/src/pages/docs/custom/[...path].mdx.ts +2 -2
- package/eventcatalog/src/pages/docs/teams/[id].md.ts +3 -2
- package/eventcatalog/src/pages/docs/teams/[id].mdx.ts +3 -3
- package/eventcatalog/src/pages/docs/users/[id].md.ts +3 -2
- package/eventcatalog/src/pages/docs/users/[id].mdx.ts +3 -3
- package/eventcatalog/src/stores/sidebar-store/builders/container.ts +20 -4
- package/eventcatalog/src/stores/sidebar-store/builders/domain.ts +20 -12
- package/eventcatalog/src/stores/sidebar-store/builders/flow.ts +1 -1
- package/eventcatalog/src/stores/sidebar-store/builders/message.ts +20 -4
- package/eventcatalog/src/stores/sidebar-store/builders/service.ts +18 -6
- package/eventcatalog/src/stores/sidebar-store/builders/shared.ts +20 -0
- package/eventcatalog/src/stores/sidebar-store/state.ts +34 -6
- package/eventcatalog/src/types/index.ts +4 -2
- package/eventcatalog/src/utils/collections/diagrams.ts +64 -0
- package/eventcatalog/src/utils/collections/util.ts +2 -0
- package/eventcatalog/src/utils/feature.ts +4 -2
- package/eventcatalog/src/utils/page-loaders/page-data-loader.ts +2 -0
- package/package.json +2 -2
|
@@ -0,0 +1,267 @@
|
|
|
1
|
+
---
|
|
2
|
+
import { render } from 'astro:content';
|
|
3
|
+
import components from '@components/MDX/components';
|
|
4
|
+
import config from '@config';
|
|
5
|
+
|
|
6
|
+
import { Page } from './_index.data';
|
|
7
|
+
|
|
8
|
+
export const prerender = Page.prerender;
|
|
9
|
+
export const getStaticPaths = Page.getStaticPaths;
|
|
10
|
+
|
|
11
|
+
const props = await Page.getData(Astro);
|
|
12
|
+
const { Content } = await render(props);
|
|
13
|
+
|
|
14
|
+
const currentVersion = props.data.version;
|
|
15
|
+
const diagramId = props.data.id;
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
<html lang="en">
|
|
19
|
+
<head>
|
|
20
|
+
<meta charset="UTF-8" />
|
|
21
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
22
|
+
<title>v{currentVersion}</title>
|
|
23
|
+
<style is:global>
|
|
24
|
+
* {
|
|
25
|
+
margin: 0;
|
|
26
|
+
padding: 0;
|
|
27
|
+
box-sizing: border-box;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
:root {
|
|
31
|
+
--ec-page-bg: 255 255 255;
|
|
32
|
+
--ec-page-text: 15 23 42;
|
|
33
|
+
--ec-page-text-muted: 100 116 139;
|
|
34
|
+
--ec-page-border: 226 232 240;
|
|
35
|
+
--ec-content-hover: 241 245 249;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
:root[data-theme='dark'] {
|
|
39
|
+
--ec-page-bg: 13 17 23;
|
|
40
|
+
--ec-page-text: 240 246 252;
|
|
41
|
+
--ec-page-text-muted: 139 148 158;
|
|
42
|
+
--ec-page-border: 33 38 45;
|
|
43
|
+
--ec-content-hover: 33 38 45;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
body {
|
|
47
|
+
font-family:
|
|
48
|
+
system-ui,
|
|
49
|
+
-apple-system,
|
|
50
|
+
BlinkMacSystemFont,
|
|
51
|
+
'Segoe UI',
|
|
52
|
+
Roboto,
|
|
53
|
+
sans-serif;
|
|
54
|
+
background: rgb(var(--ec-page-bg));
|
|
55
|
+
color: rgb(var(--ec-page-text));
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
.embed-container {
|
|
59
|
+
padding: 1.5rem;
|
|
60
|
+
height: 100vh;
|
|
61
|
+
overflow: auto;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
.mermaid svg {
|
|
65
|
+
margin: 0 auto;
|
|
66
|
+
display: block;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/* Prose styles */
|
|
70
|
+
.prose {
|
|
71
|
+
max-width: none;
|
|
72
|
+
color: rgb(var(--ec-page-text));
|
|
73
|
+
}
|
|
74
|
+
.prose h1,
|
|
75
|
+
.prose h2,
|
|
76
|
+
.prose h3,
|
|
77
|
+
.prose h4 {
|
|
78
|
+
color: rgb(var(--ec-page-text));
|
|
79
|
+
margin-top: 1.5rem;
|
|
80
|
+
margin-bottom: 0.75rem;
|
|
81
|
+
font-weight: 600;
|
|
82
|
+
}
|
|
83
|
+
.prose h1 {
|
|
84
|
+
font-size: 1.875rem;
|
|
85
|
+
}
|
|
86
|
+
.prose h2 {
|
|
87
|
+
font-size: 1.5rem;
|
|
88
|
+
}
|
|
89
|
+
.prose h3 {
|
|
90
|
+
font-size: 1.25rem;
|
|
91
|
+
}
|
|
92
|
+
.prose p {
|
|
93
|
+
color: rgb(var(--ec-page-text));
|
|
94
|
+
margin-bottom: 1rem;
|
|
95
|
+
line-height: 1.6;
|
|
96
|
+
}
|
|
97
|
+
.prose strong {
|
|
98
|
+
color: rgb(var(--ec-page-text));
|
|
99
|
+
font-weight: 600;
|
|
100
|
+
}
|
|
101
|
+
.prose a {
|
|
102
|
+
color: rgb(var(--ec-page-text));
|
|
103
|
+
text-decoration: underline;
|
|
104
|
+
}
|
|
105
|
+
.prose ul,
|
|
106
|
+
.prose ol {
|
|
107
|
+
color: rgb(var(--ec-page-text));
|
|
108
|
+
margin-bottom: 1rem;
|
|
109
|
+
padding-left: 1.5rem;
|
|
110
|
+
}
|
|
111
|
+
.prose li {
|
|
112
|
+
margin-bottom: 0.25rem;
|
|
113
|
+
}
|
|
114
|
+
.prose code {
|
|
115
|
+
color: rgb(var(--ec-page-text));
|
|
116
|
+
background: rgb(var(--ec-page-border));
|
|
117
|
+
padding: 0.125rem 0.25rem;
|
|
118
|
+
border-radius: 0.25rem;
|
|
119
|
+
font-size: 0.875rem;
|
|
120
|
+
}
|
|
121
|
+
.prose pre {
|
|
122
|
+
background: rgb(var(--ec-page-border));
|
|
123
|
+
padding: 1rem;
|
|
124
|
+
border-radius: 0.5rem;
|
|
125
|
+
overflow-x: auto;
|
|
126
|
+
margin-bottom: 1rem;
|
|
127
|
+
}
|
|
128
|
+
.prose pre code {
|
|
129
|
+
background: transparent;
|
|
130
|
+
padding: 0;
|
|
131
|
+
}
|
|
132
|
+
.prose img {
|
|
133
|
+
max-width: 100%;
|
|
134
|
+
height: auto;
|
|
135
|
+
}
|
|
136
|
+
.prose blockquote {
|
|
137
|
+
border-left: 4px solid rgb(var(--ec-page-border));
|
|
138
|
+
padding-left: 1rem;
|
|
139
|
+
color: rgb(var(--ec-page-text-muted));
|
|
140
|
+
margin: 1rem 0;
|
|
141
|
+
}
|
|
142
|
+
</style>
|
|
143
|
+
</head>
|
|
144
|
+
<body>
|
|
145
|
+
<script is:inline>
|
|
146
|
+
// Inherit theme from parent window
|
|
147
|
+
try {
|
|
148
|
+
const parentTheme = window.parent?.document?.documentElement?.getAttribute('data-theme');
|
|
149
|
+
if (parentTheme) {
|
|
150
|
+
document.documentElement.setAttribute('data-theme', parentTheme);
|
|
151
|
+
}
|
|
152
|
+
} catch (e) {
|
|
153
|
+
// Cross-origin, ignore
|
|
154
|
+
}
|
|
155
|
+
</script>
|
|
156
|
+
|
|
157
|
+
<div class="embed-container">
|
|
158
|
+
<div class="flex items-center justify-between mb-4 pb-3 border-b border-[rgb(var(--ec-page-border))]">
|
|
159
|
+
<span class="text-sm font-semibold text-[rgb(var(--ec-page-text))]">v{currentVersion}</span>
|
|
160
|
+
<a
|
|
161
|
+
id="go-to-diagram"
|
|
162
|
+
href="#"
|
|
163
|
+
target="_top"
|
|
164
|
+
class="text-xs font-medium text-[rgb(var(--ec-page-text-muted))] border border-[rgb(var(--ec-page-border))] rounded-md px-3 py-1 hover:bg-[rgb(var(--ec-content-hover))] hover:text-[rgb(var(--ec-page-text))] transition-colors"
|
|
165
|
+
>
|
|
166
|
+
Go to diagram
|
|
167
|
+
</a>
|
|
168
|
+
</div>
|
|
169
|
+
<article class="prose">
|
|
170
|
+
<Content components={components(props)} />
|
|
171
|
+
</article>
|
|
172
|
+
</div>
|
|
173
|
+
|
|
174
|
+
<script is:inline define:vars={{ config, baseUrl: import.meta.env.BASE_URL }}>
|
|
175
|
+
window.eventcatalog = { mermaid: config?.mermaid };
|
|
176
|
+
|
|
177
|
+
// Set the go-to-diagram link by parsing URL: /diagrams/{id}/{version}/embed
|
|
178
|
+
const goToBtn = document.getElementById('go-to-diagram');
|
|
179
|
+
if (goToBtn) {
|
|
180
|
+
const pathParts = window.location.pathname.split('/');
|
|
181
|
+
const diagramsIndex = pathParts.indexOf('diagrams');
|
|
182
|
+
const diagramId = diagramsIndex !== -1 ? pathParts[diagramsIndex + 1] : '';
|
|
183
|
+
const version = diagramsIndex !== -1 ? pathParts[diagramsIndex + 2] : '';
|
|
184
|
+
const base = baseUrl === '/' ? '' : baseUrl;
|
|
185
|
+
goToBtn.href = `${base}/diagrams/${diagramId}/${version}`;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
async function renderMermaid() {
|
|
189
|
+
const graphs = document.getElementsByClassName('mermaid');
|
|
190
|
+
if (graphs.length === 0) return;
|
|
191
|
+
|
|
192
|
+
const { default: mermaid } = await import('https://cdn.jsdelivr.net/npm/mermaid@10/dist/mermaid.esm.min.mjs');
|
|
193
|
+
const isDarkMode = document.documentElement.getAttribute('data-theme') === 'dark';
|
|
194
|
+
|
|
195
|
+
mermaid.initialize({
|
|
196
|
+
startOnLoad: false,
|
|
197
|
+
theme: isDarkMode ? 'dark' : 'default',
|
|
198
|
+
fontFamily: 'system-ui, -apple-system, sans-serif',
|
|
199
|
+
});
|
|
200
|
+
|
|
201
|
+
for (const graph of graphs) {
|
|
202
|
+
const content = graph.getAttribute('data-content');
|
|
203
|
+
if (!content) continue;
|
|
204
|
+
const id = 'mermaid-' + Math.round(Math.random() * 100000);
|
|
205
|
+
try {
|
|
206
|
+
const result = await mermaid.render(id, content);
|
|
207
|
+
graph.innerHTML = result.svg;
|
|
208
|
+
} catch (e) {
|
|
209
|
+
console.error('Mermaid render error:', e);
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
renderMermaid();
|
|
215
|
+
|
|
216
|
+
// PlantUML rendering
|
|
217
|
+
async function renderPlantUML() {
|
|
218
|
+
const blocks = document.getElementsByClassName('plantuml');
|
|
219
|
+
if (blocks.length === 0) return;
|
|
220
|
+
|
|
221
|
+
const { deflate } = await import('https://cdn.jsdelivr.net/npm/pako@2.1.0/+esm');
|
|
222
|
+
|
|
223
|
+
function encode64(data) {
|
|
224
|
+
const chars = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz-_';
|
|
225
|
+
let str = '';
|
|
226
|
+
const len = data.length;
|
|
227
|
+
for (let i = 0; i < len; i += 3) {
|
|
228
|
+
const b1 = data[i];
|
|
229
|
+
const b2 = i + 1 < len ? data[i + 1] : 0;
|
|
230
|
+
const b3 = i + 2 < len ? data[i + 2] : 0;
|
|
231
|
+
|
|
232
|
+
let c1 = b1 >> 2;
|
|
233
|
+
let c2 = ((b1 & 0x3) << 4) | (b2 >> 4);
|
|
234
|
+
let c3 = ((b2 & 0xf) << 2) | (b3 >> 6);
|
|
235
|
+
let c4 = b3 & 0x3f;
|
|
236
|
+
|
|
237
|
+
str += chars[c1] + chars[c2] + chars[c3] + chars[c4];
|
|
238
|
+
}
|
|
239
|
+
return str;
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
function encodePlantUML(text) {
|
|
243
|
+
const data = new TextEncoder().encode(text);
|
|
244
|
+
const compressed = deflate(data, { level: 9, to: 'Uint8Array' });
|
|
245
|
+
return encode64(compressed);
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
for (const block of blocks) {
|
|
249
|
+
const content = block.getAttribute('data-content');
|
|
250
|
+
if (!content) continue;
|
|
251
|
+
|
|
252
|
+
const encoded = encodePlantUML(content);
|
|
253
|
+
const img = document.createElement('img');
|
|
254
|
+
img.src = `https://www.plantuml.com/plantuml/svg/~1${encoded}`;
|
|
255
|
+
img.alt = 'PlantUML diagram';
|
|
256
|
+
img.loading = 'lazy';
|
|
257
|
+
img.style.margin = '0 auto';
|
|
258
|
+
img.style.display = 'block';
|
|
259
|
+
block.innerHTML = '';
|
|
260
|
+
block.appendChild(img);
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
renderPlantUML();
|
|
265
|
+
</script>
|
|
266
|
+
</body>
|
|
267
|
+
</html>
|
|
@@ -0,0 +1,411 @@
|
|
|
1
|
+
---
|
|
2
|
+
import { render } from 'astro:content';
|
|
3
|
+
import { ClientRouter } from 'astro:transitions';
|
|
4
|
+
import VisualiserLayout from '@layouts/VisualiserLayout.astro';
|
|
5
|
+
import components from '@components/MDX/components';
|
|
6
|
+
import config from '@config';
|
|
7
|
+
import { buildUrl } from '@utils/url-builder';
|
|
8
|
+
import { ChevronDown, GitCompare, X, Rocket } from 'lucide-react';
|
|
9
|
+
import CopyAsMarkdown from '@components/CopyAsMarkdown';
|
|
10
|
+
import { isLLMSTxtEnabled, isEventCatalogChatEnabled, isDiagramComparisonEnabled } from '@utils/feature';
|
|
11
|
+
|
|
12
|
+
import { Page } from './_index.data';
|
|
13
|
+
|
|
14
|
+
export const prerender = Page.prerender;
|
|
15
|
+
export const getStaticPaths = Page.getStaticPaths;
|
|
16
|
+
|
|
17
|
+
const props = await Page.getData(Astro);
|
|
18
|
+
const { Content } = await render(props);
|
|
19
|
+
|
|
20
|
+
const pageTitle = `Diagram | ${props.data.name}`;
|
|
21
|
+
const currentVersion = props.data.version;
|
|
22
|
+
const allVersions = props.allVersions || [currentVersion];
|
|
23
|
+
const hasMultipleVersions = allVersions.length > 1;
|
|
24
|
+
const scaleEnabled = isDiagramComparisonEnabled();
|
|
25
|
+
const chatEnabled = isEventCatalogChatEnabled();
|
|
26
|
+
const markdownDownloadEnabled = isLLMSTxtEnabled();
|
|
27
|
+
const chatQuery = `Tell me about the "${props.data.name}" diagram (version ${props.data.version})`;
|
|
28
|
+
---
|
|
29
|
+
|
|
30
|
+
<VisualiserLayout title={pageTitle} description={props.data.summary}>
|
|
31
|
+
<div class="diagram-page min-h-[calc(100vh-64px)] bg-[rgb(var(--ec-page-bg))]">
|
|
32
|
+
<header class="diagram-header border-b border-[rgb(var(--ec-page-border))]">
|
|
33
|
+
<div class="px-6 py-6 flex items-center justify-between gap-4">
|
|
34
|
+
<div class="min-w-0">
|
|
35
|
+
<div class="flex items-center gap-3">
|
|
36
|
+
<h1 class="text-2xl md:text-2xl font-bold text-[rgb(var(--ec-page-text))] truncate">
|
|
37
|
+
{props.data.name}
|
|
38
|
+
</h1>
|
|
39
|
+
{
|
|
40
|
+
hasMultipleVersions ? (
|
|
41
|
+
<div class="relative flex-shrink-0">
|
|
42
|
+
<select
|
|
43
|
+
id="version-select"
|
|
44
|
+
class="appearance-none text-xs font-medium text-[rgb(var(--ec-page-text-muted))] bg-transparent border border-[rgb(var(--ec-page-border))] rounded-md pl-2 pr-6 py-1 cursor-pointer hover:border-[rgb(var(--ec-accent))] transition-colors"
|
|
45
|
+
>
|
|
46
|
+
{allVersions.map((version: string) => (
|
|
47
|
+
<option value={buildUrl(`/diagrams/${props.data.id}/${version}`)} selected={version === currentVersion}>
|
|
48
|
+
v{version}
|
|
49
|
+
{version === props.data.latestVersion ? ' (latest)' : ''}
|
|
50
|
+
</option>
|
|
51
|
+
))}
|
|
52
|
+
</select>
|
|
53
|
+
<ChevronDown className="absolute right-1.5 top-1/2 -translate-y-1/2 w-3 h-3 text-[rgb(var(--ec-icon-color))] pointer-events-none" />
|
|
54
|
+
</div>
|
|
55
|
+
) : (
|
|
56
|
+
<span class="text-xs font-medium text-[rgb(var(--ec-page-text-muted))]">v{currentVersion}</span>
|
|
57
|
+
)
|
|
58
|
+
}
|
|
59
|
+
</div>
|
|
60
|
+
{props.data.summary && <p class="mt-1 text-sm text-[rgb(var(--ec-page-text-muted))]">{props.data.summary}</p>}
|
|
61
|
+
</div>
|
|
62
|
+
|
|
63
|
+
<div class="flex items-center gap-2">
|
|
64
|
+
{
|
|
65
|
+
hasMultipleVersions && (
|
|
66
|
+
<button
|
|
67
|
+
id="compare-btn"
|
|
68
|
+
type="button"
|
|
69
|
+
data-scale-enabled={scaleEnabled}
|
|
70
|
+
class="inline-flex items-center justify-center gap-1.5 px-3 py-1.5 text-sm font-medium text-[rgb(var(--ec-dropdown-text))] bg-[rgb(var(--ec-dropdown-bg))] border border-[rgb(var(--ec-dropdown-border))] rounded-md shadow-sm hover:bg-[rgb(var(--ec-dropdown-hover))] focus:outline-none focus:ring-1 focus:ring-[rgb(var(--ec-accent))] transition-colors"
|
|
71
|
+
>
|
|
72
|
+
<GitCompare className="w-4 h-4" />
|
|
73
|
+
Compare diagram versions
|
|
74
|
+
</button>
|
|
75
|
+
)
|
|
76
|
+
}
|
|
77
|
+
<CopyAsMarkdown
|
|
78
|
+
client:only="react"
|
|
79
|
+
schemas={[]}
|
|
80
|
+
chatQuery={chatQuery}
|
|
81
|
+
chatEnabled={chatEnabled}
|
|
82
|
+
editUrl=""
|
|
83
|
+
markdownDownloadEnabled={markdownDownloadEnabled}
|
|
84
|
+
rssFeedEnabled={false}
|
|
85
|
+
preferChatAsDefault={chatEnabled}
|
|
86
|
+
chatButtonText="Ask about this diagram"
|
|
87
|
+
/>
|
|
88
|
+
</div>
|
|
89
|
+
</div>
|
|
90
|
+
</header>
|
|
91
|
+
|
|
92
|
+
<main class="diagram-content p-6">
|
|
93
|
+
<article
|
|
94
|
+
class="diagram-article prose prose-lg max-w-none dark:prose-invert prose-headings:text-[rgb(var(--ec-page-text))] prose-p:text-[rgb(var(--ec-page-text))] prose-strong:text-[rgb(var(--ec-page-text))] prose-code:text-[rgb(var(--ec-page-text))]"
|
|
95
|
+
>
|
|
96
|
+
<Content components={components(props)} />
|
|
97
|
+
</article>
|
|
98
|
+
</main>
|
|
99
|
+
</div>
|
|
100
|
+
|
|
101
|
+
{/* Upgrade modal - shown when Scale is not enabled */}
|
|
102
|
+
{
|
|
103
|
+
hasMultipleVersions && !scaleEnabled && (
|
|
104
|
+
<div
|
|
105
|
+
id="upgrade-modal"
|
|
106
|
+
class="hidden fixed inset-0 z-50 bg-[rgb(var(--ec-page-bg)/0.8)] backdrop-blur-sm flex items-center justify-center"
|
|
107
|
+
>
|
|
108
|
+
<div class="bg-[rgb(var(--ec-card-bg))] border border-[rgb(var(--ec-page-border))] rounded-lg p-8 max-w-md mx-4 shadow-xl">
|
|
109
|
+
<div class="flex flex-col items-center text-center">
|
|
110
|
+
<div class="flex-shrink-0 mb-4 p-3 bg-[rgb(var(--ec-accent-subtle))] rounded-full">
|
|
111
|
+
<Rocket className="w-10 h-10 text-[rgb(var(--ec-accent))]" />
|
|
112
|
+
</div>
|
|
113
|
+
<h4 class="text-xl font-semibold text-[rgb(var(--ec-page-text))] mb-2">Upgrade to Scale</h4>
|
|
114
|
+
<p class="text-sm text-[rgb(var(--ec-page-text-muted))] mb-6">
|
|
115
|
+
Compare diagram versions side-by-side. Track changes across versions and maintain better documentation governance
|
|
116
|
+
with visual comparisons.
|
|
117
|
+
</p>
|
|
118
|
+
<div class="flex items-center gap-3">
|
|
119
|
+
<a
|
|
120
|
+
href="https://eventcatalog.cloud"
|
|
121
|
+
target="_blank"
|
|
122
|
+
rel="noopener noreferrer"
|
|
123
|
+
class="inline-flex items-center gap-2 px-4 py-2 text-sm font-medium text-[rgb(var(--ec-button-text))] bg-[rgb(var(--ec-accent))] rounded-md hover:opacity-90 transition-opacity"
|
|
124
|
+
>
|
|
125
|
+
Start 14-day free trial
|
|
126
|
+
<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
|
127
|
+
<path
|
|
128
|
+
stroke-linecap="round"
|
|
129
|
+
stroke-linejoin="round"
|
|
130
|
+
stroke-width="2"
|
|
131
|
+
d="M10 6H6a2 2 0 00-2 2v10a2 2 0 002 2h10a2 2 0 002-2v-4M14 4h6m0 0v6m0-6L10 14"
|
|
132
|
+
/>
|
|
133
|
+
</svg>
|
|
134
|
+
</a>
|
|
135
|
+
<button
|
|
136
|
+
id="upgrade-close-btn"
|
|
137
|
+
type="button"
|
|
138
|
+
class="px-4 py-2 text-sm font-medium text-[rgb(var(--ec-page-text-muted))] hover:text-[rgb(var(--ec-page-text))] transition-colors"
|
|
139
|
+
>
|
|
140
|
+
Maybe later
|
|
141
|
+
</button>
|
|
142
|
+
</div>
|
|
143
|
+
</div>
|
|
144
|
+
</div>
|
|
145
|
+
</div>
|
|
146
|
+
)
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
{/* Compare modal - shown when Scale is enabled */}
|
|
150
|
+
{
|
|
151
|
+
hasMultipleVersions && scaleEnabled && (
|
|
152
|
+
<div id="compare-modal" class="hidden fixed inset-0 z-50 bg-[rgb(var(--ec-page-bg))]">
|
|
153
|
+
<div class="flex items-center justify-between px-6 py-3 border-b border-[rgb(var(--ec-page-border))] bg-[rgb(var(--ec-card-bg))]">
|
|
154
|
+
<h2 class="text-sm font-semibold text-[rgb(var(--ec-page-text))]">Compare: {props.data.name}</h2>
|
|
155
|
+
<div class="flex items-center gap-6">
|
|
156
|
+
<div class="flex items-center gap-2">
|
|
157
|
+
<span class="text-xs text-[rgb(var(--ec-page-text-muted))]">Left:</span>
|
|
158
|
+
<select
|
|
159
|
+
id="compare-left-version"
|
|
160
|
+
class="appearance-none text-xs font-medium text-[rgb(var(--ec-input-text))] bg-[rgb(var(--ec-input-bg))] border border-[rgb(var(--ec-input-border))] rounded-md pl-2 pr-2 py-1 cursor-pointer"
|
|
161
|
+
>
|
|
162
|
+
{allVersions.map((version: string, index: number) => (
|
|
163
|
+
<option value={version} selected={index === 1 || allVersions.length === 1}>
|
|
164
|
+
v{version}
|
|
165
|
+
</option>
|
|
166
|
+
))}
|
|
167
|
+
</select>
|
|
168
|
+
</div>
|
|
169
|
+
<div class="flex items-center gap-2">
|
|
170
|
+
<span class="text-xs text-[rgb(var(--ec-page-text-muted))]">Right:</span>
|
|
171
|
+
<select
|
|
172
|
+
id="compare-right-version"
|
|
173
|
+
class="appearance-none text-xs font-medium text-[rgb(var(--ec-input-text))] bg-[rgb(var(--ec-input-bg))] border border-[rgb(var(--ec-input-border))] rounded-md pl-2 pr-2 py-1 cursor-pointer"
|
|
174
|
+
>
|
|
175
|
+
{allVersions.map((version: string, index: number) => (
|
|
176
|
+
<option value={version} selected={index === 0}>
|
|
177
|
+
v{version}
|
|
178
|
+
</option>
|
|
179
|
+
))}
|
|
180
|
+
</select>
|
|
181
|
+
</div>
|
|
182
|
+
<button
|
|
183
|
+
id="compare-close-btn"
|
|
184
|
+
type="button"
|
|
185
|
+
class="p-1.5 hover:bg-[rgb(var(--ec-content-hover))] rounded-md text-[rgb(var(--ec-icon-color))] hover:text-[rgb(var(--ec-icon-hover))]"
|
|
186
|
+
>
|
|
187
|
+
<X className="w-5 h-5" />
|
|
188
|
+
</button>
|
|
189
|
+
</div>
|
|
190
|
+
</div>
|
|
191
|
+
<div class="flex h-[calc(100vh-57px)]">
|
|
192
|
+
<div class="flex-1 border-r border-[rgb(var(--ec-page-border))]">
|
|
193
|
+
<iframe id="compare-left-frame" class="w-full h-full border-0" />
|
|
194
|
+
</div>
|
|
195
|
+
<div class="flex-1">
|
|
196
|
+
<iframe id="compare-right-frame" class="w-full h-full border-0" />
|
|
197
|
+
</div>
|
|
198
|
+
</div>
|
|
199
|
+
</div>
|
|
200
|
+
)
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
<ClientRouter />
|
|
204
|
+
</VisualiserLayout>
|
|
205
|
+
|
|
206
|
+
<script is:inline define:vars={{ config, baseUrl: import.meta.env.BASE_URL }}>
|
|
207
|
+
window.eventcatalog = window.eventcatalog || {};
|
|
208
|
+
window.eventcatalog.mermaid = config?.mermaid;
|
|
209
|
+
window.eventcatalog.baseUrl = baseUrl;
|
|
210
|
+
</script>
|
|
211
|
+
|
|
212
|
+
<script>
|
|
213
|
+
function initDiagramPage() {
|
|
214
|
+
// Version selector
|
|
215
|
+
const versionSelect = document.getElementById('version-select') as HTMLSelectElement;
|
|
216
|
+
if (versionSelect) {
|
|
217
|
+
versionSelect.onchange = () => {
|
|
218
|
+
window.location.href = versionSelect.value;
|
|
219
|
+
};
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
// Compare modal (Scale) and Upgrade modal (non-Scale)
|
|
223
|
+
const compareBtn = document.getElementById('compare-btn') as HTMLButtonElement;
|
|
224
|
+
const compareModal = document.getElementById('compare-modal');
|
|
225
|
+
const upgradeModal = document.getElementById('upgrade-modal');
|
|
226
|
+
const compareCloseBtn = document.getElementById('compare-close-btn');
|
|
227
|
+
const upgradeCloseBtn = document.getElementById('upgrade-close-btn');
|
|
228
|
+
const leftVersionSelect = document.getElementById('compare-left-version') as HTMLSelectElement;
|
|
229
|
+
const rightVersionSelect = document.getElementById('compare-right-version') as HTMLSelectElement;
|
|
230
|
+
const leftFrame = document.getElementById('compare-left-frame') as HTMLIFrameElement;
|
|
231
|
+
const rightFrame = document.getElementById('compare-right-frame') as HTMLIFrameElement;
|
|
232
|
+
|
|
233
|
+
function buildCompareUrl(version: string) {
|
|
234
|
+
// Parse diagramId from current URL: /diagrams/{id}/{version}
|
|
235
|
+
const pathParts = window.location.pathname.split('/');
|
|
236
|
+
const diagramsIndex = pathParts.indexOf('diagrams');
|
|
237
|
+
const diagramId = diagramsIndex !== -1 ? pathParts[diagramsIndex + 1] : '';
|
|
238
|
+
const baseUrl = (window as any).eventcatalog?.baseUrl || '/';
|
|
239
|
+
const base = baseUrl === '/' ? '' : baseUrl;
|
|
240
|
+
return `${window.location.origin}${base}/diagrams/${diagramId}/${version}/embed`;
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
function openCompareModal() {
|
|
244
|
+
if (!compareModal) return;
|
|
245
|
+
compareModal.classList.remove('hidden');
|
|
246
|
+
document.body.style.overflow = 'hidden';
|
|
247
|
+
if (leftFrame && leftVersionSelect) {
|
|
248
|
+
leftFrame.src = buildCompareUrl(leftVersionSelect.value);
|
|
249
|
+
}
|
|
250
|
+
if (rightFrame && rightVersionSelect) {
|
|
251
|
+
rightFrame.src = buildCompareUrl(rightVersionSelect.value);
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
function closeCompareModal() {
|
|
256
|
+
if (!compareModal) return;
|
|
257
|
+
compareModal.classList.add('hidden');
|
|
258
|
+
document.body.style.overflow = '';
|
|
259
|
+
if (leftFrame) leftFrame.src = '';
|
|
260
|
+
if (rightFrame) rightFrame.src = '';
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
function openUpgradeModal() {
|
|
264
|
+
if (!upgradeModal) return;
|
|
265
|
+
upgradeModal.classList.remove('hidden');
|
|
266
|
+
document.body.style.overflow = 'hidden';
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
function closeUpgradeModal() {
|
|
270
|
+
if (!upgradeModal) return;
|
|
271
|
+
upgradeModal.classList.add('hidden');
|
|
272
|
+
document.body.style.overflow = '';
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
// Handle compare button click - check if Scale is enabled
|
|
276
|
+
if (compareBtn) {
|
|
277
|
+
compareBtn.onclick = () => {
|
|
278
|
+
const scaleEnabled = compareBtn.dataset.scaleEnabled === 'true';
|
|
279
|
+
if (scaleEnabled) {
|
|
280
|
+
openCompareModal();
|
|
281
|
+
} else {
|
|
282
|
+
openUpgradeModal();
|
|
283
|
+
}
|
|
284
|
+
};
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
if (compareCloseBtn) compareCloseBtn.onclick = closeCompareModal;
|
|
288
|
+
if (upgradeCloseBtn) upgradeCloseBtn.onclick = closeUpgradeModal;
|
|
289
|
+
|
|
290
|
+
// Close upgrade modal when clicking outside the card
|
|
291
|
+
if (upgradeModal) {
|
|
292
|
+
upgradeModal.onclick = (e) => {
|
|
293
|
+
if (e.target === upgradeModal) {
|
|
294
|
+
closeUpgradeModal();
|
|
295
|
+
}
|
|
296
|
+
};
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
if (leftVersionSelect) {
|
|
300
|
+
leftVersionSelect.onchange = () => {
|
|
301
|
+
if (leftFrame) leftFrame.src = buildCompareUrl(leftVersionSelect.value);
|
|
302
|
+
};
|
|
303
|
+
}
|
|
304
|
+
if (rightVersionSelect) {
|
|
305
|
+
rightVersionSelect.onchange = () => {
|
|
306
|
+
if (rightFrame) rightFrame.src = buildCompareUrl(rightVersionSelect.value);
|
|
307
|
+
};
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
document.onkeydown = (e) => {
|
|
311
|
+
if (e.key === 'Escape') {
|
|
312
|
+
if (compareModal && !compareModal.classList.contains('hidden')) {
|
|
313
|
+
closeCompareModal();
|
|
314
|
+
}
|
|
315
|
+
if (upgradeModal && !upgradeModal.classList.contains('hidden')) {
|
|
316
|
+
closeUpgradeModal();
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
};
|
|
320
|
+
|
|
321
|
+
// Mermaid
|
|
322
|
+
renderMermaidDiagrams();
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
async function renderMermaidDiagrams() {
|
|
326
|
+
const graphs = document.getElementsByClassName('mermaid');
|
|
327
|
+
if (graphs.length === 0) return;
|
|
328
|
+
|
|
329
|
+
const { default: mermaid } = await import('mermaid');
|
|
330
|
+
const isDarkMode = document.documentElement.getAttribute('data-theme') === 'dark';
|
|
331
|
+
|
|
332
|
+
mermaid.initialize({
|
|
333
|
+
startOnLoad: false,
|
|
334
|
+
theme: isDarkMode ? 'dark' : 'default',
|
|
335
|
+
fontFamily: 'var(--sans-font)',
|
|
336
|
+
});
|
|
337
|
+
|
|
338
|
+
for (const graph of graphs) {
|
|
339
|
+
const content = graph.getAttribute('data-content');
|
|
340
|
+
if (!content) continue;
|
|
341
|
+
const id = 'mermaid-' + Math.round(Math.random() * 100000);
|
|
342
|
+
try {
|
|
343
|
+
const result = await mermaid.render(id, content);
|
|
344
|
+
graph.innerHTML = result.svg;
|
|
345
|
+
} catch (e) {
|
|
346
|
+
console.error('Mermaid error:', e);
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
// Run immediately and on page transitions
|
|
352
|
+
initDiagramPage();
|
|
353
|
+
document.addEventListener('astro:page-load', initDiagramPage);
|
|
354
|
+
</script>
|
|
355
|
+
|
|
356
|
+
<script>
|
|
357
|
+
import('pako').then(({ deflate }: any) => {
|
|
358
|
+
document.addEventListener('astro:page-load', () => {
|
|
359
|
+
const blocks = document.getElementsByClassName('plantuml');
|
|
360
|
+
if (blocks.length > 0) {
|
|
361
|
+
renderPlantUML(blocks, deflate);
|
|
362
|
+
}
|
|
363
|
+
});
|
|
364
|
+
|
|
365
|
+
function renderPlantUML(blocks: any, deflate: any) {
|
|
366
|
+
for (const block of blocks) {
|
|
367
|
+
const content = block.getAttribute('data-content');
|
|
368
|
+
if (!content) continue;
|
|
369
|
+
|
|
370
|
+
const encoded = encodePlantUML(content, deflate);
|
|
371
|
+
const img = document.createElement('img');
|
|
372
|
+
img.src = `https://www.plantuml.com/plantuml/svg/~1${encoded}`;
|
|
373
|
+
img.alt = 'PlantUML diagram';
|
|
374
|
+
img.loading = 'lazy';
|
|
375
|
+
block.innerHTML = '';
|
|
376
|
+
img.classList.add('mx-auto');
|
|
377
|
+
block.appendChild(img);
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
function encodePlantUML(text: any, deflate: any) {
|
|
382
|
+
const data = new TextEncoder().encode(text);
|
|
383
|
+
const compressed = deflate(data, { level: 9, to: 'Uint8Array' });
|
|
384
|
+
return encode64(compressed);
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
function encode64(data: any) {
|
|
388
|
+
const chars = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz-_';
|
|
389
|
+
let str = '';
|
|
390
|
+
const len = data.length;
|
|
391
|
+
for (let i = 0; i < len; i += 3) {
|
|
392
|
+
const b1 = data[i];
|
|
393
|
+
const b2 = i + 1 < len ? data[i + 1] : 0;
|
|
394
|
+
const b3 = i + 2 < len ? data[i + 2] : 0;
|
|
395
|
+
|
|
396
|
+
let c1 = b1 >> 2;
|
|
397
|
+
let c2 = ((b1 & 0x3) << 4) | (b2 >> 4);
|
|
398
|
+
let c3 = ((b2 & 0xf) << 2) | (b3 >> 6);
|
|
399
|
+
let c4 = b3 & 0x3f;
|
|
400
|
+
|
|
401
|
+
str += chars[c1] + chars[c2] + chars[c3] + chars[c4];
|
|
402
|
+
}
|
|
403
|
+
return str;
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
const graphs = document.getElementsByClassName('plantuml');
|
|
407
|
+
if (graphs.length > 0) {
|
|
408
|
+
renderPlantUML(graphs, deflate);
|
|
409
|
+
}
|
|
410
|
+
});
|
|
411
|
+
</script>
|