- <SeoPagination> (UI-SPEC L2): previous and next (left out at the ends), page 1, the last page and five pages around the current one with gap items; nothing when last <= 1; props current, last, labels, classPrefix, locale - usePagination(): hrefs in the CMS form (resolve answer, then site answer, then seo.pagination), other query parameters kept, page 1 unnumbered, <link rel=prev/next> in the head - the CMS head fills %pages% in the title and description once the listing's page count is known (seoFillPages) - seoPaginationWindow, seoPageHref, seoPageNumber; L2 default styles
34 lines
1.6 KiB
TypeScript
34 lines
1.6 KiB
TypeScript
// The page head from the CMS resolve answer: title, description, robots,
|
|
// canonical, Open Graph (with og:locale and its alternates), X/Twitter,
|
|
// verification meta, <html lang>, hreflang links and exactly one JSON-LD
|
|
// script holding one @graph (the CMS nodes plus those added through
|
|
// useSchemaNode, merged by @id). A listing's %pages% in the CMS title and
|
|
// description becomes its number of pages once usePagination() knows it. One entry with tagPriority 'critical', so
|
|
// its tags win over the same tags a page, a layer or a module sets; a value
|
|
// the answer lacks adds no tag and the page's own stays. The layer's app
|
|
// plugin (seo-head) is the only caller: pages and other layers never set CMS
|
|
// values themselves.
|
|
|
|
import type { Ref } from 'vue'
|
|
import { mergeGraph } from '../utils/graph.ts'
|
|
import { seoFillPages, seoHeadInput } from '../utils/seo.ts'
|
|
import type { SeoResolveAnswer } from '../utils/types.ts'
|
|
|
|
export function useCmsSeo(answer: Ref<SeoResolveAnswer | null>): void {
|
|
const origin = useRequestURL().origin
|
|
const nodes = useSchemaNodes()
|
|
const pages = useSeoPages()
|
|
useHead(
|
|
computed(() => {
|
|
const head = seoFillPages(seoHeadInput(answer.value, origin), pages.value)
|
|
const cmsGraph = answer.value?.action === 'ok' ? answer.value.jsonld : null
|
|
const graph = mergeGraph(cmsGraph, nodes())
|
|
// unhead serializes the object and escapes "<" inside it, so a value
|
|
// such as "</script>" cannot end the script element.
|
|
const script = graph ? [{ type: 'application/ld+json', key: 'seo-jsonld', innerHTML: graph }] : []
|
|
return { ...head, script }
|
|
}),
|
|
{ tagPriority: 'critical' },
|
|
)
|
|
}
|