PronounsPage/components/blog/BlogEntriesList.vue
2025-01-01 23:52:44 +01:00

95 lines
3.2 KiB
Vue

<script setup lang="ts">
import Columnist from 'avris-columnist';
import type { RouteLocationRaw } from 'vue-router';
import useConfig from '~/composables/useConfig.ts';
import type { Post } from '~/server/blog.ts';
const props = defineProps<{
posts: string[] | Post[];
details?: boolean;
}>();
const { data: postsFull } = useAsyncData(`posts-${JSON.stringify(props.posts)}`, async () => {
if (!props.posts.length) {
return [];
}
if (typeof props.posts[0] === 'object') {
return props.posts as Post[];
}
return await $fetch('/api/blog', {
params: {
slugs: props.posts,
},
});
});
const config = useConfig();
const shortcuts: Record<string, string | undefined> = {};
if (config.blog && config.blog.shortcuts) {
for (const shortcut in config.blog.shortcuts) {
if (!config.blog.shortcuts.hasOwnProperty(shortcut)) {
continue;
}
shortcuts[config.blog.shortcuts[shortcut]] = shortcut;
}
}
const generateLink = (slug: string): RouteLocationRaw => {
const keepFullPath = config.blog?.keepFullPath || [];
return shortcuts[slug] !== undefined && !keepFullPath.includes(slug)
? `/${shortcuts[slug]}`
: { name: 'blogEntry', params: { slug } };
};
const entries = useTemplateRef<HTMLDivElement>('entries');
onMounted(async () => {
if (entries.value) {
const columnist = new Columnist(entries.value);
columnist.start();
}
});
</script>
<template>
<div ref="entries" class="columnist-wall row">
<div v-for="post in postsFull" class="columnist-column col-12 col-sm-6 col-md-4 mb-3">
<div class="card shadow">
<nuxt-link v-if="post.hero" :to="generateLink(post.slug)">
<img :src="post.hero.src" :class="['w-100', post.hero.class]" :alt="post.hero.alt" loading="lazy">
</nuxt-link>
<nuxt-link :to="generateLink(post.slug)" class="card-body text-center h4 p-3 mb-0 post-title">
<Spelling :text="post.title" />
</nuxt-link>
<div v-if="details" class="card-footer small">
<ul class="list-inline mb-0">
<li class="list-inline-item small">
<Icon v="calendar" />
{{ post.date }}
</li>
<li v-for="author in post.authors" class="list-inline-item">
<nuxt-link v-if="author.startsWith('@')" :to="`/${author}`" class="badge bg-light text-dark border">
<Icon v="collective-logo.svg" class="invertible" />
{{ author }}
</nuxt-link>
<span v-else class="badge bg-light text-dark border">
{{ author }}
</span>
</li>
</ul>
</div>
</div>
</div>
</div>
</template>
<style lang="scss" scoped>
.columnist-wall > .columnist-column {
transition: margin-top .2s ease-in-out;
}
.post-title {
text-wrap: balance;
}
</style>