add: more SEO meta
More seometa, better markdown parser
This commit is contained in:
parent
ca3868299c
commit
fa0435efdf
10 changed files with 52 additions and 14 deletions
|
@ -8,8 +8,6 @@
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
useSeoMeta({
|
useSeoMeta({
|
||||||
title: 'Home',
|
|
||||||
description: 'Headless CMS, Components & APIs by Fiona Urban. Storyblok, FirstSpirit, Nuxt.',
|
|
||||||
author: 'webfussel',
|
author: 'webfussel',
|
||||||
robots: 'index, follow',
|
robots: 'index, follow',
|
||||||
themeColor: '#2a2723',
|
themeColor: '#2a2723',
|
||||||
|
|
|
@ -130,7 +130,7 @@ const oneOff : Service[] = [
|
||||||
]
|
]
|
||||||
|
|
||||||
const { data: faq } = await useAsyncData('faq', () => queryCollection('faq').path('/snippets/faq/booking').first())
|
const { data: faq } = await useAsyncData('faq', () => queryCollection('faq').path('/snippets/faq/booking').first())
|
||||||
const texts = usePlainFaq(faq.value?.body.value)
|
const texts = generatePlainText<['title']>(faq.value?.body.value)
|
||||||
|
|
||||||
if (faq) {
|
if (faq) {
|
||||||
useSchemaOrg({
|
useSchemaOrg({
|
||||||
|
@ -138,10 +138,10 @@ if (faq) {
|
||||||
'@type': 'FAQPage',
|
'@type': 'FAQPage',
|
||||||
'mainEntity': texts.map(entity => ({
|
'mainEntity': texts.map(entity => ({
|
||||||
'@type': 'Question',
|
'@type': 'Question',
|
||||||
'name': entity.question,
|
'name': entity.meta.title,
|
||||||
'acceptedAnswer': {
|
'acceptedAnswer': {
|
||||||
'@type': 'Answer',
|
'@type': 'Answer',
|
||||||
'text': entity.answer,
|
'text': entity.text,
|
||||||
},
|
},
|
||||||
}))
|
}))
|
||||||
})
|
})
|
||||||
|
|
|
@ -139,7 +139,7 @@ const flatrate : Service[] =
|
||||||
]
|
]
|
||||||
|
|
||||||
const { data : faq } = await useAsyncData('faq', () => queryCollection('faq').path('/snippets/faq/flatrate').first())
|
const { data : faq } = await useAsyncData('faq', () => queryCollection('faq').path('/snippets/faq/flatrate').first())
|
||||||
const texts = usePlainFaq(faq.value?.body.value)
|
const texts = generatePlainText<['title']>(faq.value?.body.value)
|
||||||
|
|
||||||
if (faq) {
|
if (faq) {
|
||||||
useSchemaOrg({
|
useSchemaOrg({
|
||||||
|
@ -147,10 +147,10 @@ if (faq) {
|
||||||
'@type': 'FAQPage',
|
'@type': 'FAQPage',
|
||||||
'mainEntity': texts.map(entity => ({
|
'mainEntity': texts.map(entity => ({
|
||||||
'@type': 'Question',
|
'@type': 'Question',
|
||||||
'name': entity.question,
|
'name': entity.meta.title,
|
||||||
'acceptedAnswer': {
|
'acceptedAnswer': {
|
||||||
'@type': 'Answer',
|
'@type': 'Answer',
|
||||||
'text': entity.answer,
|
'text': entity.text,
|
||||||
},
|
},
|
||||||
}))
|
}))
|
||||||
})
|
})
|
||||||
|
|
|
@ -3,3 +3,10 @@
|
||||||
<SectionBooking />
|
<SectionBooking />
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
useSeoMeta({
|
||||||
|
title: 'Projektbuchung',
|
||||||
|
description: 'Buche jetzt dein Projekt auf webfussel. Du brauchst eine Schulung in JavaScript, Typescript, HTML, CSS, Vue oder Nuxt? Kein Problem.',
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
|
@ -3,3 +3,10 @@
|
||||||
<SectionContact />
|
<SectionContact />
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
useSeoMeta({
|
||||||
|
title: 'Kontakt',
|
||||||
|
description: 'Nimm Kontakt zu webfussel auf. Egal ob über E-Mail oder Social Media - ich freue mich auf deine Nachricht.',
|
||||||
|
})
|
||||||
|
</script>
|
|
@ -3,3 +3,10 @@
|
||||||
<SectionFlatrate />
|
<SectionFlatrate />
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
useSeoMeta({
|
||||||
|
title: 'Flatrate',
|
||||||
|
description: 'Buche webfussel ganz einfach für eine zugesicherte Anzahl Stunden pro Woche. Wenn immer mal wieder was anfällt - vertrau auf Fusselqualität.',
|
||||||
|
})
|
||||||
|
</script>
|
|
@ -14,4 +14,9 @@ useHead({
|
||||||
{ rel: 'icon', href: '/favicon.ico', type: 'image/x-icon' },
|
{ rel: 'icon', href: '/favicon.ico', type: 'image/x-icon' },
|
||||||
],
|
],
|
||||||
})
|
})
|
||||||
|
|
||||||
|
useSeoMeta({
|
||||||
|
title: 'Home',
|
||||||
|
description: 'Webprojekte und Retainer mit Fusselqualität. Du brauchst eine Website mit CMS? Bock auf Flatrate? webfussel by Fiona Urban',
|
||||||
|
})
|
||||||
</script>
|
</script>
|
|
@ -3,3 +3,10 @@
|
||||||
<SectionCustomers />
|
<SectionCustomers />
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
useSeoMeta({
|
||||||
|
title: 'Referenzen',
|
||||||
|
description: 'Schau dir dir Projekte von webfussel an. Über persönliche Webseiten, über Schulungen bis hin zu API Projekten.',
|
||||||
|
})
|
||||||
|
</script>
|
|
@ -1,5 +1,12 @@
|
||||||
import type { MinimalElement, MinimalNode } from '@nuxt/content'
|
import type { MinimalElement, MinimalNode } from '@nuxt/content'
|
||||||
|
|
||||||
|
type TypedRecord<T extends readonly string[]> = Record<T[number], string>
|
||||||
|
|
||||||
|
type PlainText<T extends string[]> = {
|
||||||
|
meta: TypedRecord<T>
|
||||||
|
text: string
|
||||||
|
}
|
||||||
|
|
||||||
const extractText = (element ?: MinimalNode) : string => {
|
const extractText = (element ?: MinimalNode) : string => {
|
||||||
if (!element) return ''
|
if (!element) return ''
|
||||||
if (typeof element === 'string') return element
|
if (typeof element === 'string') return element
|
||||||
|
@ -7,13 +14,13 @@ const extractText = (element ?: MinimalNode) : string => {
|
||||||
return nodes?.map((el : MinimalNode) => typeof el === 'string' ? el : extractText(el)).join(' ') ?? ''
|
return nodes?.map((el : MinimalNode) => typeof el === 'string' ? el : extractText(el)).join(' ') ?? ''
|
||||||
}
|
}
|
||||||
|
|
||||||
export const usePlainFaq = (body ?: MinimalNode[]) => {
|
export const generatePlainText = <T extends string[] = []>(body ?: MinimalNode[]) : PlainText<T>[] => {
|
||||||
if (!body) return []
|
if (!body) return []
|
||||||
return body.map(part => {
|
return body.map<PlainText<T>>(part => {
|
||||||
const [, meta] = part as MinimalElement
|
const [, meta] = part as MinimalElement
|
||||||
return {
|
return {
|
||||||
question: meta.title,
|
meta : meta as TypedRecord<T>,
|
||||||
answer: extractText(part).replace(/\n/g, ' ')
|
text: extractText(part).replace(/\n/g, ' ')
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
|
@ -63,5 +63,5 @@ Tja.
|
||||||
|
|
||||||
Ne, awas. Meld dich einfach trotzdem über meine E-Mail-Adresse und vielleicht finden wir eine Lösung.
|
Ne, awas. Meld dich einfach trotzdem über meine E-Mail-Adresse und vielleicht finden wir eine Lösung.
|
||||||
|
|
||||||
Du findest weitere Kontaktmöglichkeiten auf meiner [Kontakt-Seite <IconLinkInternal />](contact/){class="text inline-flex-row"}.
|
Du findest weitere Kontaktmöglichkeiten auf meiner [Kontakt-Seite <IconLinkInternal />](/contact/){class="text inline-flex-row"}.
|
||||||
::
|
::
|
Loading…
Add table
Add a link
Reference in a new issue