import type { Directions } from 'vue-i18n-routing' import type { LocaleObject } from '#i18n' export function setupPageHeader() { const { locale, locales, t } = useI18n() const colorMode = useColorMode() const buildInfo = useBuildInfo() const enablePinchToZoom = usePreferences('enablePinchToZoom') const localeMap = (locales.value as LocaleObject[]).reduce((acc, l) => { acc[l.code!] = l.dir ?? 'ltr' return acc }, {} as Record) useHydratedHead({ htmlAttrs: { lang: () => locale.value, dir: () => localeMap[locale.value] ?? 'ltr', class: () => enablePinchToZoom.value ? ['enable-pinch-to-zoom'] : [], }, meta: [{ name: 'viewport', content: () => `width=device-width,initial-scale=1${enablePinchToZoom.value ? '' : ',maximum-scale=1,user-scalable=0'},viewport-fit=cover`, }], titleTemplate: (title) => { let titleTemplate = title ?? '' if (titleTemplate.match(/&[a-z0-9#]+;/gi)) { titleTemplate = unescapeTitleTemplate(titleTemplate, [ ['"', ['"', '"']], ['&', ['&', '&']], ['\'', [''', ''']], ['\u003C', ['<', '<']], ['\u003E', ['>', '>']], ]) if (titleTemplate.length > 60) titleTemplate = `${titleTemplate.slice(0, 60)}...${titleTemplate.endsWith('"') ? '"' : ''}` if (!titleTemplate.includes('"')) titleTemplate = `"${titleTemplate}"` } else if (titleTemplate.length > 60) { titleTemplate = `${titleTemplate.slice(0, 60)}...${titleTemplate.endsWith('"') ? '"' : ''}` } if (titleTemplate.length) titleTemplate += ' | ' titleTemplate += t('app_name') if (buildInfo.env !== 'release') titleTemplate += ` (${buildInfo.env})` return titleTemplate }, link: process.client && useAppConfig().pwaEnabled ? () => [{ key: 'webmanifest', rel: 'manifest', href: `/manifest-${locale.value}${colorMode.value === 'dark' ? '-dark' : ''}.webmanifest`, }] : [], }) } function unescapeTitleTemplate(titleTemplate: string, replacements: [string, string[]][]) { let result = titleTemplate for (const [replacement, entities] of replacements) { for (const e of entities) result = result.replaceAll(e, replacement) } return result.trim() }