Adds `useSiteMeta()` composable that wraps useSeoMeta with site defaults (title template, canonical URL, og/twitter image, og:site_name) and absolute-URL handling via runtimeConfig.public.appUrl. Adds /og/events/[slug].png route that renders per-event OG images via satori + @resvg/resvg-js, cached on disk by slug + updatedAt. Bundles Brygada 1918 + Commit Mono fonts as server assets, ships a fallback default.png, and patches @shuding/opentype.js via patch-package. Converts ~25 pages from useHead to useSiteMeta and adds noindex on private/auth/admin pages.
58 lines
1.9 KiB
JavaScript
58 lines
1.9 KiB
JavaScript
/**
|
|
* useSiteMeta — set page-level SEO + social meta with site defaults baked in.
|
|
*
|
|
* Builds absolute URLs from runtimeConfig.public.appUrl so og:image and og:url
|
|
* resolve for crawlers. Defaults og:type=website, twitter:card=summary_large_image,
|
|
* og:site_name=Ghost Guild. Set noindex:true to emit robots="noindex, nofollow".
|
|
*
|
|
* Pass a function (or refs in fields) to keep tags reactive when content loads
|
|
* asynchronously via useFetch.
|
|
*/
|
|
export function useSiteMeta(input) {
|
|
const runtimeConfig = useRuntimeConfig()
|
|
const route = useRoute()
|
|
const appUrl = (runtimeConfig.public.appUrl || '').replace(/\/$/, '')
|
|
|
|
const resolve = () => (typeof input === 'function' ? input() : input) || {}
|
|
|
|
const buildAbsolute = (path) => {
|
|
if (!path) return undefined
|
|
if (/^https?:\/\//i.test(path)) return path
|
|
return `${appUrl}${path.startsWith('/') ? '' : '/'}${path}`
|
|
}
|
|
|
|
const titleGetter = () => resolve().title || 'Ghost Guild'
|
|
const descGetter = () => resolve().description || undefined
|
|
const isBareTitle = () => Boolean(resolve().bareTitle)
|
|
const imageGetter = () => buildAbsolute(resolve().image || '/og/default.png')
|
|
const typeGetter = () => resolve().type || 'website'
|
|
const robotsGetter = () =>
|
|
resolve().noindex ? 'noindex, nofollow' : undefined
|
|
const canonicalGetter = () => buildAbsolute(route.path)
|
|
|
|
useSeoMeta({
|
|
title: titleGetter,
|
|
description: descGetter,
|
|
ogSiteName: 'Ghost Guild',
|
|
ogTitle: titleGetter,
|
|
ogDescription: descGetter,
|
|
ogType: typeGetter,
|
|
ogUrl: canonicalGetter,
|
|
ogImage: imageGetter,
|
|
ogImageWidth: 1200,
|
|
ogImageHeight: 630,
|
|
twitterCard: 'summary_large_image',
|
|
twitterTitle: titleGetter,
|
|
twitterDescription: descGetter,
|
|
twitterImage: imageGetter,
|
|
robots: robotsGetter,
|
|
})
|
|
|
|
useHead({
|
|
link: [{ rel: 'canonical', href: canonicalGetter }],
|
|
})
|
|
|
|
if (isBareTitle()) {
|
|
useHead({ titleTemplate: null })
|
|
}
|
|
}
|