I'm having this list of blogposts called articles
that I call from the content folder.
async asyncData ({ $content }) {
const articles = await $content('', { deep: true })
// .where({ cat: 'A' })
.only(['title', 'description', 'img', 'slug', 'cat'])
.sortBy('createdAt', 'asc')
.fetch()
return { articles }
}
This fetches all of my articles and returns a list of them.
Now, I would like to populate my different categories in my website following this structure :
<template>
<div class="container">
<div v-for="article in articles" :key="article">
{{ article.title }}
</div>
<pre> {{ articles }}</pre>
<div v-for="accordion in accordions" :key="accordion.title" class="l">
<Item>
<template #title>
{{ accordion.title }}
</template>
<template #content>
<div> {{ accordion.text }}</div>
</template>
</Item>
</div>
<!-- here goes R -->
<div class="r" />
</div>
</template>
<script>
import Item from '../components/List-item.vue'
export default {
components: { Item },
async asyncData ({ $content }) {
const articles = await $content('', { deep: true })
// .where({ cat: 'A' })
.only(['title', 'description', 'img', 'slug', 'cat'])
.sortBy('createdAt', 'asc')
.fetch()
return { articles }
},
data () {
return {
accordions: [
{
title: 'A',
text: 'Projects from content/A'
},
{
title: 'B',
text: 'Projects from content/B'
},
{
title: 'C',
text: 'Projects from content/C'
}
]
}
</script>
It's using slots from a componenent :
<template>
<div class="wrapper">
<div
:class="{ active: isActive }"
@click="toggle"
>
<a class="title">
<slot name="title" />
</a>
<div v-show="show" :class="{ active: isActive }" class="content">
<slot name="content" />
</div>
</div>
</div>
</template>
I've nested my array into a v-for, but I don't know how to dynamically group that array by URL or by category.
This is how I would achieve that while keeping it fully dynamic and less error prone.
<template>
<div class="container">
<div v-for="(filteredArticles, categoryKey) in groupedCategories" :key="categoryKey">
<h2>{{ categoryKey }}</h2>
<list-item v-for="article in filteredArticles" :key="article.slug">
<template #title>
{{ article.title }}
</template>
<template #content>
<div> {{ article.description }}</div>
</template>
<br>
</list-item>
<hr>
</div>
</div>
</template>
<script>
export default {
async asyncData ({ $content }) {
const articles = await $content('', { deep: true })
.only(['title', 'description', 'img', 'slug', 'cat', 'dir'])
.sortBy('createdAt', 'asc')
.fetch()
return { articles }
},
computed: {
groupedCategories () {
return this.articles.reduce((finalObject, obj) => {
const directory = obj.dir
finalObject[directory] ?? (finalObject[directory] = [])
finalObject[directory].push(obj)
return finalObject
}, {})
}
}
}
</script>
The .only(['dir'])
gives us all the directories aka /A
, /B
etc, so that it's fully dynamic and not relying on OP's needing to remember to put a cat
in the .md
file.
It is generated for any kind of content as shown here and avoids us some ugly and complex regex subgroups.
Then we're using a reduce
to properly group all the articles depending on their respective directories, filtering on dir
as explained before.
The Logical Nullish Assignment operator in the documentation didn't worked for me for some reason, hence I replaced it with it's alternative aka finalObject[directory] ?? (finalObject[directory] = [])
to basically set a new array in case of a non-existing key.
The idea is to get an object with a key for each directory, itself containing an array of all the articles.
This is how it looks locally + Vue devtools.
A github repo can be found here: https://github.com/kissu/AppPortfolio
Useful since it's a bit cumbersome to mock all kind of .md
files.
A deployed version can be found here: https://papaya-truffle-df823c.netlify.app/