@veiag/payload-enhanced-sidebar 0.1.2 → 0.2.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 +182 -5
- package/dist/components/EnhancedSidebar/Badge/index.d.ts +22 -0
- package/dist/components/EnhancedSidebar/Badge/index.js +30 -0
- package/dist/components/EnhancedSidebar/Badge/index.js.map +1 -0
- package/dist/components/EnhancedSidebar/Badge/index.scss +65 -0
- package/dist/components/EnhancedSidebar/BadgeProvider/index.d.ts +64 -0
- package/dist/components/EnhancedSidebar/BadgeProvider/index.js +66 -0
- package/dist/components/EnhancedSidebar/BadgeProvider/index.js.map +1 -0
- package/dist/components/EnhancedSidebar/InternalBadgeProvider/index.d.ts +15 -0
- package/dist/components/EnhancedSidebar/InternalBadgeProvider/index.js +132 -0
- package/dist/components/EnhancedSidebar/InternalBadgeProvider/index.js.map +1 -0
- package/dist/components/EnhancedSidebar/NavItem/index.d.ts +11 -0
- package/dist/components/EnhancedSidebar/NavItem/index.js +46 -0
- package/dist/components/EnhancedSidebar/NavItem/index.js.map +1 -0
- package/dist/components/EnhancedSidebar/SettingsMenuButton/index.d.ts +6 -0
- package/dist/components/EnhancedSidebar/SettingsMenuButton/index.js +33 -0
- package/dist/components/EnhancedSidebar/SettingsMenuButton/index.js.map +1 -0
- package/dist/components/EnhancedSidebar/SettingsMenuButton/index.scss +25 -0
- package/dist/components/EnhancedSidebar/SidebarContent.d.ts +1 -0
- package/dist/components/EnhancedSidebar/SidebarContent.js +112 -86
- package/dist/components/EnhancedSidebar/SidebarContent.js.map +1 -1
- package/dist/components/EnhancedSidebar/TabsBar/TabItem.d.ts +15 -0
- package/dist/components/EnhancedSidebar/TabsBar/TabItem.js +56 -0
- package/dist/components/EnhancedSidebar/TabsBar/TabItem.js.map +1 -0
- package/dist/components/EnhancedSidebar/TabsBar/index.d.ts +1 -0
- package/dist/components/EnhancedSidebar/TabsBar/index.js +58 -52
- package/dist/components/EnhancedSidebar/TabsBar/index.js.map +1 -1
- package/dist/components/EnhancedSidebar/TabsBar/index.scss +2 -2
- package/dist/components/EnhancedSidebar/hooks/useBadge.d.ts +11 -0
- package/dist/components/EnhancedSidebar/hooks/useBadge.js +31 -0
- package/dist/components/EnhancedSidebar/hooks/useBadge.js.map +1 -0
- package/dist/components/EnhancedSidebar/index.client.d.ts +2 -1
- package/dist/components/EnhancedSidebar/index.client.js +18 -31
- package/dist/components/EnhancedSidebar/index.client.js.map +1 -1
- package/dist/components/EnhancedSidebar/index.js +8 -1
- package/dist/components/EnhancedSidebar/index.js.map +1 -1
- package/dist/exports/client.d.ts +1 -0
- package/dist/exports/client.js +2 -1
- package/dist/exports/client.js.map +1 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.js +16 -0
- package/dist/index.js.map +1 -1
- package/dist/types.d.ts +104 -1
- package/dist/types.js.map +1 -1
- package/package.json +10 -10
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../src/components/EnhancedSidebar/TabsBar/index.tsx"],"sourcesContent":["'use client'\n\nimport { getTranslation } from '@payloadcms/translations'\nimport { Link, useConfig, useTranslation } from '@payloadcms/ui'\nimport { usePathname } from 'next/navigation'\nimport { formatAdminURL } from 'payload/shared'\nimport React from 'react'\n\nimport type { EnhancedSidebarConfig, SidebarTabContent, SidebarTabLink } from '../../../types'\n\nimport { Icon } from '../Icon'\nimport './index.scss'\n\nconst tabsBaseClass = 'tabs-bar'\n\nexport type TabsBarProps = {\n activeTabId: string\n onTabChange: (tabId: string) => void\n sidebarConfig: EnhancedSidebarConfig\n}\n\nexport const TabsBar: React.FC<TabsBarProps> = ({
|
|
1
|
+
{"version":3,"sources":["../../../../src/components/EnhancedSidebar/TabsBar/index.tsx"],"sourcesContent":["'use client'\n\nimport { getTranslation } from '@payloadcms/translations'\nimport { Link, useConfig, useTranslation } from '@payloadcms/ui'\nimport { usePathname } from 'next/navigation'\nimport { formatAdminURL } from 'payload/shared'\nimport React from 'react'\n\nimport type { EnhancedSidebarConfig, SidebarTabContent, SidebarTabLink } from '../../../types'\n\nimport { Icon } from '../Icon'\nimport { SettingsMenuButton } from '../SettingsMenuButton'\nimport { TabButton, TabLink } from './TabItem'\nimport './index.scss'\n\nconst tabsBaseClass = 'tabs-bar'\n\nexport type TabsBarProps = {\n activeTabId: string\n onTabChange: (tabId: string) => void\n settingsMenu?: React.ReactNode[]\n sidebarConfig: EnhancedSidebarConfig\n}\n\nexport const TabsBar: React.FC<TabsBarProps> = ({\n activeTabId,\n onTabChange,\n settingsMenu,\n sidebarConfig,\n}) => {\n const { i18n } = useTranslation()\n const pathname = usePathname()\n\n const {\n config: {\n admin: {\n routes: { browseByFolder: foldersRoute, logout: logoutRoute },\n },\n folders,\n routes: { admin: adminRoute },\n },\n } = useConfig()\n\n const showLogout = sidebarConfig.showLogout !== false\n const showFolders = folders && folders.browseByFolder\n\n const folderURL = formatAdminURL({\n adminRoute,\n path: foldersRoute,\n })\n const isFoldersActive = pathname.startsWith(folderURL)\n\n const renderTabItem = (item: SidebarTabContent | SidebarTabLink) => {\n if (item.type === 'tab') {\n return (\n <TabButton\n isActive={activeTabId === item.id}\n key={item.id}\n onTabChange={onTabChange}\n tab={item}\n />\n )\n }\n\n // Check if link is active\n const href = item.isExternal\n ? item.href\n : formatAdminURL({ adminRoute, path: item.href })\n const isActive = pathname === href || (item.href === '/' && pathname === adminRoute)\n\n return <TabLink href={href} isActive={isActive} key={item.id} link={item} />\n }\n\n const tabItems = sidebarConfig.tabs ?? []\n\n return (\n <div className={tabsBaseClass}>\n <div className={`${tabsBaseClass}__tabs`}>{tabItems.map(renderTabItem)}</div>\n\n <div className={`${tabsBaseClass}__actions`}>\n {showFolders && (\n <Link\n className={`${tabsBaseClass}__action ${isFoldersActive ? `${tabsBaseClass}__link--active` : ''}`}\n href={folderURL}\n title={getTranslation({ en: 'Browse by Folder', uk: 'Переглянути по папках' }, i18n)}\n >\n <Icon name=\"Folder\" size={20} />\n </Link>\n )}\n <SettingsMenuButton settingsMenu={settingsMenu} />\n {showLogout && (\n <Link\n className={`${tabsBaseClass}__action`}\n href={formatAdminURL({\n adminRoute,\n path: logoutRoute,\n })}\n title={getTranslation({ en: 'Logout', uk: 'Вийти' }, i18n)}\n type=\"button\"\n >\n <Icon name=\"LogOut\" size={20} />\n </Link>\n )}\n </div>\n </div>\n )\n}\n"],"names":["getTranslation","Link","useConfig","useTranslation","usePathname","formatAdminURL","React","Icon","SettingsMenuButton","TabButton","TabLink","tabsBaseClass","TabsBar","activeTabId","onTabChange","settingsMenu","sidebarConfig","i18n","pathname","config","admin","routes","browseByFolder","foldersRoute","logout","logoutRoute","folders","adminRoute","showLogout","showFolders","folderURL","path","isFoldersActive","startsWith","renderTabItem","item","type","isActive","id","tab","href","isExternal","link","tabItems","tabs","div","className","map","title","en","uk","name","size"],"mappings":"AAAA;;AAEA,SAASA,cAAc,QAAQ,2BAA0B;AACzD,SAASC,IAAI,EAAEC,SAAS,EAAEC,cAAc,QAAQ,iBAAgB;AAChE,SAASC,WAAW,QAAQ,kBAAiB;AAC7C,SAASC,cAAc,QAAQ,iBAAgB;AAC/C,OAAOC,WAAW,QAAO;AAIzB,SAASC,IAAI,QAAQ,UAAS;AAC9B,SAASC,kBAAkB,QAAQ,wBAAuB;AAC1D,SAASC,SAAS,EAAEC,OAAO,QAAQ,YAAW;AAC9C,OAAO,eAAc;AAErB,MAAMC,gBAAgB;AAStB,OAAO,MAAMC,UAAkC,CAAC,EAC9CC,WAAW,EACXC,WAAW,EACXC,YAAY,EACZC,aAAa,EACd;IACC,MAAM,EAAEC,IAAI,EAAE,GAAGd;IACjB,MAAMe,WAAWd;IAEjB,MAAM,EACJe,QAAQ,EACNC,OAAO,EACLC,QAAQ,EAAEC,gBAAgBC,YAAY,EAAEC,QAAQC,WAAW,EAAE,EAC9D,EACDC,OAAO,EACPL,QAAQ,EAAED,OAAOO,UAAU,EAAE,EAC9B,EACF,GAAGzB;IAEJ,MAAM0B,aAAaZ,cAAcY,UAAU,KAAK;IAChD,MAAMC,cAAcH,WAAWA,QAAQJ,cAAc;IAErD,MAAMQ,YAAYzB,eAAe;QAC/BsB;QACAI,MAAMR;IACR;IACA,MAAMS,kBAAkBd,SAASe,UAAU,CAACH;IAE5C,MAAMI,gBAAgB,CAACC;QACrB,IAAIA,KAAKC,IAAI,KAAK,OAAO;YACvB,qBACE,KAAC3B;gBACC4B,UAAUxB,gBAAgBsB,KAAKG,EAAE;gBAEjCxB,aAAaA;gBACbyB,KAAKJ;eAFAA,KAAKG,EAAE;QAKlB;QAEA,0BAA0B;QAC1B,MAAME,OAAOL,KAAKM,UAAU,GACxBN,KAAKK,IAAI,GACTnC,eAAe;YAAEsB;YAAYI,MAAMI,KAAKK,IAAI;QAAC;QACjD,MAAMH,WAAWnB,aAAasB,QAASL,KAAKK,IAAI,KAAK,OAAOtB,aAAaS;QAEzE,qBAAO,KAACjB;YAAQ8B,MAAMA;YAAMH,UAAUA;YAAwBK,MAAMP;WAAfA,KAAKG,EAAE;IAC9D;IAEA,MAAMK,WAAW3B,cAAc4B,IAAI,IAAI,EAAE;IAEzC,qBACE,MAACC;QAAIC,WAAWnC;;0BACd,KAACkC;gBAAIC,WAAW,GAAGnC,cAAc,MAAM,CAAC;0BAAGgC,SAASI,GAAG,CAACb;;0BAExD,MAACW;gBAAIC,WAAW,GAAGnC,cAAc,SAAS,CAAC;;oBACxCkB,6BACC,KAAC5B;wBACC6C,WAAW,GAAGnC,cAAc,SAAS,EAAEqB,kBAAkB,GAAGrB,cAAc,cAAc,CAAC,GAAG,IAAI;wBAChG6B,MAAMV;wBACNkB,OAAOhD,eAAe;4BAAEiD,IAAI;4BAAoBC,IAAI;wBAAwB,GAAGjC;kCAE/E,cAAA,KAACV;4BAAK4C,MAAK;4BAASC,MAAM;;;kCAG9B,KAAC5C;wBAAmBO,cAAcA;;oBACjCa,4BACC,KAAC3B;wBACC6C,WAAW,GAAGnC,cAAc,QAAQ,CAAC;wBACrC6B,MAAMnC,eAAe;4BACnBsB;4BACAI,MAAMN;wBACR;wBACAuB,OAAOhD,eAAe;4BAAEiD,IAAI;4BAAUC,IAAI;wBAAQ,GAAGjC;wBACrDmB,MAAK;kCAEL,cAAA,KAAC7B;4BAAK4C,MAAK;4BAASC,MAAM;;;;;;;AAMtC,EAAC"}
|
|
@@ -27,6 +27,7 @@
|
|
|
27
27
|
|
|
28
28
|
&__tab,
|
|
29
29
|
&__link {
|
|
30
|
+
position: relative;
|
|
30
31
|
display: flex;
|
|
31
32
|
align-items: center;
|
|
32
33
|
justify-content: center;
|
|
@@ -52,8 +53,6 @@
|
|
|
52
53
|
}
|
|
53
54
|
|
|
54
55
|
&__link {
|
|
55
|
-
position: relative;
|
|
56
|
-
|
|
57
56
|
&--active {
|
|
58
57
|
color: var(--theme-text);
|
|
59
58
|
|
|
@@ -86,6 +85,7 @@
|
|
|
86
85
|
}
|
|
87
86
|
|
|
88
87
|
&__action {
|
|
88
|
+
position: relative;
|
|
89
89
|
display: flex;
|
|
90
90
|
align-items: center;
|
|
91
91
|
justify-content: center;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { ReactNode } from 'react';
|
|
2
|
+
import type { BadgeConfig } from '../../../types';
|
|
3
|
+
type UseBadgeResult = {
|
|
4
|
+
value: number | ReactNode | undefined;
|
|
5
|
+
};
|
|
6
|
+
/**
|
|
7
|
+
* Hook to get badge value based on config.
|
|
8
|
+
* All badge values are read from context (populated by InternalBadgeProvider or BadgeProvider).
|
|
9
|
+
*/
|
|
10
|
+
export declare const useBadge: (config: BadgeConfig | undefined, defaultSlug: string) => UseBadgeResult;
|
|
11
|
+
export {};
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { useBadgeValue } from '../BadgeProvider';
|
|
3
|
+
/**
|
|
4
|
+
* Hook to get badge value based on config.
|
|
5
|
+
* All badge values are read from context (populated by InternalBadgeProvider or BadgeProvider).
|
|
6
|
+
*/ export const useBadge = (config, /**
|
|
7
|
+
* Default slug to use for context lookup if not specified in config
|
|
8
|
+
*/ defaultSlug)=>{
|
|
9
|
+
// Determine the slug to look up in context
|
|
10
|
+
let slug = defaultSlug;
|
|
11
|
+
if (config?.type === 'provider' && config.slug) {
|
|
12
|
+
slug = config.slug;
|
|
13
|
+
} else if (config?.type === 'collection-count' && config.collectionSlug) {
|
|
14
|
+
// For collection-count, the InternalBadgeProvider uses the item slug as key
|
|
15
|
+
// but if collectionSlug is different, we might need to handle this
|
|
16
|
+
// For now, defaultSlug is used (which is the tab/item id)
|
|
17
|
+
slug = defaultSlug;
|
|
18
|
+
}
|
|
19
|
+
// Get value from context (populated by InternalBadgeProvider or user's BadgeProvider)
|
|
20
|
+
const contextValue = useBadgeValue(slug);
|
|
21
|
+
if (!config) {
|
|
22
|
+
return {
|
|
23
|
+
value: undefined
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
return {
|
|
27
|
+
value: contextValue
|
|
28
|
+
};
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
//# sourceMappingURL=useBadge.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../src/components/EnhancedSidebar/hooks/useBadge.ts"],"sourcesContent":["'use client'\n\nimport type { ReactNode } from 'react'\n\nimport type { BadgeConfig } from '../../../types'\n\nimport { useBadgeValue } from '../BadgeProvider'\n\ntype UseBadgeResult = {\n value: number | ReactNode | undefined\n}\n\n/**\n * Hook to get badge value based on config.\n * All badge values are read from context (populated by InternalBadgeProvider or BadgeProvider).\n */\nexport const useBadge = (\n config: BadgeConfig | undefined,\n /**\n * Default slug to use for context lookup if not specified in config\n */\n defaultSlug: string,\n): UseBadgeResult => {\n // Determine the slug to look up in context\n let slug = defaultSlug\n\n if (config?.type === 'provider' && config.slug) {\n slug = config.slug\n } else if (config?.type === 'collection-count' && config.collectionSlug) {\n // For collection-count, the InternalBadgeProvider uses the item slug as key\n // but if collectionSlug is different, we might need to handle this\n // For now, defaultSlug is used (which is the tab/item id)\n slug = defaultSlug\n }\n\n // Get value from context (populated by InternalBadgeProvider or user's BadgeProvider)\n const contextValue = useBadgeValue(slug)\n\n if (!config) {\n return { value: undefined }\n }\n\n return { value: contextValue }\n}\n"],"names":["useBadgeValue","useBadge","config","defaultSlug","slug","type","collectionSlug","contextValue","value","undefined"],"mappings":"AAAA;AAMA,SAASA,aAAa,QAAQ,mBAAkB;AAMhD;;;CAGC,GACD,OAAO,MAAMC,WAAW,CACtBC,QACA;;GAEC,GACDC;IAEA,2CAA2C;IAC3C,IAAIC,OAAOD;IAEX,IAAID,QAAQG,SAAS,cAAcH,OAAOE,IAAI,EAAE;QAC9CA,OAAOF,OAAOE,IAAI;IACpB,OAAO,IAAIF,QAAQG,SAAS,sBAAsBH,OAAOI,cAAc,EAAE;QACvE,4EAA4E;QAC5E,mEAAmE;QACnE,0DAA0D;QAC1DF,OAAOD;IACT;IAEA,sFAAsF;IACtF,MAAMI,eAAeP,cAAcI;IAEnC,IAAI,CAACF,QAAQ;QACX,OAAO;YAAEM,OAAOC;QAAU;IAC5B;IAEA,OAAO;QAAED,OAAOD;IAAa;AAC/B,EAAC"}
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import type { NavPreferences } from 'payload';
|
|
2
|
-
import type { ExtendedGroup } from 'src/types';
|
|
3
2
|
import React from 'react';
|
|
3
|
+
import type { BadgeConfig, ExtendedGroup } from '../../types';
|
|
4
4
|
export declare const EnhancedSidebarClient: React.FC<{
|
|
5
|
+
badges?: Record<string, BadgeConfig>;
|
|
5
6
|
groups: ExtendedGroup[];
|
|
6
7
|
navPreferences: NavPreferences | null;
|
|
7
8
|
}>;
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
'use client';
|
|
2
|
-
import { jsx as _jsx
|
|
2
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
3
3
|
import { getTranslation } from '@payloadcms/translations';
|
|
4
|
-
import {
|
|
4
|
+
import { NavGroup, useConfig, useTranslation } from '@payloadcms/ui';
|
|
5
5
|
import { EntityType } from '@payloadcms/ui/shared';
|
|
6
6
|
import { usePathname } from 'next/navigation.js';
|
|
7
7
|
import { formatAdminURL } from 'payload/shared';
|
|
8
8
|
import React, { Fragment } from 'react';
|
|
9
|
-
|
|
10
|
-
export const EnhancedSidebarClient = ({ groups, navPreferences })=>{
|
|
9
|
+
import { NavItem } from './NavItem';
|
|
10
|
+
export const EnhancedSidebarClient = ({ badges, groups, navPreferences })=>{
|
|
11
11
|
const pathname = usePathname();
|
|
12
12
|
const { config: { routes: { admin: adminRoute } } } = useConfig();
|
|
13
13
|
const { i18n } = useTranslation();
|
|
@@ -16,8 +16,10 @@ export const EnhancedSidebarClient = ({ groups, navPreferences })=>{
|
|
|
16
16
|
// Handle empty label (ungrouped items)
|
|
17
17
|
const groupLabel = label || '';
|
|
18
18
|
const isUngrouped = !label || typeof label === 'string' && label === '';
|
|
19
|
+
const translatedLabel = getTranslation(groupLabel, i18n);
|
|
20
|
+
const properKey = `${translatedLabel}-${key}`;
|
|
19
21
|
const content = entities.map((entity, i)=>{
|
|
20
|
-
const { slug
|
|
22
|
+
const { slug } = entity;
|
|
21
23
|
const entityType = entity.type;
|
|
22
24
|
let href;
|
|
23
25
|
let id;
|
|
@@ -54,45 +56,30 @@ export const EnhancedSidebarClient = ({ groups, navPreferences })=>{
|
|
|
54
56
|
'/',
|
|
55
57
|
undefined
|
|
56
58
|
].includes(pathname[href.length]);
|
|
57
|
-
const
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
className: `${baseClass}__link-label`,
|
|
64
|
-
children: getTranslation(entityLabel, i18n)
|
|
65
|
-
})
|
|
66
|
-
]
|
|
67
|
-
});
|
|
68
|
-
if (pathname === href) {
|
|
69
|
-
return /*#__PURE__*/ _jsx("div", {
|
|
70
|
-
className: `${baseClass}__link`,
|
|
71
|
-
id: id,
|
|
72
|
-
children: Label
|
|
73
|
-
}, i);
|
|
74
|
-
}
|
|
75
|
-
return /*#__PURE__*/ _jsx(Link, {
|
|
76
|
-
className: `${baseClass}__link`,
|
|
59
|
+
const isCurrentPage = pathname === href;
|
|
60
|
+
// Get badge config for this entity
|
|
61
|
+
const badgeConfig = badges?.[slug];
|
|
62
|
+
return /*#__PURE__*/ _jsx(NavItem, {
|
|
63
|
+
badgeConfig: badgeConfig,
|
|
64
|
+
entity: entity,
|
|
77
65
|
href: href,
|
|
78
66
|
id: id,
|
|
79
|
-
|
|
80
|
-
|
|
67
|
+
isActive: isActive,
|
|
68
|
+
isCurrentPage: isCurrentPage
|
|
81
69
|
}, i);
|
|
82
70
|
});
|
|
83
71
|
// For ungrouped items, render without NavGroup wrapper
|
|
84
72
|
if (isUngrouped) {
|
|
85
73
|
return /*#__PURE__*/ _jsx(Fragment, {
|
|
86
74
|
children: content
|
|
87
|
-
},
|
|
75
|
+
}, properKey);
|
|
88
76
|
}
|
|
89
|
-
//
|
|
90
|
-
const translatedLabel = getTranslation(groupLabel, i18n);
|
|
77
|
+
//TODO:
|
|
91
78
|
return /*#__PURE__*/ _jsx(NavGroup, {
|
|
92
79
|
isOpen: navPreferences?.groups?.[translatedLabel]?.open,
|
|
93
80
|
label: translatedLabel,
|
|
94
81
|
children: content
|
|
95
|
-
},
|
|
82
|
+
}, properKey);
|
|
96
83
|
})
|
|
97
84
|
});
|
|
98
85
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/components/EnhancedSidebar/index.client.tsx"],"sourcesContent":["'use client'\nimport type { NavPreferences } from 'payload'\
|
|
1
|
+
{"version":3,"sources":["../../../src/components/EnhancedSidebar/index.client.tsx"],"sourcesContent":["'use client'\nimport type { NavPreferences } from 'payload'\n\nimport { getTranslation } from '@payloadcms/translations'\nimport { NavGroup, useConfig, useTranslation } from '@payloadcms/ui'\nimport { EntityType } from '@payloadcms/ui/shared'\nimport { usePathname } from 'next/navigation.js'\nimport { formatAdminURL } from 'payload/shared'\nimport React, { Fragment } from 'react'\n\nimport type { BadgeConfig, ExtendedGroup } from '../../types'\n\nimport { NavItem } from './NavItem'\n\nexport const EnhancedSidebarClient: React.FC<{\n badges?: Record<string, BadgeConfig>\n groups: ExtendedGroup[]\n navPreferences: NavPreferences | null\n}> = ({ badges, groups, navPreferences }) => {\n const pathname = usePathname()\n\n const {\n config: {\n routes: { admin: adminRoute },\n },\n } = useConfig()\n\n const { i18n } = useTranslation()\n\n return (\n <Fragment>\n {groups.map(({ entities, label }, key) => {\n // Handle empty label (ungrouped items)\n const groupLabel = label || ''\n const isUngrouped = !label || (typeof label === 'string' && label === '')\n const translatedLabel = getTranslation(groupLabel, i18n)\n\n const properKey = `${translatedLabel}-${key}`\n\n const content = entities.map((entity, i) => {\n const { slug } = entity\n const entityType = entity.type\n let href: string\n let id: string\n\n // Check for collection\n //@ts-expect-error Idk why typescript is complaining here\n if (entityType === EntityType.collection) {\n href = formatAdminURL({ adminRoute, path: `/collections/${slug}` })\n id = `nav-${slug}`\n //@ts-expect-error Idk why typescript is complaining here\n } else if (entityType === EntityType.global) {\n href = formatAdminURL({ adminRoute, path: `/globals/${slug}` })\n id = `nav-global-${slug}`\n } else if (entityType === 'custom' && entity.href) {\n // Custom item with href\n id = `nav-custom-${slug}`\n if (entity.isExternal) {\n href = entity.href\n } else {\n href = formatAdminURL({ adminRoute, path: entity.href })\n }\n } else {\n return null\n }\n\n const isActive =\n pathname.startsWith(href) && ['/', undefined].includes(pathname[href.length])\n const isCurrentPage = pathname === href\n\n // Get badge config for this entity\n const badgeConfig = badges?.[slug]\n\n return (\n <NavItem\n badgeConfig={badgeConfig}\n entity={entity}\n href={href}\n id={id}\n isActive={isActive}\n isCurrentPage={isCurrentPage}\n key={i}\n />\n )\n })\n\n // For ungrouped items, render without NavGroup wrapper\n if (isUngrouped) {\n return <Fragment key={properKey}>{content}</Fragment>\n }\n //TODO:\n return (\n <NavGroup\n isOpen={navPreferences?.groups?.[translatedLabel]?.open}\n key={properKey}\n label={translatedLabel}\n >\n {content}\n </NavGroup>\n )\n })}\n </Fragment>\n )\n}\n"],"names":["getTranslation","NavGroup","useConfig","useTranslation","EntityType","usePathname","formatAdminURL","React","Fragment","NavItem","EnhancedSidebarClient","badges","groups","navPreferences","pathname","config","routes","admin","adminRoute","i18n","map","entities","label","key","groupLabel","isUngrouped","translatedLabel","properKey","content","entity","i","slug","entityType","type","href","id","collection","path","global","isExternal","isActive","startsWith","undefined","includes","length","isCurrentPage","badgeConfig","isOpen","open"],"mappings":"AAAA;;AAGA,SAASA,cAAc,QAAQ,2BAA0B;AACzD,SAASC,QAAQ,EAAEC,SAAS,EAAEC,cAAc,QAAQ,iBAAgB;AACpE,SAASC,UAAU,QAAQ,wBAAuB;AAClD,SAASC,WAAW,QAAQ,qBAAoB;AAChD,SAASC,cAAc,QAAQ,iBAAgB;AAC/C,OAAOC,SAASC,QAAQ,QAAQ,QAAO;AAIvC,SAASC,OAAO,QAAQ,YAAW;AAEnC,OAAO,MAAMC,wBAIR,CAAC,EAAEC,MAAM,EAAEC,MAAM,EAAEC,cAAc,EAAE;IACtC,MAAMC,WAAWT;IAEjB,MAAM,EACJU,QAAQ,EACNC,QAAQ,EAAEC,OAAOC,UAAU,EAAE,EAC9B,EACF,GAAGhB;IAEJ,MAAM,EAAEiB,IAAI,EAAE,GAAGhB;IAEjB,qBACE,KAACK;kBACEI,OAAOQ,GAAG,CAAC,CAAC,EAAEC,QAAQ,EAAEC,KAAK,EAAE,EAAEC;YAChC,uCAAuC;YACvC,MAAMC,aAAaF,SAAS;YAC5B,MAAMG,cAAc,CAACH,SAAU,OAAOA,UAAU,YAAYA,UAAU;YACtE,MAAMI,kBAAkB1B,eAAewB,YAAYL;YAEnD,MAAMQ,YAAY,GAAGD,gBAAgB,CAAC,EAAEH,KAAK;YAE7C,MAAMK,UAAUP,SAASD,GAAG,CAAC,CAACS,QAAQC;gBACpC,MAAM,EAAEC,IAAI,EAAE,GAAGF;gBACjB,MAAMG,aAAaH,OAAOI,IAAI;gBAC9B,IAAIC;gBACJ,IAAIC;gBAEJ,uBAAuB;gBACvB,yDAAyD;gBACzD,IAAIH,eAAe5B,WAAWgC,UAAU,EAAE;oBACxCF,OAAO5B,eAAe;wBAAEY;wBAAYmB,MAAM,CAAC,aAAa,EAAEN,MAAM;oBAAC;oBACjEI,KAAK,CAAC,IAAI,EAAEJ,MAAM;gBAClB,yDAAyD;gBAC3D,OAAO,IAAIC,eAAe5B,WAAWkC,MAAM,EAAE;oBAC3CJ,OAAO5B,eAAe;wBAAEY;wBAAYmB,MAAM,CAAC,SAAS,EAAEN,MAAM;oBAAC;oBAC7DI,KAAK,CAAC,WAAW,EAAEJ,MAAM;gBAC3B,OAAO,IAAIC,eAAe,YAAYH,OAAOK,IAAI,EAAE;oBACjD,wBAAwB;oBACxBC,KAAK,CAAC,WAAW,EAAEJ,MAAM;oBACzB,IAAIF,OAAOU,UAAU,EAAE;wBACrBL,OAAOL,OAAOK,IAAI;oBACpB,OAAO;wBACLA,OAAO5B,eAAe;4BAAEY;4BAAYmB,MAAMR,OAAOK,IAAI;wBAAC;oBACxD;gBACF,OAAO;oBACL,OAAO;gBACT;gBAEA,MAAMM,WACJ1B,SAAS2B,UAAU,CAACP,SAAS;oBAAC;oBAAKQ;iBAAU,CAACC,QAAQ,CAAC7B,QAAQ,CAACoB,KAAKU,MAAM,CAAC;gBAC9E,MAAMC,gBAAgB/B,aAAaoB;gBAEnC,mCAAmC;gBACnC,MAAMY,cAAcnC,QAAQ,CAACoB,KAAK;gBAElC,qBACE,KAACtB;oBACCqC,aAAaA;oBACbjB,QAAQA;oBACRK,MAAMA;oBACNC,IAAIA;oBACJK,UAAUA;oBACVK,eAAeA;mBACVf;YAGX;YAEA,uDAAuD;YACvD,IAAIL,aAAa;gBACf,qBAAO,KAACjB;8BAA0BoB;mBAAZD;YACxB;YACA,OAAO;YACP,qBACE,KAAC1B;gBACC8C,QAAQlC,gBAAgBD,QAAQ,CAACc,gBAAgB,EAAEsB;gBAEnD1B,OAAOI;0BAENE;eAHID;QAMX;;AAGN,EAAC"}
|
|
@@ -12,7 +12,7 @@ export const EnhancedSidebar = async (props)=>{
|
|
|
12
12
|
if (!payload?.config) {
|
|
13
13
|
return null;
|
|
14
14
|
}
|
|
15
|
-
const { admin: { components: { afterNavLinks, beforeNavLinks } }, collections, globals } = payload.config;
|
|
15
|
+
const { admin: { components: { afterNavLinks, beforeNavLinks, settingsMenu } }, collections, globals } = payload.config;
|
|
16
16
|
const groups = groupNavItems([
|
|
17
17
|
...collections.filter(({ slug })=>visibleEntities?.collections.includes(slug)).map((collection)=>({
|
|
18
18
|
type: EntityType.collection,
|
|
@@ -43,6 +43,12 @@ export const EnhancedSidebar = async (props)=>{
|
|
|
43
43
|
importMap: payload.importMap,
|
|
44
44
|
serverProps
|
|
45
45
|
});
|
|
46
|
+
const renderedSettingsMenu = settingsMenu && Array.isArray(settingsMenu) ? settingsMenu.map((item, index)=>RenderServerComponent({
|
|
47
|
+
Component: item,
|
|
48
|
+
importMap: payload.importMap,
|
|
49
|
+
key: `settings-menu-item-${index}`,
|
|
50
|
+
serverProps
|
|
51
|
+
})) : [];
|
|
46
52
|
// Default config if not provided
|
|
47
53
|
const config = sidebarConfig ?? {
|
|
48
54
|
tabs: [
|
|
@@ -66,6 +72,7 @@ export const EnhancedSidebar = async (props)=>{
|
|
|
66
72
|
groups: groups,
|
|
67
73
|
initialActiveTabId: initialActiveTabId,
|
|
68
74
|
navPreferences: navPreferences,
|
|
75
|
+
settingsMenu: renderedSettingsMenu,
|
|
69
76
|
sidebarConfig: config
|
|
70
77
|
});
|
|
71
78
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/components/EnhancedSidebar/index.tsx"],"sourcesContent":["import type { EntityToGroup } from '@payloadcms/ui/shared'\nimport type { PayloadRequest, ServerProps } from 'payload'\n\nimport { RenderServerComponent } from '@payloadcms/ui/elements/RenderServerComponent'\nimport { EntityType, groupNavItems } from '@payloadcms/ui/shared'\nimport { cookies } from 'next/headers'\nimport React from 'react'\n\nconst COOKIE_KEY = 'payload-enhanced-sidebar-active-tab'\n\nimport type { EnhancedSidebarConfig, ExtendedGroup } from '../../types'\n\nimport { getNavPrefs } from './getNavPrefs'\nimport { SidebarContent } from './SidebarContent'\nimport './index.scss'\n\nexport type EnhancedSidebarProps = {\n req?: PayloadRequest\n sidebarConfig?: EnhancedSidebarConfig\n} & ServerProps\n\nexport const EnhancedSidebar: React.FC<EnhancedSidebarProps> = async (props) => {\n const {\n i18n,\n locale,\n params,\n payload,\n permissions,\n req,\n searchParams,\n sidebarConfig,\n user,\n visibleEntities,\n } = props\n\n if (!payload?.config) {\n return null\n }\n\n const {\n admin: {\n components: { afterNavLinks, beforeNavLinks },\n },\n collections,\n globals,\n } = payload.config\n\n const groups = groupNavItems(\n [\n ...collections\n .filter(({ slug }) => visibleEntities?.collections.includes(slug))\n .map(\n (collection) =>\n ({\n type: EntityType.collection,\n entity: collection,\n }) satisfies EntityToGroup,\n ),\n ...globals\n .filter(({ slug }) => visibleEntities?.globals.includes(slug))\n .map(\n (global) =>\n ({\n type: EntityType.global,\n entity: global,\n }) satisfies EntityToGroup,\n ),\n ],\n permissions || {},\n i18n,\n ) as unknown as ExtendedGroup[]\n\n const navPreferences = await getNavPrefs(req)\n\n const serverProps = {\n i18n,\n locale,\n params,\n payload,\n permissions,\n searchParams,\n user,\n }\n\n const beforeNavLinksRendered = RenderServerComponent({\n Component: beforeNavLinks,\n importMap: payload.importMap,\n serverProps,\n })\n\n const afterNavLinksRendered = RenderServerComponent({\n Component: afterNavLinks,\n importMap: payload.importMap,\n serverProps,\n })\n\n // Default config if not provided\n const config: EnhancedSidebarConfig = sidebarConfig ?? {\n tabs: [\n {\n id: 'default',\n type: 'tab',\n icon: 'LayoutGrid',\n label: 'Collections',\n },\n ],\n }\n\n // Read active tab from cookie\n const cookieStore = await cookies()\n const storedTabId = cookieStore.get(COOKIE_KEY)?.value\n const tabs = config.tabs?.filter((t) => t.type === 'tab') ?? []\n const defaultTabId = tabs[0]?.id ?? 'default'\n const initialActiveTabId =\n storedTabId && tabs.some((t) => t.id === storedTabId) ? storedTabId : defaultTabId\n\n return (\n <SidebarContent\n afterNavLinks={afterNavLinksRendered}\n beforeNavLinks={beforeNavLinksRendered}\n groups={groups}\n initialActiveTabId={initialActiveTabId}\n navPreferences={navPreferences}\n sidebarConfig={config}\n />\n )\n}\n\nexport default EnhancedSidebar\n"],"names":["RenderServerComponent","EntityType","groupNavItems","cookies","React","COOKIE_KEY","getNavPrefs","SidebarContent","EnhancedSidebar","props","i18n","locale","params","payload","permissions","req","searchParams","sidebarConfig","user","visibleEntities","config","admin","components","afterNavLinks","beforeNavLinks","collections","globals","groups","filter","slug","includes","map","collection","type","entity","global","navPreferences","serverProps","beforeNavLinksRendered","Component","importMap","afterNavLinksRendered","tabs","id","icon","label","cookieStore","storedTabId","get","value","t","defaultTabId","initialActiveTabId","some"],"mappings":";AAGA,SAASA,qBAAqB,QAAQ,gDAA+C;AACrF,SAASC,UAAU,EAAEC,aAAa,QAAQ,wBAAuB;AACjE,SAASC,OAAO,QAAQ,eAAc;AACtC,OAAOC,WAAW,QAAO;AAEzB,MAAMC,aAAa;AAInB,SAASC,WAAW,QAAQ,gBAAe;AAC3C,SAASC,cAAc,QAAQ,mBAAkB;AACjD,OAAO,eAAc;AAOrB,OAAO,MAAMC,kBAAkD,OAAOC;IACpE,MAAM,EACJC,IAAI,EACJC,MAAM,EACNC,MAAM,EACNC,OAAO,EACPC,WAAW,EACXC,GAAG,EACHC,YAAY,EACZC,aAAa,EACbC,IAAI,EACJC,eAAe,EAChB,GAAGV;IAEJ,IAAI,CAACI,SAASO,QAAQ;QACpB,OAAO;IACT;IAEA,MAAM,EACJC,OAAO,EACLC,YAAY,EAAEC,aAAa,EAAEC,cAAc,EAAE,
|
|
1
|
+
{"version":3,"sources":["../../../src/components/EnhancedSidebar/index.tsx"],"sourcesContent":["import type { EntityToGroup } from '@payloadcms/ui/shared'\nimport type { PayloadRequest, ServerProps } from 'payload'\n\nimport { RenderServerComponent } from '@payloadcms/ui/elements/RenderServerComponent'\nimport { EntityType, groupNavItems } from '@payloadcms/ui/shared'\nimport { cookies } from 'next/headers'\nimport React from 'react'\n\nconst COOKIE_KEY = 'payload-enhanced-sidebar-active-tab'\n\nimport type { EnhancedSidebarConfig, ExtendedGroup } from '../../types'\n\nimport { getNavPrefs } from './getNavPrefs'\nimport { SidebarContent } from './SidebarContent'\nimport './index.scss'\n\nexport type EnhancedSidebarProps = {\n req?: PayloadRequest\n sidebarConfig?: EnhancedSidebarConfig\n} & ServerProps\n\nexport const EnhancedSidebar: React.FC<EnhancedSidebarProps> = async (props) => {\n const {\n i18n,\n locale,\n params,\n payload,\n permissions,\n req,\n searchParams,\n sidebarConfig,\n user,\n visibleEntities,\n } = props\n\n if (!payload?.config) {\n return null\n }\n\n const {\n admin: {\n components: { afterNavLinks, beforeNavLinks, settingsMenu },\n },\n collections,\n globals,\n } = payload.config\n\n const groups = groupNavItems(\n [\n ...collections\n .filter(({ slug }) => visibleEntities?.collections.includes(slug))\n .map(\n (collection) =>\n ({\n type: EntityType.collection,\n entity: collection,\n }) satisfies EntityToGroup,\n ),\n ...globals\n .filter(({ slug }) => visibleEntities?.globals.includes(slug))\n .map(\n (global) =>\n ({\n type: EntityType.global,\n entity: global,\n }) satisfies EntityToGroup,\n ),\n ],\n permissions || {},\n i18n,\n ) as unknown as ExtendedGroup[]\n\n const navPreferences = await getNavPrefs(req)\n\n const serverProps = {\n i18n,\n locale,\n params,\n payload,\n permissions,\n searchParams,\n user,\n }\n\n const beforeNavLinksRendered = RenderServerComponent({\n Component: beforeNavLinks,\n importMap: payload.importMap,\n serverProps,\n })\n\n const afterNavLinksRendered = RenderServerComponent({\n Component: afterNavLinks,\n importMap: payload.importMap,\n serverProps,\n })\n\n const renderedSettingsMenu =\n settingsMenu && Array.isArray(settingsMenu)\n ? settingsMenu.map((item, index) =>\n RenderServerComponent({\n Component: item,\n importMap: payload.importMap,\n key: `settings-menu-item-${index}`,\n serverProps,\n }),\n )\n : []\n\n // Default config if not provided\n const config: EnhancedSidebarConfig = sidebarConfig ?? {\n tabs: [\n {\n id: 'default',\n type: 'tab',\n icon: 'LayoutGrid',\n label: 'Collections',\n },\n ],\n }\n\n // Read active tab from cookie\n const cookieStore = await cookies()\n const storedTabId = cookieStore.get(COOKIE_KEY)?.value\n const tabs = config.tabs?.filter((t) => t.type === 'tab') ?? []\n const defaultTabId = tabs[0]?.id ?? 'default'\n const initialActiveTabId =\n storedTabId && tabs.some((t) => t.id === storedTabId) ? storedTabId : defaultTabId\n\n return (\n <SidebarContent\n afterNavLinks={afterNavLinksRendered}\n beforeNavLinks={beforeNavLinksRendered}\n groups={groups}\n initialActiveTabId={initialActiveTabId}\n navPreferences={navPreferences}\n settingsMenu={renderedSettingsMenu}\n sidebarConfig={config}\n />\n )\n}\n\nexport default EnhancedSidebar\n"],"names":["RenderServerComponent","EntityType","groupNavItems","cookies","React","COOKIE_KEY","getNavPrefs","SidebarContent","EnhancedSidebar","props","i18n","locale","params","payload","permissions","req","searchParams","sidebarConfig","user","visibleEntities","config","admin","components","afterNavLinks","beforeNavLinks","settingsMenu","collections","globals","groups","filter","slug","includes","map","collection","type","entity","global","navPreferences","serverProps","beforeNavLinksRendered","Component","importMap","afterNavLinksRendered","renderedSettingsMenu","Array","isArray","item","index","key","tabs","id","icon","label","cookieStore","storedTabId","get","value","t","defaultTabId","initialActiveTabId","some"],"mappings":";AAGA,SAASA,qBAAqB,QAAQ,gDAA+C;AACrF,SAASC,UAAU,EAAEC,aAAa,QAAQ,wBAAuB;AACjE,SAASC,OAAO,QAAQ,eAAc;AACtC,OAAOC,WAAW,QAAO;AAEzB,MAAMC,aAAa;AAInB,SAASC,WAAW,QAAQ,gBAAe;AAC3C,SAASC,cAAc,QAAQ,mBAAkB;AACjD,OAAO,eAAc;AAOrB,OAAO,MAAMC,kBAAkD,OAAOC;IACpE,MAAM,EACJC,IAAI,EACJC,MAAM,EACNC,MAAM,EACNC,OAAO,EACPC,WAAW,EACXC,GAAG,EACHC,YAAY,EACZC,aAAa,EACbC,IAAI,EACJC,eAAe,EAChB,GAAGV;IAEJ,IAAI,CAACI,SAASO,QAAQ;QACpB,OAAO;IACT;IAEA,MAAM,EACJC,OAAO,EACLC,YAAY,EAAEC,aAAa,EAAEC,cAAc,EAAEC,YAAY,EAAE,EAC5D,EACDC,WAAW,EACXC,OAAO,EACR,GAAGd,QAAQO,MAAM;IAElB,MAAMQ,SAAS1B,cACb;WACKwB,YACAG,MAAM,CAAC,CAAC,EAAEC,IAAI,EAAE,GAAKX,iBAAiBO,YAAYK,SAASD,OAC3DE,GAAG,CACF,CAACC,aACE,CAAA;gBACCC,MAAMjC,WAAWgC,UAAU;gBAC3BE,QAAQF;YACV,CAAA;WAEHN,QACAE,MAAM,CAAC,CAAC,EAAEC,IAAI,EAAE,GAAKX,iBAAiBQ,QAAQI,SAASD,OACvDE,GAAG,CACF,CAACI,SACE,CAAA;gBACCF,MAAMjC,WAAWmC,MAAM;gBACvBD,QAAQC;YACV,CAAA;KAEP,EACDtB,eAAe,CAAC,GAChBJ;IAGF,MAAM2B,iBAAiB,MAAM/B,YAAYS;IAEzC,MAAMuB,cAAc;QAClB5B;QACAC;QACAC;QACAC;QACAC;QACAE;QACAE;IACF;IAEA,MAAMqB,yBAAyBvC,sBAAsB;QACnDwC,WAAWhB;QACXiB,WAAW5B,QAAQ4B,SAAS;QAC5BH;IACF;IAEA,MAAMI,wBAAwB1C,sBAAsB;QAClDwC,WAAWjB;QACXkB,WAAW5B,QAAQ4B,SAAS;QAC5BH;IACF;IAEA,MAAMK,uBACJlB,gBAAgBmB,MAAMC,OAAO,CAACpB,gBAC1BA,aAAaO,GAAG,CAAC,CAACc,MAAMC,QACtB/C,sBAAsB;YACpBwC,WAAWM;YACXL,WAAW5B,QAAQ4B,SAAS;YAC5BO,KAAK,CAAC,mBAAmB,EAAED,OAAO;YAClCT;QACF,MAEF,EAAE;IAER,iCAAiC;IACjC,MAAMlB,SAAgCH,iBAAiB;QACrDgC,MAAM;YACJ;gBACEC,IAAI;gBACJhB,MAAM;gBACNiB,MAAM;gBACNC,OAAO;YACT;SACD;IACH;IAEA,8BAA8B;IAC9B,MAAMC,cAAc,MAAMlD;IAC1B,MAAMmD,cAAcD,YAAYE,GAAG,CAAClD,aAAamD;IACjD,MAAMP,OAAO7B,OAAO6B,IAAI,EAAEpB,OAAO,CAAC4B,IAAMA,EAAEvB,IAAI,KAAK,UAAU,EAAE;IAC/D,MAAMwB,eAAeT,IAAI,CAAC,EAAE,EAAEC,MAAM;IACpC,MAAMS,qBACJL,eAAeL,KAAKW,IAAI,CAAC,CAACH,IAAMA,EAAEP,EAAE,KAAKI,eAAeA,cAAcI;IAExE,qBACE,KAACnD;QACCgB,eAAemB;QACflB,gBAAgBe;QAChBX,QAAQA;QACR+B,oBAAoBA;QACpBtB,gBAAgBA;QAChBZ,cAAckB;QACd1B,eAAeG;;AAGrB,EAAC;AAED,eAAeZ,gBAAe"}
|
package/dist/exports/client.d.ts
CHANGED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { InternalBadgeProvider } from '../components/EnhancedSidebar/InternalBadgeProvider';
|
package/dist/exports/client.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/exports/client.ts"],"sourcesContent":["// Client components
|
|
1
|
+
{"version":3,"sources":["../../src/exports/client.ts"],"sourcesContent":["// Client components exported for Payload's component system\nexport { InternalBadgeProvider } from '../components/EnhancedSidebar/InternalBadgeProvider'\n"],"names":["InternalBadgeProvider"],"mappings":"AAAA,4DAA4D;AAC5D,SAASA,qBAAqB,QAAQ,sDAAqD"}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { type Config } from 'payload';
|
|
2
2
|
import type { EnhancedSidebarConfig } from './types';
|
|
3
3
|
export declare const payloadEnhancedSidebar: (pluginOptions?: EnhancedSidebarConfig) => (config: Config) => Config;
|
|
4
|
-
export
|
|
4
|
+
export { BadgeProvider, useBadgeContext, useBadgeValue, } from './components/EnhancedSidebar/BadgeProvider';
|
|
5
|
+
export type { BadgeColor, BadgeConfig, BadgeConfigApi, BadgeConfigCollectionCount, BadgeConfigProvider, BadgeValues, EnhancedSidebarConfig, } from './types';
|
package/dist/index.js
CHANGED
|
@@ -50,6 +50,21 @@ export const payloadEnhancedSidebar = (pluginOptions = {})=>(config)=>{
|
|
|
50
50
|
}
|
|
51
51
|
};
|
|
52
52
|
}
|
|
53
|
+
// Check if we have any badges to fetch (api or collection-count)
|
|
54
|
+
const hasBadgesToFetch = sidebarConfig.badges || sidebarConfig.tabs?.some((tab)=>tab.badge && tab.badge.type !== 'provider');
|
|
55
|
+
// Add InternalBadgeProvider if we have badges to fetch
|
|
56
|
+
if (hasBadgesToFetch) {
|
|
57
|
+
if (!config.admin.components.providers) {
|
|
58
|
+
config.admin.components.providers = [];
|
|
59
|
+
}
|
|
60
|
+
// Add our internal provider at the beginning (so user providers can override)
|
|
61
|
+
config.admin.components.providers.unshift({
|
|
62
|
+
clientProps: {
|
|
63
|
+
sidebarConfig
|
|
64
|
+
},
|
|
65
|
+
path: '@veiag/payload-enhanced-sidebar/client#InternalBadgeProvider'
|
|
66
|
+
});
|
|
67
|
+
}
|
|
53
68
|
// Adding translations
|
|
54
69
|
if (!config.i18n) {
|
|
55
70
|
config.i18n = {};
|
|
@@ -60,5 +75,6 @@ export const payloadEnhancedSidebar = (pluginOptions = {})=>(config)=>{
|
|
|
60
75
|
config.i18n.translations = deepMerge(config.i18n.translations, sidebarTranslations);
|
|
61
76
|
return config;
|
|
62
77
|
};
|
|
78
|
+
export { BadgeProvider, useBadgeContext, useBadgeValue } from './components/EnhancedSidebar/BadgeProvider';
|
|
63
79
|
|
|
64
80
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["import { type Config, deepMerge } from 'payload'\n\nimport type { EnhancedSidebarConfig } from './types'\n\nimport { sidebarTranslations } from './translations'\n\n/**\n * Default configuration for the enhanced sidebar\n */\nconst defaultConfig: EnhancedSidebarConfig = {\n showLogout: true,\n tabs: [\n {\n id: 'dashboard',\n type: 'link',\n href: '/',\n icon: 'House',\n label: { en: 'Dashboard', uk: 'Головна' },\n },\n {\n id: 'default',\n type: 'tab',\n icon: 'LayoutGrid',\n label: { en: 'Collections', uk: 'Колекції' },\n },\n ],\n}\n\nexport const payloadEnhancedSidebar =\n (pluginOptions: EnhancedSidebarConfig = {}) =>\n (config: Config): Config => {\n if (pluginOptions.disabled) {\n return config\n }\n\n // Merge user config with defaults\n const sidebarConfig: EnhancedSidebarConfig = {\n ...defaultConfig,\n ...pluginOptions,\n tabs: pluginOptions.tabs ?? defaultConfig.tabs,\n }\n\n if (!config.admin) {\n config.admin = {}\n }\n\n if (!config.admin.components) {\n config.admin.components = {}\n }\n\n if (!config.admin.components.Nav) {\n config.admin.components.Nav = {\n path: '@veiag/payload-enhanced-sidebar/rsc#EnhancedSidebar',\n serverProps: {\n sidebarConfig,\n },\n }\n }\n\n // Adding translations\n if (!config.i18n) {\n config.i18n = {}\n }\n if (!config.i18n.translations) {\n config.i18n.translations = {}\n }\n\n config.i18n.translations = deepMerge(config.i18n.translations, sidebarTranslations)\n\n return config\n }\n\nexport type {
|
|
1
|
+
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["import { type Config, deepMerge } from 'payload'\n\nimport type { EnhancedSidebarConfig } from './types'\n\nimport { sidebarTranslations } from './translations'\n\n/**\n * Default configuration for the enhanced sidebar\n */\nconst defaultConfig: EnhancedSidebarConfig = {\n showLogout: true,\n tabs: [\n {\n id: 'dashboard',\n type: 'link',\n href: '/',\n icon: 'House',\n label: { en: 'Dashboard', uk: 'Головна' },\n },\n {\n id: 'default',\n type: 'tab',\n icon: 'LayoutGrid',\n label: { en: 'Collections', uk: 'Колекції' },\n },\n ],\n}\n\nexport const payloadEnhancedSidebar =\n (pluginOptions: EnhancedSidebarConfig = {}) =>\n (config: Config): Config => {\n if (pluginOptions.disabled) {\n return config\n }\n\n // Merge user config with defaults\n const sidebarConfig: EnhancedSidebarConfig = {\n ...defaultConfig,\n ...pluginOptions,\n tabs: pluginOptions.tabs ?? defaultConfig.tabs,\n }\n\n if (!config.admin) {\n config.admin = {}\n }\n\n if (!config.admin.components) {\n config.admin.components = {}\n }\n\n if (!config.admin.components.Nav) {\n config.admin.components.Nav = {\n path: '@veiag/payload-enhanced-sidebar/rsc#EnhancedSidebar',\n serverProps: {\n sidebarConfig,\n },\n }\n }\n\n // Check if we have any badges to fetch (api or collection-count)\n const hasBadgesToFetch =\n sidebarConfig.badges ||\n sidebarConfig.tabs?.some((tab) => tab.badge && tab.badge.type !== 'provider')\n\n // Add InternalBadgeProvider if we have badges to fetch\n if (hasBadgesToFetch) {\n if (!config.admin.components.providers) {\n config.admin.components.providers = []\n }\n\n // Add our internal provider at the beginning (so user providers can override)\n config.admin.components.providers.unshift({\n clientProps: {\n sidebarConfig,\n },\n path: '@veiag/payload-enhanced-sidebar/client#InternalBadgeProvider',\n })\n }\n\n // Adding translations\n if (!config.i18n) {\n config.i18n = {}\n }\n if (!config.i18n.translations) {\n config.i18n.translations = {}\n }\n\n config.i18n.translations = deepMerge(config.i18n.translations, sidebarTranslations)\n\n return config\n }\n\nexport {\n BadgeProvider,\n useBadgeContext,\n useBadgeValue,\n} from './components/EnhancedSidebar/BadgeProvider'\n\nexport type {\n BadgeColor,\n BadgeConfig,\n BadgeConfigApi,\n BadgeConfigCollectionCount,\n BadgeConfigProvider,\n BadgeValues,\n EnhancedSidebarConfig,\n} from './types'\n"],"names":["deepMerge","sidebarTranslations","defaultConfig","showLogout","tabs","id","type","href","icon","label","en","uk","payloadEnhancedSidebar","pluginOptions","config","disabled","sidebarConfig","admin","components","Nav","path","serverProps","hasBadgesToFetch","badges","some","tab","badge","providers","unshift","clientProps","i18n","translations","BadgeProvider","useBadgeContext","useBadgeValue"],"mappings":"AAAA,SAAsBA,SAAS,QAAQ,UAAS;AAIhD,SAASC,mBAAmB,QAAQ,iBAAgB;AAEpD;;CAEC,GACD,MAAMC,gBAAuC;IAC3CC,YAAY;IACZC,MAAM;QACJ;YACEC,IAAI;YACJC,MAAM;YACNC,MAAM;YACNC,MAAM;YACNC,OAAO;gBAAEC,IAAI;gBAAaC,IAAI;YAAU;QAC1C;QACA;YACEN,IAAI;YACJC,MAAM;YACNE,MAAM;YACNC,OAAO;gBAAEC,IAAI;gBAAeC,IAAI;YAAW;QAC7C;KACD;AACH;AAEA,OAAO,MAAMC,yBACX,CAACC,gBAAuC,CAAC,CAAC,GAC1C,CAACC;QACC,IAAID,cAAcE,QAAQ,EAAE;YAC1B,OAAOD;QACT;QAEA,kCAAkC;QAClC,MAAME,gBAAuC;YAC3C,GAAGd,aAAa;YAChB,GAAGW,aAAa;YAChBT,MAAMS,cAAcT,IAAI,IAAIF,cAAcE,IAAI;QAChD;QAEA,IAAI,CAACU,OAAOG,KAAK,EAAE;YACjBH,OAAOG,KAAK,GAAG,CAAC;QAClB;QAEA,IAAI,CAACH,OAAOG,KAAK,CAACC,UAAU,EAAE;YAC5BJ,OAAOG,KAAK,CAACC,UAAU,GAAG,CAAC;QAC7B;QAEA,IAAI,CAACJ,OAAOG,KAAK,CAACC,UAAU,CAACC,GAAG,EAAE;YAChCL,OAAOG,KAAK,CAACC,UAAU,CAACC,GAAG,GAAG;gBAC5BC,MAAM;gBACNC,aAAa;oBACXL;gBACF;YACF;QACF;QAEA,iEAAiE;QACjE,MAAMM,mBACJN,cAAcO,MAAM,IACpBP,cAAcZ,IAAI,EAAEoB,KAAK,CAACC,MAAQA,IAAIC,KAAK,IAAID,IAAIC,KAAK,CAACpB,IAAI,KAAK;QAEpE,uDAAuD;QACvD,IAAIgB,kBAAkB;YACpB,IAAI,CAACR,OAAOG,KAAK,CAACC,UAAU,CAACS,SAAS,EAAE;gBACtCb,OAAOG,KAAK,CAACC,UAAU,CAACS,SAAS,GAAG,EAAE;YACxC;YAEA,8EAA8E;YAC9Eb,OAAOG,KAAK,CAACC,UAAU,CAACS,SAAS,CAACC,OAAO,CAAC;gBACxCC,aAAa;oBACXb;gBACF;gBACAI,MAAM;YACR;QACF;QAEA,sBAAsB;QACtB,IAAI,CAACN,OAAOgB,IAAI,EAAE;YAChBhB,OAAOgB,IAAI,GAAG,CAAC;QACjB;QACA,IAAI,CAAChB,OAAOgB,IAAI,CAACC,YAAY,EAAE;YAC7BjB,OAAOgB,IAAI,CAACC,YAAY,GAAG,CAAC;QAC9B;QAEAjB,OAAOgB,IAAI,CAACC,YAAY,GAAG/B,UAAUc,OAAOgB,IAAI,CAACC,YAAY,EAAE9B;QAE/D,OAAOa;IACT,EAAC;AAEH,SACEkB,aAAa,EACbC,eAAe,EACfC,aAAa,QACR,6CAA4C"}
|
package/dist/types.d.ts
CHANGED
|
@@ -1,14 +1,98 @@
|
|
|
1
1
|
import type { icons, LucideIcon } from 'lucide-react';
|
|
2
|
-
import type { CollectionSlug, GlobalSlug } from 'payload';
|
|
2
|
+
import type { CollectionSlug, GlobalSlug, Where } from 'payload';
|
|
3
|
+
import type { ReactNode } from 'react';
|
|
3
4
|
export type IconName = keyof typeof icons;
|
|
4
5
|
export type LocalizedString = {
|
|
5
6
|
[locale: string]: string;
|
|
6
7
|
} | string;
|
|
7
8
|
export type InternalIcon = IconName | LucideIcon;
|
|
9
|
+
/**
|
|
10
|
+
* Available badge color variants
|
|
11
|
+
*/
|
|
12
|
+
export type BadgeColor = 'default' | 'error' | 'primary' | 'success' | 'warning';
|
|
13
|
+
/**
|
|
14
|
+
* Badge configuration Trr API-based fetching
|
|
15
|
+
*/
|
|
16
|
+
export interface BadgeConfigApi {
|
|
17
|
+
/**
|
|
18
|
+
* Badge color variant
|
|
19
|
+
* @default 'default'
|
|
20
|
+
*/
|
|
21
|
+
color?: BadgeColor;
|
|
22
|
+
/**
|
|
23
|
+
* API endpoint to fetch badge data from.
|
|
24
|
+
* Can be relative (to current origin) or absolute URL.
|
|
25
|
+
*/
|
|
26
|
+
endpoint: string;
|
|
27
|
+
/**
|
|
28
|
+
* HTTP method for the request
|
|
29
|
+
* @default 'GET'
|
|
30
|
+
*/
|
|
31
|
+
method?: 'GET' | 'POST';
|
|
32
|
+
/**
|
|
33
|
+
* Key in the response object to extract the count from
|
|
34
|
+
* @default 'count'
|
|
35
|
+
*/
|
|
36
|
+
responseKey?: string;
|
|
37
|
+
type: 'api';
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Badge configuration for provider-based values.
|
|
41
|
+
* Values are provided via BadgeProvider context.
|
|
42
|
+
*/
|
|
43
|
+
export interface BadgeConfigProvider {
|
|
44
|
+
/**
|
|
45
|
+
* Badge color variant
|
|
46
|
+
* @default 'default'
|
|
47
|
+
*/
|
|
48
|
+
color?: BadgeColor;
|
|
49
|
+
/**
|
|
50
|
+
* Slug to look up in the BadgeProvider values.
|
|
51
|
+
* If not specified, defaults to the item's id/slug.
|
|
52
|
+
*/
|
|
53
|
+
slug?: string;
|
|
54
|
+
type: 'provider';
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Badge configuration for automatic collection document count.
|
|
58
|
+
* Fetches from /api/{collectionSlug}?limit=0 and uses totalDocs.
|
|
59
|
+
*/
|
|
60
|
+
export interface BadgeConfigCollectionCount {
|
|
61
|
+
/**
|
|
62
|
+
* Collection slug to count documents from.
|
|
63
|
+
* If not specified, defaults to the item's slug.
|
|
64
|
+
*/
|
|
65
|
+
collectionSlug?: CollectionSlug;
|
|
66
|
+
/**
|
|
67
|
+
* Badge color variant
|
|
68
|
+
* @default 'default'
|
|
69
|
+
*/
|
|
70
|
+
color?: BadgeColor;
|
|
71
|
+
type: 'collection-count';
|
|
72
|
+
/**
|
|
73
|
+
* Optional where query to filter documents.
|
|
74
|
+
* Will be serialized as query string.
|
|
75
|
+
* @example { status: { equals: 'draft' } }
|
|
76
|
+
*/
|
|
77
|
+
where?: Where;
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Badge configuration - union of all badge types
|
|
81
|
+
*/
|
|
82
|
+
export type BadgeConfig = BadgeConfigApi | BadgeConfigCollectionCount | BadgeConfigProvider;
|
|
83
|
+
/**
|
|
84
|
+
* Badge values provided via BadgeProvider context
|
|
85
|
+
*/
|
|
86
|
+
export type BadgeValues = Record<string, number | ReactNode>;
|
|
8
87
|
/**
|
|
9
88
|
* Sidebar tab that shows content when selected
|
|
10
89
|
*/
|
|
11
90
|
export interface SidebarTabContent {
|
|
91
|
+
/**
|
|
92
|
+
* Badge configuration for this tab.
|
|
93
|
+
* Shows a badge on the tab icon in the tabs bar.
|
|
94
|
+
*/
|
|
95
|
+
badge?: BadgeConfig;
|
|
12
96
|
/**
|
|
13
97
|
* Collections to show in this tab.
|
|
14
98
|
* If not specified, no collections are shown (unless items are specified).
|
|
@@ -36,6 +120,11 @@ export interface SidebarTabContent {
|
|
|
36
120
|
type: 'tab';
|
|
37
121
|
}
|
|
38
122
|
interface SidebarTabLinkBase {
|
|
123
|
+
/**
|
|
124
|
+
* Badge configuration for this link.
|
|
125
|
+
* Shows a badge on the link icon in the tabs bar.
|
|
126
|
+
*/
|
|
127
|
+
badge?: BadgeConfig;
|
|
39
128
|
/** Icon name from lucide-react */
|
|
40
129
|
icon: IconName;
|
|
41
130
|
/** Unique identifier */
|
|
@@ -95,6 +184,20 @@ export type SidebarTabItem = ExternalHrefItem | InternalHrefItem;
|
|
|
95
184
|
* Configuration for the enhanced sidebar
|
|
96
185
|
*/
|
|
97
186
|
export interface EnhancedSidebarConfig {
|
|
187
|
+
/**
|
|
188
|
+
* Badge configurations for sidebar items (collections, globals, custom items).
|
|
189
|
+
* Key is the slug of the item.
|
|
190
|
+
*
|
|
191
|
+
* @example
|
|
192
|
+
* ```typescript
|
|
193
|
+
* badges: {
|
|
194
|
+
* 'posts': { type: 'collection-count', color: 'primary' },
|
|
195
|
+
* 'orders': { type: 'api', endpoint: '/api/orders/pending', responseKey: 'count' },
|
|
196
|
+
* 'notifications': { type: 'provider', color: 'error' },
|
|
197
|
+
* }
|
|
198
|
+
* ```
|
|
199
|
+
*/
|
|
200
|
+
badges?: Record<string, BadgeConfig>;
|
|
98
201
|
/**
|
|
99
202
|
* Disable the plugin
|
|
100
203
|
* @default false
|
package/dist/types.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/types.ts"],"sourcesContent":["import type { icons, LucideIcon } from 'lucide-react'\nimport type { CollectionSlug, GlobalSlug } from 'payload'\n\nexport type IconName = keyof typeof icons\n\nexport type LocalizedString = { [locale: string]: string } | string\n\nexport type InternalIcon = IconName | LucideIcon\n\n// ============================================\n// Enhanced Sidebar Types\n// ============================================\n\n/**\n * Sidebar tab that shows content when selected\n */\nexport interface SidebarTabContent {\n /**\n * Collections to show in this tab.\n * If not specified, no collections are shown (unless items are specified).\n * Use collection slugs.\n */\n collections?: CollectionSlug[]\n /**\n * Custom items to add to this tab.\n * Items with `group` will be merged into matching collection groups.\n * Items without `group` will be shown at the bottom as a flat list.\n */\n customItems?: SidebarTabItem[]\n /**\n * Globals to show in this tab.\n * If not specified, no globals are shown.\n * Use global slugs.\n */\n globals?: GlobalSlug[]\n /** Icon name from lucide-react */\n icon: IconName\n /** Unique identifier for the tab */\n id: string\n /** Tooltip/label for the tab */\n label: LocalizedString\n type: 'tab'\n}\n\ninterface SidebarTabLinkBase {\n /** Icon name from lucide-react */\n icon: IconName\n /** Unique identifier */\n id: string\n /** Tooltip/label */\n label: LocalizedString\n type: 'link'\n}\ninterface SidebarTabLinkExternal extends SidebarTabLinkBase {\n /** Link href (absolute URL) */\n href: string\n isExternal: true\n}\ninterface SidebarTabLinkInternal extends SidebarTabLinkBase {\n /** Link href (relative to admin route) */\n href: '' | `/${string}`\n isExternal?: false\n}\n/**\n * Sidebar link that navigates to a URL (not a tab)\n */\nexport type SidebarTabLink = SidebarTabLinkExternal | SidebarTabLinkInternal\n/**\n * A tab or link in the sidebar tabs bar\n */\nexport type SidebarTab = SidebarTabContent | SidebarTabLink\n\ninterface BaseSidebarTabItem {\n /**\n * Group to add this item to.\n * If matches an existing collection group label, item will be merged into that group.\n * If no match found, a new group will be created.\n * If not specified, item will be shown at the bottom as ungrouped.\n */\n group?: LocalizedString\n /** Display label */\n label: LocalizedString\n /** Unique slug for the item */\n slug: string\n}\ninterface ExternalHrefItem extends BaseSidebarTabItem {\n /** Link href (absolute URL or relative to root) */\n href: string\n /** Whether the link is external, without admin route prefix. */\n isExternal: true\n}\n\ninterface InternalHrefItem extends BaseSidebarTabItem {\n /** Link href (relative to admin route) */\n href: '' | `/${string}`\n /** Whether the link is external, without admin route prefix. */\n isExternal?: false\n}\n/**\n * Custom item inside a sidebar tab\n */\nexport type SidebarTabItem = ExternalHrefItem | InternalHrefItem\n\n/**\n * Configuration for the enhanced sidebar\n */\nexport interface EnhancedSidebarConfig {\n /**\n * Disable the plugin\n * @default false\n */\n disabled?: boolean\n\n /**\n * Custom icons for collections and globals in the default tab.\n */\n icons?: {\n collections?: Partial<Record<CollectionSlug, IconName>>\n globals?: Partial<Record<GlobalSlug, IconName>>\n }\n\n /**\n * Show logout button at the bottom of the tabs bar.\n * @default true\n */\n showLogout?: boolean\n\n /**\n * Tabs and links to show in the sidebar tabs bar.\n * Order matters - items are rendered top to bottom.\n *\n * @default [{ type: 'tab', id: 'default', icon: 'LayoutGrid', label: 'Collections' }]\n */\n tabs?: SidebarTab[]\n}\n\n/**\n * Generic document type for collections, with dynamic keys.\n * We assume values are either string or number for simplicity, useAsTitle is making sure of that.\n */\nexport type GenericCollectionDocument = {\n [key: string]: number | string\n id: string\n}\n\ninterface BaseExtendedEntity {\n label: Record<string, string> | string\n slug: string\n type: 'collection' | 'custom' | 'global'\n}\n\ninterface InternalExtendedEntity extends BaseExtendedEntity {\n href?: '' | `/${string}`\n isExternal?: false\n}\n\ninterface ExternalExtendedEntity extends BaseExtendedEntity {\n href: string\n isExternal: true\n}\n\nexport type ExtendedEntity = ExternalExtendedEntity | InternalExtendedEntity\n\nexport type ExtendedGroup = {\n entities: ExtendedEntity[]\n label: Record<string, string> | string\n}\n"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"sources":["../src/types.ts"],"sourcesContent":["import type { icons, LucideIcon } from 'lucide-react'\nimport type { CollectionSlug, GlobalSlug, Where } from 'payload'\nimport type { ReactNode } from 'react'\n\nexport type IconName = keyof typeof icons\n\nexport type LocalizedString = { [locale: string]: string } | string\n\nexport type InternalIcon = IconName | LucideIcon\n\n// ============================================\n// Badge Types\n// ============================================\n\n/**\n * Available badge color variants\n */\nexport type BadgeColor = 'default' | 'error' | 'primary' | 'success' | 'warning'\n\n/**\n * Badge configuration Trr API-based fetching\n */\nexport interface BadgeConfigApi {\n /**\n * Badge color variant\n * @default 'default'\n */\n color?: BadgeColor\n /**\n * API endpoint to fetch badge data from.\n * Can be relative (to current origin) or absolute URL.\n */\n endpoint: string\n /**\n * HTTP method for the request\n * @default 'GET'\n */\n method?: 'GET' | 'POST'\n /**\n * Key in the response object to extract the count from\n * @default 'count'\n */\n responseKey?: string\n type: 'api'\n}\n\n/**\n * Badge configuration for provider-based values.\n * Values are provided via BadgeProvider context.\n */\nexport interface BadgeConfigProvider {\n /**\n * Badge color variant\n * @default 'default'\n */\n color?: BadgeColor\n /**\n * Slug to look up in the BadgeProvider values.\n * If not specified, defaults to the item's id/slug.\n */\n slug?: string\n type: 'provider'\n}\n\n/**\n * Badge configuration for automatic collection document count.\n * Fetches from /api/{collectionSlug}?limit=0 and uses totalDocs.\n */\nexport interface BadgeConfigCollectionCount {\n /**\n * Collection slug to count documents from.\n * If not specified, defaults to the item's slug.\n */\n collectionSlug?: CollectionSlug\n /**\n * Badge color variant\n * @default 'default'\n */\n color?: BadgeColor\n type: 'collection-count'\n /**\n * Optional where query to filter documents.\n * Will be serialized as query string.\n * @example { status: { equals: 'draft' } }\n */\n where?: Where\n}\n\n/**\n * Badge configuration - union of all badge types\n */\nexport type BadgeConfig = BadgeConfigApi | BadgeConfigCollectionCount | BadgeConfigProvider\n\n/**\n * Badge values provided via BadgeProvider context\n */\nexport type BadgeValues = Record<string, number | ReactNode>\n\n// ============================================\n// Enhanced Sidebar Types\n// ============================================\n\n/**\n * Sidebar tab that shows content when selected\n */\nexport interface SidebarTabContent {\n /**\n * Badge configuration for this tab.\n * Shows a badge on the tab icon in the tabs bar.\n */\n badge?: BadgeConfig\n /**\n * Collections to show in this tab.\n * If not specified, no collections are shown (unless items are specified).\n * Use collection slugs.\n */\n collections?: CollectionSlug[]\n /**\n * Custom items to add to this tab.\n * Items with `group` will be merged into matching collection groups.\n * Items without `group` will be shown at the bottom as a flat list.\n */\n customItems?: SidebarTabItem[]\n /**\n * Globals to show in this tab.\n * If not specified, no globals are shown.\n * Use global slugs.\n */\n globals?: GlobalSlug[]\n /** Icon name from lucide-react */\n icon: IconName\n /** Unique identifier for the tab */\n id: string\n /** Tooltip/label for the tab */\n label: LocalizedString\n type: 'tab'\n}\n\ninterface SidebarTabLinkBase {\n /**\n * Badge configuration for this link.\n * Shows a badge on the link icon in the tabs bar.\n */\n badge?: BadgeConfig\n /** Icon name from lucide-react */\n icon: IconName\n /** Unique identifier */\n id: string\n /** Tooltip/label */\n label: LocalizedString\n type: 'link'\n}\ninterface SidebarTabLinkExternal extends SidebarTabLinkBase {\n /** Link href (absolute URL) */\n href: string\n isExternal: true\n}\ninterface SidebarTabLinkInternal extends SidebarTabLinkBase {\n /** Link href (relative to admin route) */\n href: '' | `/${string}`\n isExternal?: false\n}\n/**\n * Sidebar link that navigates to a URL (not a tab)\n */\nexport type SidebarTabLink = SidebarTabLinkExternal | SidebarTabLinkInternal\n/**\n * A tab or link in the sidebar tabs bar\n */\nexport type SidebarTab = SidebarTabContent | SidebarTabLink\n\ninterface BaseSidebarTabItem {\n /**\n * Group to add this item to.\n * If matches an existing collection group label, item will be merged into that group.\n * If no match found, a new group will be created.\n * If not specified, item will be shown at the bottom as ungrouped.\n */\n group?: LocalizedString\n /** Display label */\n label: LocalizedString\n /** Unique slug for the item */\n slug: string\n}\ninterface ExternalHrefItem extends BaseSidebarTabItem {\n /** Link href (absolute URL or relative to root) */\n href: string\n /** Whether the link is external, without admin route prefix. */\n isExternal: true\n}\n\ninterface InternalHrefItem extends BaseSidebarTabItem {\n /** Link href (relative to admin route) */\n href: '' | `/${string}`\n /** Whether the link is external, without admin route prefix. */\n isExternal?: false\n}\n/**\n * Custom item inside a sidebar tab\n */\nexport type SidebarTabItem = ExternalHrefItem | InternalHrefItem\n\n/**\n * Configuration for the enhanced sidebar\n */\nexport interface EnhancedSidebarConfig {\n /**\n * Badge configurations for sidebar items (collections, globals, custom items).\n * Key is the slug of the item.\n *\n * @example\n * ```typescript\n * badges: {\n * 'posts': { type: 'collection-count', color: 'primary' },\n * 'orders': { type: 'api', endpoint: '/api/orders/pending', responseKey: 'count' },\n * 'notifications': { type: 'provider', color: 'error' },\n * }\n * ```\n */\n badges?: Record<string, BadgeConfig>\n\n /**\n * Disable the plugin\n * @default false\n */\n disabled?: boolean\n\n /**\n * Custom icons for collections and globals in the default tab.\n */\n icons?: {\n collections?: Partial<Record<CollectionSlug, IconName>>\n globals?: Partial<Record<GlobalSlug, IconName>>\n }\n\n /**\n * Show logout button at the bottom of the tabs bar.\n * @default true\n */\n showLogout?: boolean\n\n /**\n * Tabs and links to show in the sidebar tabs bar.\n * Order matters - items are rendered top to bottom.\n *\n * @default [{ type: 'tab', id: 'default', icon: 'LayoutGrid', label: 'Collections' }]\n */\n tabs?: SidebarTab[]\n}\n\n/**\n * Generic document type for collections, with dynamic keys.\n * We assume values are either string or number for simplicity, useAsTitle is making sure of that.\n */\nexport type GenericCollectionDocument = {\n [key: string]: number | string\n id: string\n}\n\ninterface BaseExtendedEntity {\n label: Record<string, string> | string\n slug: string\n type: 'collection' | 'custom' | 'global'\n}\n\ninterface InternalExtendedEntity extends BaseExtendedEntity {\n href?: '' | `/${string}`\n isExternal?: false\n}\n\ninterface ExternalExtendedEntity extends BaseExtendedEntity {\n href: string\n isExternal: true\n}\n\nexport type ExtendedEntity = ExternalExtendedEntity | InternalExtendedEntity\n\nexport type ExtendedGroup = {\n entities: ExtendedEntity[]\n label: Record<string, string> | string\n}\n"],"names":[],"mappings":"AAqRA,WAGC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@veiag/payload-enhanced-sidebar",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "An enhanced sidebar plugin for Payload CMS with tabbed navigation to organize collections and globals.",
|
|
5
5
|
"author": "VeiaG",
|
|
6
6
|
"license": "MIT",
|
|
@@ -29,13 +29,13 @@
|
|
|
29
29
|
],
|
|
30
30
|
"devDependencies": {
|
|
31
31
|
"@eslint/eslintrc": "^3.2.0",
|
|
32
|
-
"@payloadcms/db-mongodb": "3.
|
|
33
|
-
"@payloadcms/db-postgres": "3.
|
|
34
|
-
"@payloadcms/db-sqlite": "3.
|
|
32
|
+
"@payloadcms/db-mongodb": "3.60.0",
|
|
33
|
+
"@payloadcms/db-postgres": "3.60.0",
|
|
34
|
+
"@payloadcms/db-sqlite": "3.60.0",
|
|
35
35
|
"@payloadcms/eslint-config": "3.9.0",
|
|
36
|
-
"@payloadcms/next": "3.
|
|
37
|
-
"@payloadcms/richtext-lexical": "3.
|
|
38
|
-
"@payloadcms/ui": "3.
|
|
36
|
+
"@payloadcms/next": "3.60.0",
|
|
37
|
+
"@payloadcms/richtext-lexical": "3.60.0",
|
|
38
|
+
"@payloadcms/ui": "3.60.0",
|
|
39
39
|
"@playwright/test": "1.56.1",
|
|
40
40
|
"@swc-node/register": "1.10.9",
|
|
41
41
|
"@swc/cli": "0.6.0",
|
|
@@ -50,7 +50,7 @@
|
|
|
50
50
|
"mongodb-memory-server": "10.1.4",
|
|
51
51
|
"next": "15.4.8",
|
|
52
52
|
"open": "^10.1.0",
|
|
53
|
-
"payload": "3.
|
|
53
|
+
"payload": "3.60.0",
|
|
54
54
|
"prettier": "^3.4.2",
|
|
55
55
|
"qs-esm": "7.0.2",
|
|
56
56
|
"react": "19.2.1",
|
|
@@ -63,7 +63,7 @@
|
|
|
63
63
|
"vitest": "^3.1.2"
|
|
64
64
|
},
|
|
65
65
|
"peerDependencies": {
|
|
66
|
-
"payload": "^3.
|
|
66
|
+
"payload": "^3.60.0"
|
|
67
67
|
},
|
|
68
68
|
"engines": {
|
|
69
69
|
"node": "^18.20.2 || >=20.9.0",
|
|
@@ -71,7 +71,7 @@
|
|
|
71
71
|
},
|
|
72
72
|
"registry": "https://registry.npmjs.org/",
|
|
73
73
|
"dependencies": {
|
|
74
|
-
"@payloadcms/translations": "^3.
|
|
74
|
+
"@payloadcms/translations": "^3.60.0",
|
|
75
75
|
"lucide-react": "^0.556.0"
|
|
76
76
|
},
|
|
77
77
|
"scripts": {
|