Files
miaoBlog/pages/posts/index.vue
T
2025-02-04 14:49:51 +08:00

152 lines
4.0 KiB
Vue

<template>
<div class="posts-wrapper">
<article class="posts-item" v-for="post in postsData" :key="post.id">
<header class="post-title">
<nuxt-link :to="`/posts/post-${post.id}`">{{ post.title }}</nuxt-link>
</header>
<p class="post-summary">{{ post.summary }}...</p>
<footer class="post-footer">
<div class="post-date">
<time-icon class="post-date-icon" />
<span>
{{ formatDate(post.date, 'yy-MM-dd HH:mm:ss') }}
</span>
</div>
<div class="post-tags" v-if="post.tags.length">
<bookmark class="post-tags-icon" />
<div v-for="tag in post.tags">{{ tag }}</div>
</div>
</footer>
</article>
<div class="posts-skeleton" v-if="!isInit">
<div class="posts-skeleton-item" v-for="_ in range(5)">
<el-skeleton :rows="3" />
</div>
</div>
</div>
</template>
<script setup lang="ts">
import useDefaultStore from '~/hooks/pinia/useDefaultStore';
import timeIcon from '~/components/icons/time.vue'
import bookmark from '~/components/icons/tag.vue'
import type { postItem } from '~/types/post';
const store = useDefaultStore()
const isInit = ref(false)
const postsData = ref<postItem[]>([])
const getData = async () => {
const cache = store.getCache('posts')
if (cache) {
return cache as postItem[]
}
const response = await $fetch('/api/posts/getPostList')
const res = response.data
store.setCache('posts', res)
return res
}
onMounted(async () => {
// router.push('/posts/temp')
// await sleep(1000)
postsData.value = await getData()
isInit.value = true;
// console.log(postsData.value)
})
</script>
<style lang="scss" scoped>
.posts-wrapper {
// height: 50vh;
box-sizing: border-box;
width: 100%;
padding: 10px 20px;
// background-color: #15aa87;
.posts-item {
margin: 10px 0px;
padding-bottom: 20px;
&:not(:last-child) {
border-bottom: 1px solid #e8e8e8;
}
.post-title {
font-family: PT Serif, Serif;
font-size: 28px;
border-bottom: 0;
&>a {
cursor: pointer;
color: #000;
transition: all .2s;
text-decoration: none;
&:hover {
color: #15aa87;
}
}
}
.post-summary {
font-size: 14px;
color: rgba(0, 0, 0, .54);
font-weight: 200;
}
.post-footer {
display: flex;
justify-content: space-between;
align-items: center;
margin-top: 10px;
font-size: 12px;
color: rgba(0, 0, 0, .54);
font-weight: 200;
.post-date {
display: flex;
font-size: 12px;
&-icon {
height: 16px;
margin-right: 5px;
}
}
.post-tags {
display: flex;
justify-content: space-between;
align-items: center;
gap: 6px;
font-size: 12px;
color: rgba(0, 0, 0, .54);
font-weight: 200;
&-icon {
height: 10px;
transform: rotate(-90deg) translate(-1px, -1px);
// margin-right: -3px;
}
&>div {
cursor: pointer;
transition: color .2s linear;
&:hover {
color: #15aa87;
}
}
}
}
}
.posts-skeleton {
&-item {
padding: 10px 20px;
// border-bottom: 1px solid #e8e8e8;
}
}
}
</style>