sanity-plugin-seofields 1.0.10 β 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +90 -0
- package/dist/index.d.mts +323 -0
- package/dist/index.d.ts +323 -0
- package/dist/index.js +2086 -68
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +2080 -64
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
- package/src/components/SeoHealthDashboard.tsx +1245 -0
- package/src/components/SeoHealthTool.tsx +11 -0
- package/src/components/SeoPreview.tsx +132 -58
- package/src/index.ts +7 -0
- package/src/plugin.ts +216 -1
- package/src/types.ts +19 -0
- package/src/utils/seoUtils.ts +1 -1
package/README.md
CHANGED
|
@@ -20,6 +20,7 @@ A comprehensive Sanity Studio v3 plugin to manage SEO fields like meta titles, d
|
|
|
20
20
|
- π **Custom Attributes**: Flexible meta attribute system
|
|
21
21
|
- β
**Validation**: Built-in character limits and best practices
|
|
22
22
|
- ποΈ **Field Visibility**: Hide sitewide fields on specific content types
|
|
23
|
+
- π **SEO Health Dashboard**: Studio-wide overview of SEO completeness with scores, issue highlights, and direct document links
|
|
23
24
|
|
|
24
25
|
## π¦ Installation
|
|
25
26
|
|
|
@@ -441,6 +442,95 @@ defineField({
|
|
|
441
442
|
})
|
|
442
443
|
```
|
|
443
444
|
|
|
445
|
+
## π SEO Health Dashboard
|
|
446
|
+
|
|
447
|
+
The plugin includes a built-in **SEO Health Dashboard** tool accessible directly from Sanity Studio. It scans all documents that contain an `seo` field and gives you an at-a-glance picture of your site's SEO completeness.
|
|
448
|
+
|
|
449
|
+
### π License Key Required
|
|
450
|
+
|
|
451
|
+
The SEO Health Dashboard requires a valid license key to use. **Good news**: it's completely free during the current period (2β3 months). When we transition to a paid model, your existing key will remain valid for a one-time $10 fee.
|
|
452
|
+
|
|
453
|
+
[Get your free license key β](https://sanity-plugin-seofields.thehardik.in/get-license)
|
|
454
|
+
|
|
455
|
+
### Configuration
|
|
456
|
+
|
|
457
|
+
```typescript
|
|
458
|
+
// Minimal β just add your license key
|
|
459
|
+
seofields({
|
|
460
|
+
healthDashboard: {
|
|
461
|
+
licenseKey: 'YOUR_LICENSE_KEY',
|
|
462
|
+
},
|
|
463
|
+
})
|
|
464
|
+
|
|
465
|
+
// Full options β all nested under healthDashboard
|
|
466
|
+
seofields({
|
|
467
|
+
healthDashboard: {
|
|
468
|
+
// Required
|
|
469
|
+
licenseKey: 'YOUR_LICENSE_KEY',
|
|
470
|
+
|
|
471
|
+
// Studio nav tab
|
|
472
|
+
tool: {
|
|
473
|
+
title: 'SEO Audit', // tab label in Studio sidebar (default: 'SEO Health')
|
|
474
|
+
name: 'seo-health-dashboard', // internal tool slug
|
|
475
|
+
},
|
|
476
|
+
|
|
477
|
+
// Dashboard page content
|
|
478
|
+
content: {
|
|
479
|
+
icon: 'π', // emoji before the page heading
|
|
480
|
+
title: 'SEO Audit', // page heading (default: tool.title)
|
|
481
|
+
description: 'Track SEO quality across all published content.',
|
|
482
|
+
},
|
|
483
|
+
|
|
484
|
+
// Table columns
|
|
485
|
+
display: {
|
|
486
|
+
typeColumn: true, // show document type column (default: true)
|
|
487
|
+
documentId: false, // show document _id (default: true)
|
|
488
|
+
},
|
|
489
|
+
|
|
490
|
+
// Document query
|
|
491
|
+
query: {
|
|
492
|
+
types: ['post', 'page'], // limit to specific document types
|
|
493
|
+
requireSeo: true, // only include docs with seo != null (default: true)
|
|
494
|
+
// groq: '*[seo != null] { _id, _type, title, seo, _updatedAt }',
|
|
495
|
+
// ^ custom GROQ takes precedence over types + requireSeo
|
|
496
|
+
},
|
|
497
|
+
|
|
498
|
+
apiVersion: '2023-01-01', // Sanity API version (default: '2023-01-01')
|
|
499
|
+
},
|
|
500
|
+
})
|
|
501
|
+
|
|
502
|
+
// Or disable the dashboard entirely
|
|
503
|
+
seofields({
|
|
504
|
+
healthDashboard: false,
|
|
505
|
+
})
|
|
506
|
+
```
|
|
507
|
+
|
|
508
|
+
### What it shows
|
|
509
|
+
|
|
510
|
+
| Feature | Details |
|
|
511
|
+
| ------------------------ | -------------------------------------------------------------------------------- |
|
|
512
|
+
| **Summary stats** | Total documents, average score, and count per health tier |
|
|
513
|
+
| **Per-document score** | 0β95 score based on which SEO fields are filled in |
|
|
514
|
+
| **Color-coded badges** | π’ Excellent (β₯ 80) Β· π‘ Good (β₯ 60) Β· π Fair (β₯ 40) Β· π΄ Poor / Missing (< 40) |
|
|
515
|
+
| **Inline issues** | Top 2 issues per document shown inline; overflow count displayed |
|
|
516
|
+
| **Direct document link** | Click the document title to open it in the desk (new tab) |
|
|
517
|
+
| **Search & filter** | Filter by health status, sort by score or title, and full-text search |
|
|
518
|
+
|
|
519
|
+
### Scoring breakdown
|
|
520
|
+
|
|
521
|
+
| Field | Max Points |
|
|
522
|
+
| ------------------- | ---------- |
|
|
523
|
+
| Meta Title | 25 |
|
|
524
|
+
| Meta Description | 20 |
|
|
525
|
+
| OG Title | 15 |
|
|
526
|
+
| OG Description | 10 |
|
|
527
|
+
| Twitter Title | 10 |
|
|
528
|
+
| Twitter Description | 10 |
|
|
529
|
+
| Robots / No-Index | 5 |
|
|
530
|
+
| **Total** | **95** |
|
|
531
|
+
|
|
532
|
+
> **Scoring logic:** each field earns its full points when a non-empty value is present, zero when missing. `query.groq` lets you control exactly which documents are included in the audit.
|
|
533
|
+
|
|
444
534
|
## π Frontend Integration
|
|
445
535
|
|
|
446
536
|
### Next.js Example
|
package/dist/index.d.mts
CHANGED
|
@@ -1,12 +1,26 @@
|
|
|
1
|
+
import {JSX} from 'react'
|
|
1
2
|
import {ObjectDefinition} from 'sanity'
|
|
2
3
|
import {Plugin as Plugin_2} from 'sanity'
|
|
3
4
|
import {PreviewConfig} from 'sanity'
|
|
5
|
+
import {default as React_2} from 'react'
|
|
4
6
|
import {SchemaTypeDefinition} from 'sanity'
|
|
5
7
|
|
|
6
8
|
export declare type AllFieldKeys = SeoFieldKeys | openGraphFieldKeys | twitterFieldKeys
|
|
7
9
|
|
|
8
10
|
export declare function allSchemas(config?: SeoFieldsPluginConfig): SchemaTypeDefinition[]
|
|
9
11
|
|
|
12
|
+
export declare interface DocumentWithSeoHealth {
|
|
13
|
+
_id: string
|
|
14
|
+
_type: string
|
|
15
|
+
title?: string
|
|
16
|
+
slug?: {
|
|
17
|
+
current: string
|
|
18
|
+
}
|
|
19
|
+
seo?: SeoFields
|
|
20
|
+
_updatedAt?: string
|
|
21
|
+
health: SeoHealthMetrics
|
|
22
|
+
}
|
|
23
|
+
|
|
10
24
|
export declare interface FieldVisibilityConfig {
|
|
11
25
|
hiddenFields?: ValidHiddenFieldKeys[]
|
|
12
26
|
}
|
|
@@ -46,6 +60,17 @@ export declare type openGraphFieldKeys =
|
|
|
46
60
|
|
|
47
61
|
export declare function openGraphSchema(config?: SeoFieldsPluginConfig): SchemaTypeDefinition
|
|
48
62
|
|
|
63
|
+
declare interface OpenGraphSettings {
|
|
64
|
+
_type: 'openGraph'
|
|
65
|
+
title?: string
|
|
66
|
+
description?: string
|
|
67
|
+
siteName?: string
|
|
68
|
+
type?: 'website' | 'article' | 'profile' | 'book' | 'music' | 'video' | 'product'
|
|
69
|
+
imageType?: 'upload' | 'url'
|
|
70
|
+
image?: SanityImageWithAlt
|
|
71
|
+
imageUrl?: string
|
|
72
|
+
}
|
|
73
|
+
|
|
49
74
|
export declare const robotsSchema: {
|
|
50
75
|
type: 'object'
|
|
51
76
|
name: 'robots'
|
|
@@ -53,6 +78,36 @@ export declare const robotsSchema: {
|
|
|
53
78
|
preview?: PreviewConfig<Record<string, string>, Record<never, any>> | undefined
|
|
54
79
|
}
|
|
55
80
|
|
|
81
|
+
declare interface RobotsSettings {
|
|
82
|
+
noIndex?: boolean
|
|
83
|
+
noFollow?: boolean
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
declare interface SanityImage {
|
|
87
|
+
_type: 'image'
|
|
88
|
+
asset: {
|
|
89
|
+
_ref: string
|
|
90
|
+
_type: 'reference'
|
|
91
|
+
}
|
|
92
|
+
hotspot?: {
|
|
93
|
+
x: number
|
|
94
|
+
y: number
|
|
95
|
+
height: number
|
|
96
|
+
width: number
|
|
97
|
+
}
|
|
98
|
+
crop?: {
|
|
99
|
+
top: number
|
|
100
|
+
bottom: number
|
|
101
|
+
left: number
|
|
102
|
+
right: number
|
|
103
|
+
}
|
|
104
|
+
alt?: string
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
declare interface SanityImageWithAlt extends SanityImage {
|
|
108
|
+
alt: string
|
|
109
|
+
}
|
|
110
|
+
|
|
56
111
|
export declare interface SeoFieldConfig {
|
|
57
112
|
title?: string
|
|
58
113
|
description?: string
|
|
@@ -67,6 +122,19 @@ export declare type SeoFieldKeys =
|
|
|
67
122
|
| 'metaAttributes'
|
|
68
123
|
| 'robots'
|
|
69
124
|
|
|
125
|
+
declare interface SeoFields {
|
|
126
|
+
_type: 'seoFields'
|
|
127
|
+
robots?: RobotsSettings
|
|
128
|
+
preview?: string
|
|
129
|
+
title?: string
|
|
130
|
+
description?: string
|
|
131
|
+
metaImage?: SanityImage
|
|
132
|
+
keywords?: string[]
|
|
133
|
+
canonicalUrl?: string
|
|
134
|
+
openGraph?: OpenGraphSettings
|
|
135
|
+
twitter?: TwitterCardSettings
|
|
136
|
+
}
|
|
137
|
+
|
|
70
138
|
declare const seofields: Plugin_2<void | SeoFieldsPluginConfig>
|
|
71
139
|
export default seofields
|
|
72
140
|
|
|
@@ -113,10 +181,265 @@ export declare interface SeoFieldsPluginConfig {
|
|
|
113
181
|
* Defaults to 'https://www.example.com' if not provided.
|
|
114
182
|
*/
|
|
115
183
|
baseUrl?: string
|
|
184
|
+
/**
|
|
185
|
+
* Enable or configure the SEO Health Dashboard tool.
|
|
186
|
+
* If set to `true`, the dashboard is enabled with all defaults.
|
|
187
|
+
* If set to an object, you can customise the tool and dashboard settings.
|
|
188
|
+
* Defaults to `true`.
|
|
189
|
+
* Example:
|
|
190
|
+
* ```
|
|
191
|
+
* healthDashboard: {
|
|
192
|
+
* toolTitle: 'SEO Overview', // Studio nav tab label
|
|
193
|
+
* content: {
|
|
194
|
+
* icon: 'π', // Emoji icon shown before the page heading
|
|
195
|
+
* title: 'My SEO Dashboard',// Page heading inside the tool (no emoji)
|
|
196
|
+
* description: 'Track SEO across all documents', // Subtitle under the heading
|
|
197
|
+
* },
|
|
198
|
+
* display: {
|
|
199
|
+
* typeColumn: false, // Hide the document type column (default: true)
|
|
200
|
+
* documentId: false, // Hide the document ID under titles (default: true)
|
|
201
|
+
* },
|
|
202
|
+
* query: {
|
|
203
|
+
* // Option 1 β filter by specific document types
|
|
204
|
+
* types: ['post', 'page'],
|
|
205
|
+
* // Option 2 β provide a full custom GROQ query (takes precedence over `types`)
|
|
206
|
+
* // Must return documents with at least: _id, _type, title, seo, _updatedAt
|
|
207
|
+
* groq: `*[seo != null && defined(slug.current)]{ _id, _type, title, slug, seo, _updatedAt }`,
|
|
208
|
+
* },
|
|
209
|
+
* }
|
|
210
|
+
* ```
|
|
211
|
+
*/
|
|
212
|
+
healthDashboard?:
|
|
213
|
+
| boolean
|
|
214
|
+
| {
|
|
215
|
+
tool?: {
|
|
216
|
+
title?: string
|
|
217
|
+
name?: string
|
|
218
|
+
}
|
|
219
|
+
toolTitle?: string
|
|
220
|
+
content?: {
|
|
221
|
+
icon?: string
|
|
222
|
+
title?: string
|
|
223
|
+
description?: string
|
|
224
|
+
/** Text shown while the license key is being verified. Defaults to "Verifying licenseβ¦" */
|
|
225
|
+
loadingLicense?: string
|
|
226
|
+
/** Text shown while documents are being fetched. Defaults to "Loading documentsβ¦" */
|
|
227
|
+
loadingDocuments?: string
|
|
228
|
+
/** Text shown when the query returns zero results. Defaults to "No documents found" */
|
|
229
|
+
noDocuments?: string
|
|
230
|
+
}
|
|
231
|
+
display?: {
|
|
232
|
+
typeColumn?: boolean
|
|
233
|
+
documentId?: boolean
|
|
234
|
+
}
|
|
235
|
+
query?: {
|
|
236
|
+
/**
|
|
237
|
+
* Limit the dashboard to specific document types.
|
|
238
|
+
* Example: `['post', 'page']`
|
|
239
|
+
*/
|
|
240
|
+
types?: string[]
|
|
241
|
+
/**
|
|
242
|
+
* When using `types`, also require the `seo` field to be non-null.
|
|
243
|
+
* Set to `false` to include documents of those types even if `seo` is missing.
|
|
244
|
+
* Defaults to `true`.
|
|
245
|
+
*/
|
|
246
|
+
requireSeo?: boolean
|
|
247
|
+
/**
|
|
248
|
+
* Provide a fully custom GROQ query. Takes precedence over `types`.
|
|
249
|
+
* The query must return documents with at least: _id, _type, title, seo, _updatedAt
|
|
250
|
+
*/
|
|
251
|
+
groq?: string
|
|
252
|
+
}
|
|
253
|
+
/**
|
|
254
|
+
* The Sanity API version to use for the client (e.g. '2023-01-01').
|
|
255
|
+
* Defaults to '2023-01-01'.
|
|
256
|
+
*/
|
|
257
|
+
apiVersion?: string
|
|
258
|
+
/**
|
|
259
|
+
* License key for the SEO Health Dashboard pro feature.
|
|
260
|
+
* Obtain a license at https://sanity-plugin-seofields.thehardik.in
|
|
261
|
+
*/
|
|
262
|
+
licenseKey?: string
|
|
263
|
+
/**
|
|
264
|
+
* Map raw `_type` values to human-readable display labels.
|
|
265
|
+
* Used in both the Type column and the Type filter dropdown.
|
|
266
|
+
* Any type without an entry falls back to the raw `_type` string.
|
|
267
|
+
*
|
|
268
|
+
* @example
|
|
269
|
+
* typeLabels: { productDrug: 'Products', singleCondition: 'Condition' }
|
|
270
|
+
*/
|
|
271
|
+
typeLabels?: Record<string, string>
|
|
272
|
+
/**
|
|
273
|
+
* Controls how the document type is rendered in the Type column.
|
|
274
|
+
* - `'badge'` (default) β coloured pill
|
|
275
|
+
* - `'text'` β plain text, useful for dense layouts
|
|
276
|
+
*/
|
|
277
|
+
typeColumnMode?: 'badge' | 'text'
|
|
278
|
+
/**
|
|
279
|
+
* The document field to use as the display title in the dashboard.
|
|
280
|
+
*
|
|
281
|
+
* - `string` β use this field for every document type (e.g. `'name'`)
|
|
282
|
+
* - `Record<string, string>` β per-type mapping; unmapped types fall back to `title`
|
|
283
|
+
*
|
|
284
|
+
* @example
|
|
285
|
+
* titleField: 'name'
|
|
286
|
+
*
|
|
287
|
+
* @example
|
|
288
|
+
* titleField: { post: 'title', product: 'name', category: 'label' }
|
|
289
|
+
*/
|
|
290
|
+
titleField?: string | Record<string, string>
|
|
291
|
+
/**
|
|
292
|
+
* Callback function to render a custom badge next to the document title.
|
|
293
|
+
* Receives the full document and should return badge data or undefined.
|
|
294
|
+
*
|
|
295
|
+
* @example
|
|
296
|
+
* docBadge: (doc) => {
|
|
297
|
+
* if (doc.services === 'NHS')
|
|
298
|
+
* return { label: 'NHS', bgColor: '#e0f2fe', textColor: '#0369a1' }
|
|
299
|
+
* if (doc.services === 'Private')
|
|
300
|
+
* return { label: 'Private', bgColor: '#fef3c7', textColor: '#92400e' }
|
|
301
|
+
* }
|
|
302
|
+
*/
|
|
303
|
+
docBadge?: (doc: DocumentWithSeoHealth & Record<string, unknown>) =>
|
|
304
|
+
| {
|
|
305
|
+
label: string
|
|
306
|
+
bgColor?: string
|
|
307
|
+
textColor?: string
|
|
308
|
+
fontSize?: string
|
|
309
|
+
}
|
|
310
|
+
| undefined
|
|
311
|
+
}
|
|
116
312
|
}
|
|
117
313
|
|
|
118
314
|
export declare function seoFieldsSchema(config?: SeoFieldsPluginConfig): SchemaTypeDefinition
|
|
119
315
|
|
|
316
|
+
export declare const SeoHealthDashboard: React_2.FC<SeoHealthDashboardProps>
|
|
317
|
+
|
|
318
|
+
declare interface SeoHealthDashboardProps {
|
|
319
|
+
icon?: string
|
|
320
|
+
title?: string
|
|
321
|
+
description?: string
|
|
322
|
+
showTypeColumn?: boolean
|
|
323
|
+
showDocumentId?: boolean
|
|
324
|
+
/**
|
|
325
|
+
* Limit the dashboard to specific document type names.
|
|
326
|
+
* If both queryTypes and customQuery are provided, customQuery takes precedence.
|
|
327
|
+
*/
|
|
328
|
+
queryTypes?: string[]
|
|
329
|
+
/**
|
|
330
|
+
* When using `queryTypes`, also filter by `seo != null`.
|
|
331
|
+
* Set to `false` to include documents of those types even without an seo field.
|
|
332
|
+
* Defaults to `true`.
|
|
333
|
+
*/
|
|
334
|
+
queryRequireSeo?: boolean
|
|
335
|
+
/**
|
|
336
|
+
* A fully custom GROQ query used to fetch documents.
|
|
337
|
+
* Must return objects with at least: _id, _type, title, seo, _updatedAt
|
|
338
|
+
* Takes precedence over queryTypes.
|
|
339
|
+
*/
|
|
340
|
+
customQuery?: string
|
|
341
|
+
/**
|
|
342
|
+
* The Sanity API version to use for the client (e.g. '2023-01-01').
|
|
343
|
+
* Defaults to '2023-01-01'.
|
|
344
|
+
*/
|
|
345
|
+
apiVersion?: string
|
|
346
|
+
/**
|
|
347
|
+
* License key for the SEO Health Dashboard.
|
|
348
|
+
* Obtain a key at https://sanity-plugin-seofields.thehardik.in
|
|
349
|
+
*/
|
|
350
|
+
licenseKey?: string
|
|
351
|
+
/**
|
|
352
|
+
* Map raw `_type` values to human-readable display labels used in the
|
|
353
|
+
* Type column and the Type filter dropdown.
|
|
354
|
+
* Any type without an entry falls back to the raw `_type` string.
|
|
355
|
+
*
|
|
356
|
+
* @example
|
|
357
|
+
* typeLabels={{ productDrug: 'Products', singleCondition: 'Condition' }}
|
|
358
|
+
*/
|
|
359
|
+
typeLabels?: Record<string, string>
|
|
360
|
+
/**
|
|
361
|
+
* Controls how the type is rendered in the Type column.
|
|
362
|
+
* - `'badge'` (default) β coloured pill, consistent with score badges
|
|
363
|
+
* - `'text'` β plain text, useful for dense layouts
|
|
364
|
+
*/
|
|
365
|
+
typeColumnMode?: 'badge' | 'text'
|
|
366
|
+
/**
|
|
367
|
+
* The document field to use as the display title.
|
|
368
|
+
*
|
|
369
|
+
* - `string` β use this field for every document type (e.g. `'name'`)
|
|
370
|
+
* - `Record<string, string>` β per-type mapping; unmapped types fall back to `title`
|
|
371
|
+
*
|
|
372
|
+
* @example
|
|
373
|
+
* // Same field for all types
|
|
374
|
+
* titleField: 'name'
|
|
375
|
+
*
|
|
376
|
+
* @example
|
|
377
|
+
* // Different field per type
|
|
378
|
+
* titleField: { post: 'title', product: 'name', category: 'label' }
|
|
379
|
+
*/
|
|
380
|
+
titleField?: string | Record<string, string>
|
|
381
|
+
/**
|
|
382
|
+
* Callback function to render a custom badge next to the document title.
|
|
383
|
+
* Receives the full document and should return badge data or undefined.
|
|
384
|
+
*
|
|
385
|
+
* @example
|
|
386
|
+
* docBadge: (doc) => {
|
|
387
|
+
* if (doc.services === 'NHS')
|
|
388
|
+
* return { label: 'NHS', bgColor: '#e0f2fe', textColor: '#0369a1' }
|
|
389
|
+
* if (doc.services === 'Private')
|
|
390
|
+
* return { label: 'Private', bgColor: '#fef3c7', textColor: '#92400e' }
|
|
391
|
+
* }
|
|
392
|
+
*/
|
|
393
|
+
docBadge?: (doc: DocumentWithSeoHealth & Record<string, unknown>) =>
|
|
394
|
+
| {
|
|
395
|
+
label: string
|
|
396
|
+
bgColor?: string
|
|
397
|
+
textColor?: string
|
|
398
|
+
fontSize?: string
|
|
399
|
+
}
|
|
400
|
+
| undefined
|
|
401
|
+
/**
|
|
402
|
+
* Custom text shown while the license key is being verified.
|
|
403
|
+
* Defaults to `"Verifying licenseβ¦"`.
|
|
404
|
+
*/
|
|
405
|
+
loadingLicense?: React_2.ReactNode
|
|
406
|
+
/**
|
|
407
|
+
* Custom text shown while documents are being fetched.
|
|
408
|
+
* Defaults to `"Loading documentsβ¦"`.
|
|
409
|
+
*/
|
|
410
|
+
loadingDocuments?: React_2.ReactNode
|
|
411
|
+
/**
|
|
412
|
+
* Custom text shown when the query returns zero results.
|
|
413
|
+
* Defaults to `"No documents found"`.
|
|
414
|
+
*/
|
|
415
|
+
noDocuments?: React_2.ReactNode
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
export declare interface SeoHealthMetrics {
|
|
419
|
+
score: number
|
|
420
|
+
status: SeoHealthStatus
|
|
421
|
+
issues: string[]
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
export declare type SeoHealthStatus = 'excellent' | 'good' | 'fair' | 'poor' | 'missing'
|
|
425
|
+
|
|
426
|
+
/**
|
|
427
|
+
* Sanity Tool component for the SEO Health Dashboard
|
|
428
|
+
* This component wraps the SeoHealthDashboard for use as a custom tool in Sanity Studio
|
|
429
|
+
*/
|
|
430
|
+
export declare const SeoHealthTool: (props: SeoHealthDashboardProps) => JSX.Element
|
|
431
|
+
|
|
432
|
+
declare interface TwitterCardSettings {
|
|
433
|
+
_type: 'twitter'
|
|
434
|
+
card?: 'summary' | 'summary_large_image' | 'app' | 'player'
|
|
435
|
+
site?: string
|
|
436
|
+
title?: string
|
|
437
|
+
description?: string
|
|
438
|
+
imageType?: 'upload' | 'url'
|
|
439
|
+
image?: SanityImageWithAlt
|
|
440
|
+
imageUrl?: string
|
|
441
|
+
}
|
|
442
|
+
|
|
120
443
|
export declare type twitterFieldKeys =
|
|
121
444
|
| 'twitterCard'
|
|
122
445
|
| 'twitterSite'
|