@eventcatalog/core 4.10.5 → 4.10.7

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.
Files changed (38) hide show
  1. package/dist/analytics/analytics.cjs +1 -1
  2. package/dist/analytics/analytics.js +2 -2
  3. package/dist/analytics/log-build.cjs +1 -1
  4. package/dist/analytics/log-build.js +3 -3
  5. package/dist/{chunk-U52FCZQ6.js → chunk-EG62NTWS.js} +7 -7
  6. package/dist/{chunk-RX2XDKHZ.js → chunk-RJYRPQOA.js} +1 -1
  7. package/dist/{chunk-JE6ZSCPU.js → chunk-TFALFJEC.js} +1 -1
  8. package/dist/{chunk-7PXZNQPR.js → chunk-YBRQCBWG.js} +1 -1
  9. package/dist/{chunk-NWWGCVSE.js → chunk-YJVD7UW3.js} +1 -1
  10. package/dist/{chunk-GLEQKW6W.js → chunk-Z7YK3QA3.js} +1 -1
  11. package/dist/constants.cjs +1 -1
  12. package/dist/constants.js +1 -1
  13. package/dist/eventcatalog.cjs +1 -1
  14. package/dist/eventcatalog.js +10 -10
  15. package/dist/federation/federate.js +5 -5
  16. package/dist/federation/source-provider.js +2 -2
  17. package/dist/generate.cjs +1 -1
  18. package/dist/generate.js +3 -3
  19. package/dist/utils/cli-logger.cjs +1 -1
  20. package/dist/utils/cli-logger.js +2 -2
  21. package/eventcatalog/src/components/MDX/MermaidFileLoader/MermaidFileLoader.astro +10 -3
  22. package/eventcatalog/src/components/SchemaExplorer/SchemaExplorer.tsx +2 -0
  23. package/eventcatalog/src/components/Tables/Discover/DiscoverTable.tsx +2 -0
  24. package/eventcatalog/src/layouts/BaseLayout.astro +10 -2
  25. package/eventcatalog/src/layouts/VerticalSideBarLayout.astro +15 -0
  26. package/eventcatalog/src/pages/diagrams/[id]/[version]/embed.astro +665 -325
  27. package/eventcatalog/src/pages/discover/[type]/index.astro +10 -0
  28. package/eventcatalog/src/pages/schemas/[type]/[id]/[version]/index.astro +6 -0
  29. package/eventcatalog/src/pages/schemas/explorer/index.astro +10 -0
  30. package/eventcatalog/src/pages/visualiser/[type]/[id]/[version]/index.astro +11 -13
  31. package/eventcatalog/src/pages/visualiser/graph/index.astro +18 -2
  32. package/eventcatalog/src/pages/visualiser/system-context-map/index.astro +11 -13
  33. package/eventcatalog/src/pages/visualiser/systems/[id]/[version]/context/index.astro +11 -13
  34. package/eventcatalog/src/remark-plugins/mermaid.ts +48 -1
  35. package/eventcatalog/src/stores/theme-store.ts +18 -0
  36. package/eventcatalog/src/utils/mermaid-zoom.ts +781 -404
  37. package/package.json +5 -6
  38. package/dist/{chunk-6K7XZAYI.js → chunk-A2RZR3U4.js} +3 -3
@@ -444,8 +444,18 @@ const title = `${currentTypeConfig.label} (${data.length})`;
444
444
  #eventcatalog-header {
445
445
  left: calc(var(--ec-vertical-nav-width, 14rem) + var(--ec-discover-sidebar-width, 320px)) !important;
446
446
  }
447
+ :root[data-embedded='true'] #discover-filter-sidebar {
448
+ display: none !important;
449
+ }
450
+ :root[data-embedded='true'] #discover-results {
451
+ margin-left: 0 !important;
452
+ }
453
+ :root[data-embedded='true'] #discover-page {
454
+ height: 100dvh !important;
455
+ }
447
456
  </style>
448
457
  <main
458
+ id="discover-page"
449
459
  class="ml-0 flex h-full min-h-0 flex-col overflow-hidden bg-[rgb(var(--ec-page-bg))]"
450
460
  style={`--ec-discover-sidebar-width: 320px; margin-left: calc(var(--ec-app-content-padding-left, 5rem) * -1); margin-right: calc(var(--ec-app-content-padding-right, 5rem) * -1); height: calc(100dvh - 60px);`}
451
461
  >
@@ -130,8 +130,14 @@ const apiAccessEnabled = isEventCatalogScaleEnabled();
130
130
  ---
131
131
 
132
132
  <VerticalSideBarLayout title={pageTitle}>
133
+ <style is:global>
134
+ :root[data-embedded='true'] #schema-detail-page {
135
+ height: 100dvh !important;
136
+ }
137
+ </style>
133
138
  {/* The schema viewer is an app-style surface: pull it out of the content gutter so it sits flush against the sidebar. */}
134
139
  <div
140
+ id="schema-detail-page"
135
141
  class="h-[calc(100vh-4rem)] overflow-hidden flex flex-col"
136
142
  style="margin-left: calc(var(--ec-app-content-padding-left, 5rem) * -1); margin-right: calc(var(--ec-app-content-padding-right, 5rem) * -1);"
137
143
  >
@@ -17,8 +17,18 @@ const apiAccessEnabled = isEventCatalogScaleEnabled();
17
17
  #eventcatalog-header {
18
18
  left: calc(var(--ec-vertical-nav-width, 14rem) + var(--ec-schema-sidebar-width, 360px)) !important;
19
19
  }
20
+ :root[data-embedded='true'] #schema-explorer-sidebar {
21
+ display: none !important;
22
+ }
23
+ :root[data-embedded='true'] #schema-explorer-content {
24
+ margin-left: 0 !important;
25
+ }
26
+ :root[data-embedded='true'] #schema-explorer-page {
27
+ height: 100dvh !important;
28
+ }
20
29
  </style>
21
30
  <main
31
+ id="schema-explorer-page"
22
32
  class="min-h-0 overflow-hidden bg-[rgb(var(--ec-page-bg))]"
23
33
  style={`--ec-schema-sidebar-width: 360px; margin-left: calc(var(--ec-app-content-padding-left, 5rem) * -1); margin-right: calc(var(--ec-app-content-padding-right, 5rem) * -1); height: calc(100dvh - 60px);`}
24
34
  >
@@ -20,9 +20,9 @@ const {
20
20
  ---
21
21
 
22
22
  <VisualiserLayout title={`Visualiser | ${props.data.name} (${props.collection})`} description={props.data.summary}>
23
- <div class="p-2">
23
+ <div id="visualiser-page" class="p-2">
24
24
  <div
25
- class="h-[calc(100vh-5rem)] w-full relative border border-[rgb(var(--ec-page-border))]"
25
+ class="visualiser-viewport h-[calc(100vh-5rem)] w-full relative border border-[rgb(var(--ec-page-border))]"
26
26
  id={`${id}-portal`}
27
27
  transition:name="visualiser-graph"
28
28
  >
@@ -45,15 +45,13 @@ const {
45
45
  <ClientRouter />
46
46
  </VisualiserLayout>
47
47
 
48
- <script define:vars={{ id }}>
49
- document.addEventListener('DOMContentLoaded', () => {
50
- const urlSearchParams = new URLSearchParams(window.location.search);
51
- const params = Object.fromEntries(urlSearchParams.entries());
52
- const embeded = params.embed === 'true' ? true : false;
53
- const viewport = document.getElementById(`${id}-portal`);
48
+ <style is:global>
49
+ html[data-embedded='true'] #visualiser-page {
50
+ box-sizing: border-box;
51
+ height: 100vh;
52
+ }
54
53
 
55
- if (embeded) {
56
- viewport.style.height = 'calc(100vh - 30px)';
57
- }
58
- });
59
- </script>
54
+ html[data-embedded='true'] #visualiser-page .visualiser-viewport {
55
+ height: 100%;
56
+ }
57
+ </style>
@@ -16,9 +16,25 @@ const { nodes: wireNodes, links: wireLinks, linkLabels } = toCatalogForceGraphWi
16
16
  ---
17
17
 
18
18
  <VisualiserLayout title="Visualiser | Architecture Graph" description="Force-directed graph of every resource in the catalog">
19
- <div class="m-4">
20
- <div class="h-[calc(100vh-130px)] w-full relative border border-[rgb(var(--ec-page-border))] rounded-md overflow-hidden">
19
+ <div id="architecture-graph-page" class="m-4">
20
+ <div
21
+ id="architecture-graph-container"
22
+ class="h-[calc(100vh-130px)] w-full relative border border-[rgb(var(--ec-page-border))] rounded-md overflow-hidden"
23
+ >
21
24
  <CatalogForceGraph nodes={wireNodes} links={wireLinks} linkLabels={linkLabels} client:only="react" />
22
25
  </div>
23
26
  </div>
24
27
  </VisualiserLayout>
28
+
29
+ <style is:global>
30
+ html[data-embedded='true'] #architecture-graph-page {
31
+ box-sizing: border-box;
32
+ height: 100vh;
33
+ margin: 0;
34
+ padding: 1rem;
35
+ }
36
+
37
+ html[data-embedded='true'] #architecture-graph-container {
38
+ height: 100%;
39
+ }
40
+ </style>
@@ -7,9 +7,9 @@ const id = 'system-context-map';
7
7
  ---
8
8
 
9
9
  <VisualiserLayout title={`Visualiser | System context map`}>
10
- <div class="p-2">
10
+ <div id="system-context-map-page" class="p-2">
11
11
  <div
12
- class="h-[calc(100vh-5rem)] w-full relative border border-[rgb(var(--ec-page-border))]"
12
+ class="system-context-map-viewport h-[calc(100vh-5rem)] w-full relative border border-[rgb(var(--ec-page-border))]"
13
13
  id={`${id}-portal`}
14
14
  transition:name="visualiser-graph"
15
15
  >
@@ -27,15 +27,13 @@ const id = 'system-context-map';
27
27
  <ClientRouter />
28
28
  </VisualiserLayout>
29
29
 
30
- <script define:vars={{ id }}>
31
- document.addEventListener('DOMContentLoaded', () => {
32
- const urlSearchParams = new URLSearchParams(window.location.search);
33
- const params = Object.fromEntries(urlSearchParams.entries());
34
- const embeded = params.embed === 'true' ? true : false;
35
- const viewport = document.getElementById(`${id}-portal`);
30
+ <style is:global>
31
+ html[data-embedded='true'] #system-context-map-page {
32
+ box-sizing: border-box;
33
+ height: 100vh;
34
+ }
36
35
 
37
- if (embeded && viewport) {
38
- viewport.style.height = 'calc(100vh - 30px)';
39
- }
40
- });
41
- </script>
36
+ html[data-embedded='true'] #system-context-map-page .system-context-map-viewport {
37
+ height: 100%;
38
+ }
39
+ </style>
@@ -17,9 +17,9 @@ const {
17
17
  ---
18
18
 
19
19
  <VisualiserLayout title={`Visualiser | ${props.data.name} - System Context`} description={props.data.summary}>
20
- <div class="p-2">
20
+ <div id="system-context-map-page" class="p-2">
21
21
  <div
22
- class="h-[calc(100vh-5rem)] w-full relative border border-[rgb(var(--ec-page-border))]"
22
+ class="system-context-map-viewport h-[calc(100vh-5rem)] w-full relative border border-[rgb(var(--ec-page-border))]"
23
23
  id={`${id}-portal`}
24
24
  transition:name="visualiser-graph"
25
25
  >
@@ -37,15 +37,13 @@ const {
37
37
  <ClientRouter />
38
38
  </VisualiserLayout>
39
39
 
40
- <script define:vars={{ id }}>
41
- document.addEventListener('DOMContentLoaded', () => {
42
- const urlSearchParams = new URLSearchParams(window.location.search);
43
- const params = Object.fromEntries(urlSearchParams.entries());
44
- const embeded = params.embed === 'true' ? true : false;
45
- const viewport = document.getElementById(`${id}-portal`);
40
+ <style is:global>
41
+ html[data-embedded='true'] #system-context-map-page {
42
+ box-sizing: border-box;
43
+ height: 100vh;
44
+ }
46
45
 
47
- if (embeded) {
48
- viewport.style.height = 'calc(100vh - 30px)';
49
- }
50
- });
51
- </script>
46
+ html[data-embedded='true'] #system-context-map-page .system-context-map-viewport {
47
+ height: 100%;
48
+ }
49
+ </style>
@@ -11,15 +11,62 @@ const escapeMap: Record<string, string> = {
11
11
 
12
12
  const escapeHtml = (str: string) => str.replace(/[&<>"']/g, (c) => escapeMap[c]);
13
13
 
14
+ const PLACEMENTS = ['top-left', 'top-right', 'bottom-left', 'bottom-right'] as const;
15
+
16
+ export interface MermaidCodeBlockOptions {
17
+ /** Position of the interactive controls */
18
+ placement?: (typeof PLACEMENTS)[number];
19
+ /** Force the interactive controls on or off */
20
+ actions?: boolean;
21
+ }
22
+
23
+ /**
24
+ * Parses options from the code fence meta string, e.g.
25
+ *
26
+ * ```mermaid placement="top-left" actions={false}
27
+ *
28
+ * Supports `placement="..."` / `placement='...'` and `actions={true|false}` / `actions=true|false`.
29
+ */
30
+ export function parseMermaidMeta(meta: string | null | undefined): MermaidCodeBlockOptions {
31
+ const options: MermaidCodeBlockOptions = {};
32
+ if (!meta) return options;
33
+
34
+ const placementMatch = meta.match(/placement=(?:["']([^"']+)["']|\{["']([^"']+)["']\})/);
35
+ const placement = placementMatch?.[1] ?? placementMatch?.[2];
36
+ if (placement && (PLACEMENTS as readonly string[]).includes(placement)) {
37
+ options.placement = placement as MermaidCodeBlockOptions['placement'];
38
+ }
39
+
40
+ const actionsMatch = meta.match(/actions=\{?(true|false)\}?/);
41
+ if (actionsMatch) {
42
+ options.actions = actionsMatch[1] === 'true';
43
+ }
44
+
45
+ return options;
46
+ }
47
+
48
+ /**
49
+ * Builds the `data-*` attributes used by the client-side renderer to configure the controls
50
+ */
51
+ export function buildControlAttributes(options: MermaidCodeBlockOptions): string {
52
+ const attributes: string[] = [];
53
+ if (options.placement) attributes.push(`data-placement="${options.placement}"`);
54
+ if (options.actions !== undefined) attributes.push(`data-actions="${options.actions}"`);
55
+ return attributes.length > 0 ? ` ${attributes.join(' ')}` : '';
56
+ }
57
+
14
58
  export const mermaid: RemarkPlugin<[]> = () => (tree) => {
15
59
  visit(tree, 'code', (node) => {
16
60
  if (node.lang !== 'mermaid') return;
17
61
 
62
+ // @ts-ignore meta is present on code nodes
63
+ const controlAttributes = buildControlAttributes(parseMermaidMeta(node.meta));
64
+
18
65
  // @ts-ignore test
19
66
  node.type = 'html';
20
67
  node.value = `
21
68
  <div class="mermaid-block pb-4">
22
- <div class="mermaid border border-[rgb(var(--ec-page-border))] rounded-lg p-1" data-content="${escapeHtml(node.value)}">
69
+ <div class="mermaid border border-[rgb(var(--ec-page-border))] rounded-lg p-1" data-content="${escapeHtml(node.value)}"${controlAttributes}>
23
70
  <p class="text-[rgb(var(--ec-page-text-muted))]">Loading graph...</p>
24
71
  </div>
25
72
  </div>
@@ -14,6 +14,15 @@ const getDefaultTheme = (): Theme => {
14
14
  return DEFAULT_THEME;
15
15
  };
16
16
 
17
+ const getEmbeddedTheme = (): Theme | null => {
18
+ if (typeof window === 'undefined') return null;
19
+
20
+ const params = new URLSearchParams(window.location.search);
21
+ const requestedTheme = params.get('theme');
22
+ const embedded = params.get('embed') === 'true';
23
+ return embedded && (requestedTheme === 'light' || requestedTheme === 'dark') ? requestedTheme : null;
24
+ };
25
+
17
26
  // Apply theme to document via data-theme attribute
18
27
  const applyTheme = (theme: Theme) => {
19
28
  if (typeof document !== 'undefined') {
@@ -25,6 +34,13 @@ const applyTheme = (theme: Theme) => {
25
34
  const initStore = () => {
26
35
  if (typeof window !== 'undefined') {
27
36
  try {
37
+ const embeddedTheme = getEmbeddedTheme();
38
+ if (embeddedTheme) {
39
+ themeStore.set(embeddedTheme);
40
+ applyTheme(embeddedTheme);
41
+ return;
42
+ }
43
+
28
44
  const stored = localStorage.getItem(THEME_KEY) as Theme | null;
29
45
  if (stored && (stored === 'light' || stored === 'dark')) {
30
46
  // User has explicitly chosen a theme, use that
@@ -49,6 +65,8 @@ if (typeof window !== 'undefined') {
49
65
  // Listen for system preference changes
50
66
  if (window.matchMedia) {
51
67
  window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', (e) => {
68
+ if (getEmbeddedTheme()) return;
69
+
52
70
  // Only follow system preference if user hasn't explicitly set a theme
53
71
  const stored = localStorage.getItem(THEME_KEY);
54
72
  if (!stored) {