@eventcatalog/core 2.31.4 → 2.32.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.
Files changed (39) 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-C3M26NRD.js → chunk-EIEK445B.js} +1 -1
  6. package/dist/{chunk-W5HUNIMM.js → chunk-NPZQE3LM.js} +1 -1
  7. package/dist/{chunk-H5QIDJHP.js → chunk-YXHR3YSA.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/Lists/CustomSideBarSectionList.astro +67 -0
  13. package/eventcatalog/src/components/MDX/MessageTable/MessageTable.client.tsx +2 -2
  14. package/eventcatalog/src/components/MDX/ResourceGroupTable/ResourceGroupTable.astro +126 -0
  15. package/eventcatalog/src/components/MDX/ResourceGroupTable/ResourceGroupTable.client.tsx +408 -0
  16. package/eventcatalog/src/components/MDX/components.tsx +2 -0
  17. package/eventcatalog/src/components/SideBars/DomainSideBar.astro +8 -0
  18. package/eventcatalog/src/components/SideBars/FlowSideBar.astro +8 -1
  19. package/eventcatalog/src/components/SideBars/MessageSideBar.astro +8 -0
  20. package/eventcatalog/src/components/SideBars/ServiceSideBar.astro +8 -1
  21. package/eventcatalog/src/components/SideNav/CustomDocsNav.astro +1 -1
  22. package/eventcatalog/src/components/Tables/columns/ServiceTableColumns.tsx +4 -6
  23. package/eventcatalog/src/components/Tables/columns/TeamsTableColumns.tsx +0 -15
  24. package/eventcatalog/src/content.config.ts +17 -0
  25. package/eventcatalog/src/enterprise/custom-documentation/components/CustomDocsNav/CustomDocsNav.astro +9 -0
  26. package/eventcatalog/src/enterprise/custom-documentation/components/CustomDocsNav/components/NestedItem.tsx +26 -96
  27. package/eventcatalog/src/enterprise/custom-documentation/components/CustomDocsNav/index.tsx +19 -16
  28. package/eventcatalog/src/enterprise/custom-documentation/components/CustomDocsNav/types.ts +1 -0
  29. package/eventcatalog/src/enterprise/custom-documentation/pages/{index.astro → docs/custom/index.astro} +10 -5
  30. package/eventcatalog/src/enterprise/custom-documentation/utils/custom-docs.ts +6 -3
  31. package/eventcatalog/src/pages/docs/custom/[...path]/index.astro +4 -4
  32. package/eventcatalog/src/utils/collections/icons.ts +29 -0
  33. package/eventcatalog/src/utils/collections/services.ts +4 -4
  34. package/package.json +1 -1
  35. package/eventcatalog/src/components/SideNav/CustomDocsNav/CustomDocsNavWrapper.tsx +0 -11
  36. package/eventcatalog/src/components/SideNav/CustomDocsNav/components/NestedItem.tsx +0 -183
  37. package/eventcatalog/src/components/SideNav/CustomDocsNav/components/NoResultsFound.tsx +0 -21
  38. package/eventcatalog/src/components/SideNav/CustomDocsNav/index.tsx +0 -250
  39. package/eventcatalog/src/components/SideNav/CustomDocsNav/types.ts +0 -29
@@ -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>
@@ -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,
@@ -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
 
@@ -43,3 +43,32 @@ export const getIconForCollection = (collection: string) => {
43
43
  return ServerIcon;
44
44
  }
45
45
  };
46
+
47
+ export const getColorAndIconForCollection = (collection: string) => {
48
+ const icon = getIconForCollection(collection);
49
+
50
+ switch (collection) {
51
+ case 'events':
52
+ return { color: 'orange', Icon: icon };
53
+ case 'commands':
54
+ return { color: 'blue', Icon: icon };
55
+ case 'queries':
56
+ return { color: 'green', Icon: icon };
57
+ case 'flows':
58
+ return { color: 'teal', Icon: icon };
59
+ case 'teams':
60
+ return { color: 'red', Icon: icon };
61
+ case 'users':
62
+ return { color: 'gray', Icon: icon };
63
+ case 'channels':
64
+ return { color: 'purple', Icon: icon };
65
+ case 'ubiquitousLanguages':
66
+ return { color: 'green', Icon: icon };
67
+ case 'domains':
68
+ return { color: 'yellow', Icon: icon };
69
+ case 'services':
70
+ return { color: 'pink', Icon: icon };
71
+ default:
72
+ return { color: 'gray', Icon: icon };
73
+ }
74
+ };
@@ -21,10 +21,10 @@ let cachedServices: Record<string, Service[]> = {
21
21
  export const getServices = async ({ getAllVersions = true }: Props = {}): Promise<Service[]> => {
22
22
  const cacheKey = getAllVersions ? 'allVersions' : 'currentVersions';
23
23
 
24
- // // Check if we have cached domains for this specific getAllVersions value
25
- // if (cachedServices[cacheKey].length > 0) {
26
- // return cachedServices[cacheKey];
27
- // }
24
+ // Check if we have cached domains for this specific getAllVersions value
25
+ if (cachedServices[cacheKey].length > 0) {
26
+ return cachedServices[cacheKey];
27
+ }
28
28
 
29
29
  // Get services that are not versioned
30
30
  const services = await getCollection('services', (service) => {
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.4",
9
+ "version": "2.32.0",
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);