@eventcatalog/core 3.0.0-beta.8 → 3.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +41 -98
- package/dist/__mocks__/astro-content.cjs +32 -0
- package/dist/__mocks__/astro-content.d.cts +13 -0
- package/dist/__mocks__/astro-content.d.ts +13 -0
- package/dist/__mocks__/astro-content.js +7 -0
- 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/catalog-to-astro-content-directory.cjs +2 -19
- package/dist/catalog-to-astro-content-directory.d.cts +1 -2
- package/dist/catalog-to-astro-content-directory.d.ts +1 -2
- package/dist/catalog-to-astro-content-directory.js +3 -5
- package/dist/{chunk-R2BJ7MJG.js → chunk-6Z6ARMQS.js} +1 -17
- package/dist/{chunk-LQUXA3NB.js → chunk-BYP43AAT.js} +1 -1
- package/dist/{chunk-UTHNQFM7.js → chunk-E5Q7TZYT.js} +1 -1
- package/dist/{chunk-KEYJ3FB3.js → chunk-EKGR533N.js} +1 -1
- package/dist/{chunk-7MCE4J6I.js → chunk-KF5PARQK.js} +1 -1
- package/dist/{chunk-I3QUYHIK.js → chunk-VO5WYA44.js} +1 -1
- package/dist/constants.cjs +1 -1
- package/dist/constants.js +1 -1
- package/dist/eventcatalog.cjs +20 -64
- package/dist/eventcatalog.config.d.cts +4 -0
- package/dist/eventcatalog.config.d.ts +4 -0
- package/dist/eventcatalog.js +26 -52
- package/dist/generate.cjs +1 -1
- package/dist/generate.js +3 -3
- package/dist/utils/cli-logger.cjs +1 -1
- package/dist/utils/cli-logger.js +2 -2
- package/eventcatalog/astro.config.mjs +4 -1
- package/eventcatalog/integrations/eventcatalog-features.ts +69 -0
- package/eventcatalog/public/icons/asyncapi-black.svg +2 -0
- package/eventcatalog/public/icons/graphql-black.svg +1 -0
- package/eventcatalog/public/icons/openapi-black.svg +1 -0
- package/eventcatalog/src/components/ChatPanel/ChatPanel.tsx +994 -0
- package/eventcatalog/src/components/ChatPanel/ChatPanelButton.tsx +24 -0
- package/eventcatalog/src/components/Grids/DomainGrid.tsx +310 -173
- package/eventcatalog/src/components/Grids/MessageGrid.tsx +299 -180
- package/eventcatalog/src/components/Grids/specification-utils.ts +106 -0
- package/eventcatalog/src/components/Header.astro +25 -5
- package/eventcatalog/src/components/MDX/NodeGraph/NodeGraph.tsx +14 -3
- package/eventcatalog/src/components/SchemaExplorer/ApiAccessSection.tsx +95 -90
- package/eventcatalog/src/components/SchemaExplorer/ApiContentViewer.tsx +144 -0
- package/eventcatalog/src/components/SchemaExplorer/Pagination.tsx +34 -8
- package/eventcatalog/src/components/SchemaExplorer/SchemaContentViewer.tsx +2 -2
- package/eventcatalog/src/components/SchemaExplorer/SchemaDetailsHeader.tsx +140 -109
- package/eventcatalog/src/components/SchemaExplorer/SchemaDetailsPanel.tsx +5 -14
- package/eventcatalog/src/components/SchemaExplorer/SchemaExplorer.tsx +247 -59
- package/eventcatalog/src/components/SchemaExplorer/SchemaFilters.tsx +64 -126
- package/eventcatalog/src/components/SchemaExplorer/SchemaListItem.tsx +41 -43
- package/eventcatalog/src/components/Search/Search.astro +2 -2
- package/eventcatalog/src/components/Search/SearchDataLoader.astro +25 -0
- package/eventcatalog/src/components/SideNav/NestedSideBar/SearchBar.tsx +6 -3
- package/eventcatalog/src/components/SideNav/NestedSideBar/index.tsx +44 -16
- package/eventcatalog/src/components/SideNav/SideNav.astro +0 -15
- package/eventcatalog/src/components/Tables/Table.tsx +96 -77
- package/eventcatalog/src/components/Tables/columns/ContainersTableColumns.tsx +108 -74
- package/eventcatalog/src/components/Tables/columns/DomainTableColumns.tsx +74 -55
- package/eventcatalog/src/components/Tables/columns/FlowTableColumns.tsx +36 -36
- package/eventcatalog/src/components/Tables/columns/MessageTableColumns.tsx +110 -77
- package/eventcatalog/src/components/Tables/columns/ServiceTableColumns.tsx +105 -94
- package/eventcatalog/src/components/Tables/columns/SharedColumns.tsx +31 -26
- package/eventcatalog/src/components/Tables/columns/TeamsTableColumns.tsx +115 -215
- package/eventcatalog/src/components/Tables/columns/UserTableColumns.tsx +145 -243
- package/eventcatalog/src/content.config.ts +1 -13
- package/eventcatalog/src/enterprise/ai/chat-api.ts +360 -0
- package/eventcatalog/src/enterprise/auth/[...auth].ts +3 -0
- package/eventcatalog/src/enterprise/auth/login.astro +420 -0
- package/eventcatalog/src/enterprise/collections/index.ts +0 -1
- package/eventcatalog/src/layouts/Footer.astro +8 -5
- package/eventcatalog/src/layouts/VerticalSideBarLayout.astro +133 -117
- package/eventcatalog/src/pages/_index.astro +243 -559
- package/eventcatalog/src/pages/architecture/[type]/[id]/[version]/_index.data.ts +8 -2
- package/eventcatalog/src/pages/architecture/[type]/[id]/[version]/index.astro +9 -5
- package/eventcatalog/src/pages/directory/[type]/index.astro +6 -0
- package/eventcatalog/src/pages/docs/[type]/[id]/[version]/asyncapi/[filename].astro +19 -3
- package/eventcatalog/src/pages/docs/[type]/[id]/[version]/changelog/index.astro +7 -7
- package/eventcatalog/src/pages/docs/[type]/[id]/[version]/graphql/[filename].astro +1 -1
- package/eventcatalog/src/pages/docs/[type]/[id]/[version]/index.astro +10 -7
- package/eventcatalog/src/pages/docs/[type]/[id]/language/index.astro +194 -121
- package/eventcatalog/src/pages/docs/teams/[id]/index.astro +94 -70
- package/eventcatalog/src/pages/docs/teams/[id].mdx.ts +36 -0
- package/eventcatalog/src/pages/docs/users/[id]/index.astro +56 -45
- package/eventcatalog/src/pages/docs/users/[id].mdx.ts +36 -0
- package/eventcatalog/src/pages/schemas/explorer/_index.data.ts +178 -0
- package/eventcatalog/src/pages/schemas/explorer/index.astro +7 -157
- package/eventcatalog/src/pages/studio.astro +124 -72
- package/eventcatalog/src/remark-plugins/directives.ts +30 -9
- package/eventcatalog/src/{components/SideNav/NestedSideBar → stores/sidebar-store}/builders/container.ts +10 -1
- package/eventcatalog/src/{components/SideNav/NestedSideBar → stores/sidebar-store}/builders/domain.ts +17 -7
- package/eventcatalog/src/{components/SideNav/NestedSideBar → stores/sidebar-store}/builders/message.ts +10 -1
- package/eventcatalog/src/{components/SideNav/NestedSideBar → stores/sidebar-store}/builders/service.ts +11 -4
- package/eventcatalog/src/{components/SideNav/NestedSideBar → stores/sidebar-store}/builders/shared.ts +14 -0
- package/eventcatalog/src/stores/{sidebar-store.ts → sidebar-store/index.ts} +1 -1
- package/eventcatalog/src/utils/collections/channels.ts +0 -2
- package/eventcatalog/src/utils/collections/commands.ts +0 -2
- package/eventcatalog/src/utils/collections/containers.ts +0 -2
- package/eventcatalog/src/utils/collections/domains.ts +0 -2
- package/eventcatalog/src/utils/collections/entities.ts +0 -2
- package/eventcatalog/src/utils/collections/events.ts +0 -2
- package/eventcatalog/src/utils/collections/flows.ts +0 -2
- package/eventcatalog/src/utils/collections/queries.ts +0 -2
- package/eventcatalog/src/utils/collections/schemas.ts +45 -7
- package/eventcatalog/src/utils/collections/services.ts +0 -2
- package/eventcatalog/src/utils/feature.ts +9 -5
- package/eventcatalog/src/utils/node-graphs/services-node-graph.ts +1 -1
- package/eventcatalog/src/utils/resource-files.ts +86 -0
- package/package.json +12 -15
- package/default-files-for-collections/changelogs.md +0 -5
- package/default-files-for-collections/channels.md +0 -8
- package/default-files-for-collections/commands.md +0 -8
- package/default-files-for-collections/domains.md +0 -8
- package/default-files-for-collections/events.md +0 -8
- package/default-files-for-collections/flows.md +0 -11
- package/default-files-for-collections/queries.md +0 -8
- package/default-files-for-collections/services.md +0 -8
- package/default-files-for-collections/ubiquitousLanguages.md +0 -7
- package/eventcatalog/src/enterprise/collections/chat-prompts.ts +0 -32
- package/eventcatalog/src/enterprise/eventcatalog-chat/components/Chat.tsx +0 -60
- package/eventcatalog/src/enterprise/eventcatalog-chat/components/ChatMessage.tsx +0 -414
- package/eventcatalog/src/enterprise/eventcatalog-chat/components/ChatSidebar.tsx +0 -169
- package/eventcatalog/src/enterprise/eventcatalog-chat/components/InputModal.tsx +0 -244
- package/eventcatalog/src/enterprise/eventcatalog-chat/components/MentionInput.tsx +0 -211
- package/eventcatalog/src/enterprise/eventcatalog-chat/components/WelcomePromptArea.tsx +0 -176
- package/eventcatalog/src/enterprise/eventcatalog-chat/components/default-prompts.ts +0 -93
- package/eventcatalog/src/enterprise/eventcatalog-chat/components/hooks/ChatProvider.tsx +0 -143
- package/eventcatalog/src/enterprise/eventcatalog-chat/components/windows/ChatWindow.server.tsx +0 -387
- package/eventcatalog/src/enterprise/eventcatalog-chat/pages/api/chat.ts +0 -59
- package/eventcatalog/src/enterprise/eventcatalog-chat/pages/chat/index.astro +0 -104
- package/eventcatalog/src/enterprise/eventcatalog-chat/providers/ai-provider.ts +0 -140
- package/eventcatalog/src/enterprise/eventcatalog-chat/providers/anthropic.ts +0 -28
- package/eventcatalog/src/enterprise/eventcatalog-chat/providers/google.ts +0 -41
- package/eventcatalog/src/enterprise/eventcatalog-chat/providers/index.ts +0 -26
- package/eventcatalog/src/enterprise/eventcatalog-chat/providers/openai.ts +0 -61
- package/eventcatalog/src/enterprise/eventcatalog-chat/utils/chat-prompts.ts +0 -50
- package/eventcatalog/src/pages/auth/login.astro +0 -280
- package/eventcatalog/src/pages/chat/feature.astro +0 -179
- package/eventcatalog/src/pages/chat/index.astro +0 -10
- package/eventcatalog/src/pages/docs/_default-docs.mdx +0 -25
- package/eventcatalog/src/pages/docs/index.astro +0 -33
- package/eventcatalog/src/pages/nav-index.json.ts +0 -30
- /package/eventcatalog/src/{pages → enterprise}/auth/error.astro +0 -0
- /package/eventcatalog/src/{middleware-auth.ts → enterprise/auth/middleware/middleware-auth.ts} +0 -0
- /package/eventcatalog/src/{middleware.ts → enterprise/auth/middleware/middleware.ts} +0 -0
- /package/eventcatalog/src/{pages/unauthorized/index.astro → enterprise/auth/unauthorized.astro} +0 -0
- /package/eventcatalog/src/{pages → enterprise}/plans/index.astro +0 -0
- /package/eventcatalog/src/{components/SideNav/NestedSideBar → stores/sidebar-store}/builders/flow.ts +0 -0
- /package/eventcatalog/src/{components/SideNav/NestedSideBar/sidebar-builder.ts → stores/sidebar-store/state.ts} +0 -0
|
@@ -8,64 +8,62 @@ interface SchemaListItemProps {
|
|
|
8
8
|
isSelected: boolean;
|
|
9
9
|
versions: SchemaItem[];
|
|
10
10
|
onClick: () => void;
|
|
11
|
-
itemRef?: React.
|
|
11
|
+
itemRef?: React.Ref<HTMLButtonElement>;
|
|
12
12
|
}
|
|
13
13
|
|
|
14
14
|
export default function SchemaListItem({ message, isSelected, versions, onClick, itemRef }: SchemaListItemProps) {
|
|
15
15
|
const { color, Icon } = getCollectionStyles(message.collection);
|
|
16
16
|
const hasMultipleVersions = versions.length > 1;
|
|
17
17
|
|
|
18
|
+
// Get the schema icon
|
|
19
|
+
const ext = message.schemaExtension?.toLowerCase();
|
|
20
|
+
const hasSchemaIcon = ['openapi', 'asyncapi', 'graphql', 'avro', 'json', 'proto'].includes(ext || '');
|
|
21
|
+
const iconName = ext === 'json' ? 'json-schema' : ext;
|
|
22
|
+
|
|
18
23
|
return (
|
|
19
24
|
<button
|
|
20
25
|
ref={itemRef}
|
|
21
26
|
onClick={onClick}
|
|
22
|
-
className={`w-full text-left
|
|
23
|
-
isSelected ? `bg-${color}-50 border-l
|
|
27
|
+
className={`w-full text-left px-3 py-2 transition-all duration-75 group border-l-2 ${
|
|
28
|
+
isSelected ? `bg-${color}-50 border-l-${color}-500` : 'hover:bg-gray-50 border-l-transparent'
|
|
24
29
|
}`}
|
|
25
30
|
>
|
|
26
|
-
<div className="flex items-
|
|
27
|
-
|
|
31
|
+
<div className="flex items-center gap-2.5">
|
|
32
|
+
{/* Collection Icon */}
|
|
33
|
+
<div
|
|
34
|
+
className={`flex-shrink-0 flex items-center justify-center w-7 h-7 rounded-md ${
|
|
35
|
+
isSelected ? `bg-${color}-100` : `bg-${color}-100/60`
|
|
36
|
+
}`}
|
|
37
|
+
>
|
|
38
|
+
<Icon className={`h-3.5 w-3.5 text-${color}-600`} />
|
|
39
|
+
</div>
|
|
40
|
+
|
|
28
41
|
<div className="flex-1 min-w-0">
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
ext === 'json' ||
|
|
46
|
-
ext === 'proto'
|
|
47
|
-
) {
|
|
48
|
-
// Map json extension to json-schema icon
|
|
49
|
-
const iconName = ext === 'json' ? 'json-schema' : ext;
|
|
50
|
-
const iconPath = buildUrl(`/icons/${iconName}.svg`, true);
|
|
51
|
-
return (
|
|
52
|
-
<>
|
|
53
|
-
<img src={iconPath} alt={`${ext} icon`} className="h-3 w-3" />
|
|
54
|
-
{getSchemaTypeLabel(message.schemaExtension)}
|
|
55
|
-
</>
|
|
56
|
-
);
|
|
57
|
-
}
|
|
58
|
-
return getSchemaTypeLabel(message.schemaExtension);
|
|
59
|
-
})()}
|
|
60
|
-
</span>
|
|
61
|
-
{hasMultipleVersions && (
|
|
62
|
-
<span className="inline-flex items-center rounded-full bg-blue-100 px-1 py-0.5 text-xs font-medium text-blue-700">
|
|
63
|
-
{versions.length} versions
|
|
64
|
-
</span>
|
|
42
|
+
{/* Name row with version */}
|
|
43
|
+
<div className="flex items-center gap-1.5">
|
|
44
|
+
<span className={`text-[13px] font-semibold truncate ${isSelected ? 'text-gray-900' : 'text-gray-700'}`}>
|
|
45
|
+
{message.data.name}
|
|
46
|
+
</span>
|
|
47
|
+
<span className={`text-[10px] tabular-nums flex-shrink-0 ${isSelected ? 'text-gray-500' : 'text-gray-400'}`}>
|
|
48
|
+
v{message.data.version}
|
|
49
|
+
</span>
|
|
50
|
+
</div>
|
|
51
|
+
|
|
52
|
+
{/* Meta row */}
|
|
53
|
+
<div className="flex items-center gap-1.5 mt-0.5">
|
|
54
|
+
{/* Schema Format */}
|
|
55
|
+
<span className={`inline-flex items-center gap-1 text-[10px] ${isSelected ? 'text-gray-600' : 'text-gray-500'}`}>
|
|
56
|
+
{hasSchemaIcon && (
|
|
57
|
+
<img src={buildUrl(`/icons/${iconName}.svg`, true)} alt={`${ext} icon`} className="h-3 w-3 opacity-70" />
|
|
65
58
|
)}
|
|
66
|
-
|
|
59
|
+
{getSchemaTypeLabel(message.schemaExtension)}
|
|
60
|
+
</span>
|
|
61
|
+
|
|
62
|
+
{/* Versions count */}
|
|
63
|
+
{hasMultipleVersions && (
|
|
64
|
+
<span className={`text-[10px] ${isSelected ? 'text-gray-500' : 'text-gray-400'}`}>· {versions.length}v</span>
|
|
65
|
+
)}
|
|
67
66
|
</div>
|
|
68
|
-
{message.data.summary && <p className="text-xs text-gray-600 line-clamp-2">{message.data.summary}</p>}
|
|
69
67
|
</div>
|
|
70
68
|
</div>
|
|
71
69
|
</button>
|
|
@@ -4,7 +4,7 @@ import SearchModal from './SearchModal.tsx';
|
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
<div>
|
|
7
|
-
<div class="relative flex items-center w-
|
|
7
|
+
<div class="relative flex items-center w-full pr-4">
|
|
8
8
|
<input
|
|
9
9
|
id="search-dummy-input"
|
|
10
10
|
type="text"
|
|
@@ -14,7 +14,7 @@ import SearchModal from './SearchModal.tsx';
|
|
|
14
14
|
class="block w-full rounded-md caret-transparent border-0 py-1.5 pr-14 pl-10 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 font-light sm:text-sm sm:leading-6 px-4"
|
|
15
15
|
/>
|
|
16
16
|
<MagnifyingGlassIcon className="absolute inset-y-0 left-0 h-9 w-8 flex items-center pl-4 text-gray-400" />
|
|
17
|
-
<div class="absolute inset-y-0 right-0 flex py-1.5 pr-
|
|
17
|
+
<div class="absolute inset-y-0 right-0 flex py-1.5 pr-6">
|
|
18
18
|
<kbd class="inline-flex items-center rounded px-1 font-sans text-xs text-gray-400">⌘K</kbd>
|
|
19
19
|
</div>
|
|
20
20
|
</div>
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
---
|
|
2
|
+
/**
|
|
3
|
+
* SearchDataLoader.astro
|
|
4
|
+
*
|
|
5
|
+
* This component loads the sidebar/search data independently of the sidebar UI.
|
|
6
|
+
* It ensures the search functionality works on all pages, even when the nested
|
|
7
|
+
* sidebar is not rendered (e.g., /discover pages).
|
|
8
|
+
*/
|
|
9
|
+
import { getNestedSideBarData } from '@stores/sidebar-store/state';
|
|
10
|
+
|
|
11
|
+
const props = await getNestedSideBarData();
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
<script is:inline define:vars={{ props }}>
|
|
15
|
+
window.sidebarData = props;
|
|
16
|
+
</script>
|
|
17
|
+
|
|
18
|
+
<script>
|
|
19
|
+
import { setSidebarData } from '@stores/sidebar-store';
|
|
20
|
+
|
|
21
|
+
const data = (window as any).sidebarData;
|
|
22
|
+
if (data) {
|
|
23
|
+
setSidebarData(data);
|
|
24
|
+
}
|
|
25
|
+
</script>
|
|
@@ -17,7 +17,7 @@ import {
|
|
|
17
17
|
ListOrdered,
|
|
18
18
|
ArrowLeftRight,
|
|
19
19
|
} from 'lucide-react';
|
|
20
|
-
import type { NavNode } from '
|
|
20
|
+
import type { NavNode } from '@stores/sidebar-store/state';
|
|
21
21
|
|
|
22
22
|
const cn = (...classes: (string | false | undefined)[]) => classes.filter(Boolean).join(' ');
|
|
23
23
|
|
|
@@ -178,8 +178,9 @@ export default function SearchBar({ nodes, onSelectResult, onSearchChange }: Pro
|
|
|
178
178
|
<button
|
|
179
179
|
onClick={clearSearch}
|
|
180
180
|
className="absolute right-3 top-1/2 -translate-y-1/2 text-gray-400 hover:text-gray-600"
|
|
181
|
+
aria-label="Clear search"
|
|
181
182
|
>
|
|
182
|
-
<X className="w-4 h-4" />
|
|
183
|
+
<X className="w-4 h-4" aria-hidden="true" />
|
|
183
184
|
</button>
|
|
184
185
|
)}
|
|
185
186
|
</div>
|
|
@@ -193,8 +194,10 @@ export default function SearchBar({ nodes, onSelectResult, onSearchChange }: Pro
|
|
|
193
194
|
? 'bg-purple-50 border-purple-200 text-purple-600'
|
|
194
195
|
: 'bg-gray-50 border-gray-200 text-gray-400 hover:text-gray-600 hover:bg-gray-100'
|
|
195
196
|
)}
|
|
197
|
+
aria-label="Filter search results"
|
|
198
|
+
aria-expanded={showFilterDropdown}
|
|
196
199
|
>
|
|
197
|
-
<SlidersHorizontal className="w-4 h-4" />
|
|
200
|
+
<SlidersHorizontal className="w-4 h-4" aria-hidden="true" />
|
|
198
201
|
{searchFilters.size > 0 && (
|
|
199
202
|
<span className="absolute -top-1 -right-1 w-4 h-4 bg-purple-600 text-white text-[10px] font-bold rounded-full flex items-center justify-center">
|
|
200
203
|
{searchFilters.size}
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
import { useState, useEffect, useCallback, useMemo } from 'react';
|
|
4
4
|
import * as LucideIcons from 'lucide-react';
|
|
5
5
|
import { ChevronRight, ChevronLeft, ChevronDown, Home, Star, FileQuestion } from 'lucide-react';
|
|
6
|
-
import type {
|
|
6
|
+
import type { NavNode, ChildRef } from '@stores/sidebar-store/state';
|
|
7
7
|
import SearchBar from './SearchBar';
|
|
8
8
|
import { saveState, loadState, saveCollapsedSections, loadCollapsedSections } from './storage';
|
|
9
9
|
import { useStore } from '@nanostores/react';
|
|
@@ -472,9 +472,36 @@ export default function NestedSideBar() {
|
|
|
472
472
|
// Show loading state if no data yet
|
|
473
473
|
if (!data || roots.length === 0) {
|
|
474
474
|
return (
|
|
475
|
-
<aside className="w-[315px] h-
|
|
476
|
-
|
|
477
|
-
|
|
475
|
+
<aside className="w-[315px] h-full flex flex-col font-sans">
|
|
476
|
+
{/* Search skeleton */}
|
|
477
|
+
<div className="px-3 py-3 border-b border-gray-200">
|
|
478
|
+
<div className="h-9 bg-gray-100 rounded-lg animate-pulse" />
|
|
479
|
+
</div>
|
|
480
|
+
{/* Content skeleton */}
|
|
481
|
+
<div className="p-3 space-y-3">
|
|
482
|
+
{/* Group header skeleton */}
|
|
483
|
+
<div className="flex items-center gap-2 px-2 py-1.5">
|
|
484
|
+
<div className="w-3.5 h-3.5 bg-gray-200 rounded animate-pulse" />
|
|
485
|
+
<div className="h-4 w-24 bg-gray-200 rounded animate-pulse" />
|
|
486
|
+
</div>
|
|
487
|
+
{/* Item skeletons */}
|
|
488
|
+
{[1, 2, 3, 4, 5].map((i) => (
|
|
489
|
+
<div key={i} className="flex items-center gap-2.5 px-3 py-1.5 ml-3.5 border-l border-gray-100">
|
|
490
|
+
<div className="w-4 h-4 bg-gray-100 rounded animate-pulse" />
|
|
491
|
+
<div className="h-4 bg-gray-100 rounded animate-pulse" style={{ width: `${60 + ((i * 15) % 40)}%` }} />
|
|
492
|
+
</div>
|
|
493
|
+
))}
|
|
494
|
+
{/* Second group skeleton */}
|
|
495
|
+
<div className="flex items-center gap-2 px-2 py-1.5 mt-4">
|
|
496
|
+
<div className="w-3.5 h-3.5 bg-gray-200 rounded animate-pulse" />
|
|
497
|
+
<div className="h-4 w-20 bg-gray-200 rounded animate-pulse" />
|
|
498
|
+
</div>
|
|
499
|
+
{[1, 2, 3].map((i) => (
|
|
500
|
+
<div key={`g2-${i}`} className="flex items-center gap-2.5 px-3 py-1.5 ml-3.5 border-l border-gray-100">
|
|
501
|
+
<div className="w-4 h-4 bg-gray-100 rounded animate-pulse" />
|
|
502
|
+
<div className="h-4 bg-gray-100 rounded animate-pulse" style={{ width: `${50 + ((i * 20) % 35)}%` }} />
|
|
503
|
+
</div>
|
|
504
|
+
))}
|
|
478
505
|
</div>
|
|
479
506
|
</aside>
|
|
480
507
|
);
|
|
@@ -698,32 +725,32 @@ export default function NestedSideBar() {
|
|
|
698
725
|
|
|
699
726
|
const headerContent = (
|
|
700
727
|
<>
|
|
701
|
-
<div className="flex items-center">
|
|
728
|
+
<div className="flex items-center gap-2">
|
|
702
729
|
{GroupIcon && (
|
|
703
|
-
<span className="
|
|
704
|
-
<GroupIcon className="w-3
|
|
730
|
+
<span className="flex items-center justify-center w-5 h-5 rounded bg-gray-100 text-gray-600">
|
|
731
|
+
<GroupIcon className="w-3 h-3" />
|
|
705
732
|
</span>
|
|
706
733
|
)}
|
|
707
|
-
<span className="text-
|
|
734
|
+
<span className="text-[13px] text-gray-900 font-semibold tracking-tight">{group.title}</span>
|
|
708
735
|
</div>
|
|
709
736
|
{canCollapse && <ChevronDown className={cn('w-4 h-4 text-gray-400 transition-transform', isCollapsed && '-rotate-90')} />}
|
|
710
737
|
</>
|
|
711
738
|
);
|
|
712
739
|
|
|
713
740
|
return (
|
|
714
|
-
<div key={`group-${groupKey || index}`} className="mb-
|
|
741
|
+
<div key={`group-${groupKey || index}`} className="mb-5 last:mb-2">
|
|
715
742
|
{canCollapse ? (
|
|
716
743
|
<button
|
|
717
744
|
onClick={() => toggleSectionCollapse(groupId)}
|
|
718
|
-
className="flex items-center justify-between w-full px-2 py-1.5
|
|
745
|
+
className="flex items-center justify-between w-full px-2 py-1.5 hover:bg-gray-50 rounded-md transition-colors cursor-pointer"
|
|
719
746
|
>
|
|
720
747
|
{headerContent}
|
|
721
748
|
</button>
|
|
722
749
|
) : (
|
|
723
|
-
<div className="flex items-center justify-between px-2 py-1.5
|
|
750
|
+
<div className="flex items-center justify-between px-2 py-1.5">{headerContent}</div>
|
|
724
751
|
)}
|
|
725
752
|
{!isCollapsed && (
|
|
726
|
-
<div className="flex flex-col gap-0.5 border-l ml-
|
|
753
|
+
<div className="flex flex-col gap-0.5 border-l ml-4 mt-1 border-gray-200">
|
|
727
754
|
{visibleChildren.map((childRef, childIndex) => {
|
|
728
755
|
const child = resolveRef(childRef);
|
|
729
756
|
if (!child) return null;
|
|
@@ -776,6 +803,7 @@ export default function NestedSideBar() {
|
|
|
776
803
|
<IconComponent className="w-4 h-4" />
|
|
777
804
|
</span>
|
|
778
805
|
)}
|
|
806
|
+
{item.leftIcon && <img src={item.leftIcon} alt="" className="w-4 h-4 flex-shrink-0" />}
|
|
779
807
|
<span
|
|
780
808
|
className={cn(
|
|
781
809
|
'text-[13px] truncate',
|
|
@@ -809,9 +837,9 @@ export default function NestedSideBar() {
|
|
|
809
837
|
);
|
|
810
838
|
|
|
811
839
|
const baseClasses =
|
|
812
|
-
'group flex items-center justify-between w-full px-3 py-1 rounded-lg cursor-pointer text-left transition-colors hover:bg-gray-100 active:bg-gray-200';
|
|
840
|
+
'group flex items-center justify-between w-full px-3 py-1.5 rounded-lg cursor-pointer text-left transition-colors hover:bg-gray-100 active:bg-gray-200';
|
|
813
841
|
const parentClasses = itemHasChildren ? 'font-medium' : '';
|
|
814
|
-
const activeClasses = isActive ? 'bg-
|
|
842
|
+
const activeClasses = isActive ? 'bg-purple-50 hover:bg-purple-50 border-l-2 border-purple-600 rounded-l-none' : '';
|
|
815
843
|
|
|
816
844
|
// Leaf item with href → render as link
|
|
817
845
|
if (item.href && !itemHasChildren) {
|
|
@@ -1000,7 +1028,7 @@ export default function NestedSideBar() {
|
|
|
1000
1028
|
{/* Favorites Section */}
|
|
1001
1029
|
{favorites.length > 0 && isTopLevel && (
|
|
1002
1030
|
<div className="mb-6">
|
|
1003
|
-
<div className="flex items-center px-2 py-
|
|
1031
|
+
<div className="flex items-center px-2 py-1.5">
|
|
1004
1032
|
<Star className="w-3.5 h-3.5 mr-2 text-amber-400 fill-current" />
|
|
1005
1033
|
<span className="text-sm text-black font-semibold">Favorites</span>
|
|
1006
1034
|
</div>
|
|
@@ -1015,7 +1043,7 @@ export default function NestedSideBar() {
|
|
|
1015
1043
|
onClick={() => navigateToFavorite(fav)}
|
|
1016
1044
|
className={cn(
|
|
1017
1045
|
'group flex items-center justify-between w-full px-3 py-1.5 rounded-lg cursor-pointer text-left transition-colors hover:bg-amber-50 active:bg-amber-100',
|
|
1018
|
-
isActive && 'bg-
|
|
1046
|
+
isActive && 'bg-purple-50 hover:bg-purple-50 border-l-2 border-purple-600 rounded-l-none'
|
|
1019
1047
|
)}
|
|
1020
1048
|
>
|
|
1021
1049
|
<div className="flex items-center gap-2.5 min-w-0 flex-1">
|
|
@@ -2,26 +2,11 @@
|
|
|
2
2
|
import type { HTMLAttributes } from 'astro/types';
|
|
3
3
|
|
|
4
4
|
interface Props extends Omit<HTMLAttributes<'div'>, 'children'> {}
|
|
5
|
-
import { getNestedSideBarData } from './NestedSideBar/sidebar-builder';
|
|
6
5
|
import NestedSideBar from './NestedSideBar';
|
|
7
6
|
import { ClientRouter } from 'astro:transitions';
|
|
8
|
-
|
|
9
|
-
const props = await getNestedSideBarData();
|
|
10
7
|
---
|
|
11
8
|
|
|
12
9
|
<div {...Astro.props}>
|
|
13
10
|
<ClientRouter />
|
|
14
11
|
<NestedSideBar client:only="react" />
|
|
15
12
|
</div>
|
|
16
|
-
|
|
17
|
-
<script is:inline define:vars={{ props }}>
|
|
18
|
-
window.sidebarData = props;
|
|
19
|
-
</script>
|
|
20
|
-
|
|
21
|
-
<script>
|
|
22
|
-
import { setSidebarData } from '@stores/sidebar-store';
|
|
23
|
-
const data = (window as any).sidebarData;
|
|
24
|
-
if (data) {
|
|
25
|
-
setSidebarData(data);
|
|
26
|
-
}
|
|
27
|
-
</script>
|
|
@@ -11,6 +11,7 @@ import {
|
|
|
11
11
|
type ColumnFiltersState,
|
|
12
12
|
} from '@tanstack/react-table';
|
|
13
13
|
import DebouncedInput from './DebouncedInput';
|
|
14
|
+
import { ChevronLeft, ChevronRight, ChevronsLeft, ChevronsRight, SearchX } from 'lucide-react';
|
|
14
15
|
|
|
15
16
|
import { getColumnsByCollection } from './columns';
|
|
16
17
|
import { useEffect, useMemo, useState } from 'react';
|
|
@@ -240,23 +241,26 @@ export const Table = <T extends TCollectionTypes>({
|
|
|
240
241
|
},
|
|
241
242
|
});
|
|
242
243
|
|
|
244
|
+
const totalResults = table.getPrePaginationRowModel().rows.length;
|
|
245
|
+
const hasResults = table.getRowModel().rows.length > 0;
|
|
246
|
+
|
|
243
247
|
return (
|
|
244
248
|
<div>
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
<thead className="bg-gray-200/50">
|
|
249
|
+
<div className="rounded-lg border border-gray-200 overflow-hidden">
|
|
250
|
+
<table className="min-w-full divide-y divide-gray-200">
|
|
251
|
+
<thead className="bg-gray-50 sticky top-0 z-10">
|
|
249
252
|
{table.getHeaderGroups().map((headerGroup, index) => (
|
|
250
|
-
<tr key={`${headerGroup}-${index}`}
|
|
253
|
+
<tr key={`${headerGroup}-${index}`}>
|
|
251
254
|
{headerGroup.headers.map((header) => (
|
|
252
|
-
<th
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
<div
|
|
255
|
+
<th
|
|
256
|
+
key={`${header.id}`}
|
|
257
|
+
className="px-4 py-3 text-left text-xs font-semibold text-gray-600 uppercase tracking-wider"
|
|
258
|
+
>
|
|
259
|
+
<div className="flex flex-col gap-2">
|
|
260
|
+
<div>{header.isPlaceholder ? null : flexRender(header.column.columnDef.header, header.getContext())}</div>
|
|
261
|
+
<div>
|
|
258
262
|
{header.column.columnDef.meta?.showFilter !== false && <Filter column={header.column} />}
|
|
259
|
-
{header.column.columnDef.meta?.showFilter == false && <div className="h-
|
|
263
|
+
{header.column.columnDef.meta?.showFilter == false && <div className="h-9" />}
|
|
260
264
|
</div>
|
|
261
265
|
</div>
|
|
262
266
|
</th>
|
|
@@ -265,80 +269,94 @@ export const Table = <T extends TCollectionTypes>({
|
|
|
265
269
|
))}
|
|
266
270
|
</thead>
|
|
267
271
|
|
|
268
|
-
<tbody className="divide-y divide-gray-
|
|
269
|
-
{
|
|
270
|
-
|
|
271
|
-
{row.
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
272
|
+
<tbody className="bg-white divide-y divide-gray-100">
|
|
273
|
+
{hasResults ? (
|
|
274
|
+
table.getRowModel().rows.map((row, index) => (
|
|
275
|
+
<tr key={`${row.id}-${index}`} className="hover:bg-gray-50 transition-colors">
|
|
276
|
+
{row.getVisibleCells().map((cell) => (
|
|
277
|
+
<td
|
|
278
|
+
key={cell.id}
|
|
279
|
+
className={`px-4 py-3 text-sm text-gray-700 ${cell.column.columnDef.meta?.className || ''}`}
|
|
280
|
+
>
|
|
281
|
+
{flexRender(cell.column.columnDef.cell, cell.getContext())}
|
|
282
|
+
</td>
|
|
283
|
+
))}
|
|
284
|
+
</tr>
|
|
285
|
+
))
|
|
286
|
+
) : (
|
|
287
|
+
<tr>
|
|
288
|
+
<td colSpan={table.getAllColumns().length} className="px-4 py-12 text-center">
|
|
289
|
+
<div className="flex flex-col items-center justify-center text-gray-500">
|
|
290
|
+
<SearchX className="w-10 h-10 text-gray-300 mb-3" />
|
|
291
|
+
<p className="text-sm font-medium text-gray-600">No results found</p>
|
|
292
|
+
<p className="text-xs text-gray-400 mt-1">Try adjusting your search or filters</p>
|
|
293
|
+
</div>
|
|
294
|
+
</td>
|
|
279
295
|
</tr>
|
|
280
|
-
)
|
|
296
|
+
)}
|
|
281
297
|
</tbody>
|
|
282
298
|
</table>
|
|
283
299
|
</div>
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
<
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
300
|
+
|
|
301
|
+
{/* Pagination */}
|
|
302
|
+
<div className="flex items-center justify-between px-1 py-4">
|
|
303
|
+
<div className="text-sm text-gray-500">
|
|
304
|
+
{totalResults > 0 && (
|
|
305
|
+
<span>
|
|
306
|
+
Showing <span className="font-medium text-gray-700">{table.getRowModel().rows.length}</span> of{' '}
|
|
307
|
+
<span className="font-medium text-gray-700">{totalResults}</span> results
|
|
308
|
+
</span>
|
|
309
|
+
)}
|
|
310
|
+
</div>
|
|
311
|
+
<div className="flex items-center gap-2">
|
|
312
|
+
<div className="flex items-center rounded-lg border border-gray-200 bg-white">
|
|
313
|
+
<button
|
|
314
|
+
className="p-2 text-gray-500 hover:text-gray-700 hover:bg-gray-50 disabled:opacity-40 disabled:cursor-not-allowed disabled:hover:bg-transparent transition-colors rounded-l-lg"
|
|
315
|
+
onClick={() => table.setPageIndex(0)}
|
|
316
|
+
disabled={!table.getCanPreviousPage()}
|
|
317
|
+
title="First page"
|
|
318
|
+
>
|
|
319
|
+
<ChevronsLeft className="w-4 h-4" />
|
|
320
|
+
</button>
|
|
321
|
+
<button
|
|
322
|
+
className="p-2 text-gray-500 hover:text-gray-700 hover:bg-gray-50 disabled:opacity-40 disabled:cursor-not-allowed disabled:hover:bg-transparent transition-colors border-l border-gray-200"
|
|
323
|
+
onClick={() => table.previousPage()}
|
|
324
|
+
disabled={!table.getCanPreviousPage()}
|
|
325
|
+
title="Previous page"
|
|
326
|
+
>
|
|
327
|
+
<ChevronLeft className="w-4 h-4" />
|
|
328
|
+
</button>
|
|
329
|
+
<span className="px-3 py-2 text-sm text-gray-600 border-l border-r border-gray-200 min-w-[100px] text-center">
|
|
330
|
+
Page <span className="font-medium">{table.getState().pagination.pageIndex + 1}</span> of{' '}
|
|
331
|
+
<span className="font-medium">{table.getPageCount() || 1}</span>
|
|
332
|
+
</span>
|
|
333
|
+
<button
|
|
334
|
+
className="p-2 text-gray-500 hover:text-gray-700 hover:bg-gray-50 disabled:opacity-40 disabled:cursor-not-allowed disabled:hover:bg-transparent transition-colors border-r border-gray-200"
|
|
335
|
+
onClick={() => table.nextPage()}
|
|
336
|
+
disabled={!table.getCanNextPage()}
|
|
337
|
+
title="Next page"
|
|
338
|
+
>
|
|
339
|
+
<ChevronRight className="w-4 h-4" />
|
|
340
|
+
</button>
|
|
341
|
+
<button
|
|
342
|
+
className="p-2 text-gray-500 hover:text-gray-700 hover:bg-gray-50 disabled:opacity-40 disabled:cursor-not-allowed disabled:hover:bg-transparent transition-colors rounded-r-lg"
|
|
343
|
+
onClick={() => table.setPageIndex(table.getPageCount() - 1)}
|
|
344
|
+
disabled={!table.getCanNextPage()}
|
|
345
|
+
title="Last page"
|
|
346
|
+
>
|
|
347
|
+
<ChevronsRight className="w-4 h-4" />
|
|
348
|
+
</button>
|
|
349
|
+
</div>
|
|
333
350
|
<select
|
|
334
351
|
value={table.getState().pagination.pageSize}
|
|
335
352
|
onChange={(e) => {
|
|
336
353
|
table.setPageSize(Number(e.target.value));
|
|
337
354
|
}}
|
|
355
|
+
className="px-3 py-2 text-sm text-gray-600 bg-white border border-gray-200 rounded-lg hover:border-gray-300 focus:outline-none focus:ring-2 focus:ring-gray-200 transition-colors"
|
|
338
356
|
>
|
|
339
357
|
{[10, 20, 30, 40, 50].map((pageSize) => (
|
|
340
358
|
<option key={pageSize} value={pageSize}>
|
|
341
|
-
|
|
359
|
+
{pageSize} per page
|
|
342
360
|
</option>
|
|
343
361
|
))}
|
|
344
362
|
</select>
|
|
@@ -394,6 +412,8 @@ function Filter<T extends TCollectionTypes>({ column }: { column: Column<TData<T
|
|
|
394
412
|
return Array.from(column.getFacetedUniqueValues().keys()).sort().slice(0, 2000);
|
|
395
413
|
}, [column.getFacetedUniqueValues(), filterVariant]);
|
|
396
414
|
|
|
415
|
+
const uniqueCount = column.getFacetedUniqueValues().size;
|
|
416
|
+
|
|
397
417
|
return (
|
|
398
418
|
<div>
|
|
399
419
|
{/* Autocomplete suggestions from faceted values feature */}
|
|
@@ -406,11 +426,10 @@ function Filter<T extends TCollectionTypes>({ column }: { column: Column<TData<T
|
|
|
406
426
|
type="text"
|
|
407
427
|
value={(columnFilterValue ?? '') as string}
|
|
408
428
|
onChange={(value) => column.setFilterValue(value)}
|
|
409
|
-
placeholder={
|
|
410
|
-
className="w-full
|
|
429
|
+
placeholder={!column?.columnDef?.meta?.filterVariant ? `Search (${uniqueCount})...` : 'Search...'}
|
|
430
|
+
className="w-full px-3 py-2 text-sm bg-white border border-gray-200 rounded-lg placeholder:text-gray-400 focus:outline-none focus:ring-2 focus:ring-gray-200 focus:border-gray-300 transition-colors"
|
|
411
431
|
list={column.id + 'list'}
|
|
412
432
|
/>
|
|
413
|
-
<div className="h-1" />
|
|
414
433
|
</div>
|
|
415
434
|
);
|
|
416
435
|
}
|