@eventcatalog/core 2.31.3 → 2.31.5

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 (26) 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-34ONBQTK.js → chunk-45XUM7UR.js} +1 -1
  6. package/dist/{chunk-KYLVZEB2.js → chunk-NPIJWM72.js} +1 -1
  7. package/dist/{chunk-4EXYGKM6.js → chunk-VCKSLDEL.js} +1 -1
  8. package/dist/constants.cjs +1 -1
  9. package/dist/constants.js +1 -1
  10. package/dist/eventcatalog.cjs +1 -1
  11. package/dist/eventcatalog.js +3 -3
  12. package/eventcatalog/src/components/SideNav/CustomDocsNav.astro +1 -1
  13. package/eventcatalog/src/enterprise/custom-documentation/components/CustomDocsNav/CustomDocsNav.astro +9 -0
  14. package/eventcatalog/src/enterprise/custom-documentation/components/CustomDocsNav/components/NestedItem.tsx +26 -96
  15. package/eventcatalog/src/enterprise/custom-documentation/components/CustomDocsNav/index.tsx +19 -16
  16. package/eventcatalog/src/enterprise/custom-documentation/components/CustomDocsNav/types.ts +1 -0
  17. package/eventcatalog/src/enterprise/custom-documentation/pages/{index.astro → docs/custom/index.astro} +11 -6
  18. package/eventcatalog/src/enterprise/custom-documentation/utils/custom-docs.ts +6 -3
  19. package/eventcatalog/src/pages/docs/[type]/[id]/[version]/index.astro +2 -115
  20. package/eventcatalog/src/pages/docs/custom/[...path]/index.astro +4 -4
  21. package/package.json +1 -1
  22. package/eventcatalog/src/components/SideNav/CustomDocsNav/CustomDocsNavWrapper.tsx +0 -11
  23. package/eventcatalog/src/components/SideNav/CustomDocsNav/components/NestedItem.tsx +0 -183
  24. package/eventcatalog/src/components/SideNav/CustomDocsNav/components/NoResultsFound.tsx +0 -21
  25. package/eventcatalog/src/components/SideNav/CustomDocsNav/index.tsx +0 -250
  26. package/eventcatalog/src/components/SideNav/CustomDocsNav/types.ts +0 -29
@@ -37,7 +37,7 @@ var import_axios = __toESM(require("axios"), 1);
37
37
  var import_os = __toESM(require("os"), 1);
38
38
 
39
39
  // package.json
40
- var version = "2.31.3";
40
+ var version = "2.31.5";
41
41
 
42
42
  // src/constants.ts
43
43
  var VERSION = version;
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  raiseEvent
3
- } from "../chunk-34ONBQTK.js";
4
- import "../chunk-4EXYGKM6.js";
3
+ } from "../chunk-45XUM7UR.js";
4
+ import "../chunk-VCKSLDEL.js";
5
5
  export {
6
6
  raiseEvent
7
7
  };
@@ -106,7 +106,7 @@ var import_axios = __toESM(require("axios"), 1);
106
106
  var import_os = __toESM(require("os"), 1);
107
107
 
108
108
  // package.json
109
- var version = "2.31.3";
109
+ var version = "2.31.5";
110
110
 
111
111
  // src/constants.ts
112
112
  var VERSION = version;
@@ -1,8 +1,8 @@
1
1
  import {
2
2
  log_build_default
3
- } from "../chunk-KYLVZEB2.js";
4
- import "../chunk-34ONBQTK.js";
5
- import "../chunk-4EXYGKM6.js";
3
+ } from "../chunk-NPIJWM72.js";
4
+ import "../chunk-45XUM7UR.js";
5
+ import "../chunk-VCKSLDEL.js";
6
6
  import "../chunk-E7TXTI7G.js";
7
7
  export {
8
8
  log_build_default as default
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  VERSION
3
- } from "./chunk-4EXYGKM6.js";
3
+ } from "./chunk-VCKSLDEL.js";
4
4
 
5
5
  // src/analytics/analytics.js
6
6
  import axios from "axios";
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  raiseEvent
3
- } from "./chunk-34ONBQTK.js";
3
+ } from "./chunk-45XUM7UR.js";
4
4
  import {
5
5
  getEventCatalogConfigFile,
6
6
  verifyRequiredFieldsAreInCatalogConfigFile
@@ -1,5 +1,5 @@
1
1
  // package.json
2
- var version = "2.31.3";
2
+ var version = "2.31.5";
3
3
 
4
4
  // src/constants.ts
5
5
  var VERSION = version;
@@ -25,7 +25,7 @@ __export(constants_exports, {
25
25
  module.exports = __toCommonJS(constants_exports);
26
26
 
27
27
  // package.json
28
- var version = "2.31.3";
28
+ var version = "2.31.5";
29
29
 
30
30
  // src/constants.ts
31
31
  var VERSION = version;
package/dist/constants.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  VERSION
3
- } from "./chunk-4EXYGKM6.js";
3
+ } from "./chunk-VCKSLDEL.js";
4
4
  export {
5
5
  VERSION
6
6
  };
@@ -157,7 +157,7 @@ var import_axios = __toESM(require("axios"), 1);
157
157
  var import_os = __toESM(require("os"), 1);
158
158
 
159
159
  // package.json
160
- var version = "2.31.3";
160
+ var version = "2.31.5";
161
161
 
162
162
  // src/constants.ts
163
163
  var VERSION = version;
@@ -6,15 +6,15 @@ import {
6
6
  } from "./chunk-UKJ7F5WR.js";
7
7
  import {
8
8
  log_build_default
9
- } from "./chunk-KYLVZEB2.js";
10
- import "./chunk-34ONBQTK.js";
9
+ } from "./chunk-NPIJWM72.js";
10
+ import "./chunk-45XUM7UR.js";
11
11
  import {
12
12
  catalogToAstro,
13
13
  checkAndConvertMdToMdx
14
14
  } from "./chunk-7SI5EVOX.js";
15
15
  import {
16
16
  VERSION
17
- } from "./chunk-4EXYGKM6.js";
17
+ } from "./chunk-VCKSLDEL.js";
18
18
  import {
19
19
  isBackstagePluginEnabled,
20
20
  isEventCatalogProEnabled
@@ -6,4 +6,4 @@ const currentPath = Astro.url.pathname;
6
6
  const sidebarItems = await getNavigationItems();
7
7
  ---
8
8
 
9
- <CustomDocsNavWrapper client:load sidebarItems={sidebarItems} currentPath={currentPath} />
9
+ <CustomDocsNavWrapper client:only sidebarItems={sidebarItems} currentPath={currentPath} />
@@ -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:only sidebarItems={sidebarItems} currentPath={currentPath} />
@@ -27,7 +27,7 @@ const NestedItem: React.FC<NestedItemProps> = ({
27
27
  <div className="py-1">
28
28
  <div className="flex items-center">
29
29
  <button
30
- className="p-1 hover:bg-gray-100 rounded-md"
30
+ className="p-1 hover:bg-gray-100 rounded-md flex-shrink-0"
31
31
  onClick={(e) => {
32
32
  e.stopPropagation();
33
33
  toggleGroupCollapse(`nested-${itemId}`);
@@ -35,29 +35,34 @@ const NestedItem: React.FC<NestedItemProps> = ({
35
35
  >
36
36
  <div className={`transition-transform duration-150 ${collapsedGroups[`nested-${itemId}`] ? '' : 'rotate-180'}`}>
37
37
  <svg
38
- className="h-3 w-3 text-gray-500"
39
38
  xmlns="http://www.w3.org/2000/svg"
40
- width="16"
41
- height="16"
42
- viewBox="0 0 24 24"
43
39
  fill="none"
40
+ viewBox="0 0 24 24"
41
+ strokeWidth="1.5"
44
42
  stroke="currentColor"
45
- strokeWidth="2"
46
- strokeLinecap="round"
47
- strokeLinejoin="round"
43
+ aria-hidden="true"
44
+ data-slot="icon"
45
+ className="h-3 w-3 text-gray-500"
48
46
  >
49
- <polyline points="6 9 12 15 18 9" />
47
+ <path strokeLinecap="round" strokeLinejoin="round" d="m19.5 8.25-7.5 7.5-7.5-7.5"></path>
50
48
  </svg>
51
49
  </div>
52
50
  </button>
53
51
  <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"
52
+ className="flex items-center px-2 py-1 text-xs font-medium text-gray-700 rounded-md hover:bg-purple-50 min-w-0 flex-1"
55
53
  onClick={(e) => {
56
54
  e.stopPropagation();
57
55
  toggleGroupCollapse(`nested-${itemId}`);
58
56
  }}
59
57
  >
60
58
  <span className="truncate">{item.label}</span>
59
+ {item.badge && item?.badge?.text && (
60
+ <span
61
+ 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`}
62
+ >
63
+ {item.badge.text}
64
+ </span>
65
+ )}
61
66
  </button>
62
67
  </div>
63
68
 
@@ -67,92 +72,17 @@ const NestedItem: React.FC<NestedItemProps> = ({
67
72
  }`}
68
73
  >
69
74
  <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
- })}
75
+ {item.items.map((nestedItem: SidebarItem, nestedIndex: number) => (
76
+ <NestedItem
77
+ key={`nested-${itemId}-${nestedIndex}`}
78
+ item={nestedItem}
79
+ currentPath={currentPath}
80
+ parentId={itemId}
81
+ itemIndex={nestedIndex}
82
+ collapsedGroups={collapsedGroups}
83
+ toggleGroupCollapse={toggleGroupCollapse}
84
+ />
85
+ ))}
156
86
  </div>
157
87
  </div>
158
88
  </div>
@@ -7,7 +7,7 @@ import NoResultsFound from './components/NoResultsFound';
7
7
  const STORAGE_KEY = 'EventCatalog:customDocsSidebarCollapsedGroups';
8
8
  const DEBOUNCE_DELAY = 300; // 300ms debounce delay
9
9
 
10
- const CustomDocsNav: React.FC<CustomDocsNavProps> = ({ sidebarItems, currentPath }) => {
10
+ const CustomDocsNav: React.FC<CustomDocsNavProps> = ({ sidebarItems }) => {
11
11
  const navRef = useRef<HTMLElement>(null);
12
12
  const [searchTerm, setSearchTerm] = useState('');
13
13
  const [debouncedSearchTerm, setDebouncedSearchTerm] = useState('');
@@ -21,6 +21,8 @@ const CustomDocsNav: React.FC<CustomDocsNavProps> = ({ sidebarItems, currentPath
21
21
  return {};
22
22
  });
23
23
 
24
+ const currentPath = window.location.pathname;
25
+
24
26
  // Set up debounced search
25
27
  useEffect(() => {
26
28
  const timer = setTimeout(() => {
@@ -128,29 +130,32 @@ const CustomDocsNav: React.FC<CustomDocsNavProps> = ({ sidebarItems, currentPath
128
130
 
129
131
  const hasNoResults = debouncedSearchTerm && filteredSidebarItems.length === 0;
130
132
 
133
+ console.log('filteredSidebarItems', filteredSidebarItems);
134
+ console.log('currentPath', currentPath);
135
+
131
136
  return (
132
- <nav ref={navRef} className="h-full text-gray-800 pt-2">
133
- <div className="mb-2 px-4">
137
+ <nav ref={navRef} className="h-full text-gray-800 pt-4 overflow-y-auto">
138
+ <div className="mb-2 px-3 bg-white z-10">
134
139
  <input
135
140
  type="text"
136
141
  value={searchTerm}
137
142
  onChange={handleSearchChange}
138
143
  placeholder="Quick search..."
139
- className="w-full p-2 text-sm rounded-md border border-gray-200 h-[30px]"
144
+ className="w-full p-2 px-2 text-sm rounded-md border border-gray-200 h-[30px]"
140
145
  />
141
146
  </div>
142
147
 
143
- <div className="space-y-2 divide-y divide-gray-100/40">
148
+ <div className="space-y-2 divide-y divide-gray-100/40 pb-4">
144
149
  {hasNoResults ? (
145
150
  <NoResultsFound searchTerm={debouncedSearchTerm} />
146
151
  ) : (
147
152
  filteredSidebarItems.map((section: SidebarSection, index: number) => (
148
- <div className="pt-2 pb-2 px-4" key={`section-${index}`}>
153
+ <div className="pt-2 pb-2 px-3" key={`section-${index}`}>
149
154
  <div className="space-y-0" data-section={`section-${index}`}>
150
155
  {section.items ? (
151
156
  <div className="flex items-center">
152
157
  <button
153
- className="p-1 hover:bg-gray-100 rounded-md"
158
+ className="p-1 hover:bg-gray-100 rounded-md flex-shrink-0"
154
159
  onClick={(e) => {
155
160
  e.stopPropagation();
156
161
  toggleGroupCollapse(`section-${index}`);
@@ -160,23 +165,21 @@ const CustomDocsNav: React.FC<CustomDocsNavProps> = ({ sidebarItems, currentPath
160
165
  className={`transition-transform duration-150 ${collapsedGroups[`section-${index}`] ? '' : 'rotate-180'}`}
161
166
  >
162
167
  <svg
163
- className="h-3 w-3 text-gray-500"
164
168
  xmlns="http://www.w3.org/2000/svg"
165
- width="16"
166
- height="16"
167
- viewBox="0 0 24 24"
168
169
  fill="none"
170
+ viewBox="0 0 24 24"
171
+ strokeWidth="1.5"
169
172
  stroke="currentColor"
170
- strokeWidth="2"
171
- strokeLinecap="round"
172
- strokeLinejoin="round"
173
+ aria-hidden="true"
174
+ data-slot="icon"
175
+ className="h-3 w-3 text-gray-500"
173
176
  >
174
- <polyline points="6 9 12 15 18 9" />
177
+ <path strokeLinecap="round" strokeLinejoin="round" d="m19.5 8.25-7.5 7.5-7.5-7.5"></path>
175
178
  </svg>
176
179
  </div>
177
180
  </button>
178
181
  <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"
182
+ className="flex items-center justify-between px-2 py-0.5 text-xs font-bold rounded-md hover:bg-purple-50 min-w-0 flex-1"
180
183
  onClick={(e) => {
181
184
  e.stopPropagation();
182
185
  toggleGroupCollapse(`section-${index}`);
@@ -15,6 +15,7 @@ export interface SidebarSection {
15
15
  slug?: string;
16
16
  autogenerated?: {
17
17
  directory: string;
18
+ collapsed?: boolean;
18
19
  };
19
20
  badge?: {
20
21
  text: string;
@@ -1,14 +1,17 @@
1
1
  ---
2
2
  import VerticalSideBarLayout from '@layouts/VerticalSideBarLayout.astro';
3
3
  import { render } from 'astro:content';
4
- import { buildUrl } from '@utils/url-builder';
5
4
  import config from '@config';
6
5
  import { AlignLeftIcon } from 'lucide-react';
6
+
7
7
  import mdxComponents from '@components/MDX/components';
8
8
  import OwnersList from '@components/Lists/OwnersList';
9
+
9
10
  import { getOwner } from '@utils/collections/owners';
10
- import CustomDocsNav from '@components/SideNav/CustomDocsNav.astro';
11
- import { getAdjacentPages } from '../utils/custom-docs';
11
+ import { buildUrl } from '@utils/url-builder';
12
+
13
+ import CustomDocsNav from '@enterprise/custom-documentation/components/CustomDocsNav/CustomDocsNav.astro';
14
+ import { getAdjacentPages } from '@enterprise/custom-documentation/utils/custom-docs';
12
15
 
13
16
  const props = Astro.props;
14
17
  const doc = props.data;
@@ -72,14 +75,16 @@ const badges = doc?.badges || [];
72
75
  ---
73
76
 
74
77
  <VerticalSideBarLayout title={doc.title || 'Documentation'}>
75
- <div class="flex w-full">
78
+ <div class="flex w-full" data-pagefind-body data-pagefind-meta={`title:${doc.title}`}>
76
79
  <!-- Left Sidebar Navigation -->
77
80
  <aside class="sidebar-transition overflow-y-auto bg-white border-r border-gray-100 w-80 fixed top-16 bottom-0 z-10">
78
81
  <CustomDocsNav />
79
82
  </aside>
80
83
 
81
84
  <!-- Main Content Area - Independent scrolling -->
82
- <main class="sidebar-transition w-full max-h-content ml-[22em] 2xl:ml-[24em] mr-80 lg:mr-[20em] max-w-5xl mx-auto">
85
+ <main
86
+ class="sidebar-transition w-full max-h-content ml-[22em] md:ml-[21em] lg:mr-[21em] 2xl:mr-[26em] 2xl:ml-[22em] mr-80 max-w-5xl mx-auto"
87
+ >
83
88
  <div class="max-w-7xl mx-auto px-6 py-10">
84
89
  <div class="border-b border-gray-200 flex justify-between items-start md:pb-6">
85
90
  <div>
@@ -223,7 +228,7 @@ const badges = doc?.badges || [];
223
228
  let observerPaused = false;
224
229
 
225
230
  // Function to highlight a TOC item
226
- function highlightTocItem(id) {
231
+ function highlightTocItem(id: string) {
227
232
  // Remove active class from all links
228
233
  document.querySelectorAll('.active-toc-item').forEach((link) => {
229
234
  link.classList.remove('active-toc-item', 'text-purple-600', 'font-light');
@@ -20,10 +20,11 @@ type SidebarItem = {
20
20
 
21
21
  type SideBarConfigurationItem = {
22
22
  label: string;
23
- items?: SidebarItem[];
23
+ items?: SideBarConfigurationItem[];
24
24
  slug?: string;
25
25
  autogenerated?: {
26
26
  directory: string;
27
+ collapsed?: boolean;
27
28
  };
28
29
  badge?: Badge;
29
30
  collapsed?: boolean;
@@ -78,6 +79,8 @@ const processAutoGeneratedDirectory = async (
78
79
 
79
80
  return {
80
81
  label,
82
+ badge,
83
+ collapsed,
81
84
  items: filteredEntries.map((entry) => ({
82
85
  label: entry?.data?.title,
83
86
  slug: entry?.data?.slug || entry?.id.replace(DOCS_DIR, ''),
@@ -98,13 +101,13 @@ const processSidebarItems = async (items: SideBarConfigurationItem[]): Promise<S
98
101
  item.autogenerated.directory,
99
102
  item.label,
100
103
  item.badge,
101
- item.collapsed
104
+ item.autogenerated.collapsed !== undefined ? item.autogenerated.collapsed : item.collapsed
102
105
  );
103
106
  processedItems.push(processedItem);
104
107
  }
105
108
  // If item has nested items, process them recursively
106
109
  else if (item.items && item.items.length > 0) {
107
- const processedNestedItems = await processSidebarItems(item.items as SideBarConfigurationItem[]);
110
+ const processedNestedItems = await processSidebarItems(item.items);
108
111
  processedItems.push({
109
112
  label: item.label,
110
113
  slug: item.slug,
@@ -268,126 +268,13 @@ const pagefindAttributes =
268
268
  if (document.getElementsByClassName('mermaid').length > 0) {
269
269
  renderDiagrams(graphs);
270
270
  }
271
-
272
- // Set up TOC highlighting and scrolling
273
- setupTOCHighlighting();
274
271
  });
275
272
 
276
- /**
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
273
  /**
387
274
  * Renders mermaid diagrams in the page
388
275
  * @param {HTMLCollectionOf<HTMLElement>} graphs - The collection of mermaid graph elements
389
276
  */
390
- async function renderDiagrams(graphs) {
277
+ async function renderDiagrams(graphs: any) {
391
278
  const { default: mermaid } = await import('mermaid');
392
279
 
393
280
  if (window.eventcatalog.mermaid) {
@@ -395,7 +282,7 @@ const pagefindAttributes =
395
282
  const { iconPacks = [] } = window.eventcatalog.mermaid ?? {};
396
283
 
397
284
  if (iconPacks.length > 0) {
398
- const iconPacksToRegister = iconPacks.map((name) => {
285
+ const iconPacksToRegister = iconPacks.map((name: any) => {
399
286
  return {
400
287
  name,
401
288
  icons,
@@ -1,6 +1,7 @@
1
1
  ---
2
- import CustomDocumentationPage from '@enterprise/custom-documentation/pages/index.astro';
2
+ import CustomDocumentationPage from '@enterprise/custom-documentation/pages/docs/custom/index.astro';
3
3
  import { getCollection } from 'astro:content';
4
+ import { buildUrl } from '@utils/url-builder';
4
5
  import type { GetStaticPaths } from 'astro';
5
6
  import { isEventCatalogProEnabled } from '@utils/feature';
6
7
  import path from 'node:path';
@@ -21,9 +22,8 @@ export const getStaticPaths = (async () => {
21
22
 
22
23
  const props = Astro.props;
23
24
 
24
- // Redirect
25
- if (!directoryExists || !isEventCatalogProEnabled()) {
26
- Astro.redirect('/docs/custom');
25
+ if (!isEventCatalogProEnabled()) {
26
+ return Astro.redirect('/docs/custom');
27
27
  }
28
28
  ---
29
29
 
package/package.json CHANGED
@@ -6,7 +6,7 @@
6
6
  "url": "https://github.com/event-catalog/eventcatalog.git"
7
7
  },
8
8
  "type": "module",
9
- "version": "2.31.3",
9
+ "version": "2.31.5",
10
10
  "publishConfig": {
11
11
  "access": "public"
12
12
  },
@@ -1,11 +0,0 @@
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
- }
@@ -1,183 +0,0 @@
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);
@@ -1,21 +0,0 @@
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);
@@ -1,250 +0,0 @@
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);
@@ -1,29 +0,0 @@
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
- }