diff --git a/src/app/java/changelog/layout.tsx b/src/app/java/changelog/layout.tsx
index 430bbb5..230db52 100644
--- a/src/app/java/changelog/layout.tsx
+++ b/src/app/java/changelog/layout.tsx
@@ -3,7 +3,6 @@ import {
getVersionManifest,
type VersionManifest,
} from "~/server/java/versions";
-import VersionLink from "~/components/java/version-link";
import { Alert, AlertDescription, AlertTitle } from "~/components/ui/alert";
import {
ActivityLogIcon,
@@ -19,6 +18,9 @@ import {
SheetTrigger,
} from "~/components/ui/sheet";
import { Button } from "~/components/ui/button";
+import ReleaseVersionLinkSet from "~/components/java/release-version-link-set";
+import "~/styles/game-versions.css";
+import { type ReleaseVersionEntry } from "~/components/java/version-link";
export default async function ChangelogLayout({
children,
@@ -64,12 +66,9 @@ export default async function ChangelogLayout({
-
+
+
+
@@ -79,12 +78,10 @@ export default async function ChangelogLayout({
className="h-page rounded-md border"
viewportClassName="overscroll-contain"
>
-
+ Versions
+
+
+
{children}
@@ -95,32 +92,44 @@ export default async function ChangelogLayout({
function VersionLinks({
versions,
- className = "",
+ type,
+ className = ""
}: {
versions: VersionManifest["entries"];
+ type: string;
className?: string;
}) {
- return (
- <>
-
-
-
- {versions.map((v) => {
- return (
-
-
-
- );
- })}
- >
- );
+ const orderedVersions: ReleaseVersionEntry[] = [
+ {
+ name: "Latest",
+ url: "",
+ title: versions[0].title,
+ description: versions[0].shortText,
+ image: versions[0].image,
+ nonReleaseVersions: [],
+ isLatest: true
+ }
+ ];
+ for (const version of versions) {
+ if (version.type === "release") {
+ orderedVersions.push({
+ name: version.version,
+ url: version.version,
+ title: version.title,
+ description: version.shortText,
+ image: version.image,
+ nonReleaseVersions: [],
+ isLatest: false
+ });
+ continue;
+ }
+ orderedVersions.at(-1)!.nonReleaseVersions.push({
+ name: version.version,
+ url: version.version,
+ title: version.title,
+ description: version.shortText,
+ image: version.image
+ });
+ }
+ return orderedVersions.map(version => );
}
diff --git a/src/components/java/release-version-link-set.tsx b/src/components/java/release-version-link-set.tsx
new file mode 100644
index 0000000..5c25106
--- /dev/null
+++ b/src/components/java/release-version-link-set.tsx
@@ -0,0 +1,53 @@
+"use client";
+
+import { usePathname } from "next/navigation";
+import VersionLink, { type ReleaseVersionEntry } from "./version-link";
+
+export default function ReleaseVersionLinkSet({
+ release,
+ type,
+ className,
+}: {
+ release: ReleaseVersionEntry;
+ type: string;
+ className: string;
+}) {
+ const selectedVersion = useVersion();
+ return (
+
+
+ {
+ release.nonReleaseVersions.length > 0 && <>
+
+
+
+ {release.nonReleaseVersions.map(nonReleaseVersion => )}
+
+ >
+ }
+
+ );
+}
+
+function useVersion(): string {
+ const prefix = "java/changelog/";
+ const pathname = usePathname();
+ if (pathname === prefix) {
+ return "";
+ }
+ const probableVersion = pathname.substring(prefix.length);
+ if (probableVersion.startsWith("/")) {
+ return probableVersion.substring(1);
+ }
+ return probableVersion;
+}
+
+function containsVersion(release: ReleaseVersionEntry, version: string): boolean {
+ if (release.isLatest && version === "") {
+ return true;
+ }
+ if (release.name === version) {
+ return true;
+ }
+ return release.nonReleaseVersions.some(nonRelease => nonRelease.name === version);
+}
diff --git a/src/components/java/version-link.tsx b/src/components/java/version-link.tsx
index eb38c55..24f0e95 100644
--- a/src/components/java/version-link.tsx
+++ b/src/components/java/version-link.tsx
@@ -8,41 +8,34 @@ import {
} from "~/components/ui/hover-card";
import Link from "next/link";
import { cn } from "~/lib/utils";
-import { usePathname } from "next/navigation";
import {
BASE_ASSET_URL,
- type VersionManifestEntry,
} from "~/server/java/versions";
import type { ClassValue } from "clsx";
export default function VersionLink({
- versionName,
- versionLink = versionName,
- data: { shortText, title, image },
+ version,
className = "px-3 py-1",
+ selected,
}: {
- versionName: string;
- versionLink?: string;
- data: VersionManifestEntry;
+ version: VersionEntry;
className?: ClassValue;
+ selected: boolean;
}) {
- const url = `/java/changelog/${versionLink}`;
- const pathname = usePathname();
- const selected = url === pathname || url === pathname + "/";
-
+ const url = `/java/changelog/${version.url}`;
return (
- {versionName}
+ {version.name}
@@ -53,13 +46,26 @@ export default function VersionLink({
- {title}
- {shortText}…
+ {version.title}
+ {version.description}…
);
}
+
+export interface VersionEntry {
+ name: string;
+ url: string;
+ title: string;
+ description: string;
+ image: { title: string; url: string; };
+}
+
+export interface ReleaseVersionEntry extends VersionEntry {
+ nonReleaseVersions: VersionEntry[];
+ isLatest: boolean;
+}
diff --git a/src/styles/arrow_down.svg b/src/styles/arrow_down.svg
new file mode 100644
index 0000000..349e67e
--- /dev/null
+++ b/src/styles/arrow_down.svg
@@ -0,0 +1,3 @@
+
diff --git a/src/styles/arrow_up.svg b/src/styles/arrow_up.svg
new file mode 100644
index 0000000..f58a950
--- /dev/null
+++ b/src/styles/arrow_up.svg
@@ -0,0 +1,3 @@
+
diff --git a/src/styles/game-versions.css b/src/styles/game-versions.css
new file mode 100644
index 0000000..c1d72ef
--- /dev/null
+++ b/src/styles/game-versions.css
@@ -0,0 +1,47 @@
+.versions {
+ display: flex;
+ flex-direction: column;
+ margin-left: 0.5em;
+ user-select: none;
+}
+
+.versions input {
+ display: none;
+}
+
+.major-version {
+ display: grid;
+ gap: 0 0.5em;
+ grid-template-rows: auto 1fr;
+ grid-template-columns: 1em 1fr;
+ grid-template-areas:
+ "button title"
+ ". body";
+}
+
+.major-version > .version-label {
+ grid-area: title;
+ font-weight: bold;
+}
+
+.major-version-button {
+ aspect-ratio: 1 / 1;
+ align-self: center;
+ grid-area: button;
+ mask-image: url("arrow_down.svg");
+ background-color: rgb(var(--ctp-subtext1));
+}
+
+input:checked + .major-version-button {
+ mask-image: url("arrow_up.svg");
+}
+
+.major-version-body {
+ grid-area: body;
+ display: none;
+}
+
+input:checked ~ .major-version-body {
+ display: flex;
+ flex-direction: column;
+}