Files
scriptshare-cursor-clone/src/components/ScriptCard.tsx

149 lines
5.9 KiB
TypeScript
Raw Normal View History

import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card';
import { Badge } from '@/components/ui/badge';
import { Button } from '@/components/ui/button';
import { Eye, Calendar, User, ExternalLink, Star, TrendingUp } from 'lucide-react';
import { useNavigate } from 'react-router-dom';
import { formatDate, formatRelativeTime } from '@/lib/utils';
export interface Script {
id: string;
name: string;
description: string;
compatible_os: string[];
categories: string[];
git_repository_url?: string;
author_name: string;
view_count: number;
created_at: string;
updated_at: string;
is_approved: boolean;
}
interface ScriptCardProps {
script: Script;
}
export function ScriptCard({ script }: ScriptCardProps) {
const navigate = useNavigate();
const isPopular = script.view_count > 500;
const isTrending = script.view_count > 200;
return (
<Card className="group h-full hover:shadow-2xl hover:shadow-primary/20 transition-all duration-500 cursor-pointer border-muted/50 hover:border-primary/30 bg-gradient-to-br from-card/80 to-card/40 backdrop-blur-sm hover:scale-[1.02] relative overflow-hidden">
{/* Animated background gradient */}
<div className="absolute inset-0 bg-gradient-to-br from-primary/5 via-transparent to-accent/5 opacity-0 group-hover:opacity-100 transition-opacity duration-500" />
{/* Popular/Trending indicators */}
{isPopular && (
<div className="absolute top-3 right-3 z-10">
<Badge variant="secondary" className="bg-gradient-to-r from-yellow-500/20 to-orange-500/20 text-yellow-600 border-yellow-500/30 animate-pulse">
<Star className="h-3 w-3 mr-1 fill-current" />
Popular
</Badge>
</div>
)}
{isTrending && !isPopular && (
<div className="absolute top-3 right-3 z-10">
<Badge variant="secondary" className="bg-gradient-to-r from-green-500/20 to-emerald-500/20 text-green-600 border-green-500/30">
<TrendingUp className="h-3 w-3 mr-1" />
Trending
</Badge>
</div>
)}
<CardHeader onClick={() => navigate(`/script/${script.id}`)} className="pb-3 relative z-10">
<CardTitle className="line-clamp-2 group-hover:text-transparent group-hover:bg-gradient-to-r group-hover:from-primary group-hover:to-accent group-hover:bg-clip-text transition-all duration-300 text-lg font-bold">
{script.name}
</CardTitle>
<CardDescription className="line-clamp-3 text-muted-foreground group-hover:text-foreground/80 transition-colors duration-300">
{script.description}
</CardDescription>
</CardHeader>
<CardContent className="space-y-4 relative z-10">
{/* OS Badges with enhanced styling */}
<div className="flex flex-wrap gap-1.5">
{script.compatible_os.map(os => (
<Badge
key={os}
variant="outline"
className="text-xs border-primary/40 text-primary/90 hover:bg-primary/15 transition-all duration-200 rounded-full px-2 py-1 font-medium shadow-sm"
>
{os}
</Badge>
))}
</div>
{/* Categories with gradient backgrounds */}
<div className="flex flex-wrap gap-1.5">
{script.categories.slice(0, 2).map((category, index) => (
<Badge
key={category}
variant="secondary"
className={`text-xs rounded-full px-3 py-1 font-medium shadow-sm transition-all duration-200 hover:scale-105 ${
index === 0
? 'bg-gradient-to-r from-accent/20 to-accent/30 text-accent border-accent/30'
: 'bg-gradient-to-r from-primary/20 to-primary/30 text-primary border-primary/30'
}`}
>
{category}
</Badge>
))}
{script.categories.length > 2 && (
<Badge
variant="secondary"
className="text-xs bg-gradient-to-r from-muted to-muted/80 text-muted-foreground border-muted rounded-full px-2 py-1"
>
+{script.categories.length - 2}
</Badge>
)}
</div>
{/* Script metadata */}
<div className="flex items-center justify-between text-xs text-muted-foreground">
<div className="flex items-center space-x-3">
<div className="flex items-center space-x-1">
<User className="h-3 w-3" />
<span>{script.author_name}</span>
</div>
<div className="flex items-center space-x-1">
<Eye className="h-3 w-3" />
<span>{script.view_count.toLocaleString()}</span>
</div>
</div>
<div className="flex items-center space-x-1">
<Calendar className="h-3 w-3" />
<span title={formatDate(script.updated_at)}>
{formatRelativeTime(script.updated_at)}
</span>
</div>
</div>
{/* Action buttons */}
<div className="flex space-x-2 pt-2">
<Button
size="sm"
className="flex-1 bg-gradient-to-r from-primary to-accent hover:from-primary/90 hover:to-accent/90"
onClick={() => navigate(`/script/${script.id}`)}
>
View Script
</Button>
{script.git_repository_url && (
<Button
size="sm"
variant="outline"
onClick={(e) => {
e.stopPropagation();
window.open(script.git_repository_url, '_blank');
}}
>
<ExternalLink className="h-3 w-3" />
</Button>
)}
</div>
</CardContent>
</Card>
);
}