@focus-reactive/payload-plugin-seo 1.6.0 → 1.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (127) hide show
  1. package/README.md +13 -2
  2. package/dist/admin.css +200 -17
  3. package/dist/components/SeoButton/SeoButtonInner.d.ts.map +1 -1
  4. package/dist/components/SeoButton/SeoButtonInner.js +46 -16
  5. package/dist/components/SeoButton/SeoButtonInner.js.map +1 -1
  6. package/dist/components/SeoDrawer/build-analysis-input.d.ts +2 -2
  7. package/dist/components/SeoDrawer/build-analysis-input.d.ts.map +1 -1
  8. package/dist/components/SeoDrawer/build-analysis-input.js +1 -1
  9. package/dist/components/SeoDrawer/build-analysis-input.js.map +1 -1
  10. package/dist/components/SeoDrawer/buildInput.d.ts +3 -3
  11. package/dist/components/SeoDrawer/buildInput.d.ts.map +1 -1
  12. package/dist/components/SeoDrawer/buildInput.js +3 -2
  13. package/dist/components/SeoDrawer/buildInput.js.map +1 -1
  14. package/dist/components/SeoDrawer/components/SerpPreview/highlight-keyphrase.d.ts +1 -1
  15. package/dist/components/SeoDrawer/components/SerpPreview/highlight-keyphrase.d.ts.map +1 -1
  16. package/dist/components/SeoDrawer/components/SerpPreview/highlight-keyphrase.js +10 -3
  17. package/dist/components/SeoDrawer/components/SerpPreview/highlight-keyphrase.js.map +1 -1
  18. package/dist/components/SeoDrawer/components/SerpPreview/index.d.ts +2 -1
  19. package/dist/components/SeoDrawer/components/SerpPreview/index.d.ts.map +1 -1
  20. package/dist/components/SeoDrawer/components/SerpPreview/index.js +8 -2
  21. package/dist/components/SeoDrawer/components/SerpPreview/index.js.map +1 -1
  22. package/dist/components/SeoDrawer/components/SerpPreview/variants.d.ts +6 -6
  23. package/dist/components/SeoDrawer/components/TabWrapper.d.ts +6 -0
  24. package/dist/components/SeoDrawer/components/TabWrapper.d.ts.map +1 -0
  25. package/dist/components/SeoDrawer/components/TabWrapper.js +8 -0
  26. package/dist/components/SeoDrawer/components/TabWrapper.js.map +1 -0
  27. package/dist/components/SeoDrawer/index.d.ts +11 -4
  28. package/dist/components/SeoDrawer/index.d.ts.map +1 -1
  29. package/dist/components/SeoDrawer/index.js +38 -16
  30. package/dist/components/SeoDrawer/index.js.map +1 -1
  31. package/dist/components/SeoDrawer/keyphraseState.d.ts +16 -0
  32. package/dist/components/SeoDrawer/keyphraseState.d.ts.map +1 -0
  33. package/dist/components/SeoDrawer/keyphraseState.js +73 -0
  34. package/dist/components/SeoDrawer/keyphraseState.js.map +1 -0
  35. package/dist/components/SeoDrawer/keyphraseStorage.d.ts +5 -0
  36. package/dist/components/SeoDrawer/keyphraseStorage.d.ts.map +1 -0
  37. package/dist/components/SeoDrawer/keyphraseStorage.js +60 -0
  38. package/dist/components/SeoDrawer/keyphraseStorage.js.map +1 -0
  39. package/dist/components/SeoDrawer/tabs/InclusiveTab.d.ts.map +1 -1
  40. package/dist/components/SeoDrawer/tabs/InclusiveTab.js +3 -2
  41. package/dist/components/SeoDrawer/tabs/InclusiveTab.js.map +1 -1
  42. package/dist/components/SeoDrawer/tabs/KeyphraseTab.d.ts +14 -7
  43. package/dist/components/SeoDrawer/tabs/KeyphraseTab.d.ts.map +1 -1
  44. package/dist/components/SeoDrawer/tabs/KeyphraseTab.js +110 -69
  45. package/dist/components/SeoDrawer/tabs/KeyphraseTab.js.map +1 -1
  46. package/dist/components/SeoDrawer/tabs/OnPageTab.d.ts.map +1 -1
  47. package/dist/components/SeoDrawer/tabs/OnPageTab.js +3 -2
  48. package/dist/components/SeoDrawer/tabs/OnPageTab.js.map +1 -1
  49. package/dist/components/SeoDrawer/tabs/ReadabilityTab.d.ts.map +1 -1
  50. package/dist/components/SeoDrawer/tabs/ReadabilityTab.js +3 -2
  51. package/dist/components/SeoDrawer/tabs/ReadabilityTab.js.map +1 -1
  52. package/dist/components/SeoDrawer/tabs/SerpTab.d.ts +2 -1
  53. package/dist/components/SeoDrawer/tabs/SerpTab.d.ts.map +1 -1
  54. package/dist/components/SeoDrawer/tabs/SerpTab.js +14 -3
  55. package/dist/components/SeoDrawer/tabs/SerpTab.js.map +1 -1
  56. package/dist/components/SeoDrawer/tabs/VitalsTab.d.ts.map +1 -1
  57. package/dist/components/SeoDrawer/tabs/VitalsTab.js +7 -3
  58. package/dist/components/SeoDrawer/tabs/VitalsTab.js.map +1 -1
  59. package/dist/components/SeoDrawer/tabs/keyphrase/KeyphraseCard.d.ts +21 -0
  60. package/dist/components/SeoDrawer/tabs/keyphrase/KeyphraseCard.d.ts.map +1 -0
  61. package/dist/components/SeoDrawer/tabs/keyphrase/KeyphraseCard.js +38 -0
  62. package/dist/components/SeoDrawer/tabs/keyphrase/KeyphraseCard.js.map +1 -0
  63. package/dist/components/SeoDrawer/tabs/keyphrase/KeyphraseDetail.d.ts +25 -0
  64. package/dist/components/SeoDrawer/tabs/keyphrase/KeyphraseDetail.d.ts.map +1 -0
  65. package/dist/components/SeoDrawer/tabs/keyphrase/KeyphraseDetail.js +127 -0
  66. package/dist/components/SeoDrawer/tabs/keyphrase/KeyphraseDetail.js.map +1 -0
  67. package/dist/components/SeoDrawer/tabs/keyphrase/KeyphraseRail.d.ts +12 -0
  68. package/dist/components/SeoDrawer/tabs/keyphrase/KeyphraseRail.d.ts.map +1 -0
  69. package/dist/components/SeoDrawer/tabs/keyphrase/KeyphraseRail.js +54 -0
  70. package/dist/components/SeoDrawer/tabs/keyphrase/KeyphraseRail.js.map +1 -0
  71. package/dist/components/SeoDrawer/tabs/keyphrase/SynonymsField.d.ts +7 -0
  72. package/dist/components/SeoDrawer/tabs/keyphrase/SynonymsField.d.ts.map +1 -0
  73. package/dist/components/SeoDrawer/tabs/keyphrase/SynonymsField.js +93 -0
  74. package/dist/components/SeoDrawer/tabs/keyphrase/SynonymsField.js.map +1 -0
  75. package/dist/components/SeoDrawer/tabs/keyphrase/icons.d.ts +2 -0
  76. package/dist/components/SeoDrawer/tabs/keyphrase/icons.d.ts.map +1 -0
  77. package/dist/components/SeoDrawer/tabs/keyphrase/icons.js +7 -0
  78. package/dist/components/SeoDrawer/tabs/keyphrase/icons.js.map +1 -0
  79. package/dist/components/SeoDrawer/useAnalysis.d.ts +0 -1
  80. package/dist/components/SeoDrawer/useAnalysis.d.ts.map +1 -1
  81. package/dist/components/SeoDrawer/useAnalysis.js +0 -3
  82. package/dist/components/SeoDrawer/useAnalysis.js.map +1 -1
  83. package/dist/components/SeoDrawer/useKeyphrases.d.ts +18 -0
  84. package/dist/components/SeoDrawer/useKeyphrases.d.ts.map +1 -0
  85. package/dist/components/SeoDrawer/useKeyphrases.js +78 -0
  86. package/dist/components/SeoDrawer/useKeyphrases.js.map +1 -0
  87. package/dist/components/SeoDrawer/useLiveDocument.d.ts +4 -3
  88. package/dist/components/SeoDrawer/useLiveDocument.d.ts.map +1 -1
  89. package/dist/components/SeoDrawer/useLiveDocument.js +17 -9
  90. package/dist/components/SeoDrawer/useLiveDocument.js.map +1 -1
  91. package/dist/components/SeoDrawer/variants.d.ts +1 -1
  92. package/dist/components/SeoDrawer/variants.d.ts.map +1 -1
  93. package/dist/components/SeoDrawer/variants.js +2 -1
  94. package/dist/components/SeoDrawer/variants.js.map +1 -1
  95. package/dist/constants/generation.d.ts +1 -1
  96. package/dist/constants/generation.js +1 -1
  97. package/dist/constants/generation.js.map +1 -1
  98. package/dist/constants/index.d.ts +1 -0
  99. package/dist/constants/index.d.ts.map +1 -1
  100. package/dist/constants/index.js +2 -0
  101. package/dist/constants/index.js.map +1 -1
  102. package/dist/engine/buildPaper.d.ts +2 -2
  103. package/dist/engine/buildPaper.d.ts.map +1 -1
  104. package/dist/engine/buildPaper.js +4 -2
  105. package/dist/engine/buildPaper.js.map +1 -1
  106. package/dist/engine/runAnalysis/index.d.ts.map +1 -1
  107. package/dist/engine/runAnalysis/index.js +7 -0
  108. package/dist/engine/runAnalysis/index.js.map +1 -1
  109. package/dist/engine/runAnalysis/services/derive-related.d.ts +4 -0
  110. package/dist/engine/runAnalysis/services/derive-related.d.ts.map +1 -0
  111. package/dist/engine/runAnalysis/services/derive-related.js +16 -0
  112. package/dist/engine/runAnalysis/services/derive-related.js.map +1 -0
  113. package/dist/engine/types/analysis.d.ts +11 -0
  114. package/dist/engine/types/analysis.d.ts.map +1 -1
  115. package/dist/ui/Button.d.ts +9 -0
  116. package/dist/ui/Button.d.ts.map +1 -0
  117. package/dist/ui/Button.js +34 -0
  118. package/dist/ui/Button.js.map +1 -0
  119. package/dist/ui/ScoreRing.d.ts +17 -4
  120. package/dist/ui/ScoreRing.d.ts.map +1 -1
  121. package/dist/ui/ScoreRing.js +38 -14
  122. package/dist/ui/ScoreRing.js.map +1 -1
  123. package/package.json +1 -1
  124. package/dist/components/SeoDrawer/keyphrasePending.d.ts +0 -2
  125. package/dist/components/SeoDrawer/keyphrasePending.d.ts.map +0 -1
  126. package/dist/components/SeoDrawer/keyphrasePending.js +0 -9
  127. package/dist/components/SeoDrawer/keyphrasePending.js.map +0 -1
@@ -11,7 +11,6 @@ function useAnalysis({
11
11
  }) {
12
12
  const [result, setResult] = useState(null);
13
13
  const [analyzing, setAnalyzing] = useState(false);
14
- const [analyzedKeyphrase, setAnalyzedKeyphrase] = useState(null);
15
14
  const getInputRef = useRef(getInput);
16
15
  getInputRef.current = getInput;
17
16
  const signatureRef = useRef(signature);
@@ -30,7 +29,6 @@ function useAnalysis({
30
29
  if (runId !== runSeq.current)
31
30
  return;
32
31
  setResult(runAnalysis(input));
33
- setAnalyzedKeyphrase(input.keyphrase);
34
32
  } finally {
35
33
  if (runId === runSeq.current)
36
34
  setAnalyzing(false);
@@ -52,7 +50,6 @@ function useAnalysis({
52
50
  return {
53
51
  result,
54
52
  analyzing,
55
- analyzedKeyphrase,
56
53
  analyzeNow
57
54
  };
58
55
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/components/SeoDrawer/useAnalysis.ts"],"sourcesContent":["\"use client\";\n\nimport { useCallback, useEffect, useRef, useState } from \"react\";\nimport { runAnalysis } from \"../../engine/runAnalysis\";\nimport type { AnalysisInput, AnalysisResult } from \"../../engine/types/analysis\";\nimport { decideAutoAction } from \"./analysisDecision\";\nimport { ensureLanguagePack } from \"./languagePacks\";\n\nexport interface UseAnalysisArgs {\n getInput: (opts?: { live?: boolean }) => Promise<AnalysisInput>;\n signature: string;\n supportedLocales: string[];\n enabled?: boolean;\n}\n\nexport interface UseAnalysisResult {\n result: AnalysisResult | null;\n analyzing: boolean;\n analyzedKeyphrase: string | null;\n analyzeNow: () => void;\n}\n\nexport function useAnalysis({\n getInput,\n signature,\n supportedLocales,\n enabled = true,\n}: UseAnalysisArgs): UseAnalysisResult {\n const [result, setResult] = useState<AnalysisResult | null>(null);\n const [analyzing, setAnalyzing] = useState(false);\n const [analyzedKeyphrase, setAnalyzedKeyphrase] = useState<string | null>(null);\n\n const getInputRef = useRef(getInput);\n getInputRef.current = getInput;\n const signatureRef = useRef(signature);\n signatureRef.current = signature;\n const localesRef = useRef(supportedLocales);\n localesRef.current = supportedLocales;\n\n const lastSignature = useRef<string | null>(null);\n const runSeq = useRef(0);\n\n const run = useCallback(async (live: boolean) => {\n const runId = ++runSeq.current;\n\n lastSignature.current = signatureRef.current;\n setAnalyzing(true);\n\n try {\n const input = await getInputRef.current({ live });\n await ensureLanguagePack(input.locale, localesRef.current);\n if (runId !== runSeq.current) return;\n\n setResult(runAnalysis(input));\n setAnalyzedKeyphrase(input.keyphrase);\n } finally {\n if (runId === runSeq.current) setAnalyzing(false);\n }\n }, []);\n\n const analyzeNow = useCallback(() => {\n void run(true);\n }, [run]);\n\n useEffect(() => {\n const action = decideAutoAction({\n enabled,\n signature,\n lastSignature: lastSignature.current,\n });\n\n if (action === \"skip\") return;\n\n void run(false);\n }, [signature, run, enabled]);\n\n return {\n result,\n analyzing,\n analyzedKeyphrase,\n analyzeNow,\n };\n}\n"],"mappings":";AAEA,SAAS,aAAa,WAAW,QAAQ,gBAAgB;AACzD,SAAS,mBAAmB;AAE5B,SAAS,wBAAwB;AACjC,SAAS,0BAA0B;AAgB5B,SAAS,YAAY;AAAA,EAC1B;AAAA,EACA;AAAA,EACA;AAAA,EACA,UAAU;AACZ,GAAuC;AACrC,QAAM,CAAC,QAAQ,SAAS,IAAI,SAAgC,IAAI;AAChE,QAAM,CAAC,WAAW,YAAY,IAAI,SAAS,KAAK;AAChD,QAAM,CAAC,mBAAmB,oBAAoB,IAAI,SAAwB,IAAI;AAE9E,QAAM,cAAc,OAAO,QAAQ;AACnC,cAAY,UAAU;AACtB,QAAM,eAAe,OAAO,SAAS;AACrC,eAAa,UAAU;AACvB,QAAM,aAAa,OAAO,gBAAgB;AAC1C,aAAW,UAAU;AAErB,QAAM,gBAAgB,OAAsB,IAAI;AAChD,QAAM,SAAS,OAAO,CAAC;AAEvB,QAAM,MAAM,YAAY,OAAO,SAAkB;AAC/C,UAAM,QAAQ,EAAE,OAAO;AAEvB,kBAAc,UAAU,aAAa;AACrC,iBAAa,IAAI;AAEjB,QAAI;AACF,YAAM,QAAQ,MAAM,YAAY,QAAQ,EAAE,KAAK,CAAC;AAChD,YAAM,mBAAmB,MAAM,QAAQ,WAAW,OAAO;AACzD,UAAI,UAAU,OAAO;AAAS;AAE9B,gBAAU,YAAY,KAAK,CAAC;AAC5B,2BAAqB,MAAM,SAAS;AAAA,IACtC,UAAE;AACA,UAAI,UAAU,OAAO;AAAS,qBAAa,KAAK;AAAA,IAClD;AAAA,EACF,GAAG,CAAC,CAAC;AAEL,QAAM,aAAa,YAAY,MAAM;AACnC,SAAK,IAAI,IAAI;AAAA,EACf,GAAG,CAAC,GAAG,CAAC;AAER,YAAU,MAAM;AACd,UAAM,SAAS,iBAAiB;AAAA,MAC9B;AAAA,MACA;AAAA,MACA,eAAe,cAAc;AAAA,IAC/B,CAAC;AAED,QAAI,WAAW;AAAQ;AAEvB,SAAK,IAAI,KAAK;AAAA,EAChB,GAAG,CAAC,WAAW,KAAK,OAAO,CAAC;AAE5B,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;","names":[]}
1
+ {"version":3,"sources":["../../../src/components/SeoDrawer/useAnalysis.ts"],"sourcesContent":["\"use client\";\n\nimport { useCallback, useEffect, useRef, useState } from \"react\";\nimport { runAnalysis } from \"../../engine/runAnalysis\";\nimport type { AnalysisInput, AnalysisResult } from \"../../engine/types/analysis\";\nimport { decideAutoAction } from \"./analysisDecision\";\nimport { ensureLanguagePack } from \"./languagePacks\";\n\nexport interface UseAnalysisArgs {\n getInput: (opts?: { live?: boolean }) => Promise<AnalysisInput>;\n signature: string;\n supportedLocales: string[];\n enabled?: boolean;\n}\n\nexport interface UseAnalysisResult {\n result: AnalysisResult | null;\n analyzing: boolean;\n analyzeNow: () => void;\n}\n\nexport function useAnalysis({\n getInput,\n signature,\n supportedLocales,\n enabled = true,\n}: UseAnalysisArgs): UseAnalysisResult {\n const [result, setResult] = useState<AnalysisResult | null>(null);\n const [analyzing, setAnalyzing] = useState(false);\n\n const getInputRef = useRef(getInput);\n getInputRef.current = getInput;\n const signatureRef = useRef(signature);\n signatureRef.current = signature;\n const localesRef = useRef(supportedLocales);\n localesRef.current = supportedLocales;\n\n const lastSignature = useRef<string | null>(null);\n const runSeq = useRef(0);\n\n const run = useCallback(async (live: boolean) => {\n const runId = ++runSeq.current;\n\n lastSignature.current = signatureRef.current;\n setAnalyzing(true);\n\n try {\n const input = await getInputRef.current({ live });\n await ensureLanguagePack(input.locale, localesRef.current);\n if (runId !== runSeq.current) return;\n\n setResult(runAnalysis(input));\n } finally {\n if (runId === runSeq.current) setAnalyzing(false);\n }\n }, []);\n\n const analyzeNow = useCallback(() => {\n void run(true);\n }, [run]);\n\n useEffect(() => {\n const action = decideAutoAction({\n enabled,\n signature,\n lastSignature: lastSignature.current,\n });\n\n if (action === \"skip\") return;\n\n void run(false);\n }, [signature, run, enabled]);\n\n return {\n result,\n analyzing,\n analyzeNow,\n };\n}\n"],"mappings":";AAEA,SAAS,aAAa,WAAW,QAAQ,gBAAgB;AACzD,SAAS,mBAAmB;AAE5B,SAAS,wBAAwB;AACjC,SAAS,0BAA0B;AAe5B,SAAS,YAAY;AAAA,EAC1B;AAAA,EACA;AAAA,EACA;AAAA,EACA,UAAU;AACZ,GAAuC;AACrC,QAAM,CAAC,QAAQ,SAAS,IAAI,SAAgC,IAAI;AAChE,QAAM,CAAC,WAAW,YAAY,IAAI,SAAS,KAAK;AAEhD,QAAM,cAAc,OAAO,QAAQ;AACnC,cAAY,UAAU;AACtB,QAAM,eAAe,OAAO,SAAS;AACrC,eAAa,UAAU;AACvB,QAAM,aAAa,OAAO,gBAAgB;AAC1C,aAAW,UAAU;AAErB,QAAM,gBAAgB,OAAsB,IAAI;AAChD,QAAM,SAAS,OAAO,CAAC;AAEvB,QAAM,MAAM,YAAY,OAAO,SAAkB;AAC/C,UAAM,QAAQ,EAAE,OAAO;AAEvB,kBAAc,UAAU,aAAa;AACrC,iBAAa,IAAI;AAEjB,QAAI;AACF,YAAM,QAAQ,MAAM,YAAY,QAAQ,EAAE,KAAK,CAAC;AAChD,YAAM,mBAAmB,MAAM,QAAQ,WAAW,OAAO;AACzD,UAAI,UAAU,OAAO;AAAS;AAE9B,gBAAU,YAAY,KAAK,CAAC;AAAA,IAC9B,UAAE;AACA,UAAI,UAAU,OAAO;AAAS,qBAAa,KAAK;AAAA,IAClD;AAAA,EACF,GAAG,CAAC,CAAC;AAEL,QAAM,aAAa,YAAY,MAAM;AACnC,SAAK,IAAI,IAAI;AAAA,EACf,GAAG,CAAC,GAAG,CAAC;AAER,YAAU,MAAM;AACd,UAAM,SAAS,iBAAiB;AAAA,MAC9B;AAAA,MACA;AAAA,MACA,eAAe,cAAc;AAAA,IAC/B,CAAC;AAED,QAAI,WAAW;AAAQ;AAEvB,SAAK,IAAI,KAAK;AAAA,EAChB,GAAG,CAAC,WAAW,KAAK,OAAO,CAAC;AAE5B,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;","names":[]}
@@ -0,0 +1,18 @@
1
+ import type { KeyphraseEntry } from "./keyphraseState";
2
+ export interface UseKeyphrasesArgs {
3
+ collectionSlug: string;
4
+ docId: string;
5
+ localeCode: string;
6
+ }
7
+ export interface UseKeyphrasesApi {
8
+ keyphrases: KeyphraseEntry[];
9
+ addRelated: () => string | undefined;
10
+ updateText: (id: string, text: string) => void;
11
+ addSynonym: (id: string, syn: string) => void;
12
+ removeSynonym: (id: string, index: number) => void;
13
+ remove: (id: string) => void;
14
+ setFocus: (id: string) => void;
15
+ isDuplicate: (id: string, text: string) => boolean;
16
+ }
17
+ export declare function useKeyphrases({ collectionSlug, docId, localeCode, }: UseKeyphrasesArgs): UseKeyphrasesApi;
18
+ //# sourceMappingURL=useKeyphrases.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useKeyphrases.d.ts","sourceRoot":"","sources":["../../../src/components/SeoDrawer/useKeyphrases.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAGvD,MAAM,WAAW,iBAAiB;IAChC,cAAc,EAAE,MAAM,CAAC;IACvB,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,gBAAgB;IAC/B,UAAU,EAAE,cAAc,EAAE,CAAC;IAC7B,UAAU,EAAE,MAAM,MAAM,GAAG,SAAS,CAAC;IACrC,UAAU,EAAE,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IAC/C,UAAU,EAAE,CAAC,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;IAC9C,aAAa,EAAE,CAAC,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACnD,MAAM,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAC;IAC7B,QAAQ,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAC;IAC/B,WAAW,EAAE,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC;CACpD;AAED,wBAAgB,aAAa,CAAC,EAC5B,cAAc,EACd,KAAK,EACL,UAAU,GACX,EAAE,iBAAiB,GAAG,gBAAgB,CAyEtC"}
@@ -0,0 +1,78 @@
1
+ "use client";
2
+ import { useCallback, useEffect, useRef, useState } from "react";
3
+ import * as ops from "./keyphraseState";
4
+ import { loadKeyphrases, saveKeyphrases, storageKey } from "./keyphraseStorage";
5
+ function useKeyphrases({
6
+ collectionSlug,
7
+ docId,
8
+ localeCode
9
+ }) {
10
+ const key = storageKey(collectionSlug, docId, localeCode);
11
+ const [list, setList] = useState(() => loadKeyphrases(key));
12
+ const keyRef = useRef(key);
13
+ useEffect(() => {
14
+ if (keyRef.current !== key) {
15
+ keyRef.current = key;
16
+ setList(loadKeyphrases(key));
17
+ }
18
+ }, [key]);
19
+ useEffect(() => {
20
+ saveKeyphrases(key, list);
21
+ }, [key, list]);
22
+ const listRef = useRef(list);
23
+ listRef.current = list;
24
+ useEffect(
25
+ () => () => {
26
+ const pruned = ops.pruneEmpties(listRef.current);
27
+ if (pruned.length !== listRef.current.length)
28
+ saveKeyphrases(keyRef.current, pruned);
29
+ },
30
+ []
31
+ );
32
+ const addRelated = useCallback(() => {
33
+ const current = listRef.current;
34
+ const next = ops.addRelated(current);
35
+ if (next === current)
36
+ return ops.firstEmptyId(current);
37
+ setList(next);
38
+ return next.at(-1)?.id;
39
+ }, []);
40
+ const updateText = useCallback(
41
+ (id, text) => setList((l) => ops.updateText(l, id, text)),
42
+ []
43
+ );
44
+ const addSynonym = useCallback(
45
+ (id, syn) => setList((l) => ops.addSynonym(l, id, syn)),
46
+ []
47
+ );
48
+ const removeSynonym = useCallback(
49
+ (id, index) => setList((l) => ops.removeSynonym(l, id, index)),
50
+ []
51
+ );
52
+ const remove = useCallback(
53
+ (id) => setList((l) => {
54
+ const next = ops.remove(l, id);
55
+ return next.length > 0 ? next : [ops.createEntry()];
56
+ }),
57
+ []
58
+ );
59
+ const setFocus = useCallback((id) => setList((l) => ops.setFocus(l, id)), []);
60
+ const isDuplicate = useCallback(
61
+ (id, text) => ops.isDuplicate(listRef.current, id, text),
62
+ []
63
+ );
64
+ return {
65
+ keyphrases: list,
66
+ addRelated,
67
+ updateText,
68
+ addSynonym,
69
+ removeSynonym,
70
+ remove,
71
+ setFocus,
72
+ isDuplicate
73
+ };
74
+ }
75
+ export {
76
+ useKeyphrases
77
+ };
78
+ //# sourceMappingURL=useKeyphrases.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/components/SeoDrawer/useKeyphrases.ts"],"sourcesContent":["\"use client\";\n\nimport { useCallback, useEffect, useRef, useState } from \"react\";\nimport * as ops from \"./keyphraseState\";\nimport type { KeyphraseEntry } from \"./keyphraseState\";\nimport { loadKeyphrases, saveKeyphrases, storageKey } from \"./keyphraseStorage\";\n\nexport interface UseKeyphrasesArgs {\n collectionSlug: string;\n docId: string;\n localeCode: string;\n}\n\nexport interface UseKeyphrasesApi {\n keyphrases: KeyphraseEntry[];\n addRelated: () => string | undefined;\n updateText: (id: string, text: string) => void;\n addSynonym: (id: string, syn: string) => void;\n removeSynonym: (id: string, index: number) => void;\n remove: (id: string) => void;\n setFocus: (id: string) => void;\n isDuplicate: (id: string, text: string) => boolean;\n}\n\nexport function useKeyphrases({\n collectionSlug,\n docId,\n localeCode,\n}: UseKeyphrasesArgs): UseKeyphrasesApi {\n const key = storageKey(collectionSlug, docId, localeCode);\n const [list, setList] = useState<KeyphraseEntry[]>(() => loadKeyphrases(key));\n\n const keyRef = useRef(key);\n\n useEffect(() => {\n if (keyRef.current !== key) {\n keyRef.current = key;\n setList(loadKeyphrases(key));\n }\n }, [key]);\n\n useEffect(() => {\n saveKeyphrases(key, list);\n }, [key, list]);\n\n const listRef = useRef(list);\n listRef.current = list;\n useEffect(\n () => () => {\n const pruned = ops.pruneEmpties(listRef.current);\n if (pruned.length !== listRef.current.length) saveKeyphrases(keyRef.current, pruned);\n },\n []\n );\n\n const addRelated = useCallback((): string | undefined => {\n const current = listRef.current;\n const next = ops.addRelated(current);\n\n if (next === current) return ops.firstEmptyId(current);\n setList(next);\n\n return next.at(-1)?.id;\n }, []);\n const updateText = useCallback(\n (id: string, text: string) => setList((l) => ops.updateText(l, id, text)),\n []\n );\n const addSynonym = useCallback(\n (id: string, syn: string) => setList((l) => ops.addSynonym(l, id, syn)),\n []\n );\n const removeSynonym = useCallback(\n (id: string, index: number) => setList((l) => ops.removeSynonym(l, id, index)),\n []\n );\n const remove = useCallback(\n (id: string) =>\n setList((l) => {\n const next = ops.remove(l, id);\n\n return next.length > 0 ? next : [ops.createEntry()];\n }),\n []\n );\n const setFocus = useCallback((id: string) => setList((l) => ops.setFocus(l, id)), []);\n const isDuplicate = useCallback(\n (id: string, text: string) => ops.isDuplicate(listRef.current, id, text),\n []\n );\n\n return {\n keyphrases: list,\n addRelated,\n updateText,\n addSynonym,\n removeSynonym,\n remove,\n setFocus,\n isDuplicate,\n };\n}\n"],"mappings":";AAEA,SAAS,aAAa,WAAW,QAAQ,gBAAgB;AACzD,YAAY,SAAS;AAErB,SAAS,gBAAgB,gBAAgB,kBAAkB;AAmBpD,SAAS,cAAc;AAAA,EAC5B;AAAA,EACA;AAAA,EACA;AACF,GAAwC;AACtC,QAAM,MAAM,WAAW,gBAAgB,OAAO,UAAU;AACxD,QAAM,CAAC,MAAM,OAAO,IAAI,SAA2B,MAAM,eAAe,GAAG,CAAC;AAE5E,QAAM,SAAS,OAAO,GAAG;AAEzB,YAAU,MAAM;AACd,QAAI,OAAO,YAAY,KAAK;AAC1B,aAAO,UAAU;AACjB,cAAQ,eAAe,GAAG,CAAC;AAAA,IAC7B;AAAA,EACF,GAAG,CAAC,GAAG,CAAC;AAER,YAAU,MAAM;AACd,mBAAe,KAAK,IAAI;AAAA,EAC1B,GAAG,CAAC,KAAK,IAAI,CAAC;AAEd,QAAM,UAAU,OAAO,IAAI;AAC3B,UAAQ,UAAU;AAClB;AAAA,IACE,MAAM,MAAM;AACV,YAAM,SAAS,IAAI,aAAa,QAAQ,OAAO;AAC/C,UAAI,OAAO,WAAW,QAAQ,QAAQ;AAAQ,uBAAe,OAAO,SAAS,MAAM;AAAA,IACrF;AAAA,IACA,CAAC;AAAA,EACH;AAEA,QAAM,aAAa,YAAY,MAA0B;AACvD,UAAM,UAAU,QAAQ;AACxB,UAAM,OAAO,IAAI,WAAW,OAAO;AAEnC,QAAI,SAAS;AAAS,aAAO,IAAI,aAAa,OAAO;AACrD,YAAQ,IAAI;AAEZ,WAAO,KAAK,GAAG,EAAE,GAAG;AAAA,EACtB,GAAG,CAAC,CAAC;AACL,QAAM,aAAa;AAAA,IACjB,CAAC,IAAY,SAAiB,QAAQ,CAAC,MAAM,IAAI,WAAW,GAAG,IAAI,IAAI,CAAC;AAAA,IACxE,CAAC;AAAA,EACH;AACA,QAAM,aAAa;AAAA,IACjB,CAAC,IAAY,QAAgB,QAAQ,CAAC,MAAM,IAAI,WAAW,GAAG,IAAI,GAAG,CAAC;AAAA,IACtE,CAAC;AAAA,EACH;AACA,QAAM,gBAAgB;AAAA,IACpB,CAAC,IAAY,UAAkB,QAAQ,CAAC,MAAM,IAAI,cAAc,GAAG,IAAI,KAAK,CAAC;AAAA,IAC7E,CAAC;AAAA,EACH;AACA,QAAM,SAAS;AAAA,IACb,CAAC,OACC,QAAQ,CAAC,MAAM;AACb,YAAM,OAAO,IAAI,OAAO,GAAG,EAAE;AAE7B,aAAO,KAAK,SAAS,IAAI,OAAO,CAAC,IAAI,YAAY,CAAC;AAAA,IACpD,CAAC;AAAA,IACH,CAAC;AAAA,EACH;AACA,QAAM,WAAW,YAAY,CAAC,OAAe,QAAQ,CAAC,MAAM,IAAI,SAAS,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC;AACpF,QAAM,cAAc;AAAA,IAClB,CAAC,IAAY,SAAiB,IAAI,YAAY,QAAQ,SAAS,IAAI,IAAI;AAAA,IACvE,CAAC;AAAA,EACH;AAEA,SAAO;AAAA,IACL,YAAY;AAAA,IACZ;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;","names":[]}
@@ -1,5 +1,6 @@
1
- import type { AnalysisInput } from "../../engine/types/analysis";
1
+ import type { AnalysisInput, KeyphraseInput } from "../../engine/types/analysis";
2
2
  import type { SeoFieldPaths } from "../../types/config";
3
+ export declare function keyphraseSignature(keyphrases: KeyphraseInput[]): string;
3
4
  export interface LiveDocArgs {
4
5
  collectionSlug: string;
5
6
  fields: SeoFieldPaths;
@@ -7,7 +8,7 @@ export interface LiveDocArgs {
7
8
  name: string;
8
9
  baseUrl: string;
9
10
  };
10
- keyphrase: string;
11
+ keyphrases: KeyphraseInput[];
11
12
  enabled?: boolean;
12
13
  extractContentPath: string;
13
14
  }
@@ -17,5 +18,5 @@ export interface UseLiveDocumentResult {
17
18
  live?: boolean;
18
19
  }) => Promise<AnalysisInput>;
19
20
  }
20
- export declare function useLiveDocument({ collectionSlug: _collectionSlug, fields, site, keyphrase, enabled, extractContentPath, }: LiveDocArgs): UseLiveDocumentResult;
21
+ export declare function useLiveDocument({ collectionSlug: _collectionSlug, fields, site, keyphrases, enabled, extractContentPath, }: LiveDocArgs): UseLiveDocumentResult;
21
22
  //# sourceMappingURL=useLiveDocument.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"useLiveDocument.d.ts","sourceRoot":"","sources":["../../../src/components/SeoDrawer/useLiveDocument.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAC;AACjE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAMxD,MAAM,WAAW,WAAW;IAC1B,cAAc,EAAE,MAAM,CAAC;IACvB,MAAM,EAAE,aAAa,CAAC;IACtB,IAAI,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC;IACxC,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,kBAAkB,EAAE,MAAM,CAAC;CAC5B;AAED,MAAM,WAAW,qBAAqB;IACpC,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,CAAC,IAAI,CAAC,EAAE;QAAE,IAAI,CAAC,EAAE,OAAO,CAAA;KAAE,KAAK,OAAO,CAAC,aAAa,CAAC,CAAC;CACjE;AAED,wBAAgB,eAAe,CAAC,EAC9B,cAAc,EAAE,eAAe,EAC/B,MAAM,EACN,IAAI,EACJ,SAAS,EACT,OAAc,EACd,kBAAkB,GACnB,EAAE,WAAW,GAAG,qBAAqB,CAwErC"}
1
+ {"version":3,"file":"useLiveDocument.d.ts","sourceRoot":"","sources":["../../../src/components/SeoDrawer/useLiveDocument.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAC;AACjF,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAMxD,wBAAgB,kBAAkB,CAAC,UAAU,EAAE,cAAc,EAAE,GAAG,MAAM,CAEvE;AAED,MAAM,WAAW,WAAW;IAC1B,cAAc,EAAE,MAAM,CAAC;IACvB,MAAM,EAAE,aAAa,CAAC;IACtB,IAAI,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC;IACxC,UAAU,EAAE,cAAc,EAAE,CAAC;IAC7B,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,kBAAkB,EAAE,MAAM,CAAC;CAC5B;AAED,MAAM,WAAW,qBAAqB;IACpC,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,CAAC,IAAI,CAAC,EAAE;QAAE,IAAI,CAAC,EAAE,OAAO,CAAA;KAAE,KAAK,OAAO,CAAC,aAAa,CAAC,CAAC;CACjE;AAED,wBAAgB,eAAe,CAAC,EAC9B,cAAc,EAAE,eAAe,EAC/B,MAAM,EACN,IAAI,EACJ,UAAU,EACV,OAAc,EACd,kBAAkB,GACnB,EAAE,WAAW,GAAG,qBAAqB,CA6ErC"}
@@ -6,11 +6,14 @@ import { resolveContentExtractor } from "../../content/registry";
6
6
  import { buildAnalysisInput } from "./build-analysis-input";
7
7
  const erroredPaths = /* @__PURE__ */ new Set();
8
8
  const DEBOUNCE_MS = 1e3;
9
+ function keyphraseSignature(keyphrases) {
10
+ return JSON.stringify(keyphrases.map((k) => [k.text, k.synonyms]));
11
+ }
9
12
  function useLiveDocument({
10
13
  collectionSlug: _collectionSlug,
11
14
  fields,
12
15
  site,
13
- keyphrase,
16
+ keyphrases,
14
17
  enabled = true,
15
18
  extractContentPath
16
19
  }) {
@@ -18,21 +21,25 @@ function useLiveDocument({
18
21
  const locale = useLocale();
19
22
  const { config } = useConfig();
20
23
  const debouncedFields = useDebounce(formFields, DEBOUNCE_MS);
21
- const debouncedKeyphrase = useDebounce(keyphrase, DEBOUNCE_MS);
24
+ const debouncedKeyphrases = useDebounce(keyphrases, DEBOUNCE_MS);
22
25
  const apiRoute = config.routes.api;
23
26
  const values = useMemo(
24
27
  () => enabled ? reduceFieldsToValues(debouncedFields, true) : {},
25
28
  [enabled, debouncedFields]
26
29
  );
27
30
  const signature = useMemo(
28
- () => JSON.stringify({ values, keyphrase: debouncedKeyphrase, locale: locale?.code ?? null }),
29
- [values, debouncedKeyphrase, locale]
31
+ () => JSON.stringify({
32
+ values,
33
+ keyphrases: keyphraseSignature(debouncedKeyphrases),
34
+ locale: locale?.code ?? null
35
+ }),
36
+ [values, debouncedKeyphrases, locale]
30
37
  );
31
38
  const liveRef = useRef({
32
39
  formFields,
33
40
  values,
34
- keyphrase,
35
- debouncedKeyphrase,
41
+ keyphrases,
42
+ debouncedKeyphrases,
36
43
  locale,
37
44
  fields,
38
45
  site,
@@ -42,8 +49,8 @@ function useLiveDocument({
42
49
  liveRef.current = {
43
50
  formFields,
44
51
  values,
45
- keyphrase,
46
- debouncedKeyphrase,
52
+ keyphrases,
53
+ debouncedKeyphrases,
47
54
  locale,
48
55
  fields,
49
56
  site,
@@ -66,7 +73,7 @@ function useLiveDocument({
66
73
  locale: s.locale,
67
74
  payloadLocale: s.locale?.code,
68
75
  apiRoute: s.apiRoute,
69
- keyphrase: live ? s.keyphrase : s.debouncedKeyphrase,
76
+ keyphrases: live ? s.keyphrases : s.debouncedKeyphrases,
70
77
  fields: s.fields,
71
78
  site: s.site,
72
79
  extractor
@@ -77,6 +84,7 @@ function useLiveDocument({
77
84
  return { signature, getInput };
78
85
  }
79
86
  export {
87
+ keyphraseSignature,
80
88
  useLiveDocument
81
89
  };
82
90
  //# sourceMappingURL=useLiveDocument.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/components/SeoDrawer/useLiveDocument.ts"],"sourcesContent":["\"use client\";\n\nimport { useAllFormFields, useConfig, useDebounce, useLocale } from \"@payloadcms/ui\";\nimport { reduceFieldsToValues } from \"payload/shared\";\nimport { useCallback, useMemo, useRef } from \"react\";\nimport { resolveContentExtractor } from \"../../content/registry\";\nimport type { AnalysisInput } from \"../../engine/types/analysis\";\nimport type { SeoFieldPaths } from \"../../types/config\";\nimport { buildAnalysisInput } from \"./build-analysis-input\";\n\nconst erroredPaths = new Set<string>();\nconst DEBOUNCE_MS = 1000;\n\nexport interface LiveDocArgs {\n collectionSlug: string;\n fields: SeoFieldPaths;\n site: { name: string; baseUrl: string };\n keyphrase: string;\n enabled?: boolean;\n extractContentPath: string;\n}\n\nexport interface UseLiveDocumentResult {\n signature: string;\n getInput: (opts?: { live?: boolean }) => Promise<AnalysisInput>;\n}\n\nexport function useLiveDocument({\n collectionSlug: _collectionSlug,\n fields,\n site,\n keyphrase,\n enabled = true,\n extractContentPath,\n}: LiveDocArgs): UseLiveDocumentResult {\n const [formFields] = useAllFormFields();\n const locale = useLocale();\n const { config } = useConfig();\n\n const debouncedFields = useDebounce(formFields, DEBOUNCE_MS);\n const debouncedKeyphrase = useDebounce(keyphrase, DEBOUNCE_MS);\n const apiRoute = config.routes.api;\n\n const values = useMemo<Record<string, unknown>>(\n () => (enabled ? (reduceFieldsToValues(debouncedFields, true) as Record<string, unknown>) : {}),\n [enabled, debouncedFields]\n );\n\n const signature = useMemo(\n () => JSON.stringify({ values, keyphrase: debouncedKeyphrase, locale: locale?.code ?? null }),\n [values, debouncedKeyphrase, locale]\n );\n\n const liveRef = useRef({\n formFields,\n values,\n keyphrase,\n debouncedKeyphrase,\n locale,\n fields,\n site,\n extractContentPath,\n apiRoute,\n });\n liveRef.current = {\n formFields,\n values,\n keyphrase,\n debouncedKeyphrase,\n locale,\n fields,\n site,\n extractContentPath,\n apiRoute,\n };\n\n const getInput = useCallback(\n async ({ live = false }: { live?: boolean } = {}): Promise<AnalysisInput> => {\n const s = liveRef.current;\n const inputValues = live\n ? (reduceFieldsToValues(s.formFields, true) as Record<string, unknown>)\n : s.values;\n\n const extractor = resolveContentExtractor(s.extractContentPath);\n if (!extractor && !erroredPaths.has(s.extractContentPath)) {\n erroredPaths.add(s.extractContentPath);\n console.error(\n `[payload-plugin-seo] extractContentPath \"${s.extractContentPath}\" is not registered; content analysis will be empty. Call registerContentExtractors from \"@focus-reactive/payload-plugin-seo/content\" in an admin-mounted client module.`\n );\n }\n\n return buildAnalysisInput({\n values: inputValues,\n locale: s.locale,\n payloadLocale: s.locale?.code,\n apiRoute: s.apiRoute,\n keyphrase: live ? s.keyphrase : s.debouncedKeyphrase,\n fields: s.fields,\n site: s.site,\n extractor,\n });\n },\n []\n );\n\n return { signature, getInput };\n}\n"],"mappings":";AAEA,SAAS,kBAAkB,WAAW,aAAa,iBAAiB;AACpE,SAAS,4BAA4B;AACrC,SAAS,aAAa,SAAS,cAAc;AAC7C,SAAS,+BAA+B;AAGxC,SAAS,0BAA0B;AAEnC,MAAM,eAAe,oBAAI,IAAY;AACrC,MAAM,cAAc;AAgBb,SAAS,gBAAgB;AAAA,EAC9B,gBAAgB;AAAA,EAChB;AAAA,EACA;AAAA,EACA;AAAA,EACA,UAAU;AAAA,EACV;AACF,GAAuC;AACrC,QAAM,CAAC,UAAU,IAAI,iBAAiB;AACtC,QAAM,SAAS,UAAU;AACzB,QAAM,EAAE,OAAO,IAAI,UAAU;AAE7B,QAAM,kBAAkB,YAAY,YAAY,WAAW;AAC3D,QAAM,qBAAqB,YAAY,WAAW,WAAW;AAC7D,QAAM,WAAW,OAAO,OAAO;AAE/B,QAAM,SAAS;AAAA,IACb,MAAO,UAAW,qBAAqB,iBAAiB,IAAI,IAAgC,CAAC;AAAA,IAC7F,CAAC,SAAS,eAAe;AAAA,EAC3B;AAEA,QAAM,YAAY;AAAA,IAChB,MAAM,KAAK,UAAU,EAAE,QAAQ,WAAW,oBAAoB,QAAQ,QAAQ,QAAQ,KAAK,CAAC;AAAA,IAC5F,CAAC,QAAQ,oBAAoB,MAAM;AAAA,EACrC;AAEA,QAAM,UAAU,OAAO;AAAA,IACrB;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,CAAC;AACD,UAAQ,UAAU;AAAA,IAChB;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAEA,QAAM,WAAW;AAAA,IACf,OAAO,EAAE,OAAO,MAAM,IAAwB,CAAC,MAA8B;AAC3E,YAAM,IAAI,QAAQ;AAClB,YAAM,cAAc,OACf,qBAAqB,EAAE,YAAY,IAAI,IACxC,EAAE;AAEN,YAAM,YAAY,wBAAwB,EAAE,kBAAkB;AAC9D,UAAI,CAAC,aAAa,CAAC,aAAa,IAAI,EAAE,kBAAkB,GAAG;AACzD,qBAAa,IAAI,EAAE,kBAAkB;AACrC,gBAAQ;AAAA,UACN,4CAA4C,EAAE,kBAAkB;AAAA,QAClE;AAAA,MACF;AAEA,aAAO,mBAAmB;AAAA,QACxB,QAAQ;AAAA,QACR,QAAQ,EAAE;AAAA,QACV,eAAe,EAAE,QAAQ;AAAA,QACzB,UAAU,EAAE;AAAA,QACZ,WAAW,OAAO,EAAE,YAAY,EAAE;AAAA,QAClC,QAAQ,EAAE;AAAA,QACV,MAAM,EAAE;AAAA,QACR;AAAA,MACF,CAAC;AAAA,IACH;AAAA,IACA,CAAC;AAAA,EACH;AAEA,SAAO,EAAE,WAAW,SAAS;AAC/B;","names":[]}
1
+ {"version":3,"sources":["../../../src/components/SeoDrawer/useLiveDocument.ts"],"sourcesContent":["\"use client\";\n\nimport { useAllFormFields, useConfig, useDebounce, useLocale } from \"@payloadcms/ui\";\nimport { reduceFieldsToValues } from \"payload/shared\";\nimport { useCallback, useMemo, useRef } from \"react\";\nimport { resolveContentExtractor } from \"../../content/registry\";\nimport type { AnalysisInput, KeyphraseInput } from \"../../engine/types/analysis\";\nimport type { SeoFieldPaths } from \"../../types/config\";\nimport { buildAnalysisInput } from \"./build-analysis-input\";\n\nconst erroredPaths = new Set<string>();\nconst DEBOUNCE_MS = 1000;\n\nexport function keyphraseSignature(keyphrases: KeyphraseInput[]): string {\n return JSON.stringify(keyphrases.map((k) => [k.text, k.synonyms]));\n}\n\nexport interface LiveDocArgs {\n collectionSlug: string;\n fields: SeoFieldPaths;\n site: { name: string; baseUrl: string };\n keyphrases: KeyphraseInput[];\n enabled?: boolean;\n extractContentPath: string;\n}\n\nexport interface UseLiveDocumentResult {\n signature: string;\n getInput: (opts?: { live?: boolean }) => Promise<AnalysisInput>;\n}\n\nexport function useLiveDocument({\n collectionSlug: _collectionSlug,\n fields,\n site,\n keyphrases,\n enabled = true,\n extractContentPath,\n}: LiveDocArgs): UseLiveDocumentResult {\n const [formFields] = useAllFormFields();\n const locale = useLocale();\n const { config } = useConfig();\n\n const debouncedFields = useDebounce(formFields, DEBOUNCE_MS);\n const debouncedKeyphrases = useDebounce(keyphrases, DEBOUNCE_MS);\n const apiRoute = config.routes.api;\n\n const values = useMemo<Record<string, unknown>>(\n () => (enabled ? (reduceFieldsToValues(debouncedFields, true) as Record<string, unknown>) : {}),\n [enabled, debouncedFields]\n );\n\n const signature = useMemo(\n () =>\n JSON.stringify({\n values,\n keyphrases: keyphraseSignature(debouncedKeyphrases),\n locale: locale?.code ?? null,\n }),\n [values, debouncedKeyphrases, locale]\n );\n\n const liveRef = useRef({\n formFields,\n values,\n keyphrases,\n debouncedKeyphrases,\n locale,\n fields,\n site,\n extractContentPath,\n apiRoute,\n });\n liveRef.current = {\n formFields,\n values,\n keyphrases,\n debouncedKeyphrases,\n locale,\n fields,\n site,\n extractContentPath,\n apiRoute,\n };\n\n const getInput = useCallback(\n async ({ live = false }: { live?: boolean } = {}): Promise<AnalysisInput> => {\n const s = liveRef.current;\n const inputValues = live\n ? (reduceFieldsToValues(s.formFields, true) as Record<string, unknown>)\n : s.values;\n\n const extractor = resolveContentExtractor(s.extractContentPath);\n if (!extractor && !erroredPaths.has(s.extractContentPath)) {\n erroredPaths.add(s.extractContentPath);\n console.error(\n `[payload-plugin-seo] extractContentPath \"${s.extractContentPath}\" is not registered; content analysis will be empty. Call registerContentExtractors from \"@focus-reactive/payload-plugin-seo/content\" in an admin-mounted client module.`\n );\n }\n\n return buildAnalysisInput({\n values: inputValues,\n locale: s.locale,\n payloadLocale: s.locale?.code,\n apiRoute: s.apiRoute,\n keyphrases: live ? s.keyphrases : s.debouncedKeyphrases,\n fields: s.fields,\n site: s.site,\n extractor,\n });\n },\n []\n );\n\n return { signature, getInput };\n}\n"],"mappings":";AAEA,SAAS,kBAAkB,WAAW,aAAa,iBAAiB;AACpE,SAAS,4BAA4B;AACrC,SAAS,aAAa,SAAS,cAAc;AAC7C,SAAS,+BAA+B;AAGxC,SAAS,0BAA0B;AAEnC,MAAM,eAAe,oBAAI,IAAY;AACrC,MAAM,cAAc;AAEb,SAAS,mBAAmB,YAAsC;AACvE,SAAO,KAAK,UAAU,WAAW,IAAI,CAAC,MAAM,CAAC,EAAE,MAAM,EAAE,QAAQ,CAAC,CAAC;AACnE;AAgBO,SAAS,gBAAgB;AAAA,EAC9B,gBAAgB;AAAA,EAChB;AAAA,EACA;AAAA,EACA;AAAA,EACA,UAAU;AAAA,EACV;AACF,GAAuC;AACrC,QAAM,CAAC,UAAU,IAAI,iBAAiB;AACtC,QAAM,SAAS,UAAU;AACzB,QAAM,EAAE,OAAO,IAAI,UAAU;AAE7B,QAAM,kBAAkB,YAAY,YAAY,WAAW;AAC3D,QAAM,sBAAsB,YAAY,YAAY,WAAW;AAC/D,QAAM,WAAW,OAAO,OAAO;AAE/B,QAAM,SAAS;AAAA,IACb,MAAO,UAAW,qBAAqB,iBAAiB,IAAI,IAAgC,CAAC;AAAA,IAC7F,CAAC,SAAS,eAAe;AAAA,EAC3B;AAEA,QAAM,YAAY;AAAA,IAChB,MACE,KAAK,UAAU;AAAA,MACb;AAAA,MACA,YAAY,mBAAmB,mBAAmB;AAAA,MAClD,QAAQ,QAAQ,QAAQ;AAAA,IAC1B,CAAC;AAAA,IACH,CAAC,QAAQ,qBAAqB,MAAM;AAAA,EACtC;AAEA,QAAM,UAAU,OAAO;AAAA,IACrB;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,CAAC;AACD,UAAQ,UAAU;AAAA,IAChB;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAEA,QAAM,WAAW;AAAA,IACf,OAAO,EAAE,OAAO,MAAM,IAAwB,CAAC,MAA8B;AAC3E,YAAM,IAAI,QAAQ;AAClB,YAAM,cAAc,OACf,qBAAqB,EAAE,YAAY,IAAI,IACxC,EAAE;AAEN,YAAM,YAAY,wBAAwB,EAAE,kBAAkB;AAC9D,UAAI,CAAC,aAAa,CAAC,aAAa,IAAI,EAAE,kBAAkB,GAAG;AACzD,qBAAa,IAAI,EAAE,kBAAkB;AACrC,gBAAQ;AAAA,UACN,4CAA4C,EAAE,kBAAkB;AAAA,QAClE;AAAA,MACF;AAEA,aAAO,mBAAmB;AAAA,QACxB,QAAQ;AAAA,QACR,QAAQ,EAAE;AAAA,QACV,eAAe,EAAE,QAAQ;AAAA,QACzB,UAAU,EAAE;AAAA,QACZ,YAAY,OAAO,EAAE,aAAa,EAAE;AAAA,QACpC,QAAQ,EAAE;AAAA,QACV,MAAM,EAAE;AAAA,QACR;AAAA,MACF,CAAC;AAAA,IACH;AAAA,IACA,CAAC;AAAA,EACH;AAEA,SAAO,EAAE,WAAW,SAAS;AAC/B;","names":[]}
@@ -1,4 +1,4 @@
1
1
  export declare const statusVar: (props?: ({
2
- status?: "good" | "warn" | "bad" | null | undefined;
2
+ status?: "good" | "warn" | "bad" | "idle" | null | undefined;
3
3
  } & import("class-variance-authority/types").ClassProp) | undefined) => string;
4
4
  //# sourceMappingURL=variants.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"variants.d.ts","sourceRoot":"","sources":["../../../src/components/SeoDrawer/variants.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,SAAS;;8EAQpB,CAAC"}
1
+ {"version":3,"file":"variants.d.ts","sourceRoot":"","sources":["../../../src/components/SeoDrawer/variants.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,SAAS;;8EASpB,CAAC"}
@@ -4,7 +4,8 @@ const statusVar = cva("", {
4
4
  status: {
5
5
  good: "[--seo-c:var(--color-seo-good)]",
6
6
  warn: "[--seo-c:var(--color-seo-warn)]",
7
- bad: "[--seo-c:var(--color-seo-bad)]"
7
+ bad: "[--seo-c:var(--color-seo-bad)]",
8
+ idle: "[--seo-c:var(--color-neutral-300)]"
8
9
  }
9
10
  }
10
11
  });
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/components/SeoDrawer/variants.ts"],"sourcesContent":["import { cva } from \"class-variance-authority\";\n\nexport const statusVar = cva(\"\", {\n variants: {\n status: {\n good: \"[--seo-c:var(--color-seo-good)]\",\n warn: \"[--seo-c:var(--color-seo-warn)]\",\n bad: \"[--seo-c:var(--color-seo-bad)]\",\n },\n },\n});\n"],"mappings":"AAAA,SAAS,WAAW;AAEb,MAAM,YAAY,IAAI,IAAI;AAAA,EAC/B,UAAU;AAAA,IACR,QAAQ;AAAA,MACN,MAAM;AAAA,MACN,MAAM;AAAA,MACN,KAAK;AAAA,IACP;AAAA,EACF;AACF,CAAC;","names":[]}
1
+ {"version":3,"sources":["../../../src/components/SeoDrawer/variants.ts"],"sourcesContent":["import { cva } from \"class-variance-authority\";\n\nexport const statusVar = cva(\"\", {\n variants: {\n status: {\n good: \"[--seo-c:var(--color-seo-good)]\",\n warn: \"[--seo-c:var(--color-seo-warn)]\",\n bad: \"[--seo-c:var(--color-seo-bad)]\",\n idle: \"[--seo-c:var(--color-neutral-300)]\",\n },\n },\n});\n"],"mappings":"AAAA,SAAS,WAAW;AAEb,MAAM,YAAY,IAAI,IAAI;AAAA,EAC/B,UAAU;AAAA,IACR,QAAQ;AAAA,MACN,MAAM;AAAA,MACN,MAAM;AAAA,MACN,KAAK;AAAA,MACL,MAAM;AAAA,IACR;AAAA,EACF;AACF,CAAC;","names":[]}
@@ -8,6 +8,6 @@ export declare const TITLE_RANGE: {
8
8
  };
9
9
  export declare const DESCRIPTION_RANGE: {
10
10
  readonly min: 120;
11
- readonly max: 160;
11
+ readonly max: 156;
12
12
  };
13
13
  //# sourceMappingURL=generation.d.ts.map
@@ -8,7 +8,7 @@ const TITLE_RANGE = {
8
8
  };
9
9
  const DESCRIPTION_RANGE = {
10
10
  min: 120,
11
- max: 160
11
+ max: 156
12
12
  };
13
13
  export {
14
14
  AVG_GLYPH_PX,
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/constants/generation.ts"],"sourcesContent":["export const GENERATE_ENDPOINT_PATH = \"/seo/generate\";\nexport const DEFAULT_MODEL = \"gpt-4o-mini\";\nexport const DEFAULT_MAX_CONTENT_CHARS = 6000;\n\nexport const AVG_GLYPH_PX = 8.5;\n\nexport const TITLE_RANGE = {\n min: 400,\n max: 600,\n} as const;\n\nexport const DESCRIPTION_RANGE = {\n min: 120,\n max: 160,\n} as const;\n"],"mappings":"AAAO,MAAM,yBAAyB;AAC/B,MAAM,gBAAgB;AACtB,MAAM,4BAA4B;AAElC,MAAM,eAAe;AAErB,MAAM,cAAc;AAAA,EACzB,KAAK;AAAA,EACL,KAAK;AACP;AAEO,MAAM,oBAAoB;AAAA,EAC/B,KAAK;AAAA,EACL,KAAK;AACP;","names":[]}
1
+ {"version":3,"sources":["../../src/constants/generation.ts"],"sourcesContent":["export const GENERATE_ENDPOINT_PATH = \"/seo/generate\";\nexport const DEFAULT_MODEL = \"gpt-4o-mini\";\nexport const DEFAULT_MAX_CONTENT_CHARS = 6000;\n\nexport const AVG_GLYPH_PX = 8.5;\n\nexport const TITLE_RANGE = {\n min: 400,\n max: 600,\n} as const;\n\nexport const DESCRIPTION_RANGE = {\n min: 120,\n max: 156,\n} as const;\n"],"mappings":"AAAO,MAAM,yBAAyB;AAC/B,MAAM,gBAAgB;AACtB,MAAM,4BAA4B;AAElC,MAAM,eAAe;AAErB,MAAM,cAAc;AAAA,EACzB,KAAK;AAAA,EACL,KAAK;AACP;AAEO,MAAM,oBAAoB;AAAA,EAC/B,KAAK;AAAA,EACL,KAAK;AACP;","names":[]}
@@ -1,5 +1,6 @@
1
1
  export declare const PLUGIN_NAME = "payload-plugin-seo";
2
2
  export declare const PKG = "@focus-reactive/payload-plugin-seo";
3
3
  export declare const DEFAULT_LOCALES: readonly ["en"];
4
+ export declare const MAX_KEYPHRASES = 5;
4
5
  export * from "./statuses";
5
6
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/constants/index.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,WAAW,uBAAuB,CAAC;AAChD,eAAO,MAAM,GAAG,uCAAuC,CAAC;AAExD,eAAO,MAAM,eAAe,iBAAkB,CAAC;AAE/C,cAAc,YAAY,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/constants/index.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,WAAW,uBAAuB,CAAC;AAChD,eAAO,MAAM,GAAG,uCAAuC,CAAC;AAExD,eAAO,MAAM,eAAe,iBAAkB,CAAC;AAE/C,eAAO,MAAM,cAAc,IAAI,CAAC;AAEhC,cAAc,YAAY,CAAC"}
@@ -1,9 +1,11 @@
1
1
  const PLUGIN_NAME = "payload-plugin-seo";
2
2
  const PKG = "@focus-reactive/payload-plugin-seo";
3
3
  const DEFAULT_LOCALES = ["en"];
4
+ const MAX_KEYPHRASES = 5;
4
5
  export * from "./statuses";
5
6
  export {
6
7
  DEFAULT_LOCALES,
8
+ MAX_KEYPHRASES,
7
9
  PKG,
8
10
  PLUGIN_NAME
9
11
  };
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/constants/index.ts"],"sourcesContent":["export const PLUGIN_NAME = \"payload-plugin-seo\";\nexport const PKG = \"@focus-reactive/payload-plugin-seo\";\n\nexport const DEFAULT_LOCALES = [\"en\"] as const;\n\nexport * from \"./statuses\";\n"],"mappings":"AAAO,MAAM,cAAc;AACpB,MAAM,MAAM;AAEZ,MAAM,kBAAkB,CAAC,IAAI;AAEpC,cAAc;","names":[]}
1
+ {"version":3,"sources":["../../src/constants/index.ts"],"sourcesContent":["export const PLUGIN_NAME = \"payload-plugin-seo\";\nexport const PKG = \"@focus-reactive/payload-plugin-seo\";\n\nexport const DEFAULT_LOCALES = [\"en\"] as const;\n\nexport const MAX_KEYPHRASES = 5;\n\nexport * from \"./statuses\";\n"],"mappings":"AAAO,MAAM,cAAc;AACpB,MAAM,MAAM;AAEZ,MAAM,kBAAkB,CAAC,IAAI;AAE7B,MAAM,iBAAiB;AAE9B,cAAc;","names":[]}
@@ -1,4 +1,4 @@
1
- import type { AnalysisInput } from "./types/analysis";
1
+ import type { AnalysisInput, KeyphraseInput } from "./types/analysis";
2
2
  import type { PaperData } from "./types/paper";
3
- export declare function buildPaper(input: AnalysisInput): PaperData;
3
+ export declare function buildPaper(input: AnalysisInput, keyphrase?: KeyphraseInput): PaperData;
4
4
  //# sourceMappingURL=buildPaper.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"buildPaper.d.ts","sourceRoot":"","sources":["../../src/engine/buildPaper.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACtD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAE/C,wBAAgB,UAAU,CAAC,KAAK,EAAE,aAAa,GAAG,SAAS,CAU1D"}
1
+ {"version":3,"file":"buildPaper.d.ts","sourceRoot":"","sources":["../../src/engine/buildPaper.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AACtE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAE/C,wBAAgB,UAAU,CAAC,KAAK,EAAE,aAAa,EAAE,SAAS,CAAC,EAAE,cAAc,GAAG,SAAS,CActF"}
@@ -1,7 +1,9 @@
1
1
  import { Paper } from "yoastseo";
2
- function buildPaper(input) {
2
+ function buildPaper(input, keyphrase) {
3
+ const focus = keyphrase ?? input.keyphrases[0] ?? { text: input.keyphrase, synonyms: [] };
3
4
  return new Paper(input.contentHtml, {
4
- keyword: input.keyphrase,
5
+ keyword: focus.text,
6
+ synonyms: focus.synonyms.join(", "),
5
7
  title: input.title,
6
8
  titleWidth: 0,
7
9
  description: input.description,
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/engine/buildPaper.ts"],"sourcesContent":["import { Paper } from \"yoastseo\";\nimport type { AnalysisInput } from \"./types/analysis\";\nimport type { PaperData } from \"./types/paper\";\n\nexport function buildPaper(input: AnalysisInput): PaperData {\n return new Paper(input.contentHtml, {\n keyword: input.keyphrase,\n title: input.title,\n titleWidth: 0,\n description: input.description,\n slug: input.slug,\n permalink: input.site.baseUrl ? `${input.site.baseUrl}/${input.slug}` : input.slug,\n locale: input.locale,\n });\n}\n"],"mappings":"AAAA,SAAS,aAAa;AAIf,SAAS,WAAW,OAAiC;AAC1D,SAAO,IAAI,MAAM,MAAM,aAAa;AAAA,IAClC,SAAS,MAAM;AAAA,IACf,OAAO,MAAM;AAAA,IACb,YAAY;AAAA,IACZ,aAAa,MAAM;AAAA,IACnB,MAAM,MAAM;AAAA,IACZ,WAAW,MAAM,KAAK,UAAU,GAAG,MAAM,KAAK,OAAO,IAAI,MAAM,IAAI,KAAK,MAAM;AAAA,IAC9E,QAAQ,MAAM;AAAA,EAChB,CAAC;AACH;","names":[]}
1
+ {"version":3,"sources":["../../src/engine/buildPaper.ts"],"sourcesContent":["import { Paper } from \"yoastseo\";\nimport type { AnalysisInput, KeyphraseInput } from \"./types/analysis\";\nimport type { PaperData } from \"./types/paper\";\n\nexport function buildPaper(input: AnalysisInput, keyphrase?: KeyphraseInput): PaperData {\n const focus: KeyphraseInput = keyphrase ??\n input.keyphrases[0] ?? { text: input.keyphrase, synonyms: [] };\n\n return new Paper(input.contentHtml, {\n keyword: focus.text,\n synonyms: focus.synonyms.join(\", \"),\n title: input.title,\n titleWidth: 0,\n description: input.description,\n slug: input.slug,\n permalink: input.site.baseUrl ? `${input.site.baseUrl}/${input.slug}` : input.slug,\n locale: input.locale,\n });\n}\n"],"mappings":"AAAA,SAAS,aAAa;AAIf,SAAS,WAAW,OAAsB,WAAuC;AACtF,QAAM,QAAwB,aAC5B,MAAM,WAAW,CAAC,KAAK,EAAE,MAAM,MAAM,WAAW,UAAU,CAAC,EAAE;AAE/D,SAAO,IAAI,MAAM,MAAM,aAAa;AAAA,IAClC,SAAS,MAAM;AAAA,IACf,UAAU,MAAM,SAAS,KAAK,IAAI;AAAA,IAClC,OAAO,MAAM;AAAA,IACb,YAAY;AAAA,IACZ,aAAa,MAAM;AAAA,IACnB,MAAM,MAAM;AAAA,IACZ,WAAW,MAAM,KAAK,UAAU,GAAG,MAAM,KAAK,OAAO,IAAI,MAAM,IAAI,KAAK,MAAM;AAAA,IAC9E,QAAQ,MAAM;AAAA,EAChB,CAAC;AACH;","names":[]}
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/engine/runAnalysis/index.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAOvE,wBAAgB,WAAW,CAAC,KAAK,EAAE,aAAa,GAAG,cAAc,CAehE"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/engine/runAnalysis/index.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,aAAa,EAAE,cAAc,EAA0B,MAAM,mBAAmB,CAAC;AAQ/F,wBAAgB,WAAW,CAAC,KAAK,EAAE,aAAa,GAAG,cAAc,CAyBhE"}
@@ -1,6 +1,7 @@
1
1
  import { buildPaper } from "../buildPaper";
2
2
  import { deriveInclusive } from "./services/derive-inclusive";
3
3
  import { deriveReadability } from "./services/derive-readability";
4
+ import { deriveRelatedKeyphrase } from "./services/derive-related";
4
5
  import { deriveSeo } from "./services/derive-seo";
5
6
  import { deriveSerp } from "./services/derive-serp";
6
7
  import { deriveVitals } from "./services/derive-vitals";
@@ -8,9 +9,15 @@ function runAnalysis(input) {
8
9
  const paper = buildPaper(input);
9
10
  const { keyphrase } = input;
10
11
  const seo = deriveSeo(paper, keyphrase);
12
+ const relatedKeyphrases = input.keyphrases.slice(1).filter((kp) => kp.text.trim().length > 0).map((kp) => ({
13
+ text: kp.text,
14
+ result: deriveRelatedKeyphrase(buildPaper(input, kp), kp.text)
15
+ }));
11
16
  return {
12
17
  overall: seo.overall,
18
+ keyphraseText: keyphrase,
13
19
  keyphrase: seo.keyphrase,
20
+ relatedKeyphrases,
14
21
  onPage: seo.onPage,
15
22
  readability: deriveReadability(paper, keyphrase),
16
23
  inclusive: deriveInclusive(paper),
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/engine/runAnalysis/index.ts"],"sourcesContent":["import { buildPaper } from \"../buildPaper\";\nimport type { AnalysisInput, AnalysisResult } from \"../types/analysis\";\nimport { deriveInclusive } from \"./services/derive-inclusive\";\nimport { deriveReadability } from \"./services/derive-readability\";\nimport { deriveSeo } from \"./services/derive-seo\";\nimport { deriveSerp } from \"./services/derive-serp\";\nimport { deriveVitals } from \"./services/derive-vitals\";\n\nexport function runAnalysis(input: AnalysisInput): AnalysisResult {\n const paper = buildPaper(input);\n const { keyphrase } = input;\n\n const seo = deriveSeo(paper, keyphrase);\n\n return {\n overall: seo.overall,\n keyphrase: seo.keyphrase,\n onPage: seo.onPage,\n readability: deriveReadability(paper, keyphrase),\n inclusive: deriveInclusive(paper),\n vitals: deriveVitals(paper, keyphrase),\n serp: deriveSerp(input),\n };\n}\n"],"mappings":"AAAA,SAAS,kBAAkB;AAE3B,SAAS,uBAAuB;AAChC,SAAS,yBAAyB;AAClC,SAAS,iBAAiB;AAC1B,SAAS,kBAAkB;AAC3B,SAAS,oBAAoB;AAEtB,SAAS,YAAY,OAAsC;AAChE,QAAM,QAAQ,WAAW,KAAK;AAC9B,QAAM,EAAE,UAAU,IAAI;AAEtB,QAAM,MAAM,UAAU,OAAO,SAAS;AAEtC,SAAO;AAAA,IACL,SAAS,IAAI;AAAA,IACb,WAAW,IAAI;AAAA,IACf,QAAQ,IAAI;AAAA,IACZ,aAAa,kBAAkB,OAAO,SAAS;AAAA,IAC/C,WAAW,gBAAgB,KAAK;AAAA,IAChC,QAAQ,aAAa,OAAO,SAAS;AAAA,IACrC,MAAM,WAAW,KAAK;AAAA,EACxB;AACF;","names":[]}
1
+ {"version":3,"sources":["../../../src/engine/runAnalysis/index.ts"],"sourcesContent":["import { buildPaper } from \"../buildPaper\";\nimport type { AnalysisInput, AnalysisResult, RelatedKeyphraseResult } from \"../types/analysis\";\nimport { deriveInclusive } from \"./services/derive-inclusive\";\nimport { deriveReadability } from \"./services/derive-readability\";\nimport { deriveRelatedKeyphrase } from \"./services/derive-related\";\nimport { deriveSeo } from \"./services/derive-seo\";\nimport { deriveSerp } from \"./services/derive-serp\";\nimport { deriveVitals } from \"./services/derive-vitals\";\n\nexport function runAnalysis(input: AnalysisInput): AnalysisResult {\n const paper = buildPaper(input);\n const { keyphrase } = input;\n\n const seo = deriveSeo(paper, keyphrase);\n\n const relatedKeyphrases: RelatedKeyphraseResult[] = input.keyphrases\n .slice(1)\n .filter((kp) => kp.text.trim().length > 0)\n .map((kp) => ({\n text: kp.text,\n result: deriveRelatedKeyphrase(buildPaper(input, kp), kp.text),\n }));\n\n return {\n overall: seo.overall,\n keyphraseText: keyphrase,\n keyphrase: seo.keyphrase,\n relatedKeyphrases,\n onPage: seo.onPage,\n readability: deriveReadability(paper, keyphrase),\n inclusive: deriveInclusive(paper),\n vitals: deriveVitals(paper, keyphrase),\n serp: deriveSerp(input),\n };\n}\n"],"mappings":"AAAA,SAAS,kBAAkB;AAE3B,SAAS,uBAAuB;AAChC,SAAS,yBAAyB;AAClC,SAAS,8BAA8B;AACvC,SAAS,iBAAiB;AAC1B,SAAS,kBAAkB;AAC3B,SAAS,oBAAoB;AAEtB,SAAS,YAAY,OAAsC;AAChE,QAAM,QAAQ,WAAW,KAAK;AAC9B,QAAM,EAAE,UAAU,IAAI;AAEtB,QAAM,MAAM,UAAU,OAAO,SAAS;AAEtC,QAAM,oBAA8C,MAAM,WACvD,MAAM,CAAC,EACP,OAAO,CAAC,OAAO,GAAG,KAAK,KAAK,EAAE,SAAS,CAAC,EACxC,IAAI,CAAC,QAAQ;AAAA,IACZ,MAAM,GAAG;AAAA,IACT,QAAQ,uBAAuB,WAAW,OAAO,EAAE,GAAG,GAAG,IAAI;AAAA,EAC/D,EAAE;AAEJ,SAAO;AAAA,IACL,SAAS,IAAI;AAAA,IACb,eAAe;AAAA,IACf,WAAW,IAAI;AAAA,IACf;AAAA,IACA,QAAQ,IAAI;AAAA,IACZ,aAAa,kBAAkB,OAAO,SAAS;AAAA,IAC/C,WAAW,gBAAgB,KAAK;AAAA,IAChC,QAAQ,aAAa,OAAO,SAAS;AAAA,IACrC,MAAM,WAAW,KAAK;AAAA,EACxB;AACF;","names":[]}
@@ -0,0 +1,4 @@
1
+ import type { CategoryResult } from "../../types/analysis";
2
+ import type { PaperData } from "../../types/paper";
3
+ export declare function deriveRelatedKeyphrase(paper: PaperData, keyphrase: string): CategoryResult;
4
+ //# sourceMappingURL=derive-related.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"derive-related.d.ts","sourceRoot":"","sources":["../../../../src/engine/runAnalysis/services/derive-related.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAC3D,OAAO,KAAK,EAAE,SAAS,EAAa,MAAM,mBAAmB,CAAC;AAI9D,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,GAAG,cAAc,CAO1F"}
@@ -0,0 +1,16 @@
1
+ import RelatedKeywordAssessor from "yoastseo/build/scoring/assessors/relatedKeywordAssessor";
2
+ import { runAssessor } from "../../assessorAdapter";
3
+ import { makeResearcher } from "../../researcherAdapter";
4
+ import { enrich } from "../utils/enrich";
5
+ import { toCategory } from "../utils/toCategory";
6
+ function deriveRelatedKeyphrase(paper, keyphrase) {
7
+ const ctx = { keyphrase };
8
+ const researcher = makeResearcher(paper);
9
+ const assessor = new RelatedKeywordAssessor(makeResearcher(paper));
10
+ const checks = enrich(runAssessor(assessor, ctx, paper), paper, researcher);
11
+ return toCategory(checks);
12
+ }
13
+ export {
14
+ deriveRelatedKeyphrase
15
+ };
16
+ //# sourceMappingURL=derive-related.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../src/engine/runAnalysis/services/derive-related.ts"],"sourcesContent":["import RelatedKeywordAssessor from \"yoastseo/build/scoring/assessors/relatedKeywordAssessor\";\nimport { runAssessor } from \"../../assessorAdapter\";\nimport { makeResearcher } from \"../../researcherAdapter\";\nimport type { CategoryResult } from \"../../types/analysis\";\nimport type { PaperData, PaperLike } from \"../../types/paper\";\nimport { enrich } from \"../utils/enrich\";\nimport { toCategory } from \"../utils/toCategory\";\n\nexport function deriveRelatedKeyphrase(paper: PaperData, keyphrase: string): CategoryResult {\n const ctx = { keyphrase };\n const researcher = makeResearcher(paper);\n const assessor = new RelatedKeywordAssessor(makeResearcher(paper));\n const checks = enrich(runAssessor(assessor, ctx, paper), paper as PaperLike, researcher);\n\n return toCategory(checks);\n}\n"],"mappings":"AAAA,OAAO,4BAA4B;AACnC,SAAS,mBAAmB;AAC5B,SAAS,sBAAsB;AAG/B,SAAS,cAAc;AACvB,SAAS,kBAAkB;AAEpB,SAAS,uBAAuB,OAAkB,WAAmC;AAC1F,QAAM,MAAM,EAAE,UAAU;AACxB,QAAM,aAAa,eAAe,KAAK;AACvC,QAAM,WAAW,IAAI,uBAAuB,eAAe,KAAK,CAAC;AACjE,QAAM,SAAS,OAAO,YAAY,UAAU,KAAK,KAAK,GAAG,OAAoB,UAAU;AAEvF,SAAO,WAAW,MAAM;AAC1B;","names":[]}
@@ -60,12 +60,22 @@ export interface CategoryResult {
60
60
  status: Status;
61
61
  checks: CheckResult[];
62
62
  }
63
+ export interface KeyphraseInput {
64
+ text: string;
65
+ synonyms: string[];
66
+ }
67
+ export interface RelatedKeyphraseResult {
68
+ text: string;
69
+ result: CategoryResult;
70
+ }
63
71
  export interface AnalysisResult {
64
72
  overall: {
65
73
  seoScore: number;
66
74
  status: Status;
67
75
  };
76
+ keyphraseText: string;
68
77
  keyphrase: CategoryResult;
78
+ relatedKeyphrases: RelatedKeyphraseResult[];
69
79
  onPage: CategoryResult;
70
80
  readability: CategoryResult;
71
81
  inclusive: {
@@ -83,6 +93,7 @@ export interface AnalysisInput {
83
93
  description: string;
84
94
  contentHtml: string;
85
95
  keyphrase: string;
96
+ keyphrases: KeyphraseInput[];
86
97
  locale: string;
87
98
  site: {
88
99
  name: string;
@@ -1 +1 @@
1
- {"version":3,"file":"analysis.d.ts","sourceRoot":"","sources":["../../../src/engine/types/analysis.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"analysis.d.ts","sourceRoot":"","sources":["../../../src/engine/types/analysis.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,9 @@
1
+ import type { ButtonHTMLAttributes, ReactNode } from "react";
2
+ interface ButtonProps extends ButtonHTMLAttributes<HTMLButtonElement> {
3
+ variant?: "primary" | "error";
4
+ icon?: ReactNode;
5
+ children: ReactNode;
6
+ }
7
+ export declare function Button({ variant, icon, children, className, type, ...props }: ButtonProps): import("react/jsx-runtime").JSX.Element;
8
+ export {};
9
+ //# sourceMappingURL=Button.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Button.d.ts","sourceRoot":"","sources":["../../src/ui/Button.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,oBAAoB,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAiB7D,UAAU,WAAY,SAAQ,oBAAoB,CAAC,iBAAiB,CAAC;IACnE,OAAO,CAAC,EAAE,SAAS,GAAG,OAAO,CAAC;IAC9B,IAAI,CAAC,EAAE,SAAS,CAAC;IACjB,QAAQ,EAAE,SAAS,CAAC;CACrB;AAED,wBAAgB,MAAM,CAAC,EACrB,OAAO,EACP,IAAI,EACJ,QAAQ,EACR,SAAS,EACT,IAAe,EACf,GAAG,KAAK,EACT,EAAE,WAAW,2CAOb"}
@@ -0,0 +1,34 @@
1
+ "use client";
2
+ import { jsxs } from "react/jsx-runtime";
3
+ import { cva } from "class-variance-authority";
4
+ const buttonVariants = cva(
5
+ "inline-flex items-center justify-center gap-[6px] rounded-rs px-[14px] py-[8px] text-[12px] font-semibold [&_svg]:size-[14px]",
6
+ {
7
+ variants: {
8
+ variant: {
9
+ primary: "text-neutral-0 bg-neutral-1000 hover:bg-black",
10
+ error: "text-seo-bad bg-seo-bad-100 hover:bg-seo-200"
11
+ }
12
+ },
13
+ defaultVariants: {
14
+ variant: "primary"
15
+ }
16
+ }
17
+ );
18
+ function Button({
19
+ variant,
20
+ icon,
21
+ children,
22
+ className,
23
+ type = "button",
24
+ ...props
25
+ }) {
26
+ return /* @__PURE__ */ jsxs("button", { className: buttonVariants({ variant, className }), type, ...props, children: [
27
+ icon,
28
+ children
29
+ ] });
30
+ }
31
+ export {
32
+ Button
33
+ };
34
+ //# sourceMappingURL=Button.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/ui/Button.tsx"],"sourcesContent":["\"use client\";\n\nimport { cva } from \"class-variance-authority\";\nimport type { ButtonHTMLAttributes, ReactNode } from \"react\";\n\nconst buttonVariants = cva(\n \"inline-flex items-center justify-center gap-[6px] rounded-rs px-[14px] py-[8px] text-[12px] font-semibold [&_svg]:size-[14px]\",\n {\n variants: {\n variant: {\n primary: \"text-neutral-0 bg-neutral-1000 hover:bg-black\",\n error: \"text-seo-bad bg-seo-bad-100 hover:bg-seo-200\",\n },\n },\n defaultVariants: {\n variant: \"primary\",\n },\n }\n);\n\ninterface ButtonProps extends ButtonHTMLAttributes<HTMLButtonElement> {\n variant?: \"primary\" | \"error\";\n icon?: ReactNode;\n children: ReactNode;\n}\n\nexport function Button({\n variant,\n icon,\n children,\n className,\n type = \"button\",\n ...props\n}: ButtonProps) {\n return (\n <button className={buttonVariants({ variant, className })} type={type} {...props}>\n {icon}\n {children}\n </button>\n );\n}\n"],"mappings":";AAmCI;AAjCJ,SAAS,WAAW;AAGpB,MAAM,iBAAiB;AAAA,EACrB;AAAA,EACA;AAAA,IACE,UAAU;AAAA,MACR,SAAS;AAAA,QACP,SAAS;AAAA,QACT,OAAO;AAAA,MACT;AAAA,IACF;AAAA,IACA,iBAAiB;AAAA,MACf,SAAS;AAAA,IACX;AAAA,EACF;AACF;AAQO,SAAS,OAAO;AAAA,EACrB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,OAAO;AAAA,EACP,GAAG;AACL,GAAgB;AACd,SACE,qBAAC,YAAO,WAAW,eAAe,EAAE,SAAS,UAAU,CAAC,GAAG,MAAa,GAAG,OACxE;AAAA;AAAA,IACA;AAAA,KACH;AAEJ;","names":[]}
@@ -1,8 +1,21 @@
1
+ import type { VariantProps } from "class-variance-authority";
1
2
  import type { Status } from "../engine/types/analysis";
2
- interface ScoreRingProps {
3
- score: number;
3
+ declare const ringVar: (props?: ({
4
+ size?: "small" | "medium" | null | undefined;
5
+ } & import("class-variance-authority/types").ClassProp) | undefined) => string;
6
+ type RingSize = NonNullable<VariantProps<typeof ringVar>["size"]>;
7
+ type ScoreRingProps = {
8
+ size?: RingSize;
9
+ } & ({
4
10
  status: Status;
5
- }
6
- export declare function ScoreRing({ score, status }: ScoreRingProps): import("react/jsx-runtime").JSX.Element;
11
+ score: number;
12
+ } | {
13
+ status: "idle";
14
+ score?: never;
15
+ } | {
16
+ status: "loading";
17
+ score?: never;
18
+ });
19
+ export declare function ScoreRing({ size, status, score }: ScoreRingProps): import("react/jsx-runtime").JSX.Element;
7
20
  export {};
8
21
  //# sourceMappingURL=ScoreRing.d.ts.map