@eventcatalog/core 2.30.8 → 2.31.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (49) hide show
  1. package/README.md +1 -1
  2. package/dist/analytics/analytics.cjs +1 -1
  3. package/dist/analytics/analytics.js +2 -2
  4. package/dist/analytics/log-build.cjs +9 -3
  5. package/dist/analytics/log-build.d.cts +4 -1
  6. package/dist/analytics/log-build.d.ts +4 -1
  7. package/dist/analytics/log-build.js +3 -3
  8. package/dist/{chunk-NALVGTIE.js → chunk-GHBJ372G.js} +1 -1
  9. package/dist/{chunk-XMDPVKIJ.js → chunk-NJGR7XUU.js} +44 -1
  10. package/dist/{chunk-D4IJRFPJ.js → chunk-QR5UTYCE.js} +9 -3
  11. package/dist/{chunk-XJBJFIN7.js → chunk-YUINCBLT.js} +1 -1
  12. package/dist/constants.cjs +1 -1
  13. package/dist/constants.js +1 -1
  14. package/dist/eventcatalog.cjs +74 -14
  15. package/dist/eventcatalog.config.d.cts +28 -0
  16. package/dist/eventcatalog.config.d.ts +28 -0
  17. package/dist/eventcatalog.js +29 -16
  18. package/dist/features.cjs +46 -2
  19. package/dist/features.d.cts +2 -1
  20. package/dist/features.d.ts +2 -1
  21. package/dist/features.js +5 -3
  22. package/eventcatalog/public/images/custom-docs-placeholder.png +0 -0
  23. package/eventcatalog/src/components/MDX/NodeGraph/Nodes/Custom.tsx +0 -2
  24. package/eventcatalog/src/components/MDX/Steps/Step.astro +1 -1
  25. package/eventcatalog/src/components/MDX/Steps/Steps.astro +15 -0
  26. package/eventcatalog/src/components/SideNav/CustomDocsNav/CustomDocsNavWrapper.tsx +11 -0
  27. package/eventcatalog/src/components/SideNav/CustomDocsNav/components/NestedItem.tsx +183 -0
  28. package/eventcatalog/src/components/SideNav/CustomDocsNav/components/NoResultsFound.tsx +21 -0
  29. package/eventcatalog/src/components/SideNav/CustomDocsNav/index.tsx +250 -0
  30. package/eventcatalog/src/components/SideNav/CustomDocsNav/types.ts +29 -0
  31. package/eventcatalog/src/components/SideNav/CustomDocsNav.astro +9 -0
  32. package/eventcatalog/src/content.config.ts +15 -24
  33. package/eventcatalog/src/enterprise/collections/custom-pages.ts +19 -0
  34. package/eventcatalog/src/enterprise/custom-documentation/collection.ts +16 -0
  35. package/eventcatalog/src/enterprise/custom-documentation/components/CustomDocsNav/CustomDocsNavWrapper.tsx +11 -0
  36. package/eventcatalog/src/enterprise/custom-documentation/components/CustomDocsNav/components/NestedItem.tsx +183 -0
  37. package/eventcatalog/src/enterprise/custom-documentation/components/CustomDocsNav/components/NoResultsFound.tsx +21 -0
  38. package/eventcatalog/src/enterprise/custom-documentation/components/CustomDocsNav/index.tsx +250 -0
  39. package/eventcatalog/src/enterprise/custom-documentation/components/CustomDocsNav/types.ts +29 -0
  40. package/eventcatalog/src/enterprise/custom-documentation/pages/index.astro +389 -0
  41. package/eventcatalog/src/enterprise/custom-documentation/utils/custom-docs.ts +118 -0
  42. package/eventcatalog/src/layouts/VerticalSideBarLayout.astro +57 -10
  43. package/eventcatalog/src/pages/docs/[type]/[id]/[version]/index.astro +117 -3
  44. package/eventcatalog/src/pages/docs/custom/[...path]/index.astro +34 -0
  45. package/eventcatalog/src/pages/pro/index.astro +272 -0
  46. package/eventcatalog/src/shared-collections.ts +25 -0
  47. package/eventcatalog/src/utils/eventcatalog-config/catalog.ts +12 -1
  48. package/eventcatalog/src/utils/feature.ts +5 -0
  49. package/package.json +1 -1
@@ -25,3 +25,18 @@ const data = splitByLi(html);
25
25
  {data.map((item: any) => <Fragment set:html={item} />)}
26
26
  </ol>
27
27
  </div>
28
+
29
+ <script>
30
+ function applyStepNumbers() {
31
+ document.querySelectorAll('li[data-step]').forEach((li) => {
32
+ const stepNumber = li.getAttribute('data-step');
33
+ const stepSpan = li.querySelector('.step-number div');
34
+ if (stepSpan) {
35
+ stepSpan.textContent = stepNumber;
36
+ }
37
+ });
38
+ }
39
+
40
+ document.addEventListener('DOMContentLoaded', applyStepNumbers);
41
+ document.addEventListener('astro:page-load', applyStepNumbers);
42
+ </script>
@@ -0,0 +1,11 @@
1
+ import CustomDocsNav from './';
2
+ import type { SidebarSection } from './types';
3
+
4
+ interface CustomDocsNavWrapperProps {
5
+ sidebarItems: SidebarSection[];
6
+ currentPath: string;
7
+ }
8
+
9
+ export default function CustomDocsNavWrapper(props: CustomDocsNavWrapperProps) {
10
+ return <CustomDocsNav {...props} />;
11
+ }
@@ -0,0 +1,183 @@
1
+ import React from 'react';
2
+ import { buildUrl } from '@utils/url-builder';
3
+ import type { SidebarItem } from '../types';
4
+
5
+ interface NestedItemProps {
6
+ item: SidebarItem;
7
+ currentPath: string;
8
+ parentId: string;
9
+ itemIndex: number;
10
+ collapsedGroups: { [key: string]: boolean };
11
+ toggleGroupCollapse: (group: string) => void;
12
+ }
13
+
14
+ const NestedItem: React.FC<NestedItemProps> = ({
15
+ item,
16
+ currentPath,
17
+ parentId,
18
+ itemIndex,
19
+ collapsedGroups,
20
+ toggleGroupCollapse,
21
+ }) => {
22
+ const hasNestedItems = item.items && item.items.length > 0;
23
+ const itemId = `${parentId}-${itemIndex}`;
24
+
25
+ if (hasNestedItems && item.items) {
26
+ return (
27
+ <div className="py-1">
28
+ <div className="flex items-center">
29
+ <button
30
+ className="p-1 hover:bg-gray-100 rounded-md"
31
+ onClick={(e) => {
32
+ e.stopPropagation();
33
+ toggleGroupCollapse(`nested-${itemId}`);
34
+ }}
35
+ >
36
+ <div className={`transition-transform duration-150 ${collapsedGroups[`nested-${itemId}`] ? '' : 'rotate-180'}`}>
37
+ <svg
38
+ className="h-3 w-3 text-gray-500"
39
+ xmlns="http://www.w3.org/2000/svg"
40
+ width="16"
41
+ height="16"
42
+ viewBox="0 0 24 24"
43
+ fill="none"
44
+ stroke="currentColor"
45
+ strokeWidth="2"
46
+ strokeLinecap="round"
47
+ strokeLinejoin="round"
48
+ >
49
+ <polyline points="6 9 12 15 18 9" />
50
+ </svg>
51
+ </div>
52
+ </button>
53
+ <button
54
+ className="flex-grow flex items-center px-2 py-1 text-xs font-medium text-gray-700 rounded-md hover:bg-purple-50"
55
+ onClick={(e) => {
56
+ e.stopPropagation();
57
+ toggleGroupCollapse(`nested-${itemId}`);
58
+ }}
59
+ >
60
+ <span className="truncate">{item.label}</span>
61
+ </button>
62
+ </div>
63
+
64
+ <div
65
+ className={`overflow-hidden transition-[height] duration-150 ease-out ${
66
+ collapsedGroups[`nested-${itemId}`] ? 'h-0' : 'h-auto'
67
+ }`}
68
+ >
69
+ <div className="space-y-0.5 border-gray-200/80 border-l pl-4 ml-[9px] mt-1">
70
+ {item.items.map((nestedItem: SidebarItem, nestedIndex: number) => {
71
+ if (nestedItem.items && nestedItem.items.length > 0) {
72
+ // Recursively render deeper nested items
73
+ const nestedItemId = `${itemId}-${nestedIndex}`;
74
+ return (
75
+ <div className="py-1" key={`nested-${nestedItemId}`}>
76
+ <div className="flex items-center">
77
+ <button
78
+ className="p-1 hover:bg-gray-100 rounded-md"
79
+ onClick={(e) => {
80
+ e.stopPropagation();
81
+ toggleGroupCollapse(`nested-${nestedItemId}`);
82
+ }}
83
+ >
84
+ <div
85
+ className={`transition-transform duration-150 ${collapsedGroups[`nested-${nestedItemId}`] ? '' : 'rotate-180'}`}
86
+ >
87
+ <svg
88
+ className="h-3 w-3 text-gray-500"
89
+ xmlns="http://www.w3.org/2000/svg"
90
+ width="16"
91
+ height="16"
92
+ viewBox="0 0 24 24"
93
+ fill="none"
94
+ stroke="currentColor"
95
+ strokeWidth="2"
96
+ strokeLinecap="round"
97
+ strokeLinejoin="round"
98
+ >
99
+ <polyline points="6 9 12 15 18 9" />
100
+ </svg>
101
+ </div>
102
+ </button>
103
+ <button
104
+ className="flex-grow flex items-center px-2 py-1 text-xs font-medium text-gray-700 rounded-md hover:bg-purple-50"
105
+ onClick={(e) => {
106
+ e.stopPropagation();
107
+ toggleGroupCollapse(`nested-${nestedItemId}`);
108
+ }}
109
+ >
110
+ <span className="truncate">{nestedItem.label}</span>
111
+ </button>
112
+ </div>
113
+
114
+ <div
115
+ className={`overflow-hidden transition-[height] duration-150 ease-out ${
116
+ collapsedGroups[`nested-${nestedItemId}`] ? 'h-0' : 'h-auto'
117
+ }`}
118
+ >
119
+ <div className="space-y-0.5 border-gray-200/80 border-l pl-4 ml-[9px] mt-1">
120
+ {nestedItem.items.map((deepNestedItem: SidebarItem, deepIndex: number) => {
121
+ const deepNestedItemPath = deepNestedItem.slug ? buildUrl(`/docs/custom/${deepNestedItem.slug}`) : '#';
122
+ const isDeepActive =
123
+ currentPath === deepNestedItemPath || currentPath.endsWith(`/${deepNestedItem.slug}`);
124
+
125
+ return (
126
+ <a
127
+ key={`deep-${nestedItemId}-${deepIndex}`}
128
+ href={deepNestedItemPath}
129
+ className={`flex items-center px-2 py-1.5 text-xs ${isDeepActive ? 'bg-purple-100 text-purple-900 font-medium' : 'text-gray-600 hover:bg-purple-100'} rounded-md`}
130
+ data-active={isDeepActive}
131
+ >
132
+ <span className="truncate">{deepNestedItem.label}</span>
133
+ </a>
134
+ );
135
+ })}
136
+ </div>
137
+ </div>
138
+ </div>
139
+ );
140
+ }
141
+
142
+ const nestedItemPath = nestedItem.slug ? buildUrl(`/docs/custom/${nestedItem.slug}`) : '#';
143
+ const isActive = currentPath === nestedItemPath || currentPath.endsWith(`/${nestedItem.slug}`);
144
+
145
+ return (
146
+ <a
147
+ key={`nested-link-${itemId}-${nestedIndex}`}
148
+ href={nestedItemPath}
149
+ className={`flex items-center px-2 py-1.5 text-xs ${isActive ? 'bg-purple-100 text-purple-900 font-medium' : 'text-gray-600 hover:bg-purple-100'} rounded-md`}
150
+ data-active={isActive}
151
+ >
152
+ <span className="truncate">{nestedItem.label}</span>
153
+ </a>
154
+ );
155
+ })}
156
+ </div>
157
+ </div>
158
+ </div>
159
+ );
160
+ }
161
+
162
+ const itemPath = item.slug ? buildUrl(`/docs/custom/${item.slug}`) : '#';
163
+ const isActive = currentPath === itemPath || currentPath.endsWith(`/${item.slug}`);
164
+
165
+ return (
166
+ <a
167
+ href={itemPath}
168
+ className={`flex items-center px-2 py-1.5 text-xs ${isActive ? 'bg-purple-100 text-purple-900 font-medium' : 'text-gray-600 hover:bg-purple-100'} rounded-md`}
169
+ data-active={isActive}
170
+ >
171
+ <span className="truncate">{item.label}</span>
172
+ {item.badge && item?.badge?.text && (
173
+ <span
174
+ className={`text-${item.badge.color || 'purple'}-600 ml-2 text-[10px] font-medium bg-${item.badge.color || 'purple'}-50 px-2 py-0.5 rounded uppercase`}
175
+ >
176
+ {item.badge.text}
177
+ </span>
178
+ )}
179
+ </a>
180
+ );
181
+ };
182
+
183
+ export default React.memo(NestedItem);
@@ -0,0 +1,21 @@
1
+ import React from 'react';
2
+
3
+ interface NoResultsFoundProps {
4
+ searchTerm: string;
5
+ }
6
+
7
+ const NoResultsFound: React.FC<NoResultsFoundProps> = ({ searchTerm }) => (
8
+ <div className="px-4 py-6 text-center">
9
+ <div className="text-gray-400 text-sm mb-2">No results found for "{searchTerm}"</div>
10
+ <div className="text-gray-400 text-xs">
11
+ Try:
12
+ <ul className="mt-2 space-y-1 text-left list-disc pl-4">
13
+ <li>Checking for typos</li>
14
+ <li>Using fewer keywords</li>
15
+ <li>Using more general terms</li>
16
+ </ul>
17
+ </div>
18
+ </div>
19
+ );
20
+
21
+ export default React.memo(NoResultsFound);
@@ -0,0 +1,250 @@
1
+ import React, { useState, useRef, useEffect, useCallback, useMemo } from 'react';
2
+ import { buildUrl } from '@utils/url-builder';
3
+ import type { CustomDocsNavProps, SidebarSection, SidebarItem } from './types';
4
+ import NestedItem from './components/NestedItem';
5
+ import NoResultsFound from './components/NoResultsFound';
6
+
7
+ const STORAGE_KEY = 'EventCatalog:customDocsSidebarCollapsedGroups';
8
+ const DEBOUNCE_DELAY = 300; // 300ms debounce delay
9
+
10
+ const CustomDocsNav: React.FC<CustomDocsNavProps> = ({ sidebarItems, currentPath }) => {
11
+ const navRef = useRef<HTMLElement>(null);
12
+ const [searchTerm, setSearchTerm] = useState('');
13
+ const [debouncedSearchTerm, setDebouncedSearchTerm] = useState('');
14
+ const [isInitialized, setIsInitialized] = useState(false);
15
+ const [collapsedGroups, setCollapsedGroups] = useState<{ [key: string]: boolean }>(() => {
16
+ if (typeof window !== 'undefined') {
17
+ const saved = window.localStorage.getItem(STORAGE_KEY);
18
+ setIsInitialized(true);
19
+ return saved ? JSON.parse(saved) : {};
20
+ }
21
+ return {};
22
+ });
23
+
24
+ // Set up debounced search
25
+ useEffect(() => {
26
+ const timer = setTimeout(() => {
27
+ setDebouncedSearchTerm(searchTerm.toLowerCase());
28
+ }, DEBOUNCE_DELAY);
29
+
30
+ return () => clearTimeout(timer);
31
+ }, [searchTerm]);
32
+
33
+ // Filter sidebar items based on search term
34
+ const filteredSidebarItems = useMemo(() => {
35
+ if (!debouncedSearchTerm) return sidebarItems;
36
+
37
+ const matchesSearchTerm = (text: string) => text.toLowerCase().includes(debouncedSearchTerm);
38
+
39
+ // Helper function to check if an item or any of its nested items match the search term
40
+ const itemContainsSearchTerm = (item: SidebarItem): boolean => {
41
+ if (matchesSearchTerm(item.label)) return true;
42
+
43
+ if (item.items && item.items.length > 0) {
44
+ return item.items.some(itemContainsSearchTerm);
45
+ }
46
+
47
+ return false;
48
+ };
49
+
50
+ return sidebarItems
51
+ .map((section) => {
52
+ if (!section.items) {
53
+ return matchesSearchTerm(section.label) ? section : null;
54
+ }
55
+
56
+ const filteredItems = section.items.filter(itemContainsSearchTerm);
57
+
58
+ if (filteredItems.length > 0 || matchesSearchTerm(section.label)) {
59
+ return {
60
+ ...section,
61
+ items: filteredItems,
62
+ };
63
+ }
64
+
65
+ return null;
66
+ })
67
+ .filter(Boolean) as SidebarSection[];
68
+ }, [sidebarItems, debouncedSearchTerm]);
69
+
70
+ // Auto-expand groups when searching
71
+ useEffect(() => {
72
+ if (debouncedSearchTerm) {
73
+ // Expand all groups when searching
74
+ const newCollapsedState = { ...collapsedGroups };
75
+ Object.keys(newCollapsedState).forEach((key) => {
76
+ newCollapsedState[key] = false;
77
+ });
78
+ setCollapsedGroups(newCollapsedState);
79
+ }
80
+ }, [debouncedSearchTerm]);
81
+
82
+ // Store collapsed groups in local storage
83
+ useEffect(() => {
84
+ if (typeof window !== 'undefined' && isInitialized) {
85
+ window.localStorage.setItem(STORAGE_KEY, JSON.stringify(collapsedGroups));
86
+ }
87
+ }, [collapsedGroups, isInitialized]);
88
+
89
+ // Initialize collapsed state from section config
90
+ useEffect(() => {
91
+ if (isInitialized && sidebarItems && sidebarItems.length > 0) {
92
+ const initialState = { ...collapsedGroups };
93
+
94
+ sidebarItems.forEach((section, index) => {
95
+ const sectionKey = `section-${index}`;
96
+ if (section.collapsed !== undefined && initialState[sectionKey] === undefined) {
97
+ initialState[sectionKey] = section.collapsed;
98
+ }
99
+ });
100
+
101
+ setCollapsedGroups(initialState);
102
+ }
103
+ }, [sidebarItems, isInitialized]);
104
+
105
+ // If we find a data-active element, scroll to it on mount
106
+ useEffect(() => {
107
+ const activeElement = document.querySelector('[data-active="true"]');
108
+ if (activeElement) {
109
+ // Add y offset to the scroll position
110
+ setTimeout(() => {
111
+ activeElement.scrollIntoView({ behavior: 'smooth', block: 'center' });
112
+ }, 300);
113
+ }
114
+ }, []);
115
+
116
+ const toggleGroupCollapse = useCallback((group: string) => {
117
+ setCollapsedGroups((prev) => ({
118
+ ...prev,
119
+ [group]: !prev[group],
120
+ }));
121
+ }, []);
122
+
123
+ const handleSearchChange = useCallback((e: React.ChangeEvent<HTMLInputElement>) => {
124
+ setSearchTerm(e.target.value);
125
+ }, []);
126
+
127
+ if (!isInitialized) return null;
128
+
129
+ const hasNoResults = debouncedSearchTerm && filteredSidebarItems.length === 0;
130
+
131
+ return (
132
+ <nav ref={navRef} className="h-full text-gray-800 pt-2">
133
+ <div className="mb-2 px-4">
134
+ <input
135
+ type="text"
136
+ value={searchTerm}
137
+ onChange={handleSearchChange}
138
+ placeholder="Quick search..."
139
+ className="w-full p-2 text-sm rounded-md border border-gray-200 h-[30px]"
140
+ />
141
+ </div>
142
+
143
+ <div className="space-y-2 divide-y divide-gray-100/40">
144
+ {hasNoResults ? (
145
+ <NoResultsFound searchTerm={debouncedSearchTerm} />
146
+ ) : (
147
+ filteredSidebarItems.map((section: SidebarSection, index: number) => (
148
+ <div className="pt-2 pb-2 px-4" key={`section-${index}`}>
149
+ <div className="space-y-0" data-section={`section-${index}`}>
150
+ {section.items ? (
151
+ <div className="flex items-center">
152
+ <button
153
+ className="p-1 hover:bg-gray-100 rounded-md"
154
+ onClick={(e) => {
155
+ e.stopPropagation();
156
+ toggleGroupCollapse(`section-${index}`);
157
+ }}
158
+ >
159
+ <div
160
+ className={`transition-transform duration-150 ${collapsedGroups[`section-${index}`] ? '' : 'rotate-180'}`}
161
+ >
162
+ <svg
163
+ className="h-3 w-3 text-gray-500"
164
+ xmlns="http://www.w3.org/2000/svg"
165
+ width="16"
166
+ height="16"
167
+ viewBox="0 0 24 24"
168
+ fill="none"
169
+ stroke="currentColor"
170
+ strokeWidth="2"
171
+ strokeLinecap="round"
172
+ strokeLinejoin="round"
173
+ >
174
+ <polyline points="6 9 12 15 18 9" />
175
+ </svg>
176
+ </div>
177
+ </button>
178
+ <button
179
+ className="flex-grow flex items-center justify-between px-2 py-0.5 text-xs font-bold rounded-md hover:bg-purple-50"
180
+ onClick={(e) => {
181
+ e.stopPropagation();
182
+ toggleGroupCollapse(`section-${index}`);
183
+ }}
184
+ >
185
+ <span className="truncate">{section.label}</span>
186
+ {section.badge && section?.badge?.text && (
187
+ <span
188
+ className={`text-${section.badge.color || 'purple'}-600 ml-2 text-[10px] font-medium bg-${section.badge.color || 'purple'}-50 px-2 py-0.5 rounded uppercase`}
189
+ >
190
+ {section.badge.text}
191
+ </span>
192
+ )}
193
+ </button>
194
+ </div>
195
+ ) : (
196
+ <div className="flex items-center">
197
+ <span className="flex-grow flex items-center justify-between px-2 py-0.5 text-xs font-bold rounded-md">
198
+ <span className="truncate">{section.label}</span>
199
+ <span className="text-purple-600 ml-2 text-[10px] font-medium bg-purple-50 px-2 py-0.5 rounded uppercase">
200
+ Section
201
+ </span>
202
+ </span>
203
+ </div>
204
+ )}
205
+
206
+ {section.items && (
207
+ <div
208
+ className={`overflow-hidden transition-[height] duration-150 ease-out ${
209
+ collapsedGroups[`section-${index}`] ? 'h-0' : 'h-auto'
210
+ }`}
211
+ >
212
+ <div className="space-y-0.5 border-gray-200/80 border-l pl-4 ml-[9px] mt-1">
213
+ {section.items.map((item: SidebarItem, itemIndex: number) => (
214
+ <NestedItem
215
+ key={`item-${index}-${itemIndex}`}
216
+ item={item}
217
+ currentPath={currentPath}
218
+ parentId={`${index}`}
219
+ itemIndex={itemIndex}
220
+ collapsedGroups={collapsedGroups}
221
+ toggleGroupCollapse={toggleGroupCollapse}
222
+ />
223
+ ))}
224
+ </div>
225
+ </div>
226
+ )}
227
+
228
+ {section.slug && !section.items && (
229
+ <a
230
+ href={buildUrl(`/docs/custom/${section.slug}`)}
231
+ className={`flex items-center px-2 py-1.5 text-xs ${
232
+ currentPath.endsWith(`/${section.slug}`)
233
+ ? 'bg-purple-100 text-purple-900 font-medium'
234
+ : 'text-gray-600 hover:bg-purple-100'
235
+ } rounded-md ml-6`}
236
+ data-active={currentPath.endsWith(`/${section.slug}`)}
237
+ >
238
+ <span className="truncate">{section.label}</span>
239
+ </a>
240
+ )}
241
+ </div>
242
+ </div>
243
+ ))
244
+ )}
245
+ </div>
246
+ </nav>
247
+ );
248
+ };
249
+
250
+ export default React.memo(CustomDocsNav);
@@ -0,0 +1,29 @@
1
+ export interface SidebarItem {
2
+ label: string;
3
+ slug?: string;
4
+ items?: SidebarItem[];
5
+ badge?: {
6
+ text: string;
7
+ color: string;
8
+ };
9
+ collapsed?: boolean;
10
+ }
11
+
12
+ export interface SidebarSection {
13
+ label: string;
14
+ items?: SidebarItem[];
15
+ slug?: string;
16
+ autogenerated?: {
17
+ directory: string;
18
+ };
19
+ badge?: {
20
+ text: string;
21
+ color: string;
22
+ };
23
+ collapsed?: boolean;
24
+ }
25
+
26
+ export interface CustomDocsNavProps {
27
+ sidebarItems: SidebarSection[];
28
+ currentPath: string;
29
+ }
@@ -0,0 +1,9 @@
1
+ ---
2
+ import { getNavigationItems } from '@enterprise/custom-documentation/utils/custom-docs';
3
+ import CustomDocsNavWrapper from '@enterprise/custom-documentation/components/CustomDocsNav/CustomDocsNavWrapper';
4
+
5
+ const currentPath = Astro.url.pathname;
6
+ const sidebarItems = await getNavigationItems();
7
+ ---
8
+
9
+ <CustomDocsNavWrapper client:load sidebarItems={sidebarItems} currentPath={currentPath} />
@@ -1,8 +1,10 @@
1
1
  import { z, defineCollection, reference } from 'astro:content';
2
2
  import { glob } from 'astro/loaders';
3
3
  import { v4 as uuidv4 } from 'uuid';
4
+ import { badge, ownerReference } from './shared-collections';
5
+ import { customPagesSchema } from './enterprise/custom-documentation/collection';
4
6
 
5
- const projectDirBase = (() => {
7
+ export const projectDirBase = (() => {
6
8
  if (process.platform === 'win32') {
7
9
  const projectDirPath = process.env.PROJECT_DIR!.replace(/\\/g, '/');
8
10
  return projectDirPath.startsWith('/') ? projectDirPath : `/${projectDirPath}`;
@@ -10,12 +12,6 @@ const projectDirBase = (() => {
10
12
  return process.env.PROJECT_DIR;
11
13
  })();
12
14
 
13
- const badge = z.object({
14
- content: z.string(),
15
- backgroundColor: z.string(),
16
- textColor: z.string(),
17
- });
18
-
19
15
  const pages = defineCollection({
20
16
  loader: glob({
21
17
  pattern: ['**/pages/*.(md|mdx)'],
@@ -64,23 +60,6 @@ const changelogs = defineCollection({
64
60
  }),
65
61
  });
66
62
 
67
- // Create a union type for owners
68
- const ownerReference = z
69
- .union([
70
- // The ID of the user or team
71
- z.string(),
72
- // The full object with the ID and collection (keep compatibility with `reference`)
73
- z.object({
74
- id: z.string(),
75
- collection: z.enum(['users', 'teams']),
76
- }),
77
- ])
78
- .transform(
79
- // This transformation is needed to keep compatibility with `reference`.
80
- // The utilities `getTeams` and `getUsers` rely on this transformation.
81
- (lookup) => ({ id: typeof lookup === 'string' ? lookup : lookup.id })
82
- );
83
-
84
63
  const baseSchema = z.object({
85
64
  id: z.string(),
86
65
  name: z.string(),
@@ -283,6 +262,15 @@ const services = defineCollection({
283
262
  .merge(baseSchema),
284
263
  });
285
264
 
265
+ const customPages = defineCollection({
266
+ loader: glob({
267
+ // any number of child folders
268
+ pattern: ['docs/*.(md|mdx)', 'docs/**/*.@(md|mdx)'],
269
+ base: projectDirBase,
270
+ }),
271
+ schema: customPagesSchema,
272
+ });
273
+
286
274
  const domains = defineCollection({
287
275
  loader: glob({
288
276
  pattern: [
@@ -405,4 +393,7 @@ export const collections = {
405
393
  pages,
406
394
  changelogs,
407
395
  ubiquitousLanguages,
396
+
397
+ // EventCatalog Pro Collections
398
+ customPages,
408
399
  };
@@ -0,0 +1,19 @@
1
+ import { glob } from 'astro/loaders';
2
+ import { z, defineCollection } from 'astro:content';
3
+ import { projectDirBase } from '../../content.config';
4
+
5
+ export const customPages = defineCollection({
6
+ loader: glob({
7
+ pattern: ['docs/hello-world.mdx'],
8
+ base: projectDirBase,
9
+ }),
10
+ schema: z.object({
11
+ id: z.string(),
12
+ title: z.string(),
13
+ description: z.string(),
14
+ sidebar: z.object({
15
+ label: z.string(),
16
+ order: z.number(),
17
+ }),
18
+ }),
19
+ });
@@ -0,0 +1,16 @@
1
+ import { z } from 'astro:content';
2
+ import { badge, ownerReference } from '../../shared-collections';
3
+
4
+ export const customPagesSchema = z.object({
5
+ title: z.string(),
6
+ description: z.string(),
7
+ slug: z.string().optional(),
8
+ sidebar: z
9
+ .object({
10
+ label: z.string(),
11
+ order: z.number(),
12
+ })
13
+ .optional(),
14
+ owners: z.array(ownerReference).optional(),
15
+ badges: z.array(badge).optional(),
16
+ });
@@ -0,0 +1,11 @@
1
+ import CustomDocsNav from './';
2
+ import type { SidebarSection } from './types';
3
+
4
+ interface CustomDocsNavWrapperProps {
5
+ sidebarItems: SidebarSection[];
6
+ currentPath: string;
7
+ }
8
+
9
+ export default function CustomDocsNavWrapper(props: CustomDocsNavWrapperProps) {
10
+ return <CustomDocsNav {...props} />;
11
+ }