125 lines
5.5 KiB
TypeScript
125 lines
5.5 KiB
TypeScript
import React from 'react';
|
|
import { SalesAsset, AssetType } from '../types';
|
|
import { Play, ArrowUpRight, BarChart3, Image as ImageIcon } from 'lucide-react';
|
|
|
|
interface SalesCardProps {
|
|
asset: SalesAsset;
|
|
onClick: (asset: SalesAsset) => void;
|
|
}
|
|
|
|
const SalesCard: React.FC<SalesCardProps> = ({ asset, onClick }) => {
|
|
const baseClasses = `
|
|
group relative overflow-hidden rounded-2xl bg-white border border-slate-100 shadow-sm hover:shadow-xl hover:-translate-y-1 transition-all duration-300 ease-out cursor-pointer
|
|
${asset.gridSpan === 'col-span-2' ? 'md:col-span-2' : 'md:col-span-1'}
|
|
${asset.rowSpan === 'row-span-2' ? 'md:row-span-2' : 'md:row-span-1'}
|
|
flex flex-col
|
|
`;
|
|
|
|
// Handle click properly
|
|
const handleClick = (e: React.MouseEvent) => {
|
|
// Prevent triggering if clicking specific action buttons if needed,
|
|
// but generally the whole card should open the modal.
|
|
onClick(asset);
|
|
};
|
|
|
|
// Render Video Card
|
|
if (asset.type === AssetType.VIDEO) {
|
|
return (
|
|
<div className={`${baseClasses} bg-slate-900 text-white min-h-[300px]`} onClick={handleClick}>
|
|
<div className="absolute inset-0 w-full h-full pointer-events-none">
|
|
{/* Pointer events none on iframe to allow card click, or use a cover div */}
|
|
<iframe
|
|
src={`https://player.vimeo.com/video/${asset.src}?background=1&autoplay=0&loop=0&byline=0&title=0`}
|
|
className="w-full h-full object-cover opacity-60 group-hover:opacity-40 transition-opacity duration-500"
|
|
frameBorder="0"
|
|
allow="autoplay; fullscreen; picture-in-picture"
|
|
title={asset.videoTitle}
|
|
></iframe>
|
|
</div>
|
|
<div className="relative z-10 p-6 flex flex-col h-full justify-between pointer-events-none">
|
|
<div className="flex justify-between items-start">
|
|
<span className="bg-red-600 text-white text-xs font-bold px-2 py-1 rounded-full uppercase tracking-wider flex items-center gap-1">
|
|
<Play size={10} fill="currentColor" /> Video
|
|
</span>
|
|
</div>
|
|
<div>
|
|
<h3 className="text-2xl font-bold mb-2 leading-tight">{asset.title}</h3>
|
|
<p className="text-slate-300 text-sm line-clamp-2">{asset.description}</p>
|
|
</div>
|
|
<div className="mt-4 inline-flex items-center gap-2 text-sm font-medium text-white/80 group-hover:text-red-400 transition-colors">
|
|
상세 보기 및 스크립트 <ArrowUpRight size={16} />
|
|
</div>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
// Render Image Card
|
|
if (asset.type === AssetType.IMAGE) {
|
|
return (
|
|
<div className={`${baseClasses} min-h-[250px]`} onClick={handleClick}>
|
|
<div className="absolute inset-0">
|
|
<img
|
|
src={asset.src}
|
|
alt={asset.title}
|
|
className="w-full h-full object-cover transition-transform duration-700 group-hover:scale-110"
|
|
/>
|
|
<div className="absolute inset-0 bg-gradient-to-t from-black/80 via-transparent to-transparent opacity-80" />
|
|
</div>
|
|
<div className="relative z-10 p-6 mt-auto text-white h-full flex flex-col justify-end">
|
|
<div className="mb-auto">
|
|
<span className="bg-white/20 backdrop-blur-md text-white text-xs font-bold px-2 py-1 rounded-full uppercase tracking-wider inline-flex items-center gap-1">
|
|
<ImageIcon size={10} /> Image
|
|
</span>
|
|
</div>
|
|
<h3 className="text-xl font-bold mb-1">{asset.title}</h3>
|
|
<p className="text-slate-200 text-sm">{asset.description}</p>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
// Render Stat Card
|
|
if (asset.type === AssetType.STAT) {
|
|
return (
|
|
<div className={`${baseClasses} bg-brand-600 text-white p-6 flex flex-col justify-between min-h-[200px]`} onClick={handleClick}>
|
|
<div className="flex justify-between items-start opacity-80">
|
|
<BarChart3 size={24} />
|
|
<span className="text-xs font-medium bg-white/10 px-2 py-1 rounded-lg">{asset.tags[0]}</span>
|
|
</div>
|
|
<div className="mt-4">
|
|
<div className="text-5xl font-extrabold tracking-tight mb-1">{asset.statValue}</div>
|
|
<div className="text-brand-100 font-medium">{asset.statLabel}</div>
|
|
</div>
|
|
<div className="mt-4 text-xs text-brand-100 opacity-60 flex items-center justify-between">
|
|
<span>* 내부 데이터 기준</span>
|
|
<ArrowUpRight size={16} />
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
// Render Text Card (Default)
|
|
return (
|
|
<div className={`${baseClasses} p-6 flex flex-col justify-between min-h-[200px] hover:border-brand-200`} onClick={handleClick}>
|
|
<div>
|
|
<div className="flex flex-wrap gap-2 mb-4">
|
|
{asset.tags.map(tag => (
|
|
<span key={tag} className="text-[10px] uppercase font-bold text-slate-500 bg-slate-100 px-2 py-1 rounded-md">
|
|
{tag}
|
|
</span>
|
|
))}
|
|
</div>
|
|
<h3 className="text-xl font-bold text-slate-900 mb-3">{asset.title}</h3>
|
|
<p className="text-slate-600 text-sm leading-relaxed line-clamp-4">{asset.content}</p>
|
|
</div>
|
|
<div className="mt-6 pt-4 border-t border-slate-100 flex items-center justify-between">
|
|
<span className="text-xs text-slate-400 font-medium group-hover:text-brand-600 transition-colors">전체 스크립트 보기</span>
|
|
<ArrowUpRight size={16} className="text-slate-400 group-hover:text-brand-600 transition-colors" />
|
|
</div>
|
|
</div>
|
|
);
|
|
};
|
|
|
|
export default SalesCard;
|