@eventcatalog/core 2.31.4 → 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.
- package/dist/analytics/analytics.cjs +1 -1
- package/dist/analytics/analytics.js +2 -2
- package/dist/analytics/log-build.cjs +1 -1
- package/dist/analytics/log-build.js +3 -3
- package/dist/{chunk-W5HUNIMM.js → chunk-45XUM7UR.js} +1 -1
- package/dist/{chunk-C3M26NRD.js → chunk-NPIJWM72.js} +1 -1
- package/dist/{chunk-H5QIDJHP.js → chunk-VCKSLDEL.js} +1 -1
- package/dist/constants.cjs +1 -1
- package/dist/constants.js +1 -1
- package/dist/eventcatalog.cjs +1 -1
- package/dist/eventcatalog.js +3 -3
- package/eventcatalog/src/components/SideNav/CustomDocsNav.astro +1 -1
- package/eventcatalog/src/enterprise/custom-documentation/components/CustomDocsNav/CustomDocsNav.astro +9 -0
- package/eventcatalog/src/enterprise/custom-documentation/components/CustomDocsNav/components/NestedItem.tsx +26 -96
- package/eventcatalog/src/enterprise/custom-documentation/components/CustomDocsNav/index.tsx +19 -16
- package/eventcatalog/src/enterprise/custom-documentation/components/CustomDocsNav/types.ts +1 -0
- package/eventcatalog/src/enterprise/custom-documentation/pages/{index.astro → docs/custom/index.astro} +10 -5
- package/eventcatalog/src/enterprise/custom-documentation/utils/custom-docs.ts +6 -3
- package/eventcatalog/src/pages/docs/custom/[...path]/index.astro +4 -4
- package/package.json +1 -1
- package/eventcatalog/src/components/SideNav/CustomDocsNav/CustomDocsNavWrapper.tsx +0 -11
- package/eventcatalog/src/components/SideNav/CustomDocsNav/components/NestedItem.tsx +0 -183
- package/eventcatalog/src/components/SideNav/CustomDocsNav/components/NoResultsFound.tsx +0 -21
- package/eventcatalog/src/components/SideNav/CustomDocsNav/index.tsx +0 -250
- package/eventcatalog/src/components/SideNav/CustomDocsNav/types.ts +0 -29
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import {
|
|
2
2
|
log_build_default
|
|
3
|
-
} from "../chunk-
|
|
4
|
-
import "../chunk-
|
|
5
|
-
import "../chunk-
|
|
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
|
package/dist/constants.cjs
CHANGED
package/dist/constants.js
CHANGED
package/dist/eventcatalog.cjs
CHANGED
package/dist/eventcatalog.js
CHANGED
|
@@ -6,15 +6,15 @@ import {
|
|
|
6
6
|
} from "./chunk-UKJ7F5WR.js";
|
|
7
7
|
import {
|
|
8
8
|
log_build_default
|
|
9
|
-
} from "./chunk-
|
|
10
|
-
import "./chunk-
|
|
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-
|
|
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:
|
|
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
|
-
|
|
46
|
-
|
|
47
|
-
|
|
43
|
+
aria-hidden="true"
|
|
44
|
+
data-slot="icon"
|
|
45
|
+
className="h-3 w-3 text-gray-500"
|
|
48
46
|
>
|
|
49
|
-
<
|
|
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
|
|
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
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
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
|
|
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-
|
|
133
|
-
<div className="mb-2 px-
|
|
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-
|
|
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
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
+
aria-hidden="true"
|
|
174
|
+
data-slot="icon"
|
|
175
|
+
className="h-3 w-3 text-gray-500"
|
|
173
176
|
>
|
|
174
|
-
<
|
|
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
|
|
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}`);
|
|
@@ -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
|
|
11
|
-
|
|
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
|
|
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?:
|
|
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
|
|
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
|
-
|
|
25
|
-
|
|
26
|
-
Astro.redirect('/docs/custom');
|
|
25
|
+
if (!isEventCatalogProEnabled()) {
|
|
26
|
+
return Astro.redirect('/docs/custom');
|
|
27
27
|
}
|
|
28
28
|
---
|
|
29
29
|
|
package/package.json
CHANGED
|
@@ -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
|
-
}
|