sanity-plugin-seofields 1.8.0 → 1.10.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 +508 -26
- package/dist/SeoHealthTool-2COI27KI.cjs +8 -0
- package/dist/SeoHealthTool-2COI27KI.cjs.map +1 -0
- package/dist/SeoHealthTool-CWI3KB2V.js +8 -0
- package/dist/SeoHealthTool-CWI3KB2V.js.map +1 -0
- package/dist/{SeoPreview-3EXR6FD4.cjs → SeoPreview-LMZAWWOE.cjs} +35 -38
- package/dist/SeoPreview-LMZAWWOE.cjs.map +1 -0
- package/dist/{SeoPreview-4PPAF4NO.js → SeoPreview-UNQBKTQO.js} +14 -11
- package/dist/SeoPreview-UNQBKTQO.js.map +1 -0
- package/dist/{chunk-B5IVI5LP.cjs → chunk-5XTQRILL.cjs} +286 -236
- package/dist/chunk-5XTQRILL.cjs.map +1 -0
- package/dist/{chunk-254YHUN3.cjs → chunk-7N4MLTMR.js} +8 -6
- package/dist/chunk-7N4MLTMR.js.map +1 -0
- package/dist/{chunk-DDAAVRWG.js → chunk-A57XNQC7.cjs} +9 -4
- package/dist/chunk-A57XNQC7.cjs.map +1 -0
- package/dist/chunk-BWLJDK5J.js +624 -0
- package/dist/chunk-BWLJDK5J.js.map +1 -0
- package/dist/chunk-CRCXC45D.js +56 -0
- package/dist/chunk-CRCXC45D.js.map +1 -0
- package/dist/chunk-EUG4MNRC.cjs +713 -0
- package/dist/chunk-EUG4MNRC.cjs.map +1 -0
- package/dist/{chunk-ZBHLMQTS.cjs → chunk-HHO2AKAP.js} +44 -17
- package/dist/chunk-HHO2AKAP.js.map +1 -0
- package/dist/chunk-NLEB47UV.js +713 -0
- package/dist/chunk-NLEB47UV.js.map +1 -0
- package/dist/chunk-OULUDJPI.cjs +254 -0
- package/dist/chunk-OULUDJPI.cjs.map +1 -0
- package/dist/chunk-R2U7JF7U.cjs +624 -0
- package/dist/chunk-R2U7JF7U.cjs.map +1 -0
- package/dist/chunk-XD4HKLEA.js +254 -0
- package/dist/chunk-XD4HKLEA.js.map +1 -0
- package/dist/chunk-XYAZJ3WX.cjs +56 -0
- package/dist/chunk-XYAZJ3WX.cjs.map +1 -0
- package/dist/{chunk-VR44E62I.js → chunk-XZKQWV2H.js} +204 -33
- package/dist/chunk-XZKQWV2H.js.map +1 -0
- package/dist/{chunk-HDZZQCH7.js → chunk-Y46ACXM4.cjs} +45 -5
- package/dist/chunk-Y46ACXM4.cjs.map +1 -0
- package/dist/cli.js +27 -27
- package/dist/{component-DEXwtemT.d.ts → component-CjT1hvxh.d.ts} +2 -2
- package/dist/{component-BzI-LHPw.d.cts → component-WYh0z8as.d.cts} +2 -2
- package/dist/define-cli.cjs +2 -4
- package/dist/define-cli.cjs.map +1 -1
- package/dist/define-cli.js +4 -4
- package/dist/define-cli.js.map +1 -1
- package/dist/head.cjs +22 -0
- package/dist/head.cjs.map +1 -0
- package/dist/head.d.cts +314 -0
- package/dist/head.d.ts +314 -0
- package/dist/head.js +22 -0
- package/dist/head.js.map +1 -0
- package/dist/hreflang-_VbSuWYD.d.cts +29 -0
- package/dist/hreflang-_VbSuWYD.d.ts +29 -0
- package/dist/index.cjs +1072 -368
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +7 -374
- package/dist/index.d.ts +7 -374
- package/dist/index.js +1015 -288
- package/dist/index.js.map +1 -1
- package/dist/next.cjs +212 -455
- package/dist/next.cjs.map +1 -1
- package/dist/next.d.cts +9 -206
- package/dist/next.d.ts +9 -206
- package/dist/next.js +189 -111
- package/dist/next.js.map +1 -1
- package/dist/plugin-HFuWZsJu.d.cts +516 -0
- package/dist/plugin-oQUCim56.d.ts +516 -0
- package/dist/schema/next.cjs +173 -327
- package/dist/schema/next.cjs.map +1 -1
- package/dist/schema/next.d.cts +4 -4
- package/dist/schema/next.d.ts +4 -4
- package/dist/schema/next.js +172 -8
- package/dist/schema/next.js.map +1 -1
- package/dist/schema.cjs +376 -517
- package/dist/schema.cjs.map +1 -1
- package/dist/schema.d.cts +5 -5
- package/dist/schema.d.ts +5 -5
- package/dist/schema.js +216 -11
- package/dist/schema.js.map +1 -1
- package/dist/server.cjs +149 -0
- package/dist/server.cjs.map +1 -0
- package/dist/server.d.cts +100 -0
- package/dist/server.d.ts +100 -0
- package/dist/server.js +149 -0
- package/dist/server.js.map +1 -0
- package/dist/{types-CW8qFdAn.d.ts → types-BAdN1RMu.d.ts} +2 -2
- package/dist/{types-B_vjMPtM.d.cts → types-C5i3KMgs.d.cts} +2 -2
- package/dist/{types-BXSCbl6p.d.cts → types-DP-DiW6f.d.cts} +2 -2
- package/dist/{types-C19cQx5D.d.ts → types-DRLUGLtX.d.ts} +2 -2
- package/dist/{types-yVmQfby9.d.cts → types-DxlPXihz.d.cts} +1 -1
- package/dist/{types-yVmQfby9.d.ts → types-DxlPXihz.d.ts} +1 -1
- package/package.json +25 -4
- package/dist/SeoHealthDashboard-AEKVVMUR-7NWV3C3Y.js +0 -4
- package/dist/SeoHealthDashboard-AEKVVMUR-7NWV3C3Y.js.map +0 -1
- package/dist/SeoHealthDashboard-AEKVVMUR-XWKJUH24.cjs +0 -10
- package/dist/SeoHealthDashboard-AEKVVMUR-XWKJUH24.cjs.map +0 -1
- package/dist/SeoHealthTool-2KKQJLJL.cjs +0 -11
- package/dist/SeoHealthTool-2KKQJLJL.cjs.map +0 -1
- package/dist/SeoHealthTool-3CUKGADZ.js +0 -5
- package/dist/SeoHealthTool-3CUKGADZ.js.map +0 -1
- package/dist/SeoPreview-3EXR6FD4.cjs.map +0 -1
- package/dist/SeoPreview-4PPAF4NO.js.map +0 -1
- package/dist/chunk-254YHUN3.cjs.map +0 -1
- package/dist/chunk-27XSYENH.js +0 -2215
- package/dist/chunk-27XSYENH.js.map +0 -1
- package/dist/chunk-B5IVI5LP.cjs.map +0 -1
- package/dist/chunk-BNXMFD3T.cjs +0 -431
- package/dist/chunk-BNXMFD3T.cjs.map +0 -1
- package/dist/chunk-DDAAVRWG.js.map +0 -1
- package/dist/chunk-HDZZQCH7.js.map +0 -1
- package/dist/chunk-P6IOWIO2.cjs +0 -480
- package/dist/chunk-P6IOWIO2.cjs.map +0 -1
- package/dist/chunk-UOCZFYYP.js +0 -407
- package/dist/chunk-UOCZFYYP.js.map +0 -1
- package/dist/chunk-VR44E62I.js.map +0 -1
- package/dist/chunk-WKXHX3GO.js +0 -424
- package/dist/chunk-WKXHX3GO.js.map +0 -1
- package/dist/chunk-XZDLJ2N6.cjs +0 -2224
- package/dist/chunk-XZDLJ2N6.cjs.map +0 -1
- package/dist/chunk-ZBHLMQTS.cjs.map +0 -1
package/dist/index.js
CHANGED
|
@@ -1,15 +1,59 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
import {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
import {
|
|
10
|
-
|
|
11
|
-
|
|
1
|
+
import {
|
|
2
|
+
buildHreflangs
|
|
3
|
+
} from "./chunk-CRCXC45D.js";
|
|
4
|
+
import {
|
|
5
|
+
analyzeReadability,
|
|
6
|
+
generateSeoText,
|
|
7
|
+
pickTestOutput
|
|
8
|
+
} from "./chunk-NLEB47UV.js";
|
|
9
|
+
import {
|
|
10
|
+
SchemaOrgJsonLdPreview,
|
|
11
|
+
tokenizeHtml
|
|
12
|
+
} from "./chunk-XZKQWV2H.js";
|
|
13
|
+
import {
|
|
14
|
+
getFocusKeywordPlacement,
|
|
15
|
+
getMetaDescriptionValidationMessages,
|
|
16
|
+
getMetaImageValidation,
|
|
17
|
+
getMetaTitleValidationMessages,
|
|
18
|
+
getOgDescriptionValidation,
|
|
19
|
+
getOgImageUrlValidation,
|
|
20
|
+
getOgImageValidation,
|
|
21
|
+
getOgTitleValidation,
|
|
22
|
+
getTwitterDescriptionValidation,
|
|
23
|
+
getTwitterImageUrlValidation,
|
|
24
|
+
getTwitterImageValidation,
|
|
25
|
+
getTwitterTitleValidation,
|
|
26
|
+
hasKeywordOveruse,
|
|
27
|
+
hasMatchingKeyword
|
|
28
|
+
} from "./chunk-HHO2AKAP.js";
|
|
29
|
+
import {
|
|
30
|
+
__spreadProps,
|
|
31
|
+
__spreadValues
|
|
32
|
+
} from "./chunk-7N4MLTMR.js";
|
|
12
33
|
|
|
34
|
+
// src/plugin.ts
|
|
35
|
+
import { createElement as createElement2, lazy as lazy2, Suspense as Suspense2 } from "react";
|
|
36
|
+
import { definePlugin } from "sanity";
|
|
37
|
+
|
|
38
|
+
// src/actions/SeoPublishGateAction.tsx
|
|
39
|
+
import { createSeoPublishGateAction } from "seofields-pro";
|
|
40
|
+
|
|
41
|
+
// src/schemas/index.ts
|
|
42
|
+
import { createElement, lazy, Suspense } from "react";
|
|
43
|
+
import {
|
|
44
|
+
defineField as defineField3,
|
|
45
|
+
defineType as defineType3
|
|
46
|
+
} from "sanity";
|
|
47
|
+
|
|
48
|
+
// src/components/geo/GEOChecklist.tsx
|
|
49
|
+
import { useMemo, useState } from "react";
|
|
50
|
+
import { useFormValue } from "sanity";
|
|
51
|
+
import {
|
|
52
|
+
buildGEOProChecks,
|
|
53
|
+
GEOChecklistProChecks,
|
|
54
|
+
GEOLockedTeaser
|
|
55
|
+
} from "seofields-pro";
|
|
56
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
13
57
|
var GEOChecklist = (props) => {
|
|
14
58
|
var _a;
|
|
15
59
|
const { path, schemaType } = props;
|
|
@@ -339,23 +383,174 @@ function CheckRow({ check }) {
|
|
|
339
383
|
);
|
|
340
384
|
}
|
|
341
385
|
var GEOChecklist_default = GEOChecklist;
|
|
386
|
+
|
|
387
|
+
// src/components/meta/FocusKeywordInput.tsx
|
|
388
|
+
import { Stack, Text as Text2 } from "@sanity/ui";
|
|
389
|
+
import { useMemo as useMemo2 } from "react";
|
|
390
|
+
import { PatchEvent, set, useFormValue as useFormValue3 } from "sanity";
|
|
391
|
+
|
|
392
|
+
// src/components/ai/SeoGenButton.tsx
|
|
393
|
+
import { SparklesIcon } from "@sanity/icons";
|
|
394
|
+
import { Button, Card, Flex, Text } from "@sanity/ui";
|
|
395
|
+
import { useCallback, useEffect, useRef, useState as useState2 } from "react";
|
|
396
|
+
import { useFormValue as useFormValue2, useWorkspace } from "sanity";
|
|
397
|
+
|
|
398
|
+
// src/utils/extractDocText.ts
|
|
399
|
+
function extractBlockText(block) {
|
|
400
|
+
if (block._type === "block" && Array.isArray(block.children)) {
|
|
401
|
+
return block.children.map((s) => {
|
|
402
|
+
var _a;
|
|
403
|
+
return (_a = s.text) != null ? _a : "";
|
|
404
|
+
}).join("");
|
|
405
|
+
}
|
|
406
|
+
const parts = [];
|
|
407
|
+
for (const key of Object.keys(block)) {
|
|
408
|
+
if (key === "_type" || key === "_key") continue;
|
|
409
|
+
const val = block[key];
|
|
410
|
+
if (typeof val === "string" && val.trim()) parts.push(val.trim());
|
|
411
|
+
else if (Array.isArray(val)) parts.push(extractArrayText(val));
|
|
412
|
+
}
|
|
413
|
+
return parts.filter(Boolean).join(" ");
|
|
414
|
+
}
|
|
415
|
+
function extractArrayText(arr) {
|
|
416
|
+
return arr.map((b) => extractBlockText(b)).filter(Boolean).join("\n");
|
|
417
|
+
}
|
|
418
|
+
function extractFieldText(value) {
|
|
419
|
+
if (typeof value === "string") return value;
|
|
420
|
+
if (!Array.isArray(value)) return "";
|
|
421
|
+
return extractArrayText(value).replace(/\n{3,}/g, "\n\n").trim();
|
|
422
|
+
}
|
|
423
|
+
function extractDocText(doc, bodyField) {
|
|
424
|
+
const fields = [bodyField].flat();
|
|
425
|
+
const text = fields.map((f) => extractFieldText(doc[f])).filter(Boolean).join("\n\n");
|
|
426
|
+
return text.slice(0, 4e3);
|
|
427
|
+
}
|
|
428
|
+
function resolveContentFields(content, docType) {
|
|
429
|
+
var _a;
|
|
430
|
+
if (!content || typeof content === "string" || Array.isArray(content)) return content != null ? content : "body";
|
|
431
|
+
const key = docType && docType in content ? docType : "default";
|
|
432
|
+
return (_a = content[key]) != null ? _a : "body";
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
// src/components/ai/SeoGenButton.tsx
|
|
436
|
+
import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
437
|
+
function SeoGenButton({
|
|
438
|
+
field,
|
|
439
|
+
ai,
|
|
440
|
+
seoFieldPath,
|
|
441
|
+
onGenerate
|
|
442
|
+
}) {
|
|
443
|
+
var _a, _b, _c, _d, _e, _f, _g;
|
|
444
|
+
const [state, setState] = useState2("idle");
|
|
445
|
+
const [errorMsg, setErrorMsg] = useState2(null);
|
|
446
|
+
const abortRef = useRef(null);
|
|
447
|
+
const cooldownRef = useRef(null);
|
|
448
|
+
const rootDoc = useFormValue2([]);
|
|
449
|
+
const workspace = useWorkspace();
|
|
450
|
+
const seoObj = useFormValue2([seoFieldPath]);
|
|
451
|
+
const focusKeyword = (_a = seoObj == null ? void 0 : seoObj.focusKeyword) != null ? _a : "";
|
|
452
|
+
const keywords = (_b = seoObj == null ? void 0 : seoObj.keywords) != null ? _b : [];
|
|
453
|
+
const bodyField = resolveContentFields(ai == null ? void 0 : ai.content, rootDoc == null ? void 0 : rootDoc._type);
|
|
454
|
+
const content = rootDoc ? extractDocText(rootDoc, bodyField) : "";
|
|
455
|
+
const meta = field === "focusKeyword" ? {
|
|
456
|
+
title: (_c = seoObj == null ? void 0 : seoObj.title) != null ? _c : void 0,
|
|
457
|
+
description: (_d = seoObj == null ? void 0 : seoObj.description) != null ? _d : void 0,
|
|
458
|
+
slug: (_f = (_e = rootDoc == null ? void 0 : rootDoc.slug) == null ? void 0 : _e.current) != null ? _f : void 0
|
|
459
|
+
} : void 0;
|
|
460
|
+
const handleGenerate = useCallback(async () => {
|
|
461
|
+
var _a2;
|
|
462
|
+
if (!ai) return;
|
|
463
|
+
(_a2 = abortRef.current) == null ? void 0 : _a2.abort();
|
|
464
|
+
if (cooldownRef.current) clearTimeout(cooldownRef.current);
|
|
465
|
+
setState("loading");
|
|
466
|
+
setErrorMsg(null);
|
|
467
|
+
try {
|
|
468
|
+
let result;
|
|
469
|
+
if (ai.testMode) {
|
|
470
|
+
await new Promise((r) => setTimeout(r, 400));
|
|
471
|
+
result = pickTestOutput(field);
|
|
472
|
+
} else {
|
|
473
|
+
const controller = new AbortController();
|
|
474
|
+
abortRef.current = controller;
|
|
475
|
+
result = await generateSeoText(field, content, focusKeyword, keywords, {
|
|
476
|
+
config: __spreadProps(__spreadValues({}, ai), { _projectId: workspace.projectId }),
|
|
477
|
+
signal: controller.signal,
|
|
478
|
+
meta
|
|
479
|
+
});
|
|
480
|
+
}
|
|
481
|
+
onGenerate(result);
|
|
482
|
+
setState("cooldown");
|
|
483
|
+
cooldownRef.current = setTimeout(() => setState("idle"), 2e3);
|
|
484
|
+
} catch (err) {
|
|
485
|
+
if (err.name === "AbortError") {
|
|
486
|
+
setState("idle");
|
|
487
|
+
return;
|
|
488
|
+
}
|
|
489
|
+
setErrorMsg(err instanceof Error ? err.message : "Generation failed.");
|
|
490
|
+
setState("error");
|
|
491
|
+
}
|
|
492
|
+
}, [ai, field, content, focusKeyword, keywords, meta, onGenerate, workspace.projectId]);
|
|
493
|
+
useEffect(() => {
|
|
494
|
+
return () => {
|
|
495
|
+
var _a2;
|
|
496
|
+
(_a2 = abortRef.current) == null ? void 0 : _a2.abort();
|
|
497
|
+
if (cooldownRef.current) clearTimeout(cooldownRef.current);
|
|
498
|
+
};
|
|
499
|
+
}, []);
|
|
500
|
+
const isConfigured = Boolean(
|
|
501
|
+
(ai == null ? void 0 : ai.apiKey) || (ai == null ? void 0 : ai.endpoint) || (ai == null ? void 0 : ai.testMode) || (ai == null ? void 0 : ai.provider) === "ollama"
|
|
502
|
+
);
|
|
503
|
+
if (!isConfigured) return null;
|
|
504
|
+
const isLoading = state === "loading";
|
|
505
|
+
const isTestMode = Boolean(ai == null ? void 0 : ai.testMode);
|
|
506
|
+
let buttonText = "Generate with AI";
|
|
507
|
+
if (isLoading) buttonText = "Generating\u2026";
|
|
508
|
+
else if (isTestMode) buttonText = "Generate (test)";
|
|
509
|
+
const isFullWidth = ((_g = ai == null ? void 0 : ai.buttonWidth) != null ? _g : "full") === "full";
|
|
510
|
+
return /* @__PURE__ */ jsxs2(Flex, { direction: "column", gap: 1, align: isFullWidth ? "stretch" : "flex-start", children: [
|
|
511
|
+
/* @__PURE__ */ jsx2(
|
|
512
|
+
Button,
|
|
513
|
+
{
|
|
514
|
+
mode: "ghost",
|
|
515
|
+
tone: "primary",
|
|
516
|
+
paddingX: isFullWidth ? 2 : 3,
|
|
517
|
+
paddingY: 3,
|
|
518
|
+
fontSize: 1,
|
|
519
|
+
icon: SparklesIcon,
|
|
520
|
+
text: buttonText,
|
|
521
|
+
onClick: handleGenerate,
|
|
522
|
+
disabled: isLoading || state === "cooldown"
|
|
523
|
+
}
|
|
524
|
+
),
|
|
525
|
+
!content && /* @__PURE__ */ jsxs2(Text, { size: 0, muted: true, children: [
|
|
526
|
+
"(Set ",
|
|
527
|
+
/* @__PURE__ */ jsx2("code", { children: "ai.content" }),
|
|
528
|
+
" in plugin config for better results)"
|
|
529
|
+
] }),
|
|
530
|
+
state === "error" && errorMsg && /* @__PURE__ */ jsx2(Card, { padding: 2, tone: "critical", radius: 2, children: /* @__PURE__ */ jsx2(Text, { size: 1, children: errorMsg }) })
|
|
531
|
+
] });
|
|
532
|
+
}
|
|
533
|
+
|
|
534
|
+
// src/components/meta/FocusKeywordInput.tsx
|
|
535
|
+
import { jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
342
536
|
var FocusKeywordInput = (props) => {
|
|
343
537
|
var _a;
|
|
344
|
-
const { value, renderDefault, path } = props;
|
|
345
|
-
const
|
|
346
|
-
const
|
|
347
|
-
const
|
|
348
|
-
|
|
538
|
+
const { value, renderDefault, path, schemaType, onChange } = props;
|
|
539
|
+
const { options } = schemaType;
|
|
540
|
+
const parent = useFormValue3([path[0]]);
|
|
541
|
+
const rootDoc = useFormValue3([]);
|
|
542
|
+
const feedbackItems = useMemo2(() => {
|
|
543
|
+
var _a2;
|
|
349
544
|
if (!value) return [];
|
|
350
|
-
const
|
|
351
|
-
const
|
|
352
|
-
const description = ((parent == null ? void 0 : parent.description) || "").toLowerCase();
|
|
545
|
+
const title = (parent == null ? void 0 : parent.title) || "";
|
|
546
|
+
const description = (parent == null ? void 0 : parent.description) || "";
|
|
353
547
|
const slug = ((_a2 = rootDoc == null ? void 0 : rootDoc.slug) == null ? void 0 : _a2.current) || "";
|
|
548
|
+
const placement = getFocusKeywordPlacement(value, title, description);
|
|
354
549
|
const items = [];
|
|
355
550
|
if (title) {
|
|
356
|
-
if (
|
|
551
|
+
if (placement.atStartOfTitle) {
|
|
357
552
|
items.push({ text: "Keyword at start of title \u2014 excellent", color: "green" });
|
|
358
|
-
} else if (
|
|
553
|
+
} else if (placement.inTitle) {
|
|
359
554
|
items.push({
|
|
360
555
|
text: "Keyword in title \u2014 move it to the start for more prominence",
|
|
361
556
|
color: "orange"
|
|
@@ -365,14 +560,14 @@ var FocusKeywordInput = (props) => {
|
|
|
365
560
|
}
|
|
366
561
|
}
|
|
367
562
|
if (description) {
|
|
368
|
-
if (
|
|
563
|
+
if (placement.inDescription) {
|
|
369
564
|
items.push({ text: "Keyword in meta description", color: "green" });
|
|
370
565
|
} else {
|
|
371
566
|
items.push({ text: "Not in description \u2014 include it naturally", color: "orange" });
|
|
372
567
|
}
|
|
373
568
|
}
|
|
374
569
|
if (slug) {
|
|
375
|
-
const kwSlug =
|
|
570
|
+
const kwSlug = value.toLowerCase().replace(/\s+/g, "-");
|
|
376
571
|
if (slug.includes(kwSlug)) {
|
|
377
572
|
items.push({ text: "Keyword in URL slug", color: "green" });
|
|
378
573
|
} else {
|
|
@@ -382,8 +577,7 @@ var FocusKeywordInput = (props) => {
|
|
|
382
577
|
});
|
|
383
578
|
}
|
|
384
579
|
}
|
|
385
|
-
|
|
386
|
-
if (((_b = title.match(new RegExp(safeKw, "g"))) != null ? _b : []).length > 2) {
|
|
580
|
+
if (placement.isStuffed) {
|
|
387
581
|
items.push({
|
|
388
582
|
text: "Keyword appears too many times in title \u2014 avoid stuffing",
|
|
389
583
|
color: "red"
|
|
@@ -391,10 +585,19 @@ var FocusKeywordInput = (props) => {
|
|
|
391
585
|
}
|
|
392
586
|
return items;
|
|
393
587
|
}, [value, parent == null ? void 0 : parent.title, parent == null ? void 0 : parent.description, (_a = rootDoc == null ? void 0 : rootDoc.slug) == null ? void 0 : _a.current]);
|
|
394
|
-
return /* @__PURE__ */
|
|
588
|
+
return /* @__PURE__ */ jsxs3(Stack, { space: 3, children: [
|
|
395
589
|
renderDefault(props),
|
|
396
|
-
/* @__PURE__ */
|
|
397
|
-
|
|
590
|
+
/* @__PURE__ */ jsx3(
|
|
591
|
+
SeoGenButton,
|
|
592
|
+
{
|
|
593
|
+
field: "focusKeyword",
|
|
594
|
+
ai: options == null ? void 0 : options.ai,
|
|
595
|
+
seoFieldPath: String(path[0]),
|
|
596
|
+
onGenerate: (v) => onChange(PatchEvent.from(set(v)))
|
|
597
|
+
}
|
|
598
|
+
),
|
|
599
|
+
/* @__PURE__ */ jsx3(Stack, { space: 2, children: feedbackItems.map((item) => /* @__PURE__ */ jsxs3("div", { style: { display: "flex", alignItems: "center", gap: 7 }, children: [
|
|
600
|
+
/* @__PURE__ */ jsx3(
|
|
398
601
|
"div",
|
|
399
602
|
{
|
|
400
603
|
style: {
|
|
@@ -405,87 +608,357 @@ var FocusKeywordInput = (props) => {
|
|
|
405
608
|
}
|
|
406
609
|
}
|
|
407
610
|
),
|
|
408
|
-
/* @__PURE__ */
|
|
611
|
+
/* @__PURE__ */ jsx3(Text2, { weight: "bold", muted: true, size: 14, children: item.text })
|
|
409
612
|
] }, item.text)) })
|
|
410
613
|
] });
|
|
411
614
|
};
|
|
412
615
|
var FocusKeywordInput_default = FocusKeywordInput;
|
|
413
616
|
|
|
414
|
-
// src/
|
|
415
|
-
|
|
617
|
+
// src/components/meta/HreflangInput.tsx
|
|
618
|
+
import { TranslateIcon } from "@sanity/icons";
|
|
619
|
+
import { Button as Button2, Card as Card2, Flex as Flex2, Stack as Stack2, Text as Text3 } from "@sanity/ui";
|
|
620
|
+
import { useCallback as useCallback2, useState as useState3 } from "react";
|
|
621
|
+
import { PatchEvent as PatchEvent2, set as set2, useClient, useFormValue as useFormValue4 } from "sanity";
|
|
622
|
+
import { jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
623
|
+
var DEFAULT_LOCALE_FIELD = "language";
|
|
624
|
+
var DEFAULT_API_VERSION = "2024-01-01";
|
|
625
|
+
function safeField(name) {
|
|
626
|
+
return name && /^[A-Za-z_][A-Za-z0-9_]*$/.test(name) ? name : DEFAULT_LOCALE_FIELD;
|
|
627
|
+
}
|
|
628
|
+
var HreflangInput = (props) => {
|
|
629
|
+
const { schemaType, onChange, renderDefault } = props;
|
|
630
|
+
const { options } = schemaType;
|
|
631
|
+
const { hreflang, baseUrl, apiVersion } = options != null ? options : {};
|
|
632
|
+
const rootDoc = useFormValue4([]);
|
|
633
|
+
const client = useClient({ apiVersion: apiVersion != null ? apiVersion : DEFAULT_API_VERSION });
|
|
634
|
+
const [state, setState] = useState3("idle");
|
|
635
|
+
const [message, setMessage] = useState3(null);
|
|
636
|
+
const localeField = safeField(hreflang == null ? void 0 : hreflang.localeField);
|
|
637
|
+
const handleSync = useCallback2(async () => {
|
|
638
|
+
var _a;
|
|
639
|
+
const rawId = rootDoc == null ? void 0 : rootDoc._id;
|
|
640
|
+
if (!rawId) {
|
|
641
|
+
setState("error");
|
|
642
|
+
setMessage("Save the document once before syncing translations.");
|
|
643
|
+
return;
|
|
644
|
+
}
|
|
645
|
+
setState("loading");
|
|
646
|
+
setMessage(null);
|
|
647
|
+
try {
|
|
648
|
+
const publishedId = rawId.replace(/^drafts\./, "");
|
|
649
|
+
const query = `*[_type == "translation.metadata" && references($id)][0].translations[].value->{
|
|
650
|
+
"language": ${localeField},
|
|
651
|
+
"slug": slug.current
|
|
652
|
+
}`;
|
|
653
|
+
const translations = (_a = await client.fetch(query, { id: publishedId })) != null ? _a : [];
|
|
654
|
+
const entries = buildHreflangs(translations, {
|
|
655
|
+
baseUrl,
|
|
656
|
+
resolvePath: hreflang == null ? void 0 : hreflang.resolvePath
|
|
657
|
+
});
|
|
658
|
+
if (entries.length === 0) {
|
|
659
|
+
setState("error");
|
|
660
|
+
setMessage("No translations with a resolvable URL were found for this document.");
|
|
661
|
+
return;
|
|
662
|
+
}
|
|
663
|
+
const items = entries.map((e) => ({
|
|
664
|
+
_type: "hreflangEntry",
|
|
665
|
+
_key: e.locale,
|
|
666
|
+
locale: e.locale,
|
|
667
|
+
url: e.url
|
|
668
|
+
}));
|
|
669
|
+
onChange(PatchEvent2.from(set2(items)));
|
|
670
|
+
setState("done");
|
|
671
|
+
setMessage(
|
|
672
|
+
`Synced ${items.length} alternate${items.length === 1 ? "" : "s"} from translations.`
|
|
673
|
+
);
|
|
674
|
+
} catch (err) {
|
|
675
|
+
setState("error");
|
|
676
|
+
setMessage(err instanceof Error ? err.message : "Failed to sync translations.");
|
|
677
|
+
}
|
|
678
|
+
}, [rootDoc == null ? void 0 : rootDoc._id, client, localeField, baseUrl, hreflang, onChange]);
|
|
679
|
+
return /* @__PURE__ */ jsxs4(Stack2, { space: 3, children: [
|
|
680
|
+
/* @__PURE__ */ jsx4(Flex2, { children: /* @__PURE__ */ jsx4(
|
|
681
|
+
Button2,
|
|
682
|
+
{
|
|
683
|
+
mode: "ghost",
|
|
684
|
+
tone: "primary",
|
|
685
|
+
fontSize: 1,
|
|
686
|
+
icon: TranslateIcon,
|
|
687
|
+
text: state === "loading" ? "Syncing\u2026" : "Sync from translations",
|
|
688
|
+
onClick: handleSync,
|
|
689
|
+
disabled: state === "loading"
|
|
690
|
+
}
|
|
691
|
+
) }),
|
|
692
|
+
message && /* @__PURE__ */ jsx4(Card2, { padding: 2, radius: 2, tone: state === "error" ? "critical" : "positive", children: /* @__PURE__ */ jsx4(Text3, { size: 1, children: message }) }),
|
|
693
|
+
renderDefault(props)
|
|
694
|
+
] });
|
|
695
|
+
};
|
|
696
|
+
var HreflangInput_default = HreflangInput;
|
|
697
|
+
|
|
698
|
+
// src/components/meta/KeywordsInput.tsx
|
|
699
|
+
import { Stack as Stack4 } from "@sanity/ui";
|
|
700
|
+
import { PatchEvent as PatchEvent3, set as set3 } from "sanity";
|
|
701
|
+
|
|
702
|
+
// src/components/ai/KeywordSuggestions.tsx
|
|
703
|
+
import { SparklesIcon as SparklesIcon2 } from "@sanity/icons";
|
|
704
|
+
import { Badge, Box, Button as Button3, Card as Card3, Flex as Flex3, Spinner, Stack as Stack3, Text as Text4 } from "@sanity/ui";
|
|
705
|
+
import { useCallback as useCallback3, useEffect as useEffect2, useRef as useRef2, useState as useState4 } from "react";
|
|
706
|
+
import { useFormValue as useFormValue5, useWorkspace as useWorkspace2 } from "sanity";
|
|
707
|
+
import { jsx as jsx5, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
708
|
+
function KeywordSuggestions({
|
|
709
|
+
ai,
|
|
710
|
+
seoFieldPath,
|
|
711
|
+
existing,
|
|
712
|
+
onAdd,
|
|
713
|
+
onAddAll
|
|
714
|
+
}) {
|
|
416
715
|
var _a;
|
|
417
|
-
const
|
|
418
|
-
|
|
419
|
-
const
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
716
|
+
const [panelState, setPanelState] = useState4("idle");
|
|
717
|
+
const [suggestions, setSuggestions] = useState4([]);
|
|
718
|
+
const [errorMsg, setErrorMsg] = useState4(null);
|
|
719
|
+
const abortRef = useRef2(null);
|
|
720
|
+
const rootDoc = useFormValue5([]);
|
|
721
|
+
const workspace = useWorkspace2();
|
|
722
|
+
const seoObj = useFormValue5([seoFieldPath]);
|
|
723
|
+
const focusKeyword = (_a = seoObj == null ? void 0 : seoObj.focusKeyword) != null ? _a : "";
|
|
724
|
+
const bodyField = resolveContentFields(ai == null ? void 0 : ai.content, rootDoc == null ? void 0 : rootDoc._type);
|
|
725
|
+
const content = rootDoc ? extractDocText(rootDoc, bodyField) : "";
|
|
726
|
+
const handleSuggest = useCallback3(async () => {
|
|
727
|
+
var _a2;
|
|
728
|
+
if (!ai) return;
|
|
729
|
+
(_a2 = abortRef.current) == null ? void 0 : _a2.abort();
|
|
730
|
+
abortRef.current = new AbortController();
|
|
731
|
+
setPanelState("loading");
|
|
732
|
+
setErrorMsg(null);
|
|
733
|
+
setSuggestions([]);
|
|
734
|
+
try {
|
|
735
|
+
let csv;
|
|
736
|
+
if (ai.testMode) {
|
|
737
|
+
await new Promise((r) => setTimeout(r, 400));
|
|
738
|
+
csv = pickTestOutput("keywords");
|
|
739
|
+
} else {
|
|
740
|
+
csv = await generateSeoText("keywords", content, focusKeyword, existing, {
|
|
741
|
+
config: __spreadProps(__spreadValues({}, ai), { _projectId: workspace.projectId }),
|
|
742
|
+
signal: abortRef.current.signal
|
|
743
|
+
});
|
|
744
|
+
}
|
|
745
|
+
const parsed = csv.split(",").map((k) => k.replace(/^["']|["']$/g, "").trim()).filter(Boolean);
|
|
746
|
+
if (parsed.length === 0) {
|
|
747
|
+
setErrorMsg("No keywords returned. Try again.");
|
|
748
|
+
setPanelState("error");
|
|
749
|
+
return;
|
|
750
|
+
}
|
|
751
|
+
setSuggestions(parsed);
|
|
752
|
+
setPanelState("suggestions");
|
|
753
|
+
} catch (err) {
|
|
754
|
+
if (err.name === "AbortError") {
|
|
755
|
+
setPanelState("idle");
|
|
756
|
+
return;
|
|
757
|
+
}
|
|
758
|
+
setErrorMsg(err instanceof Error ? err.message : "Keyword generation failed.");
|
|
759
|
+
setPanelState("error");
|
|
760
|
+
}
|
|
761
|
+
}, [ai, content, focusKeyword, existing, workspace.projectId]);
|
|
762
|
+
const handleAdd = useCallback3(
|
|
763
|
+
(kw) => {
|
|
764
|
+
onAdd(kw);
|
|
765
|
+
setSuggestions((prev) => prev.filter((s) => s !== kw));
|
|
766
|
+
if (suggestions.length <= 1) setPanelState("idle");
|
|
767
|
+
},
|
|
768
|
+
[onAdd, suggestions.length]
|
|
769
|
+
);
|
|
770
|
+
const handleAddAll = useCallback3(() => {
|
|
771
|
+
const toAdd = suggestions.filter((kw) => !existing.includes(kw));
|
|
772
|
+
if (toAdd.length > 0) onAddAll(toAdd);
|
|
773
|
+
setSuggestions([]);
|
|
774
|
+
setPanelState("idle");
|
|
775
|
+
}, [suggestions, existing, onAddAll]);
|
|
776
|
+
const handleDismiss = useCallback3(() => {
|
|
777
|
+
var _a2;
|
|
778
|
+
(_a2 = abortRef.current) == null ? void 0 : _a2.abort();
|
|
779
|
+
setSuggestions([]);
|
|
780
|
+
setPanelState("idle");
|
|
781
|
+
setErrorMsg(null);
|
|
782
|
+
}, []);
|
|
783
|
+
useEffect2(() => {
|
|
784
|
+
return () => {
|
|
785
|
+
var _a2;
|
|
786
|
+
(_a2 = abortRef.current) == null ? void 0 : _a2.abort();
|
|
787
|
+
};
|
|
788
|
+
}, []);
|
|
789
|
+
const isConfigured = Boolean(
|
|
790
|
+
(ai == null ? void 0 : ai.apiKey) || (ai == null ? void 0 : ai.endpoint) || (ai == null ? void 0 : ai.testMode) || (ai == null ? void 0 : ai.provider) === "ollama"
|
|
791
|
+
);
|
|
792
|
+
if (!isConfigured) return null;
|
|
793
|
+
if (panelState === "idle" || panelState === "error") {
|
|
794
|
+
return /* @__PURE__ */ jsxs5(Stack3, { space: 2, children: [
|
|
795
|
+
/* @__PURE__ */ jsx5(
|
|
796
|
+
Button3,
|
|
797
|
+
{
|
|
798
|
+
mode: "ghost",
|
|
799
|
+
tone: "primary",
|
|
800
|
+
paddingX: 2,
|
|
801
|
+
paddingY: 3,
|
|
802
|
+
fontSize: 1,
|
|
803
|
+
icon: SparklesIcon2,
|
|
804
|
+
text: (ai == null ? void 0 : ai.testMode) ? "Suggest Keywords (test)" : "Suggest Keywords with AI",
|
|
805
|
+
onClick: handleSuggest
|
|
806
|
+
}
|
|
807
|
+
),
|
|
808
|
+
panelState === "error" && errorMsg && /* @__PURE__ */ jsx5(Card3, { padding: 2, tone: "critical", radius: 2, children: /* @__PURE__ */ jsx5(Text4, { size: 1, children: errorMsg }) })
|
|
809
|
+
] });
|
|
423
810
|
}
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
}
|
|
430
|
-
function analyzeReadability(text) {
|
|
431
|
-
const wordList = text.trim().split(/\s+/).filter(Boolean);
|
|
432
|
-
const words = wordList.length;
|
|
433
|
-
if (words < 10) return null;
|
|
434
|
-
const sentences = countSentences(text);
|
|
435
|
-
const syllables = wordList.reduce((acc, word) => acc + countSyllables(word), 0);
|
|
436
|
-
const rawScore = 206.835 - 1.015 * (words / sentences) - 84.6 * (syllables / words);
|
|
437
|
-
const score = Math.round(rawScore * 10) / 10;
|
|
438
|
-
const rawGrade = 0.39 * (words / sentences) + 11.8 * (syllables / words) - 15.59;
|
|
439
|
-
const gradeLevel = Math.round(rawGrade * 10) / 10;
|
|
440
|
-
const avgWordsPerSentence = Math.round(words / sentences * 10) / 10;
|
|
441
|
-
let label;
|
|
442
|
-
let color;
|
|
443
|
-
if (score >= 70) {
|
|
444
|
-
label = "Easy to read";
|
|
445
|
-
color = "green";
|
|
446
|
-
} else if (score >= 50) {
|
|
447
|
-
label = "Fairly easy";
|
|
448
|
-
color = "green";
|
|
449
|
-
} else if (score >= 30) {
|
|
450
|
-
label = "Moderately difficult";
|
|
451
|
-
color = "orange";
|
|
452
|
-
} else {
|
|
453
|
-
label = "Difficult to read";
|
|
454
|
-
color = "red";
|
|
811
|
+
if (panelState === "loading") {
|
|
812
|
+
return /* @__PURE__ */ jsxs5(Flex3, { align: "center", gap: 2, paddingY: 2, children: [
|
|
813
|
+
/* @__PURE__ */ jsx5(Spinner, { muted: true }),
|
|
814
|
+
/* @__PURE__ */ jsx5(Text4, { size: 1, muted: true, children: "Finding keywords\u2026" })
|
|
815
|
+
] });
|
|
455
816
|
}
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
817
|
+
const pendingSuggestions = suggestions.filter((kw) => !existing.includes(kw));
|
|
818
|
+
const alreadyAdded = suggestions.filter((kw) => existing.includes(kw));
|
|
819
|
+
return /* @__PURE__ */ jsx5(Card3, { padding: 3, radius: 2, tone: "transparent", border: true, children: /* @__PURE__ */ jsxs5(Stack3, { space: 3, children: [
|
|
820
|
+
/* @__PURE__ */ jsxs5(Flex3, { align: "center", justify: "space-between", children: [
|
|
821
|
+
/* @__PURE__ */ jsx5(Text4, { size: 1, weight: "semibold", muted: true, children: "AI keyword suggestions" }),
|
|
822
|
+
/* @__PURE__ */ jsxs5(Flex3, { gap: 2, children: [
|
|
823
|
+
pendingSuggestions.length > 1 && /* @__PURE__ */ jsx5(
|
|
824
|
+
Button3,
|
|
825
|
+
{
|
|
826
|
+
mode: "ghost",
|
|
827
|
+
tone: "primary",
|
|
828
|
+
paddingX: 2,
|
|
829
|
+
paddingY: 2,
|
|
830
|
+
fontSize: 1,
|
|
831
|
+
text: "Add all",
|
|
832
|
+
onClick: handleAddAll
|
|
833
|
+
}
|
|
834
|
+
),
|
|
835
|
+
/* @__PURE__ */ jsx5(
|
|
836
|
+
Button3,
|
|
837
|
+
{
|
|
838
|
+
mode: "ghost",
|
|
839
|
+
tone: "default",
|
|
840
|
+
paddingX: 2,
|
|
841
|
+
paddingY: 2,
|
|
842
|
+
fontSize: 1,
|
|
843
|
+
text: "Dismiss",
|
|
844
|
+
onClick: handleDismiss
|
|
845
|
+
}
|
|
846
|
+
)
|
|
847
|
+
] })
|
|
848
|
+
] }),
|
|
849
|
+
pendingSuggestions.length > 0 && /* @__PURE__ */ jsxs5(Box, { children: [
|
|
850
|
+
/* @__PURE__ */ jsx5(Text4, { size: 0, muted: true, style: { marginBottom: 8 }, children: "Click to add:" }),
|
|
851
|
+
/* @__PURE__ */ jsx5(Flex3, { gap: 2, wrap: "wrap", style: { marginTop: 6 }, children: pendingSuggestions.map((kw) => /* @__PURE__ */ jsxs5(
|
|
852
|
+
"button",
|
|
853
|
+
{
|
|
854
|
+
type: "button",
|
|
855
|
+
onClick: () => handleAdd(kw),
|
|
856
|
+
style: {
|
|
857
|
+
padding: "4px 10px",
|
|
858
|
+
borderRadius: 20,
|
|
859
|
+
border: "1px solid var(--card-border-color)",
|
|
860
|
+
background: "transparent",
|
|
861
|
+
color: "var(--card-fg-color)",
|
|
862
|
+
cursor: "pointer",
|
|
863
|
+
fontSize: 12,
|
|
864
|
+
lineHeight: 1.4,
|
|
865
|
+
transition: "background 0.15s"
|
|
866
|
+
},
|
|
867
|
+
onMouseEnter: (e) => {
|
|
868
|
+
;
|
|
869
|
+
e.currentTarget.style.background = "var(--card-border-color)";
|
|
870
|
+
},
|
|
871
|
+
onMouseLeave: (e) => {
|
|
872
|
+
;
|
|
873
|
+
e.currentTarget.style.background = "transparent";
|
|
874
|
+
},
|
|
875
|
+
children: [
|
|
876
|
+
"+ ",
|
|
877
|
+
kw
|
|
878
|
+
]
|
|
879
|
+
},
|
|
880
|
+
kw
|
|
881
|
+
)) })
|
|
882
|
+
] }),
|
|
883
|
+
alreadyAdded.length > 0 && /* @__PURE__ */ jsxs5(Box, { children: [
|
|
884
|
+
/* @__PURE__ */ jsx5(Text4, { size: 0, muted: true, style: { marginBottom: 6 }, children: "Already added:" }),
|
|
885
|
+
/* @__PURE__ */ jsx5(Flex3, { gap: 2, wrap: "wrap", style: { marginTop: 4 }, children: alreadyAdded.map((kw) => /* @__PURE__ */ jsxs5(Badge, { tone: "positive", radius: 5, fontSize: 0, padding: 2, children: [
|
|
886
|
+
"\u2713 ",
|
|
887
|
+
kw
|
|
888
|
+
] }, kw)) })
|
|
889
|
+
] }),
|
|
890
|
+
pendingSuggestions.length === 0 && /* @__PURE__ */ jsx5(Text4, { size: 1, muted: true, children: "All suggested keywords added." })
|
|
891
|
+
] }) });
|
|
465
892
|
}
|
|
893
|
+
|
|
894
|
+
// src/components/meta/KeywordsInput.tsx
|
|
895
|
+
import { jsx as jsx6, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
896
|
+
var KeywordsInput = (props) => {
|
|
897
|
+
const { value, renderDefault, path, schemaType, onChange } = props;
|
|
898
|
+
const { options } = schemaType;
|
|
899
|
+
const existing = value != null ? value : [];
|
|
900
|
+
const handleAdd = (kw) => {
|
|
901
|
+
if (existing.includes(kw)) return;
|
|
902
|
+
onChange(PatchEvent3.from(set3([...existing, kw])));
|
|
903
|
+
};
|
|
904
|
+
const handleAddAll = (keywords) => {
|
|
905
|
+
const merged = [.../* @__PURE__ */ new Set([...existing, ...keywords])];
|
|
906
|
+
onChange(PatchEvent3.from(set3(merged)));
|
|
907
|
+
};
|
|
908
|
+
return /* @__PURE__ */ jsxs6(Stack4, { space: 3, children: [
|
|
909
|
+
renderDefault(props),
|
|
910
|
+
/* @__PURE__ */ jsx6(
|
|
911
|
+
KeywordSuggestions,
|
|
912
|
+
{
|
|
913
|
+
ai: options == null ? void 0 : options.ai,
|
|
914
|
+
seoFieldPath: String(path[0]),
|
|
915
|
+
existing,
|
|
916
|
+
onAdd: handleAdd,
|
|
917
|
+
onAddAll: handleAddAll
|
|
918
|
+
}
|
|
919
|
+
)
|
|
920
|
+
] });
|
|
921
|
+
};
|
|
922
|
+
var KeywordsInput_default = KeywordsInput;
|
|
923
|
+
|
|
924
|
+
// src/components/meta/MetaDescription.tsx
|
|
925
|
+
import { Stack as Stack5, Text as Text5 } from "@sanity/ui";
|
|
926
|
+
import { useMemo as useMemo3 } from "react";
|
|
927
|
+
import { PatchEvent as PatchEvent4, set as set4, useFormValue as useFormValue6 } from "sanity";
|
|
928
|
+
import { jsx as jsx7, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
466
929
|
var MetaDescription = (props) => {
|
|
467
|
-
const { value, renderDefault, path } = props;
|
|
468
|
-
const
|
|
930
|
+
const { value, renderDefault, path, schemaType, onChange } = props;
|
|
931
|
+
const { options } = schemaType;
|
|
932
|
+
const parent = useFormValue6([path[0]]);
|
|
469
933
|
const isParentseoField = parent && (parent == null ? void 0 : parent._type) === "seoFields";
|
|
470
|
-
const keywords =
|
|
471
|
-
const feedbackItems =
|
|
934
|
+
const keywords = useMemo3(() => (parent == null ? void 0 : parent.keywords) || [], [parent == null ? void 0 : parent.keywords]);
|
|
935
|
+
const feedbackItems = useMemo3(
|
|
472
936
|
() => getMetaDescriptionValidationMessages(value || "", keywords, isParentseoField),
|
|
473
937
|
[value, keywords, isParentseoField]
|
|
474
938
|
);
|
|
475
|
-
const readability =
|
|
476
|
-
return /* @__PURE__ */
|
|
939
|
+
const readability = useMemo3(() => analyzeReadability(value || ""), [value]);
|
|
940
|
+
return /* @__PURE__ */ jsxs7(Stack5, { space: 3, children: [
|
|
477
941
|
renderDefault(props),
|
|
478
|
-
/* @__PURE__ */
|
|
479
|
-
|
|
942
|
+
/* @__PURE__ */ jsx7(
|
|
943
|
+
SeoGenButton,
|
|
944
|
+
{
|
|
945
|
+
field: "description",
|
|
946
|
+
ai: options == null ? void 0 : options.ai,
|
|
947
|
+
seoFieldPath: String(path[0]),
|
|
948
|
+
onGenerate: (v) => onChange(PatchEvent4.from(set4(v)))
|
|
949
|
+
}
|
|
950
|
+
),
|
|
951
|
+
/* @__PURE__ */ jsx7(Stack5, { space: 2, children: feedbackItems.map((item) => /* @__PURE__ */ jsxs7("div", { style: { display: "flex", alignItems: "center", gap: 7 }, children: [
|
|
952
|
+
/* @__PURE__ */ jsx7(
|
|
480
953
|
"div",
|
|
481
954
|
{
|
|
482
955
|
style: { width: 10, height: 10, borderRadius: "50%", backgroundColor: item.color }
|
|
483
956
|
}
|
|
484
957
|
),
|
|
485
|
-
/* @__PURE__ */
|
|
958
|
+
/* @__PURE__ */ jsx7(Text5, { weight: "bold", muted: true, size: 14, children: item.text })
|
|
486
959
|
] }, item.text)) }),
|
|
487
|
-
readability && /* @__PURE__ */
|
|
488
|
-
/* @__PURE__ */
|
|
960
|
+
readability && /* @__PURE__ */ jsxs7("div", { style: { display: "flex", alignItems: "center", gap: 7 }, children: [
|
|
961
|
+
/* @__PURE__ */ jsx7(
|
|
489
962
|
"div",
|
|
490
963
|
{
|
|
491
964
|
style: {
|
|
@@ -496,7 +969,7 @@ var MetaDescription = (props) => {
|
|
|
496
969
|
}
|
|
497
970
|
}
|
|
498
971
|
),
|
|
499
|
-
/* @__PURE__ */
|
|
972
|
+
/* @__PURE__ */ jsxs7(Text5, { weight: "bold", muted: true, size: 14, children: [
|
|
500
973
|
"Readability: ",
|
|
501
974
|
readability.label,
|
|
502
975
|
" (Flesch ",
|
|
@@ -510,18 +983,24 @@ var MetaDescription = (props) => {
|
|
|
510
983
|
] });
|
|
511
984
|
};
|
|
512
985
|
var MetaDescription_default = MetaDescription;
|
|
986
|
+
|
|
987
|
+
// src/components/meta/MetaImage.tsx
|
|
988
|
+
import { Stack as Stack6, Text as Text6 } from "@sanity/ui";
|
|
989
|
+
import { useMemo as useMemo4 } from "react";
|
|
990
|
+
import { useFormValue as useFormValue7 } from "sanity";
|
|
991
|
+
import { jsx as jsx8, jsxs as jsxs8 } from "react/jsx-runtime";
|
|
513
992
|
var MetaImage = (props) => {
|
|
514
993
|
const { value, renderDefault, path } = props;
|
|
515
|
-
const seoParent =
|
|
994
|
+
const seoParent = useFormValue7([path[0]]);
|
|
516
995
|
const hasImage = !!(value == null ? void 0 : value.asset);
|
|
517
|
-
const feedbackItems =
|
|
996
|
+
const feedbackItems = useMemo4(
|
|
518
997
|
() => getMetaImageValidation(hasImage, seoParent),
|
|
519
998
|
[hasImage, seoParent]
|
|
520
999
|
);
|
|
521
|
-
return /* @__PURE__ */
|
|
1000
|
+
return /* @__PURE__ */ jsxs8(Stack6, { space: 3, children: [
|
|
522
1001
|
renderDefault(props),
|
|
523
|
-
/* @__PURE__ */
|
|
524
|
-
/* @__PURE__ */
|
|
1002
|
+
/* @__PURE__ */ jsx8(Stack6, { space: 2, children: feedbackItems.map((item) => /* @__PURE__ */ jsxs8("div", { style: { display: "flex", alignItems: "center", gap: 7 }, children: [
|
|
1003
|
+
/* @__PURE__ */ jsx8(
|
|
525
1004
|
"div",
|
|
526
1005
|
{
|
|
527
1006
|
style: {
|
|
@@ -532,11 +1011,17 @@ var MetaImage = (props) => {
|
|
|
532
1011
|
}
|
|
533
1012
|
}
|
|
534
1013
|
),
|
|
535
|
-
/* @__PURE__ */
|
|
1014
|
+
/* @__PURE__ */ jsx8(Text6, { weight: "bold", muted: true, size: 14, children: item.text })
|
|
536
1015
|
] }, item.text)) })
|
|
537
1016
|
] });
|
|
538
1017
|
};
|
|
539
1018
|
var MetaImage_default = MetaImage;
|
|
1019
|
+
|
|
1020
|
+
// src/components/meta/MetaTagsPreview.tsx
|
|
1021
|
+
import { Box as Box2, Button as Button4, Card as Card4, Flex as Flex4, Stack as Stack7, Text as Text7 } from "@sanity/ui";
|
|
1022
|
+
import { useMemo as useMemo5, useState as useState5 } from "react";
|
|
1023
|
+
import { useClient as useClient2, useColorScheme, useFormValue as useFormValue8 } from "sanity";
|
|
1024
|
+
import { jsx as jsx9, jsxs as jsxs9 } from "react/jsx-runtime";
|
|
540
1025
|
function resolveImageUrl(asset, projectId, dataset) {
|
|
541
1026
|
const ref = asset == null ? void 0 : asset._ref;
|
|
542
1027
|
if (!ref) return null;
|
|
@@ -548,13 +1033,13 @@ function resolveImageUrl(asset, projectId, dataset) {
|
|
|
548
1033
|
}
|
|
549
1034
|
var MetaTagsPreview = (props) => {
|
|
550
1035
|
const { path } = props;
|
|
551
|
-
const [expanded, setExpanded] =
|
|
552
|
-
const [copyLabel, setCopyLabel] =
|
|
1036
|
+
const [expanded, setExpanded] = useState5(false);
|
|
1037
|
+
const [copyLabel, setCopyLabel] = useState5("Copy");
|
|
553
1038
|
const { scheme } = useColorScheme();
|
|
554
|
-
const seoFields =
|
|
555
|
-
const client =
|
|
1039
|
+
const seoFields = useFormValue8([path[0]]);
|
|
1040
|
+
const client = useClient2({ apiVersion: "2024-01-01" });
|
|
556
1041
|
const { projectId = "", dataset = "" } = client.config();
|
|
557
|
-
const rawHtml =
|
|
1042
|
+
const rawHtml = useMemo5(() => {
|
|
558
1043
|
var _a, _b, _c, _d, _e, _f, _g;
|
|
559
1044
|
const lines = [];
|
|
560
1045
|
lines.push('<meta charset="UTF-8" />');
|
|
@@ -610,8 +1095,8 @@ var MetaTagsPreview = (props) => {
|
|
|
610
1095
|
}
|
|
611
1096
|
return lines.join("\n");
|
|
612
1097
|
}, [seoFields, projectId, dataset]);
|
|
613
|
-
const tagCount =
|
|
614
|
-
const tokens =
|
|
1098
|
+
const tagCount = useMemo5(() => rawHtml.split("\n").filter(Boolean).length, [rawHtml]);
|
|
1099
|
+
const tokens = useMemo5(() => tokenizeHtml(rawHtml, scheme), [rawHtml, scheme]);
|
|
615
1100
|
const handleCopy = () => {
|
|
616
1101
|
navigator.clipboard.writeText(rawHtml).then(() => {
|
|
617
1102
|
setCopyLabel("Copied!");
|
|
@@ -624,16 +1109,16 @@ var MetaTagsPreview = (props) => {
|
|
|
624
1109
|
const headerBg = isDark ? "#21262d" : "#f0f2f4";
|
|
625
1110
|
const headerBorder = isDark ? "#30363d" : "#d0d7de";
|
|
626
1111
|
const headerText = isDark ? "#e6edf3" : "#24292f";
|
|
627
|
-
return /* @__PURE__ */
|
|
628
|
-
/* @__PURE__ */
|
|
629
|
-
/* @__PURE__ */
|
|
630
|
-
/* @__PURE__ */
|
|
631
|
-
/* @__PURE__ */
|
|
1112
|
+
return /* @__PURE__ */ jsx9(Card4, { padding: 3, radius: 2, tone: "default", border: true, children: /* @__PURE__ */ jsxs9(Stack7, { space: 3, children: [
|
|
1113
|
+
/* @__PURE__ */ jsxs9(Flex4, { align: "center", justify: "space-between", gap: 3, children: [
|
|
1114
|
+
/* @__PURE__ */ jsx9(Text7, { weight: "semibold", size: 1, children: "Meta Tags Preview" }),
|
|
1115
|
+
/* @__PURE__ */ jsxs9(Flex4, { gap: 2, align: "center", children: [
|
|
1116
|
+
/* @__PURE__ */ jsxs9(Text7, { size: 0, muted: true, children: [
|
|
632
1117
|
tagCount,
|
|
633
1118
|
" tags generated"
|
|
634
1119
|
] }),
|
|
635
|
-
/* @__PURE__ */
|
|
636
|
-
|
|
1120
|
+
/* @__PURE__ */ jsx9(
|
|
1121
|
+
Button4,
|
|
637
1122
|
{
|
|
638
1123
|
text: copyLabel,
|
|
639
1124
|
tone: "default",
|
|
@@ -645,7 +1130,7 @@ var MetaTagsPreview = (props) => {
|
|
|
645
1130
|
)
|
|
646
1131
|
] })
|
|
647
1132
|
] }),
|
|
648
|
-
/* @__PURE__ */
|
|
1133
|
+
/* @__PURE__ */ jsxs9(
|
|
649
1134
|
"button",
|
|
650
1135
|
{
|
|
651
1136
|
type: "button",
|
|
@@ -666,12 +1151,12 @@ var MetaTagsPreview = (props) => {
|
|
|
666
1151
|
color: headerText
|
|
667
1152
|
},
|
|
668
1153
|
children: [
|
|
669
|
-
/* @__PURE__ */
|
|
1154
|
+
/* @__PURE__ */ jsx9("span", { style: { fontSize: 10 }, children: expanded ? "\u25B2" : "\u25BC" }),
|
|
670
1155
|
expanded ? "Hide tags" : "Show tags"
|
|
671
1156
|
]
|
|
672
1157
|
}
|
|
673
1158
|
),
|
|
674
|
-
expanded && /* @__PURE__ */
|
|
1159
|
+
expanded && /* @__PURE__ */ jsxs9(
|
|
675
1160
|
"div",
|
|
676
1161
|
{
|
|
677
1162
|
style: {
|
|
@@ -680,7 +1165,7 @@ var MetaTagsPreview = (props) => {
|
|
|
680
1165
|
overflow: "hidden"
|
|
681
1166
|
},
|
|
682
1167
|
children: [
|
|
683
|
-
/* @__PURE__ */
|
|
1168
|
+
/* @__PURE__ */ jsxs9(
|
|
684
1169
|
"div",
|
|
685
1170
|
{
|
|
686
1171
|
style: {
|
|
@@ -692,7 +1177,7 @@ var MetaTagsPreview = (props) => {
|
|
|
692
1177
|
gap: 6
|
|
693
1178
|
},
|
|
694
1179
|
children: [
|
|
695
|
-
/* @__PURE__ */
|
|
1180
|
+
/* @__PURE__ */ jsx9(
|
|
696
1181
|
"span",
|
|
697
1182
|
{
|
|
698
1183
|
style: {
|
|
@@ -704,12 +1189,12 @@ var MetaTagsPreview = (props) => {
|
|
|
704
1189
|
}
|
|
705
1190
|
}
|
|
706
1191
|
),
|
|
707
|
-
/* @__PURE__ */
|
|
1192
|
+
/* @__PURE__ */ jsx9("span", { style: { fontSize: 11, color: headerText, fontFamily: "monospace" }, children: "HTML" })
|
|
708
1193
|
]
|
|
709
1194
|
}
|
|
710
1195
|
),
|
|
711
|
-
/* @__PURE__ */
|
|
712
|
-
|
|
1196
|
+
/* @__PURE__ */ jsx9(
|
|
1197
|
+
Box2,
|
|
713
1198
|
{
|
|
714
1199
|
as: "pre",
|
|
715
1200
|
padding: 3,
|
|
@@ -724,7 +1209,7 @@ var MetaTagsPreview = (props) => {
|
|
|
724
1209
|
wordBreak: "break-word",
|
|
725
1210
|
backgroundColor: codeBg
|
|
726
1211
|
},
|
|
727
|
-
children: tokens.map((token, idx) => /* @__PURE__ */
|
|
1212
|
+
children: tokens.map((token, idx) => /* @__PURE__ */ jsx9("span", { style: { color: token.color }, children: token.text }, idx))
|
|
728
1213
|
}
|
|
729
1214
|
)
|
|
730
1215
|
]
|
|
@@ -733,20 +1218,26 @@ var MetaTagsPreview = (props) => {
|
|
|
733
1218
|
] }) });
|
|
734
1219
|
};
|
|
735
1220
|
var MetaTagsPreview_default = MetaTagsPreview;
|
|
1221
|
+
|
|
1222
|
+
// src/components/meta/MetaTitle.tsx
|
|
1223
|
+
import { Stack as Stack8, Text as Text8 } from "@sanity/ui";
|
|
1224
|
+
import { useEffect as useEffect3, useMemo as useMemo6, useState as useState6 } from "react";
|
|
1225
|
+
import { PatchEvent as PatchEvent5, set as set5, useClient as useClient3, useFormValue as useFormValue9 } from "sanity";
|
|
1226
|
+
import { jsx as jsx10, jsxs as jsxs10 } from "react/jsx-runtime";
|
|
736
1227
|
var MetaTitle = (props) => {
|
|
737
1228
|
var _a, _b, _c;
|
|
738
|
-
const { value, renderDefault, path, schemaType } = props;
|
|
1229
|
+
const { value, renderDefault, path, schemaType, onChange } = props;
|
|
739
1230
|
const { options } = schemaType;
|
|
740
|
-
const parent =
|
|
1231
|
+
const parent = useFormValue9([path[0]]);
|
|
741
1232
|
const isParentseoField = parent && (parent == null ? void 0 : parent._type) === "seoFields";
|
|
742
|
-
const keywords =
|
|
743
|
-
const rootDoc = (_a =
|
|
744
|
-
const client =
|
|
745
|
-
const [groqTitleSuffix, setGroqTitleSuffix] =
|
|
746
|
-
const [isDuplicateTitle, setIsDuplicateTitle] =
|
|
1233
|
+
const keywords = useMemo6(() => (parent == null ? void 0 : parent.keywords) || [], [parent == null ? void 0 : parent.keywords]);
|
|
1234
|
+
const rootDoc = (_a = useFormValue9([])) != null ? _a : {};
|
|
1235
|
+
const client = useClient3({ apiVersion: (_b = options == null ? void 0 : options.apiVersion) != null ? _b : "2024-01-01" });
|
|
1236
|
+
const [groqTitleSuffix, setGroqTitleSuffix] = useState6("");
|
|
1237
|
+
const [isDuplicateTitle, setIsDuplicateTitle] = useState6(false);
|
|
747
1238
|
const titleSuffixQuery = options == null ? void 0 : options.titleSuffixQuery;
|
|
748
1239
|
const titleSuffixOption = options == null ? void 0 : options.titleSuffix;
|
|
749
|
-
|
|
1240
|
+
useEffect3(() => {
|
|
750
1241
|
if (!titleSuffixQuery) return;
|
|
751
1242
|
client.fetch(titleSuffixQuery).then((result) => {
|
|
752
1243
|
setGroqTitleSuffix(result === null || result === void 0 ? "" : String(result));
|
|
@@ -755,7 +1246,7 @@ var MetaTitle = (props) => {
|
|
|
755
1246
|
});
|
|
756
1247
|
}, [titleSuffixQuery, client]);
|
|
757
1248
|
const currentDocId = (_c = rootDoc._id) != null ? _c : "";
|
|
758
|
-
|
|
1249
|
+
useEffect3(() => {
|
|
759
1250
|
if (!(value == null ? void 0 : value.trim()) || !currentDocId) {
|
|
760
1251
|
setIsDuplicateTitle(false);
|
|
761
1252
|
return () => {
|
|
@@ -769,7 +1260,7 @@ var MetaTitle = (props) => {
|
|
|
769
1260
|
}, 600);
|
|
770
1261
|
return () => clearTimeout(timer);
|
|
771
1262
|
}, [value, client, currentDocId]);
|
|
772
|
-
const resolvedSuffix =
|
|
1263
|
+
const resolvedSuffix = useMemo6(() => {
|
|
773
1264
|
if (titleSuffixQuery) return groqTitleSuffix;
|
|
774
1265
|
if (!titleSuffixOption) return "";
|
|
775
1266
|
if (typeof titleSuffixOption === "function") {
|
|
@@ -778,15 +1269,24 @@ var MetaTitle = (props) => {
|
|
|
778
1269
|
return titleSuffixOption;
|
|
779
1270
|
}, [titleSuffixQuery, groqTitleSuffix, titleSuffixOption, rootDoc]);
|
|
780
1271
|
const suffixLength = resolvedSuffix ? resolvedSuffix.length + 3 : 0;
|
|
781
|
-
const feedbackItems =
|
|
1272
|
+
const feedbackItems = useMemo6(
|
|
782
1273
|
() => getMetaTitleValidationMessages(value || "", keywords, isParentseoField, suffixLength),
|
|
783
1274
|
[value, keywords, isParentseoField, suffixLength]
|
|
784
1275
|
);
|
|
785
|
-
return /* @__PURE__ */
|
|
1276
|
+
return /* @__PURE__ */ jsxs10(Stack8, { space: 3, children: [
|
|
786
1277
|
renderDefault(props),
|
|
787
|
-
/* @__PURE__ */
|
|
788
|
-
|
|
789
|
-
|
|
1278
|
+
/* @__PURE__ */ jsx10(
|
|
1279
|
+
SeoGenButton,
|
|
1280
|
+
{
|
|
1281
|
+
field: "title",
|
|
1282
|
+
ai: options == null ? void 0 : options.ai,
|
|
1283
|
+
seoFieldPath: String(path[0]),
|
|
1284
|
+
onGenerate: (v) => onChange(PatchEvent5.from(set5(v)))
|
|
1285
|
+
}
|
|
1286
|
+
),
|
|
1287
|
+
/* @__PURE__ */ jsxs10(Stack8, { space: 2, children: [
|
|
1288
|
+
feedbackItems.map((item) => /* @__PURE__ */ jsxs10("div", { style: { display: "flex", alignItems: "center", gap: 7 }, children: [
|
|
1289
|
+
/* @__PURE__ */ jsx10(
|
|
790
1290
|
"div",
|
|
791
1291
|
{
|
|
792
1292
|
style: {
|
|
@@ -797,10 +1297,10 @@ var MetaTitle = (props) => {
|
|
|
797
1297
|
}
|
|
798
1298
|
}
|
|
799
1299
|
),
|
|
800
|
-
/* @__PURE__ */
|
|
1300
|
+
/* @__PURE__ */ jsx10(Text8, { weight: "bold", muted: true, size: 14, children: item.text })
|
|
801
1301
|
] }, item.text)),
|
|
802
|
-
isDuplicateTitle && /* @__PURE__ */
|
|
803
|
-
/* @__PURE__ */
|
|
1302
|
+
isDuplicateTitle && /* @__PURE__ */ jsxs10("div", { style: { display: "flex", alignItems: "center", gap: 7 }, children: [
|
|
1303
|
+
/* @__PURE__ */ jsx10(
|
|
804
1304
|
"div",
|
|
805
1305
|
{
|
|
806
1306
|
style: {
|
|
@@ -811,7 +1311,7 @@ var MetaTitle = (props) => {
|
|
|
811
1311
|
}
|
|
812
1312
|
}
|
|
813
1313
|
),
|
|
814
|
-
/* @__PURE__ */
|
|
1314
|
+
/* @__PURE__ */ jsx10(Text8, { weight: "bold", muted: true, size: 14, children: "Duplicate meta title \u2014 another published document uses this exact title." })
|
|
815
1315
|
] })
|
|
816
1316
|
] })
|
|
817
1317
|
] });
|
|
@@ -819,6 +1319,10 @@ var MetaTitle = (props) => {
|
|
|
819
1319
|
var MetaTitle_default = MetaTitle;
|
|
820
1320
|
|
|
821
1321
|
// src/utils/fieldsUtils.ts
|
|
1322
|
+
function withLicense(ai, licenseKey) {
|
|
1323
|
+
if (!ai) return void 0;
|
|
1324
|
+
return licenseKey ? __spreadProps(__spreadValues({}, ai), { _licenseKey: licenseKey }) : ai;
|
|
1325
|
+
}
|
|
822
1326
|
var DEFAULT_FIELD_INFO = {
|
|
823
1327
|
title: {
|
|
824
1328
|
title: "Meta Title",
|
|
@@ -956,19 +1460,38 @@ var getFieldHiddenFunction = (fieldName, config) => {
|
|
|
956
1460
|
var isEmpty = (value) => {
|
|
957
1461
|
return value === null || value === void 0 || typeof value === "string" && value.trim() === "" || Array.isArray(value) && value.length === 0 || typeof value === "object" && !Array.isArray(value) && Object.keys(value).length === 0;
|
|
958
1462
|
};
|
|
1463
|
+
|
|
1464
|
+
// src/schemas/types/openGraph/index.ts
|
|
1465
|
+
import { defineField, defineType } from "sanity";
|
|
1466
|
+
|
|
1467
|
+
// src/components/openGraph/OgDescription.tsx
|
|
1468
|
+
import { Stack as Stack9, Text as Text9 } from "@sanity/ui";
|
|
1469
|
+
import { useMemo as useMemo7 } from "react";
|
|
1470
|
+
import { PatchEvent as PatchEvent6, set as set6, useFormValue as useFormValue10 } from "sanity";
|
|
1471
|
+
import { jsx as jsx11, jsxs as jsxs11 } from "react/jsx-runtime";
|
|
959
1472
|
var OgDescription = (props) => {
|
|
960
|
-
const { value, renderDefault, path } = props;
|
|
961
|
-
const
|
|
1473
|
+
const { value, renderDefault, path, schemaType, onChange } = props;
|
|
1474
|
+
const { options } = schemaType;
|
|
1475
|
+
const parent = useFormValue10([path[0]]);
|
|
962
1476
|
const isParentseoField = parent && (parent == null ? void 0 : parent._type) === "seoFields";
|
|
963
|
-
const keywords =
|
|
964
|
-
const feedbackItems =
|
|
1477
|
+
const keywords = useMemo7(() => (parent == null ? void 0 : parent.keywords) || [], [parent == null ? void 0 : parent.keywords]);
|
|
1478
|
+
const feedbackItems = useMemo7(
|
|
965
1479
|
() => getOgDescriptionValidation(value || "", keywords, isParentseoField),
|
|
966
1480
|
[value, keywords, isParentseoField]
|
|
967
1481
|
);
|
|
968
|
-
return /* @__PURE__ */
|
|
1482
|
+
return /* @__PURE__ */ jsxs11(Stack9, { space: 3, children: [
|
|
969
1483
|
renderDefault(props),
|
|
970
|
-
/* @__PURE__ */
|
|
971
|
-
|
|
1484
|
+
/* @__PURE__ */ jsx11(
|
|
1485
|
+
SeoGenButton,
|
|
1486
|
+
{
|
|
1487
|
+
field: "ogDescription",
|
|
1488
|
+
ai: options == null ? void 0 : options.ai,
|
|
1489
|
+
seoFieldPath: String(path[0]),
|
|
1490
|
+
onGenerate: (v) => onChange(PatchEvent6.from(set6(v)))
|
|
1491
|
+
}
|
|
1492
|
+
),
|
|
1493
|
+
/* @__PURE__ */ jsx11(Stack9, { space: 2, children: feedbackItems.map((item) => /* @__PURE__ */ jsxs11("div", { style: { display: "flex", alignItems: "center", gap: 7 }, children: [
|
|
1494
|
+
/* @__PURE__ */ jsx11(
|
|
972
1495
|
"div",
|
|
973
1496
|
{
|
|
974
1497
|
style: {
|
|
@@ -979,25 +1502,31 @@ var OgDescription = (props) => {
|
|
|
979
1502
|
}
|
|
980
1503
|
}
|
|
981
1504
|
),
|
|
982
|
-
/* @__PURE__ */
|
|
1505
|
+
/* @__PURE__ */ jsx11(Text9, { weight: "bold", muted: true, size: 14, children: item.text })
|
|
983
1506
|
] }, item.text)) })
|
|
984
1507
|
] });
|
|
985
1508
|
};
|
|
986
1509
|
var OgDescription_default = OgDescription;
|
|
1510
|
+
|
|
1511
|
+
// src/components/openGraph/OgImage.tsx
|
|
1512
|
+
import { Stack as Stack10, Text as Text10 } from "@sanity/ui";
|
|
1513
|
+
import { useMemo as useMemo8 } from "react";
|
|
1514
|
+
import { useFormValue as useFormValue11 } from "sanity";
|
|
1515
|
+
import { jsx as jsx12, jsxs as jsxs12 } from "react/jsx-runtime";
|
|
987
1516
|
var OgImage = (props) => {
|
|
988
1517
|
const { value, renderDefault, path } = props;
|
|
989
|
-
const seoParent =
|
|
1518
|
+
const seoParent = useFormValue11([path[0]]);
|
|
990
1519
|
const imgValue = value;
|
|
991
1520
|
const hasImage = !!(imgValue == null ? void 0 : imgValue.asset);
|
|
992
1521
|
const altText = imgValue == null ? void 0 : imgValue.alt;
|
|
993
|
-
const feedbackItems =
|
|
1522
|
+
const feedbackItems = useMemo8(
|
|
994
1523
|
() => getOgImageValidation(hasImage, altText, seoParent),
|
|
995
1524
|
[hasImage, altText, seoParent]
|
|
996
1525
|
);
|
|
997
|
-
return /* @__PURE__ */
|
|
1526
|
+
return /* @__PURE__ */ jsxs12(Stack10, { space: 3, children: [
|
|
998
1527
|
renderDefault(props),
|
|
999
|
-
/* @__PURE__ */
|
|
1000
|
-
/* @__PURE__ */
|
|
1528
|
+
/* @__PURE__ */ jsx12(Stack10, { space: 2, children: feedbackItems.map((item) => /* @__PURE__ */ jsxs12("div", { style: { display: "flex", alignItems: "center", gap: 7 }, children: [
|
|
1529
|
+
/* @__PURE__ */ jsx12(
|
|
1001
1530
|
"div",
|
|
1002
1531
|
{
|
|
1003
1532
|
style: {
|
|
@@ -1008,19 +1537,25 @@ var OgImage = (props) => {
|
|
|
1008
1537
|
}
|
|
1009
1538
|
}
|
|
1010
1539
|
),
|
|
1011
|
-
/* @__PURE__ */
|
|
1540
|
+
/* @__PURE__ */ jsx12(Text10, { weight: "bold", muted: true, size: 14, children: item.text })
|
|
1012
1541
|
] }, item.text)) })
|
|
1013
1542
|
] });
|
|
1014
1543
|
};
|
|
1015
1544
|
var OgImage_default = OgImage;
|
|
1545
|
+
|
|
1546
|
+
// src/components/openGraph/OgImageUrl.tsx
|
|
1547
|
+
import { Stack as Stack11, Text as Text11 } from "@sanity/ui";
|
|
1548
|
+
import { useMemo as useMemo9 } from "react";
|
|
1549
|
+
import { useFormValue as useFormValue12 } from "sanity";
|
|
1550
|
+
import { jsx as jsx13, jsxs as jsxs13 } from "react/jsx-runtime";
|
|
1016
1551
|
var OgImageUrl = (props) => {
|
|
1017
1552
|
const { value, renderDefault, path } = props;
|
|
1018
|
-
const seoParent =
|
|
1019
|
-
const feedbackItems =
|
|
1020
|
-
return /* @__PURE__ */
|
|
1553
|
+
const seoParent = useFormValue12([path[0]]);
|
|
1554
|
+
const feedbackItems = useMemo9(() => getOgImageUrlValidation(value, seoParent), [value, seoParent]);
|
|
1555
|
+
return /* @__PURE__ */ jsxs13(Stack11, { space: 3, children: [
|
|
1021
1556
|
renderDefault(props),
|
|
1022
|
-
/* @__PURE__ */
|
|
1023
|
-
/* @__PURE__ */
|
|
1557
|
+
/* @__PURE__ */ jsx13(Stack11, { space: 2, children: feedbackItems.map((item) => /* @__PURE__ */ jsxs13("div", { style: { display: "flex", alignItems: "center", gap: 7 }, children: [
|
|
1558
|
+
/* @__PURE__ */ jsx13(
|
|
1024
1559
|
"div",
|
|
1025
1560
|
{
|
|
1026
1561
|
style: {
|
|
@@ -1031,24 +1566,40 @@ var OgImageUrl = (props) => {
|
|
|
1031
1566
|
}
|
|
1032
1567
|
}
|
|
1033
1568
|
),
|
|
1034
|
-
/* @__PURE__ */
|
|
1569
|
+
/* @__PURE__ */ jsx13(Text11, { weight: "bold", muted: true, size: 14, children: item.text })
|
|
1035
1570
|
] }, item.text)) })
|
|
1036
1571
|
] });
|
|
1037
1572
|
};
|
|
1038
1573
|
var OgImageUrl_default = OgImageUrl;
|
|
1574
|
+
|
|
1575
|
+
// src/components/openGraph/OgTitle.tsx
|
|
1576
|
+
import { Stack as Stack12, Text as Text12 } from "@sanity/ui";
|
|
1577
|
+
import { useMemo as useMemo10 } from "react";
|
|
1578
|
+
import { PatchEvent as PatchEvent7, set as set7, useFormValue as useFormValue13 } from "sanity";
|
|
1579
|
+
import { jsx as jsx14, jsxs as jsxs14 } from "react/jsx-runtime";
|
|
1039
1580
|
var OgTitle = (props) => {
|
|
1040
|
-
const { value, renderDefault, path } = props;
|
|
1041
|
-
const
|
|
1581
|
+
const { value, renderDefault, path, schemaType, onChange } = props;
|
|
1582
|
+
const { options } = schemaType;
|
|
1583
|
+
const parent = useFormValue13([path[0]]);
|
|
1042
1584
|
const isParentseoField = parent && (parent == null ? void 0 : parent._type) === "seoFields";
|
|
1043
|
-
const keywords =
|
|
1044
|
-
const feedbackItems =
|
|
1585
|
+
const keywords = useMemo10(() => (parent == null ? void 0 : parent.keywords) || [], [parent == null ? void 0 : parent.keywords]);
|
|
1586
|
+
const feedbackItems = useMemo10(
|
|
1045
1587
|
() => getOgTitleValidation(value || "", keywords, isParentseoField),
|
|
1046
1588
|
[value, keywords, isParentseoField]
|
|
1047
1589
|
);
|
|
1048
|
-
return /* @__PURE__ */
|
|
1590
|
+
return /* @__PURE__ */ jsxs14(Stack12, { space: 3, children: [
|
|
1049
1591
|
renderDefault(props),
|
|
1050
|
-
/* @__PURE__ */
|
|
1051
|
-
|
|
1592
|
+
/* @__PURE__ */ jsx14(
|
|
1593
|
+
SeoGenButton,
|
|
1594
|
+
{
|
|
1595
|
+
field: "ogTitle",
|
|
1596
|
+
ai: options == null ? void 0 : options.ai,
|
|
1597
|
+
seoFieldPath: String(path[0]),
|
|
1598
|
+
onGenerate: (v) => onChange(PatchEvent7.from(set7(v)))
|
|
1599
|
+
}
|
|
1600
|
+
),
|
|
1601
|
+
/* @__PURE__ */ jsx14(Stack12, { space: 2, children: feedbackItems.map((item) => /* @__PURE__ */ jsxs14("div", { style: { display: "flex", alignItems: "center", gap: 7 }, children: [
|
|
1602
|
+
/* @__PURE__ */ jsx14(
|
|
1052
1603
|
"div",
|
|
1053
1604
|
{
|
|
1054
1605
|
style: {
|
|
@@ -1059,7 +1610,7 @@ var OgTitle = (props) => {
|
|
|
1059
1610
|
}
|
|
1060
1611
|
}
|
|
1061
1612
|
),
|
|
1062
|
-
/* @__PURE__ */
|
|
1613
|
+
/* @__PURE__ */ jsx14(Text12, { weight: "bold", muted: true, size: 14, children: item.text })
|
|
1063
1614
|
] }, item.text)) })
|
|
1064
1615
|
] });
|
|
1065
1616
|
};
|
|
@@ -1086,8 +1637,8 @@ function openGraph(config = {}) {
|
|
|
1086
1637
|
hidden: getFieldHiddenFunction("openGraphTitle", config),
|
|
1087
1638
|
components: {
|
|
1088
1639
|
input: OgTitle_default
|
|
1089
|
-
|
|
1090
|
-
}
|
|
1640
|
+
},
|
|
1641
|
+
options: __spreadValues({}, config.ai ? { ai: withLicense(config.ai, config.licenseKey) } : {})
|
|
1091
1642
|
})),
|
|
1092
1643
|
defineField(__spreadProps(__spreadValues({
|
|
1093
1644
|
name: "description"
|
|
@@ -1097,8 +1648,8 @@ function openGraph(config = {}) {
|
|
|
1097
1648
|
hidden: getFieldHiddenFunction("openGraphDescription", config),
|
|
1098
1649
|
components: {
|
|
1099
1650
|
input: OgDescription_default
|
|
1100
|
-
|
|
1101
|
-
}
|
|
1651
|
+
},
|
|
1652
|
+
options: __spreadValues({}, config.ai ? { ai: withLicense(config.ai, config.licenseKey) } : {})
|
|
1102
1653
|
})),
|
|
1103
1654
|
defineField(__spreadProps(__spreadValues({
|
|
1104
1655
|
name: "siteName"
|
|
@@ -1180,19 +1731,38 @@ function openGraph(config = {}) {
|
|
|
1180
1731
|
]
|
|
1181
1732
|
});
|
|
1182
1733
|
}
|
|
1734
|
+
|
|
1735
|
+
// src/schemas/types/twitter/index.ts
|
|
1736
|
+
import { defineField as defineField2, defineType as defineType2 } from "sanity";
|
|
1737
|
+
|
|
1738
|
+
// src/components/twitter/twitterDescription.tsx
|
|
1739
|
+
import { Stack as Stack13, Text as Text13 } from "@sanity/ui";
|
|
1740
|
+
import { useMemo as useMemo11 } from "react";
|
|
1741
|
+
import { PatchEvent as PatchEvent8, set as set8, useFormValue as useFormValue14 } from "sanity";
|
|
1742
|
+
import { jsx as jsx15, jsxs as jsxs15 } from "react/jsx-runtime";
|
|
1183
1743
|
var TwitterDescription = (props) => {
|
|
1184
|
-
const { value, renderDefault, path } = props;
|
|
1185
|
-
const
|
|
1744
|
+
const { value, renderDefault, path, schemaType, onChange } = props;
|
|
1745
|
+
const { options } = schemaType;
|
|
1746
|
+
const parent = useFormValue14([path[0]]);
|
|
1186
1747
|
const isParentseoField = parent && (parent == null ? void 0 : parent._type) === "seoFields";
|
|
1187
|
-
const keywords =
|
|
1188
|
-
const feedbackItems =
|
|
1748
|
+
const keywords = useMemo11(() => (parent == null ? void 0 : parent.keywords) || [], [parent == null ? void 0 : parent.keywords]);
|
|
1749
|
+
const feedbackItems = useMemo11(
|
|
1189
1750
|
() => getTwitterDescriptionValidation(value || "", keywords, isParentseoField),
|
|
1190
1751
|
[value, keywords, isParentseoField]
|
|
1191
1752
|
);
|
|
1192
|
-
return /* @__PURE__ */
|
|
1753
|
+
return /* @__PURE__ */ jsxs15(Stack13, { space: 3, children: [
|
|
1193
1754
|
renderDefault(props),
|
|
1194
|
-
/* @__PURE__ */
|
|
1195
|
-
|
|
1755
|
+
/* @__PURE__ */ jsx15(
|
|
1756
|
+
SeoGenButton,
|
|
1757
|
+
{
|
|
1758
|
+
field: "twitterDescription",
|
|
1759
|
+
ai: options == null ? void 0 : options.ai,
|
|
1760
|
+
seoFieldPath: String(path[0]),
|
|
1761
|
+
onGenerate: (v) => onChange(PatchEvent8.from(set8(v)))
|
|
1762
|
+
}
|
|
1763
|
+
),
|
|
1764
|
+
/* @__PURE__ */ jsx15(Stack13, { space: 2, children: feedbackItems.map((item) => /* @__PURE__ */ jsxs15("div", { style: { display: "flex", alignItems: "center", gap: 7 }, children: [
|
|
1765
|
+
/* @__PURE__ */ jsx15(
|
|
1196
1766
|
"div",
|
|
1197
1767
|
{
|
|
1198
1768
|
style: {
|
|
@@ -1203,25 +1773,31 @@ var TwitterDescription = (props) => {
|
|
|
1203
1773
|
}
|
|
1204
1774
|
}
|
|
1205
1775
|
),
|
|
1206
|
-
/* @__PURE__ */
|
|
1776
|
+
/* @__PURE__ */ jsx15(Text13, { weight: "bold", muted: true, size: 14, children: item.text })
|
|
1207
1777
|
] }, item.text)) })
|
|
1208
1778
|
] });
|
|
1209
1779
|
};
|
|
1210
1780
|
var twitterDescription_default = TwitterDescription;
|
|
1781
|
+
|
|
1782
|
+
// src/components/twitter/TwitterImage.tsx
|
|
1783
|
+
import { Stack as Stack14, Text as Text14 } from "@sanity/ui";
|
|
1784
|
+
import { useMemo as useMemo12 } from "react";
|
|
1785
|
+
import { useFormValue as useFormValue15 } from "sanity";
|
|
1786
|
+
import { jsx as jsx16, jsxs as jsxs16 } from "react/jsx-runtime";
|
|
1211
1787
|
var TwitterImage = (props) => {
|
|
1212
1788
|
const { value, renderDefault, path } = props;
|
|
1213
|
-
const seoParent =
|
|
1789
|
+
const seoParent = useFormValue15([path[0]]);
|
|
1214
1790
|
const imgValue = value;
|
|
1215
1791
|
const hasImage = !!(imgValue == null ? void 0 : imgValue.asset);
|
|
1216
1792
|
const altText = imgValue == null ? void 0 : imgValue.alt;
|
|
1217
|
-
const feedbackItems =
|
|
1793
|
+
const feedbackItems = useMemo12(
|
|
1218
1794
|
() => getTwitterImageValidation(hasImage, altText, seoParent),
|
|
1219
1795
|
[hasImage, altText, seoParent]
|
|
1220
1796
|
);
|
|
1221
|
-
return /* @__PURE__ */
|
|
1797
|
+
return /* @__PURE__ */ jsxs16(Stack14, { space: 3, children: [
|
|
1222
1798
|
renderDefault(props),
|
|
1223
|
-
/* @__PURE__ */
|
|
1224
|
-
/* @__PURE__ */
|
|
1799
|
+
/* @__PURE__ */ jsx16(Stack14, { space: 2, children: feedbackItems.map((item) => /* @__PURE__ */ jsxs16("div", { style: { display: "flex", alignItems: "center", gap: 7 }, children: [
|
|
1800
|
+
/* @__PURE__ */ jsx16(
|
|
1225
1801
|
"div",
|
|
1226
1802
|
{
|
|
1227
1803
|
style: {
|
|
@@ -1232,22 +1808,28 @@ var TwitterImage = (props) => {
|
|
|
1232
1808
|
}
|
|
1233
1809
|
}
|
|
1234
1810
|
),
|
|
1235
|
-
/* @__PURE__ */
|
|
1811
|
+
/* @__PURE__ */ jsx16(Text14, { weight: "bold", muted: true, size: 14, children: item.text })
|
|
1236
1812
|
] }, item.text)) })
|
|
1237
1813
|
] });
|
|
1238
1814
|
};
|
|
1239
1815
|
var TwitterImage_default = TwitterImage;
|
|
1816
|
+
|
|
1817
|
+
// src/components/twitter/TwitterImageUrl.tsx
|
|
1818
|
+
import { Stack as Stack15, Text as Text15 } from "@sanity/ui";
|
|
1819
|
+
import { useMemo as useMemo13 } from "react";
|
|
1820
|
+
import { useFormValue as useFormValue16 } from "sanity";
|
|
1821
|
+
import { jsx as jsx17, jsxs as jsxs17 } from "react/jsx-runtime";
|
|
1240
1822
|
var TwitterImageUrl = (props) => {
|
|
1241
1823
|
const { value, renderDefault, path } = props;
|
|
1242
|
-
const seoParent =
|
|
1243
|
-
const feedbackItems =
|
|
1824
|
+
const seoParent = useFormValue16([path[0]]);
|
|
1825
|
+
const feedbackItems = useMemo13(
|
|
1244
1826
|
() => getTwitterImageUrlValidation(value, seoParent),
|
|
1245
1827
|
[value, seoParent]
|
|
1246
1828
|
);
|
|
1247
|
-
return /* @__PURE__ */
|
|
1829
|
+
return /* @__PURE__ */ jsxs17(Stack15, { space: 3, children: [
|
|
1248
1830
|
renderDefault(props),
|
|
1249
|
-
/* @__PURE__ */
|
|
1250
|
-
/* @__PURE__ */
|
|
1831
|
+
/* @__PURE__ */ jsx17(Stack15, { space: 2, children: feedbackItems.map((item) => /* @__PURE__ */ jsxs17("div", { style: { display: "flex", alignItems: "center", gap: 7 }, children: [
|
|
1832
|
+
/* @__PURE__ */ jsx17(
|
|
1251
1833
|
"div",
|
|
1252
1834
|
{
|
|
1253
1835
|
style: {
|
|
@@ -1258,24 +1840,40 @@ var TwitterImageUrl = (props) => {
|
|
|
1258
1840
|
}
|
|
1259
1841
|
}
|
|
1260
1842
|
),
|
|
1261
|
-
/* @__PURE__ */
|
|
1843
|
+
/* @__PURE__ */ jsx17(Text15, { weight: "bold", muted: true, size: 14, children: item.text })
|
|
1262
1844
|
] }, item.text)) })
|
|
1263
1845
|
] });
|
|
1264
1846
|
};
|
|
1265
1847
|
var TwitterImageUrl_default = TwitterImageUrl;
|
|
1848
|
+
|
|
1849
|
+
// src/components/twitter/twitterTitle.tsx
|
|
1850
|
+
import { Stack as Stack16, Text as Text16 } from "@sanity/ui";
|
|
1851
|
+
import { useMemo as useMemo14 } from "react";
|
|
1852
|
+
import { PatchEvent as PatchEvent9, set as set9, useFormValue as useFormValue17 } from "sanity";
|
|
1853
|
+
import { jsx as jsx18, jsxs as jsxs18 } from "react/jsx-runtime";
|
|
1266
1854
|
var TwitterTitle = (props) => {
|
|
1267
|
-
const { value, renderDefault, path } = props;
|
|
1268
|
-
const
|
|
1855
|
+
const { value, renderDefault, path, schemaType, onChange } = props;
|
|
1856
|
+
const { options } = schemaType;
|
|
1857
|
+
const parent = useFormValue17([path[0]]);
|
|
1269
1858
|
const isParentseoField = parent && (parent == null ? void 0 : parent._type) === "seoFields";
|
|
1270
|
-
const keywords =
|
|
1271
|
-
const feedbackItems =
|
|
1859
|
+
const keywords = useMemo14(() => (parent == null ? void 0 : parent.keywords) || [], [parent == null ? void 0 : parent.keywords]);
|
|
1860
|
+
const feedbackItems = useMemo14(
|
|
1272
1861
|
() => getTwitterTitleValidation(value || "", keywords, isParentseoField),
|
|
1273
1862
|
[value, keywords, isParentseoField]
|
|
1274
1863
|
);
|
|
1275
|
-
return /* @__PURE__ */
|
|
1864
|
+
return /* @__PURE__ */ jsxs18(Stack16, { space: 3, children: [
|
|
1276
1865
|
renderDefault(props),
|
|
1277
|
-
/* @__PURE__ */
|
|
1278
|
-
|
|
1866
|
+
/* @__PURE__ */ jsx18(
|
|
1867
|
+
SeoGenButton,
|
|
1868
|
+
{
|
|
1869
|
+
field: "twitterTitle",
|
|
1870
|
+
ai: options == null ? void 0 : options.ai,
|
|
1871
|
+
seoFieldPath: String(path[0]),
|
|
1872
|
+
onGenerate: (v) => onChange(PatchEvent9.from(set9(v)))
|
|
1873
|
+
}
|
|
1874
|
+
),
|
|
1875
|
+
/* @__PURE__ */ jsx18(Stack16, { space: 2, children: feedbackItems.map((item) => /* @__PURE__ */ jsxs18("div", { style: { display: "flex", alignItems: "center", gap: 7 }, children: [
|
|
1876
|
+
/* @__PURE__ */ jsx18(
|
|
1279
1877
|
"div",
|
|
1280
1878
|
{
|
|
1281
1879
|
style: {
|
|
@@ -1286,7 +1884,7 @@ var TwitterTitle = (props) => {
|
|
|
1286
1884
|
}
|
|
1287
1885
|
}
|
|
1288
1886
|
),
|
|
1289
|
-
/* @__PURE__ */
|
|
1887
|
+
/* @__PURE__ */ jsx18(Text16, { weight: "bold", muted: true, size: 14, children: item.text })
|
|
1290
1888
|
] }, item.text)) })
|
|
1291
1889
|
] });
|
|
1292
1890
|
};
|
|
@@ -1294,12 +1892,12 @@ var twitterTitle_default = TwitterTitle;
|
|
|
1294
1892
|
|
|
1295
1893
|
// src/schemas/types/twitter/index.ts
|
|
1296
1894
|
function twitter(config = {}) {
|
|
1297
|
-
return
|
|
1895
|
+
return defineType2({
|
|
1298
1896
|
name: "twitter",
|
|
1299
1897
|
title: "X (Formerly Twitter)",
|
|
1300
1898
|
type: "object",
|
|
1301
1899
|
fields: [
|
|
1302
|
-
|
|
1900
|
+
defineField2(__spreadProps(__spreadValues({
|
|
1303
1901
|
name: "card"
|
|
1304
1902
|
}, getFieldInfo("twitterCard", config.fieldOverrides)), {
|
|
1305
1903
|
type: "string",
|
|
@@ -1315,28 +1913,29 @@ function twitter(config = {}) {
|
|
|
1315
1913
|
initialValue: "summary_large_image"
|
|
1316
1914
|
// good default
|
|
1317
1915
|
})),
|
|
1318
|
-
|
|
1916
|
+
defineField2(__spreadProps(__spreadValues({
|
|
1319
1917
|
name: "site"
|
|
1320
1918
|
}, getFieldInfo("twitterSite", config.fieldOverrides)), {
|
|
1321
1919
|
type: "string",
|
|
1322
1920
|
hidden: getFieldHiddenFunction("twitterSite", config)
|
|
1323
1921
|
})),
|
|
1324
|
-
|
|
1922
|
+
defineField2(__spreadProps(__spreadValues({
|
|
1325
1923
|
name: "creator",
|
|
1326
1924
|
type: "string"
|
|
1327
1925
|
}, getFieldInfo("twitterCreator", config.fieldOverrides)), {
|
|
1328
1926
|
hidden: getFieldHiddenFunction("twitterCreator", config)
|
|
1329
1927
|
})),
|
|
1330
|
-
|
|
1928
|
+
defineField2(__spreadProps(__spreadValues({
|
|
1331
1929
|
name: "title",
|
|
1332
1930
|
type: "string"
|
|
1333
1931
|
}, getFieldInfo("twitterTitle", config.fieldOverrides)), {
|
|
1334
1932
|
hidden: getFieldHiddenFunction("twitterTitle", config),
|
|
1335
1933
|
components: {
|
|
1336
1934
|
input: twitterTitle_default
|
|
1337
|
-
}
|
|
1935
|
+
},
|
|
1936
|
+
options: __spreadValues({}, config.ai ? { ai: withLicense(config.ai, config.licenseKey) } : {})
|
|
1338
1937
|
})),
|
|
1339
|
-
|
|
1938
|
+
defineField2(__spreadProps(__spreadValues({
|
|
1340
1939
|
name: "description",
|
|
1341
1940
|
type: "text",
|
|
1342
1941
|
rows: 3
|
|
@@ -1344,9 +1943,10 @@ function twitter(config = {}) {
|
|
|
1344
1943
|
hidden: getFieldHiddenFunction("twitterDescription", config),
|
|
1345
1944
|
components: {
|
|
1346
1945
|
input: twitterDescription_default
|
|
1347
|
-
}
|
|
1946
|
+
},
|
|
1947
|
+
options: __spreadValues({}, config.ai ? { ai: withLicense(config.ai, config.licenseKey) } : {})
|
|
1348
1948
|
})),
|
|
1349
|
-
|
|
1949
|
+
defineField2(__spreadProps(__spreadValues({
|
|
1350
1950
|
name: "imageType"
|
|
1351
1951
|
}, getFieldInfo("twitterImageType", config.fieldOverrides)), {
|
|
1352
1952
|
type: "string",
|
|
@@ -1359,7 +1959,7 @@ function twitter(config = {}) {
|
|
|
1359
1959
|
hidden: getFieldHiddenFunction("twitterImage", config),
|
|
1360
1960
|
initialValue: "upload"
|
|
1361
1961
|
})),
|
|
1362
|
-
|
|
1962
|
+
defineField2(__spreadProps(__spreadValues({
|
|
1363
1963
|
name: "image"
|
|
1364
1964
|
}, getFieldInfo("twitterImage", config.fieldOverrides)), {
|
|
1365
1965
|
type: "image",
|
|
@@ -1370,7 +1970,7 @@ function twitter(config = {}) {
|
|
|
1370
1970
|
input: TwitterImage_default
|
|
1371
1971
|
},
|
|
1372
1972
|
fields: [
|
|
1373
|
-
|
|
1973
|
+
defineField2({
|
|
1374
1974
|
name: "alt",
|
|
1375
1975
|
title: "Image Alt Text",
|
|
1376
1976
|
type: "string",
|
|
@@ -1384,7 +1984,7 @@ function twitter(config = {}) {
|
|
|
1384
1984
|
return typeof hiddenFn === "function" ? hiddenFn(context) : hiddenFn;
|
|
1385
1985
|
}
|
|
1386
1986
|
})),
|
|
1387
|
-
|
|
1987
|
+
defineField2(__spreadProps(__spreadValues({
|
|
1388
1988
|
name: "imageUrl"
|
|
1389
1989
|
}, getFieldInfo("twitterImageUrl", config.fieldOverrides)), {
|
|
1390
1990
|
type: "url",
|
|
@@ -1403,7 +2003,7 @@ function twitter(config = {}) {
|
|
|
1403
2003
|
}
|
|
1404
2004
|
|
|
1405
2005
|
// src/schemas/index.ts
|
|
1406
|
-
var LazySeoPreview = lazy(() => import(
|
|
2006
|
+
var LazySeoPreview = lazy(() => import("./SeoPreview-UNQBKTQO.js"));
|
|
1407
2007
|
var SeoPreviewWrapper = (props) => createElement(Suspense, { fallback: null }, createElement(LazySeoPreview, props));
|
|
1408
2008
|
function buildFieldGroupMap(groups) {
|
|
1409
2009
|
const map = /* @__PURE__ */ new Map();
|
|
@@ -1438,18 +2038,87 @@ function withGroup(field, fieldGroupMap) {
|
|
|
1438
2038
|
if (!groups || groups.length === 0) return field;
|
|
1439
2039
|
return __spreadProps(__spreadValues({}, field), { group: groups.length === 1 ? groups[0] : groups });
|
|
1440
2040
|
}
|
|
2041
|
+
function shouldShowPreviewField(seoPreview) {
|
|
2042
|
+
if (typeof seoPreview === "boolean") return seoPreview;
|
|
2043
|
+
if (typeof seoPreview === "object") return !isEmpty(seoPreview);
|
|
2044
|
+
return false;
|
|
2045
|
+
}
|
|
2046
|
+
function getSeoPreviewSuffixOptions(seoPreview) {
|
|
2047
|
+
if (typeof seoPreview !== "object" || !seoPreview) return {};
|
|
2048
|
+
const extra = {};
|
|
2049
|
+
if (seoPreview.titleSuffix) extra.titleSuffix = seoPreview.titleSuffix;
|
|
2050
|
+
if (seoPreview.titleSuffixQuery) extra.titleSuffixQuery = seoPreview.titleSuffixQuery;
|
|
2051
|
+
return extra;
|
|
2052
|
+
}
|
|
2053
|
+
function getPreviewFieldOptions(config) {
|
|
2054
|
+
const seoPreview = config.seoPreview;
|
|
2055
|
+
const extra = {};
|
|
2056
|
+
if (typeof seoPreview === "object" && seoPreview) {
|
|
2057
|
+
if (seoPreview.prefix) extra.prefix = seoPreview.prefix;
|
|
2058
|
+
if (seoPreview.titleSuffixInheritColor) {
|
|
2059
|
+
extra.titleSuffixInheritColor = seoPreview.titleSuffixInheritColor;
|
|
2060
|
+
}
|
|
2061
|
+
}
|
|
2062
|
+
return __spreadValues(__spreadValues(__spreadValues({
|
|
2063
|
+
baseUrl: config.baseUrl || "https://www.example.com"
|
|
2064
|
+
}, config.apiVersion ? { apiVersion: config.apiVersion } : {}), getSeoPreviewSuffixOptions(seoPreview)), extra);
|
|
2065
|
+
}
|
|
2066
|
+
function getAiOption(config) {
|
|
2067
|
+
return config.ai ? { ai: withLicense(config.ai, config.licenseKey) } : {};
|
|
2068
|
+
}
|
|
2069
|
+
function getTitleFieldOptions(config) {
|
|
2070
|
+
return __spreadValues(__spreadValues(__spreadValues({}, config.apiVersion ? { apiVersion: config.apiVersion } : {}), getSeoPreviewSuffixOptions(config.seoPreview)), getAiOption(config));
|
|
2071
|
+
}
|
|
2072
|
+
function buildGeoChecklistField(config, fieldGroupMap) {
|
|
2073
|
+
if (config.geo === false) return [];
|
|
2074
|
+
return [
|
|
2075
|
+
withGroup(
|
|
2076
|
+
defineField3(__spreadProps(__spreadValues({
|
|
2077
|
+
name: "geoChecklist"
|
|
2078
|
+
}, getFieldInfo("geoChecklist", config.fieldOverrides)), {
|
|
2079
|
+
type: "string",
|
|
2080
|
+
readOnly: true,
|
|
2081
|
+
components: {
|
|
2082
|
+
input: GEOChecklist_default
|
|
2083
|
+
},
|
|
2084
|
+
options: __spreadValues({}, config.licenseKey ? { licenseKey: config.licenseKey } : {}),
|
|
2085
|
+
hidden: getFieldHiddenFunction("geoChecklist", config)
|
|
2086
|
+
})),
|
|
2087
|
+
fieldGroupMap
|
|
2088
|
+
)
|
|
2089
|
+
];
|
|
2090
|
+
}
|
|
2091
|
+
function buildMetaTagsPreviewField(config, fieldGroupMap) {
|
|
2092
|
+
if (config.metaTagsPreview === false) return [];
|
|
2093
|
+
return [
|
|
2094
|
+
withGroup(
|
|
2095
|
+
defineField3(__spreadProps(__spreadValues({
|
|
2096
|
+
name: "metaTagsPreview"
|
|
2097
|
+
}, getFieldInfo("metaTagsPreview", config.fieldOverrides)), {
|
|
2098
|
+
type: "string",
|
|
2099
|
+
readOnly: true,
|
|
2100
|
+
components: {
|
|
2101
|
+
input: MetaTagsPreview_default
|
|
2102
|
+
},
|
|
2103
|
+
hidden: getFieldHiddenFunction("metaTagsPreview", config)
|
|
2104
|
+
})),
|
|
2105
|
+
fieldGroupMap
|
|
2106
|
+
)
|
|
2107
|
+
];
|
|
2108
|
+
}
|
|
1441
2109
|
function seoFieldsSchema(config = {}) {
|
|
2110
|
+
var _a;
|
|
1442
2111
|
const groupsCfg = config.fieldGroups;
|
|
1443
2112
|
const fieldGroupMap = (groupsCfg == null ? void 0 : groupsCfg.length) ? buildFieldGroupMap(groupsCfg) : void 0;
|
|
1444
2113
|
const sanityGroups = (groupsCfg == null ? void 0 : groupsCfg.length) ? toSanityGroups(groupsCfg) : void 0;
|
|
1445
|
-
return
|
|
2114
|
+
return defineType3(__spreadProps(__spreadValues({
|
|
1446
2115
|
name: "seoFields",
|
|
1447
2116
|
title: "SEO Fields",
|
|
1448
2117
|
type: "object"
|
|
1449
2118
|
}, sanityGroups ? { groups: sanityGroups } : {}), {
|
|
1450
2119
|
fields: [
|
|
1451
2120
|
withGroup(
|
|
1452
|
-
|
|
2121
|
+
defineField3({
|
|
1453
2122
|
name: "robots",
|
|
1454
2123
|
title: "Robots Settings",
|
|
1455
2124
|
type: "robots",
|
|
@@ -1458,16 +2127,14 @@ function seoFieldsSchema(config = {}) {
|
|
|
1458
2127
|
fieldGroupMap
|
|
1459
2128
|
),
|
|
1460
2129
|
// 👇 conditionally spread preview field
|
|
1461
|
-
...
|
|
2130
|
+
...shouldShowPreviewField(config.seoPreview) ? [
|
|
1462
2131
|
withGroup(
|
|
1463
|
-
|
|
2132
|
+
defineField3({
|
|
1464
2133
|
name: "preview",
|
|
1465
2134
|
title: "SEO Preview",
|
|
1466
2135
|
type: "string",
|
|
1467
2136
|
components: { input: SeoPreviewWrapper },
|
|
1468
|
-
options:
|
|
1469
|
-
baseUrl: config.baseUrl || "https://www.example.com"
|
|
1470
|
-
}, config.apiVersion ? { apiVersion: config.apiVersion } : {}), typeof config.seoPreview === "object" && config.seoPreview && config.seoPreview.prefix ? { prefix: config.seoPreview.prefix } : {}), typeof config.seoPreview === "object" && config.seoPreview && config.seoPreview.titleSuffix ? { titleSuffix: config.seoPreview.titleSuffix } : {}), typeof config.seoPreview === "object" && config.seoPreview && config.seoPreview.titleSuffixInheritColor ? { titleSuffixInheritColor: config.seoPreview.titleSuffixInheritColor } : {}), typeof config.seoPreview === "object" && config.seoPreview && config.seoPreview.titleSuffixQuery ? { titleSuffixQuery: config.seoPreview.titleSuffixQuery } : {}),
|
|
2137
|
+
options: getPreviewFieldOptions(config),
|
|
1471
2138
|
initialValue: "",
|
|
1472
2139
|
readOnly: true
|
|
1473
2140
|
}),
|
|
@@ -1475,20 +2142,20 @@ function seoFieldsSchema(config = {}) {
|
|
|
1475
2142
|
)
|
|
1476
2143
|
] : [],
|
|
1477
2144
|
withGroup(
|
|
1478
|
-
|
|
2145
|
+
defineField3(__spreadProps(__spreadValues({
|
|
1479
2146
|
name: "title"
|
|
1480
2147
|
}, getFieldInfo("title", config.fieldOverrides)), {
|
|
1481
2148
|
type: "string",
|
|
1482
2149
|
components: {
|
|
1483
2150
|
input: MetaTitle_default
|
|
1484
2151
|
},
|
|
1485
|
-
options:
|
|
2152
|
+
options: getTitleFieldOptions(config),
|
|
1486
2153
|
hidden: getFieldHiddenFunction("title", config)
|
|
1487
2154
|
})),
|
|
1488
2155
|
fieldGroupMap
|
|
1489
2156
|
),
|
|
1490
2157
|
withGroup(
|
|
1491
|
-
|
|
2158
|
+
defineField3(__spreadProps(__spreadValues({
|
|
1492
2159
|
name: "description"
|
|
1493
2160
|
}, getFieldInfo("description", config.fieldOverrides)), {
|
|
1494
2161
|
type: "text",
|
|
@@ -1496,12 +2163,13 @@ function seoFieldsSchema(config = {}) {
|
|
|
1496
2163
|
components: {
|
|
1497
2164
|
input: MetaDescription_default
|
|
1498
2165
|
},
|
|
2166
|
+
options: getAiOption(config),
|
|
1499
2167
|
hidden: getFieldHiddenFunction("description", config)
|
|
1500
2168
|
})),
|
|
1501
2169
|
fieldGroupMap
|
|
1502
2170
|
),
|
|
1503
2171
|
withGroup(
|
|
1504
|
-
|
|
2172
|
+
defineField3(__spreadProps(__spreadValues({
|
|
1505
2173
|
name: "metaImage"
|
|
1506
2174
|
}, getFieldInfo("metaImage", config.fieldOverrides)), {
|
|
1507
2175
|
type: "image",
|
|
@@ -1516,7 +2184,7 @@ function seoFieldsSchema(config = {}) {
|
|
|
1516
2184
|
fieldGroupMap
|
|
1517
2185
|
),
|
|
1518
2186
|
withGroup(
|
|
1519
|
-
|
|
2187
|
+
defineField3(__spreadProps(__spreadValues({
|
|
1520
2188
|
name: "metaAttributes"
|
|
1521
2189
|
}, getFieldInfo("metaAttributes", config.fieldOverrides)), {
|
|
1522
2190
|
type: "array",
|
|
@@ -1526,19 +2194,21 @@ function seoFieldsSchema(config = {}) {
|
|
|
1526
2194
|
fieldGroupMap
|
|
1527
2195
|
),
|
|
1528
2196
|
withGroup(
|
|
1529
|
-
|
|
2197
|
+
defineField3(__spreadProps(__spreadValues({
|
|
1530
2198
|
name: "keywords"
|
|
1531
2199
|
}, getFieldInfo("keywords", config.fieldOverrides)), {
|
|
1532
2200
|
title: "Keywords",
|
|
1533
2201
|
type: "array",
|
|
1534
2202
|
of: [{ type: "string" }],
|
|
1535
2203
|
description: "Add relevant keywords for this page. These keywords will be used for SEO purposes.",
|
|
2204
|
+
components: config.ai ? { input: KeywordsInput_default } : void 0,
|
|
2205
|
+
options: getAiOption(config),
|
|
1536
2206
|
hidden: getFieldHiddenFunction("keywords", config)
|
|
1537
2207
|
})),
|
|
1538
2208
|
fieldGroupMap
|
|
1539
2209
|
),
|
|
1540
2210
|
withGroup(
|
|
1541
|
-
|
|
2211
|
+
defineField3(__spreadProps(__spreadValues({
|
|
1542
2212
|
name: "canonicalUrl"
|
|
1543
2213
|
}, getFieldInfo("canonicalUrl", config.fieldOverrides)), {
|
|
1544
2214
|
title: "Canonical URL",
|
|
@@ -1549,71 +2219,54 @@ function seoFieldsSchema(config = {}) {
|
|
|
1549
2219
|
fieldGroupMap
|
|
1550
2220
|
),
|
|
1551
2221
|
withGroup(
|
|
1552
|
-
|
|
2222
|
+
defineField3(__spreadProps(__spreadValues({
|
|
1553
2223
|
name: "focusKeyword"
|
|
1554
2224
|
}, getFieldInfo("focusKeyword", config.fieldOverrides)), {
|
|
1555
2225
|
type: "string",
|
|
1556
2226
|
components: {
|
|
1557
2227
|
input: FocusKeywordInput_default
|
|
1558
2228
|
},
|
|
2229
|
+
options: getAiOption(config),
|
|
1559
2230
|
hidden: getFieldHiddenFunction("focusKeyword", config)
|
|
1560
2231
|
})),
|
|
1561
2232
|
fieldGroupMap
|
|
1562
2233
|
),
|
|
1563
2234
|
withGroup(
|
|
1564
|
-
|
|
2235
|
+
defineField3(__spreadProps(__spreadValues(__spreadProps(__spreadValues({
|
|
1565
2236
|
name: "hreflangs"
|
|
1566
2237
|
}, getFieldInfo("hreflangs", config.fieldOverrides)), {
|
|
1567
2238
|
type: "array",
|
|
1568
2239
|
of: [{ type: "hreflangEntry" }],
|
|
1569
|
-
description: "Add alternate language/region versions. Include x-default for the fallback URL."
|
|
2240
|
+
description: "Add alternate language/region versions. Include x-default for the fallback URL."
|
|
2241
|
+
}), ((_a = config.hreflang) == null ? void 0 : _a.autoFill) ? {
|
|
2242
|
+
components: { input: HreflangInput_default },
|
|
2243
|
+
options: {
|
|
2244
|
+
hreflang: config.hreflang,
|
|
2245
|
+
baseUrl: config.baseUrl,
|
|
2246
|
+
apiVersion: config.apiVersion
|
|
2247
|
+
}
|
|
2248
|
+
} : {}), {
|
|
1570
2249
|
hidden: getFieldHiddenFunction("hreflangs", config)
|
|
1571
2250
|
})),
|
|
1572
2251
|
fieldGroupMap
|
|
1573
2252
|
),
|
|
1574
|
-
...config
|
|
1575
|
-
|
|
1576
|
-
defineField(__spreadProps(__spreadValues({
|
|
1577
|
-
name: "geoChecklist"
|
|
1578
|
-
}, getFieldInfo("geoChecklist", config.fieldOverrides)), {
|
|
1579
|
-
type: "string",
|
|
1580
|
-
readOnly: true,
|
|
1581
|
-
components: {
|
|
1582
|
-
input: GEOChecklist_default
|
|
1583
|
-
},
|
|
1584
|
-
options: __spreadValues({}, config.licenseKey ? { licenseKey: config.licenseKey } : {}),
|
|
1585
|
-
hidden: getFieldHiddenFunction("geoChecklist", config)
|
|
1586
|
-
})),
|
|
1587
|
-
fieldGroupMap
|
|
1588
|
-
)
|
|
1589
|
-
],
|
|
1590
|
-
...config.metaTagsPreview === false ? [] : [
|
|
1591
|
-
withGroup(
|
|
1592
|
-
defineField(__spreadProps(__spreadValues({
|
|
1593
|
-
name: "metaTagsPreview"
|
|
1594
|
-
}, getFieldInfo("metaTagsPreview", config.fieldOverrides)), {
|
|
1595
|
-
type: "string",
|
|
1596
|
-
readOnly: true,
|
|
1597
|
-
components: {
|
|
1598
|
-
input: MetaTagsPreview_default
|
|
1599
|
-
},
|
|
1600
|
-
hidden: getFieldHiddenFunction("metaTagsPreview", config)
|
|
1601
|
-
})),
|
|
1602
|
-
fieldGroupMap
|
|
1603
|
-
)
|
|
1604
|
-
],
|
|
2253
|
+
...buildGeoChecklistField(config, fieldGroupMap),
|
|
2254
|
+
...buildMetaTagsPreviewField(config, fieldGroupMap),
|
|
1605
2255
|
withGroup(openGraph(config), fieldGroupMap),
|
|
1606
2256
|
withGroup(twitter(config), fieldGroupMap)
|
|
1607
2257
|
]
|
|
1608
2258
|
}));
|
|
1609
2259
|
}
|
|
2260
|
+
|
|
2261
|
+
// src/schemas/types/baseMeta/index.ts
|
|
2262
|
+
import { defineField as defineField4, defineType as defineType4 } from "sanity";
|
|
1610
2263
|
function baseMeta(config = {}) {
|
|
1611
|
-
return
|
|
2264
|
+
return defineType4({
|
|
1612
2265
|
name: "baseMeta",
|
|
1613
2266
|
title: "Basic Meta Settings",
|
|
1614
2267
|
type: "object",
|
|
1615
2268
|
fields: [
|
|
1616
|
-
|
|
2269
|
+
defineField4(__spreadProps(__spreadValues({
|
|
1617
2270
|
name: "title"
|
|
1618
2271
|
}, getFieldInfo("title", config.fieldOverrides)), {
|
|
1619
2272
|
type: "string",
|
|
@@ -1622,7 +2275,7 @@ function baseMeta(config = {}) {
|
|
|
1622
2275
|
},
|
|
1623
2276
|
hidden: getFieldHiddenFunction("title", config)
|
|
1624
2277
|
})),
|
|
1625
|
-
|
|
2278
|
+
defineField4(__spreadProps(__spreadValues({
|
|
1626
2279
|
name: "description"
|
|
1627
2280
|
}, getFieldInfo("description", config.fieldOverrides)), {
|
|
1628
2281
|
type: "text",
|
|
@@ -1632,7 +2285,7 @@ function baseMeta(config = {}) {
|
|
|
1632
2285
|
},
|
|
1633
2286
|
hidden: getFieldHiddenFunction("description", config)
|
|
1634
2287
|
})),
|
|
1635
|
-
|
|
2288
|
+
defineField4(__spreadProps(__spreadValues({
|
|
1636
2289
|
name: "metaImage"
|
|
1637
2290
|
}, getFieldInfo("metaImage", config.fieldOverrides)), {
|
|
1638
2291
|
type: "image",
|
|
@@ -1644,7 +2297,7 @@ function baseMeta(config = {}) {
|
|
|
1644
2297
|
},
|
|
1645
2298
|
hidden: getFieldHiddenFunction("metaImage", config)
|
|
1646
2299
|
})),
|
|
1647
|
-
|
|
2300
|
+
defineField4(__spreadProps(__spreadValues({
|
|
1648
2301
|
name: "keywords"
|
|
1649
2302
|
}, getFieldInfo("keywords", config.fieldOverrides)), {
|
|
1650
2303
|
title: "Keywords",
|
|
@@ -1653,7 +2306,7 @@ function baseMeta(config = {}) {
|
|
|
1653
2306
|
description: "Add relevant keywords for this page. These keywords will be used for SEO purposes.",
|
|
1654
2307
|
hidden: getFieldHiddenFunction("keywords", config)
|
|
1655
2308
|
})),
|
|
1656
|
-
|
|
2309
|
+
defineField4(__spreadProps(__spreadValues({
|
|
1657
2310
|
name: "canonicalUrl"
|
|
1658
2311
|
}, getFieldInfo("canonicalUrl", config.fieldOverrides)), {
|
|
1659
2312
|
title: "Canonical URL",
|
|
@@ -1661,7 +2314,7 @@ function baseMeta(config = {}) {
|
|
|
1661
2314
|
description: "Specify the canonical URL for this page. This helps prevent duplicate content issues by indicating the preferred version of a page.",
|
|
1662
2315
|
hidden: getFieldHiddenFunction("canonicalUrl", config)
|
|
1663
2316
|
})),
|
|
1664
|
-
|
|
2317
|
+
defineField4(__spreadProps(__spreadValues({
|
|
1665
2318
|
name: "metaAttributes"
|
|
1666
2319
|
}, getFieldInfo("metaAttributes", config.fieldOverrides)), {
|
|
1667
2320
|
type: "array",
|
|
@@ -1671,12 +2324,15 @@ function baseMeta(config = {}) {
|
|
|
1671
2324
|
]
|
|
1672
2325
|
});
|
|
1673
2326
|
}
|
|
1674
|
-
|
|
2327
|
+
|
|
2328
|
+
// src/schemas/types/hreflang/index.ts
|
|
2329
|
+
import { defineField as defineField5, defineType as defineType5 } from "sanity";
|
|
2330
|
+
var hreflang_default = defineType5({
|
|
1675
2331
|
name: "hreflangEntry",
|
|
1676
2332
|
title: "Hreflang Entry",
|
|
1677
2333
|
type: "object",
|
|
1678
2334
|
fields: [
|
|
1679
|
-
|
|
2335
|
+
defineField5({
|
|
1680
2336
|
name: "locale",
|
|
1681
2337
|
title: "Language / Region",
|
|
1682
2338
|
type: "string",
|
|
@@ -1689,7 +2345,7 @@ var hreflang_default = defineType({
|
|
|
1689
2345
|
return true;
|
|
1690
2346
|
})
|
|
1691
2347
|
}),
|
|
1692
|
-
|
|
2348
|
+
defineField5({
|
|
1693
2349
|
name: "url",
|
|
1694
2350
|
title: "URL",
|
|
1695
2351
|
type: "url",
|
|
@@ -1703,17 +2359,20 @@ var hreflang_default = defineType({
|
|
|
1703
2359
|
}
|
|
1704
2360
|
}
|
|
1705
2361
|
});
|
|
1706
|
-
|
|
2362
|
+
|
|
2363
|
+
// src/schemas/types/metaAttribute/index.ts
|
|
2364
|
+
import { defineField as defineField6, defineType as defineType6 } from "sanity";
|
|
2365
|
+
var metaAttribute_default = defineType6({
|
|
1707
2366
|
name: "metaAttribute",
|
|
1708
2367
|
title: "Meta Attribute",
|
|
1709
2368
|
type: "object",
|
|
1710
2369
|
fields: [
|
|
1711
|
-
|
|
2370
|
+
defineField6({
|
|
1712
2371
|
name: "key",
|
|
1713
2372
|
title: "Attribute Name",
|
|
1714
2373
|
type: "string"
|
|
1715
2374
|
}),
|
|
1716
|
-
|
|
2375
|
+
defineField6({
|
|
1717
2376
|
name: "type",
|
|
1718
2377
|
title: "Attribute Value Type",
|
|
1719
2378
|
type: "string",
|
|
@@ -1725,13 +2384,13 @@ var metaAttribute_default = defineType({
|
|
|
1725
2384
|
},
|
|
1726
2385
|
initialValue: "string"
|
|
1727
2386
|
}),
|
|
1728
|
-
|
|
2387
|
+
defineField6({
|
|
1729
2388
|
name: "value",
|
|
1730
2389
|
title: "Attribute Value",
|
|
1731
2390
|
type: "string",
|
|
1732
2391
|
hidden: ({ parent }) => (parent == null ? void 0 : parent.type) === "image"
|
|
1733
2392
|
}),
|
|
1734
|
-
|
|
2393
|
+
defineField6({
|
|
1735
2394
|
name: "image",
|
|
1736
2395
|
title: "Attribute Image Value",
|
|
1737
2396
|
type: "image",
|
|
@@ -1761,7 +2420,10 @@ var metaAttribute_default = defineType({
|
|
|
1761
2420
|
}
|
|
1762
2421
|
}
|
|
1763
2422
|
});
|
|
1764
|
-
|
|
2423
|
+
|
|
2424
|
+
// src/schemas/types/metaTag/index.ts
|
|
2425
|
+
import { defineType as defineType7 } from "sanity";
|
|
2426
|
+
var metaTag_default = defineType7({
|
|
1765
2427
|
name: "metaTag",
|
|
1766
2428
|
title: "Meta Tag",
|
|
1767
2429
|
type: "object",
|
|
@@ -1775,33 +2437,36 @@ var metaTag_default = defineType({
|
|
|
1775
2437
|
}
|
|
1776
2438
|
]
|
|
1777
2439
|
});
|
|
1778
|
-
|
|
2440
|
+
|
|
2441
|
+
// src/schemas/types/robots/index.ts
|
|
2442
|
+
import { defineField as defineField7, defineType as defineType8 } from "sanity";
|
|
2443
|
+
var robots_default = defineType8({
|
|
1779
2444
|
name: "robots",
|
|
1780
2445
|
title: "Robots Settings",
|
|
1781
2446
|
type: "object",
|
|
1782
2447
|
fields: [
|
|
1783
|
-
|
|
2448
|
+
defineField7({
|
|
1784
2449
|
name: "noIndex",
|
|
1785
2450
|
title: "No Index",
|
|
1786
2451
|
type: "boolean",
|
|
1787
2452
|
initialValue: false,
|
|
1788
2453
|
description: "Enable this to prevent search engines from indexing this page. The page will not appear in search results."
|
|
1789
2454
|
}),
|
|
1790
|
-
|
|
2455
|
+
defineField7({
|
|
1791
2456
|
name: "noFollow",
|
|
1792
2457
|
title: "No Follow",
|
|
1793
2458
|
type: "boolean",
|
|
1794
2459
|
initialValue: false,
|
|
1795
2460
|
description: "Enable this to prevent search engines from following links on this page. Links will not pass SEO value."
|
|
1796
2461
|
}),
|
|
1797
|
-
|
|
2462
|
+
defineField7({
|
|
1798
2463
|
name: "noTranslate",
|
|
1799
2464
|
title: "No Translate",
|
|
1800
2465
|
type: "boolean",
|
|
1801
2466
|
initialValue: false,
|
|
1802
2467
|
description: "Enable this to prevent search engines from offering a translated version of this page in search results."
|
|
1803
2468
|
}),
|
|
1804
|
-
|
|
2469
|
+
defineField7({
|
|
1805
2470
|
name: "noImageIndex",
|
|
1806
2471
|
title: "No Image Index",
|
|
1807
2472
|
type: "boolean",
|
|
@@ -1898,11 +2563,11 @@ var seofields = definePlugin((config = {}) => {
|
|
|
1898
2563
|
const cfg = config;
|
|
1899
2564
|
const { healthDashboard = true, licenseKey, publishGate } = cfg;
|
|
1900
2565
|
const dash = resolveDashboardConfig(healthDashboard, cfg.apiVersion, licenseKey);
|
|
1901
|
-
const LazySeoHealthTool =
|
|
1902
|
-
const BoundSeoHealthTool = () =>
|
|
1903
|
-
|
|
2566
|
+
const LazySeoHealthTool = lazy2(() => import("./SeoHealthTool-CWI3KB2V.js"));
|
|
2567
|
+
const BoundSeoHealthTool = () => createElement2(
|
|
2568
|
+
Suspense2,
|
|
1904
2569
|
{ fallback: null },
|
|
1905
|
-
|
|
2570
|
+
createElement2(LazySeoHealthTool, {
|
|
1906
2571
|
icon: dash.icon,
|
|
1907
2572
|
title: dash.title,
|
|
1908
2573
|
description: dash.description,
|
|
@@ -1957,6 +2622,10 @@ var seofields = definePlugin((config = {}) => {
|
|
|
1957
2622
|
});
|
|
1958
2623
|
var plugin_default = seofields;
|
|
1959
2624
|
|
|
2625
|
+
// src/components/SeoHealthPane.tsx
|
|
2626
|
+
import { createSeoHealthPane } from "seofields-pro";
|
|
2627
|
+
import { createSeoHealthPaneDefault } from "seofields-pro";
|
|
2628
|
+
|
|
1960
2629
|
// src/utils/scoring.ts
|
|
1961
2630
|
var getStatusCategory = (score) => {
|
|
1962
2631
|
if (score >= 80) return "excellent";
|
|
@@ -2025,6 +2694,50 @@ var scoreTwitterCard = (twitter2) => {
|
|
|
2025
2694
|
}
|
|
2026
2695
|
return { score, issues };
|
|
2027
2696
|
};
|
|
2697
|
+
var scoreKeywordArray = (keywords, title, description) => {
|
|
2698
|
+
if (!keywords || keywords.length === 0) {
|
|
2699
|
+
return { score: 0, issues: ["No keywords defined"], stuffed: false };
|
|
2700
|
+
}
|
|
2701
|
+
const issues = [];
|
|
2702
|
+
let score = 2;
|
|
2703
|
+
if (hasMatchingKeyword(title || "", keywords) || hasMatchingKeyword(description || "", keywords)) {
|
|
2704
|
+
score += 3;
|
|
2705
|
+
} else {
|
|
2706
|
+
issues.push("Keywords defined but not used in title or description");
|
|
2707
|
+
}
|
|
2708
|
+
const stuffed = hasKeywordOveruse(title || "", keywords) || hasKeywordOveruse(description || "", keywords);
|
|
2709
|
+
if (stuffed) issues.push("Keyword stuffing detected \u2014 reduce repeated keyword usage");
|
|
2710
|
+
return { score, issues, stuffed };
|
|
2711
|
+
};
|
|
2712
|
+
var scoreFocusKeyword = (focusKeyword, title, description) => {
|
|
2713
|
+
const placement = getFocusKeywordPlacement(focusKeyword, title, description);
|
|
2714
|
+
if (!placement.hasFocusKeyword) {
|
|
2715
|
+
return { score: 0, issues: ["No focus keyword defined"], stuffed: false };
|
|
2716
|
+
}
|
|
2717
|
+
const issues = [];
|
|
2718
|
+
let score = 1;
|
|
2719
|
+
if (placement.atStartOfTitle) {
|
|
2720
|
+
score += 4;
|
|
2721
|
+
} else if (placement.inTitle) {
|
|
2722
|
+
score += 2;
|
|
2723
|
+
issues.push("Focus keyword is in the title but not at the start");
|
|
2724
|
+
} else if (placement.inDescription) {
|
|
2725
|
+
score += 1;
|
|
2726
|
+
issues.push("Focus keyword missing from meta title");
|
|
2727
|
+
} else {
|
|
2728
|
+
issues.push("Focus keyword missing from meta title and description");
|
|
2729
|
+
}
|
|
2730
|
+
if (placement.isStuffed)
|
|
2731
|
+
issues.push("Focus keyword appears too many times in title \u2014 avoid stuffing");
|
|
2732
|
+
return { score, issues, stuffed: placement.isStuffed };
|
|
2733
|
+
};
|
|
2734
|
+
var scoreKeywordOptimization = (keywords, focusKeyword, title, description) => {
|
|
2735
|
+
const arrayResult = scoreKeywordArray(keywords, title, description);
|
|
2736
|
+
const focusResult = scoreFocusKeyword(focusKeyword, title, description);
|
|
2737
|
+
let score = arrayResult.score + focusResult.score;
|
|
2738
|
+
if (arrayResult.stuffed || focusResult.stuffed) score = Math.max(0, score - 2);
|
|
2739
|
+
return { score: Math.min(score, 10), issues: [...arrayResult.issues, ...focusResult.issues] };
|
|
2740
|
+
};
|
|
2028
2741
|
var calculateHealthScore = (doc) => {
|
|
2029
2742
|
if (!doc.seo) {
|
|
2030
2743
|
return { score: 0, status: "missing", issues: ["SEO fields not configured"] };
|
|
@@ -2033,6 +2746,7 @@ var calculateHealthScore = (doc) => {
|
|
|
2033
2746
|
const title = seo.title;
|
|
2034
2747
|
const description = seo.description;
|
|
2035
2748
|
const keywords = seo.keywords;
|
|
2749
|
+
const focusKeyword = seo.focusKeyword;
|
|
2036
2750
|
const robots = seo.robots;
|
|
2037
2751
|
const openGraph2 = seo.openGraph;
|
|
2038
2752
|
const twitter2 = seo.twitter;
|
|
@@ -2046,8 +2760,9 @@ var calculateHealthScore = (doc) => {
|
|
|
2046
2760
|
issues.push(...descResult.issues);
|
|
2047
2761
|
if (seo.metaImage) score += 10;
|
|
2048
2762
|
else issues.push("Missing meta image");
|
|
2049
|
-
|
|
2050
|
-
|
|
2763
|
+
const keywordResult = scoreKeywordOptimization(keywords, focusKeyword, title, description);
|
|
2764
|
+
score += keywordResult.score;
|
|
2765
|
+
issues.push(...keywordResult.issues);
|
|
2051
2766
|
if (robots && !robots.noIndex) score += 5;
|
|
2052
2767
|
else if (!robots) score += 5;
|
|
2053
2768
|
const ogResult = scoreOpenGraph(openGraph2);
|
|
@@ -2074,7 +2789,19 @@ var calculateHealthScore = (doc) => {
|
|
|
2074
2789
|
|
|
2075
2790
|
// src/index.ts
|
|
2076
2791
|
var src_default = plugin_default;
|
|
2077
|
-
|
|
2078
|
-
|
|
2079
|
-
|
|
2792
|
+
export {
|
|
2793
|
+
SchemaOrgJsonLdPreview as SchemaOrgDocumentJsonLdPreview,
|
|
2794
|
+
SchemaOrgJsonLdPreview,
|
|
2795
|
+
types as allSchemas,
|
|
2796
|
+
baseMeta as baseMetaSchema,
|
|
2797
|
+
calculateHealthScore,
|
|
2798
|
+
createSeoHealthPane,
|
|
2799
|
+
src_default as default,
|
|
2800
|
+
metaAttribute_default as metaAttributeSchema,
|
|
2801
|
+
metaTag_default as metaTagSchema,
|
|
2802
|
+
openGraph as openGraphSchema,
|
|
2803
|
+
robots_default as robotsSchema,
|
|
2804
|
+
seoFieldsSchema,
|
|
2805
|
+
twitter as twitterSchema
|
|
2806
|
+
};
|
|
2080
2807
|
//# sourceMappingURL=index.js.map
|