add support for blog
This commit is contained in:
@@ -0,0 +1,26 @@
|
||||
<template>
|
||||
<template v-if="post">
|
||||
<NuxtLink class="project-card" :to="post.path">
|
||||
<img :src="baseUrl + '/portal/f/assets/' + post.coverImage" :alt="post?.title + '’s cover image'"/>
|
||||
<div class="project-card-content">
|
||||
<h3>{{ post.title }}</h3>
|
||||
<p :title="post.description">{{ post.description }}</p>
|
||||
<p class="mt-4 text-xs" :title="useFormatDate(post.dateUpdated)">{{ useRelativeDate(post.dateUpdated) }}</p>
|
||||
</div>
|
||||
</NuxtLink>
|
||||
</template>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
const config = useRuntimeConfig();
|
||||
const baseUrl = config.public.baseUrl
|
||||
import { useFormatDate } from '~/composables/formatDate';
|
||||
import { useRelativeDate } from '~/composables/relativeDate';
|
||||
import type { PostsCollectionItem } from '@nuxt/content'
|
||||
|
||||
|
||||
|
||||
defineProps<{
|
||||
post: PostsCollectionItem
|
||||
}>()
|
||||
</script>
|
||||
@@ -0,0 +1,26 @@
|
||||
<template>
|
||||
<section class="project-cards">
|
||||
<template v-for="post in posts" :key="post.id">
|
||||
<PostCard :post="post" />
|
||||
</template>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
const route = useRoute();
|
||||
const currentRoute = route.path
|
||||
const props = defineProps<{
|
||||
limit?: number | null
|
||||
}>()
|
||||
const fetchLimit = props.limit ?? undefined
|
||||
const { data: posts } = await useAsyncData(
|
||||
`${currentRoute}-blog`,
|
||||
async () => {
|
||||
let query = queryCollection('posts').order('dateUpdated', 'DESC')
|
||||
if (fetchLimit) {
|
||||
query = query.limit(fetchLimit)
|
||||
}
|
||||
return query.all()
|
||||
}
|
||||
)
|
||||
</script>
|
||||
@@ -0,0 +1,11 @@
|
||||
import dayjs from 'dayjs'
|
||||
import localizedFormat from 'dayjs/plugin/localizedFormat'
|
||||
import 'dayjs/locale/th'
|
||||
import 'dayjs/locale/en'
|
||||
|
||||
dayjs.extend(localizedFormat)
|
||||
|
||||
export const useFormatDate = (date: string) => {
|
||||
const localizedDayjs = dayjs(date).locale('en')
|
||||
return localizedDayjs.format('D MMMM YYYY - HH:mm')
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
import dayjs from 'dayjs'
|
||||
import relativeTime from 'dayjs/plugin/relativeTime'
|
||||
import 'dayjs/locale/en'
|
||||
|
||||
dayjs.extend(relativeTime)
|
||||
|
||||
export const useRelativeDate = (date: string) => {
|
||||
dayjs.locale('en')
|
||||
return dayjs().to(dayjs(date))
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
<template>
|
||||
<!-- <div class="page">
|
||||
<div>
|
||||
<img class="aspect-video w-full h-full object-cover rounded-[calc(var(--ui-radius)*1.5)] mb-12" :alt="post?.title" :src="post?.coverImage">
|
||||
<ContentHeading :data="post"/>
|
||||
</div>
|
||||
<div>
|
||||
<div class="flex not-md:flex-col-reverse gap-2">
|
||||
<article class="prose prose-zinc dark:prose-invert w-full max-w-[48rem]">
|
||||
<ContentRenderer v-if="post" :value="post"/>
|
||||
{{ post ? post : 'wtf' }}
|
||||
</article>
|
||||
<div class="flex h-fit md:sticky top-16">
|
||||
<BlogToC :toc="post?.body?.toc?.links"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div> -->
|
||||
<main>
|
||||
<article class="article">
|
||||
<section class="web-hero relative web-hero-bg bg-cover " :style="`background-image: url('${baseUrl + '/portal/f/assets/' + post?.coverImage}');`" aria-labelledby="hero" aria-describedby="hero-desc">
|
||||
<div class="absolute inset-0 bg-(--color-deep-semidark)/80"></div>
|
||||
<h1 id="hero" class="font-hero z-[1]">{{ post?.title }}</h1>
|
||||
<p id="hero-desc" class="font-hero-desc z-[1]">{{ post?.description }}</p>
|
||||
</section>
|
||||
<section class="web-section" aria-labelledby="post-content" aria-describedby="post-content-desc">
|
||||
<div class="prose">
|
||||
<ContentRenderer v-if="post" :value="post"/>
|
||||
{{ post ? '' : 'Loading...' }}
|
||||
</div>
|
||||
</section>
|
||||
</article>
|
||||
</main>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
const config = useRuntimeConfig();
|
||||
const baseUrl = config.public.baseUrl
|
||||
const route = useRoute()
|
||||
|
||||
const { data: post } = await useAsyncData(route.path, () => {
|
||||
return queryCollection('posts').path(route.path).first()
|
||||
})
|
||||
|
||||
const ogUrl = `${config.public.baseUrl}${route.path}`
|
||||
useHead({
|
||||
title: post.value?.title || 'Untitled blog post',
|
||||
meta: [
|
||||
{ name: 'description', content: post.value?.description || 'A blog post with no description provided.' },
|
||||
{ property: 'og:title', content: `${post.value?.title || 'Untitled blog post'} · ${config.public.siteName}`},
|
||||
{ property: 'og:description', content: post.value?.description || 'A blog post with no description provided.' },
|
||||
{ property: 'og:url', content: ogUrl },
|
||||
{ property: 'og:type', content: 'article' },
|
||||
{ name: 'twitter:title', content: `${post.value?.title || 'Untitled blog post'} · ${config.public.siteName}` },
|
||||
{ name: 'twitter:description', content: post.value?.description || 'A blog post with no description provided.' }
|
||||
]
|
||||
})
|
||||
</script>
|
||||
@@ -0,0 +1,29 @@
|
||||
<template>
|
||||
<main>
|
||||
<article class="article">
|
||||
<section class="web-hero web-hero-bg" aria-labelledby="hero" aria-describedby="hero-desc">
|
||||
<h1 id="hero" class="font-hero">Posts</h1>
|
||||
<p id="hero-desc" class="font-hero-desc">This is where I post my thoughts, articles, and updates.</p>
|
||||
</section>
|
||||
<section class="web-section" aria-labelledby="latest-posts" aria-describedby="latest-posts-paragraph-1">
|
||||
<h2 class="web-title" id="latest-posts">All Posts</h2>
|
||||
<PostsArticleList />
|
||||
</section>
|
||||
</article>
|
||||
</main>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
const TITLE = "Posts"
|
||||
const DESC = "Techit's posts and writings."
|
||||
|
||||
useHead({
|
||||
title: TITLE,
|
||||
meta: [
|
||||
{ name: 'description', content: DESC },
|
||||
{ property: 'og:title', content: TITLE },
|
||||
{ property: 'og:description', content: DESC },
|
||||
{ property: 'og:type', content: 'website' }
|
||||
]
|
||||
})
|
||||
</script>
|
||||
Reference in New Issue
Block a user