sanity-plugin-seofields 1.2.0 → 1.2.2

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 CHANGED
@@ -21,6 +21,7 @@ A comprehensive Sanity Studio v3 plugin to manage SEO fields like meta titles, d
21
21
  - ✅ **Validation**: Built-in character limits and best practices
22
22
  - 🎛️ **Field Visibility**: Hide sitewide fields on specific content types
23
23
  - 📊 **SEO Health Dashboard**: Studio-wide overview of SEO completeness with scores, issue highlights, and direct document links
24
+ - 🗂️ **Desk Structure Pane**: Embed the dashboard inside the Structure tool with `createSeoHealthPane` — supports split-pane document editing
24
25
 
25
26
  ## 📦 Installation
26
27
 
@@ -531,6 +532,65 @@ seofields({
531
532
 
532
533
  > **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
534
 
535
+ ## 🗂️ Desk Structure Pane
536
+
537
+ Embed the SEO Health Dashboard **directly inside the Structure tool** as a pane with split-pane document editing — clicking any row opens the document editor to the right.
538
+
539
+ ### Import
540
+
541
+ ```typescript
542
+ import {createSeoHealthPane} from 'sanity-plugin-seofields'
543
+ ```
544
+
545
+ ### Usage
546
+
547
+ `createSeoHealthPane(S, options)` requires both arguments: Sanity's structure builder `S` and an options object with a required `licenseKey`. It returns a **`ComponentBuilder`** — use it **directly** as the `.child()` value.
548
+
549
+ > ⚠️ **Do NOT wrap in `S.component()`.** The function already calls `S.component()` internally. Wrapping it again causes: _"component is required for component structure item"_.
550
+
551
+ ```typescript
552
+ // sanity.config.ts
553
+ import {defineConfig} from 'sanity'
554
+ import {structureTool} from 'sanity/structure'
555
+ import seofields, {createSeoHealthPane} from 'sanity-plugin-seofields'
556
+
557
+ export default defineConfig({
558
+ plugins: [
559
+ seofields({healthDashboard: false}), // optional: hide the top-level tool tab
560
+ structureTool({
561
+ structure: (S) =>
562
+ S.list()
563
+ .title('Content')
564
+ .items([
565
+ S.documentTypeListItem('post').title('Posts'),
566
+ S.divider(),
567
+ S.listItem()
568
+ .title('SEO Health')
569
+ .child(
570
+ createSeoHealthPane(S, {
571
+ licenseKey: 'SEOF-XXXX-XXXX-XXXX',
572
+ query: `*[_type == "post" && defined(seo)]{
573
+ _id, _type, title, slug, seo, _updatedAt
574
+ }`,
575
+ title: 'Posts SEO Health',
576
+ }),
577
+ ),
578
+ ]),
579
+ }),
580
+ ],
581
+ })
582
+ ```
583
+
584
+ ### `createSeoHealthPane` options
585
+
586
+ | Option | Type | Default | Description |
587
+ | ------------ | --------- | -------------- | --------------------------------------------------------------------- |
588
+ | `licenseKey` | `string` | **required** | License key (format `SEOF-XXXX-XXXX-XXXX`). |
589
+ | `query` | `string` | — | GROQ query. Must return `_id`, `_type`, `title`, `seo`, `_updatedAt`. |
590
+ | `title` | `string` | `'SEO Health'` | Pane title shown in breadcrumb |
591
+ | `openInPane` | `boolean` | `true` | Enable row links that open the document editor as a pane to the right. |
592
+ | `...rest` | — | — | All other `SeoHealthDashboardProps` |
593
+
534
594
  ## 🌐 Frontend Integration
535
595
 
536
596
  ### Next.js Example
package/dist/index.d.mts CHANGED
@@ -1,14 +1,44 @@
1
+ import type {ComponentBuilder} from 'sanity/structure'
1
2
  import {JSX} from 'react'
2
3
  import {ObjectDefinition} from 'sanity'
3
4
  import {Plugin as Plugin_2} from 'sanity'
4
5
  import {PreviewConfig} from 'sanity'
5
6
  import {default as React_2} from 'react'
6
7
  import {SchemaTypeDefinition} from 'sanity'
8
+ import type {StructureBuilder} from 'sanity/structure'
7
9
 
8
10
  export declare type AllFieldKeys = SeoFieldKeys | openGraphFieldKeys | twitterFieldKeys
9
11
 
10
12
  export declare function allSchemas(config?: SeoFieldsPluginConfig): SchemaTypeDefinition[]
11
13
 
14
+ /**
15
+ * Creates a desk-structure pane for the SEO Health Dashboard.
16
+ *
17
+ * Returns a **`ComponentBuilder`** with a built-in `.child()` resolver so that
18
+ * clicking any document row opens the document editor as a split pane to the right.
19
+ *
20
+ * Use it **directly** as the `.child()` value — do **not** wrap it in `S.component()`.
21
+ *
22
+ * ```ts
23
+ * // sanity.config.ts
24
+ * structure: (S) =>
25
+ * S.list().items([
26
+ * S.listItem()
27
+ * .title('SEO Health')
28
+ * .child(
29
+ * createSeoHealthPane(S, {
30
+ * licenseKey: 'SEOF-XXXX-XXXX-XXXX',
31
+ * query: `*[_type == "post" && defined(seo)]{ _id, _type, title, slug, seo, _updatedAt }`,
32
+ * })
33
+ * ),
34
+ * ])
35
+ * ```
36
+ */
37
+ export declare function createSeoHealthPane(
38
+ optionsOrS: StructureBuilder,
39
+ optionsWhenS: SeoHealthPaneOptions,
40
+ ): ComponentBuilder
41
+
12
42
  export declare interface DocumentWithSeoHealth {
13
43
  _id: string
14
44
  _type: string
@@ -308,6 +338,16 @@ export declare interface SeoFieldsPluginConfig {
308
338
  fontSize?: string
309
339
  }
310
340
  | undefined
341
+ /**
342
+ * Enable preview/demo mode to show dummy data.
343
+ * Useful for testing, documentation, or showcasing the dashboard.
344
+ * When enabled, displays realistic sample documents with various SEO scores.
345
+ * Defaults to `false`.
346
+ *
347
+ * @example
348
+ * previewMode: true
349
+ */
350
+ previewMode?: boolean
311
351
  }
312
352
  }
313
353
 
@@ -413,6 +453,25 @@ declare interface SeoHealthDashboardProps {
413
453
  * Defaults to `"No documents found"`.
414
454
  */
415
455
  noDocuments?: React_2.ReactNode
456
+ /**
457
+ * Enable preview/demo mode to show dummy data.
458
+ * Useful for testing, documentation, or showcasing the dashboard.
459
+ * When enabled, displays realistic sample documents with various SEO scores.
460
+ * Defaults to `false`.
461
+ */
462
+ previewMode?: boolean
463
+ /**
464
+ * When `true`, clicking a document title opens the document editor as a split
465
+ * pane to the right, keeping the SEO Health pane visible on the left.
466
+ * This uses Sanity's pane router and requires the component to be rendered
467
+ * inside a desk-structure pane context (i.e. via `createSeoHealthPane`).
468
+ *
469
+ * When `false` (default), clicking navigates to the document via the standard
470
+ * intent-link system (full navigation).
471
+ *
472
+ * This is set to `true` automatically by `createSeoHealthPane`.
473
+ */
474
+ openInPane?: boolean
416
475
  }
417
476
 
418
477
  export declare interface SeoHealthMetrics {
@@ -421,6 +480,27 @@ export declare interface SeoHealthMetrics {
421
480
  issues: string[]
422
481
  }
423
482
 
483
+ /**
484
+ * Options accepted by `createSeoHealthPane`.
485
+ * All props from `SeoHealthDashboardProps` are supported.
486
+ *
487
+ * `licenseKey` is **required** — the dashboard will not render without it.
488
+ */
489
+ export declare interface SeoHealthPaneOptions extends Omit<SeoHealthDashboardProps, 'customQuery'> {
490
+ /** Required license key (format: `SEOF-XXXX-XXXX-XXXX`). */
491
+ licenseKey: string
492
+ /**
493
+ * A fully custom GROQ query used to fetch documents for the dashboard.
494
+ * The query must return documents with at least: `_id`, `_type`, `title`, `seo`, `_updatedAt`.
495
+ *
496
+ * Takes precedence over `queryTypes` when both are provided.
497
+ *
498
+ * @example
499
+ * query: `*[_type in ["post","page"] && defined(seo)]{ _id, _type, title, slug, seo, _updatedAt }`
500
+ */
501
+ query?: string
502
+ }
503
+
424
504
  export declare type SeoHealthStatus = 'excellent' | 'good' | 'fair' | 'poor' | 'missing'
425
505
 
426
506
  /**
package/dist/index.d.ts CHANGED
@@ -1,14 +1,44 @@
1
+ import type {ComponentBuilder} from 'sanity/structure'
1
2
  import {JSX} from 'react'
2
3
  import {ObjectDefinition} from 'sanity'
3
4
  import {Plugin as Plugin_2} from 'sanity'
4
5
  import {PreviewConfig} from 'sanity'
5
6
  import {default as React_2} from 'react'
6
7
  import {SchemaTypeDefinition} from 'sanity'
8
+ import type {StructureBuilder} from 'sanity/structure'
7
9
 
8
10
  export declare type AllFieldKeys = SeoFieldKeys | openGraphFieldKeys | twitterFieldKeys
9
11
 
10
12
  export declare function allSchemas(config?: SeoFieldsPluginConfig): SchemaTypeDefinition[]
11
13
 
14
+ /**
15
+ * Creates a desk-structure pane for the SEO Health Dashboard.
16
+ *
17
+ * Returns a **`ComponentBuilder`** with a built-in `.child()` resolver so that
18
+ * clicking any document row opens the document editor as a split pane to the right.
19
+ *
20
+ * Use it **directly** as the `.child()` value — do **not** wrap it in `S.component()`.
21
+ *
22
+ * ```ts
23
+ * // sanity.config.ts
24
+ * structure: (S) =>
25
+ * S.list().items([
26
+ * S.listItem()
27
+ * .title('SEO Health')
28
+ * .child(
29
+ * createSeoHealthPane(S, {
30
+ * licenseKey: 'SEOF-XXXX-XXXX-XXXX',
31
+ * query: `*[_type == "post" && defined(seo)]{ _id, _type, title, slug, seo, _updatedAt }`,
32
+ * })
33
+ * ),
34
+ * ])
35
+ * ```
36
+ */
37
+ export declare function createSeoHealthPane(
38
+ optionsOrS: StructureBuilder,
39
+ optionsWhenS: SeoHealthPaneOptions,
40
+ ): ComponentBuilder
41
+
12
42
  export declare interface DocumentWithSeoHealth {
13
43
  _id: string
14
44
  _type: string
@@ -308,6 +338,16 @@ export declare interface SeoFieldsPluginConfig {
308
338
  fontSize?: string
309
339
  }
310
340
  | undefined
341
+ /**
342
+ * Enable preview/demo mode to show dummy data.
343
+ * Useful for testing, documentation, or showcasing the dashboard.
344
+ * When enabled, displays realistic sample documents with various SEO scores.
345
+ * Defaults to `false`.
346
+ *
347
+ * @example
348
+ * previewMode: true
349
+ */
350
+ previewMode?: boolean
311
351
  }
312
352
  }
313
353
 
@@ -413,6 +453,25 @@ declare interface SeoHealthDashboardProps {
413
453
  * Defaults to `"No documents found"`.
414
454
  */
415
455
  noDocuments?: React_2.ReactNode
456
+ /**
457
+ * Enable preview/demo mode to show dummy data.
458
+ * Useful for testing, documentation, or showcasing the dashboard.
459
+ * When enabled, displays realistic sample documents with various SEO scores.
460
+ * Defaults to `false`.
461
+ */
462
+ previewMode?: boolean
463
+ /**
464
+ * When `true`, clicking a document title opens the document editor as a split
465
+ * pane to the right, keeping the SEO Health pane visible on the left.
466
+ * This uses Sanity's pane router and requires the component to be rendered
467
+ * inside a desk-structure pane context (i.e. via `createSeoHealthPane`).
468
+ *
469
+ * When `false` (default), clicking navigates to the document via the standard
470
+ * intent-link system (full navigation).
471
+ *
472
+ * This is set to `true` automatically by `createSeoHealthPane`.
473
+ */
474
+ openInPane?: boolean
416
475
  }
417
476
 
418
477
  export declare interface SeoHealthMetrics {
@@ -421,6 +480,27 @@ export declare interface SeoHealthMetrics {
421
480
  issues: string[]
422
481
  }
423
482
 
483
+ /**
484
+ * Options accepted by `createSeoHealthPane`.
485
+ * All props from `SeoHealthDashboardProps` are supported.
486
+ *
487
+ * `licenseKey` is **required** — the dashboard will not render without it.
488
+ */
489
+ export declare interface SeoHealthPaneOptions extends Omit<SeoHealthDashboardProps, 'customQuery'> {
490
+ /** Required license key (format: `SEOF-XXXX-XXXX-XXXX`). */
491
+ licenseKey: string
492
+ /**
493
+ * A fully custom GROQ query used to fetch documents for the dashboard.
494
+ * The query must return documents with at least: `_id`, `_type`, `title`, `seo`, `_updatedAt`.
495
+ *
496
+ * Takes precedence over `queryTypes` when both are provided.
497
+ *
498
+ * @example
499
+ * query: `*[_type in ["post","page"] && defined(seo)]{ _id, _type, title, slug, seo, _updatedAt }`
500
+ */
501
+ query?: string
502
+ }
503
+
424
504
  export declare type SeoHealthStatus = 'excellent' | 'good' | 'fair' | 'poor' | 'missing'
425
505
 
426
506
  /**