@focus-reactive/payload-plugin-seo 1.6.1 → 1.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +12 -1
- package/dist/admin.css +232 -17
- package/dist/components/SeoButton/SeoButtonInner.d.ts.map +1 -1
- package/dist/components/SeoButton/SeoButtonInner.js +46 -16
- package/dist/components/SeoButton/SeoButtonInner.js.map +1 -1
- package/dist/components/SeoDrawer/build-analysis-input.d.ts +2 -2
- package/dist/components/SeoDrawer/build-analysis-input.d.ts.map +1 -1
- package/dist/components/SeoDrawer/build-analysis-input.js +1 -1
- package/dist/components/SeoDrawer/build-analysis-input.js.map +1 -1
- package/dist/components/SeoDrawer/buildInput.d.ts +3 -3
- package/dist/components/SeoDrawer/buildInput.d.ts.map +1 -1
- package/dist/components/SeoDrawer/buildInput.js +3 -2
- package/dist/components/SeoDrawer/buildInput.js.map +1 -1
- package/dist/components/SeoDrawer/components/HeadingsSection/HeadingIssueBanner.d.ts +7 -0
- package/dist/components/SeoDrawer/components/HeadingsSection/HeadingIssueBanner.d.ts.map +1 -0
- package/dist/components/SeoDrawer/components/HeadingsSection/HeadingIssueBanner.js +26 -0
- package/dist/components/SeoDrawer/components/HeadingsSection/HeadingIssueBanner.js.map +1 -0
- package/dist/components/SeoDrawer/components/HeadingsSection/HeadingIssuePills.d.ts +8 -0
- package/dist/components/SeoDrawer/components/HeadingsSection/HeadingIssuePills.d.ts.map +1 -0
- package/dist/components/SeoDrawer/components/HeadingsSection/HeadingIssuePills.js +17 -0
- package/dist/components/SeoDrawer/components/HeadingsSection/HeadingIssuePills.js.map +1 -0
- package/dist/components/SeoDrawer/components/HeadingsSection/HeadingTree/HeadingTreeRow.d.ts.map +1 -1
- package/dist/components/SeoDrawer/components/HeadingsSection/HeadingTree/HeadingTreeRow.js +2 -0
- package/dist/components/SeoDrawer/components/HeadingsSection/HeadingTree/HeadingTreeRow.js.map +1 -1
- package/dist/components/SeoDrawer/components/HeadingsSection/HeadingTree/headingTreeView.d.ts +1 -0
- package/dist/components/SeoDrawer/components/HeadingsSection/HeadingTree/headingTreeView.d.ts.map +1 -1
- package/dist/components/SeoDrawer/components/HeadingsSection/HeadingTree/headingTreeView.js +14 -1
- package/dist/components/SeoDrawer/components/HeadingsSection/HeadingTree/headingTreeView.js.map +1 -1
- package/dist/components/SeoDrawer/components/HeadingsSection/headingIssueCopy.d.ts +7 -0
- package/dist/components/SeoDrawer/components/HeadingsSection/headingIssueCopy.d.ts.map +1 -0
- package/dist/components/SeoDrawer/components/HeadingsSection/headingIssueCopy.js +26 -0
- package/dist/components/SeoDrawer/components/HeadingsSection/headingIssueCopy.js.map +1 -0
- package/dist/components/SeoDrawer/components/HeadingsSection/index.d.ts.map +1 -1
- package/dist/components/SeoDrawer/components/HeadingsSection/index.js +17 -6
- package/dist/components/SeoDrawer/components/HeadingsSection/index.js.map +1 -1
- package/dist/components/SeoDrawer/components/SerpPreview/highlight-keyphrase.d.ts +1 -1
- package/dist/components/SeoDrawer/components/SerpPreview/highlight-keyphrase.d.ts.map +1 -1
- package/dist/components/SeoDrawer/components/SerpPreview/highlight-keyphrase.js +10 -3
- package/dist/components/SeoDrawer/components/SerpPreview/highlight-keyphrase.js.map +1 -1
- package/dist/components/SeoDrawer/components/SerpPreview/index.d.ts +2 -1
- package/dist/components/SeoDrawer/components/SerpPreview/index.d.ts.map +1 -1
- package/dist/components/SeoDrawer/components/SerpPreview/index.js +8 -2
- package/dist/components/SeoDrawer/components/SerpPreview/index.js.map +1 -1
- package/dist/components/SeoDrawer/components/SerpPreview/variants.d.ts +6 -6
- package/dist/components/SeoDrawer/components/TabWrapper.d.ts +6 -0
- package/dist/components/SeoDrawer/components/TabWrapper.d.ts.map +1 -0
- package/dist/components/SeoDrawer/components/TabWrapper.js +8 -0
- package/dist/components/SeoDrawer/components/TabWrapper.js.map +1 -0
- package/dist/components/SeoDrawer/index.d.ts +11 -4
- package/dist/components/SeoDrawer/index.d.ts.map +1 -1
- package/dist/components/SeoDrawer/index.js +38 -16
- package/dist/components/SeoDrawer/index.js.map +1 -1
- package/dist/components/SeoDrawer/keyphraseState.d.ts +16 -0
- package/dist/components/SeoDrawer/keyphraseState.d.ts.map +1 -0
- package/dist/components/SeoDrawer/keyphraseState.js +73 -0
- package/dist/components/SeoDrawer/keyphraseState.js.map +1 -0
- package/dist/components/SeoDrawer/keyphraseStorage.d.ts +5 -0
- package/dist/components/SeoDrawer/keyphraseStorage.d.ts.map +1 -0
- package/dist/components/SeoDrawer/keyphraseStorage.js +60 -0
- package/dist/components/SeoDrawer/keyphraseStorage.js.map +1 -0
- package/dist/components/SeoDrawer/tabs/InclusiveTab.d.ts.map +1 -1
- package/dist/components/SeoDrawer/tabs/InclusiveTab.js +3 -2
- package/dist/components/SeoDrawer/tabs/InclusiveTab.js.map +1 -1
- package/dist/components/SeoDrawer/tabs/KeyphraseTab.d.ts +14 -7
- package/dist/components/SeoDrawer/tabs/KeyphraseTab.d.ts.map +1 -1
- package/dist/components/SeoDrawer/tabs/KeyphraseTab.js +110 -69
- package/dist/components/SeoDrawer/tabs/KeyphraseTab.js.map +1 -1
- package/dist/components/SeoDrawer/tabs/OnPageTab.d.ts.map +1 -1
- package/dist/components/SeoDrawer/tabs/OnPageTab.js +3 -2
- package/dist/components/SeoDrawer/tabs/OnPageTab.js.map +1 -1
- package/dist/components/SeoDrawer/tabs/ReadabilityTab.d.ts.map +1 -1
- package/dist/components/SeoDrawer/tabs/ReadabilityTab.js +3 -2
- package/dist/components/SeoDrawer/tabs/ReadabilityTab.js.map +1 -1
- package/dist/components/SeoDrawer/tabs/SerpTab.d.ts +2 -1
- package/dist/components/SeoDrawer/tabs/SerpTab.d.ts.map +1 -1
- package/dist/components/SeoDrawer/tabs/SerpTab.js +14 -3
- package/dist/components/SeoDrawer/tabs/SerpTab.js.map +1 -1
- package/dist/components/SeoDrawer/tabs/VitalsTab.d.ts.map +1 -1
- package/dist/components/SeoDrawer/tabs/VitalsTab.js +7 -3
- package/dist/components/SeoDrawer/tabs/VitalsTab.js.map +1 -1
- package/dist/components/SeoDrawer/tabs/keyphrase/KeyphraseCard.d.ts +21 -0
- package/dist/components/SeoDrawer/tabs/keyphrase/KeyphraseCard.d.ts.map +1 -0
- package/dist/components/SeoDrawer/tabs/keyphrase/KeyphraseCard.js +38 -0
- package/dist/components/SeoDrawer/tabs/keyphrase/KeyphraseCard.js.map +1 -0
- package/dist/components/SeoDrawer/tabs/keyphrase/KeyphraseDetail.d.ts +25 -0
- package/dist/components/SeoDrawer/tabs/keyphrase/KeyphraseDetail.d.ts.map +1 -0
- package/dist/components/SeoDrawer/tabs/keyphrase/KeyphraseDetail.js +127 -0
- package/dist/components/SeoDrawer/tabs/keyphrase/KeyphraseDetail.js.map +1 -0
- package/dist/components/SeoDrawer/tabs/keyphrase/KeyphraseRail.d.ts +12 -0
- package/dist/components/SeoDrawer/tabs/keyphrase/KeyphraseRail.d.ts.map +1 -0
- package/dist/components/SeoDrawer/tabs/keyphrase/KeyphraseRail.js +54 -0
- package/dist/components/SeoDrawer/tabs/keyphrase/KeyphraseRail.js.map +1 -0
- package/dist/components/SeoDrawer/tabs/keyphrase/SynonymsField.d.ts +7 -0
- package/dist/components/SeoDrawer/tabs/keyphrase/SynonymsField.d.ts.map +1 -0
- package/dist/components/SeoDrawer/tabs/keyphrase/SynonymsField.js +93 -0
- package/dist/components/SeoDrawer/tabs/keyphrase/SynonymsField.js.map +1 -0
- package/dist/components/SeoDrawer/tabs/keyphrase/icons.d.ts +2 -0
- package/dist/components/SeoDrawer/tabs/keyphrase/icons.d.ts.map +1 -0
- package/dist/components/SeoDrawer/tabs/keyphrase/icons.js +7 -0
- package/dist/components/SeoDrawer/tabs/keyphrase/icons.js.map +1 -0
- package/dist/components/SeoDrawer/useAnalysis.d.ts +0 -1
- package/dist/components/SeoDrawer/useAnalysis.d.ts.map +1 -1
- package/dist/components/SeoDrawer/useAnalysis.js +0 -3
- package/dist/components/SeoDrawer/useAnalysis.js.map +1 -1
- package/dist/components/SeoDrawer/useKeyphrases.d.ts +18 -0
- package/dist/components/SeoDrawer/useKeyphrases.d.ts.map +1 -0
- package/dist/components/SeoDrawer/useKeyphrases.js +78 -0
- package/dist/components/SeoDrawer/useKeyphrases.js.map +1 -0
- package/dist/components/SeoDrawer/useLiveDocument.d.ts +4 -3
- package/dist/components/SeoDrawer/useLiveDocument.d.ts.map +1 -1
- package/dist/components/SeoDrawer/useLiveDocument.js +17 -9
- package/dist/components/SeoDrawer/useLiveDocument.js.map +1 -1
- package/dist/components/SeoDrawer/variants.d.ts +1 -1
- package/dist/components/SeoDrawer/variants.d.ts.map +1 -1
- package/dist/components/SeoDrawer/variants.js +2 -1
- package/dist/components/SeoDrawer/variants.js.map +1 -1
- package/dist/constants/index.d.ts +1 -0
- package/dist/constants/index.d.ts.map +1 -1
- package/dist/constants/index.js +2 -0
- package/dist/constants/index.js.map +1 -1
- package/dist/engine/buildPaper.d.ts +2 -2
- package/dist/engine/buildPaper.d.ts.map +1 -1
- package/dist/engine/buildPaper.js +4 -2
- package/dist/engine/buildPaper.js.map +1 -1
- package/dist/engine/runAnalysis/index.d.ts.map +1 -1
- package/dist/engine/runAnalysis/index.js +7 -0
- package/dist/engine/runAnalysis/index.js.map +1 -1
- package/dist/engine/runAnalysis/services/derive-related.d.ts +4 -0
- package/dist/engine/runAnalysis/services/derive-related.d.ts.map +1 -0
- package/dist/engine/runAnalysis/services/derive-related.js +16 -0
- package/dist/engine/runAnalysis/services/derive-related.js.map +1 -0
- package/dist/engine/runAnalysis/services/derive-vitals/heading-issues.d.ts +8 -0
- package/dist/engine/runAnalysis/services/derive-vitals/heading-issues.d.ts.map +1 -0
- package/dist/engine/runAnalysis/services/derive-vitals/heading-issues.js +37 -0
- package/dist/engine/runAnalysis/services/derive-vitals/heading-issues.js.map +1 -0
- package/dist/engine/runAnalysis/services/derive-vitals/heading-tree.d.ts.map +1 -1
- package/dist/engine/runAnalysis/services/derive-vitals/heading-tree.js +7 -3
- package/dist/engine/runAnalysis/services/derive-vitals/heading-tree.js.map +1 -1
- package/dist/engine/types/analysis.d.ts +23 -0
- package/dist/engine/types/analysis.d.ts.map +1 -1
- package/dist/ui/Button.d.ts +9 -0
- package/dist/ui/Button.d.ts.map +1 -0
- package/dist/ui/Button.js +34 -0
- package/dist/ui/Button.js.map +1 -0
- package/dist/ui/ScoreRing.d.ts +17 -4
- package/dist/ui/ScoreRing.d.ts.map +1 -1
- package/dist/ui/ScoreRing.js +38 -14
- package/dist/ui/ScoreRing.js.map +1 -1
- package/package.json +1 -1
- package/dist/components/SeoDrawer/keyphrasePending.d.ts +0 -2
- package/dist/components/SeoDrawer/keyphrasePending.d.ts.map +0 -1
- package/dist/components/SeoDrawer/keyphrasePending.js +0 -9
- package/dist/components/SeoDrawer/keyphrasePending.js.map +0 -1
|
@@ -10,7 +10,13 @@ import {
|
|
|
10
10
|
serpUrlRow
|
|
11
11
|
} from "./variants";
|
|
12
12
|
import { truncateDescription } from "./truncate-description";
|
|
13
|
-
function SerpPreview({
|
|
13
|
+
function SerpPreview({
|
|
14
|
+
data,
|
|
15
|
+
keyphrase,
|
|
16
|
+
synonyms = [],
|
|
17
|
+
faviconUrl,
|
|
18
|
+
mode
|
|
19
|
+
}) {
|
|
14
20
|
const result = /* @__PURE__ */ jsxs("div", { className: serpContainer({ mode }), children: [
|
|
15
21
|
/* @__PURE__ */ jsxs("div", { className: serpUrlRow({ mode }), children: [
|
|
16
22
|
/* @__PURE__ */ jsx(SerpFavicon, { faviconUrl, siteName: data.siteName }),
|
|
@@ -20,7 +26,7 @@ function SerpPreview({ data, keyphrase, faviconUrl, mode }) {
|
|
|
20
26
|
] })
|
|
21
27
|
] }),
|
|
22
28
|
/* @__PURE__ */ jsx("div", { className: serpTitle({ mode }), children: data.title }),
|
|
23
|
-
/* @__PURE__ */ jsx("div", { className: serpDescription({ mode }), children: highlightKeyphrase(truncateDescription(data.description), keyphrase) })
|
|
29
|
+
/* @__PURE__ */ jsx("div", { className: serpDescription({ mode }), children: highlightKeyphrase(truncateDescription(data.description), keyphrase, synonyms) })
|
|
24
30
|
] });
|
|
25
31
|
return mode === "desktop" ? /* @__PURE__ */ jsx("div", { className: "overflow-x-auto", children: result }) : result;
|
|
26
32
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../../src/components/SeoDrawer/components/SerpPreview/index.tsx"],"sourcesContent":["import type { ReactElement } from \"react\";\nimport type { SerpResult } from \"../../../../engine/types/analysis\";\nimport { highlightKeyphrase } from \"./highlight-keyphrase\";\nimport { SerpFavicon } from \"./serp-favicon\";\nimport {\n serpContainer,\n serpDescription,\n serpHostname,\n serpSiteName,\n serpTitle,\n serpUrlRow,\n} from \"./variants\";\nimport { truncateDescription } from \"./truncate-description\";\n\nexport type SerpMode = \"mobile\" | \"desktop\";\n\ninterface SerpPreviewProps {\n data: SerpResult;\n keyphrase: string;\n faviconUrl: string;\n mode: SerpMode;\n}\n\nexport function SerpPreview({
|
|
1
|
+
{"version":3,"sources":["../../../../../src/components/SeoDrawer/components/SerpPreview/index.tsx"],"sourcesContent":["import type { ReactElement } from \"react\";\nimport type { SerpResult } from \"../../../../engine/types/analysis\";\nimport { highlightKeyphrase } from \"./highlight-keyphrase\";\nimport { SerpFavicon } from \"./serp-favicon\";\nimport {\n serpContainer,\n serpDescription,\n serpHostname,\n serpSiteName,\n serpTitle,\n serpUrlRow,\n} from \"./variants\";\nimport { truncateDescription } from \"./truncate-description\";\n\nexport type SerpMode = \"mobile\" | \"desktop\";\n\ninterface SerpPreviewProps {\n data: SerpResult;\n keyphrase: string;\n synonyms?: string[];\n faviconUrl: string;\n mode: SerpMode;\n}\n\nexport function SerpPreview({\n data,\n keyphrase,\n synonyms = [],\n faviconUrl,\n mode,\n}: SerpPreviewProps): ReactElement {\n const result = (\n <div className={serpContainer({ mode })}>\n <div className={serpUrlRow({ mode })}>\n <SerpFavicon faviconUrl={faviconUrl} siteName={data.siteName} />\n\n <div className=\"overflow-hidden\">\n <div className={serpSiteName({ mode })}>{data.siteName}</div>\n <div className={serpHostname({ mode })}>{data.url}</div>\n </div>\n </div>\n\n <div className={serpTitle({ mode })}>{data.title}</div>\n\n <div className={serpDescription({ mode })}>\n {highlightKeyphrase(truncateDescription(data.description), keyphrase, synonyms)}\n </div>\n </div>\n );\n\n return mode === \"desktop\" ? <div className=\"overflow-x-auto\">{result}</div> : result;\n}\n"],"mappings":"AAkCQ,cAEA,YAFA;AAhCR,SAAS,0BAA0B;AACnC,SAAS,mBAAmB;AAC5B;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP,SAAS,2BAA2B;AAY7B,SAAS,YAAY;AAAA,EAC1B;AAAA,EACA;AAAA,EACA,WAAW,CAAC;AAAA,EACZ;AAAA,EACA;AACF,GAAmC;AACjC,QAAM,SACJ,qBAAC,SAAI,WAAW,cAAc,EAAE,KAAK,CAAC,GACpC;AAAA,yBAAC,SAAI,WAAW,WAAW,EAAE,KAAK,CAAC,GACjC;AAAA,0BAAC,eAAY,YAAwB,UAAU,KAAK,UAAU;AAAA,MAE9D,qBAAC,SAAI,WAAU,mBACb;AAAA,4BAAC,SAAI,WAAW,aAAa,EAAE,KAAK,CAAC,GAAI,eAAK,UAAS;AAAA,QACvD,oBAAC,SAAI,WAAW,aAAa,EAAE,KAAK,CAAC,GAAI,eAAK,KAAI;AAAA,SACpD;AAAA,OACF;AAAA,IAEA,oBAAC,SAAI,WAAW,UAAU,EAAE,KAAK,CAAC,GAAI,eAAK,OAAM;AAAA,IAEjD,oBAAC,SAAI,WAAW,gBAAgB,EAAE,KAAK,CAAC,GACrC,6BAAmB,oBAAoB,KAAK,WAAW,GAAG,WAAW,QAAQ,GAChF;AAAA,KACF;AAGF,SAAO,SAAS,YAAY,oBAAC,SAAI,WAAU,mBAAmB,kBAAO,IAAS;AAChF;","names":[]}
|
|
@@ -1,19 +1,19 @@
|
|
|
1
1
|
export declare const serpContainer: (props?: ({
|
|
2
|
-
mode?: "
|
|
2
|
+
mode?: "mobile" | "desktop" | null | undefined;
|
|
3
3
|
} & import("class-variance-authority/types").ClassProp) | undefined) => string;
|
|
4
4
|
export declare const serpUrlRow: (props?: ({
|
|
5
|
-
mode?: "
|
|
5
|
+
mode?: "mobile" | "desktop" | null | undefined;
|
|
6
6
|
} & import("class-variance-authority/types").ClassProp) | undefined) => string;
|
|
7
7
|
export declare const serpSiteName: (props?: ({
|
|
8
|
-
mode?: "
|
|
8
|
+
mode?: "mobile" | "desktop" | null | undefined;
|
|
9
9
|
} & import("class-variance-authority/types").ClassProp) | undefined) => string;
|
|
10
10
|
export declare const serpHostname: (props?: ({
|
|
11
|
-
mode?: "
|
|
11
|
+
mode?: "mobile" | "desktop" | null | undefined;
|
|
12
12
|
} & import("class-variance-authority/types").ClassProp) | undefined) => string;
|
|
13
13
|
export declare const serpTitle: (props?: ({
|
|
14
|
-
mode?: "
|
|
14
|
+
mode?: "mobile" | "desktop" | null | undefined;
|
|
15
15
|
} & import("class-variance-authority/types").ClassProp) | undefined) => string;
|
|
16
16
|
export declare const serpDescription: (props?: ({
|
|
17
|
-
mode?: "
|
|
17
|
+
mode?: "mobile" | "desktop" | null | undefined;
|
|
18
18
|
} & import("class-variance-authority/types").ClassProp) | undefined) => string;
|
|
19
19
|
//# sourceMappingURL=variants.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"TabWrapper.d.ts","sourceRoot":"","sources":["../../../../src/components/SeoDrawer/components/TabWrapper.tsx"],"names":[],"mappings":"AAAA,UAAU,eAAe;IACvB,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;CAC3B;AAED,wBAAgB,UAAU,CAAC,EAAE,QAAQ,EAAE,EAAE,eAAe,2CAEvD"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../src/components/SeoDrawer/components/TabWrapper.tsx"],"sourcesContent":["interface TabWrapperProps {\n children: React.ReactNode;\n}\n\nexport function TabWrapper({ children }: TabWrapperProps) {\n return <div className=\"py-[18px]\">{children}</div>;\n}\n"],"mappings":"AAKS;AADF,SAAS,WAAW,EAAE,SAAS,GAAoB;AACxD,SAAO,oBAAC,SAAI,WAAU,aAAa,UAAS;AAC9C;","names":[]}
|
|
@@ -1,13 +1,20 @@
|
|
|
1
1
|
import type { AnalysisResult } from "../../engine/types/analysis";
|
|
2
|
+
import type { KeyphraseEntry } from "./keyphraseState";
|
|
2
3
|
import "../../admin.css";
|
|
3
4
|
export interface SeoDrawerProps {
|
|
4
5
|
drawerSlug: string;
|
|
5
|
-
|
|
6
|
-
|
|
6
|
+
keyphrases: KeyphraseEntry[];
|
|
7
|
+
selectedId: string | null;
|
|
8
|
+
onSelect: (id: string) => void;
|
|
7
9
|
result: AnalysisResult | null;
|
|
8
10
|
analyzing: boolean;
|
|
9
|
-
|
|
10
|
-
|
|
11
|
+
onAddRelated: () => void;
|
|
12
|
+
onTextChange: (id: string, text: string) => void;
|
|
13
|
+
onAddSynonym: (id: string, syn: string) => void;
|
|
14
|
+
onRemoveSynonym: (id: string, index: number) => void;
|
|
15
|
+
onRemove: (id: string) => void;
|
|
16
|
+
onSetFocus: (id: string) => void;
|
|
17
|
+
isDuplicate: (id: string, text: string) => boolean;
|
|
11
18
|
site: {
|
|
12
19
|
name: string;
|
|
13
20
|
baseUrl: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/SeoDrawer/index.tsx"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,cAAc,EAAe,MAAM,6BAA6B,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/SeoDrawer/index.tsx"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,cAAc,EAAe,MAAM,6BAA6B,CAAC;AAC/E,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAWvD,OAAO,iBAAiB,CAAC;AAEzB,MAAM,WAAW,cAAc;IAC7B,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,cAAc,EAAE,CAAC;IAC7B,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,QAAQ,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAC;IAC/B,MAAM,EAAE,cAAc,GAAG,IAAI,CAAC;IAC9B,SAAS,EAAE,OAAO,CAAC;IACnB,YAAY,EAAE,MAAM,IAAI,CAAC;IACzB,YAAY,EAAE,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IACjD,YAAY,EAAE,CAAC,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;IAChD,eAAe,EAAE,CAAC,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACrD,QAAQ,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAC;IAC/B,UAAU,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAC;IACjC,WAAW,EAAE,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC;IACnD,IAAI,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAA;KAAE,CAAC;CAC7D;AAED,eAAO,MAAM,SAAS,sDAiFpB,CAAC"}
|
|
@@ -14,17 +14,25 @@ import { VitalsTab } from "./tabs/VitalsTab";
|
|
|
14
14
|
import "../../admin.css";
|
|
15
15
|
const SeoDrawer = memo(function SeoDrawer2({
|
|
16
16
|
drawerSlug,
|
|
17
|
-
keyphrase,
|
|
18
|
-
setKeyphrase,
|
|
19
17
|
result,
|
|
18
|
+
site,
|
|
20
19
|
analyzing,
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
20
|
+
isDuplicate,
|
|
21
|
+
keyphrases,
|
|
22
|
+
onAddRelated,
|
|
23
|
+
onAddSynonym,
|
|
24
|
+
onRemove,
|
|
25
|
+
onRemoveSynonym,
|
|
26
|
+
onSelect,
|
|
27
|
+
onSetFocus,
|
|
28
|
+
onTextChange,
|
|
29
|
+
selectedId
|
|
24
30
|
}) {
|
|
25
31
|
const [tab, setTab] = useState("keyphrase");
|
|
26
32
|
const total = result?.overall.seoScore ?? 0;
|
|
27
33
|
const totalStatus = result ? result.overall.status : "idle";
|
|
34
|
+
const focusKeyphrase = keyphrases[0]?.text ?? "";
|
|
35
|
+
const focusSynonyms = keyphrases[0]?.synonyms ?? [];
|
|
28
36
|
return /* @__PURE__ */ jsx(
|
|
29
37
|
Drawer,
|
|
30
38
|
{
|
|
@@ -33,7 +41,7 @@ const SeoDrawer = memo(function SeoDrawer2({
|
|
|
33
41
|
Header: /* @__PURE__ */ jsx(Header, { drawerSlug, total, totalStatus }),
|
|
34
42
|
children: /* @__PURE__ */ jsxs("div", { className: "seo-root relative text-neutral-800", "data-status": totalStatus, children: [
|
|
35
43
|
/* @__PURE__ */ jsx(TabsNav, { active: tab, onChange: setTab }),
|
|
36
|
-
/* @__PURE__ */ jsx("div", {
|
|
44
|
+
/* @__PURE__ */ jsx("div", { children: result === null && tab !== "keyphrase" ? /* @__PURE__ */ jsxs(
|
|
37
45
|
"div",
|
|
38
46
|
{
|
|
39
47
|
className: "flex items-center gap-[8px] text-neutral-500 text-[13px]",
|
|
@@ -48,19 +56,33 @@ const SeoDrawer = memo(function SeoDrawer2({
|
|
|
48
56
|
tab === "keyphrase" && /* @__PURE__ */ jsx(
|
|
49
57
|
KeyphraseTab,
|
|
50
58
|
{
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
59
|
+
keyphrases,
|
|
60
|
+
selectedId,
|
|
61
|
+
onSelect,
|
|
62
|
+
result,
|
|
54
63
|
analyzing,
|
|
55
|
-
|
|
56
|
-
|
|
64
|
+
onAddRelated,
|
|
65
|
+
onTextChange,
|
|
66
|
+
onAddSynonym,
|
|
67
|
+
onRemoveSynonym,
|
|
68
|
+
onRemove,
|
|
69
|
+
onSetFocus,
|
|
70
|
+
isDuplicate
|
|
57
71
|
}
|
|
58
72
|
),
|
|
59
|
-
tab === "onpage" && /* @__PURE__ */ jsx(OnPageTab, { data: result.onPage }),
|
|
60
|
-
tab === "readability" && /* @__PURE__ */ jsx(ReadabilityTab, { data: result.readability }),
|
|
61
|
-
tab === "inclusive" && /* @__PURE__ */ jsx(InclusiveTab, { data: result.inclusive }),
|
|
62
|
-
tab === "vitals" && /* @__PURE__ */ jsx(VitalsTab, { data: result.vitals, onRequestKeyphrase: () => setTab("keyphrase") }),
|
|
63
|
-
tab === "serp" && /* @__PURE__ */ jsx(
|
|
73
|
+
tab === "onpage" && result && /* @__PURE__ */ jsx(OnPageTab, { data: result.onPage }),
|
|
74
|
+
tab === "readability" && result && /* @__PURE__ */ jsx(ReadabilityTab, { data: result.readability }),
|
|
75
|
+
tab === "inclusive" && result && /* @__PURE__ */ jsx(InclusiveTab, { data: result.inclusive }),
|
|
76
|
+
tab === "vitals" && result && /* @__PURE__ */ jsx(VitalsTab, { data: result.vitals, onRequestKeyphrase: () => setTab("keyphrase") }),
|
|
77
|
+
tab === "serp" && result && /* @__PURE__ */ jsx(
|
|
78
|
+
SerpTab,
|
|
79
|
+
{
|
|
80
|
+
data: result.serp,
|
|
81
|
+
keyphrase: focusKeyphrase,
|
|
82
|
+
synonyms: focusSynonyms,
|
|
83
|
+
faviconUrl: site.faviconUrl
|
|
84
|
+
}
|
|
85
|
+
)
|
|
64
86
|
] }) })
|
|
65
87
|
] })
|
|
66
88
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/components/SeoDrawer/index.tsx"],"sourcesContent":["\"use client\";\n\nimport { Drawer } from \"@payloadcms/ui\";\nimport { Loader2 } from \"lucide-react\";\nimport { memo, useState } from \"react\";\nimport type { AnalysisResult, TotalStatus } from \"../../engine/types/analysis\";\nimport { Header } from \"./components/Header\";\nimport { TabsNav } from \"./TabsNav\";\nimport type { TabKey } from \"./TabsNav\";\nimport { KeyphraseTab } from \"./tabs/KeyphraseTab\";\nimport { OnPageTab } from \"./tabs/OnPageTab\";\nimport { ReadabilityTab } from \"./tabs/ReadabilityTab\";\nimport { InclusiveTab } from \"./tabs/InclusiveTab\";\nimport { SerpTab } from \"./tabs/SerpTab\";\nimport { VitalsTab } from \"./tabs/VitalsTab\";\n\nimport \"../../admin.css\";\n\nexport interface SeoDrawerProps {\n drawerSlug: string;\n
|
|
1
|
+
{"version":3,"sources":["../../../src/components/SeoDrawer/index.tsx"],"sourcesContent":["\"use client\";\n\nimport { Drawer } from \"@payloadcms/ui\";\nimport { Loader2 } from \"lucide-react\";\nimport { memo, useState } from \"react\";\nimport type { AnalysisResult, TotalStatus } from \"../../engine/types/analysis\";\nimport type { KeyphraseEntry } from \"./keyphraseState\";\nimport { Header } from \"./components/Header\";\nimport { TabsNav } from \"./TabsNav\";\nimport type { TabKey } from \"./TabsNav\";\nimport { KeyphraseTab } from \"./tabs/KeyphraseTab\";\nimport { OnPageTab } from \"./tabs/OnPageTab\";\nimport { ReadabilityTab } from \"./tabs/ReadabilityTab\";\nimport { InclusiveTab } from \"./tabs/InclusiveTab\";\nimport { SerpTab } from \"./tabs/SerpTab\";\nimport { VitalsTab } from \"./tabs/VitalsTab\";\n\nimport \"../../admin.css\";\n\nexport interface SeoDrawerProps {\n drawerSlug: string;\n keyphrases: KeyphraseEntry[];\n selectedId: string | null;\n onSelect: (id: string) => void;\n result: AnalysisResult | null;\n analyzing: boolean;\n onAddRelated: () => void;\n onTextChange: (id: string, text: string) => void;\n onAddSynonym: (id: string, syn: string) => void;\n onRemoveSynonym: (id: string, index: number) => void;\n onRemove: (id: string) => void;\n onSetFocus: (id: string) => void;\n isDuplicate: (id: string, text: string) => boolean;\n site: { name: string; baseUrl: string; faviconUrl: string };\n}\n\nexport const SeoDrawer = memo(function SeoDrawer({\n drawerSlug,\n result,\n site,\n analyzing,\n isDuplicate,\n keyphrases,\n onAddRelated,\n onAddSynonym,\n onRemove,\n onRemoveSynonym,\n onSelect,\n onSetFocus,\n onTextChange,\n selectedId,\n}: SeoDrawerProps) {\n const [tab, setTab] = useState<TabKey>(\"keyphrase\");\n\n const total = result?.overall.seoScore ?? 0;\n const totalStatus: TotalStatus = result ? result.overall.status : \"idle\";\n\n const focusKeyphrase = keyphrases[0]?.text ?? \"\";\n const focusSynonyms = keyphrases[0]?.synonyms ?? [];\n\n return (\n <Drawer\n slug={drawerSlug}\n className=\"seo-drawer\"\n Header={<Header drawerSlug={drawerSlug} total={total} totalStatus={totalStatus} />}\n >\n <div className=\"seo-root relative text-neutral-800\" data-status={totalStatus}>\n <TabsNav active={tab} onChange={setTab} />\n\n <div>\n {result === null && tab !== \"keyphrase\" ? (\n <div\n className=\"flex items-center gap-[8px] text-neutral-500 text-[13px]\"\n role=\"status\"\n aria-live=\"polite\"\n >\n <Loader2 aria-hidden=\"true\" className=\"w-[14px] h-[14px] animate-spin\" />\n Analyzing…\n </div>\n ) : (\n <>\n {tab === \"keyphrase\" && (\n <KeyphraseTab\n keyphrases={keyphrases}\n selectedId={selectedId}\n onSelect={onSelect}\n result={result}\n analyzing={analyzing}\n onAddRelated={onAddRelated}\n onTextChange={onTextChange}\n onAddSynonym={onAddSynonym}\n onRemoveSynonym={onRemoveSynonym}\n onRemove={onRemove}\n onSetFocus={onSetFocus}\n isDuplicate={isDuplicate}\n />\n )}\n {tab === \"onpage\" && result && <OnPageTab data={result.onPage} />}\n {tab === \"readability\" && result && <ReadabilityTab data={result.readability} />}\n {tab === \"inclusive\" && result && <InclusiveTab data={result.inclusive} />}\n {tab === \"vitals\" && result && (\n <VitalsTab data={result.vitals} onRequestKeyphrase={() => setTab(\"keyphrase\")} />\n )}\n {tab === \"serp\" && result && (\n <SerpTab\n data={result.serp}\n keyphrase={focusKeyphrase}\n synonyms={focusSynonyms}\n faviconUrl={site.faviconUrl}\n />\n )}\n </>\n )}\n </div>\n </div>\n </Drawer>\n );\n});\n"],"mappings":";AAgEc,SAgBF,UAhBE,KAOF,YAPE;AA9Dd,SAAS,cAAc;AACvB,SAAS,eAAe;AACxB,SAAS,MAAM,gBAAgB;AAG/B,SAAS,cAAc;AACvB,SAAS,eAAe;AAExB,SAAS,oBAAoB;AAC7B,SAAS,iBAAiB;AAC1B,SAAS,sBAAsB;AAC/B,SAAS,oBAAoB;AAC7B,SAAS,eAAe;AACxB,SAAS,iBAAiB;AAE1B,OAAO;AAmBA,MAAM,YAAY,KAAK,SAASA,WAAU;AAAA,EAC/C;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAAmB;AACjB,QAAM,CAAC,KAAK,MAAM,IAAI,SAAiB,WAAW;AAElD,QAAM,QAAQ,QAAQ,QAAQ,YAAY;AAC1C,QAAM,cAA2B,SAAS,OAAO,QAAQ,SAAS;AAElE,QAAM,iBAAiB,WAAW,CAAC,GAAG,QAAQ;AAC9C,QAAM,gBAAgB,WAAW,CAAC,GAAG,YAAY,CAAC;AAElD,SACE;AAAA,IAAC;AAAA;AAAA,MACC,MAAM;AAAA,MACN,WAAU;AAAA,MACV,QAAQ,oBAAC,UAAO,YAAwB,OAAc,aAA0B;AAAA,MAEhF,+BAAC,SAAI,WAAU,sCAAqC,eAAa,aAC/D;AAAA,4BAAC,WAAQ,QAAQ,KAAK,UAAU,QAAQ;AAAA,QAExC,oBAAC,SACE,qBAAW,QAAQ,QAAQ,cAC1B;AAAA,UAAC;AAAA;AAAA,YACC,WAAU;AAAA,YACV,MAAK;AAAA,YACL,aAAU;AAAA,YAEV;AAAA,kCAAC,WAAQ,eAAY,QAAO,WAAU,kCAAiC;AAAA,cAAE;AAAA;AAAA;AAAA,QAE3E,IAEA,iCACG;AAAA,kBAAQ,eACP;AAAA,YAAC;AAAA;AAAA,cACC;AAAA,cACA;AAAA,cACA;AAAA,cACA;AAAA,cACA;AAAA,cACA;AAAA,cACA;AAAA,cACA;AAAA,cACA;AAAA,cACA;AAAA,cACA;AAAA,cACA;AAAA;AAAA,UACF;AAAA,UAED,QAAQ,YAAY,UAAU,oBAAC,aAAU,MAAM,OAAO,QAAQ;AAAA,UAC9D,QAAQ,iBAAiB,UAAU,oBAAC,kBAAe,MAAM,OAAO,aAAa;AAAA,UAC7E,QAAQ,eAAe,UAAU,oBAAC,gBAAa,MAAM,OAAO,WAAW;AAAA,UACvE,QAAQ,YAAY,UACnB,oBAAC,aAAU,MAAM,OAAO,QAAQ,oBAAoB,MAAM,OAAO,WAAW,GAAG;AAAA,UAEhF,QAAQ,UAAU,UACjB;AAAA,YAAC;AAAA;AAAA,cACC,MAAM,OAAO;AAAA,cACb,WAAW;AAAA,cACX,UAAU;AAAA,cACV,YAAY,KAAK;AAAA;AAAA,UACnB;AAAA,WAEJ,GAEJ;AAAA,SACF;AAAA;AAAA,EACF;AAEJ,CAAC;","names":["SeoDrawer"]}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export interface KeyphraseEntry {
|
|
2
|
+
id: string;
|
|
3
|
+
text: string;
|
|
4
|
+
synonyms: string[];
|
|
5
|
+
}
|
|
6
|
+
export declare function createEntry(text?: string, synonyms?: string[]): KeyphraseEntry;
|
|
7
|
+
export declare function firstEmptyId(list: KeyphraseEntry[]): string | undefined;
|
|
8
|
+
export declare function addRelated(list: KeyphraseEntry[]): KeyphraseEntry[];
|
|
9
|
+
export declare function updateText(list: KeyphraseEntry[], id: string, text: string): KeyphraseEntry[];
|
|
10
|
+
export declare function addSynonym(list: KeyphraseEntry[], id: string, syn: string): KeyphraseEntry[];
|
|
11
|
+
export declare function removeSynonym(list: KeyphraseEntry[], id: string, index: number): KeyphraseEntry[];
|
|
12
|
+
export declare function remove(list: KeyphraseEntry[], id: string): KeyphraseEntry[];
|
|
13
|
+
export declare function setFocus(list: KeyphraseEntry[], id: string): KeyphraseEntry[];
|
|
14
|
+
export declare function isDuplicate(list: KeyphraseEntry[], id: string, text: string): boolean;
|
|
15
|
+
export declare function pruneEmpties(list: KeyphraseEntry[]): KeyphraseEntry[];
|
|
16
|
+
//# sourceMappingURL=keyphraseState.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"keyphraseState.d.ts","sourceRoot":"","sources":["../../../src/components/SeoDrawer/keyphraseState.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,cAAc;IAC7B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,EAAE,CAAC;CACpB;AAUD,wBAAgB,WAAW,CAAC,IAAI,SAAK,EAAE,QAAQ,GAAE,MAAM,EAAO,GAAG,cAAc,CAM9E;AAED,wBAAgB,YAAY,CAAC,IAAI,EAAE,cAAc,EAAE,GAAG,MAAM,GAAG,SAAS,CAEvE;AAED,wBAAgB,UAAU,CAAC,IAAI,EAAE,cAAc,EAAE,GAAG,cAAc,EAAE,CAKnE;AAED,wBAAgB,UAAU,CAAC,IAAI,EAAE,cAAc,EAAE,EAAE,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,cAAc,EAAE,CAE7F;AAED,wBAAgB,UAAU,CAAC,IAAI,EAAE,cAAc,EAAE,EAAE,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,cAAc,EAAE,CAS5F;AAED,wBAAgB,aAAa,CAAC,IAAI,EAAE,cAAc,EAAE,EAAE,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,cAAc,EAAE,CAIjG;AAED,wBAAgB,MAAM,CAAC,IAAI,EAAE,cAAc,EAAE,EAAE,EAAE,EAAE,MAAM,GAAG,cAAc,EAAE,CAE3E;AAED,wBAAgB,QAAQ,CAAC,IAAI,EAAE,cAAc,EAAE,EAAE,EAAE,EAAE,MAAM,GAAG,cAAc,EAAE,CAK7E;AAED,wBAAgB,WAAW,CAAC,IAAI,EAAE,cAAc,EAAE,EAAE,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAKrF;AAED,wBAAgB,YAAY,CAAC,IAAI,EAAE,cAAc,EAAE,GAAG,cAAc,EAAE,CAErE"}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { MAX_KEYPHRASES } from "../../constants";
|
|
2
|
+
function makeId() {
|
|
3
|
+
const c = globalThis.crypto;
|
|
4
|
+
return c?.randomUUID ? c.randomUUID() : `kp_${Math.random().toString(36).slice(2)}${Date.now().toString(36)}`;
|
|
5
|
+
}
|
|
6
|
+
function createEntry(text = "", synonyms = []) {
|
|
7
|
+
return {
|
|
8
|
+
id: makeId(),
|
|
9
|
+
text,
|
|
10
|
+
synonyms: [...synonyms]
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
function firstEmptyId(list) {
|
|
14
|
+
return list.find((k) => k.text.trim() === "")?.id;
|
|
15
|
+
}
|
|
16
|
+
function addRelated(list) {
|
|
17
|
+
if (list.length >= MAX_KEYPHRASES)
|
|
18
|
+
return list;
|
|
19
|
+
if (firstEmptyId(list))
|
|
20
|
+
return list;
|
|
21
|
+
return [...list, createEntry()];
|
|
22
|
+
}
|
|
23
|
+
function updateText(list, id, text) {
|
|
24
|
+
return list.map((k) => k.id === id ? { ...k, text } : k);
|
|
25
|
+
}
|
|
26
|
+
function addSynonym(list, id, syn) {
|
|
27
|
+
const value = syn.trim();
|
|
28
|
+
if (!value)
|
|
29
|
+
return list;
|
|
30
|
+
return list.map((k) => {
|
|
31
|
+
if (k.id !== id)
|
|
32
|
+
return k;
|
|
33
|
+
if (k.synonyms.some((s) => s.toLowerCase() === value.toLowerCase()))
|
|
34
|
+
return k;
|
|
35
|
+
return { ...k, synonyms: [...k.synonyms, value] };
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
function removeSynonym(list, id, index) {
|
|
39
|
+
return list.map(
|
|
40
|
+
(k) => k.id === id ? { ...k, synonyms: k.synonyms.filter((_, i) => i !== index) } : k
|
|
41
|
+
);
|
|
42
|
+
}
|
|
43
|
+
function remove(list, id) {
|
|
44
|
+
return list.filter((k) => k.id !== id);
|
|
45
|
+
}
|
|
46
|
+
function setFocus(list, id) {
|
|
47
|
+
const target = list.find((k) => k.id === id);
|
|
48
|
+
if (!target)
|
|
49
|
+
return list;
|
|
50
|
+
return [target, ...list.filter((k) => k.id !== id)];
|
|
51
|
+
}
|
|
52
|
+
function isDuplicate(list, id, text) {
|
|
53
|
+
const value = text.trim().toLowerCase();
|
|
54
|
+
if (!value)
|
|
55
|
+
return false;
|
|
56
|
+
return list.some((k) => k.id !== id && k.text.trim().toLowerCase() === value);
|
|
57
|
+
}
|
|
58
|
+
function pruneEmpties(list) {
|
|
59
|
+
return list.filter((k) => k.text.trim() !== "");
|
|
60
|
+
}
|
|
61
|
+
export {
|
|
62
|
+
addRelated,
|
|
63
|
+
addSynonym,
|
|
64
|
+
createEntry,
|
|
65
|
+
firstEmptyId,
|
|
66
|
+
isDuplicate,
|
|
67
|
+
pruneEmpties,
|
|
68
|
+
remove,
|
|
69
|
+
removeSynonym,
|
|
70
|
+
setFocus,
|
|
71
|
+
updateText
|
|
72
|
+
};
|
|
73
|
+
//# sourceMappingURL=keyphraseState.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/components/SeoDrawer/keyphraseState.ts"],"sourcesContent":["import { MAX_KEYPHRASES } from \"../../constants\";\n\nexport interface KeyphraseEntry {\n id: string;\n text: string;\n synonyms: string[];\n}\n\nfunction makeId(): string {\n const c = (globalThis as { crypto?: { randomUUID?: () => string } }).crypto;\n\n return c?.randomUUID\n ? c.randomUUID()\n : `kp_${Math.random().toString(36).slice(2)}${Date.now().toString(36)}`;\n}\n\nexport function createEntry(text = \"\", synonyms: string[] = []): KeyphraseEntry {\n return {\n id: makeId(),\n text,\n synonyms: [...synonyms],\n };\n}\n\nexport function firstEmptyId(list: KeyphraseEntry[]): string | undefined {\n return list.find((k) => k.text.trim() === \"\")?.id;\n}\n\nexport function addRelated(list: KeyphraseEntry[]): KeyphraseEntry[] {\n if (list.length >= MAX_KEYPHRASES) return list;\n if (firstEmptyId(list)) return list;\n\n return [...list, createEntry()];\n}\n\nexport function updateText(list: KeyphraseEntry[], id: string, text: string): KeyphraseEntry[] {\n return list.map((k) => (k.id === id ? { ...k, text } : k));\n}\n\nexport function addSynonym(list: KeyphraseEntry[], id: string, syn: string): KeyphraseEntry[] {\n const value = syn.trim();\n if (!value) return list;\n\n return list.map((k) => {\n if (k.id !== id) return k;\n if (k.synonyms.some((s) => s.toLowerCase() === value.toLowerCase())) return k;\n return { ...k, synonyms: [...k.synonyms, value] };\n });\n}\n\nexport function removeSynonym(list: KeyphraseEntry[], id: string, index: number): KeyphraseEntry[] {\n return list.map((k) =>\n k.id === id ? { ...k, synonyms: k.synonyms.filter((_, i) => i !== index) } : k\n );\n}\n\nexport function remove(list: KeyphraseEntry[], id: string): KeyphraseEntry[] {\n return list.filter((k) => k.id !== id);\n}\n\nexport function setFocus(list: KeyphraseEntry[], id: string): KeyphraseEntry[] {\n const target = list.find((k) => k.id === id);\n if (!target) return list;\n\n return [target, ...list.filter((k) => k.id !== id)];\n}\n\nexport function isDuplicate(list: KeyphraseEntry[], id: string, text: string): boolean {\n const value = text.trim().toLowerCase();\n if (!value) return false;\n\n return list.some((k) => k.id !== id && k.text.trim().toLowerCase() === value);\n}\n\nexport function pruneEmpties(list: KeyphraseEntry[]): KeyphraseEntry[] {\n return list.filter((k) => k.text.trim() !== \"\");\n}\n"],"mappings":"AAAA,SAAS,sBAAsB;AAQ/B,SAAS,SAAiB;AACxB,QAAM,IAAK,WAA0D;AAErE,SAAO,GAAG,aACN,EAAE,WAAW,IACb,MAAM,KAAK,OAAO,EAAE,SAAS,EAAE,EAAE,MAAM,CAAC,CAAC,GAAG,KAAK,IAAI,EAAE,SAAS,EAAE,CAAC;AACzE;AAEO,SAAS,YAAY,OAAO,IAAI,WAAqB,CAAC,GAAmB;AAC9E,SAAO;AAAA,IACL,IAAI,OAAO;AAAA,IACX;AAAA,IACA,UAAU,CAAC,GAAG,QAAQ;AAAA,EACxB;AACF;AAEO,SAAS,aAAa,MAA4C;AACvE,SAAO,KAAK,KAAK,CAAC,MAAM,EAAE,KAAK,KAAK,MAAM,EAAE,GAAG;AACjD;AAEO,SAAS,WAAW,MAA0C;AACnE,MAAI,KAAK,UAAU;AAAgB,WAAO;AAC1C,MAAI,aAAa,IAAI;AAAG,WAAO;AAE/B,SAAO,CAAC,GAAG,MAAM,YAAY,CAAC;AAChC;AAEO,SAAS,WAAW,MAAwB,IAAY,MAAgC;AAC7F,SAAO,KAAK,IAAI,CAAC,MAAO,EAAE,OAAO,KAAK,EAAE,GAAG,GAAG,KAAK,IAAI,CAAE;AAC3D;AAEO,SAAS,WAAW,MAAwB,IAAY,KAA+B;AAC5F,QAAM,QAAQ,IAAI,KAAK;AACvB,MAAI,CAAC;AAAO,WAAO;AAEnB,SAAO,KAAK,IAAI,CAAC,MAAM;AACrB,QAAI,EAAE,OAAO;AAAI,aAAO;AACxB,QAAI,EAAE,SAAS,KAAK,CAAC,MAAM,EAAE,YAAY,MAAM,MAAM,YAAY,CAAC;AAAG,aAAO;AAC5E,WAAO,EAAE,GAAG,GAAG,UAAU,CAAC,GAAG,EAAE,UAAU,KAAK,EAAE;AAAA,EAClD,CAAC;AACH;AAEO,SAAS,cAAc,MAAwB,IAAY,OAAiC;AACjG,SAAO,KAAK;AAAA,IAAI,CAAC,MACf,EAAE,OAAO,KAAK,EAAE,GAAG,GAAG,UAAU,EAAE,SAAS,OAAO,CAAC,GAAG,MAAM,MAAM,KAAK,EAAE,IAAI;AAAA,EAC/E;AACF;AAEO,SAAS,OAAO,MAAwB,IAA8B;AAC3E,SAAO,KAAK,OAAO,CAAC,MAAM,EAAE,OAAO,EAAE;AACvC;AAEO,SAAS,SAAS,MAAwB,IAA8B;AAC7E,QAAM,SAAS,KAAK,KAAK,CAAC,MAAM,EAAE,OAAO,EAAE;AAC3C,MAAI,CAAC;AAAQ,WAAO;AAEpB,SAAO,CAAC,QAAQ,GAAG,KAAK,OAAO,CAAC,MAAM,EAAE,OAAO,EAAE,CAAC;AACpD;AAEO,SAAS,YAAY,MAAwB,IAAY,MAAuB;AACrF,QAAM,QAAQ,KAAK,KAAK,EAAE,YAAY;AACtC,MAAI,CAAC;AAAO,WAAO;AAEnB,SAAO,KAAK,KAAK,CAAC,MAAM,EAAE,OAAO,MAAM,EAAE,KAAK,KAAK,EAAE,YAAY,MAAM,KAAK;AAC9E;AAEO,SAAS,aAAa,MAA0C;AACrE,SAAO,KAAK,OAAO,CAAC,MAAM,EAAE,KAAK,KAAK,MAAM,EAAE;AAChD;","names":[]}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { KeyphraseEntry } from './keyphraseState';
|
|
2
|
+
export declare function storageKey(collectionSlug: string, docId: string, locale: string): string;
|
|
3
|
+
export declare function loadKeyphrases(key: string): KeyphraseEntry[];
|
|
4
|
+
export declare function saveKeyphrases(key: string, list: KeyphraseEntry[]): void;
|
|
5
|
+
//# sourceMappingURL=keyphraseStorage.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"keyphraseStorage.d.ts","sourceRoot":"","sources":["../../../src/components/SeoDrawer/keyphraseStorage.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AASvD,wBAAgB,UAAU,CAAC,cAAc,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAExF;AAWD,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,cAAc,EAAE,CAyB5D;AAED,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,cAAc,EAAE,GAAG,IAAI,CAmBxE"}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { createEntry, pruneEmpties } from "./keyphraseState";
|
|
2
|
+
const PREFIX = "seo-kw";
|
|
3
|
+
function storageKey(collectionSlug, docId, locale) {
|
|
4
|
+
return `${PREFIX}:${collectionSlug}:${docId}:${locale}`;
|
|
5
|
+
}
|
|
6
|
+
function store() {
|
|
7
|
+
try {
|
|
8
|
+
if (typeof window === "undefined" || !window.localStorage)
|
|
9
|
+
return null;
|
|
10
|
+
return window.localStorage;
|
|
11
|
+
} catch {
|
|
12
|
+
return null;
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
function loadKeyphrases(key) {
|
|
16
|
+
const fallback = () => [createEntry()];
|
|
17
|
+
const s = store();
|
|
18
|
+
if (!s)
|
|
19
|
+
return fallback();
|
|
20
|
+
try {
|
|
21
|
+
const raw = s.getItem(key);
|
|
22
|
+
if (!raw)
|
|
23
|
+
return fallback();
|
|
24
|
+
const parsed = JSON.parse(raw);
|
|
25
|
+
if (!Array.isArray(parsed) || parsed.length === 0)
|
|
26
|
+
return fallback();
|
|
27
|
+
const list = parsed.filter((e) => e && typeof e.text === "string").map(
|
|
28
|
+
(e) => createEntry(
|
|
29
|
+
e.text,
|
|
30
|
+
Array.isArray(e.synonyms) ? e.synonyms.filter((x) => typeof x === "string") : []
|
|
31
|
+
)
|
|
32
|
+
);
|
|
33
|
+
return list.length ? list : fallback();
|
|
34
|
+
} catch {
|
|
35
|
+
return fallback();
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
function saveKeyphrases(key, list) {
|
|
39
|
+
const s = store();
|
|
40
|
+
if (!s)
|
|
41
|
+
return;
|
|
42
|
+
try {
|
|
43
|
+
const persistable = pruneEmpties(list).map((k) => ({
|
|
44
|
+
text: k.text,
|
|
45
|
+
synonyms: k.synonyms
|
|
46
|
+
}));
|
|
47
|
+
if (persistable.length === 0) {
|
|
48
|
+
s.removeItem(key);
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
s.setItem(key, JSON.stringify(persistable));
|
|
52
|
+
} catch {
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
export {
|
|
56
|
+
loadKeyphrases,
|
|
57
|
+
saveKeyphrases,
|
|
58
|
+
storageKey
|
|
59
|
+
};
|
|
60
|
+
//# sourceMappingURL=keyphraseStorage.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/components/SeoDrawer/keyphraseStorage.ts"],"sourcesContent":["import { createEntry, pruneEmpties } from './keyphraseState';\nimport type { KeyphraseEntry } from './keyphraseState';\n\nconst PREFIX = \"seo-kw\";\n\ninterface StoredEntry {\n text: string;\n synonyms: string[];\n}\n\nexport function storageKey(collectionSlug: string, docId: string, locale: string): string {\n return `${PREFIX}:${collectionSlug}:${docId}:${locale}`;\n}\n\nfunction store(): Storage | null {\n try {\n if (typeof window === \"undefined\" || !window.localStorage) return null;\n return window.localStorage;\n } catch {\n return null;\n }\n}\n\nexport function loadKeyphrases(key: string): KeyphraseEntry[] {\n const fallback = () => [createEntry()];\n const s = store();\n if (!s) return fallback();\n\n try {\n const raw = s.getItem(key);\n if (!raw) return fallback();\n\n const parsed = JSON.parse(raw) as StoredEntry[];\n if (!Array.isArray(parsed) || parsed.length === 0) return fallback();\n\n const list = parsed\n .filter((e) => e && typeof e.text === \"string\")\n .map((e) =>\n createEntry(\n e.text,\n Array.isArray(e.synonyms) ? e.synonyms.filter((x) => typeof x === \"string\") : []\n )\n );\n\n return list.length ? list : fallback();\n } catch {\n return fallback();\n }\n}\n\nexport function saveKeyphrases(key: string, list: KeyphraseEntry[]): void {\n const s = store();\n if (!s) return;\n\n try {\n const persistable = pruneEmpties(list).map<StoredEntry>((k) => ({\n text: k.text,\n synonyms: k.synonyms,\n }));\n\n if (persistable.length === 0) {\n s.removeItem(key);\n return;\n }\n\n s.setItem(key, JSON.stringify(persistable));\n } catch {\n // quota / serialization — fail soft\n }\n}\n"],"mappings":"AAAA,SAAS,aAAa,oBAAoB;AAG1C,MAAM,SAAS;AAOR,SAAS,WAAW,gBAAwB,OAAe,QAAwB;AACxF,SAAO,GAAG,MAAM,IAAI,cAAc,IAAI,KAAK,IAAI,MAAM;AACvD;AAEA,SAAS,QAAwB;AAC/B,MAAI;AACF,QAAI,OAAO,WAAW,eAAe,CAAC,OAAO;AAAc,aAAO;AAClE,WAAO,OAAO;AAAA,EAChB,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEO,SAAS,eAAe,KAA+B;AAC5D,QAAM,WAAW,MAAM,CAAC,YAAY,CAAC;AACrC,QAAM,IAAI,MAAM;AAChB,MAAI,CAAC;AAAG,WAAO,SAAS;AAExB,MAAI;AACF,UAAM,MAAM,EAAE,QAAQ,GAAG;AACzB,QAAI,CAAC;AAAK,aAAO,SAAS;AAE1B,UAAM,SAAS,KAAK,MAAM,GAAG;AAC7B,QAAI,CAAC,MAAM,QAAQ,MAAM,KAAK,OAAO,WAAW;AAAG,aAAO,SAAS;AAEnE,UAAM,OAAO,OACV,OAAO,CAAC,MAAM,KAAK,OAAO,EAAE,SAAS,QAAQ,EAC7C;AAAA,MAAI,CAAC,MACJ;AAAA,QACE,EAAE;AAAA,QACF,MAAM,QAAQ,EAAE,QAAQ,IAAI,EAAE,SAAS,OAAO,CAAC,MAAM,OAAO,MAAM,QAAQ,IAAI,CAAC;AAAA,MACjF;AAAA,IACF;AAEF,WAAO,KAAK,SAAS,OAAO,SAAS;AAAA,EACvC,QAAQ;AACN,WAAO,SAAS;AAAA,EAClB;AACF;AAEO,SAAS,eAAe,KAAa,MAA8B;AACxE,QAAM,IAAI,MAAM;AAChB,MAAI,CAAC;AAAG;AAER,MAAI;AACF,UAAM,cAAc,aAAa,IAAI,EAAE,IAAiB,CAAC,OAAO;AAAA,MAC9D,MAAM,EAAE;AAAA,MACR,UAAU,EAAE;AAAA,IACd,EAAE;AAEF,QAAI,YAAY,WAAW,GAAG;AAC5B,QAAE,WAAW,GAAG;AAChB;AAAA,IACF;AAEA,MAAE,QAAQ,KAAK,KAAK,UAAU,WAAW,CAAC;AAAA,EAC5C,QAAQ;AAAA,EAER;AACF;","names":[]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"InclusiveTab.d.ts","sourceRoot":"","sources":["../../../../src/components/SeoDrawer/tabs/InclusiveTab.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,gCAAgC,CAAC;
|
|
1
|
+
{"version":3,"file":"InclusiveTab.d.ts","sourceRoot":"","sources":["../../../../src/components/SeoDrawer/tabs/InclusiveTab.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,gCAAgC,CAAC;AAOrE,wBAAgB,YAAY,CAAC,EAAE,IAAI,EAAE,EAAE;IAAE,IAAI,EAAE,cAAc,CAAC,WAAW,CAAC,CAAA;CAAE,2CAgE3E"}
|
|
@@ -4,9 +4,10 @@ import { cn, ROW_SEPARATOR } from "../../../utils/style";
|
|
|
4
4
|
import { TabHeader } from "../../../ui/TabHeader";
|
|
5
5
|
import { SectionCard } from "../../../ui/SectionCard";
|
|
6
6
|
import { Pill } from "../../../ui/Pill";
|
|
7
|
+
import { TabWrapper } from "../components/TabWrapper";
|
|
7
8
|
function InclusiveTab({ data }) {
|
|
8
9
|
const flagged = data.categories.reduce((n, c) => n + c.flags.length, 0);
|
|
9
|
-
return /* @__PURE__ */ jsxs("section", { className: "flex flex-col gap-[13px]", children: [
|
|
10
|
+
return /* @__PURE__ */ jsx(TabWrapper, { children: /* @__PURE__ */ jsxs("section", { className: "flex flex-col gap-[13px]", children: [
|
|
10
11
|
/* @__PURE__ */ jsx(
|
|
11
12
|
TabHeader,
|
|
12
13
|
{
|
|
@@ -59,7 +60,7 @@ function InclusiveTab({ data }) {
|
|
|
59
60
|
)) })
|
|
60
61
|
}
|
|
61
62
|
)
|
|
62
|
-
] });
|
|
63
|
+
] }) });
|
|
63
64
|
}
|
|
64
65
|
export {
|
|
65
66
|
InclusiveTab
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../src/components/SeoDrawer/tabs/InclusiveTab.tsx"],"sourcesContent":["\"use client\";\n\nimport type { AnalysisResult } from \"../../../engine/types/analysis\";\nimport { cn, ROW_SEPARATOR } from \"../../../utils/style\";\nimport { TabHeader } from \"../../../ui/TabHeader\";\nimport { SectionCard } from \"../../../ui/SectionCard\";\nimport { Pill } from \"../../../ui/Pill\";\n\nexport function InclusiveTab({ data }: { data: AnalysisResult[\"inclusive\"] }) {\n const flagged = data.categories.reduce((n, c) => n + c.flags.length, 0);\n\n return (\n <section className=\"flex flex-col gap-[13px]\">\n
|
|
1
|
+
{"version":3,"sources":["../../../../src/components/SeoDrawer/tabs/InclusiveTab.tsx"],"sourcesContent":["\"use client\";\n\nimport type { AnalysisResult } from \"../../../engine/types/analysis\";\nimport { cn, ROW_SEPARATOR } from \"../../../utils/style\";\nimport { TabHeader } from \"../../../ui/TabHeader\";\nimport { SectionCard } from \"../../../ui/SectionCard\";\nimport { Pill } from \"../../../ui/Pill\";\nimport { TabWrapper } from \"../components/TabWrapper\";\n\nexport function InclusiveTab({ data }: { data: AnalysisResult[\"inclusive\"] }) {\n const flagged = data.categories.reduce((n, c) => n + c.flags.length, 0);\n\n return (\n <TabWrapper>\n <section className=\"flex flex-col gap-[13px]\">\n <TabHeader\n title=\"Inclusive language\"\n score={data.ringScore}\n status={data.status}\n statusLabel={data.status === \"good\" ? \"Good\" : \"Needs work\"}\n subtitle={\n <>\n {flagged} phrases flagged across {data.categories.length} categories\n </>\n }\n />\n\n {data.categories.length > 0 && (\n <SectionCard title=\"Marked by category\" widget={<Pill variant=\"neutral\">{flagged}</Pill>}>\n {data.categories.map((cat) => (\n <div className={cn(\"relative px-[15px] py-[12px]\", ROW_SEPARATOR)} key={cat.name}>\n <div className=\"flex items-center gap-[8px] mb-[9px]\">\n <span className=\"font-bold text-[12.5px]\">{cat.name}</span>\n <Pill variant=\"bad\">{cat.flags.length}</Pill>\n </div>\n {cat.flags.map((f, i) => (\n <div\n className=\"flex items-center gap-[9px] py-[6px] text-[12px]\"\n key={`${f.term}-${i}`}\n >\n <span className=\"text-seo-bad font-medium whitespace-nowrap\">{f.term}</span>\n <span className=\"text-neutral-300\">›</span>\n <span className=\"text-seo-good font-medium flex-1\">{f.suggestion}</span>\n <span className=\"text-neutral-500 font-mono text-[10.5px] whitespace-nowrap\">\n {f.location}\n </span>\n </div>\n ))}\n </div>\n ))}\n </SectionCard>\n )}\n\n {data.cleanCategories.length > 0 && (\n <SectionCard\n title=\"No issues found\"\n widget={<Pill variant=\"neutral\">{data.cleanCategories.length}</Pill>}\n >\n <div className=\"flex gap-[8px] flex-wrap px-[15px] py-[13px]\">\n {data.cleanCategories.map((n) => (\n <span\n className=\"inline-flex items-center gap-[6px] text-[11.5px] text-seo-good bg-seo-good-100 border border-seo-good-200 rounded-[20px] px-[11px] py-[4px] font-medium\"\n key={n}\n >\n ✓ {n}\n </span>\n ))}\n </div>\n </SectionCard>\n )}\n </section>\n </TabWrapper>\n );\n}\n"],"mappings":";AAeQ,SAMI,UANJ,KAMI,YANJ;AAZR,SAAS,IAAI,qBAAqB;AAClC,SAAS,iBAAiB;AAC1B,SAAS,mBAAmB;AAC5B,SAAS,YAAY;AACrB,SAAS,kBAAkB;AAEpB,SAAS,aAAa,EAAE,KAAK,GAA0C;AAC5E,QAAM,UAAU,KAAK,WAAW,OAAO,CAAC,GAAG,MAAM,IAAI,EAAE,MAAM,QAAQ,CAAC;AAEtE,SACE,oBAAC,cACC,+BAAC,aAAQ,WAAU,4BACjB;AAAA;AAAA,MAAC;AAAA;AAAA,QACC,OAAM;AAAA,QACN,OAAO,KAAK;AAAA,QACZ,QAAQ,KAAK;AAAA,QACb,aAAa,KAAK,WAAW,SAAS,SAAS;AAAA,QAC/C,UACE,iCACG;AAAA;AAAA,UAAQ;AAAA,UAAyB,KAAK,WAAW;AAAA,UAAO;AAAA,WAC3D;AAAA;AAAA,IAEJ;AAAA,IAEC,KAAK,WAAW,SAAS,KACxB,oBAAC,eAAY,OAAM,sBAAqB,QAAQ,oBAAC,QAAK,SAAQ,WAAW,mBAAQ,GAC9E,eAAK,WAAW,IAAI,CAAC,QACpB,qBAAC,SAAI,WAAW,GAAG,gCAAgC,aAAa,GAC9D;AAAA,2BAAC,SAAI,WAAU,wCACb;AAAA,4BAAC,UAAK,WAAU,2BAA2B,cAAI,MAAK;AAAA,QACpD,oBAAC,QAAK,SAAQ,OAAO,cAAI,MAAM,QAAO;AAAA,SACxC;AAAA,MACC,IAAI,MAAM,IAAI,CAAC,GAAG,MACjB;AAAA,QAAC;AAAA;AAAA,UACC,WAAU;AAAA,UAGV;AAAA,gCAAC,UAAK,WAAU,8CAA8C,YAAE,MAAK;AAAA,YACrE,oBAAC,UAAK,WAAU,oBAAmB,oBAAC;AAAA,YACpC,oBAAC,UAAK,WAAU,oCAAoC,YAAE,YAAW;AAAA,YACjE,oBAAC,UAAK,WAAU,8DACb,YAAE,UACL;AAAA;AAAA;AAAA,QAPK,GAAG,EAAE,IAAI,IAAI,CAAC;AAAA,MAQrB,CACD;AAAA,SAjBqE,IAAI,IAkB5E,CACD,GACH;AAAA,IAGD,KAAK,gBAAgB,SAAS,KAC7B;AAAA,MAAC;AAAA;AAAA,QACC,OAAM;AAAA,QACN,QAAQ,oBAAC,QAAK,SAAQ,WAAW,eAAK,gBAAgB,QAAO;AAAA,QAE7D,8BAAC,SAAI,WAAU,gDACZ,eAAK,gBAAgB,IAAI,CAAC,MACzB;AAAA,UAAC;AAAA;AAAA,YACC,WAAU;AAAA,YAEX;AAAA;AAAA,cACI;AAAA;AAAA;AAAA,UAFE;AAAA,QAGP,CACD,GACH;AAAA;AAAA,IACF;AAAA,KAEJ,GACF;AAEJ;","names":[]}
|
|
@@ -1,11 +1,18 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { AnalysisResult } from "../../../engine/types/analysis";
|
|
2
|
+
import type { KeyphraseEntry } from "../keyphraseState";
|
|
2
3
|
export interface KeyphraseTabProps {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
4
|
+
keyphrases: KeyphraseEntry[];
|
|
5
|
+
selectedId: string | null;
|
|
6
|
+
onSelect: (id: string) => void;
|
|
7
|
+
result: AnalysisResult | null;
|
|
6
8
|
analyzing: boolean;
|
|
7
|
-
|
|
8
|
-
|
|
9
|
+
onAddRelated: () => void;
|
|
10
|
+
onTextChange: (id: string, text: string) => void;
|
|
11
|
+
onAddSynonym: (id: string, syn: string) => void;
|
|
12
|
+
onRemoveSynonym: (id: string, index: number) => void;
|
|
13
|
+
onRemove: (id: string) => void;
|
|
14
|
+
onSetFocus: (id: string) => void;
|
|
15
|
+
isDuplicate: (id: string, text: string) => boolean;
|
|
9
16
|
}
|
|
10
|
-
export declare function KeyphraseTab({
|
|
17
|
+
export declare function KeyphraseTab({ keyphrases, selectedId: selectedIdProp, onSelect, result, analyzing, onAddRelated, onTextChange, onAddSynonym, onRemoveSynonym, onRemove, onSetFocus, isDuplicate, }: KeyphraseTabProps): import("react/jsx-runtime").JSX.Element;
|
|
11
18
|
//# sourceMappingURL=KeyphraseTab.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"KeyphraseTab.d.ts","sourceRoot":"","sources":["../../../../src/components/SeoDrawer/tabs/KeyphraseTab.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"KeyphraseTab.d.ts","sourceRoot":"","sources":["../../../../src/components/SeoDrawer/tabs/KeyphraseTab.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,cAAc,EAAkB,MAAM,gCAAgC,CAAC;AACrF,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAMxD,MAAM,WAAW,iBAAiB;IAChC,UAAU,EAAE,cAAc,EAAE,CAAC;IAC7B,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,QAAQ,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAC;IAC/B,MAAM,EAAE,cAAc,GAAG,IAAI,CAAC;IAC9B,SAAS,EAAE,OAAO,CAAC;IACnB,YAAY,EAAE,MAAM,IAAI,CAAC;IACzB,YAAY,EAAE,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IACjD,YAAY,EAAE,CAAC,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;IAChD,eAAe,EAAE,CAAC,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACrD,QAAQ,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAC;IAC/B,UAAU,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAC;IACjC,WAAW,EAAE,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC;CACpD;AAYD,wBAAgB,YAAY,CAAC,EAC3B,UAAU,EACV,UAAU,EAAE,cAAc,EAC1B,QAAQ,EACR,MAAM,EACN,SAAS,EACT,YAAY,EACZ,YAAY,EACZ,YAAY,EACZ,eAAe,EACf,QAAQ,EACR,UAAU,EACV,WAAW,GACZ,EAAE,iBAAiB,2CAkGnB"}
|