add: SEO for articles
SEO and SchemaORg for articles
This commit is contained in:
parent
f1cb4048a4
commit
d6859cdaad
22 changed files with 198 additions and 125 deletions
|
@ -5,29 +5,54 @@
|
|||
Zurück zur Übersicht
|
||||
</NuxtLink>
|
||||
|
||||
<p v-if="!article">
|
||||
Sorry bro, aber der Artikel existiert einfach nicht.
|
||||
</p>
|
||||
|
||||
<div v-else>
|
||||
<main v-if="article" class="article-content z-3">
|
||||
<div class="image z-2">
|
||||
<img :src="article.image" alt="Artikelbild" aria-hidden="true"/>
|
||||
</div>
|
||||
<header>
|
||||
<div class="image z-2">
|
||||
<img :src="article.image" alt="Artikelbild" aria-hidden="true"/>
|
||||
<div class="meta">
|
||||
<NuxtLink :to="`/blog/?category=${article.category}`">
|
||||
<span class="chip interactive"><BlogCategory :name="article.category as Category"/></span>
|
||||
</NuxtLink>
|
||||
</div>
|
||||
<h1 class="margin-top">{{ article.title }}</h1>
|
||||
<h2>{{ article.description }}</h2>
|
||||
</header>
|
||||
<div class="flex-col gap-default">
|
||||
<div class="flex-col gap-default article-text">
|
||||
<ContentRenderer v-if="article" :value="article" :style="{ display: 'contents' }"/>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import type { Category } from '../../components/Blog/types'
|
||||
|
||||
const route = useRoute()
|
||||
|
||||
const { data: article } = await useAsyncData('article', () => queryCollection('blog').path(route.path).where('date', '<', tomorrow(new Date())).first())
|
||||
|
||||
if (!article.value) {
|
||||
throw createError({
|
||||
statusCode: 404,
|
||||
statusMessage: 'Page Not Found',
|
||||
})
|
||||
} else {
|
||||
useHead(article.value.head || {})
|
||||
useSeoMeta({
|
||||
...(article.value.seo || {}),
|
||||
ogTitle: article.value.title,
|
||||
ogDescription: article.value.description,
|
||||
ogImage: article.value.image,
|
||||
ogImageAlt: article.value.description,
|
||||
ogUrl: `https://webfussel.de${article.value.path}`,
|
||||
twitterTitle: article.value.title,
|
||||
twitterDescription: article.value.description,
|
||||
twitterImage: article.value.image,
|
||||
twitterImageAlt: article.value.description,
|
||||
twitterUrl: `https://webfussel.de${article.value.path}`,
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
|
|
@ -1,10 +1,17 @@
|
|||
<template>
|
||||
<section id="blog" class="BlogOverview content">
|
||||
<main>
|
||||
<h1>Blogfussel - für mehr Fussel im Blog</h1>
|
||||
<p>Hey! Hier sammel ich alles, was mir so durch den Kopf geht - von handfesten Tutorials und Code-Snippets über Freelancing-Stories
|
||||
bis hin zu News meiner Apps und random Gedanken. Manchmal ausführlich, manchmal nur kurz angerissen.</p>
|
||||
|
||||
<main class="margin-top">
|
||||
<ul class="category-list">
|
||||
<li>
|
||||
<NuxtLink class="inline-flex-row gap-sm side" to="/blog">
|
||||
<span class="chip" :class="{ 'dark' : route.query.category}">Alle {{ articles?.length }}</span>
|
||||
<span class="chip"
|
||||
:class="{ 'dark' : route.query.category && Object.keys(allCategoriesAndCount).includes(route.query.category as string)}">Alle {{
|
||||
articles?.length
|
||||
}}</span>
|
||||
</NuxtLink>
|
||||
</li>
|
||||
<li v-for="(count, category) in allCategoriesAndCount">
|
||||
|
@ -15,6 +22,8 @@
|
|||
</ul>
|
||||
<div class="grid margin-top-middle article-overview">
|
||||
<BlogCard v-for="article in firstTen" v-bind="makeBlogCard(article)"/>
|
||||
<div v-if="firstTen.length < 2"/>
|
||||
<div v-if="firstTen.length < 3"/>
|
||||
</div>
|
||||
</main>
|
||||
</section>
|
||||
|
@ -33,8 +42,8 @@ const { data: articles } = await useAsyncData('articles', () => queryCollection(
|
|||
)
|
||||
|
||||
const firstTen = computed(() => {
|
||||
if (route.query.category) {
|
||||
return articles.value?.filter(article => article.meta.category === route.query.category).slice(0, 10) ?? []
|
||||
if (route.query.category && Object.keys(allCategoriesAndCount.value).includes(route.query.category as Category)) {
|
||||
return articles.value?.filter(article => article.category === route.query.category).slice(0, 10) ?? []
|
||||
}
|
||||
return articles.value?.slice(0, 10) ?? []
|
||||
})
|
||||
|
@ -42,7 +51,7 @@ const firstTen = computed(() => {
|
|||
const allCategoriesAndCount = computed(() => {
|
||||
const categories = {} as Record<Category, number>
|
||||
articles.value?.forEach(article => {
|
||||
const category = article.meta.category as Category
|
||||
const category = article.category as Category
|
||||
if (category) {
|
||||
categories[category] = (categories[category] ?? 0) + 1
|
||||
}
|
||||
|
@ -55,9 +64,7 @@ const makeBlogCard = (article: BlogCollectionItem) => ({
|
|||
description: article.description,
|
||||
image: article.thumbnail as string,
|
||||
date: article.date as string,
|
||||
excerpt: article.excerpt as any,
|
||||
link: article.path,
|
||||
tags: article.tags as string[],
|
||||
category: article.category as Category,
|
||||
author: article.author as { name: string, image: string },
|
||||
})
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue