280 lines
7.6 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
>
<div
v-for="article in filteredArticles"
:key="article.id"
class="article"
>
<NuxtLinkLocale
:to="localePath({ name: 'article-link', params: { link: article.slug } })"
class="article-link"
>
<div class="image-wrapper">
<NuxtImg
v-if="article.image?.url"
:src="article.image.url"
provider="strapi"
:alt="article.image.alternativeText"
format="webp"
class="article-image"
/>
<div class="overlay">
<h2>{{ article.header }}</h2>
</div>
<button class="btn mintBtn">{{ $t('pages.magazin.readmore') }}</button>
</div>
</NuxtLinkLocale>
</div>
</transition-group>
</section>
</div>
</template>
<script setup lang="ts">
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
width: 100%
max-width: 500px
border: 1px solid $beige
background: linear-gradient(to bottom right, white, $lightgrey)
border-radius: 1rem
position: relative
display: flex
flex-direction: column
align-items: flex-start
overflow: hidden
cursor: pointer
transition: transform 0.3s ease, opacity 0.3s ease
&:hover
transform: scale(1.05)
.article-enter-from,
.article-leave-to
opacity: 0
transform: scale(0.85)
.article-enter-active,
.article-leave-active
transition: all 0.3s ease
.article-link
position: relative
display: block
color: white
text-decoration: none
.image-wrapper
position: relative
width: 100%
height: 220px
border: 1px solid $lightgrey
.article-image
width: 100%
height: 500px
object-fit: cover
border-top-left-radius: 1rem
border-top-right-radius: 1rem
opacity: .6
button
position: absolute
bottom: .6rem
right: 0rem
border: 1px solid $darkgrey
font-size: 1rem
box-shadow: 1px 1px 4px 2px rgba(black, .2)
background-color: lighten($darkgrey, 10%)
letter-spacing: .05rem
.overlay
position: absolute
top: 0
left: 0
width: 80%
height: auto
min-height: 80%
background-image: linear-gradient(to bottom right, rgba(darken(white, 0), 1), rgba(darken($beige, 0), 0.9) )
margin: 0 20% 7rem 0
display: flex
flex-direction: column
align-items: center
justify-content: flex-start
padding: 1rem
border-top-left-radius: 1rem
border-bottom-right-radius: 50%
//border: 1px solid darken($beige, 10%)
//border-radius: .5rem
text-align: left
transition: .3s
box-shadow: 2px 2px 5px 3px rgba(black, .2)
h2
color: $darkgrey
font-size: 1rem
line-height: 140%
font-family: 'Mainfont-Bold'
margin: .2rem 1rem
//text-transform: uppercase
hyphens: auto
.mintBtn
background-color: $primaryColor
color: white
font-size: 0.9rem
font-family: 'Mainfont-Bold'
border: none
padding: 0.4rem 1rem
border-radius: 0.3rem
cursor: pointer
</style>