Improve MineGeo interface and functionality
This commit is contained in:
@@ -1,4 +1,7 @@
|
||||
"use client";
|
||||
import { statusMessage } from "@/shared/i18n";
|
||||
import { useI18n } from "@/components/I18nProvider";
|
||||
|
||||
import { useCallback, useEffect, useState } from "react";
|
||||
import Link from "next/link";
|
||||
import { createBrowserClient } from "@supabase/ssr";
|
||||
@@ -11,6 +14,7 @@ type Draft = MapListing & {
|
||||
upload_jobs: ProcessingJob | null;
|
||||
};
|
||||
export function Dashboard() {
|
||||
const { t } = useI18n();
|
||||
const [maps, setMaps] = useState<Draft[]>([]),
|
||||
[error, setError] = useState(""),
|
||||
[tokens, setTokens] = useState<
|
||||
@@ -77,33 +81,34 @@ export function Dashboard() {
|
||||
<>
|
||||
<div className="dashboard-toolbar">
|
||||
<p className="muted">
|
||||
Your maps start privately. You decide when they’re ready for review.
|
||||
Contributions are hidden here after five days. Their panoramas and
|
||||
direct links stay available.
|
||||
{t(
|
||||
"Your maps start privately. You decide when they’re ready for review. Contributions are hidden here after five days. Their panoramas and direct links stay available.",
|
||||
)}
|
||||
</p>
|
||||
<div className="inline-actions">
|
||||
<Link className="button" href="/settings">
|
||||
Account settings
|
||||
{t("Account settings")}
|
||||
</Link>
|
||||
<button className="button" onClick={logout}>
|
||||
Sign out
|
||||
{t("Sign out")}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
{error && (
|
||||
<p role="alert" className="error-message">
|
||||
{error}
|
||||
{t(error)}
|
||||
</p>
|
||||
)}
|
||||
{!maps.length && (
|
||||
<div className="empty-state">
|
||||
<h2>A blank map is a beginning.</h2>
|
||||
<h2>{t("A blank map is a beginning.")}</h2>
|
||||
<p>
|
||||
Install the Fabric mod to capture while you explore, or the server
|
||||
plugin to export your world.
|
||||
{t(
|
||||
"Install the Fabric mod to capture while you explore, or the server plugin to export your world.",
|
||||
)}
|
||||
</p>
|
||||
<Link className="button primary" href="/downloads">
|
||||
Get the capture tools →
|
||||
{t("Get the capture tools →")}
|
||||
</Link>
|
||||
</div>
|
||||
)}
|
||||
@@ -111,24 +116,34 @@ export function Dashboard() {
|
||||
<article className="draft-row" key={m.id}>
|
||||
<div>
|
||||
<span className="eyebrow">
|
||||
{m.source === "plugin" ? "SERVER EXPORT" : "PLAYER CAPTURE"}
|
||||
{m.source === "plugin" ? t("SERVER EXPORT") : t("PLAYER CAPTURE")}
|
||||
</span>
|
||||
<h3>{m.name}</h3>
|
||||
<span className="badge">
|
||||
{m.contribution_status
|
||||
? `Contribution: ${m.contribution_status}`
|
||||
? t("Contribution: {status}", {
|
||||
status: t(statusMessage(m.contribution_status)),
|
||||
})
|
||||
: m.update_state
|
||||
? `Update: ${m.update_state}`
|
||||
: m.state}
|
||||
? t("Update: {status}", {
|
||||
status: t(statusMessage(m.update_state)),
|
||||
})
|
||||
: t(statusMessage(m.state))}
|
||||
</span>{" "}
|
||||
<span className="muted">{m.panorama_count} locations</span>
|
||||
<span className="muted">
|
||||
{m.panorama_count} {t("locations")}
|
||||
</span>
|
||||
{m.banned_at ? (
|
||||
<p className="error-message">
|
||||
Map banned after three confirmed reports. Open your map to
|
||||
appeal.
|
||||
{t(
|
||||
"Map banned after three confirmed reports. Open your map to appeal.",
|
||||
)}
|
||||
</p>
|
||||
) : m.report_strikes > 0 ? (
|
||||
<p className="muted">{m.report_strikes}/3 confirmed reports</p>
|
||||
<p className="muted">
|
||||
{m.report_strikes}
|
||||
{t("/3 confirmed reports")}
|
||||
</p>
|
||||
) : null}
|
||||
<ProcessingProgress job={m.upload_jobs} />
|
||||
{m.rejection_reason && (
|
||||
@@ -139,38 +154,42 @@ export function Dashboard() {
|
||||
)}
|
||||
</div>
|
||||
<Link href={"/dashboard/" + m.id} className="button">
|
||||
{m.parent_dataset_id ? "Open contribution →" : "Open map →"}
|
||||
{m.parent_dataset_id ? t("Open contribution →") : t("Open map →")}
|
||||
</Link>
|
||||
</article>
|
||||
))}
|
||||
<section className="token-box">
|
||||
<span className="eyebrow">FOR SERVER ADMINISTRATORS</span>
|
||||
<h2>Link your server plugin.</h2>
|
||||
<span className="eyebrow">{t("FOR SERVER ADMINISTRATORS")}</span>
|
||||
<h2>{t("Link your server plugin.")}</h2>
|
||||
<p className="muted">
|
||||
Create a contributor token, then run{" "}
|
||||
<code>/minegeo link <token></code> in your server console.
|
||||
Fabric uses browser pairing instead.
|
||||
{t("Create a contributor token, then run")}{" "}
|
||||
<code>/minegeo link <token></code>{" "}
|
||||
{t("in your server console. Fabric uses browser pairing instead.")}
|
||||
</p>
|
||||
<button className="button" disabled={busy} onClick={newToken}>
|
||||
Generate plugin token
|
||||
{t("Generate plugin token")}
|
||||
</button>
|
||||
{token && (
|
||||
<>
|
||||
<p className="success-message">
|
||||
Copy this token now. It is shown once. Keep it out of public chat.
|
||||
{t(
|
||||
"Copy this token now. It is shown once. Keep it out of public chat.",
|
||||
)}
|
||||
</p>
|
||||
<code>{token}</code>
|
||||
</>
|
||||
)}
|
||||
{tokens.map((t) => (
|
||||
<div className="draft-row" key={t.id}>
|
||||
{tokens.map((entry) => (
|
||||
<div className="draft-row" key={entry.id}>
|
||||
<span>
|
||||
{t.label}{" "}
|
||||
<small className="muted">{t.revoked ? "· revoked" : ""}</small>
|
||||
{entry.label}{" "}
|
||||
<small className="muted">
|
||||
{entry.revoked ? t("· revoked") : ""}
|
||||
</small>
|
||||
</span>
|
||||
{!t.revoked && (
|
||||
<button className="button" onClick={() => revoke(t.id)}>
|
||||
Revoke
|
||||
{!entry.revoked && (
|
||||
<button className="button" onClick={() => revoke(entry.id)}>
|
||||
{t("Revoke")}
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user