186 lines
4.8 KiB
Vue
186 lines
4.8 KiB
Vue
<template>
|
||
<div class="knowledgeBox topSpace">
|
||
<section class="teaserBox">
|
||
<div class="container">
|
||
<h1>Digital Insights Magazin</h1>
|
||
<h2>Wissenswertes rund um moderne Weblösungen</h2>
|
||
<p>Hier finden Sie praxisnahe Beiträge zu Technik, Strategie und Gestaltung im Web. Wir bieten wertvolle Impulse und aktuelles Wissen,
|
||
damit Sie gut informiert sind und fundierte Entscheidungen für Ihre Webprojekte treffen können.
|
||
</p>
|
||
<div class="selectionZone">
|
||
<button
|
||
:class="{ active: isAllSelected }"
|
||
@click="selectAll"
|
||
>
|
||
Alle
|
||
</button>
|
||
<button
|
||
v-for="category in categories"
|
||
:key="category.id"
|
||
:class="{ active: selectedCategories.has(category.id) }"
|
||
@click="toggleCategory(category.id)"
|
||
>
|
||
{{ category.name }}
|
||
</button>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
<section class="articleBox container">
|
||
<transition-group
|
||
name="article"
|
||
tag="div"
|
||
class="grid"
|
||
appear
|
||
>
|
||
<ArticleCard
|
||
v-for="article in filteredArticles"
|
||
:key="article.id"
|
||
:header="article.header"
|
||
:image="article.image"
|
||
:link="localePath({ name: 'article-link', params: { link: article.slug } })"
|
||
:readmore-text="$t('pages.magazin.readmore')"
|
||
/>
|
||
</transition-group>
|
||
|
||
</section>
|
||
|
||
</div>
|
||
</template>
|
||
|
||
|
||
<script setup lang="ts">
|
||
definePageMeta({
|
||
sitemap: {
|
||
lastmod: '2025-06-23', // ISO 8601 – oder dynamisch generieren
|
||
changefreq: 'daily', // optional
|
||
priority: 1 // optional
|
||
}
|
||
})
|
||
|
||
import { useMainStore } from '@/stores/main'
|
||
import { storeToRefs } from 'pinia'
|
||
import { useLocalePath } from '#i18n'
|
||
const localePath = useLocalePath()
|
||
|
||
const mainStore = useMainStore()
|
||
const { articles, categories } = storeToRefs(mainStore)
|
||
|
||
const truncateText = (text: string, length = 200) =>
|
||
text?.length > length ? text.substring(0, length) + '…' : text
|
||
|
||
const currentDomain = typeof window !== 'undefined'
|
||
? window.location.origin
|
||
: 'https://www.digimedialoop.de'
|
||
|
||
const selectedCategories = ref<Set<number>>(new Set())
|
||
|
||
const isAllSelected = computed(() => selectedCategories.value.size === 0)
|
||
|
||
function toggleCategory(categoryId: number) {
|
||
if (selectedCategories.value.has(categoryId)) {
|
||
selectedCategories.value.delete(categoryId)
|
||
} else {
|
||
selectedCategories.value.add(categoryId)
|
||
}
|
||
}
|
||
|
||
function selectAll() {
|
||
selectedCategories.value.clear()
|
||
}
|
||
|
||
const filteredArticles = computed(() => {
|
||
if (isAllSelected.value) return articles.value
|
||
return articles.value.filter(article => {
|
||
if (!article.categories || article.categories.length === 0) return false
|
||
return article.categories.some(cat => selectedCategories.value.has(cat.id))
|
||
})
|
||
})
|
||
|
||
// SEO: JSON-LD für Artikelübersicht
|
||
watch(articles, (newVal) => {
|
||
if (newVal?.length) {
|
||
useHead({
|
||
script: [
|
||
{
|
||
type: 'application/ld+json',
|
||
children: JSON.stringify({
|
||
"@context": "https://schema.org",
|
||
"@type": "ItemList",
|
||
itemListElement: newVal.map((article, index) => ({
|
||
"@type": "ListItem",
|
||
position: index + 1,
|
||
url: `${currentDomain}/wissenswertes/artikel/${article.slug}`,
|
||
name: article.header,
|
||
}))
|
||
})
|
||
}
|
||
]
|
||
})
|
||
}
|
||
}, { immediate: true })
|
||
</script>
|
||
|
||
|
||
<style lang="sass">
|
||
.knowledgeBox
|
||
h1
|
||
margin: 2rem 0 0 0
|
||
h2
|
||
margin: 0 0 0 0
|
||
.selectionZone
|
||
border: 1px solid $lightgrey
|
||
border-radius: 1rem
|
||
padding: 1rem 1.5rem 0 1.5rem
|
||
background-color: lighten($beige, 5%)
|
||
margin: 0 0 4rem 0
|
||
button
|
||
all: unset
|
||
background-color: white
|
||
padding: .5rem 1.5rem
|
||
border-radius: .8rem
|
||
margin: 0 1rem 1rem 0
|
||
box-shadow: 1px 1px 1px 0 rgba(black, .3)
|
||
border: 1px solid darken($lightgrey, 8%)
|
||
transition: .5s
|
||
cursor: pointer
|
||
|
||
&:hover
|
||
transform: scale(1.05)
|
||
|
||
&.active
|
||
font-family: 'Mainfont-Bold'
|
||
box-shadow: 0 0 2px 0 rgba(black, .3)
|
||
background-color: darken($lightgrey, 10%)
|
||
border: 1px solid darken($lightgrey, 25%)
|
||
|
||
.articleBox
|
||
display: flex
|
||
justify-content: center
|
||
width: (9)0%
|
||
|
||
|
||
.grid
|
||
display: grid
|
||
grid-template-columns: repeat(auto-fill, minmax(280px, 1fr))
|
||
gap: 2.5rem
|
||
justify-content: start
|
||
width: 100%
|
||
max-width: 100%
|
||
margin: 0 auto
|
||
transition: all 0.3s ease-in-out // weichere Umordnung der Items
|
||
|
||
|
||
|
||
.article-enter-from,
|
||
.article-leave-to
|
||
opacity: 0
|
||
transform: scale(0.85)
|
||
|
||
.article-enter-active,
|
||
.article-leave-active
|
||
transition: all 0.3s ease
|
||
|
||
|
||
|
||
</style> |