mirror of
https://gitlab.com/PronounsPage/PronounsPage.git
synced 2025-08-03 19:17:07 -04:00
96 lines
3.2 KiB
TypeScript
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(/'/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);
|
|
};
|