Add Void difficulty and publish changelogs
Some checks failed
Deploy MineGeo to Dokploy / deploy (push) Failing after 3m40s

This commit is contained in:
2026-10-20 14:05:01 +05:00
parent 3ba398a838
commit de0e891b62
37 changed files with 995 additions and 65 deletions

View File

@@ -33,7 +33,7 @@ export default async function About() {
<h2>{t("Five chances to find your way")}</h2>
<p>
{t(
"Easy gives you 180 seconds, Normal 90, and Hard 30. Hard disables zoom. A timed-out round scores zero; you can still finish the expedition.",
"Easy gives you 180 seconds, Normal 90, and Hard 30. Void is the hardest: just 10 seconds, a fixed panorama and map, no zoom, no compass or coordinates, and strict scoring. A timed-out round scores zero; you can still finish the expedition.",
)}
</p>
<h2>{t("Closer means better")}</h2>

View File

@@ -384,7 +384,10 @@ html[data-theme="light"] .site-cursor-dot span {
background: #273b21;
box-shadow: 0 0 1px #fff;
}
@media (max-width: 1200px) {
.header-inner {
max-width: 1600px;
}
@media (max-width: 1500px) {
.site-header {
height: auto;
}
@@ -458,3 +461,31 @@ html[data-theme="light"] .site-cursor-dot span {
grid-row: 3;
}
}
.difficulty-options button.difficulty-void {
border-color: #a855f7;
background: linear-gradient(145deg, #21122f, #100c18);
color: #e9d5ff;
box-shadow: 0 0 16px #a855f738, inset 0 0 20px #a855f710;
}
.difficulty-options button.difficulty-void strong {
color: #e9d5ff;
text-shadow: 0 0 10px #c084fc99, 0 0 22px #a855f780;
}
.difficulty-options button.difficulty-void.selected,
html[data-theme="light"] .difficulty-options button.difficulty-void.selected {
color: #f3e8ff;
background: linear-gradient(145deg, #482363, #21122f);
border-color: #d8b4fe;
box-shadow: 0 0 24px #a855f760, inset 0 0 20px #c084fc18;
}
html[data-theme="light"] .difficulty-options button.difficulty-void {
background: #f3e8ff;
border-color: #a855f7;
color: #581c87;
}
html[data-theme="light"] .difficulty-options button.difficulty-void strong {
color: #7e22ce;
}
html[data-theme="light"] .difficulty-options button.difficulty-void.selected strong {
color: #f3e8ff;
}

77
app/changelogs/page.tsx Normal file
View File

@@ -0,0 +1,77 @@
import Link from "next/link";
import type { Metadata } from "next";
import { Header, Footer } from "@/components/Shell";
import { ReleaseNotes } from "@/components/ReleaseNotes";
import { ChangelogRefresh } from "@/components/ChangelogRefresh";
import { getChangelog } from "@/lib/changelog";
import { getI18n } from "@/lib/i18n";
export const metadata: Metadata = {
title: "Changelogs",
description: "The latest MineGeo releases, improvements, and bug fixes.",
};
export default async function ChangelogsPage({
searchParams,
}: {
searchParams: Promise<{ before?: string }>;
}) {
const params = await searchParams;
const before =
typeof params.before === "string" && /^\d{17,20}$/.test(params.before)
? params.before
: undefined;
const [{ t, formatDate }, feed] = await Promise.all([
getI18n(),
getChangelog(before),
]);
return (
<>
<Header />
<main className="section page-content changelog-page">
{!before && <ChangelogRefresh />}
<span className="eyebrow">{t("WHAT'S NEW")}</span>
<h1>{t("Changelogs")}</h1>
<p className="lead">
{t("New releases, improvements, and fixes from MineGeo.")}
</p>
{before && <Link href="/changelogs">{t("Latest releases")}</Link>}
{feed.unavailable ? (
<div className="empty-state">
<h2>{t("Release notes are temporarily unavailable")}</h2>
<p>{t("Please check back soon.")}</p>
</div>
) : feed.entries.length === 0 ? (
<p className="muted">{t("No releases on this page yet.")}</p>
) : (
<div className="changelog-list">
{feed.entries.map((entry) => (
<article
className="changelog-entry"
key={entry.id}
id={`release-${entry.id}`}
>
<div className="changelog-meta">
<span className="tag">{t(entry.kind)}</span>
<time dateTime={entry.publishedAt}>
{formatDate(entry.publishedAt)}
</time>
</div>
<h2>{entry.title}</h2>
<div className="release-notes">
<ReleaseNotes body={entry.body} />
</div>
</article>
))}
</div>
)}
{!feed.unavailable && "before" in feed && feed.before && (
<Link className="button" href={`/changelogs?before=${feed.before}`}>
{t("Older posts")}
</Link>
)}
</main>
<Footer />
</>
);
}

View File

@@ -56,7 +56,7 @@ export default async function DashboardPage() {
typeof s.difficulty_settings === "object" &&
!Array.isArray(s.difficulty_settings) &&
typeof s.difficulty_settings.name === "string"
? ["easy", "normal", "hard"].includes(s.difficulty)
? ["easy", "normal", "hard", "void"].includes(s.difficulty)
? t(s.difficulty_settings.name)
: s.difficulty_settings.name
: t(

View File

@@ -1745,3 +1745,13 @@ pre {
display: block;
position: relative;
}
.changelog-page { max-width: 960px; }
.changelog-list { margin: 36px 0; }
.changelog-entry { padding: 32px 0; border-top: 1px solid var(--line); scroll-margin-top: 100px; }
.changelog-entry h2 { margin: 14px 0 20px; font-size: clamp(1.4rem, 3vw, 2rem); }
.changelog-meta { display: flex; align-items: center; flex-wrap: wrap; gap: 16px; color: var(--muted); font-size: .85rem; }
.release-notes { line-height: 1.8; overflow-wrap: anywhere; }
.release-notes ul { padding-left: 24px; }
.release-notes li + li { margin-top: 12px; }
.release-notes p { white-space: normal; }

View File

@@ -23,7 +23,7 @@ export async function generateMetadata(): Promise<Metadata> {
return {
title: t("Leaderboard"),
description: t(
"Meet MineGeo’s top explorers. Compare the best five-round scores across easy, normal, and hard Minecraft expeditions.",
"Meet MineGeo’s top explorers. Compare the best five-round scores across Easy, Normal, Hard, and Void Minecraft expeditions.",
),
};
}