From aeb9d11b7e266128ee07c9ed2e24062395c9b376 Mon Sep 17 00:00:00 2001 From: Rupert Dunk Date: Wed, 6 Mar 2024 20:09:19 +0000 Subject: [PATCH] feat: support visual editing (#949) --- .gitignore | 2 +- .../1.getting-started/2.configuration.md | 7 + .../1.getting-started/4.visual-editing.md | 90 +++ index.d.ts | 63 +- package.json | 3 + playground/.env.example | 2 + playground/cms/package.json | 5 +- playground/cms/sanity.config.ts | 20 +- playground/nuxt.config.js | 5 + playground/pages/index.vue | 7 +- playground/pages/movie/[slug].vue | 15 +- pnpm-lock.yaml | 661 +++++++++++++----- src/module.ts | 236 ++++++- src/runtime/client.ts | 91 +-- src/runtime/composables.ts | 13 +- src/runtime/minimal-client.ts | 91 +++ src/runtime/nitro-imports.ts | 20 +- src/runtime/plugin.ts | 2 +- src/runtime/visual-editing/composables.ts | 371 ++++++++++ src/runtime/visual-editing/plugins/client.ts | 21 + src/runtime/visual-editing/plugins/server.ts | 20 + src/runtime/visual-editing/preview/disable.ts | 6 + src/runtime/visual-editing/preview/enable.ts | 32 + test/unit/client.test.ts | 2 +- test/unit/helpers.test.ts | 2 +- 25 files changed, 1471 insertions(+), 316 deletions(-) create mode 100644 docs/content/1.getting-started/4.visual-editing.md create mode 100644 playground/.env.example create mode 100644 src/runtime/minimal-client.ts create mode 100644 src/runtime/visual-editing/composables.ts create mode 100644 src/runtime/visual-editing/plugins/client.ts create mode 100644 src/runtime/visual-editing/plugins/server.ts create mode 100644 src/runtime/visual-editing/preview/disable.ts create mode 100644 src/runtime/visual-editing/preview/enable.ts diff --git a/.gitignore b/.gitignore index 3aaad353..e07e212d 100755 --- a/.gitignore +++ b/.gitignore @@ -8,5 +8,5 @@ node_modules .DS_Store coverage dist - +playground/.env .vercel diff --git a/docs/content/1.getting-started/2.configuration.md b/docs/content/1.getting-started/2.configuration.md index f0961f15..ade2f40f 100644 --- a/docs/content/1.getting-started/2.configuration.md +++ b/docs/content/1.getting-started/2.configuration.md @@ -140,3 +140,10 @@ export default defineNuxtConfig({ }, }) ``` + +### `visualEditing` + +- Type: **Object** +- Default: **undefined** + +Used to enable and configure Visual Editing. See the [Visual Editing](/getting-started/visual-editing) section for more details. \ No newline at end of file diff --git a/docs/content/1.getting-started/4.visual-editing.md b/docs/content/1.getting-started/4.visual-editing.md new file mode 100644 index 00000000..46ea5c29 --- /dev/null +++ b/docs/content/1.getting-started/4.visual-editing.md @@ -0,0 +1,90 @@ +# Visual Editing + +--- + +## Overview + +`@nuxtjs/sanity` provides a simple method of integrating [visual editing](https://www.sanity.io/docs/visual-editing) in your Nuxt application. Before enabling this feature, make sure you have [Presentation](https://www.sanity.io/docs/presentation) installed in your studio. + +::alert{type="warning"} +Installing `@sanity/client` is required for visual editing. The `minimal` client must not be enabled. +:: + +## Configuration + +You can configure visual editing via the `sanity.visualEditing` key in your Nuxt config. The following options are available: + +#### `studioUrl` + +- **Required** +- Type: **string** + +The URL of the Sanity Studio with Presentation installed. + +#### `token` + +- **Required** +- Type: **string** + +A Sanity read token used for server side queries. This is required in order to fetch draft content. This value will not be exposed to the client. + +#### `mode` + +- Type: **string** +- Default: **`'live-visual-editing'`** + +Accepts one of the following options: + +- **`'live-visual-editing'`** - Default behaviour. Lets the module handle setup to provide fully featured visual editing with live updates. Queries should be executed using `useSanityQuery`. +- **`'visual-editing'`** - Used to enable visual editing without live updates, for example if fetching data using the Sanity client directly. Passing a custom `refresh` handler is recommended, as by default the entire app will refresh to display updates. +- **`'custom'`** - The module will not handle any setup, instead the `useSanityVisualEditing` and/or `useSanityLiveMode` composables will need to be called manually. + + +#### `previewMode` + +- Type: **boolean**, **object** +- Default: **true** + +To enable preview mode with defaults, or optionally configure the endpoints used to enable and disable preview mode. If passing an object, the options that can be provided are: + +- `enable` - the path of the enable endpoint, defaults to `/preview/enable` +- `disable` - the path of the disable endpoint, defaults to `/preview/disable` + +#### `stega` + +- Type: **boolean** +- Default: **true** + +Used to enable or disable [stega](https://www.sanity.io/docs/loaders-and-overlays#1dbcc04a7093). + + +#### `refresh` + +- Type: **function** + +An optional function for overriding the default handling of refresh events received from the studio. This is generally not need needed if the `mode` option is set to `live-visual-editing`. + +#### `zIndex` + +- Type: **number**, **string** +- Default: **9999999** + +The CSS z-index on the root node that renders overlays. + + +### Recommended Configuration + +For most use cases, the following minimum `visualEditing` configuration will suffice: + +```ts{}[nuxt.config.ts] +export default defineNuxtConfig({ + modules: ['@nuxtjs/sanity'], + sanity: { + // ... Sanity config + visualEditing: { + token: process.env.NUXT_SANITY_VISUAL_EDITING_TOKEN, + studioUrl: process.env.NUXT_SANITY_VISUAL_EDITING_STUDIO_URL, + } + }, +}) +``` \ No newline at end of file diff --git a/index.d.ts b/index.d.ts index 893e6340..836464ff 100644 --- a/index.d.ts +++ b/index.d.ts @@ -1,7 +1,68 @@ -import { SanityHelper } from './src/runtime/composables' +import type { ClientPerspective, StegaConfig } from '@sanity/client' +import type { SanityHelper } from '#sanity-composables' +import type { + SanityVisualEditingMode, + SanityVisualEditingRefreshHandler, + SanityVisualEditingZIndex, +} from './src/module' + +type nullish = null | undefined | void declare module '#app' { interface NuxtApp { _sanity?: Record } } + +declare module 'nuxt/schema' { + interface RuntimeConfig { + sanity: { + visualEditing: + | { + previewMode: + | false + | { + enable: string + disable: string + } + mode: SanityVisualEditingMode + studioUrl: string + previewModeId: string + token: string + + } + | undefined + } + } + + interface PublicRuntimeConfig { + sanity: { + additionalClients: Record + apiVersion: string + dataset: string + disableSmartCdn: boolean + perspective: ClientPerspective + projectId: string + stega: StegaConfig + token: string + useCdn: boolean + visualEditing: + | { + previewMode: + | false + | { + enable: string + disable: string + } + mode: SanityVisualEditingMode, + studioUrl: string + refresh: SanityVisualEditingRefreshHandler, + zIndex: SanityVisualEditingZIndex + } + | nullish + } + withCredentials: boolean + } +} + +export {} diff --git a/package.json b/package.json index 7163db04..a3cd7513 100755 --- a/package.json +++ b/package.json @@ -49,6 +49,9 @@ "dependencies": { "@nuxt/kit": "^3.9.0", "@portabletext/types": "^2.0.8", + "@sanity/core-loader": "^1.4.0", + "@sanity/preview-url-secret": "^1.6.0", + "@sanity/visual-editing": "^1.5.2", "chalk": "^5.3.0", "defu": "^6.1.3", "knitwork": "^1.0.0", diff --git a/playground/.env.example b/playground/.env.example new file mode 100644 index 00000000..7fc10784 --- /dev/null +++ b/playground/.env.example @@ -0,0 +1,2 @@ +# add a Viewer token issued from https://www.sanity.io/organizations//project//api#tokens +NUXT_SANITY_VISUAL_EDITING_TOKEN= diff --git a/playground/cms/package.json b/playground/cms/package.json index 44d0a8ff..1d20a6ea 100644 --- a/playground/cms/package.json +++ b/playground/cms/package.json @@ -7,6 +7,7 @@ "author": "Daniel Roe ", "license": "MIT", "scripts": { + "dev": "sanity dev", "start": "sanity start", "test": "sanity check" }, @@ -18,11 +19,11 @@ "react": "18.2.0", "react-dom": "18.2.0", "react-icons": "^4.12.0", - "sanity": "3.23.4", + "sanity": "3.30.1", "styled-components": "^6.1.6" }, "devDependencies": { - "@sanity/vision": "3.23.4", + "@sanity/vision": "3.30.1", "@types/react": "18.2.61", "@types/styled-components": "5.1.34" } diff --git a/playground/cms/sanity.config.ts b/playground/cms/sanity.config.ts index 69df8204..3c060cea 100644 --- a/playground/cms/sanity.config.ts +++ b/playground/cms/sanity.config.ts @@ -1,17 +1,29 @@ -import { createConfig } from 'sanity' -import { deskTool } from 'sanity/desk' +import { structureTool } from 'sanity/structure' +import { presentationTool } from 'sanity/presentation' +import { defineConfig } from 'sanity' import { visionTool } from '@sanity/vision' import { schemaTypes } from './schemas' +import { debugSecrets } from '@sanity/preview-url-secret/sanity-plugin-debug-secrets' -export default createConfig({ +export default defineConfig({ name: 'default', projectId: 'j1o4tmjp', dataset: 'production', plugins: [ - deskTool(), + structureTool(), visionTool(), + presentationTool({ + previewUrl: { + origin: 'http://localhost:3000', + previewMode: { + enable: '/preview/enable', + disable: '/preview/disable', + }, + }, + }), + debugSecrets(), ], schema: { diff --git a/playground/nuxt.config.js b/playground/nuxt.config.js index 52dc8882..b10489cc 100644 --- a/playground/nuxt.config.js +++ b/playground/nuxt.config.js @@ -9,8 +9,13 @@ export default defineNuxtConfig({ globalHelper: true, projectId: 'j1o4tmjp', dataset: 'production', + apiVersion: '2021-03-25', additionalClients: { another: {}, }, + visualEditing: { + token: process.env.NUXT_SANITY_VISUAL_EDITING_TOKEN, + studioUrl: 'http://localhost:3333', + }, }, }) diff --git a/playground/pages/index.vue b/playground/pages/index.vue index fef5a34b..4e1a7271 100644 --- a/playground/pages/index.vue +++ b/playground/pages/index.vue @@ -4,13 +4,14 @@ >

Project ID: {{ $sanity.config.projectId }}

{{ title }}
@@ -38,7 +39,5 @@ interface QueryResult { slug: string } -const sanity = useSanity() - -const { data: movies } = await useAsyncData('movies', () => sanity.fetch(query)) +const { data: movies, encodeDataAttribute } = await useSanityQuery(query) diff --git a/playground/pages/movie/[slug].vue b/playground/pages/movie/[slug].vue index 90c6b96d..fd6fc1c3 100644 --- a/playground/pages/movie/[slug].vue +++ b/playground/pages/movie/[slug].vue @@ -1,7 +1,9 @@