All checks were successful
Deploy MineGeo to Dokploy / deploy (push) Successful in 8m58s
84 lines
2.4 KiB
TypeScript
84 lines
2.4 KiB
TypeScript
"use client";
|
|
import { useI18n } from "@/components/I18nProvider";
|
|
|
|
import { useState } from "react";
|
|
import { Search } from "lucide-react";
|
|
import { MapCard, type CardMap } from "./MapCard";
|
|
import { ImportMap } from "./MapTransfer";
|
|
export function CatalogBrowser({
|
|
maps,
|
|
signedIn = false,
|
|
}: {
|
|
maps: CardMap[];
|
|
signedIn?: boolean;
|
|
}) {
|
|
const { t } = useI18n();
|
|
const [query, setQuery] = useState(""),
|
|
[source, setSource] = useState("all");
|
|
const shown = maps.filter(
|
|
(m) =>
|
|
(source === "all" || m.source === source) &&
|
|
(m.name + " " + m.description + " " + (m.server?.name ?? ""))
|
|
.toLowerCase()
|
|
.includes(query.trim().toLowerCase()),
|
|
);
|
|
return (
|
|
<>
|
|
<div className="catalog-controls">
|
|
<div className="catalog-search">
|
|
<label className="search-field">
|
|
<Search size={17} />
|
|
<input
|
|
aria-label={t("Search worlds")}
|
|
placeholder={t("Search worlds or servers…")}
|
|
value={query}
|
|
onChange={(e) => setQuery(e.target.value)}
|
|
/>
|
|
</label>
|
|
<ImportMap signedIn={signedIn} />
|
|
</div>
|
|
<div className="tabs" aria-label={t("Capture source")}>
|
|
{[
|
|
["all", t("All worlds")],
|
|
["plugin", t("Server exports")],
|
|
["fabric", t("Player captures")],
|
|
].map(([id, label]) => (
|
|
<button
|
|
key={id}
|
|
className={source === id ? "active" : ""}
|
|
aria-pressed={source === id}
|
|
onClick={() => setSource(id)}
|
|
>
|
|
{t(label)}
|
|
</button>
|
|
))}
|
|
</div>
|
|
</div>
|
|
<p className="muted catalog-count" role="status">
|
|
{t("Worlds to explore: {count}", { count: shown.length })}
|
|
</p>
|
|
<div className="cards-grid">
|
|
{shown.map((m, i) => (
|
|
<MapCard map={m} index={i} key={m.id} />
|
|
))}
|
|
</div>
|
|
{!shown.length && (
|
|
<div className="empty-state catalog-empty">
|
|
<Search size={28} aria-hidden="true" />
|
|
<p>{t("No worlds match that search.")}</p>
|
|
<button
|
|
type="button"
|
|
className="button secondary"
|
|
onClick={() => {
|
|
setQuery("");
|
|
setSource("all");
|
|
}}
|
|
>
|
|
{t("Clear filters")}
|
|
</button>
|
|
</div>
|
|
)}
|
|
</>
|
|
);
|
|
}
|