@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.
Files changed (144) hide show
  1. package/README.md +16 -0
  2. package/dist/defaults.d.ts +11 -0
  3. package/dist/defaults.d.ts.map +1 -0
  4. package/dist/exports/client.d.ts +6 -0
  5. package/dist/exports/client.d.ts.map +1 -0
  6. package/dist/exports/fields-components.d.ts +6 -0
  7. package/dist/exports/fields-components.d.ts.map +1 -0
  8. package/dist/exports/fields.d.ts +6 -0
  9. package/dist/exports/fields.d.ts.map +1 -0
  10. package/dist/exports/types.d.ts +2 -0
  11. package/dist/exports/types.d.ts.map +1 -0
  12. package/dist/fields/MetaDescription/MetaDescriptionComponent.d.ts +9 -0
  13. package/dist/fields/MetaDescription/MetaDescriptionComponent.d.ts.map +1 -0
  14. package/dist/fields/MetaDescription/index.d.ts +16 -0
  15. package/dist/fields/MetaDescription/index.d.ts.map +1 -0
  16. package/dist/fields/MetaImage/MetaImageComponent.d.ts +8 -0
  17. package/dist/fields/MetaImage/MetaImageComponent.d.ts.map +1 -0
  18. package/dist/fields/MetaImage/index.d.ts +13 -0
  19. package/dist/fields/MetaImage/index.d.ts.map +1 -0
  20. package/dist/fields/MetaTitle/MetaTitleComponent.d.ts +10 -0
  21. package/dist/fields/MetaTitle/MetaTitleComponent.d.ts.map +1 -0
  22. package/dist/fields/MetaTitle/index.d.ts +16 -0
  23. package/dist/fields/MetaTitle/index.d.ts.map +1 -0
  24. package/dist/fields/Overview/OverviewComponent.d.ts +18 -0
  25. package/dist/fields/Overview/OverviewComponent.d.ts.map +1 -0
  26. package/dist/fields/Overview/index.d.ts +34 -0
  27. package/dist/fields/Overview/index.d.ts.map +1 -0
  28. package/dist/fields/Preview/PreviewComponent.d.ts +9 -0
  29. package/dist/fields/Preview/PreviewComponent.d.ts.map +1 -0
  30. package/dist/fields/Preview/index.d.ts +24 -0
  31. package/dist/fields/Preview/index.d.ts.map +1 -0
  32. package/dist/fields/index.scss +7 -0
  33. package/dist/index.d.ts +4 -0
  34. package/dist/index.d.ts.map +1 -0
  35. package/dist/openai/message.d.ts +7 -0
  36. package/dist/openai/message.d.ts.map +1 -0
  37. package/dist/src/defaults.js +12 -0
  38. package/dist/src/defaults.js.map +1 -0
  39. package/dist/src/exports/client.js +7 -0
  40. package/dist/src/exports/client.js.map +1 -0
  41. package/dist/src/exports/fields-components.js +7 -0
  42. package/dist/src/exports/fields-components.js.map +1 -0
  43. package/dist/src/exports/fields.js +7 -0
  44. package/dist/src/exports/fields.js.map +1 -0
  45. package/dist/src/exports/types.js +3 -0
  46. package/dist/src/exports/types.js.map +1 -0
  47. package/dist/src/fields/MetaDescription/MetaDescriptionComponent.js +224 -0
  48. package/dist/src/fields/MetaDescription/MetaDescriptionComponent.js.map +1 -0
  49. package/dist/src/fields/MetaDescription/index.js +22 -0
  50. package/dist/src/fields/MetaDescription/index.js.map +1 -0
  51. package/dist/src/fields/MetaImage/MetaImageComponent.js +173 -0
  52. package/dist/src/fields/MetaImage/MetaImageComponent.js.map +1 -0
  53. package/dist/src/fields/MetaImage/index.js +24 -0
  54. package/dist/src/fields/MetaImage/index.js.map +1 -0
  55. package/dist/src/fields/MetaTitle/MetaTitleComponent.js +225 -0
  56. package/dist/src/fields/MetaTitle/MetaTitleComponent.js.map +1 -0
  57. package/dist/src/fields/MetaTitle/index.js +22 -0
  58. package/dist/src/fields/MetaTitle/index.js.map +1 -0
  59. package/dist/src/fields/Overview/OverviewComponent.js +67 -0
  60. package/dist/src/fields/Overview/OverviewComponent.js.map +1 -0
  61. package/dist/src/fields/Overview/index.js +25 -0
  62. package/dist/src/fields/Overview/index.js.map +1 -0
  63. package/dist/src/fields/Preview/PreviewComponent.js +117 -0
  64. package/dist/src/fields/Preview/PreviewComponent.js.map +1 -0
  65. package/dist/src/fields/Preview/index.js +23 -0
  66. package/dist/src/fields/Preview/index.js.map +1 -0
  67. package/dist/src/index.js +309 -0
  68. package/dist/src/index.js.map +1 -0
  69. package/dist/src/openai/message.js +28 -0
  70. package/dist/src/openai/message.js.map +1 -0
  71. package/dist/src/translations/cs.js +26 -0
  72. package/dist/src/translations/cs.js.map +1 -0
  73. package/dist/src/translations/de.js +26 -0
  74. package/dist/src/translations/de.js.map +1 -0
  75. package/dist/src/translations/en.js +27 -0
  76. package/dist/src/translations/en.js.map +1 -0
  77. package/dist/src/translations/es.js +26 -0
  78. package/dist/src/translations/es.js.map +1 -0
  79. package/dist/src/translations/fa.js +26 -0
  80. package/dist/src/translations/fa.js.map +1 -0
  81. package/dist/src/translations/fr.js +26 -0
  82. package/dist/src/translations/fr.js.map +1 -0
  83. package/dist/src/translations/index.js +30 -0
  84. package/dist/src/translations/index.js.map +1 -0
  85. package/dist/src/translations/it.js +26 -0
  86. package/dist/src/translations/it.js.map +1 -0
  87. package/dist/src/translations/nb.js +26 -0
  88. package/dist/src/translations/nb.js.map +1 -0
  89. package/dist/src/translations/pl.js +26 -0
  90. package/dist/src/translations/pl.js.map +1 -0
  91. package/dist/src/translations/ru.js +26 -0
  92. package/dist/src/translations/ru.js.map +1 -0
  93. package/dist/src/translations/sv.js +26 -0
  94. package/dist/src/translations/sv.js.map +1 -0
  95. package/dist/src/translations/tr.js +26 -0
  96. package/dist/src/translations/tr.js.map +1 -0
  97. package/dist/src/translations/uk.js +26 -0
  98. package/dist/src/translations/uk.js.map +1 -0
  99. package/dist/src/translations/vi.js +26 -0
  100. package/dist/src/translations/vi.js.map +1 -0
  101. package/dist/src/types.js +3 -0
  102. package/dist/src/types.js.map +1 -0
  103. package/dist/src/ui/LengthIndicator.js +135 -0
  104. package/dist/src/ui/LengthIndicator.js.map +1 -0
  105. package/dist/src/ui/Pill.js +23 -0
  106. package/dist/src/ui/Pill.js.map +1 -0
  107. package/dist/translations/cs.d.ts +3 -0
  108. package/dist/translations/cs.d.ts.map +1 -0
  109. package/dist/translations/de.d.ts +3 -0
  110. package/dist/translations/de.d.ts.map +1 -0
  111. package/dist/translations/en.d.ts +3 -0
  112. package/dist/translations/en.d.ts.map +1 -0
  113. package/dist/translations/es.d.ts +3 -0
  114. package/dist/translations/es.d.ts.map +1 -0
  115. package/dist/translations/fa.d.ts +3 -0
  116. package/dist/translations/fa.d.ts.map +1 -0
  117. package/dist/translations/fr.d.ts +3 -0
  118. package/dist/translations/fr.d.ts.map +1 -0
  119. package/dist/translations/index.d.ts +19 -0
  120. package/dist/translations/index.d.ts.map +1 -0
  121. package/dist/translations/it.d.ts +3 -0
  122. package/dist/translations/it.d.ts.map +1 -0
  123. package/dist/translations/nb.d.ts +3 -0
  124. package/dist/translations/nb.d.ts.map +1 -0
  125. package/dist/translations/pl.d.ts +3 -0
  126. package/dist/translations/pl.d.ts.map +1 -0
  127. package/dist/translations/ru.d.ts +3 -0
  128. package/dist/translations/ru.d.ts.map +1 -0
  129. package/dist/translations/sv.d.ts +3 -0
  130. package/dist/translations/sv.d.ts.map +1 -0
  131. package/dist/translations/tr.d.ts +3 -0
  132. package/dist/translations/tr.d.ts.map +1 -0
  133. package/dist/translations/translation-schema.json +96 -0
  134. package/dist/translations/uk.d.ts +3 -0
  135. package/dist/translations/uk.d.ts.map +1 -0
  136. package/dist/translations/vi.d.ts +3 -0
  137. package/dist/translations/vi.d.ts.map +1 -0
  138. package/dist/types.d.ts +82 -0
  139. package/dist/types.d.ts.map +1 -0
  140. package/dist/ui/LengthIndicator.d.ts +7 -0
  141. package/dist/ui/LengthIndicator.d.ts.map +1 -0
  142. package/dist/ui/Pill.d.ts +7 -0
  143. package/dist/ui/Pill.d.ts.map +1 -0
  144. 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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"}