123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206 |
- <script setup lang="ts">
- import type { PostSketch, Tag } from '@/models'
- import { computed, onMounted, ref, watch } from 'vue'
- import { api } from '@/utils/axios'
- import { useTokenStore } from '@/stores/auth.ts'
- import { colorMatchTheme, delay, formateDateAccurateToDay } from '@/utils'
- import { writeIcon } from '@/assets/icons.ts'
- import { getQuery, router } from '@/router'
- import { optionOfCate } from '@/utils/cates.ts'
- import TagCard from '@/components/TagCard.vue'
- const data = ref<PostSketch[]>([])
- const targetTag = ref<Tag | null>(null)
- const tokenStore = useTokenStore()
- const archiveType = ref<'cate' | 'tag' | undefined>(undefined)
- const cate = ref('')
- let tag = ''
- onMounted(() => {
- cate.value = getQuery('cate')
- tag = getQuery('tag')
- if ((!cate.value && !tag) || (cate.value && tag)) {
- router.push('/archives')
- return
- }
- if (cate.value) {
- archiveType.value = 'cate'
- api.postsOfCate(cate.value).then((res) => {
- data.value = res.data
- })
- } else if (tag) {
- archiveType.value = 'tag'
- api.postsOfTag(tag).then((res) => {
- data.value = res.data.posts
- targetTag.value = res.data.tag
- })
- }
- })
- const tokenAvailable = ref(false)
- const floatBtnElementAnimationStyle = ref({
- display: 'none',
- transform: 'scale(0)',
- transition: 'all .3s',
- })
- watch(
- () => tokenStore.available,
- async (newValue) => {
- if (!tokenAvailable.value && newValue) {
- tokenAvailable.value = true
- floatBtnElementAnimationStyle.value.display = 'block'
- floatBtnElementAnimationStyle.value.transform = 'scale(0)'
- await delay(20)
- floatBtnElementAnimationStyle.value.transform = 'scale(100%)'
- } else if (tokenAvailable.value && !newValue) {
- tokenAvailable.value = false
- floatBtnElementAnimationStyle.value.transform = 'scale(0)'
- await delay(320)
- floatBtnElementAnimationStyle.value.display = 'none'
- }
- },
- { immediate: true },
- )
- function handleWriteClick() {
- if (archiveType.value == 'tag') router.push(`/editor?tag=${tag}`)
- else if (archiveType.value == 'cate') router.push(`/editor?cate=${cate.value}`)
- }
- const cateOption = computed(() => optionOfCate(cate.value))
- const handlePostLineClick = (post: PostSketch) => {
- router.push(`/detail?id=${post.id}`)
- }
- </script>
- <template>
- <div style="position: relative">
- <div class="float-btn" @click.stop="handleWriteClick" :style="floatBtnElementAnimationStyle">
- <div class="float-btn-ico" v-html="writeIcon.template" />
- </div>
- <div class="post-item" style="display: flex; flex-direction: column; gap: 12px">
- <div class="cate-title" v-if="archiveType == 'cate'">
- <div class="cate-icon" v-html="cateOption.svg.template" />
- <div class="cate-content">{{ cateOption.label }}</div>
- </div>
- <div class="tag-title" v-else-if="archiveType == 'tag' && targetTag">
- <div class="tag-title-content">正在浏览话题包含</div>
- <TagCard :target="targetTag" />
- <div class="tag-title-content">的文章</div>
- </div>
- <div class="post-line" v-for="item of data" :key="item.id" @click="handlePostLineClick(item)">
- <div class="post-line-title">{{ item.title }}</div>
- <div class="post-line-date">{{ formateDateAccurateToDay(item.createdAt, false) }}</div>
- </div>
- </div>
- </div>
- </template>
- <style scoped>
- .cate-title {
- color: var(--text-color);
- display: flex;
- width: 100%;
- align-items: center;
- gap: 8px;
- padding-bottom: 4px;
- background: linear-gradient(to right, var(--secondary-text-color), var(--secondary-text-color)) no-repeat bottom left;
- background-size: 100% 1px;
- }
- .cate-icon {
- width: 24px;
- height: 24px;
- padding-left: 4px;
- fill: var(--text-color);
- }
- .cate-content {
- font-size: large;
- }
- .tag-title {
- display: flex;
- align-items: end;
- gap: 12px;
- color: var(--text-color);
- width: 100%;
- padding-bottom: 4px;
- background: linear-gradient(to right, var(--secondary-text-color), var(--secondary-text-color)) no-repeat bottom left;
- background-size: 100% 1px;
- }
- .tag-title-content {
- font-size: large;
- }
- .post-line {
- display: flex;
- cursor: pointer;
- justify-content: space-between;
- }
- .post-line-title {
- color: var(--text-color);
- background: linear-gradient(to right, var(--text-color), var(--text-color)) no-repeat left bottom;
- background-size: 0 2px;
- transition: background-size 0.2s;
- }
- .post-line:hover .post-line-title {
- background-size: 100% 2px;
- }
- .post-line .post-line-date {
- color: var(--secondary-text-color);
- background: linear-gradient(to right, var(--secondary-text-color), var(--secondary-text-color))
- no-repeat right bottom;
- background-size: 0 1px;
- transition: background-size 0.2s;
- }
- .post-line:hover .post-line-date {
- background-size: 100% 1px;
- }
- .float-btn {
- position: fixed;
- right: 48px;
- bottom: 32px;
- padding: 8px;
- width: 32px;
- height: 32px;
- border-radius: 50%;
- overflow: hidden;
- fill: var(--text-color);
- background-color: var(--secondary-background-color);
- box-shadow: rgba(0, 0, 0, 0.4) 0 0 6px;
- cursor: pointer;
- z-index: 10;
- }
- .float-btn:hover {
- fill: var(--secondary-background-color);
- background-color: var(--text-color);
- width: 48px;
- height: 48px;
- }
- .float-btn-ico {
- width: 32px;
- height: 32px;
- transition: all 0.3s;
- }
- .float-btn:hover .float-btn-ico {
- width: 48px;
- height: 48px;
- }
- </style>
|