PinnovateCloud/components/news/TrendingNewsList.vue

130 lines
3.8 KiB
Vue
Raw Normal View History

2025-09-11 10:55:59 +08:00
<!-- 热门新闻列表组件 -->
<template>
<div class="trending-news">
<div class="trending-news-header">
<h3 class="font-semibold text-lg mb-3 dark:text-white">
<i class="fas fa-fire text-red-500 dark:text-red-400 mr-2"></i>
{{ $t('news.trendingNews') }}
</h3>
</div>
<div class="trending-news-list">
<NuxtLink
v-for="(article, index) in trendingNews"
:key="index"
:to="`/awsnews/${getArticleSlug(article)}`"
class="trending-news-item"
>
<div class="trending-news-rank">{{ index + 1 }}</div>
<div class="trending-news-content">
<h4 class="trending-news-title">{{ article.title }}</h4>
<div class="trending-news-meta">
<span class="trending-news-category" :class="getCategoryClass(article.category || article.meta?.category || 'other')">
{{ $t(`news.categories.${article.category || article.meta?.category || 'other'}`) }}
</span>
<!-- <span class="trending-news-views">
<i class="fas fa-eye text-gray-400 mr-1"></i> {{ article.views }}
</span> -->
</div>
</div>
</NuxtLink>
</div>
</div>
</template>
<script setup lang="ts">
import type { PropType } from 'vue';
import { useI18n } from 'vue-i18n';
const { t } = useI18n();
// 定义组件属性
const props = defineProps({
trendingNews: {
type: Array as PropType<any[]>,
required: true
}
});
// 安全获取文章路径最后部分slug
const getArticleSlug = (article: any) => {
if (!article) return '';
// 优先使用path如果没有则尝试使用_path
const path = article.path || article._path || '';
// 移除开头的斜杠
const cleanPath = path.startsWith('/') ? path.substring(1) : path;
// 如果路径中包含斜杠,取最后一段;否则使用整个路径
return cleanPath.includes('/') ? cleanPath.split('/').pop() : cleanPath;
};
// 获取分类样式
const getCategoryClass = (category: string) => {
const categoryColors: Record<string, string> = {
'cloud-computing': 'text-blue-600',
'security': 'text-red-600',
'serverless': 'text-purple-600',
'ai': 'text-green-600',
'database': 'text-yellow-600',
'quantum-computing': 'text-blue-700',
'networking': 'text-blue-500',
'containers': 'text-blue-600',
'machine-learning': 'text-blue-500',
'sustainability': 'text-blue-600',
'other': 'text-gray-600'
};
return categoryColors[category] || categoryColors.other;
};
</script>
<style scoped>
.trending-news {
@apply bg-white dark:bg-gray-800 rounded-lg shadow p-4 mt-6 sticky top-24;
}
.trending-news-list {
@apply space-y-4;
}
.trending-news-item {
@apply flex items-start py-2 border-b border-gray-100 dark:border-gray-700 last:border-0 hover:bg-gray-50 dark:hover:bg-gray-700/50 transition-colors;
}
.trending-news-rank {
@apply flex-shrink-0 w-6 h-6 rounded-full bg-gray-100 dark:bg-gray-700 flex items-center justify-center text-sm font-bold text-gray-700 dark:text-gray-300 mr-3;
}
.trending-news-item:nth-child(1) .trending-news-rank {
@apply bg-red-100 dark:bg-red-900/30 text-red-700 dark:text-red-400;
}
.trending-news-item:nth-child(2) .trending-news-rank {
@apply bg-orange-100 dark:bg-orange-900/30 text-orange-700 dark:text-orange-400;
}
.trending-news-item:nth-child(3) .trending-news-rank {
@apply bg-yellow-100 dark:bg-yellow-900/30 text-yellow-700 dark:text-yellow-400;
}
.trending-news-content {
@apply flex-grow;
}
.trending-news-title {
@apply text-sm font-medium mb-1 line-clamp-2 dark:text-white;
}
.trending-news-meta {
@apply flex justify-between items-center text-xs;
}
.trending-news-category {
@apply font-medium;
}
.trending-news-views {
@apply text-gray-500 dark:text-gray-400;
}
</style>