@eventcatalog/core 2.30.7 → 2.31.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/README.md +3 -2
- package/dist/analytics/analytics.cjs +1 -1
- package/dist/analytics/analytics.js +2 -2
- package/dist/analytics/log-build.cjs +9 -3
- package/dist/analytics/log-build.d.cts +4 -1
- package/dist/analytics/log-build.d.ts +4 -1
- package/dist/analytics/log-build.js +3 -3
- package/dist/{chunk-SUJLBNZK.js → chunk-4S3UNXH2.js} +1 -1
- package/dist/{chunk-HINNLTBH.js → chunk-D7LV5JLL.js} +9 -3
- package/dist/{chunk-EFSBN3ZZ.js → chunk-I6OFOESY.js} +1 -1
- package/dist/{chunk-XMDPVKIJ.js → chunk-NJGR7XUU.js} +44 -1
- package/dist/constants.cjs +1 -1
- package/dist/constants.js +1 -1
- package/dist/eventcatalog.cjs +74 -14
- package/dist/eventcatalog.config.d.cts +28 -0
- package/dist/eventcatalog.config.d.ts +28 -0
- package/dist/eventcatalog.js +29 -16
- package/dist/features.cjs +46 -2
- package/dist/features.d.cts +2 -1
- package/dist/features.d.ts +2 -1
- package/dist/features.js +5 -3
- package/eventcatalog/public/images/custom-docs-placeholder.png +0 -0
- package/eventcatalog/src/components/MDX/NodeGraph/Nodes/Custom.tsx +0 -2
- package/eventcatalog/src/components/MDX/Steps/Step.astro +1 -1
- package/eventcatalog/src/components/MDX/Steps/Steps.astro +15 -0
- package/eventcatalog/src/components/SideBars/FlowSideBar.astro +75 -0
- package/eventcatalog/src/components/SideNav/CustomDocsNav/CustomDocsNavWrapper.tsx +11 -0
- package/eventcatalog/src/components/SideNav/CustomDocsNav/components/NestedItem.tsx +183 -0
- package/eventcatalog/src/components/SideNav/CustomDocsNav/components/NoResultsFound.tsx +21 -0
- package/eventcatalog/src/components/SideNav/CustomDocsNav/index.tsx +250 -0
- package/eventcatalog/src/components/SideNav/CustomDocsNav/types.ts +29 -0
- package/eventcatalog/src/components/SideNav/CustomDocsNav.astro +9 -0
- package/eventcatalog/src/components/SideNav/TreeView/getTreeView.ts +2 -2
- package/eventcatalog/src/content.config.ts +15 -24
- package/eventcatalog/src/enterprise/collections/custom-pages.ts +19 -0
- package/eventcatalog/src/enterprise/custom-documentation/collection.ts +16 -0
- package/eventcatalog/src/enterprise/custom-documentation/components/CustomDocsNav/CustomDocsNavWrapper.tsx +11 -0
- package/eventcatalog/src/enterprise/custom-documentation/components/CustomDocsNav/components/NestedItem.tsx +183 -0
- package/eventcatalog/src/enterprise/custom-documentation/components/CustomDocsNav/components/NoResultsFound.tsx +21 -0
- package/eventcatalog/src/enterprise/custom-documentation/components/CustomDocsNav/index.tsx +250 -0
- package/eventcatalog/src/enterprise/custom-documentation/components/CustomDocsNav/types.ts +29 -0
- package/eventcatalog/src/enterprise/custom-documentation/pages/index.astro +389 -0
- package/eventcatalog/src/enterprise/custom-documentation/utils/custom-docs.ts +118 -0
- package/eventcatalog/src/layouts/VerticalSideBarLayout.astro +58 -9
- package/eventcatalog/src/pages/docs/[type]/[id]/[version]/asyncapi/index.astro +23 -3
- package/eventcatalog/src/pages/docs/[type]/[id]/[version]/changelog/index.astro +13 -3
- package/eventcatalog/src/pages/docs/[type]/[id]/[version]/index.astro +134 -17
- package/eventcatalog/src/pages/docs/[type]/[id]/[version]/spec/index.astro +21 -3
- package/eventcatalog/src/pages/docs/[type]/[id]/language/[dictionaryId]/index.astro +1 -1
- package/eventcatalog/src/pages/docs/[type]/[id]/language.astro +1 -1
- package/eventcatalog/src/pages/docs/custom/[...path]/index.astro +260 -0
- package/eventcatalog/src/pages/docs/teams/[id]/index.astro +5 -3
- package/eventcatalog/src/pages/docs/users/[id]/index.astro +9 -4
- package/eventcatalog/src/pages/pro/index.astro +272 -0
- package/eventcatalog/src/shared-collections.ts +25 -0
- package/eventcatalog/src/types/index.ts +1 -1
- package/eventcatalog/src/utils/eventcatalog-config/catalog.ts +12 -1
- package/eventcatalog/src/utils/feature.ts +5 -0
- package/eventcatalog/src/utils/page-loaders/page-data-loader.ts +2 -0
- package/package.json +1 -1
|
@@ -3,7 +3,14 @@ import Footer from '@layouts/Footer.astro';
|
|
|
3
3
|
|
|
4
4
|
import type { PageTypes } from '@types';
|
|
5
5
|
import { getChangeLogs } from '@utils/collections/changelogs';
|
|
6
|
-
import {
|
|
6
|
+
import {
|
|
7
|
+
RectangleGroupIcon,
|
|
8
|
+
ServerIcon,
|
|
9
|
+
BoltIcon,
|
|
10
|
+
ChatBubbleLeftIcon,
|
|
11
|
+
MagnifyingGlassIcon,
|
|
12
|
+
QueueListIcon,
|
|
13
|
+
} from '@heroicons/react/24/outline';
|
|
7
14
|
import { pageDataLoader } from '@utils/page-loaders/page-data-loader';
|
|
8
15
|
import { render, getEntry } from 'astro:content';
|
|
9
16
|
import 'diff2html/bundles/css/diff2html.min.css';
|
|
@@ -15,7 +22,7 @@ import VerticalSideBarLayout from '@layouts/VerticalSideBarLayout.astro';
|
|
|
15
22
|
import { ClientRouter } from 'astro:transitions';
|
|
16
23
|
|
|
17
24
|
export async function getStaticPaths() {
|
|
18
|
-
const itemTypes: PageTypes[] = ['events', 'commands', 'queries', 'services', 'domains'];
|
|
25
|
+
const itemTypes: PageTypes[] = ['events', 'commands', 'queries', 'services', 'domains', 'flows'];
|
|
19
26
|
const allItems = await Promise.all(itemTypes.map((type) => pageDataLoader[type]()));
|
|
20
27
|
|
|
21
28
|
return allItems.flatMap((items, index) =>
|
|
@@ -44,7 +51,7 @@ const logs = await getChangeLogs(props);
|
|
|
44
51
|
const { data } = props;
|
|
45
52
|
const latestVersion = data.latestVersion;
|
|
46
53
|
|
|
47
|
-
const renderedLogs =
|
|
54
|
+
const renderedLogs = logs.map(async (log) => {
|
|
48
55
|
const logEntry = await getEntry('changelogs', log.id);
|
|
49
56
|
const { Content } = await render(logEntry as any);
|
|
50
57
|
return {
|
|
@@ -104,6 +111,9 @@ const getBadge = () => {
|
|
|
104
111
|
class: 'text-yellow-400',
|
|
105
112
|
};
|
|
106
113
|
}
|
|
114
|
+
if (props.collection === 'flows') {
|
|
115
|
+
return { backgroundColor: 'teal', textColor: 'teal', content: 'Flow', icon: QueueListIcon, class: 'text-teal-400' };
|
|
116
|
+
}
|
|
107
117
|
};
|
|
108
118
|
|
|
109
119
|
const badges = [getBadge()];
|
|
@@ -11,12 +11,12 @@ import ServiceSideBar from '@components/SideBars/ServiceSideBar.astro';
|
|
|
11
11
|
import MessageSideBar from '@components/SideBars/MessageSideBar.astro';
|
|
12
12
|
import DomainSideBar from '@components/SideBars/DomainSideBar.astro';
|
|
13
13
|
import ChannelSideBar from '@components/SideBars/ChannelSideBar.astro';
|
|
14
|
+
import FlowSideBar from '@components/SideBars/FlowSideBar.astro';
|
|
14
15
|
|
|
15
16
|
import { QueueListIcon, RectangleGroupIcon, ServerIcon, BoltIcon, ChatBubbleLeftIcon } from '@heroicons/react/24/outline';
|
|
16
17
|
import type { PageTypes } from '@types';
|
|
17
18
|
|
|
18
19
|
import { buildUrl } from '@utils/url-builder';
|
|
19
|
-
import { getFlows } from '@utils/collections/flows';
|
|
20
20
|
import { pageDataLoader } from '@utils/page-loaders/page-data-loader';
|
|
21
21
|
import { ClientRouter } from 'astro:transitions';
|
|
22
22
|
import { render } from 'astro:content';
|
|
@@ -24,16 +24,9 @@ import { ArrowsRightLeftIcon } from '@heroicons/react/20/solid';
|
|
|
24
24
|
|
|
25
25
|
import config from '@config';
|
|
26
26
|
|
|
27
|
-
type PageTypesWithFlows = PageTypes | 'flows';
|
|
28
|
-
|
|
29
27
|
export async function getStaticPaths() {
|
|
30
|
-
const
|
|
31
|
-
|
|
32
|
-
flows: getFlows,
|
|
33
|
-
};
|
|
34
|
-
|
|
35
|
-
const itemTypes: PageTypesWithFlows[] = ['events', 'commands', 'queries', 'services', 'domains', 'flows', 'channels'];
|
|
36
|
-
const allItems = await Promise.all(itemTypes.map((type) => loaders[type]()));
|
|
28
|
+
const itemTypes: PageTypes[] = ['events', 'commands', 'queries', 'services', 'domains', 'flows', 'channels'];
|
|
29
|
+
const allItems = await Promise.all(itemTypes.map((type) => pageDataLoader[type]()));
|
|
37
30
|
|
|
38
31
|
return allItems.flatMap((items, index) =>
|
|
39
32
|
items.map((item) => ({
|
|
@@ -123,10 +116,19 @@ const getSpecificationBadges = () => {
|
|
|
123
116
|
};
|
|
124
117
|
|
|
125
118
|
const badges = [getBadge(), ...contentBadges, ...getSpecificationBadges()];
|
|
119
|
+
|
|
120
|
+
// Index only the latest version
|
|
121
|
+
const pagefindAttributes =
|
|
122
|
+
props.data.version === props.data.latestVersion
|
|
123
|
+
? {
|
|
124
|
+
'data-pagefind-body': '',
|
|
125
|
+
'data-pagefind-meta': `title:${pageTitle}`,
|
|
126
|
+
}
|
|
127
|
+
: {};
|
|
126
128
|
---
|
|
127
129
|
|
|
128
130
|
<VerticalSideBarLayout title={pageTitle} description={props.data.summary}>
|
|
129
|
-
<main class="flex sm:px-8 docs-layout h-full">
|
|
131
|
+
<main class="flex sm:px-8 docs-layout h-full" {...pagefindAttributes}>
|
|
130
132
|
<div class="flex docs-layout w-full">
|
|
131
133
|
<div class="w-full lg:mr-2 pr-8 overflow-y-auto py-8">
|
|
132
134
|
<div class="border-b border-gray-200 flex justify-between items-start md:pb-2">
|
|
@@ -159,7 +161,7 @@ const badges = [getBadge(), ...contentBadges, ...getSpecificationBadges()];
|
|
|
159
161
|
</div>
|
|
160
162
|
</div>
|
|
161
163
|
|
|
162
|
-
<div>
|
|
164
|
+
<div data-pagefind-ignore>
|
|
163
165
|
{
|
|
164
166
|
props.data.version !== props.data.latestVersion && (
|
|
165
167
|
<div class="rounded-md bg-gradient-to-r from-purple-50 to-purple-100 p-4 not-prose my-4">
|
|
@@ -198,7 +200,7 @@ const badges = [getBadge(), ...contentBadges, ...getSpecificationBadges()];
|
|
|
198
200
|
<div class="prose prose-md py-4 w-full">
|
|
199
201
|
<Content components={components(props)} />
|
|
200
202
|
</div>
|
|
201
|
-
<div>
|
|
203
|
+
<div data-pagefind-ignore>
|
|
202
204
|
<!-- @ts-ignore -->
|
|
203
205
|
<SchemaViewer id={props.data.id} catalog={props.catalog} filePath={props.filePath} />
|
|
204
206
|
<NodeGraph
|
|
@@ -215,7 +217,7 @@ const badges = [getBadge(), ...contentBadges, ...getSpecificationBadges()];
|
|
|
215
217
|
</div>
|
|
216
218
|
<Footer />
|
|
217
219
|
</div>
|
|
218
|
-
<aside class="hidden lg:block sticky top-0 pb-10 w-96 overflow-y-auto py-2">
|
|
220
|
+
<aside class="hidden lg:block sticky top-0 pb-10 w-96 overflow-y-auto py-2" data-pagefind-ignore>
|
|
219
221
|
<!-- @ts-ignore -->
|
|
220
222
|
{
|
|
221
223
|
(props?.collection === 'events' || props.collection === 'commands' || props.collection === 'queries') && (
|
|
@@ -225,6 +227,7 @@ const badges = [getBadge(), ...contentBadges, ...getSpecificationBadges()];
|
|
|
225
227
|
{props?.collection === 'services' && <ServiceSideBar service={props} />}
|
|
226
228
|
{props?.collection === 'domains' && <DomainSideBar domain={props} />}
|
|
227
229
|
{props?.collection === 'channels' && <ChannelSideBar channel={props} />}
|
|
230
|
+
{props?.collection === 'flows' && <FlowSideBar flow={props} />}
|
|
228
231
|
</aside>
|
|
229
232
|
</div>
|
|
230
233
|
<ClientRouter />
|
|
@@ -265,12 +268,126 @@ const badges = [getBadge(), ...contentBadges, ...getSpecificationBadges()];
|
|
|
265
268
|
if (document.getElementsByClassName('mermaid').length > 0) {
|
|
266
269
|
renderDiagrams(graphs);
|
|
267
270
|
}
|
|
271
|
+
|
|
272
|
+
// Set up TOC highlighting and scrolling
|
|
273
|
+
setupTOCHighlighting();
|
|
268
274
|
});
|
|
269
275
|
|
|
270
276
|
/**
|
|
271
|
-
*
|
|
277
|
+
* Setup TOC highlighting and scrolling
|
|
278
|
+
*/
|
|
279
|
+
function setupTOCHighlighting() {
|
|
280
|
+
// Check if there's a sidebar with navigation
|
|
281
|
+
const sidebarNav = document.querySelector('aside nav');
|
|
282
|
+
if (!sidebarNav) return;
|
|
283
|
+
|
|
284
|
+
const observerOptions = {
|
|
285
|
+
rootMargin: '0px 0px -40% 0px',
|
|
286
|
+
threshold: 0.1,
|
|
287
|
+
};
|
|
288
|
+
|
|
289
|
+
// Flag to temporarily disable observer after click
|
|
290
|
+
let observerPaused = false;
|
|
291
|
+
|
|
292
|
+
/**
|
|
293
|
+
* Highlights a TOC item and scrolls it into view
|
|
294
|
+
* @param {string} id - The ID of the heading to highlight in the TOC
|
|
295
|
+
*/
|
|
296
|
+
function highlightTocItem(id) {
|
|
297
|
+
// Remove active class from all links
|
|
298
|
+
document.querySelectorAll('.active-toc-item').forEach((link) => {
|
|
299
|
+
link.classList.remove('active-toc-item', 'text-primary-600', 'font-medium');
|
|
300
|
+
link.classList.add('text-gray-400');
|
|
301
|
+
});
|
|
302
|
+
|
|
303
|
+
// Add active class to current link
|
|
304
|
+
const tocLink = document.querySelector(`aside nav a[href="#${id}"]`);
|
|
305
|
+
if (tocLink) {
|
|
306
|
+
tocLink.classList.add('active-toc-item', 'text-primary-600', 'font-medium');
|
|
307
|
+
tocLink.classList.remove('text-gray-400');
|
|
308
|
+
|
|
309
|
+
// Scroll the highlighted item into view with a small delay to ensure DOM updates first
|
|
310
|
+
setTimeout(() => {
|
|
311
|
+
tocLink.scrollIntoView({ behavior: 'smooth', block: 'nearest', inline: 'nearest' });
|
|
312
|
+
}, 10);
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
// Set up the intersection observer for scrolling
|
|
317
|
+
const observer = new IntersectionObserver((entries) => {
|
|
318
|
+
// If observer is paused, don't process entries
|
|
319
|
+
if (observerPaused) return;
|
|
320
|
+
|
|
321
|
+
entries.forEach((entry) => {
|
|
322
|
+
try {
|
|
323
|
+
const id = entry.target.getAttribute('id');
|
|
324
|
+
if (entry.isIntersecting && id) {
|
|
325
|
+
highlightTocItem(id);
|
|
326
|
+
}
|
|
327
|
+
} catch (entryError) {
|
|
328
|
+
console.error('Error processing intersection entry:', entryError);
|
|
329
|
+
}
|
|
330
|
+
});
|
|
331
|
+
}, observerOptions);
|
|
332
|
+
|
|
333
|
+
// Find all headings in the content area
|
|
334
|
+
const prose = document.querySelector('.prose');
|
|
335
|
+
if (!prose) return;
|
|
336
|
+
|
|
337
|
+
// First try to find headings with IDs
|
|
338
|
+
const headings = prose.querySelectorAll('h1[id], h2[id], h3[id]');
|
|
339
|
+
|
|
340
|
+
if (headings.length > 0) {
|
|
341
|
+
headings.forEach((heading) => {
|
|
342
|
+
observer.observe(heading);
|
|
343
|
+
});
|
|
344
|
+
} else {
|
|
345
|
+
// Fallback: If no headings with IDs found, attach IDs to them
|
|
346
|
+
const allHeadings = prose.querySelectorAll('h1, h2, h3');
|
|
347
|
+
|
|
348
|
+
allHeadings.forEach((heading) => {
|
|
349
|
+
// Only add ID if it doesn't exist
|
|
350
|
+
if (!heading.id) {
|
|
351
|
+
const text = heading.textContent || '';
|
|
352
|
+
const slug = text
|
|
353
|
+
.toLowerCase()
|
|
354
|
+
.replace(/[^\w\s-]/g, '')
|
|
355
|
+
.replace(/\s+/g, '-');
|
|
356
|
+
heading.id = slug;
|
|
357
|
+
}
|
|
358
|
+
observer.observe(heading);
|
|
359
|
+
});
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
// Add click event listeners to all TOC links
|
|
363
|
+
const tocLinks = document.querySelectorAll('aside nav a[href^="#"]');
|
|
364
|
+
tocLinks.forEach((link) => {
|
|
365
|
+
link.addEventListener('click', (e) => {
|
|
366
|
+
// Get the ID from the href attribute
|
|
367
|
+
const hrefAttr = link.getAttribute('href');
|
|
368
|
+
if (!hrefAttr) return;
|
|
369
|
+
|
|
370
|
+
const id = hrefAttr.substring(1);
|
|
371
|
+
|
|
372
|
+
// Highlight the clicked item
|
|
373
|
+
highlightTocItem(id);
|
|
374
|
+
|
|
375
|
+
// Temporarily pause the observer to prevent immediate highlighting changes
|
|
376
|
+
observerPaused = true;
|
|
377
|
+
|
|
378
|
+
// Resume the observer after a delay
|
|
379
|
+
setTimeout(() => {
|
|
380
|
+
observerPaused = false;
|
|
381
|
+
}, 500);
|
|
382
|
+
});
|
|
383
|
+
});
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
/**
|
|
387
|
+
* Renders mermaid diagrams in the page
|
|
388
|
+
* @param {HTMLCollectionOf<HTMLElement>} graphs - The collection of mermaid graph elements
|
|
272
389
|
*/
|
|
273
|
-
async function renderDiagrams(graphs
|
|
390
|
+
async function renderDiagrams(graphs) {
|
|
274
391
|
const { default: mermaid } = await import('mermaid');
|
|
275
392
|
|
|
276
393
|
if (window.eventcatalog.mermaid) {
|
|
@@ -278,7 +395,7 @@ const badges = [getBadge(), ...contentBadges, ...getSpecificationBadges()];
|
|
|
278
395
|
const { iconPacks = [] } = window.eventcatalog.mermaid ?? {};
|
|
279
396
|
|
|
280
397
|
if (iconPacks.length > 0) {
|
|
281
|
-
const iconPacksToRegister = iconPacks.map((name
|
|
398
|
+
const iconPacksToRegister = iconPacks.map((name) => {
|
|
282
399
|
return {
|
|
283
400
|
name,
|
|
284
401
|
icons,
|
|
@@ -35,7 +35,7 @@ export async function getStaticPaths() {
|
|
|
35
35
|
}
|
|
36
36
|
|
|
37
37
|
// @ts-ignore
|
|
38
|
-
const { data, catalog, filePath } = Astro.props;
|
|
38
|
+
const { collection, data, catalog, filePath } = Astro.props;
|
|
39
39
|
const fileName = data.specifications?.openapiPath || 'openapi.yml';
|
|
40
40
|
|
|
41
41
|
const directory = path.dirname(filePath || '');
|
|
@@ -44,12 +44,24 @@ const fileExists = fs.existsSync(pathToSpec);
|
|
|
44
44
|
|
|
45
45
|
let content = '';
|
|
46
46
|
|
|
47
|
+
// Capitalize the first letter of a string
|
|
48
|
+
const pageTitle = `${collection} | ${data.name} | OpenAPI Spec`.replace(/^\w/, (c) => c.toUpperCase());
|
|
49
|
+
|
|
50
|
+
// Index only the latest version
|
|
51
|
+
const pagefindAttributes =
|
|
52
|
+
data.version === data.latestVersion
|
|
53
|
+
? {
|
|
54
|
+
'data-pagefind-body': '',
|
|
55
|
+
'data-pagefind-meta': `title:${pageTitle}`,
|
|
56
|
+
}
|
|
57
|
+
: {};
|
|
58
|
+
|
|
47
59
|
if (fileExists) {
|
|
48
60
|
content = fs.readFileSync(pathToSpec, 'utf8');
|
|
49
61
|
}
|
|
50
62
|
---
|
|
51
63
|
|
|
52
|
-
<VerticalSideBarLayout title=
|
|
64
|
+
<VerticalSideBarLayout title={pageTitle}>
|
|
53
65
|
{
|
|
54
66
|
!fileExists ? (
|
|
55
67
|
<div class="text-center h-screen flex flex-col justify-center ">
|
|
@@ -60,7 +72,13 @@ if (fileExists) {
|
|
|
60
72
|
</p>
|
|
61
73
|
</div>
|
|
62
74
|
) : (
|
|
63
|
-
<div>
|
|
75
|
+
<div {...pagefindAttributes}>
|
|
76
|
+
{
|
|
77
|
+
// Currently, Pagefind does not index metadata (such as the title),
|
|
78
|
+
// so we need to ensure it is included as text on the page.
|
|
79
|
+
// https://github.com/CloudCannon/pagefind/issues/437
|
|
80
|
+
}
|
|
81
|
+
<h2 class="hidden">{pageTitle}</h2>
|
|
64
82
|
<OpenAPISpec client:only="react" spec={content} />
|
|
65
83
|
</div>
|
|
66
84
|
)
|
|
@@ -68,7 +68,7 @@ const badges = [
|
|
|
68
68
|
---
|
|
69
69
|
|
|
70
70
|
<VerticalSideBarLayout title={pageTitle} description={ubiquitousLanguage.summary}>
|
|
71
|
-
<main class="flex sm:px-8 docs-layout h-full max-w-7xl">
|
|
71
|
+
<main class="flex sm:px-8 docs-layout h-full max-w-7xl" data-pagefind-body data-pagefind-meta={`title:${pageTitle}`}>
|
|
72
72
|
<div class="flex docs-layout w-full">
|
|
73
73
|
<div class="w-full lg:mr-2 pr-8 overflow-y-auto py-8 min-h-[50em]">
|
|
74
74
|
<nav class="flex mb-4" aria-label="Breadcrumb">
|
|
@@ -34,7 +34,7 @@ const ubiquitousLanguage = ubiquitousLanguages[0];
|
|
|
34
34
|
---
|
|
35
35
|
|
|
36
36
|
<VerticalSideBarLayout title={pageTitle} description={props.data.summary}>
|
|
37
|
-
<main class="flex sm:px-8 docs-layout h-full">
|
|
37
|
+
<main class="flex sm:px-8 docs-layout h-full" data-pagefind-body data-pagefind-meta={`title:${pageTitle}`}>
|
|
38
38
|
<div class="flex docs-layout w-full">
|
|
39
39
|
<div class="w-full lg:mr-2 pr-8 overflow-y-auto py-8 min-h-[50em]">
|
|
40
40
|
<nav class="flex mb-4" aria-label="Breadcrumb">
|
|
@@ -0,0 +1,260 @@
|
|
|
1
|
+
---
|
|
2
|
+
import CustomDocumentationPage from '@enterprise/custom-documentation/pages/index.astro';
|
|
3
|
+
import { getCollection } from 'astro:content';
|
|
4
|
+
import type { GetStaticPaths } from 'astro';
|
|
5
|
+
import VerticalSideBarLayout from '@layouts/VerticalSideBarLayout.astro';
|
|
6
|
+
import { Code } from 'astro-expressive-code/components';
|
|
7
|
+
import { isEventCatalogProEnabled } from '@utils/feature';
|
|
8
|
+
import path from 'node:path';
|
|
9
|
+
import fs from 'node:fs';
|
|
10
|
+
|
|
11
|
+
const PROJECT_DIR = path.resolve(process.env.PROJECT_DIR || process.cwd());
|
|
12
|
+
const CUSTOM_DOCS_DIR = path.resolve(PROJECT_DIR, 'docs/');
|
|
13
|
+
const directoryExists = fs.existsSync(CUSTOM_DOCS_DIR);
|
|
14
|
+
|
|
15
|
+
export const getStaticPaths = (async () => {
|
|
16
|
+
const docs = await getCollection('customPages');
|
|
17
|
+
const paths = docs.map((doc) => ({
|
|
18
|
+
params: { path: doc.id.replace('docs/', '') },
|
|
19
|
+
props: doc,
|
|
20
|
+
}));
|
|
21
|
+
console.log(
|
|
22
|
+
'paths',
|
|
23
|
+
paths.map((path) => path.params.path)
|
|
24
|
+
);
|
|
25
|
+
return paths;
|
|
26
|
+
}) satisfies GetStaticPaths;
|
|
27
|
+
|
|
28
|
+
const props = Astro.props;
|
|
29
|
+
|
|
30
|
+
// Example for folder structure
|
|
31
|
+
const folderStructureExample = `my-catalog/
|
|
32
|
+
└── docs/
|
|
33
|
+
├── getting-started/
|
|
34
|
+
│ ├── 01-introduction.mdx
|
|
35
|
+
│ └── 02-quick-start.mdx
|
|
36
|
+
├── architecture-decisions/
|
|
37
|
+
│ ├── 01-what-are-architecture-decisions.mdx
|
|
38
|
+
│ ├── 02-how-to-create-architecture-decisions.mdx
|
|
39
|
+
│ ├── published/
|
|
40
|
+
│ │ ├── 01-adr-001-event-driven.mdx
|
|
41
|
+
│ │ └── 02-adr-002-api-first.mdx
|
|
42
|
+
│ └── drafts/
|
|
43
|
+
│ ├── 01-adr-003-microservices.mdx
|
|
44
|
+
│ └── 02-adr-004-monolith.mdx
|
|
45
|
+
└`;
|
|
46
|
+
// Example MDX file content
|
|
47
|
+
const mdxFileExample = `---
|
|
48
|
+
title: Getting Started
|
|
49
|
+
description: How to get started with our event-driven architecture
|
|
50
|
+
---
|
|
51
|
+
|
|
52
|
+
# Getting Started with our Event-Driven Architecture
|
|
53
|
+
|
|
54
|
+
This guide will help you understand how our services communicate using events.
|
|
55
|
+
|
|
56
|
+
## Prerequisites
|
|
57
|
+
|
|
58
|
+
- Understanding of basic messaging patterns
|
|
59
|
+
- Node.js installed on your machine
|
|
60
|
+
|
|
61
|
+
## Key Concepts
|
|
62
|
+
|
|
63
|
+
Events are the backbone of our architecture. They represent facts that have happened in our system.
|
|
64
|
+
`;
|
|
65
|
+
|
|
66
|
+
// Example config file
|
|
67
|
+
const configExample = `// eventcatalog.config.js
|
|
68
|
+
|
|
69
|
+
module.exports = {
|
|
70
|
+
// Your existing config...
|
|
71
|
+
|
|
72
|
+
customDocs: {
|
|
73
|
+
sidebar: [
|
|
74
|
+
{
|
|
75
|
+
label: 'Getting Started',
|
|
76
|
+
badge: {
|
|
77
|
+
text: 'New', color: 'green'
|
|
78
|
+
},
|
|
79
|
+
collapsed: false,
|
|
80
|
+
items: [
|
|
81
|
+
{ label: 'Introduction', slug: 'getting-started/01-introduction' },
|
|
82
|
+
{ label: 'Quick Start', slug: 'getting-started/02-quick-start' }
|
|
83
|
+
]
|
|
84
|
+
},
|
|
85
|
+
{
|
|
86
|
+
label: 'Architecture Decisions',
|
|
87
|
+
badge: {
|
|
88
|
+
text: 'New', color: 'green'
|
|
89
|
+
},
|
|
90
|
+
collapsed: true,
|
|
91
|
+
items: [
|
|
92
|
+
{
|
|
93
|
+
label: 'What are Architecture Decisions?',
|
|
94
|
+
slug: 'architecture-decisions/01-what-are-architecture-decisions'
|
|
95
|
+
},
|
|
96
|
+
{
|
|
97
|
+
label: 'How to Create Architecture Decisions',
|
|
98
|
+
slug: 'architecture-decisions/02-how-to-create-architecture-decisions'
|
|
99
|
+
},
|
|
100
|
+
{
|
|
101
|
+
label: 'Published ADRs',
|
|
102
|
+
autogenerated: {
|
|
103
|
+
directory: 'architecture-decisions/published',
|
|
104
|
+
collapsed: true
|
|
105
|
+
}
|
|
106
|
+
},
|
|
107
|
+
{
|
|
108
|
+
label: 'Draft ADRs',
|
|
109
|
+
autogenerated: {
|
|
110
|
+
directory: 'architecture-decisions/drafts',
|
|
111
|
+
collapsed: true
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
]
|
|
115
|
+
}
|
|
116
|
+
]
|
|
117
|
+
}
|
|
118
|
+
}`;
|
|
119
|
+
---
|
|
120
|
+
|
|
121
|
+
{
|
|
122
|
+
directoryExists && isEventCatalogProEnabled() ? (
|
|
123
|
+
<CustomDocumentationPage {...props} />
|
|
124
|
+
) : (
|
|
125
|
+
<VerticalSideBarLayout title="Custom Documentation">
|
|
126
|
+
<body class="min-h-screen font-inter">
|
|
127
|
+
<main class="container px-8 lg:px-8 mx-auto py-8 max-w-[80em]">
|
|
128
|
+
<div class="mb-12">
|
|
129
|
+
<div class="flex flex-col md:flex-row md:items-center md:justify-between gap-6">
|
|
130
|
+
<div>
|
|
131
|
+
<div class="flex flex-wrap items-center gap-3 mb-3">
|
|
132
|
+
<h1 class="text-4xl font-semibold text-gray-900 font-inter">Custom Documentation</h1>
|
|
133
|
+
<div class="inline-flex items-center px-3 py-1.5 rounded-full text-xs font-medium bg-purple-100 text-purple-800 border border-purple-200 shadow-sm">
|
|
134
|
+
Pro feature
|
|
135
|
+
</div>
|
|
136
|
+
</div>
|
|
137
|
+
<p class="text-base mb-0 text-gray-600 max-w-3xl">
|
|
138
|
+
Add custom documentation to EventCatalog to create a unified source of truth for your team. Document your
|
|
139
|
+
architecture decisions, patterns, and guidelines.
|
|
140
|
+
</p>
|
|
141
|
+
</div>
|
|
142
|
+
<div class="flex space-x-4 shrink-0">
|
|
143
|
+
<a
|
|
144
|
+
href="https://www.eventcatalog.dev/docs/custom-documentation"
|
|
145
|
+
class="inline-flex items-center justify-center px-5 py-2 border border-gray-300 text-sm font-medium rounded-md text-gray-700 bg-white hover:bg-gray-50"
|
|
146
|
+
>
|
|
147
|
+
Read documentation →
|
|
148
|
+
</a>
|
|
149
|
+
{!isEventCatalogProEnabled() && (
|
|
150
|
+
<a
|
|
151
|
+
href="https://www.eventcatalog.dev/pro/trial"
|
|
152
|
+
class="inline-flex items-center justify-center px-5 py-2 border border-transparent text-sm font-medium rounded-md text-white bg-gradient-to-r from-purple-500 to-purple-700 hover:from-purple-600 hover:to-purple-800 shadow-sm"
|
|
153
|
+
>
|
|
154
|
+
Start 14-day trial
|
|
155
|
+
</a>
|
|
156
|
+
)}
|
|
157
|
+
</div>
|
|
158
|
+
</div>
|
|
159
|
+
</div>
|
|
160
|
+
|
|
161
|
+
<h2 class="text-2xl font-semibold mb-2 text-gray-900">Setup Guide</h2>
|
|
162
|
+
<p class="text-gray-600 mb-8 max-w-3xl">
|
|
163
|
+
Custom documentation let's you bring any documentation into EventCatalog. This is useful for documenting your
|
|
164
|
+
architecture decisions, patterns, and guidelines. Follow these steps to get started:
|
|
165
|
+
</p>
|
|
166
|
+
|
|
167
|
+
<div class="space-y-10 mb-12">
|
|
168
|
+
<div class="bg-white p-6 rounded-lg shadow-sm border border-gray-200">
|
|
169
|
+
<div class="flex items-start gap-4">
|
|
170
|
+
<div class="inline-flex items-center justify-center w-8 h-8 rounded-full bg-blue-100 text-blue-600 text-lg font-medium shrink-0 mt-1">
|
|
171
|
+
1
|
|
172
|
+
</div>
|
|
173
|
+
<div class="w-full">
|
|
174
|
+
<h3 class="text-xl font-semibold text-gray-900 mb-3">Create the content structure</h3>
|
|
175
|
+
<p class="text-gray-600 mb-4">Create a folder structure in your directory to organize your documentation.</p>
|
|
176
|
+
<Code code={folderStructureExample} lang="bash" frame="terminal" />
|
|
177
|
+
</div>
|
|
178
|
+
</div>
|
|
179
|
+
</div>
|
|
180
|
+
|
|
181
|
+
<div class="bg-white p-6 rounded-lg shadow-sm border border-gray-200">
|
|
182
|
+
<div class="flex items-start gap-4">
|
|
183
|
+
<div class="inline-flex items-center justify-center w-8 h-8 rounded-full bg-blue-100 text-blue-600 text-lg font-medium shrink-0 mt-1">
|
|
184
|
+
2
|
|
185
|
+
</div>
|
|
186
|
+
<div class="w-full">
|
|
187
|
+
<h3 class="text-xl font-semibold text-gray-900 mb-3">Add MDX files</h3>
|
|
188
|
+
<p class="text-gray-600 mb-4">Create MDX files with frontmatter and markdown content.</p>
|
|
189
|
+
<Code code={mdxFileExample} lang="mdx" frame="terminal" />
|
|
190
|
+
</div>
|
|
191
|
+
</div>
|
|
192
|
+
</div>
|
|
193
|
+
|
|
194
|
+
<div class="bg-white p-6 rounded-lg shadow-sm border border-gray-200">
|
|
195
|
+
<div class="flex items-start gap-4">
|
|
196
|
+
<div class="inline-flex items-center justify-center w-8 h-8 rounded-full bg-blue-100 text-blue-600 text-lg font-medium shrink-0 mt-1">
|
|
197
|
+
3
|
|
198
|
+
</div>
|
|
199
|
+
<div class="w-full">
|
|
200
|
+
<h3 class="text-xl font-semibold text-gray-900 mb-3">Update your eventcatalog.config.js file</h3>
|
|
201
|
+
<p class="text-gray-600 mb-4">
|
|
202
|
+
Add the customDocs configuration to your eventcatalog.config.js file to define your sidebar structure.
|
|
203
|
+
</p>
|
|
204
|
+
<Code code={configExample} lang="js" frame="terminal" />
|
|
205
|
+
<p class="text-gray-600 mt-4">
|
|
206
|
+
This configuration defines the sidebar structure for your custom documentation:
|
|
207
|
+
</p>
|
|
208
|
+
<ul class="list-disc list-inside text-gray-600 mt-2 ml-2 space-y-1">
|
|
209
|
+
<li>
|
|
210
|
+
<strong>label</strong>: The display name for each sidebar section
|
|
211
|
+
</li>
|
|
212
|
+
<li>
|
|
213
|
+
<strong>badge</strong>: Optional badge to highlight new sections
|
|
214
|
+
</li>
|
|
215
|
+
<li>
|
|
216
|
+
<strong>collapsed</strong>: Whether the section is collapsed by default
|
|
217
|
+
</li>
|
|
218
|
+
<li>
|
|
219
|
+
<strong>autogenerated</strong>: Automatically generate sidebar items from a directory
|
|
220
|
+
</li>
|
|
221
|
+
<li>
|
|
222
|
+
<strong>slug</strong>: Direct link to a specific page
|
|
223
|
+
</li>
|
|
224
|
+
</ul>
|
|
225
|
+
</div>
|
|
226
|
+
</div>
|
|
227
|
+
</div>
|
|
228
|
+
|
|
229
|
+
<div class="bg-white p-6 rounded-lg shadow-sm border border-gray-200">
|
|
230
|
+
<div class="flex items-start gap-4">
|
|
231
|
+
<div class="inline-flex items-center justify-center w-8 h-8 rounded-full bg-blue-100 text-blue-600 text-lg font-medium shrink-0 mt-1">
|
|
232
|
+
4
|
|
233
|
+
</div>
|
|
234
|
+
<div class="w-full">
|
|
235
|
+
<h3 class="text-xl font-semibold text-gray-900 mb-3">Restart EventCatalog</h3>
|
|
236
|
+
<p class="text-gray-600 mb-4">
|
|
237
|
+
After configuring your documentation, restart EventCatalog to see your custom documentation.
|
|
238
|
+
</p>
|
|
239
|
+
<div class="mb-4">
|
|
240
|
+
<Code code="npm run dev" lang="bash" frame="terminal" />
|
|
241
|
+
</div>
|
|
242
|
+
<p class="text-gray-600 mb-4">
|
|
243
|
+
Once restarted, you'll see your custom documentation displayed with the sidebar structure you defined:
|
|
244
|
+
</p>
|
|
245
|
+
<div class="border border-gray-200 rounded-lg overflow-hidden">
|
|
246
|
+
<img
|
|
247
|
+
src="/images/custom-docs-placeholder.png"
|
|
248
|
+
alt="Example of custom documentation interface"
|
|
249
|
+
class="w-full"
|
|
250
|
+
/>
|
|
251
|
+
</div>
|
|
252
|
+
</div>
|
|
253
|
+
</div>
|
|
254
|
+
</div>
|
|
255
|
+
</div>
|
|
256
|
+
</main>
|
|
257
|
+
</body>
|
|
258
|
+
</VerticalSideBarLayout>
|
|
259
|
+
)
|
|
260
|
+
}
|
|
@@ -69,11 +69,13 @@ const ownedQueriesList = queries.map((p) => ({
|
|
|
69
69
|
collection: p.collection,
|
|
70
70
|
tag: `v${p.data.version}`,
|
|
71
71
|
}));
|
|
72
|
+
|
|
73
|
+
const pageTitle = `Team | ${props.data.name}`;
|
|
72
74
|
---
|
|
73
75
|
|
|
74
|
-
<VerticalSideBarLayout title={
|
|
76
|
+
<VerticalSideBarLayout title={pageTitle} description={props.data.summary}>
|
|
75
77
|
<div class="flex min-h-screen docs-layout sm:px-8">
|
|
76
|
-
<main class="flex-1 w-full pr-10 pt-4">
|
|
78
|
+
<main class="flex-1 w-full pr-10 pt-4" data-pagefind-body data-pagefind-meta={`title:${pageTitle}`}>
|
|
77
79
|
<!-- <span class="text-purple-500 bg-purple-100 px-2 py-1 rounded-md">v{props.data.version}</span> -->
|
|
78
80
|
|
|
79
81
|
<div class="border-b border-gray-200 py-4 pb-2">
|
|
@@ -131,7 +133,7 @@ const ownedQueriesList = queries.map((p) => ({
|
|
|
131
133
|
<NodeGraph id={props.data.id} type={props?.catalog?.type} nodes={props.nodes} masterNode={{ name: props.data.name, id: props.data.id }} client:load />
|
|
132
134
|
</div> -->
|
|
133
135
|
</main>
|
|
134
|
-
<aside class="sticky top-20 h-[calc(100vh-theme(spacing.16))] w-72 overflow-y-auto">
|
|
136
|
+
<aside class="sticky top-20 h-[calc(100vh-theme(spacing.16))] w-72 overflow-y-auto" data-pagefind-ignore>
|
|
135
137
|
<div class="divide-y-2 divide-gray-100">
|
|
136
138
|
<PillListFlat
|
|
137
139
|
color="pink"
|
|
@@ -59,10 +59,12 @@ const associatedTeams = teams.map((o) => ({
|
|
|
59
59
|
badge: 'Team',
|
|
60
60
|
href: buildUrl(`/docs/${o.collection}/${o.data.id}`),
|
|
61
61
|
}));
|
|
62
|
+
|
|
63
|
+
const pageTitle = `User | ${props.data.name}`;
|
|
62
64
|
---
|
|
63
65
|
|
|
64
|
-
<VerticalSideBarLayout title={
|
|
65
|
-
<main class="flex sm:px-8 docs-layout h-full">
|
|
66
|
+
<VerticalSideBarLayout title={pageTitle}>
|
|
67
|
+
<main class="flex sm:px-8 docs-layout h-full" data-pagefind-body data-pagefind-meta={`title:${pageTitle}`}>
|
|
66
68
|
<div class="flex docs-layout w-full">
|
|
67
69
|
<div class="w-full lg:mr-6 pr-8 overflow-y-auto py-4">
|
|
68
70
|
<!-- <span class="text-purple-500 bg-purple-100 px-2 py-1 rounded-md">v{props.data.version}</span> -->
|
|
@@ -105,7 +107,7 @@ const associatedTeams = teams.map((o) => ({
|
|
|
105
107
|
</div>
|
|
106
108
|
</div>
|
|
107
109
|
</div>
|
|
108
|
-
<div class="border-b border-gray-200">
|
|
110
|
+
<div class="border-b border-gray-200" data-pagefind-ignore>
|
|
109
111
|
<div class="mx-auto max-w-7xl px-6 lg:px-8">
|
|
110
112
|
<div class="mx-auto max-w-2xl lg:max-w-none">
|
|
111
113
|
<dl
|
|
@@ -139,7 +141,10 @@ const associatedTeams = teams.map((o) => ({
|
|
|
139
141
|
<Content components={components(props)} />
|
|
140
142
|
</div>
|
|
141
143
|
</div>
|
|
142
|
-
<aside
|
|
144
|
+
<aside
|
|
145
|
+
class="hidden lg:block sticky top-0 h-[calc(100vh-theme(spacing.16))] w-72 overflow-y-auto py-2"
|
|
146
|
+
data-pagefind-ignore
|
|
147
|
+
>
|
|
143
148
|
<div class="divide-y-2 divide-gray-100 pr-6">
|
|
144
149
|
{
|
|
145
150
|
ownedDomainsList.length > 0 && (
|