magazin new categories

This commit is contained in:
Sabrina Hennrich 2025-06-20 15:36:08 +02:00
parent d2923187d5
commit bbe1f7382e
8 changed files with 218 additions and 554 deletions

View File

@ -140,14 +140,8 @@
} }
const navigationLinks = [ const navigationLinks = [
{ { routeKey: 'webagency', label: 'menu.webagency' },
routeKey: '', { routeKey: 'magazin', label: 'menu.menuMagazin' },
label: 'menu.webagency',
subNav: [
{ routeKey: 'webagency', label: 'menu.menuAbout' },
{ routeKey: 'magazin', label: 'menu.menuMagazin' }
]
},
{ {
routeKey: '', routeKey: '',
label: 'menu.services', label: 'menu.services',

View File

@ -1,436 +0,0 @@
<template>
<div
class="navigationBox"
:class="[
isMenuOpen ? 'menu-active' : '',
screenWidth < 1350 ? 'mobile' : 'desk'
]"
role="navigation"
aria-label="Hauptnavigation"
tabindex="0"
>
<div
class="closer"
role="button"
tabindex="0"
aria-label="Navigation schließen"
@click="toggleMenu"
@keydown.enter="toggleMenu"
/>
<nav
v-if="isMenuOpen || screenWidth > 1350"
:aria-expanded="screenWidth < 1350 ? 'true' : undefined"
@mouseleave="screenWidth >= 1350 && hideSubNav()"
>
<!-- <div class="mobilNavLogo">
<NuxtImg
v-if="screenWidth < 1350"
provider="strapi"
src="/uploads/DML_Logo_mint_negative_2024_9257db5430.svg"
alt="digimedialoop Logo"
width="120"
/>
</div> -->
<span
v-for="link in navigationLinks"
:key="link.routeKey"
class="main-nav-item"
@mouseenter="screenWidth >= 1350 && showSubNav(link.routeKey)"
@mouseleave="screenWidth >= 1350 && hideSubNav(link.routeKey)"
>
<NuxtLinkLocale
:to="link.routeKey"
class="main-nav-link"
:aria-haspopup="link.subNav && link.subNav.length > 0 ? 'true' : undefined"
:aria-expanded="isSubNavOpen === link.routeKey ? 'true' : 'false'"
@click="handleMobileClose"
>
{{ $t(link.label) }}
</NuxtLinkLocale>
<!-- PFEIL FÜR MOBILE UND TOGGLE -->
<button
v-if="link.subNav && link.subNav.length > 0 && screenWidth < 1350"
class="submenu-toggle"
@click.prevent="toggleMobileSubNav(link.routeKey)"
:aria-expanded="isMobileSubNavOpen === link.routeKey ? 'true' : 'false'"
aria-label="Untermenü öffnen/schließen"
>
<svg
:class="{ 'open': isMobileSubNavOpen === link.routeKey }"
xmlns="http://www.w3.org/2000/svg"
width="12"
height="8"
viewBox="0 0 12 8"
fill="none"
>
<path d="M1 1L6 6L11 1" stroke="currentColor" stroke-width="2"/>
</svg>
</button>
<!-- SUBNAVIGATION -->
<ul
v-if="link.subNav && link.subNav.length > 0"
v-show="(screenWidth >= 1350 && isSubNavOpen === link.routeKey) || (screenWidth < 1350 && isMobileSubNavOpen === link.routeKey)"
class="sub-nav"
>
<li v-for="subLink in link.subNav" :key="subLink.routeKey" class="sub-nav-item">
<NuxtLinkLocale
:to="subLink.routeKey"
class="sub-nav-link"
@click="handleMobileClose"
>
{{ $t(subLink.label) }}
</NuxtLinkLocale>
</li>
</ul>
</span>
<a
class="menu_link" href="#"
role="button"
aria-label="Kontaktformular öffnen"
@click="toggleContactBubble"
>
{{ $t('contact') }}
</a>
<SettingsPanel v-if="screenWidth < 1350" />
</nav>
</div>
</template>
<script setup>
import { ref, computed } from 'vue'
import { useMainStore } from '@/stores/main'
const mainStore = useMainStore()
const screenWidth = computed(() => mainStore.screenWidth)
const scrollPosition = computed(() => mainStore.scrollPosition)
const isSubNavOpen = ref(null) // speichert, welches Submenü auf Desktop offen ist
const isMobileSubNavOpen = ref(null) // Trackt, welches Submenü auf Mobile offen ist
function toggleMobileSubNav(routeKey) {
if (screenWidth.value < 1350) {
isMobileSubNavOpen.value = isMobileSubNavOpen.value === routeKey ? null : routeKey
}
}
// Funktionen zum Öffnen und Schließen der Subnavigation auf Desktop
function showSubNav(routeKey) {
isSubNavOpen.value = routeKey
}
function hideSubNav(routeKey) {
if (isSubNavOpen.value === routeKey) {
isSubNavOpen.value = null
}
}
const isMenuOpen = computed(() => mainStore.menuOpen)
const toggleMenu = () => mainStore.toggleMenu()
const toggleContactBubble = () => mainStore.toggleContactBubble()
const handleMobileClose = () => {
if (screenWidth.value < 1350 && isMenuOpen.value) {
toggleMenu()
} else {
hideSubNav()
}
}
const navigationLinks = [
{
routeKey: 'webagency',
label: 'webagency'
},
{
routeKey: '',
label: 'services',
subNav: [
{ routeKey: 'services-cms', label: 'menuCms' },
{ routeKey: 'services-seo', label: 'menuSEO' },
{ routeKey: 'services-accessibility', label: 'menuAccessibility' },
{ routeKey: 'services-ai', label: 'menuAi' },
]
},
{
routeKey: '',
label: 'sectors',
subNav: [
{ routeKey: 'sectors-schools', label: 'menuSchools' },
{ routeKey: 'sectors-film', label: 'menuFilm' }
]
},
{ routeKey: 'references', label: 'references' }
]
</script>
<style lang="sass">
.navigationBox
position: relative
display: flex
align-items: center
justify-content: flex-end
width: 80%
transition: .8s
margin-top: 1.2rem // -1rem
nav
display: block
z-index: 102
//background: linear-gradient(to right, rgba($lightgrey, 0.8), rgba(white, 0.9), rgba(white, 0.9))
background: white
border: 1px solid adjust-color($beige, $lightness: 5%)
padding: 1rem 2rem
text-align: center
border-radius: 1rem
margin: 4.8rem 1rem 0 1rem
transition: .8s
a
margin: 0 1.2rem
text-decoration: none
color: $darkgrey
text-transform: uppercase
font-family: 'Comfortaa-Bold'
font-size: 1.1rem
letter-spacing: .05rem
transition: .6s
display: inline-block
&:hover
transform: scale(1.15)
background-image: radial-gradient(rgba(white, .5), rgba(white, .1))
box-shadow: 0 0 10px 10px rgba(white, 0.2)
border-radius: 10px
&.desk
.sub-nav
display: block
position: absolute
top: 3rem
right: 5%
background-color: rgba(white, .95)
padding: 2rem 2rem 1rem 2rem
text-align: left
cursor: pointer
border-bottom-left-radius: 1rem
border-bottom-right-radius: 1rem
list-style: none
.sub-nav-item
padding: 0 0 1.5rem 0
.sub-nav-link
position: relative
margin-left: 1.2rem
&::before
content: ''
width: .5rem
height: .4rem
background-color: rgba($primaryColor, .9)
border-radius: $loopShape
position: absolute
top: .4rem
left: -1.3rem
border-radius: 20px
&:hover
transform: scale(1.025)
&.mobile
top: 0
&.navigationBox
display: block
position: relative
background-color: $darkgrey
width: 4rem
height: 4rem
z-index: 8
border-radius: 50%
margin-right: 5vw
margin-top: 2rem
.closer
position: relative
width: 100%
height: 4rem
&::after, &::before
position: absolute
content: ''
width: 2rem
z-index: 12
height: 5px
border-radius: 4px
background-color: white
right: 75%
transform: translateX(100%)
transition: .8s
&::before
top: 35%
&::after
top: 55%
nav
display: none
background-image: none
background: transparent
border: none
padding-top: 0rem !important
.submenu-toggle
background: none
border: none
padding: 0 0 0 0.5rem
margin-top: -1rem
cursor: pointer
display: inline-flex
align-items: center
color: white
transition: transform 0.3s ease
svg
transition: transform 0.3s ease
&.open svg,
svg.open
transform: rotate(180deg) // Pfeil zeigt nach oben, wenn offen
.sub-nav
overflow: hidden
max-height: 0
opacity: 0
transition: max-height 0.4s ease, opacity 0.4s ease
&.open
max-height: 500px
opacity: 1
.sub-nav
list-style: none
padding-left: 1.8rem
margin: 0
.sub-nav-item
padding-left: 1rem
margin-bottom: 0.2rem
.sub-nav-link
color: white
font-size: 1rem !important
line-height: 1.5rem
padding: 0.5rem 1.5rem
&:hover
&::before
content: ''
width: .5rem
height: .4rem
background-color: rgba($primaryColor, .9)
border-radius: $loopShape
position: absolute
top: 1rem
left: 0
border-radius: 20px
.menu_link
margin-left: 1.5rem
transition: .8s
&:hover
transform: scale(1.06)
background-image: radial-gradient(rgba($primaryColor, .1), transparent, transparent)
box-shadow: 0 0 0 0 transparent
border-radius: 20px
a, .menu_link
display: block
color: white
text-align: left
margin-bottom: .2rem
padding: 1rem 2.8rem .5rem 1.2rem
position: relative
font-size: 1.25rem !important
width: auto
max-width: 18rem
text-transform: uppercase
font-family: 'Mainfont-Bold'
&::before
content: ''
width: .8rem
height: .6rem
background-color: rgba($primaryColor, .9)
border-radius: $loopShape
position: absolute
top: 1.5rem
left: -.5rem
border-radius: 20px
&:hover
transform: scale(1.06)
background-image: radial-gradient(rgba($primaryColor, .1), transparent, transparent)
box-shadow: 0 0 0 0 transparent
border-radius: 20px
&.menu-active
width: 100vw
height: 98vh
border-radius: 5px
margin: 0
background-color: rgba($darkgrey, .97)
.closer
&::before, &::after
top: 2rem
right: 2rem
&::before
transform: rotate(45deg)
&::after
transform: rotate(-45deg)
nav
display: block
padding: 10vh 0
margin: 0 5vw
.navigationBox
margin-top: .5rem
nav
display: flex
margin: 2.5rem 0 0 0
padding: 1rem .5rem
border-top-right-radius: 0
border-top-left-radius: 0
border-bottom-left-radius: 50px
border-bottom-right-radius: 0
background: transparent
border: 1px solid transparent
a
font-size: 1rem
font-weight: bold
margin: 0 .8rem
&.desk
.sub-nav
top: 1.5rem
right: 2%
background-color: transparent
background-image: linear-gradient(to bottom, transparent 0%, white 15%)
</style>

View File

@ -120,7 +120,7 @@ export const i18nPages = {
tr: '/kosullar' tr: '/kosullar'
}, },
magazin: { magazin: {
de: '/wissenswertes', de: '/magazin',
en: '/magazine', en: '/magazine',
fr: '/magazine', fr: '/magazine',
it: '/magazine', it: '/magazine',

View File

@ -5,7 +5,7 @@
"menu": { "menu": {
"webagency": "Webagentur", "webagency": "Webagentur",
"menuAbout": "Über uns", "menuAbout": "Über uns",
"menuMagazin": "Wissenswertes", "menuMagazin": "Magazin",
"services": "Leistungen", "services": "Leistungen",
"sectors": "Branchen", "sectors": "Branchen",
"menuCms": "Headless Content-Management-System (CMS)", "menuCms": "Headless Content-Management-System (CMS)",

View File

@ -1,6 +1,6 @@
<template> <template>
<div v-if="article" class="article"> <div v-if="article" class="article">
<SideBarNaviSlider link="/wissenswertes"> <SideBarNaviSlider link="/magazin">
{{ $t('pages.article.artikelUebersicht') }} {{ $t('pages.article.artikelUebersicht') }}
</SideBarNaviSlider> </SideBarNaviSlider>

View File

@ -2,25 +2,46 @@
<div class="knowledgeBox topSpace"> <div class="knowledgeBox topSpace">
<section class="teaserBox"> <section class="teaserBox">
<div class="container"> <div class="container">
<h1>Wissenswertes für digitale Entscheider</h1> <h1>Digital Insights Magazin</h1>
<h2>Webdesign und Webentwicklung, SEO, Performance & AI</h2> <h2>Wissenswertes rund um moderne Weblösungen</h2>
<p>In unserem Fachmagazin erfahren Sie, wie moderne Webseiten aufgebaut sein müssen, <p>Hier finden Sie praxisnahe Beiträge zu Technik, Strategie und Gestaltung im Web. Wir bieten wertvolle Impulse und aktuelles Wissen,
um technisch, inhaltlich und strategisch zu überzeugen. damit Sie gut informiert sind und fundierte Entscheidungen für Ihre Webprojekte treffen können.
Themen wie <b>KI-gestütztes SEO (AI-SEO)</b>, <b>nachhaltige Webentwicklung</b>, <b>Barrierefreiheit</b>, </p>
<b>Ladezeit-Optimierung</b>, <b>User Experience</b> und <b>Headless CMS</b> zeigen, worauf es heute im Webdesign wirklich ankommt.</p> <div class="selectionZone">
<p>Entdecken Sie <b>praxisnahe Insights und zukunftsorientierte Lösungen</b> für mehr Sichtbarkeit, Effizienz und Erfolg im digitalen Raum.</p> <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> </div>
</section> </section>
<section class="articleBox container"> <section class="articleBox container">
<div class="grid"> <transition-group
name="article"
tag="div"
class="grid"
appear
>
<div <div
v-for="article in articles" v-for="article in filteredArticles"
:key="article.id" :key="article.id"
class="article" class="article"
> >
<NuxtLinkLocale
<NuxtLinkLocale :to="localePath({ name: 'article-link', params: { link: article.slug } })" class="article-link"> :to="localePath({ name: 'article-link', params: { link: article.slug } })"
class="article-link"
>
<div class="image-wrapper"> <div class="image-wrapper">
<NuxtImg <NuxtImg
v-if="article.image?.url" v-if="article.image?.url"
@ -32,29 +53,26 @@
/> />
<div class="overlay"> <div class="overlay">
<h2>{{ article.header }}</h2> <h2>{{ article.header }}</h2>
</div> </div>
<button class="btn mintBtn">{{ $t('pages.magazin.readmore') }}</button> <button class="btn mintBtn">{{ $t('pages.magazin.readmore') }}</button>
</div> </div>
</NuxtLinkLocale> </NuxtLinkLocale>
</div>
</div> </div>
</transition-group>
</section> </section>
</div> </div>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { watch } from 'vue'
import { useMainStore } from '@/stores/main' import { useMainStore } from '@/stores/main'
import { storeToRefs } from 'pinia' import { storeToRefs } from 'pinia'
import { useLocalePath } from '#i18n' import { useLocalePath } from '#i18n'
const localePath = useLocalePath() const localePath = useLocalePath()
const mainStore = useMainStore() const mainStore = useMainStore()
const { articles } = storeToRefs(mainStore) const { articles, categories } = storeToRefs(mainStore)
const truncateText = (text: string, length = 200) => const truncateText = (text: string, length = 200) =>
text?.length > length ? text.substring(0, length) + '…' : text text?.length > length ? text.substring(0, length) + '…' : text
@ -63,6 +81,29 @@ const currentDomain = typeof window !== 'undefined'
? window.location.origin ? window.location.origin
: 'https://www.digimedialoop.de' : '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 // SEO: JSON-LD für Artikelübersicht
watch(articles, (newVal) => { watch(articles, (newVal) => {
@ -90,19 +131,52 @@ watch(articles, (newVal) => {
<style lang="sass"> <style lang="sass">
.articleBox .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 display: flex
justify-content: center justify-content: center
width: 100% width: (9)0%
.grid .grid
display: grid display: grid
grid-template-columns: repeat(auto-fill, minmax(320px, 1fr)) grid-template-columns: repeat(auto-fill, minmax(280px, 1fr))
gap: 2rem gap: 2.5rem
justify-content: start justify-content: start
width: 100% width: 100%
max-width: 100% max-width: 100%
margin: 0 auto margin: 0 auto
transition: all 0.3s ease-in-out // weichere Umordnung der Items
.article .article
width: 100% width: 100%
@ -110,15 +184,27 @@ watch(articles, (newVal) => {
border: 1px solid $beige border: 1px solid $beige
background: linear-gradient(to bottom right, white, $lightgrey) background: linear-gradient(to bottom right, white, $lightgrey)
border-radius: 1rem border-radius: 1rem
transition: .5s
position: relative position: relative
display: flex display: flex
flex-direction: column flex-direction: column
align-items: flex-start align-items: flex-start
overflow: hidden overflow: hidden
cursor: pointer
transition: transform 0.3s ease, opacity 0.3s ease
&:hover &:hover
transform: scale(1.05) 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 .article-link
position: relative position: relative
display: block display: block
@ -128,7 +214,7 @@ watch(articles, (newVal) => {
.image-wrapper .image-wrapper
position: relative position: relative
width: 100% width: 100%
height: 280px height: 220px
border: 1px solid $lightgrey border: 1px solid $lightgrey
.article-image .article-image
@ -143,10 +229,10 @@ watch(articles, (newVal) => {
position: absolute position: absolute
bottom: .6rem bottom: .6rem
right: 0rem right: 0rem
border: 1px solid darken($primaryColor, 30%) border: 1px solid $darkgrey
font-size: 1rem font-size: 1rem
box-shadow: 1px 1px 4px 2px rgba(black, .2) box-shadow: 1px 1px 4px 2px rgba(black, .2)
background-color: darken($primaryColor, 15%) background-color: lighten($darkgrey, 10%)
letter-spacing: .05rem letter-spacing: .05rem
@ -156,8 +242,8 @@ watch(articles, (newVal) => {
left: 0 left: 0
width: 80% width: 80%
height: auto height: auto
min-height: 60% min-height: 80%
background-image: linear-gradient(to bottom right, rgba(255, 255, 255, 1), rgba(255, 255, 255, 0.96) ) background-image: linear-gradient(to bottom right, rgba(darken(white, 0), 1), rgba(darken($beige, 0), 0.9) )
margin: 0 20% 7rem 0 margin: 0 20% 7rem 0
display: flex display: flex
flex-direction: column flex-direction: column
@ -165,7 +251,8 @@ watch(articles, (newVal) => {
justify-content: flex-start justify-content: flex-start
padding: 1rem padding: 1rem
border-top-left-radius: 1rem border-top-left-radius: 1rem
border-bottom-right-radius: 1rem border-bottom-right-radius: 50%
//border: 1px solid darken($beige, 10%)
//border-radius: .5rem //border-radius: .5rem
text-align: left text-align: left
transition: .3s transition: .3s
@ -173,11 +260,13 @@ watch(articles, (newVal) => {
h2 h2
color: black color: $darkgrey
font-size: 1.1rem font-size: 1rem
line-height: 140% line-height: 140%
font-family: 'Mainfont-Bold' font-family: 'Mainfont-Bold'
margin: .2rem 1rem margin: .2rem 1rem
//text-transform: uppercase
hyphens: auto
.mintBtn .mintBtn
background-color: $primaryColor background-color: $primaryColor

View File

@ -144,7 +144,7 @@ const mainStore = useMainStore();
const { projects, companyinfo } = storeToRefs(mainStore) const { projects, companyinfo } = storeToRefs(mainStore)
const navigateToArticle = () => { const navigateToArticle = () => {
router.push('/wissenswertes/artikel/design-und-inhalt-sauber-getrennt-warum-headless-webdesign-die-beste-wahl-fuer-moderne-unternehmen-ist'); router.push('/artikel/design-und-inhalt-sauber-getrennt-warum-headless-webdesign-die-beste-wahl-fuer-moderne-unternehmen-ist');
}; };
const projectItems = computed(() => { const projectItems = computed(() => {

View File

@ -93,6 +93,10 @@ interface NewsArticle {
name: string name: string
// optional: weitere Felder aus dem Team-Modell // optional: weitere Felder aus dem Team-Modell
} | null } | null
categories?: {
id: number
name: string
}[]
} }
interface ContactData { interface ContactData {
@ -118,6 +122,7 @@ export const useMainStore = defineStore('main', {
customers: [] as Customer[], customers: [] as Customer[],
projects: [] as CustomerProject[], projects: [] as CustomerProject[],
articles: [] as NewsArticle[], articles: [] as NewsArticle[],
categories: [] as { id: number; name: string }[],
dataFetched: false, dataFetched: false,
loading: false, loading: false,
error: null as { message: string; stack?: string } | null, error: null as { message: string; stack?: string } | null,
@ -211,7 +216,7 @@ export const useMainStore = defineStore('main', {
const { public: cfg } = useRuntimeConfig() const { public: cfg } = useRuntimeConfig()
try { try {
const [companyRes, pagesRes, customersRes, projectsRes, articlesRes] = await Promise.all([ const [companyRes, pagesRes, customersRes, projectsRes, articlesRes, categoriesRes] = await Promise.all([
$fetch(`${cfg.cmsBaseUrl}/api/companyinfo?populate=*`, { $fetch(`${cfg.cmsBaseUrl}/api/companyinfo?populate=*`, {
headers: { Authorization: `Bearer ${cfg.cmsToken}` }, headers: { Authorization: `Bearer ${cfg.cmsToken}` },
}), }),
@ -224,7 +229,10 @@ export const useMainStore = defineStore('main', {
$fetch(`${cfg.cmsBaseUrl}/api/references?populate=projectImages,Technologien,customer&sort=launchDate:desc`, { $fetch(`${cfg.cmsBaseUrl}/api/references?populate=projectImages,Technologien,customer&sort=launchDate:desc`, {
headers: { Authorization: `Bearer ${cfg.cmsToken}` }, headers: { Authorization: `Bearer ${cfg.cmsToken}` },
}), }),
$fetch(`${cfg.cmsBaseUrl}/api/newsarticels?populate=image,SEO,author&locale=all&sort=createdAt:desc`, { $fetch(`${cfg.cmsBaseUrl}/api/newsarticels?populate=image,SEO,categories,author&locale=all&sort=createdAt:desc`, {
headers: { Authorization: `Bearer ${cfg.cmsToken}` },
}),
$fetch(`${cfg.cmsBaseUrl}/api/magazin-cats?populate=*&locale=all`, {
headers: { Authorization: `Bearer ${cfg.cmsToken}` }, headers: { Authorization: `Bearer ${cfg.cmsToken}` },
}), }),
]) ])
@ -348,9 +356,18 @@ export const useMainStore = defineStore('main', {
name: a.author.data.attributes.name, name: a.author.data.attributes.name,
} }
: null, : null,
categories: a.categories?.data?.map((c: any) => ({
id: c.id,
name: c.attributes.category,
})) ?? [],
} }
}) })
this.categories = categoriesRes.data.map((item: any) => ({
id: item.id,
name: item.attributes.category,
}))
this.dataFetched = true this.dataFetched = true
} catch (err) { } catch (err) {
const e = err as Error const e = err as Error