104 lines
3.5 KiB
TypeScript
104 lines
3.5 KiB
TypeScript
import { Place } from '../types';
|
||
|
||
interface PlaceCardProps {
|
||
place: Place;
|
||
onClick: () => void;
|
||
showDay?: boolean;
|
||
compact?: boolean;
|
||
}
|
||
|
||
const getCategoryIcon = (category: string): string => {
|
||
const icons: Record<string, string> = {
|
||
sight: '🏯',
|
||
restaurant: '🍜',
|
||
coffee: '☕',
|
||
snack: '🍡',
|
||
hotel: '🏨',
|
||
};
|
||
return icons[category] || '📍';
|
||
};
|
||
|
||
const getCategoryLabel = (category: string): string => {
|
||
const labels: Record<string, string> = {
|
||
sight: 'Достопримечательность',
|
||
restaurant: 'Ресторан',
|
||
coffee: 'Кофейня',
|
||
snack: 'Перекус',
|
||
hotel: 'Отель',
|
||
};
|
||
return labels[category] || 'Место';
|
||
};
|
||
|
||
export function PlaceCard({ place, onClick, showDay = false, compact = false }: PlaceCardProps) {
|
||
if (compact) {
|
||
return (
|
||
<button
|
||
onClick={onClick}
|
||
className="flex items-center gap-3 w-full p-3 bg-white rounded-xl shadow-sm border border-gray-100 card-hover text-left"
|
||
>
|
||
<span className="text-2xl">{getCategoryIcon(place.category)}</span>
|
||
<div className="flex-1 min-w-0">
|
||
<h3 className="font-semibold text-gray-900 truncate">{place.name}</h3>
|
||
<p className="text-xs text-gray-500">{place.nameJp}</p>
|
||
</div>
|
||
{place.rating === 5 && <span className="text-yellow-500">★</span>}
|
||
</button>
|
||
);
|
||
}
|
||
|
||
return (
|
||
<button
|
||
onClick={onClick}
|
||
className="w-full text-left bg-white rounded-2xl shadow-sm border border-gray-100 overflow-hidden card-hover"
|
||
>
|
||
{/* Image placeholder */}
|
||
<div className="h-32 bg-gradient-to-br from-gray-100 to-gray-200 relative">
|
||
<div className="absolute inset-0 flex items-center justify-center">
|
||
<span className="text-5xl opacity-50">{getCategoryIcon(place.category)}</span>
|
||
</div>
|
||
{place.rating === 5 && (
|
||
<div className="absolute top-2 right-2 bg-white/90 backdrop-blur-sm px-2 py-1 rounded-full">
|
||
<span className="text-yellow-500 text-sm">★ Must See</span>
|
||
</div>
|
||
)}
|
||
{showDay && place.day && (
|
||
<div className="absolute top-2 left-2 bg-[#FF6B6B] text-white px-2 py-1 rounded-full text-xs font-medium">
|
||
День {place.day}
|
||
</div>
|
||
)}
|
||
</div>
|
||
|
||
<div className="p-4">
|
||
<div className="flex items-start justify-between gap-2 mb-2">
|
||
<div>
|
||
<h3 className="font-bold text-gray-900 text-lg leading-tight">{place.name}</h3>
|
||
<p className="text-sm text-gray-400">{place.nameJp}</p>
|
||
</div>
|
||
</div>
|
||
|
||
<p className="text-sm text-gray-600 line-clamp-2 mb-3">{place.description}</p>
|
||
|
||
<div className="flex flex-wrap items-center gap-2 text-xs">
|
||
<span className="px-2 py-1 bg-gray-100 rounded-full text-gray-600">
|
||
{getCategoryLabel(place.category)}
|
||
</span>
|
||
{place.duration && (
|
||
<span className="px-2 py-1 bg-gray-100 rounded-full text-gray-600">
|
||
⏱️ {place.duration}
|
||
</span>
|
||
)}
|
||
{place.price && (
|
||
<span className={"px-2 py-1 rounded-full " +
|
||
(place.price === 'Бесплатно'
|
||
? "bg-green-50 text-green-600"
|
||
: "bg-[#FFE8E8] text-[#FF6B6B]")
|
||
}>
|
||
{place.price === 'Бесплатно' ? '✓ Бесплатно' : place.price}
|
||
</span>
|
||
)}
|
||
</div>
|
||
</div>
|
||
</button>
|
||
);
|
||
}
|