|
| 1 | +import { Sample } from '../types/Sample'; |
| 2 | +import { TagPill } from './TagPill'; |
| 3 | + |
| 4 | +const languageIcons: Record<string, string> = { |
| 5 | + 'Node.js': '⬡', |
| 6 | + Python: '🐍', |
| 7 | + TypeScript: '𝗧𝗦', |
| 8 | + Go: '◉', |
| 9 | + Java: '☕', |
| 10 | + 'C#': '♯', |
| 11 | + Rust: '⚙', |
| 12 | +}; |
| 13 | + |
| 14 | +const languageColors: Record<string, string> = { |
| 15 | + 'Node.js': 'from-green-500 to-green-600', |
| 16 | + Python: 'from-blue-500 to-yellow-500', |
| 17 | + TypeScript: 'from-blue-500 to-blue-600', |
| 18 | + Go: 'from-cyan-500 to-cyan-600', |
| 19 | + Java: 'from-orange-500 to-red-500', |
| 20 | + 'C#': 'from-purple-500 to-purple-600', |
| 21 | + Rust: 'from-orange-600 to-red-700', |
| 22 | +}; |
| 23 | + |
| 24 | +export function SampleCard({ sample }: { sample: Sample }) { |
| 25 | + const gradient = languageColors[sample.language] ?? 'from-neutral-500 to-neutral-600'; |
| 26 | + const icon = languageIcons[sample.language] ?? '◈'; |
| 27 | + |
| 28 | + return ( |
| 29 | + <article className="group relative flex flex-col h-full"> |
| 30 | + <div className="absolute inset-0 bg-gradient-to-r from-purple-500/10 to-teal-500/10 rounded-2xl blur-xl opacity-0 group-hover:opacity-100 transition-all duration-500"></div> |
| 31 | + <div className="relative flex flex-col h-full bg-neutral-800/80 backdrop-blur-sm rounded-2xl border border-neutral-700/50 hover:border-purple-500/40 transition-all duration-300 overflow-hidden"> |
| 32 | + <div className="p-6 flex flex-col flex-1"> |
| 33 | + {/* Header */} |
| 34 | + <div className="flex items-start justify-between mb-4"> |
| 35 | + <div className="flex items-center gap-3"> |
| 36 | + <div className={`w-9 h-9 bg-gradient-to-br ${gradient} rounded-lg flex items-center justify-center text-white text-sm font-bold shrink-0`}> |
| 37 | + {icon} |
| 38 | + </div> |
| 39 | + <div> |
| 40 | + <span className="text-teal-400 text-xs font-medium">{sample.language}</span> |
| 41 | + <p className="text-gray-500 text-xs">{sample.industry}</p> |
| 42 | + </div> |
| 43 | + </div> |
| 44 | + <TagPill tag={sample.difficulty} variant="difficulty" /> |
| 45 | + </div> |
| 46 | + |
| 47 | + {/* Title */} |
| 48 | + <h2 className="text-base font-bold text-white mb-2 group-hover:text-purple-300 transition-colors leading-snug"> |
| 49 | + {sample.title} |
| 50 | + </h2> |
| 51 | + |
| 52 | + {/* Description */} |
| 53 | + <p className="text-gray-400 text-sm leading-relaxed mb-4 flex-1"> |
| 54 | + {sample.description} |
| 55 | + </p> |
| 56 | + |
| 57 | + {/* Tags */} |
| 58 | + <div className="flex flex-wrap gap-1.5 mb-5"> |
| 59 | + {sample.tags.map((tag) => ( |
| 60 | + <TagPill key={tag} tag={tag} variant="default" /> |
| 61 | + ))} |
| 62 | + </div> |
| 63 | + |
| 64 | + {/* CTA */} |
| 65 | + <a |
| 66 | + href={sample.githubUrl} |
| 67 | + target="_blank" |
| 68 | + rel="noopener noreferrer" |
| 69 | + className="inline-flex items-center text-teal-400 hover:text-teal-300 transition-colors font-medium text-sm mt-auto" |
| 70 | + > |
| 71 | + View on GitHub |
| 72 | + <svg |
| 73 | + className="w-3.5 h-3.5 ml-1.5 group-hover:translate-x-1 transition-transform" |
| 74 | + fill="none" |
| 75 | + stroke="currentColor" |
| 76 | + viewBox="0 0 24 24" |
| 77 | + > |
| 78 | + <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M17 8l4 4m0 0l-4 4m4-4H3" /> |
| 79 | + </svg> |
| 80 | + </a> |
| 81 | + </div> |
| 82 | + </div> |
| 83 | + </article> |
| 84 | + ); |
| 85 | +} |
0 commit comments