valaxy/packages/valaxy-theme-yun/components/YunPostCollapse.vue

172 lines
4.0 KiB
Vue

<script lang="ts" setup>
import { computed, ref, watch } from 'vue'
import type { Post } from 'valaxy'
import { formatDate, sortByDate } from 'valaxy'
import { useI18n } from 'vue-i18n'
const props = defineProps<{
posts: Post[]
}>()
const { t } = useI18n()
const years = ref<number[]>([])
const postListByYear = ref<Record<string, Post[]>>({})
watch(() => props.posts, () => {
postListByYear.value = {}
years.value = []
props.posts.forEach((post) => {
if (post.hide && post.hide !== 'index')
return
if (post.date) {
const year = Number.parseInt(formatDate(post.date, 'YYYY'))
if (postListByYear.value[year]) {
postListByYear.value[year].push(post)
}
else {
years.value.push(year)
postListByYear.value[year] = [post]
}
}
})
}, { immediate: true })
const isDesc = ref(true)
const sortedYears = computed(() => {
const y = years.value
const arr = y.sort((a, b) => b - a)
return isDesc.value ? arr : arr.reverse()
})
</script>
<template>
<div class="post-collapse px-10 lt-sm:px-5" relative>
<div w="full" text="center" class="yun-text-light" p="2">
{{ t('counter.archives', posts.length) }}
</div>
<div class="post-collapse-action" text="center">
<button class="yun-icon-btn shadow hover:shadow-md" @click="isDesc = !isDesc">
<div v-if="isDesc" i-ri-sort-desc />
<div v-else i-ri-sort-asc />
</button>
</div>
<div v-for="year in sortedYears" :key="year" m="b-6">
<div class="collection-title" m-0 relative>
<h2 :id="`#archive-year-${year}`" class="archive-year" text="4xl" p="y-2">
{{ year }}
</h2>
</div>
<article
v-for="post, j in sortByDate(postListByYear[year], isDesc)" :key="j"
class="post-item" relative
>
<header class="post-header" flex items-center relative>
<div class="post-meta">
<time v-if="post.date" class="post-time" font="mono" opacity="80">{{
formatDate(post.date, 'MM-DD') }}
</time>
</div>
<h2 class="post-title" inline-flex items-center font="serif black">
<RouterLink :to="post.path || ''" class="post-title-link">
{{ post.title }}
</RouterLink>
</h2>
</header>
</article>
</div>
</div>
</template>
<style lang="scss">
.post-collapse {
.collection-title {
border-bottom: 2px solid rgba(var(--va-c-primary-rgb), 0.6);
&::before {
content: '';
position: absolute;
top: 50%;
width: 2px;
height: 50%;
background: rgba(var(--va-c-primary-rgb), 0.3);
}
.archive-year {
color: var(--va-c-primary);
margin: 0 1.5rem;
&::before {
content: '';
position: absolute;
left: 0;
top: 35%;
margin-left: -11px;
margin-top: -4px;
width: 1.5rem;
height: 1.5rem;
background: var(--va-c-primary);
border-radius: 50%;
}
}
}
.post-item {
&::before {
content: '';
position: absolute;
width: 2px;
height: 100%;
background: rgba(var(--va-c-primary-rgb), 0.3);
}
}
.post-header {
border-bottom: 1px solid rgba(var(--va-c-primary-rgb), 0.3);
&::before {
content: '';
position: absolute;
left: 0;
width: 10px;
height: 10px;
margin-left: -4px;
border-radius: 50%;
border: 1px solid var(--va-c-primary);
background-color: var(--va-c-bg-light);
z-index: 1;
transition: background var(--va-transition-duration);
}
&:hover {
&::before {
background: var(--va-c-primary);
}
}
.post-title {
margin-left: 0.1rem;
padding: 0;
font-size: 1rem;
.post-title-link {
.icon {
width: 1.1rem;
height: 1.1rem;
margin-right: 0.3rem;
}
}
}
.post-meta {
font-size: 1rem;
margin: 1rem 0 1rem 1.2rem;
white-space: nowrap;
}
}
}
</style>