sanity
Version:
Sanity is a real-time content infrastructure with a scalable, hosted backend featuring a Graph Oriented Query Language (GROQ), asset pipelines and fast edge caches
154 lines (139 loc) • 4.85 kB
text/typescript
import {MasterDetailIcon} from '@sanity/icons'
import {lazy} from 'react'
import {definePlugin} from 'sanity'
import {tasks} from '../tasks'
import {comments} from './comments'
import {
DeleteAction,
DiscardChangesAction,
DuplicateAction,
HistoryRestoreAction,
PublishAction,
UnpublishAction,
} from './documentActions'
import {LiveEditBadge} from './documentBadges'
import {getIntentState} from './getIntentState'
import {structureUsEnglishLocaleBundle} from './i18n'
import {changesInspector} from './panes/document/inspectors/changes'
import {validationInspector} from './panes/document/inspectors/validation'
import {router} from './router'
import {type StructureToolOptions} from './types'
const documentActions = [
PublishAction,
UnpublishAction,
DiscardChangesAction,
DuplicateAction,
DeleteAction,
HistoryRestoreAction,
]
const documentBadges = [LiveEditBadge]
const inspectors = [validationInspector, changesInspector]
/**
* The structureTool is a studio plugin which adds the “structure tool” – a tool within
* Sanity Studio in which content editors can drill down to specific documents to edit them.
* You can configure your Studio's structure tool(s).
*
* @public
* @param options - Options for the structure tool. See {@link StructureToolOptions}
* @example Minimal example
* ```ts
* // sanity.config.ts
* import { defineConfig } from 'sanity'
* import { structureTool } from 'sanity/structure'
*
* export default defineConfig((
* // ...
* plugins: [
* structureTool() // use defaults
* ]
* })
* ```
*
* @example To customise your structure tool
* ```ts
* // sanity.config.ts
* import { defineConfig } from 'sanity'
* import { structureTool } from 'sanity/structure'
* import { FaCar } from 'react-icons'
* export default defineConfig((
* // ...
* plugins: [
* structureTool({
* name: 'cars',
* title: 'Cars',
* icon: FaCar,
* structure: (S) => S.documentTypeList('car'),
* defaultDocumentNode: (S) =>
* S.document().views([
* S.view.form(),
* S.view.component(Preview).title('Preview')
* ])
* })
* ]
* })
* ```
* */
export const structureTool = definePlugin<StructureToolOptions | void>((options) => {
const icon = options?.icon || MasterDetailIcon
return {
name: 'sanity/structure',
document: {
actions: (prevActions) => {
// NOTE: since it's possible to have several structure tools in one Studio,
// we need to check whether the document actions already exist in the Studio config
return Array.from(new Set([...prevActions, ...documentActions]))
},
badges: (prevBadges) => {
// NOTE: since it's possible to have several structure tools in one Studio,
// we need to check whether the document badges already exist in the Studio config
return Array.from(new Set([...prevBadges, ...documentBadges]))
},
inspectors: (prevInspectors) => {
// NOTE: since it's possible to have several structure tools in one Studio,
// we need to check whether the inspectors already exist in the Studio config
return Array.from(new Set([...prevInspectors, ...inspectors]))
},
},
plugins: [comments(), tasks()],
tools: [
{
name: options?.name || 'structure',
title: options?.title || 'Structure',
icon,
component: lazy(() => import('./components/structureTool')),
canHandleIntent: (intent, params) => {
if (intent === 'create') return canHandleCreateIntent(params)
if (intent === 'edit') return canHandleEditIntent(params)
return false
},
getIntentState,
// Controlled by sanity/src/structure/components/structureTool/StructureTitle.tsx
controlsDocumentTitle: true,
options,
router,
},
],
i18n: {
bundles: [structureUsEnglishLocaleBundle],
},
}
})
function canHandleCreateIntent(params: Record<string, unknown>) {
// We can't handle create intents without a `type` parameter
if (!('type' in params)) {
return false
}
// We can handle any create intent as long as it has a `type` parameter,
// but we also know how to deal with templates, where other tools might not
return 'template' in params ? {template: true} : true
}
function canHandleEditIntent(params: Record<string, unknown>) {
// We can't handle edit intents without an `id` parameter
if (!('id' in params)) {
return false
}
// We can handle any edit intent with a document ID, but we're best at `structure` mode
// This ensures that other tools that can handle modes such as `presentation` or `batch`
// can take precedence over the structure tool
return 'mode' in params ? {mode: params.mode === 'structure'} : true
}