@devite/nuxt-sanity 1.5.2 → 2.0.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 +3 -3
- package/dist/module.d.mts +62 -14
- package/dist/module.d.ts +62 -14
- package/dist/module.json +3 -3
- package/dist/module.mjs +98 -4
- package/dist/runtime/client/DefaultSanityClient.d.ts +15 -0
- package/dist/runtime/client/DefaultSanityClient.js +44 -0
- package/dist/runtime/client/MinimalSanityClient.d.ts +15 -0
- package/dist/runtime/client/MinimalSanityClient.js +59 -0
- package/dist/runtime/client/SanityClient.d.ts +10 -0
- package/dist/runtime/client/SanityClient.js +7 -0
- package/dist/runtime/components/SanityComponent.vue +34 -20
- package/dist/runtime/components/SanityImageAsset.vue +9 -5
- package/dist/runtime/components/SanityLinkExternal.vue +2 -1
- package/dist/runtime/components/SanityLinkInternal.vue +5 -7
- package/dist/runtime/components/SanityPage.vue +23 -14
- package/dist/runtime/components/SanityRichText.vue +14 -18
- package/dist/runtime/composables/useLazySanityQuery.d.ts +4 -0
- package/dist/runtime/composables/useLazySanityQuery.js +4 -0
- package/dist/runtime/composables/useSanityLiveMode.d.ts +1 -0
- package/dist/runtime/composables/useSanityLiveMode.js +16 -0
- package/dist/runtime/composables/useSanityQuery.d.ts +30 -0
- package/dist/runtime/composables/useSanityQuery.js +69 -0
- package/dist/runtime/composables/useSanityVisualEditing.d.ts +8 -0
- package/dist/runtime/composables/useSanityVisualEditing.js +44 -0
- package/dist/runtime/composables/useSanityVisualEditingState.d.ts +4 -0
- package/dist/runtime/composables/useSanityVisualEditingState.js +12 -0
- package/dist/runtime/plugins/visual-editing.d.ts +2 -0
- package/dist/runtime/plugins/visual-editing.js +30 -0
- package/dist/runtime/server/routes/preview/disable.d.ts +2 -0
- package/dist/runtime/server/routes/preview/disable.js +6 -0
- package/dist/runtime/server/routes/preview/enable.d.ts +2 -0
- package/dist/runtime/server/routes/preview/enable.js +20 -0
- package/dist/runtime/server/routes/proxy.d.ts +2 -0
- package/dist/runtime/server/routes/proxy.js +19 -0
- package/dist/runtime/server/tsconfig.json +3 -0
- package/dist/runtime/server/utils/useSanityClient.d.ts +3 -0
- package/dist/runtime/server/utils/useSanityClient.js +17 -0
- package/dist/runtime/utils/getOrCreateSanityClient.d.ts +4 -0
- package/dist/runtime/utils/getOrCreateSanityClient.js +15 -0
- package/dist/runtime/utils/groq.d.ts +8 -0
- package/dist/runtime/utils/groq.js +6 -0
- package/dist/runtime/utils/projections.d.ts +4 -4
- package/dist/runtime/utils/projections.js +1 -1
- package/dist/runtime/utils/resolveImageAssetById.d.ts +2 -2
- package/dist/runtime/utils/resolveImageAssetById.js +2 -2
- package/dist/runtime/utils/resolveInternalLink.d.ts +2 -2
- package/dist/runtime/utils/resolveInternalLink.js +2 -2
- package/dist/runtime/utils/useSanityClient.d.ts +2 -0
- package/dist/runtime/utils/useSanityClient.js +8 -0
- package/dist/types.d.mts +1 -7
- package/dist/types.d.ts +1 -7
- package/package.json +29 -14
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<main v-if="sanityData?.modules?.length
|
|
2
|
+
<main v-if="sanityData?.modules?.length">
|
|
3
3
|
<SanityComponent
|
|
4
4
|
v-for="module in sanityData.modules"
|
|
5
5
|
:key="module._key"
|
|
@@ -9,24 +9,35 @@
|
|
|
9
9
|
</template>
|
|
10
10
|
|
|
11
11
|
<script setup lang="ts">
|
|
12
|
-
import {
|
|
13
|
-
import { groq } from '@nuxtjs/sanity/runtime/groq'
|
|
14
|
-
import type { ComputedRef } from 'vue'
|
|
12
|
+
import { computed, type ComputedRef } from 'vue'
|
|
15
13
|
import type { ImageAsset } from '@sanity/types'
|
|
16
|
-
import type {
|
|
14
|
+
import type { GlobalSEO, Home, NotFound, Page } from '@devite/nuxt-sanity'
|
|
17
15
|
import { IMAGE_WITHOUT_PREVIEW_PROJECTION } from '../utils/projections'
|
|
18
|
-
import {
|
|
16
|
+
import { useSanityQuery } from '../composables/useSanityQuery'
|
|
17
|
+
import { groq } from '../utils/groq'
|
|
18
|
+
import { useHead, useRoute, useRuntimeConfig, useSeoMeta } from '#imports'
|
|
19
19
|
|
|
20
20
|
const path = useRoute().fullPath
|
|
21
21
|
const groqFilter = path === '/' ? '_type == "home"' : `_type == "page" && slug.current == $slug`
|
|
22
|
-
const { data: sanityData } = await useSanityQuery<Home | Page | NotFound>(
|
|
22
|
+
const { data: sanityData } = await useSanityQuery<Home | Page | NotFound>(
|
|
23
|
+
groq`*[(${groqFilter}) || _type == "notFound"][0] { _id, _type, title, modules, seo { _type, indexable, title, shortTitle, description, image ${IMAGE_WITHOUT_PREVIEW_PROJECTION} } }`,
|
|
24
|
+
{ slug: path.substring(1) },
|
|
25
|
+
)
|
|
23
26
|
|
|
24
27
|
const { baseURL } = useRuntimeConfig().public
|
|
25
28
|
const seo = computed(() => sanityData.value?.seo)
|
|
26
|
-
const url = computed(
|
|
29
|
+
const url = computed(
|
|
30
|
+
() =>
|
|
31
|
+
((baseURL as string) || '')
|
|
32
|
+
+ ((sanityData.value && ('slug' in sanityData.value ? sanityData.value.slug.current : null)) || '/'),
|
|
33
|
+
)
|
|
27
34
|
|
|
28
|
-
const { data: globalSEO } = await useSanityQuery<GlobalSEO>(
|
|
29
|
-
|
|
35
|
+
const { data: globalSEO } = await useSanityQuery<GlobalSEO>(
|
|
36
|
+
groq`*[_type == 'settings'][0].seo { siteName, image ${IMAGE_WITHOUT_PREVIEW_PROJECTION} }`,
|
|
37
|
+
)
|
|
38
|
+
const image: ComputedRef<ImageAsset | undefined> = computed(
|
|
39
|
+
() => sanityData.value?.seo.image?.asset || globalSEO.value?.image?.asset,
|
|
40
|
+
)
|
|
30
41
|
const imageUrl = computed(() => image.value?.url)
|
|
31
42
|
const imageDimensions = computed(() => image.value?.metadata.dimensions)
|
|
32
43
|
|
|
@@ -42,14 +53,12 @@ useHead({
|
|
|
42
53
|
{ name: 'og:url', content: () => url.value },
|
|
43
54
|
{ name: 'twitter:url', content: () => url.value },
|
|
44
55
|
],
|
|
45
|
-
link: [
|
|
46
|
-
{ rel: 'canonical', href: () => url.value },
|
|
47
|
-
],
|
|
56
|
+
link: [{ rel: 'canonical', href: () => url.value }],
|
|
48
57
|
})
|
|
49
58
|
|
|
50
59
|
useSeoMeta({
|
|
51
60
|
robots: () => `${seo.value?.indexable ? '' : 'no'}index,follow`,
|
|
52
|
-
title: () => seo.value?.title,
|
|
61
|
+
title: () => seo.value?.title || '',
|
|
53
62
|
description: () => seo.value?.description,
|
|
54
63
|
ogTitle: () => seo.value?.shortTitle,
|
|
55
64
|
ogDescription: () => seo.value?.description,
|
|
@@ -7,33 +7,27 @@
|
|
|
7
7
|
|
|
8
8
|
<script setup lang="ts">
|
|
9
9
|
import { PortableText, type PortableTextComponents } from '@portabletext/vue'
|
|
10
|
+
import type { PortableTextChild, PortableTextSpan } from '@sanity/types'
|
|
10
11
|
import type { RichText } from '@devite/nuxt-sanity'
|
|
11
|
-
import { computed, h } from '
|
|
12
|
+
import { computed, h } from 'vue'
|
|
12
13
|
import { SanityLinkExternal, SanityLinkInternal } from '#components'
|
|
13
14
|
|
|
14
|
-
const
|
|
15
|
+
const props = defineProps<{ data: RichText, placeholders?: Record<string, string> }>()
|
|
15
16
|
const currentData = computed(() => {
|
|
16
|
-
return data.map((block) => {
|
|
17
|
+
return props.data.map((block) => {
|
|
17
18
|
return {
|
|
18
19
|
...block,
|
|
19
|
-
children: replaceChildren(block.children),
|
|
20
|
+
children: replaceChildren(block.children as PortableTextChild[]),
|
|
20
21
|
}
|
|
21
22
|
})
|
|
22
23
|
})
|
|
23
24
|
|
|
24
|
-
function replaceChildren(children:
|
|
25
|
+
function replaceChildren(children: PortableTextChild[]): PortableTextChild[] {
|
|
25
26
|
return children.map((child) => {
|
|
26
27
|
if (child._type === 'span') {
|
|
27
28
|
return {
|
|
28
29
|
...child,
|
|
29
|
-
text: replacePlaceholders(child.text),
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
if (child.children) {
|
|
34
|
-
return {
|
|
35
|
-
...child,
|
|
36
|
-
children: replaceChildren(child.children),
|
|
30
|
+
text: replacePlaceholders((child as PortableTextSpan).text),
|
|
37
31
|
}
|
|
38
32
|
}
|
|
39
33
|
|
|
@@ -42,15 +36,17 @@ function replaceChildren(children: object[]) {
|
|
|
42
36
|
}
|
|
43
37
|
|
|
44
38
|
function replacePlaceholders(text: string) {
|
|
45
|
-
return text.replace(/\{\{(.*?)
|
|
39
|
+
return text.replace(/\{\{(.*?)}}/g, (match, key) => {
|
|
40
|
+
if (!props.placeholders || !Object.prototype.hasOwnProperty.call(props.placeholders, key)) return match
|
|
41
|
+
|
|
42
|
+
return props.placeholders[key]
|
|
43
|
+
})
|
|
46
44
|
}
|
|
47
45
|
|
|
48
46
|
const richTextSerializer: PortableTextComponents = {
|
|
49
47
|
marks: {
|
|
50
|
-
linkExternal: ({ value }, { slots }) =>
|
|
51
|
-
|
|
52
|
-
linkInternal: ({ value }, { slots }) =>
|
|
53
|
-
h(SanityLinkInternal, { data: value }, slots.default),
|
|
48
|
+
linkExternal: ({ value }, { slots }) => h(SanityLinkExternal, { data: value }, slots.default),
|
|
49
|
+
linkInternal: ({ value }, { slots }) => h(SanityLinkInternal, { data: value }, slots.default),
|
|
54
50
|
},
|
|
55
51
|
}
|
|
56
52
|
</script>
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { AsyncDataOptions } from 'nuxt/app';
|
|
2
|
+
import type { QueryParams } from '@sanity/client';
|
|
3
|
+
import { type AsyncSanityData, type SanityQueryResponse } from './useSanityQuery.js';
|
|
4
|
+
export declare const useLazySanityQuery: <T = unknown, E = Error>(query: string, _params?: QueryParams, options?: AsyncDataOptions<SanityQueryResponse<T | null>>) => AsyncSanityData<T | null, E>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const useSanityLiveMode: () => () => void;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { onScopeDispose } from "vue";
|
|
2
|
+
import useSanityClient from "../utils/useSanityClient.js";
|
|
3
|
+
export const useSanityLiveMode = () => {
|
|
4
|
+
let disable = () => {
|
|
5
|
+
};
|
|
6
|
+
if (import.meta.client) {
|
|
7
|
+
const client = useSanityClient("default");
|
|
8
|
+
if (client.queryStore) {
|
|
9
|
+
disable = client.queryStore.enableLiveMode({
|
|
10
|
+
client: client.client
|
|
11
|
+
});
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
onScopeDispose(disable);
|
|
15
|
+
return disable;
|
|
16
|
+
};
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { ContentSourceMap, QueryParams } from '@sanity/client';
|
|
2
|
+
import type { EncodeDataAttributeFunction } from '@sanity/core-loader/encode-data-attribute';
|
|
3
|
+
import type { AsyncDataOptions, AsyncDataRequestStatus } from 'nuxt/app';
|
|
4
|
+
import { type Ref } from 'vue';
|
|
5
|
+
export interface SanityQueryResponse<T> {
|
|
6
|
+
data: T;
|
|
7
|
+
sourceMap?: ContentSourceMap;
|
|
8
|
+
encodeDataAttribute?: EncodeDataAttributeFunction;
|
|
9
|
+
}
|
|
10
|
+
interface AsyncDataExecuteOptions {
|
|
11
|
+
_initial?: boolean;
|
|
12
|
+
dedupe?: boolean;
|
|
13
|
+
}
|
|
14
|
+
export interface _AsyncSanityData<T, E> {
|
|
15
|
+
data: Ref<T>;
|
|
16
|
+
sourceMap: Ref<ContentSourceMap | null>;
|
|
17
|
+
encodeDataAttribute: Ref<EncodeDataAttributeFunction | (() => void)>;
|
|
18
|
+
pending: Ref<boolean>;
|
|
19
|
+
refresh: (opts?: AsyncDataExecuteOptions) => Promise<void>;
|
|
20
|
+
execute: (opts?: AsyncDataExecuteOptions) => Promise<void>;
|
|
21
|
+
error: Ref<E | null>;
|
|
22
|
+
status: Ref<AsyncDataRequestStatus>;
|
|
23
|
+
}
|
|
24
|
+
export type AsyncSanityData<T, E> = _AsyncSanityData<T, E> & Promise<_AsyncSanityData<T, E>>;
|
|
25
|
+
export interface UseSanityQueryOptions<T> extends AsyncDataOptions<T> {
|
|
26
|
+
client?: 'default' | 'minimal';
|
|
27
|
+
perspective?: 'previewDrafts' | 'published' | 'raw';
|
|
28
|
+
}
|
|
29
|
+
export declare const useSanityQuery: <T = unknown, E = Error>(query: string, _params?: QueryParams, _options?: UseSanityQueryOptions<SanityQueryResponse<T | null>>, lazy?: boolean) => AsyncSanityData<T | null, E>;
|
|
30
|
+
export {};
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { hash } from "ohash";
|
|
2
|
+
import { defineEncodeDataAttribute } from "@sanity/core-loader/encode-data-attribute";
|
|
3
|
+
import { onScopeDispose, reactive, ref } from "vue";
|
|
4
|
+
import useSanityClient from "../utils/useSanityClient.js";
|
|
5
|
+
import { useAsyncData, useLazyAsyncData } from "#imports";
|
|
6
|
+
export const useSanityQuery = (query, _params = {}, _options = {}, lazy = false) => {
|
|
7
|
+
const { client: clientType, perspective: _perspective, ...options } = _options;
|
|
8
|
+
const client = clientType ? useSanityClient(clientType) : useSanityClient();
|
|
9
|
+
const hasQueryStore = "queryStore" in client && client.queryStore !== null;
|
|
10
|
+
const perspective = _perspective || (hasQueryStore ? "previewDrafts" : "published");
|
|
11
|
+
const key = "sanity-" + hash(query + (_params ? JSON.stringify(_params) : ""));
|
|
12
|
+
const reactiveParams = _params ? reactive(_params) : void 0;
|
|
13
|
+
if (reactiveParams) {
|
|
14
|
+
options.watch ||= [];
|
|
15
|
+
options.watch.push(reactiveParams);
|
|
16
|
+
}
|
|
17
|
+
const data = ref(null);
|
|
18
|
+
const sourceMap = ref(null);
|
|
19
|
+
const encodeDataAttribute = ref(() => {
|
|
20
|
+
});
|
|
21
|
+
function updateResult(newData, newSourceMap) {
|
|
22
|
+
data.value = newData;
|
|
23
|
+
sourceMap.value = newSourceMap || null;
|
|
24
|
+
if (client.config.visualEditing) {
|
|
25
|
+
encodeDataAttribute.value = defineEncodeDataAttribute(newData, newSourceMap, client.config.visualEditing?.studioUrl);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
let fetchFunc = async () => {
|
|
29
|
+
return { data: await client.fetch(query, reactiveParams || {}, { perspective }) };
|
|
30
|
+
};
|
|
31
|
+
if (hasQueryStore) {
|
|
32
|
+
let setupFetcher = function(cb) {
|
|
33
|
+
unsubscribe();
|
|
34
|
+
const deepClonedParams = JSON.parse(JSON.stringify(_params));
|
|
35
|
+
const fetcher = defaultClient.queryStore.createFetcherStore(query, deepClonedParams, void 0);
|
|
36
|
+
unsubscribe = fetcher.subscribe((newSnapshot) => {
|
|
37
|
+
if (newSnapshot.data) {
|
|
38
|
+
updateResult(newSnapshot.data, newSnapshot.sourceMap);
|
|
39
|
+
cb?.(newSnapshot);
|
|
40
|
+
}
|
|
41
|
+
});
|
|
42
|
+
};
|
|
43
|
+
const defaultClient = client;
|
|
44
|
+
let unsubscribe = () => {
|
|
45
|
+
};
|
|
46
|
+
const proxyClient = {
|
|
47
|
+
fetch: (query2, params, options2) => $fetch(defaultClient.config.visualEditing.proxyEndpoint || "/_sanity/fetch", {
|
|
48
|
+
method: "POST",
|
|
49
|
+
body: { query: query2, params, options: options2 }
|
|
50
|
+
})
|
|
51
|
+
};
|
|
52
|
+
fetchFunc = async () => {
|
|
53
|
+
const currentClient = import.meta.server ? defaultClient.queryStore.unstable__serverClient.instance || defaultClient.client : proxyClient;
|
|
54
|
+
const { result: fetchData, resultSourceMap: sourceMap2 } = await currentClient.fetch(query, reactiveParams || {}, {
|
|
55
|
+
perspective,
|
|
56
|
+
filterResponse: false,
|
|
57
|
+
resultSourceMap: "withKeyArraySelector"
|
|
58
|
+
});
|
|
59
|
+
return sourceMap2 ? { data: fetchData, sourceMap: sourceMap2 } : { data: fetchData };
|
|
60
|
+
};
|
|
61
|
+
if (import.meta.client) setupFetcher();
|
|
62
|
+
onScopeDispose(unsubscribe);
|
|
63
|
+
}
|
|
64
|
+
const pendingData = lazy ? useLazyAsyncData(key, fetchFunc, options) : useAsyncData(key, fetchFunc, options);
|
|
65
|
+
return Object.assign(new Promise((resolve) => pendingData.then(({ data: { value } }) => {
|
|
66
|
+
updateResult(value.data, value.sourceMap);
|
|
67
|
+
resolve({ ...pendingData, data, sourceMap, encodeDataAttribute });
|
|
68
|
+
})), { ...pendingData, data, sourceMap, encodeDataAttribute });
|
|
69
|
+
};
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { DisableVisualEditing, VisualEditingOptions } from '@sanity/visual-editing';
|
|
2
|
+
import type { SanityVisualEditingRefreshHandler } from '@devite/nuxt-sanity';
|
|
3
|
+
export interface VisualEditingProps {
|
|
4
|
+
refresh?: SanityVisualEditingRefreshHandler;
|
|
5
|
+
zIndex?: VisualEditingOptions['zIndex'];
|
|
6
|
+
}
|
|
7
|
+
/** @return A function to disable visual editing */
|
|
8
|
+
export declare const useSanityVisualEditing: (options?: VisualEditingProps) => DisableVisualEditing;
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { enableVisualEditing } from "@sanity/visual-editing";
|
|
2
|
+
import { onScopeDispose } from "vue";
|
|
3
|
+
import { reloadNuxtApp, useRouter } from "#imports";
|
|
4
|
+
export const useSanityVisualEditing = (options = {}) => {
|
|
5
|
+
const { refresh, zIndex } = options;
|
|
6
|
+
let disable = () => {
|
|
7
|
+
};
|
|
8
|
+
if (import.meta.client) {
|
|
9
|
+
const router = useRouter();
|
|
10
|
+
disable = enableVisualEditing({
|
|
11
|
+
zIndex,
|
|
12
|
+
refresh: (payload) => {
|
|
13
|
+
function refreshDefault() {
|
|
14
|
+
if (payload.source === "mutation" && payload.livePreviewEnabled)
|
|
15
|
+
return false;
|
|
16
|
+
return new Promise((resolve) => {
|
|
17
|
+
reloadNuxtApp({ ttl: 1e3 });
|
|
18
|
+
resolve();
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
return refresh ? refresh(payload, refreshDefault) : refreshDefault();
|
|
22
|
+
},
|
|
23
|
+
history: {
|
|
24
|
+
subscribe(navigate) {
|
|
25
|
+
router.isReady().then(() => navigate({ type: "replace", url: router.currentRoute.value.fullPath }));
|
|
26
|
+
return router.afterEach((to) => navigate({ type: "push", url: to.fullPath }));
|
|
27
|
+
},
|
|
28
|
+
update(update) {
|
|
29
|
+
switch (update.type) {
|
|
30
|
+
case "push":
|
|
31
|
+
case "replace":
|
|
32
|
+
router[update.type](update.url);
|
|
33
|
+
break;
|
|
34
|
+
case "pop":
|
|
35
|
+
router.back();
|
|
36
|
+
break;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
onScopeDispose(disable);
|
|
43
|
+
return disable;
|
|
44
|
+
};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { reactive } from "vue";
|
|
2
|
+
import { useState } from "#imports";
|
|
3
|
+
export const useSanityVisualEditingState = () => {
|
|
4
|
+
const enabled = useState("_sanity_visualEditing", () => false);
|
|
5
|
+
return reactive({
|
|
6
|
+
enabled,
|
|
7
|
+
isInFrame() {
|
|
8
|
+
if (import.meta.server) return void 0;
|
|
9
|
+
return !!(window.self !== window.top || window.opener);
|
|
10
|
+
}
|
|
11
|
+
});
|
|
12
|
+
};
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { useSanityVisualEditingState } from "../composables/useSanityVisualEditingState.js";
|
|
2
|
+
import { useSanityLiveMode } from "../composables/useSanityLiveMode.js";
|
|
3
|
+
import { useSanityVisualEditing } from "../composables/useSanityVisualEditing.js";
|
|
4
|
+
import {
|
|
5
|
+
defineNuxtPlugin,
|
|
6
|
+
useCookie,
|
|
7
|
+
useRuntimeConfig
|
|
8
|
+
} from "#imports";
|
|
9
|
+
export default defineNuxtPlugin(() => {
|
|
10
|
+
const visualEditingState = useSanityVisualEditingState();
|
|
11
|
+
const $config = useRuntimeConfig();
|
|
12
|
+
const { visualEditing } = $config.public.sanity;
|
|
13
|
+
if (import.meta.server) {
|
|
14
|
+
if (visualEditing?.previewMode) {
|
|
15
|
+
const previewModeCookie = useCookie("__sanity_preview");
|
|
16
|
+
visualEditingState.enabled = visualEditing.previewModeId === previewModeCookie.value;
|
|
17
|
+
}
|
|
18
|
+
} else if (visualEditingState.enabled && visualEditing.mode !== "custom") {
|
|
19
|
+
switch (visualEditing?.mode) {
|
|
20
|
+
case "live-visual-editing":
|
|
21
|
+
case "visual-editing":
|
|
22
|
+
useSanityVisualEditing({
|
|
23
|
+
refresh: visualEditing?.refresh,
|
|
24
|
+
zIndex: visualEditing?.zIndex
|
|
25
|
+
});
|
|
26
|
+
if (visualEditing?.mode === "live-visual-editing") useSanityLiveMode();
|
|
27
|
+
break;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
});
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { defineEventHandler, deleteCookie, getQuery, sendRedirect } from "h3";
|
|
2
|
+
export default defineEventHandler(async (event) => {
|
|
3
|
+
const { redirect } = getQuery(event);
|
|
4
|
+
deleteCookie(event, "__sanity_preview");
|
|
5
|
+
await sendRedirect(event, redirect?.toString() || "/");
|
|
6
|
+
});
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { validatePreviewUrl } from "@sanity/preview-url-secret";
|
|
2
|
+
import { createError, defineEventHandler, getRequestURL, sendRedirect, setCookie } from "h3";
|
|
3
|
+
import useSanityClient from "../../utils/useSanityClient.js";
|
|
4
|
+
export default defineEventHandler(async (event) => {
|
|
5
|
+
const client = useSanityClient("default");
|
|
6
|
+
const { isValid, redirectTo = "/" } = await validatePreviewUrl(client.client, getRequestURL(event).toString());
|
|
7
|
+
if (!isValid) {
|
|
8
|
+
return createError({
|
|
9
|
+
statusCode: 403,
|
|
10
|
+
statusMessage: "Invalid secret"
|
|
11
|
+
});
|
|
12
|
+
}
|
|
13
|
+
setCookie(event, "__sanity_preview", client.config.visualEditing.previewModeId || "", {
|
|
14
|
+
httpOnly: true,
|
|
15
|
+
sameSite: !import.meta.dev ? "none" : "lax",
|
|
16
|
+
secure: !import.meta.dev,
|
|
17
|
+
path: "/"
|
|
18
|
+
});
|
|
19
|
+
await sendRedirect(event, redirectTo, 307);
|
|
20
|
+
});
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { createError, defineEventHandler, getCookie, readBody } from "h3";
|
|
2
|
+
import useSanityClient from "../utils/useSanityClient.js";
|
|
3
|
+
export default defineEventHandler(async (event) => {
|
|
4
|
+
const previewModeCookie = getCookie(event, "__sanity_preview");
|
|
5
|
+
if (!previewModeCookie) {
|
|
6
|
+
return createError({
|
|
7
|
+
statusCode: 403,
|
|
8
|
+
statusMessage: "This route is only available in preview mode"
|
|
9
|
+
});
|
|
10
|
+
}
|
|
11
|
+
const { query, params = {} } = await readBody(event);
|
|
12
|
+
if (!query) {
|
|
13
|
+
return createError({
|
|
14
|
+
statusCode: 400,
|
|
15
|
+
statusMessage: `Field "query" is required`
|
|
16
|
+
});
|
|
17
|
+
}
|
|
18
|
+
return await useSanityClient("default").fetch(query, params);
|
|
19
|
+
});
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import defu from "defu";
|
|
2
|
+
import getOrCreateSanityClient from "../../utils/getOrCreateSanityClient.js";
|
|
3
|
+
import { useRuntimeConfig } from "#imports";
|
|
4
|
+
export default function useSanityClient(type) {
|
|
5
|
+
const $config = useRuntimeConfig();
|
|
6
|
+
const sanityConfig = defu($config.sanity, $config.public.sanity || {});
|
|
7
|
+
const visualEditingEnabled = sanityConfig.visualEditing && sanityConfig.visualEditing.previewMode !== false;
|
|
8
|
+
return getOrCreateSanityClient(
|
|
9
|
+
visualEditingEnabled || false,
|
|
10
|
+
visualEditingEnabled ? {
|
|
11
|
+
...sanityConfig,
|
|
12
|
+
token: sanityConfig.visualEditing?.token,
|
|
13
|
+
useCdn: false
|
|
14
|
+
} : sanityConfig,
|
|
15
|
+
type
|
|
16
|
+
);
|
|
17
|
+
}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { ModuleOptions } from '@devite/nuxt-sanity';
|
|
2
|
+
import type SanityClient from '~/src/runtime/client/SanityClient';
|
|
3
|
+
export type SanityClientType = 'minimal' | 'default';
|
|
4
|
+
export default function getOrCreateSanityClient(visualEditing: boolean, config: ModuleOptions, type?: SanityClientType): SanityClient;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import MinimalSanityClient from "../client/MinimalSanityClient.js";
|
|
2
|
+
import DefaultSanityClient from "../client/DefaultSanityClient.js";
|
|
3
|
+
const clients = {};
|
|
4
|
+
export default function getOrCreateSanityClient(visualEditing, config, type) {
|
|
5
|
+
const clientType = visualEditing ? "default" : type || (config.minimalClient ? "minimal" : "default");
|
|
6
|
+
if (clientType in clients) return clients[clientType];
|
|
7
|
+
const clientConfig = {
|
|
8
|
+
...config,
|
|
9
|
+
stega: visualEditing && config.stega
|
|
10
|
+
};
|
|
11
|
+
const client = clientType === "minimal" ? new MinimalSanityClient(clientConfig) : new DefaultSanityClient(clientConfig);
|
|
12
|
+
if (visualEditing && import.meta.client) client.createQueryStore();
|
|
13
|
+
clients[clientType] = client;
|
|
14
|
+
return client;
|
|
15
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* GROQ template string tag that allows for syntax highlighting and linting.
|
|
3
|
+
*
|
|
4
|
+
* Source: https://github.com/sanity-io/sanity/blob/next/packages/groq/src/groq.ts
|
|
5
|
+
*/
|
|
6
|
+
export declare const groq: (template: {
|
|
7
|
+
raw: readonly string[] | ArrayLike<string>;
|
|
8
|
+
}, ...substitutions: any[]) => string;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export declare const IMAGE_ASSET_PROJECTION:
|
|
2
|
-
export declare const IMAGE_WITHOUT_PREVIEW_PROJECTION:
|
|
3
|
-
export declare const IMAGE_WITH_PREVIEW_PROJECTION:
|
|
4
|
-
export declare const LINK_PROJECTION:
|
|
1
|
+
export declare const IMAGE_ASSET_PROJECTION: string;
|
|
2
|
+
export declare const IMAGE_WITHOUT_PREVIEW_PROJECTION: string;
|
|
3
|
+
export declare const IMAGE_WITH_PREVIEW_PROJECTION: string;
|
|
4
|
+
export declare const LINK_PROJECTION: string;
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import type { ImageAsset } from '@sanity/types';
|
|
2
|
-
import type { Ref } from '
|
|
3
|
-
export declare const resolveImageAssetById: (id: string) => Promise<Ref<ImageAsset |
|
|
2
|
+
import type { Ref } from 'vue';
|
|
3
|
+
export declare const resolveImageAssetById: (id: string) => Promise<Ref<ImageAsset | null>>;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { useSanityQuery } from "
|
|
1
|
+
import { useSanityQuery } from "../composables/useSanityQuery.js";
|
|
2
2
|
import { IMAGE_ASSET_PROJECTION } from "./projections.js";
|
|
3
3
|
export const resolveImageAssetById = async (id) => {
|
|
4
|
-
return
|
|
4
|
+
return useSanityQuery(`*[_type == "sanity.imageAsset" && _id == $assetId][0] ${IMAGE_ASSET_PROJECTION}`, { assetId: id }).data;
|
|
5
5
|
};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import type { Reference } from '@sanity/types';
|
|
2
2
|
import type { LinkInternal } from '@devite/nuxt-sanity';
|
|
3
|
-
import type { Ref } from '
|
|
4
|
-
export declare const resolveInternalLink: (reference: Reference) => Promise<Ref<LinkInternal |
|
|
3
|
+
import type { Ref } from 'vue';
|
|
4
|
+
export declare const resolveInternalLink: (reference: Reference) => Promise<Ref<LinkInternal | null>>;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { useSanityQuery } from "
|
|
1
|
+
import { useSanityQuery } from "../composables/useSanityQuery.js";
|
|
2
2
|
export const resolveInternalLink = async (reference) => {
|
|
3
|
-
return
|
|
3
|
+
return useSanityQuery(`*[_id == $documentId][0] { '_type': 'linkInternal', 'slug': coalesce(slug.current, '/') }`, { documentId: reference._ref }).data;
|
|
4
4
|
};
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { useSanityVisualEditingState } from "../composables/useSanityVisualEditingState.js";
|
|
2
|
+
import getOrCreateSanityClient from "./getOrCreateSanityClient.js";
|
|
3
|
+
import { useRuntimeConfig } from "#imports";
|
|
4
|
+
export default function useSanityClient(type) {
|
|
5
|
+
const $config = useRuntimeConfig();
|
|
6
|
+
const sanityConfig = $config.public.sanity;
|
|
7
|
+
return getOrCreateSanityClient(useSanityVisualEditingState().enabled, sanityConfig, type);
|
|
8
|
+
}
|
package/dist/types.d.mts
CHANGED
|
@@ -1,7 +1 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
import type { default as Module } from './module.js'
|
|
4
|
-
|
|
5
|
-
export type ModuleOptions = typeof Module extends NuxtModule<infer O> ? Partial<O> : Record<string, any>
|
|
6
|
-
|
|
7
|
-
export { type GlobalSEO, type Home, type LinkExternal, type LinkInternal, type NotFound, type Page, type RichText, type SEO, default } from './module.js'
|
|
1
|
+
export { type GlobalSEO, type Home, type LinkExternal, type LinkInternal, type ModuleOptions, type NotFound, type Page, type RichText, type SEO, type SanityArray, type SanityModule, type SanityVisualEditingRefreshHandler, type VisualEditingOptions, default } from './module.js'
|
package/dist/types.d.ts
CHANGED
|
@@ -1,7 +1 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
import type { default as Module } from './module'
|
|
4
|
-
|
|
5
|
-
export type ModuleOptions = typeof Module extends NuxtModule<infer O> ? Partial<O> : Record<string, any>
|
|
6
|
-
|
|
7
|
-
export { type GlobalSEO, type Home, type LinkExternal, type LinkInternal, type NotFound, type Page, type RichText, type SEO, default } from './module'
|
|
1
|
+
export { type GlobalSEO, type Home, type LinkExternal, type LinkInternal, type ModuleOptions, type NotFound, type Page, type RichText, type SEO, type SanityArray, type SanityModule, type SanityVisualEditingRefreshHandler, type VisualEditingOptions, default } from './module'
|