mirror of
https://github.com/ArthurDanjou/ui.git
synced 2026-01-19 06:21:46 +01:00
99 lines
2.8 KiB
Vue
99 lines
2.8 KiB
Vue
<script setup lang="ts">
|
|
import { kebabCase } from 'scule'
|
|
|
|
const route = useRoute()
|
|
|
|
const [{ data: page }, { data: surround }] = await Promise.all([
|
|
useAsyncData(kebabCase(route.path), () => queryCollection('blog').path(route.path).first()),
|
|
useAsyncData(`${kebabCase(route.path)}-surround`, () => {
|
|
return queryCollectionItemSurroundings('blog', route.path, {
|
|
fields: ['description']
|
|
}).order('date', 'DESC')
|
|
})
|
|
])
|
|
if (!page.value) {
|
|
throw createError({ statusCode: 404, statusMessage: 'Article not found', fatal: true })
|
|
}
|
|
|
|
const title = page.value.seo?.title || page.value.title
|
|
const description = page.value.seo?.description || page.value.description
|
|
|
|
useSeoMeta({
|
|
title,
|
|
description,
|
|
ogDescription: description,
|
|
ogTitle: title
|
|
})
|
|
|
|
if (page.value.image) {
|
|
defineOgImage({ url: page.value.image })
|
|
} else {
|
|
defineOgImageComponent('Docs', {
|
|
headline: 'Blog',
|
|
title,
|
|
description
|
|
})
|
|
}
|
|
|
|
const formatDate = (dateString: string) => {
|
|
return new Date(dateString).toLocaleDateString('en-US', {
|
|
year: 'numeric',
|
|
month: 'short',
|
|
day: 'numeric'
|
|
})
|
|
}
|
|
</script>
|
|
|
|
<template>
|
|
<UMain class="mt-20 px-2">
|
|
<UContainer class="relative min-h-screen">
|
|
<UPage v-if="page">
|
|
<ULink
|
|
to="/blog"
|
|
class="text-sm flex items-center gap-1"
|
|
>
|
|
<UIcon name="lucide:chevron-left" />
|
|
Blog
|
|
</ULink>
|
|
<div class="flex flex-col gap-3 mt-8">
|
|
<div class="flex text-xs text-muted items-center justify-center gap-2">
|
|
<span v-if="page.date">
|
|
{{ formatDate(page.date) }}
|
|
</span>
|
|
<span v-if="page.date && page.minRead">
|
|
-
|
|
</span>
|
|
<span v-if="page.minRead">
|
|
{{ page.minRead }} MIN READ
|
|
</span>
|
|
</div>
|
|
<NuxtImg
|
|
:src="page.image"
|
|
:alt="page.title"
|
|
class="rounded-lg w-full h-[400px] object-cover object-center max-w-5xl mx-auto"
|
|
/>
|
|
<h1 class="text-4xl text-center font-medium max-w-3xl mx-auto mt-4">
|
|
{{ page.title }}
|
|
</h1>
|
|
<p class="text-muted text-center max-w-2xl mx-auto">
|
|
{{ page.description }}
|
|
</p>
|
|
<div class="mt-4 flex justify-center flex-wrap items-center gap-6">
|
|
<UUser v-for="(author, index) in page.authors" :key="index" v-bind="author" :description="author.to ? `@${author.to.split('/').pop()}` : undefined" />
|
|
</div>
|
|
</div>
|
|
<UPageBody class="max-w-3xl mx-auto">
|
|
<ContentRenderer
|
|
v-if="page.body"
|
|
:value="page"
|
|
/>
|
|
|
|
<USeparator v-if="surround?.length" />
|
|
|
|
<UContentSurround :surround="surround" />
|
|
</UPageBody>
|
|
</UPage>
|
|
</UContainer>
|
|
</UMain>
|
|
</template>
|