tahamajs's picture
download
raw
4.26 kB
// src/components/article/ArticleMeta.tsx
import { Calendar, Clock, Eye, Heart, MessageCircle, Bookmark, Share2, TrendingUp, Award, Star } from "lucide-react";
import { Link } from "react-router-dom";
interface ArticleMetaProps {
createdAt: string;
updatedAt?: string;
readTime?: number;
views?: number;
likes?: number;
comments?: number;
bookmarks?: number;
shares?: number;
citations?: number;
impactScore?: number;
className?: string;
variant?: "horizontal" | "vertical" | "compact";
showIcons?: boolean;
showLabels?: boolean;
}
export function ArticleMeta({
createdAt,
updatedAt,
readTime = 5,
views = 0,
likes = 0,
comments = 0,
bookmarks = 0,
shares = 0,
citations = 0,
impactScore,
className = "",
variant = "horizontal",
showIcons = true,
showLabels = false
}: ArticleMetaProps) {
const formatDate = (date: string) => {
const d = new Date(date);
const now = new Date();
const diff = now.getTime() - d.getTime();
const days = Math.floor(diff / (1000 * 60 * 60 * 24));
if (days === 0) return "Today";
if (days === 1) return "Yesterday";
if (days < 7) return `${days} days ago`;
if (days < 30) return `${Math.floor(days / 7)} weeks ago`;
if (days < 365) return `${Math.floor(days / 30)} months ago`;
return `${Math.floor(days / 365)} years ago`;
};
const metaItems = [
{ icon: Calendar, label: "Published", value: formatDate(createdAt) },
{ icon: Clock, label: "Read time", value: `${readTime} min` },
{ icon: Eye, label: "Views", value: views.toLocaleString() },
{ icon: Heart, label: "Likes", value: likes.toLocaleString() },
{ icon: MessageCircle, label: "Comments", value: comments.toLocaleString() },
{ icon: Bookmark, label: "Bookmarks", value: bookmarks.toLocaleString() },
{ icon: Share2, label: "Shares", value: shares.toLocaleString() },
{ icon: TrendingUp, label: "Citations", value: citations.toLocaleString() },
];
if (variant === "vertical") {
return (
<div className={`space-y-2 ${className}`}>
{metaItems.map((item) => (
<div key={item.label} className="flex items-center justify-between text-sm">
<div className="flex items-center gap-2 text-gray-500">
<item.icon className="h-4 w-4" />
{showLabels && <span>{item.label}</span>}
</div>
<span className="font-medium text-gray-900 dark:text-white">{item.value}</span>
</div>
))}
{impactScore && (
<div className="flex items-center justify-between text-sm pt-2 border-t border-gray-100 dark:border-gray-700">
<div className="flex items-center gap-2 text-gray-500">
<Award className="h-4 w-4" />
<span>Impact Score</span>
</div>
<div className="flex items-center gap-1">
<Star className="h-3 w-3 fill-yellow-400 text-yellow-400" />
<span className="font-bold text-yellow-600">{impactScore}</span>
</div>
</div>
)}
</div>
);
}
if (variant === "compact") {
return (
<div className={`flex flex-wrap items-center gap-3 text-xs text-gray-500 ${className}`}>
<span className="flex items-center gap-1">
<Calendar className="h-3 w-3" />
{formatDate(createdAt)}
</span>
<span className="flex items-center gap-1">
<Clock className="h-3 w-3" />
{readTime} min
</span>
<span className="flex items-center gap-1">
<Eye className="h-3 w-3" />
{views}
</span>
<span className="flex items-center gap-1">
<Heart className="h-3 w-3" />
{likes}
</span>
</div>
);
}
// Horizontal variant (default)
return (
<div className={`flex flex-wrap items-center gap-4 text-sm text-gray-500 ${className}`}>
{metaItems.map((item) => (
<div key={item.label} className="flex items-center gap-1.5">
{showIcons && <item.icon className="h-4 w-4" />}
<span>{item.value}</span>
{showLabels && <span className="text-xs text-gray-400">{item.label}</span>}
</div>
))}
</div>
);
}

Xet Storage Details

Size:
4.26 kB
·
Xet hash:
015e6069c34fab5abe2ebecd794c5f6baef6bd2f840e397a674baf6de74f9d52

Xet efficiently stores files, intelligently splitting them into unique chunks and accelerating uploads and downloads. More info.