sanity-plugin-seofields 1.2.1 → 1.2.3
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 +60 -0
- package/dist/index.d.mts +86 -0
- package/dist/index.d.ts +86 -0
- package/dist/index.js +51 -17
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +52 -17
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
- package/src/components/SeoHealthDashboard.tsx +104 -19
- package/src/components/SeoHealthPane.tsx +81 -0
- package/src/index.ts +2 -0
- package/src/plugin.ts +13 -0
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
|
+
* The `name` of the Sanity structure tool that contains the monitored documents.
|
|
343
|
+
* Required when you have multiple structure tools and the documents live in a
|
|
344
|
+
* non-default one. Clicking a title will navigate to
|
|
345
|
+
* `/{basePath}/{structureTool}/intent/edit/…` directly.
|
|
346
|
+
*
|
|
347
|
+
* @example
|
|
348
|
+
* structureTool: 'common'
|
|
349
|
+
*/
|
|
350
|
+
structureTool?: string
|
|
311
351
|
/**
|
|
312
352
|
* Enable preview/demo mode to show dummy data.
|
|
313
353
|
* Useful for testing, documentation, or showcasing the dashboard.
|
|
@@ -430,6 +470,31 @@ declare interface SeoHealthDashboardProps {
|
|
|
430
470
|
* Defaults to `false`.
|
|
431
471
|
*/
|
|
432
472
|
previewMode?: boolean
|
|
473
|
+
/**
|
|
474
|
+
* When `true`, clicking a document title opens the document editor as a split
|
|
475
|
+
* pane to the right, keeping the SEO Health pane visible on the left.
|
|
476
|
+
* This uses Sanity's pane router and requires the component to be rendered
|
|
477
|
+
* inside a desk-structure pane context (i.e. via `createSeoHealthPane`).
|
|
478
|
+
*
|
|
479
|
+
* When `false` (default), clicking navigates to the document via the standard
|
|
480
|
+
* intent-link system (full navigation).
|
|
481
|
+
*
|
|
482
|
+
* This is set to `true` automatically by `createSeoHealthPane`.
|
|
483
|
+
*/
|
|
484
|
+
openInPane?: boolean
|
|
485
|
+
/**
|
|
486
|
+
* The `name` of the Sanity structure tool that contains the monitored documents.
|
|
487
|
+
* When provided, clicking a document title navigates directly to that tool's
|
|
488
|
+
* intent URL (`/{basePath}/{structureTool}/intent/edit/id=…;type=…/`) instead of
|
|
489
|
+
* using the generic intent resolver, which always picks the first registered tool.
|
|
490
|
+
*
|
|
491
|
+
* Required when you have multiple structure tools and the documents live in a
|
|
492
|
+
* non-default one (e.g. `name: 'common'`).
|
|
493
|
+
*
|
|
494
|
+
* @example
|
|
495
|
+
* structureTool: 'common'
|
|
496
|
+
*/
|
|
497
|
+
structureTool?: string
|
|
433
498
|
}
|
|
434
499
|
|
|
435
500
|
export declare interface SeoHealthMetrics {
|
|
@@ -438,6 +503,27 @@ export declare interface SeoHealthMetrics {
|
|
|
438
503
|
issues: string[]
|
|
439
504
|
}
|
|
440
505
|
|
|
506
|
+
/**
|
|
507
|
+
* Options accepted by `createSeoHealthPane`.
|
|
508
|
+
* All props from `SeoHealthDashboardProps` are supported.
|
|
509
|
+
*
|
|
510
|
+
* `licenseKey` is **required** — the dashboard will not render without it.
|
|
511
|
+
*/
|
|
512
|
+
export declare interface SeoHealthPaneOptions extends Omit<SeoHealthDashboardProps, 'customQuery'> {
|
|
513
|
+
/** Required license key (format: `SEOF-XXXX-XXXX-XXXX`). */
|
|
514
|
+
licenseKey: string
|
|
515
|
+
/**
|
|
516
|
+
* A fully custom GROQ query used to fetch documents for the dashboard.
|
|
517
|
+
* The query must return documents with at least: `_id`, `_type`, `title`, `seo`, `_updatedAt`.
|
|
518
|
+
*
|
|
519
|
+
* Takes precedence over `queryTypes` when both are provided.
|
|
520
|
+
*
|
|
521
|
+
* @example
|
|
522
|
+
* query: `*[_type in ["post","page"] && defined(seo)]{ _id, _type, title, slug, seo, _updatedAt }`
|
|
523
|
+
*/
|
|
524
|
+
query?: string
|
|
525
|
+
}
|
|
526
|
+
|
|
441
527
|
export declare type SeoHealthStatus = 'excellent' | 'good' | 'fair' | 'poor' | 'missing'
|
|
442
528
|
|
|
443
529
|
/**
|
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
|
+
* The `name` of the Sanity structure tool that contains the monitored documents.
|
|
343
|
+
* Required when you have multiple structure tools and the documents live in a
|
|
344
|
+
* non-default one. Clicking a title will navigate to
|
|
345
|
+
* `/{basePath}/{structureTool}/intent/edit/…` directly.
|
|
346
|
+
*
|
|
347
|
+
* @example
|
|
348
|
+
* structureTool: 'common'
|
|
349
|
+
*/
|
|
350
|
+
structureTool?: string
|
|
311
351
|
/**
|
|
312
352
|
* Enable preview/demo mode to show dummy data.
|
|
313
353
|
* Useful for testing, documentation, or showcasing the dashboard.
|
|
@@ -430,6 +470,31 @@ declare interface SeoHealthDashboardProps {
|
|
|
430
470
|
* Defaults to `false`.
|
|
431
471
|
*/
|
|
432
472
|
previewMode?: boolean
|
|
473
|
+
/**
|
|
474
|
+
* When `true`, clicking a document title opens the document editor as a split
|
|
475
|
+
* pane to the right, keeping the SEO Health pane visible on the left.
|
|
476
|
+
* This uses Sanity's pane router and requires the component to be rendered
|
|
477
|
+
* inside a desk-structure pane context (i.e. via `createSeoHealthPane`).
|
|
478
|
+
*
|
|
479
|
+
* When `false` (default), clicking navigates to the document via the standard
|
|
480
|
+
* intent-link system (full navigation).
|
|
481
|
+
*
|
|
482
|
+
* This is set to `true` automatically by `createSeoHealthPane`.
|
|
483
|
+
*/
|
|
484
|
+
openInPane?: boolean
|
|
485
|
+
/**
|
|
486
|
+
* The `name` of the Sanity structure tool that contains the monitored documents.
|
|
487
|
+
* When provided, clicking a document title navigates directly to that tool's
|
|
488
|
+
* intent URL (`/{basePath}/{structureTool}/intent/edit/id=…;type=…/`) instead of
|
|
489
|
+
* using the generic intent resolver, which always picks the first registered tool.
|
|
490
|
+
*
|
|
491
|
+
* Required when you have multiple structure tools and the documents live in a
|
|
492
|
+
* non-default one (e.g. `name: 'common'`).
|
|
493
|
+
*
|
|
494
|
+
* @example
|
|
495
|
+
* structureTool: 'common'
|
|
496
|
+
*/
|
|
497
|
+
structureTool?: string
|
|
433
498
|
}
|
|
434
499
|
|
|
435
500
|
export declare interface SeoHealthMetrics {
|
|
@@ -438,6 +503,27 @@ export declare interface SeoHealthMetrics {
|
|
|
438
503
|
issues: string[]
|
|
439
504
|
}
|
|
440
505
|
|
|
506
|
+
/**
|
|
507
|
+
* Options accepted by `createSeoHealthPane`.
|
|
508
|
+
* All props from `SeoHealthDashboardProps` are supported.
|
|
509
|
+
*
|
|
510
|
+
* `licenseKey` is **required** — the dashboard will not render without it.
|
|
511
|
+
*/
|
|
512
|
+
export declare interface SeoHealthPaneOptions extends Omit<SeoHealthDashboardProps, 'customQuery'> {
|
|
513
|
+
/** Required license key (format: `SEOF-XXXX-XXXX-XXXX`). */
|
|
514
|
+
licenseKey: string
|
|
515
|
+
/**
|
|
516
|
+
* A fully custom GROQ query used to fetch documents for the dashboard.
|
|
517
|
+
* The query must return documents with at least: `_id`, `_type`, `title`, `seo`, `_updatedAt`.
|
|
518
|
+
*
|
|
519
|
+
* Takes precedence over `queryTypes` when both are provided.
|
|
520
|
+
*
|
|
521
|
+
* @example
|
|
522
|
+
* query: `*[_type in ["post","page"] && defined(seo)]{ _id, _type, title, slug, seo, _updatedAt }`
|
|
523
|
+
*/
|
|
524
|
+
query?: string
|
|
525
|
+
}
|
|
526
|
+
|
|
441
527
|
export declare type SeoHealthStatus = 'excellent' | 'good' | 'fair' | 'poor' | 'missing'
|
|
442
528
|
|
|
443
529
|
/**
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: !0 });
|
|
3
|
-
var o = require("react"), sanity = require("sanity"), jsxRuntime = require("react/jsx-runtime"), router = require("sanity/router"), ui = require("@sanity/ui");
|
|
3
|
+
var o = require("react"), sanity = require("sanity"), jsxRuntime = require("react/jsx-runtime"), router = require("sanity/router"), structure = require("sanity/structure"), ui = require("@sanity/ui");
|
|
4
4
|
function _interopDefaultCompat(e) {
|
|
5
5
|
return e && typeof e == "object" && "default" in e ? e : { default: e };
|
|
6
6
|
}
|
|
@@ -1192,16 +1192,9 @@ const DashboardContainer = dt.div`
|
|
|
1192
1192
|
color: #6b7280;
|
|
1193
1193
|
`, StatsGrid = dt.div`
|
|
1194
1194
|
display: grid;
|
|
1195
|
-
grid-template-columns: repeat(
|
|
1195
|
+
grid-template-columns: repeat(auto-fit, minmax(130px, 1fr));
|
|
1196
1196
|
gap: 14px;
|
|
1197
1197
|
margin-bottom: 20px;
|
|
1198
|
-
|
|
1199
|
-
@media (max-width: 1100px) {
|
|
1200
|
-
grid-template-columns: repeat(3, 1fr);
|
|
1201
|
-
}
|
|
1202
|
-
@media (max-width: 600px) {
|
|
1203
|
-
grid-template-columns: repeat(2, 1fr);
|
|
1204
|
-
}
|
|
1205
1198
|
`, StatCard = dt.div`
|
|
1206
1199
|
background: #ffffff;
|
|
1207
1200
|
border-radius: 10px;
|
|
@@ -1334,6 +1327,11 @@ const DashboardContainer = dt.div`
|
|
|
1334
1327
|
align-items: center;
|
|
1335
1328
|
gap: 4px;
|
|
1336
1329
|
flex-wrap: wrap;
|
|
1330
|
+
min-width: 0;
|
|
1331
|
+
`, TitleCell = dt.div`
|
|
1332
|
+
min-width: 0;
|
|
1333
|
+
overflow: hidden;
|
|
1334
|
+
flex: 1;
|
|
1337
1335
|
`, ColType = dt.div`
|
|
1338
1336
|
flex: 0.8;
|
|
1339
1337
|
min-width: 80px;
|
|
@@ -1525,13 +1523,37 @@ const DashboardContainer = dt.div`
|
|
|
1525
1523
|
color: #374151;
|
|
1526
1524
|
border-color: #9ca3af;
|
|
1527
1525
|
}
|
|
1528
|
-
`, DocTitleAnchor = ({
|
|
1526
|
+
`, DocTitleAnchor = ({ id, type, structureTool, children }) => {
|
|
1527
|
+
const { basePath } = sanity.useWorkspace(), { onClick: intentOnClick, href: intentHref } = router.useIntentLink({ intent: "edit", params: { id, type } }), href = structureTool ? `${basePath}/${structureTool}/intent/edit/id=${id};type=${type}/` : intentHref;
|
|
1528
|
+
return /* @__PURE__ */ jsxRuntime.jsx(DocTitleLink, { href, onClick: structureTool ? void 0 : intentOnClick, title: "Open document", children });
|
|
1529
|
+
}, PaneLinkWrapper = dt.span`
|
|
1530
|
+
display: block;
|
|
1531
|
+
min-width: 0;
|
|
1532
|
+
overflow: hidden;
|
|
1533
|
+
|
|
1534
|
+
a {
|
|
1535
|
+
font-size: 13px;
|
|
1536
|
+
font-weight: 600;
|
|
1537
|
+
color: #4f46e5;
|
|
1538
|
+
white-space: nowrap;
|
|
1539
|
+
overflow: hidden;
|
|
1540
|
+
text-overflow: ellipsis;
|
|
1541
|
+
text-decoration: none;
|
|
1542
|
+
display: block;
|
|
1543
|
+
transition: color 0.15s;
|
|
1544
|
+
|
|
1545
|
+
&:hover {
|
|
1546
|
+
color: #4338ca;
|
|
1547
|
+
text-decoration: underline;
|
|
1548
|
+
}
|
|
1549
|
+
}
|
|
1550
|
+
`, DocTitleAnchorPane = ({
|
|
1529
1551
|
id,
|
|
1530
1552
|
type,
|
|
1531
1553
|
children
|
|
1532
1554
|
}) => {
|
|
1533
|
-
const {
|
|
1534
|
-
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
1555
|
+
const { ChildLink } = structure.usePaneRouter();
|
|
1556
|
+
return /* @__PURE__ */ jsxRuntime.jsx(PaneLinkWrapper, { children: /* @__PURE__ */ jsxRuntime.jsx(ChildLink, { childId: id, childParameters: { type }, children }) });
|
|
1535
1557
|
}, DocBadgeRenderer = ({ doc, docBadge }) => {
|
|
1536
1558
|
const badge = docBadge(doc);
|
|
1537
1559
|
return badge ? /* @__PURE__ */ jsxRuntime.jsx(CustomBadge, { $bgColor: badge.bgColor, $textColor: badge.textColor, $fontSize: badge.fontSize, children: badge.label }) : null;
|
|
@@ -1773,7 +1795,9 @@ const DashboardContainer = dt.div`
|
|
|
1773
1795
|
loadingLicense,
|
|
1774
1796
|
loadingDocuments,
|
|
1775
1797
|
noDocuments,
|
|
1776
|
-
previewMode = !1
|
|
1798
|
+
previewMode = !1,
|
|
1799
|
+
openInPane = !1,
|
|
1800
|
+
structureTool
|
|
1777
1801
|
}) => {
|
|
1778
1802
|
const client = sanity.useClient({ apiVersion }), [licenseStatus, setLicenseStatus] = o.useState("loading"), [documents, setDocuments] = o.useState([]), [loading, setLoading] = o.useState(!0), [searchQuery, setSearchQuery] = o.useState(""), [filterStatus, setFilterStatus] = o.useState("all"), [filterType, setFilterType] = o.useState("all"), [sortBy, setSortBy] = o.useState("score"), [activePopover, setActivePopover] = o.useState(null), VALIDATION_ENDPOINT = "https://sanity-plugin-seofields.thehardik.in/api/validate-license", CACHE_TTL_MS = 3600 * 1e3, validateLicense = o.useCallback(
|
|
1779
1803
|
async (forceRefresh = !1) => {
|
|
@@ -2058,8 +2082,8 @@ export default defineConfig({
|
|
|
2058
2082
|
] }),
|
|
2059
2083
|
filteredAndSortedDocs.map((doc) => /* @__PURE__ */ jsxRuntime.jsxs(TableRow, { children: [
|
|
2060
2084
|
/* @__PURE__ */ jsxRuntime.jsx(ColTitle, { children: /* @__PURE__ */ jsxRuntime.jsxs(TitleWrapper, { children: [
|
|
2061
|
-
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
2062
|
-
/* @__PURE__ */ jsxRuntime.jsx(DocTitleAnchor, { id: doc._id, type: doc._type, children: doc.title || "Untitled" }),
|
|
2085
|
+
/* @__PURE__ */ jsxRuntime.jsxs(TitleCell, { children: [
|
|
2086
|
+
openInPane ? /* @__PURE__ */ jsxRuntime.jsx(DocTitleAnchorPane, { id: doc._id, type: doc._type, children: doc.title || "Untitled" }) : /* @__PURE__ */ jsxRuntime.jsx(DocTitleAnchor, { id: doc._id, type: doc._type, structureTool, children: doc.title || "Untitled" }),
|
|
2063
2087
|
showDocumentId && /* @__PURE__ */ jsxRuntime.jsx(DocId, { children: doc._id })
|
|
2064
2088
|
] }),
|
|
2065
2089
|
docBadge && /* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -3081,7 +3105,8 @@ const resolveDashboardConfig = (healthDashboard) => {
|
|
|
3081
3105
|
loadingLicense: cfg?.content?.loadingLicense,
|
|
3082
3106
|
loadingDocuments: cfg?.content?.loadingDocuments,
|
|
3083
3107
|
noDocuments: cfg?.content?.noDocuments,
|
|
3084
|
-
previewMode: cfg?.previewMode
|
|
3108
|
+
previewMode: cfg?.previewMode,
|
|
3109
|
+
structureTool: cfg?.structureTool
|
|
3085
3110
|
};
|
|
3086
3111
|
}, seofields = sanity.definePlugin((config = {}) => {
|
|
3087
3112
|
const { healthDashboard = !0 } = config, dash = resolveDashboardConfig(healthDashboard), BoundSeoHealthTool = () => o__default.default.createElement(SeoHealthTool, {
|
|
@@ -3102,7 +3127,8 @@ const resolveDashboardConfig = (healthDashboard) => {
|
|
|
3102
3127
|
loadingLicense: dash.loadingLicense,
|
|
3103
3128
|
loadingDocuments: dash.loadingDocuments,
|
|
3104
3129
|
noDocuments: dash.noDocuments,
|
|
3105
|
-
previewMode: dash.previewMode
|
|
3130
|
+
previewMode: dash.previewMode,
|
|
3131
|
+
structureTool: dash.structureTool
|
|
3106
3132
|
});
|
|
3107
3133
|
return {
|
|
3108
3134
|
name: "sanity-plugin-seofields",
|
|
@@ -3121,9 +3147,17 @@ const resolveDashboardConfig = (healthDashboard) => {
|
|
|
3121
3147
|
}
|
|
3122
3148
|
};
|
|
3123
3149
|
});
|
|
3150
|
+
function createSeoHealthPane(optionsOrS, optionsWhenS) {
|
|
3151
|
+
const S2 = optionsOrS, { query, openInPane = !0, title: paneTitle, ...rest } = optionsWhenS ?? {}, SeoHealthPane = () => /* @__PURE__ */ jsxRuntime.jsx(SeoHealthDashboard, { customQuery: query, openInPane, title: paneTitle, ...rest });
|
|
3152
|
+
return SeoHealthPane.displayName = "SeoHealthPane", S2.component(SeoHealthPane).title(paneTitle ?? "SEO Health").child((docId, { params }) => {
|
|
3153
|
+
const builder = S2.document().documentId(docId);
|
|
3154
|
+
return params?.type ? builder.schemaType(params.type) : builder;
|
|
3155
|
+
});
|
|
3156
|
+
}
|
|
3124
3157
|
exports.SeoHealthDashboard = SeoHealthDashboard;
|
|
3125
3158
|
exports.SeoHealthTool = SeoHealthTool;
|
|
3126
3159
|
exports.allSchemas = types;
|
|
3160
|
+
exports.createSeoHealthPane = createSeoHealthPane;
|
|
3127
3161
|
exports.default = seofields;
|
|
3128
3162
|
exports.metaAttributeSchema = metaAttribute;
|
|
3129
3163
|
exports.metaTagSchema = metaTag;
|