@payloadcms/plugin-seo 1.0.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 +120 -0
- package/dist/defaults.d.ts +10 -0
- package/dist/defaults.js +14 -0
- package/dist/defaults.js.map +1 -0
- package/dist/fields/MetaDescription.d.ts +12 -0
- package/dist/fields/MetaDescription.js +158 -0
- package/dist/fields/MetaDescription.js.map +1 -0
- package/dist/fields/MetaImage.d.ts +10 -0
- package/dist/fields/MetaImage.js +161 -0
- package/dist/fields/MetaImage.js.map +1 -0
- package/dist/fields/MetaTitle.d.ts +10 -0
- package/dist/fields/MetaTitle.js +159 -0
- package/dist/fields/MetaTitle.js.map +1 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +100 -0
- package/dist/index.js.map +1 -0
- package/dist/types.d.ts +24 -0
- package/dist/types.js +3 -0
- package/dist/types.js.map +1 -0
- package/dist/ui/LengthIndicator.d.ts +6 -0
- package/dist/ui/LengthIndicator.js +127 -0
- package/dist/ui/LengthIndicator.js.map +1 -0
- package/dist/ui/Overview.d.ts +2 -0
- package/dist/ui/Overview.js +72 -0
- package/dist/ui/Overview.js.map +1 -0
- package/dist/ui/Pill.d.ts +6 -0
- package/dist/ui/Pill.js +25 -0
- package/dist/ui/Pill.js.map +1 -0
- package/dist/ui/Preview.d.ts +9 -0
- package/dist/ui/Preview.js +136 -0
- package/dist/ui/Preview.js.map +1 -0
- package/package.json +37 -0
package/README.md
ADDED
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
# Payload SEO Plugin
|
|
2
|
+
|
|
3
|
+
[](https://www.npmjs.com/package/@payloadcms/plugin-seo)
|
|
4
|
+
|
|
5
|
+
A plugin for [Payload CMS](https://github.com/payloadcms/payload) to auto-generate SEO meta data based on the content of your documents.
|
|
6
|
+
|
|
7
|
+
Core features:
|
|
8
|
+
- Adds a `meta` field to every SEO-enabled collection that:
|
|
9
|
+
- Includes title, description, and image subfields
|
|
10
|
+
- Auto-generates meta data from your document's content
|
|
11
|
+
- Displays hints and indicators to help content editors
|
|
12
|
+
- Renders a snippet of what a search engine might display
|
|
13
|
+
- Soon: variable injection
|
|
14
|
+
|
|
15
|
+
## Installation
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
yarn add @payloadcms/plugin-seo
|
|
19
|
+
# OR
|
|
20
|
+
npm i @payloadcms/plugin-seo
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## Basic Usage
|
|
24
|
+
|
|
25
|
+
In the `plugins` array of your [Payload config](https://payloadcms.com/docs/configuration/overview), call the plugin with [options](#options):
|
|
26
|
+
|
|
27
|
+
```js
|
|
28
|
+
import { buildConfig } from 'payload/config';
|
|
29
|
+
import seo from '@payloadcms/plugin-seo';
|
|
30
|
+
|
|
31
|
+
const config = buildConfig({
|
|
32
|
+
collections: [
|
|
33
|
+
{
|
|
34
|
+
slug: 'pages',
|
|
35
|
+
fields: []
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
slug: 'media',
|
|
39
|
+
upload: {
|
|
40
|
+
staticDir: // path to your static directory,
|
|
41
|
+
},
|
|
42
|
+
fields: []
|
|
43
|
+
}
|
|
44
|
+
],
|
|
45
|
+
plugins: [
|
|
46
|
+
seo({
|
|
47
|
+
collections: [
|
|
48
|
+
'pages',
|
|
49
|
+
],
|
|
50
|
+
uploadsCollection: 'media',
|
|
51
|
+
generateTitle: ({ doc }) => `Website.com — ${doc.title.value}`,
|
|
52
|
+
generateDescription: ({ doc }) => doc.excerpt
|
|
53
|
+
})
|
|
54
|
+
]
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
export default config;
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
### Options
|
|
61
|
+
|
|
62
|
+
- `collections`
|
|
63
|
+
|
|
64
|
+
An array of collections slugs to enable SEO. Enabled collections receive a `meta` field which is an object of title, description, and image subfields.
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
- `uploadsCollection`
|
|
68
|
+
|
|
69
|
+
An upload-enabled collection slug, for the meta image to access.
|
|
70
|
+
|
|
71
|
+
- `generateTitle`
|
|
72
|
+
|
|
73
|
+
A function that allows you to return any meta title, including from document's content.
|
|
74
|
+
|
|
75
|
+
```js
|
|
76
|
+
seo({
|
|
77
|
+
...
|
|
78
|
+
generateTitle: ({ doc }) => `Website.com — ${doc?.title?.value}`,
|
|
79
|
+
})
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
- `generateDescription`
|
|
83
|
+
|
|
84
|
+
A function that allows you to return any meta description, including from document's content.
|
|
85
|
+
|
|
86
|
+
```js
|
|
87
|
+
seo({
|
|
88
|
+
...
|
|
89
|
+
generateDescription: ({ doc }) => doc?.excerpt?.value
|
|
90
|
+
})
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
- `generateURL`
|
|
94
|
+
|
|
95
|
+
A function called by the search preview component to display the actual URL of your page.
|
|
96
|
+
|
|
97
|
+
```js
|
|
98
|
+
seo({
|
|
99
|
+
...
|
|
100
|
+
generateURL: ({ doc }) => `https://yoursite.com/${doc?.slug?.value}`
|
|
101
|
+
})
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
## TypeScript
|
|
105
|
+
|
|
106
|
+
All types can be directly imported:
|
|
107
|
+
|
|
108
|
+
```js
|
|
109
|
+
import {
|
|
110
|
+
SEOConfig,
|
|
111
|
+
GenerateTitle,
|
|
112
|
+
GenerateDescription
|
|
113
|
+
GenerateURL
|
|
114
|
+
} from '@payloadcms/plugin-seo/dist/types';
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
## Screenshots
|
|
118
|
+

|
|
119
|
+
|
|
120
|
+
<!--  -->
|
package/dist/defaults.js
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.defaults = void 0;
|
|
4
|
+
exports.defaults = {
|
|
5
|
+
title: {
|
|
6
|
+
minLength: 50,
|
|
7
|
+
maxLength: 60,
|
|
8
|
+
},
|
|
9
|
+
description: {
|
|
10
|
+
minLength: 100,
|
|
11
|
+
maxLength: 150,
|
|
12
|
+
},
|
|
13
|
+
};
|
|
14
|
+
//# sourceMappingURL=defaults.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"defaults.js","sourceRoot":"","sources":["../src/defaults.ts"],"names":[],"mappings":";;;AAAa,QAAA,QAAQ,GAAG;IACtB,KAAK,EAAE;QACL,SAAS,EAAE,EAAE;QACb,SAAS,EAAE,EAAE;KACd;IACD,WAAW,EAAE;QACX,SAAS,EAAE,GAAG;QACd,SAAS,EAAE,GAAG;KACf;CACF,CAAC"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { TextareaField } from 'payload/dist/fields/config/types';
|
|
3
|
+
import { SEOConfig } from '../types';
|
|
4
|
+
declare type TextareaFieldWithProps = TextareaField & {
|
|
5
|
+
path: string;
|
|
6
|
+
seoConfig: SEOConfig;
|
|
7
|
+
};
|
|
8
|
+
export declare const MetaDescription: React.FC<(TextareaFieldWithProps | {}) & {
|
|
9
|
+
seoConfig: SEOConfig;
|
|
10
|
+
}>;
|
|
11
|
+
export declare const getMetaDescriptionField: (props: any) => JSX.Element;
|
|
12
|
+
export {};
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __assign = (this && this.__assign) || function () {
|
|
3
|
+
__assign = Object.assign || function(t) {
|
|
4
|
+
for (var s, i = 1, n = arguments.length; i < n; i++) {
|
|
5
|
+
s = arguments[i];
|
|
6
|
+
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
|
|
7
|
+
t[p] = s[p];
|
|
8
|
+
}
|
|
9
|
+
return t;
|
|
10
|
+
};
|
|
11
|
+
return __assign.apply(this, arguments);
|
|
12
|
+
};
|
|
13
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
14
|
+
if (k2 === undefined) k2 = k;
|
|
15
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
16
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
17
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
18
|
+
}
|
|
19
|
+
Object.defineProperty(o, k2, desc);
|
|
20
|
+
}) : (function(o, m, k, k2) {
|
|
21
|
+
if (k2 === undefined) k2 = k;
|
|
22
|
+
o[k2] = m[k];
|
|
23
|
+
}));
|
|
24
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
25
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
26
|
+
}) : function(o, v) {
|
|
27
|
+
o["default"] = v;
|
|
28
|
+
});
|
|
29
|
+
var __importStar = (this && this.__importStar) || function (mod) {
|
|
30
|
+
if (mod && mod.__esModule) return mod;
|
|
31
|
+
var result = {};
|
|
32
|
+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
33
|
+
__setModuleDefault(result, mod);
|
|
34
|
+
return result;
|
|
35
|
+
};
|
|
36
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
37
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
38
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
39
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
40
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
41
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
42
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
43
|
+
});
|
|
44
|
+
};
|
|
45
|
+
var __generator = (this && this.__generator) || function (thisArg, body) {
|
|
46
|
+
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
|
|
47
|
+
return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
|
|
48
|
+
function verb(n) { return function (v) { return step([n, v]); }; }
|
|
49
|
+
function step(op) {
|
|
50
|
+
if (f) throw new TypeError("Generator is already executing.");
|
|
51
|
+
while (_) try {
|
|
52
|
+
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
|
|
53
|
+
if (y = 0, t) op = [op[0] & 2, t.value];
|
|
54
|
+
switch (op[0]) {
|
|
55
|
+
case 0: case 1: t = op; break;
|
|
56
|
+
case 4: _.label++; return { value: op[1], done: false };
|
|
57
|
+
case 5: _.label++; y = op[1]; op = [0]; continue;
|
|
58
|
+
case 7: op = _.ops.pop(); _.trys.pop(); continue;
|
|
59
|
+
default:
|
|
60
|
+
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
|
|
61
|
+
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
|
|
62
|
+
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
|
|
63
|
+
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
|
|
64
|
+
if (t[2]) _.ops.pop();
|
|
65
|
+
_.trys.pop(); continue;
|
|
66
|
+
}
|
|
67
|
+
op = body.call(thisArg, _);
|
|
68
|
+
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
|
|
69
|
+
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
|
|
70
|
+
}
|
|
71
|
+
};
|
|
72
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
73
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
74
|
+
};
|
|
75
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
76
|
+
exports.getMetaDescriptionField = exports.MetaDescription = void 0;
|
|
77
|
+
var react_1 = __importStar(require("react"));
|
|
78
|
+
var forms_1 = require("payload/components/forms");
|
|
79
|
+
var LengthIndicator_1 = require("../ui/LengthIndicator");
|
|
80
|
+
var defaults_1 = require("../defaults");
|
|
81
|
+
var Input_1 = __importDefault(require("payload/dist/admin/components/forms/field-types/Textarea/Input"));
|
|
82
|
+
var _a = defaults_1.defaults.description, minLength = _a.minLength, maxLength = _a.maxLength;
|
|
83
|
+
var MetaDescription = function (props) {
|
|
84
|
+
var _a = props || {}, path = _a.path, label = _a.label, name = _a.name, seoConfig = _a.seoConfig; // TODO: this typing is temporary until payload types are updated for custom field props
|
|
85
|
+
var fields = (0, forms_1.useWatchForm)().fields;
|
|
86
|
+
var field = (0, forms_1.useField)({
|
|
87
|
+
label: label,
|
|
88
|
+
name: name,
|
|
89
|
+
path: path
|
|
90
|
+
});
|
|
91
|
+
var value = field.value, setValue = field.setValue, showError = field.showError;
|
|
92
|
+
var regenerateDescription = (0, react_1.useCallback)(function () {
|
|
93
|
+
var generateDescription = seoConfig.generateDescription;
|
|
94
|
+
var getDescription = function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
95
|
+
var generatedDescription;
|
|
96
|
+
return __generator(this, function (_a) {
|
|
97
|
+
switch (_a.label) {
|
|
98
|
+
case 0:
|
|
99
|
+
if (!(typeof generateDescription === 'function')) return [3 /*break*/, 2];
|
|
100
|
+
return [4 /*yield*/, generateDescription({ doc: __assign({}, fields) })];
|
|
101
|
+
case 1:
|
|
102
|
+
generatedDescription = _a.sent();
|
|
103
|
+
_a.label = 2;
|
|
104
|
+
case 2:
|
|
105
|
+
setValue(generatedDescription);
|
|
106
|
+
return [2 /*return*/];
|
|
107
|
+
}
|
|
108
|
+
});
|
|
109
|
+
}); };
|
|
110
|
+
getDescription();
|
|
111
|
+
}, [
|
|
112
|
+
fields,
|
|
113
|
+
setValue,
|
|
114
|
+
seoConfig
|
|
115
|
+
]);
|
|
116
|
+
return (react_1.default.createElement("div", { style: {
|
|
117
|
+
marginBottom: '20px',
|
|
118
|
+
} },
|
|
119
|
+
react_1.default.createElement("div", { style: {
|
|
120
|
+
marginBottom: '5px',
|
|
121
|
+
position: 'relative',
|
|
122
|
+
} },
|
|
123
|
+
react_1.default.createElement("div", null,
|
|
124
|
+
label,
|
|
125
|
+
"\u00A0 \u2014 \u00A0",
|
|
126
|
+
react_1.default.createElement("button", { onClick: regenerateDescription, type: "button", style: {
|
|
127
|
+
padding: 0,
|
|
128
|
+
background: 'none',
|
|
129
|
+
border: 'none',
|
|
130
|
+
backgroundColor: 'transparent',
|
|
131
|
+
cursor: 'pointer',
|
|
132
|
+
textDecoration: 'underline',
|
|
133
|
+
} }, "Auto-generate")),
|
|
134
|
+
react_1.default.createElement("div", { style: {
|
|
135
|
+
color: '#9A9A9A',
|
|
136
|
+
} }, "This should be between ".concat(minLength, " and ").concat(maxLength, " characters. Auto-generation will format a description using the page content. For help in writing quality meta descriptions, see "),
|
|
137
|
+
react_1.default.createElement("a", { href: "https://developers.google.com/search/docs/advanced/appearance/snippet#meta-descriptions", rel: "noopener noreferrer", target: "_blank", style: {
|
|
138
|
+
color: '-webkit-link',
|
|
139
|
+
textDecoration: 'none',
|
|
140
|
+
} }, "best practices"))),
|
|
141
|
+
react_1.default.createElement("div", { style: {
|
|
142
|
+
marginBottom: '10px',
|
|
143
|
+
position: 'relative',
|
|
144
|
+
} },
|
|
145
|
+
react_1.default.createElement(Input_1.default, { path: name, name: name, onChange: setValue, value: value, showError: showError, style: {
|
|
146
|
+
marginBottom: 0
|
|
147
|
+
} })),
|
|
148
|
+
react_1.default.createElement("div", { style: {
|
|
149
|
+
display: 'flex',
|
|
150
|
+
alignItems: 'center',
|
|
151
|
+
width: '100%',
|
|
152
|
+
} },
|
|
153
|
+
react_1.default.createElement(LengthIndicator_1.LengthIndicator, { text: value, minLength: minLength, maxLength: maxLength }))));
|
|
154
|
+
};
|
|
155
|
+
exports.MetaDescription = MetaDescription;
|
|
156
|
+
var getMetaDescriptionField = function (props) { return (react_1.default.createElement(exports.MetaDescription, __assign({}, props))); };
|
|
157
|
+
exports.getMetaDescriptionField = getMetaDescriptionField;
|
|
158
|
+
//# sourceMappingURL=MetaDescription.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"MetaDescription.js","sourceRoot":"","sources":["../../src/fields/MetaDescription.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { Props as UploadFieldType } from 'payload/dist/admin/components/forms/field-types/Upload/types';
|
|
3
|
+
import { SEOConfig } from '../types';
|
|
4
|
+
declare type UploadFieldWithProps = UploadFieldType & {
|
|
5
|
+
path: string;
|
|
6
|
+
seoConfig: SEOConfig;
|
|
7
|
+
};
|
|
8
|
+
export declare const MetaImage: React.FC<UploadFieldWithProps | {}>;
|
|
9
|
+
export declare const getMetaImageField: (props: any) => JSX.Element;
|
|
10
|
+
export {};
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __assign = (this && this.__assign) || function () {
|
|
3
|
+
__assign = Object.assign || function(t) {
|
|
4
|
+
for (var s, i = 1, n = arguments.length; i < n; i++) {
|
|
5
|
+
s = arguments[i];
|
|
6
|
+
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
|
|
7
|
+
t[p] = s[p];
|
|
8
|
+
}
|
|
9
|
+
return t;
|
|
10
|
+
};
|
|
11
|
+
return __assign.apply(this, arguments);
|
|
12
|
+
};
|
|
13
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
14
|
+
if (k2 === undefined) k2 = k;
|
|
15
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
16
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
17
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
18
|
+
}
|
|
19
|
+
Object.defineProperty(o, k2, desc);
|
|
20
|
+
}) : (function(o, m, k, k2) {
|
|
21
|
+
if (k2 === undefined) k2 = k;
|
|
22
|
+
o[k2] = m[k];
|
|
23
|
+
}));
|
|
24
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
25
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
26
|
+
}) : function(o, v) {
|
|
27
|
+
o["default"] = v;
|
|
28
|
+
});
|
|
29
|
+
var __importStar = (this && this.__importStar) || function (mod) {
|
|
30
|
+
if (mod && mod.__esModule) return mod;
|
|
31
|
+
var result = {};
|
|
32
|
+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
33
|
+
__setModuleDefault(result, mod);
|
|
34
|
+
return result;
|
|
35
|
+
};
|
|
36
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
37
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
38
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
39
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
40
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
41
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
42
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
43
|
+
});
|
|
44
|
+
};
|
|
45
|
+
var __generator = (this && this.__generator) || function (thisArg, body) {
|
|
46
|
+
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
|
|
47
|
+
return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
|
|
48
|
+
function verb(n) { return function (v) { return step([n, v]); }; }
|
|
49
|
+
function step(op) {
|
|
50
|
+
if (f) throw new TypeError("Generator is already executing.");
|
|
51
|
+
while (_) try {
|
|
52
|
+
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
|
|
53
|
+
if (y = 0, t) op = [op[0] & 2, t.value];
|
|
54
|
+
switch (op[0]) {
|
|
55
|
+
case 0: case 1: t = op; break;
|
|
56
|
+
case 4: _.label++; return { value: op[1], done: false };
|
|
57
|
+
case 5: _.label++; y = op[1]; op = [0]; continue;
|
|
58
|
+
case 7: op = _.ops.pop(); _.trys.pop(); continue;
|
|
59
|
+
default:
|
|
60
|
+
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
|
|
61
|
+
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
|
|
62
|
+
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
|
|
63
|
+
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
|
|
64
|
+
if (t[2]) _.ops.pop();
|
|
65
|
+
_.trys.pop(); continue;
|
|
66
|
+
}
|
|
67
|
+
op = body.call(thisArg, _);
|
|
68
|
+
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
|
|
69
|
+
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
|
|
70
|
+
}
|
|
71
|
+
};
|
|
72
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
73
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
74
|
+
};
|
|
75
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
76
|
+
exports.getMetaImageField = exports.MetaImage = void 0;
|
|
77
|
+
var react_1 = __importStar(require("react"));
|
|
78
|
+
var config_provider_1 = require("@payloadcms/config-provider");
|
|
79
|
+
var Input_1 = __importDefault(require("payload/dist/admin/components/forms/field-types/Upload/Input"));
|
|
80
|
+
var forms_1 = require("payload/components/forms");
|
|
81
|
+
var Pill_1 = require("../ui/Pill");
|
|
82
|
+
var MetaImage = function (props) {
|
|
83
|
+
var _a = props || {}, label = _a.label, relationTo = _a.relationTo, fieldTypes = _a.fieldTypes, name = _a.name, seoConfig = _a.seoConfig; // TODO: this typing is temporary until payload types are updated for custom field props
|
|
84
|
+
var field = (0, forms_1.useField)(props);
|
|
85
|
+
var fields = (0, forms_1.useWatchForm)().fields;
|
|
86
|
+
var value = field.value, setValue = field.setValue, showError = field.showError;
|
|
87
|
+
var regenerateImage = (0, react_1.useCallback)(function () {
|
|
88
|
+
var generateImage = seoConfig.generateImage;
|
|
89
|
+
var getDescription = function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
90
|
+
var generatedImage;
|
|
91
|
+
return __generator(this, function (_a) {
|
|
92
|
+
switch (_a.label) {
|
|
93
|
+
case 0:
|
|
94
|
+
if (!(typeof generateImage === 'function')) return [3 /*break*/, 2];
|
|
95
|
+
return [4 /*yield*/, generateImage({ doc: __assign({}, fields) })];
|
|
96
|
+
case 1:
|
|
97
|
+
generatedImage = _a.sent();
|
|
98
|
+
_a.label = 2;
|
|
99
|
+
case 2:
|
|
100
|
+
setValue(generatedImage);
|
|
101
|
+
return [2 /*return*/];
|
|
102
|
+
}
|
|
103
|
+
});
|
|
104
|
+
}); };
|
|
105
|
+
getDescription();
|
|
106
|
+
}, [
|
|
107
|
+
fields,
|
|
108
|
+
setValue,
|
|
109
|
+
seoConfig
|
|
110
|
+
]);
|
|
111
|
+
var hasImage = Boolean(value);
|
|
112
|
+
var config = (0, config_provider_1.useConfig)();
|
|
113
|
+
var collections = config.collections, serverURL = config.serverURL, _b = config.routes, _c = _b === void 0 ? {} : _b, api = _c.api;
|
|
114
|
+
var collection = (collections === null || collections === void 0 ? void 0 : collections.find(function (coll) { return coll.slug === relationTo; })) || undefined;
|
|
115
|
+
return (react_1.default.createElement("div", { style: {
|
|
116
|
+
marginBottom: '20px',
|
|
117
|
+
} },
|
|
118
|
+
react_1.default.createElement("div", { style: {
|
|
119
|
+
marginBottom: '5px',
|
|
120
|
+
position: 'relative',
|
|
121
|
+
} },
|
|
122
|
+
react_1.default.createElement("div", null,
|
|
123
|
+
label,
|
|
124
|
+
"\u00A0 \u2014 \u00A0",
|
|
125
|
+
react_1.default.createElement("button", { onClick: regenerateImage, type: "button", style: {
|
|
126
|
+
padding: 0,
|
|
127
|
+
background: 'none',
|
|
128
|
+
border: 'none',
|
|
129
|
+
backgroundColor: 'transparent',
|
|
130
|
+
cursor: 'pointer',
|
|
131
|
+
textDecoration: 'underline',
|
|
132
|
+
} }, "Auto-generate")),
|
|
133
|
+
react_1.default.createElement("div", { style: {
|
|
134
|
+
color: '#9A9A9A',
|
|
135
|
+
} }, "Auto-generation will retrieve the selected hero image.")),
|
|
136
|
+
react_1.default.createElement("div", { style: {
|
|
137
|
+
marginBottom: '10px',
|
|
138
|
+
position: 'relative',
|
|
139
|
+
} },
|
|
140
|
+
react_1.default.createElement(Input_1.default, { path: name, fieldTypes: fieldTypes, name: name, relationTo: relationTo, value: value, onChange: function (incomingImage) {
|
|
141
|
+
if (incomingImage !== null) {
|
|
142
|
+
var incomingID = incomingImage.id;
|
|
143
|
+
setValue(incomingID);
|
|
144
|
+
}
|
|
145
|
+
else {
|
|
146
|
+
setValue(null);
|
|
147
|
+
}
|
|
148
|
+
}, label: undefined, showError: showError, api: api, collection: collection, serverURL: serverURL, filterOptions: {}, style: {
|
|
149
|
+
marginBottom: 0,
|
|
150
|
+
} })),
|
|
151
|
+
react_1.default.createElement("div", { style: {
|
|
152
|
+
display: 'flex',
|
|
153
|
+
alignItems: 'center',
|
|
154
|
+
width: '100%',
|
|
155
|
+
} },
|
|
156
|
+
react_1.default.createElement(Pill_1.Pill, { backgroundColor: hasImage ? 'green' : 'red', color: "white", label: hasImage ? 'Good' : 'No Image' }))));
|
|
157
|
+
};
|
|
158
|
+
exports.MetaImage = MetaImage;
|
|
159
|
+
var getMetaImageField = function (props) { return (react_1.default.createElement(exports.MetaImage, __assign({}, props))); };
|
|
160
|
+
exports.getMetaImageField = getMetaImageField;
|
|
161
|
+
//# sourceMappingURL=MetaImage.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"MetaImage.js","sourceRoot":"","sources":["../../src/fields/MetaImage.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { Props as TextFieldType } from 'payload/dist/admin/components/forms/field-types/Text/types';
|
|
3
|
+
import { SEOConfig } from '../types';
|
|
4
|
+
declare type TextFieldWithProps = TextFieldType & {
|
|
5
|
+
path: string;
|
|
6
|
+
seoConfig: SEOConfig;
|
|
7
|
+
};
|
|
8
|
+
export declare const MetaTitle: React.FC<TextFieldWithProps | {}>;
|
|
9
|
+
export declare const getMetaTitleField: (props: any) => JSX.Element;
|
|
10
|
+
export {};
|