@veiag/payload-enhanced-sidebar 0.1.1 → 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 +2 -0
- package/dist/components/EnhancedSidebar/SidebarContent.js +117 -99
- 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 +17 -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
package/README.md
CHANGED
|
@@ -10,9 +10,12 @@ An enhanced sidebar plugin for [Payload CMS](https://payloadcms.com) that adds a
|
|
|
10
10
|
- **Vertical Tab Bar** - Icon-based tabs on the left side of the sidebar
|
|
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
|
+
- **Badges** - Show notification badges on tabs and navigation items (API-based or reactive provider)
|
|
13
14
|
- **i18n Support** - Full localization support for labels and groups
|
|
14
15
|
- **Lucide Icons** - Use any [Lucide icon](https://lucide.dev/icons) for tabs and links
|
|
15
16
|
|
|
17
|
+

|
|
18
|
+
|
|
16
19
|
## Installation
|
|
17
20
|
|
|
18
21
|
```bash
|
|
@@ -44,6 +47,8 @@ This will add:
|
|
|
44
47
|
- A default tab showing all collections and globals
|
|
45
48
|
- A logout button at the bottom
|
|
46
49
|
|
|
50
|
+

|
|
51
|
+
|
|
47
52
|
## Configuration
|
|
48
53
|
|
|
49
54
|
### Full Configuration Example
|
|
@@ -150,9 +155,11 @@ Array of tabs and links to show in the sidebar.
|
|
|
150
155
|
| `collections` | `CollectionSlug[]` | No | Collections to show in this tab |
|
|
151
156
|
| `globals` | `GlobalSlug[]` | No | Globals to show in this tab |
|
|
152
157
|
| `customItems` | `SidebarTabItem[]` | No | Custom navigation items |
|
|
158
|
+
| `badge` | `BadgeConfig` | No | Badge configuration for the tab icon |
|
|
153
159
|
|
|
154
160
|
> If neither `collections` nor `globals` are specified, the tab shows all collections and globals.
|
|
155
161
|
|
|
162
|
+
|
|
156
163
|
**Link (`type: 'link'`)**
|
|
157
164
|
|
|
158
165
|
| Property | Type | Required | Description |
|
|
@@ -163,6 +170,10 @@ Array of tabs and links to show in the sidebar.
|
|
|
163
170
|
| `label` | `LocalizedString` | Yes | Link tooltip/label |
|
|
164
171
|
| `href` | `string` | Yes | URL |
|
|
165
172
|
| `isExternal` | `boolean` | No | If true, `href` is absolute URL, if not, `href` is relative to admin route |
|
|
173
|
+
| `badge` | `BadgeConfig` | No | Badge configuration for the link icon |
|
|
174
|
+
|
|
175
|
+
|
|
176
|
+

|
|
166
177
|
|
|
167
178
|
### `customItems`
|
|
168
179
|
|
|
@@ -183,6 +194,174 @@ Custom items can be added to any tab:
|
|
|
183
194
|
- If `group` doesn't match any existing group, a new group is created
|
|
184
195
|
- If `group` is not specified, the item appears at the bottom as ungrouped
|
|
185
196
|
|
|
197
|
+
|
|
198
|
+
## Badges
|
|
199
|
+
|
|
200
|
+
Badges allow you to show notification counts on tabs and navigation items. There are three ways to configure badges:
|
|
201
|
+
|
|
202
|
+
<!-- [screenshot - Badges showcase: show sidebar with multiple badges - on tab icon (red "5"), on nav item (blue "12"), maybe one with "99+". Show different colors: error (red), primary (blue), warning (yellow)] -->
|
|
203
|
+
|
|
204
|
+
### Badge on Tabs/Links
|
|
205
|
+
|
|
206
|
+
Add a `badge` property to any tab or link in the `tabs` array:
|
|
207
|
+
|
|
208
|
+
```typescript
|
|
209
|
+
tabs: [
|
|
210
|
+
{
|
|
211
|
+
id: 'orders',
|
|
212
|
+
type: 'tab',
|
|
213
|
+
icon: 'ShoppingCart',
|
|
214
|
+
label: 'Orders',
|
|
215
|
+
collections: ['orders'],
|
|
216
|
+
// Badge on the tab icon
|
|
217
|
+
badge: {
|
|
218
|
+
type: 'collection-count',
|
|
219
|
+
collectionSlug: 'orders',
|
|
220
|
+
color: 'error',
|
|
221
|
+
},
|
|
222
|
+
},
|
|
223
|
+
]
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
### Badges on Navigation Items
|
|
227
|
+
|
|
228
|
+
Use the `badges` configuration to add badges to any sidebar item (collections, globals, or custom items):
|
|
229
|
+
|
|
230
|
+
```typescript
|
|
231
|
+
payloadEnhancedSidebar({
|
|
232
|
+
badges: {
|
|
233
|
+
// Show document count for posts collection
|
|
234
|
+
posts: { type: 'collection-count', color: 'primary' },
|
|
235
|
+
// Custom API endpoint
|
|
236
|
+
orders: {
|
|
237
|
+
type: 'api',
|
|
238
|
+
endpoint: '/api/orders/pending',
|
|
239
|
+
responseKey: 'count',
|
|
240
|
+
color: 'error',
|
|
241
|
+
},
|
|
242
|
+
// Provider-based (reactive)
|
|
243
|
+
notifications: { type: 'provider', color: 'warning' },
|
|
244
|
+
},
|
|
245
|
+
})
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
### Badge Types
|
|
249
|
+
|
|
250
|
+
#### `collection-count`
|
|
251
|
+
|
|
252
|
+
Automatically fetches document count from a collection.
|
|
253
|
+
|
|
254
|
+
```typescript
|
|
255
|
+
{
|
|
256
|
+
type: 'collection-count',
|
|
257
|
+
collectionSlug?: string, // Defaults to item's slug
|
|
258
|
+
color?: BadgeColor, // 'default' | 'primary' | 'success' | 'warning' | 'error'
|
|
259
|
+
where?: object, // Optional filter query
|
|
260
|
+
}
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
#### `api`
|
|
264
|
+
|
|
265
|
+
Fetches badge value from a custom API endpoint.
|
|
266
|
+
|
|
267
|
+
```typescript
|
|
268
|
+
{
|
|
269
|
+
type: 'api',
|
|
270
|
+
endpoint: string, // API URL (relative or absolute)
|
|
271
|
+
method?: 'GET' | 'POST', // Default: 'GET'
|
|
272
|
+
responseKey?: string, // Key to extract from response. Default: 'count'
|
|
273
|
+
color?: BadgeColor,
|
|
274
|
+
}
|
|
275
|
+
```
|
|
276
|
+
|
|
277
|
+
#### `provider`
|
|
278
|
+
|
|
279
|
+
Uses reactive values from `BadgeProvider` context. Values update automatically when the provider changes.
|
|
280
|
+
|
|
281
|
+
```typescript
|
|
282
|
+
{
|
|
283
|
+
type: 'provider',
|
|
284
|
+
slug?: string, // Key in provider values. Defaults to item's slug/id
|
|
285
|
+
color?: BadgeColor,
|
|
286
|
+
}
|
|
287
|
+
```
|
|
288
|
+
|
|
289
|
+
### Using BadgeProvider
|
|
290
|
+
|
|
291
|
+
For reactive badges (real-time updates, websockets, etc.), use the `BadgeProvider`:
|
|
292
|
+
|
|
293
|
+
1. Create a provider component:
|
|
294
|
+
|
|
295
|
+
```typescript
|
|
296
|
+
// components/MyBadgeProvider.tsx
|
|
297
|
+
'use client'
|
|
298
|
+
|
|
299
|
+
import { BadgeProvider } from '@veiag/payload-enhanced-sidebar'
|
|
300
|
+
import { useEffect, useState } from 'react'
|
|
301
|
+
|
|
302
|
+
export const MyBadgeProvider = ({ children }) => {
|
|
303
|
+
const [counts, setCounts] = useState({
|
|
304
|
+
orders: 0,
|
|
305
|
+
notifications: 0,
|
|
306
|
+
})
|
|
307
|
+
|
|
308
|
+
useEffect(() => {
|
|
309
|
+
// Fetch initial counts, subscribe to websocket, etc.
|
|
310
|
+
const ws = new WebSocket('wss://your-api/counts')
|
|
311
|
+
ws.onmessage = (e) => setCounts(JSON.parse(e.data))
|
|
312
|
+
return () => ws.close()
|
|
313
|
+
}, [])
|
|
314
|
+
|
|
315
|
+
return <BadgeProvider values={counts}>{children}</BadgeProvider>
|
|
316
|
+
}
|
|
317
|
+
```
|
|
318
|
+
|
|
319
|
+
2. Add it to Payload's providers:
|
|
320
|
+
|
|
321
|
+
```typescript
|
|
322
|
+
// payload.config.ts
|
|
323
|
+
export default buildConfig({
|
|
324
|
+
admin: {
|
|
325
|
+
components: {
|
|
326
|
+
providers: ['./components/MyBadgeProvider#MyBadgeProvider'],
|
|
327
|
+
},
|
|
328
|
+
},
|
|
329
|
+
})
|
|
330
|
+
```
|
|
331
|
+
|
|
332
|
+
3. Configure badges to use the provider:
|
|
333
|
+
|
|
334
|
+
```typescript
|
|
335
|
+
payloadEnhancedSidebar({
|
|
336
|
+
badges: {
|
|
337
|
+
orders: { type: 'provider', color: 'error' },
|
|
338
|
+
},
|
|
339
|
+
tabs: [
|
|
340
|
+
{
|
|
341
|
+
id: 'notifications',
|
|
342
|
+
type: 'link',
|
|
343
|
+
href: '/notifications',
|
|
344
|
+
icon: 'Bell',
|
|
345
|
+
label: 'Notifications',
|
|
346
|
+
badge: { type: 'provider', slug: 'notifications', color: 'warning' },
|
|
347
|
+
},
|
|
348
|
+
],
|
|
349
|
+
})
|
|
350
|
+
```
|
|
351
|
+
|
|
352
|
+
### Badge Colors
|
|
353
|
+
|
|
354
|
+
Available colors: `default`, `primary`, `success`, `warning`, `error`
|
|
355
|
+
|
|
356
|
+

|
|
357
|
+
|
|
358
|
+
### Badge Display
|
|
359
|
+
|
|
360
|
+
- Numbers up to 99 are shown as-is
|
|
361
|
+
- Numbers > 99 are shown as "99+"
|
|
362
|
+
- Zero or undefined values hide the badge
|
|
363
|
+
- Provider values can also be React nodes for custom rendering
|
|
364
|
+
|
|
186
365
|
### `showLogout`
|
|
187
366
|
|
|
188
367
|
Show/hide the logout button at the bottom of the tabs bar.
|
|
@@ -211,12 +390,10 @@ label: {
|
|
|
211
390
|
}
|
|
212
391
|
```
|
|
213
392
|
|
|
214
|
-
##
|
|
215
|
-
|
|
216
|
-
The following features are planned but not yet implemented:
|
|
393
|
+
## Payload Features Support
|
|
217
394
|
|
|
218
|
-
-
|
|
219
|
-
-
|
|
395
|
+
- **Browse by Folder Button** - Automatically shows folder view button when Payload folders are enabled (requires Payload v3.41.0+)
|
|
396
|
+
- **Settings Menu Items** - Integrates with Payload's SettingsMenu components (requires Payload v3.60.0+)
|
|
220
397
|
|
|
221
398
|
## Contributing
|
|
222
399
|
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import type { BadgeColor } from '../../../types';
|
|
3
|
+
import './index.scss';
|
|
4
|
+
export type BadgeProps = {
|
|
5
|
+
/**
|
|
6
|
+
* Badge color variant
|
|
7
|
+
* @default 'default'
|
|
8
|
+
*/
|
|
9
|
+
color?: BadgeColor;
|
|
10
|
+
/**
|
|
11
|
+
* Position modifier
|
|
12
|
+
* - 'absolute': positioned at top-right corner (for icons)
|
|
13
|
+
* - 'inline': inline with margin (for nav items)
|
|
14
|
+
*/
|
|
15
|
+
position?: 'absolute' | 'inline';
|
|
16
|
+
/**
|
|
17
|
+
* Badge value - number or React node
|
|
18
|
+
* Numbers > 99 will be displayed as "99+"
|
|
19
|
+
*/
|
|
20
|
+
value: number | React.ReactNode;
|
|
21
|
+
};
|
|
22
|
+
export declare const Badge: React.FC<BadgeProps>;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
3
|
+
import React from 'react';
|
|
4
|
+
import './index.scss';
|
|
5
|
+
const baseClass = 'sidebar-badge';
|
|
6
|
+
/**
|
|
7
|
+
* Format badge value - show up to 2 digits, 99+ for larger numbers
|
|
8
|
+
*/ const formatValue = (value)=>{
|
|
9
|
+
if (typeof value === 'number') {
|
|
10
|
+
return value > 99 ? '99+' : value;
|
|
11
|
+
}
|
|
12
|
+
return value;
|
|
13
|
+
};
|
|
14
|
+
export const Badge = ({ color = 'default', position, value })=>{
|
|
15
|
+
// Don't render if value is 0 or falsy (except for React nodes)
|
|
16
|
+
if (value === 0 || value === null || typeof value !== 'object' && !value) {
|
|
17
|
+
return null;
|
|
18
|
+
}
|
|
19
|
+
const classes = [
|
|
20
|
+
baseClass,
|
|
21
|
+
`${baseClass}--${color}`,
|
|
22
|
+
position && `${baseClass}--${position}`
|
|
23
|
+
].filter(Boolean).join(' ');
|
|
24
|
+
return /*#__PURE__*/ _jsx("span", {
|
|
25
|
+
className: classes,
|
|
26
|
+
children: formatValue(value)
|
|
27
|
+
});
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../src/components/EnhancedSidebar/Badge/index.tsx"],"sourcesContent":["'use client'\n\nimport React from 'react'\n\nimport type { BadgeColor } from '../../../types'\n\nimport './index.scss'\n\nconst baseClass = 'sidebar-badge'\n\nexport type BadgeProps = {\n /**\n * Badge color variant\n * @default 'default'\n */\n color?: BadgeColor\n /**\n * Position modifier\n * - 'absolute': positioned at top-right corner (for icons)\n * - 'inline': inline with margin (for nav items)\n */\n position?: 'absolute' | 'inline'\n /**\n * Badge value - number or React node\n * Numbers > 99 will be displayed as \"99+\"\n */\n value: number | React.ReactNode\n}\n\n/**\n * Format badge value - show up to 2 digits, 99+ for larger numbers\n */\nconst formatValue = (value: number | React.ReactNode): React.ReactNode => {\n if (typeof value === 'number') {\n return value > 99 ? '99+' : value\n }\n return value\n}\n\nexport const Badge: React.FC<BadgeProps> = ({ color = 'default', position, value }) => {\n // Don't render if value is 0 or falsy (except for React nodes)\n if (value === 0 || value === null || (typeof value !== 'object' && !value)) {\n return null\n }\n\n const classes = [baseClass, `${baseClass}--${color}`, position && `${baseClass}--${position}`]\n .filter(Boolean)\n .join(' ')\n\n return <span className={classes}>{formatValue(value)}</span>\n}\n"],"names":["React","baseClass","formatValue","value","Badge","color","position","classes","filter","Boolean","join","span","className"],"mappings":"AAAA;;AAEA,OAAOA,WAAW,QAAO;AAIzB,OAAO,eAAc;AAErB,MAAMC,YAAY;AAqBlB;;CAEC,GACD,MAAMC,cAAc,CAACC;IACnB,IAAI,OAAOA,UAAU,UAAU;QAC7B,OAAOA,QAAQ,KAAK,QAAQA;IAC9B;IACA,OAAOA;AACT;AAEA,OAAO,MAAMC,QAA8B,CAAC,EAAEC,QAAQ,SAAS,EAAEC,QAAQ,EAAEH,KAAK,EAAE;IAChF,+DAA+D;IAC/D,IAAIA,UAAU,KAAKA,UAAU,QAAS,OAAOA,UAAU,YAAY,CAACA,OAAQ;QAC1E,OAAO;IACT;IAEA,MAAMI,UAAU;QAACN;QAAW,GAAGA,UAAU,EAAE,EAAEI,OAAO;QAAEC,YAAY,GAAGL,UAAU,EAAE,EAAEK,UAAU;KAAC,CAC3FE,MAAM,CAACC,SACPC,IAAI,CAAC;IAER,qBAAO,KAACC;QAAKC,WAAWL;kBAAUL,YAAYC;;AAChD,EAAC"}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
@import '~@payloadcms/ui/scss';
|
|
2
|
+
|
|
3
|
+
@layer payload-default {
|
|
4
|
+
.sidebar-badge {
|
|
5
|
+
display: inline-flex;
|
|
6
|
+
align-items: center;
|
|
7
|
+
justify-content: center;
|
|
8
|
+
min-width: 18px;
|
|
9
|
+
height: 18px;
|
|
10
|
+
padding: 0 base(0.25);
|
|
11
|
+
border-radius: 9px;
|
|
12
|
+
font-size: 11px;
|
|
13
|
+
font-weight: 600;
|
|
14
|
+
line-height: 1;
|
|
15
|
+
white-space: nowrap;
|
|
16
|
+
|
|
17
|
+
// Color variants - using fixed colors for consistent contrast in both themes
|
|
18
|
+
&--default {
|
|
19
|
+
background: var(--theme-elevation-200);
|
|
20
|
+
color: var(--theme-elevation-800);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
&--primary {
|
|
24
|
+
background: #3b82f6; // Blue
|
|
25
|
+
color: #fff;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
&--success {
|
|
29
|
+
background: #22c55e; // Green
|
|
30
|
+
color: #fff;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
&--warning {
|
|
34
|
+
background: #f59e0b; // Amber
|
|
35
|
+
color: #000;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
&--error {
|
|
39
|
+
background: #ef4444; // Red
|
|
40
|
+
color: #fff;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// Position modifier for absolute positioning (used on icons)
|
|
44
|
+
&--absolute {
|
|
45
|
+
position: absolute;
|
|
46
|
+
top: -4px;
|
|
47
|
+
right: -4px;
|
|
48
|
+
|
|
49
|
+
[dir='rtl'] & {
|
|
50
|
+
right: auto;
|
|
51
|
+
left: -4px;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// Inline modifier (used in nav items)
|
|
56
|
+
&--inline {
|
|
57
|
+
margin-left: base(0.5);
|
|
58
|
+
|
|
59
|
+
[dir='rtl'] & {
|
|
60
|
+
margin-left: 0;
|
|
61
|
+
margin-right: base(0.5);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import type { BadgeValues } from '../../../types';
|
|
3
|
+
type BadgeContextValue = {
|
|
4
|
+
values: BadgeValues;
|
|
5
|
+
};
|
|
6
|
+
export type BadgeProviderProps = {
|
|
7
|
+
children: React.ReactNode;
|
|
8
|
+
/**
|
|
9
|
+
* Badge values object.
|
|
10
|
+
* Keys are slugs (collection slug, global slug, or custom item slug).
|
|
11
|
+
* Values can be numbers or React nodes.
|
|
12
|
+
*
|
|
13
|
+
* Values are merged with any parent BadgeProvider values.
|
|
14
|
+
* This provider's values take priority over parent values.
|
|
15
|
+
*
|
|
16
|
+
* @example
|
|
17
|
+
* ```tsx
|
|
18
|
+
* <BadgeProvider values={{ orders: 5, notifications: <CustomBadge /> }}>
|
|
19
|
+
* {children}
|
|
20
|
+
* </BadgeProvider>
|
|
21
|
+
* ```
|
|
22
|
+
*/
|
|
23
|
+
values: BadgeValues;
|
|
24
|
+
};
|
|
25
|
+
/**
|
|
26
|
+
* Provider for badge values.
|
|
27
|
+
* Wrap your app with this provider and pass badge values.
|
|
28
|
+
* Values are reactive - changes will update badges automatically.
|
|
29
|
+
*
|
|
30
|
+
* Values are merged with any parent BadgeProvider (e.g., InternalBadgeProvider).
|
|
31
|
+
* This provider's values take priority, allowing you to override internal values.
|
|
32
|
+
*
|
|
33
|
+
* @example
|
|
34
|
+
* ```tsx
|
|
35
|
+
* // In your admin.components.providers
|
|
36
|
+
* import { BadgeProvider } from '@veiag/payload-enhanced-sidebar'
|
|
37
|
+
*
|
|
38
|
+
* export const MyProvider = ({ children }) => {
|
|
39
|
+
* const [counts, setCounts] = useState({ orders: 0 })
|
|
40
|
+
*
|
|
41
|
+
* useEffect(() => {
|
|
42
|
+
* // Fetch counts, subscribe to realtime updates, etc.
|
|
43
|
+
* }, [])
|
|
44
|
+
*
|
|
45
|
+
* return (
|
|
46
|
+
* <BadgeProvider values={counts}>
|
|
47
|
+
* {children}
|
|
48
|
+
* </BadgeProvider>
|
|
49
|
+
* )
|
|
50
|
+
* }
|
|
51
|
+
* ```
|
|
52
|
+
*/
|
|
53
|
+
export declare const BadgeProvider: React.FC<BadgeProviderProps>;
|
|
54
|
+
/**
|
|
55
|
+
* Hook to access badge values from context.
|
|
56
|
+
* Returns the full values object from BadgeProvider.
|
|
57
|
+
*/
|
|
58
|
+
export declare const useBadgeContext: () => BadgeContextValue;
|
|
59
|
+
/**
|
|
60
|
+
* Hook to get a specific badge value by slug.
|
|
61
|
+
* Returns the value for the given slug, or undefined if not found.
|
|
62
|
+
*/
|
|
63
|
+
export declare const useBadgeValue: (slug: string) => number | React.ReactNode | undefined;
|
|
64
|
+
export {};
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
3
|
+
import React, { createContext, useContext, useMemo } from 'react';
|
|
4
|
+
const BadgeContext = /*#__PURE__*/ createContext({
|
|
5
|
+
values: {}
|
|
6
|
+
});
|
|
7
|
+
/**
|
|
8
|
+
* Provider for badge values.
|
|
9
|
+
* Wrap your app with this provider and pass badge values.
|
|
10
|
+
* Values are reactive - changes will update badges automatically.
|
|
11
|
+
*
|
|
12
|
+
* Values are merged with any parent BadgeProvider (e.g., InternalBadgeProvider).
|
|
13
|
+
* This provider's values take priority, allowing you to override internal values.
|
|
14
|
+
*
|
|
15
|
+
* @example
|
|
16
|
+
* ```tsx
|
|
17
|
+
* // In your admin.components.providers
|
|
18
|
+
* import { BadgeProvider } from '@veiag/payload-enhanced-sidebar'
|
|
19
|
+
*
|
|
20
|
+
* export const MyProvider = ({ children }) => {
|
|
21
|
+
* const [counts, setCounts] = useState({ orders: 0 })
|
|
22
|
+
*
|
|
23
|
+
* useEffect(() => {
|
|
24
|
+
* // Fetch counts, subscribe to realtime updates, etc.
|
|
25
|
+
* }, [])
|
|
26
|
+
*
|
|
27
|
+
* return (
|
|
28
|
+
* <BadgeProvider values={counts}>
|
|
29
|
+
* {children}
|
|
30
|
+
* </BadgeProvider>
|
|
31
|
+
* )
|
|
32
|
+
* }
|
|
33
|
+
* ```
|
|
34
|
+
*/ export const BadgeProvider = ({ children, values })=>{
|
|
35
|
+
// Get parent context values (if any)
|
|
36
|
+
const parentContext = useContext(BadgeContext);
|
|
37
|
+
// Merge parent values with this provider's values (this provider wins)
|
|
38
|
+
const mergedValues = useMemo(()=>({
|
|
39
|
+
...parentContext.values,
|
|
40
|
+
...values
|
|
41
|
+
}), [
|
|
42
|
+
parentContext.values,
|
|
43
|
+
values
|
|
44
|
+
]);
|
|
45
|
+
return /*#__PURE__*/ _jsx(BadgeContext.Provider, {
|
|
46
|
+
value: {
|
|
47
|
+
values: mergedValues
|
|
48
|
+
},
|
|
49
|
+
children: children
|
|
50
|
+
});
|
|
51
|
+
};
|
|
52
|
+
/**
|
|
53
|
+
* Hook to access badge values from context.
|
|
54
|
+
* Returns the full values object from BadgeProvider.
|
|
55
|
+
*/ export const useBadgeContext = ()=>{
|
|
56
|
+
return useContext(BadgeContext);
|
|
57
|
+
};
|
|
58
|
+
/**
|
|
59
|
+
* Hook to get a specific badge value by slug.
|
|
60
|
+
* Returns the value for the given slug, or undefined if not found.
|
|
61
|
+
*/ export const useBadgeValue = (slug)=>{
|
|
62
|
+
const { values } = useBadgeContext();
|
|
63
|
+
return values[slug];
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../src/components/EnhancedSidebar/BadgeProvider/index.tsx"],"sourcesContent":["'use client'\n\nimport React, { createContext, useContext, useMemo } from 'react'\n\nimport type { BadgeValues } from '../../../types'\n\ntype BadgeContextValue = {\n values: BadgeValues\n}\n\nconst BadgeContext = createContext<BadgeContextValue>({ values: {} })\n\nexport type BadgeProviderProps = {\n children: React.ReactNode\n /**\n * Badge values object.\n * Keys are slugs (collection slug, global slug, or custom item slug).\n * Values can be numbers or React nodes.\n *\n * Values are merged with any parent BadgeProvider values.\n * This provider's values take priority over parent values.\n *\n * @example\n * ```tsx\n * <BadgeProvider values={{ orders: 5, notifications: <CustomBadge /> }}>\n * {children}\n * </BadgeProvider>\n * ```\n */\n values: BadgeValues\n}\n\n/**\n * Provider for badge values.\n * Wrap your app with this provider and pass badge values.\n * Values are reactive - changes will update badges automatically.\n *\n * Values are merged with any parent BadgeProvider (e.g., InternalBadgeProvider).\n * This provider's values take priority, allowing you to override internal values.\n *\n * @example\n * ```tsx\n * // In your admin.components.providers\n * import { BadgeProvider } from '@veiag/payload-enhanced-sidebar'\n *\n * export const MyProvider = ({ children }) => {\n * const [counts, setCounts] = useState({ orders: 0 })\n *\n * useEffect(() => {\n * // Fetch counts, subscribe to realtime updates, etc.\n * }, [])\n *\n * return (\n * <BadgeProvider values={counts}>\n * {children}\n * </BadgeProvider>\n * )\n * }\n * ```\n */\nexport const BadgeProvider: React.FC<BadgeProviderProps> = ({ children, values }) => {\n // Get parent context values (if any)\n const parentContext = useContext(BadgeContext)\n\n // Merge parent values with this provider's values (this provider wins)\n const mergedValues = useMemo(\n () => ({\n ...parentContext.values,\n ...values,\n }),\n [parentContext.values, values],\n )\n\n return <BadgeContext.Provider value={{ values: mergedValues }}>{children}</BadgeContext.Provider>\n}\n\n/**\n * Hook to access badge values from context.\n * Returns the full values object from BadgeProvider.\n */\nexport const useBadgeContext = (): BadgeContextValue => {\n return useContext(BadgeContext)\n}\n\n/**\n * Hook to get a specific badge value by slug.\n * Returns the value for the given slug, or undefined if not found.\n */\nexport const useBadgeValue = (slug: string): number | React.ReactNode | undefined => {\n const { values } = useBadgeContext()\n return values[slug]\n}\n"],"names":["React","createContext","useContext","useMemo","BadgeContext","values","BadgeProvider","children","parentContext","mergedValues","Provider","value","useBadgeContext","useBadgeValue","slug"],"mappings":"AAAA;;AAEA,OAAOA,SAASC,aAAa,EAAEC,UAAU,EAAEC,OAAO,QAAQ,QAAO;AAQjE,MAAMC,6BAAeH,cAAiC;IAAEI,QAAQ,CAAC;AAAE;AAsBnE;;;;;;;;;;;;;;;;;;;;;;;;;;;CA2BC,GACD,OAAO,MAAMC,gBAA8C,CAAC,EAAEC,QAAQ,EAAEF,MAAM,EAAE;IAC9E,qCAAqC;IACrC,MAAMG,gBAAgBN,WAAWE;IAEjC,uEAAuE;IACvE,MAAMK,eAAeN,QACnB,IAAO,CAAA;YACL,GAAGK,cAAcH,MAAM;YACvB,GAAGA,MAAM;QACX,CAAA,GACA;QAACG,cAAcH,MAAM;QAAEA;KAAO;IAGhC,qBAAO,KAACD,aAAaM,QAAQ;QAACC,OAAO;YAAEN,QAAQI;QAAa;kBAAIF;;AAClE,EAAC;AAED;;;CAGC,GACD,OAAO,MAAMK,kBAAkB;IAC7B,OAAOV,WAAWE;AACpB,EAAC;AAED;;;CAGC,GACD,OAAO,MAAMS,gBAAgB,CAACC;IAC5B,MAAM,EAAET,MAAM,EAAE,GAAGO;IACnB,OAAOP,MAAM,CAACS,KAAK;AACrB,EAAC"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import type { EnhancedSidebarConfig } from '../../../types';
|
|
3
|
+
export type InternalBadgeProviderProps = {
|
|
4
|
+
children: React.ReactNode;
|
|
5
|
+
/**
|
|
6
|
+
* Sidebar configuration containing badge configs
|
|
7
|
+
*/
|
|
8
|
+
sidebarConfig: EnhancedSidebarConfig;
|
|
9
|
+
};
|
|
10
|
+
/**
|
|
11
|
+
* Internal provider that fetches all API-based badges once on mount.
|
|
12
|
+
* This provider is automatically injected by the plugin.
|
|
13
|
+
* Values are stored in context and don't refetch on navigation.
|
|
14
|
+
*/
|
|
15
|
+
export declare const InternalBadgeProvider: React.FC<InternalBadgeProviderProps>;
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
3
|
+
import { useConfig } from '@payloadcms/ui';
|
|
4
|
+
import { stringify } from 'qs-esm';
|
|
5
|
+
import React, { useCallback, useEffect, useMemo, useState } from 'react';
|
|
6
|
+
import { BadgeProvider } from '../BadgeProvider';
|
|
7
|
+
/**
|
|
8
|
+
* Internal provider that fetches all API-based badges once on mount.
|
|
9
|
+
* This provider is automatically injected by the plugin.
|
|
10
|
+
* Values are stored in context and don't refetch on navigation.
|
|
11
|
+
*/ export const InternalBadgeProvider = ({ children, sidebarConfig })=>{
|
|
12
|
+
const [values, setValues] = useState({});
|
|
13
|
+
const { config: { routes: { api: apiRoute }, serverURL } } = useConfig();
|
|
14
|
+
// Collect all badges that need to be fetched (api and collection-count types)
|
|
15
|
+
const badgesToFetch = useMemo(()=>{
|
|
16
|
+
const badges = [];
|
|
17
|
+
// From tabs
|
|
18
|
+
if (sidebarConfig.tabs) {
|
|
19
|
+
for (const tab of sidebarConfig.tabs){
|
|
20
|
+
if (tab.badge && tab.badge.type !== 'provider') {
|
|
21
|
+
badges.push({
|
|
22
|
+
slug: tab.id,
|
|
23
|
+
config: tab.badge
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
// From badges config
|
|
29
|
+
if (sidebarConfig.badges) {
|
|
30
|
+
for (const [slug, config] of Object.entries(sidebarConfig.badges)){
|
|
31
|
+
if (config.type !== 'provider') {
|
|
32
|
+
badges.push({
|
|
33
|
+
slug,
|
|
34
|
+
config
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
return badges;
|
|
40
|
+
}, [
|
|
41
|
+
sidebarConfig
|
|
42
|
+
]);
|
|
43
|
+
// Fetch a single badge value
|
|
44
|
+
const fetchBadge = useCallback(async (badge)=>{
|
|
45
|
+
const { slug, config } = badge;
|
|
46
|
+
try {
|
|
47
|
+
let url;
|
|
48
|
+
let responseKey;
|
|
49
|
+
if (config.type === 'api') {
|
|
50
|
+
url = config.endpoint;
|
|
51
|
+
responseKey = config.responseKey ?? 'count';
|
|
52
|
+
// If endpoint is relative, prepend serverURL
|
|
53
|
+
if (!url.startsWith('http')) {
|
|
54
|
+
url = `${serverURL || ''}${url}`;
|
|
55
|
+
}
|
|
56
|
+
} else if (config.type === 'collection-count') {
|
|
57
|
+
const collectionSlug = config.collectionSlug ?? slug;
|
|
58
|
+
const baseUrl = `${serverURL || ''}${apiRoute}/${collectionSlug}`;
|
|
59
|
+
if (config.where) {
|
|
60
|
+
const whereParams = stringify({
|
|
61
|
+
where: config.where
|
|
62
|
+
});
|
|
63
|
+
url = `${baseUrl}?${whereParams}`;
|
|
64
|
+
} else {
|
|
65
|
+
url = `${baseUrl}`;
|
|
66
|
+
}
|
|
67
|
+
responseKey = 'totalDocs';
|
|
68
|
+
} else {
|
|
69
|
+
return {
|
|
70
|
+
slug,
|
|
71
|
+
value: undefined
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
const response = await fetch(url, {
|
|
75
|
+
credentials: 'include',
|
|
76
|
+
method: config.type === 'api' ? config.method ?? 'GET' : 'GET'
|
|
77
|
+
});
|
|
78
|
+
if (response.ok) {
|
|
79
|
+
const data = await response.json();
|
|
80
|
+
// Extract value from nested key (e.g., "data.count")
|
|
81
|
+
const keys = responseKey.split('.');
|
|
82
|
+
let value = data;
|
|
83
|
+
for (const key of keys){
|
|
84
|
+
value = value?.[key];
|
|
85
|
+
}
|
|
86
|
+
return {
|
|
87
|
+
slug,
|
|
88
|
+
value: typeof value === 'number' ? value : undefined
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
} catch (error) {
|
|
92
|
+
//eslint-disable-next-line no-console
|
|
93
|
+
console.error(`Failed to fetch badge data for ${slug}:`, error);
|
|
94
|
+
}
|
|
95
|
+
return {
|
|
96
|
+
slug,
|
|
97
|
+
value: undefined
|
|
98
|
+
};
|
|
99
|
+
}, [
|
|
100
|
+
apiRoute,
|
|
101
|
+
serverURL
|
|
102
|
+
]);
|
|
103
|
+
// Fetch all badges on mount
|
|
104
|
+
useEffect(()=>{
|
|
105
|
+
if (badgesToFetch.length === 0) {
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
108
|
+
const fetchAll = async ()=>{
|
|
109
|
+
const results = await Promise.all(badgesToFetch.map(fetchBadge));
|
|
110
|
+
const newValues = {};
|
|
111
|
+
for (const result of results){
|
|
112
|
+
if (result.value !== undefined) {
|
|
113
|
+
newValues[result.slug] = result.value;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
setValues(newValues);
|
|
117
|
+
};
|
|
118
|
+
fetchAll().catch((err)=>{
|
|
119
|
+
//eslint-disable-next-line no-console
|
|
120
|
+
console.error('Error fetching badge data:', err);
|
|
121
|
+
});
|
|
122
|
+
}, [
|
|
123
|
+
badgesToFetch,
|
|
124
|
+
fetchBadge
|
|
125
|
+
]);
|
|
126
|
+
return /*#__PURE__*/ _jsx(BadgeProvider, {
|
|
127
|
+
values: values,
|
|
128
|
+
children: children
|
|
129
|
+
});
|
|
130
|
+
};
|
|
131
|
+
|
|
132
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../src/components/EnhancedSidebar/InternalBadgeProvider/index.tsx"],"sourcesContent":["'use client'\n\nimport { useConfig } from '@payloadcms/ui'\nimport { stringify } from 'qs-esm'\nimport React, { useCallback, useEffect, useMemo, useState } from 'react'\n\nimport type { BadgeConfig, BadgeValues, EnhancedSidebarConfig } from '../../../types'\n\nimport { BadgeProvider } from '../BadgeProvider'\n\ntype BadgeToFetch = {\n config: BadgeConfig\n slug: string\n}\n\nexport type InternalBadgeProviderProps = {\n children: React.ReactNode\n /**\n * Sidebar configuration containing badge configs\n */\n sidebarConfig: EnhancedSidebarConfig\n}\n\n/**\n * Internal provider that fetches all API-based badges once on mount.\n * This provider is automatically injected by the plugin.\n * Values are stored in context and don't refetch on navigation.\n */\nexport const InternalBadgeProvider: React.FC<InternalBadgeProviderProps> = ({\n children,\n sidebarConfig,\n}) => {\n const [values, setValues] = useState<BadgeValues>({})\n\n const {\n config: {\n routes: { api: apiRoute },\n serverURL,\n },\n } = useConfig()\n\n // Collect all badges that need to be fetched (api and collection-count types)\n const badgesToFetch = useMemo(() => {\n const badges: BadgeToFetch[] = []\n\n // From tabs\n if (sidebarConfig.tabs) {\n for (const tab of sidebarConfig.tabs) {\n if (tab.badge && tab.badge.type !== 'provider') {\n badges.push({ slug: tab.id, config: tab.badge })\n }\n }\n }\n\n // From badges config\n if (sidebarConfig.badges) {\n for (const [slug, config] of Object.entries(sidebarConfig.badges)) {\n if (config.type !== 'provider') {\n badges.push({ slug, config })\n }\n }\n }\n\n return badges\n }, [sidebarConfig])\n\n // Fetch a single badge value\n const fetchBadge = useCallback(\n async (badge: BadgeToFetch): Promise<{ slug: string; value: number | undefined }> => {\n const { slug, config } = badge\n\n try {\n let url: string\n let responseKey: string\n\n if (config.type === 'api') {\n url = config.endpoint\n responseKey = config.responseKey ?? 'count'\n\n // If endpoint is relative, prepend serverURL\n if (!url.startsWith('http')) {\n url = `${serverURL || ''}${url}`\n }\n } else if (config.type === 'collection-count') {\n const collectionSlug = config.collectionSlug ?? slug\n const baseUrl = `${serverURL || ''}${apiRoute}/${collectionSlug}`\n\n if (config.where) {\n const whereParams = stringify({\n where: config.where,\n })\n url = `${baseUrl}?${whereParams}`\n } else {\n url = `${baseUrl}`\n }\n\n responseKey = 'totalDocs'\n } else {\n return { slug, value: undefined }\n }\n\n const response = await fetch(url, {\n credentials: 'include',\n method: config.type === 'api' ? (config.method ?? 'GET') : 'GET',\n })\n\n if (response.ok) {\n const data = await response.json()\n // Extract value from nested key (e.g., \"data.count\")\n const keys = responseKey.split('.')\n let value = data\n for (const key of keys) {\n value = value?.[key]\n }\n return { slug, value: typeof value === 'number' ? value : undefined }\n }\n } catch (error) {\n //eslint-disable-next-line no-console\n console.error(`Failed to fetch badge data for ${slug}:`, error)\n }\n\n return { slug, value: undefined }\n },\n [apiRoute, serverURL],\n )\n\n // Fetch all badges on mount\n useEffect(() => {\n if (badgesToFetch.length === 0) {\n return\n }\n\n const fetchAll = async () => {\n const results = await Promise.all(badgesToFetch.map(fetchBadge))\n\n const newValues: BadgeValues = {}\n for (const result of results) {\n if (result.value !== undefined) {\n newValues[result.slug] = result.value\n }\n }\n\n setValues(newValues)\n }\n\n fetchAll().catch((err) => {\n //eslint-disable-next-line no-console\n console.error('Error fetching badge data:', err)\n })\n }, [badgesToFetch, fetchBadge])\n\n return <BadgeProvider values={values}>{children}</BadgeProvider>\n}\n"],"names":["useConfig","stringify","React","useCallback","useEffect","useMemo","useState","BadgeProvider","InternalBadgeProvider","children","sidebarConfig","values","setValues","config","routes","api","apiRoute","serverURL","badgesToFetch","badges","tabs","tab","badge","type","push","slug","id","Object","entries","fetchBadge","url","responseKey","endpoint","startsWith","collectionSlug","baseUrl","where","whereParams","value","undefined","response","fetch","credentials","method","ok","data","json","keys","split","key","error","console","length","fetchAll","results","Promise","all","map","newValues","result","catch","err"],"mappings":"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"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import type { BadgeConfig, ExtendedEntity } from '../../../types';
|
|
3
|
+
export type NavItemProps = {
|
|
4
|
+
badgeConfig?: BadgeConfig;
|
|
5
|
+
entity: ExtendedEntity;
|
|
6
|
+
href: string;
|
|
7
|
+
id: string;
|
|
8
|
+
isActive: boolean;
|
|
9
|
+
isCurrentPage: boolean;
|
|
10
|
+
};
|
|
11
|
+
export declare const NavItem: React.FC<NavItemProps>;
|