@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
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
3
|
+
import { getTranslation } from '@payloadcms/translations';
|
|
4
|
+
import { Link, useTranslation } from '@payloadcms/ui';
|
|
5
|
+
import React from 'react';
|
|
6
|
+
import { Badge } from '../Badge';
|
|
7
|
+
import { useBadge } from '../hooks/useBadge';
|
|
8
|
+
const baseClass = 'enhanced-sidebar';
|
|
9
|
+
export const NavItem = ({ id, badgeConfig, entity, href, isActive, isCurrentPage })=>{
|
|
10
|
+
const { i18n } = useTranslation();
|
|
11
|
+
const { value: badgeValue } = useBadge(badgeConfig, entity.slug);
|
|
12
|
+
const Label = /*#__PURE__*/ _jsxs(_Fragment, {
|
|
13
|
+
children: [
|
|
14
|
+
isActive && /*#__PURE__*/ _jsx("div", {
|
|
15
|
+
className: `${baseClass}__link-indicator`
|
|
16
|
+
}),
|
|
17
|
+
/*#__PURE__*/ _jsx("span", {
|
|
18
|
+
className: `${baseClass}__link-label`,
|
|
19
|
+
children: getTranslation(entity.label, i18n)
|
|
20
|
+
}),
|
|
21
|
+
badgeValue !== undefined && /*#__PURE__*/ _jsx(Badge, {
|
|
22
|
+
color: badgeConfig?.color,
|
|
23
|
+
position: "inline",
|
|
24
|
+
value: badgeValue
|
|
25
|
+
})
|
|
26
|
+
]
|
|
27
|
+
});
|
|
28
|
+
if (isCurrentPage) {
|
|
29
|
+
return /*#__PURE__*/ _jsx("div", {
|
|
30
|
+
className: `${baseClass}__link`,
|
|
31
|
+
id: id,
|
|
32
|
+
children: Label
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
return /*#__PURE__*/ _jsx(Link, {
|
|
36
|
+
className: `${baseClass}__link`,
|
|
37
|
+
href: href,
|
|
38
|
+
id: id,
|
|
39
|
+
prefetch: false,
|
|
40
|
+
rel: entity.isExternal ? 'noopener noreferrer' : undefined,
|
|
41
|
+
target: entity.isExternal ? '_blank' : undefined,
|
|
42
|
+
children: Label
|
|
43
|
+
});
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../src/components/EnhancedSidebar/NavItem/index.tsx"],"sourcesContent":["'use client'\n\nimport { getTranslation } from '@payloadcms/translations'\nimport { Link, useTranslation } from '@payloadcms/ui'\nimport React from 'react'\n\nimport type { BadgeConfig, ExtendedEntity } from '../../../types'\n\nimport { Badge } from '../Badge'\nimport { useBadge } from '../hooks/useBadge'\n\nconst baseClass = 'enhanced-sidebar'\n\nexport type NavItemProps = {\n badgeConfig?: BadgeConfig\n entity: ExtendedEntity\n href: string\n id: string\n isActive: boolean\n isCurrentPage: boolean\n}\n\nexport const NavItem: React.FC<NavItemProps> = ({\n id,\n badgeConfig,\n entity,\n href,\n isActive,\n isCurrentPage,\n}) => {\n const { i18n } = useTranslation()\n const { value: badgeValue } = useBadge(badgeConfig, entity.slug)\n\n const Label = (\n <>\n {isActive && <div className={`${baseClass}__link-indicator`} />}\n <span className={`${baseClass}__link-label`}>{getTranslation(entity.label, i18n)}</span>\n {badgeValue !== undefined && (\n <Badge color={badgeConfig?.color} position=\"inline\" value={badgeValue} />\n )}\n </>\n )\n\n if (isCurrentPage) {\n return (\n <div className={`${baseClass}__link`} id={id}>\n {Label}\n </div>\n )\n }\n\n return (\n <Link\n className={`${baseClass}__link`}\n href={href}\n id={id}\n prefetch={false}\n rel={entity.isExternal ? 'noopener noreferrer' : undefined}\n target={entity.isExternal ? '_blank' : undefined}\n >\n {Label}\n </Link>\n )\n}\n"],"names":["getTranslation","Link","useTranslation","React","Badge","useBadge","baseClass","NavItem","id","badgeConfig","entity","href","isActive","isCurrentPage","i18n","value","badgeValue","slug","Label","div","className","span","label","undefined","color","position","prefetch","rel","isExternal","target"],"mappings":"AAAA;;AAEA,SAASA,cAAc,QAAQ,2BAA0B;AACzD,SAASC,IAAI,EAAEC,cAAc,QAAQ,iBAAgB;AACrD,OAAOC,WAAW,QAAO;AAIzB,SAASC,KAAK,QAAQ,WAAU;AAChC,SAASC,QAAQ,QAAQ,oBAAmB;AAE5C,MAAMC,YAAY;AAWlB,OAAO,MAAMC,UAAkC,CAAC,EAC9CC,EAAE,EACFC,WAAW,EACXC,MAAM,EACNC,IAAI,EACJC,QAAQ,EACRC,aAAa,EACd;IACC,MAAM,EAAEC,IAAI,EAAE,GAAGZ;IACjB,MAAM,EAAEa,OAAOC,UAAU,EAAE,GAAGX,SAASI,aAAaC,OAAOO,IAAI;IAE/D,MAAMC,sBACJ;;YACGN,0BAAY,KAACO;gBAAIC,WAAW,GAAGd,UAAU,gBAAgB,CAAC;;0BAC3D,KAACe;gBAAKD,WAAW,GAAGd,UAAU,YAAY,CAAC;0BAAGN,eAAeU,OAAOY,KAAK,EAAER;;YAC1EE,eAAeO,2BACd,KAACnB;gBAAMoB,OAAOf,aAAae;gBAAOC,UAAS;gBAASV,OAAOC;;;;IAKjE,IAAIH,eAAe;QACjB,qBACE,KAACM;YAAIC,WAAW,GAAGd,UAAU,MAAM,CAAC;YAAEE,IAAIA;sBACvCU;;IAGP;IAEA,qBACE,KAACjB;QACCmB,WAAW,GAAGd,UAAU,MAAM,CAAC;QAC/BK,MAAMA;QACNH,IAAIA;QACJkB,UAAU;QACVC,KAAKjB,OAAOkB,UAAU,GAAG,wBAAwBL;QACjDM,QAAQnB,OAAOkB,UAAU,GAAG,WAAWL;kBAEtCL;;AAGP,EAAC"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
3
|
+
import { Popup, useTranslation } from '@payloadcms/ui';
|
|
4
|
+
import React, { Fragment } from 'react';
|
|
5
|
+
import { Icon } from '../Icon';
|
|
6
|
+
import './index.scss';
|
|
7
|
+
const baseClass = 'settings-menu-button';
|
|
8
|
+
export const SettingsMenuButton = ({ settingsMenu })=>{
|
|
9
|
+
const { t } = useTranslation();
|
|
10
|
+
if (!settingsMenu || settingsMenu.length === 0) {
|
|
11
|
+
return null;
|
|
12
|
+
}
|
|
13
|
+
return /*#__PURE__*/ _jsx(Popup, {
|
|
14
|
+
button: /*#__PURE__*/ _jsx("span", {
|
|
15
|
+
"aria-label": t('general:menu'),
|
|
16
|
+
className: `${baseClass}__button`,
|
|
17
|
+
children: /*#__PURE__*/ _jsx(Icon, {
|
|
18
|
+
name: "Settings",
|
|
19
|
+
size: 20
|
|
20
|
+
})
|
|
21
|
+
}),
|
|
22
|
+
className: baseClass,
|
|
23
|
+
horizontalAlign: "right",
|
|
24
|
+
id: "settings-menu",
|
|
25
|
+
size: "small",
|
|
26
|
+
verticalAlign: "top",
|
|
27
|
+
children: settingsMenu.map((item, i)=>/*#__PURE__*/ _jsx(Fragment, {
|
|
28
|
+
children: item
|
|
29
|
+
}, `settings-menu-item-${i}`))
|
|
30
|
+
});
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../src/components/EnhancedSidebar/SettingsMenuButton/index.tsx"],"sourcesContent":["'use client'\nimport { Popup, useTranslation } from '@payloadcms/ui'\nimport React, { Fragment } from 'react'\n\nimport { Icon } from '../Icon'\nimport './index.scss'\n\nconst baseClass = 'settings-menu-button'\n\nexport type SettingsMenuButtonProps = {\n settingsMenu?: React.ReactNode[]\n}\n\nexport const SettingsMenuButton: React.FC<SettingsMenuButtonProps> = ({ settingsMenu }) => {\n const { t } = useTranslation()\n\n if (!settingsMenu || settingsMenu.length === 0) {\n return null\n }\n\n return (\n <Popup\n button={\n <span aria-label={t('general:menu')} className={`${baseClass}__button`}>\n <Icon name=\"Settings\" size={20} />\n </span>\n }\n className={baseClass}\n horizontalAlign=\"right\"\n id=\"settings-menu\"\n size=\"small\"\n verticalAlign=\"top\"\n >\n {settingsMenu.map((item, i) => (\n <Fragment key={`settings-menu-item-${i}`}>{item}</Fragment>\n ))}\n </Popup>\n )\n}\n"],"names":["Popup","useTranslation","React","Fragment","Icon","baseClass","SettingsMenuButton","settingsMenu","t","length","button","span","aria-label","className","name","size","horizontalAlign","id","verticalAlign","map","item","i"],"mappings":"AAAA;;AACA,SAASA,KAAK,EAAEC,cAAc,QAAQ,iBAAgB;AACtD,OAAOC,SAASC,QAAQ,QAAQ,QAAO;AAEvC,SAASC,IAAI,QAAQ,UAAS;AAC9B,OAAO,eAAc;AAErB,MAAMC,YAAY;AAMlB,OAAO,MAAMC,qBAAwD,CAAC,EAAEC,YAAY,EAAE;IACpF,MAAM,EAAEC,CAAC,EAAE,GAAGP;IAEd,IAAI,CAACM,gBAAgBA,aAAaE,MAAM,KAAK,GAAG;QAC9C,OAAO;IACT;IAEA,qBACE,KAACT;QACCU,sBACE,KAACC;YAAKC,cAAYJ,EAAE;YAAiBK,WAAW,GAAGR,UAAU,QAAQ,CAAC;sBACpE,cAAA,KAACD;gBAAKU,MAAK;gBAAWC,MAAM;;;QAGhCF,WAAWR;QACXW,iBAAgB;QAChBC,IAAG;QACHF,MAAK;QACLG,eAAc;kBAEbX,aAAaY,GAAG,CAAC,CAACC,MAAMC,kBACvB,KAAClB;0BAA0CiB;eAA5B,CAAC,mBAAmB,EAAEC,GAAG;;AAIhD,EAAC"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
@import '~@payloadcms/ui/scss';
|
|
2
|
+
|
|
3
|
+
@layer payload-default {
|
|
4
|
+
.settings-menu-button {
|
|
5
|
+
&__button {
|
|
6
|
+
display: flex;
|
|
7
|
+
align-items: center;
|
|
8
|
+
justify-content: center;
|
|
9
|
+
width: 36px;
|
|
10
|
+
height: 36px;
|
|
11
|
+
border: none;
|
|
12
|
+
border-radius: base(0.25);
|
|
13
|
+
background: transparent;
|
|
14
|
+
color: var(--theme-elevation-500);
|
|
15
|
+
cursor: pointer;
|
|
16
|
+
transition: all 150ms ease;
|
|
17
|
+
|
|
18
|
+
&:hover {
|
|
19
|
+
background: var(--theme-elevation-100);
|
|
20
|
+
color: var(--theme-text);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
}
|
|
25
|
+
}
|
|
@@ -7,6 +7,7 @@ export type SidebarContentProps = {
|
|
|
7
7
|
groups: ExtendedGroup[];
|
|
8
8
|
initialActiveTabId: string;
|
|
9
9
|
navPreferences: NavPreferences | null;
|
|
10
|
+
settingsMenu?: React.ReactNode[];
|
|
10
11
|
sidebarConfig: EnhancedSidebarConfig;
|
|
11
12
|
};
|
|
12
13
|
export declare const SidebarContent: React.FC<SidebarContentProps>;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
3
|
import { useTranslation } from '@payloadcms/ui';
|
|
4
|
-
import React, { useMemo, useState } from 'react';
|
|
4
|
+
import React, { useCallback, useMemo, useState } from 'react';
|
|
5
5
|
import { extractLocalizedValue } from '../../utils';
|
|
6
6
|
import { EnhancedSidebarClient } from './index.client';
|
|
7
7
|
import { SidebarWrapper } from './SidebarWrapper';
|
|
@@ -11,107 +11,117 @@ const COOKIE_KEY = 'payload-enhanced-sidebar-active-tab';
|
|
|
11
11
|
const setTabCookie = (tabId)=>{
|
|
12
12
|
document.cookie = `${COOKIE_KEY}=${tabId}; path=/; max-age=31536000; SameSite=Lax`;
|
|
13
13
|
};
|
|
14
|
-
|
|
14
|
+
/**
|
|
15
|
+
* Computes filtered groups for a specific tab
|
|
16
|
+
*/ const computeGroupsForTab = (tab, groups, currentLang)=>{
|
|
17
|
+
const { collections: tabCollections, customItems, globals: tabGlobals } = tab;
|
|
18
|
+
// If no specific collections/globals defined, show all
|
|
19
|
+
const showAll = !tabCollections && !tabGlobals;
|
|
20
|
+
const allowedSlugs = new Set([
|
|
21
|
+
...tabCollections ?? [],
|
|
22
|
+
...tabGlobals ?? []
|
|
23
|
+
]);
|
|
24
|
+
let result = [];
|
|
25
|
+
if (showAll) {
|
|
26
|
+
result = groups.map((g)=>({
|
|
27
|
+
...g,
|
|
28
|
+
entities: [
|
|
29
|
+
...g.entities
|
|
30
|
+
]
|
|
31
|
+
}));
|
|
32
|
+
} else if (allowedSlugs.size > 0) {
|
|
33
|
+
result = groups.map((group)=>({
|
|
34
|
+
...group,
|
|
35
|
+
entities: group.entities.filter((entity)=>allowedSlugs.has(entity.slug))
|
|
36
|
+
})).filter((group)=>group.entities.length > 0);
|
|
37
|
+
}
|
|
38
|
+
// Merge custom items into groups
|
|
39
|
+
if (customItems && customItems.length > 0) {
|
|
40
|
+
const ungroupedItems = [];
|
|
41
|
+
for (const item of customItems){
|
|
42
|
+
if (item.group) {
|
|
43
|
+
// Get localized group name for comparison
|
|
44
|
+
const itemGroupLabel = extractLocalizedValue(item.group, currentLang);
|
|
45
|
+
// Find existing group by comparing localized labels
|
|
46
|
+
const existingGroup = result.find((g)=>{
|
|
47
|
+
const groupLabel = extractLocalizedValue(g.label, currentLang);
|
|
48
|
+
return groupLabel === itemGroupLabel;
|
|
49
|
+
});
|
|
50
|
+
if (existingGroup) {
|
|
51
|
+
existingGroup.entities.push({
|
|
52
|
+
slug: item.slug,
|
|
53
|
+
type: 'custom',
|
|
54
|
+
href: item.href,
|
|
55
|
+
isExternal: item.isExternal,
|
|
56
|
+
label: item.label
|
|
57
|
+
});
|
|
58
|
+
} else {
|
|
59
|
+
// Create new group
|
|
60
|
+
result.push({
|
|
61
|
+
entities: [
|
|
62
|
+
{
|
|
63
|
+
slug: item.slug,
|
|
64
|
+
type: 'custom',
|
|
65
|
+
href: item.href,
|
|
66
|
+
isExternal: item.isExternal,
|
|
67
|
+
label: item.label
|
|
68
|
+
}
|
|
69
|
+
],
|
|
70
|
+
label: item.group
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
} else {
|
|
74
|
+
ungroupedItems.push(item);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
// Add ungrouped items at the end
|
|
78
|
+
if (ungroupedItems.length > 0) {
|
|
79
|
+
result.push({
|
|
80
|
+
entities: ungroupedItems.map((item)=>({
|
|
81
|
+
slug: item.slug,
|
|
82
|
+
type: 'custom',
|
|
83
|
+
href: item.href,
|
|
84
|
+
isExternal: item.isExternal,
|
|
85
|
+
label: item.label
|
|
86
|
+
})),
|
|
87
|
+
label: ''
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
return result;
|
|
92
|
+
};
|
|
93
|
+
export const SidebarContent = ({ afterNavLinks, beforeNavLinks, groups, initialActiveTabId, navPreferences, settingsMenu, sidebarConfig })=>{
|
|
15
94
|
const { i18n } = useTranslation();
|
|
16
95
|
const currentLang = i18n.language;
|
|
17
|
-
const tabs = sidebarConfig.tabs?.filter((t)=>t.type === 'tab') ?? []
|
|
96
|
+
const tabs = useMemo(()=>sidebarConfig.tabs?.filter((t)=>t.type === 'tab') ?? [], [
|
|
97
|
+
sidebarConfig.tabs
|
|
98
|
+
]);
|
|
18
99
|
const [activeTabId, setActiveTabId] = useState(initialActiveTabId);
|
|
19
|
-
const handleTabChange = (tabId)=>{
|
|
100
|
+
const handleTabChange = useCallback((tabId)=>{
|
|
20
101
|
setActiveTabId(tabId);
|
|
21
102
|
setTabCookie(tabId);
|
|
22
|
-
};
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
}
|
|
29
|
-
const { collections: tabCollections, customItems, globals: tabGlobals } = activeTab;
|
|
30
|
-
// If no specific collections/globals defined, show all
|
|
31
|
-
const showAll = !tabCollections && !tabGlobals;
|
|
32
|
-
const allowedSlugs = new Set([
|
|
33
|
-
...tabCollections ?? [],
|
|
34
|
-
...tabGlobals ?? []
|
|
35
|
-
]);
|
|
36
|
-
let result = [];
|
|
37
|
-
if (showAll) {
|
|
38
|
-
result = groups.map((g)=>({
|
|
39
|
-
...g,
|
|
40
|
-
entities: [
|
|
41
|
-
...g.entities
|
|
42
|
-
]
|
|
43
|
-
}));
|
|
44
|
-
} else if (allowedSlugs.size > 0) {
|
|
45
|
-
result = groups.map((group)=>({
|
|
46
|
-
...group,
|
|
47
|
-
entities: group.entities.filter((entity)=>allowedSlugs.has(entity.slug))
|
|
48
|
-
})).filter((group)=>group.entities.length > 0);
|
|
49
|
-
}
|
|
50
|
-
// Merge custom items into groups
|
|
51
|
-
if (customItems && customItems.length > 0) {
|
|
52
|
-
const ungroupedItems = [];
|
|
53
|
-
for (const item of customItems){
|
|
54
|
-
if (item.group) {
|
|
55
|
-
// Get localized group name for comparison
|
|
56
|
-
const itemGroupLabel = extractLocalizedValue(item.group, currentLang);
|
|
57
|
-
// Find existing group by comparing localized labels
|
|
58
|
-
const existingGroup = result.find((g)=>{
|
|
59
|
-
const groupLabel = extractLocalizedValue(g.label, currentLang);
|
|
60
|
-
return groupLabel === itemGroupLabel;
|
|
61
|
-
});
|
|
62
|
-
if (existingGroup) {
|
|
63
|
-
existingGroup.entities.push({
|
|
64
|
-
slug: item.slug,
|
|
65
|
-
type: 'custom',
|
|
66
|
-
href: item.href,
|
|
67
|
-
isExternal: item.isExternal,
|
|
68
|
-
label: item.label
|
|
69
|
-
});
|
|
70
|
-
} else {
|
|
71
|
-
// Create new group
|
|
72
|
-
result.push({
|
|
73
|
-
entities: [
|
|
74
|
-
{
|
|
75
|
-
slug: item.slug,
|
|
76
|
-
type: 'custom',
|
|
77
|
-
href: item.href,
|
|
78
|
-
isExternal: item.isExternal,
|
|
79
|
-
label: item.label
|
|
80
|
-
}
|
|
81
|
-
],
|
|
82
|
-
label: item.group
|
|
83
|
-
});
|
|
84
|
-
}
|
|
85
|
-
} else {
|
|
86
|
-
ungroupedItems.push(item);
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
// Add ungrouped items at the end
|
|
90
|
-
if (ungroupedItems.length > 0) {
|
|
91
|
-
result.push({
|
|
92
|
-
entities: ungroupedItems.map((item)=>({
|
|
93
|
-
slug: item.slug,
|
|
94
|
-
type: 'custom',
|
|
95
|
-
href: item.href,
|
|
96
|
-
isExternal: item.isExternal,
|
|
97
|
-
label: item.label
|
|
98
|
-
})),
|
|
99
|
-
label: ''
|
|
100
|
-
});
|
|
101
|
-
}
|
|
103
|
+
}, []);
|
|
104
|
+
// Build groups for all tabs at once to keep them mounted
|
|
105
|
+
const groupsPerTab = useMemo(()=>{
|
|
106
|
+
const result = {};
|
|
107
|
+
for (const tab of tabs){
|
|
108
|
+
result[tab.id] = computeGroupsForTab(tab, groups, currentLang);
|
|
102
109
|
}
|
|
103
110
|
return result;
|
|
104
111
|
}, [
|
|
105
|
-
|
|
112
|
+
tabs,
|
|
106
113
|
groups,
|
|
107
114
|
currentLang
|
|
108
115
|
]);
|
|
116
|
+
// Fallback: if no tabs defined, show all groups
|
|
117
|
+
const hasTabs = tabs.length > 0;
|
|
109
118
|
return /*#__PURE__*/ _jsxs(SidebarWrapper, {
|
|
110
119
|
baseClass: baseClass,
|
|
111
120
|
children: [
|
|
112
121
|
/*#__PURE__*/ _jsx(TabsBar, {
|
|
113
122
|
activeTabId: activeTabId,
|
|
114
123
|
onTabChange: handleTabChange,
|
|
124
|
+
settingsMenu: settingsMenu,
|
|
115
125
|
sidebarConfig: sidebarConfig
|
|
116
126
|
}),
|
|
117
127
|
/*#__PURE__*/ _jsx("nav", {
|
|
@@ -120,8 +130,24 @@ export const SidebarContent = ({ afterNavLinks, beforeNavLinks, groups, initialA
|
|
|
120
130
|
className: `${baseClass}__content-scroll`,
|
|
121
131
|
children: [
|
|
122
132
|
beforeNavLinks,
|
|
133
|
+
hasTabs ? // Render all tabs but hide inactive ones to preserve NavGroup state
|
|
134
|
+
tabs.map((tab)=>{
|
|
135
|
+
const isActive = activeTabId === tab.id;
|
|
136
|
+
return /*#__PURE__*/ _jsx("div", {
|
|
137
|
+
"aria-hidden": !isActive,
|
|
138
|
+
style: {
|
|
139
|
+
display: isActive ? undefined : 'none'
|
|
140
|
+
},
|
|
141
|
+
children: /*#__PURE__*/ _jsx(EnhancedSidebarClient, {
|
|
142
|
+
badges: sidebarConfig.badges,
|
|
143
|
+
groups: groupsPerTab[tab.id] ?? [],
|
|
144
|
+
navPreferences: navPreferences
|
|
145
|
+
})
|
|
146
|
+
}, tab.id);
|
|
147
|
+
}) : // No tabs defined - show all groups
|
|
123
148
|
/*#__PURE__*/ _jsx(EnhancedSidebarClient, {
|
|
124
|
-
|
|
149
|
+
badges: sidebarConfig.badges,
|
|
150
|
+
groups: groups,
|
|
125
151
|
navPreferences: navPreferences
|
|
126
152
|
}),
|
|
127
153
|
afterNavLinks
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/components/EnhancedSidebar/SidebarContent.tsx"],"sourcesContent":["'use client'\nimport type { NavPreferences } from 'payload'\n\nimport { useTranslation } from '@payloadcms/ui'\nimport React, { useMemo, useState } from 'react'\n\nimport type {\n EnhancedSidebarConfig,\n ExtendedEntity,\n ExtendedGroup,\n SidebarTabContent as SidebarTabContentType,\n SidebarTabItem,\n} from '../../types'\n\nimport { extractLocalizedValue } from '../../utils'\nimport { EnhancedSidebarClient } from './index.client'\nimport { SidebarWrapper } from './SidebarWrapper'\nimport { TabsBar } from './TabsBar'\n\nconst baseClass = 'enhanced-sidebar'\n\nexport type SidebarContentProps = {\n afterNavLinks?: React.ReactNode\n beforeNavLinks?: React.ReactNode\n groups: ExtendedGroup[]\n initialActiveTabId: string\n navPreferences: NavPreferences | null\n sidebarConfig: EnhancedSidebarConfig\n}\n\nconst COOKIE_KEY = 'payload-enhanced-sidebar-active-tab'\n\nconst setTabCookie = (tabId: string) => {\n document.cookie = `${COOKIE_KEY}=${tabId}; path=/; max-age=31536000; SameSite=Lax`\n}\n\nexport const SidebarContent: React.FC<SidebarContentProps> = ({\n afterNavLinks,\n beforeNavLinks,\n groups,\n initialActiveTabId,\n navPreferences,\n sidebarConfig,\n}) => {\n const { i18n } = useTranslation()\n const currentLang = i18n.language\n\n const tabs = sidebarConfig.tabs?.filter((t): t is SidebarTabContentType => t.type === 'tab') ?? []\n\n const [activeTabId, setActiveTabId] = useState(initialActiveTabId)\n\n const handleTabChange = (tabId: string) => {\n setActiveTabId(tabId)\n setTabCookie(tabId)\n }\n\n const activeTab = tabs.find((tab) => tab.id === activeTabId)\n\n // Build groups for the active tab\n const filteredGroups = useMemo(() => {\n if (!activeTab) {\n return groups\n }\n\n const { collections: tabCollections, customItems, globals: tabGlobals } = activeTab\n\n // If no specific collections/globals defined, show all\n const showAll = !tabCollections && !tabGlobals\n const allowedSlugs = new Set([...(tabCollections ?? []), ...(tabGlobals ?? [])])\n\n let result: ExtendedGroup[] = []\n\n if (showAll) {\n result = groups.map((g) => ({ ...g, entities: [...g.entities] }))\n } else if (allowedSlugs.size > 0) {\n result = groups\n .map((group) => ({\n ...group,\n entities: group.entities.filter((entity) => allowedSlugs.has(entity.slug)),\n }))\n .filter((group) => group.entities.length > 0)\n }\n\n // Merge custom items into groups\n if (customItems && customItems.length > 0) {\n const ungroupedItems: SidebarTabItem[] = []\n\n for (const item of customItems) {\n if (item.group) {\n // Get localized group name for comparison\n const itemGroupLabel = extractLocalizedValue(item.group, currentLang)\n\n // Find existing group by comparing localized labels\n const existingGroup = result.find((g) => {\n const groupLabel = extractLocalizedValue(g.label, currentLang)\n return groupLabel === itemGroupLabel\n })\n\n if (existingGroup) {\n existingGroup.entities.push({\n slug: item.slug,\n type: 'custom',\n href: item.href,\n isExternal: item.isExternal,\n label: item.label,\n } as ExtendedEntity)\n } else {\n // Create new group\n result.push({\n entities: [\n {\n slug: item.slug,\n type: 'custom',\n href: item.href,\n isExternal: item.isExternal,\n label: item.label,\n } as ExtendedEntity,\n ],\n label: item.group,\n })\n }\n } else {\n ungroupedItems.push(item)\n }\n }\n\n // Add ungrouped items at the end\n if (ungroupedItems.length > 0) {\n result.push({\n entities: ungroupedItems.map((item) => ({\n slug: item.slug,\n type: 'custom',\n href: item.href,\n isExternal: item.isExternal,\n label: item.label,\n })) as ExtendedEntity[],\n label: '',\n })\n }\n }\n\n return result\n }, [activeTab, groups, currentLang])\n\n return (\n <SidebarWrapper baseClass={baseClass}>\n <TabsBar\n activeTabId={activeTabId}\n onTabChange={handleTabChange}\n sidebarConfig={sidebarConfig}\n />\n <nav className={`${baseClass}__content`}>\n <div className={`${baseClass}__content-scroll`}>\n {beforeNavLinks}\n <EnhancedSidebarClient groups={filteredGroups} navPreferences={navPreferences} />\n {afterNavLinks}\n </div>\n </nav>\n </SidebarWrapper>\n )\n}\n"],"names":["useTranslation","React","useMemo","useState","extractLocalizedValue","EnhancedSidebarClient","SidebarWrapper","TabsBar","baseClass","COOKIE_KEY","setTabCookie","tabId","document","cookie","SidebarContent","afterNavLinks","beforeNavLinks","groups","initialActiveTabId","navPreferences","sidebarConfig","i18n","currentLang","language","tabs","filter","t","type","activeTabId","setActiveTabId","handleTabChange","activeTab","find","tab","id","filteredGroups","collections","tabCollections","customItems","globals","tabGlobals","showAll","allowedSlugs","Set","result","map","g","entities","size","group","entity","has","slug","length","ungroupedItems","item","itemGroupLabel","existingGroup","groupLabel","label","push","href","isExternal","onTabChange","nav","className","div"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../../src/components/EnhancedSidebar/SidebarContent.tsx"],"sourcesContent":["'use client'\nimport type { NavPreferences } from 'payload'\n\nimport { useTranslation } from '@payloadcms/ui'\nimport React, { useCallback, useMemo, useState } from 'react'\n\nimport type {\n EnhancedSidebarConfig,\n ExtendedEntity,\n ExtendedGroup,\n SidebarTabContent as SidebarTabContentType,\n SidebarTabItem,\n} from '../../types'\n\nimport { extractLocalizedValue } from '../../utils'\nimport { EnhancedSidebarClient } from './index.client'\nimport { SidebarWrapper } from './SidebarWrapper'\nimport { TabsBar } from './TabsBar'\n\nconst baseClass = 'enhanced-sidebar'\n\nexport type SidebarContentProps = {\n afterNavLinks?: React.ReactNode\n beforeNavLinks?: React.ReactNode\n groups: ExtendedGroup[]\n initialActiveTabId: string\n navPreferences: NavPreferences | null\n settingsMenu?: React.ReactNode[]\n sidebarConfig: EnhancedSidebarConfig\n}\n\nconst COOKIE_KEY = 'payload-enhanced-sidebar-active-tab'\n\nconst setTabCookie = (tabId: string) => {\n document.cookie = `${COOKIE_KEY}=${tabId}; path=/; max-age=31536000; SameSite=Lax`\n}\n\n/**\n * Computes filtered groups for a specific tab\n */\nconst computeGroupsForTab = (\n tab: SidebarTabContentType,\n groups: ExtendedGroup[],\n currentLang: string,\n): ExtendedGroup[] => {\n const { collections: tabCollections, customItems, globals: tabGlobals } = tab\n\n // If no specific collections/globals defined, show all\n const showAll = !tabCollections && !tabGlobals\n const allowedSlugs = new Set([...(tabCollections ?? []), ...(tabGlobals ?? [])])\n\n let result: ExtendedGroup[] = []\n\n if (showAll) {\n result = groups.map((g) => ({ ...g, entities: [...g.entities] }))\n } else if (allowedSlugs.size > 0) {\n result = groups\n .map((group) => ({\n ...group,\n entities: group.entities.filter((entity) => allowedSlugs.has(entity.slug)),\n }))\n .filter((group) => group.entities.length > 0)\n }\n\n // Merge custom items into groups\n if (customItems && customItems.length > 0) {\n const ungroupedItems: SidebarTabItem[] = []\n\n for (const item of customItems) {\n if (item.group) {\n // Get localized group name for comparison\n const itemGroupLabel = extractLocalizedValue(item.group, currentLang)\n\n // Find existing group by comparing localized labels\n const existingGroup = result.find((g) => {\n const groupLabel = extractLocalizedValue(g.label, currentLang)\n return groupLabel === itemGroupLabel\n })\n\n if (existingGroup) {\n existingGroup.entities.push({\n slug: item.slug,\n type: 'custom',\n href: item.href,\n isExternal: item.isExternal,\n label: item.label,\n } as ExtendedEntity)\n } else {\n // Create new group\n result.push({\n entities: [\n {\n slug: item.slug,\n type: 'custom',\n href: item.href,\n isExternal: item.isExternal,\n label: item.label,\n } as ExtendedEntity,\n ],\n label: item.group,\n })\n }\n } else {\n ungroupedItems.push(item)\n }\n }\n\n // Add ungrouped items at the end\n if (ungroupedItems.length > 0) {\n result.push({\n entities: ungroupedItems.map((item) => ({\n slug: item.slug,\n type: 'custom',\n href: item.href,\n isExternal: item.isExternal,\n label: item.label,\n })) as ExtendedEntity[],\n label: '',\n })\n }\n }\n\n return result\n}\n\nexport const SidebarContent: React.FC<SidebarContentProps> = ({\n afterNavLinks,\n beforeNavLinks,\n groups,\n initialActiveTabId,\n navPreferences,\n settingsMenu,\n sidebarConfig,\n}) => {\n const { i18n } = useTranslation()\n const currentLang = i18n.language\n\n const tabs = useMemo(\n () => sidebarConfig.tabs?.filter((t): t is SidebarTabContentType => t.type === 'tab') ?? [],\n [sidebarConfig.tabs],\n )\n\n const [activeTabId, setActiveTabId] = useState(initialActiveTabId)\n\n const handleTabChange = useCallback((tabId: string) => {\n setActiveTabId(tabId)\n setTabCookie(tabId)\n }, [])\n\n // Build groups for all tabs at once to keep them mounted\n const groupsPerTab = useMemo(() => {\n const result: Record<string, ExtendedGroup[]> = {}\n for (const tab of tabs) {\n result[tab.id] = computeGroupsForTab(tab, groups, currentLang)\n }\n return result\n }, [tabs, groups, currentLang])\n\n // Fallback: if no tabs defined, show all groups\n const hasTabs = tabs.length > 0\n\n return (\n <SidebarWrapper baseClass={baseClass}>\n <TabsBar\n activeTabId={activeTabId}\n onTabChange={handleTabChange}\n settingsMenu={settingsMenu}\n sidebarConfig={sidebarConfig}\n />\n <nav className={`${baseClass}__content`}>\n <div className={`${baseClass}__content-scroll`}>\n {beforeNavLinks}\n {hasTabs ? (\n // Render all tabs but hide inactive ones to preserve NavGroup state\n tabs.map((tab) => {\n const isActive = activeTabId === tab.id\n return (\n <div\n aria-hidden={!isActive}\n key={tab.id}\n style={{ display: isActive ? undefined : 'none' }}\n >\n <EnhancedSidebarClient\n badges={sidebarConfig.badges}\n groups={groupsPerTab[tab.id] ?? []}\n navPreferences={navPreferences}\n />\n </div>\n )\n })\n ) : (\n // No tabs defined - show all groups\n <EnhancedSidebarClient\n badges={sidebarConfig.badges}\n groups={groups}\n navPreferences={navPreferences}\n />\n )}\n {afterNavLinks}\n </div>\n </nav>\n </SidebarWrapper>\n )\n}\n"],"names":["useTranslation","React","useCallback","useMemo","useState","extractLocalizedValue","EnhancedSidebarClient","SidebarWrapper","TabsBar","baseClass","COOKIE_KEY","setTabCookie","tabId","document","cookie","computeGroupsForTab","tab","groups","currentLang","collections","tabCollections","customItems","globals","tabGlobals","showAll","allowedSlugs","Set","result","map","g","entities","size","group","filter","entity","has","slug","length","ungroupedItems","item","itemGroupLabel","existingGroup","find","groupLabel","label","push","type","href","isExternal","SidebarContent","afterNavLinks","beforeNavLinks","initialActiveTabId","navPreferences","settingsMenu","sidebarConfig","i18n","language","tabs","t","activeTabId","setActiveTabId","handleTabChange","groupsPerTab","id","hasTabs","onTabChange","nav","className","div","isActive","aria-hidden","style","display","undefined","badges"],"mappings":"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"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import type { SidebarTabContent, SidebarTabLink } from '../../../types';
|
|
3
|
+
type TabButtonProps = {
|
|
4
|
+
isActive: boolean;
|
|
5
|
+
onTabChange: (tabId: string) => void;
|
|
6
|
+
tab: SidebarTabContent;
|
|
7
|
+
};
|
|
8
|
+
export declare const TabButton: React.FC<TabButtonProps>;
|
|
9
|
+
type TabLinkProps = {
|
|
10
|
+
href: string;
|
|
11
|
+
isActive: boolean;
|
|
12
|
+
link: SidebarTabLink;
|
|
13
|
+
};
|
|
14
|
+
export declare const TabLink: React.FC<TabLinkProps>;
|
|
15
|
+
export {};
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { getTranslation } from '@payloadcms/translations';
|
|
4
|
+
import { Link, useTranslation } from '@payloadcms/ui';
|
|
5
|
+
import React from 'react';
|
|
6
|
+
import { Badge } from '../Badge';
|
|
7
|
+
import { useBadge } from '../hooks/useBadge';
|
|
8
|
+
import { Icon } from '../Icon';
|
|
9
|
+
const tabsBaseClass = 'tabs-bar';
|
|
10
|
+
export const TabButton = ({ isActive, onTabChange, tab })=>{
|
|
11
|
+
const { i18n } = useTranslation();
|
|
12
|
+
const label = getTranslation(tab.label, i18n);
|
|
13
|
+
const { value } = useBadge(tab.badge, tab.id);
|
|
14
|
+
return /*#__PURE__*/ _jsxs("button", {
|
|
15
|
+
className: `${tabsBaseClass}__tab ${isActive ? `${tabsBaseClass}__tab--active` : ''}`,
|
|
16
|
+
onClick: ()=>onTabChange(tab.id),
|
|
17
|
+
title: label,
|
|
18
|
+
type: "button",
|
|
19
|
+
children: [
|
|
20
|
+
/*#__PURE__*/ _jsx(Icon, {
|
|
21
|
+
name: tab.icon,
|
|
22
|
+
size: 20
|
|
23
|
+
}),
|
|
24
|
+
value !== undefined && /*#__PURE__*/ _jsx(Badge, {
|
|
25
|
+
color: tab.badge?.color,
|
|
26
|
+
position: "absolute",
|
|
27
|
+
value: value
|
|
28
|
+
})
|
|
29
|
+
]
|
|
30
|
+
});
|
|
31
|
+
};
|
|
32
|
+
export const TabLink = ({ href, isActive, link })=>{
|
|
33
|
+
const { i18n } = useTranslation();
|
|
34
|
+
const label = getTranslation(link.label, i18n);
|
|
35
|
+
const { value } = useBadge(link.badge, link.id);
|
|
36
|
+
return /*#__PURE__*/ _jsxs(Link, {
|
|
37
|
+
className: `${tabsBaseClass}__link ${isActive ? `${tabsBaseClass}__link--active` : ''}`,
|
|
38
|
+
href: href,
|
|
39
|
+
rel: link.isExternal ? 'noopener noreferrer' : undefined,
|
|
40
|
+
target: link.isExternal ? '_blank' : undefined,
|
|
41
|
+
title: label,
|
|
42
|
+
children: [
|
|
43
|
+
/*#__PURE__*/ _jsx(Icon, {
|
|
44
|
+
name: link.icon,
|
|
45
|
+
size: 20
|
|
46
|
+
}),
|
|
47
|
+
value !== undefined && /*#__PURE__*/ _jsx(Badge, {
|
|
48
|
+
color: link.badge?.color,
|
|
49
|
+
position: "absolute",
|
|
50
|
+
value: value
|
|
51
|
+
})
|
|
52
|
+
]
|
|
53
|
+
});
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
//# sourceMappingURL=TabItem.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../src/components/EnhancedSidebar/TabsBar/TabItem.tsx"],"sourcesContent":["'use client'\n\nimport { getTranslation } from '@payloadcms/translations'\nimport { Link, useTranslation } from '@payloadcms/ui'\nimport React from 'react'\n\nimport type { SidebarTabContent, SidebarTabLink } from '../../../types'\n\nimport { Badge } from '../Badge'\nimport { useBadge } from '../hooks/useBadge'\nimport { Icon } from '../Icon'\n\nconst tabsBaseClass = 'tabs-bar'\n\ntype TabButtonProps = {\n isActive: boolean\n onTabChange: (tabId: string) => void\n tab: SidebarTabContent\n}\n\nexport const TabButton: React.FC<TabButtonProps> = ({ isActive, onTabChange, tab }) => {\n const { i18n } = useTranslation()\n const label = getTranslation(tab.label, i18n)\n const { value } = useBadge(tab.badge, tab.id)\n\n return (\n <button\n className={`${tabsBaseClass}__tab ${isActive ? `${tabsBaseClass}__tab--active` : ''}`}\n onClick={() => onTabChange(tab.id)}\n title={label}\n type=\"button\"\n >\n <Icon name={tab.icon} size={20} />\n {value !== undefined && <Badge color={tab.badge?.color} position=\"absolute\" value={value} />}\n </button>\n )\n}\n\ntype TabLinkProps = {\n href: string\n isActive: boolean\n link: SidebarTabLink\n}\n\nexport const TabLink: React.FC<TabLinkProps> = ({ href, isActive, link }) => {\n const { i18n } = useTranslation()\n const label = getTranslation(link.label, i18n)\n const { value } = useBadge(link.badge, link.id)\n\n return (\n <Link\n className={`${tabsBaseClass}__link ${isActive ? `${tabsBaseClass}__link--active` : ''}`}\n href={href}\n rel={link.isExternal ? 'noopener noreferrer' : undefined}\n target={link.isExternal ? '_blank' : undefined}\n title={label}\n >\n <Icon name={link.icon} size={20} />\n {value !== undefined && <Badge color={link.badge?.color} position=\"absolute\" value={value} />}\n </Link>\n )\n}\n"],"names":["getTranslation","Link","useTranslation","React","Badge","useBadge","Icon","tabsBaseClass","TabButton","isActive","onTabChange","tab","i18n","label","value","badge","id","button","className","onClick","title","type","name","icon","size","undefined","color","position","TabLink","href","link","rel","isExternal","target"],"mappings":"AAAA;;AAEA,SAASA,cAAc,QAAQ,2BAA0B;AACzD,SAASC,IAAI,EAAEC,cAAc,QAAQ,iBAAgB;AACrD,OAAOC,WAAW,QAAO;AAIzB,SAASC,KAAK,QAAQ,WAAU;AAChC,SAASC,QAAQ,QAAQ,oBAAmB;AAC5C,SAASC,IAAI,QAAQ,UAAS;AAE9B,MAAMC,gBAAgB;AAQtB,OAAO,MAAMC,YAAsC,CAAC,EAAEC,QAAQ,EAAEC,WAAW,EAAEC,GAAG,EAAE;IAChF,MAAM,EAAEC,IAAI,EAAE,GAAGV;IACjB,MAAMW,QAAQb,eAAeW,IAAIE,KAAK,EAAED;IACxC,MAAM,EAAEE,KAAK,EAAE,GAAGT,SAASM,IAAII,KAAK,EAAEJ,IAAIK,EAAE;IAE5C,qBACE,MAACC;QACCC,WAAW,GAAGX,cAAc,MAAM,EAAEE,WAAW,GAAGF,cAAc,aAAa,CAAC,GAAG,IAAI;QACrFY,SAAS,IAAMT,YAAYC,IAAIK,EAAE;QACjCI,OAAOP;QACPQ,MAAK;;0BAEL,KAACf;gBAAKgB,MAAMX,IAAIY,IAAI;gBAAEC,MAAM;;YAC3BV,UAAUW,2BAAa,KAACrB;gBAAMsB,OAAOf,IAAII,KAAK,EAAEW;gBAAOC,UAAS;gBAAWb,OAAOA;;;;AAGzF,EAAC;AAQD,OAAO,MAAMc,UAAkC,CAAC,EAAEC,IAAI,EAAEpB,QAAQ,EAAEqB,IAAI,EAAE;IACtE,MAAM,EAAElB,IAAI,EAAE,GAAGV;IACjB,MAAMW,QAAQb,eAAe8B,KAAKjB,KAAK,EAAED;IACzC,MAAM,EAAEE,KAAK,EAAE,GAAGT,SAASyB,KAAKf,KAAK,EAAEe,KAAKd,EAAE;IAE9C,qBACE,MAACf;QACCiB,WAAW,GAAGX,cAAc,OAAO,EAAEE,WAAW,GAAGF,cAAc,cAAc,CAAC,GAAG,IAAI;QACvFsB,MAAMA;QACNE,KAAKD,KAAKE,UAAU,GAAG,wBAAwBP;QAC/CQ,QAAQH,KAAKE,UAAU,GAAG,WAAWP;QACrCL,OAAOP;;0BAEP,KAACP;gBAAKgB,MAAMQ,KAAKP,IAAI;gBAAEC,MAAM;;YAC5BV,UAAUW,2BAAa,KAACrB;gBAAMsB,OAAOI,KAAKf,KAAK,EAAEW;gBAAOC,UAAS;gBAAWb,OAAOA;;;;AAG1F,EAAC"}
|
|
@@ -6,51 +6,40 @@ import { usePathname } from 'next/navigation';
|
|
|
6
6
|
import { formatAdminURL } from 'payload/shared';
|
|
7
7
|
import React from 'react';
|
|
8
8
|
import { Icon } from '../Icon';
|
|
9
|
+
import { SettingsMenuButton } from '../SettingsMenuButton';
|
|
10
|
+
import { TabButton, TabLink } from './TabItem';
|
|
9
11
|
import './index.scss';
|
|
10
12
|
const tabsBaseClass = 'tabs-bar';
|
|
11
|
-
export const TabsBar = ({ activeTabId, onTabChange, sidebarConfig })=>{
|
|
13
|
+
export const TabsBar = ({ activeTabId, onTabChange, settingsMenu, sidebarConfig })=>{
|
|
12
14
|
const { i18n } = useTranslation();
|
|
13
15
|
const pathname = usePathname();
|
|
14
|
-
const { config: { admin: { routes: { logout: logoutRoute } }, routes: { admin: adminRoute } } } = useConfig();
|
|
16
|
+
const { config: { admin: { routes: { browseByFolder: foldersRoute, logout: logoutRoute } }, folders, routes: { admin: adminRoute } } } = useConfig();
|
|
15
17
|
const showLogout = sidebarConfig.showLogout !== false;
|
|
16
|
-
const
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
title: label,
|
|
23
|
-
type: "button",
|
|
24
|
-
children: /*#__PURE__*/ _jsx(Icon, {
|
|
25
|
-
name: tab.icon,
|
|
26
|
-
size: 20
|
|
27
|
-
})
|
|
28
|
-
}, tab.id);
|
|
29
|
-
};
|
|
30
|
-
const renderLink = (link)=>{
|
|
31
|
-
const label = getTranslation(link.label, i18n);
|
|
32
|
-
const href = link.isExternal ? link.href : formatAdminURL({
|
|
33
|
-
adminRoute,
|
|
34
|
-
path: link.href
|
|
35
|
-
});
|
|
36
|
-
// Check if this link is active
|
|
37
|
-
const isActive = pathname === href || link.href === '/' && pathname === adminRoute;
|
|
38
|
-
return /*#__PURE__*/ _jsx(Link, {
|
|
39
|
-
className: `${tabsBaseClass}__link ${isActive ? `${tabsBaseClass}__link--active` : ''}`,
|
|
40
|
-
href: href,
|
|
41
|
-
target: link.isExternal ? '_blank' : undefined,
|
|
42
|
-
title: label,
|
|
43
|
-
children: /*#__PURE__*/ _jsx(Icon, {
|
|
44
|
-
name: link.icon,
|
|
45
|
-
size: 20
|
|
46
|
-
})
|
|
47
|
-
}, link.id);
|
|
48
|
-
};
|
|
18
|
+
const showFolders = folders && folders.browseByFolder;
|
|
19
|
+
const folderURL = formatAdminURL({
|
|
20
|
+
adminRoute,
|
|
21
|
+
path: foldersRoute
|
|
22
|
+
});
|
|
23
|
+
const isFoldersActive = pathname.startsWith(folderURL);
|
|
49
24
|
const renderTabItem = (item)=>{
|
|
50
25
|
if (item.type === 'tab') {
|
|
51
|
-
return
|
|
26
|
+
return /*#__PURE__*/ _jsx(TabButton, {
|
|
27
|
+
isActive: activeTabId === item.id,
|
|
28
|
+
onTabChange: onTabChange,
|
|
29
|
+
tab: item
|
|
30
|
+
}, item.id);
|
|
52
31
|
}
|
|
53
|
-
|
|
32
|
+
// Check if link is active
|
|
33
|
+
const href = item.isExternal ? item.href : formatAdminURL({
|
|
34
|
+
adminRoute,
|
|
35
|
+
path: item.href
|
|
36
|
+
});
|
|
37
|
+
const isActive = pathname === href || item.href === '/' && pathname === adminRoute;
|
|
38
|
+
return /*#__PURE__*/ _jsx(TabLink, {
|
|
39
|
+
href: href,
|
|
40
|
+
isActive: isActive,
|
|
41
|
+
link: item
|
|
42
|
+
}, item.id);
|
|
54
43
|
};
|
|
55
44
|
const tabItems = sidebarConfig.tabs ?? [];
|
|
56
45
|
return /*#__PURE__*/ _jsxs("div", {
|
|
@@ -60,24 +49,41 @@ export const TabsBar = ({ activeTabId, onTabChange, sidebarConfig })=>{
|
|
|
60
49
|
className: `${tabsBaseClass}__tabs`,
|
|
61
50
|
children: tabItems.map(renderTabItem)
|
|
62
51
|
}),
|
|
63
|
-
|
|
52
|
+
/*#__PURE__*/ _jsxs("div", {
|
|
64
53
|
className: `${tabsBaseClass}__actions`,
|
|
65
|
-
children:
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
54
|
+
children: [
|
|
55
|
+
showFolders && /*#__PURE__*/ _jsx(Link, {
|
|
56
|
+
className: `${tabsBaseClass}__action ${isFoldersActive ? `${tabsBaseClass}__link--active` : ''}`,
|
|
57
|
+
href: folderURL,
|
|
58
|
+
title: getTranslation({
|
|
59
|
+
en: 'Browse by Folder',
|
|
60
|
+
uk: 'Переглянути по папках'
|
|
61
|
+
}, i18n),
|
|
62
|
+
children: /*#__PURE__*/ _jsx(Icon, {
|
|
63
|
+
name: "Folder",
|
|
64
|
+
size: 20
|
|
65
|
+
})
|
|
66
|
+
}),
|
|
67
|
+
/*#__PURE__*/ _jsx(SettingsMenuButton, {
|
|
68
|
+
settingsMenu: settingsMenu
|
|
70
69
|
}),
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
70
|
+
showLogout && /*#__PURE__*/ _jsx(Link, {
|
|
71
|
+
className: `${tabsBaseClass}__action`,
|
|
72
|
+
href: formatAdminURL({
|
|
73
|
+
adminRoute,
|
|
74
|
+
path: logoutRoute
|
|
75
|
+
}),
|
|
76
|
+
title: getTranslation({
|
|
77
|
+
en: 'Logout',
|
|
78
|
+
uk: 'Вийти'
|
|
79
|
+
}, i18n),
|
|
80
|
+
type: "button",
|
|
81
|
+
children: /*#__PURE__*/ _jsx(Icon, {
|
|
82
|
+
name: "LogOut",
|
|
83
|
+
size: 20
|
|
84
|
+
})
|
|
79
85
|
})
|
|
80
|
-
|
|
86
|
+
]
|
|
81
87
|
})
|
|
82
88
|
]
|
|
83
89
|
});
|