Files
japan/src/components/PlaceCard.tsx
2026-03-21 04:59:39 +00:00

104 lines
3.5 KiB
TypeScript
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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>
);
}