dml_frontend/composables/usePageMeta.ts
2025-06-11 18:19:53 +02:00

138 lines
4.7 KiB
TypeScript

import { watch, computed } from 'vue'
import { useRoute } from 'vue-router'
import { useMainStore } from '@/stores/main'
import { useHead } from '@unhead/vue'
import { storeToRefs } from 'pinia'
// Importiere die Seiten-Routen
import { i18nPages } from '../i18n/i18n-pages' // relativ zu deinem Composable-Pfad anpassen!
export function usePageMeta () {
const nearbyPlaces = [
'Herrsching', 'Starnberg', 'Landsberg am Lech',
'Weilheim', 'Fürstenfeldbruck', 'Kaufering',
'Andechs', 'Seefeld', 'Utting am Ammersee',
'Dießen am Ammersee', 'Schondorf am Ammersee',
'Wörthsee', 'Inning am Ammersee', 'Greifenberg',
'Pöcking', 'Weßling', 'Gauting', 'Gilching',
'Feldafing', 'Tutzing', 'Krailling', 'Germering', 'München',
'Erding', 'Augsburg', 'Wolfratshausen', 'Bad Tölz', 'Murnau',
'Grünwald', 'Planegg', 'Oberhaching', 'Geltendorf', 'Peißenberg',
'Bad Tölz', 'Schongau', 'Peißenberg', 'Schwabmünchen',
'Oberbayern', 'Bayern', 'Deutschland'
]
function makeAreaServedArray(names: string[]) {
return names.map(name => {
if (name === 'Deutschland') return { '@type': 'Country', name }
if (name === 'Bayern') return { '@type': 'State', name }
if (name === 'Oberbayern') return { '@type': 'AdministrativeArea', name }
return { '@type': 'Place', name }
})
}
const route = useRoute()
const mainStore = useMainStore()
const { companyinfo } = storeToRefs(mainStore)
const currentPage = computed(() => mainStore.getPageByLink(route.path))
watch(
() => currentPage.value,
(page) => {
if (!page || !companyinfo.value) return
const metaTitle = page.SEO?.pageTitle ?? 'digimedialoop'
const metaDescription = page.SEO?.seoDescription ?? 'Webdesign und Webentwicklung'
const metaImage = page.SEO?.seoImage?.url ?? 'https://strapi.digimedialoop.de/uploads/DML_Logo_Info_c4011028f9.png'
// Canonical URL
const config = useRuntimeConfig()
const canonical = `${config.public.appUrl}${page.pageLink}`
// Robots Meta Tag
const robotsContent = route.path === '/danke' ? 'noindex, nofollow' : 'index, follow'
// Prüfe, ob Route Home oder References in allen Sprachen ist
const isHomePage = Object.values(i18nPages.index).includes(route.path)
const isReferencesPage = Object.values(i18nPages.references).includes(route.path)
// Basis LocalBusiness JSON-LD
const baseJsonLd = {
'@context': 'https://schema.org',
'@type': 'LocalBusiness',
name: companyinfo.value.company,
image: metaImage,
url: config.public.appUrl,
telephone: companyinfo.value.phone,
email: companyinfo.value.email,
address: {
'@type': 'PostalAddress',
streetAddress: companyinfo.value.street,
addressLocality: companyinfo.value.city,
postalCode: companyinfo.value.postalcode,
addressCountry: 'DE'
},
geo: {
'@type': 'GeoCoordinates',
latitude: 47.9975,
longitude: 11.1864
},
openingHoursSpecification: [
{
'@type': 'OpeningHoursSpecification',
dayOfWeek: ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday'],
opens: '09:00',
closes: '17:00'
}
],
areaServed: makeAreaServedArray(nearbyPlaces)
}
// Falls Home oder References: ergänze das Rating (2 Bewertungen mit 5 Sternen)
let jsonLd = undefined
if (isHomePage || isReferencesPage) {
jsonLd = {
...baseJsonLd,
aggregateRating: {
'@type': 'AggregateRating',
ratingValue: '5',
reviewCount: '2'
}
}
} else if (isHomePage) {
// Nur LocalBusiness ohne Rating z.B.
jsonLd = baseJsonLd
}
useHead({
title: metaTitle,
meta: [
{ name: 'description', content: metaDescription },
{ name: 'robots', content: robotsContent },
{ property: 'og:title', content: metaTitle },
{ property: 'og:description', content: metaDescription },
{ property: 'og:image', content: metaImage },
{ property: 'og:type', content: 'website' },
{ name: 'twitter:title', content: metaTitle },
{ name: 'twitter:description', content: metaDescription },
{ name: 'twitter:image', content: metaImage }
],
link: [
{ rel: 'canonical', href: canonical }
],
script: jsonLd
? [
{
type: 'application/ld+json',
children: JSON.stringify(jsonLd)
}
]
: []
})
},
{ immediate: true }
)
}