@payloadcms/plugin-seo 3.0.0-alpha.48 → 3.0.0-alpha.49
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/dist/fields/MetaDescription.d.ts +1 -1
- package/dist/fields/MetaDescription.d.ts.map +1 -1
- package/dist/fields/MetaDescription.js +12 -8
- package/dist/fields/MetaDescription.js.map +1 -1
- package/dist/fields/MetaImage.d.ts +1 -1
- package/dist/fields/MetaImage.d.ts.map +1 -1
- package/dist/fields/MetaImage.js +11 -4
- package/dist/fields/MetaImage.js.map +1 -1
- package/dist/fields/MetaTitle.d.ts +1 -1
- package/dist/fields/MetaTitle.d.ts.map +1 -1
- package/dist/fields/MetaTitle.js +12 -6
- package/dist/fields/MetaTitle.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -5
- package/dist/index.js.map +1 -1
- package/dist/translations/index.d.ts +1 -2
- package/dist/translations/index.d.ts.map +1 -1
- package/dist/translations/index.js +1 -1
- package/dist/translations/index.js.map +1 -1
- package/dist/types.d.ts +1 -1
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/dist/ui/LengthIndicator.js +3 -2
- package/dist/ui/LengthIndicator.js.map +1 -1
- package/dist/ui/Overview.d.ts.map +1 -1
- package/dist/ui/Overview.js +2 -1
- package/dist/ui/Overview.js.map +1 -1
- package/dist/ui/Preview.d.ts.map +1 -1
- package/dist/ui/Preview.js +4 -1
- package/dist/ui/Preview.js.map +1 -1
- package/package.json +7 -7
- package/src/index.tsx +279 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MetaDescription.d.ts","sourceRoot":"","sources":["../../src/fields/MetaDescription.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"MetaDescription.d.ts","sourceRoot":"","sources":["../../src/fields/MetaDescription.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,8BAA8B,CAAA;AAWjE,OAAO,KAAsB,MAAM,OAAO,CAAA;AAU1C,KAAK,oBAAoB,GAAG,aAAa,GAAG;IAC1C,wBAAwB,EAAE,OAAO,CAAA;IACjC,IAAI,EAAE,MAAM,CAAA;CACb,CAAA;AAED,eAAO,MAAM,eAAe,EAAE,KAAK,CAAC,EAAE,CAAC,oBAAoB,CA+H1D,CAAA"}
|
|
@@ -1,15 +1,19 @@
|
|
|
1
1
|
'use client';
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import { useAllFormFields
|
|
2
|
+
import { TextareaInput } from '@payloadcms/ui/fields/Textarea';
|
|
3
|
+
import { FieldLabel } from '@payloadcms/ui/forms/FieldLabel';
|
|
4
|
+
import { useFieldProps } from '@payloadcms/ui/forms/FieldPropsProvider';
|
|
5
|
+
import { useAllFormFields } from '@payloadcms/ui/forms/Form';
|
|
6
|
+
import { useField } from '@payloadcms/ui/forms/useField';
|
|
7
|
+
import { useDocumentInfo } from '@payloadcms/ui/providers/DocumentInfo';
|
|
8
|
+
import { useLocale } from '@payloadcms/ui/providers/Locale';
|
|
9
|
+
import { useTranslation } from '@payloadcms/ui/providers/Translation';
|
|
6
10
|
import React, { useCallback } from 'react';
|
|
7
11
|
import { defaults } from '../defaults.js';
|
|
8
12
|
import { LengthIndicator } from '../ui/LengthIndicator.js';
|
|
9
13
|
const { maxLength, minLength } = defaults.description;
|
|
10
14
|
export const MetaDescription = (props)=>{
|
|
11
|
-
const {
|
|
12
|
-
const { path: pathFromContext
|
|
15
|
+
const { CustomLabel, hasGenerateDescriptionFn, labelProps, path, required } = props;
|
|
16
|
+
const { path: pathFromContext } = useFieldProps();
|
|
13
17
|
const { t } = useTranslation();
|
|
14
18
|
const locale = useLocale();
|
|
15
19
|
const [fields] = useAllFormFields();
|
|
@@ -54,7 +58,7 @@ export const MetaDescription = (props)=>{
|
|
|
54
58
|
}
|
|
55
59
|
}, /*#__PURE__*/ React.createElement("div", {
|
|
56
60
|
className: "plugin-seo__field"
|
|
57
|
-
},
|
|
61
|
+
}, CustomLabel !== undefined ? CustomLabel : /*#__PURE__*/ React.createElement(FieldLabel, labelProps || {}), required && /*#__PURE__*/ React.createElement("span", {
|
|
58
62
|
style: {
|
|
59
63
|
color: 'var(--theme-error-500)',
|
|
60
64
|
marginLeft: '5px'
|
|
@@ -88,7 +92,7 @@ export const MetaDescription = (props)=>{
|
|
|
88
92
|
position: 'relative'
|
|
89
93
|
}
|
|
90
94
|
}, /*#__PURE__*/ React.createElement(TextareaInput, {
|
|
91
|
-
|
|
95
|
+
CustomError: errorMessage,
|
|
92
96
|
onChange: setValue,
|
|
93
97
|
path: pathFromContext,
|
|
94
98
|
required: required,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/fields/MetaDescription.tsx"],"sourcesContent":["'use client'\n\nimport type { FieldType,
|
|
1
|
+
{"version":3,"sources":["../../src/fields/MetaDescription.tsx"],"sourcesContent":["'use client'\n\nimport type { FormFieldBase } from '@payloadcms/ui/fields/shared'\nimport type { FieldType, Options } from '@payloadcms/ui/forms/useField'\n\nimport { TextareaInput } from '@payloadcms/ui/fields/Textarea'\nimport { FieldLabel } from '@payloadcms/ui/forms/FieldLabel'\nimport { useFieldProps } from '@payloadcms/ui/forms/FieldPropsProvider'\nimport { useAllFormFields } from '@payloadcms/ui/forms/Form'\nimport { useField } from '@payloadcms/ui/forms/useField'\nimport { useDocumentInfo } from '@payloadcms/ui/providers/DocumentInfo'\nimport { useLocale } from '@payloadcms/ui/providers/Locale'\nimport { useTranslation } from '@payloadcms/ui/providers/Translation'\nimport React, { useCallback } from 'react'\n\nimport type { GenerateDescription } from '../types.js'\n\nimport { defaults } from '../defaults.js'\nimport { LengthIndicator } from '../ui/LengthIndicator.js'\n\nconst { maxLength, minLength } = defaults.description\n\n// eslint-disable-next-line @typescript-eslint/no-redundant-type-constituents\ntype MetaDescriptionProps = FormFieldBase & {\n hasGenerateDescriptionFn: boolean\n path: string\n}\n\nexport const MetaDescription: React.FC<MetaDescriptionProps> = (props) => {\n const { CustomLabel, hasGenerateDescriptionFn, labelProps, path, required } = props\n const { path: pathFromContext } = useFieldProps()\n\n const { t } = useTranslation()\n\n const locale = useLocale()\n const [fields] = useAllFormFields()\n const docInfo = useDocumentInfo()\n\n const field: FieldType<string> = useField({\n path,\n } as Options)\n\n const { errorMessage, setValue, showError, value } = field\n\n const regenerateDescription = useCallback(async () => {\n if (!hasGenerateDescriptionFn) return\n\n const genDescriptionResponse = await fetch('/api/plugin-seo/generate-description', {\n body: JSON.stringify({\n ...docInfo,\n doc: { ...fields },\n locale: typeof locale === 'object' ? locale?.code : locale,\n } satisfies Parameters<GenerateDescription>[0]),\n credentials: 'include',\n headers: {\n 'Content-Type': 'application/json',\n },\n method: 'POST',\n })\n\n const { result: generatedDescription } = await genDescriptionResponse.json()\n\n setValue(generatedDescription || '')\n }, [fields, setValue, hasGenerateDescriptionFn, locale, docInfo])\n\n return (\n <div\n style={{\n marginBottom: '20px',\n }}\n >\n <div\n style={{\n marginBottom: '5px',\n position: 'relative',\n }}\n >\n <div className=\"plugin-seo__field\">\n {CustomLabel !== undefined ? CustomLabel : <FieldLabel {...(labelProps || {})} />}\n {required && (\n <span\n style={{\n color: 'var(--theme-error-500)',\n marginLeft: '5px',\n }}\n >\n *\n </span>\n )}\n\n {hasGenerateDescriptionFn && (\n <React.Fragment>\n — \n <button\n onClick={regenerateDescription}\n style={{\n background: 'none',\n backgroundColor: 'transparent',\n border: 'none',\n color: 'currentcolor',\n cursor: 'pointer',\n padding: 0,\n textDecoration: 'underline',\n }}\n type=\"button\"\n >\n {t('plugin-seo:autoGenerate')}\n </button>\n </React.Fragment>\n )}\n </div>\n <div\n style={{\n color: '#9A9A9A',\n }}\n >\n {t('plugin-seo:lengthTipDescription', { maxLength, minLength })}\n <a\n href=\"https://developers.google.com/search/docs/advanced/appearance/snippet#meta-descriptions\"\n rel=\"noopener noreferrer\"\n target=\"_blank\"\n >\n {t('plugin-seo:bestPractices')}\n </a>\n </div>\n </div>\n <div\n style={{\n marginBottom: '10px',\n position: 'relative',\n }}\n >\n <TextareaInput\n CustomError={errorMessage}\n onChange={setValue}\n path={pathFromContext}\n required={required}\n showError={showError}\n style={{\n marginBottom: 0,\n }}\n value={value}\n />\n </div>\n <div\n style={{\n alignItems: 'center',\n display: 'flex',\n width: '100%',\n }}\n >\n <LengthIndicator maxLength={maxLength} minLength={minLength} text={value} />\n </div>\n </div>\n )\n}\n"],"names":["TextareaInput","FieldLabel","useFieldProps","useAllFormFields","useField","useDocumentInfo","useLocale","useTranslation","React","useCallback","defaults","LengthIndicator","maxLength","minLength","description","MetaDescription","props","CustomLabel","hasGenerateDescriptionFn","labelProps","path","required","pathFromContext","t","locale","fields","docInfo","field","errorMessage","setValue","showError","value","regenerateDescription","genDescriptionResponse","fetch","body","JSON","stringify","doc","code","credentials","headers","method","result","generatedDescription","json","div","style","marginBottom","position","className","undefined","span","color","marginLeft","Fragment","button","onClick","background","backgroundColor","border","cursor","padding","textDecoration","type","a","href","rel","target","CustomError","onChange","alignItems","display","width","text"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MetaImage.d.ts","sourceRoot":"","sources":["../../src/fields/MetaImage.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"MetaImage.d.ts","sourceRoot":"","sources":["../../src/fields/MetaImage.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,8BAA8B,CAAA;AAWpE,OAAO,KAAsB,MAAM,OAAO,CAAA;AAO1C,KAAK,cAAc,GAAG,gBAAgB,GAAG;IACvC,kBAAkB,EAAE,OAAO,CAAA;CAC5B,CAAA;AAED,eAAO,MAAM,SAAS,EAAE,KAAK,CAAC,EAAE,CAAC,cAAc,CA8I9C,CAAA"}
|
package/dist/fields/MetaImage.js
CHANGED
|
@@ -1,9 +1,16 @@
|
|
|
1
1
|
'use client';
|
|
2
|
-
import { UploadInput
|
|
2
|
+
import { UploadInput } from '@payloadcms/ui/fields/Upload';
|
|
3
|
+
import { FieldLabel } from '@payloadcms/ui/forms/FieldLabel';
|
|
4
|
+
import { useAllFormFields } from '@payloadcms/ui/forms/Form';
|
|
5
|
+
import { useField } from '@payloadcms/ui/forms/useField';
|
|
6
|
+
import { useConfig } from '@payloadcms/ui/providers/Config';
|
|
7
|
+
import { useDocumentInfo } from '@payloadcms/ui/providers/DocumentInfo';
|
|
8
|
+
import { useLocale } from '@payloadcms/ui/providers/Locale';
|
|
9
|
+
import { useTranslation } from '@payloadcms/ui/providers/Translation';
|
|
3
10
|
import React, { useCallback } from 'react';
|
|
4
11
|
import { Pill } from '../ui/Pill.js';
|
|
5
12
|
export const MetaImage = (props)=>{
|
|
6
|
-
const {
|
|
13
|
+
const { CustomLabel, hasGenerateImageFn, labelProps, relationTo, required } = props || {};
|
|
7
14
|
const field = useField(props);
|
|
8
15
|
const { t } = useTranslation();
|
|
9
16
|
const locale = useLocale();
|
|
@@ -50,7 +57,7 @@ export const MetaImage = (props)=>{
|
|
|
50
57
|
}
|
|
51
58
|
}, /*#__PURE__*/ React.createElement("div", {
|
|
52
59
|
className: "plugin-seo__field"
|
|
53
|
-
},
|
|
60
|
+
}, CustomLabel !== undefined ? CustomLabel : /*#__PURE__*/ React.createElement(FieldLabel, labelProps || {}), required && /*#__PURE__*/ React.createElement("span", {
|
|
54
61
|
style: {
|
|
55
62
|
color: 'var(--theme-error-500)',
|
|
56
63
|
marginLeft: '5px'
|
|
@@ -77,7 +84,7 @@ export const MetaImage = (props)=>{
|
|
|
77
84
|
position: 'relative'
|
|
78
85
|
}
|
|
79
86
|
}, /*#__PURE__*/ React.createElement(UploadInput, {
|
|
80
|
-
|
|
87
|
+
CustomError: errorMessage,
|
|
81
88
|
api: api,
|
|
82
89
|
collection: collection,
|
|
83
90
|
filterOptions: {},
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/fields/MetaImage.tsx"],"sourcesContent":["'use client'\n\nimport type { FieldType, Options
|
|
1
|
+
{"version":3,"sources":["../../src/fields/MetaImage.tsx"],"sourcesContent":["'use client'\n\nimport type { UploadInputProps } from '@payloadcms/ui/fields/Upload'\nimport type { FieldType, Options } from '@payloadcms/ui/forms/useField'\n\nimport { UploadInput } from '@payloadcms/ui/fields/Upload'\nimport { FieldLabel } from '@payloadcms/ui/forms/FieldLabel'\nimport { useAllFormFields } from '@payloadcms/ui/forms/Form'\nimport { useField } from '@payloadcms/ui/forms/useField'\nimport { useConfig } from '@payloadcms/ui/providers/Config'\nimport { useDocumentInfo } from '@payloadcms/ui/providers/DocumentInfo'\nimport { useLocale } from '@payloadcms/ui/providers/Locale'\nimport { useTranslation } from '@payloadcms/ui/providers/Translation'\nimport React, { useCallback } from 'react'\n\nimport type { GenerateImage } from '../types.js'\n\nimport { Pill } from '../ui/Pill.js'\n\n// eslint-disable-next-line @typescript-eslint/no-redundant-type-constituents\ntype MetaImageProps = UploadInputProps & {\n hasGenerateImageFn: boolean\n}\n\nexport const MetaImage: React.FC<MetaImageProps> = (props) => {\n const { CustomLabel, hasGenerateImageFn, labelProps, relationTo, required } = props || {}\n\n const field: FieldType<string> = useField(props as Options)\n\n const { t } = useTranslation()\n\n const locale = useLocale()\n const [fields] = useAllFormFields()\n const docInfo = useDocumentInfo()\n\n const { errorMessage, setValue, showError, value } = field\n\n const regenerateImage = useCallback(async () => {\n if (!hasGenerateImageFn) return\n\n const genImageResponse = await fetch('/api/plugin-seo/generate-image', {\n body: JSON.stringify({\n ...docInfo,\n doc: { ...fields },\n locale: typeof locale === 'object' ? locale?.code : locale,\n } satisfies Parameters<GenerateImage>[0]),\n credentials: 'include',\n headers: {\n 'Content-Type': 'application/json',\n },\n method: 'POST',\n })\n\n const { result: generatedImage } = await genImageResponse.json()\n\n setValue(generatedImage || '')\n }, [fields, setValue, hasGenerateImageFn, locale, docInfo])\n\n const hasImage = Boolean(value)\n\n const config = useConfig()\n\n const { collections, routes: { api } = {}, serverURL } = config\n\n const collection = collections?.find((coll) => coll.slug === relationTo) || undefined\n\n return (\n <div\n style={{\n marginBottom: '20px',\n }}\n >\n <div\n style={{\n marginBottom: '5px',\n position: 'relative',\n }}\n >\n <div className=\"plugin-seo__field\">\n {CustomLabel !== undefined ? CustomLabel : <FieldLabel {...(labelProps || {})} />}\n {required && (\n <span\n style={{\n color: 'var(--theme-error-500)',\n marginLeft: '5px',\n }}\n >\n *\n </span>\n )}\n {hasGenerateImageFn && (\n <React.Fragment>\n — \n <button\n onClick={regenerateImage}\n style={{\n background: 'none',\n backgroundColor: 'transparent',\n border: 'none',\n color: 'currentcolor',\n cursor: 'pointer',\n padding: 0,\n textDecoration: 'underline',\n }}\n type=\"button\"\n >\n {t('plugin-seo:autoGenerate')}\n </button>\n </React.Fragment>\n )}\n </div>\n {hasGenerateImageFn && (\n <div\n style={{\n color: '#9A9A9A',\n }}\n >\n {t('plugin-seo:imageAutoGenerationTip')}\n </div>\n )}\n </div>\n <div\n style={{\n marginBottom: '10px',\n position: 'relative',\n }}\n >\n <UploadInput\n CustomError={errorMessage}\n api={api}\n collection={collection}\n filterOptions={{}}\n label={undefined}\n onChange={(incomingImage) => {\n if (incomingImage !== null) {\n const { id: incomingID } = incomingImage\n setValue(incomingID)\n } else {\n setValue(null)\n }\n }}\n relationTo={relationTo}\n required={required}\n serverURL={serverURL}\n showError={showError}\n style={{\n marginBottom: 0,\n }}\n value={value}\n />\n </div>\n <div\n style={{\n alignItems: 'center',\n display: 'flex',\n width: '100%',\n }}\n >\n <Pill\n backgroundColor={hasImage ? 'green' : 'red'}\n color=\"white\"\n label={hasImage ? t('plugin-seo:good') : t('plugin-seo:noImage')}\n />\n </div>\n </div>\n )\n}\n"],"names":["UploadInput","FieldLabel","useAllFormFields","useField","useConfig","useDocumentInfo","useLocale","useTranslation","React","useCallback","Pill","MetaImage","props","CustomLabel","hasGenerateImageFn","labelProps","relationTo","required","field","t","locale","fields","docInfo","errorMessage","setValue","showError","value","regenerateImage","genImageResponse","fetch","body","JSON","stringify","doc","code","credentials","headers","method","result","generatedImage","json","hasImage","Boolean","config","collections","routes","api","serverURL","collection","find","coll","slug","undefined","div","style","marginBottom","position","className","span","color","marginLeft","Fragment","button","onClick","background","backgroundColor","border","cursor","padding","textDecoration","type","CustomError","filterOptions","label","onChange","incomingImage","id","incomingID","alignItems","display","width"],"mappings":"AAAA;AAKA,SAASA,WAAW,QAAQ,+BAA8B;AAC1D,SAASC,UAAU,QAAQ,kCAAiC;AAC5D,SAASC,gBAAgB,QAAQ,4BAA2B;AAC5D,SAASC,QAAQ,QAAQ,gCAA+B;AACxD,SAASC,SAAS,QAAQ,kCAAiC;AAC3D,SAASC,eAAe,QAAQ,wCAAuC;AACvE,SAASC,SAAS,QAAQ,kCAAiC;AAC3D,SAASC,cAAc,QAAQ,uCAAsC;AACrE,OAAOC,SAASC,WAAW,QAAQ,QAAO;AAI1C,SAASC,IAAI,QAAQ,gBAAe;AAOpC,OAAO,MAAMC,YAAsC,CAACC;IAClD,MAAM,EAAEC,WAAW,EAAEC,kBAAkB,EAAEC,UAAU,EAAEC,UAAU,EAAEC,QAAQ,EAAE,GAAGL,SAAS,CAAC;IAExF,MAAMM,QAA2Bf,SAASS;IAE1C,MAAM,EAAEO,CAAC,EAAE,GAAGZ;IAEd,MAAMa,SAASd;IACf,MAAM,CAACe,OAAO,GAAGnB;IACjB,MAAMoB,UAAUjB;IAEhB,MAAM,EAAEkB,YAAY,EAAEC,QAAQ,EAAEC,SAAS,EAAEC,KAAK,EAAE,GAAGR;IAErD,MAAMS,kBAAkBlB,YAAY;QAClC,IAAI,CAACK,oBAAoB;QAEzB,MAAMc,mBAAmB,MAAMC,MAAM,kCAAkC;YACrEC,MAAMC,KAAKC,SAAS,CAAC;gBACnB,GAAGV,OAAO;gBACVW,KAAK;oBAAE,GAAGZ,MAAM;gBAAC;gBACjBD,QAAQ,OAAOA,WAAW,WAAWA,QAAQc,OAAOd;YACtD;YACAe,aAAa;YACbC,SAAS;gBACP,gBAAgB;YAClB;YACAC,QAAQ;QACV;QAEA,MAAM,EAAEC,QAAQC,cAAc,EAAE,GAAG,MAAMX,iBAAiBY,IAAI;QAE9DhB,SAASe,kBAAkB;IAC7B,GAAG;QAAClB;QAAQG;QAAUV;QAAoBM;QAAQE;KAAQ;IAE1D,MAAMmB,WAAWC,QAAQhB;IAEzB,MAAMiB,SAASvC;IAEf,MAAM,EAAEwC,WAAW,EAAEC,QAAQ,EAAEC,GAAG,EAAE,GAAG,CAAC,CAAC,EAAEC,SAAS,EAAE,GAAGJ;IAEzD,MAAMK,aAAaJ,aAAaK,KAAK,CAACC,OAASA,KAAKC,IAAI,KAAKnC,eAAeoC;IAE5E,qBACE,oBAACC;QACCC,OAAO;YACLC,cAAc;QAChB;qBAEA,oBAACF;QACCC,OAAO;YACLC,cAAc;YACdC,UAAU;QACZ;qBAEA,oBAACH;QAAII,WAAU;OACZ5C,gBAAgBuC,YAAYvC,4BAAc,oBAACZ,YAAgBc,cAAc,CAAC,IAC1EE,0BACC,oBAACyC;QACCJ,OAAO;YACLK,OAAO;YACPC,YAAY;QACd;OACD,MAIF9C,oCACC,oBAACN,MAAMqD,QAAQ,QAAC,uBAEd,oBAACC;QACCC,SAASpC;QACT2B,OAAO;YACLU,YAAY;YACZC,iBAAiB;YACjBC,QAAQ;YACRP,OAAO;YACPQ,QAAQ;YACRC,SAAS;YACTC,gBAAgB;QAClB;QACAC,MAAK;OAEJnD,EAAE,+BAKVL,oCACC,oBAACuC;QACCC,OAAO;YACLK,OAAO;QACT;OAECxC,EAAE,sDAIT,oBAACkC;QACCC,OAAO;YACLC,cAAc;YACdC,UAAU;QACZ;qBAEA,oBAACxD;QACCuE,aAAahD;QACbuB,KAAKA;QACLE,YAAYA;QACZwB,eAAe,CAAC;QAChBC,OAAOrB;QACPsB,UAAU,CAACC;YACT,IAAIA,kBAAkB,MAAM;gBAC1B,MAAM,EAAEC,IAAIC,UAAU,EAAE,GAAGF;gBAC3BnD,SAASqD;YACX,OAAO;gBACLrD,SAAS;YACX;QACF;QACAR,YAAYA;QACZC,UAAUA;QACV8B,WAAWA;QACXtB,WAAWA;QACX6B,OAAO;YACLC,cAAc;QAChB;QACA7B,OAAOA;uBAGX,oBAAC2B;QACCC,OAAO;YACLwB,YAAY;YACZC,SAAS;YACTC,OAAO;QACT;qBAEA,oBAACtE;QACCuD,iBAAiBxB,WAAW,UAAU;QACtCkB,OAAM;QACNc,OAAOhC,WAAWtB,EAAE,qBAAqBA,EAAE;;AAKrD,EAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MetaTitle.d.ts","sourceRoot":"","sources":["../../src/fields/MetaTitle.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"MetaTitle.d.ts","sourceRoot":"","sources":["../../src/fields/MetaTitle.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,8BAA8B,CAAA;AAYjE,OAAO,KAAsB,MAAM,OAAO,CAAA;AAM1C,OAAO,cAAc,CAAA;AAKrB,KAAK,cAAc,GAAG,aAAa,GAAG;IACpC,kBAAkB,EAAE,OAAO,CAAA;CAC5B,CAAA;AAED,eAAO,MAAM,SAAS,EAAE,KAAK,CAAC,EAAE,CAAC,cAAc,CA+H9C,CAAA"}
|
package/dist/fields/MetaTitle.js
CHANGED
|
@@ -1,14 +1,20 @@
|
|
|
1
1
|
'use client';
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
2
|
+
import { TextInput } from '@payloadcms/ui/fields/Text';
|
|
3
|
+
import { FieldLabel } from '@payloadcms/ui/forms/FieldLabel';
|
|
4
|
+
import { useFieldProps } from '@payloadcms/ui/forms/FieldPropsProvider';
|
|
5
|
+
import { useAllFormFields } from '@payloadcms/ui/forms/Form';
|
|
6
|
+
import { useField } from '@payloadcms/ui/forms/useField';
|
|
7
|
+
import { useDocumentInfo } from '@payloadcms/ui/providers/DocumentInfo';
|
|
8
|
+
import { useLocale } from '@payloadcms/ui/providers/Locale';
|
|
9
|
+
import { useTranslation } from '@payloadcms/ui/providers/Translation';
|
|
4
10
|
import React, { useCallback } from 'react';
|
|
5
11
|
import { defaults } from '../defaults.js';
|
|
6
12
|
import { LengthIndicator } from '../ui/LengthIndicator.js';
|
|
7
13
|
import './index.scss';
|
|
8
14
|
const { maxLength, minLength } = defaults.title;
|
|
9
15
|
export const MetaTitle = (props)=>{
|
|
10
|
-
const {
|
|
11
|
-
const { path: pathFromContext
|
|
16
|
+
const { CustomLabel, hasGenerateTitleFn, labelProps, path, required } = props || {};
|
|
17
|
+
const { path: pathFromContext } = useFieldProps();
|
|
12
18
|
const { t } = useTranslation();
|
|
13
19
|
const field = useField({
|
|
14
20
|
path
|
|
@@ -53,7 +59,7 @@ export const MetaTitle = (props)=>{
|
|
|
53
59
|
}
|
|
54
60
|
}, /*#__PURE__*/ React.createElement("div", {
|
|
55
61
|
className: "plugin-seo__field"
|
|
56
|
-
},
|
|
62
|
+
}, CustomLabel !== undefined ? CustomLabel : /*#__PURE__*/ React.createElement(FieldLabel, labelProps || {}), required && /*#__PURE__*/ React.createElement("span", {
|
|
57
63
|
style: {
|
|
58
64
|
color: 'var(--theme-error-500)',
|
|
59
65
|
marginLeft: '5px'
|
|
@@ -87,7 +93,7 @@ export const MetaTitle = (props)=>{
|
|
|
87
93
|
position: 'relative'
|
|
88
94
|
}
|
|
89
95
|
}, /*#__PURE__*/ React.createElement(TextInput, {
|
|
90
|
-
|
|
96
|
+
CustomError: errorMessage,
|
|
91
97
|
onChange: setValue,
|
|
92
98
|
path: pathFromContext,
|
|
93
99
|
required: required,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/fields/MetaTitle.tsx"],"sourcesContent":["'use client'\n\nimport type {
|
|
1
|
+
{"version":3,"sources":["../../src/fields/MetaTitle.tsx"],"sourcesContent":["'use client'\n\nimport type { FormFieldBase } from '@payloadcms/ui/fields/shared'\nimport type { Options } from '@payloadcms/ui/forms/useField'\nimport type { FieldType } from '@payloadcms/ui/forms/useField'\n\nimport { TextInput } from '@payloadcms/ui/fields/Text'\nimport { FieldLabel } from '@payloadcms/ui/forms/FieldLabel'\nimport { useFieldProps } from '@payloadcms/ui/forms/FieldPropsProvider'\nimport { useAllFormFields } from '@payloadcms/ui/forms/Form'\nimport { useField } from '@payloadcms/ui/forms/useField'\nimport { useDocumentInfo } from '@payloadcms/ui/providers/DocumentInfo'\nimport { useLocale } from '@payloadcms/ui/providers/Locale'\nimport { useTranslation } from '@payloadcms/ui/providers/Translation'\nimport React, { useCallback } from 'react'\n\nimport type { GenerateTitle } from '../types.js'\n\nimport { defaults } from '../defaults.js'\nimport { LengthIndicator } from '../ui/LengthIndicator.js'\nimport './index.scss'\n\nconst { maxLength, minLength } = defaults.title\n\n// eslint-disable-next-line @typescript-eslint/no-redundant-type-constituents\ntype MetaTitleProps = FormFieldBase & {\n hasGenerateTitleFn: boolean\n}\n\nexport const MetaTitle: React.FC<MetaTitleProps> = (props) => {\n const { CustomLabel, hasGenerateTitleFn, labelProps, path, required } = props || {}\n const { path: pathFromContext } = useFieldProps()\n\n const { t } = useTranslation()\n\n const field: FieldType<string> = useField({\n path,\n } as Options)\n\n const locale = useLocale()\n const [fields] = useAllFormFields()\n const docInfo = useDocumentInfo()\n\n const { errorMessage, setValue, showError, value } = field\n\n const regenerateTitle = useCallback(async () => {\n if (!hasGenerateTitleFn) return\n\n const genTitleResponse = await fetch('/api/plugin-seo/generate-title', {\n body: JSON.stringify({\n ...docInfo,\n doc: { ...fields },\n locale: typeof locale === 'object' ? locale?.code : locale,\n } satisfies Parameters<GenerateTitle>[0]),\n credentials: 'include',\n headers: {\n 'Content-Type': 'application/json',\n },\n method: 'POST',\n })\n\n const { result: generatedTitle } = await genTitleResponse.json()\n\n setValue(generatedTitle || '')\n }, [fields, setValue, hasGenerateTitleFn, locale, docInfo])\n\n return (\n <div\n style={{\n marginBottom: '20px',\n }}\n >\n <div\n style={{\n marginBottom: '5px',\n position: 'relative',\n }}\n >\n <div className=\"plugin-seo__field\">\n {CustomLabel !== undefined ? CustomLabel : <FieldLabel {...(labelProps || {})} />}\n {required && (\n <span\n style={{\n color: 'var(--theme-error-500)',\n marginLeft: '5px',\n }}\n >\n *\n </span>\n )}\n {hasGenerateTitleFn && (\n <React.Fragment>\n — \n <button\n onClick={regenerateTitle}\n style={{\n background: 'none',\n backgroundColor: 'transparent',\n border: 'none',\n color: 'currentcolor',\n cursor: 'pointer',\n padding: 0,\n textDecoration: 'underline',\n }}\n type=\"button\"\n >\n {t('plugin-seo:autoGenerate')}\n </button>\n </React.Fragment>\n )}\n </div>\n <div\n style={{\n color: '#9A9A9A',\n }}\n >\n {t('plugin-seo:lengthTipTitle', { maxLength, minLength })}\n <a\n href=\"https://developers.google.com/search/docs/advanced/appearance/title-link#page-titles\"\n rel=\"noopener noreferrer\"\n target=\"_blank\"\n >\n {t('plugin-seo:bestPractices')}\n </a>\n .\n </div>\n </div>\n <div\n style={{\n marginBottom: '10px',\n position: 'relative',\n }}\n >\n <TextInput\n CustomError={errorMessage}\n onChange={setValue}\n path={pathFromContext}\n required={required}\n showError={showError}\n style={{\n marginBottom: 0,\n }}\n value={value}\n />\n </div>\n <div\n style={{\n alignItems: 'center',\n display: 'flex',\n width: '100%',\n }}\n >\n <LengthIndicator maxLength={maxLength} minLength={minLength} text={value} />\n </div>\n </div>\n )\n}\n"],"names":["TextInput","FieldLabel","useFieldProps","useAllFormFields","useField","useDocumentInfo","useLocale","useTranslation","React","useCallback","defaults","LengthIndicator","maxLength","minLength","title","MetaTitle","props","CustomLabel","hasGenerateTitleFn","labelProps","path","required","pathFromContext","t","field","locale","fields","docInfo","errorMessage","setValue","showError","value","regenerateTitle","genTitleResponse","fetch","body","JSON","stringify","doc","code","credentials","headers","method","result","generatedTitle","json","div","style","marginBottom","position","className","undefined","span","color","marginLeft","Fragment","button","onClick","background","backgroundColor","border","cursor","padding","textDecoration","type","a","href","rel","target","CustomError","onChange","alignItems","display","width","text"],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,gBAAgB,CAAA;AAM5C,OAAO,KAAK,EAKV,YAAY,EACb,MAAM,YAAY,CAAA;AASnB,QAAA,MAAM,GAAG,iBACQ,YAAY,cAClB,MAAM,KAAG,MA6PjB,CAAA;AAEH,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,gBAAgB,CAAA;AAM5C,OAAO,KAAK,EAKV,YAAY,EACb,MAAM,YAAY,CAAA;AASnB,QAAA,MAAM,GAAG,iBACQ,YAAY,cAClB,MAAM,KAAG,MA6PjB,CAAA;AAEH,OAAO,EAAE,GAAG,EAAE,CAAA"}
|
package/dist/index.js
CHANGED
|
@@ -3,7 +3,7 @@ import React from 'react';
|
|
|
3
3
|
import { MetaDescription } from './fields/MetaDescription.js';
|
|
4
4
|
import { MetaImage } from './fields/MetaImage.js';
|
|
5
5
|
import { MetaTitle } from './fields/MetaTitle.js';
|
|
6
|
-
import translations from './translations/index.js';
|
|
6
|
+
import { translations } from './translations/index.js';
|
|
7
7
|
import { Overview } from './ui/Overview.js';
|
|
8
8
|
import { Preview } from './ui/Preview.js';
|
|
9
9
|
const seo = (pluginConfig)=>(config)=>{
|
|
@@ -104,7 +104,7 @@ const seo = (pluginConfig)=>(config)=>{
|
|
|
104
104
|
tabs: [
|
|
105
105
|
// append a new tab onto the end of the tabs array, if there is one at the first index
|
|
106
106
|
// if needed, create a new `Content` tab in the first index for this collection's base fields
|
|
107
|
-
...collection?.fields?.[0]?.type === 'tabs' ? collection.fields[0]
|
|
107
|
+
...collection?.fields?.[0]?.type === 'tabs' && collection?.fields?.[0]?.tabs ? collection.fields[0].tabs : [
|
|
108
108
|
{
|
|
109
109
|
fields: [
|
|
110
110
|
...(emailField ? collection.fields.filter((field)=>'name' in field && field.name !== 'email') : collection.fields) || []
|
|
@@ -203,7 +203,7 @@ const seo = (pluginConfig)=>(config)=>{
|
|
|
203
203
|
tabs: [
|
|
204
204
|
// append a new tab onto the end of the tabs array, if there is one at the first index
|
|
205
205
|
// if needed, create a new `Content` tab in the first index for this global's base fields
|
|
206
|
-
...global?.fields?.[0].type === 'tabs' ? global.fields[0]
|
|
206
|
+
...global?.fields?.[0].type === 'tabs' && global?.fields?.[0].tabs ? global.fields[0].tabs : [
|
|
207
207
|
{
|
|
208
208
|
fields: [
|
|
209
209
|
...global?.fields || []
|
|
@@ -222,7 +222,7 @@ const seo = (pluginConfig)=>(config)=>{
|
|
|
222
222
|
...global,
|
|
223
223
|
fields: [
|
|
224
224
|
...seoTabs,
|
|
225
|
-
...global?.fields?.[0].type === 'tabs' ? global
|
|
225
|
+
...global?.fields?.[0].type === 'tabs' ? global.fields.slice(1) : []
|
|
226
226
|
]
|
|
227
227
|
};
|
|
228
228
|
}
|
|
@@ -244,6 +244,6 @@ const seo = (pluginConfig)=>(config)=>{
|
|
|
244
244
|
}
|
|
245
245
|
};
|
|
246
246
|
};
|
|
247
|
-
export
|
|
247
|
+
export { seo };
|
|
248
248
|
|
|
249
249
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.tsx"],"sourcesContent":["import type { Config } from 'payload/config'\nimport type { Field, GroupField, TabsField, TextField } from 'payload/types'\n\nimport { deepMerge } from 'payload/utilities'\nimport React from 'react'\n\nimport type {\n GenerateDescription,\n GenerateImage,\n GenerateTitle,\n GenerateURL,\n PluginConfig,\n} from './types.js'\n\nimport { MetaDescription } from './fields/MetaDescription.js'\nimport { MetaImage } from './fields/MetaImage.js'\nimport { MetaTitle } from './fields/MetaTitle.js'\nimport translations from './translations/index.js'\nimport { Overview } from './ui/Overview.js'\nimport { Preview } from './ui/Preview.js'\n\nconst seo =\n (pluginConfig: PluginConfig) =>\n (config: Config): Config => {\n const seoFields: GroupField[] = [\n {\n name: 'meta',\n type: 'group',\n fields: [\n {\n name: 'overview',\n type: 'ui',\n admin: {\n components: {\n Field: Overview,\n },\n },\n label: 'Overview',\n },\n {\n name: 'title',\n type: 'text',\n admin: {\n components: {\n Field: (props) => (\n <MetaTitle\n {...props}\n hasGenerateTitleFn={typeof pluginConfig.generateTitle === 'function'}\n />\n ),\n },\n },\n localized: true,\n ...((pluginConfig?.fieldOverrides?.title as unknown as TextField) ?? {}),\n },\n {\n name: 'description',\n type: 'textarea',\n admin: {\n components: {\n Field: (props) => (\n <MetaDescription\n {...props}\n hasGenerateDescriptionFn={\n typeof pluginConfig.generateDescription === 'function'\n }\n />\n ),\n },\n },\n localized: true,\n ...(pluginConfig?.fieldOverrides?.description ?? {}),\n },\n ...(pluginConfig?.uploadsCollection\n ? [\n // eslint-disable-next-line @typescript-eslint/consistent-type-assertions\n {\n name: 'image',\n type: 'upload',\n admin: {\n components: {\n Field: (props) => (\n <MetaImage\n {...props}\n hasGenerateImageFn={typeof pluginConfig.generateImage === 'function'}\n />\n ),\n },\n description:\n 'Maximum upload file size: 12MB. Recommended file size for images is <500KB.',\n },\n label: 'Meta Image',\n localized: true,\n relationTo: pluginConfig?.uploadsCollection,\n ...(pluginConfig?.fieldOverrides?.image ?? {}),\n } as Field,\n ]\n : []),\n ...(pluginConfig?.fields || []),\n {\n name: 'preview',\n type: 'ui',\n admin: {\n components: {\n Field: (props) => (\n <Preview\n {...props}\n hasGenerateURLFn={typeof pluginConfig.generateURL === 'function'}\n />\n ),\n },\n },\n label: 'Preview',\n },\n ],\n interfaceName: pluginConfig.interfaceName,\n label: 'SEO',\n },\n ]\n\n return {\n ...config,\n collections:\n config.collections?.map((collection) => {\n const { slug } = collection\n const isEnabled = pluginConfig?.collections?.includes(slug)\n\n if (isEnabled) {\n if (pluginConfig?.tabbedUI) {\n // prevent issues with auth enabled collections having an email field that shouldn't be moved to the SEO tab\n const emailField =\n (collection.auth ||\n !(typeof collection.auth === 'object' && collection.auth.disableLocalStrategy)) &&\n collection.fields?.find((field) => 'name' in field && field.name === 'email')\n\n const seoTabs: TabsField[] = [\n {\n type: 'tabs',\n tabs: [\n // append a new tab onto the end of the tabs array, if there is one at the first index\n // if needed, create a new `Content` tab in the first index for this collection's base fields\n ...(collection?.fields?.[0]?.type === 'tabs'\n ? collection.fields[0]?.tabs\n : [\n {\n fields: [\n ...((emailField\n ? collection.fields.filter(\n (field) => 'name' in field && field.name !== 'email',\n )\n : collection.fields) || []),\n ],\n label: collection?.labels?.singular || 'Content',\n },\n ]),\n {\n fields: seoFields,\n label: 'SEO',\n },\n ],\n },\n ]\n\n return {\n ...collection,\n fields: [\n ...(emailField ? [emailField] : []),\n ...seoTabs,\n ...(collection?.fields?.[0]?.type === 'tabs' ? collection.fields.slice(1) : []),\n ],\n }\n }\n\n return {\n ...collection,\n fields: [...(collection?.fields || []), ...seoFields],\n }\n }\n\n return collection\n }) || [],\n endpoints: [\n {\n handler: async (req) => {\n const args: Parameters<GenerateTitle>[0] =\n req.data as unknown as Parameters<GenerateTitle>[0]\n const result = await pluginConfig.generateTitle(args)\n return new Response(JSON.stringify({ result }), { status: 200 })\n },\n method: 'post',\n path: '/plugin-seo/generate-title',\n },\n {\n handler: async (req) => {\n const args: Parameters<GenerateDescription>[0] =\n req.data as unknown as Parameters<GenerateDescription>[0]\n const result = await pluginConfig.generateDescription(args)\n return new Response(JSON.stringify({ result }), { status: 200 })\n },\n method: 'post',\n path: '/plugin-seo/generate-description',\n },\n {\n handler: async (req) => {\n const args: Parameters<GenerateURL>[0] =\n req.data as unknown as Parameters<GenerateURL>[0]\n const result = await pluginConfig.generateURL(args)\n return new Response(JSON.stringify({ result }), { status: 200 })\n },\n method: 'post',\n path: '/plugin-seo/generate-url',\n },\n {\n handler: async (req) => {\n const args: Parameters<GenerateImage>[0] =\n req.data as unknown as Parameters<GenerateImage>[0]\n const result = await pluginConfig.generateImage(args)\n return new Response(result, { status: 200 })\n },\n method: 'post',\n path: '/plugin-seo/generate-image',\n },\n ],\n globals:\n config.globals?.map((global) => {\n const { slug } = global\n const isEnabled = pluginConfig?.globals?.includes(slug)\n\n if (isEnabled) {\n if (pluginConfig?.tabbedUI) {\n const seoTabs: TabsField[] = [\n {\n type: 'tabs',\n tabs: [\n // append a new tab onto the end of the tabs array, if there is one at the first index\n // if needed, create a new `Content` tab in the first index for this global's base fields\n ...(global?.fields?.[0].type === 'tabs'\n ? global.fields[0]?.tabs\n : [\n {\n fields: [...(global?.fields || [])],\n label: global?.label || 'Content',\n },\n ]),\n {\n fields: seoFields,\n label: 'SEO',\n },\n ],\n },\n ]\n\n return {\n ...global,\n fields: [\n ...seoTabs,\n ...(global?.fields?.[0].type === 'tabs' ? global?.fields?.slice(1) : []),\n ],\n }\n }\n\n return {\n ...global,\n fields: [...(global?.fields || []), ...seoFields],\n }\n }\n\n return global\n }) || [],\n i18n: {\n ...config.i18n,\n translations: {\n ...deepMerge(translations, config.i18n?.translations),\n },\n },\n }\n }\n\nexport default seo\n"],"names":["deepMerge","React","MetaDescription","MetaImage","MetaTitle","translations","Overview","Preview","seo","pluginConfig","config","seoFields","name","type","fields","admin","components","Field","label","props","hasGenerateTitleFn","generateTitle","localized","fieldOverrides","title","hasGenerateDescriptionFn","generateDescription","description","uploadsCollection","hasGenerateImageFn","generateImage","relationTo","image","hasGenerateURLFn","generateURL","interfaceName","collections","map","collection","slug","isEnabled","includes","tabbedUI","emailField","auth","disableLocalStrategy","find","field","seoTabs","tabs","filter","labels","singular","slice","endpoints","handler","req","args","data","result","Response","JSON","stringify","status","method","path","globals","global","i18n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../src/index.tsx"],"sourcesContent":["import type { Config } from 'payload/config'\nimport type { Field, GroupField, TabsField, TextField } from 'payload/types'\n\nimport { deepMerge } from 'payload/utilities'\nimport React from 'react'\n\nimport type {\n GenerateDescription,\n GenerateImage,\n GenerateTitle,\n GenerateURL,\n PluginConfig,\n} from './types.js'\n\nimport { MetaDescription } from './fields/MetaDescription.js'\nimport { MetaImage } from './fields/MetaImage.js'\nimport { MetaTitle } from './fields/MetaTitle.js'\nimport { translations } from './translations/index.js'\nimport { Overview } from './ui/Overview.js'\nimport { Preview } from './ui/Preview.js'\n\nconst seo =\n (pluginConfig: PluginConfig) =>\n (config: Config): Config => {\n const seoFields: GroupField[] = [\n {\n name: 'meta',\n type: 'group',\n fields: [\n {\n name: 'overview',\n type: 'ui',\n admin: {\n components: {\n Field: Overview,\n },\n },\n label: 'Overview',\n },\n {\n name: 'title',\n type: 'text',\n admin: {\n components: {\n Field: (props) => (\n <MetaTitle\n {...props}\n hasGenerateTitleFn={typeof pluginConfig.generateTitle === 'function'}\n />\n ),\n },\n },\n localized: true,\n ...((pluginConfig?.fieldOverrides?.title as unknown as TextField) ?? {}),\n },\n {\n name: 'description',\n type: 'textarea',\n admin: {\n components: {\n Field: (props) => (\n <MetaDescription\n {...props}\n hasGenerateDescriptionFn={\n typeof pluginConfig.generateDescription === 'function'\n }\n />\n ),\n },\n },\n localized: true,\n ...(pluginConfig?.fieldOverrides?.description ?? {}),\n },\n ...(pluginConfig?.uploadsCollection\n ? [\n // eslint-disable-next-line @typescript-eslint/consistent-type-assertions\n {\n name: 'image',\n type: 'upload',\n admin: {\n components: {\n Field: (props) => (\n <MetaImage\n {...props}\n hasGenerateImageFn={typeof pluginConfig.generateImage === 'function'}\n />\n ),\n },\n description:\n 'Maximum upload file size: 12MB. Recommended file size for images is <500KB.',\n },\n label: 'Meta Image',\n localized: true,\n relationTo: pluginConfig?.uploadsCollection,\n ...(pluginConfig?.fieldOverrides?.image ?? {}),\n } as Field,\n ]\n : []),\n ...(pluginConfig?.fields || []),\n {\n name: 'preview',\n type: 'ui',\n admin: {\n components: {\n Field: (props) => (\n <Preview\n {...props}\n hasGenerateURLFn={typeof pluginConfig.generateURL === 'function'}\n />\n ),\n },\n },\n label: 'Preview',\n },\n ],\n interfaceName: pluginConfig.interfaceName,\n label: 'SEO',\n },\n ]\n\n return {\n ...config,\n collections:\n config.collections?.map((collection) => {\n const { slug } = collection\n const isEnabled = pluginConfig?.collections?.includes(slug)\n\n if (isEnabled) {\n if (pluginConfig?.tabbedUI) {\n // prevent issues with auth enabled collections having an email field that shouldn't be moved to the SEO tab\n const emailField =\n (collection.auth ||\n !(typeof collection.auth === 'object' && collection.auth.disableLocalStrategy)) &&\n collection.fields?.find((field) => 'name' in field && field.name === 'email')\n\n const seoTabs: TabsField[] = [\n {\n type: 'tabs',\n tabs: [\n // append a new tab onto the end of the tabs array, if there is one at the first index\n // if needed, create a new `Content` tab in the first index for this collection's base fields\n ...(collection?.fields?.[0]?.type === 'tabs' && collection?.fields?.[0]?.tabs\n ? collection.fields[0].tabs\n : [\n {\n fields: [\n ...((emailField\n ? collection.fields.filter(\n (field) => 'name' in field && field.name !== 'email',\n )\n : collection.fields) || []),\n ],\n label: collection?.labels?.singular || 'Content',\n },\n ]),\n {\n fields: seoFields,\n label: 'SEO',\n },\n ],\n },\n ]\n\n return {\n ...collection,\n fields: [\n ...(emailField ? [emailField] : []),\n ...seoTabs,\n ...(collection?.fields?.[0]?.type === 'tabs' ? collection.fields.slice(1) : []),\n ],\n }\n }\n\n return {\n ...collection,\n fields: [...(collection?.fields || []), ...seoFields],\n }\n }\n\n return collection\n }) || [],\n endpoints: [\n {\n handler: async (req) => {\n const args: Parameters<GenerateTitle>[0] =\n req.data as unknown as Parameters<GenerateTitle>[0]\n const result = await pluginConfig.generateTitle(args)\n return new Response(JSON.stringify({ result }), { status: 200 })\n },\n method: 'post',\n path: '/plugin-seo/generate-title',\n },\n {\n handler: async (req) => {\n const args: Parameters<GenerateDescription>[0] =\n req.data as unknown as Parameters<GenerateDescription>[0]\n const result = await pluginConfig.generateDescription(args)\n return new Response(JSON.stringify({ result }), { status: 200 })\n },\n method: 'post',\n path: '/plugin-seo/generate-description',\n },\n {\n handler: async (req) => {\n const args: Parameters<GenerateURL>[0] =\n req.data as unknown as Parameters<GenerateURL>[0]\n const result = await pluginConfig.generateURL(args)\n return new Response(JSON.stringify({ result }), { status: 200 })\n },\n method: 'post',\n path: '/plugin-seo/generate-url',\n },\n {\n handler: async (req) => {\n const args: Parameters<GenerateImage>[0] =\n req.data as unknown as Parameters<GenerateImage>[0]\n const result = await pluginConfig.generateImage(args)\n return new Response(result, { status: 200 })\n },\n method: 'post',\n path: '/plugin-seo/generate-image',\n },\n ],\n globals:\n config.globals?.map((global) => {\n const { slug } = global\n const isEnabled = pluginConfig?.globals?.includes(slug)\n\n if (isEnabled) {\n if (pluginConfig?.tabbedUI) {\n const seoTabs: TabsField[] = [\n {\n type: 'tabs',\n tabs: [\n // append a new tab onto the end of the tabs array, if there is one at the first index\n // if needed, create a new `Content` tab in the first index for this global's base fields\n ...(global?.fields?.[0].type === 'tabs' && global?.fields?.[0].tabs\n ? global.fields[0].tabs\n : [\n {\n fields: [...(global?.fields || [])],\n label: global?.label || 'Content',\n },\n ]),\n {\n fields: seoFields,\n label: 'SEO',\n },\n ],\n },\n ]\n\n return {\n ...global,\n fields: [\n ...seoTabs,\n ...(global?.fields?.[0].type === 'tabs' ? global.fields.slice(1) : []),\n ],\n }\n }\n\n return {\n ...global,\n fields: [...(global?.fields || []), ...seoFields],\n }\n }\n\n return global\n }) || [],\n i18n: {\n ...config.i18n,\n translations: {\n ...deepMerge(translations, config.i18n?.translations),\n },\n },\n }\n }\n\nexport { seo }\n"],"names":["deepMerge","React","MetaDescription","MetaImage","MetaTitle","translations","Overview","Preview","seo","pluginConfig","config","seoFields","name","type","fields","admin","components","Field","label","props","hasGenerateTitleFn","generateTitle","localized","fieldOverrides","title","hasGenerateDescriptionFn","generateDescription","description","uploadsCollection","hasGenerateImageFn","generateImage","relationTo","image","hasGenerateURLFn","generateURL","interfaceName","collections","map","collection","slug","isEnabled","includes","tabbedUI","emailField","auth","disableLocalStrategy","find","field","seoTabs","tabs","filter","labels","singular","slice","endpoints","handler","req","args","data","result","Response","JSON","stringify","status","method","path","globals","global","i18n"],"mappings":"AAGA,SAASA,SAAS,QAAQ,oBAAmB;AAC7C,OAAOC,WAAW,QAAO;AAUzB,SAASC,eAAe,QAAQ,8BAA6B;AAC7D,SAASC,SAAS,QAAQ,wBAAuB;AACjD,SAASC,SAAS,QAAQ,wBAAuB;AACjD,SAASC,YAAY,QAAQ,0BAAyB;AACtD,SAASC,QAAQ,QAAQ,mBAAkB;AAC3C,SAASC,OAAO,QAAQ,kBAAiB;AAEzC,MAAMC,MACJ,CAACC,eACD,CAACC;QACC,MAAMC,YAA0B;YAC9B;gBACEC,MAAM;gBACNC,MAAM;gBACNC,QAAQ;oBACN;wBACEF,MAAM;wBACNC,MAAM;wBACNE,OAAO;4BACLC,YAAY;gCACVC,OAAOX;4BACT;wBACF;wBACAY,OAAO;oBACT;oBACA;wBACEN,MAAM;wBACNC,MAAM;wBACNE,OAAO;4BACLC,YAAY;gCACVC,OAAO,CAACE,sBACN,oBAACf;wCACE,GAAGe,KAAK;wCACTC,oBAAoB,OAAOX,aAAaY,aAAa,KAAK;;4BAGhE;wBACF;wBACAC,WAAW;wBACX,GAAI,AAACb,cAAcc,gBAAgBC,SAAkC,CAAC,CAAC;oBACzE;oBACA;wBACEZ,MAAM;wBACNC,MAAM;wBACNE,OAAO;4BACLC,YAAY;gCACVC,OAAO,CAACE,sBACN,oBAACjB;wCACE,GAAGiB,KAAK;wCACTM,0BACE,OAAOhB,aAAaiB,mBAAmB,KAAK;;4BAIpD;wBACF;wBACAJ,WAAW;wBACX,GAAIb,cAAcc,gBAAgBI,eAAe,CAAC,CAAC;oBACrD;uBACIlB,cAAcmB,oBACd;wBACE,yEAAyE;wBACzE;4BACEhB,MAAM;4BACNC,MAAM;4BACNE,OAAO;gCACLC,YAAY;oCACVC,OAAO,CAACE,sBACN,oBAAChB;4CACE,GAAGgB,KAAK;4CACTU,oBAAoB,OAAOpB,aAAaqB,aAAa,KAAK;;gCAGhE;gCACAH,aACE;4BACJ;4BACAT,OAAO;4BACPI,WAAW;4BACXS,YAAYtB,cAAcmB;4BAC1B,GAAInB,cAAcc,gBAAgBS,SAAS,CAAC,CAAC;wBAC/C;qBACD,GACD,EAAE;uBACFvB,cAAcK,UAAU,EAAE;oBAC9B;wBACEF,MAAM;wBACNC,MAAM;wBACNE,OAAO;4BACLC,YAAY;gCACVC,OAAO,CAACE,sBACN,oBAACZ;wCACE,GAAGY,KAAK;wCACTc,kBAAkB,OAAOxB,aAAayB,WAAW,KAAK;;4BAG5D;wBACF;wBACAhB,OAAO;oBACT;iBACD;gBACDiB,eAAe1B,aAAa0B,aAAa;gBACzCjB,OAAO;YACT;SACD;QAED,OAAO;YACL,GAAGR,MAAM;YACT0B,aACE1B,OAAO0B,WAAW,EAAEC,IAAI,CAACC;gBACvB,MAAM,EAAEC,IAAI,EAAE,GAAGD;gBACjB,MAAME,YAAY/B,cAAc2B,aAAaK,SAASF;gBAEtD,IAAIC,WAAW;oBACb,IAAI/B,cAAciC,UAAU;wBAC1B,4GAA4G;wBAC5G,MAAMC,aACJ,AAACL,CAAAA,WAAWM,IAAI,IACd,CAAE,CAAA,OAAON,WAAWM,IAAI,KAAK,YAAYN,WAAWM,IAAI,CAACC,oBAAoB,AAAD,CAAC,KAC/EP,WAAWxB,MAAM,EAAEgC,KAAK,CAACC,QAAU,UAAUA,SAASA,MAAMnC,IAAI,KAAK;wBAEvE,MAAMoC,UAAuB;4BAC3B;gCACEnC,MAAM;gCACNoC,MAAM;oCACJ,sFAAsF;oCACtF,6FAA6F;uCACzFX,YAAYxB,QAAQ,CAAC,EAAE,EAAED,SAAS,UAAUyB,YAAYxB,QAAQ,CAAC,EAAE,EAAEmC,OACrEX,WAAWxB,MAAM,CAAC,EAAE,CAACmC,IAAI,GACzB;wCACE;4CACEnC,QAAQ;mDACF,AAAC6B,CAAAA,aACDL,WAAWxB,MAAM,CAACoC,MAAM,CACtB,CAACH,QAAU,UAAUA,SAASA,MAAMnC,IAAI,KAAK,WAE/C0B,WAAWxB,MAAM,AAAD,KAAM,EAAE;6CAC7B;4CACDI,OAAOoB,YAAYa,QAAQC,YAAY;wCACzC;qCACD;oCACL;wCACEtC,QAAQH;wCACRO,OAAO;oCACT;iCACD;4BACH;yBACD;wBAED,OAAO;4BACL,GAAGoB,UAAU;4BACbxB,QAAQ;mCACF6B,aAAa;oCAACA;iCAAW,GAAG,EAAE;mCAC/BK;mCACCV,YAAYxB,QAAQ,CAAC,EAAE,EAAED,SAAS,SAASyB,WAAWxB,MAAM,CAACuC,KAAK,CAAC,KAAK,EAAE;6BAC/E;wBACH;oBACF;oBAEA,OAAO;wBACL,GAAGf,UAAU;wBACbxB,QAAQ;+BAAKwB,YAAYxB,UAAU,EAAE;+BAAMH;yBAAU;oBACvD;gBACF;gBAEA,OAAO2B;YACT,MAAM,EAAE;YACVgB,WAAW;gBACT;oBACEC,SAAS,OAAOC;wBACd,MAAMC,OACJD,IAAIE,IAAI;wBACV,MAAMC,SAAS,MAAMlD,aAAaY,aAAa,CAACoC;wBAChD,OAAO,IAAIG,SAASC,KAAKC,SAAS,CAAC;4BAAEH;wBAAO,IAAI;4BAAEI,QAAQ;wBAAI;oBAChE;oBACAC,QAAQ;oBACRC,MAAM;gBACR;gBACA;oBACEV,SAAS,OAAOC;wBACd,MAAMC,OACJD,IAAIE,IAAI;wBACV,MAAMC,SAAS,MAAMlD,aAAaiB,mBAAmB,CAAC+B;wBACtD,OAAO,IAAIG,SAASC,KAAKC,SAAS,CAAC;4BAAEH;wBAAO,IAAI;4BAAEI,QAAQ;wBAAI;oBAChE;oBACAC,QAAQ;oBACRC,MAAM;gBACR;gBACA;oBACEV,SAAS,OAAOC;wBACd,MAAMC,OACJD,IAAIE,IAAI;wBACV,MAAMC,SAAS,MAAMlD,aAAayB,WAAW,CAACuB;wBAC9C,OAAO,IAAIG,SAASC,KAAKC,SAAS,CAAC;4BAAEH;wBAAO,IAAI;4BAAEI,QAAQ;wBAAI;oBAChE;oBACAC,QAAQ;oBACRC,MAAM;gBACR;gBACA;oBACEV,SAAS,OAAOC;wBACd,MAAMC,OACJD,IAAIE,IAAI;wBACV,MAAMC,SAAS,MAAMlD,aAAaqB,aAAa,CAAC2B;wBAChD,OAAO,IAAIG,SAASD,QAAQ;4BAAEI,QAAQ;wBAAI;oBAC5C;oBACAC,QAAQ;oBACRC,MAAM;gBACR;aACD;YACDC,SACExD,OAAOwD,OAAO,EAAE7B,IAAI,CAAC8B;gBACnB,MAAM,EAAE5B,IAAI,EAAE,GAAG4B;gBACjB,MAAM3B,YAAY/B,cAAcyD,SAASzB,SAASF;gBAElD,IAAIC,WAAW;oBACb,IAAI/B,cAAciC,UAAU;wBAC1B,MAAMM,UAAuB;4BAC3B;gCACEnC,MAAM;gCACNoC,MAAM;oCACJ,sFAAsF;oCACtF,yFAAyF;uCACrFkB,QAAQrD,QAAQ,CAAC,EAAE,CAACD,SAAS,UAAUsD,QAAQrD,QAAQ,CAAC,EAAE,CAACmC,OAC3DkB,OAAOrD,MAAM,CAAC,EAAE,CAACmC,IAAI,GACrB;wCACE;4CACEnC,QAAQ;mDAAKqD,QAAQrD,UAAU,EAAE;6CAAE;4CACnCI,OAAOiD,QAAQjD,SAAS;wCAC1B;qCACD;oCACL;wCACEJ,QAAQH;wCACRO,OAAO;oCACT;iCACD;4BACH;yBACD;wBAED,OAAO;4BACL,GAAGiD,MAAM;4BACTrD,QAAQ;mCACHkC;mCACCmB,QAAQrD,QAAQ,CAAC,EAAE,CAACD,SAAS,SAASsD,OAAOrD,MAAM,CAACuC,KAAK,CAAC,KAAK,EAAE;6BACtE;wBACH;oBACF;oBAEA,OAAO;wBACL,GAAGc,MAAM;wBACTrD,QAAQ;+BAAKqD,QAAQrD,UAAU,EAAE;+BAAMH;yBAAU;oBACnD;gBACF;gBAEA,OAAOwD;YACT,MAAM,EAAE;YACVC,MAAM;gBACJ,GAAG1D,OAAO0D,IAAI;gBACd/D,cAAc;oBACZ,GAAGL,UAAUK,cAAcK,OAAO0D,IAAI,EAAE/D,aAAa;gBACvD;YACF;QACF;IACF;AAEF,SAASG,GAAG,GAAE"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/translations/index.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/translations/index.ts"],"names":[],"mappings":"AAMA,eAAO,MAAM,YAAY;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAAyB,CAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/translations/index.ts"],"sourcesContent":["import en from './en.json'\nimport es from './es.json'\nimport fa from './fa.json'\nimport fr from './fr.json'\nimport pl from './pl.json'\n\nexport
|
|
1
|
+
{"version":3,"sources":["../../src/translations/index.ts"],"sourcesContent":["import en from './en.json'\nimport es from './es.json'\nimport fa from './fa.json'\nimport fr from './fr.json'\nimport pl from './pl.json'\n\nexport const translations = { en, es, fa, fr, pl }\n"],"names":["en","es","fa","fr","pl","translations"],"mappings":"AAAA,OAAOA,QAAQ,YAAW;AAC1B,OAAOC,QAAQ,YAAW;AAC1B,OAAOC,QAAQ,YAAW;AAC1B,OAAOC,QAAQ,YAAW;AAC1B,OAAOC,QAAQ,YAAW;AAE1B,OAAO,MAAMC,eAAe;IAAEL;IAAIC;IAAIC;IAAIC;IAAIC;AAAG,EAAC"}
|
package/dist/types.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { DocumentInfoContext } from '@payloadcms/ui/providers';
|
|
1
|
+
import type { DocumentInfoContext } from '@payloadcms/ui/providers/DocumentInfo';
|
|
2
2
|
import type { Field, TextField, TextareaField, UploadField } from 'payload/types';
|
|
3
3
|
export type GenerateTitle = <T = any>(args: DocumentInfoContext & {
|
|
4
4
|
doc: T;
|
package/dist/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,uCAAuC,CAAA;AAChF,OAAO,KAAK,EAAE,KAAK,EAAE,SAAS,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,eAAe,CAAA;AAEjF,MAAM,MAAM,aAAa,GAAG,CAAC,CAAC,GAAG,GAAG,EAClC,IAAI,EAAE,mBAAmB,GAAG;IAAE,GAAG,EAAE,CAAC,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE,KACpD,OAAO,CAAC,MAAM,CAAC,GAAG,MAAM,CAAA;AAE7B,MAAM,MAAM,mBAAmB,GAAG,CAAC,CAAC,GAAG,GAAG,EACxC,IAAI,EAAE,mBAAmB,GAAG;IAC1B,GAAG,EAAE,CAAC,CAAA;IACN,MAAM,CAAC,EAAE,MAAM,CAAA;CAChB,KACE,OAAO,CAAC,MAAM,CAAC,GAAG,MAAM,CAAA;AAE7B,MAAM,MAAM,aAAa,GAAG,CAAC,CAAC,GAAG,GAAG,EAClC,IAAI,EAAE,mBAAmB,GAAG;IAAE,GAAG,EAAE,CAAC,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE,KACpD,OAAO,CAAC,MAAM,CAAC,GAAG,MAAM,CAAA;AAE7B,MAAM,MAAM,WAAW,GAAG,CAAC,CAAC,GAAG,GAAG,EAChC,IAAI,EAAE,mBAAmB,GAAG;IAAE,GAAG,EAAE,CAAC,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE,KACpD,OAAO,CAAC,MAAM,CAAC,GAAG,MAAM,CAAA;AAE7B,MAAM,WAAW,YAAY;IAC3B,WAAW,CAAC,EAAE,MAAM,EAAE,CAAA;IACtB,cAAc,CAAC,EAAE;QACf,WAAW,CAAC,EAAE,OAAO,CAAC,aAAa,CAAC,CAAA;QACpC,KAAK,CAAC,EAAE,OAAO,CAAC,WAAW,CAAC,CAAA;QAC5B,KAAK,CAAC,EAAE,OAAO,CAAC,SAAS,CAAC,CAAA;KAC3B,CAAA;IACD,MAAM,CAAC,EAAE,KAAK,EAAE,CAAA;IAChB,mBAAmB,CAAC,EAAE,mBAAmB,CAAA;IACzC,aAAa,CAAC,EAAE,aAAa,CAAA;IAC7B,aAAa,CAAC,EAAE,aAAa,CAAA;IAC7B,WAAW,CAAC,EAAE,WAAW,CAAA;IACzB,OAAO,CAAC,EAAE,MAAM,EAAE,CAAA;IAClB,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,iBAAiB,CAAC,EAAE,MAAM,CAAA;CAC3B;AAED,MAAM,WAAW,IAAI;IACnB,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,KAAK,CAAC,EAAE,GAAG,CAAA;IACX,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,KAAK,CAAC,EAAE,MAAM,CAAA;CACf"}
|
package/dist/types.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/types.ts"],"sourcesContent":["import type { DocumentInfoContext } from '@payloadcms/ui/providers'\nimport type { Field, TextField, TextareaField, UploadField } from 'payload/types'\n\nexport type GenerateTitle = <T = any>(\n args: DocumentInfoContext & { doc: T; locale?: string },\n) => Promise<string> | string\n\nexport type GenerateDescription = <T = any>(\n args: DocumentInfoContext & {\n doc: T\n locale?: string\n },\n) => Promise<string> | string\n\nexport type GenerateImage = <T = any>(\n args: DocumentInfoContext & { doc: T; locale?: string },\n) => Promise<string> | string\n\nexport type GenerateURL = <T = any>(\n args: DocumentInfoContext & { doc: T; locale?: string },\n) => Promise<string> | string\n\nexport interface PluginConfig {\n collections?: string[]\n fieldOverrides?: {\n description?: Partial<TextareaField>\n image?: Partial<UploadField>\n title?: Partial<TextField>\n }\n fields?: Field[]\n generateDescription?: GenerateDescription\n generateImage?: GenerateImage\n generateTitle?: GenerateTitle\n generateURL?: GenerateURL\n globals?: string[]\n interfaceName?: string\n tabbedUI?: boolean\n uploadsCollection?: string\n}\n\nexport interface Meta {\n description?: string\n image?: any // TODO: type this\n keywords?: string\n title?: string\n}\n"],"names":[],"mappings":"AAwCA,WAKC"}
|
|
1
|
+
{"version":3,"sources":["../src/types.ts"],"sourcesContent":["import type { DocumentInfoContext } from '@payloadcms/ui/providers/DocumentInfo'\nimport type { Field, TextField, TextareaField, UploadField } from 'payload/types'\n\nexport type GenerateTitle = <T = any>(\n args: DocumentInfoContext & { doc: T; locale?: string },\n) => Promise<string> | string\n\nexport type GenerateDescription = <T = any>(\n args: DocumentInfoContext & {\n doc: T\n locale?: string\n },\n) => Promise<string> | string\n\nexport type GenerateImage = <T = any>(\n args: DocumentInfoContext & { doc: T; locale?: string },\n) => Promise<string> | string\n\nexport type GenerateURL = <T = any>(\n args: DocumentInfoContext & { doc: T; locale?: string },\n) => Promise<string> | string\n\nexport interface PluginConfig {\n collections?: string[]\n fieldOverrides?: {\n description?: Partial<TextareaField>\n image?: Partial<UploadField>\n title?: Partial<TextField>\n }\n fields?: Field[]\n generateDescription?: GenerateDescription\n generateImage?: GenerateImage\n generateTitle?: GenerateTitle\n generateURL?: GenerateURL\n globals?: string[]\n interfaceName?: string\n tabbedUI?: boolean\n uploadsCollection?: string\n}\n\nexport interface Meta {\n description?: string\n image?: any // TODO: type this\n keywords?: string\n title?: string\n}\n"],"names":[],"mappings":"AAwCA,WAKC"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
'use client';
|
|
2
|
-
import { useTranslation } from '@payloadcms/ui';
|
|
2
|
+
import { useTranslation } from '@payloadcms/ui/providers/Translation';
|
|
3
3
|
import React, { Fragment, useEffect, useState } from 'react';
|
|
4
4
|
import { Pill } from './Pill.js';
|
|
5
5
|
export const LengthIndicator = (props)=>{
|
|
@@ -59,7 +59,8 @@ export const LengthIndicator = (props)=>{
|
|
|
59
59
|
}, [
|
|
60
60
|
minLength,
|
|
61
61
|
maxLength,
|
|
62
|
-
text
|
|
62
|
+
text,
|
|
63
|
+
t
|
|
63
64
|
]);
|
|
64
65
|
const textLength = text?.length || 0;
|
|
65
66
|
const charsUntilMax = maxLength - textLength;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/ui/LengthIndicator.tsx"],"sourcesContent":["'use client'\n\nimport { useTranslation } from '@payloadcms/ui'\nimport React, { Fragment, useEffect, useState } from 'react'\n\nimport { Pill } from './Pill.js'\n\nexport const LengthIndicator: React.FC<{\n maxLength?: number\n minLength?: number\n text?: string\n}> = (props) => {\n const { maxLength = 0, minLength = 0, text } = props\n\n const [labelStyle, setLabelStyle] = useState({\n backgroundColor: '',\n color: '',\n })\n\n const [label, setLabel] = useState('')\n const [barWidth, setBarWidth] = useState<number>(0)\n const { t } = useTranslation()\n\n useEffect(() => {\n const textLength = text?.length || 0\n\n if (textLength === 0) {\n setLabel('Missing')\n setLabelStyle({\n backgroundColor: 'red',\n color: 'white',\n })\n setBarWidth(0)\n } else {\n const progress = (textLength - minLength) / (maxLength - minLength)\n\n if (progress < 0) {\n const ratioUntilMin = textLength / minLength\n\n if (ratioUntilMin > 0.9) {\n setLabel(t('plugin-seo:almostThere'))\n setLabelStyle({\n backgroundColor: 'orange',\n color: 'white',\n })\n } else {\n setLabel(t('plugin-seo:tooShort'))\n setLabelStyle({\n backgroundColor: 'orangered',\n color: 'white',\n })\n }\n\n setBarWidth(ratioUntilMin)\n }\n\n if (progress >= 0 && progress <= 1) {\n setLabel(t('plugin-seo:good'))\n setLabelStyle({\n backgroundColor: 'green',\n color: 'white',\n })\n setBarWidth(progress)\n }\n\n if (progress > 1) {\n setLabel(t('plugin-seo:tooLong'))\n setLabelStyle({\n backgroundColor: 'red',\n color: 'white',\n })\n setBarWidth(1)\n }\n }\n }, [minLength, maxLength, text])\n\n const textLength = text?.length || 0\n\n const charsUntilMax = maxLength - textLength\n const charsUntilMin = minLength - textLength\n\n return (\n <div\n style={{\n alignItems: 'center',\n display: 'flex',\n width: '100%',\n }}\n >\n <Pill backgroundColor={labelStyle.backgroundColor} color={labelStyle.color} label={label} />\n <div\n style={{\n flexShrink: 0,\n lineHeight: 1,\n marginRight: '10px',\n whiteSpace: 'nowrap',\n }}\n >\n <small>\n {t('plugin-seo:characterCount', { current: text?.length || 0, maxLength, minLength })}\n {(textLength === 0 || charsUntilMin > 0) && (\n <Fragment>{t('plugin-seo:charactersToGo', { characters: charsUntilMin })}</Fragment>\n )}\n {charsUntilMin <= 0 && charsUntilMax >= 0 && (\n <Fragment>{t('plugin-seo:charactersLeftOver', { characters: charsUntilMax })}</Fragment>\n )}\n {charsUntilMax < 0 && (\n <Fragment>\n {t('plugin-seo:charactersTooMany', { characters: charsUntilMax * -1 })}\n </Fragment>\n )}\n </small>\n </div>\n <div\n style={{\n backgroundColor: '#F3F3F3',\n height: '2px',\n position: 'relative',\n width: '100%',\n }}\n >\n <div\n style={{\n backgroundColor: labelStyle.backgroundColor,\n height: '100%',\n left: 0,\n position: 'absolute',\n top: 0,\n width: `${barWidth * 100}%`,\n }}\n />\n </div>\n </div>\n )\n}\n"],"names":["useTranslation","React","Fragment","useEffect","useState","Pill","LengthIndicator","props","maxLength","minLength","text","labelStyle","setLabelStyle","backgroundColor","color","label","setLabel","barWidth","setBarWidth","t","textLength","length","progress","ratioUntilMin","charsUntilMax","charsUntilMin","div","style","alignItems","display","width","flexShrink","lineHeight","marginRight","whiteSpace","small","current","characters","height","position","left","top"],"mappings":"AAAA;AAEA,SAASA,cAAc,QAAQ,
|
|
1
|
+
{"version":3,"sources":["../../src/ui/LengthIndicator.tsx"],"sourcesContent":["'use client'\n\nimport { useTranslation } from '@payloadcms/ui/providers/Translation'\nimport React, { Fragment, useEffect, useState } from 'react'\n\nimport { Pill } from './Pill.js'\n\nexport const LengthIndicator: React.FC<{\n maxLength?: number\n minLength?: number\n text?: string\n}> = (props) => {\n const { maxLength = 0, minLength = 0, text } = props\n\n const [labelStyle, setLabelStyle] = useState({\n backgroundColor: '',\n color: '',\n })\n\n const [label, setLabel] = useState('')\n const [barWidth, setBarWidth] = useState<number>(0)\n const { t } = useTranslation()\n\n useEffect(() => {\n const textLength = text?.length || 0\n\n if (textLength === 0) {\n setLabel('Missing')\n setLabelStyle({\n backgroundColor: 'red',\n color: 'white',\n })\n setBarWidth(0)\n } else {\n const progress = (textLength - minLength) / (maxLength - minLength)\n\n if (progress < 0) {\n const ratioUntilMin = textLength / minLength\n\n if (ratioUntilMin > 0.9) {\n setLabel(t('plugin-seo:almostThere'))\n setLabelStyle({\n backgroundColor: 'orange',\n color: 'white',\n })\n } else {\n setLabel(t('plugin-seo:tooShort'))\n setLabelStyle({\n backgroundColor: 'orangered',\n color: 'white',\n })\n }\n\n setBarWidth(ratioUntilMin)\n }\n\n if (progress >= 0 && progress <= 1) {\n setLabel(t('plugin-seo:good'))\n setLabelStyle({\n backgroundColor: 'green',\n color: 'white',\n })\n setBarWidth(progress)\n }\n\n if (progress > 1) {\n setLabel(t('plugin-seo:tooLong'))\n setLabelStyle({\n backgroundColor: 'red',\n color: 'white',\n })\n setBarWidth(1)\n }\n }\n }, [minLength, maxLength, text, t])\n\n const textLength = text?.length || 0\n\n const charsUntilMax = maxLength - textLength\n const charsUntilMin = minLength - textLength\n\n return (\n <div\n style={{\n alignItems: 'center',\n display: 'flex',\n width: '100%',\n }}\n >\n <Pill backgroundColor={labelStyle.backgroundColor} color={labelStyle.color} label={label} />\n <div\n style={{\n flexShrink: 0,\n lineHeight: 1,\n marginRight: '10px',\n whiteSpace: 'nowrap',\n }}\n >\n <small>\n {t('plugin-seo:characterCount', { current: text?.length || 0, maxLength, minLength })}\n {(textLength === 0 || charsUntilMin > 0) && (\n <Fragment>{t('plugin-seo:charactersToGo', { characters: charsUntilMin })}</Fragment>\n )}\n {charsUntilMin <= 0 && charsUntilMax >= 0 && (\n <Fragment>{t('plugin-seo:charactersLeftOver', { characters: charsUntilMax })}</Fragment>\n )}\n {charsUntilMax < 0 && (\n <Fragment>\n {t('plugin-seo:charactersTooMany', { characters: charsUntilMax * -1 })}\n </Fragment>\n )}\n </small>\n </div>\n <div\n style={{\n backgroundColor: '#F3F3F3',\n height: '2px',\n position: 'relative',\n width: '100%',\n }}\n >\n <div\n style={{\n backgroundColor: labelStyle.backgroundColor,\n height: '100%',\n left: 0,\n position: 'absolute',\n top: 0,\n width: `${barWidth * 100}%`,\n }}\n />\n </div>\n </div>\n )\n}\n"],"names":["useTranslation","React","Fragment","useEffect","useState","Pill","LengthIndicator","props","maxLength","minLength","text","labelStyle","setLabelStyle","backgroundColor","color","label","setLabel","barWidth","setBarWidth","t","textLength","length","progress","ratioUntilMin","charsUntilMax","charsUntilMin","div","style","alignItems","display","width","flexShrink","lineHeight","marginRight","whiteSpace","small","current","characters","height","position","left","top"],"mappings":"AAAA;AAEA,SAASA,cAAc,QAAQ,uCAAsC;AACrE,OAAOC,SAASC,QAAQ,EAAEC,SAAS,EAAEC,QAAQ,QAAQ,QAAO;AAE5D,SAASC,IAAI,QAAQ,YAAW;AAEhC,OAAO,MAAMC,kBAIR,CAACC;IACJ,MAAM,EAAEC,YAAY,CAAC,EAAEC,YAAY,CAAC,EAAEC,IAAI,EAAE,GAAGH;IAE/C,MAAM,CAACI,YAAYC,cAAc,GAAGR,SAAS;QAC3CS,iBAAiB;QACjBC,OAAO;IACT;IAEA,MAAM,CAACC,OAAOC,SAAS,GAAGZ,SAAS;IACnC,MAAM,CAACa,UAAUC,YAAY,GAAGd,SAAiB;IACjD,MAAM,EAAEe,CAAC,EAAE,GAAGnB;IAEdG,UAAU;QACR,MAAMiB,aAAaV,MAAMW,UAAU;QAEnC,IAAID,eAAe,GAAG;YACpBJ,SAAS;YACTJ,cAAc;gBACZC,iBAAiB;gBACjBC,OAAO;YACT;YACAI,YAAY;QACd,OAAO;YACL,MAAMI,WAAW,AAACF,CAAAA,aAAaX,SAAQ,IAAMD,CAAAA,YAAYC,SAAQ;YAEjE,IAAIa,WAAW,GAAG;gBAChB,MAAMC,gBAAgBH,aAAaX;gBAEnC,IAAIc,gBAAgB,KAAK;oBACvBP,SAASG,EAAE;oBACXP,cAAc;wBACZC,iBAAiB;wBACjBC,OAAO;oBACT;gBACF,OAAO;oBACLE,SAASG,EAAE;oBACXP,cAAc;wBACZC,iBAAiB;wBACjBC,OAAO;oBACT;gBACF;gBAEAI,YAAYK;YACd;YAEA,IAAID,YAAY,KAAKA,YAAY,GAAG;gBAClCN,SAASG,EAAE;gBACXP,cAAc;oBACZC,iBAAiB;oBACjBC,OAAO;gBACT;gBACAI,YAAYI;YACd;YAEA,IAAIA,WAAW,GAAG;gBAChBN,SAASG,EAAE;gBACXP,cAAc;oBACZC,iBAAiB;oBACjBC,OAAO;gBACT;gBACAI,YAAY;YACd;QACF;IACF,GAAG;QAACT;QAAWD;QAAWE;QAAMS;KAAE;IAElC,MAAMC,aAAaV,MAAMW,UAAU;IAEnC,MAAMG,gBAAgBhB,YAAYY;IAClC,MAAMK,gBAAgBhB,YAAYW;IAElC,qBACE,oBAACM;QACCC,OAAO;YACLC,YAAY;YACZC,SAAS;YACTC,OAAO;QACT;qBAEA,oBAACzB;QAAKQ,iBAAiBF,WAAWE,eAAe;QAAEC,OAAOH,WAAWG,KAAK;QAAEC,OAAOA;sBACnF,oBAACW;QACCC,OAAO;YACLI,YAAY;YACZC,YAAY;YACZC,aAAa;YACbC,YAAY;QACd;qBAEA,oBAACC,eACEhB,EAAE,6BAA6B;QAAEiB,SAAS1B,MAAMW,UAAU;QAAGb;QAAWC;IAAU,IAClF,AAACW,CAAAA,eAAe,KAAKK,gBAAgB,CAAA,mBACpC,oBAACvB,gBAAUiB,EAAE,6BAA6B;QAAEkB,YAAYZ;IAAc,KAEvEA,iBAAiB,KAAKD,iBAAiB,mBACtC,oBAACtB,gBAAUiB,EAAE,iCAAiC;QAAEkB,YAAYb;IAAc,KAE3EA,gBAAgB,mBACf,oBAACtB,gBACEiB,EAAE,gCAAgC;QAAEkB,YAAYb,gBAAgB,CAAC;IAAE,qBAK5E,oBAACE;QACCC,OAAO;YACLd,iBAAiB;YACjByB,QAAQ;YACRC,UAAU;YACVT,OAAO;QACT;qBAEA,oBAACJ;QACCC,OAAO;YACLd,iBAAiBF,WAAWE,eAAe;YAC3CyB,QAAQ;YACRE,MAAM;YACND,UAAU;YACVE,KAAK;YACLX,OAAO,CAAC,EAAEb,WAAW,IAAI,CAAC,CAAC;QAC7B;;AAKV,EAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Overview.d.ts","sourceRoot":"","sources":["../../src/ui/Overview.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"Overview.d.ts","sourceRoot":"","sources":["../../src/ui/Overview.tsx"],"names":[],"mappings":"AAMA,OAAO,KAA2C,MAAM,OAAO,CAAA;AAS/D,eAAO,MAAM,QAAQ,EAAE,KAAK,CAAC,EAoD5B,CAAA"}
|
package/dist/ui/Overview.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
'use client';
|
|
2
|
-
import { useAllFormFields, useForm
|
|
2
|
+
import { useAllFormFields, useForm } from '@payloadcms/ui/forms/Form';
|
|
3
|
+
import { useTranslation } from '@payloadcms/ui/providers/Translation';
|
|
3
4
|
import React, { useCallback, useEffect, useState } from 'react';
|
|
4
5
|
import { defaults } from '../defaults.js';
|
|
5
6
|
const { description: { maxLength: maxDesc, minLength: minDesc }, title: { maxLength: maxTitle, minLength: minTitle } } = defaults;
|
package/dist/ui/Overview.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/ui/Overview.tsx"],"sourcesContent":["'use client'\n\nimport type { FormField } from 'payload/types'\n\nimport { useAllFormFields, useForm
|
|
1
|
+
{"version":3,"sources":["../../src/ui/Overview.tsx"],"sourcesContent":["'use client'\n\nimport type { FormField } from 'payload/types'\n\nimport { useAllFormFields, useForm } from '@payloadcms/ui/forms/Form'\nimport { useTranslation } from '@payloadcms/ui/providers/Translation'\nimport React, { useCallback, useEffect, useState } from 'react'\n\nimport { defaults } from '../defaults.js'\n\nconst {\n description: { maxLength: maxDesc, minLength: minDesc },\n title: { maxLength: maxTitle, minLength: minTitle },\n} = defaults\n\nexport const Overview: React.FC = () => {\n const {\n // dispatchFields,\n getFields,\n } = useForm()\n\n const [\n {\n 'meta.description': { value: metaDesc } = {} as FormField,\n 'meta.image': { value: metaImage } = {} as FormField,\n 'meta.title': { value: metaTitle } = {} as FormField,\n },\n ] = useAllFormFields()\n const { t } = useTranslation()\n\n const [titleIsValid, setTitleIsValid] = useState<boolean | undefined>()\n const [descIsValid, setDescIsValid] = useState<boolean | undefined>()\n const [imageIsValid, setImageIsValid] = useState<boolean | undefined>()\n\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n const resetAll = useCallback(() => {\n const fields = getFields()\n const fieldsWithoutMeta = fields\n fieldsWithoutMeta['meta.title'].value = ''\n fieldsWithoutMeta['meta.description'].value = ''\n fieldsWithoutMeta['meta.image'].value = ''\n // dispatchFields(fieldsWithoutMeta);\n }, [getFields])\n\n useEffect(() => {\n if (typeof metaTitle === 'string')\n setTitleIsValid(metaTitle.length >= minTitle && metaTitle.length <= maxTitle)\n if (typeof metaDesc === 'string')\n setDescIsValid(metaDesc.length >= minDesc && metaDesc.length <= maxDesc)\n setImageIsValid(Boolean(metaImage))\n }, [metaTitle, metaDesc, metaImage])\n\n const testResults = [titleIsValid, descIsValid, imageIsValid]\n\n const numberOfPasses = testResults.filter(Boolean).length\n\n return (\n <div\n style={{\n marginBottom: '20px',\n }}\n >\n <div>\n {t('plugin-seo:checksPassing', { current: numberOfPasses, max: testResults.length })}\n </div>\n </div>\n )\n}\n"],"names":["useAllFormFields","useForm","useTranslation","React","useCallback","useEffect","useState","defaults","description","maxLength","maxDesc","minLength","minDesc","title","maxTitle","minTitle","Overview","getFields","value","metaDesc","metaImage","metaTitle","t","titleIsValid","setTitleIsValid","descIsValid","setDescIsValid","imageIsValid","setImageIsValid","resetAll","fields","fieldsWithoutMeta","length","Boolean","testResults","numberOfPasses","filter","div","style","marginBottom","current","max"],"mappings":"AAAA;AAIA,SAASA,gBAAgB,EAAEC,OAAO,QAAQ,4BAA2B;AACrE,SAASC,cAAc,QAAQ,uCAAsC;AACrE,OAAOC,SAASC,WAAW,EAAEC,SAAS,EAAEC,QAAQ,QAAQ,QAAO;AAE/D,SAASC,QAAQ,QAAQ,iBAAgB;AAEzC,MAAM,EACJC,aAAa,EAAEC,WAAWC,OAAO,EAAEC,WAAWC,OAAO,EAAE,EACvDC,OAAO,EAAEJ,WAAWK,QAAQ,EAAEH,WAAWI,QAAQ,EAAE,EACpD,GAAGR;AAEJ,OAAO,MAAMS,WAAqB;IAChC,MAAM,EACJ,mBAAmB;IACnBC,SAAS,EACV,GAAGhB;IAEJ,MAAM,CACJ,EACE,oBAAoB,EAAEiB,OAAOC,QAAQ,EAAE,GAAG,CAAC,CAAc,EACzD,cAAc,EAAED,OAAOE,SAAS,EAAE,GAAG,CAAC,CAAc,EACpD,cAAc,EAAEF,OAAOG,SAAS,EAAE,GAAG,CAAC,CAAc,EACrD,CACF,GAAGrB;IACJ,MAAM,EAAEsB,CAAC,EAAE,GAAGpB;IAEd,MAAM,CAACqB,cAAcC,gBAAgB,GAAGlB;IACxC,MAAM,CAACmB,aAAaC,eAAe,GAAGpB;IACtC,MAAM,CAACqB,cAAcC,gBAAgB,GAAGtB;IAExC,6DAA6D;IAC7D,MAAMuB,WAAWzB,YAAY;QAC3B,MAAM0B,SAASb;QACf,MAAMc,oBAAoBD;QAC1BC,iBAAiB,CAAC,aAAa,CAACb,KAAK,GAAG;QACxCa,iBAAiB,CAAC,mBAAmB,CAACb,KAAK,GAAG;QAC9Ca,iBAAiB,CAAC,aAAa,CAACb,KAAK,GAAG;IACxC,qCAAqC;IACvC,GAAG;QAACD;KAAU;IAEdZ,UAAU;QACR,IAAI,OAAOgB,cAAc,UACvBG,gBAAgBH,UAAUW,MAAM,IAAIjB,YAAYM,UAAUW,MAAM,IAAIlB;QACtE,IAAI,OAAOK,aAAa,UACtBO,eAAeP,SAASa,MAAM,IAAIpB,WAAWO,SAASa,MAAM,IAAItB;QAClEkB,gBAAgBK,QAAQb;IAC1B,GAAG;QAACC;QAAWF;QAAUC;KAAU;IAEnC,MAAMc,cAAc;QAACX;QAAcE;QAAaE;KAAa;IAE7D,MAAMQ,iBAAiBD,YAAYE,MAAM,CAACH,SAASD,MAAM;IAEzD,qBACE,oBAACK;QACCC,OAAO;YACLC,cAAc;QAChB;qBAEA,oBAACF,aACEf,EAAE,4BAA4B;QAAEkB,SAASL;QAAgBM,KAAKP,YAAYF,MAAM;IAAC;AAI1F,EAAC"}
|
package/dist/ui/Preview.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Preview.d.ts","sourceRoot":"","sources":["../../src/ui/Preview.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAa,OAAO,EAAE,MAAM,eAAe,CAAA;
|
|
1
|
+
{"version":3,"file":"Preview.d.ts","sourceRoot":"","sources":["../../src/ui/Preview.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAa,OAAO,EAAE,MAAM,eAAe,CAAA;AAMvD,OAAO,KAA8B,MAAM,OAAO,CAAA;AAKlD,KAAK,YAAY,GAAG,OAAO,GAAG;IAC5B,gBAAgB,EAAE,OAAO,CAAA;CAC1B,CAAA;AAED,eAAO,MAAM,OAAO,EAAE,KAAK,CAAC,EAAE,CAAC,YAAY,CA+F1C,CAAA"}
|
package/dist/ui/Preview.js
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
'use client';
|
|
2
|
-
import { useAllFormFields
|
|
2
|
+
import { useAllFormFields } from '@payloadcms/ui/forms/Form';
|
|
3
|
+
import { useDocumentInfo } from '@payloadcms/ui/providers/DocumentInfo';
|
|
4
|
+
import { useLocale } from '@payloadcms/ui/providers/Locale';
|
|
5
|
+
import { useTranslation } from '@payloadcms/ui/providers/Translation';
|
|
3
6
|
import React, { useEffect, useState } from 'react';
|
|
4
7
|
export const Preview = ({ hasGenerateURLFn })=>{
|
|
5
8
|
const { t } = useTranslation();
|
package/dist/ui/Preview.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/ui/Preview.tsx"],"sourcesContent":["'use client'\n\nimport type { FormField, UIField } from 'payload/types'\n\nimport { useAllFormFields
|
|
1
|
+
{"version":3,"sources":["../../src/ui/Preview.tsx"],"sourcesContent":["'use client'\n\nimport type { FormField, UIField } from 'payload/types'\n\nimport { useAllFormFields } from '@payloadcms/ui/forms/Form'\nimport { useDocumentInfo } from '@payloadcms/ui/providers/DocumentInfo'\nimport { useLocale } from '@payloadcms/ui/providers/Locale'\nimport { useTranslation } from '@payloadcms/ui/providers/Translation'\nimport React, { useEffect, useState } from 'react'\n\nimport type { GenerateURL } from '../types.js'\n\n// eslint-disable-next-line @typescript-eslint/no-redundant-type-constituents\ntype PreviewProps = UIField & {\n hasGenerateURLFn: boolean\n}\n\nexport const Preview: React.FC<PreviewProps> = ({ hasGenerateURLFn }) => {\n const { t } = useTranslation()\n\n const locale = useLocale()\n const [fields] = useAllFormFields()\n const docInfo = useDocumentInfo()\n\n const {\n 'meta.description': { value: metaDescription } = {} as FormField,\n 'meta.title': { value: metaTitle } = {} as FormField,\n } = fields\n\n const [href, setHref] = useState<string>()\n\n useEffect(() => {\n const getHref = async () => {\n const genURLResponse = await fetch('/api/plugin-seo/generate-url', {\n body: JSON.stringify({\n ...docInfo,\n doc: { ...fields },\n locale: typeof locale === 'object' ? locale?.code : locale,\n } satisfies Parameters<GenerateURL>[0]),\n credentials: 'include',\n headers: {\n 'Content-Type': 'application/json',\n },\n method: 'POST',\n })\n\n const { result: newHref } = await genURLResponse.json()\n\n setHref(newHref)\n }\n\n if (hasGenerateURLFn && !href) {\n void getHref()\n }\n }, [fields, href, locale, docInfo, hasGenerateURLFn])\n\n return (\n <div>\n <div>{t('plugin-seo:preview')}</div>\n <div\n style={{\n color: '#9A9A9A',\n marginBottom: '5px',\n }}\n >\n {t('plugin-seo:previewDescription')}\n </div>\n <div\n style={{\n background: 'var(--theme-elevation-50)',\n borderRadius: '5px',\n boxShadow: '0px 0px 10px rgba(0, 0, 0, 0.1)',\n maxWidth: '600px',\n padding: '20px',\n pointerEvents: 'none',\n width: '100%',\n }}\n >\n <div>\n <a\n href={href}\n style={{\n textDecoration: 'none',\n }}\n >\n {href || 'https://...'}\n </a>\n </div>\n <h4\n style={{\n margin: 0,\n }}\n >\n <a\n href=\"/\"\n style={{\n textDecoration: 'none',\n }}\n >\n {metaTitle as string}\n </a>\n </h4>\n <p\n style={{\n margin: 0,\n }}\n >\n {metaDescription as string}\n </p>\n </div>\n </div>\n )\n}\n"],"names":["useAllFormFields","useDocumentInfo","useLocale","useTranslation","React","useEffect","useState","Preview","hasGenerateURLFn","t","locale","fields","docInfo","value","metaDescription","metaTitle","href","setHref","getHref","genURLResponse","fetch","body","JSON","stringify","doc","code","credentials","headers","method","result","newHref","json","div","style","color","marginBottom","background","borderRadius","boxShadow","maxWidth","padding","pointerEvents","width","a","textDecoration","h4","margin","p"],"mappings":"AAAA;AAIA,SAASA,gBAAgB,QAAQ,4BAA2B;AAC5D,SAASC,eAAe,QAAQ,wCAAuC;AACvE,SAASC,SAAS,QAAQ,kCAAiC;AAC3D,SAASC,cAAc,QAAQ,uCAAsC;AACrE,OAAOC,SAASC,SAAS,EAAEC,QAAQ,QAAQ,QAAO;AASlD,OAAO,MAAMC,UAAkC,CAAC,EAAEC,gBAAgB,EAAE;IAClE,MAAM,EAAEC,CAAC,EAAE,GAAGN;IAEd,MAAMO,SAASR;IACf,MAAM,CAACS,OAAO,GAAGX;IACjB,MAAMY,UAAUX;IAEhB,MAAM,EACJ,oBAAoB,EAAEY,OAAOC,eAAe,EAAE,GAAG,CAAC,CAAc,EAChE,cAAc,EAAED,OAAOE,SAAS,EAAE,GAAG,CAAC,CAAc,EACrD,GAAGJ;IAEJ,MAAM,CAACK,MAAMC,QAAQ,GAAGX;IAExBD,UAAU;QACR,MAAMa,UAAU;YACd,MAAMC,iBAAiB,MAAMC,MAAM,gCAAgC;gBACjEC,MAAMC,KAAKC,SAAS,CAAC;oBACnB,GAAGX,OAAO;oBACVY,KAAK;wBAAE,GAAGb,MAAM;oBAAC;oBACjBD,QAAQ,OAAOA,WAAW,WAAWA,QAAQe,OAAOf;gBACtD;gBACAgB,aAAa;gBACbC,SAAS;oBACP,gBAAgB;gBAClB;gBACAC,QAAQ;YACV;YAEA,MAAM,EAAEC,QAAQC,OAAO,EAAE,GAAG,MAAMX,eAAeY,IAAI;YAErDd,QAAQa;QACV;QAEA,IAAItB,oBAAoB,CAACQ,MAAM;YAC7B,KAAKE;QACP;IACF,GAAG;QAACP;QAAQK;QAAMN;QAAQE;QAASJ;KAAiB;IAEpD,qBACE,oBAACwB,2BACC,oBAACA,aAAKvB,EAAE,sCACR,oBAACuB;QACCC,OAAO;YACLC,OAAO;YACPC,cAAc;QAChB;OAEC1B,EAAE,iDAEL,oBAACuB;QACCC,OAAO;YACLG,YAAY;YACZC,cAAc;YACdC,WAAW;YACXC,UAAU;YACVC,SAAS;YACTC,eAAe;YACfC,OAAO;QACT;qBAEA,oBAACV,2BACC,oBAACW;QACC3B,MAAMA;QACNiB,OAAO;YACLW,gBAAgB;QAClB;OAEC5B,QAAQ,+BAGb,oBAAC6B;QACCZ,OAAO;YACLa,QAAQ;QACV;qBAEA,oBAACH;QACC3B,MAAK;QACLiB,OAAO;YACLW,gBAAgB;QAClB;OAEC7B,2BAGL,oBAACgC;QACCd,OAAO;YACLa,QAAQ;QACV;OAEChC;AAKX,EAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@payloadcms/plugin-seo",
|
|
3
|
-
"version": "3.0.0-alpha.
|
|
3
|
+
"version": "3.0.0-alpha.49",
|
|
4
4
|
"homepage:": "https://payloadcms.com",
|
|
5
5
|
"repository": "git@github.com:payloadcms/plugin-seo.git",
|
|
6
6
|
"description": "SEO plugin for Payload",
|
|
@@ -20,17 +20,17 @@
|
|
|
20
20
|
"license": "MIT",
|
|
21
21
|
"peerDependencies": {
|
|
22
22
|
"react": "^18.0.0",
|
|
23
|
-
"payload": "3.0.0-alpha.
|
|
24
|
-
"@payloadcms/
|
|
25
|
-
"@payloadcms/
|
|
23
|
+
"payload": "3.0.0-alpha.49",
|
|
24
|
+
"@payloadcms/translations": "3.0.0-alpha.49",
|
|
25
|
+
"@payloadcms/ui": "3.0.0-alpha.49"
|
|
26
26
|
},
|
|
27
27
|
"devDependencies": {
|
|
28
28
|
"@types/react": "18.2.15",
|
|
29
29
|
"react": "^18.0.0",
|
|
30
30
|
"@payloadcms/eslint-config": "1.1.1",
|
|
31
|
-
"payload": "3.0.0-alpha.
|
|
32
|
-
"@payloadcms/
|
|
33
|
-
"@payloadcms/
|
|
31
|
+
"payload": "3.0.0-alpha.49",
|
|
32
|
+
"@payloadcms/translations": "3.0.0-alpha.49",
|
|
33
|
+
"@payloadcms/ui": "3.0.0-alpha.49"
|
|
34
34
|
},
|
|
35
35
|
"exports": null,
|
|
36
36
|
"publishConfig": {
|
package/src/index.tsx
ADDED
|
@@ -0,0 +1,279 @@
|
|
|
1
|
+
import type { Config } from 'payload/config'
|
|
2
|
+
import type { Field, GroupField, TabsField, TextField } from 'payload/types'
|
|
3
|
+
|
|
4
|
+
import { deepMerge } from 'payload/utilities'
|
|
5
|
+
import React from 'react'
|
|
6
|
+
|
|
7
|
+
import type {
|
|
8
|
+
GenerateDescription,
|
|
9
|
+
GenerateImage,
|
|
10
|
+
GenerateTitle,
|
|
11
|
+
GenerateURL,
|
|
12
|
+
PluginConfig,
|
|
13
|
+
} from './types.js'
|
|
14
|
+
|
|
15
|
+
import { MetaDescription } from './fields/MetaDescription.js'
|
|
16
|
+
import { MetaImage } from './fields/MetaImage.js'
|
|
17
|
+
import { MetaTitle } from './fields/MetaTitle.js'
|
|
18
|
+
import { translations } from './translations/index.js'
|
|
19
|
+
import { Overview } from './ui/Overview.js'
|
|
20
|
+
import { Preview } from './ui/Preview.js'
|
|
21
|
+
|
|
22
|
+
const seo =
|
|
23
|
+
(pluginConfig: PluginConfig) =>
|
|
24
|
+
(config: Config): Config => {
|
|
25
|
+
const seoFields: GroupField[] = [
|
|
26
|
+
{
|
|
27
|
+
name: 'meta',
|
|
28
|
+
type: 'group',
|
|
29
|
+
fields: [
|
|
30
|
+
{
|
|
31
|
+
name: 'overview',
|
|
32
|
+
type: 'ui',
|
|
33
|
+
admin: {
|
|
34
|
+
components: {
|
|
35
|
+
Field: Overview,
|
|
36
|
+
},
|
|
37
|
+
},
|
|
38
|
+
label: 'Overview',
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
name: 'title',
|
|
42
|
+
type: 'text',
|
|
43
|
+
admin: {
|
|
44
|
+
components: {
|
|
45
|
+
Field: (props) => (
|
|
46
|
+
<MetaTitle
|
|
47
|
+
{...props}
|
|
48
|
+
hasGenerateTitleFn={typeof pluginConfig.generateTitle === 'function'}
|
|
49
|
+
/>
|
|
50
|
+
),
|
|
51
|
+
},
|
|
52
|
+
},
|
|
53
|
+
localized: true,
|
|
54
|
+
...((pluginConfig?.fieldOverrides?.title as unknown as TextField) ?? {}),
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
name: 'description',
|
|
58
|
+
type: 'textarea',
|
|
59
|
+
admin: {
|
|
60
|
+
components: {
|
|
61
|
+
Field: (props) => (
|
|
62
|
+
<MetaDescription
|
|
63
|
+
{...props}
|
|
64
|
+
hasGenerateDescriptionFn={
|
|
65
|
+
typeof pluginConfig.generateDescription === 'function'
|
|
66
|
+
}
|
|
67
|
+
/>
|
|
68
|
+
),
|
|
69
|
+
},
|
|
70
|
+
},
|
|
71
|
+
localized: true,
|
|
72
|
+
...(pluginConfig?.fieldOverrides?.description ?? {}),
|
|
73
|
+
},
|
|
74
|
+
...(pluginConfig?.uploadsCollection
|
|
75
|
+
? [
|
|
76
|
+
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
|
77
|
+
{
|
|
78
|
+
name: 'image',
|
|
79
|
+
type: 'upload',
|
|
80
|
+
admin: {
|
|
81
|
+
components: {
|
|
82
|
+
Field: (props) => (
|
|
83
|
+
<MetaImage
|
|
84
|
+
{...props}
|
|
85
|
+
hasGenerateImageFn={typeof pluginConfig.generateImage === 'function'}
|
|
86
|
+
/>
|
|
87
|
+
),
|
|
88
|
+
},
|
|
89
|
+
description:
|
|
90
|
+
'Maximum upload file size: 12MB. Recommended file size for images is <500KB.',
|
|
91
|
+
},
|
|
92
|
+
label: 'Meta Image',
|
|
93
|
+
localized: true,
|
|
94
|
+
relationTo: pluginConfig?.uploadsCollection,
|
|
95
|
+
...(pluginConfig?.fieldOverrides?.image ?? {}),
|
|
96
|
+
} as Field,
|
|
97
|
+
]
|
|
98
|
+
: []),
|
|
99
|
+
...(pluginConfig?.fields || []),
|
|
100
|
+
{
|
|
101
|
+
name: 'preview',
|
|
102
|
+
type: 'ui',
|
|
103
|
+
admin: {
|
|
104
|
+
components: {
|
|
105
|
+
Field: (props) => (
|
|
106
|
+
<Preview
|
|
107
|
+
{...props}
|
|
108
|
+
hasGenerateURLFn={typeof pluginConfig.generateURL === 'function'}
|
|
109
|
+
/>
|
|
110
|
+
),
|
|
111
|
+
},
|
|
112
|
+
},
|
|
113
|
+
label: 'Preview',
|
|
114
|
+
},
|
|
115
|
+
],
|
|
116
|
+
interfaceName: pluginConfig.interfaceName,
|
|
117
|
+
label: 'SEO',
|
|
118
|
+
},
|
|
119
|
+
]
|
|
120
|
+
|
|
121
|
+
return {
|
|
122
|
+
...config,
|
|
123
|
+
collections:
|
|
124
|
+
config.collections?.map((collection) => {
|
|
125
|
+
const { slug } = collection
|
|
126
|
+
const isEnabled = pluginConfig?.collections?.includes(slug)
|
|
127
|
+
|
|
128
|
+
if (isEnabled) {
|
|
129
|
+
if (pluginConfig?.tabbedUI) {
|
|
130
|
+
// prevent issues with auth enabled collections having an email field that shouldn't be moved to the SEO tab
|
|
131
|
+
const emailField =
|
|
132
|
+
(collection.auth ||
|
|
133
|
+
!(typeof collection.auth === 'object' && collection.auth.disableLocalStrategy)) &&
|
|
134
|
+
collection.fields?.find((field) => 'name' in field && field.name === 'email')
|
|
135
|
+
|
|
136
|
+
const seoTabs: TabsField[] = [
|
|
137
|
+
{
|
|
138
|
+
type: 'tabs',
|
|
139
|
+
tabs: [
|
|
140
|
+
// append a new tab onto the end of the tabs array, if there is one at the first index
|
|
141
|
+
// if needed, create a new `Content` tab in the first index for this collection's base fields
|
|
142
|
+
...(collection?.fields?.[0]?.type === 'tabs' && collection?.fields?.[0]?.tabs
|
|
143
|
+
? collection.fields[0].tabs
|
|
144
|
+
: [
|
|
145
|
+
{
|
|
146
|
+
fields: [
|
|
147
|
+
...((emailField
|
|
148
|
+
? collection.fields.filter(
|
|
149
|
+
(field) => 'name' in field && field.name !== 'email',
|
|
150
|
+
)
|
|
151
|
+
: collection.fields) || []),
|
|
152
|
+
],
|
|
153
|
+
label: collection?.labels?.singular || 'Content',
|
|
154
|
+
},
|
|
155
|
+
]),
|
|
156
|
+
{
|
|
157
|
+
fields: seoFields,
|
|
158
|
+
label: 'SEO',
|
|
159
|
+
},
|
|
160
|
+
],
|
|
161
|
+
},
|
|
162
|
+
]
|
|
163
|
+
|
|
164
|
+
return {
|
|
165
|
+
...collection,
|
|
166
|
+
fields: [
|
|
167
|
+
...(emailField ? [emailField] : []),
|
|
168
|
+
...seoTabs,
|
|
169
|
+
...(collection?.fields?.[0]?.type === 'tabs' ? collection.fields.slice(1) : []),
|
|
170
|
+
],
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
return {
|
|
175
|
+
...collection,
|
|
176
|
+
fields: [...(collection?.fields || []), ...seoFields],
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
return collection
|
|
181
|
+
}) || [],
|
|
182
|
+
endpoints: [
|
|
183
|
+
{
|
|
184
|
+
handler: async (req) => {
|
|
185
|
+
const args: Parameters<GenerateTitle>[0] =
|
|
186
|
+
req.data as unknown as Parameters<GenerateTitle>[0]
|
|
187
|
+
const result = await pluginConfig.generateTitle(args)
|
|
188
|
+
return new Response(JSON.stringify({ result }), { status: 200 })
|
|
189
|
+
},
|
|
190
|
+
method: 'post',
|
|
191
|
+
path: '/plugin-seo/generate-title',
|
|
192
|
+
},
|
|
193
|
+
{
|
|
194
|
+
handler: async (req) => {
|
|
195
|
+
const args: Parameters<GenerateDescription>[0] =
|
|
196
|
+
req.data as unknown as Parameters<GenerateDescription>[0]
|
|
197
|
+
const result = await pluginConfig.generateDescription(args)
|
|
198
|
+
return new Response(JSON.stringify({ result }), { status: 200 })
|
|
199
|
+
},
|
|
200
|
+
method: 'post',
|
|
201
|
+
path: '/plugin-seo/generate-description',
|
|
202
|
+
},
|
|
203
|
+
{
|
|
204
|
+
handler: async (req) => {
|
|
205
|
+
const args: Parameters<GenerateURL>[0] =
|
|
206
|
+
req.data as unknown as Parameters<GenerateURL>[0]
|
|
207
|
+
const result = await pluginConfig.generateURL(args)
|
|
208
|
+
return new Response(JSON.stringify({ result }), { status: 200 })
|
|
209
|
+
},
|
|
210
|
+
method: 'post',
|
|
211
|
+
path: '/plugin-seo/generate-url',
|
|
212
|
+
},
|
|
213
|
+
{
|
|
214
|
+
handler: async (req) => {
|
|
215
|
+
const args: Parameters<GenerateImage>[0] =
|
|
216
|
+
req.data as unknown as Parameters<GenerateImage>[0]
|
|
217
|
+
const result = await pluginConfig.generateImage(args)
|
|
218
|
+
return new Response(result, { status: 200 })
|
|
219
|
+
},
|
|
220
|
+
method: 'post',
|
|
221
|
+
path: '/plugin-seo/generate-image',
|
|
222
|
+
},
|
|
223
|
+
],
|
|
224
|
+
globals:
|
|
225
|
+
config.globals?.map((global) => {
|
|
226
|
+
const { slug } = global
|
|
227
|
+
const isEnabled = pluginConfig?.globals?.includes(slug)
|
|
228
|
+
|
|
229
|
+
if (isEnabled) {
|
|
230
|
+
if (pluginConfig?.tabbedUI) {
|
|
231
|
+
const seoTabs: TabsField[] = [
|
|
232
|
+
{
|
|
233
|
+
type: 'tabs',
|
|
234
|
+
tabs: [
|
|
235
|
+
// append a new tab onto the end of the tabs array, if there is one at the first index
|
|
236
|
+
// if needed, create a new `Content` tab in the first index for this global's base fields
|
|
237
|
+
...(global?.fields?.[0].type === 'tabs' && global?.fields?.[0].tabs
|
|
238
|
+
? global.fields[0].tabs
|
|
239
|
+
: [
|
|
240
|
+
{
|
|
241
|
+
fields: [...(global?.fields || [])],
|
|
242
|
+
label: global?.label || 'Content',
|
|
243
|
+
},
|
|
244
|
+
]),
|
|
245
|
+
{
|
|
246
|
+
fields: seoFields,
|
|
247
|
+
label: 'SEO',
|
|
248
|
+
},
|
|
249
|
+
],
|
|
250
|
+
},
|
|
251
|
+
]
|
|
252
|
+
|
|
253
|
+
return {
|
|
254
|
+
...global,
|
|
255
|
+
fields: [
|
|
256
|
+
...seoTabs,
|
|
257
|
+
...(global?.fields?.[0].type === 'tabs' ? global.fields.slice(1) : []),
|
|
258
|
+
],
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
return {
|
|
263
|
+
...global,
|
|
264
|
+
fields: [...(global?.fields || []), ...seoFields],
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
return global
|
|
269
|
+
}) || [],
|
|
270
|
+
i18n: {
|
|
271
|
+
...config.i18n,
|
|
272
|
+
translations: {
|
|
273
|
+
...deepMerge(translations, config.i18n?.translations),
|
|
274
|
+
},
|
|
275
|
+
},
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
export { seo }
|