Initial commit: Japan PWA guide

This commit is contained in:
Cosmo
2026-03-21 04:59:39 +00:00
commit 7db42fd784
36 changed files with 5705 additions and 0 deletions

View File

@@ -0,0 +1,103 @@
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>
);
}