import type { UseSeoMetaInput } from '@unhead/vue'; import { unref } from 'vue'; import type { MaybeRef } from 'vue'; import { clearLinkedText } from '../src/helpers.ts'; import type { Translator } from '../src/translator'; import { useSeoMeta } from '#imports'; import type { Config } from '~/locale/config.ts'; import { getUrlForLocale } from '~/src/domain.ts'; export const getDefaultSeo = (config: Config, translator: Translator) => ({ title: translator.translate('title'), description: translator.translate('description'), keywords: (translator.translate('seo.keywords') || []).join(', '), banner: `${getUrlForLocale(config.locale)}/api/banner/zaimki.png`, }); export interface HeadParams { title?: MaybeRef; description?: MaybeRef; banner?: MaybeRef; noindex?: boolean; keywords?: MaybeRef; } const DESCRIPTION_MAX_WORDCOUNT = 24; export default ( { title, description, banner, noindex = false, keywords }: HeadParams, translator: Translator, ): void => { const config = useConfig(); const defaultSeo = getDefaultSeo(config, translator); const seo: UseSeoMetaInput = {}; const seoTitle = () => { let titleUnwrapped = unref(title); if (!titleUnwrapped) { return defaultSeo.title; } titleUnwrapped = titleUnwrapped.replace(/'/g, '\''); titleUnwrapped = titleUnwrapped.replace(/<\/?[^>]+(>|$)/g, ''); // html tags titleUnwrapped = clearLinkedText(titleUnwrapped, false); titleUnwrapped += ` • ${translator.translate('title')}`; return titleUnwrapped; }; seo.title = seoTitle; seo.ogTitle = seoTitle; seo.twitterTitle = seoTitle; const seoDescription = () => { let descriptionUnwrapped = unref(description); if (!descriptionUnwrapped) { return defaultSeo.description; } descriptionUnwrapped = clearLinkedText(descriptionUnwrapped); const words = descriptionUnwrapped.split(' '); if (words.length > DESCRIPTION_MAX_WORDCOUNT) { descriptionUnwrapped = `${words.slice(0, DESCRIPTION_MAX_WORDCOUNT) .join(' ')}…`; } return descriptionUnwrapped; }; seo.description = seoDescription; seo.ogDescription = seoDescription; seo.twitterDescription = seoDescription; const baseUrl = getUrlForLocale(config.locale); const seoImage = () => { let bannerUnwrapped = unref(banner); if (!bannerUnwrapped) { return defaultSeo.banner; } bannerUnwrapped = bannerUnwrapped.replace(/^\//, ''); if (!bannerUnwrapped.startsWith('https://')) { bannerUnwrapped = `${baseUrl}/${bannerUnwrapped}`; } return bannerUnwrapped; }; seo.ogImage = seoImage; seo.twitterImage = seoImage; if (noindex) { seo.robots = 'noindex'; } seo.keywords = () => { const keywordsUnwrapped = unref(keywords) ?? []; const mergedKeywords = defaultSeo.keywords.split(', ').concat(keywordsUnwrapped); return mergedKeywords.join(', '); }; useSeoMeta(seo); };