feat: ranking page topic

This commit is contained in:
KUN1007 2023-10-17 23:41:04 +08:00
parent e401702c0a
commit 9d4a34aa72
5 changed files with 190 additions and 40 deletions

View file

@ -2,7 +2,7 @@ export interface RankingGetTopicsRequestData {
page: number
limit: number
sortField: string
sortOrder: string
sortOrder: 'asc' | 'desc'
}
export interface RankingTopics {

View file

@ -34,13 +34,13 @@ export const navSortItem: Sort[] = [
index: 5,
icon: 'line-md:thumbs-up-twotone',
name: 'likes',
sortField: 'likes',
sortField: 'likes_count',
},
{
index: 6,
icon: 'ri:reply-line',
name: 'replies',
sortField: 'replies',
sortField: 'replies_count',
},
{
index: 7,

View file

@ -6,7 +6,7 @@ import KUNgalgamer from './KUNGalgamer.vue'
<!-- 用户排行 -->
<div class="kungalgamer-ranking">
<!-- 用户排行标题 -->
<div class="kungalgamer-title">最萌的萝莉</div>
<div class="kungalgamer-title">用户</div>
<!-- 用户排行的交互 -->
<div class="kungalgamer-nav">
<!-- 萌萌点 -->

View file

@ -10,7 +10,7 @@ const props = defineProps<{
const topics = computed(() => props.topics)
const icons: Record<string, string> = {
const iconMap: Record<string, string> = {
popularity: 'bi:fire',
upvotes_count: 'bi:rocket',
views: 'ic:outline-remove-red-eye',
@ -26,33 +26,50 @@ const parseTopicNumber = (field: string | string[]) => {
</script>
<template>
<!-- 单个话题 -->
<div class="single-topic" v-for="(topic, index) in topics" :key="index">
<!-- 话题的名字 -->
<div class="topic-name">
{{ topic.title }}
<TransitionGroup name="list">
<!-- 单个话题 -->
<div class="single-topic" v-for="topic in topics" :key="topic.tid">
<RouterLink :to="`/topic/${topic.tid}`">
<!-- 话题的名字 -->
<div class="topic-name">
{{ topic.title }}
</div>
<!-- 话题的其它信息 -->
<div class="detail">
<!-- 浏览数 -->
<Icon :icon="iconMap[props.field]" />
<span>{{ parseTopicNumber(topic.field) }}</span>
</div>
</RouterLink>
</div>
<!-- 话题的其它信息 -->
<div class="detail">
<!-- 浏览数 -->
<span>
<Icon :icon="icons[props.field]" />
{{ parseTopicNumber(topic.field) }}
</span>
</div>
</div>
</TransitionGroup>
</template>
<style lang="scss" scoped>
/* 单个话题 */
.single-topic {
flex-shrink: 0;
height: 37px;
border-bottom: 1px solid var(--kungalgame-blue-4);
margin: 7px;
display: flex;
justify-content: space-between;
align-items: center;
a {
flex-shrink: 0;
height: 37px;
margin: 7px;
display: flex;
justify-content: space-between;
align-items: center;
background-color: var(--kungalgame-trans-blue-0);
border: 1px solid var(--kungalgame-trans-blue-0);
border-radius: 5px;
color: var(--kungalgame-font-color-3);
padding: 0 10px;
cursor: pointer;
&:hover {
transition: all 0.5s;
background-color: var(--kungalgame-trans-white-9);
border: 1px solid var(--kungalgame-blue-4);
color: var(--kungalgame-blue-4);
}
}
}
/* 话题的名字 */
.topic-name {
@ -60,16 +77,31 @@ const parseTopicNumber = (field: string | string[]) => {
overflow: hidden;
text-overflow: ellipsis;
}
/* 话题的其它信息 */
.v-l-c-t {
flex-shrink: 0;
}
.detail {
display: flex;
align-items: center;
color: var(--kungalgame-blue-4);
span {
display: flex;
align-items: center;
color: var(--kungalgame-font-color-3);
margin-left: 10px;
}
}
.list-move, /* 对移动中的元素应用的过渡 */
.list-enter-active,
.list-leave-active {
transition: all 0.5s ease;
}
.list-enter-from,
.list-leave-to {
opacity: 0;
}
/*
以便能够正确地计算移动的动画 */
.list-leave-active {
position: absolute;
}
</style>

View file

@ -9,8 +9,10 @@ import { storeToRefs } from 'pinia'
import type { RankingTopics } from '@/api'
import { topicNavSortItem } from './navSortItem'
const { topic, user } = storeToRefs(useKUNGalgameRankingStore())
const { topic } = storeToRefs(useKUNGalgameRankingStore())
const topics = ref<RankingTopics[]>([])
//
const isAscending = ref(false)
//
const getTopics = async () => {
@ -18,6 +20,15 @@ const getTopics = async () => {
return responseData.data
}
const iconMap: Record<string, string> = {
popularity: 'bi:fire',
upvotes_count: 'bi:rocket',
views: 'ic:outline-remove-red-eye',
likes_count: 'line-md:thumbs-up-twotone',
replies_count: 'ri:reply-line',
comments: 'fa-regular:comment-dots',
}
//
watch(
() => topic,
@ -31,29 +42,53 @@ watch(
onMounted(async () => {
topics.value = await getTopics()
})
//
const handleClickSortOrder = () => {
isAscending.value = !isAscending.value
if (isAscending.value) {
topic.value.sortOrder = 'asc'
} else {
topic.value.sortOrder = 'desc'
}
}
</script>
<template>
<!-- 话题排行 -->
<div class="topic">
<!-- 话题排行标题 -->
<div class="title">最萌的话题</div>
<div class="title">话题</div>
<!-- 话题排行的交互 -->
<div class="nav">
<!-- 升序降序 -->
<div class="order">排序</div>
<div class="order" @click="handleClickSortOrder">
<Transition name="order" mode="out-in">
<div v-if="isAscending">
<span>升序</span>
<Icon class="icon" icon="line-md:arrow-small-up" />
</div>
<div v-else-if="!isAscending">
<span>降序</span>
<Icon class="icon" icon="line-md:arrow-small-down" />
</div>
</Transition>
</div>
<div class="field">
<!-- 排序 -->
<div class="sort">
<Icon class="icon" :icon="iconMap[topic.sortField]" />
<span>筛选</span>
<!-- 排序子菜单 -->
<div class="sort-submenu">
<div class="submenu">
<div
class="sort-item"
class="item"
v-for="kun in topicNavSortItem"
:key="kun.index"
@click="topic.sortField = kun.sortField"
>
<span><Icon class="icon-item" :icon="kun.icon" /></span>
<span>按时间排序</span>
<span><Icon class="icon" :icon="kun.icon" /></span>
<span>{{ kun.name }}</span>
</div>
</div>
</div>
@ -69,6 +104,7 @@ onMounted(async () => {
/* 话题排行 */
.topic {
width: 50%;
height: calc(100% - 50px - 20px - 40px);
}
/* 话题排行标题 */
.title {
@ -82,8 +118,75 @@ onMounted(async () => {
}
/* 话题排行的交互 */
.nav {
height: 40px;
display: flex;
justify-content: space-around;
align-items: center;
margin-left: 10px;
border: 1px solid var(--kungalgame-blue-4);
border-radius: 5px;
}
.order {
width: 100%;
height: 100%;
cursor: pointer;
transition: all 0.2s;
display: flex;
align-items: center;
.icon {
font-size: 22px;
}
& > div {
width: 100%;
display: flex;
justify-content: space-around;
align-items: center;
}
}
.sort {
position: relative;
width: 100%;
height: 100%;
display: flex;
justify-content: space-around;
align-items: center;
cursor: pointer;
border-left: 1px solid var(--kungalgame-blue-4);
}
.sort:hover .submenu {
display: flex;
}
.icon {
color: var(--kungalgame-blue-4);
}
.submenu {
top: 40px;
position: absolute;
width: 100%;
display: none;
flex-direction: column;
border-radius: 5px;
border: 1px solid var(--kungalgame-blue-1);
box-shadow: var(--shadow);
background-color: var(--kungalgame-trans-white-5);
backdrop-filter: blur(5px);
.item {
transition: all 0.2s;
height: 40px;
display: flex;
justify-content: space-around;
align-items: center;
&:hover {
background-color: var(--kungalgame-trans-blue-1);
}
}
}
/* 单个话题的容器 */
@ -108,4 +211,19 @@ onMounted(async () => {
scrollbar-width: thin;
scrollbar-color: var(--kungalgame-blue-4) var(--kungalgame-blue-1);
}
.order-enter-active,
.order-leave-active {
transition: all 0.25s ease-out;
}
.order-enter-from {
opacity: 0;
transform: translateY(-30px);
}
.order-leave-to {
opacity: 0;
transform: translateY(30px);
}
</style>