@vitrailweb/payload-plugin-home-nav 0.1.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 +70 -0
- package/dist/exports/rsc.d.ts +43 -0
- package/dist/exports/rsc.js +84 -0
- package/dist/exports/rsc.js.map +1 -0
- package/dist/index.d.ts +49 -0
- package/dist/index.js +51 -0
- package/dist/index.js.map +1 -0
- package/package.json +58 -0
package/README.md
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
# @vitrailweb/payload-plugin-home-nav
|
|
2
|
+
|
|
3
|
+
A [Payload CMS](https://payloadcms.com) plugin that makes the admin's way home
|
|
4
|
+
obvious:
|
|
5
|
+
|
|
6
|
+
- a translated **"Home" label next to the icon** in the app header (the
|
|
7
|
+
`admin.components.graphics.Icon` slot — the step-nav already links it to the
|
|
8
|
+
dashboard), and
|
|
9
|
+
- a **"Home" link at the top of the collapsible nav sidebar** (prepended to
|
|
10
|
+
`admin.components.beforeNavLinks`, styled like the built-in nav links).
|
|
11
|
+
|
|
12
|
+
Both are **server components** resolved against the admin language. The label
|
|
13
|
+
defaults to the plugin's bundled translations ("Home" / "Accueil") and can be
|
|
14
|
+
overridden with a plain string or a per-language record. A custom icon the
|
|
15
|
+
project already configured through `admin.components.graphics.Icon` is kept
|
|
16
|
+
and rendered next to the label.
|
|
17
|
+
|
|
18
|
+
## Usage
|
|
19
|
+
|
|
20
|
+
```ts
|
|
21
|
+
import { buildConfig } from 'payload'
|
|
22
|
+
import { VWPayloadPluginHomeNav } from '@vitrailweb/payload-plugin-home-nav'
|
|
23
|
+
|
|
24
|
+
export default buildConfig({
|
|
25
|
+
plugins: [
|
|
26
|
+
VWPayloadPluginHomeNav(),
|
|
27
|
+
],
|
|
28
|
+
// ...
|
|
29
|
+
})
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
Point "Home" somewhere else (e.g. the public site) or change the label:
|
|
33
|
+
|
|
34
|
+
```ts
|
|
35
|
+
VWPayloadPluginHomeNav({
|
|
36
|
+
href: '/',
|
|
37
|
+
label: { en: 'Back to site', fr: 'Retour au site' },
|
|
38
|
+
})
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
> Registers admin components, so run `payload generate:importmap` after adding
|
|
42
|
+
> the plugin.
|
|
43
|
+
|
|
44
|
+
## Options
|
|
45
|
+
|
|
46
|
+
| Option | Type | Notes |
|
|
47
|
+
| ----------- | --------------- | ------------------------------------------------------------------------------------------ |
|
|
48
|
+
| `href` | `string` | where the nav-sidebar "Home" link points. Default: the admin dashboard (`routes.admin`) |
|
|
49
|
+
| `label` | `LocalizedText` | the label, plain or per-language. Default: "Home" / "Accueil" from the bundled translations |
|
|
50
|
+
| `iconLabel` | `boolean` | show the label next to the app-header icon (default `true`) |
|
|
51
|
+
| `navLink` | `boolean` | add the link at the top of the nav sidebar (default `true`) |
|
|
52
|
+
| `disabled` | `boolean` | leaves the config untouched |
|
|
53
|
+
|
|
54
|
+
`LocalizedText` is `string | Record<string, string>` — a per-language record
|
|
55
|
+
is resolved as: exact admin-language match, then `en`, then the first value.
|
|
56
|
+
|
|
57
|
+
## Development
|
|
58
|
+
|
|
59
|
+
From the monorepo root:
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
pnpm install
|
|
63
|
+
pnpm generate:importmap:home-nav # register the components
|
|
64
|
+
pnpm dev:home-nav # dev Payload app with this plugin
|
|
65
|
+
pnpm vitest run packages/payload-plugin-home-nav/test # unit tests
|
|
66
|
+
pnpm vitest run dev/configs/home-nav # integration tests
|
|
67
|
+
pnpm --filter @vitrailweb/payload-plugin-home-nav build # build to dist/
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
See the [root README](../../README.md) for the release flow.
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
+
import { ServerProps, PayloadComponent } from 'payload';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* A plain string, or a per-language record keyed by admin language code
|
|
6
|
+
* (e.g. `{ en: 'Home', fr: 'Accueil' }`).
|
|
7
|
+
*/
|
|
8
|
+
type LocalizedText = string | Record<string, string>;
|
|
9
|
+
|
|
10
|
+
type HomeNavIconProps = ServerProps & {
|
|
11
|
+
/**
|
|
12
|
+
* The `admin.components.graphics.Icon` the project had configured before
|
|
13
|
+
* the plugin took the slot over — re-rendered next to the label so custom
|
|
14
|
+
* icons keep working. Default: Payload's own icon.
|
|
15
|
+
*/
|
|
16
|
+
icon?: PayloadComponent;
|
|
17
|
+
/** Label override from the plugin options, plain or per-language. */
|
|
18
|
+
label?: LocalizedText;
|
|
19
|
+
};
|
|
20
|
+
/**
|
|
21
|
+
* Server component for the `admin.components.graphics.Icon` slot: the
|
|
22
|
+
* project's icon (custom `graphics.Icon` if one was configured, Payload's
|
|
23
|
+
* icon otherwise) with a translated "Home" label next to it. The step-nav
|
|
24
|
+
* already wraps this slot in a link to the admin dashboard, so the label
|
|
25
|
+
* needs no link of its own.
|
|
26
|
+
*/
|
|
27
|
+
declare const HomeNavIcon: ({ i18n, icon, label, payload, ...serverProps }: HomeNavIconProps) => react_jsx_runtime.JSX.Element;
|
|
28
|
+
|
|
29
|
+
type HomeNavLinkProps = ServerProps & {
|
|
30
|
+
/** Destination from the plugin options. Default: the admin dashboard. */
|
|
31
|
+
href?: string;
|
|
32
|
+
/** Label override from the plugin options, plain or per-language. */
|
|
33
|
+
label?: LocalizedText;
|
|
34
|
+
};
|
|
35
|
+
/**
|
|
36
|
+
* Server component for the `admin.components.beforeNavLinks` slot: a "Home"
|
|
37
|
+
* link rendered above the collection/global links of the nav sidebar. It
|
|
38
|
+
* reuses the nav's own `nav__link` classes so it looks like the built-in
|
|
39
|
+
* links, and @payloadcms/ui's Link so navigation stays client-side.
|
|
40
|
+
*/
|
|
41
|
+
declare const HomeNavLink: ({ href, i18n, label, payload }: HomeNavLinkProps) => react_jsx_runtime.JSX.Element;
|
|
42
|
+
|
|
43
|
+
export { HomeNavIcon, HomeNavLink };
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
// src/components/HomeNavIcon.tsx
|
|
2
|
+
import { PayloadIcon } from "@payloadcms/ui";
|
|
3
|
+
import { RenderServerComponent } from "@payloadcms/ui/elements/RenderServerComponent";
|
|
4
|
+
|
|
5
|
+
// src/localized.ts
|
|
6
|
+
var resolveLocalizedText = (text, language) => {
|
|
7
|
+
if (text === void 0 || typeof text === "string") {
|
|
8
|
+
return text;
|
|
9
|
+
}
|
|
10
|
+
return text[language] ?? text.en ?? Object.values(text)[0];
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
// src/translations/en.ts
|
|
14
|
+
var en = {
|
|
15
|
+
homeNav: {
|
|
16
|
+
home: "Home"
|
|
17
|
+
}
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
// src/translations/fr.ts
|
|
21
|
+
var fr = {
|
|
22
|
+
homeNav: {
|
|
23
|
+
home: "Accueil"
|
|
24
|
+
}
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
// src/label.ts
|
|
28
|
+
var translations = { en, fr };
|
|
29
|
+
var resolveHomeLabel = (label, language) => resolveLocalizedText(label, language) ?? (translations[language] ?? en).homeNav.home;
|
|
30
|
+
|
|
31
|
+
// src/components/HomeNavIcon.tsx
|
|
32
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
33
|
+
var iconStyles = `
|
|
34
|
+
.home-nav-icon > style {
|
|
35
|
+
display: none;
|
|
36
|
+
}
|
|
37
|
+
.step-nav__home:has(.home-nav-icon) {
|
|
38
|
+
width: auto;
|
|
39
|
+
height: auto;
|
|
40
|
+
}
|
|
41
|
+
.home-nav-icon {
|
|
42
|
+
display: flex;
|
|
43
|
+
align-items: center;
|
|
44
|
+
gap: 8px;
|
|
45
|
+
line-height: 1;
|
|
46
|
+
}
|
|
47
|
+
.home-nav-icon__icon {
|
|
48
|
+
display: block;
|
|
49
|
+
width: 18px;
|
|
50
|
+
height: 18px;
|
|
51
|
+
flex-shrink: 0;
|
|
52
|
+
}
|
|
53
|
+
.home-nav-icon__label {
|
|
54
|
+
font-weight: 600;
|
|
55
|
+
}
|
|
56
|
+
`;
|
|
57
|
+
var HomeNavIcon = ({ i18n, icon, label, payload, ...serverProps }) => {
|
|
58
|
+
const text = resolveHomeLabel(label, i18n?.language ?? "en");
|
|
59
|
+
const Icon = RenderServerComponent({
|
|
60
|
+
Component: icon,
|
|
61
|
+
Fallback: PayloadIcon,
|
|
62
|
+
importMap: payload?.importMap,
|
|
63
|
+
serverProps: { ...serverProps, i18n, payload }
|
|
64
|
+
});
|
|
65
|
+
return /* @__PURE__ */ jsxs("span", { className: "home-nav-icon", children: [
|
|
66
|
+
/* @__PURE__ */ jsx("style", { children: iconStyles }),
|
|
67
|
+
/* @__PURE__ */ jsx("span", { className: "home-nav-icon__icon", children: Icon }),
|
|
68
|
+
/* @__PURE__ */ jsx("span", { className: "home-nav-icon__label", children: text })
|
|
69
|
+
] });
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
// src/components/HomeNavLink.tsx
|
|
73
|
+
import { Link } from "@payloadcms/ui";
|
|
74
|
+
import { jsx as jsx2 } from "react/jsx-runtime";
|
|
75
|
+
var HomeNavLink = ({ href, i18n, label, payload }) => {
|
|
76
|
+
const text = resolveHomeLabel(label, i18n?.language ?? "en");
|
|
77
|
+
const url = href ?? payload?.config?.routes?.admin ?? "/admin";
|
|
78
|
+
return /* @__PURE__ */ jsx2(Link, { className: "nav__link", href: url, id: "nav-home", prefetch: false, children: /* @__PURE__ */ jsx2("span", { className: "nav__link-label", children: text }) });
|
|
79
|
+
};
|
|
80
|
+
export {
|
|
81
|
+
HomeNavIcon,
|
|
82
|
+
HomeNavLink
|
|
83
|
+
};
|
|
84
|
+
//# sourceMappingURL=rsc.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/components/HomeNavIcon.tsx","../../src/localized.ts","../../src/translations/en.ts","../../src/translations/fr.ts","../../src/label.ts","../../src/components/HomeNavLink.tsx"],"sourcesContent":["import type { PayloadComponent, ServerProps } from 'payload'\n\nimport { PayloadIcon } from '@payloadcms/ui'\nimport { RenderServerComponent } from '@payloadcms/ui/elements/RenderServerComponent'\nimport React from 'react'\n\nimport type { LocalizedText } from '../localized.js'\n\nimport { resolveHomeLabel } from '../label.js'\n\n/**\n * The step-nav fixes its home link to 18px x 18px (icon-only), which would\n * clip the label — un-fix it when this component is inside. These rules are\n * unlayered, so they win over Payload's `@layer payload-default` styles.\n * The icon gets its own 18px box instead (PayloadIcon is width/height 100%).\n * The step-nav also sets `* { display: block }`, which beats the browser's\n * `style { display: none }` and would render this CSS as text — hide it back.\n */\nconst iconStyles = `\n.home-nav-icon > style {\n display: none;\n}\n.step-nav__home:has(.home-nav-icon) {\n width: auto;\n height: auto;\n}\n.home-nav-icon {\n display: flex;\n align-items: center;\n gap: 8px;\n line-height: 1;\n}\n.home-nav-icon__icon {\n display: block;\n width: 18px;\n height: 18px;\n flex-shrink: 0;\n}\n.home-nav-icon__label {\n font-weight: 600;\n}\n`\n\nexport type HomeNavIconProps = ServerProps & {\n /**\n * The `admin.components.graphics.Icon` the project had configured before\n * the plugin took the slot over — re-rendered next to the label so custom\n * icons keep working. Default: Payload's own icon.\n */\n icon?: PayloadComponent\n /** Label override from the plugin options, plain or per-language. */\n label?: LocalizedText\n}\n\n/**\n * Server component for the `admin.components.graphics.Icon` slot: the\n * project's icon (custom `graphics.Icon` if one was configured, Payload's\n * icon otherwise) with a translated \"Home\" label next to it. The step-nav\n * already wraps this slot in a link to the admin dashboard, so the label\n * needs no link of its own.\n */\nexport const HomeNavIcon = ({ i18n, icon, label, payload, ...serverProps }: HomeNavIconProps) => {\n const text = resolveHomeLabel(label, i18n?.language ?? 'en')\n\n const Icon = RenderServerComponent({\n Component: icon,\n Fallback: PayloadIcon,\n importMap: payload?.importMap,\n serverProps: { ...serverProps, i18n, payload },\n })\n\n return (\n <span className=\"home-nav-icon\">\n <style>{iconStyles}</style>\n <span className=\"home-nav-icon__icon\">{Icon}</span>\n <span className=\"home-nav-icon__label\">{text}</span>\n </span>\n )\n}\n","/**\n * A plain string, or a per-language record keyed by admin language code\n * (e.g. `{ en: 'Home', fr: 'Accueil' }`).\n */\nexport type LocalizedText = string | Record<string, string>\n\n/**\n * Resolves a `LocalizedText` for the current admin language: exact language\n * match first, then `en`, then the first value in the record.\n */\nexport const resolveLocalizedText = (\n text: LocalizedText | undefined,\n language: string,\n): string | undefined => {\n if (text === undefined || typeof text === 'string') {\n return text\n }\n\n return text[language] ?? text.en ?? Object.values(text)[0]\n}\n","export const en = {\n homeNav: {\n home: 'Home',\n },\n}\n","import type { Translation } from './index.js'\n\nexport const fr: Translation = {\n homeNav: {\n home: 'Accueil',\n },\n}\n","import type { LocalizedText } from './localized.js'\nimport type { Translation } from './translations/index.js'\n\nimport { resolveLocalizedText } from './localized.js'\nimport { en } from './translations/en.js'\nimport { fr } from './translations/fr.js'\n\nconst translations: Record<string, Translation> = { en, fr }\n\n/**\n * Resolves the \"Home\" label for the current admin language: the `label`\n * plugin option when set, otherwise the plugin's bundled translations.\n */\nexport const resolveHomeLabel = (\n label: LocalizedText | undefined,\n language: string,\n): string => resolveLocalizedText(label, language) ?? (translations[language] ?? en).homeNav.home\n","import type { ServerProps } from 'payload'\n\nimport { Link } from '@payloadcms/ui'\nimport React from 'react'\n\nimport type { LocalizedText } from '../localized.js'\n\nimport { resolveHomeLabel } from '../label.js'\n\nexport type HomeNavLinkProps = ServerProps & {\n /** Destination from the plugin options. Default: the admin dashboard. */\n href?: string\n /** Label override from the plugin options, plain or per-language. */\n label?: LocalizedText\n}\n\n/**\n * Server component for the `admin.components.beforeNavLinks` slot: a \"Home\"\n * link rendered above the collection/global links of the nav sidebar. It\n * reuses the nav's own `nav__link` classes so it looks like the built-in\n * links, and @payloadcms/ui's Link so navigation stays client-side.\n */\nexport const HomeNavLink = ({ href, i18n, label, payload }: HomeNavLinkProps) => {\n const text = resolveHomeLabel(label, i18n?.language ?? 'en')\n const url = href ?? payload?.config?.routes?.admin ?? '/admin'\n\n return (\n <Link className=\"nav__link\" href={url} id=\"nav-home\" prefetch={false}>\n <span className=\"nav__link-label\">{text}</span>\n </Link>\n )\n}\n"],"mappings":";AAEA,SAAS,mBAAmB;AAC5B,SAAS,6BAA6B;;;ACO/B,IAAM,uBAAuB,CAClC,MACA,aACuB;AACvB,MAAI,SAAS,UAAa,OAAO,SAAS,UAAU;AAClD,WAAO;AAAA,EACT;AAEA,SAAO,KAAK,QAAQ,KAAK,KAAK,MAAM,OAAO,OAAO,IAAI,EAAE,CAAC;AAC3D;;;ACnBO,IAAM,KAAK;AAAA,EAChB,SAAS;AAAA,IACP,MAAM;AAAA,EACR;AACF;;;ACFO,IAAM,KAAkB;AAAA,EAC7B,SAAS;AAAA,IACP,MAAM;AAAA,EACR;AACF;;;ACCA,IAAM,eAA4C,EAAE,IAAI,GAAG;AAMpD,IAAM,mBAAmB,CAC9B,OACA,aACW,qBAAqB,OAAO,QAAQ,MAAM,aAAa,QAAQ,KAAK,IAAI,QAAQ;;;AJwDzF,SACE,KADF;AAtDJ,IAAM,aAAa;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AA2CZ,IAAM,cAAc,CAAC,EAAE,MAAM,MAAM,OAAO,SAAS,GAAG,YAAY,MAAwB;AAC/F,QAAM,OAAO,iBAAiB,OAAO,MAAM,YAAY,IAAI;AAE3D,QAAM,OAAO,sBAAsB;AAAA,IACjC,WAAW;AAAA,IACX,UAAU;AAAA,IACV,WAAW,SAAS;AAAA,IACpB,aAAa,EAAE,GAAG,aAAa,MAAM,QAAQ;AAAA,EAC/C,CAAC;AAED,SACE,qBAAC,UAAK,WAAU,iBACd;AAAA,wBAAC,WAAO,sBAAW;AAAA,IACnB,oBAAC,UAAK,WAAU,uBAAuB,gBAAK;AAAA,IAC5C,oBAAC,UAAK,WAAU,wBAAwB,gBAAK;AAAA,KAC/C;AAEJ;;;AK5EA,SAAS,YAAY;AA0Bf,gBAAAA,YAAA;AANC,IAAM,cAAc,CAAC,EAAE,MAAM,MAAM,OAAO,QAAQ,MAAwB;AAC/E,QAAM,OAAO,iBAAiB,OAAO,MAAM,YAAY,IAAI;AAC3D,QAAM,MAAM,QAAQ,SAAS,QAAQ,QAAQ,SAAS;AAEtD,SACE,gBAAAA,KAAC,QAAK,WAAU,aAAY,MAAM,KAAK,IAAG,YAAW,UAAU,OAC7D,0BAAAA,KAAC,UAAK,WAAU,mBAAmB,gBAAK,GAC1C;AAEJ;","names":["jsx"]}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { Config } from 'payload';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* A plain string, or a per-language record keyed by admin language code
|
|
5
|
+
* (e.g. `{ en: 'Home', fr: 'Accueil' }`).
|
|
6
|
+
*/
|
|
7
|
+
type LocalizedText = string | Record<string, string>;
|
|
8
|
+
/**
|
|
9
|
+
* Resolves a `LocalizedText` for the current admin language: exact language
|
|
10
|
+
* match first, then `en`, then the first value in the record.
|
|
11
|
+
*/
|
|
12
|
+
declare const resolveLocalizedText: (text: LocalizedText | undefined, language: string) => string | undefined;
|
|
13
|
+
|
|
14
|
+
type VWPayloadPluginHomeNavConfig = {
|
|
15
|
+
/**
|
|
16
|
+
* Where "Home" links to.
|
|
17
|
+
* @default the admin dashboard (`routes.admin`)
|
|
18
|
+
*/
|
|
19
|
+
href?: string;
|
|
20
|
+
/**
|
|
21
|
+
* The label, plain or per-language. Default: "Home" / "Accueil" from the
|
|
22
|
+
* plugin's bundled translations, resolved against the admin language.
|
|
23
|
+
*/
|
|
24
|
+
label?: LocalizedText;
|
|
25
|
+
/**
|
|
26
|
+
* Show the label next to the icon in the app header (the
|
|
27
|
+
* `admin.components.graphics.Icon` slot). A custom icon configured before
|
|
28
|
+
* the plugin runs is kept and rendered next to the label.
|
|
29
|
+
* @default true
|
|
30
|
+
*/
|
|
31
|
+
iconLabel?: boolean;
|
|
32
|
+
/**
|
|
33
|
+
* Add a "Home" link at the top of the nav sidebar (prepended to
|
|
34
|
+
* `admin.components.beforeNavLinks`, above the collection links).
|
|
35
|
+
* @default true
|
|
36
|
+
*/
|
|
37
|
+
navLink?: boolean;
|
|
38
|
+
/** Leaves the config untouched. */
|
|
39
|
+
disabled?: boolean;
|
|
40
|
+
};
|
|
41
|
+
/**
|
|
42
|
+
* Makes the admin's way home obvious: a translated "Home" label next to the
|
|
43
|
+
* icon in the app header (which already links to the dashboard), and a
|
|
44
|
+
* matching "Home" link at the top of the collapsible nav sidebar. Both are
|
|
45
|
+
* server components resolved against the admin language.
|
|
46
|
+
*/
|
|
47
|
+
declare const VWPayloadPluginHomeNav: (pluginOptions?: VWPayloadPluginHomeNavConfig) => (config: Config) => Config;
|
|
48
|
+
|
|
49
|
+
export { type LocalizedText, VWPayloadPluginHomeNav, type VWPayloadPluginHomeNavConfig, resolveLocalizedText };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
// src/localized.ts
|
|
2
|
+
var resolveLocalizedText = (text, language) => {
|
|
3
|
+
if (text === void 0 || typeof text === "string") {
|
|
4
|
+
return text;
|
|
5
|
+
}
|
|
6
|
+
return text[language] ?? text.en ?? Object.values(text)[0];
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
// src/index.ts
|
|
10
|
+
var COMPONENT_PATH = "@vitrailweb/payload-plugin-home-nav/rsc";
|
|
11
|
+
var VWPayloadPluginHomeNav = (pluginOptions = {}) => (config) => {
|
|
12
|
+
if (pluginOptions.disabled) {
|
|
13
|
+
return config;
|
|
14
|
+
}
|
|
15
|
+
const { href, label } = pluginOptions;
|
|
16
|
+
if (!config.admin) config.admin = {};
|
|
17
|
+
if (!config.admin.components) config.admin.components = {};
|
|
18
|
+
if (pluginOptions.iconLabel !== false) {
|
|
19
|
+
if (!config.admin.components.graphics) config.admin.components.graphics = {};
|
|
20
|
+
const existingIcon = config.admin.components.graphics.Icon;
|
|
21
|
+
config.admin.components.graphics.Icon = {
|
|
22
|
+
path: COMPONENT_PATH,
|
|
23
|
+
exportName: "HomeNavIcon",
|
|
24
|
+
// Server component — serverProps never reach the client, so they can
|
|
25
|
+
// safely carry the existing icon's component config.
|
|
26
|
+
serverProps: {
|
|
27
|
+
icon: existingIcon,
|
|
28
|
+
label
|
|
29
|
+
}
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
if (pluginOptions.navLink !== false) {
|
|
33
|
+
config.admin.components.beforeNavLinks = [
|
|
34
|
+
{
|
|
35
|
+
path: COMPONENT_PATH,
|
|
36
|
+
exportName: "HomeNavLink",
|
|
37
|
+
serverProps: {
|
|
38
|
+
href,
|
|
39
|
+
label
|
|
40
|
+
}
|
|
41
|
+
},
|
|
42
|
+
...config.admin.components.beforeNavLinks ?? []
|
|
43
|
+
];
|
|
44
|
+
}
|
|
45
|
+
return config;
|
|
46
|
+
};
|
|
47
|
+
export {
|
|
48
|
+
VWPayloadPluginHomeNav,
|
|
49
|
+
resolveLocalizedText
|
|
50
|
+
};
|
|
51
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/localized.ts","../src/index.ts"],"sourcesContent":["/**\n * A plain string, or a per-language record keyed by admin language code\n * (e.g. `{ en: 'Home', fr: 'Accueil' }`).\n */\nexport type LocalizedText = string | Record<string, string>\n\n/**\n * Resolves a `LocalizedText` for the current admin language: exact language\n * match first, then `en`, then the first value in the record.\n */\nexport const resolveLocalizedText = (\n text: LocalizedText | undefined,\n language: string,\n): string | undefined => {\n if (text === undefined || typeof text === 'string') {\n return text\n }\n\n return text[language] ?? text.en ?? Object.values(text)[0]\n}\n","import type { Config } from 'payload'\n\nimport type { LocalizedText } from './localized.js'\n\nexport { resolveLocalizedText } from './localized.js'\nexport type { LocalizedText } from './localized.js'\n\nexport type VWPayloadPluginHomeNavConfig = {\n /**\n * Where \"Home\" links to.\n * @default the admin dashboard (`routes.admin`)\n */\n href?: string\n /**\n * The label, plain or per-language. Default: \"Home\" / \"Accueil\" from the\n * plugin's bundled translations, resolved against the admin language.\n */\n label?: LocalizedText\n /**\n * Show the label next to the icon in the app header (the\n * `admin.components.graphics.Icon` slot). A custom icon configured before\n * the plugin runs is kept and rendered next to the label.\n * @default true\n */\n iconLabel?: boolean\n /**\n * Add a \"Home\" link at the top of the nav sidebar (prepended to\n * `admin.components.beforeNavLinks`, above the collection links).\n * @default true\n */\n navLink?: boolean\n /** Leaves the config untouched. */\n disabled?: boolean\n}\n\nconst COMPONENT_PATH = '@vitrailweb/payload-plugin-home-nav/rsc'\n\n/**\n * Makes the admin's way home obvious: a translated \"Home\" label next to the\n * icon in the app header (which already links to the dashboard), and a\n * matching \"Home\" link at the top of the collapsible nav sidebar. Both are\n * server components resolved against the admin language.\n */\nexport const VWPayloadPluginHomeNav =\n (pluginOptions: VWPayloadPluginHomeNavConfig = {}) =>\n (config: Config): Config => {\n if (pluginOptions.disabled) {\n return config\n }\n\n const { href, label } = pluginOptions\n\n if (!config.admin) config.admin = {}\n if (!config.admin.components) config.admin.components = {}\n\n if (pluginOptions.iconLabel !== false) {\n if (!config.admin.components.graphics) config.admin.components.graphics = {}\n\n // The slot is taken over, but a custom icon the project configured is\n // handed to the component and rendered next to the label.\n const existingIcon = config.admin.components.graphics.Icon\n config.admin.components.graphics.Icon = {\n path: COMPONENT_PATH,\n exportName: 'HomeNavIcon',\n // Server component — serverProps never reach the client, so they can\n // safely carry the existing icon's component config.\n serverProps: {\n icon: existingIcon,\n label,\n },\n }\n }\n\n if (pluginOptions.navLink !== false) {\n // Prepended so \"Home\" stays on top even when other plugins add links.\n config.admin.components.beforeNavLinks = [\n {\n path: COMPONENT_PATH,\n exportName: 'HomeNavLink',\n serverProps: {\n href,\n label,\n },\n },\n ...(config.admin.components.beforeNavLinks ?? []),\n ]\n }\n\n return config\n }\n"],"mappings":";AAUO,IAAM,uBAAuB,CAClC,MACA,aACuB;AACvB,MAAI,SAAS,UAAa,OAAO,SAAS,UAAU;AAClD,WAAO;AAAA,EACT;AAEA,SAAO,KAAK,QAAQ,KAAK,KAAK,MAAM,OAAO,OAAO,IAAI,EAAE,CAAC;AAC3D;;;ACgBA,IAAM,iBAAiB;AAQhB,IAAM,yBACX,CAAC,gBAA8C,CAAC,MAChD,CAAC,WAA2B;AAC1B,MAAI,cAAc,UAAU;AAC1B,WAAO;AAAA,EACT;AAEA,QAAM,EAAE,MAAM,MAAM,IAAI;AAExB,MAAI,CAAC,OAAO,MAAO,QAAO,QAAQ,CAAC;AACnC,MAAI,CAAC,OAAO,MAAM,WAAY,QAAO,MAAM,aAAa,CAAC;AAEzD,MAAI,cAAc,cAAc,OAAO;AACrC,QAAI,CAAC,OAAO,MAAM,WAAW,SAAU,QAAO,MAAM,WAAW,WAAW,CAAC;AAI3E,UAAM,eAAe,OAAO,MAAM,WAAW,SAAS;AACtD,WAAO,MAAM,WAAW,SAAS,OAAO;AAAA,MACtC,MAAM;AAAA,MACN,YAAY;AAAA;AAAA;AAAA,MAGZ,aAAa;AAAA,QACX,MAAM;AAAA,QACN;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAEA,MAAI,cAAc,YAAY,OAAO;AAEnC,WAAO,MAAM,WAAW,iBAAiB;AAAA,MACvC;AAAA,QACE,MAAM;AAAA,QACN,YAAY;AAAA,QACZ,aAAa;AAAA,UACX;AAAA,UACA;AAAA,QACF;AAAA,MACF;AAAA,MACA,GAAI,OAAO,MAAM,WAAW,kBAAkB,CAAC;AAAA,IACjD;AAAA,EACF;AAEA,SAAO;AACT;","names":[]}
|
package/package.json
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@vitrailweb/payload-plugin-home-nav",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Payload plugin that labels the admin navbar icon with a translated “Home” and adds a Home link at the top of the nav sidebar",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"author": {
|
|
7
|
+
"name": "Vitrail Web"
|
|
8
|
+
},
|
|
9
|
+
"repository": {
|
|
10
|
+
"type": "git",
|
|
11
|
+
"url": "https://github.com/Vitrail-Web/payload-plugins",
|
|
12
|
+
"directory": "packages/payload-plugin-home-nav"
|
|
13
|
+
},
|
|
14
|
+
"type": "module",
|
|
15
|
+
"exports": {
|
|
16
|
+
".": {
|
|
17
|
+
"import": "./dist/index.js",
|
|
18
|
+
"types": "./dist/index.d.ts",
|
|
19
|
+
"default": "./dist/index.js"
|
|
20
|
+
},
|
|
21
|
+
"./rsc": {
|
|
22
|
+
"import": "./dist/exports/rsc.js",
|
|
23
|
+
"types": "./dist/exports/rsc.d.ts",
|
|
24
|
+
"default": "./dist/exports/rsc.js"
|
|
25
|
+
}
|
|
26
|
+
},
|
|
27
|
+
"main": "./dist/index.js",
|
|
28
|
+
"types": "./dist/index.d.ts",
|
|
29
|
+
"files": [
|
|
30
|
+
"dist"
|
|
31
|
+
],
|
|
32
|
+
"devDependencies": {
|
|
33
|
+
"@payloadcms/ui": "3.84.1",
|
|
34
|
+
"@types/react": "19.2.14",
|
|
35
|
+
"payload": "3.84.1",
|
|
36
|
+
"react": "19.2.6",
|
|
37
|
+
"rimraf": "3.0.2",
|
|
38
|
+
"tsup": "8.5.0",
|
|
39
|
+
"typescript": "5.7.3"
|
|
40
|
+
},
|
|
41
|
+
"peerDependencies": {
|
|
42
|
+
"@payloadcms/ui": "^3.84.1",
|
|
43
|
+
"payload": "^3.84.1",
|
|
44
|
+
"react": "^19.0.0"
|
|
45
|
+
},
|
|
46
|
+
"engines": {
|
|
47
|
+
"node": "^18.20.2 || >=20.9.0",
|
|
48
|
+
"pnpm": "^9 || ^10 || ^11"
|
|
49
|
+
},
|
|
50
|
+
"publishConfig": {
|
|
51
|
+
"access": "public",
|
|
52
|
+
"registry": "https://registry.npmjs.org/"
|
|
53
|
+
},
|
|
54
|
+
"scripts": {
|
|
55
|
+
"build": "tsup",
|
|
56
|
+
"clean": "rimraf {dist,*.tsbuildinfo}"
|
|
57
|
+
}
|
|
58
|
+
}
|