@veiag/payload-enhanced-sidebar 0.2.0 → 0.3.0-beta.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (39) hide show
  1. package/README.md +62 -5
  2. package/dist/components/EnhancedSidebar/NavContent/index.d.ts +3 -0
  3. package/dist/components/EnhancedSidebar/NavContent/index.js +34 -0
  4. package/dist/components/EnhancedSidebar/NavContent/index.js.map +1 -0
  5. package/dist/components/EnhancedSidebar/NavItem/index.d.ts +0 -2
  6. package/dist/components/EnhancedSidebar/NavItem/index.js +3 -1
  7. package/dist/components/EnhancedSidebar/NavItem/index.js.map +1 -1
  8. package/dist/components/EnhancedSidebar/SidebarContent.d.ts +6 -4
  9. package/dist/components/EnhancedSidebar/SidebarContent.js +31 -140
  10. package/dist/components/EnhancedSidebar/SidebarContent.js.map +1 -1
  11. package/dist/components/EnhancedSidebar/TabsBar/TabItem.d.ts +2 -0
  12. package/dist/components/EnhancedSidebar/TabsBar/TabItem.js +4 -4
  13. package/dist/components/EnhancedSidebar/TabsBar/TabItem.js.map +1 -1
  14. package/dist/components/EnhancedSidebar/TabsBar/index.d.ts +2 -0
  15. package/dist/components/EnhancedSidebar/TabsBar/index.js +4 -2
  16. package/dist/components/EnhancedSidebar/TabsBar/index.js.map +1 -1
  17. package/dist/components/EnhancedSidebar/context.d.ts +6 -0
  18. package/dist/components/EnhancedSidebar/context.js +9 -0
  19. package/dist/components/EnhancedSidebar/context.js.map +1 -0
  20. package/dist/components/EnhancedSidebar/hooks/useNavItemState.d.ts +23 -0
  21. package/dist/components/EnhancedSidebar/hooks/useNavItemState.js +32 -0
  22. package/dist/components/EnhancedSidebar/hooks/useNavItemState.js.map +1 -0
  23. package/dist/components/EnhancedSidebar/hooks/useTabState.d.ts +13 -0
  24. package/dist/components/EnhancedSidebar/hooks/useTabState.js +19 -0
  25. package/dist/components/EnhancedSidebar/hooks/useTabState.js.map +1 -0
  26. package/dist/components/EnhancedSidebar/index.js +286 -9
  27. package/dist/components/EnhancedSidebar/index.js.map +1 -1
  28. package/dist/index.d.ts +4 -1
  29. package/dist/index.js +33 -1
  30. package/dist/index.js.map +1 -1
  31. package/dist/types.d.ts +243 -14
  32. package/dist/types.js.map +1 -1
  33. package/dist/utils/index.d.ts +8 -1
  34. package/dist/utils/index.js +14 -0
  35. package/dist/utils/index.js.map +1 -1
  36. package/package.json +2 -1
  37. package/dist/components/EnhancedSidebar/index.client.d.ts +0 -8
  38. package/dist/components/EnhancedSidebar/index.client.js +0 -87
  39. package/dist/components/EnhancedSidebar/index.client.js.map +0 -1
package/README.md CHANGED
@@ -11,8 +11,9 @@ An enhanced sidebar plugin for [Payload CMS](https://payloadcms.com) that adds a
11
11
  - **Link Support** - Add navigation links (like Dashboard) alongside tabs
12
12
  - **Custom Items** - Add custom navigation items that can be merged into existing groups
13
13
  - **Badges** - Show notification badges on tabs and navigation items (API-based or reactive provider)
14
+ - **Custom Components** - Replace any part of the sidebar with your own React components
14
15
  - **i18n Support** - Full localization support for labels and groups
15
- - **Lucide Icons** - Use any [Lucide icon](https://lucide.dev/icons) for tabs and links
16
+ - **Lucide Icons** - Use any [Lucide icon](https://lucide.dev/icons) for tabs and links, or provide a custom icon component per tab
16
17
 
17
18
  ![Showcase](docs/showcase.gif)
18
19
 
@@ -101,6 +102,12 @@ export default buildConfig({
101
102
  label: { en: 'Analytics', uk: 'Аналітика' },
102
103
  group: 'E-commerce', // Merge into existing group
103
104
  },
105
+ {
106
+ slug: 'quick-add',
107
+ href: '/quick-add',
108
+ label: { en: 'Quick Add', uk: 'Швидке додавання' },
109
+ position: 'top', // Appears above all collection groups
110
+ },
104
111
  ],
105
112
  },
106
113
  // Settings tab with globals
@@ -150,13 +157,15 @@ Array of tabs and links to show in the sidebar.
150
157
  |----------|------|----------|-------------|
151
158
  | `id` | `string` | Yes | Unique identifier |
152
159
  | `type` | `'tab'` | Yes | Tab type |
153
- | `icon` | `string` | Yes | Lucide icon name |
160
+ | `icon` | `IconName` | Yes* | Lucide icon name |
161
+ | `iconComponent` | `SidebarComponent` | Yes* | Path to a custom icon component (string or `{ path, clientProps }`) |
154
162
  | `label` | `LocalizedString` | Yes | Tab tooltip/label |
155
163
  | `collections` | `CollectionSlug[]` | No | Collections to show in this tab |
156
164
  | `globals` | `GlobalSlug[]` | No | Globals to show in this tab |
157
- | `customItems` | `SidebarTabItem[]` | No | Custom navigation items |
165
+ | `customItems` | `SidebarTabItem[]` | No | Custom navigation items (see below) |
158
166
  | `badge` | `BadgeConfig` | No | Badge configuration for the tab icon |
159
167
 
168
+ > \* Exactly one of `icon` or `iconComponent` is required — they are mutually exclusive.
160
169
  > If neither `collections` nor `globals` are specified, the tab shows all collections and globals.
161
170
 
162
171
 
@@ -166,12 +175,15 @@ Array of tabs and links to show in the sidebar.
166
175
  |----------|------|----------|-------------|
167
176
  | `id` | `string` | Yes | Unique identifier |
168
177
  | `type` | `'link'` | Yes | Link type |
169
- | `icon` | `string` | Yes | Lucide icon name |
178
+ | `icon` | `IconName` | Yes* | Lucide icon name |
179
+ | `iconComponent` | `SidebarComponent` | Yes* | Path to a custom icon component (string or `{ path, clientProps }`) |
170
180
  | `label` | `LocalizedString` | Yes | Link tooltip/label |
171
181
  | `href` | `string` | Yes | URL |
172
182
  | `isExternal` | `boolean` | No | If true, `href` is absolute URL, if not, `href` is relative to admin route |
173
183
  | `badge` | `BadgeConfig` | No | Badge configuration for the link icon |
174
184
 
185
+ > \* Exactly one of `icon` or `iconComponent` is required — they are mutually exclusive.
186
+
175
187
 
176
188
  ![Tab and Link active difference](docs/tab-link-active.png)
177
189
 
@@ -186,13 +198,19 @@ Custom items can be added to any tab:
186
198
  label: { en: 'Label' }, // Required: display label
187
199
  group: { en: 'Group Name' }, // Optional: merge into existing group or create new
188
200
  isExternal: true, // Optional: if true, href is absolute URL
201
+ position: 'top', // Optional: 'top' | 'bottom' (default: 'bottom')
189
202
  }
190
203
  ```
191
204
 
192
205
  **Group behavior:**
193
206
  - If `group` matches an existing collection group label, the item is added to that group
194
207
  - If `group` doesn't match any existing group, a new group is created
195
- - If `group` is not specified, the item appears at the bottom as ungrouped
208
+ - If `group` is not specified, the item appears as ungrouped
209
+
210
+ **Position behavior:**
211
+ - `position: 'top'` — item (or new custom group) appears **above** all collection/global groups
212
+ - `position: 'bottom'` — appears below all groups (default)
213
+ - Has no effect on items that merge into an existing collection group via `group`
196
214
 
197
215
 
198
216
  ## Badges
@@ -376,6 +394,45 @@ Completely disable the plugin.
376
394
  - **Type:** `boolean`
377
395
  - **Default:** `false`
378
396
 
397
+ ## Custom Components
398
+
399
+ You can replace any part of the sidebar with your own React components. The plugin registers them automatically in Payload's import map — no manual import map configuration needed.
400
+
401
+ ```typescript
402
+ payloadEnhancedSidebar({
403
+ customComponents: {
404
+ // Replace individual nav items (collections, globals, custom links)
405
+ NavItem: './components/Sidebar#MyNavItem',
406
+ // Replace group headers
407
+ NavGroup: './components/Sidebar#MyNavGroup',
408
+ // Replace the entire nav scroll area
409
+ NavContent: './components/Sidebar#MyNavContent',
410
+ // Replace every button in the tabs bar (tabs and links)
411
+ TabButton: './components/Sidebar#MyTabButton',
412
+ },
413
+ tabs: [
414
+ {
415
+ id: 'dashboard',
416
+ type: 'link',
417
+ href: '/',
418
+ // Custom icon for just this tab/link (mutually exclusive with `icon`)
419
+ iconComponent: './components/Sidebar#DashboardIcon',
420
+ label: 'Dashboard',
421
+ },
422
+ ],
423
+ })
424
+ ```
425
+
426
+ All custom components are client components (`'use client'`). The plugin provides hooks to connect them to sidebar state:
427
+
428
+ | Hook | Description |
429
+ |------|-------------|
430
+ | `useNavItemState(href)` | `{ isActive, isCurrentPage }` — for custom NavItem |
431
+ | `useTabState(id)` | `{ isActive }` — for custom NavContent or TabButton |
432
+ | `useEnhancedSidebar()` | `{ activeTabId, onTabChange }` — full tab context |
433
+
434
+ **→ See [docs/custom-components.md](docs/custom-components.md) for full documentation, prop types, and examples for each slot.**
435
+
379
436
  ## Localization
380
437
 
381
438
  All labels support localized strings:
@@ -0,0 +1,3 @@
1
+ import React from 'react';
2
+ import type { CustomNavContentProps } from '../../../types';
3
+ export declare const NavContent: React.FC<CustomNavContentProps>;
@@ -0,0 +1,34 @@
1
+ 'use client';
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import React from 'react';
4
+ import { useTabState } from '../hooks/useTabState';
5
+ const baseClass = 'enhanced-sidebar';
6
+ const TabPanel = ({ children, id })=>{
7
+ const { isActive } = useTabState(id);
8
+ return /*#__PURE__*/ _jsx("div", {
9
+ "aria-hidden": !isActive,
10
+ style: {
11
+ display: isActive ? undefined : 'none'
12
+ },
13
+ children: children
14
+ });
15
+ };
16
+ export const NavContent = ({ afterNavLinks, allContent, beforeNavLinks, tabs, tabsContent })=>{
17
+ const hasTabs = tabs.length > 0;
18
+ return /*#__PURE__*/ _jsx("nav", {
19
+ className: `${baseClass}__content`,
20
+ children: /*#__PURE__*/ _jsxs("div", {
21
+ className: `${baseClass}__content-scroll`,
22
+ children: [
23
+ beforeNavLinks,
24
+ hasTabs ? tabs.map((tab)=>/*#__PURE__*/ _jsx(TabPanel, {
25
+ id: tab.id,
26
+ children: tabsContent[tab.id]
27
+ }, tab.id)) : allContent,
28
+ afterNavLinks
29
+ ]
30
+ })
31
+ });
32
+ };
33
+
34
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../src/components/EnhancedSidebar/NavContent/index.tsx"],"sourcesContent":["'use client'\n\nimport React from 'react'\n\nimport type { CustomNavContentProps } from '../../../types'\n\nimport { useTabState } from '../hooks/useTabState'\n\nconst baseClass = 'enhanced-sidebar'\n\nconst TabPanel: React.FC<{ id: string; children: React.ReactNode }> = ({ children, id }) => {\n const { isActive } = useTabState(id)\n return (\n <div aria-hidden={!isActive} style={{ display: isActive ? undefined : 'none' }}>\n {children}\n </div>\n )\n}\n\nexport const NavContent: React.FC<CustomNavContentProps> = ({\n afterNavLinks,\n allContent,\n beforeNavLinks,\n tabs,\n tabsContent,\n}) => {\n const hasTabs = tabs.length > 0\n\n return (\n <nav className={`${baseClass}__content`}>\n <div className={`${baseClass}__content-scroll`}>\n {beforeNavLinks}\n {hasTabs\n ? tabs.map((tab) => (\n <TabPanel id={tab.id} key={tab.id}>\n {tabsContent[tab.id]}\n </TabPanel>\n ))\n : allContent}\n {afterNavLinks}\n </div>\n </nav>\n )\n}\n"],"names":["React","useTabState","baseClass","TabPanel","children","id","isActive","div","aria-hidden","style","display","undefined","NavContent","afterNavLinks","allContent","beforeNavLinks","tabs","tabsContent","hasTabs","length","nav","className","map","tab"],"mappings":"AAAA;;AAEA,OAAOA,WAAW,QAAO;AAIzB,SAASC,WAAW,QAAQ,uBAAsB;AAElD,MAAMC,YAAY;AAElB,MAAMC,WAAgE,CAAC,EAAEC,QAAQ,EAAEC,EAAE,EAAE;IACrF,MAAM,EAAEC,QAAQ,EAAE,GAAGL,YAAYI;IACjC,qBACE,KAACE;QAAIC,eAAa,CAACF;QAAUG,OAAO;YAAEC,SAASJ,WAAWK,YAAY;QAAO;kBAC1EP;;AAGP;AAEA,OAAO,MAAMQ,aAA8C,CAAC,EAC1DC,aAAa,EACbC,UAAU,EACVC,cAAc,EACdC,IAAI,EACJC,WAAW,EACZ;IACC,MAAMC,UAAUF,KAAKG,MAAM,GAAG;IAE9B,qBACE,KAACC;QAAIC,WAAW,GAAGnB,UAAU,SAAS,CAAC;kBACrC,cAAA,MAACK;YAAIc,WAAW,GAAGnB,UAAU,gBAAgB,CAAC;;gBAC3Ca;gBACAG,UACGF,KAAKM,GAAG,CAAC,CAACC,oBACR,KAACpB;wBAASE,IAAIkB,IAAIlB,EAAE;kCACjBY,WAAW,CAACM,IAAIlB,EAAE,CAAC;uBADKkB,IAAIlB,EAAE,KAInCS;gBACHD;;;;AAIT,EAAC"}
@@ -5,7 +5,5 @@ export type NavItemProps = {
5
5
  entity: ExtendedEntity;
6
6
  href: string;
7
7
  id: string;
8
- isActive: boolean;
9
- isCurrentPage: boolean;
10
8
  };
11
9
  export declare const NavItem: React.FC<NavItemProps>;
@@ -5,10 +5,12 @@ import { Link, useTranslation } from '@payloadcms/ui';
5
5
  import React from 'react';
6
6
  import { Badge } from '../Badge';
7
7
  import { useBadge } from '../hooks/useBadge';
8
+ import { useNavItemState } from '../hooks/useNavItemState';
8
9
  const baseClass = 'enhanced-sidebar';
9
- export const NavItem = ({ id, badgeConfig, entity, href, isActive, isCurrentPage })=>{
10
+ export const NavItem = ({ id, badgeConfig, entity, href })=>{
10
11
  const { i18n } = useTranslation();
11
12
  const { value: badgeValue } = useBadge(badgeConfig, entity.slug);
13
+ const { isActive, isCurrentPage } = useNavItemState(href);
12
14
  const Label = /*#__PURE__*/ _jsxs(_Fragment, {
13
15
  children: [
14
16
  isActive && /*#__PURE__*/ _jsx("div", {
@@ -1 +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"}
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'\nimport { useNavItemState } from '../hooks/useNavItemState'\n\nconst baseClass = 'enhanced-sidebar'\n\nexport type NavItemProps = {\n badgeConfig?: BadgeConfig\n entity: ExtendedEntity\n href: string\n id: string\n}\n\nexport const NavItem: React.FC<NavItemProps> = ({ id, badgeConfig, entity, href }) => {\n const { i18n } = useTranslation()\n const { value: badgeValue } = useBadge(badgeConfig, entity.slug)\n const { isActive, isCurrentPage } = useNavItemState(href)\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","useNavItemState","baseClass","NavItem","id","badgeConfig","entity","href","i18n","value","badgeValue","slug","isActive","isCurrentPage","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;AAC5C,SAASC,eAAe,QAAQ,2BAA0B;AAE1D,MAAMC,YAAY;AASlB,OAAO,MAAMC,UAAkC,CAAC,EAAEC,EAAE,EAAEC,WAAW,EAAEC,MAAM,EAAEC,IAAI,EAAE;IAC/E,MAAM,EAAEC,IAAI,EAAE,GAAGX;IACjB,MAAM,EAAEY,OAAOC,UAAU,EAAE,GAAGV,SAASK,aAAaC,OAAOK,IAAI;IAC/D,MAAM,EAAEC,QAAQ,EAAEC,aAAa,EAAE,GAAGZ,gBAAgBM;IAEpD,MAAMO,sBACJ;;YACGF,0BAAY,KAACG;gBAAIC,WAAW,GAAGd,UAAU,gBAAgB,CAAC;;0BAC3D,KAACe;gBAAKD,WAAW,GAAGd,UAAU,YAAY,CAAC;0BAAGP,eAAeW,OAAOY,KAAK,EAAEV;;YAC1EE,eAAeS,2BACd,KAACpB;gBAAMqB,OAAOf,aAAae;gBAAOC,UAAS;gBAASZ,OAAOC;;;;IAKjE,IAAIG,eAAe;QACjB,qBACE,KAACE;YAAIC,WAAW,GAAGd,UAAU,MAAM,CAAC;YAAEE,IAAIA;sBACvCU;;IAGP;IAEA,qBACE,KAAClB;QACCoB,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"}
@@ -1,13 +1,15 @@
1
- import type { NavPreferences } from 'payload';
2
1
  import React from 'react';
3
- import type { EnhancedSidebarConfig, ExtendedGroup } from '../../types';
2
+ import type { EnhancedSidebarConfig } from '../../types';
4
3
  export type SidebarContentProps = {
5
4
  afterNavLinks?: React.ReactNode;
5
+ allContent?: React.ReactNode;
6
6
  beforeNavLinks?: React.ReactNode;
7
- groups: ExtendedGroup[];
7
+ customNavContent?: React.ReactNode;
8
8
  initialActiveTabId: string;
9
- navPreferences: NavPreferences | null;
9
+ renderedTabItems?: React.ReactNode[];
10
10
  settingsMenu?: React.ReactNode[];
11
11
  sidebarConfig: EnhancedSidebarConfig;
12
+ tabIcons?: Record<string, React.ReactNode>;
13
+ tabsContent: Record<string, React.ReactNode>;
12
14
  };
13
15
  export declare const SidebarContent: React.FC<SidebarContentProps>;
@@ -1,9 +1,8 @@
1
1
  'use client';
2
2
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
- import { useTranslation } from '@payloadcms/ui';
4
3
  import React, { useCallback, useMemo, useState } from 'react';
5
- import { extractLocalizedValue } from '../../utils';
6
- import { EnhancedSidebarClient } from './index.client';
4
+ import { EnhancedSidebarContext } from './context';
5
+ import { NavContent } from './NavContent';
7
6
  import { SidebarWrapper } from './SidebarWrapper';
8
7
  import { TabsBar } from './TabsBar';
9
8
  const baseClass = 'enhanced-sidebar';
@@ -11,150 +10,42 @@ const COOKIE_KEY = 'payload-enhanced-sidebar-active-tab';
11
10
  const setTabCookie = (tabId)=>{
12
11
  document.cookie = `${COOKIE_KEY}=${tabId}; path=/; max-age=31536000; SameSite=Lax`;
13
12
  };
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 })=>{
94
- const { i18n } = useTranslation();
95
- const currentLang = i18n.language;
96
- const tabs = useMemo(()=>sidebarConfig.tabs?.filter((t)=>t.type === 'tab') ?? [], [
97
- sidebarConfig.tabs
98
- ]);
13
+ export const SidebarContent = ({ afterNavLinks, allContent, beforeNavLinks, customNavContent, initialActiveTabId, renderedTabItems, settingsMenu, sidebarConfig, tabIcons, tabsContent })=>{
99
14
  const [activeTabId, setActiveTabId] = useState(initialActiveTabId);
100
15
  const handleTabChange = useCallback((tabId)=>{
101
16
  setActiveTabId(tabId);
102
17
  setTabCookie(tabId);
103
18
  }, []);
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);
109
- }
110
- return result;
111
- }, [
112
- tabs,
113
- groups,
114
- currentLang
19
+ const contextValue = useMemo(()=>({
20
+ activeTabId,
21
+ onTabChange: handleTabChange
22
+ }), [
23
+ activeTabId,
24
+ handleTabChange
115
25
  ]);
116
- // Fallback: if no tabs defined, show all groups
117
- const hasTabs = tabs.length > 0;
118
- return /*#__PURE__*/ _jsxs(SidebarWrapper, {
119
- baseClass: baseClass,
120
- children: [
121
- /*#__PURE__*/ _jsx(TabsBar, {
122
- activeTabId: activeTabId,
123
- onTabChange: handleTabChange,
124
- settingsMenu: settingsMenu,
125
- sidebarConfig: sidebarConfig
126
- }),
127
- /*#__PURE__*/ _jsx("nav", {
128
- className: `${baseClass}__content`,
129
- children: /*#__PURE__*/ _jsxs("div", {
130
- className: `${baseClass}__content-scroll`,
131
- children: [
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
148
- /*#__PURE__*/ _jsx(EnhancedSidebarClient, {
149
- badges: sidebarConfig.badges,
150
- groups: groups,
151
- navPreferences: navPreferences
152
- }),
153
- afterNavLinks
154
- ]
26
+ const tabs = sidebarConfig.tabs?.filter((t)=>t.type === 'tab') ?? [];
27
+ return /*#__PURE__*/ _jsx(EnhancedSidebarContext.Provider, {
28
+ value: contextValue,
29
+ children: /*#__PURE__*/ _jsxs(SidebarWrapper, {
30
+ baseClass: baseClass,
31
+ children: [
32
+ /*#__PURE__*/ _jsx(TabsBar, {
33
+ activeTabId: activeTabId,
34
+ onTabChange: handleTabChange,
35
+ renderedTabItems: renderedTabItems,
36
+ settingsMenu: settingsMenu,
37
+ sidebarConfig: sidebarConfig,
38
+ tabIcons: tabIcons
39
+ }),
40
+ customNavContent ?? /*#__PURE__*/ _jsx(NavContent, {
41
+ afterNavLinks: afterNavLinks,
42
+ allContent: allContent,
43
+ beforeNavLinks: beforeNavLinks,
44
+ tabs: tabs,
45
+ tabsContent: tabsContent
155
46
  })
156
- })
157
- ]
47
+ ]
48
+ })
158
49
  });
159
50
  };
160
51
 
@@ -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, { 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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"}
1
+ {"version":3,"sources":["../../../src/components/EnhancedSidebar/SidebarContent.tsx"],"sourcesContent":["'use client'\n\nimport React, { useCallback, useMemo, useState } from 'react'\n\nimport type { EnhancedSidebarConfig } from '../../types'\n\nimport { EnhancedSidebarContext } from './context'\nimport { NavContent } from './NavContent'\nimport { SidebarWrapper } from './SidebarWrapper'\nimport { TabsBar } from './TabsBar'\n\nconst baseClass = 'enhanced-sidebar'\n\nexport type SidebarContentProps = {\n afterNavLinks?: React.ReactNode\n allContent?: React.ReactNode\n beforeNavLinks?: React.ReactNode\n customNavContent?: React.ReactNode\n initialActiveTabId: string\n renderedTabItems?: React.ReactNode[]\n settingsMenu?: React.ReactNode[]\n sidebarConfig: EnhancedSidebarConfig\n tabIcons?: Record<string, React.ReactNode>\n tabsContent: Record<string, React.ReactNode>\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 allContent,\n beforeNavLinks,\n customNavContent,\n initialActiveTabId,\n renderedTabItems,\n settingsMenu,\n sidebarConfig,\n tabIcons,\n tabsContent,\n}) => {\n const [activeTabId, setActiveTabId] = useState(initialActiveTabId)\n\n const handleTabChange = useCallback((tabId: string) => {\n setActiveTabId(tabId)\n setTabCookie(tabId)\n }, [])\n\n const contextValue = useMemo(\n () => ({ activeTabId, onTabChange: handleTabChange }),\n [activeTabId, handleTabChange],\n )\n\n const tabs = sidebarConfig.tabs?.filter((t) => t.type === 'tab') ?? []\n\n return (\n <EnhancedSidebarContext.Provider value={contextValue}>\n <SidebarWrapper baseClass={baseClass}>\n <TabsBar\n activeTabId={activeTabId}\n onTabChange={handleTabChange}\n renderedTabItems={renderedTabItems}\n settingsMenu={settingsMenu}\n sidebarConfig={sidebarConfig}\n tabIcons={tabIcons}\n />\n {customNavContent ?? (\n <NavContent\n afterNavLinks={afterNavLinks}\n allContent={allContent}\n beforeNavLinks={beforeNavLinks}\n tabs={tabs}\n tabsContent={tabsContent}\n />\n )}\n </SidebarWrapper>\n </EnhancedSidebarContext.Provider>\n )\n}\n"],"names":["React","useCallback","useMemo","useState","EnhancedSidebarContext","NavContent","SidebarWrapper","TabsBar","baseClass","COOKIE_KEY","setTabCookie","tabId","document","cookie","SidebarContent","afterNavLinks","allContent","beforeNavLinks","customNavContent","initialActiveTabId","renderedTabItems","settingsMenu","sidebarConfig","tabIcons","tabsContent","activeTabId","setActiveTabId","handleTabChange","contextValue","onTabChange","tabs","filter","t","type","Provider","value"],"mappings":"AAAA;;AAEA,OAAOA,SAASC,WAAW,EAAEC,OAAO,EAAEC,QAAQ,QAAQ,QAAO;AAI7D,SAASC,sBAAsB,QAAQ,YAAW;AAClD,SAASC,UAAU,QAAQ,eAAc;AACzC,SAASC,cAAc,QAAQ,mBAAkB;AACjD,SAASC,OAAO,QAAQ,YAAW;AAEnC,MAAMC,YAAY;AAelB,MAAMC,aAAa;AAEnB,MAAMC,eAAe,CAACC;IACpBC,SAASC,MAAM,GAAG,GAAGJ,WAAW,CAAC,EAAEE,MAAM,wCAAwC,CAAC;AACpF;AAEA,OAAO,MAAMG,iBAAgD,CAAC,EAC5DC,aAAa,EACbC,UAAU,EACVC,cAAc,EACdC,gBAAgB,EAChBC,kBAAkB,EAClBC,gBAAgB,EAChBC,YAAY,EACZC,aAAa,EACbC,QAAQ,EACRC,WAAW,EACZ;IACC,MAAM,CAACC,aAAaC,eAAe,GAAGvB,SAASgB;IAE/C,MAAMQ,kBAAkB1B,YAAY,CAACU;QACnCe,eAAef;QACfD,aAAaC;IACf,GAAG,EAAE;IAEL,MAAMiB,eAAe1B,QACnB,IAAO,CAAA;YAAEuB;YAAaI,aAAaF;QAAgB,CAAA,GACnD;QAACF;QAAaE;KAAgB;IAGhC,MAAMG,OAAOR,cAAcQ,IAAI,EAAEC,OAAO,CAACC,IAAMA,EAAEC,IAAI,KAAK,UAAU,EAAE;IAEtE,qBACE,KAAC7B,uBAAuB8B,QAAQ;QAACC,OAAOP;kBACtC,cAAA,MAACtB;YAAeE,WAAWA;;8BACzB,KAACD;oBACCkB,aAAaA;oBACbI,aAAaF;oBACbP,kBAAkBA;oBAClBC,cAAcA;oBACdC,eAAeA;oBACfC,UAAUA;;gBAEXL,kCACC,KAACb;oBACCU,eAAeA;oBACfC,YAAYA;oBACZC,gBAAgBA;oBAChBa,MAAMA;oBACNN,aAAaA;;;;;AAMzB,EAAC"}
@@ -1,6 +1,7 @@
1
1
  import React from 'react';
2
2
  import type { SidebarTabContent, SidebarTabLink } from '../../../types';
3
3
  type TabButtonProps = {
4
+ icon?: React.ReactNode;
4
5
  isActive: boolean;
5
6
  onTabChange: (tabId: string) => void;
6
7
  tab: SidebarTabContent;
@@ -8,6 +9,7 @@ type TabButtonProps = {
8
9
  export declare const TabButton: React.FC<TabButtonProps>;
9
10
  type TabLinkProps = {
10
11
  href: string;
12
+ icon?: React.ReactNode;
11
13
  isActive: boolean;
12
14
  link: SidebarTabLink;
13
15
  };
@@ -7,7 +7,7 @@ import { Badge } from '../Badge';
7
7
  import { useBadge } from '../hooks/useBadge';
8
8
  import { Icon } from '../Icon';
9
9
  const tabsBaseClass = 'tabs-bar';
10
- export const TabButton = ({ isActive, onTabChange, tab })=>{
10
+ export const TabButton = ({ icon, isActive, onTabChange, tab })=>{
11
11
  const { i18n } = useTranslation();
12
12
  const label = getTranslation(tab.label, i18n);
13
13
  const { value } = useBadge(tab.badge, tab.id);
@@ -17,7 +17,7 @@ export const TabButton = ({ isActive, onTabChange, tab })=>{
17
17
  title: label,
18
18
  type: "button",
19
19
  children: [
20
- /*#__PURE__*/ _jsx(Icon, {
20
+ icon ?? /*#__PURE__*/ _jsx(Icon, {
21
21
  name: tab.icon,
22
22
  size: 20
23
23
  }),
@@ -29,7 +29,7 @@ export const TabButton = ({ isActive, onTabChange, tab })=>{
29
29
  ]
30
30
  });
31
31
  };
32
- export const TabLink = ({ href, isActive, link })=>{
32
+ export const TabLink = ({ href, icon, isActive, link })=>{
33
33
  const { i18n } = useTranslation();
34
34
  const label = getTranslation(link.label, i18n);
35
35
  const { value } = useBadge(link.badge, link.id);
@@ -40,7 +40,7 @@ export const TabLink = ({ href, isActive, link })=>{
40
40
  target: link.isExternal ? '_blank' : undefined,
41
41
  title: label,
42
42
  children: [
43
- /*#__PURE__*/ _jsx(Icon, {
43
+ icon ?? /*#__PURE__*/ _jsx(Icon, {
44
44
  name: link.icon,
45
45
  size: 20
46
46
  }),
@@ -1 +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"}
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 icon?: React.ReactNode\n isActive: boolean\n onTabChange: (tabId: string) => void\n tab: SidebarTabContent\n}\n\nexport const TabButton: React.FC<TabButtonProps> = ({ icon, 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 ?? <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 icon?: React.ReactNode\n isActive: boolean\n link: SidebarTabLink\n}\n\nexport const TabLink: React.FC<TabLinkProps> = ({ href, icon, 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 ?? <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","icon","isActive","onTabChange","tab","i18n","label","value","badge","id","button","className","onClick","title","type","name","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;AAStB,OAAO,MAAMC,YAAsC,CAAC,EAAEC,IAAI,EAAEC,QAAQ,EAAEC,WAAW,EAAEC,GAAG,EAAE;IACtF,MAAM,EAAEC,IAAI,EAAE,GAAGX;IACjB,MAAMY,QAAQd,eAAeY,IAAIE,KAAK,EAAED;IACxC,MAAM,EAAEE,KAAK,EAAE,GAAGV,SAASO,IAAII,KAAK,EAAEJ,IAAIK,EAAE;IAE5C,qBACE,MAACC;QACCC,WAAW,GAAGZ,cAAc,MAAM,EAAEG,WAAW,GAAGH,cAAc,aAAa,CAAC,GAAG,IAAI;QACrFa,SAAS,IAAMT,YAAYC,IAAIK,EAAE;QACjCI,OAAOP;QACPQ,MAAK;;YAEJb,sBAAQ,KAACH;gBAAKiB,MAAMX,IAAIH,IAAI;gBAAGe,MAAM;;YACrCT,UAAUU,2BAAa,KAACrB;gBAAMsB,OAAOd,IAAII,KAAK,EAAEU;gBAAOC,UAAS;gBAAWZ,OAAOA;;;;AAGzF,EAAC;AASD,OAAO,MAAMa,UAAkC,CAAC,EAAEC,IAAI,EAAEpB,IAAI,EAAEC,QAAQ,EAAEoB,IAAI,EAAE;IAC5E,MAAM,EAAEjB,IAAI,EAAE,GAAGX;IACjB,MAAMY,QAAQd,eAAe8B,KAAKhB,KAAK,EAAED;IACzC,MAAM,EAAEE,KAAK,EAAE,GAAGV,SAASyB,KAAKd,KAAK,EAAEc,KAAKb,EAAE;IAE9C,qBACE,MAAChB;QACCkB,WAAW,GAAGZ,cAAc,OAAO,EAAEG,WAAW,GAAGH,cAAc,cAAc,CAAC,GAAG,IAAI;QACvFsB,MAAMA;QACNE,KAAKD,KAAKE,UAAU,GAAG,wBAAwBP;QAC/CQ,QAAQH,KAAKE,UAAU,GAAG,WAAWP;QACrCJ,OAAOP;;YAENL,sBAAQ,KAACH;gBAAKiB,MAAMO,KAAKrB,IAAI;gBAAGe,MAAM;;YACtCT,UAAUU,2BAAa,KAACrB;gBAAMsB,OAAOI,KAAKd,KAAK,EAAEU;gBAAOC,UAAS;gBAAWZ,OAAOA;;;;AAG1F,EAAC"}
@@ -4,7 +4,9 @@ import './index.scss';
4
4
  export type TabsBarProps = {
5
5
  activeTabId: string;
6
6
  onTabChange: (tabId: string) => void;
7
+ renderedTabItems?: React.ReactNode[];
7
8
  settingsMenu?: React.ReactNode[];
8
9
  sidebarConfig: EnhancedSidebarConfig;
10
+ tabIcons?: Record<string, React.ReactNode>;
9
11
  };
10
12
  export declare const TabsBar: React.FC<TabsBarProps>;
@@ -10,7 +10,7 @@ import { SettingsMenuButton } from '../SettingsMenuButton';
10
10
  import { TabButton, TabLink } from './TabItem';
11
11
  import './index.scss';
12
12
  const tabsBaseClass = 'tabs-bar';
13
- export const TabsBar = ({ activeTabId, onTabChange, settingsMenu, sidebarConfig })=>{
13
+ export const TabsBar = ({ activeTabId, onTabChange, renderedTabItems, settingsMenu, sidebarConfig, tabIcons })=>{
14
14
  const { i18n } = useTranslation();
15
15
  const pathname = usePathname();
16
16
  const { config: { admin: { routes: { browseByFolder: foldersRoute, logout: logoutRoute } }, folders, routes: { admin: adminRoute } } } = useConfig();
@@ -24,6 +24,7 @@ export const TabsBar = ({ activeTabId, onTabChange, settingsMenu, sidebarConfig
24
24
  const renderTabItem = (item)=>{
25
25
  if (item.type === 'tab') {
26
26
  return /*#__PURE__*/ _jsx(TabButton, {
27
+ icon: tabIcons?.[item.id],
27
28
  isActive: activeTabId === item.id,
28
29
  onTabChange: onTabChange,
29
30
  tab: item
@@ -37,6 +38,7 @@ export const TabsBar = ({ activeTabId, onTabChange, settingsMenu, sidebarConfig
37
38
  const isActive = pathname === href || item.href === '/' && pathname === adminRoute;
38
39
  return /*#__PURE__*/ _jsx(TabLink, {
39
40
  href: href,
41
+ icon: tabIcons?.[item.id],
40
42
  isActive: isActive,
41
43
  link: item
42
44
  }, item.id);
@@ -47,7 +49,7 @@ export const TabsBar = ({ activeTabId, onTabChange, settingsMenu, sidebarConfig
47
49
  children: [
48
50
  /*#__PURE__*/ _jsx("div", {
49
51
  className: `${tabsBaseClass}__tabs`,
50
- children: tabItems.map(renderTabItem)
52
+ children: renderedTabItems ?? tabItems.map(renderTabItem)
51
53
  }),
52
54
  /*#__PURE__*/ _jsxs("div", {
53
55
  className: `${tabsBaseClass}__actions`,
@@ -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 { 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"}
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 renderedTabItems?: React.ReactNode[]\n settingsMenu?: React.ReactNode[]\n sidebarConfig: EnhancedSidebarConfig\n tabIcons?: Record<string, React.ReactNode>\n}\n\nexport const TabsBar: React.FC<TabsBarProps> = ({\n activeTabId,\n onTabChange,\n renderedTabItems,\n settingsMenu,\n sidebarConfig,\n tabIcons,\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 icon={tabIcons?.[item.id]}\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} icon={tabIcons?.[item.id]} 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`}>\n {renderedTabItems ?? tabItems.map(renderTabItem)}\n </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","renderedTabItems","settingsMenu","sidebarConfig","tabIcons","i18n","pathname","config","admin","routes","browseByFolder","foldersRoute","logout","logoutRoute","folders","adminRoute","showLogout","showFolders","folderURL","path","isFoldersActive","startsWith","renderTabItem","item","type","icon","id","isActive","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;AAWtB,OAAO,MAAMC,UAAkC,CAAC,EAC9CC,WAAW,EACXC,WAAW,EACXC,gBAAgB,EAChBC,YAAY,EACZC,aAAa,EACbC,QAAQ,EACT;IACC,MAAM,EAAEC,IAAI,EAAE,GAAGhB;IACjB,MAAMiB,WAAWhB;IAEjB,MAAM,EACJiB,QAAQ,EACNC,OAAO,EACLC,QAAQ,EAAEC,gBAAgBC,YAAY,EAAEC,QAAQC,WAAW,EAAE,EAC9D,EACDC,OAAO,EACPL,QAAQ,EAAED,OAAOO,UAAU,EAAE,EAC9B,EACF,GAAG3B;IAEJ,MAAM4B,aAAab,cAAca,UAAU,KAAK;IAChD,MAAMC,cAAcH,WAAWA,QAAQJ,cAAc;IAErD,MAAMQ,YAAY3B,eAAe;QAC/BwB;QACAI,MAAMR;IACR;IACA,MAAMS,kBAAkBd,SAASe,UAAU,CAACH;IAE5C,MAAMI,gBAAgB,CAACC;QACrB,IAAIA,KAAKC,IAAI,KAAK,OAAO;YACvB,qBACE,KAAC7B;gBACC8B,MAAMrB,UAAU,CAACmB,KAAKG,EAAE,CAAC;gBACzBC,UAAU5B,gBAAgBwB,KAAKG,EAAE;gBAEjC1B,aAAaA;gBACb4B,KAAKL;eAFAA,KAAKG,EAAE;QAKlB;QAEA,0BAA0B;QAC1B,MAAMG,OAAON,KAAKO,UAAU,GACxBP,KAAKM,IAAI,GACTtC,eAAe;YAAEwB;YAAYI,MAAMI,KAAKM,IAAI;QAAC;QACjD,MAAMF,WAAWrB,aAAauB,QAASN,KAAKM,IAAI,KAAK,OAAOvB,aAAaS;QAEzE,qBAAO,KAACnB;YAAQiC,MAAMA;YAAMJ,MAAMrB,UAAU,CAACmB,KAAKG,EAAE,CAAC;YAAEC,UAAUA;YAAwBI,MAAMR;WAAfA,KAAKG,EAAE;IACzF;IAEA,MAAMM,WAAW7B,cAAc8B,IAAI,IAAI,EAAE;IAEzC,qBACE,MAACC;QAAIC,WAAWtC;;0BACd,KAACqC;gBAAIC,WAAW,GAAGtC,cAAc,MAAM,CAAC;0BACrCI,oBAAoB+B,SAASI,GAAG,CAACd;;0BAGpC,MAACY;gBAAIC,WAAW,GAAGtC,cAAc,SAAS,CAAC;;oBACxCoB,6BACC,KAAC9B;wBACCgD,WAAW,GAAGtC,cAAc,SAAS,EAAEuB,kBAAkB,GAAGvB,cAAc,cAAc,CAAC,GAAG,IAAI;wBAChGgC,MAAMX;wBACNmB,OAAOnD,eAAe;4BAAEoD,IAAI;4BAAoBC,IAAI;wBAAwB,GAAGlC;kCAE/E,cAAA,KAACZ;4BAAK+C,MAAK;4BAASC,MAAM;;;kCAG9B,KAAC/C;wBAAmBQ,cAAcA;;oBACjCc,4BACC,KAAC7B;wBACCgD,WAAW,GAAGtC,cAAc,QAAQ,CAAC;wBACrCgC,MAAMtC,eAAe;4BACnBwB;4BACAI,MAAMN;wBACR;wBACAwB,OAAOnD,eAAe;4BAAEoD,IAAI;4BAAUC,IAAI;wBAAQ,GAAGlC;wBACrDmB,MAAK;kCAEL,cAAA,KAAC/B;4BAAK+C,MAAK;4BAASC,MAAM;;;;;;;AAMtC,EAAC"}