PronounsPage/composables/useSimpleHead.ts

96 lines
3.2 KiB
TypeScript

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<string[]>('seo.keywords') || []).join(', '),
banner: `${getUrlForLocale(config.locale)}/api/banner/zaimki.png`,
});
export interface HeadParams {
title?: MaybeRef<string | null>;
description?: MaybeRef<string | null>;
banner?: MaybeRef<string | null>;
noindex?: boolean;
keywords?: MaybeRef<string[] | undefined>;
}
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(/&#39;/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);
};