@focus-reactive/payload-plugin-seo 1.0.2 → 1.2.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/dist/admin.css +172 -11
- package/dist/components/SeoButton/ScoreBadge.d.ts +9 -0
- package/dist/components/SeoButton/ScoreBadge.d.ts.map +1 -0
- package/dist/components/SeoButton/ScoreBadge.js +20 -0
- package/dist/components/SeoButton/ScoreBadge.js.map +1 -0
- package/dist/components/SeoButton/SeoButtonInner.d.ts +13 -0
- package/dist/components/SeoButton/SeoButtonInner.d.ts.map +1 -0
- package/dist/components/SeoButton/SeoButtonInner.js +68 -0
- package/dist/components/SeoButton/SeoButtonInner.js.map +1 -0
- package/dist/components/SeoButton/index.d.ts +3 -12
- package/dist/components/SeoButton/index.d.ts.map +1 -1
- package/dist/components/SeoButton/index.js +9 -73
- package/dist/components/SeoButton/index.js.map +1 -1
- package/dist/components/SeoButton/isExistingDocument.d.ts +2 -0
- package/dist/components/SeoButton/isExistingDocument.d.ts.map +1 -0
- package/dist/components/SeoButton/isExistingDocument.js +11 -0
- package/dist/components/SeoButton/isExistingDocument.js.map +1 -0
- package/dist/components/SeoDrawer/components/HeadingsSection/HeadingLevelTiles.d.ts +7 -0
- package/dist/components/SeoDrawer/components/HeadingsSection/HeadingLevelTiles.d.ts.map +1 -0
- package/dist/components/SeoDrawer/components/HeadingsSection/HeadingLevelTiles.js +29 -0
- package/dist/components/SeoDrawer/components/HeadingsSection/HeadingLevelTiles.js.map +1 -0
- package/dist/components/SeoDrawer/components/HeadingsSection/HeadingTree/Chevron.d.ts +4 -0
- package/dist/components/SeoDrawer/components/HeadingsSection/HeadingTree/Chevron.d.ts.map +1 -0
- package/dist/components/SeoDrawer/components/HeadingsSection/HeadingTree/Chevron.js +10 -0
- package/dist/components/SeoDrawer/components/HeadingsSection/HeadingTree/Chevron.js.map +1 -0
- package/dist/components/SeoDrawer/components/HeadingsSection/HeadingTree/HeadingTreeGroup.d.ts +10 -0
- package/dist/components/SeoDrawer/components/HeadingsSection/HeadingTree/HeadingTreeGroup.d.ts.map +1 -0
- package/dist/components/SeoDrawer/components/HeadingsSection/HeadingTree/HeadingTreeGroup.js +50 -0
- package/dist/components/SeoDrawer/components/HeadingsSection/HeadingTree/HeadingTreeGroup.js.map +1 -0
- package/dist/components/SeoDrawer/components/HeadingsSection/HeadingTree/HeadingTreeRow.d.ts +15 -0
- package/dist/components/SeoDrawer/components/HeadingsSection/HeadingTree/HeadingTreeRow.d.ts.map +1 -0
- package/dist/components/SeoDrawer/components/HeadingsSection/HeadingTree/HeadingTreeRow.js +38 -0
- package/dist/components/SeoDrawer/components/HeadingsSection/HeadingTree/HeadingTreeRow.js.map +1 -0
- package/dist/components/SeoDrawer/components/HeadingsSection/HeadingTree/headingTreeView.d.ts +3 -0
- package/dist/components/SeoDrawer/components/HeadingsSection/HeadingTree/headingTreeView.d.ts.map +1 -0
- package/dist/components/SeoDrawer/components/HeadingsSection/HeadingTree/headingTreeView.js +17 -0
- package/dist/components/SeoDrawer/components/HeadingsSection/HeadingTree/headingTreeView.js.map +1 -0
- package/dist/components/SeoDrawer/components/HeadingsSection/HeadingTree/index.d.ts +6 -0
- package/dist/components/SeoDrawer/components/HeadingsSection/HeadingTree/index.d.ts.map +1 -0
- package/dist/components/SeoDrawer/components/HeadingsSection/HeadingTree/index.js +41 -0
- package/dist/components/SeoDrawer/components/HeadingsSection/HeadingTree/index.js.map +1 -0
- package/dist/components/SeoDrawer/components/HeadingsSection/HeadingTree/useHeadingRails.d.ts +32 -0
- package/dist/components/SeoDrawer/components/HeadingsSection/HeadingTree/useHeadingRails.d.ts.map +1 -0
- package/dist/components/SeoDrawer/components/HeadingsSection/HeadingTree/useHeadingRails.js +84 -0
- package/dist/components/SeoDrawer/components/HeadingsSection/HeadingTree/useHeadingRails.js.map +1 -0
- package/dist/components/SeoDrawer/components/HeadingsSection/index.d.ts +7 -0
- package/dist/components/SeoDrawer/components/HeadingsSection/index.d.ts.map +1 -0
- package/dist/components/SeoDrawer/components/HeadingsSection/index.js +17 -0
- package/dist/components/SeoDrawer/components/HeadingsSection/index.js.map +1 -0
- package/dist/components/SeoDrawer/tabs/VitalsTab.d.ts.map +1 -1
- package/dist/components/SeoDrawer/tabs/VitalsTab.js +2 -0
- package/dist/components/SeoDrawer/tabs/VitalsTab.js.map +1 -1
- package/dist/engine/runAnalysis/services/derive-vitals/heading-tree.d.ts +7 -0
- package/dist/engine/runAnalysis/services/derive-vitals/heading-tree.d.ts.map +1 -0
- package/dist/engine/runAnalysis/services/derive-vitals/heading-tree.js +41 -0
- package/dist/engine/runAnalysis/services/derive-vitals/heading-tree.js.map +1 -0
- package/dist/engine/runAnalysis/services/derive-vitals/headings.d.ts +8 -0
- package/dist/engine/runAnalysis/services/derive-vitals/headings.d.ts.map +1 -0
- package/dist/engine/runAnalysis/services/derive-vitals/headings.js +50 -0
- package/dist/engine/runAnalysis/services/derive-vitals/headings.js.map +1 -0
- package/dist/engine/runAnalysis/services/derive-vitals/index.d.ts.map +1 -1
- package/dist/engine/runAnalysis/services/derive-vitals/index.js +4 -1
- package/dist/engine/runAnalysis/services/derive-vitals/index.js.map +1 -1
- package/dist/engine/types/analysis.d.ts +17 -0
- package/dist/engine/types/analysis.d.ts.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { useLayoutEffect, useRef, useState } from "react";
|
|
3
|
+
function useHeadingRails({ node, isOpen, collapsed, onBadgeMount }) {
|
|
4
|
+
const containerRef = useRef(null);
|
|
5
|
+
const badgeRef = useRef(null);
|
|
6
|
+
const childBadges = useRef(/* @__PURE__ */ new Map());
|
|
7
|
+
const childSetters = useRef(/* @__PURE__ */ new Map());
|
|
8
|
+
const [rails, setRails] = useState(null);
|
|
9
|
+
const setBadgeRef = (el) => {
|
|
10
|
+
badgeRef.current = el;
|
|
11
|
+
onBadgeMount?.(el);
|
|
12
|
+
};
|
|
13
|
+
const registerChildBadge = (childId) => {
|
|
14
|
+
let setter = childSetters.current.get(childId);
|
|
15
|
+
if (!setter) {
|
|
16
|
+
setter = (el) => {
|
|
17
|
+
if (el)
|
|
18
|
+
childBadges.current.set(childId, el);
|
|
19
|
+
else
|
|
20
|
+
childBadges.current.delete(childId);
|
|
21
|
+
};
|
|
22
|
+
childSetters.current.set(childId, setter);
|
|
23
|
+
}
|
|
24
|
+
return setter;
|
|
25
|
+
};
|
|
26
|
+
useLayoutEffect(() => {
|
|
27
|
+
if (!isOpen) {
|
|
28
|
+
setRails(null);
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
const container = containerRef.current;
|
|
32
|
+
const parentBadge = badgeRef.current;
|
|
33
|
+
if (!container || !parentBadge)
|
|
34
|
+
return;
|
|
35
|
+
const measure = () => {
|
|
36
|
+
const containerRect = container.getBoundingClientRect();
|
|
37
|
+
const parentBadgeRect = parentBadge.getBoundingClientRect();
|
|
38
|
+
const railCenterX = parentBadgeRect.left + parentBadgeRect.width / 2 - containerRect.left;
|
|
39
|
+
const railStartY = parentBadgeRect.bottom - containerRect.top;
|
|
40
|
+
const elbows = [];
|
|
41
|
+
for (const child of node.children) {
|
|
42
|
+
const childBadge = childBadges.current.get(child.id);
|
|
43
|
+
if (!childBadge)
|
|
44
|
+
continue;
|
|
45
|
+
const childBadgeRect = childBadge.getBoundingClientRect();
|
|
46
|
+
const childCenterX = childBadgeRect.left + childBadgeRect.width / 2 - containerRect.left;
|
|
47
|
+
const childCenterY = childBadgeRect.top + childBadgeRect.height / 2 - containerRect.top;
|
|
48
|
+
elbows.push({
|
|
49
|
+
id: child.id,
|
|
50
|
+
left: railCenterX,
|
|
51
|
+
top: childCenterY,
|
|
52
|
+
width: Math.max(0, childCenterX - railCenterX)
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
if (elbows.length === 0) {
|
|
56
|
+
setRails(null);
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
const lastChildCenterY = elbows.at(-1)?.top ?? railStartY;
|
|
60
|
+
setRails({
|
|
61
|
+
vertical: {
|
|
62
|
+
left: railCenterX,
|
|
63
|
+
top: railStartY,
|
|
64
|
+
height: Math.max(0, lastChildCenterY - railStartY)
|
|
65
|
+
},
|
|
66
|
+
elbows
|
|
67
|
+
});
|
|
68
|
+
};
|
|
69
|
+
measure();
|
|
70
|
+
const observer = new ResizeObserver(measure);
|
|
71
|
+
observer.observe(container);
|
|
72
|
+
return () => observer.disconnect();
|
|
73
|
+
}, [isOpen, collapsed, node]);
|
|
74
|
+
return {
|
|
75
|
+
containerRef,
|
|
76
|
+
setBadgeRef,
|
|
77
|
+
registerChildBadge,
|
|
78
|
+
rails
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
export {
|
|
82
|
+
useHeadingRails
|
|
83
|
+
};
|
|
84
|
+
//# sourceMappingURL=useHeadingRails.js.map
|
package/dist/components/SeoDrawer/components/HeadingsSection/HeadingTree/useHeadingRails.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../../../src/components/SeoDrawer/components/HeadingsSection/HeadingTree/useHeadingRails.ts"],"sourcesContent":["\"use client\";\n\nimport type { RefObject } from \"react\";\nimport { useLayoutEffect, useRef, useState } from \"react\";\nimport type { HeadingNode } from \"../../../../../engine/types/analysis\";\n\ninterface VerticalRail {\n left: number;\n top: number;\n height: number;\n}\n\ninterface Elbow {\n id: string;\n left: number;\n top: number;\n width: number;\n}\n\nexport interface RailGeometry {\n vertical: VerticalRail;\n elbows: Elbow[];\n}\n\ninterface UseHeadingRailsParams {\n node: HeadingNode;\n isOpen: boolean;\n collapsed: ReadonlySet<string>;\n onBadgeMount?: (el: HTMLSpanElement | null) => void;\n}\n\ninterface UseHeadingRailsResult {\n containerRef: RefObject<HTMLDivElement | null>;\n setBadgeRef: (el: HTMLSpanElement | null) => void;\n registerChildBadge: (childId: string) => (el: HTMLSpanElement | null) => void;\n rails: RailGeometry | null;\n}\n\nexport function useHeadingRails({ node, isOpen, collapsed, onBadgeMount }: UseHeadingRailsParams): UseHeadingRailsResult {\n const containerRef = useRef<HTMLDivElement>(null);\n const badgeRef = useRef<HTMLSpanElement | null>(null);\n const childBadges = useRef(new Map<string, HTMLSpanElement>());\n const childSetters = useRef(new Map<string, (el: HTMLSpanElement | null) => void>());\n const [rails, setRails] = useState<RailGeometry | null>(null);\n\n const setBadgeRef = (el: HTMLSpanElement | null) => {\n badgeRef.current = el;\n onBadgeMount?.(el);\n };\n\n const registerChildBadge = (childId: string) => {\n let setter = childSetters.current.get(childId);\n\n if (!setter) {\n setter = (el: HTMLSpanElement | null) => {\n if (el) childBadges.current.set(childId, el);\n else childBadges.current.delete(childId);\n };\n\n childSetters.current.set(childId, setter);\n }\n\n return setter;\n };\n\n useLayoutEffect(() => {\n if (!isOpen) {\n setRails(null);\n return;\n }\n\n const container = containerRef.current;\n const parentBadge = badgeRef.current;\n if (!container || !parentBadge) return;\n\n const measure = () => {\n const containerRect = container.getBoundingClientRect();\n const parentBadgeRect = parentBadge.getBoundingClientRect();\n\n const railCenterX = parentBadgeRect.left + parentBadgeRect.width / 2 - containerRect.left;\n const railStartY = parentBadgeRect.bottom - containerRect.top;\n\n const elbows: Elbow[] = [];\n for (const child of node.children) {\n const childBadge = childBadges.current.get(child.id);\n if (!childBadge) continue;\n\n const childBadgeRect = childBadge.getBoundingClientRect();\n\n const childCenterX = childBadgeRect.left + childBadgeRect.width / 2 - containerRect.left;\n const childCenterY = childBadgeRect.top + childBadgeRect.height / 2 - containerRect.top;\n\n elbows.push({\n id: child.id,\n left: railCenterX,\n top: childCenterY,\n width: Math.max(0, childCenterX - railCenterX),\n });\n }\n\n if (elbows.length === 0) {\n setRails(null);\n return;\n }\n\n const lastChildCenterY = elbows.at(-1)?.top ?? railStartY;\n setRails({\n vertical: {\n left: railCenterX,\n top: railStartY,\n height: Math.max(0, lastChildCenterY - railStartY),\n },\n elbows,\n });\n };\n\n measure();\n\n const observer = new ResizeObserver(measure);\n\n observer.observe(container);\n\n return () => observer.disconnect();\n }, [isOpen, collapsed, node]);\n\n return {\n containerRef,\n setBadgeRef,\n registerChildBadge,\n rails,\n };\n}\n"],"mappings":";AAGA,SAAS,iBAAiB,QAAQ,gBAAgB;AAmC3C,SAAS,gBAAgB,EAAE,MAAM,QAAQ,WAAW,aAAa,GAAiD;AACvH,QAAM,eAAe,OAAuB,IAAI;AAChD,QAAM,WAAW,OAA+B,IAAI;AACpD,QAAM,cAAc,OAAO,oBAAI,IAA6B,CAAC;AAC7D,QAAM,eAAe,OAAO,oBAAI,IAAkD,CAAC;AACnF,QAAM,CAAC,OAAO,QAAQ,IAAI,SAA8B,IAAI;AAE5D,QAAM,cAAc,CAAC,OAA+B;AAClD,aAAS,UAAU;AACnB,mBAAe,EAAE;AAAA,EACnB;AAEA,QAAM,qBAAqB,CAAC,YAAoB;AAC9C,QAAI,SAAS,aAAa,QAAQ,IAAI,OAAO;AAE7C,QAAI,CAAC,QAAQ;AACX,eAAS,CAAC,OAA+B;AACvC,YAAI;AAAI,sBAAY,QAAQ,IAAI,SAAS,EAAE;AAAA;AACtC,sBAAY,QAAQ,OAAO,OAAO;AAAA,MACzC;AAEA,mBAAa,QAAQ,IAAI,SAAS,MAAM;AAAA,IAC1C;AAEA,WAAO;AAAA,EACT;AAEA,kBAAgB,MAAM;AACpB,QAAI,CAAC,QAAQ;AACX,eAAS,IAAI;AACb;AAAA,IACF;AAEA,UAAM,YAAY,aAAa;AAC/B,UAAM,cAAc,SAAS;AAC7B,QAAI,CAAC,aAAa,CAAC;AAAa;AAEhC,UAAM,UAAU,MAAM;AACpB,YAAM,gBAAgB,UAAU,sBAAsB;AACtD,YAAM,kBAAkB,YAAY,sBAAsB;AAE1D,YAAM,cAAc,gBAAgB,OAAO,gBAAgB,QAAQ,IAAI,cAAc;AACrF,YAAM,aAAa,gBAAgB,SAAS,cAAc;AAE1D,YAAM,SAAkB,CAAC;AACzB,iBAAW,SAAS,KAAK,UAAU;AACjC,cAAM,aAAa,YAAY,QAAQ,IAAI,MAAM,EAAE;AACnD,YAAI,CAAC;AAAY;AAEjB,cAAM,iBAAiB,WAAW,sBAAsB;AAExD,cAAM,eAAe,eAAe,OAAO,eAAe,QAAQ,IAAI,cAAc;AACpF,cAAM,eAAe,eAAe,MAAM,eAAe,SAAS,IAAI,cAAc;AAEpF,eAAO,KAAK;AAAA,UACV,IAAI,MAAM;AAAA,UACV,MAAM;AAAA,UACN,KAAK;AAAA,UACL,OAAO,KAAK,IAAI,GAAG,eAAe,WAAW;AAAA,QAC/C,CAAC;AAAA,MACH;AAEA,UAAI,OAAO,WAAW,GAAG;AACvB,iBAAS,IAAI;AACb;AAAA,MACF;AAEA,YAAM,mBAAmB,OAAO,GAAG,EAAE,GAAG,OAAO;AAC/C,eAAS;AAAA,QACP,UAAU;AAAA,UACR,MAAM;AAAA,UACN,KAAK;AAAA,UACL,QAAQ,KAAK,IAAI,GAAG,mBAAmB,UAAU;AAAA,QACnD;AAAA,QACA;AAAA,MACF,CAAC;AAAA,IACH;AAEA,YAAQ;AAER,UAAM,WAAW,IAAI,eAAe,OAAO;AAE3C,aAAS,QAAQ,SAAS;AAE1B,WAAO,MAAM,SAAS,WAAW;AAAA,EACnC,GAAG,CAAC,QAAQ,WAAW,IAAI,CAAC;AAE5B,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;","names":[]}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { HeadingStructure } from "../../../../engine/types/analysis";
|
|
2
|
+
interface HeadingsSectionProps {
|
|
3
|
+
data: HeadingStructure;
|
|
4
|
+
}
|
|
5
|
+
export declare function HeadingsSection({ data }: HeadingsSectionProps): import("react/jsx-runtime").JSX.Element;
|
|
6
|
+
export {};
|
|
7
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/components/SeoDrawer/components/HeadingsSection/index.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,mCAAmC,CAAC;AAM1E,UAAU,oBAAoB;IAC5B,IAAI,EAAE,gBAAgB,CAAC;CACxB;AAED,wBAAgB,eAAe,CAAC,EAAE,IAAI,EAAE,EAAE,oBAAoB,2CAQ7D"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { SectionCard } from "../../../../ui/SectionCard";
|
|
4
|
+
import { Pill } from "../../../../ui/Pill";
|
|
5
|
+
import { HeadingLevelTiles } from "./HeadingLevelTiles";
|
|
6
|
+
import { HeadingTree } from "./HeadingTree";
|
|
7
|
+
function HeadingsSection({ data }) {
|
|
8
|
+
return /* @__PURE__ */ jsxs(SectionCard, { title: "Headings", widget: /* @__PURE__ */ jsx(Pill, { variant: "neutral", children: data.total }), children: [
|
|
9
|
+
/* @__PURE__ */ jsx("div", { className: "text-[9.5px] font-semibold uppercase tracking-[0.05em] text-neutral-500 px-[15px] pt-[11px]", children: "Levels" }),
|
|
10
|
+
/* @__PURE__ */ jsx(HeadingLevelTiles, { levels: data.levels }),
|
|
11
|
+
/* @__PURE__ */ jsx(HeadingTree, { tree: data.tree })
|
|
12
|
+
] });
|
|
13
|
+
}
|
|
14
|
+
export {
|
|
15
|
+
HeadingsSection
|
|
16
|
+
};
|
|
17
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../../src/components/SeoDrawer/components/HeadingsSection/index.tsx"],"sourcesContent":["\"use client\";\n\nimport type { HeadingStructure } from \"../../../../engine/types/analysis\";\nimport { SectionCard } from \"../../../../ui/SectionCard\";\nimport { Pill } from \"../../../../ui/Pill\";\nimport { HeadingLevelTiles } from \"./HeadingLevelTiles\";\nimport { HeadingTree } from \"./HeadingTree\";\n\ninterface HeadingsSectionProps {\n data: HeadingStructure;\n}\n\nexport function HeadingsSection({ data }: HeadingsSectionProps) {\n return (\n <SectionCard title=\"Headings\" widget={<Pill variant=\"neutral\">{data.total}</Pill>}>\n <div className=\"text-[9.5px] font-semibold uppercase tracking-[0.05em] text-neutral-500 px-[15px] pt-[11px]\">Levels</div>\n <HeadingLevelTiles levels={data.levels} />\n <HeadingTree tree={data.tree} />\n </SectionCard>\n );\n}\n"],"mappings":";AAcI,SAAsC,KAAtC;AAXJ,SAAS,mBAAmB;AAC5B,SAAS,YAAY;AACrB,SAAS,yBAAyB;AAClC,SAAS,mBAAmB;AAMrB,SAAS,gBAAgB,EAAE,KAAK,GAAyB;AAC9D,SACE,qBAAC,eAAY,OAAM,YAAW,QAAQ,oBAAC,QAAK,SAAQ,WAAW,eAAK,OAAM,GACxE;AAAA,wBAAC,SAAI,WAAU,+FAA8F,oBAAM;AAAA,IACnH,oBAAC,qBAAkB,QAAQ,KAAK,QAAQ;AAAA,IACxC,oBAAC,eAAY,MAAM,KAAK,MAAM;AAAA,KAChC;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;AAOnE,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,2CA0CrE"}
|
|
@@ -4,6 +4,7 @@ import { cn, ROW_SEPARATOR } from "../../../utils/style";
|
|
|
4
4
|
import { KpiCard } from "../../../ui/KpiCard";
|
|
5
5
|
import { SectionCard } from "../../../ui/SectionCard";
|
|
6
6
|
import { Pill } from "../../../ui/Pill";
|
|
7
|
+
import { HeadingsSection } from "../components/HeadingsSection";
|
|
7
8
|
function VitalsTab({ data, onRequestKeyphrase }) {
|
|
8
9
|
const max = Math.max(1, ...data.prominentWords.map((w) => w.count));
|
|
9
10
|
const noKeyphraseMatch = data.prominentWords.every((w) => !w.isKeyphrase);
|
|
@@ -16,6 +17,7 @@ function VitalsTab({ data, onRequestKeyphrase }) {
|
|
|
16
17
|
/* @__PURE__ */ jsx(KpiCard, { label: "Videos", value: data.videos }),
|
|
17
18
|
/* @__PURE__ */ jsx(KpiCard, { label: "Reading time", value: data.readingTimeMinutes, suffix: "min" })
|
|
18
19
|
] }),
|
|
20
|
+
/* @__PURE__ */ jsx(HeadingsSection, { data: data.headings }),
|
|
19
21
|
/* @__PURE__ */ jsx(SectionCard, { title: "Prominent words", widget: /* @__PURE__ */ jsx(Pill, { variant: "neutral", children: data.prominentWords.length }), children: data.prominentWords.map((w) => /* @__PURE__ */ jsxs("div", { className: cn("relative flex items-center gap-[12px] px-[15px] py-[9px]", ROW_SEPARATOR), children: [
|
|
20
22
|
/* @__PURE__ */ jsxs("div", { className: "w-[120px] flex-none text-[12px] font-medium flex items-center gap-[6px]", children: [
|
|
21
23
|
w.word,
|
|
@@ -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\";\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 <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 <SectionCard title=\"Prominent words\" widget={<Pill variant=\"neutral\">{data.prominentWords.length}</Pill>}>\n {data.prominentWords.map((w) => (\n <div className={cn(\"relative flex items-center gap-[12px] px-[15px] py-[9px]\", ROW_SEPARATOR)} key={w.word}>\n <div className=\"w-[120px] flex-none text-[12px] font-medium flex items-center gap-[6px]\">\n {w.word} {w.isKeyphrase && <span className=\"text-[9px] font-bold uppercase tracking-[0.04em] text-neutral-1000 bg-neutral-150 rounded-[3px] px-[5px] py-[1px]\">Key</span>}\n </div>\n <div className=\"flex-1 h-[6px] rounded-[3px] bg-neutral-100 overflow-hidden\">\n <i className={cn(\"block h-full\", w.isKeyphrase ? \"bg-neutral-1000\" : \"bg-neutral-400\")} style={{ width: `${(w.count / max) * 100}%` }} />\n </div>\n <div className=\"w-[30px] text-right font-mono text-[11px] font-semibold text-neutral-700\">{w.count}</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 );\n}\n"],"mappings":";
|
|
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 <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 title=\"Prominent words\" widget={<Pill variant=\"neutral\">{data.prominentWords.length}</Pill>}>\n {data.prominentWords.map((w) => (\n <div className={cn(\"relative flex items-center gap-[12px] px-[15px] py-[9px]\", ROW_SEPARATOR)} key={w.word}>\n <div className=\"w-[120px] flex-none text-[12px] font-medium flex items-center gap-[6px]\">\n {w.word} {w.isKeyphrase && <span className=\"text-[9px] font-bold uppercase tracking-[0.04em] text-neutral-1000 bg-neutral-150 rounded-[3px] px-[5px] py-[1px]\">Key</span>}\n </div>\n <div className=\"flex-1 h-[6px] rounded-[3px] bg-neutral-100 overflow-hidden\">\n <i className={cn(\"block h-full\", w.isKeyphrase ? \"bg-neutral-1000\" : \"bg-neutral-400\")} style={{ width: `${(w.count / max) * 100}%` }} />\n </div>\n <div className=\"w-[30px] text-right font-mono text-[11px] font-semibold text-neutral-700\">{w.count}</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 );\n}\n"],"mappings":";AAoBM,SACE,KADF;AAjBN,SAAS,IAAI,qBAAqB;AAClC,SAAS,eAAe;AACxB,SAAS,mBAAmB;AAC5B,SAAS,YAAY;AACrB,SAAS,uBAAuB;AAOzB,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,qBAAC,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,oBAAC,eAAY,OAAM,mBAAkB,QAAQ,oBAAC,QAAK,SAAQ,WAAW,eAAK,eAAe,QAAO,GAC9F,eAAK,eAAe,IAAI,CAAC,MACxB,qBAAC,SAAI,WAAW,GAAG,4DAA4D,aAAa,GAC1F;AAAA,2BAAC,SAAI,WAAU,2EACZ;AAAA,UAAE;AAAA,QAAK;AAAA,QAAE,EAAE,eAAe,oBAAC,UAAK,WAAU,qHAAoH,iBAAG;AAAA,SACpK;AAAA,MACA,oBAAC,SAAI,WAAU,+DACb,8BAAC,OAAE,WAAW,GAAG,gBAAgB,EAAE,cAAc,oBAAoB,gBAAgB,GAAG,OAAO,EAAE,OAAO,GAAI,EAAE,QAAQ,MAAO,GAAG,IAAI,GAAG,GACzI;AAAA,MACA,oBAAC,SAAI,WAAU,4EAA4E,YAAE,OAAM;AAAA,SAPD,EAAE,IAQtG,CACD,GACH;AAAA,IAEC,oBACC;AAAA,MAAC;AAAA;AAAA,QACC,MAAK;AAAA,QACL,SAAS;AAAA,QACT,WAAU;AAAA,QACX;AAAA;AAAA,IAED;AAAA,KAEJ;AAEJ;","names":[]}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { HeadingLevel, HeadingStructure } from "../../../types/analysis";
|
|
2
|
+
export interface FlatHeading {
|
|
3
|
+
level: HeadingLevel;
|
|
4
|
+
text: string;
|
|
5
|
+
}
|
|
6
|
+
export declare function buildHeadingTree(flat: FlatHeading[]): HeadingStructure;
|
|
7
|
+
//# sourceMappingURL=heading-tree.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"heading-tree.d.ts","sourceRoot":"","sources":["../../../../../src/engine/runAnalysis/services/derive-vitals/heading-tree.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAkC,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAE9G,MAAM,WAAW,WAAW;IAC1B,KAAK,EAAE,YAAY,CAAC;IACpB,IAAI,EAAE,MAAM,CAAC;CACd;AAWD,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,WAAW,EAAE,GAAG,gBAAgB,CAkCtE"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
const LEVELS = [1, 2, 3, 4, 5, 6];
|
|
2
|
+
function countLevels(flat) {
|
|
3
|
+
return LEVELS.map((level) => ({
|
|
4
|
+
level,
|
|
5
|
+
count: flat.filter((h) => h.level === level).length
|
|
6
|
+
}));
|
|
7
|
+
}
|
|
8
|
+
function buildHeadingTree(flat) {
|
|
9
|
+
const roots = [];
|
|
10
|
+
const stack = [];
|
|
11
|
+
for (const heading of flat) {
|
|
12
|
+
let top = stack.at(-1);
|
|
13
|
+
while (top && top.level >= heading.level) {
|
|
14
|
+
stack.pop();
|
|
15
|
+
top = stack.at(-1);
|
|
16
|
+
}
|
|
17
|
+
const parent = top;
|
|
18
|
+
const id = parent ? `${parent.id}.${parent.children.length}` : `${roots.length}`;
|
|
19
|
+
const node = {
|
|
20
|
+
id,
|
|
21
|
+
level: heading.level,
|
|
22
|
+
text: heading.text,
|
|
23
|
+
children: []
|
|
24
|
+
};
|
|
25
|
+
if (parent) {
|
|
26
|
+
parent.children.push(node);
|
|
27
|
+
} else {
|
|
28
|
+
roots.push(node);
|
|
29
|
+
}
|
|
30
|
+
stack.push(node);
|
|
31
|
+
}
|
|
32
|
+
return {
|
|
33
|
+
total: flat.length,
|
|
34
|
+
levels: countLevels(flat),
|
|
35
|
+
tree: roots
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
export {
|
|
39
|
+
buildHeadingTree
|
|
40
|
+
};
|
|
41
|
+
//# sourceMappingURL=heading-tree.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../../src/engine/runAnalysis/services/derive-vitals/heading-tree.ts"],"sourcesContent":["import type { HeadingLevel, HeadingLevelCount, HeadingNode, HeadingStructure } from \"../../../types/analysis\";\n\nexport interface FlatHeading {\n level: HeadingLevel;\n text: string;\n}\n\nconst LEVELS: HeadingLevel[] = [1, 2, 3, 4, 5, 6];\n\nfunction countLevels(flat: FlatHeading[]): HeadingLevelCount[] {\n return LEVELS.map((level) => ({\n level,\n count: flat.filter((h) => h.level === level).length,\n }));\n}\n\nexport function buildHeadingTree(flat: FlatHeading[]): HeadingStructure {\n const roots: HeadingNode[] = [];\n const stack: HeadingNode[] = [];\n\n for (const heading of flat) {\n let top = stack.at(-1);\n\n while (top && top.level >= heading.level) {\n stack.pop();\n top = stack.at(-1);\n }\n\n const parent = top;\n const id = parent ? `${parent.id}.${parent.children.length}` : `${roots.length}`;\n\n const node: HeadingNode = {\n id,\n level: heading.level,\n text: heading.text,\n children: [],\n };\n if (parent) {\n parent.children.push(node);\n } else {\n roots.push(node);\n }\n stack.push(node);\n }\n\n return {\n total: flat.length,\n levels: countLevels(flat),\n tree: roots,\n };\n}\n"],"mappings":"AAOA,MAAM,SAAyB,CAAC,GAAG,GAAG,GAAG,GAAG,GAAG,CAAC;AAEhD,SAAS,YAAY,MAA0C;AAC7D,SAAO,OAAO,IAAI,CAAC,WAAW;AAAA,IAC5B;AAAA,IACA,OAAO,KAAK,OAAO,CAAC,MAAM,EAAE,UAAU,KAAK,EAAE;AAAA,EAC/C,EAAE;AACJ;AAEO,SAAS,iBAAiB,MAAuC;AACtE,QAAM,QAAuB,CAAC;AAC9B,QAAM,QAAuB,CAAC;AAE9B,aAAW,WAAW,MAAM;AAC1B,QAAI,MAAM,MAAM,GAAG,EAAE;AAErB,WAAO,OAAO,IAAI,SAAS,QAAQ,OAAO;AACxC,YAAM,IAAI;AACV,YAAM,MAAM,GAAG,EAAE;AAAA,IACnB;AAEA,UAAM,SAAS;AACf,UAAM,KAAK,SAAS,GAAG,OAAO,EAAE,IAAI,OAAO,SAAS,MAAM,KAAK,GAAG,MAAM,MAAM;AAE9E,UAAM,OAAoB;AAAA,MACxB;AAAA,MACA,OAAO,QAAQ;AAAA,MACf,MAAM,QAAQ;AAAA,MACd,UAAU,CAAC;AAAA,IACb;AACA,QAAI,QAAQ;AACV,aAAO,SAAS,KAAK,IAAI;AAAA,IAC3B,OAAO;AACL,YAAM,KAAK,IAAI;AAAA,IACjB;AACA,UAAM,KAAK,IAAI;AAAA,EACjB;AAEA,SAAO;AAAA,IACL,OAAO,KAAK;AAAA,IACZ,QAAQ,YAAY,IAAI;AAAA,IACxB,MAAM;AAAA,EACR;AACF;","names":[]}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { YoastResearcher } from "../../../researcherAdapter";
|
|
2
|
+
import type { FlatHeading } from "./heading-tree";
|
|
3
|
+
interface PaperLike {
|
|
4
|
+
getText?: () => string;
|
|
5
|
+
}
|
|
6
|
+
export declare function extractHeadings(researcher: YoastResearcher, paper: PaperLike): FlatHeading[];
|
|
7
|
+
export {};
|
|
8
|
+
//# sourceMappingURL=headings.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"headings.d.ts","sourceRoot":"","sources":["../../../../../src/engine/runAnalysis/services/derive-vitals/headings.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAC;AAElE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAElD,UAAU,SAAS;IACjB,OAAO,CAAC,EAAE,MAAM,MAAM,CAAC;CACxB;AAmDD,wBAAgB,eAAe,CAAC,UAAU,EAAE,eAAe,EAAE,KAAK,EAAE,SAAS,GAAG,WAAW,EAAE,CAO5F"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { getResearch } from "../../../researcherAdapter";
|
|
2
|
+
const GLOBAL_HEADING_RE = /<h([1-6])\b[^>]*>([\s\S]*?)<\/h\1>/giu;
|
|
3
|
+
const SINGLE_HEADING_RE = /^<h([1-6])\b[^>]*>([\s\S]*?)<\/h\1>$/iu;
|
|
4
|
+
function toText(inner) {
|
|
5
|
+
return inner.replace(/<[^>]*>/gu, "").replace(/\s+/gu, " ").trim();
|
|
6
|
+
}
|
|
7
|
+
function parseEntry(html) {
|
|
8
|
+
const m = SINGLE_HEADING_RE.exec(html.trim());
|
|
9
|
+
if (!m)
|
|
10
|
+
return null;
|
|
11
|
+
return {
|
|
12
|
+
level: Number(m[1] ?? 0),
|
|
13
|
+
text: toText(m[2] ?? "")
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
function fromResearch(researcher) {
|
|
17
|
+
const entries = getResearch(researcher, "getSubheadingTextLengths");
|
|
18
|
+
if (!Array.isArray(entries))
|
|
19
|
+
return null;
|
|
20
|
+
const headings = [];
|
|
21
|
+
for (const entry of entries) {
|
|
22
|
+
if (!entry?.subheading)
|
|
23
|
+
continue;
|
|
24
|
+
const parsed = parseEntry(entry.subheading);
|
|
25
|
+
if (parsed)
|
|
26
|
+
headings.push(parsed);
|
|
27
|
+
}
|
|
28
|
+
return headings;
|
|
29
|
+
}
|
|
30
|
+
function fromHtml(html) {
|
|
31
|
+
const headings = [];
|
|
32
|
+
for (const m of html.matchAll(GLOBAL_HEADING_RE)) {
|
|
33
|
+
headings.push({
|
|
34
|
+
level: Number(m[1] ?? 0),
|
|
35
|
+
text: toText(m[2] ?? "")
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
return headings;
|
|
39
|
+
}
|
|
40
|
+
function extractHeadings(researcher, paper) {
|
|
41
|
+
const researched = fromResearch(researcher);
|
|
42
|
+
if (researched && researched.length > 0)
|
|
43
|
+
return researched;
|
|
44
|
+
const html = typeof paper.getText === "function" ? paper.getText() : "";
|
|
45
|
+
return fromHtml(html);
|
|
46
|
+
}
|
|
47
|
+
export {
|
|
48
|
+
extractHeadings
|
|
49
|
+
};
|
|
50
|
+
//# sourceMappingURL=headings.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../../src/engine/runAnalysis/services/derive-vitals/headings.ts"],"sourcesContent":["import { getResearch } from \"../../../researcherAdapter\";\nimport type { YoastResearcher } from \"../../../researcherAdapter\";\nimport type { HeadingLevel } from \"../../../types/analysis\";\nimport type { FlatHeading } from \"./heading-tree\";\n\ninterface PaperLike {\n getText?: () => string;\n}\n\nconst GLOBAL_HEADING_RE = /<h([1-6])\\b[^>]*>([\\s\\S]*?)<\\/h\\1>/giu;\nconst SINGLE_HEADING_RE = /^<h([1-6])\\b[^>]*>([\\s\\S]*?)<\\/h\\1>$/iu;\n\nfunction toText(inner: string): string {\n return inner\n .replace(/<[^>]*>/gu, \"\")\n .replace(/\\s+/gu, \" \")\n .trim();\n}\n\nfunction parseEntry(html: string): FlatHeading | null {\n const m = SINGLE_HEADING_RE.exec(html.trim());\n if (!m) return null;\n\n return {\n level: Number(m[1] ?? 0) as HeadingLevel,\n text: toText(m[2] ?? \"\"),\n };\n}\n\nfunction fromResearch(researcher: YoastResearcher): FlatHeading[] | null {\n const entries = getResearch<{ subheading?: string }[]>(researcher, \"getSubheadingTextLengths\");\n if (!Array.isArray(entries)) return null;\n\n const headings: FlatHeading[] = [];\n\n for (const entry of entries) {\n if (!entry?.subheading) continue;\n\n const parsed = parseEntry(entry.subheading);\n if (parsed) headings.push(parsed);\n }\n\n return headings;\n}\n\nfunction fromHtml(html: string): FlatHeading[] {\n const headings: FlatHeading[] = [];\n\n for (const m of html.matchAll(GLOBAL_HEADING_RE)) {\n headings.push({\n level: Number(m[1] ?? 0) as HeadingLevel,\n text: toText(m[2] ?? \"\"),\n });\n }\n\n return headings;\n}\n\nexport function extractHeadings(researcher: YoastResearcher, paper: PaperLike): FlatHeading[] {\n const researched = fromResearch(researcher);\n if (researched && researched.length > 0) return researched;\n\n const html = typeof paper.getText === \"function\" ? paper.getText() : \"\";\n\n return fromHtml(html);\n}\n"],"mappings":"AAAA,SAAS,mBAAmB;AAS5B,MAAM,oBAAoB;AAC1B,MAAM,oBAAoB;AAE1B,SAAS,OAAO,OAAuB;AACrC,SAAO,MACJ,QAAQ,aAAa,EAAE,EACvB,QAAQ,SAAS,GAAG,EACpB,KAAK;AACV;AAEA,SAAS,WAAW,MAAkC;AACpD,QAAM,IAAI,kBAAkB,KAAK,KAAK,KAAK,CAAC;AAC5C,MAAI,CAAC;AAAG,WAAO;AAEf,SAAO;AAAA,IACL,OAAO,OAAO,EAAE,CAAC,KAAK,CAAC;AAAA,IACvB,MAAM,OAAO,EAAE,CAAC,KAAK,EAAE;AAAA,EACzB;AACF;AAEA,SAAS,aAAa,YAAmD;AACvE,QAAM,UAAU,YAAuC,YAAY,0BAA0B;AAC7F,MAAI,CAAC,MAAM,QAAQ,OAAO;AAAG,WAAO;AAEpC,QAAM,WAA0B,CAAC;AAEjC,aAAW,SAAS,SAAS;AAC3B,QAAI,CAAC,OAAO;AAAY;AAExB,UAAM,SAAS,WAAW,MAAM,UAAU;AAC1C,QAAI;AAAQ,eAAS,KAAK,MAAM;AAAA,EAClC;AAEA,SAAO;AACT;AAEA,SAAS,SAAS,MAA6B;AAC7C,QAAM,WAA0B,CAAC;AAEjC,aAAW,KAAK,KAAK,SAAS,iBAAiB,GAAG;AAChD,aAAS,KAAK;AAAA,MACZ,OAAO,OAAO,EAAE,CAAC,KAAK,CAAC;AAAA,MACvB,MAAM,OAAO,EAAE,CAAC,KAAK,EAAE;AAAA,IACzB,CAAC;AAAA,EACH;AAEA,SAAO;AACT;AAEO,SAAS,gBAAgB,YAA6B,OAAiC;AAC5F,QAAM,aAAa,aAAa,UAAU;AAC1C,MAAI,cAAc,WAAW,SAAS;AAAG,WAAO;AAEhD,QAAM,OAAO,OAAO,MAAM,YAAY,aAAa,MAAM,QAAQ,IAAI;AAErE,SAAO,SAAS,IAAI;AACtB;","names":[]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/engine/runAnalysis/services/derive-vitals/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,UAAU,CAAC;AAEtC,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/engine/runAnalysis/services/derive-vitals/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,UAAU,CAAC;AAEtC,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AAK5D,wBAAgB,YAAY,CAAC,KAAK,EAAE,YAAY,CAAC,OAAO,KAAK,CAAC,EAAE,SAAS,EAAE,MAAM,GAAG,YAAY,CAc/F"}
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import { makeResearcher } from "../../../researcherAdapter";
|
|
2
|
+
import { buildHeadingTree } from "./heading-tree";
|
|
3
|
+
import { extractHeadings } from "./headings";
|
|
2
4
|
import { countImages, countParagraphs, countSentences, countVideos, countWords, estimateReadingTime, findProminentWords } from "./researches";
|
|
3
5
|
function deriveVitals(paper, keyphrase) {
|
|
4
6
|
const researcher = makeResearcher(paper);
|
|
@@ -10,7 +12,8 @@ function deriveVitals(paper, keyphrase) {
|
|
|
10
12
|
images: countImages(researcher),
|
|
11
13
|
videos: countVideos(researcher),
|
|
12
14
|
readingTimeMinutes: estimateReadingTime({ researcher, words }),
|
|
13
|
-
prominentWords: findProminentWords({ researcher, keyphrase })
|
|
15
|
+
prominentWords: findProminentWords({ researcher, keyphrase }),
|
|
16
|
+
headings: buildHeadingTree(extractHeadings(researcher, paper))
|
|
14
17
|
};
|
|
15
18
|
}
|
|
16
19
|
export {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../../src/engine/runAnalysis/services/derive-vitals/index.ts"],"sourcesContent":["import type { Paper } from \"yoastseo\";\nimport { makeResearcher } from \"../../../researcherAdapter\";\nimport type { VitalsResult } from \"../../../types/analysis\";\nimport { countImages, countParagraphs, countSentences, countVideos, countWords, estimateReadingTime, findProminentWords } from \"./researches\";\n\nexport function deriveVitals(paper: InstanceType<typeof Paper>, keyphrase: string): VitalsResult {\n const researcher = makeResearcher(paper);\n const words = countWords(researcher);\n\n return {\n words,\n sentences: countSentences(researcher),\n paragraphs: countParagraphs(researcher),\n images: countImages(researcher),\n videos: countVideos(researcher),\n readingTimeMinutes: estimateReadingTime({ researcher, words }),\n prominentWords: findProminentWords({ researcher, keyphrase }),\n };\n}\n"],"mappings":"AACA,SAAS,sBAAsB;AAE/B,SAAS,aAAa,iBAAiB,gBAAgB,aAAa,YAAY,qBAAqB,0BAA0B;AAExH,SAAS,aAAa,OAAmC,WAAiC;AAC/F,QAAM,aAAa,eAAe,KAAK;AACvC,QAAM,QAAQ,WAAW,UAAU;AAEnC,SAAO;AAAA,IACL;AAAA,IACA,WAAW,eAAe,UAAU;AAAA,IACpC,YAAY,gBAAgB,UAAU;AAAA,IACtC,QAAQ,YAAY,UAAU;AAAA,IAC9B,QAAQ,YAAY,UAAU;AAAA,IAC9B,oBAAoB,oBAAoB,EAAE,YAAY,MAAM,CAAC;AAAA,IAC7D,gBAAgB,mBAAmB,EAAE,YAAY,UAAU,CAAC;AAAA,
|
|
1
|
+
{"version":3,"sources":["../../../../../src/engine/runAnalysis/services/derive-vitals/index.ts"],"sourcesContent":["import type { Paper } from \"yoastseo\";\nimport { makeResearcher } from \"../../../researcherAdapter\";\nimport type { VitalsResult } from \"../../../types/analysis\";\nimport { buildHeadingTree } from \"./heading-tree\";\nimport { extractHeadings } from \"./headings\";\nimport { countImages, countParagraphs, countSentences, countVideos, countWords, estimateReadingTime, findProminentWords } from \"./researches\";\n\nexport function deriveVitals(paper: InstanceType<typeof Paper>, keyphrase: string): VitalsResult {\n const researcher = makeResearcher(paper);\n const words = countWords(researcher);\n\n return {\n words,\n sentences: countSentences(researcher),\n paragraphs: countParagraphs(researcher),\n images: countImages(researcher),\n videos: countVideos(researcher),\n readingTimeMinutes: estimateReadingTime({ researcher, words }),\n prominentWords: findProminentWords({ researcher, keyphrase }),\n headings: buildHeadingTree(extractHeadings(researcher, paper)),\n };\n}\n"],"mappings":"AACA,SAAS,sBAAsB;AAE/B,SAAS,wBAAwB;AACjC,SAAS,uBAAuB;AAChC,SAAS,aAAa,iBAAiB,gBAAgB,aAAa,YAAY,qBAAqB,0BAA0B;AAExH,SAAS,aAAa,OAAmC,WAAiC;AAC/F,QAAM,aAAa,eAAe,KAAK;AACvC,QAAM,QAAQ,WAAW,UAAU;AAEnC,SAAO;AAAA,IACL;AAAA,IACA,WAAW,eAAe,UAAU;AAAA,IACpC,YAAY,gBAAgB,UAAU;AAAA,IACtC,QAAQ,YAAY,UAAU;AAAA,IAC9B,QAAQ,YAAY,UAAU;AAAA,IAC9B,oBAAoB,oBAAoB,EAAE,YAAY,MAAM,CAAC;AAAA,IAC7D,gBAAgB,mBAAmB,EAAE,YAAY,UAAU,CAAC;AAAA,IAC5D,UAAU,iBAAiB,gBAAgB,YAAY,KAAK,CAAC;AAAA,EAC/D;AACF;","names":[]}
|
|
@@ -23,6 +23,22 @@ export interface ProminentWord {
|
|
|
23
23
|
count: number;
|
|
24
24
|
isKeyphrase: boolean;
|
|
25
25
|
}
|
|
26
|
+
export type HeadingLevel = 1 | 2 | 3 | 4 | 5 | 6;
|
|
27
|
+
export interface HeadingNode {
|
|
28
|
+
id: string;
|
|
29
|
+
level: HeadingLevel;
|
|
30
|
+
text: string;
|
|
31
|
+
children: HeadingNode[];
|
|
32
|
+
}
|
|
33
|
+
export interface HeadingLevelCount {
|
|
34
|
+
level: HeadingLevel;
|
|
35
|
+
count: number;
|
|
36
|
+
}
|
|
37
|
+
export interface HeadingStructure {
|
|
38
|
+
total: number;
|
|
39
|
+
levels: HeadingLevelCount[];
|
|
40
|
+
tree: HeadingNode[];
|
|
41
|
+
}
|
|
26
42
|
export interface VitalsResult {
|
|
27
43
|
words: number;
|
|
28
44
|
sentences: number;
|
|
@@ -31,6 +47,7 @@ export interface VitalsResult {
|
|
|
31
47
|
videos: number;
|
|
32
48
|
readingTimeMinutes: number;
|
|
33
49
|
prominentWords: ProminentWord[];
|
|
50
|
+
headings: HeadingStructure;
|
|
34
51
|
}
|
|
35
52
|
export interface SerpResult {
|
|
36
53
|
title: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"analysis.d.ts","sourceRoot":"","sources":["../../../src/engine/types/analysis.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAErD,MAAM,MAAM,MAAM,GAAG,MAAM,GAAG,MAAM,GAAG,KAAK,CAAC;AAE7C,MAAM,MAAM,WAAW,GAAG,MAAM,GAAG,MAAM,CAAC;AAE1C,MAAM,WAAW,WAAW;IAC1B,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC/B,GAAG,CAAC,EAAE,aAAa,CAAC;CACrB;AAED,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;CAClB;AACD,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,aAAa,EAAE,CAAC;CACxB;AAED,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,OAAO,CAAC;CACtB;AAED,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,kBAAkB,EAAE,MAAM,CAAC;IAC3B,cAAc,EAAE,aAAa,EAAE,CAAC;
|
|
1
|
+
{"version":3,"file":"analysis.d.ts","sourceRoot":"","sources":["../../../src/engine/types/analysis.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAErD,MAAM,MAAM,MAAM,GAAG,MAAM,GAAG,MAAM,GAAG,KAAK,CAAC;AAE7C,MAAM,MAAM,WAAW,GAAG,MAAM,GAAG,MAAM,CAAC;AAE1C,MAAM,WAAW,WAAW;IAC1B,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC/B,GAAG,CAAC,EAAE,aAAa,CAAC;CACrB;AAED,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;CAClB;AACD,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,aAAa,EAAE,CAAC;CACxB;AAED,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,OAAO,CAAC;CACtB;AAED,MAAM,MAAM,YAAY,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;AAEjD,MAAM,WAAW,WAAW;IAC1B,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,YAAY,CAAC;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,WAAW,EAAE,CAAC;CACzB;AAED,MAAM,WAAW,iBAAiB;IAChC,KAAK,EAAE,YAAY,CAAC;IACpB,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,gBAAgB;IAC/B,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,iBAAiB,EAAE,CAAC;IAC5B,IAAI,EAAE,WAAW,EAAE,CAAC;CACrB;AAED,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,kBAAkB,EAAE,MAAM,CAAC;IAC3B,cAAc,EAAE,aAAa,EAAE,CAAC;IAChC,QAAQ,EAAE,gBAAgB,CAAC;CAC5B;AAED,MAAM,WAAW,UAAU;IACzB,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,MAAM,CAAC;IACZ,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,cAAc;IAC7B,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,WAAW,EAAE,CAAC;CACvB;AAED,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC;IAC9C,SAAS,EAAE,cAAc,CAAC;IAC1B,MAAM,EAAE,cAAc,CAAC;IACvB,WAAW,EAAE,cAAc,CAAC;IAC5B,SAAS,EAAE;QACT,SAAS,EAAE,MAAM,CAAC;QAClB,MAAM,EAAE,MAAM,CAAC;QACf,UAAU,EAAE,iBAAiB,EAAE,CAAC;QAChC,eAAe,EAAE,MAAM,EAAE,CAAC;KAC3B,CAAC;IACF,MAAM,EAAE,YAAY,CAAC;IACrB,IAAI,EAAE,UAAU,CAAC;CAClB;AAED,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC;IACxC,GAAG,EAAE;QACH,QAAQ,EAAE,OAAO,CAAC;QAClB,eAAe,EAAE,OAAO,CAAC;QACzB,IAAI,EAAE,OAAO,CAAC;QACd,OAAO,EAAE,OAAO,CAAC;KAClB,CAAC;CACH"}
|