mirror of
https://github.com/mroxso/zelo-news.git
synced 2026-04-23 13:29:16 +02:00
Add TrendingTags component to BlogHomePage for displaying popular topics
This commit is contained in:
107
src/components/TrendingTags.tsx
Normal file
107
src/components/TrendingTags.tsx
Normal file
@@ -0,0 +1,107 @@
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import { Card, CardContent } from '@/components/ui/card';
|
||||
import { Badge } from '@/components/ui/badge';
|
||||
import { Skeleton } from '@/components/ui/skeleton';
|
||||
import { TrendingUp, Hash } from 'lucide-react';
|
||||
import { useBlogPosts } from '@/hooks/useBlogPosts';
|
||||
|
||||
interface TagCount {
|
||||
tag: string;
|
||||
count: number;
|
||||
}
|
||||
|
||||
export function TrendingTags() {
|
||||
const navigate = useNavigate();
|
||||
const { data: posts, isLoading } = useBlogPosts();
|
||||
|
||||
// Loading state
|
||||
if (isLoading) {
|
||||
return (
|
||||
<div className="space-y-4">
|
||||
<div className="flex items-center gap-3">
|
||||
<TrendingUp className="h-6 w-6 text-primary" />
|
||||
<div>
|
||||
<Skeleton className="h-7 w-48 mb-1" />
|
||||
<Skeleton className="h-4 w-32" />
|
||||
</div>
|
||||
</div>
|
||||
<Card>
|
||||
<CardContent className="pt-6">
|
||||
<div className="flex flex-wrap gap-2">
|
||||
{[1, 2, 3, 4, 5, 6, 7, 8].map((i) => (
|
||||
<Skeleton key={i} className="h-8 w-20" />
|
||||
))}
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
// No posts found
|
||||
if (!posts || posts.length === 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Calculate trending tags
|
||||
const tagCounts = new Map<string, number>();
|
||||
|
||||
posts.forEach((post) => {
|
||||
const tags = post.tags
|
||||
.filter(([name]) => name === 't')
|
||||
.map(([, value]) => value.toLowerCase());
|
||||
|
||||
tags.forEach((tag) => {
|
||||
tagCounts.set(tag, (tagCounts.get(tag) || 0) + 1);
|
||||
});
|
||||
});
|
||||
|
||||
// Sort tags by count and get top tags
|
||||
const trendingTags: TagCount[] = Array.from(tagCounts.entries())
|
||||
.map(([tag, count]) => ({ tag, count }))
|
||||
.sort((a, b) => b.count - a.count)
|
||||
.slice(0, 12);
|
||||
|
||||
if (trendingTags.length === 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="space-y-4">
|
||||
{/* Section Header */}
|
||||
<div className="flex items-center gap-3">
|
||||
<TrendingUp className="h-6 w-6 text-primary" />
|
||||
<div>
|
||||
<h2 className="text-2xl font-bold tracking-tight">
|
||||
Trending Tags
|
||||
</h2>
|
||||
<p className="text-sm text-muted-foreground">
|
||||
Popular topics across all articles
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Tags Card */}
|
||||
<Card>
|
||||
<CardContent className="pt-6">
|
||||
<div className="flex flex-wrap gap-2">
|
||||
{trendingTags.map(({ tag, count }) => (
|
||||
<Badge
|
||||
key={tag}
|
||||
variant="secondary"
|
||||
className="text-sm py-2 px-3 cursor-pointer hover:bg-primary hover:text-primary-foreground transition-colors"
|
||||
onClick={() => navigate(`/search?q=${encodeURIComponent('#' + tag)}`)}
|
||||
>
|
||||
<Hash className="h-3 w-3 mr-1" />
|
||||
{tag}
|
||||
<span className="ml-1.5 text-xs opacity-70">
|
||||
{count}
|
||||
</span>
|
||||
</Badge>
|
||||
))}
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
import { SearchBar } from '@/components/SearchBar';
|
||||
import { LatestArticles } from '@/components/LatestArticles';
|
||||
import { LatestInHashtag } from '@/components/LatestInHashtag';
|
||||
import { TrendingTags } from '@/components/TrendingTags';
|
||||
import { Music, Leaf, BrainCircuit, Bitcoin } from 'lucide-react';
|
||||
|
||||
export default function BlogHomePage() {
|
||||
@@ -13,6 +14,9 @@ export default function BlogHomePage() {
|
||||
<SearchBar />
|
||||
</div>
|
||||
|
||||
{/* Trending Tags */}
|
||||
<TrendingTags />
|
||||
|
||||
{/* Latest Articles */}
|
||||
<LatestArticles />
|
||||
|
||||
|
||||
Reference in New Issue
Block a user