@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
|
@@ -1,76 +1,117 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
2
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { useRef } from "react";
|
|
4
|
+
import { KeyphraseDetail } from "./keyphrase/KeyphraseDetail";
|
|
5
|
+
import { KeyphraseRail } from "./keyphrase/KeyphraseRail";
|
|
6
|
+
function resultForEntry(entry, isFocus, result) {
|
|
7
|
+
if (!result)
|
|
8
|
+
return void 0;
|
|
9
|
+
if (isFocus)
|
|
10
|
+
return result.keyphraseText === entry.text ? result.keyphrase : void 0;
|
|
11
|
+
return result.relatedKeyphrases.find((r) => r.text === entry.text)?.result;
|
|
12
|
+
}
|
|
11
13
|
function KeyphraseTab({
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
14
|
+
keyphrases,
|
|
15
|
+
selectedId: selectedIdProp,
|
|
16
|
+
onSelect,
|
|
17
|
+
result,
|
|
15
18
|
analyzing,
|
|
16
|
-
|
|
17
|
-
|
|
19
|
+
onAddRelated,
|
|
20
|
+
onTextChange,
|
|
21
|
+
onAddSynonym,
|
|
22
|
+
onRemoveSynonym,
|
|
23
|
+
onRemove,
|
|
24
|
+
onSetFocus,
|
|
25
|
+
isDuplicate
|
|
18
26
|
}) {
|
|
19
|
-
const [
|
|
20
|
-
const
|
|
21
|
-
const
|
|
22
|
-
const
|
|
23
|
-
const
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
27
|
+
const selectedId = selectedIdProp ?? keyphrases[0]?.id ?? null;
|
|
28
|
+
const selected = keyphrases.find((k) => k.id === selectedId) ?? keyphrases[0] ?? null;
|
|
29
|
+
const selectedIsFocus = selected ? keyphrases.indexOf(selected) === 0 : true;
|
|
30
|
+
const lastMetrics = useRef(/* @__PURE__ */ new Map());
|
|
31
|
+
const liveIds = new Set(keyphrases.map((k) => k.id));
|
|
32
|
+
for (const id of [...lastMetrics.current.keys()]) {
|
|
33
|
+
if (!liveIds.has(id))
|
|
34
|
+
lastMetrics.current.delete(id);
|
|
35
|
+
}
|
|
36
|
+
keyphrases.forEach((entry, index) => {
|
|
37
|
+
if (entry.text.trim() === "") {
|
|
38
|
+
lastMetrics.current.delete(entry.id);
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
const fresh = resultForEntry(entry, index === 0, result);
|
|
42
|
+
if (fresh)
|
|
43
|
+
lastMetrics.current.set(entry.id, fresh);
|
|
44
|
+
});
|
|
45
|
+
const stateFor = (entry) => {
|
|
46
|
+
if (!entry.text.trim())
|
|
47
|
+
return { kind: "idle" };
|
|
48
|
+
const isFocus = keyphrases.indexOf(entry) === 0;
|
|
49
|
+
if (!isFocus && isDuplicate(entry.id, entry.text))
|
|
50
|
+
return { kind: "idle" };
|
|
51
|
+
const category = resultForEntry(entry, isFocus, result);
|
|
52
|
+
if (category)
|
|
53
|
+
return { kind: "score", score: category.ringScore, status: category.status };
|
|
54
|
+
return { kind: "analyzing" };
|
|
55
|
+
};
|
|
56
|
+
const detailAnalysis = () => {
|
|
57
|
+
if (!selected)
|
|
58
|
+
return { kind: "hint", message: "" };
|
|
59
|
+
if (isDuplicate(selected.id, selected.text)) {
|
|
60
|
+
return {
|
|
61
|
+
kind: "hint",
|
|
62
|
+
message: "Resolve the duplicate to analyse this keyphrase."
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
if (!selected.text.trim()) {
|
|
66
|
+
return {
|
|
67
|
+
kind: "hint",
|
|
68
|
+
message: "Start typing a keyphrase to see its analysis."
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
const category = resultForEntry(selected, selectedIsFocus, result);
|
|
72
|
+
if (category) {
|
|
73
|
+
return {
|
|
74
|
+
kind: "metrics",
|
|
75
|
+
result: category,
|
|
76
|
+
dim: analyzing
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
const previous = lastMetrics.current.get(selected.id);
|
|
80
|
+
if (previous) {
|
|
81
|
+
return {
|
|
82
|
+
kind: "metrics",
|
|
83
|
+
result: previous,
|
|
84
|
+
dim: true
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
return { kind: "analyzing" };
|
|
88
|
+
};
|
|
89
|
+
const analysis = detailAnalysis();
|
|
90
|
+
return /* @__PURE__ */ jsxs("div", { className: "flex min-h-[420px]", children: [
|
|
91
|
+
/* @__PURE__ */ jsx(
|
|
92
|
+
KeyphraseRail,
|
|
93
|
+
{
|
|
94
|
+
entries: keyphrases,
|
|
95
|
+
onAdd: onAddRelated,
|
|
96
|
+
onSelect,
|
|
97
|
+
selectedId,
|
|
98
|
+
stateFor
|
|
99
|
+
}
|
|
100
|
+
),
|
|
101
|
+
selected && /* @__PURE__ */ jsx(
|
|
102
|
+
KeyphraseDetail,
|
|
103
|
+
{
|
|
104
|
+
analysis,
|
|
105
|
+
duplicate: isDuplicate(selected.id, selected.text),
|
|
106
|
+
entry: selected,
|
|
107
|
+
isFocus: selectedIsFocus,
|
|
108
|
+
onAddSynonym: (syn) => onAddSynonym(selected.id, syn),
|
|
109
|
+
onRemove: () => onRemove(selected.id),
|
|
110
|
+
onRemoveSynonym: (index) => onRemoveSynonym(selected.id, index),
|
|
111
|
+
onSetFocus: () => onSetFocus(selected.id),
|
|
112
|
+
onTextChange: (text) => onTextChange(selected.id, text)
|
|
113
|
+
}
|
|
114
|
+
)
|
|
74
115
|
] });
|
|
75
116
|
}
|
|
76
117
|
export {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../src/components/SeoDrawer/tabs/KeyphraseTab.tsx"],"sourcesContent":["\"use client\";\n\nimport {
|
|
1
|
+
{"version":3,"sources":["../../../../src/components/SeoDrawer/tabs/KeyphraseTab.tsx"],"sourcesContent":["\"use client\";\n\nimport { useRef } from \"react\";\nimport type { AnalysisResult, CategoryResult } from \"../../../engine/types/analysis\";\nimport type { KeyphraseEntry } from \"../keyphraseState\";\nimport type { CardState } from \"./keyphrase/KeyphraseCard\";\nimport { KeyphraseDetail } from \"./keyphrase/KeyphraseDetail\";\nimport type { DetailAnalysis } from \"./keyphrase/KeyphraseDetail\";\nimport { KeyphraseRail } from \"./keyphrase/KeyphraseRail\";\n\nexport interface KeyphraseTabProps {\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}\n\nfunction resultForEntry(\n entry: KeyphraseEntry,\n isFocus: boolean,\n result: AnalysisResult | null\n): CategoryResult | undefined {\n if (!result) return undefined;\n if (isFocus) return result.keyphraseText === entry.text ? result.keyphrase : undefined;\n return result.relatedKeyphrases.find((r) => r.text === entry.text)?.result;\n}\n\nexport function KeyphraseTab({\n keyphrases,\n selectedId: selectedIdProp,\n onSelect,\n result,\n analyzing,\n onAddRelated,\n onTextChange,\n onAddSynonym,\n onRemoveSynonym,\n onRemove,\n onSetFocus,\n isDuplicate,\n}: KeyphraseTabProps) {\n const selectedId = selectedIdProp ?? keyphrases[0]?.id ?? null;\n const selected = keyphrases.find((k) => k.id === selectedId) ?? keyphrases[0] ?? null;\n const selectedIsFocus = selected ? keyphrases.indexOf(selected) === 0 : true;\n\n const lastMetrics = useRef<Map<string, CategoryResult>>(new Map());\n const liveIds = new Set(keyphrases.map((k) => k.id));\n\n for (const id of [...lastMetrics.current.keys()]) {\n if (!liveIds.has(id)) lastMetrics.current.delete(id);\n }\n\n keyphrases.forEach((entry, index) => {\n if (entry.text.trim() === \"\") {\n lastMetrics.current.delete(entry.id);\n return;\n }\n const fresh = resultForEntry(entry, index === 0, result);\n if (fresh) lastMetrics.current.set(entry.id, fresh);\n });\n\n const stateFor = (entry: KeyphraseEntry): CardState => {\n if (!entry.text.trim()) return { kind: \"idle\" };\n\n const isFocus = keyphrases.indexOf(entry) === 0;\n if (!isFocus && isDuplicate(entry.id, entry.text)) return { kind: \"idle\" };\n\n const category = resultForEntry(entry, isFocus, result);\n if (category) return { kind: \"score\", score: category.ringScore, status: category.status };\n\n return { kind: \"analyzing\" };\n };\n\n const detailAnalysis = (): DetailAnalysis => {\n if (!selected) return { kind: \"hint\", message: \"\" };\n\n if (isDuplicate(selected.id, selected.text)) {\n return {\n kind: \"hint\",\n message: \"Resolve the duplicate to analyse this keyphrase.\",\n };\n }\n\n if (!selected.text.trim()) {\n return {\n kind: \"hint\",\n message: \"Start typing a keyphrase to see its analysis.\",\n };\n }\n\n const category = resultForEntry(selected, selectedIsFocus, result);\n if (category) {\n return {\n kind: \"metrics\",\n result: category,\n dim: analyzing,\n };\n }\n\n const previous = lastMetrics.current.get(selected.id);\n if (previous) {\n return {\n kind: \"metrics\",\n result: previous,\n dim: true,\n };\n }\n\n return { kind: \"analyzing\" };\n };\n\n const analysis = detailAnalysis();\n\n return (\n <div className=\"flex min-h-[420px]\">\n <KeyphraseRail\n entries={keyphrases}\n onAdd={onAddRelated}\n onSelect={onSelect}\n selectedId={selectedId}\n stateFor={stateFor}\n />\n\n {selected && (\n <KeyphraseDetail\n analysis={analysis}\n duplicate={isDuplicate(selected.id, selected.text)}\n entry={selected}\n isFocus={selectedIsFocus}\n onAddSynonym={(syn) => onAddSynonym(selected.id, syn)}\n onRemove={() => onRemove(selected.id)}\n onRemoveSynonym={(index) => onRemoveSynonym(selected.id, index)}\n onSetFocus={() => onSetFocus(selected.id)}\n onTextChange={(text) => onTextChange(selected.id, text)}\n />\n )}\n </div>\n );\n}\n"],"mappings":"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","names":[]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"OnPageTab.d.ts","sourceRoot":"","sources":["../../../../src/components/SeoDrawer/tabs/OnPageTab.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,gCAAgC,CAAC;
|
|
1
|
+
{"version":3,"file":"OnPageTab.d.ts","sourceRoot":"","sources":["../../../../src/components/SeoDrawer/tabs/OnPageTab.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,gCAAgC,CAAC;AASrE,wBAAgB,SAAS,CAAC,EAAE,IAAI,EAAE,EAAE;IAAE,IAAI,EAAE,cAAc,CAAA;CAAE,2CA4B3D"}
|
|
@@ -6,11 +6,12 @@ import { SectionCard } from "../../../ui/SectionCard";
|
|
|
6
6
|
import { Pill } from "../../../ui/Pill";
|
|
7
7
|
import { FilterPills } from "../../../ui/FilterPills";
|
|
8
8
|
import { CheckRow } from "../../../ui/CheckRow";
|
|
9
|
+
import { TabWrapper } from "../components/TabWrapper";
|
|
9
10
|
function OnPageTab({ data }) {
|
|
10
11
|
const [filter, setFilter] = useState("all");
|
|
11
12
|
const visible = data.checks.filter((c) => filter === "all" || c.status === filter);
|
|
12
13
|
const passing = data.checks.filter((c) => c.status === "good").length;
|
|
13
|
-
return /* @__PURE__ */ jsxs("section", { className: "flex flex-col gap-[13px]", children: [
|
|
14
|
+
return /* @__PURE__ */ jsx(TabWrapper, { children: /* @__PURE__ */ jsxs("section", { className: "flex flex-col gap-[13px]", children: [
|
|
14
15
|
/* @__PURE__ */ jsx(
|
|
15
16
|
TabHeader,
|
|
16
17
|
{
|
|
@@ -29,7 +30,7 @@ function OnPageTab({ data }) {
|
|
|
29
30
|
/* @__PURE__ */ jsx(FilterPills, { checks: data.checks, value: filter, onChange: setFilter }),
|
|
30
31
|
visible.map((c) => /* @__PURE__ */ jsx(CheckRow, { check: c }, c.id))
|
|
31
32
|
] })
|
|
32
|
-
] });
|
|
33
|
+
] }) });
|
|
33
34
|
}
|
|
34
35
|
export {
|
|
35
36
|
OnPageTab
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../src/components/SeoDrawer/tabs/OnPageTab.tsx"],"sourcesContent":["\"use client\";\n\nimport { useState } from \"react\";\nimport type { CategoryResult } from \"../../../engine/types/analysis\";\nimport { TabHeader } from \"../../../ui/TabHeader\";\nimport { SectionCard } from \"../../../ui/SectionCard\";\nimport { Pill } from \"../../../ui/Pill\";\nimport { FilterPills } from \"../../../ui/FilterPills\";\nimport type { Filter } from \"../../../ui/FilterPills\";\nimport { CheckRow } from \"../../../ui/CheckRow\";\n\nexport function OnPageTab({ data }: { data: CategoryResult }) {\n const [filter, setFilter] = useState<Filter>(\"all\");\n const visible = data.checks.filter((c) => filter === \"all\" || c.status === filter);\n const passing = data.checks.filter((c) => c.status === \"good\").length;\n\n return (\n <section className=\"flex flex-col gap-[13px]\">\n
|
|
1
|
+
{"version":3,"sources":["../../../../src/components/SeoDrawer/tabs/OnPageTab.tsx"],"sourcesContent":["\"use client\";\n\nimport { useState } from \"react\";\nimport type { CategoryResult } from \"../../../engine/types/analysis\";\nimport { TabHeader } from \"../../../ui/TabHeader\";\nimport { SectionCard } from \"../../../ui/SectionCard\";\nimport { Pill } from \"../../../ui/Pill\";\nimport { FilterPills } from \"../../../ui/FilterPills\";\nimport type { Filter } from \"../../../ui/FilterPills\";\nimport { CheckRow } from \"../../../ui/CheckRow\";\nimport { TabWrapper } from \"../components/TabWrapper\";\n\nexport function OnPageTab({ data }: { data: CategoryResult }) {\n const [filter, setFilter] = useState<Filter>(\"all\");\n const visible = data.checks.filter((c) => filter === \"all\" || c.status === filter);\n const passing = data.checks.filter((c) => c.status === \"good\").length;\n\n return (\n <TabWrapper>\n <section className=\"flex flex-col gap-[13px]\">\n <TabHeader\n title=\"On-page structure\"\n score={data.ringScore}\n status={data.status}\n subtitle={\n <>\n {passing} / {data.checks.length} checks passing\n </>\n }\n />\n\n <SectionCard title=\"Checks\" widget={<Pill variant=\"neutral\">{data.checks.length}</Pill>}>\n <FilterPills checks={data.checks} value={filter} onChange={setFilter} />\n {visible.map((c) => (\n <CheckRow key={c.id} check={c} />\n ))}\n </SectionCard>\n </section>\n </TabWrapper>\n );\n}\n"],"mappings":";AAoBQ,SAKI,UALJ,KAKI,YALJ;AAlBR,SAAS,gBAAgB;AAEzB,SAAS,iBAAiB;AAC1B,SAAS,mBAAmB;AAC5B,SAAS,YAAY;AACrB,SAAS,mBAAmB;AAE5B,SAAS,gBAAgB;AACzB,SAAS,kBAAkB;AAEpB,SAAS,UAAU,EAAE,KAAK,GAA6B;AAC5D,QAAM,CAAC,QAAQ,SAAS,IAAI,SAAiB,KAAK;AAClD,QAAM,UAAU,KAAK,OAAO,OAAO,CAAC,MAAM,WAAW,SAAS,EAAE,WAAW,MAAM;AACjF,QAAM,UAAU,KAAK,OAAO,OAAO,CAAC,MAAM,EAAE,WAAW,MAAM,EAAE;AAE/D,SACE,oBAAC,cACC,+BAAC,aAAQ,WAAU,4BACjB;AAAA;AAAA,MAAC;AAAA;AAAA,QACC,OAAM;AAAA,QACN,OAAO,KAAK;AAAA,QACZ,QAAQ,KAAK;AAAA,QACb,UACE,iCACG;AAAA;AAAA,UAAQ;AAAA,UAAI,KAAK,OAAO;AAAA,UAAO;AAAA,WAClC;AAAA;AAAA,IAEJ;AAAA,IAEA,qBAAC,eAAY,OAAM,UAAS,QAAQ,oBAAC,QAAK,SAAQ,WAAW,eAAK,OAAO,QAAO,GAC9E;AAAA,0BAAC,eAAY,QAAQ,KAAK,QAAQ,OAAO,QAAQ,UAAU,WAAW;AAAA,MACrE,QAAQ,IAAI,CAAC,MACZ,oBAAC,YAAoB,OAAO,KAAb,EAAE,EAAc,CAChC;AAAA,OACH;AAAA,KACF,GACF;AAEJ;","names":[]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ReadabilityTab.d.ts","sourceRoot":"","sources":["../../../../src/components/SeoDrawer/tabs/ReadabilityTab.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,gCAAgC,CAAC;
|
|
1
|
+
{"version":3,"file":"ReadabilityTab.d.ts","sourceRoot":"","sources":["../../../../src/components/SeoDrawer/tabs/ReadabilityTab.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,gCAAgC,CAAC;AASrE,wBAAgB,cAAc,CAAC,EAAE,IAAI,EAAE,EAAE;IAAE,IAAI,EAAE,cAAc,CAAA;CAAE,2CA4BhE"}
|
|
@@ -6,11 +6,12 @@ import { SectionCard } from "../../../ui/SectionCard";
|
|
|
6
6
|
import { Pill } from "../../../ui/Pill";
|
|
7
7
|
import { FilterPills } from "../../../ui/FilterPills";
|
|
8
8
|
import { CheckRow } from "../../../ui/CheckRow";
|
|
9
|
+
import { TabWrapper } from "../components/TabWrapper";
|
|
9
10
|
function ReadabilityTab({ data }) {
|
|
10
11
|
const [filter, setFilter] = useState("all");
|
|
11
12
|
const visible = data.checks.filter((c) => filter === "all" || c.status === filter);
|
|
12
13
|
const passing = data.checks.filter((c) => c.status === "good").length;
|
|
13
|
-
return /* @__PURE__ */ jsxs("section", { className: "flex flex-col gap-[13px]", children: [
|
|
14
|
+
return /* @__PURE__ */ jsx(TabWrapper, { children: /* @__PURE__ */ jsxs("section", { className: "flex flex-col gap-[13px]", children: [
|
|
14
15
|
/* @__PURE__ */ jsx(
|
|
15
16
|
TabHeader,
|
|
16
17
|
{
|
|
@@ -29,7 +30,7 @@ function ReadabilityTab({ data }) {
|
|
|
29
30
|
/* @__PURE__ */ jsx(FilterPills, { checks: data.checks, value: filter, onChange: setFilter }),
|
|
30
31
|
visible.map((c) => /* @__PURE__ */ jsx(CheckRow, { check: c }, c.id))
|
|
31
32
|
] })
|
|
32
|
-
] });
|
|
33
|
+
] }) });
|
|
33
34
|
}
|
|
34
35
|
export {
|
|
35
36
|
ReadabilityTab
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../src/components/SeoDrawer/tabs/ReadabilityTab.tsx"],"sourcesContent":["\"use client\";\n\nimport { useState } from \"react\";\nimport type { CategoryResult } from \"../../../engine/types/analysis\";\nimport { TabHeader } from \"../../../ui/TabHeader\";\nimport { SectionCard } from \"../../../ui/SectionCard\";\nimport { Pill } from \"../../../ui/Pill\";\nimport { FilterPills } from \"../../../ui/FilterPills\";\nimport type { Filter } from \"../../../ui/FilterPills\";\nimport { CheckRow } from \"../../../ui/CheckRow\";\n\nexport function ReadabilityTab({ data }: { data: CategoryResult }) {\n const [filter, setFilter] = useState<Filter>(\"all\");\n const visible = data.checks.filter((c) => filter === \"all\" || c.status === filter);\n const passing = data.checks.filter((c) => c.status === \"good\").length;\n\n return (\n <section className=\"flex flex-col gap-[13px]\">\n
|
|
1
|
+
{"version":3,"sources":["../../../../src/components/SeoDrawer/tabs/ReadabilityTab.tsx"],"sourcesContent":["\"use client\";\n\nimport { useState } from \"react\";\nimport type { CategoryResult } from \"../../../engine/types/analysis\";\nimport { TabHeader } from \"../../../ui/TabHeader\";\nimport { SectionCard } from \"../../../ui/SectionCard\";\nimport { Pill } from \"../../../ui/Pill\";\nimport { FilterPills } from \"../../../ui/FilterPills\";\nimport type { Filter } from \"../../../ui/FilterPills\";\nimport { CheckRow } from \"../../../ui/CheckRow\";\nimport { TabWrapper } from \"../components/TabWrapper\";\n\nexport function ReadabilityTab({ data }: { data: CategoryResult }) {\n const [filter, setFilter] = useState<Filter>(\"all\");\n const visible = data.checks.filter((c) => filter === \"all\" || c.status === filter);\n const passing = data.checks.filter((c) => c.status === \"good\").length;\n\n return (\n <TabWrapper>\n <section className=\"flex flex-col gap-[13px]\">\n <TabHeader\n title=\"Readability\"\n score={data.ringScore}\n status={data.status}\n subtitle={\n <>\n {passing} / {data.checks.length} checks passing\n </>\n }\n />\n\n <SectionCard title=\"Checks\" widget={<Pill variant=\"neutral\">{data.checks.length}</Pill>}>\n <FilterPills checks={data.checks} value={filter} onChange={setFilter} />\n {visible.map((c) => (\n <CheckRow key={c.id} check={c} />\n ))}\n </SectionCard>\n </section>\n </TabWrapper>\n );\n}\n"],"mappings":";AAoBQ,SAKI,UALJ,KAKI,YALJ;AAlBR,SAAS,gBAAgB;AAEzB,SAAS,iBAAiB;AAC1B,SAAS,mBAAmB;AAC5B,SAAS,YAAY;AACrB,SAAS,mBAAmB;AAE5B,SAAS,gBAAgB;AACzB,SAAS,kBAAkB;AAEpB,SAAS,eAAe,EAAE,KAAK,GAA6B;AACjE,QAAM,CAAC,QAAQ,SAAS,IAAI,SAAiB,KAAK;AAClD,QAAM,UAAU,KAAK,OAAO,OAAO,CAAC,MAAM,WAAW,SAAS,EAAE,WAAW,MAAM;AACjF,QAAM,UAAU,KAAK,OAAO,OAAO,CAAC,MAAM,EAAE,WAAW,MAAM,EAAE;AAE/D,SACE,oBAAC,cACC,+BAAC,aAAQ,WAAU,4BACjB;AAAA;AAAA,MAAC;AAAA;AAAA,QACC,OAAM;AAAA,QACN,OAAO,KAAK;AAAA,QACZ,QAAQ,KAAK;AAAA,QACb,UACE,iCACG;AAAA;AAAA,UAAQ;AAAA,UAAI,KAAK,OAAO;AAAA,UAAO;AAAA,WAClC;AAAA;AAAA,IAEJ;AAAA,IAEA,qBAAC,eAAY,OAAM,UAAS,QAAQ,oBAAC,QAAK,SAAQ,WAAW,eAAK,OAAO,QAAO,GAC9E;AAAA,0BAAC,eAAY,QAAQ,KAAK,QAAQ,OAAO,QAAQ,UAAU,WAAW;AAAA,MACrE,QAAQ,IAAI,CAAC,MACZ,oBAAC,YAAoB,OAAO,KAAb,EAAE,EAAc,CAChC;AAAA,OACH;AAAA,KACF,GACF;AAEJ;","names":[]}
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import type { SerpResult } from "../../../engine/types/analysis";
|
|
2
|
-
export declare function SerpTab({ data, keyphrase, faviconUrl, }: {
|
|
2
|
+
export declare function SerpTab({ data, keyphrase, synonyms, faviconUrl, }: {
|
|
3
3
|
data: SerpResult;
|
|
4
4
|
keyphrase: string;
|
|
5
|
+
synonyms?: string[];
|
|
5
6
|
faviconUrl: string;
|
|
6
7
|
}): import("react/jsx-runtime").JSX.Element;
|
|
7
8
|
//# sourceMappingURL=SerpTab.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SerpTab.d.ts","sourceRoot":"","sources":["../../../../src/components/SeoDrawer/tabs/SerpTab.tsx"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,gCAAgC,CAAC;
|
|
1
|
+
{"version":3,"file":"SerpTab.d.ts","sourceRoot":"","sources":["../../../../src/components/SeoDrawer/tabs/SerpTab.tsx"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,gCAAgC,CAAC;AAOjE,wBAAgB,OAAO,CAAC,EACtB,IAAI,EACJ,SAAS,EACT,QAAa,EACb,UAAU,GACX,EAAE;IACD,IAAI,EAAE,UAAU,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;CACpB,2CAyCA"}
|
|
@@ -5,13 +5,15 @@ import { useState } from "react";
|
|
|
5
5
|
import { SectionCard } from "../../../ui/SectionCard";
|
|
6
6
|
import { SegmentedControl } from "../../../ui/SegmentedControl";
|
|
7
7
|
import { SerpPreview } from "../components/SerpPreview";
|
|
8
|
+
import { TabWrapper } from "../components/TabWrapper";
|
|
8
9
|
function SerpTab({
|
|
9
10
|
data,
|
|
10
11
|
keyphrase,
|
|
12
|
+
synonyms = [],
|
|
11
13
|
faviconUrl
|
|
12
14
|
}) {
|
|
13
15
|
const [mode, setMode] = useState("mobile");
|
|
14
|
-
return /* @__PURE__ */ jsx("section", { className: "flex flex-col gap-[13px]", children: /* @__PURE__ */ jsx(
|
|
16
|
+
return /* @__PURE__ */ jsx(TabWrapper, { children: /* @__PURE__ */ jsx("section", { className: "flex flex-col gap-[13px]", children: /* @__PURE__ */ jsx(
|
|
15
17
|
SectionCard,
|
|
16
18
|
{
|
|
17
19
|
title: "Search result preview",
|
|
@@ -35,9 +37,18 @@ function SerpTab({
|
|
|
35
37
|
label: "Preview device"
|
|
36
38
|
}
|
|
37
39
|
),
|
|
38
|
-
children: /* @__PURE__ */ jsx("div", { className: "p-4", children: /* @__PURE__ */ jsx(
|
|
40
|
+
children: /* @__PURE__ */ jsx("div", { className: "p-4", children: /* @__PURE__ */ jsx(
|
|
41
|
+
SerpPreview,
|
|
42
|
+
{
|
|
43
|
+
data,
|
|
44
|
+
keyphrase,
|
|
45
|
+
synonyms,
|
|
46
|
+
faviconUrl,
|
|
47
|
+
mode
|
|
48
|
+
}
|
|
49
|
+
) })
|
|
39
50
|
}
|
|
40
|
-
) });
|
|
51
|
+
) }) });
|
|
41
52
|
}
|
|
42
53
|
export {
|
|
43
54
|
SerpTab
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../src/components/SeoDrawer/tabs/SerpTab.tsx"],"sourcesContent":["\"use client\";\n\nimport { Monitor, Smartphone } from \"lucide-react\";\nimport { useState } from \"react\";\n\nimport type { SerpResult } from \"../../../engine/types/analysis\";\nimport { SectionCard } from \"../../../ui/SectionCard\";\nimport { SegmentedControl } from \"../../../ui/SegmentedControl\";\nimport { SerpPreview } from \"../components/SerpPreview\";\nimport type { SerpMode } from \"../components/SerpPreview\";\n\nexport function SerpTab({\n data,\n keyphrase,\n faviconUrl,\n}: {\n data: SerpResult;\n keyphrase: string;\n faviconUrl: string;\n}) {\n const [mode, setMode] = useState<SerpMode>(\"mobile\");\n\n return (\n <section className=\"flex flex-col gap-[13px]\">\n
|
|
1
|
+
{"version":3,"sources":["../../../../src/components/SeoDrawer/tabs/SerpTab.tsx"],"sourcesContent":["\"use client\";\n\nimport { Monitor, Smartphone } from \"lucide-react\";\nimport { useState } from \"react\";\n\nimport type { SerpResult } from \"../../../engine/types/analysis\";\nimport { SectionCard } from \"../../../ui/SectionCard\";\nimport { SegmentedControl } from \"../../../ui/SegmentedControl\";\nimport { SerpPreview } from \"../components/SerpPreview\";\nimport type { SerpMode } from \"../components/SerpPreview\";\nimport { TabWrapper } from \"../components/TabWrapper\";\n\nexport function SerpTab({\n data,\n keyphrase,\n synonyms = [],\n faviconUrl,\n}: {\n data: SerpResult;\n keyphrase: string;\n synonyms?: string[];\n faviconUrl: string;\n}) {\n const [mode, setMode] = useState<SerpMode>(\"mobile\");\n\n return (\n <TabWrapper>\n <section className=\"flex flex-col gap-[13px]\">\n <SectionCard\n title=\"Search result preview\"\n widget={\n <SegmentedControl\n options={[\n {\n value: \"mobile\",\n label: \"Mobile\",\n icon: <Smartphone aria-hidden=\"true\" className=\"w-[13px] h-[13px]\" />,\n },\n {\n value: \"desktop\",\n label: \"Desktop\",\n icon: <Monitor aria-hidden=\"true\" className=\"w-[13px] h-[13px]\" />,\n },\n ]}\n value={mode}\n onChange={setMode}\n label=\"Preview device\"\n />\n }\n >\n <div className=\"p-4\">\n <SerpPreview\n data={data}\n keyphrase={keyphrase}\n synonyms={synonyms}\n faviconUrl={faviconUrl}\n mode={mode}\n />\n </div>\n </SectionCard>\n </section>\n </TabWrapper>\n );\n}\n"],"mappings":";AAoCwB;AAlCxB,SAAS,SAAS,kBAAkB;AACpC,SAAS,gBAAgB;AAGzB,SAAS,mBAAmB;AAC5B,SAAS,wBAAwB;AACjC,SAAS,mBAAmB;AAE5B,SAAS,kBAAkB;AAEpB,SAAS,QAAQ;AAAA,EACtB;AAAA,EACA;AAAA,EACA,WAAW,CAAC;AAAA,EACZ;AACF,GAKG;AACD,QAAM,CAAC,MAAM,OAAO,IAAI,SAAmB,QAAQ;AAEnD,SACE,oBAAC,cACC,8BAAC,aAAQ,WAAU,4BACjB;AAAA,IAAC;AAAA;AAAA,MACC,OAAM;AAAA,MACN,QACE;AAAA,QAAC;AAAA;AAAA,UACC,SAAS;AAAA,YACP;AAAA,cACE,OAAO;AAAA,cACP,OAAO;AAAA,cACP,MAAM,oBAAC,cAAW,eAAY,QAAO,WAAU,qBAAoB;AAAA,YACrE;AAAA,YACA;AAAA,cACE,OAAO;AAAA,cACP,OAAO;AAAA,cACP,MAAM,oBAAC,WAAQ,eAAY,QAAO,WAAU,qBAAoB;AAAA,YAClE;AAAA,UACF;AAAA,UACA,OAAO;AAAA,UACP,UAAU;AAAA,UACV,OAAM;AAAA;AAAA,MACR;AAAA,MAGF,8BAAC,SAAI,WAAU,OACb;AAAA,QAAC;AAAA;AAAA,UACC;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA;AAAA,MACF,GACF;AAAA;AAAA,EACF,GACF,GACF;AAEJ;","names":[]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"VitalsTab.d.ts","sourceRoot":"","sources":["../../../../src/components/SeoDrawer/tabs/VitalsTab.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,gCAAgC,CAAC;
|
|
1
|
+
{"version":3,"file":"VitalsTab.d.ts","sourceRoot":"","sources":["../../../../src/components/SeoDrawer/tabs/VitalsTab.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,gCAAgC,CAAC;AAQnE,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,YAAY,CAAC;IACnB,kBAAkB,EAAE,MAAM,IAAI,CAAC;CAChC;AAED,wBAAgB,SAAS,CAAC,EAAE,IAAI,EAAE,kBAAkB,EAAE,EAAE,cAAc,2CAkErE"}
|
|
@@ -5,10 +5,11 @@ import { KpiCard } from "../../../ui/KpiCard";
|
|
|
5
5
|
import { SectionCard } from "../../../ui/SectionCard";
|
|
6
6
|
import { Pill } from "../../../ui/Pill";
|
|
7
7
|
import { HeadingsSection } from "../components/HeadingsSection";
|
|
8
|
+
import { TabWrapper } from "../components/TabWrapper";
|
|
8
9
|
function VitalsTab({ data, onRequestKeyphrase }) {
|
|
9
10
|
const max = Math.max(1, ...data.prominentWords.map((w) => w.count));
|
|
10
11
|
const noKeyphraseMatch = data.prominentWords.every((w) => !w.isKeyphrase);
|
|
11
|
-
return /* @__PURE__ */ jsxs("section", { className: "flex flex-col gap-[13px]", children: [
|
|
12
|
+
return /* @__PURE__ */ jsx(TabWrapper, { children: /* @__PURE__ */ jsxs("section", { className: "flex flex-col gap-[13px]", children: [
|
|
12
13
|
/* @__PURE__ */ jsxs("div", { className: "grid grid-cols-3 gap-[9px]", children: [
|
|
13
14
|
/* @__PURE__ */ jsx(KpiCard, { label: "Words", value: data.words.toLocaleString() }),
|
|
14
15
|
/* @__PURE__ */ jsx(KpiCard, { label: "Sentences", value: data.sentences }),
|
|
@@ -39,7 +40,10 @@ function VitalsTab({ data, onRequestKeyphrase }) {
|
|
|
39
40
|
/* @__PURE__ */ jsx("div", { className: "flex-1 h-[6px] rounded-[3px] bg-neutral-100 overflow-hidden", children: /* @__PURE__ */ jsx(
|
|
40
41
|
"i",
|
|
41
42
|
{
|
|
42
|
-
className: cn(
|
|
43
|
+
className: cn(
|
|
44
|
+
"block h-full",
|
|
45
|
+
w.isKeyphrase ? "bg-neutral-1000" : "bg-neutral-400"
|
|
46
|
+
),
|
|
43
47
|
style: { width: `${w.count / max * 100}%` }
|
|
44
48
|
}
|
|
45
49
|
) }),
|
|
@@ -59,7 +63,7 @@ function VitalsTab({ data, onRequestKeyphrase }) {
|
|
|
59
63
|
children: "Set a focus keyphrase to see which prominent words match it"
|
|
60
64
|
}
|
|
61
65
|
)
|
|
62
|
-
] });
|
|
66
|
+
] }) });
|
|
63
67
|
}
|
|
64
68
|
export {
|
|
65
69
|
VitalsTab
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../src/components/SeoDrawer/tabs/VitalsTab.tsx"],"sourcesContent":["\"use client\";\n\nimport type { VitalsResult } from \"../../../engine/types/analysis\";\nimport { cn, ROW_SEPARATOR } from \"../../../utils/style\";\nimport { KpiCard } from \"../../../ui/KpiCard\";\nimport { SectionCard } from \"../../../ui/SectionCard\";\nimport { Pill } from \"../../../ui/Pill\";\nimport { HeadingsSection } from \"../components/HeadingsSection\";\n\nexport interface VitalsTabProps {\n data: VitalsResult;\n onRequestKeyphrase: () => void;\n}\n\nexport function VitalsTab({ data, onRequestKeyphrase }: VitalsTabProps) {\n const max = Math.max(1, ...data.prominentWords.map((w) => w.count));\n const noKeyphraseMatch = data.prominentWords.every((w) => !w.isKeyphrase);\n\n return (\n <section className=\"flex flex-col gap-[13px]\">\n
|
|
1
|
+
{"version":3,"sources":["../../../../src/components/SeoDrawer/tabs/VitalsTab.tsx"],"sourcesContent":["\"use client\";\n\nimport type { VitalsResult } from \"../../../engine/types/analysis\";\nimport { cn, ROW_SEPARATOR } from \"../../../utils/style\";\nimport { KpiCard } from \"../../../ui/KpiCard\";\nimport { SectionCard } from \"../../../ui/SectionCard\";\nimport { Pill } from \"../../../ui/Pill\";\nimport { HeadingsSection } from \"../components/HeadingsSection\";\nimport { TabWrapper } from \"../components/TabWrapper\";\n\nexport interface VitalsTabProps {\n data: VitalsResult;\n onRequestKeyphrase: () => void;\n}\n\nexport function VitalsTab({ data, onRequestKeyphrase }: VitalsTabProps) {\n const max = Math.max(1, ...data.prominentWords.map((w) => w.count));\n const noKeyphraseMatch = data.prominentWords.every((w) => !w.isKeyphrase);\n\n return (\n <TabWrapper>\n <section className=\"flex flex-col gap-[13px]\">\n <div className=\"grid grid-cols-3 gap-[9px]\">\n <KpiCard label=\"Words\" value={data.words.toLocaleString()} />\n <KpiCard label=\"Sentences\" value={data.sentences} />\n <KpiCard label=\"Paragraphs\" value={data.paragraphs} />\n <KpiCard label=\"Images\" value={data.images} />\n <KpiCard label=\"Videos\" value={data.videos} />\n <KpiCard label=\"Reading time\" value={data.readingTimeMinutes} suffix=\"min\" />\n </div>\n\n <HeadingsSection data={data.headings} />\n\n <SectionCard\n title=\"Prominent words\"\n widget={<Pill variant=\"neutral\">{data.prominentWords.length}</Pill>}\n >\n {data.prominentWords.map((w) => (\n <div\n className={cn(\n \"relative flex items-center gap-[12px] px-[15px] py-[9px]\",\n ROW_SEPARATOR\n )}\n key={w.word}\n >\n <div className=\"w-[120px] flex-none text-[12px] font-medium flex items-center gap-[6px]\">\n {w.word}{\" \"}\n {w.isKeyphrase && (\n <span className=\"text-[9px] font-bold uppercase tracking-[0.04em] text-neutral-1000 bg-neutral-150 rounded-[3px] px-[5px] py-[1px]\">\n Key\n </span>\n )}\n </div>\n <div className=\"flex-1 h-[6px] rounded-[3px] bg-neutral-100 overflow-hidden\">\n <i\n className={cn(\n \"block h-full\",\n w.isKeyphrase ? \"bg-neutral-1000\" : \"bg-neutral-400\"\n )}\n style={{ width: `${(w.count / max) * 100}%` }}\n />\n </div>\n <div className=\"w-[30px] text-right font-mono text-[11px] font-semibold text-neutral-700\">\n {w.count}\n </div>\n </div>\n ))}\n </SectionCard>\n\n {noKeyphraseMatch && (\n <button\n type=\"button\"\n onClick={onRequestKeyphrase}\n className=\"self-start text-[12px] text-neutral-600 underline underline-offset-2 hover:text-neutral-800 cursor-pointer bg-transparent border-0 p-0\"\n >\n Set a focus keyphrase to see which prominent words match it\n </button>\n )}\n </section>\n </TabWrapper>\n );\n}\n"],"mappings":";AAsBQ,SACE,KADF;AAnBR,SAAS,IAAI,qBAAqB;AAClC,SAAS,eAAe;AACxB,SAAS,mBAAmB;AAC5B,SAAS,YAAY;AACrB,SAAS,uBAAuB;AAChC,SAAS,kBAAkB;AAOpB,SAAS,UAAU,EAAE,MAAM,mBAAmB,GAAmB;AACtE,QAAM,MAAM,KAAK,IAAI,GAAG,GAAG,KAAK,eAAe,IAAI,CAAC,MAAM,EAAE,KAAK,CAAC;AAClE,QAAM,mBAAmB,KAAK,eAAe,MAAM,CAAC,MAAM,CAAC,EAAE,WAAW;AAExE,SACE,oBAAC,cACC,+BAAC,aAAQ,WAAU,4BACjB;AAAA,yBAAC,SAAI,WAAU,8BACb;AAAA,0BAAC,WAAQ,OAAM,SAAQ,OAAO,KAAK,MAAM,eAAe,GAAG;AAAA,MAC3D,oBAAC,WAAQ,OAAM,aAAY,OAAO,KAAK,WAAW;AAAA,MAClD,oBAAC,WAAQ,OAAM,cAAa,OAAO,KAAK,YAAY;AAAA,MACpD,oBAAC,WAAQ,OAAM,UAAS,OAAO,KAAK,QAAQ;AAAA,MAC5C,oBAAC,WAAQ,OAAM,UAAS,OAAO,KAAK,QAAQ;AAAA,MAC5C,oBAAC,WAAQ,OAAM,gBAAe,OAAO,KAAK,oBAAoB,QAAO,OAAM;AAAA,OAC7E;AAAA,IAEA,oBAAC,mBAAgB,MAAM,KAAK,UAAU;AAAA,IAEtC;AAAA,MAAC;AAAA;AAAA,QACC,OAAM;AAAA,QACN,QAAQ,oBAAC,QAAK,SAAQ,WAAW,eAAK,eAAe,QAAO;AAAA,QAE3D,eAAK,eAAe,IAAI,CAAC,MACxB;AAAA,UAAC;AAAA;AAAA,YACC,WAAW;AAAA,cACT;AAAA,cACA;AAAA,YACF;AAAA,YAGA;AAAA,mCAAC,SAAI,WAAU,2EACZ;AAAA,kBAAE;AAAA,gBAAM;AAAA,gBACR,EAAE,eACD,oBAAC,UAAK,WAAU,qHAAoH,iBAEpI;AAAA,iBAEJ;AAAA,cACA,oBAAC,SAAI,WAAU,+DACb;AAAA,gBAAC;AAAA;AAAA,kBACC,WAAW;AAAA,oBACT;AAAA,oBACA,EAAE,cAAc,oBAAoB;AAAA,kBACtC;AAAA,kBACA,OAAO,EAAE,OAAO,GAAI,EAAE,QAAQ,MAAO,GAAG,IAAI;AAAA;AAAA,cAC9C,GACF;AAAA,cACA,oBAAC,SAAI,WAAU,4EACZ,YAAE,OACL;AAAA;AAAA;AAAA,UArBK,EAAE;AAAA,QAsBT,CACD;AAAA;AAAA,IACH;AAAA,IAEC,oBACC;AAAA,MAAC;AAAA;AAAA,QACC,MAAK;AAAA,QACL,SAAS;AAAA,QACT,WAAU;AAAA,QACX;AAAA;AAAA,IAED;AAAA,KAEJ,GACF;AAEJ;","names":[]}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { Status } from "../../../../engine/types/analysis";
|
|
2
|
+
import type { KeyphraseEntry } from "../../keyphraseState";
|
|
3
|
+
export type CardState = {
|
|
4
|
+
kind: "score";
|
|
5
|
+
score: number;
|
|
6
|
+
status: Status;
|
|
7
|
+
} | {
|
|
8
|
+
kind: "analyzing";
|
|
9
|
+
} | {
|
|
10
|
+
kind: "idle";
|
|
11
|
+
};
|
|
12
|
+
interface KeyphraseCardProps {
|
|
13
|
+
entry: KeyphraseEntry;
|
|
14
|
+
isFocus: boolean;
|
|
15
|
+
selected: boolean;
|
|
16
|
+
state: CardState;
|
|
17
|
+
onSelect: (id: string) => void;
|
|
18
|
+
}
|
|
19
|
+
export declare function KeyphraseCard({ entry, isFocus, selected, state, onSelect }: KeyphraseCardProps): import("react/jsx-runtime").JSX.Element;
|
|
20
|
+
export {};
|
|
21
|
+
//# sourceMappingURL=KeyphraseCard.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"KeyphraseCard.d.ts","sourceRoot":"","sources":["../../../../../src/components/SeoDrawer/tabs/keyphrase/KeyphraseCard.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,mCAAmC,CAAC;AAGhE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAE3D,MAAM,MAAM,SAAS,GACjB;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GAChD;IAAE,IAAI,EAAE,WAAW,CAAA;CAAE,GACrB;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC;AAErB,UAAU,kBAAkB;IAC1B,KAAK,EAAE,cAAc,CAAC;IACtB,OAAO,EAAE,OAAO,CAAC;IACjB,QAAQ,EAAE,OAAO,CAAC;IAClB,KAAK,EAAE,SAAS,CAAC;IACjB,QAAQ,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAC;CAChC;AAcD,wBAAgB,aAAa,CAAC,EAAE,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,QAAQ,EAAE,EAAE,kBAAkB,2CAgC9F"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { ScoreRing } from "../../../../ui/ScoreRing";
|
|
4
|
+
import { cn } from "../../../../utils/style";
|
|
5
|
+
function MiniRing({ state }) {
|
|
6
|
+
if (state.kind === "analyzing") {
|
|
7
|
+
return /* @__PURE__ */ jsx(ScoreRing, { size: "small", status: "loading" });
|
|
8
|
+
}
|
|
9
|
+
if (state.kind === "score") {
|
|
10
|
+
return /* @__PURE__ */ jsx(ScoreRing, { score: state.score, size: "small", status: state.status });
|
|
11
|
+
}
|
|
12
|
+
return /* @__PURE__ */ jsx(ScoreRing, { size: "small", status: "idle" });
|
|
13
|
+
}
|
|
14
|
+
function KeyphraseCard({ entry, isFocus, selected, state, onSelect }) {
|
|
15
|
+
return /* @__PURE__ */ jsxs(
|
|
16
|
+
"button",
|
|
17
|
+
{
|
|
18
|
+
type: "button",
|
|
19
|
+
"aria-pressed": selected,
|
|
20
|
+
onClick: () => onSelect(entry.id),
|
|
21
|
+
className: cn(
|
|
22
|
+
"flex items-center gap-[10px] p-[8px] rounded-rs w-full text-left bg-neutral-0 border",
|
|
23
|
+
selected ? "border-neutral-300 shadow-[0_1px_5px_rgba(30,25,20,0.09)]" : "border-transparent hover:border-neutral-150"
|
|
24
|
+
),
|
|
25
|
+
children: [
|
|
26
|
+
/* @__PURE__ */ jsx(MiniRing, { state }),
|
|
27
|
+
/* @__PURE__ */ jsxs("span", { className: "flex-1 min-w-0 flex flex-col gap-[2px]", children: [
|
|
28
|
+
isFocus && /* @__PURE__ */ jsx("span", { className: "self-start text-[7px] leading-none uppercase bg-neutral-1000 text-neutral-0 px-[6px] py-[2px] rounded-[7px] tracking-[0.06em] font-bold", children: "Focus" }),
|
|
29
|
+
entry.text ? /* @__PURE__ */ jsx("span", { className: "text-[12px] font-semibold text-neutral-800 truncate", children: entry.text }) : /* @__PURE__ */ jsx("span", { className: "text-[12px] font-medium italic text-neutral-300 truncate", children: "New keyphrase" })
|
|
30
|
+
] })
|
|
31
|
+
]
|
|
32
|
+
}
|
|
33
|
+
);
|
|
34
|
+
}
|
|
35
|
+
export {
|
|
36
|
+
KeyphraseCard
|
|
37
|
+
};
|
|
38
|
+
//# sourceMappingURL=KeyphraseCard.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../../src/components/SeoDrawer/tabs/keyphrase/KeyphraseCard.tsx"],"sourcesContent":["\"use client\";\n\nimport type { Status } from \"../../../../engine/types/analysis\";\nimport { ScoreRing } from \"../../../../ui/ScoreRing\";\nimport { cn } from \"../../../../utils/style\";\nimport type { KeyphraseEntry } from \"../../keyphraseState\";\n\nexport type CardState =\n | { kind: \"score\"; score: number; status: Status }\n | { kind: \"analyzing\" }\n | { kind: \"idle\" };\n\ninterface KeyphraseCardProps {\n entry: KeyphraseEntry;\n isFocus: boolean;\n selected: boolean;\n state: CardState;\n onSelect: (id: string) => void;\n}\n\nfunction MiniRing({ state }: { state: CardState }) {\n if (state.kind === \"analyzing\") {\n return <ScoreRing size=\"small\" status=\"loading\" />;\n }\n\n if (state.kind === \"score\") {\n return <ScoreRing score={state.score} size=\"small\" status={state.status} />;\n }\n\n return <ScoreRing size=\"small\" status=\"idle\" />;\n}\n\nexport function KeyphraseCard({ entry, isFocus, selected, state, onSelect }: KeyphraseCardProps) {\n return (\n <button\n type=\"button\"\n aria-pressed={selected}\n onClick={() => onSelect(entry.id)}\n className={cn(\n \"flex items-center gap-[10px] p-[8px] rounded-rs w-full text-left bg-neutral-0 border\",\n selected\n ? \"border-neutral-300 shadow-[0_1px_5px_rgba(30,25,20,0.09)]\"\n : \"border-transparent hover:border-neutral-150\"\n )}\n >\n <MiniRing state={state} />\n\n <span className=\"flex-1 min-w-0 flex flex-col gap-[2px]\">\n {isFocus && (\n <span className=\"self-start text-[7px] leading-none uppercase bg-neutral-1000 text-neutral-0 px-[6px] py-[2px] rounded-[7px] tracking-[0.06em] font-bold\">\n Focus\n </span>\n )}\n\n {entry.text ? (\n <span className=\"text-[12px] font-semibold text-neutral-800 truncate\">{entry.text}</span>\n ) : (\n <span className=\"text-[12px] font-medium italic text-neutral-300 truncate\">\n New keyphrase\n </span>\n )}\n </span>\n </button>\n );\n}\n"],"mappings":";AAsBW,cAyBL,YAzBK;AAnBX,SAAS,iBAAiB;AAC1B,SAAS,UAAU;AAgBnB,SAAS,SAAS,EAAE,MAAM,GAAyB;AACjD,MAAI,MAAM,SAAS,aAAa;AAC9B,WAAO,oBAAC,aAAU,MAAK,SAAQ,QAAO,WAAU;AAAA,EAClD;AAEA,MAAI,MAAM,SAAS,SAAS;AAC1B,WAAO,oBAAC,aAAU,OAAO,MAAM,OAAO,MAAK,SAAQ,QAAQ,MAAM,QAAQ;AAAA,EAC3E;AAEA,SAAO,oBAAC,aAAU,MAAK,SAAQ,QAAO,QAAO;AAC/C;AAEO,SAAS,cAAc,EAAE,OAAO,SAAS,UAAU,OAAO,SAAS,GAAuB;AAC/F,SACE;AAAA,IAAC;AAAA;AAAA,MACC,MAAK;AAAA,MACL,gBAAc;AAAA,MACd,SAAS,MAAM,SAAS,MAAM,EAAE;AAAA,MAChC,WAAW;AAAA,QACT;AAAA,QACA,WACI,8DACA;AAAA,MACN;AAAA,MAEA;AAAA,4BAAC,YAAS,OAAc;AAAA,QAExB,qBAAC,UAAK,WAAU,0CACb;AAAA,qBACC,oBAAC,UAAK,WAAU,2IAA0I,mBAE1J;AAAA,UAGD,MAAM,OACL,oBAAC,UAAK,WAAU,uDAAuD,gBAAM,MAAK,IAElF,oBAAC,UAAK,WAAU,4DAA2D,2BAE3E;AAAA,WAEJ;AAAA;AAAA;AAAA,EACF;AAEJ;","names":[]}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { CategoryResult } from "../../../../engine/types/analysis";
|
|
2
|
+
import type { KeyphraseEntry } from "../../keyphraseState";
|
|
3
|
+
export type DetailAnalysis = {
|
|
4
|
+
kind: "metrics";
|
|
5
|
+
result: CategoryResult;
|
|
6
|
+
dim: boolean;
|
|
7
|
+
} | {
|
|
8
|
+
kind: "analyzing";
|
|
9
|
+
} | {
|
|
10
|
+
kind: "hint";
|
|
11
|
+
message: string;
|
|
12
|
+
};
|
|
13
|
+
export interface KeyphraseDetailProps {
|
|
14
|
+
entry: KeyphraseEntry;
|
|
15
|
+
isFocus: boolean;
|
|
16
|
+
duplicate: boolean;
|
|
17
|
+
analysis: DetailAnalysis;
|
|
18
|
+
onTextChange: (text: string) => void;
|
|
19
|
+
onAddSynonym: (syn: string) => void;
|
|
20
|
+
onRemoveSynonym: (index: number) => void;
|
|
21
|
+
onSetFocus: () => void;
|
|
22
|
+
onRemove: () => void;
|
|
23
|
+
}
|
|
24
|
+
export declare function KeyphraseDetail({ entry, isFocus, duplicate, analysis, onTextChange, onAddSynonym, onRemoveSynonym, onSetFocus, onRemove, }: KeyphraseDetailProps): import("react/jsx-runtime").JSX.Element;
|
|
25
|
+
//# sourceMappingURL=KeyphraseDetail.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"KeyphraseDetail.d.ts","sourceRoot":"","sources":["../../../../../src/components/SeoDrawer/tabs/keyphrase/KeyphraseDetail.tsx"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,mCAAmC,CAAC;AASxE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAI3D,MAAM,MAAM,cAAc,GACtB;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,MAAM,EAAE,cAAc,CAAC;IAAC,GAAG,EAAE,OAAO,CAAA;CAAE,GACzD;IAAE,IAAI,EAAE,WAAW,CAAA;CAAE,GACrB;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC;AAEtC,MAAM,WAAW,oBAAoB;IACnC,KAAK,EAAE,cAAc,CAAC;IACtB,OAAO,EAAE,OAAO,CAAC;IACjB,SAAS,EAAE,OAAO,CAAC;IACnB,QAAQ,EAAE,cAAc,CAAC;IACzB,YAAY,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IACrC,YAAY,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;IACpC,eAAe,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACzC,UAAU,EAAE,MAAM,IAAI,CAAC;IACvB,QAAQ,EAAE,MAAM,IAAI,CAAC;CACtB;AA0DD,wBAAgB,eAAe,CAAC,EAC9B,KAAK,EACL,OAAO,EACP,SAAS,EACT,QAAQ,EACR,YAAY,EACZ,YAAY,EACZ,eAAe,EACf,UAAU,EACV,QAAQ,GACT,EAAE,oBAAoB,2CAqDtB"}
|