71 lines
2.0 KiB
TypeScript
71 lines
2.0 KiB
TypeScript
"use client";
|
||
import { useI18n } from "@/components/I18nProvider";
|
||
import Image from "next/image";
|
||
import Link from "next/link";
|
||
import { ArrowUpRight, MapPin } from "lucide-react";
|
||
export type CardMap = {
|
||
id: string;
|
||
name: string;
|
||
description: string;
|
||
source: string;
|
||
panorama_count: number;
|
||
image?: string | null;
|
||
credit?: string;
|
||
server?: { name: string } | undefined;
|
||
bounds: { minX: number; minZ: number; maxX: number; maxZ: number };
|
||
};
|
||
export function MapCard({
|
||
map,
|
||
index = 0,
|
||
minecraftPaper = false,
|
||
}: {
|
||
map: CardMap;
|
||
index?: number;
|
||
minecraftPaper?: boolean;
|
||
}) {
|
||
const { t } = useI18n();
|
||
return (
|
||
<Link className="map-card" href={`/servers/${map.id}`}>
|
||
<div className={`card-image${minecraftPaper ? " minecraft-paper" : ""}`}>
|
||
<div className="card-map-content">
|
||
<Image
|
||
src={map.image || "/images/example-map.webp"}
|
||
alt={t("Terrain of {name}", { name: map.name })}
|
||
fill
|
||
loading={index < 3 ? "eager" : "lazy"}
|
||
unoptimized
|
||
sizes="(max-width: 640px) 100vw, 33vw"
|
||
/>
|
||
</div>
|
||
<span className="card-type">
|
||
{map.source === "plugin" ? t("SERVER EXPORT") : t("PLAYER CAPTURE")}
|
||
</span>
|
||
<span className="card-number">0{index + 1}</span>
|
||
</div>
|
||
<div className="card-body">
|
||
<span className="eyebrow">{map.server?.name || t("Overworld")}</span>
|
||
<h3>
|
||
{map.name}
|
||
<ArrowUpRight size={20} />
|
||
</h3>
|
||
<p>{map.description}</p>
|
||
{map.credit && (
|
||
<p className="map-credit">
|
||
{t("By")} {map.credit}
|
||
</p>
|
||
)}
|
||
<div className="card-meta">
|
||
<span>
|
||
<MapPin size={13} />
|
||
{map.panorama_count} {t("locations")}
|
||
</span>
|
||
<span>
|
||
{map.bounds.maxX - map.bounds.minX} ×{" "}
|
||
{map.bounds.maxZ - map.bounds.minZ} {t("blocks")}
|
||
</span>
|
||
</div>
|
||
</div>
|
||
</Link>
|
||
);
|
||
}
|