sanity-plugin-seofields 1.7.0 → 1.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -3
- package/dist/SchemaOrgJsonLdPreview-DJLkIPq4.d.cts +78 -0
- package/dist/SchemaOrgJsonLdPreview-DJLkIPq4.d.ts +78 -0
- package/dist/SeoHealthDashboard-AEKVVMUR-7NWV3C3Y.js +4 -0
- package/dist/SeoHealthDashboard-AEKVVMUR-7NWV3C3Y.js.map +1 -0
- package/dist/SeoHealthDashboard-AEKVVMUR-XWKJUH24.cjs +10 -0
- package/dist/SeoHealthDashboard-AEKVVMUR-XWKJUH24.cjs.map +1 -0
- package/dist/SeoHealthTool-2KKQJLJL.cjs +11 -0
- package/dist/{SeoHealthDashboard-PTUEVYZL.js.map → SeoHealthTool-2KKQJLJL.cjs.map} +1 -1
- package/dist/SeoHealthTool-3CUKGADZ.js +5 -0
- package/dist/{SeoHealthDashboard-IP5BJ322.cjs.map → SeoHealthTool-3CUKGADZ.js.map} +1 -1
- package/dist/{SeoPreview-WYH7NYNM.cjs → SeoPreview-3EXR6FD4.cjs} +3 -3
- package/dist/{SeoPreview-WYH7NYNM.cjs.map → SeoPreview-3EXR6FD4.cjs.map} +1 -1
- package/dist/{SeoPreview-KEGGQSPJ.js → SeoPreview-4PPAF4NO.js} +3 -3
- package/dist/{SeoPreview-KEGGQSPJ.js.map → SeoPreview-4PPAF4NO.js.map} +1 -1
- package/dist/{chunk-S367Y35J.cjs → chunk-254YHUN3.cjs} +2 -15
- package/dist/{chunk-S367Y35J.cjs.map → chunk-254YHUN3.cjs.map} +1 -1
- package/dist/{chunk-AW7OKBQQ.js → chunk-27XSYENH.js} +59 -5
- package/dist/chunk-27XSYENH.js.map +1 -0
- package/dist/{chunk-GWPOJSGW.cjs → chunk-B5IVI5LP.cjs} +821 -156
- package/dist/chunk-B5IVI5LP.cjs.map +1 -0
- package/dist/chunk-BNXMFD3T.cjs +431 -0
- package/dist/chunk-BNXMFD3T.cjs.map +1 -0
- package/dist/{chunk-2NMEKWO5.js → chunk-DDAAVRWG.js} +3 -15
- package/dist/{chunk-2NMEKWO5.js.map → chunk-DDAAVRWG.js.map} +1 -1
- package/dist/chunk-P6IOWIO2.cjs +480 -0
- package/dist/chunk-P6IOWIO2.cjs.map +1 -0
- package/dist/{chunk-FONJYVF2.js → chunk-UOCZFYYP.js} +5 -208
- package/dist/chunk-UOCZFYYP.js.map +1 -0
- package/dist/{chunk-HRKRV2X7.js → chunk-VR44E62I.js} +802 -147
- package/dist/chunk-VR44E62I.js.map +1 -0
- package/dist/chunk-WKXHX3GO.js +424 -0
- package/dist/chunk-WKXHX3GO.js.map +1 -0
- package/dist/{chunk-5YRH47VQ.cjs → chunk-XZDLJ2N6.cjs} +63 -6
- package/dist/chunk-XZDLJ2N6.cjs.map +1 -0
- package/dist/cli.js +18 -18
- package/dist/{component-DQ4KuQQD.d.ts → component-BzI-LHPw.d.cts} +3 -27
- package/dist/{component-D1sBm6ts.d.cts → component-DEXwtemT.d.ts} +3 -27
- package/dist/define-cli.cjs +1 -1
- package/dist/define-cli.js +1 -1
- package/dist/index.cjs +1050 -94
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +76 -295
- package/dist/index.d.ts +76 -295
- package/dist/index.js +1009 -63
- package/dist/index.js.map +1 -1
- package/dist/next.cjs +136 -122
- package/dist/next.cjs.map +1 -1
- package/dist/next.d.cts +9 -3
- package/dist/next.d.ts +9 -3
- package/dist/next.js +38 -32
- package/dist/next.js.map +1 -1
- package/dist/schema/next.cjs +103 -95
- package/dist/schema/next.d.cts +4 -4
- package/dist/schema/next.d.ts +4 -4
- package/dist/schema/next.js +4 -4
- package/dist/schema.cjs +202 -160
- package/dist/schema.cjs.map +1 -1
- package/dist/schema.d.cts +26 -16
- package/dist/schema.d.ts +26 -16
- package/dist/schema.js +25 -7
- package/dist/schema.js.map +1 -1
- package/dist/{types-9_wbCIi9.d.ts → types-BXSCbl6p.d.cts} +29 -2
- package/dist/{types-_wBLg6RV.d.cts → types-B_vjMPtM.d.cts} +1 -1
- package/dist/{types-Bb49oRBV.d.cts → types-C19cQx5D.d.ts} +29 -2
- package/dist/{types-CeBULNFF.d.ts → types-CW8qFdAn.d.ts} +1 -1
- package/dist/{types-B91ena4g.d.cts → types-yVmQfby9.d.cts} +7 -0
- package/dist/{types-B91ena4g.d.ts → types-yVmQfby9.d.ts} +7 -0
- package/package.json +2 -1
- package/dist/SeoHealthDashboard-IP5BJ322.cjs +0 -10
- package/dist/SeoHealthDashboard-PTUEVYZL.js +0 -4
- package/dist/SeoHealthTool-CZZRMWQK.cjs +0 -14
- package/dist/SeoHealthTool-CZZRMWQK.cjs.map +0 -1
- package/dist/SeoHealthTool-IULT4G25.js +0 -12
- package/dist/SeoHealthTool-IULT4G25.js.map +0 -1
- package/dist/chunk-5YRH47VQ.cjs.map +0 -1
- package/dist/chunk-ARELX3GK.cjs +0 -689
- package/dist/chunk-ARELX3GK.cjs.map +0 -1
- package/dist/chunk-AW7OKBQQ.js.map +0 -1
- package/dist/chunk-FONJYVF2.js.map +0 -1
- package/dist/chunk-GWPOJSGW.cjs.map +0 -1
- package/dist/chunk-HRKRV2X7.js.map +0 -1
package/README.md
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-

|
|
2
2
|
|
|
3
3
|
# sanity-plugin-seofields
|
|
4
4
|
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
|
|
7
7
|
Manage SEO fields, social previews, robots directives, canonical URLs, Schema.org JSON-LD, and studio-wide SEO health checks — directly inside Sanity Studio v3, v4, or v5.
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
<p><a href="https://www.npmjs.com/package/sanity-plugin-seofields"><img src="https://img.shields.io/npm/v/sanity-plugin-seofields.svg?color=10b981&label=npm" alt="npm version" /></a> <a href="https://www.npmjs.com/package/sanity-plugin-seofields"><img src="https://img.shields.io/npm/dm/sanity-plugin-seofields.svg?color=2563eb&label=downloads" alt="npm downloads" /></a> <a href="./LICENSE"><img src="https://img.shields.io/npm/l/sanity-plugin-seofields.svg?color=f59e0b" alt="license" /></a> <a href="https://github.com/hardik-143/sanity-plugin-seofields"><img src="https://img.shields.io/github/stars/hardik-143/sanity-plugin-seofields?style=social" alt="GitHub stars" /></a> <a href="https://www.sanity.io"><img src="https://img.shields.io/badge/Sanity-v3%20%7C%20v4%20%7C%20v5-f03e2f?logo=sanity" alt="Sanity" /></a> <a href="#compatibility"><img src="https://img.shields.io/badge/TypeScript-ready-3178c6?logo=typescript&logoColor=white" alt="TypeScript" /></a></p>
|
|
10
10
|
|
|
11
11
|
[**Documentation**](https://sanity-plugin-seofields.thehardik.in/docs) • [Quick Start](#quick-start) • [Configuration](#configuration) • [Schema.org](#schemaorg-structured-data) • [CLI](#cli)
|
|
12
12
|
|
|
@@ -217,7 +217,7 @@ Full guide: [Frontend integration](https://sanity-plugin-seofields.thehardik.in/
|
|
|
217
217
|
| `seoFields` | Complete SEO field bundle for document schemas |
|
|
218
218
|
| `openGraph` | Open Graph metadata for Facebook, LinkedIn, Slack, and other social surfaces |
|
|
219
219
|
| `twitter` | X/Twitter Card metadata |
|
|
220
|
-
| `robots` | Indexing and
|
|
220
|
+
| `robots` | Indexing, crawling, translation, and image indexing directives |
|
|
221
221
|
| `metaTag` | Custom meta tag container |
|
|
222
222
|
| `metaAttribute` | Single custom meta attribute |
|
|
223
223
|
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { JSX } from 'react';
|
|
2
|
+
import { InputProps } from 'sanity';
|
|
3
|
+
|
|
4
|
+
type DocumentRecord = {
|
|
5
|
+
_id?: string;
|
|
6
|
+
_type?: string;
|
|
7
|
+
title?: string;
|
|
8
|
+
} & Record<string, unknown>;
|
|
9
|
+
type DocumentViewDocument = DocumentRecord | {
|
|
10
|
+
displayed?: DocumentRecord | null;
|
|
11
|
+
draft?: DocumentRecord | null;
|
|
12
|
+
published?: DocumentRecord | null;
|
|
13
|
+
} | null;
|
|
14
|
+
interface SchemaOrgJsonLdPreviewOptions {
|
|
15
|
+
/**
|
|
16
|
+
* The base site URL used with the document slug to show a resolved page URL.
|
|
17
|
+
* Defaults to `https://www.example.com`.
|
|
18
|
+
*/
|
|
19
|
+
baseUrl?: string;
|
|
20
|
+
/**
|
|
21
|
+
* Document field used for the slug. Supports dot paths such as `seo.slug`.
|
|
22
|
+
* Defaults to `slug`.
|
|
23
|
+
*/
|
|
24
|
+
slugField?: string;
|
|
25
|
+
/**
|
|
26
|
+
* Combined Schema.org field on the document. Defaults to `schemaOrg`.
|
|
27
|
+
*/
|
|
28
|
+
schemaOrgField?: string;
|
|
29
|
+
/**
|
|
30
|
+
* Optional path segment placed before the document slug, e.g. `blog`.
|
|
31
|
+
* Can be a function of the current document.
|
|
32
|
+
*/
|
|
33
|
+
pathPrefix?: string | ((document: DocumentRecord) => string);
|
|
34
|
+
/**
|
|
35
|
+
* Full override for building the resolved document URL.
|
|
36
|
+
*/
|
|
37
|
+
urlBuilder?: (document: DocumentRecord) => string;
|
|
38
|
+
/**
|
|
39
|
+
* API version for the slug-list query.
|
|
40
|
+
*/
|
|
41
|
+
apiVersion?: string;
|
|
42
|
+
/**
|
|
43
|
+
* Custom GROQ query for the slug list. Should return `_id`, optional `title`,
|
|
44
|
+
* and `slug` as a string.
|
|
45
|
+
*/
|
|
46
|
+
slugQuery?: string;
|
|
47
|
+
/**
|
|
48
|
+
* Show existing slugs for the same document type.
|
|
49
|
+
* Defaults to `true` for document previews and `false` for field input previews.
|
|
50
|
+
*/
|
|
51
|
+
showSlugList?: boolean;
|
|
52
|
+
/**
|
|
53
|
+
* Max number of existing slugs to fetch. Defaults to `25`.
|
|
54
|
+
*/
|
|
55
|
+
maxSlugItems?: number;
|
|
56
|
+
/**
|
|
57
|
+
* Title field used in the slug list. Defaults to `title`.
|
|
58
|
+
*/
|
|
59
|
+
titleField?: string;
|
|
60
|
+
}
|
|
61
|
+
interface SchemaOrgJsonLdPreviewProps extends SchemaOrgJsonLdPreviewOptions {
|
|
62
|
+
/** Schema.org value to preview. Uses `document[schemaOrgField]` when omitted. */
|
|
63
|
+
value?: Record<string, unknown> | Array<Record<string, unknown>> | null;
|
|
64
|
+
/** Current Sanity document or document-view `document` prop. */
|
|
65
|
+
document?: DocumentViewDocument;
|
|
66
|
+
/** Optional document id from a Sanity document-node component view. */
|
|
67
|
+
documentId?: string;
|
|
68
|
+
/** Optional schema type from a Sanity document-node component view. */
|
|
69
|
+
schemaType?: string;
|
|
70
|
+
/** Fallback Schema.org type name for individual object inputs. */
|
|
71
|
+
schemaTypeName?: string;
|
|
72
|
+
/** Internal flag used by field input previews. */
|
|
73
|
+
fieldPreview?: boolean;
|
|
74
|
+
}
|
|
75
|
+
declare function SchemaOrgJsonLdPreview({ value, document, documentId, schemaType, schemaTypeName, fieldPreview, baseUrl, slugField, schemaOrgField, pathPrefix, urlBuilder, apiVersion, slugQuery, showSlugList, maxSlugItems, titleField, }: SchemaOrgJsonLdPreviewProps): JSX.Element;
|
|
76
|
+
declare function SchemaOrgJsonLdPreviewInput(props: InputProps): JSX.Element;
|
|
77
|
+
|
|
78
|
+
export { SchemaOrgJsonLdPreview as S, type SchemaOrgJsonLdPreviewOptions as a, type SchemaOrgJsonLdPreviewProps as b, SchemaOrgJsonLdPreviewInput as c };
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { JSX } from 'react';
|
|
2
|
+
import { InputProps } from 'sanity';
|
|
3
|
+
|
|
4
|
+
type DocumentRecord = {
|
|
5
|
+
_id?: string;
|
|
6
|
+
_type?: string;
|
|
7
|
+
title?: string;
|
|
8
|
+
} & Record<string, unknown>;
|
|
9
|
+
type DocumentViewDocument = DocumentRecord | {
|
|
10
|
+
displayed?: DocumentRecord | null;
|
|
11
|
+
draft?: DocumentRecord | null;
|
|
12
|
+
published?: DocumentRecord | null;
|
|
13
|
+
} | null;
|
|
14
|
+
interface SchemaOrgJsonLdPreviewOptions {
|
|
15
|
+
/**
|
|
16
|
+
* The base site URL used with the document slug to show a resolved page URL.
|
|
17
|
+
* Defaults to `https://www.example.com`.
|
|
18
|
+
*/
|
|
19
|
+
baseUrl?: string;
|
|
20
|
+
/**
|
|
21
|
+
* Document field used for the slug. Supports dot paths such as `seo.slug`.
|
|
22
|
+
* Defaults to `slug`.
|
|
23
|
+
*/
|
|
24
|
+
slugField?: string;
|
|
25
|
+
/**
|
|
26
|
+
* Combined Schema.org field on the document. Defaults to `schemaOrg`.
|
|
27
|
+
*/
|
|
28
|
+
schemaOrgField?: string;
|
|
29
|
+
/**
|
|
30
|
+
* Optional path segment placed before the document slug, e.g. `blog`.
|
|
31
|
+
* Can be a function of the current document.
|
|
32
|
+
*/
|
|
33
|
+
pathPrefix?: string | ((document: DocumentRecord) => string);
|
|
34
|
+
/**
|
|
35
|
+
* Full override for building the resolved document URL.
|
|
36
|
+
*/
|
|
37
|
+
urlBuilder?: (document: DocumentRecord) => string;
|
|
38
|
+
/**
|
|
39
|
+
* API version for the slug-list query.
|
|
40
|
+
*/
|
|
41
|
+
apiVersion?: string;
|
|
42
|
+
/**
|
|
43
|
+
* Custom GROQ query for the slug list. Should return `_id`, optional `title`,
|
|
44
|
+
* and `slug` as a string.
|
|
45
|
+
*/
|
|
46
|
+
slugQuery?: string;
|
|
47
|
+
/**
|
|
48
|
+
* Show existing slugs for the same document type.
|
|
49
|
+
* Defaults to `true` for document previews and `false` for field input previews.
|
|
50
|
+
*/
|
|
51
|
+
showSlugList?: boolean;
|
|
52
|
+
/**
|
|
53
|
+
* Max number of existing slugs to fetch. Defaults to `25`.
|
|
54
|
+
*/
|
|
55
|
+
maxSlugItems?: number;
|
|
56
|
+
/**
|
|
57
|
+
* Title field used in the slug list. Defaults to `title`.
|
|
58
|
+
*/
|
|
59
|
+
titleField?: string;
|
|
60
|
+
}
|
|
61
|
+
interface SchemaOrgJsonLdPreviewProps extends SchemaOrgJsonLdPreviewOptions {
|
|
62
|
+
/** Schema.org value to preview. Uses `document[schemaOrgField]` when omitted. */
|
|
63
|
+
value?: Record<string, unknown> | Array<Record<string, unknown>> | null;
|
|
64
|
+
/** Current Sanity document or document-view `document` prop. */
|
|
65
|
+
document?: DocumentViewDocument;
|
|
66
|
+
/** Optional document id from a Sanity document-node component view. */
|
|
67
|
+
documentId?: string;
|
|
68
|
+
/** Optional schema type from a Sanity document-node component view. */
|
|
69
|
+
schemaType?: string;
|
|
70
|
+
/** Fallback Schema.org type name for individual object inputs. */
|
|
71
|
+
schemaTypeName?: string;
|
|
72
|
+
/** Internal flag used by field input previews. */
|
|
73
|
+
fieldPreview?: boolean;
|
|
74
|
+
}
|
|
75
|
+
declare function SchemaOrgJsonLdPreview({ value, document, documentId, schemaType, schemaTypeName, fieldPreview, baseUrl, slugField, schemaOrgField, pathPrefix, urlBuilder, apiVersion, slugQuery, showSlugList, maxSlugItems, titleField, }: SchemaOrgJsonLdPreviewProps): JSX.Element;
|
|
76
|
+
declare function SchemaOrgJsonLdPreviewInput(props: InputProps): JSX.Element;
|
|
77
|
+
|
|
78
|
+
export { SchemaOrgJsonLdPreview as S, type SchemaOrgJsonLdPreviewOptions as a, type SchemaOrgJsonLdPreviewProps as b, SchemaOrgJsonLdPreviewInput as c };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"names":[],"mappings":"","file":"SeoHealthDashboard-AEKVVMUR-7NWV3C3Y.js"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var chunkXZDLJ2N6_cjs = require('./chunk-XZDLJ2N6.cjs');
|
|
4
|
+
require('./chunk-254YHUN3.cjs');
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
module.exports = chunkXZDLJ2N6_cjs.SeoHealthDashboard_default;
|
|
9
|
+
//# sourceMappingURL=SeoHealthDashboard-AEKVVMUR-XWKJUH24.cjs.map
|
|
10
|
+
//# sourceMappingURL=SeoHealthDashboard-AEKVVMUR-XWKJUH24.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"names":[],"mappings":"","file":"SeoHealthDashboard-AEKVVMUR-XWKJUH24.cjs"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var chunkBNXMFD3T_cjs = require('./chunk-BNXMFD3T.cjs');
|
|
4
|
+
require('./chunk-XZDLJ2N6.cjs');
|
|
5
|
+
require('./chunk-254YHUN3.cjs');
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
module.exports = chunkBNXMFD3T_cjs.SeoHealthTool_default;
|
|
10
|
+
//# sourceMappingURL=SeoHealthTool-2KKQJLJL.cjs.map
|
|
11
|
+
//# sourceMappingURL=SeoHealthTool-2KKQJLJL.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":[],"names":[],"mappings":"","file":"
|
|
1
|
+
{"version":3,"sources":[],"names":[],"mappings":"","file":"SeoHealthTool-2KKQJLJL.cjs"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":[],"names":[],"mappings":"","file":"
|
|
1
|
+
{"version":3,"sources":[],"names":[],"mappings":"","file":"SeoHealthTool-3CUKGADZ.js"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
var chunkZBHLMQTS_cjs = require('./chunk-ZBHLMQTS.cjs');
|
|
4
|
-
require('./chunk-
|
|
4
|
+
require('./chunk-254YHUN3.cjs');
|
|
5
5
|
var ui = require('@sanity/ui');
|
|
6
6
|
var react = require('react');
|
|
7
7
|
var sanity = require('sanity');
|
|
@@ -186,5 +186,5 @@ var SeoPreview = (props) => {
|
|
|
186
186
|
var SeoPreview_default = SeoPreview;
|
|
187
187
|
|
|
188
188
|
module.exports = SeoPreview_default;
|
|
189
|
-
//# sourceMappingURL=SeoPreview-
|
|
190
|
-
//# sourceMappingURL=SeoPreview-
|
|
189
|
+
//# sourceMappingURL=SeoPreview-3EXR6FD4.cjs.map
|
|
190
|
+
//# sourceMappingURL=SeoPreview-3EXR6FD4.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/components/SeoPreview.tsx"],"names":["styled","useClient","useState","useEffect","useFormValue","jsx","Box","jsxs","Fragment","truncate"],"mappings":"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","file":"SeoPreview-WYH7NYNM.cjs","sourcesContent":["import {Box} from '@sanity/ui'\nimport {type ReactElement, useEffect, useState} from 'react'\nimport {StringInputProps, useClient, useFormValue} from 'sanity'\nimport styled from 'styled-components'\n\nimport {truncate} from '../utils/seoUtils'\n\nconst PreviewContainer = styled.div`\n max-width: 600px;\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;\n background: #ffffff;\n border: 1px solid #dadce0;\n border-radius: 8px;\n overflow: hidden;\n`\n\nconst PreviewHeader = styled.div`\n background: #f8f9fa;\n padding: 12px 16px;\n border-bottom: 1px solid #dadce0;\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 8px;\n`\n\nconst PreviewBody = styled.div`\n padding: 16px;\n`\n\nconst SerpUrl = styled.p`\n margin: 0 0 4px;\n color: #006621;\n font-size: 13px;\n line-height: 1.4;\n word-break: break-word;\n`\n\nconst SerpTitle = styled.h3`\n margin: 0 0 8px;\n color: #1a0dab;\n font-size: 18px;\n font-weight: 500;\n line-height: 1.4;\n word-break: break-word;\n\n &:hover {\n text-decoration: underline;\n }\n`\n\nconst SerpDescription = styled.p`\n margin: 0;\n color: #545454;\n font-size: 14px;\n line-height: 1.6;\n word-break: break-word;\n display: -webkit-box;\n -webkit-line-clamp: 2;\n -webkit-box-orient: vertical;\n overflow: hidden;\n`\n\nconst LiveIndicator = styled.span`\n display: inline-flex;\n align-items: center;\n gap: 4px;\n font-size: 11px;\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.05em;\n color: #4f46e5;\n background: #f0f4ff;\n padding: 4px 8px;\n border-radius: 4px;\n`\n\nconst SeoPreview = (props: StringInputProps): ReactElement => {\n const {path, schemaType} = props\n const {options} = schemaType as {\n options?: {\n baseUrl?: string\n apiVersion?: string\n prefix?: ((doc: {_type?: string} & Record<string, unknown>) => string) | string\n titleSuffix?: ((doc: {_type?: string} & Record<string, unknown>) => string) | string\n titleSuffixInheritColor?: boolean\n titleSuffixQuery?: string\n }\n }\n const baseUrl = options?.baseUrl || 'https://www.example.com'\n const prefixFunction = options?.prefix as\n | ((doc: {_type?: string} & Record<string, unknown>) => string)\n | undefined\n const titleSuffixOption = options?.titleSuffix\n const titleSuffixInheritColor = options?.titleSuffixInheritColor ?? false\n const titleSuffixQuery = options?.titleSuffixQuery\n\n const client = useClient({apiVersion: options?.apiVersion ?? '2024-01-01'})\n const [groqTitleSuffix, setGroqTitleSuffix] = useState<string>('')\n\n useEffect(() => {\n if (!titleSuffixQuery) return\n client\n .fetch<string>(titleSuffixQuery)\n .then((result) => {\n setGroqTitleSuffix(result === null || result === undefined ? '' : String(result))\n })\n .catch(() => {\n setGroqTitleSuffix('')\n })\n }, [titleSuffixQuery, client])\n const parent = useFormValue([path[0]]) || {\n title: '',\n description: '',\n canonicalUrl: '',\n }\n const rootDoc: {\n slug?: {current: string}\n } = useFormValue([]) || {\n slug: {current: ''},\n }\n const slug: string = rootDoc?.slug?.current || ''\n\n const {\n title,\n description,\n canonicalUrl: url,\n } = parent as {\n title?: string\n description?: string\n canonicalUrl?: string\n }\n\n const getTitleSuffix = (): string => {\n if (titleSuffixQuery) return groqTitleSuffix\n if (!titleSuffixOption) return ''\n if (typeof titleSuffixOption === 'function') {\n return titleSuffixOption(rootDoc as {_type?: string} & Record<string, unknown>)\n }\n return titleSuffixOption\n }\n const titleSuffix: string = getTitleSuffix()\n\n // Build full URL\n const base = (url || baseUrl)?.replace(/\\/+$/, '')\n const slugStr = String(slug || '').replace(/^\\/+/, '')\n const pref = String(\n prefixFunction ? prefixFunction(rootDoc as {slug?: {current: string}}) : '',\n ).replace(/^\\/+|\\/+$/g, '')\n const urlPath = [pref, slugStr].filter(Boolean).join('/')\n const finalUrl = urlPath ? `${base}/${urlPath}` : base\n\n // Extract domain for display\n const domain = (() => {\n try {\n const u = new URL(finalUrl || base)\n return u.hostname\n } catch {\n return 'example.com'\n }\n })()\n\n // Format URL display with › separator\n const urlDisplay = `${domain}${urlPath ? ` › ${urlPath.split('/').slice(-1)[0]}` : ''}`\n\n return (\n <Box padding={3}>\n <PreviewContainer>\n <PreviewHeader>\n <span\n style={{\n fontSize: '11px',\n color: '#5f6368',\n textTransform: 'uppercase',\n letterSpacing: '0.05em',\n }}\n >\n Search Preview\n </span>\n <LiveIndicator>\n <span\n style={{\n width: '4px',\n height: '4px',\n borderRadius: '50%',\n backgroundColor: '#4f46e5',\n display: 'inline-block',\n }}\n />\n Live\n </LiveIndicator>\n </PreviewHeader>\n\n <PreviewBody>\n <SerpUrl>{finalUrl ? urlDisplay : 'example.com › page-url'}</SerpUrl>\n <SerpTitle>\n {title && title.length > 0 ? (\n <>\n {truncate(title, Math.max(1, 60 - (titleSuffix ? titleSuffix.length + 3 : 0)))}\n {titleSuffix && (\n <span\n style={\n titleSuffixInheritColor ? undefined : {color: '#70757a', fontWeight: 400}\n }\n >\n {' '}\n | {titleSuffix}\n </span>\n )}\n </>\n ) : (\n 'Your SEO Title will appear here'\n )}\n </SerpTitle>\n <SerpDescription>\n {description && description.length > 0\n ? truncate(description, 160)\n : 'Your meta description will show up here. Make it compelling!'}\n </SerpDescription>\n </PreviewBody>\n </PreviewContainer>\n </Box>\n )\n}\n\nexport default SeoPreview\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/components/SeoPreview.tsx"],"names":["styled","useClient","useState","useEffect","useFormValue","jsx","Box","jsxs","Fragment","truncate"],"mappings":"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","file":"SeoPreview-3EXR6FD4.cjs","sourcesContent":["import {Box} from '@sanity/ui'\nimport {type ReactElement, useEffect, useState} from 'react'\nimport {StringInputProps, useClient, useFormValue} from 'sanity'\nimport styled from 'styled-components'\n\nimport {truncate} from '../utils/seoUtils'\n\nconst PreviewContainer = styled.div`\n max-width: 600px;\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;\n background: #ffffff;\n border: 1px solid #dadce0;\n border-radius: 8px;\n overflow: hidden;\n`\n\nconst PreviewHeader = styled.div`\n background: #f8f9fa;\n padding: 12px 16px;\n border-bottom: 1px solid #dadce0;\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 8px;\n`\n\nconst PreviewBody = styled.div`\n padding: 16px;\n`\n\nconst SerpUrl = styled.p`\n margin: 0 0 4px;\n color: #006621;\n font-size: 13px;\n line-height: 1.4;\n word-break: break-word;\n`\n\nconst SerpTitle = styled.h3`\n margin: 0 0 8px;\n color: #1a0dab;\n font-size: 18px;\n font-weight: 500;\n line-height: 1.4;\n word-break: break-word;\n\n &:hover {\n text-decoration: underline;\n }\n`\n\nconst SerpDescription = styled.p`\n margin: 0;\n color: #545454;\n font-size: 14px;\n line-height: 1.6;\n word-break: break-word;\n display: -webkit-box;\n -webkit-line-clamp: 2;\n -webkit-box-orient: vertical;\n overflow: hidden;\n`\n\nconst LiveIndicator = styled.span`\n display: inline-flex;\n align-items: center;\n gap: 4px;\n font-size: 11px;\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.05em;\n color: #4f46e5;\n background: #f0f4ff;\n padding: 4px 8px;\n border-radius: 4px;\n`\n\nconst SeoPreview = (props: StringInputProps): ReactElement => {\n const {path, schemaType} = props\n const {options} = schemaType as {\n options?: {\n baseUrl?: string\n apiVersion?: string\n prefix?: ((doc: {_type?: string} & Record<string, unknown>) => string) | string\n titleSuffix?: ((doc: {_type?: string} & Record<string, unknown>) => string) | string\n titleSuffixInheritColor?: boolean\n titleSuffixQuery?: string\n }\n }\n const baseUrl = options?.baseUrl || 'https://www.example.com'\n const prefixFunction = options?.prefix as\n | ((doc: {_type?: string} & Record<string, unknown>) => string)\n | undefined\n const titleSuffixOption = options?.titleSuffix\n const titleSuffixInheritColor = options?.titleSuffixInheritColor ?? false\n const titleSuffixQuery = options?.titleSuffixQuery\n\n const client = useClient({apiVersion: options?.apiVersion ?? '2024-01-01'})\n const [groqTitleSuffix, setGroqTitleSuffix] = useState<string>('')\n\n useEffect(() => {\n if (!titleSuffixQuery) return\n client\n .fetch<string>(titleSuffixQuery)\n .then((result) => {\n setGroqTitleSuffix(result === null || result === undefined ? '' : String(result))\n })\n .catch(() => {\n setGroqTitleSuffix('')\n })\n }, [titleSuffixQuery, client])\n const parent = useFormValue([path[0]]) || {\n title: '',\n description: '',\n canonicalUrl: '',\n }\n const rootDoc: {\n slug?: {current: string}\n } = useFormValue([]) || {\n slug: {current: ''},\n }\n const slug: string = rootDoc?.slug?.current || ''\n\n const {\n title,\n description,\n canonicalUrl: url,\n } = parent as {\n title?: string\n description?: string\n canonicalUrl?: string\n }\n\n const getTitleSuffix = (): string => {\n if (titleSuffixQuery) return groqTitleSuffix\n if (!titleSuffixOption) return ''\n if (typeof titleSuffixOption === 'function') {\n return titleSuffixOption(rootDoc as {_type?: string} & Record<string, unknown>)\n }\n return titleSuffixOption\n }\n const titleSuffix: string = getTitleSuffix()\n\n // Build full URL\n const base = (url || baseUrl)?.replace(/\\/+$/, '')\n const slugStr = String(slug || '').replace(/^\\/+/, '')\n const pref = String(\n prefixFunction ? prefixFunction(rootDoc as {slug?: {current: string}}) : '',\n ).replace(/^\\/+|\\/+$/g, '')\n const urlPath = [pref, slugStr].filter(Boolean).join('/')\n const finalUrl = urlPath ? `${base}/${urlPath}` : base\n\n // Extract domain for display\n const domain = (() => {\n try {\n const u = new URL(finalUrl || base)\n return u.hostname\n } catch {\n return 'example.com'\n }\n })()\n\n // Format URL display with › separator\n const urlDisplay = `${domain}${urlPath ? ` › ${urlPath.split('/').slice(-1)[0]}` : ''}`\n\n return (\n <Box padding={3}>\n <PreviewContainer>\n <PreviewHeader>\n <span\n style={{\n fontSize: '11px',\n color: '#5f6368',\n textTransform: 'uppercase',\n letterSpacing: '0.05em',\n }}\n >\n Search Preview\n </span>\n <LiveIndicator>\n <span\n style={{\n width: '4px',\n height: '4px',\n borderRadius: '50%',\n backgroundColor: '#4f46e5',\n display: 'inline-block',\n }}\n />\n Live\n </LiveIndicator>\n </PreviewHeader>\n\n <PreviewBody>\n <SerpUrl>{finalUrl ? urlDisplay : 'example.com › page-url'}</SerpUrl>\n <SerpTitle>\n {title && title.length > 0 ? (\n <>\n {truncate(title, Math.max(1, 60 - (titleSuffix ? titleSuffix.length + 3 : 0)))}\n {titleSuffix && (\n <span\n style={\n titleSuffixInheritColor ? undefined : {color: '#70757a', fontWeight: 400}\n }\n >\n {' '}\n | {titleSuffix}\n </span>\n )}\n </>\n ) : (\n 'Your SEO Title will appear here'\n )}\n </SerpTitle>\n <SerpDescription>\n {description && description.length > 0\n ? truncate(description, 160)\n : 'Your meta description will show up here. Make it compelling!'}\n </SerpDescription>\n </PreviewBody>\n </PreviewContainer>\n </Box>\n )\n}\n\nexport default SeoPreview\n"]}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { truncate } from './chunk-HDZZQCH7.js';
|
|
2
|
-
import './chunk-
|
|
2
|
+
import './chunk-DDAAVRWG.js';
|
|
3
3
|
import { Box } from '@sanity/ui';
|
|
4
4
|
import { useState, useEffect } from 'react';
|
|
5
5
|
import { useClient, useFormValue } from 'sanity';
|
|
@@ -180,5 +180,5 @@ var SeoPreview = (props) => {
|
|
|
180
180
|
var SeoPreview_default = SeoPreview;
|
|
181
181
|
|
|
182
182
|
export { SeoPreview_default as default };
|
|
183
|
-
//# sourceMappingURL=SeoPreview-
|
|
184
|
-
//# sourceMappingURL=SeoPreview-
|
|
183
|
+
//# sourceMappingURL=SeoPreview-4PPAF4NO.js.map
|
|
184
|
+
//# sourceMappingURL=SeoPreview-4PPAF4NO.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/components/SeoPreview.tsx"],"names":[],"mappings":"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","file":"SeoPreview-KEGGQSPJ.js","sourcesContent":["import {Box} from '@sanity/ui'\nimport {type ReactElement, useEffect, useState} from 'react'\nimport {StringInputProps, useClient, useFormValue} from 'sanity'\nimport styled from 'styled-components'\n\nimport {truncate} from '../utils/seoUtils'\n\nconst PreviewContainer = styled.div`\n max-width: 600px;\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;\n background: #ffffff;\n border: 1px solid #dadce0;\n border-radius: 8px;\n overflow: hidden;\n`\n\nconst PreviewHeader = styled.div`\n background: #f8f9fa;\n padding: 12px 16px;\n border-bottom: 1px solid #dadce0;\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 8px;\n`\n\nconst PreviewBody = styled.div`\n padding: 16px;\n`\n\nconst SerpUrl = styled.p`\n margin: 0 0 4px;\n color: #006621;\n font-size: 13px;\n line-height: 1.4;\n word-break: break-word;\n`\n\nconst SerpTitle = styled.h3`\n margin: 0 0 8px;\n color: #1a0dab;\n font-size: 18px;\n font-weight: 500;\n line-height: 1.4;\n word-break: break-word;\n\n &:hover {\n text-decoration: underline;\n }\n`\n\nconst SerpDescription = styled.p`\n margin: 0;\n color: #545454;\n font-size: 14px;\n line-height: 1.6;\n word-break: break-word;\n display: -webkit-box;\n -webkit-line-clamp: 2;\n -webkit-box-orient: vertical;\n overflow: hidden;\n`\n\nconst LiveIndicator = styled.span`\n display: inline-flex;\n align-items: center;\n gap: 4px;\n font-size: 11px;\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.05em;\n color: #4f46e5;\n background: #f0f4ff;\n padding: 4px 8px;\n border-radius: 4px;\n`\n\nconst SeoPreview = (props: StringInputProps): ReactElement => {\n const {path, schemaType} = props\n const {options} = schemaType as {\n options?: {\n baseUrl?: string\n apiVersion?: string\n prefix?: ((doc: {_type?: string} & Record<string, unknown>) => string) | string\n titleSuffix?: ((doc: {_type?: string} & Record<string, unknown>) => string) | string\n titleSuffixInheritColor?: boolean\n titleSuffixQuery?: string\n }\n }\n const baseUrl = options?.baseUrl || 'https://www.example.com'\n const prefixFunction = options?.prefix as\n | ((doc: {_type?: string} & Record<string, unknown>) => string)\n | undefined\n const titleSuffixOption = options?.titleSuffix\n const titleSuffixInheritColor = options?.titleSuffixInheritColor ?? false\n const titleSuffixQuery = options?.titleSuffixQuery\n\n const client = useClient({apiVersion: options?.apiVersion ?? '2024-01-01'})\n const [groqTitleSuffix, setGroqTitleSuffix] = useState<string>('')\n\n useEffect(() => {\n if (!titleSuffixQuery) return\n client\n .fetch<string>(titleSuffixQuery)\n .then((result) => {\n setGroqTitleSuffix(result === null || result === undefined ? '' : String(result))\n })\n .catch(() => {\n setGroqTitleSuffix('')\n })\n }, [titleSuffixQuery, client])\n const parent = useFormValue([path[0]]) || {\n title: '',\n description: '',\n canonicalUrl: '',\n }\n const rootDoc: {\n slug?: {current: string}\n } = useFormValue([]) || {\n slug: {current: ''},\n }\n const slug: string = rootDoc?.slug?.current || ''\n\n const {\n title,\n description,\n canonicalUrl: url,\n } = parent as {\n title?: string\n description?: string\n canonicalUrl?: string\n }\n\n const getTitleSuffix = (): string => {\n if (titleSuffixQuery) return groqTitleSuffix\n if (!titleSuffixOption) return ''\n if (typeof titleSuffixOption === 'function') {\n return titleSuffixOption(rootDoc as {_type?: string} & Record<string, unknown>)\n }\n return titleSuffixOption\n }\n const titleSuffix: string = getTitleSuffix()\n\n // Build full URL\n const base = (url || baseUrl)?.replace(/\\/+$/, '')\n const slugStr = String(slug || '').replace(/^\\/+/, '')\n const pref = String(\n prefixFunction ? prefixFunction(rootDoc as {slug?: {current: string}}) : '',\n ).replace(/^\\/+|\\/+$/g, '')\n const urlPath = [pref, slugStr].filter(Boolean).join('/')\n const finalUrl = urlPath ? `${base}/${urlPath}` : base\n\n // Extract domain for display\n const domain = (() => {\n try {\n const u = new URL(finalUrl || base)\n return u.hostname\n } catch {\n return 'example.com'\n }\n })()\n\n // Format URL display with › separator\n const urlDisplay = `${domain}${urlPath ? ` › ${urlPath.split('/').slice(-1)[0]}` : ''}`\n\n return (\n <Box padding={3}>\n <PreviewContainer>\n <PreviewHeader>\n <span\n style={{\n fontSize: '11px',\n color: '#5f6368',\n textTransform: 'uppercase',\n letterSpacing: '0.05em',\n }}\n >\n Search Preview\n </span>\n <LiveIndicator>\n <span\n style={{\n width: '4px',\n height: '4px',\n borderRadius: '50%',\n backgroundColor: '#4f46e5',\n display: 'inline-block',\n }}\n />\n Live\n </LiveIndicator>\n </PreviewHeader>\n\n <PreviewBody>\n <SerpUrl>{finalUrl ? urlDisplay : 'example.com › page-url'}</SerpUrl>\n <SerpTitle>\n {title && title.length > 0 ? (\n <>\n {truncate(title, Math.max(1, 60 - (titleSuffix ? titleSuffix.length + 3 : 0)))}\n {titleSuffix && (\n <span\n style={\n titleSuffixInheritColor ? undefined : {color: '#70757a', fontWeight: 400}\n }\n >\n {' '}\n | {titleSuffix}\n </span>\n )}\n </>\n ) : (\n 'Your SEO Title will appear here'\n )}\n </SerpTitle>\n <SerpDescription>\n {description && description.length > 0\n ? truncate(description, 160)\n : 'Your meta description will show up here. Make it compelling!'}\n </SerpDescription>\n </PreviewBody>\n </PreviewContainer>\n </Box>\n )\n}\n\nexport default SeoPreview\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/components/SeoPreview.tsx"],"names":[],"mappings":"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","file":"SeoPreview-4PPAF4NO.js","sourcesContent":["import {Box} from '@sanity/ui'\nimport {type ReactElement, useEffect, useState} from 'react'\nimport {StringInputProps, useClient, useFormValue} from 'sanity'\nimport styled from 'styled-components'\n\nimport {truncate} from '../utils/seoUtils'\n\nconst PreviewContainer = styled.div`\n max-width: 600px;\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;\n background: #ffffff;\n border: 1px solid #dadce0;\n border-radius: 8px;\n overflow: hidden;\n`\n\nconst PreviewHeader = styled.div`\n background: #f8f9fa;\n padding: 12px 16px;\n border-bottom: 1px solid #dadce0;\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 8px;\n`\n\nconst PreviewBody = styled.div`\n padding: 16px;\n`\n\nconst SerpUrl = styled.p`\n margin: 0 0 4px;\n color: #006621;\n font-size: 13px;\n line-height: 1.4;\n word-break: break-word;\n`\n\nconst SerpTitle = styled.h3`\n margin: 0 0 8px;\n color: #1a0dab;\n font-size: 18px;\n font-weight: 500;\n line-height: 1.4;\n word-break: break-word;\n\n &:hover {\n text-decoration: underline;\n }\n`\n\nconst SerpDescription = styled.p`\n margin: 0;\n color: #545454;\n font-size: 14px;\n line-height: 1.6;\n word-break: break-word;\n display: -webkit-box;\n -webkit-line-clamp: 2;\n -webkit-box-orient: vertical;\n overflow: hidden;\n`\n\nconst LiveIndicator = styled.span`\n display: inline-flex;\n align-items: center;\n gap: 4px;\n font-size: 11px;\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.05em;\n color: #4f46e5;\n background: #f0f4ff;\n padding: 4px 8px;\n border-radius: 4px;\n`\n\nconst SeoPreview = (props: StringInputProps): ReactElement => {\n const {path, schemaType} = props\n const {options} = schemaType as {\n options?: {\n baseUrl?: string\n apiVersion?: string\n prefix?: ((doc: {_type?: string} & Record<string, unknown>) => string) | string\n titleSuffix?: ((doc: {_type?: string} & Record<string, unknown>) => string) | string\n titleSuffixInheritColor?: boolean\n titleSuffixQuery?: string\n }\n }\n const baseUrl = options?.baseUrl || 'https://www.example.com'\n const prefixFunction = options?.prefix as\n | ((doc: {_type?: string} & Record<string, unknown>) => string)\n | undefined\n const titleSuffixOption = options?.titleSuffix\n const titleSuffixInheritColor = options?.titleSuffixInheritColor ?? false\n const titleSuffixQuery = options?.titleSuffixQuery\n\n const client = useClient({apiVersion: options?.apiVersion ?? '2024-01-01'})\n const [groqTitleSuffix, setGroqTitleSuffix] = useState<string>('')\n\n useEffect(() => {\n if (!titleSuffixQuery) return\n client\n .fetch<string>(titleSuffixQuery)\n .then((result) => {\n setGroqTitleSuffix(result === null || result === undefined ? '' : String(result))\n })\n .catch(() => {\n setGroqTitleSuffix('')\n })\n }, [titleSuffixQuery, client])\n const parent = useFormValue([path[0]]) || {\n title: '',\n description: '',\n canonicalUrl: '',\n }\n const rootDoc: {\n slug?: {current: string}\n } = useFormValue([]) || {\n slug: {current: ''},\n }\n const slug: string = rootDoc?.slug?.current || ''\n\n const {\n title,\n description,\n canonicalUrl: url,\n } = parent as {\n title?: string\n description?: string\n canonicalUrl?: string\n }\n\n const getTitleSuffix = (): string => {\n if (titleSuffixQuery) return groqTitleSuffix\n if (!titleSuffixOption) return ''\n if (typeof titleSuffixOption === 'function') {\n return titleSuffixOption(rootDoc as {_type?: string} & Record<string, unknown>)\n }\n return titleSuffixOption\n }\n const titleSuffix: string = getTitleSuffix()\n\n // Build full URL\n const base = (url || baseUrl)?.replace(/\\/+$/, '')\n const slugStr = String(slug || '').replace(/^\\/+/, '')\n const pref = String(\n prefixFunction ? prefixFunction(rootDoc as {slug?: {current: string}}) : '',\n ).replace(/^\\/+|\\/+$/g, '')\n const urlPath = [pref, slugStr].filter(Boolean).join('/')\n const finalUrl = urlPath ? `${base}/${urlPath}` : base\n\n // Extract domain for display\n const domain = (() => {\n try {\n const u = new URL(finalUrl || base)\n return u.hostname\n } catch {\n return 'example.com'\n }\n })()\n\n // Format URL display with › separator\n const urlDisplay = `${domain}${urlPath ? ` › ${urlPath.split('/').slice(-1)[0]}` : ''}`\n\n return (\n <Box padding={3}>\n <PreviewContainer>\n <PreviewHeader>\n <span\n style={{\n fontSize: '11px',\n color: '#5f6368',\n textTransform: 'uppercase',\n letterSpacing: '0.05em',\n }}\n >\n Search Preview\n </span>\n <LiveIndicator>\n <span\n style={{\n width: '4px',\n height: '4px',\n borderRadius: '50%',\n backgroundColor: '#4f46e5',\n display: 'inline-block',\n }}\n />\n Live\n </LiveIndicator>\n </PreviewHeader>\n\n <PreviewBody>\n <SerpUrl>{finalUrl ? urlDisplay : 'example.com › page-url'}</SerpUrl>\n <SerpTitle>\n {title && title.length > 0 ? (\n <>\n {truncate(title, Math.max(1, 60 - (titleSuffix ? titleSuffix.length + 3 : 0)))}\n {titleSuffix && (\n <span\n style={\n titleSuffixInheritColor ? undefined : {color: '#70757a', fontWeight: 400}\n }\n >\n {' '}\n | {titleSuffix}\n </span>\n )}\n </>\n ) : (\n 'Your SEO Title will appear here'\n )}\n </SerpTitle>\n <SerpDescription>\n {description && description.length > 0\n ? truncate(description, 160)\n : 'Your meta description will show up here. Make it compelling!'}\n </SerpDescription>\n </PreviewBody>\n </PreviewContainer>\n </Box>\n )\n}\n\nexport default SeoPreview\n"]}
|
|
@@ -19,21 +19,8 @@ var __spreadValues = (a, b) => {
|
|
|
19
19
|
return a;
|
|
20
20
|
};
|
|
21
21
|
var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
|
|
22
|
-
var __objRest = (source, exclude) => {
|
|
23
|
-
var target = {};
|
|
24
|
-
for (var prop in source)
|
|
25
|
-
if (__hasOwnProp.call(source, prop) && exclude.indexOf(prop) < 0)
|
|
26
|
-
target[prop] = source[prop];
|
|
27
|
-
if (source != null && __getOwnPropSymbols)
|
|
28
|
-
for (var prop of __getOwnPropSymbols(source)) {
|
|
29
|
-
if (exclude.indexOf(prop) < 0 && __propIsEnum.call(source, prop))
|
|
30
|
-
target[prop] = source[prop];
|
|
31
|
-
}
|
|
32
|
-
return target;
|
|
33
|
-
};
|
|
34
22
|
|
|
35
|
-
exports.__objRest = __objRest;
|
|
36
23
|
exports.__spreadProps = __spreadProps;
|
|
37
24
|
exports.__spreadValues = __spreadValues;
|
|
38
|
-
//# sourceMappingURL=chunk-
|
|
39
|
-
//# sourceMappingURL=chunk-
|
|
25
|
+
//# sourceMappingURL=chunk-254YHUN3.cjs.map
|
|
26
|
+
//# sourceMappingURL=chunk-254YHUN3.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":[],"names":[],"mappings":"","file":"chunk-
|
|
1
|
+
{"version":3,"sources":[],"names":[],"mappings":"","file":"chunk-254YHUN3.cjs"}
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { __spreadProps, __spreadValues } from './chunk-2NMEKWO5.js';
|
|
2
1
|
import { useMemo, useState, useRef, useEffect, useCallback } from 'react';
|
|
3
2
|
import { useClient, useWorkspace } from 'sanity';
|
|
4
3
|
import { useIntentLink } from 'sanity/router';
|
|
@@ -6,6 +5,38 @@ import { usePaneRouter } from 'sanity/structure';
|
|
|
6
5
|
import styled, { keyframes, css } from 'styled-components';
|
|
7
6
|
import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
|
|
8
7
|
|
|
8
|
+
// node_modules/seofields-pro/dist/chunk-CKPRJ6MG.js
|
|
9
|
+
var __defProp = Object.defineProperty;
|
|
10
|
+
var __defProps = Object.defineProperties;
|
|
11
|
+
var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
|
|
12
|
+
var __getOwnPropSymbols = Object.getOwnPropertySymbols;
|
|
13
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
14
|
+
var __propIsEnum = Object.prototype.propertyIsEnumerable;
|
|
15
|
+
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
16
|
+
var __spreadValues = (a, b) => {
|
|
17
|
+
for (var prop in b || (b = {}))
|
|
18
|
+
if (__hasOwnProp.call(b, prop))
|
|
19
|
+
__defNormalProp(a, prop, b[prop]);
|
|
20
|
+
if (__getOwnPropSymbols)
|
|
21
|
+
for (var prop of __getOwnPropSymbols(b)) {
|
|
22
|
+
if (__propIsEnum.call(b, prop))
|
|
23
|
+
__defNormalProp(a, prop, b[prop]);
|
|
24
|
+
}
|
|
25
|
+
return a;
|
|
26
|
+
};
|
|
27
|
+
var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
|
|
28
|
+
var __objRest = (source, exclude) => {
|
|
29
|
+
var target = {};
|
|
30
|
+
for (var prop in source)
|
|
31
|
+
if (__hasOwnProp.call(source, prop) && exclude.indexOf(prop) < 0)
|
|
32
|
+
target[prop] = source[prop];
|
|
33
|
+
if (source != null && __getOwnPropSymbols)
|
|
34
|
+
for (var prop of __getOwnPropSymbols(source)) {
|
|
35
|
+
if (exclude.indexOf(prop) < 0 && __propIsEnum.call(source, prop))
|
|
36
|
+
target[prop] = source[prop];
|
|
37
|
+
}
|
|
38
|
+
return target;
|
|
39
|
+
};
|
|
9
40
|
var themeVars = {
|
|
10
41
|
light: {
|
|
11
42
|
"--seo-bg": "#f0f2f5",
|
|
@@ -1590,6 +1621,7 @@ var SeoHealthDashboard = ({
|
|
|
1590
1621
|
const JSONStringifiedTitleField = JSON.stringify(titleField);
|
|
1591
1622
|
const fetchDocuments = useCallback(
|
|
1592
1623
|
async (isManualRefresh = false) => {
|
|
1624
|
+
var _a, _b, _c;
|
|
1593
1625
|
try {
|
|
1594
1626
|
if (isManualRefresh) {
|
|
1595
1627
|
setIsRefreshing(true);
|
|
@@ -1631,7 +1663,29 @@ var SeoHealthDashboard = ({
|
|
|
1631
1663
|
const docsWithHealth = result.map((doc) => __spreadProps(__spreadValues({}, doc), {
|
|
1632
1664
|
health: calculateHealthScore(doc)
|
|
1633
1665
|
}));
|
|
1634
|
-
|
|
1666
|
+
const titleCount = /* @__PURE__ */ new Map();
|
|
1667
|
+
for (const doc of docsWithHealth) {
|
|
1668
|
+
const t = (_b = (_a = doc.seo) == null ? void 0 : _a.title) == null ? void 0 : _b.trim();
|
|
1669
|
+
if (t) titleCount.set(t, ((_c = titleCount.get(t)) != null ? _c : 0) + 1);
|
|
1670
|
+
}
|
|
1671
|
+
const duplicateTitles = /* @__PURE__ */ new Set();
|
|
1672
|
+
titleCount.forEach((count, t) => {
|
|
1673
|
+
if (count > 1) duplicateTitles.add(t);
|
|
1674
|
+
});
|
|
1675
|
+
const finalDocs = docsWithHealth.map((doc) => {
|
|
1676
|
+
var _a2, _b2;
|
|
1677
|
+
const t = (_b2 = (_a2 = doc.seo) == null ? void 0 : _a2.title) == null ? void 0 : _b2.trim();
|
|
1678
|
+
if (!t || !duplicateTitles.has(t)) return doc;
|
|
1679
|
+
const penalizedScore = Math.max(0, doc.health.score - 10);
|
|
1680
|
+
return __spreadProps(__spreadValues({}, doc), {
|
|
1681
|
+
health: __spreadProps(__spreadValues({}, doc.health), {
|
|
1682
|
+
score: penalizedScore,
|
|
1683
|
+
status: getStatusCategory(penalizedScore),
|
|
1684
|
+
issues: ["Duplicate meta title \u2014 used by multiple documents", ...doc.health.issues]
|
|
1685
|
+
})
|
|
1686
|
+
});
|
|
1687
|
+
});
|
|
1688
|
+
setDocuments(finalDocs);
|
|
1635
1689
|
} catch (error) {
|
|
1636
1690
|
console.error("Error fetching documents:", error);
|
|
1637
1691
|
} finally {
|
|
@@ -2156,6 +2210,6 @@ var SeoHealthDashboard = ({
|
|
|
2156
2210
|
};
|
|
2157
2211
|
var SeoHealthDashboard_default = SeoHealthDashboard;
|
|
2158
2212
|
|
|
2159
|
-
export { SeoHealthDashboard_default };
|
|
2160
|
-
//# sourceMappingURL=chunk-
|
|
2161
|
-
//# sourceMappingURL=chunk-
|
|
2213
|
+
export { SeoHealthDashboard_default, __objRest, __spreadProps, __spreadValues };
|
|
2214
|
+
//# sourceMappingURL=chunk-27XSYENH.js.map
|
|
2215
|
+
//# sourceMappingURL=chunk-27XSYENH.js.map
|