@bison-lab/payload-core 3.17.0 → 3.19.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 +71 -14
- package/dist/admin.d.mts +41 -4
- package/dist/admin.d.mts.map +1 -1
- package/dist/admin.mjs +265 -8
- package/dist/admin.mjs.map +1 -1
- package/dist/index.d.mts +113 -10
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +447 -9
- package/dist/index.mjs.map +1 -1
- package/dist/{looks-Dk0l0mif.d.mts → looks-CQ_DiSQO.d.mts} +1 -1
- package/dist/{looks-Dk0l0mif.d.mts.map → looks-CQ_DiSQO.d.mts.map} +1 -1
- package/dist/metadata.d.mts +1 -1
- package/dist/navigation.d.mts +2 -0
- package/dist/navigation.mjs +2 -0
- package/dist/published-ByS86dhW.mjs +43 -0
- package/dist/published-ByS86dhW.mjs.map +1 -0
- package/dist/published-C49gmzAL.d.mts +68 -0
- package/dist/published-C49gmzAL.d.mts.map +1 -0
- package/dist/theme.d.mts +1 -1
- package/dist/{title-B2-gWQZd.d.mts → title-sWwcCqHT.d.mts} +1 -1
- package/dist/{title-B2-gWQZd.d.mts.map → title-sWwcCqHT.d.mts.map} +1 -1
- package/package.json +5 -1
package/README.md
CHANGED
|
@@ -18,14 +18,15 @@ and `react` are needed for its admin fields; `@bison-lab/ui` and
|
|
|
18
18
|
Pin the plugin to the same version as `payload`; Payload releases them in
|
|
19
19
|
lockstep.
|
|
20
20
|
|
|
21
|
-
##
|
|
21
|
+
## Six entry points, and why
|
|
22
22
|
|
|
23
23
|
| Import | Contents | Runs where |
|
|
24
24
|
| ---------------------------------- | ------------------------------------------------------------------------------------------------ | -------------------------------------------------------------------------- |
|
|
25
|
-
| `@bison-lab/payload-core` | `seoPlugin`, `createTheme`, `createBrandAssets`, `createRoles`, `createFeatures`, `createPages`, `createUsers`, `createMedia`, `adminOnlyApiTab`, `documentTitleActions`, `seedTheme`, `seedRoles`, `seedFeatures`, predicates, `lookField`, `colorTokenField`, import-map strings, title and text helpers, types | Node. What `payload.config.ts` imports; it loads the plugin. |
|
|
25
|
+
| `@bison-lab/payload-core` | `seoPlugin`, `createTheme`, `createBrandAssets`, `createRoles`, `createFeatures`, `createPages`, `createUsers`, `createMedia`, `createAdminNav`, `adminNav`, `createNavigation`, `adminOnlyApiTab`, `documentTitleActions`, `seedTheme`, `seedRoles`, `seedFeatures`, predicates, `lookField`, `colorTokenField`, import-map strings, title and text helpers, types | Node. What `payload.config.ts` imports; it loads the plugin. |
|
|
26
26
|
| `@bison-lab/payload-core/metadata` | `pageMetadata`, the title helpers, the same types | Server. What a page route imports; it does not load the plugin. |
|
|
27
27
|
| `@bison-lab/payload-core/theme` | `getPublishedTheme`, `getPublishedIdentity`, `themeConfigFromDoc`, `themeHead`, `themeHeadFromDoc` | Server. What a root layout imports; it does not load the plugin or React. |
|
|
28
|
-
| `@bison-lab/payload-core/
|
|
28
|
+
| `@bison-lab/payload-core/navigation` | `getNavigation`, the Header and Footer slugs | Server. What a site header imports; it does not load the plugin or React. |
|
|
29
|
+
| `@bison-lab/payload-core/admin` | Theme fields, the Roles and Features matrices, Admin nav, and the Users Roles checklist | Admin. Referenced by import-map string; `generate:importmap` writes it. |
|
|
29
30
|
| `@bison-lab/payload-core/react` | `ThemePreview` (legacy; Theme has no preview pane) | Client. Kept so an older site import does not break. |
|
|
30
31
|
|
|
31
32
|
## What editors get
|
|
@@ -265,9 +266,11 @@ implicit — every catalogue feature, including ones not released. That
|
|
|
265
266
|
row is visible only to a Developer, with every tick on and locked.
|
|
266
267
|
Defaults ship in the package (Theme
|
|
267
268
|
screens on Designer; Designer also has Users and Roles; Admin + Designer
|
|
268
|
-
both store).
|
|
269
|
-
|
|
270
|
-
|
|
269
|
+
both store). An Admin may remove Admin, Designer, or Author after first
|
|
270
|
+
run; only Developer stays. A site may pass `extras` into `createRoles` —
|
|
271
|
+
each extra is a slug, a display label, and default `grants` — and an
|
|
272
|
+
Admin can add further custom rows and edit any row’s name. Remaining
|
|
273
|
+
seed slugs stay read-only.
|
|
271
274
|
`canManageBrand` and the other predicates read the saved Global and fall
|
|
272
275
|
back to that seed (plus extras). The package never writes `developer`
|
|
273
276
|
onto a user row.
|
|
@@ -288,8 +291,8 @@ assets), and Users (Users, Roles). Features itself is not a row. The
|
|
|
288
291
|
document API tab and Better Editor overlay settings are not rows either
|
|
289
292
|
— they stay code-locked to Developer (`adminOnlyApiTab`,
|
|
290
293
|
`developerOnlyAccess` / `hideUnlessDeveloper`). A site may pass `extras`
|
|
291
|
-
into `createFeatures` — those rows appear only there, including
|
|
292
|
-
|
|
294
|
+
into `createFeatures` — those rows appear only there, including the
|
|
295
|
+
Navigation tick `createNavigation` reads:
|
|
293
296
|
|
|
294
297
|
```ts
|
|
295
298
|
createFeatures({
|
|
@@ -298,10 +301,6 @@ createFeatures({
|
|
|
298
301
|
{ slug: "navigation", label: "Navigation" },
|
|
299
302
|
],
|
|
300
303
|
});
|
|
301
|
-
|
|
302
|
-
// On that Global:
|
|
303
|
-
// access: { update: canUseFeature("navigation") }
|
|
304
|
-
// Drafts use the same Publish tick as Pages to go live.
|
|
305
304
|
```
|
|
306
305
|
|
|
307
306
|
`canUseFeature(slug)` is true when the row is released and a held role
|
|
@@ -338,10 +337,67 @@ settings (Better Editor) take `developerOnlyAccess` and
|
|
|
338
337
|
`hideUnlessDeveloper` on the site — the package does not add that
|
|
339
338
|
plugin as a peer.
|
|
340
339
|
|
|
340
|
+
## Admin nav
|
|
341
|
+
|
|
342
|
+
Settings → Admin nav is Developer chrome, not a Features row. A Developer
|
|
343
|
+
adds, renames, deletes, and drags group headers and the collections or
|
|
344
|
+
globals under each. An Admin never opens the editor. Every login can read
|
|
345
|
+
the document so the sidebar can paint. Save writes immediately.
|
|
346
|
+
|
|
347
|
+
`adminNav()` sets `admin.components.Nav` to the package Nav. A consuming
|
|
348
|
+
site must not write a Nav component. An empty document falls back to
|
|
349
|
+
Payload's first-seen walk (collections, then globals, bucketed by
|
|
350
|
+
`admin.group`). `group: false` stays off the sidebar. `resolveAdminNav`
|
|
351
|
+
is the layout source so a later skin (SPI-10) does not invent a second
|
|
352
|
+
one.
|
|
353
|
+
|
|
354
|
+
```ts
|
|
355
|
+
import { adminNav, createAdminNav } from "@bison-lab/payload-core";
|
|
356
|
+
|
|
357
|
+
export default buildConfig({
|
|
358
|
+
plugins: [adminNav()],
|
|
359
|
+
globals: [createAdminNav(), createRoles(), createFeatures()],
|
|
360
|
+
});
|
|
361
|
+
```
|
|
362
|
+
|
|
363
|
+
Then `payload generate:importmap` and `payload migrate:create`.
|
|
364
|
+
|
|
365
|
+
## Header and Footer
|
|
366
|
+
|
|
367
|
+
`createNavigation({ blocks })` returns two Globals so each has its own
|
|
368
|
+
Save / Publish / drafts. Header keeps slug `navigation` and table `nav`
|
|
369
|
+
so an existing one-document row does not move. Footer is
|
|
370
|
+
`navigation-footer` / `navf` — short because nested footer arrays hit
|
|
371
|
+
Postgres's 63-character identifier cap the same way `nav` did. Both sit
|
|
372
|
+
in `admin.group: "Navigation"` until a Developer moves them from Admin
|
|
373
|
+
nav. One Features tick (`navigation`, passed as a `createFeatures`
|
|
374
|
+
extra). Publish still needs the Publish tick. `getNavigation({ payload,
|
|
375
|
+
draft })` finds both and returns `{ header, footer }`.
|
|
376
|
+
|
|
377
|
+
```ts
|
|
378
|
+
import { createNavigation } from "@bison-lab/payload-core";
|
|
379
|
+
import { getNavigation } from "@bison-lab/payload-core/navigation";
|
|
380
|
+
|
|
381
|
+
globals: [
|
|
382
|
+
...createNavigation({
|
|
383
|
+
blocks: [megaMenuBlock({ variants }), LinkBlock],
|
|
384
|
+
preview: () => "/preview",
|
|
385
|
+
}),
|
|
386
|
+
];
|
|
387
|
+
|
|
388
|
+
// In a site header — the /navigation entry keeps the SEO plugin off the layout.
|
|
389
|
+
const { header, footer } = await getNavigation({ payload, draft });
|
|
390
|
+
```
|
|
391
|
+
|
|
392
|
+
A site that already stored footer columns on the `nav` document copies
|
|
393
|
+
`footer.columns` onto the new global, then drops the footer fields from
|
|
394
|
+
`nav`. Bar behaviour (hide on scroll, viewport, default panel width) is
|
|
395
|
+
not this factory.
|
|
396
|
+
|
|
341
397
|
## No generated types
|
|
342
398
|
|
|
343
399
|
The package cannot import a site's `payload-types`, so the shapes it reads
|
|
344
|
-
(`SeoMeta`, `SeoImageDoc`, `SeoPage`, `ThemeDoc`, `RolesDoc`) are hand-written and
|
|
400
|
+
(`SeoMeta`, `SeoImageDoc`, `SeoPage`, `ThemeDoc`, `RolesDoc`, `AdminNavDoc`, `NavigationDoc`) are hand-written and
|
|
345
401
|
structural. A generated `Page`, `Media` or Theme Global is assignable to
|
|
346
402
|
them; nothing carries an index signature, since an interface will not assign
|
|
347
403
|
to a type that has one.
|
|
@@ -349,6 +405,7 @@ to a type that has one.
|
|
|
349
405
|
## Changing a field
|
|
350
406
|
|
|
351
407
|
`noIndexField`, the plugin's own fields, the Theme Global fields, the
|
|
352
|
-
Roles Global fields,
|
|
408
|
+
Roles Global fields, the Admin nav fields, the Header and Footer fields,
|
|
409
|
+
and the brand-assets collection fields are columns
|
|
353
410
|
in every consuming site. A change to them is a schema change: say "run
|
|
354
411
|
`payload migrate:create`" in the changeset.
|
package/dist/admin.d.mts
CHANGED
|
@@ -104,9 +104,9 @@ declare const LookField: TextFieldClientComponent;
|
|
|
104
104
|
//#endregion
|
|
105
105
|
//#region src/admin/roles-matrix-field.d.ts
|
|
106
106
|
/**
|
|
107
|
-
* Payload's array field: drag rank stays, add is for custom rows
|
|
108
|
-
*
|
|
109
|
-
*
|
|
107
|
+
* Payload's array field: drag rank stays, add is for custom rows.
|
|
108
|
+
* Developer has no remove, stays in the saved array, and is shown only
|
|
109
|
+
* to a Developer. Reset restores the package four and leaves extras.
|
|
110
110
|
*/
|
|
111
111
|
declare const RolesMatrixField: ArrayFieldClientComponent;
|
|
112
112
|
//#endregion
|
|
@@ -170,5 +170,42 @@ declare function DocumentCreateNew({
|
|
|
170
170
|
path: string;
|
|
171
171
|
}): react_jsx_runtime0.JSX.Element;
|
|
172
172
|
//#endregion
|
|
173
|
-
|
|
173
|
+
//#region src/admin-nav/types.d.ts
|
|
174
|
+
interface AdminNavVisibleEntities {
|
|
175
|
+
collections?: readonly string[];
|
|
176
|
+
globals?: readonly string[];
|
|
177
|
+
}
|
|
178
|
+
//#endregion
|
|
179
|
+
//#region src/admin/admin-nav.d.ts
|
|
180
|
+
interface AdminNavProps {
|
|
181
|
+
visibleEntities?: AdminNavVisibleEntities;
|
|
182
|
+
}
|
|
183
|
+
/**
|
|
184
|
+
* Default admin sidebar. Reads the Admin nav Global and paints
|
|
185
|
+
* `resolveAdminNav`. SPI-10 may replace this component; it should keep
|
|
186
|
+
* calling that function so the document stays the one layout source.
|
|
187
|
+
*/
|
|
188
|
+
declare function AdminNav({
|
|
189
|
+
visibleEntities
|
|
190
|
+
}: AdminNavProps): react_jsx_runtime0.JSX.Element;
|
|
191
|
+
//#endregion
|
|
192
|
+
//#region src/admin/admin-nav-row-label.d.ts
|
|
193
|
+
/**
|
|
194
|
+
* Array row header. Shows the group label, or “Group” when empty.
|
|
195
|
+
*/
|
|
196
|
+
declare function AdminNavRowLabel(): react_jsx_runtime0.JSX.Element;
|
|
197
|
+
//#endregion
|
|
198
|
+
//#region src/admin/admin-nav-entity-field.d.ts
|
|
199
|
+
/**
|
|
200
|
+
* A select of collections or globals from this site's config. Type on the
|
|
201
|
+
* sibling row decides which list. `group: false` stays off — those entities
|
|
202
|
+
* are not on the sidebar.
|
|
203
|
+
*/
|
|
204
|
+
declare function AdminNavEntityField({
|
|
205
|
+
path
|
|
206
|
+
}: {
|
|
207
|
+
path: string;
|
|
208
|
+
}): react_jsx_runtime0.JSX.Element;
|
|
209
|
+
//#endregion
|
|
210
|
+
export { AdminNav, AdminNavEntityField, AdminNavRowLabel, AppearanceField, ColorField, ColorScaleField, ContrastReport, DocumentCreateNew, DocumentTitleActions, FeaturesMatrixField, FontField, GreyScaleField, HiddenSaveButton, IdentityFallback, LibraryField, LookField, PairingField, PublishChild, RoleNameField, RoleSlugField, RolesField, RolesGrantsField, RolesMatrixField, RolesRowLabel, SectionHeading, ThemeDocumentControls, ThemeSaveButton };
|
|
174
211
|
//# sourceMappingURL=admin.d.mts.map
|
package/dist/admin.d.mts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"admin.d.mts","names":[],"sources":["../src/admin/color-field.tsx","../src/admin/color-scale-field.tsx","../src/admin/library-field.tsx","../src/admin/font-field.tsx","../src/admin/pairing-field.tsx","../src/admin/appearance-field.tsx","../src/admin/grey-scale-field.tsx","../src/admin/contrast-report.tsx","../src/admin/section-heading.tsx","../src/admin/publish-child.tsx","../src/admin/save-button.tsx","../src/admin/identity-fallback.tsx","../src/admin/look-field.tsx","../src/admin/roles-matrix-field.tsx","../src/admin/roles-row-label.tsx","../src/admin/role-slug-field.tsx","../src/admin/role-name-field.tsx","../src/admin/roles-field.tsx","../src/admin/roles-grants-field.tsx","../src/admin/features-matrix-field.tsx","../src/admin/document-title-actions.tsx","../src/admin/document-create-new.tsx"],"mappings":";;;;;;;;;;;cAWa,UAAA,EAAY,wBAAA;;;;;;;cCsBZ,eAAA,EAAiB,yBAAA;;;;;;;;;cCNjB,YAAA,EAAc,yBAAA;;;;;;;;;cCTd,SAAA,EAAW,0BAAA;;;;;;;cCNX,YAAA,EAAc,sBAAA;;;;;;;cCCd,eAAA,EAAiB,yBAAA;;;ALF9B;;;;AAAA,cMyDa,cAAA,EAAgB,0BAAA;;;;;;;cChDhB,cAAA,EAAgB,sBAAA;;;;;;cCbhB,cAAA,EAAgB,sBAAA;;;cCgJhB,YAAA,EAAc,sBAAA;;;;;;;;iBC3IX,qBAAA,CAAA,GAAqB,kBAAA,CAAA,GAAA,CAAA,OAAA;;AVDrC;;;iBUgBgB,eAAA,CAAA,GAAe,kBAAA,CAAA,GAAA,CAAA,OAAA;;iBA0Bf,gBAAA,CAAA,GAAgB,kBAAA,CAAA,GAAA,CAAA,OAAA;;;;;;;cC7CnB,gBAAA,EAAkB,sBAAA;;;;;;;cCIlB,SAAA,EAAW,wBAAA;;;;;;;;
|
|
1
|
+
{"version":3,"file":"admin.d.mts","names":[],"sources":["../src/admin/color-field.tsx","../src/admin/color-scale-field.tsx","../src/admin/library-field.tsx","../src/admin/font-field.tsx","../src/admin/pairing-field.tsx","../src/admin/appearance-field.tsx","../src/admin/grey-scale-field.tsx","../src/admin/contrast-report.tsx","../src/admin/section-heading.tsx","../src/admin/publish-child.tsx","../src/admin/save-button.tsx","../src/admin/identity-fallback.tsx","../src/admin/look-field.tsx","../src/admin/roles-matrix-field.tsx","../src/admin/roles-row-label.tsx","../src/admin/role-slug-field.tsx","../src/admin/role-name-field.tsx","../src/admin/roles-field.tsx","../src/admin/roles-grants-field.tsx","../src/admin/features-matrix-field.tsx","../src/admin/document-title-actions.tsx","../src/admin/document-create-new.tsx","../src/admin-nav/types.ts","../src/admin/admin-nav.tsx","../src/admin/admin-nav-row-label.tsx","../src/admin/admin-nav-entity-field.tsx"],"mappings":";;;;;;;;;;;cAWa,UAAA,EAAY,wBAAA;;;;;;;cCsBZ,eAAA,EAAiB,yBAAA;;;;;;;;;cCNjB,YAAA,EAAc,yBAAA;;;;;;;;;cCTd,SAAA,EAAW,0BAAA;;;;;;;cCNX,YAAA,EAAc,sBAAA;;;;;;;cCCd,eAAA,EAAiB,yBAAA;;;ALF9B;;;;AAAA,cMyDa,cAAA,EAAgB,0BAAA;;;;;;;cChDhB,cAAA,EAAgB,sBAAA;;;;;;cCbhB,cAAA,EAAgB,sBAAA;;;cCgJhB,YAAA,EAAc,sBAAA;;;;;;;;iBC3IX,qBAAA,CAAA,GAAqB,kBAAA,CAAA,GAAA,CAAA,OAAA;;AVDrC;;;iBUgBgB,eAAA,CAAA,GAAe,kBAAA,CAAA,GAAA,CAAA,OAAA;;iBA0Bf,gBAAA,CAAA,GAAgB,kBAAA,CAAA,GAAA,CAAA,OAAA;;;;;;;cC7CnB,gBAAA,EAAkB,sBAAA;;;;;;;cCIlB,SAAA,EAAW,wBAAA;;;;;;;;cCqBX,gBAAA,EAAkB,yBAAA;;;;;;iBC1Bf,aAAA,CAAA,GAAa,kBAAA,CAAA,GAAA,CAAA,OAAA;;;;;;cCChB,aAAA,EAAe,wBAAA;;;;;;;cCCf,aAAA,EAAe,wBAAA;;;;;;;;cC8Cf,UAAA,EAAY,0BAAA;;;;;;;;cChCZ,gBAAA,EAAkB,wBAAA;;;;;;;;;AlBZ/B;;cmB0Ca,mBAAA,EAAqB,yBAAA;;;iBCjBlB,oBAAA,CAAA;EAAuB;AAAA;EAAc,QAAA,GAAW,SAAA;AAAA,IAAW,kBAAA,CAAA,GAAA,CAAA,OAAA;;;iBCtB3D,iBAAA,CAAA;EAAoB;AAAA;EAAU,IAAA;AAAA,IAAc,kBAAA,CAAA,GAAA,CAAA,OAAA;;;UCmB3C,uBAAA;EACf,WAAA;EACA,OAAA;AAAA;;;UC5Be,aAAA;EACf,eAAA,GAAkB,uBAAA;AAAA;;;;AvBGpB;;iBuBsCgB,QAAA,CAAA;EAAW;AAAA,GAAmB,aAAA,GAAa,kBAAA,CAAA,GAAA,CAAA,OAAA;;;;;;iBC5C3C,gBAAA,CAAA,GAAgB,kBAAA,CAAA,GAAA,CAAA,OAAA;;;;;;;;iBCEhB,mBAAA,CAAA;EAAsB;AAAA;EAAU,IAAA;AAAA,IAAc,kBAAA,CAAA,GAAA,CAAA,OAAA"}
|
package/dist/admin.mjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { a as colorDocFromState, i as SYSTEM_COLOR_KEYS, n as pageEditorLooks, r as pageEditorTokens, s as stateFromColorDoc } from "./looks-BbL309kO.mjs";
|
|
3
|
-
import { ArrayField, Button, CheckboxInput, FieldDescription, FieldError, FieldLabel, fieldBaseClass, useAuth, useConfig, useField, useForm, useFormFields, useRowLabel } from "@payloadcms/ui";
|
|
3
|
+
import { ArrayField, Button, CheckboxInput, FieldDescription, FieldError, FieldLabel, Link, Logout, NavGroup, NavToggler, fieldBaseClass, useAuth, useConfig, useField, useForm, useFormFields, useNav, useRowLabel } from "@payloadcms/ui";
|
|
4
4
|
import { GREY_SCALES, SHADE_STEPS, contrastForeground, contrastRatio, createColorScale, deriveDarkPalette, deriveLightPalette, hexToHSL, hslToString, includedShadeSteps, isThemeHex, presetHints, setColorScaleInclude } from "@bison-lab/tokens";
|
|
5
5
|
import { useCallback, useEffect, useId, useLayoutEffect, useMemo, useRef, useState } from "react";
|
|
6
6
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
@@ -2737,7 +2737,7 @@ const DEFAULT_ROLE_MATRIX = ROLES.map((role) => ({
|
|
|
2737
2737
|
grants: defaultGrantsForRole(role)
|
|
2738
2738
|
}));
|
|
2739
2739
|
const DEVELOPER_DESCRIPTION = "Everything, including features not released for assignment.";
|
|
2740
|
-
const MISSING_SEED_ROLES_MESSAGE = "Roles must include Developer
|
|
2740
|
+
const MISSING_SEED_ROLES_MESSAGE = "Roles must include Developer.";
|
|
2741
2741
|
const DUPLICATE_ROLE_SLUG_MESSAGE = "Each role needs a unique slug.";
|
|
2742
2742
|
function uniqueSlugs(values) {
|
|
2743
2743
|
const slugs = [];
|
|
@@ -2805,7 +2805,7 @@ function parseRolesMatrix(value) {
|
|
|
2805
2805
|
seen.add(parsed.role);
|
|
2806
2806
|
rows.push(parsed);
|
|
2807
2807
|
}
|
|
2808
|
-
if (
|
|
2808
|
+
if (!seen.has("developer")) return {
|
|
2809
2809
|
ok: false,
|
|
2810
2810
|
message: MISSING_SEED_ROLES_MESSAGE
|
|
2811
2811
|
};
|
|
@@ -2847,7 +2847,7 @@ function seedRoleFromTrigger(trigger) {
|
|
|
2847
2847
|
let node = trigger.parentElement;
|
|
2848
2848
|
while (node) {
|
|
2849
2849
|
const slugs = node.querySelectorAll("[data-role-slug]");
|
|
2850
|
-
if (slugs.length === 1) return
|
|
2850
|
+
if (slugs.length === 1) return (slugs[0]?.getAttribute("data-role-seed") || slugs[0]?.getAttribute("data-role-slug")) === "developer";
|
|
2851
2851
|
if (slugs.length > 1) return false;
|
|
2852
2852
|
node = node.parentElement;
|
|
2853
2853
|
}
|
|
@@ -2859,9 +2859,9 @@ function viewerIsDeveloper(user) {
|
|
|
2859
2859
|
return Array.isArray(roles) && roles.includes("developer");
|
|
2860
2860
|
}
|
|
2861
2861
|
/**
|
|
2862
|
-
* Payload's array field: drag rank stays, add is for custom rows
|
|
2863
|
-
*
|
|
2864
|
-
*
|
|
2862
|
+
* Payload's array field: drag rank stays, add is for custom rows.
|
|
2863
|
+
* Developer has no remove, stays in the saved array, and is shown only
|
|
2864
|
+
* to a Developer. Reset restores the package four and leaves extras.
|
|
2865
2865
|
*/
|
|
2866
2866
|
const RolesMatrixField = (props) => {
|
|
2867
2867
|
const { setValue, value } = useField({ path: props.path });
|
|
@@ -3395,6 +3395,263 @@ function DocumentCreateNew({ path }) {
|
|
|
3395
3395
|
})] });
|
|
3396
3396
|
}
|
|
3397
3397
|
//#endregion
|
|
3398
|
-
|
|
3398
|
+
//#region src/admin-nav/types.ts
|
|
3399
|
+
/**
|
|
3400
|
+
* Developer-owned admin sidebar. SPI-10 skins this with AppSidebarBlock;
|
|
3401
|
+
* this package ships the document and the default Nav. A consuming site
|
|
3402
|
+
* waits for SPI-97 after this and BIS-110 publish.
|
|
3403
|
+
*/
|
|
3404
|
+
const ADMIN_NAV_SLUG = "admin-nav";
|
|
3405
|
+
//#endregion
|
|
3406
|
+
//#region src/admin-nav/resolve.ts
|
|
3407
|
+
function sidebarGroup(group) {
|
|
3408
|
+
if (group === false) return false;
|
|
3409
|
+
if (typeof group === "string") return group;
|
|
3410
|
+
return "";
|
|
3411
|
+
}
|
|
3412
|
+
function asLabel(value, fallback) {
|
|
3413
|
+
return typeof value === "string" && value ? value : fallback;
|
|
3414
|
+
}
|
|
3415
|
+
function entityLabel(entity, type) {
|
|
3416
|
+
if (type === "collection") return asLabel(entity.labels?.plural, asLabel(entity.labels?.singular, entity.slug));
|
|
3417
|
+
return asLabel(entity.label, entity.slug);
|
|
3418
|
+
}
|
|
3419
|
+
function keyOf(type, slug) {
|
|
3420
|
+
return `${type}:${slug}`;
|
|
3421
|
+
}
|
|
3422
|
+
function catalog(config) {
|
|
3423
|
+
const collections = (config.collections ?? []).map((entity) => ({
|
|
3424
|
+
type: "collection",
|
|
3425
|
+
slug: entity.slug,
|
|
3426
|
+
label: entityLabel(entity, "collection"),
|
|
3427
|
+
group: sidebarGroup(entity.admin?.group)
|
|
3428
|
+
}));
|
|
3429
|
+
const globals = (config.globals ?? []).map((entity) => ({
|
|
3430
|
+
type: "global",
|
|
3431
|
+
slug: entity.slug,
|
|
3432
|
+
label: entityLabel(entity, "global"),
|
|
3433
|
+
group: sidebarGroup(entity.admin?.group)
|
|
3434
|
+
}));
|
|
3435
|
+
return [...collections, ...globals];
|
|
3436
|
+
}
|
|
3437
|
+
function defaultGroups(entities) {
|
|
3438
|
+
const groups = [];
|
|
3439
|
+
for (const entity of entities) {
|
|
3440
|
+
if (entity.group === false) continue;
|
|
3441
|
+
let group = groups.find((entry) => entry.label === entity.group);
|
|
3442
|
+
if (!group) {
|
|
3443
|
+
group = {
|
|
3444
|
+
label: entity.group,
|
|
3445
|
+
items: []
|
|
3446
|
+
};
|
|
3447
|
+
groups.push(group);
|
|
3448
|
+
}
|
|
3449
|
+
group.items.push({
|
|
3450
|
+
type: entity.type,
|
|
3451
|
+
slug: entity.slug,
|
|
3452
|
+
label: entity.label
|
|
3453
|
+
});
|
|
3454
|
+
}
|
|
3455
|
+
return groups;
|
|
3456
|
+
}
|
|
3457
|
+
function itemFromSaved(item, byKey) {
|
|
3458
|
+
const type = item.type === "global" || item.type === "collection" ? item.type : null;
|
|
3459
|
+
const slug = typeof item.slug === "string" ? item.slug : "";
|
|
3460
|
+
if (!type || !slug) return null;
|
|
3461
|
+
const entity = byKey.get(keyOf(type, slug));
|
|
3462
|
+
if (!entity || entity.group === false) return null;
|
|
3463
|
+
return {
|
|
3464
|
+
type,
|
|
3465
|
+
slug,
|
|
3466
|
+
label: entity.label
|
|
3467
|
+
};
|
|
3468
|
+
}
|
|
3469
|
+
function fromDocument(doc, entities) {
|
|
3470
|
+
const byKey = new Map(entities.map((entity) => [keyOf(entity.type, entity.slug), entity]));
|
|
3471
|
+
const groups = (doc.groups ?? []).map((row) => ({
|
|
3472
|
+
label: typeof row.label === "string" ? row.label : "",
|
|
3473
|
+
items: (row.items ?? []).flatMap((item) => {
|
|
3474
|
+
const resolved = itemFromSaved(item ?? {}, byKey);
|
|
3475
|
+
return resolved ? [resolved] : [];
|
|
3476
|
+
})
|
|
3477
|
+
}));
|
|
3478
|
+
const seen = new Set(groups.flatMap((group) => group.items.map((item) => keyOf(item.type, item.slug))));
|
|
3479
|
+
for (const entity of entities) {
|
|
3480
|
+
if (entity.group === false) continue;
|
|
3481
|
+
const key = keyOf(entity.type, entity.slug);
|
|
3482
|
+
if (seen.has(key)) continue;
|
|
3483
|
+
let group = groups.find((entry) => entry.label === entity.group);
|
|
3484
|
+
if (!group) {
|
|
3485
|
+
group = {
|
|
3486
|
+
label: entity.group,
|
|
3487
|
+
items: []
|
|
3488
|
+
};
|
|
3489
|
+
groups.push(group);
|
|
3490
|
+
}
|
|
3491
|
+
group.items.push({
|
|
3492
|
+
type: entity.type,
|
|
3493
|
+
slug: entity.slug,
|
|
3494
|
+
label: entity.label
|
|
3495
|
+
});
|
|
3496
|
+
seen.add(key);
|
|
3497
|
+
}
|
|
3498
|
+
return groups;
|
|
3499
|
+
}
|
|
3500
|
+
/**
|
|
3501
|
+
* Layout for the package Nav (and later SPI-10). Permissions are
|
|
3502
|
+
* `visibleEntities` — this function does not re-derive access.
|
|
3503
|
+
*/
|
|
3504
|
+
function resolveAdminNav({ config, doc, visibleEntities }) {
|
|
3505
|
+
const entities = catalog(config);
|
|
3506
|
+
const saved = Array.isArray(doc?.groups) ? doc.groups : [];
|
|
3507
|
+
let groups = saved.length === 0 ? defaultGroups(entities) : fromDocument({ groups: saved }, entities);
|
|
3508
|
+
if (visibleEntities) {
|
|
3509
|
+
const collections = new Set(visibleEntities.collections ?? []);
|
|
3510
|
+
const globals = new Set(visibleEntities.globals ?? []);
|
|
3511
|
+
groups = groups.map((group) => ({
|
|
3512
|
+
...group,
|
|
3513
|
+
items: group.items.filter((item) => item.type === "collection" ? collections.has(item.slug) : globals.has(item.slug))
|
|
3514
|
+
}));
|
|
3515
|
+
}
|
|
3516
|
+
return groups;
|
|
3517
|
+
}
|
|
3518
|
+
//#endregion
|
|
3519
|
+
//#region src/admin/admin-nav.tsx
|
|
3520
|
+
const BASE = "nav";
|
|
3521
|
+
function isAbortError(error) {
|
|
3522
|
+
return error instanceof DOMException ? error.name === "AbortError" : error instanceof Error && error.name === "AbortError";
|
|
3523
|
+
}
|
|
3524
|
+
/**
|
|
3525
|
+
* Payload's DefaultNav roots in an `@internal` NavWrapper. Copy the
|
|
3526
|
+
* class contract here — this package does not depend on `@payloadcms/next`.
|
|
3527
|
+
* Without `nav--nav-open`, Payload's CSS keeps `.nav` at opacity 0.
|
|
3528
|
+
*/
|
|
3529
|
+
function AdminNavShell({ children }) {
|
|
3530
|
+
const { hydrated, navOpen, navRef, shouldAnimate } = useNav();
|
|
3531
|
+
return /* @__PURE__ */ jsx("aside", {
|
|
3532
|
+
className: [
|
|
3533
|
+
BASE,
|
|
3534
|
+
navOpen && `${BASE}--nav-open`,
|
|
3535
|
+
shouldAnimate && `${BASE}--nav-animate`,
|
|
3536
|
+
hydrated && `${BASE}--nav-hydrated`
|
|
3537
|
+
].filter(Boolean).join(" "),
|
|
3538
|
+
inert: navOpen ? void 0 : true,
|
|
3539
|
+
children: /* @__PURE__ */ jsx("div", {
|
|
3540
|
+
className: `${BASE}__scroll`,
|
|
3541
|
+
ref: navRef,
|
|
3542
|
+
children
|
|
3543
|
+
})
|
|
3544
|
+
});
|
|
3545
|
+
}
|
|
3546
|
+
/**
|
|
3547
|
+
* Default admin sidebar. Reads the Admin nav Global and paints
|
|
3548
|
+
* `resolveAdminNav`. SPI-10 may replace this component; it should keep
|
|
3549
|
+
* calling that function so the document stays the one layout source.
|
|
3550
|
+
*/
|
|
3551
|
+
function AdminNav({ visibleEntities }) {
|
|
3552
|
+
const { config } = useConfig();
|
|
3553
|
+
const [doc, setDoc] = useState(null);
|
|
3554
|
+
const adminRoute = config.routes.admin ?? "/admin";
|
|
3555
|
+
const apiRoute = config.routes.api ?? "/api";
|
|
3556
|
+
useEffect(() => {
|
|
3557
|
+
const controller = new AbortController();
|
|
3558
|
+
const url = `${config.serverURL ?? ""}${apiRoute}/globals/${ADMIN_NAV_SLUG}`;
|
|
3559
|
+
fetch(url, {
|
|
3560
|
+
credentials: "include",
|
|
3561
|
+
signal: controller.signal
|
|
3562
|
+
}).then((response) => response.ok ? response.json() : null).then((payload) => {
|
|
3563
|
+
if (controller.signal.aborted) return;
|
|
3564
|
+
setDoc(payload);
|
|
3565
|
+
}).catch((error) => {
|
|
3566
|
+
if (isAbortError(error) || controller.signal.aborted) return;
|
|
3567
|
+
setDoc(null);
|
|
3568
|
+
});
|
|
3569
|
+
return () => controller.abort();
|
|
3570
|
+
}, [apiRoute, config.serverURL]);
|
|
3571
|
+
const groups = useMemo(() => resolveAdminNav({
|
|
3572
|
+
config,
|
|
3573
|
+
doc,
|
|
3574
|
+
visibleEntities
|
|
3575
|
+
}), [
|
|
3576
|
+
config,
|
|
3577
|
+
doc,
|
|
3578
|
+
visibleEntities
|
|
3579
|
+
]);
|
|
3580
|
+
return /* @__PURE__ */ jsxs(AdminNavShell, { children: [/* @__PURE__ */ jsxs("nav", {
|
|
3581
|
+
className: `${BASE}__wrap`,
|
|
3582
|
+
"aria-label": "Admin",
|
|
3583
|
+
children: [/* @__PURE__ */ jsx("div", {
|
|
3584
|
+
className: `${BASE}__links`,
|
|
3585
|
+
children: groups.map((group, index) => {
|
|
3586
|
+
const items = group.items.map((item) => {
|
|
3587
|
+
return /* @__PURE__ */ jsx(Link, {
|
|
3588
|
+
href: item.type === "collection" ? `${adminRoute}/collections/${item.slug}` : `${adminRoute}/globals/${item.slug}`,
|
|
3589
|
+
className: `${BASE}__link`,
|
|
3590
|
+
children: item.label
|
|
3591
|
+
}, `${item.type}:${item.slug}`);
|
|
3592
|
+
});
|
|
3593
|
+
if (!group.label) return /* @__PURE__ */ jsx("div", {
|
|
3594
|
+
className: `${BASE}__ungrouped`,
|
|
3595
|
+
children: items
|
|
3596
|
+
}, `ungrouped-${index}`);
|
|
3597
|
+
return /* @__PURE__ */ jsx(NavGroup, {
|
|
3598
|
+
label: group.label,
|
|
3599
|
+
children: items
|
|
3600
|
+
}, `${group.label}-${index}`);
|
|
3601
|
+
})
|
|
3602
|
+
}), /* @__PURE__ */ jsx("div", {
|
|
3603
|
+
className: `${BASE}__controls`,
|
|
3604
|
+
children: /* @__PURE__ */ jsx(Logout, {})
|
|
3605
|
+
})]
|
|
3606
|
+
}), /* @__PURE__ */ jsx("div", {
|
|
3607
|
+
className: `${BASE}__header`,
|
|
3608
|
+
children: /* @__PURE__ */ jsx("div", {
|
|
3609
|
+
className: `${BASE}__header-content`,
|
|
3610
|
+
children: /* @__PURE__ */ jsx(NavToggler, {})
|
|
3611
|
+
})
|
|
3612
|
+
})] });
|
|
3613
|
+
}
|
|
3614
|
+
//#endregion
|
|
3615
|
+
//#region src/admin/admin-nav-row-label.tsx
|
|
3616
|
+
/**
|
|
3617
|
+
* Array row header. Shows the group label, or “Group” when empty.
|
|
3618
|
+
*/
|
|
3619
|
+
function AdminNavRowLabel() {
|
|
3620
|
+
const { data } = useRowLabel();
|
|
3621
|
+
return /* @__PURE__ */ jsx("span", { children: typeof data.label === "string" && data.label.trim() ? data.label.trim() : "Group" });
|
|
3622
|
+
}
|
|
3623
|
+
//#endregion
|
|
3624
|
+
//#region src/admin/admin-nav-entity-field.tsx
|
|
3625
|
+
/**
|
|
3626
|
+
* A select of collections or globals from this site's config. Type on the
|
|
3627
|
+
* sibling row decides which list. `group: false` stays off — those entities
|
|
3628
|
+
* are not on the sidebar.
|
|
3629
|
+
*/
|
|
3630
|
+
function AdminNavEntityField({ path }) {
|
|
3631
|
+
const { value, setValue } = useField({ path });
|
|
3632
|
+
const { getDataByPath } = useForm();
|
|
3633
|
+
const type = getDataByPath(path.replace(/\.slug$/, ".type"));
|
|
3634
|
+
const { config } = useConfig();
|
|
3635
|
+
const options = type === "global" ? (config.globals ?? []).filter((entity) => entity.admin?.group !== false).map((entity) => ({
|
|
3636
|
+
value: entity.slug,
|
|
3637
|
+
label: typeof entity.label === "string" ? entity.label : entity.slug
|
|
3638
|
+
})) : (config.collections ?? []).filter((entity) => entity.admin?.group !== false).map((entity) => ({
|
|
3639
|
+
value: entity.slug,
|
|
3640
|
+
label: typeof entity.labels?.plural === "string" ? entity.labels.plural : entity.slug
|
|
3641
|
+
}));
|
|
3642
|
+
return /* @__PURE__ */ jsxs("label", { children: ["Slug", /* @__PURE__ */ jsxs("select", {
|
|
3643
|
+
value: typeof value === "string" ? value : "",
|
|
3644
|
+
onChange: (event) => setValue(event.target.value),
|
|
3645
|
+
children: [/* @__PURE__ */ jsx("option", {
|
|
3646
|
+
value: "",
|
|
3647
|
+
children: "Select…"
|
|
3648
|
+
}), options.map((option) => /* @__PURE__ */ jsx("option", {
|
|
3649
|
+
value: option.value,
|
|
3650
|
+
children: option.label
|
|
3651
|
+
}, option.value))]
|
|
3652
|
+
})] });
|
|
3653
|
+
}
|
|
3654
|
+
//#endregion
|
|
3655
|
+
export { AdminNav, AdminNavEntityField, AdminNavRowLabel, AppearanceField, ColorField, ColorScaleField, ContrastReport, DocumentCreateNew, DocumentTitleActions, FeaturesMatrixField, FontField, GreyScaleField, HiddenSaveButton, IdentityFallback, LibraryField, LookField, PairingField, PublishChild, RoleNameField, RoleSlugField, RolesField, RolesGrantsField, RolesMatrixField, RolesRowLabel, SectionHeading, ThemeDocumentControls, ThemeSaveButton };
|
|
3399
3656
|
|
|
3400
3657
|
//# sourceMappingURL=admin.mjs.map
|