@phtngyn/cms 0.2.0-beta.3 → 0.2.0-beta.4
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/package.json +1 -1
- package/src/cli.js +1 -1
- package/src/runtime/delivery/document-page.js +1 -5
- package/src/runtime/delivery/document-page.js.map +1 -1
- package/src/runtime/delivery/plugin.js +34 -5
- package/src/runtime/delivery/plugin.js.map +1 -1
- package/src/runtime/delivery/useCmsDocumentSeo.d.ts +1 -0
- package/src/runtime/delivery/useCmsDocumentSeo.js +5 -4
- package/src/runtime/delivery/useCmsDocumentSeo.js.map +1 -1
- package/studio/host.js +2 -1
package/package.json
CHANGED
package/src/cli.js
CHANGED
|
@@ -7,7 +7,7 @@ import { FetchHttpClient } from "effect/unstable/http";
|
|
|
7
7
|
import { Argument, CliError, Command, Flag, Prompt } from "effect/unstable/cli";
|
|
8
8
|
|
|
9
9
|
//#region package.json
|
|
10
|
-
var version = "0.2.0-beta.
|
|
10
|
+
var version = "0.2.0-beta.4";
|
|
11
11
|
|
|
12
12
|
//#endregion
|
|
13
13
|
//#region src/cli.ts
|
|
@@ -13,11 +13,7 @@ function resolveDocumentPage(request) {
|
|
|
13
13
|
}
|
|
14
14
|
return page ? h(DocumentRenderer_default, { value: page }) : void 0;
|
|
15
15
|
}
|
|
16
|
-
return request.ready.then(() =>
|
|
17
|
-
const failure = request.error() ?? (!request.page() ? request.notFound() : void 0);
|
|
18
|
-
if (failure && !request.renderError) throw failure;
|
|
19
|
-
return render;
|
|
20
|
-
});
|
|
16
|
+
return request.ready.then(() => render);
|
|
21
17
|
}
|
|
22
18
|
|
|
23
19
|
//#endregion
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"document-page.js","names":["DocumentRenderer"],"sources":["../../../../../src/runtime/delivery/document-page.ts"],"sourcesContent":["import type { VNode } from 'vue'\nimport type { DeliveryDocument } from './types'\nimport { h } from 'vue'\nimport DocumentRenderer from './DocumentRenderer'\n\nexport interface DocumentPageRequest {\n readonly error: () => Error | undefined\n readonly notFound: () => Error\n readonly page: () => DeliveryDocument | null\n readonly renderError?: ((error: Error) => () => VNode) | undefined\n readonly ready: Promise<unknown>\n}\n\nexport function resolveDocumentPage(request: DocumentPageRequest): Promise<() => VNode | undefined> {\n function render(): VNode | undefined {\n const error = request.error()\n const page = request.page()\n const failure = error ?? (!page ? request.notFound() : undefined)\n\n if (failure) {\n if (request.renderError) return request.renderError(failure)()\n throw failure\n }\n\n return page ? h(DocumentRenderer, { value: page }) : undefined\n }\n\n
|
|
1
|
+
{"version":3,"file":"document-page.js","names":["DocumentRenderer"],"sources":["../../../../../src/runtime/delivery/document-page.ts"],"sourcesContent":["import type { VNode } from 'vue'\nimport type { DeliveryDocument } from './types'\nimport { h } from 'vue'\nimport DocumentRenderer from './DocumentRenderer'\n\nexport interface DocumentPageRequest {\n readonly error: () => Error | undefined\n readonly notFound: () => Error\n readonly page: () => DeliveryDocument | null\n readonly renderError?: ((error: Error) => () => VNode) | undefined\n readonly ready: Promise<unknown>\n}\n\nexport function resolveDocumentPage(request: DocumentPageRequest): Promise<() => VNode | undefined> {\n function render(): VNode | undefined {\n const error = request.error()\n const page = request.page()\n const failure = error ?? (!page ? request.notFound() : undefined)\n\n if (failure) {\n if (request.renderError) return request.renderError(failure)()\n throw failure\n }\n\n return page ? h(DocumentRenderer, { value: page }) : undefined\n }\n\n // Always resolve setup with a renderer. Throwing delivery failures from render\n // lets Nuxt set the HTTP status without making Vue report a missing renderer.\n return request.ready.then(() => render)\n}\n"],"mappings":";;;;AAaA,SAAgB,oBAAoB,SAAgE;CAClG,SAAS,SAA4B;EACnC,MAAM,QAAQ,QAAQ,MAAM;EAC5B,MAAM,OAAO,QAAQ,KAAK;EAC1B,MAAM,UAAU,UAAU,CAAC,OAAO,QAAQ,SAAS,IAAI;EAEvD,IAAI,SAAS;GACX,IAAI,QAAQ,aAAa,OAAO,QAAQ,YAAY,OAAO,CAAC,CAAC;GAC7D,MAAM;EACR;EAEA,OAAO,OAAO,EAAEA,0BAAkB,EAAE,OAAO,KAAK,CAAC,IAAI;CACvD;CAIA,OAAO,QAAQ,MAAM,WAAW,MAAM;AACxC"}
|
|
@@ -1,16 +1,17 @@
|
|
|
1
1
|
import { ownsCmsLocale } from "../../internal/i18n.js";
|
|
2
2
|
import { n as readPreviewLocation, t as previewRedirect } from "../../location-CPX7oj0o.js";
|
|
3
3
|
import { usePreviewDelivery } from "./context.js";
|
|
4
|
-
import { installCmsDocumentSeoAdapters } from "./useCmsDocumentSeo.js";
|
|
5
4
|
import { localeFromPath } from "../i18n/translator.js";
|
|
5
|
+
import { installCmsDocumentSeoAdapters } from "./useCmsDocumentSeo.js";
|
|
6
6
|
import { computed, watch } from "vue";
|
|
7
|
-
import { addRouteMiddleware, defineNuxtPlugin, useHead, useRequestURL, useResponseHeader, useRoute,
|
|
7
|
+
import { addRouteMiddleware, defineNuxtPlugin, useHead, useRequestURL, useResponseHeader, useRoute, useState } from "nuxt/app";
|
|
8
8
|
import configuration from "#cms/i18n";
|
|
9
9
|
import { updateSiteConfig, useRobotsRule, useSchemaOrg } from "#imports";
|
|
10
10
|
|
|
11
11
|
//#region src/runtime/delivery/plugin.ts
|
|
12
12
|
var plugin_default = defineNuxtPlugin(() => {
|
|
13
13
|
const route = useRoute();
|
|
14
|
+
const url = useRequestURL();
|
|
14
15
|
const documentLocale = useState("cms-document-locale", () => void 0);
|
|
15
16
|
if (configuration.defaultLocale) {
|
|
16
17
|
const ownsRoute = computed(() => ownsCmsLocale(configuration, route.meta.cmsDocument === true));
|
|
@@ -38,13 +39,42 @@ var plugin_default = defineNuxtPlugin(() => {
|
|
|
38
39
|
const robots = useRobotsRule(input);
|
|
39
40
|
if (import.meta.server) watch(input, (value) => {
|
|
40
41
|
robots.value = value;
|
|
41
|
-
}, {
|
|
42
|
+
}, {
|
|
43
|
+
flush: "sync",
|
|
44
|
+
immediate: true
|
|
45
|
+
});
|
|
42
46
|
},
|
|
43
47
|
schema: (input) => {
|
|
44
48
|
useSchemaOrg(input);
|
|
45
49
|
},
|
|
46
50
|
seoMeta: (input) => {
|
|
47
|
-
|
|
51
|
+
useHead(() => {
|
|
52
|
+
const meta = [];
|
|
53
|
+
const addName = (name, content) => {
|
|
54
|
+
if (content) meta.push({
|
|
55
|
+
content,
|
|
56
|
+
name
|
|
57
|
+
});
|
|
58
|
+
};
|
|
59
|
+
const addProperty = (property, content) => {
|
|
60
|
+
if (content) meta.push({
|
|
61
|
+
content,
|
|
62
|
+
property
|
|
63
|
+
});
|
|
64
|
+
};
|
|
65
|
+
addName("description", input.description());
|
|
66
|
+
addName("robots", input.robots());
|
|
67
|
+
addProperty("og:title", input.ogTitle());
|
|
68
|
+
addProperty("og:description", input.ogDescription());
|
|
69
|
+
addProperty("og:image", input.ogImage());
|
|
70
|
+
addProperty("og:image:alt", input.ogImageAlt());
|
|
71
|
+
addProperty("og:locale", input.ogLocale());
|
|
72
|
+
addProperty("og:url", input.ogUrl() ?? (input.robots()?.startsWith("noindex") ? url.href : void 0));
|
|
73
|
+
return {
|
|
74
|
+
meta,
|
|
75
|
+
title: input.title()
|
|
76
|
+
};
|
|
77
|
+
});
|
|
48
78
|
},
|
|
49
79
|
locale: (input) => {
|
|
50
80
|
watch(input, (value) => documentLocale.value = value, {
|
|
@@ -53,7 +83,6 @@ var plugin_default = defineNuxtPlugin(() => {
|
|
|
53
83
|
});
|
|
54
84
|
}
|
|
55
85
|
});
|
|
56
|
-
const url = useRequestURL();
|
|
57
86
|
const parameters = readPreviewLocation(url);
|
|
58
87
|
if (!usePreviewDelivery().value || !parameters) return;
|
|
59
88
|
if (import.meta.server) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"plugin.js","names":[],"sources":["../../../../../src/runtime/delivery/plugin.ts"],"sourcesContent":["import configuration from '#cms/i18n'\nimport {\n addRouteMiddleware,\n defineNuxtPlugin,\n useHead,\n useRequestURL,\n useResponseHeader,\n useRoute,\n
|
|
1
|
+
{"version":3,"file":"plugin.js","names":[],"sources":["../../../../../src/runtime/delivery/plugin.ts"],"sourcesContent":["import configuration from '#cms/i18n'\nimport {\n addRouteMiddleware,\n defineNuxtPlugin,\n useHead,\n useRequestURL,\n useResponseHeader,\n useRoute,\n useState,\n} from 'nuxt/app'\nimport { updateSiteConfig, useRobotsRule, useSchemaOrg } from '#imports'\nimport { previewRedirect, readPreviewLocation } from '@internal/protocol/Preview'\nimport { computed, watch } from 'vue'\nimport { usePreviewDelivery } from './context'\nimport { installCmsDocumentSeoAdapters } from './useCmsDocumentSeo'\nimport { ownsCmsLocale } from '../../internal/i18n'\nimport { localeFromPath } from '../i18n/translator'\n\nexport default defineNuxtPlugin(() => {\n const route = useRoute()\n const url = useRequestURL()\n const documentLocale = useState<string | undefined>('cms-document-locale', () => undefined)\n\n if (configuration.defaultLocale) {\n const ownsRoute = computed(() => ownsCmsLocale(configuration, route.meta.cmsDocument === true))\n const locale = computed(() => documentLocale.value ?? localeFromPath(configuration, route.path))\n\n watch(\n () => route.fullPath,\n () => {\n documentLocale.value = undefined\n },\n { flush: 'sync' },\n )\n useHead({ htmlAttrs: { lang: computed(() => (ownsRoute.value ? locale.value : undefined)) } })\n updateSiteConfig({\n _context: '@phtngyn/cms',\n _priority: 0,\n currentLocale: computed(() => (ownsRoute.value ? locale.value : undefined)),\n defaultLocale: computed(() => (ownsRoute.value ? configuration.defaultLocale : undefined)),\n locales: computed(() =>\n ownsRoute.value\n ? Object.entries(configuration.locales).map(([code, value]) => ({ code, name: value.name }))\n : undefined,\n ),\n })\n }\n\n installCmsDocumentSeoAdapters({\n head: (input) => {\n useHead(input)\n },\n robots: (input) => {\n const robots = useRobotsRule(input)\n\n if (import.meta.server) {\n watch(\n input,\n (value) => {\n robots.value = value\n },\n { flush: 'sync', immediate: true },\n )\n }\n },\n schema: (input) => {\n useSchemaOrg(input)\n },\n seoMeta: (input) => {\n useHead(() => {\n const meta: Array<{ content: string; name: string } | { content: string; property: string }> = []\n\n const addName = (name: string, content: string | undefined) => {\n if (content) meta.push({ content, name })\n }\n\n const addProperty = (property: string, content: string | undefined) => {\n if (content) meta.push({ content, property })\n }\n\n addName('description', input.description())\n addName('robots', input.robots())\n addProperty('og:title', input.ogTitle())\n addProperty('og:description', input.ogDescription())\n addProperty('og:image', input.ogImage())\n addProperty('og:image:alt', input.ogImageAlt())\n addProperty('og:locale', input.ogLocale())\n addProperty('og:url', input.ogUrl() ?? (input.robots()?.startsWith('noindex') ? url.href : undefined))\n\n return { meta, title: input.title() }\n })\n },\n locale: (input) => {\n watch(input, (value) => (documentLocale.value = value), { immediate: true, flush: 'sync' })\n },\n })\n\n const parameters = readPreviewLocation(url)\n const preview = usePreviewDelivery()\n\n if (!preview.value || !parameters) return\n\n if (import.meta.server) {\n useResponseHeader('cache-control').value = 'private, no-store'\n useResponseHeader('x-frame-options').value = 'SAMEORIGIN'\n }\n\n addRouteMiddleware(\n 'cms-preview',\n (to) => {\n return previewRedirect(new URL(to.fullPath, url.origin), parameters)\n },\n { global: true },\n )\n})\n"],"mappings":";;;;;;;;;;;AAkBA,qBAAe,uBAAuB;CACpC,MAAM,QAAQ,SAAS;CACvB,MAAM,MAAM,cAAc;CAC1B,MAAM,iBAAiB,SAA6B,6BAA6B,MAAS;CAE1F,IAAI,cAAc,eAAe;EAC/B,MAAM,YAAY,eAAe,cAAc,eAAe,MAAM,KAAK,gBAAgB,IAAI,CAAC;EAC9F,MAAM,SAAS,eAAe,eAAe,SAAS,eAAe,eAAe,MAAM,IAAI,CAAC;EAE/F,YACQ,MAAM,gBACN;GACJ,eAAe,QAAQ;EACzB,GACA,EAAE,OAAO,OAAO,CAClB;EACA,QAAQ,EAAE,WAAW,EAAE,MAAM,eAAgB,UAAU,QAAQ,OAAO,QAAQ,MAAU,EAAE,EAAE,CAAC;EAC7F,iBAAiB;GACf,UAAU;GACV,WAAW;GACX,eAAe,eAAgB,UAAU,QAAQ,OAAO,QAAQ,MAAU;GAC1E,eAAe,eAAgB,UAAU,QAAQ,cAAc,gBAAgB,MAAU;GACzF,SAAS,eACP,UAAU,QACN,OAAO,QAAQ,cAAc,OAAO,CAAC,CAAC,KAAK,CAAC,MAAM,YAAY;IAAE;IAAM,MAAM,MAAM;GAAK,EAAE,IACzF,MACN;EACF,CAAC;CACH;CAEA,8BAA8B;EAC5B,OAAO,UAAU;GACf,QAAQ,KAAK;EACf;EACA,SAAS,UAAU;GACjB,MAAM,SAAS,cAAc,KAAK;GAElC,IAAI,YAAY,QACd,MACE,QACC,UAAU;IACT,OAAO,QAAQ;GACjB,GACA;IAAE,OAAO;IAAQ,WAAW;GAAK,CACnC;EAEJ;EACA,SAAS,UAAU;GACjB,aAAa,KAAK;EACpB;EACA,UAAU,UAAU;GAClB,cAAc;IACZ,MAAM,OAAyF,CAAC;IAEhG,MAAM,WAAW,MAAc,YAAgC;KAC7D,IAAI,SAAS,KAAK,KAAK;MAAE;MAAS;KAAK,CAAC;IAC1C;IAEA,MAAM,eAAe,UAAkB,YAAgC;KACrE,IAAI,SAAS,KAAK,KAAK;MAAE;MAAS;KAAS,CAAC;IAC9C;IAEA,QAAQ,eAAe,MAAM,YAAY,CAAC;IAC1C,QAAQ,UAAU,MAAM,OAAO,CAAC;IAChC,YAAY,YAAY,MAAM,QAAQ,CAAC;IACvC,YAAY,kBAAkB,MAAM,cAAc,CAAC;IACnD,YAAY,YAAY,MAAM,QAAQ,CAAC;IACvC,YAAY,gBAAgB,MAAM,WAAW,CAAC;IAC9C,YAAY,aAAa,MAAM,SAAS,CAAC;IACzC,YAAY,UAAU,MAAM,MAAM,MAAM,MAAM,OAAO,CAAC,EAAE,WAAW,SAAS,IAAI,IAAI,OAAO,OAAU;IAErG,OAAO;KAAE;KAAM,OAAO,MAAM,MAAM;IAAE;GACtC,CAAC;EACH;EACA,SAAS,UAAU;GACjB,MAAM,QAAQ,UAAW,eAAe,QAAQ,OAAQ;IAAE,WAAW;IAAM,OAAO;GAAO,CAAC;EAC5F;CACF,CAAC;CAED,MAAM,aAAa,oBAAoB,GAAG;CAG1C,IAAI,CAFY,mBAEL,CAAC,CAAC,SAAS,CAAC,YAAY;CAEnC,IAAI,YAAY,QAAQ;EACtB,kBAAkB,eAAe,CAAC,CAAC,QAAQ;EAC3C,kBAAkB,iBAAiB,CAAC,CAAC,QAAQ;CAC/C;CAEA,mBACE,gBACC,OAAO;EACN,OAAO,gBAAgB,IAAI,IAAI,GAAG,UAAU,IAAI,MAAM,GAAG,UAAU;CACrE,GACA,EAAE,QAAQ,KAAK,CACjB;AACF,CAAC"}
|
|
@@ -11,6 +11,7 @@ export interface CmsSeoMetadata {
|
|
|
11
11
|
readonly ogImage: ReactiveMetadataValue;
|
|
12
12
|
readonly ogImageAlt: ReactiveMetadataValue;
|
|
13
13
|
readonly ogLocale: ReactiveMetadataValue;
|
|
14
|
+
readonly ogUrl: ReactiveMetadataValue;
|
|
14
15
|
readonly robots: ReactiveMetadataValue;
|
|
15
16
|
}
|
|
16
17
|
interface CmsIdentitySchemaNode {
|
|
@@ -14,11 +14,12 @@ function useCmsDocumentSeo(document) {
|
|
|
14
14
|
title: () => seo.value?.title,
|
|
15
15
|
description: () => seo.value?.description,
|
|
16
16
|
ogTitle: () => seo.value?.socialTitle,
|
|
17
|
-
ogDescription: () => seo.value?.socialDescription,
|
|
17
|
+
ogDescription: () => seo.value?.socialDescription || (current.value?.draft ? seo.value?.title : void 0),
|
|
18
18
|
ogImage: () => seo.value?.socialImage?.url,
|
|
19
19
|
ogImageAlt: () => seo.value?.socialImage?.alt,
|
|
20
20
|
ogLocale: () => current.value?.locale,
|
|
21
|
-
|
|
21
|
+
ogUrl: () => seo.value?.canonicalUrl,
|
|
22
|
+
robots: () => seo.value && !current.value?.draft ? `${seo.value.index ? "index" : "noindex"}, ${seo.value.follow ? "follow" : "nofollow"}` : "noindex, nofollow"
|
|
22
23
|
});
|
|
23
24
|
adapters.locale(computed(() => current.value?.locale));
|
|
24
25
|
adapters.head(() => ({
|
|
@@ -27,8 +28,8 @@ function useCmsDocumentSeo(document) {
|
|
|
27
28
|
titleTemplate: null
|
|
28
29
|
}));
|
|
29
30
|
adapters.robots(computed(() => ({
|
|
30
|
-
follow: seo.value?.follow ??
|
|
31
|
-
index: seo.value?.index ??
|
|
31
|
+
follow: current.value?.draft ? false : seo.value?.follow ?? false,
|
|
32
|
+
index: current.value?.draft ? false : seo.value?.index ?? false
|
|
32
33
|
})));
|
|
33
34
|
adapters.schema(computed(() => seo.value ? schemaNodes(seo.value, current.value?.locale) : []));
|
|
34
35
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useCmsDocumentSeo.js","names":[],"sources":["../../../../../src/runtime/delivery/useCmsDocumentSeo.ts"],"sourcesContent":["import type { ResolvedSeo, SiteIdentity } from '@internal/protocol/Seo'\nimport type { ComputedRef, MaybeRefOrGetter } from 'vue'\nimport type { DeliveryDocument } from './types'\nimport { computed, toValue } from 'vue'\n\ntype ReactiveMetadataValue = () => string | undefined\n\nexport interface CmsSeoMetadata {\n readonly title: ReactiveMetadataValue\n readonly description: ReactiveMetadataValue\n readonly ogTitle: ReactiveMetadataValue\n readonly ogDescription: ReactiveMetadataValue\n readonly ogImage: ReactiveMetadataValue\n readonly ogImageAlt: ReactiveMetadataValue\n readonly ogLocale: ReactiveMetadataValue\n readonly robots: ReactiveMetadataValue\n}\n\ninterface CmsIdentitySchemaNode {\n readonly '@type': SiteIdentity['type']\n readonly name: string\n readonly url?: string\n readonly image?: string\n readonly logo?: string\n readonly telephone?: string\n readonly address?: NonNullable<Extract<SiteIdentity, { readonly type: 'LocalBusiness' }>['address']>\n}\n\ninterface CmsPageSchemaNode {\n readonly '@type': 'Article' | 'WebPage'\n readonly name: string\n readonly description?: string\n readonly image?: string\n readonly url?: string\n readonly headline?: string\n readonly datePublished?: string\n readonly dateModified?: string\n readonly inLanguage?: string\n}\n\nexport type CmsSeoSchemaNode = CmsIdentitySchemaNode | CmsPageSchemaNode\n\ntype EffectiveSeo = Omit<ResolvedSeo, 'canonicalUrl'> & {\n readonly canonicalUrl?: ResolvedSeo['canonicalUrl']\n}\n\nexport interface CmsDocumentSeoAdapters {\n readonly head: (\n input: () => {\n htmlAttrs?: { lang: string }\n link: Array<{ href: string; rel: 'canonical' } | { href: string; hreflang: string; rel: 'alternate' }>\n titleTemplate: null\n },\n ) => void\n readonly robots: (input: ComputedRef<{ readonly follow: boolean; readonly index: boolean }>) => void\n readonly schema: (input: ComputedRef<ReadonlyArray<CmsSeoSchemaNode>>) => void\n readonly seoMeta: (input: CmsSeoMetadata) => void\n readonly locale: (input: ComputedRef<string | undefined>) => void\n}\n\nlet installedAdapters: CmsDocumentSeoAdapters | undefined\n\n/** Installs Nuxt's composables once before document page setup. */\nexport function installCmsDocumentSeoAdapters(adapters: CmsDocumentSeoAdapters): void {\n installedAdapters = adapters\n}\n\nexport function useCmsDocumentSeo(document: MaybeRefOrGetter<DeliveryDocument | null>): void {\n const adapters = installedCmsDocumentSeoAdapters()\n const current = computed(() => toValue(document))\n const seo = computed(() => resolvedSeo(current.value))\n\n adapters.seoMeta({\n title: () => seo.value?.title,\n description: () => seo.value?.description,\n ogTitle: () => seo.value?.socialTitle,\n ogDescription: () => seo.value?.socialDescription,\n ogImage: () => seo.value?.socialImage?.url,\n ogImageAlt: () => seo.value?.socialImage?.alt,\n ogLocale: () => current.value?.locale,\n robots: () =>\n seo.value ? `${seo.value.index ? 'index' : 'noindex'}, ${seo.value.follow ? 'follow' : 'nofollow'}
|
|
1
|
+
{"version":3,"file":"useCmsDocumentSeo.js","names":[],"sources":["../../../../../src/runtime/delivery/useCmsDocumentSeo.ts"],"sourcesContent":["import type { ResolvedSeo, SiteIdentity } from '@internal/protocol/Seo'\nimport type { ComputedRef, MaybeRefOrGetter } from 'vue'\nimport type { DeliveryDocument } from './types'\nimport { computed, toValue } from 'vue'\n\ntype ReactiveMetadataValue = () => string | undefined\n\nexport interface CmsSeoMetadata {\n readonly title: ReactiveMetadataValue\n readonly description: ReactiveMetadataValue\n readonly ogTitle: ReactiveMetadataValue\n readonly ogDescription: ReactiveMetadataValue\n readonly ogImage: ReactiveMetadataValue\n readonly ogImageAlt: ReactiveMetadataValue\n readonly ogLocale: ReactiveMetadataValue\n readonly ogUrl: ReactiveMetadataValue\n readonly robots: ReactiveMetadataValue\n}\n\ninterface CmsIdentitySchemaNode {\n readonly '@type': SiteIdentity['type']\n readonly name: string\n readonly url?: string\n readonly image?: string\n readonly logo?: string\n readonly telephone?: string\n readonly address?: NonNullable<Extract<SiteIdentity, { readonly type: 'LocalBusiness' }>['address']>\n}\n\ninterface CmsPageSchemaNode {\n readonly '@type': 'Article' | 'WebPage'\n readonly name: string\n readonly description?: string\n readonly image?: string\n readonly url?: string\n readonly headline?: string\n readonly datePublished?: string\n readonly dateModified?: string\n readonly inLanguage?: string\n}\n\nexport type CmsSeoSchemaNode = CmsIdentitySchemaNode | CmsPageSchemaNode\n\ntype EffectiveSeo = Omit<ResolvedSeo, 'canonicalUrl'> & {\n readonly canonicalUrl?: ResolvedSeo['canonicalUrl']\n}\n\nexport interface CmsDocumentSeoAdapters {\n readonly head: (\n input: () => {\n htmlAttrs?: { lang: string }\n link: Array<{ href: string; rel: 'canonical' } | { href: string; hreflang: string; rel: 'alternate' }>\n titleTemplate: null\n },\n ) => void\n readonly robots: (input: ComputedRef<{ readonly follow: boolean; readonly index: boolean }>) => void\n readonly schema: (input: ComputedRef<ReadonlyArray<CmsSeoSchemaNode>>) => void\n readonly seoMeta: (input: CmsSeoMetadata) => void\n readonly locale: (input: ComputedRef<string | undefined>) => void\n}\n\nlet installedAdapters: CmsDocumentSeoAdapters | undefined\n\n/** Installs Nuxt's composables once before document page setup. */\nexport function installCmsDocumentSeoAdapters(adapters: CmsDocumentSeoAdapters): void {\n installedAdapters = adapters\n}\n\nexport function useCmsDocumentSeo(document: MaybeRefOrGetter<DeliveryDocument | null>): void {\n const adapters = installedCmsDocumentSeoAdapters()\n const current = computed(() => toValue(document))\n const seo = computed(() => resolvedSeo(current.value))\n\n adapters.seoMeta({\n title: () => seo.value?.title,\n description: () => seo.value?.description,\n ogTitle: () => seo.value?.socialTitle,\n ogDescription: () => seo.value?.socialDescription || (current.value?.draft ? seo.value?.title : undefined),\n ogImage: () => seo.value?.socialImage?.url,\n ogImageAlt: () => seo.value?.socialImage?.alt,\n ogLocale: () => current.value?.locale,\n ogUrl: () => seo.value?.canonicalUrl,\n robots: () =>\n seo.value && !current.value?.draft\n ? `${seo.value.index ? 'index' : 'noindex'}, ${seo.value.follow ? 'follow' : 'nofollow'}`\n : 'noindex, nofollow',\n })\n\n adapters.locale(computed(() => current.value?.locale))\n adapters.head(() => ({\n ...(current.value?.locale ? { htmlAttrs: { lang: current.value.locale } } : undefined),\n link: links(current.value, seo.value?.canonicalUrl),\n titleTemplate: null,\n }))\n adapters.robots(\n computed(() => ({\n follow: current.value?.draft ? false : (seo.value?.follow ?? false),\n index: current.value?.draft ? false : (seo.value?.index ?? false),\n })),\n )\n adapters.schema(computed(() => (seo.value ? schemaNodes(seo.value, current.value?.locale) : [])))\n}\n\nfunction links(document: DeliveryDocument | null, canonicalUrl?: string) {\n const canonical = canonicalUrl ? [{ href: canonicalUrl, rel: 'canonical' as const }] : []\n\n if (!canonicalUrl || !document?.alternatives) return canonical\n\n return [\n ...canonical,\n ...document.alternatives.map((alternative) => ({\n href: new URL(alternative.path, canonicalUrl).href,\n hreflang: alternative.locale,\n rel: 'alternate' as const,\n })),\n ]\n}\n\nfunction installedCmsDocumentSeoAdapters(): CmsDocumentSeoAdapters {\n if (!installedAdapters) throw new Error('The CMS document SEO adapter has not been installed.')\n\n return installedAdapters\n}\n\nfunction resolvedSeo(document: DeliveryDocument | null): EffectiveSeo | undefined {\n if (!document) return undefined\n\n if (document.resolvedSeo) return document.resolvedSeo\n\n return {\n description: document.description,\n follow: true,\n index: true,\n socialDescription: document.description,\n socialTitle: document.title,\n structuredData: { type: 'WebPage' },\n title: document.title,\n }\n}\n\nfunction schemaNodes(seo: EffectiveSeo, locale?: string): ReadonlyArray<CmsSeoSchemaNode> {\n const identity = seo.identity ? [identityNode(seo.identity)] : []\n\n if (!seo.structuredData) return identity\n\n const common = {\n name: seo.title,\n ...(seo.description ? { description: seo.description } : undefined),\n ...(seo.socialImage ? { image: seo.socialImage.url } : undefined),\n ...(seo.canonicalUrl ? { url: seo.canonicalUrl } : undefined),\n ...(locale ? { inLanguage: locale } : undefined),\n }\n\n if (seo.structuredData.type === 'Article') {\n return [\n ...identity,\n {\n '@type': 'Article',\n ...common,\n headline: seo.structuredData.headline ?? seo.title,\n ...(seo.structuredData.datePublished ? { datePublished: seo.structuredData.datePublished } : undefined),\n ...(seo.structuredData.dateModified ? { dateModified: seo.structuredData.dateModified } : undefined),\n },\n ]\n }\n\n return [...identity, { '@type': 'WebPage', ...common }]\n}\n\nfunction identityNode(identity: SiteIdentity): CmsIdentitySchemaNode {\n const common = {\n '@type': identity.type,\n name: identity.name,\n ...(identity.url ? { url: identity.url } : undefined),\n }\n\n switch (identity.type) {\n case 'Person':\n return { ...common, ...(identity.image ? { image: identity.image.url } : undefined) }\n case 'Organization':\n return { ...common, ...(identity.logo ? { logo: identity.logo.url } : undefined) }\n case 'LocalBusiness':\n return {\n ...common,\n ...(identity.address ? { address: identity.address } : undefined),\n ...(identity.image ? { image: identity.image.url } : undefined),\n ...(identity.logo ? { logo: identity.logo.url } : undefined),\n ...(identity.telephone ? { telephone: identity.telephone } : undefined),\n }\n }\n}\n"],"mappings":"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"}
|
package/studio/host.js
CHANGED
|
@@ -25444,7 +25444,8 @@ var dC = uC(1), fC = {
|
|
|
25444
25444
|
variant: "outline",
|
|
25445
25445
|
label: "View website",
|
|
25446
25446
|
"trailing-icon": "i-lucide-arrow-up-right",
|
|
25447
|
-
|
|
25447
|
+
href: "/",
|
|
25448
|
+
external: "",
|
|
25448
25449
|
target: "_blank"
|
|
25449
25450
|
})]), B(i).error.value ? (c(), n(h, {
|
|
25450
25451
|
key: 0,
|