@justanarthur/payload-plugin-seo 1.3.6
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 +16 -0
- package/dist/defaults.d.ts +11 -0
- package/dist/defaults.d.ts.map +1 -0
- package/dist/exports/client.d.ts +6 -0
- package/dist/exports/client.d.ts.map +1 -0
- package/dist/exports/fields-components.d.ts +6 -0
- package/dist/exports/fields-components.d.ts.map +1 -0
- package/dist/exports/fields.d.ts +6 -0
- package/dist/exports/fields.d.ts.map +1 -0
- package/dist/exports/types.d.ts +2 -0
- package/dist/exports/types.d.ts.map +1 -0
- package/dist/fields/MetaDescription/MetaDescriptionComponent.d.ts +9 -0
- package/dist/fields/MetaDescription/MetaDescriptionComponent.d.ts.map +1 -0
- package/dist/fields/MetaDescription/index.d.ts +16 -0
- package/dist/fields/MetaDescription/index.d.ts.map +1 -0
- package/dist/fields/MetaImage/MetaImageComponent.d.ts +8 -0
- package/dist/fields/MetaImage/MetaImageComponent.d.ts.map +1 -0
- package/dist/fields/MetaImage/index.d.ts +13 -0
- package/dist/fields/MetaImage/index.d.ts.map +1 -0
- package/dist/fields/MetaTitle/MetaTitleComponent.d.ts +10 -0
- package/dist/fields/MetaTitle/MetaTitleComponent.d.ts.map +1 -0
- package/dist/fields/MetaTitle/index.d.ts +16 -0
- package/dist/fields/MetaTitle/index.d.ts.map +1 -0
- package/dist/fields/Overview/OverviewComponent.d.ts +18 -0
- package/dist/fields/Overview/OverviewComponent.d.ts.map +1 -0
- package/dist/fields/Overview/index.d.ts +34 -0
- package/dist/fields/Overview/index.d.ts.map +1 -0
- package/dist/fields/Preview/PreviewComponent.d.ts +9 -0
- package/dist/fields/Preview/PreviewComponent.d.ts.map +1 -0
- package/dist/fields/Preview/index.d.ts +24 -0
- package/dist/fields/Preview/index.d.ts.map +1 -0
- package/dist/fields/index.scss +7 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/openai/message.d.ts +7 -0
- package/dist/openai/message.d.ts.map +1 -0
- package/dist/src/defaults.js +12 -0
- package/dist/src/defaults.js.map +1 -0
- package/dist/src/exports/client.js +7 -0
- package/dist/src/exports/client.js.map +1 -0
- package/dist/src/exports/fields-components.js +7 -0
- package/dist/src/exports/fields-components.js.map +1 -0
- package/dist/src/exports/fields.js +7 -0
- package/dist/src/exports/fields.js.map +1 -0
- package/dist/src/exports/types.js +3 -0
- package/dist/src/exports/types.js.map +1 -0
- package/dist/src/fields/MetaDescription/MetaDescriptionComponent.js +224 -0
- package/dist/src/fields/MetaDescription/MetaDescriptionComponent.js.map +1 -0
- package/dist/src/fields/MetaDescription/index.js +22 -0
- package/dist/src/fields/MetaDescription/index.js.map +1 -0
- package/dist/src/fields/MetaImage/MetaImageComponent.js +173 -0
- package/dist/src/fields/MetaImage/MetaImageComponent.js.map +1 -0
- package/dist/src/fields/MetaImage/index.js +24 -0
- package/dist/src/fields/MetaImage/index.js.map +1 -0
- package/dist/src/fields/MetaTitle/MetaTitleComponent.js +225 -0
- package/dist/src/fields/MetaTitle/MetaTitleComponent.js.map +1 -0
- package/dist/src/fields/MetaTitle/index.js +22 -0
- package/dist/src/fields/MetaTitle/index.js.map +1 -0
- package/dist/src/fields/Overview/OverviewComponent.js +67 -0
- package/dist/src/fields/Overview/OverviewComponent.js.map +1 -0
- package/dist/src/fields/Overview/index.js +25 -0
- package/dist/src/fields/Overview/index.js.map +1 -0
- package/dist/src/fields/Preview/PreviewComponent.js +117 -0
- package/dist/src/fields/Preview/PreviewComponent.js.map +1 -0
- package/dist/src/fields/Preview/index.js +23 -0
- package/dist/src/fields/Preview/index.js.map +1 -0
- package/dist/src/index.js +309 -0
- package/dist/src/index.js.map +1 -0
- package/dist/src/openai/message.js +28 -0
- package/dist/src/openai/message.js.map +1 -0
- package/dist/src/translations/cs.js +26 -0
- package/dist/src/translations/cs.js.map +1 -0
- package/dist/src/translations/de.js +26 -0
- package/dist/src/translations/de.js.map +1 -0
- package/dist/src/translations/en.js +27 -0
- package/dist/src/translations/en.js.map +1 -0
- package/dist/src/translations/es.js +26 -0
- package/dist/src/translations/es.js.map +1 -0
- package/dist/src/translations/fa.js +26 -0
- package/dist/src/translations/fa.js.map +1 -0
- package/dist/src/translations/fr.js +26 -0
- package/dist/src/translations/fr.js.map +1 -0
- package/dist/src/translations/index.js +30 -0
- package/dist/src/translations/index.js.map +1 -0
- package/dist/src/translations/it.js +26 -0
- package/dist/src/translations/it.js.map +1 -0
- package/dist/src/translations/nb.js +26 -0
- package/dist/src/translations/nb.js.map +1 -0
- package/dist/src/translations/pl.js +26 -0
- package/dist/src/translations/pl.js.map +1 -0
- package/dist/src/translations/ru.js +26 -0
- package/dist/src/translations/ru.js.map +1 -0
- package/dist/src/translations/sv.js +26 -0
- package/dist/src/translations/sv.js.map +1 -0
- package/dist/src/translations/tr.js +26 -0
- package/dist/src/translations/tr.js.map +1 -0
- package/dist/src/translations/uk.js +26 -0
- package/dist/src/translations/uk.js.map +1 -0
- package/dist/src/translations/vi.js +26 -0
- package/dist/src/translations/vi.js.map +1 -0
- package/dist/src/types.js +3 -0
- package/dist/src/types.js.map +1 -0
- package/dist/src/ui/LengthIndicator.js +135 -0
- package/dist/src/ui/LengthIndicator.js.map +1 -0
- package/dist/src/ui/Pill.js +23 -0
- package/dist/src/ui/Pill.js.map +1 -0
- package/dist/translations/cs.d.ts +3 -0
- package/dist/translations/cs.d.ts.map +1 -0
- package/dist/translations/de.d.ts +3 -0
- package/dist/translations/de.d.ts.map +1 -0
- package/dist/translations/en.d.ts +3 -0
- package/dist/translations/en.d.ts.map +1 -0
- package/dist/translations/es.d.ts +3 -0
- package/dist/translations/es.d.ts.map +1 -0
- package/dist/translations/fa.d.ts +3 -0
- package/dist/translations/fa.d.ts.map +1 -0
- package/dist/translations/fr.d.ts +3 -0
- package/dist/translations/fr.d.ts.map +1 -0
- package/dist/translations/index.d.ts +19 -0
- package/dist/translations/index.d.ts.map +1 -0
- package/dist/translations/it.d.ts +3 -0
- package/dist/translations/it.d.ts.map +1 -0
- package/dist/translations/nb.d.ts +3 -0
- package/dist/translations/nb.d.ts.map +1 -0
- package/dist/translations/pl.d.ts +3 -0
- package/dist/translations/pl.d.ts.map +1 -0
- package/dist/translations/ru.d.ts +3 -0
- package/dist/translations/ru.d.ts.map +1 -0
- package/dist/translations/sv.d.ts +3 -0
- package/dist/translations/sv.d.ts.map +1 -0
- package/dist/translations/tr.d.ts +3 -0
- package/dist/translations/tr.d.ts.map +1 -0
- package/dist/translations/translation-schema.json +96 -0
- package/dist/translations/uk.d.ts +3 -0
- package/dist/translations/uk.d.ts.map +1 -0
- package/dist/translations/vi.d.ts +3 -0
- package/dist/translations/vi.d.ts.map +1 -0
- package/dist/types.d.ts +82 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/ui/LengthIndicator.d.ts +7 -0
- package/dist/ui/LengthIndicator.d.ts.map +1 -0
- package/dist/ui/Pill.d.ts +7 -0
- package/dist/ui/Pill.d.ts.map +1 -0
- package/package.json +59 -0
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
3
|
+
import { useAllFormFields, useForm, useTranslation } from '@payloadcms/ui';
|
|
4
|
+
import React, { useCallback, useEffect, useState } from 'react';
|
|
5
|
+
import { defaults } from '../../defaults';
|
|
6
|
+
const { description: { maxLength: maxDescDefault, minLength: minDescDefault }, title: { maxLength: maxTitleDefault, minLength: minTitleDefault } } = defaults;
|
|
7
|
+
export const OverviewComponent = ({ descriptionOverrides, descriptionPath: descriptionPathFromContext, imagePath: imagePathFromContext, titleOverrides, titlePath: titlePathFromContext })=>{
|
|
8
|
+
const { getFields } = useForm();
|
|
9
|
+
const descriptionPath = descriptionPathFromContext || 'meta.description';
|
|
10
|
+
const titlePath = titlePathFromContext || 'meta.title';
|
|
11
|
+
const imagePath = imagePathFromContext || 'meta.image';
|
|
12
|
+
const [{ [descriptionPath]: { value: metaDesc } = {}, [imagePath]: { value: metaImage } = {}, [titlePath]: { value: metaTitle } = {} }] = useAllFormFields();
|
|
13
|
+
const { t } = useTranslation();
|
|
14
|
+
const [titleIsValid, setTitleIsValid] = useState();
|
|
15
|
+
const [descIsValid, setDescIsValid] = useState();
|
|
16
|
+
const [imageIsValid, setImageIsValid] = useState();
|
|
17
|
+
const minDesc = descriptionOverrides?.minLength || minDescDefault;
|
|
18
|
+
const maxDesc = descriptionOverrides?.maxLength || maxDescDefault;
|
|
19
|
+
const minTitle = titleOverrides?.minLength || minTitleDefault;
|
|
20
|
+
const maxTitle = titleOverrides?.maxLength || maxTitleDefault;
|
|
21
|
+
const resetAll = useCallback(()=>{
|
|
22
|
+
const fields = getFields();
|
|
23
|
+
const fieldsWithoutMeta = fields;
|
|
24
|
+
fieldsWithoutMeta['meta.title'].value = '';
|
|
25
|
+
fieldsWithoutMeta['meta.description'].value = '';
|
|
26
|
+
fieldsWithoutMeta['meta.image'].value = '';
|
|
27
|
+
// dispatchFields(fieldsWithoutMeta);
|
|
28
|
+
}, [
|
|
29
|
+
getFields
|
|
30
|
+
]);
|
|
31
|
+
useEffect(()=>{
|
|
32
|
+
if (typeof metaTitle === 'string') {
|
|
33
|
+
setTitleIsValid(metaTitle.length >= minTitle && metaTitle.length <= maxTitle);
|
|
34
|
+
}
|
|
35
|
+
if (typeof metaDesc === 'string') {
|
|
36
|
+
setDescIsValid(metaDesc.length >= minDesc && metaDesc.length <= maxDesc);
|
|
37
|
+
}
|
|
38
|
+
setImageIsValid(Boolean(metaImage));
|
|
39
|
+
}, [
|
|
40
|
+
metaTitle,
|
|
41
|
+
metaDesc,
|
|
42
|
+
metaImage,
|
|
43
|
+
maxDesc,
|
|
44
|
+
maxTitle,
|
|
45
|
+
minDesc,
|
|
46
|
+
minTitle
|
|
47
|
+
]);
|
|
48
|
+
const testResults = [
|
|
49
|
+
titleIsValid,
|
|
50
|
+
descIsValid,
|
|
51
|
+
imageIsValid
|
|
52
|
+
];
|
|
53
|
+
const numberOfPasses = testResults.filter(Boolean).length;
|
|
54
|
+
return /*#__PURE__*/ _jsx("div", {
|
|
55
|
+
style: {
|
|
56
|
+
marginBottom: '20px'
|
|
57
|
+
},
|
|
58
|
+
children: /*#__PURE__*/ _jsx("div", {
|
|
59
|
+
children: t('plugin-seo:checksPassing', {
|
|
60
|
+
current: numberOfPasses,
|
|
61
|
+
max: testResults.length
|
|
62
|
+
})
|
|
63
|
+
})
|
|
64
|
+
});
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
//# sourceMappingURL=OverviewComponent.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../src/fields/Overview/OverviewComponent.tsx"],"sourcesContent":["'use client'\n\nimport { useAllFormFields, useForm, useTranslation } from '@payloadcms/ui'\nimport type { FormField, UIField } from 'payload'\nimport React, { useCallback, useEffect, useState } from 'react'\n\nimport { defaults } from '../../defaults'\nimport type { PluginSEOTranslationKeys, PluginSEOTranslations } from '../../translations'\n\nconst {\n description: { maxLength: maxDescDefault, minLength: minDescDefault },\n title: { maxLength: maxTitleDefault, minLength: minTitleDefault },\n} = defaults\n\ntype OverviewProps = {\n descriptionOverrides?: {\n maxLength?: number\n minLength?: number\n }\n descriptionPath?: string\n imagePath?: string\n titleOverrides?: {\n maxLength?: number\n minLength?: number\n }\n titlePath?: string\n} & UIField\n\nexport const OverviewComponent: React.FC<OverviewProps> = ({\n descriptionOverrides,\n descriptionPath: descriptionPathFromContext,\n imagePath: imagePathFromContext,\n titleOverrides,\n titlePath: titlePathFromContext,\n}) => {\n const { getFields } = useForm()\n\n const descriptionPath = descriptionPathFromContext || 'meta.description'\n\n const titlePath = titlePathFromContext || 'meta.title'\n\n const imagePath = imagePathFromContext || 'meta.image'\n\n const [\n {\n [descriptionPath]: { value: metaDesc } = {} as FormField,\n [imagePath]: { value: metaImage } = {} as FormField,\n [titlePath]: { value: metaTitle } = {} as FormField,\n },\n ] = useAllFormFields()\n\n const { t } = useTranslation<PluginSEOTranslations, PluginSEOTranslationKeys>()\n\n const [titleIsValid, setTitleIsValid] = useState<boolean | undefined>()\n\n const [descIsValid, setDescIsValid] = useState<boolean | undefined>()\n\n const [imageIsValid, setImageIsValid] = useState<boolean | undefined>()\n\n const minDesc = descriptionOverrides?.minLength || minDescDefault\n\n const maxDesc = descriptionOverrides?.maxLength || maxDescDefault\n\n const minTitle = titleOverrides?.minLength || minTitleDefault\n\n const maxTitle = titleOverrides?.maxLength || maxTitleDefault\n\n const resetAll = useCallback(() => {\n const fields = getFields()\n\n const fieldsWithoutMeta = fields\n\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 }\n if (typeof metaDesc === 'string') {\n setDescIsValid(metaDesc.length >= minDesc && metaDesc.length <= maxDesc)\n }\n setImageIsValid(Boolean(metaImage))\n }, [metaTitle, metaDesc, metaImage, maxDesc, maxTitle, minDesc, minTitle])\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', {\n current: numberOfPasses,\n max: testResults.length,\n })}\n </div>\n </div>\n )\n}\n"],"names":["useAllFormFields","useForm","useTranslation","React","useCallback","useEffect","useState","defaults","description","maxLength","maxDescDefault","minLength","minDescDefault","title","maxTitleDefault","minTitleDefault","OverviewComponent","descriptionOverrides","descriptionPath","descriptionPathFromContext","imagePath","imagePathFromContext","titleOverrides","titlePath","titlePathFromContext","getFields","value","metaDesc","metaImage","metaTitle","t","titleIsValid","setTitleIsValid","descIsValid","setDescIsValid","imageIsValid","setImageIsValid","minDesc","maxDesc","minTitle","maxTitle","resetAll","fields","fieldsWithoutMeta","length","Boolean","testResults","numberOfPasses","filter","div","style","marginBottom","current","max"],"mappings":"AAAA;;AAEA,SAASA,gBAAgB,EAAEC,OAAO,EAAEC,cAAc,QAAQ,iBAAgB;AAE1E,OAAOC,SAASC,WAAW,EAAEC,SAAS,EAAEC,QAAQ,QAAQ,QAAO;AAE/D,SAASC,QAAQ,QAAQ,iBAAgB;AAGzC,MAAM,EACJC,aAAa,EAAEC,WAAWC,cAAc,EAAEC,WAAWC,cAAc,EAAE,EACrEC,OAAO,EAAEJ,WAAWK,eAAe,EAAEH,WAAWI,eAAe,EAAE,EAClE,GAAGR;AAgBJ,OAAO,MAAMS,oBAA6C,CAAC,EACzDC,oBAAoB,EACpBC,iBAAiBC,0BAA0B,EAC3CC,WAAWC,oBAAoB,EAC/BC,cAAc,EACdC,WAAWC,oBAAoB,EAChC;IACC,MAAM,EAAEC,SAAS,EAAE,GAAGxB;IAEtB,MAAMiB,kBAAkBC,8BAA8B;IAEtD,MAAMI,YAAYC,wBAAwB;IAE1C,MAAMJ,YAAYC,wBAAwB;IAE1C,MAAM,CACJ,EACE,CAACH,gBAAgB,EAAE,EAAEQ,OAAOC,QAAQ,EAAE,GAAG,CAAC,CAAc,EACxD,CAACP,UAAU,EAAE,EAAEM,OAAOE,SAAS,EAAE,GAAG,CAAC,CAAc,EACnD,CAACL,UAAU,EAAE,EAAEG,OAAOG,SAAS,EAAE,GAAG,CAAC,CAAc,EACpD,CACF,GAAG7B;IAEJ,MAAM,EAAE8B,CAAC,EAAE,GAAG5B;IAEd,MAAM,CAAC6B,cAAcC,gBAAgB,GAAG1B;IAExC,MAAM,CAAC2B,aAAaC,eAAe,GAAG5B;IAEtC,MAAM,CAAC6B,cAAcC,gBAAgB,GAAG9B;IAExC,MAAM+B,UAAUpB,sBAAsBN,aAAaC;IAEnD,MAAM0B,UAAUrB,sBAAsBR,aAAaC;IAEnD,MAAM6B,WAAWjB,gBAAgBX,aAAaI;IAE9C,MAAMyB,WAAWlB,gBAAgBb,aAAaK;IAE9C,MAAM2B,WAAWrC,YAAY;QAC3B,MAAMsC,SAASjB;QAEf,MAAMkB,oBAAoBD;QAE1BC,iBAAiB,CAAC,aAAa,CAACjB,KAAK,GAAG;QACxCiB,iBAAiB,CAAC,mBAAmB,CAACjB,KAAK,GAAG;QAC9CiB,iBAAiB,CAAC,aAAa,CAACjB,KAAK,GAAG;IACxC,qCAAqC;IACvC,GAAG;QAACD;KAAU;IAEdpB,UAAU;QACR,IAAI,OAAOwB,cAAc,UAAU;YACjCG,gBAAgBH,UAAUe,MAAM,IAAIL,YAAYV,UAAUe,MAAM,IAAIJ;QACtE;QACA,IAAI,OAAOb,aAAa,UAAU;YAChCO,eAAeP,SAASiB,MAAM,IAAIP,WAAWV,SAASiB,MAAM,IAAIN;QAClE;QACAF,gBAAgBS,QAAQjB;IAC1B,GAAG;QAACC;QAAWF;QAAUC;QAAWU;QAASE;QAAUH;QAASE;KAAS;IAEzE,MAAMO,cAAc;QAACf;QAAcE;QAAaE;KAAa;IAE7D,MAAMY,iBAAiBD,YAAYE,MAAM,CAACH,SAASD,MAAM;IAEzD,qBACE,KAACK;QACCC,OAAO;YACLC,cAAc;QAChB;kBAEA,cAAA,KAACF;sBACEnB,EAAE,4BAA4B;gBAC7BsB,SAASL;gBACTM,KAAKP,YAAYF,MAAM;YACzB;;;AAIR,EAAC"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
// @ts-nocheck
|
|
2
|
+
export const OverviewField = ({ descriptionOverrides, descriptionPath, imagePath, overrides, titleOverrides, titlePath })=>{
|
|
3
|
+
return {
|
|
4
|
+
admin: {
|
|
5
|
+
components: {
|
|
6
|
+
Field: {
|
|
7
|
+
clientProps: {
|
|
8
|
+
descriptionOverrides,
|
|
9
|
+
descriptionPath,
|
|
10
|
+
imagePath,
|
|
11
|
+
titleOverrides,
|
|
12
|
+
titlePath
|
|
13
|
+
},
|
|
14
|
+
path: '@justanarthur/payload-plugin-seo/fields-components#OverviewComponent'
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
},
|
|
18
|
+
label: 'Overview',
|
|
19
|
+
name: 'overview',
|
|
20
|
+
type: 'ui',
|
|
21
|
+
...overrides ?? {}
|
|
22
|
+
};
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../src/fields/Overview/index.tsx"],"sourcesContent":["// @ts-nocheck\nimport type { UIField } from 'payload'\n\ntype FieldFunctionProps = {\n descriptionOverrides?: {\n maxLength?: number\n minLength?: number\n }\n /**\n * Path to the description field to use for the preview\n *\n * @default 'meta.description'\n */\n descriptionPath?: string\n /**\n * Path to the image field to use for the preview\n *\n * @default 'meta.image'\n */\n imagePath?: string\n overrides?: Partial<UIField>\n titleOverrides?: {\n maxLength?: number\n minLength?: number\n }\n /**\n * Path to the title field to use for the preview\n *\n * @default 'meta.title'\n */\n titlePath?: string\n}\n\ntype FieldFunction = ({ overrides }: FieldFunctionProps) => UIField\n\nexport const OverviewField: FieldFunction = ({\n descriptionOverrides,\n descriptionPath,\n imagePath,\n overrides,\n titleOverrides,\n titlePath,\n}) => {\n return {\n admin: {\n components: {\n Field: {\n clientProps: {\n descriptionOverrides,\n descriptionPath,\n imagePath,\n titleOverrides,\n titlePath,\n },\n path: '@justanarthur/payload-plugin-seo/fields-components#OverviewComponent',\n },\n },\n },\n label: 'Overview',\n name: 'overview',\n type: 'ui',\n ...((overrides as unknown as UIField) ?? {}),\n }\n}\n"],"names":["OverviewField","descriptionOverrides","descriptionPath","imagePath","overrides","titleOverrides","titlePath","admin","components","Field","clientProps","path","label","name","type"],"mappings":"AAAA,cAAc;AAmCd,OAAO,MAAMA,gBAA+B,CAAC,EAC3CC,oBAAoB,EACpBC,eAAe,EACfC,SAAS,EACTC,SAAS,EACTC,cAAc,EACdC,SAAS,EACV;IACC,OAAO;QACLC,OAAO;YACLC,YAAY;gBACVC,OAAO;oBACLC,aAAa;wBACXT;wBACAC;wBACAC;wBACAE;wBACAC;oBACF;oBACAK,MAAM;gBACR;YACF;QACF;QACAC,OAAO;QACPC,MAAM;QACNC,MAAM;QACN,GAAI,AAACV,aAAoC,CAAC,CAAC;IAC7C;AACF,EAAC"}
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { useAllFormFields, useConfig, useDocumentInfo, useForm, useLocale, useTranslation } from '@payloadcms/ui';
|
|
4
|
+
import { reduceToSerializableFields } from '@payloadcms/ui/shared';
|
|
5
|
+
import { useEffect, useState } from 'react';
|
|
6
|
+
export const PreviewComponent = (props)=>{
|
|
7
|
+
const { descriptionPath: descriptionPathFromContext, hasGenerateURLFn, titlePath: titlePathFromContext } = props;
|
|
8
|
+
const { t } = useTranslation();
|
|
9
|
+
const { config: { routes: { api }, serverURL } } = useConfig();
|
|
10
|
+
const locale = useLocale();
|
|
11
|
+
const [fields] = useAllFormFields();
|
|
12
|
+
const { getData } = useForm();
|
|
13
|
+
const docInfo = useDocumentInfo();
|
|
14
|
+
const descriptionPath = descriptionPathFromContext || 'meta.description';
|
|
15
|
+
const titlePath = titlePathFromContext || 'meta.title';
|
|
16
|
+
const { [descriptionPath]: { value: metaDescription } = {}, [titlePath]: { value: metaTitle } = {} } = fields;
|
|
17
|
+
const [href, setHref] = useState();
|
|
18
|
+
// biome-ignore lint/correctness/useExhaustiveDependencies: <explanation>
|
|
19
|
+
useEffect(()=>{
|
|
20
|
+
const endpoint = `${serverURL}${api}/plugin-seo/generate-url`;
|
|
21
|
+
const getHref = async ()=>{
|
|
22
|
+
const genURLResponse = await fetch(endpoint, {
|
|
23
|
+
body: JSON.stringify({
|
|
24
|
+
collectionSlug: docInfo.collectionSlug,
|
|
25
|
+
doc: getData(),
|
|
26
|
+
docPermissions: docInfo.docPermissions,
|
|
27
|
+
globalSlug: docInfo.globalSlug,
|
|
28
|
+
hasPublishPermission: docInfo.hasPublishPermission,
|
|
29
|
+
hasSavePermission: docInfo.hasSavePermission,
|
|
30
|
+
id: docInfo.id,
|
|
31
|
+
initialData: docInfo.initialData,
|
|
32
|
+
initialState: docInfo.initialState ? reduceToSerializableFields(docInfo.initialState) : undefined,
|
|
33
|
+
locale: typeof locale === 'object' ? locale?.code : locale,
|
|
34
|
+
title: docInfo.title
|
|
35
|
+
}),
|
|
36
|
+
credentials: 'include',
|
|
37
|
+
headers: {
|
|
38
|
+
'Content-Type': 'application/json'
|
|
39
|
+
},
|
|
40
|
+
method: 'POST'
|
|
41
|
+
});
|
|
42
|
+
const { result: newHref } = await genURLResponse.json();
|
|
43
|
+
setHref(newHref);
|
|
44
|
+
};
|
|
45
|
+
if (hasGenerateURLFn && !href) {
|
|
46
|
+
void getHref();
|
|
47
|
+
}
|
|
48
|
+
}, [
|
|
49
|
+
fields,
|
|
50
|
+
href,
|
|
51
|
+
locale,
|
|
52
|
+
docInfo,
|
|
53
|
+
hasGenerateURLFn,
|
|
54
|
+
getData,
|
|
55
|
+
serverURL,
|
|
56
|
+
api
|
|
57
|
+
]);
|
|
58
|
+
return /*#__PURE__*/ _jsxs("div", {
|
|
59
|
+
style: {
|
|
60
|
+
marginBottom: '20px'
|
|
61
|
+
},
|
|
62
|
+
children: [
|
|
63
|
+
/*#__PURE__*/ _jsx("div", {
|
|
64
|
+
children: t('plugin-seo:preview')
|
|
65
|
+
}),
|
|
66
|
+
/*#__PURE__*/ _jsx("div", {
|
|
67
|
+
style: {
|
|
68
|
+
color: '#9A9A9A',
|
|
69
|
+
marginBottom: '5px'
|
|
70
|
+
},
|
|
71
|
+
children: t('plugin-seo:previewDescription')
|
|
72
|
+
}),
|
|
73
|
+
/*#__PURE__*/ _jsxs("div", {
|
|
74
|
+
style: {
|
|
75
|
+
background: 'var(--theme-elevation-50)',
|
|
76
|
+
borderRadius: '5px',
|
|
77
|
+
boxShadow: '0px 0px 10px rgba(0, 0, 0, 0.1)',
|
|
78
|
+
maxWidth: '600px',
|
|
79
|
+
padding: '20px',
|
|
80
|
+
pointerEvents: 'none',
|
|
81
|
+
width: '100%'
|
|
82
|
+
},
|
|
83
|
+
children: [
|
|
84
|
+
/*#__PURE__*/ _jsx("div", {
|
|
85
|
+
children: /*#__PURE__*/ _jsx("a", {
|
|
86
|
+
href: href,
|
|
87
|
+
style: {
|
|
88
|
+
textDecoration: 'none'
|
|
89
|
+
},
|
|
90
|
+
children: href || 'https://...'
|
|
91
|
+
})
|
|
92
|
+
}),
|
|
93
|
+
/*#__PURE__*/ _jsx("h4", {
|
|
94
|
+
style: {
|
|
95
|
+
margin: 0
|
|
96
|
+
},
|
|
97
|
+
children: /*#__PURE__*/ _jsx("a", {
|
|
98
|
+
href: "/",
|
|
99
|
+
style: {
|
|
100
|
+
textDecoration: 'none'
|
|
101
|
+
},
|
|
102
|
+
children: metaTitle
|
|
103
|
+
})
|
|
104
|
+
}),
|
|
105
|
+
/*#__PURE__*/ _jsx("p", {
|
|
106
|
+
style: {
|
|
107
|
+
margin: 0
|
|
108
|
+
},
|
|
109
|
+
children: metaDescription
|
|
110
|
+
})
|
|
111
|
+
]
|
|
112
|
+
})
|
|
113
|
+
]
|
|
114
|
+
});
|
|
115
|
+
};
|
|
116
|
+
|
|
117
|
+
//# sourceMappingURL=PreviewComponent.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../src/fields/Preview/PreviewComponent.tsx"],"sourcesContent":["'use client'\n\nimport {\n useAllFormFields,\n useConfig,\n useDocumentInfo,\n useForm,\n useLocale,\n useTranslation,\n} from '@payloadcms/ui'\nimport { reduceToSerializableFields } from '@payloadcms/ui/shared'\nimport type { FormField, UIField } from 'payload'\nimport { useEffect, useState } from 'react'\n\nimport type { PluginSEOTranslationKeys, PluginSEOTranslations } from '../../translations'\nimport type { GenerateURL } from '../../types'\n\ntype PreviewProps = {\n readonly descriptionPath?: string\n readonly hasGenerateURLFn: boolean\n readonly titlePath?: string\n} & UIField\n\nexport const PreviewComponent: React.FC<PreviewProps> = (props) => {\n const {\n descriptionPath: descriptionPathFromContext,\n hasGenerateURLFn,\n titlePath: titlePathFromContext,\n } = props\n\n const { t } = useTranslation<PluginSEOTranslations, PluginSEOTranslationKeys>()\n\n const {\n config: {\n routes: { api },\n serverURL,\n },\n } = useConfig()\n\n const locale = useLocale()\n\n const [fields] = useAllFormFields()\n\n const { getData } = useForm()\n\n const docInfo = useDocumentInfo()\n\n const descriptionPath = descriptionPathFromContext || 'meta.description'\n\n const titlePath = titlePathFromContext || 'meta.title'\n\n const {\n [descriptionPath]: { value: metaDescription } = {} as FormField,\n [titlePath]: { value: metaTitle } = {} as FormField,\n } = fields\n\n const [href, setHref] = useState<string>()\n\n // biome-ignore lint/correctness/useExhaustiveDependencies: <explanation>\n useEffect(() => {\n const endpoint = `${serverURL}${api}/plugin-seo/generate-url`\n\n const getHref = async () => {\n const genURLResponse = await fetch(endpoint, {\n body: JSON.stringify({\n collectionSlug: docInfo.collectionSlug,\n doc: getData(),\n docPermissions: docInfo.docPermissions,\n globalSlug: docInfo.globalSlug,\n hasPublishPermission: docInfo.hasPublishPermission,\n hasSavePermission: docInfo.hasSavePermission,\n id: docInfo.id,\n initialData: docInfo.initialData,\n initialState: docInfo.initialState\n ? reduceToSerializableFields(docInfo.initialState)\n : undefined,\n locale: typeof locale === 'object' ? locale?.code : locale,\n title: docInfo.title,\n } satisfies Omit<\n Parameters<GenerateURL>[0],\n 'collectionConfig' | 'globalConfig' | 'hasPublishedDoc' | 'req' | 'versionCount'\n >),\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, getData, serverURL, api])\n\n return (\n <div\n style={{\n marginBottom: '20px',\n }}\n >\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","useConfig","useDocumentInfo","useForm","useLocale","useTranslation","reduceToSerializableFields","useEffect","useState","PreviewComponent","props","descriptionPath","descriptionPathFromContext","hasGenerateURLFn","titlePath","titlePathFromContext","t","config","routes","api","serverURL","locale","fields","getData","docInfo","value","metaDescription","metaTitle","href","setHref","endpoint","getHref","genURLResponse","fetch","body","JSON","stringify","collectionSlug","doc","docPermissions","globalSlug","hasPublishPermission","hasSavePermission","id","initialData","initialState","undefined","code","title","credentials","headers","method","result","newHref","json","div","style","marginBottom","color","background","borderRadius","boxShadow","maxWidth","padding","pointerEvents","width","a","textDecoration","h4","margin","p"],"mappings":"AAAA;;AAEA,SACEA,gBAAgB,EAChBC,SAAS,EACTC,eAAe,EACfC,OAAO,EACPC,SAAS,EACTC,cAAc,QACT,iBAAgB;AACvB,SAASC,0BAA0B,QAAQ,wBAAuB;AAElE,SAASC,SAAS,EAAEC,QAAQ,QAAQ,QAAO;AAW3C,OAAO,MAAMC,mBAA2C,CAACC;IACvD,MAAM,EACJC,iBAAiBC,0BAA0B,EAC3CC,gBAAgB,EAChBC,WAAWC,oBAAoB,EAChC,GAAGL;IAEJ,MAAM,EAAEM,CAAC,EAAE,GAAGX;IAEd,MAAM,EACJY,QAAQ,EACNC,QAAQ,EAAEC,GAAG,EAAE,EACfC,SAAS,EACV,EACF,GAAGnB;IAEJ,MAAMoB,SAASjB;IAEf,MAAM,CAACkB,OAAO,GAAGtB;IAEjB,MAAM,EAAEuB,OAAO,EAAE,GAAGpB;IAEpB,MAAMqB,UAAUtB;IAEhB,MAAMS,kBAAkBC,8BAA8B;IAEtD,MAAME,YAAYC,wBAAwB;IAE1C,MAAM,EACJ,CAACJ,gBAAgB,EAAE,EAAEc,OAAOC,eAAe,EAAE,GAAG,CAAC,CAAc,EAC/D,CAACZ,UAAU,EAAE,EAAEW,OAAOE,SAAS,EAAE,GAAG,CAAC,CAAc,EACpD,GAAGL;IAEJ,MAAM,CAACM,MAAMC,QAAQ,GAAGrB;IAExB,yEAAyE;IACzED,UAAU;QACR,MAAMuB,WAAW,GAAGV,YAAYD,IAAI,wBAAwB,CAAC;QAE7D,MAAMY,UAAU;YACd,MAAMC,iBAAiB,MAAMC,MAAMH,UAAU;gBAC3CI,MAAMC,KAAKC,SAAS,CAAC;oBACnBC,gBAAgBb,QAAQa,cAAc;oBACtCC,KAAKf;oBACLgB,gBAAgBf,QAAQe,cAAc;oBACtCC,YAAYhB,QAAQgB,UAAU;oBAC9BC,sBAAsBjB,QAAQiB,oBAAoB;oBAClDC,mBAAmBlB,QAAQkB,iBAAiB;oBAC5CC,IAAInB,QAAQmB,EAAE;oBACdC,aAAapB,QAAQoB,WAAW;oBAChCC,cAAcrB,QAAQqB,YAAY,GAC9BvC,2BAA2BkB,QAAQqB,YAAY,IAC/CC;oBACJzB,QAAQ,OAAOA,WAAW,WAAWA,QAAQ0B,OAAO1B;oBACpD2B,OAAOxB,QAAQwB,KAAK;gBACtB;gBAIAC,aAAa;gBACbC,SAAS;oBACP,gBAAgB;gBAClB;gBACAC,QAAQ;YACV;YAEA,MAAM,EAAEC,QAAQC,OAAO,EAAE,GAAG,MAAMrB,eAAesB,IAAI;YAErDzB,QAAQwB;QACV;QAEA,IAAIxC,oBAAoB,CAACe,MAAM;YAC7B,KAAKG;QACP;IACF,GAAG;QAACT;QAAQM;QAAMP;QAAQG;QAASX;QAAkBU;QAASH;QAAWD;KAAI;IAE7E,qBACE,MAACoC;QACCC,OAAO;YACLC,cAAc;QAChB;;0BAEA,KAACF;0BAAKvC,EAAE;;0BACR,KAACuC;gBACCC,OAAO;oBACLE,OAAO;oBACPD,cAAc;gBAChB;0BAECzC,EAAE;;0BAEL,MAACuC;gBACCC,OAAO;oBACLG,YAAY;oBACZC,cAAc;oBACdC,WAAW;oBACXC,UAAU;oBACVC,SAAS;oBACTC,eAAe;oBACfC,OAAO;gBACT;;kCAEA,KAACV;kCACC,cAAA,KAACW;4BACCtC,MAAMA;4BACN4B,OAAO;gCACLW,gBAAgB;4BAClB;sCAECvC,QAAQ;;;kCAGb,KAACwC;wBACCZ,OAAO;4BACLa,QAAQ;wBACV;kCAEA,cAAA,KAACH;4BACCtC,MAAK;4BACL4B,OAAO;gCACLW,gBAAgB;4BAClB;sCAECxC;;;kCAGL,KAAC2C;wBACCd,OAAO;4BACLa,QAAQ;wBACV;kCAEC3C;;;;;;AAKX,EAAC"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
// @ts-nocheck
|
|
2
|
+
export const PreviewField = ({ descriptionPath, hasGenerateFn = false, overrides, titlePath })=>{
|
|
3
|
+
return {
|
|
4
|
+
admin: {
|
|
5
|
+
components: {
|
|
6
|
+
Field: {
|
|
7
|
+
clientProps: {
|
|
8
|
+
descriptionPath,
|
|
9
|
+
hasGenerateURLFn: hasGenerateFn,
|
|
10
|
+
titlePath
|
|
11
|
+
},
|
|
12
|
+
path: '@justanarthur/payload-plugin-seo/fields-components#PreviewComponent'
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
},
|
|
16
|
+
label: 'Preview',
|
|
17
|
+
name: 'preview',
|
|
18
|
+
type: 'ui',
|
|
19
|
+
...overrides ?? {}
|
|
20
|
+
};
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../src/fields/Preview/index.tsx"],"sourcesContent":["// @ts-nocheck\nimport type { UIField } from 'payload'\n\ntype FieldFunctionProps = {\n /**\n * Path to the description field to use for the preview\n *\n * @default 'meta.description'\n */\n descriptionPath?: string\n /**\n * Tell the component if the generate function is available as configured in the plugin config\n */\n hasGenerateFn?: boolean\n overrides?: Partial<UIField>\n /**\n * Path to the title field to use for the preview\n *\n * @default 'meta.title'\n */\n titlePath?: string\n}\n\ntype FieldFunction = ({ hasGenerateFn, overrides }: FieldFunctionProps) => UIField\n\nexport const PreviewField: FieldFunction = ({\n descriptionPath,\n hasGenerateFn = false,\n overrides,\n titlePath,\n}) => {\n return {\n admin: {\n components: {\n Field: {\n clientProps: {\n descriptionPath,\n hasGenerateURLFn: hasGenerateFn,\n titlePath,\n },\n path: '@justanarthur/payload-plugin-seo/fields-components#PreviewComponent',\n },\n },\n },\n label: 'Preview',\n name: 'preview',\n type: 'ui',\n ...((overrides as unknown as UIField) ?? {}),\n }\n}\n"],"names":["PreviewField","descriptionPath","hasGenerateFn","overrides","titlePath","admin","components","Field","clientProps","hasGenerateURLFn","path","label","name","type"],"mappings":"AAAA,cAAc;AAyBd,OAAO,MAAMA,eAA8B,CAAC,EAC1CC,eAAe,EACfC,gBAAgB,KAAK,EACrBC,SAAS,EACTC,SAAS,EACV;IACC,OAAO;QACLC,OAAO;YACLC,YAAY;gBACVC,OAAO;oBACLC,aAAa;wBACXP;wBACAQ,kBAAkBP;wBAClBE;oBACF;oBACAM,MAAM;gBACR;YACF;QACF;QACAC,OAAO;QACPC,MAAM;QACNC,MAAM;QACN,GAAI,AAACV,aAAoC,CAAC,CAAC;IAC7C;AACF,EAAC"}
|
|
@@ -0,0 +1,309 @@
|
|
|
1
|
+
import { deepMergeSimple } from 'payload/shared';
|
|
2
|
+
import { MetaDescriptionField } from './fields/MetaDescription';
|
|
3
|
+
import { MetaImageField } from './fields/MetaImage';
|
|
4
|
+
import { MetaTitleField } from './fields/MetaTitle';
|
|
5
|
+
import { OverviewField } from './fields/Overview';
|
|
6
|
+
import { PreviewField } from './fields/Preview';
|
|
7
|
+
import { openaiMessage } from './openai/message';
|
|
8
|
+
import { translations } from './translations';
|
|
9
|
+
export const seoPlugin = (pluginConfig)=>(config)=>{
|
|
10
|
+
const defaultFields = [
|
|
11
|
+
OverviewField({}),
|
|
12
|
+
MetaTitleField({
|
|
13
|
+
hasGenerateAi: typeof pluginConfig?.generateTitleAi === 'function',
|
|
14
|
+
hasGenerateFn: typeof pluginConfig?.generateTitle === 'function'
|
|
15
|
+
}),
|
|
16
|
+
MetaDescriptionField({
|
|
17
|
+
hasGenerateAi: typeof pluginConfig?.generateDescriptionAi === 'function',
|
|
18
|
+
hasGenerateFn: typeof pluginConfig?.generateDescription === 'function'
|
|
19
|
+
}),
|
|
20
|
+
...pluginConfig?.uploadsCollection ? [
|
|
21
|
+
MetaImageField({
|
|
22
|
+
hasGenerateFn: typeof pluginConfig?.generateImage === 'function',
|
|
23
|
+
relationTo: pluginConfig.uploadsCollection
|
|
24
|
+
})
|
|
25
|
+
] : [],
|
|
26
|
+
PreviewField({
|
|
27
|
+
hasGenerateFn: typeof pluginConfig?.generateURL === 'function'
|
|
28
|
+
})
|
|
29
|
+
];
|
|
30
|
+
const seoFields = [
|
|
31
|
+
{
|
|
32
|
+
fields: [
|
|
33
|
+
...pluginConfig?.fields && typeof pluginConfig.fields === 'function' ? pluginConfig.fields({
|
|
34
|
+
defaultFields
|
|
35
|
+
}) : defaultFields
|
|
36
|
+
],
|
|
37
|
+
interfaceName: pluginConfig.interfaceName,
|
|
38
|
+
label: 'SEO',
|
|
39
|
+
name: 'meta',
|
|
40
|
+
type: 'group'
|
|
41
|
+
}
|
|
42
|
+
];
|
|
43
|
+
return {
|
|
44
|
+
...config,
|
|
45
|
+
collections: config.collections?.map((collection)=>{
|
|
46
|
+
const { slug } = collection;
|
|
47
|
+
const isEnabled = pluginConfig?.collections?.includes(slug);
|
|
48
|
+
if (isEnabled) {
|
|
49
|
+
if (pluginConfig?.tabbedUI) {
|
|
50
|
+
// prevent issues with auth enabled collections having an email field that shouldn't be moved to the SEO tab
|
|
51
|
+
const emailField = (collection.auth || !(typeof collection.auth === 'object' && collection.auth.disableLocalStrategy)) && collection.fields?.find((field)=>'name' in field && field.name === 'email');
|
|
52
|
+
const hasOnlyEmailField = collection.fields?.length === 1 && emailField;
|
|
53
|
+
const seoTabs = hasOnlyEmailField ? [
|
|
54
|
+
{
|
|
55
|
+
tabs: [
|
|
56
|
+
{
|
|
57
|
+
fields: seoFields,
|
|
58
|
+
label: 'SEO'
|
|
59
|
+
}
|
|
60
|
+
],
|
|
61
|
+
type: 'tabs'
|
|
62
|
+
}
|
|
63
|
+
] : [
|
|
64
|
+
{
|
|
65
|
+
tabs: [
|
|
66
|
+
// append a new tab onto the end of the tabs array, if there is one at the first index
|
|
67
|
+
// if needed, create a new `Content` tab in the first index for this collection's base fields
|
|
68
|
+
...collection?.fields?.[0]?.type === 'tabs' && collection?.fields?.[0]?.tabs ? collection.fields[0].tabs : [
|
|
69
|
+
{
|
|
70
|
+
fields: [
|
|
71
|
+
...emailField ? collection.fields.filter((field)=>'name' in field && field.name !== 'email') : collection.fields
|
|
72
|
+
],
|
|
73
|
+
label: collection?.labels?.singular || 'Content'
|
|
74
|
+
}
|
|
75
|
+
],
|
|
76
|
+
{
|
|
77
|
+
fields: seoFields,
|
|
78
|
+
label: 'SEO'
|
|
79
|
+
}
|
|
80
|
+
],
|
|
81
|
+
type: 'tabs'
|
|
82
|
+
}
|
|
83
|
+
];
|
|
84
|
+
return {
|
|
85
|
+
...collection,
|
|
86
|
+
fields: [
|
|
87
|
+
...emailField ? [
|
|
88
|
+
emailField
|
|
89
|
+
] : [],
|
|
90
|
+
...seoTabs,
|
|
91
|
+
...collection?.fields?.[0]?.type === 'tabs' ? collection.fields.slice(1) : []
|
|
92
|
+
]
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
return {
|
|
96
|
+
...collection,
|
|
97
|
+
fields: [
|
|
98
|
+
...collection?.fields || [],
|
|
99
|
+
...seoFields
|
|
100
|
+
]
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
return collection;
|
|
104
|
+
}) || [],
|
|
105
|
+
endpoints: [
|
|
106
|
+
...config.endpoints ?? [],
|
|
107
|
+
{
|
|
108
|
+
handler: async (req)=>{
|
|
109
|
+
const data = await req.json?.();
|
|
110
|
+
if (data) {
|
|
111
|
+
req.data = data;
|
|
112
|
+
}
|
|
113
|
+
const result = pluginConfig.generateTitle ? await pluginConfig.generateTitle({
|
|
114
|
+
...data,
|
|
115
|
+
collectionConfig: req.data?.collectionSlug ? config.collections?.find((c)=>c.slug === req.data?.collectionSlug) : undefined,
|
|
116
|
+
globalConfig: req.data?.globalSlug ? config.globals?.find((g)=>g.slug === req.data?.globalSlug) : undefined,
|
|
117
|
+
req
|
|
118
|
+
}) : '';
|
|
119
|
+
return new Response(JSON.stringify({
|
|
120
|
+
result
|
|
121
|
+
}), {
|
|
122
|
+
status: 200
|
|
123
|
+
});
|
|
124
|
+
},
|
|
125
|
+
method: 'post',
|
|
126
|
+
path: '/plugin-seo/generate-title'
|
|
127
|
+
},
|
|
128
|
+
{
|
|
129
|
+
handler: async (req)=>{
|
|
130
|
+
if (!pluginConfig.openaiApiKey) return new Response(JSON.stringify({
|
|
131
|
+
message: 'Something went wrong'
|
|
132
|
+
}), {
|
|
133
|
+
status: 500
|
|
134
|
+
});
|
|
135
|
+
const data = await req.json?.();
|
|
136
|
+
if (data) {
|
|
137
|
+
req.data = data;
|
|
138
|
+
}
|
|
139
|
+
const content = pluginConfig.generateTitleAi ? await pluginConfig.generateTitleAi({
|
|
140
|
+
...data,
|
|
141
|
+
collectionConfig: req.data?.collectionSlug ? config.collections?.find((c)=>c.slug === req.data?.collectionSlug) : undefined,
|
|
142
|
+
globalConfig: req.data?.globalSlug ? config.globals?.find((g)=>g.slug === req.data?.globalSlug) : undefined,
|
|
143
|
+
req
|
|
144
|
+
}) : '';
|
|
145
|
+
console.log('[handler "/plugin-seo/generate-title-ai"]', {
|
|
146
|
+
content
|
|
147
|
+
});
|
|
148
|
+
const aiResult = await openaiMessage({
|
|
149
|
+
apiKey: pluginConfig.openaiApiKey,
|
|
150
|
+
content,
|
|
151
|
+
req
|
|
152
|
+
});
|
|
153
|
+
console.log('[handler "/plugin-seo/generate-title-ai"]', {
|
|
154
|
+
aiResult
|
|
155
|
+
});
|
|
156
|
+
return Response.json({
|
|
157
|
+
result: aiResult
|
|
158
|
+
}, {
|
|
159
|
+
status: 200
|
|
160
|
+
});
|
|
161
|
+
},
|
|
162
|
+
method: 'post',
|
|
163
|
+
path: '/plugin-seo/generate-title-ai'
|
|
164
|
+
},
|
|
165
|
+
{
|
|
166
|
+
handler: async (req)=>{
|
|
167
|
+
const data = await req.json?.();
|
|
168
|
+
if (data) {
|
|
169
|
+
req.data = data;
|
|
170
|
+
}
|
|
171
|
+
const result = pluginConfig.generateDescription ? await pluginConfig.generateDescription({
|
|
172
|
+
...data,
|
|
173
|
+
collectionConfig: req.data?.collectionSlug ? config.collections?.find((c)=>c.slug === req.data?.collectionSlug) : undefined,
|
|
174
|
+
globalConfig: req.data?.globalSlug ? config.globals?.find((g)=>g.slug === req.data?.globalSlug) : undefined,
|
|
175
|
+
req
|
|
176
|
+
}) : '';
|
|
177
|
+
return new Response(JSON.stringify({
|
|
178
|
+
result
|
|
179
|
+
}), {
|
|
180
|
+
status: 200
|
|
181
|
+
});
|
|
182
|
+
},
|
|
183
|
+
method: 'post',
|
|
184
|
+
path: '/plugin-seo/generate-description'
|
|
185
|
+
},
|
|
186
|
+
{
|
|
187
|
+
handler: async (req)=>{
|
|
188
|
+
if (!pluginConfig.openaiApiKey) return new Response(JSON.stringify({
|
|
189
|
+
message: 'Something went wrong'
|
|
190
|
+
}), {
|
|
191
|
+
status: 500
|
|
192
|
+
});
|
|
193
|
+
const data = await req.json?.();
|
|
194
|
+
if (data) {
|
|
195
|
+
req.data = data;
|
|
196
|
+
}
|
|
197
|
+
const content = pluginConfig.generateDescriptionAi ? await pluginConfig.generateDescriptionAi({
|
|
198
|
+
...data,
|
|
199
|
+
collectionConfig: req.data?.collectionSlug ? config.collections?.find((c)=>c.slug === req.data?.collectionSlug) : undefined,
|
|
200
|
+
globalConfig: req.data?.globalSlug ? config.globals?.find((g)=>g.slug === req.data?.globalSlug) : undefined,
|
|
201
|
+
req
|
|
202
|
+
}) : '';
|
|
203
|
+
const aiResult = await openaiMessage({
|
|
204
|
+
apiKey: pluginConfig.openaiApiKey,
|
|
205
|
+
content,
|
|
206
|
+
req
|
|
207
|
+
});
|
|
208
|
+
return Response.json({
|
|
209
|
+
result: aiResult
|
|
210
|
+
}, {
|
|
211
|
+
status: 200
|
|
212
|
+
});
|
|
213
|
+
},
|
|
214
|
+
method: 'post',
|
|
215
|
+
path: '/plugin-seo/generate-description-ai'
|
|
216
|
+
},
|
|
217
|
+
{
|
|
218
|
+
handler: async (req)=>{
|
|
219
|
+
const data = await req.json?.();
|
|
220
|
+
if (data) {
|
|
221
|
+
req.data = data;
|
|
222
|
+
}
|
|
223
|
+
const result = pluginConfig.generateURL ? await pluginConfig.generateURL({
|
|
224
|
+
...data,
|
|
225
|
+
collectionConfig: req.data?.collectionSlug ? config.collections?.find((c)=>c.slug === req.data?.collectionSlug) : undefined,
|
|
226
|
+
globalConfig: req.data?.globalSlug ? config.globals?.find((g)=>g.slug === req.data?.globalSlug) : undefined,
|
|
227
|
+
req
|
|
228
|
+
}) : '';
|
|
229
|
+
return new Response(JSON.stringify({
|
|
230
|
+
result
|
|
231
|
+
}), {
|
|
232
|
+
status: 200
|
|
233
|
+
});
|
|
234
|
+
},
|
|
235
|
+
method: 'post',
|
|
236
|
+
path: '/plugin-seo/generate-url'
|
|
237
|
+
},
|
|
238
|
+
{
|
|
239
|
+
handler: async (req)=>{
|
|
240
|
+
const data = await req.json?.();
|
|
241
|
+
if (data) {
|
|
242
|
+
req.data = data;
|
|
243
|
+
}
|
|
244
|
+
const result = pluginConfig.generateImage ? await pluginConfig.generateImage({
|
|
245
|
+
...data,
|
|
246
|
+
collectionConfig: req.data?.collectionSlug ? config.collections?.find((c)=>c.slug === req.data?.collectionSlug) : null,
|
|
247
|
+
globalConfig: req.data?.globalSlug ? config.globals?.find((g)=>g.slug === req.data?.globalSlug) : null,
|
|
248
|
+
req
|
|
249
|
+
}) : '';
|
|
250
|
+
return new Response(result, {
|
|
251
|
+
status: 200
|
|
252
|
+
});
|
|
253
|
+
},
|
|
254
|
+
method: 'post',
|
|
255
|
+
path: '/plugin-seo/generate-image'
|
|
256
|
+
}
|
|
257
|
+
],
|
|
258
|
+
globals: config.globals?.map((global)=>{
|
|
259
|
+
const { slug } = global;
|
|
260
|
+
const isEnabled = pluginConfig?.globals?.includes(slug);
|
|
261
|
+
if (isEnabled) {
|
|
262
|
+
if (pluginConfig?.tabbedUI) {
|
|
263
|
+
const seoTabs = [
|
|
264
|
+
{
|
|
265
|
+
tabs: [
|
|
266
|
+
// append a new tab onto the end of the tabs array, if there is one at the first index
|
|
267
|
+
// if needed, create a new `Content` tab in the first index for this global's base fields
|
|
268
|
+
...global?.fields?.[0].type === 'tabs' && global?.fields?.[0].tabs ? global.fields[0].tabs : [
|
|
269
|
+
{
|
|
270
|
+
fields: [
|
|
271
|
+
...global?.fields || []
|
|
272
|
+
],
|
|
273
|
+
label: global?.label || 'Content'
|
|
274
|
+
}
|
|
275
|
+
],
|
|
276
|
+
{
|
|
277
|
+
fields: seoFields,
|
|
278
|
+
label: 'SEO'
|
|
279
|
+
}
|
|
280
|
+
],
|
|
281
|
+
type: 'tabs'
|
|
282
|
+
}
|
|
283
|
+
];
|
|
284
|
+
return {
|
|
285
|
+
...global,
|
|
286
|
+
fields: [
|
|
287
|
+
...seoTabs,
|
|
288
|
+
...global?.fields?.[0].type === 'tabs' ? global.fields.slice(1) : []
|
|
289
|
+
]
|
|
290
|
+
};
|
|
291
|
+
}
|
|
292
|
+
return {
|
|
293
|
+
...global,
|
|
294
|
+
fields: [
|
|
295
|
+
...global?.fields || [],
|
|
296
|
+
...seoFields
|
|
297
|
+
]
|
|
298
|
+
};
|
|
299
|
+
}
|
|
300
|
+
return global;
|
|
301
|
+
}) || [],
|
|
302
|
+
i18n: {
|
|
303
|
+
...config.i18n,
|
|
304
|
+
translations: config.i18n?.translations ? deepMergeSimple(translations, config.i18n.translations) : translations
|
|
305
|
+
}
|
|
306
|
+
};
|
|
307
|
+
};
|
|
308
|
+
|
|
309
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/index.tsx"],"sourcesContent":["import type { CollectionSlug, Config, Field, GlobalSlug, GroupField, TabsField } from 'payload'\nimport { deepMergeSimple } from 'payload/shared'\n\nimport { MetaDescriptionField } from './fields/MetaDescription'\nimport { MetaImageField } from './fields/MetaImage'\nimport { MetaTitleField } from './fields/MetaTitle'\nimport { OverviewField } from './fields/Overview'\nimport { PreviewField } from './fields/Preview'\nimport { openaiMessage } from './openai/message'\nimport { translations } from './translations'\nimport type {\n GenerateDescription,\n GenerateImage,\n GenerateTitle,\n GenerateURL,\n SEOPluginConfig,\n} from './types'\n\nexport const seoPlugin =\n (pluginConfig: SEOPluginConfig) =>\n (config: Config): Config => {\n const defaultFields: Field[] = [\n OverviewField({}),\n MetaTitleField({\n hasGenerateAi: typeof pluginConfig?.generateTitleAi === 'function',\n hasGenerateFn: typeof pluginConfig?.generateTitle === 'function',\n }),\n MetaDescriptionField({\n hasGenerateAi: typeof pluginConfig?.generateDescriptionAi === 'function',\n hasGenerateFn: typeof pluginConfig?.generateDescription === 'function',\n }),\n ...(pluginConfig?.uploadsCollection\n ? [\n MetaImageField({\n hasGenerateFn: typeof pluginConfig?.generateImage === 'function',\n relationTo: pluginConfig.uploadsCollection,\n }),\n ]\n : []),\n PreviewField({\n hasGenerateFn: typeof pluginConfig?.generateURL === 'function',\n }),\n ]\n\n const seoFields: GroupField[] = [\n {\n fields: [\n ...(pluginConfig?.fields && typeof pluginConfig.fields === 'function'\n ? pluginConfig.fields({ defaultFields })\n : defaultFields),\n ],\n interfaceName: pluginConfig.interfaceName,\n label: 'SEO',\n name: 'meta',\n type: 'group',\n },\n ]\n\n return {\n ...config,\n collections:\n config.collections?.map((collection) => {\n const { slug } = collection\n\n const isEnabled = pluginConfig?.collections?.includes(slug as CollectionSlug)\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 !(\n typeof collection.auth === 'object' &&\n (collection.auth as any).disableLocalStrategy\n )) &&\n collection.fields?.find((field) => 'name' in field && field.name === 'email')\n\n const hasOnlyEmailField = collection.fields?.length === 1 && emailField\n\n const seoTabs: TabsField[] = hasOnlyEmailField\n ? [\n {\n tabs: [\n {\n fields: seoFields,\n label: 'SEO',\n },\n ],\n type: 'tabs',\n },\n ]\n : [\n {\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 ? 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 type: 'tabs',\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 ...(config.endpoints ?? []),\n {\n handler: async (req) => {\n const data: Omit<\n Parameters<GenerateTitle>[0],\n 'collectionConfig' | 'globalConfig' | 'req'\n > = await req.json?.()\n\n if (data) {\n req.data = data\n }\n\n const result = pluginConfig.generateTitle\n ? await pluginConfig.generateTitle({\n ...data,\n collectionConfig: req.data?.collectionSlug\n ? config.collections?.find((c) => c.slug === req.data?.collectionSlug)\n : undefined,\n globalConfig: req.data?.globalSlug\n ? config.globals?.find((g) => g.slug === req.data?.globalSlug)\n : undefined,\n req,\n } satisfies Parameters<GenerateTitle>[0])\n : ''\n\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 if (!pluginConfig.openaiApiKey)\n return new Response(JSON.stringify({ message: 'Something went wrong' }), {\n status: 500,\n })\n\n const data: Omit<\n Parameters<GenerateTitle>[0],\n 'collectionConfig' | 'globalConfig' | 'req'\n > = await req.json?.()\n\n if (data) {\n req.data = data\n }\n\n const content = pluginConfig.generateTitleAi\n ? await pluginConfig.generateTitleAi({\n ...data,\n collectionConfig: req.data?.collectionSlug\n ? config.collections?.find((c) => c.slug === req.data?.collectionSlug)\n : undefined,\n globalConfig: req.data?.globalSlug\n ? config.globals?.find((g) => g.slug === req.data?.globalSlug)\n : undefined,\n req,\n })\n : ''\n\n console.log('[handler \"/plugin-seo/generate-title-ai\"]', { content })\n\n const aiResult = await openaiMessage({\n apiKey: pluginConfig.openaiApiKey,\n content,\n req,\n })\n\n console.log('[handler \"/plugin-seo/generate-title-ai\"]', { aiResult })\n\n return Response.json({ result: aiResult }, { status: 200 })\n },\n method: 'post',\n path: '/plugin-seo/generate-title-ai',\n },\n {\n handler: async (req) => {\n const data: Omit<\n Parameters<GenerateTitle>[0],\n 'collectionConfig' | 'globalConfig' | 'req'\n > = await req.json?.()\n\n if (data) {\n req.data = data\n }\n\n const result = pluginConfig.generateDescription\n ? await pluginConfig.generateDescription({\n ...data,\n collectionConfig: req.data?.collectionSlug\n ? config.collections?.find((c) => c.slug === req.data?.collectionSlug)\n : undefined,\n globalConfig: req.data?.globalSlug\n ? config.globals?.find((g) => g.slug === req.data?.globalSlug)\n : undefined,\n req,\n } satisfies Parameters<GenerateDescription>[0])\n : ''\n\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 if (!pluginConfig.openaiApiKey)\n return new Response(JSON.stringify({ message: 'Something went wrong' }), {\n status: 500,\n })\n\n const data: Omit<\n Parameters<GenerateTitle>[0],\n 'collectionConfig' | 'globalConfig' | 'req'\n > = await req.json?.()\n\n if (data) {\n req.data = data\n }\n const content = pluginConfig.generateDescriptionAi\n ? await pluginConfig.generateDescriptionAi({\n ...data,\n collectionConfig: req.data?.collectionSlug\n ? config.collections?.find((c) => c.slug === req.data?.collectionSlug)\n : undefined,\n globalConfig: req.data?.globalSlug\n ? config.globals?.find((g) => g.slug === req.data?.globalSlug)\n : undefined,\n req,\n })\n : ''\n\n const aiResult = await openaiMessage({\n apiKey: pluginConfig.openaiApiKey,\n content,\n req,\n })\n\n return Response.json({ result: aiResult }, { status: 200 })\n },\n method: 'post',\n path: '/plugin-seo/generate-description-ai',\n },\n {\n handler: async (req) => {\n const data: Omit<\n Parameters<GenerateTitle>[0],\n 'collectionConfig' | 'globalConfig' | 'req'\n > = await req.json?.()\n\n if (data) {\n req.data = data\n }\n\n const result = pluginConfig.generateURL\n ? await pluginConfig.generateURL({\n ...data,\n collectionConfig: req.data?.collectionSlug\n ? config.collections?.find((c) => c.slug === req.data?.collectionSlug)\n : undefined,\n globalConfig: req.data?.globalSlug\n ? config.globals?.find((g) => g.slug === req.data?.globalSlug)\n : undefined,\n req,\n } satisfies Parameters<GenerateURL>[0])\n : ''\n\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 data: Omit<\n Parameters<GenerateTitle>[0],\n 'collectionConfig' | 'globalConfig' | 'req'\n > = await req.json?.()\n\n if (data) {\n req.data = data\n }\n\n const result = pluginConfig.generateImage\n ? await pluginConfig.generateImage({\n ...data,\n collectionConfig: req.data?.collectionSlug\n ? config.collections?.find((c) => c.slug === req.data?.collectionSlug)\n : null,\n globalConfig: req.data?.globalSlug\n ? config.globals?.find((g) => g.slug === req.data?.globalSlug)\n : null,\n req,\n } as Parameters<GenerateImage>[0])\n : ''\n\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\n const isEnabled = pluginConfig?.globals?.includes(slug as GlobalSlug)\n\n if (isEnabled) {\n if (pluginConfig?.tabbedUI) {\n const seoTabs: TabsField[] = [\n {\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 type: 'tabs',\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: config.i18n?.translations\n ? deepMergeSimple(translations, config.i18n.translations)\n : translations,\n },\n }\n }\n"],"names":["deepMergeSimple","MetaDescriptionField","MetaImageField","MetaTitleField","OverviewField","PreviewField","openaiMessage","translations","seoPlugin","pluginConfig","config","defaultFields","hasGenerateAi","generateTitleAi","hasGenerateFn","generateTitle","generateDescriptionAi","generateDescription","uploadsCollection","generateImage","relationTo","generateURL","seoFields","fields","interfaceName","label","name","type","collections","map","collection","slug","isEnabled","includes","tabbedUI","emailField","auth","disableLocalStrategy","find","field","hasOnlyEmailField","length","seoTabs","tabs","filter","labels","singular","slice","endpoints","handler","req","data","json","result","collectionConfig","collectionSlug","c","undefined","globalConfig","globalSlug","globals","g","Response","JSON","stringify","status","method","path","openaiApiKey","message","content","console","log","aiResult","apiKey","global","i18n"],"mappings":"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"}
|