mirror of
https://github.com/DeveloLongScript/MHSF.git
synced 2026-05-07 17:44:59 -05:00
feat(www): added statistical banner
This commit is contained in:
parent
45e0924808
commit
bbec84c7de
@ -1,16 +1,16 @@
|
|||||||
// For Edge runtime, we need to use fetch instead of fs
|
// For Edge runtime, we need to use fetch instead of fs
|
||||||
export async function loadFonts() {
|
export async function loadFonts() {
|
||||||
const interRegularFontP = fetch(
|
const interRegularFontP = fetch(
|
||||||
new URL("./Inter-Regular.ttf", import.meta.url),
|
new URL("./Inter-Regular.ttf", import.meta.url)
|
||||||
).then((res) => res.arrayBuffer());
|
).then((res) => res.arrayBuffer());
|
||||||
|
|
||||||
const interMediumFontP = fetch(
|
const interMediumFontP = fetch(
|
||||||
new URL("./Inter-Medium.ttf", import.meta.url),
|
new URL("./Inter-Medium.ttf", import.meta.url)
|
||||||
).then((res) => res.arrayBuffer());
|
).then((res) => res.arrayBuffer());
|
||||||
|
|
||||||
const interBoldFontP = fetch(
|
const interBoldFontP = fetch(
|
||||||
new URL("./Inter-Bold.ttf", import.meta.url),
|
new URL("./Inter-Bold.ttf", import.meta.url)
|
||||||
).then((res) => res.arrayBuffer());
|
).then((res) => res.arrayBuffer());
|
||||||
|
|
||||||
return Promise.all([interRegularFontP, interMediumFontP, interBoldFontP]);
|
return Promise.all([interRegularFontP, interMediumFontP, interBoldFontP]);
|
||||||
}
|
}
|
||||||
|
|||||||
643
apps/www/src/app/api/og/server/[id]/players/route.tsx
Normal file
643
apps/www/src/app/api/og/server/[id]/players/route.tsx
Normal file
@ -0,0 +1,643 @@
|
|||||||
|
import { ImageResponse } from "@vercel/og";
|
||||||
|
import { NextRequest } from "next/server";
|
||||||
|
import { MongoClient } from "mongodb";
|
||||||
|
import fs from "node:fs";
|
||||||
|
import path from "node:path";
|
||||||
|
|
||||||
|
// Helper function to format dates
|
||||||
|
function formatDate(date: Date): string {
|
||||||
|
return date.toLocaleDateString("en-US", {
|
||||||
|
month: "short",
|
||||||
|
day: "numeric",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Helper function to format times
|
||||||
|
function formatTime(date: Date): string {
|
||||||
|
return date.toLocaleTimeString("en-US", {
|
||||||
|
hour: "2-digit",
|
||||||
|
minute: "2-digit",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Load fonts directly from the filesystem
|
||||||
|
async function loadLocalFonts() {
|
||||||
|
const fontPath = path.join(process.cwd(), "src", "app", "api", "og", "fonts");
|
||||||
|
|
||||||
|
return [
|
||||||
|
fs.readFileSync(path.join(fontPath, "Inter-Regular.ttf")),
|
||||||
|
fs.readFileSync(path.join(fontPath, "Inter-Medium.ttf")),
|
||||||
|
fs.readFileSync(path.join(fontPath, "Inter-Bold.ttf")),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function GET(
|
||||||
|
request: NextRequest,
|
||||||
|
{ params }: { params: Promise<{ id: string }> }
|
||||||
|
) {
|
||||||
|
try {
|
||||||
|
// Load banner image from filesystem
|
||||||
|
const bannerPath = path.join(
|
||||||
|
process.cwd(),
|
||||||
|
"public",
|
||||||
|
"branding",
|
||||||
|
"bg-banner.png"
|
||||||
|
);
|
||||||
|
const bannerImageData = fs.readFileSync(bannerPath);
|
||||||
|
|
||||||
|
const id = (await params).id;
|
||||||
|
|
||||||
|
// Load fonts
|
||||||
|
const [interRegular, interMedium, interBold] = await loadLocalFonts();
|
||||||
|
|
||||||
|
// Verify server exists
|
||||||
|
const serverResponse = await fetch(`https://api.minehut.com/server/${id}`);
|
||||||
|
const serverData = await serverResponse.json();
|
||||||
|
|
||||||
|
if (!serverData.server) {
|
||||||
|
// Return a default banner for server not found
|
||||||
|
return new ImageResponse(
|
||||||
|
(
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
display: "flex",
|
||||||
|
fontSize: 60,
|
||||||
|
color: "white",
|
||||||
|
width: "100%",
|
||||||
|
height: "100%",
|
||||||
|
padding: "50px 50px",
|
||||||
|
textAlign: "center",
|
||||||
|
justifyContent: "center",
|
||||||
|
alignItems: "center",
|
||||||
|
backgroundImage: `url(data:image/png;base64,${bannerImageData.toString("base64")})`,
|
||||||
|
backgroundSize: "cover",
|
||||||
|
backgroundPosition: "center",
|
||||||
|
fontFamily: "Inter",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<div style={{ display: "flex" }}>
|
||||||
|
<span style={{ display: "flex" }}>Server not found</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
),
|
||||||
|
{
|
||||||
|
width: 1200,
|
||||||
|
height: 630,
|
||||||
|
fonts: [
|
||||||
|
{
|
||||||
|
name: "Inter",
|
||||||
|
data: interRegular,
|
||||||
|
style: "normal",
|
||||||
|
weight: 400,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const serverName = serverData.server.name;
|
||||||
|
|
||||||
|
// Connect to MongoDB
|
||||||
|
const mongo = new MongoClient(process.env.MONGO_DB as string);
|
||||||
|
await mongo.connect();
|
||||||
|
const db = mongo.db(process.env.CUSTOM_MONGO_DB ?? "mhsf");
|
||||||
|
|
||||||
|
// Get player data (last 60 entries)
|
||||||
|
const historyCollection = db.collection("history");
|
||||||
|
const playerData = await historyCollection
|
||||||
|
.find({ server: serverName })
|
||||||
|
.sort({ date: -1 })
|
||||||
|
.limit(80)
|
||||||
|
.project({ player_count: 1, date: 1, _id: 0 })
|
||||||
|
.toArray();
|
||||||
|
|
||||||
|
// Close MongoDB connection
|
||||||
|
await mongo.close();
|
||||||
|
|
||||||
|
// Reverse the data to show oldest to newest
|
||||||
|
const playerHistory = playerData.reverse();
|
||||||
|
|
||||||
|
// Calculate max player count for scaling
|
||||||
|
const maxPlayerCount = Math.max(
|
||||||
|
...playerHistory.map((item: any) => item.player_count || 0),
|
||||||
|
1 // Ensure we have at least 1 as max to avoid division by zero
|
||||||
|
);
|
||||||
|
|
||||||
|
// Calculate average player count
|
||||||
|
const averagePlayerCount = Math.round(
|
||||||
|
playerHistory.reduce(
|
||||||
|
(sum: number, item: any) => sum + (item.player_count || 0),
|
||||||
|
0
|
||||||
|
) / Math.max(playerHistory.length, 1)
|
||||||
|
);
|
||||||
|
|
||||||
|
// Get current player count
|
||||||
|
const currentPlayerCount =
|
||||||
|
playerHistory.length > 0
|
||||||
|
? playerHistory[playerHistory.length - 1].player_count || 0
|
||||||
|
: 0;
|
||||||
|
|
||||||
|
const bars = [];
|
||||||
|
const numBars = Math.min(playerHistory.length, 30); // Limit to 30 bars for better visibility
|
||||||
|
const step = Math.max(1, Math.floor(playerHistory.length / numBars));
|
||||||
|
|
||||||
|
// Create Y-axis markers (player count) - Modified to avoid drawing horizontal lines that intersect with Y-axis
|
||||||
|
const yAxisMarkers = [];
|
||||||
|
const numYMarkers = 4; // Reduced to 4 for better alignment
|
||||||
|
|
||||||
|
for (let i = 0; i <= numYMarkers; i++) {
|
||||||
|
const value = Math.round((maxPlayerCount * i) / numYMarkers);
|
||||||
|
const position = 200 - (i / numYMarkers) * 200;
|
||||||
|
|
||||||
|
yAxisMarkers.push(
|
||||||
|
<div
|
||||||
|
key={`y-marker-${i}`}
|
||||||
|
style={{
|
||||||
|
display: "flex",
|
||||||
|
position: "absolute",
|
||||||
|
left: "50px",
|
||||||
|
top: `${position}px`,
|
||||||
|
width: "1100px",
|
||||||
|
borderTop: i > 0 ? "1px dashed rgba(255, 255, 255, 0.2)" : "none",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
display: "flex",
|
||||||
|
position: "absolute",
|
||||||
|
left: "-40px",
|
||||||
|
top: "-10px",
|
||||||
|
fontSize: "12px",
|
||||||
|
color: "rgba(255, 255, 255, 0.7)",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{value}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const chartWidth = 970; // Fixed width of the chart area
|
||||||
|
// Create X-axis markers (times)
|
||||||
|
const xAxisMarkers = [];
|
||||||
|
const numXMarkers = Math.min(10, playerHistory.length); // Increased to 10 for more labels
|
||||||
|
|
||||||
|
if (playerHistory.length > 0) {
|
||||||
|
for (let i = 0; i < numXMarkers; i++) {
|
||||||
|
const index = Math.floor(
|
||||||
|
(i / (numXMarkers - 1)) * (playerHistory.length - 1)
|
||||||
|
);
|
||||||
|
const item = playerHistory[index];
|
||||||
|
const position = (index / (playerHistory.length - 1)) * chartWidth;
|
||||||
|
|
||||||
|
xAxisMarkers.push(
|
||||||
|
<div
|
||||||
|
key={`x-marker-${i}`}
|
||||||
|
style={{
|
||||||
|
display: "flex",
|
||||||
|
position: "absolute",
|
||||||
|
left: `${position + 50}px`, // Add 50px offset for Y-axis
|
||||||
|
bottom: "-25px",
|
||||||
|
transform: "translateX(-50%)",
|
||||||
|
fontSize: "12px",
|
||||||
|
color: "rgba(255, 255, 255, 0.7)",
|
||||||
|
whiteSpace: "nowrap",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{formatTime(new Date(item.date))}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let i = 0; i < playerHistory.length; i += step) {
|
||||||
|
const item = playerHistory[i];
|
||||||
|
const height = Math.max(
|
||||||
|
5,
|
||||||
|
((item.player_count || 0) / maxPlayerCount) * 200
|
||||||
|
);
|
||||||
|
const position = (i / (playerHistory.length - 1)) * chartWidth;
|
||||||
|
|
||||||
|
bars.push(
|
||||||
|
<div
|
||||||
|
key={`bar-${i}`}
|
||||||
|
style={{
|
||||||
|
display: "flex",
|
||||||
|
flexDirection: "column",
|
||||||
|
justifyContent: "flex-end",
|
||||||
|
width: "16px",
|
||||||
|
height: "209px",
|
||||||
|
position: "absolute",
|
||||||
|
left: `${position}px`, // Add 50px offset for Y-axis
|
||||||
|
transform: "translateX(-50%)",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
display: "flex",
|
||||||
|
width: "100%",
|
||||||
|
height: `${height}px`,
|
||||||
|
backgroundColor: "#4ade80",
|
||||||
|
borderRadius: "2px 2px 0 0",
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new ImageResponse(
|
||||||
|
(
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
display: "flex",
|
||||||
|
flexDirection: "column",
|
||||||
|
width: "100%",
|
||||||
|
height: "100%",
|
||||||
|
padding: "50px",
|
||||||
|
position: "relative",
|
||||||
|
overflow: "hidden",
|
||||||
|
fontFamily: "Inter",
|
||||||
|
backgroundImage: `url(data:image/png;base64,${bannerImageData.toString("base64")})`,
|
||||||
|
backgroundSize: "cover",
|
||||||
|
backgroundPosition: "center",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{/* Decorative elements */}
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
position: "absolute",
|
||||||
|
top: "-100px",
|
||||||
|
right: "-100px",
|
||||||
|
width: "400px",
|
||||||
|
height: "400px",
|
||||||
|
borderRadius: "50%",
|
||||||
|
background: "rgba(79, 70, 229, 0.1)",
|
||||||
|
filter: "blur(40px)",
|
||||||
|
display: "flex",
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
position: "absolute",
|
||||||
|
bottom: "-100px",
|
||||||
|
left: "-100px",
|
||||||
|
width: "300px",
|
||||||
|
height: "300px",
|
||||||
|
borderRadius: "50%",
|
||||||
|
background: "rgba(236, 72, 153, 0.1)",
|
||||||
|
filter: "blur(40px)",
|
||||||
|
display: "flex",
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
|
||||||
|
{/* Header with server name */}
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
display: "flex",
|
||||||
|
alignItems: "center",
|
||||||
|
marginBottom: "20px",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<h1
|
||||||
|
style={{
|
||||||
|
fontSize: 40,
|
||||||
|
fontWeight: "bold",
|
||||||
|
margin: 0,
|
||||||
|
display: "flex",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<span style={{ display: "flex" }}>
|
||||||
|
{serverName} - Player Statistics
|
||||||
|
</span>
|
||||||
|
</h1>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Stats summary */}
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
display: "flex",
|
||||||
|
justifyContent: "space-around",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
display: "flex",
|
||||||
|
flexDirection: "column",
|
||||||
|
alignItems: "center",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<div style={{ fontSize: 20, opacity: 0.7, display: "flex" }}>
|
||||||
|
<span style={{ display: "flex" }}>Max Players</span>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
style={{ fontSize: 36, fontWeight: "bold", display: "flex" }}
|
||||||
|
>
|
||||||
|
<span style={{ display: "flex" }}>{maxPlayerCount}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
display: "flex",
|
||||||
|
flexDirection: "column",
|
||||||
|
alignItems: "center",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<div style={{ fontSize: 20, opacity: 0.7, display: "flex" }}>
|
||||||
|
<span style={{ display: "flex" }}>Average Players</span>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
style={{ fontSize: 36, fontWeight: "bold", display: "flex" }}
|
||||||
|
>
|
||||||
|
<span style={{ display: "flex" }}>{averagePlayerCount}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
display: "flex",
|
||||||
|
flexDirection: "column",
|
||||||
|
alignItems: "center",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<div style={{ fontSize: 20, opacity: 0.7, display: "flex" }}>
|
||||||
|
<span style={{ display: "flex" }}>Current Players</span>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
style={{ fontSize: 36, fontWeight: "bold", display: "flex" }}
|
||||||
|
>
|
||||||
|
<span style={{ display: "flex" }}>{currentPlayerCount}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Bar chart container */}
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
display: "flex",
|
||||||
|
justifyContent: "center",
|
||||||
|
alignItems: "flex-end",
|
||||||
|
marginTop: "10px",
|
||||||
|
height: "270px",
|
||||||
|
width: "100%",
|
||||||
|
backgroundColor: "rgba(0, 0, 0, 0.2)",
|
||||||
|
borderRadius: "8px",
|
||||||
|
padding: "20px 40px 20px 40px", // Added padding for Y-axis labels
|
||||||
|
position: "relative", // For absolute positioning of markers
|
||||||
|
backdropFilter: "blur(12px)",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{/* Chart content container */}
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
position: "relative",
|
||||||
|
width: "100%",
|
||||||
|
height: "220px",
|
||||||
|
paddingBottom: "10px",
|
||||||
|
display: "flex",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{/* Y-axis and X-axis are now drawn as a single element to ensure continuity */}
|
||||||
|
<svg
|
||||||
|
width="100%"
|
||||||
|
height="100%"
|
||||||
|
style={{
|
||||||
|
position: "absolute",
|
||||||
|
top: 0,
|
||||||
|
left: 0,
|
||||||
|
pointerEvents: "none",
|
||||||
|
zIndex: "20",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{/* Y-axis line */}
|
||||||
|
<line
|
||||||
|
x1="50" // Changed from 30 to match new spacing
|
||||||
|
y1="0"
|
||||||
|
x2="50" // Changed from 30 to match new spacing
|
||||||
|
y2="200"
|
||||||
|
stroke="white"
|
||||||
|
strokeWidth="2"
|
||||||
|
strokeOpacity="0.8"
|
||||||
|
/>
|
||||||
|
{/* X-axis line */}
|
||||||
|
<line
|
||||||
|
x1="50"
|
||||||
|
y1="200"
|
||||||
|
x2="1150"
|
||||||
|
y2="200"
|
||||||
|
stroke="white"
|
||||||
|
strokeWidth="2"
|
||||||
|
strokeOpacity="0.8"
|
||||||
|
/>
|
||||||
|
{/* Y-axis tick marks */}
|
||||||
|
{Array.from({ length: numYMarkers + 1 }).map((_, i) => {
|
||||||
|
const yPosition = 200 - (i / numYMarkers) * 200;
|
||||||
|
return (
|
||||||
|
<line
|
||||||
|
key={`y-tick-${i}`}
|
||||||
|
x1="45" // Changed from 25 to match new spacing
|
||||||
|
y1={yPosition}
|
||||||
|
x2="50" // Changed from 30 to match new spacing
|
||||||
|
y2={yPosition}
|
||||||
|
stroke="white"
|
||||||
|
strokeWidth="2"
|
||||||
|
strokeOpacity="0.8"
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</svg>
|
||||||
|
|
||||||
|
{/* Y-axis markers (labels and grid lines) */}
|
||||||
|
<div style={{ display: "flex" }}>{yAxisMarkers}</div>
|
||||||
|
|
||||||
|
{/* X-axis markers */}
|
||||||
|
<div style={{ display: "flex" }}>{xAxisMarkers}</div>
|
||||||
|
|
||||||
|
{/* Bars */}
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
display: "flex",
|
||||||
|
position: "relative",
|
||||||
|
width: "1100px",
|
||||||
|
height: "220px",
|
||||||
|
marginLeft: "50px",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{bars}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Chart legend */}
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
display: "flex",
|
||||||
|
justifyContent: "space-between",
|
||||||
|
marginTop: "10px",
|
||||||
|
marginBottom: "30px",
|
||||||
|
fontSize: "14px",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<div style={{ display: "flex" }}>
|
||||||
|
<span style={{ display: "flex" }}>
|
||||||
|
Oldest Entry:{" "}
|
||||||
|
{playerHistory.length > 0
|
||||||
|
? formatDate(new Date(playerHistory[0].date))
|
||||||
|
: "N/A"}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div style={{ display: "flex" }}>
|
||||||
|
<span style={{ display: "flex" }}>
|
||||||
|
Latest Entry:{" "}
|
||||||
|
{playerHistory.length > 0
|
||||||
|
? formatDate(
|
||||||
|
new Date(playerHistory[playerHistory.length - 1].date)
|
||||||
|
)
|
||||||
|
: "N/A"}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Footer */}
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
display: "flex",
|
||||||
|
justifyContent: "space-between",
|
||||||
|
alignItems: "center",
|
||||||
|
fontSize: 18,
|
||||||
|
marginTop: "30px",
|
||||||
|
opacity: 0.7,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<div style={{ display: "flex" }}>
|
||||||
|
<span style={{ display: "flex" }}>✨ Powered by mhsf.app</span>
|
||||||
|
</div>
|
||||||
|
<br />
|
||||||
|
<small
|
||||||
|
style={{
|
||||||
|
fontSize: 12,
|
||||||
|
textAlign: "center",
|
||||||
|
display: "flex",
|
||||||
|
flexDirection: "column",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<span style={{ display: "flex" }}>
|
||||||
|
Licensed under MIT license using open source technologies.
|
||||||
|
</span>
|
||||||
|
<span style={{ display: "flex", textAlign: "center" }}>
|
||||||
|
Using dynamic statistical data version 1.
|
||||||
|
</span>
|
||||||
|
<span style={{ display: "flex", textAlign: "center" }}>
|
||||||
|
Not officially affiliated with Minehut, GamerSafer or Super
|
||||||
|
League Enterprise.
|
||||||
|
</span>
|
||||||
|
</small>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
),
|
||||||
|
{
|
||||||
|
width: 1200,
|
||||||
|
height: 630,
|
||||||
|
fonts: [
|
||||||
|
{
|
||||||
|
name: "Inter",
|
||||||
|
data: interRegular,
|
||||||
|
style: "normal",
|
||||||
|
weight: 400,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Inter",
|
||||||
|
data: interBold,
|
||||||
|
style: "normal",
|
||||||
|
weight: 700,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Inter",
|
||||||
|
data: interMedium,
|
||||||
|
style: "normal",
|
||||||
|
weight: 500,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}
|
||||||
|
);
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Error generating player statistics image:", error);
|
||||||
|
|
||||||
|
// Load fonts for error page
|
||||||
|
let interRegular: Buffer | null = null;
|
||||||
|
try {
|
||||||
|
interRegular = (await loadLocalFonts())[0];
|
||||||
|
} catch (e) {
|
||||||
|
// If we can't load fonts, we'll just use a system font
|
||||||
|
console.error("Failed to load fonts for error page:", e);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try to load the banner image
|
||||||
|
let bannerImageData: Buffer | null = null;
|
||||||
|
try {
|
||||||
|
const bannerPath = path.join(
|
||||||
|
process.cwd(),
|
||||||
|
"public",
|
||||||
|
"branding",
|
||||||
|
"dark-banner.png"
|
||||||
|
);
|
||||||
|
bannerImageData = fs.readFileSync(bannerPath);
|
||||||
|
} catch (e) {
|
||||||
|
// If banner image fails to load, use a solid color background
|
||||||
|
console.error("Failed to load banner image for error page:", e);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new ImageResponse(
|
||||||
|
(
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
display: "flex",
|
||||||
|
fontSize: 60,
|
||||||
|
color: "white",
|
||||||
|
background: bannerImageData ? undefined : "#121212",
|
||||||
|
width: "100%",
|
||||||
|
height: "100%",
|
||||||
|
padding: "50px 50px",
|
||||||
|
textAlign: "center",
|
||||||
|
justifyContent: "center",
|
||||||
|
alignItems: "center",
|
||||||
|
fontFamily: "Inter",
|
||||||
|
...(bannerImageData && {
|
||||||
|
backgroundImage: `url(data:image/png;base64,${bannerImageData.toString("base64")})`,
|
||||||
|
backgroundSize: "cover",
|
||||||
|
backgroundPosition: "center",
|
||||||
|
}),
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
display: "flex",
|
||||||
|
flexDirection: "column",
|
||||||
|
alignItems: "center",
|
||||||
|
gap: "20px",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<span style={{ display: "flex" }}>
|
||||||
|
Error generating player statistics image
|
||||||
|
</span>
|
||||||
|
<span style={{ fontSize: 24, display: "flex" }}>
|
||||||
|
{String(error).substring(0, 100)}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
),
|
||||||
|
{
|
||||||
|
width: 1200,
|
||||||
|
height: 630,
|
||||||
|
fonts: interRegular
|
||||||
|
? [
|
||||||
|
{
|
||||||
|
name: "Inter",
|
||||||
|
data: interRegular,
|
||||||
|
style: "normal",
|
||||||
|
weight: 400,
|
||||||
|
},
|
||||||
|
]
|
||||||
|
: undefined,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
32
apps/www/src/config/version.ts
Normal file
32
apps/www/src/config/version.ts
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
/*
|
||||||
|
* MHSF, Minehut Server List
|
||||||
|
* All external content is rather licensed under the ECA Agreement
|
||||||
|
* located here: https://mhsf.app/docs/legal/external-content-agreement
|
||||||
|
*
|
||||||
|
* All code under MHSF is licensed under the MIT License
|
||||||
|
* by open source contributors
|
||||||
|
*
|
||||||
|
* Copyright (c) 2025 dvelo
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to
|
||||||
|
* deal in the Software without restriction, including without limitation the
|
||||||
|
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||||
|
* sell copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
||||||
|
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||||
|
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||||
|
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||||
|
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||||
|
* OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
"use client";
|
||||||
|
export const version = "2.0";
|
||||||
@ -1,527 +0,0 @@
|
|||||||
/*
|
|
||||||
* MHSF, Minehut Server List
|
|
||||||
* All external content is rather licensed under the ECA Agreement
|
|
||||||
* located here: https://mhsf.app/docs/legal/external-content-agreement
|
|
||||||
*
|
|
||||||
* All code under MHSF is licensed under the MIT License
|
|
||||||
* by open source contributors
|
|
||||||
*
|
|
||||||
* Copyright (c) 2025 dvelo
|
|
||||||
*
|
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
* of this software and associated documentation files (the "Software"), to
|
|
||||||
* deal in the Software without restriction, including without limitation the
|
|
||||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
|
||||||
* sell copies of the Software, and to permit persons to whom the Software is
|
|
||||||
* furnished to do so, subject to the following conditions:
|
|
||||||
*
|
|
||||||
* The above copyright notice and this permission notice shall be included in all
|
|
||||||
* copies or substantial portions of the Software.
|
|
||||||
*
|
|
||||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
||||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
|
||||||
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
||||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
|
||||||
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
|
||||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
||||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
|
||||||
* OTHER DEALINGS IN THE SOFTWARE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
"use client";
|
|
||||||
import { Link } from "@/components/util/link";
|
|
||||||
import { Button } from "@/components/ui/button";
|
|
||||||
import Github from "@/components/ui/github";
|
|
||||||
import type { ReactNode } from "react";
|
|
||||||
|
|
||||||
const User = ({ user }: { user: string }) => (
|
|
||||||
<span className="cursor-pointer bg-[rgba(255,165,0,0.25);] rounded p-[2.5px]">
|
|
||||||
{user}
|
|
||||||
</span>
|
|
||||||
);
|
|
||||||
|
|
||||||
const FeatureList = ({
|
|
||||||
features,
|
|
||||||
title,
|
|
||||||
github,
|
|
||||||
}: {
|
|
||||||
features: (string | ReactNode)[];
|
|
||||||
github?: string;
|
|
||||||
title: ReactNode;
|
|
||||||
}) => {
|
|
||||||
return (
|
|
||||||
<ul>
|
|
||||||
{title}
|
|
||||||
{github && (
|
|
||||||
<Link href={github}>
|
|
||||||
<Button variant="ghost" size="sm">
|
|
||||||
<Github className="mr-1" /> Release
|
|
||||||
</Button>
|
|
||||||
</Link>
|
|
||||||
)}
|
|
||||||
{features.map((feature, i) => (
|
|
||||||
<li key={i}>• {feature}</li>
|
|
||||||
))}
|
|
||||||
</ul>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export const version = "2.0";
|
|
||||||
export const changelog: { name: string; id: string; changelog: ReactNode }[] = [
|
|
||||||
{
|
|
||||||
id: "tnjageringae231nfnajrekgra",
|
|
||||||
name: "v1.8.0",
|
|
||||||
changelog: (
|
|
||||||
<FeatureList
|
|
||||||
github="https://github.com/DeveloLongScript/MHSF/releases/tag/1.8.0"
|
|
||||||
features={[
|
|
||||||
"Major changes have been made with the technical project structure",
|
|
||||||
"Please check the GitHub for information about the status of the project.",
|
|
||||||
]}
|
|
||||||
title={
|
|
||||||
<strong className="flex items-center">
|
|
||||||
Version 1.8.0 (February 14th 2025, {"<3 happy valentines"})
|
|
||||||
</strong>
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "tj4ijg09aern9eargjjuauerr",
|
|
||||||
name: "v1.7.5",
|
|
||||||
changelog: (
|
|
||||||
<FeatureList
|
|
||||||
github="https://github.com/DeveloLongScript/MHSF/releases/tag/1.7.5"
|
|
||||||
features={["Migrated accounts from development to production"]}
|
|
||||||
title={
|
|
||||||
<strong className="flex items-center">
|
|
||||||
Version 1.7.5 (January 29th 2025)
|
|
||||||
</strong>
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "38ufajf8efajwj3njdaisef",
|
|
||||||
name: "v1.7",
|
|
||||||
changelog: (
|
|
||||||
<FeatureList
|
|
||||||
github="https://github.com/DeveloLongScript/MHSF/releases/tag/1.7"
|
|
||||||
features={[
|
|
||||||
"Partnered with CoreBoxx!",
|
|
||||||
"You can now link your Minecraft account on CoreBoxx! (check out CB 3.0.15)",
|
|
||||||
"Revamped the server finding controls",
|
|
||||||
"Fixed various bugs",
|
|
||||||
"Made banners a different style",
|
|
||||||
"Made Discord embed not inside a card",
|
|
||||||
"Added incorrect server capitalization detection",
|
|
||||||
"Made the MOTD area slightly bigger",
|
|
||||||
"New footer",
|
|
||||||
"Added padding for settings page",
|
|
||||||
"Added new table mode",
|
|
||||||
"Added new button for GitHub release on changelog",
|
|
||||||
]}
|
|
||||||
title={
|
|
||||||
<strong className="flex items-center">
|
|
||||||
Version 1.7 (January 18th 2025)
|
|
||||||
</strong>
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "dut6hx3f2paswzjve4yg9r",
|
|
||||||
name: "v1.6.5",
|
|
||||||
changelog: (
|
|
||||||
<FeatureList
|
|
||||||
github="https://github.com/DeveloLongScript/MHSF/releases/tag/1.6.5"
|
|
||||||
features={[
|
|
||||||
"New MOTD engine that is over 3,000% faster, runs client-side, and doesn't need any requests to run.",
|
|
||||||
"Fixed issue where GitHub link was broken if you were signed-out",
|
|
||||||
"Adding snowfall finally (better late then ever)",
|
|
||||||
]}
|
|
||||||
title={
|
|
||||||
<strong className="flex items-center">
|
|
||||||
Version 1.6.5 (December 20th 2024)
|
|
||||||
</strong>
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "h9jr2cbxn7qwfvt5uypsdg",
|
|
||||||
name: "v1.6.0",
|
|
||||||
changelog: (
|
|
||||||
<FeatureList
|
|
||||||
github="https://github.com/DeveloLongScript/MHSF/releases/tag/1.6"
|
|
||||||
features={[
|
|
||||||
"Completely redid top of server view",
|
|
||||||
"Favorite counts are now prominent on the server view",
|
|
||||||
"New theme transition (smooth)",
|
|
||||||
"New favorite button",
|
|
||||||
"Added more padding in the server view",
|
|
||||||
"Separated the tabs on the side for sharing actions",
|
|
||||||
"Added new QR code generator",
|
|
||||||
]}
|
|
||||||
title={
|
|
||||||
<strong className="flex items-center">
|
|
||||||
Version 1.6.0 (November 17th 2024)
|
|
||||||
</strong>
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "r9swempc7kaqd2j84nutv5",
|
|
||||||
name: "v1.5.0",
|
|
||||||
changelog: (
|
|
||||||
<FeatureList
|
|
||||||
github="https://github.com/DeveloLongScript/MHSF/releases/tag/1.5"
|
|
||||||
features={[
|
|
||||||
"New embeds",
|
|
||||||
"More mobile friendly elements",
|
|
||||||
"Better tabs in the server",
|
|
||||||
"Fixed issue where some servers due to their age were not loading",
|
|
||||||
]}
|
|
||||||
title={
|
|
||||||
<strong className="flex items-center">
|
|
||||||
Version 1.5.0 (November 16th 2024)
|
|
||||||
</strong>
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "ywvhtcs4k9rqjfp57x",
|
|
||||||
name: "v1.4.5",
|
|
||||||
changelog: (
|
|
||||||
<FeatureList
|
|
||||||
github="https://github.com/DeveloLongScript/MHSF/releases/tag/1.4.5"
|
|
||||||
features={["Add server icons"]}
|
|
||||||
title={
|
|
||||||
<strong className="flex items-center">
|
|
||||||
Version 1.4.5 (November 6th 2024)
|
|
||||||
</strong>
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "amq4suhgcfwrb7y5j6",
|
|
||||||
name: "v1.4.0",
|
|
||||||
changelog: (
|
|
||||||
<FeatureList
|
|
||||||
github="https://github.com/DeveloLongScript/MHSF/releases/tag/1.4"
|
|
||||||
features={[
|
|
||||||
"Revamped documentation",
|
|
||||||
"Revamped changelog UI",
|
|
||||||
"New hover joins chart",
|
|
||||||
]}
|
|
||||||
title={
|
|
||||||
<strong className="flex items-center">
|
|
||||||
Version 1.4.0 (November 3rd 2024)
|
|
||||||
</strong>
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "jeh48p7w9bx2k3ad6f",
|
|
||||||
name: "v1.3.2",
|
|
||||||
changelog: (
|
|
||||||
<div>
|
|
||||||
<strong className="flex items-center">
|
|
||||||
Version 1.3.2 (October 4th 2024)
|
|
||||||
</strong>
|
|
||||||
<ul>
|
|
||||||
<li>• Minor backend changes</li>
|
|
||||||
<li>
|
|
||||||
•{" "}
|
|
||||||
<Link href="Special:GitHub/releases/tag/1.3.2">
|
|
||||||
Please check on GitHub for statuses about this project.
|
|
||||||
</Link>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "wvg9x5dbpj76sn4yrz",
|
|
||||||
name: "v1.3.0",
|
|
||||||
changelog: (
|
|
||||||
<div>
|
|
||||||
<strong className="flex items-center">
|
|
||||||
Version 1.3.0 (September 9th 2024)
|
|
||||||
</strong>
|
|
||||||
<ul>
|
|
||||||
<li>
|
|
||||||
• <Link href="Docs:Reading">New documentation linking</Link>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
• Achievements are here! See more at{" "}
|
|
||||||
<Link href="Docs:Advanced/Achievements">here</Link>
|
|
||||||
</li>
|
|
||||||
<li>• Finally fixed Cron actions for the final time™</li>
|
|
||||||
<li>• Overhauled account preferences</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "v1.2.0",
|
|
||||||
changelog: (
|
|
||||||
<div>
|
|
||||||
<strong className="flex items-center">
|
|
||||||
Version 1.2.0 (September 3rd 2024)
|
|
||||||
</strong>
|
|
||||||
<ul>
|
|
||||||
<li>• Added documentation</li>
|
|
||||||
<li>• Brand new linking of padding and server options</li>
|
|
||||||
<li>• New system to ensure automatic Cron actions!</li>
|
|
||||||
<li>• and alot more!</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
),
|
|
||||||
id: "e482y9k5hvjt73urfx",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "v1.1.0",
|
|
||||||
changelog: (
|
|
||||||
<div>
|
|
||||||
<strong className="flex items-center">
|
|
||||||
Version 1.1.0 (August 24rd 2024)
|
|
||||||
</strong>
|
|
||||||
<ul>
|
|
||||||
<li>• Brand new hero page</li>
|
|
||||||
<li>• New padding option on server list</li>
|
|
||||||
<li>• New help guide</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
),
|
|
||||||
id: "hfn9p243765x8bwurj",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "v1.0.0",
|
|
||||||
changelog: (
|
|
||||||
<div>
|
|
||||||
<strong className="flex items-center">
|
|
||||||
Version 1.0.0 (August 22nd 2024)
|
|
||||||
</strong>
|
|
||||||
<ul>
|
|
||||||
<li>• 1.0!</li>
|
|
||||||
<li>• New hover card on server title hover</li>
|
|
||||||
<li>• Moving to self-hosted cron jobs</li>
|
|
||||||
<li>• Fixing some mobile issues</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
),
|
|
||||||
id: "a8w4xvjbg3s7ynehu6",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "v0.10.7",
|
|
||||||
changelog: (
|
|
||||||
<div>
|
|
||||||
<strong className="flex items-center">
|
|
||||||
Version b-0.10.7 (August 18th 2024)
|
|
||||||
</strong>
|
|
||||||
<ul>
|
|
||||||
<li>• New server information tab on server pages</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
),
|
|
||||||
id: "asbt64h9fdyu8neqmp",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "v0.10.2",
|
|
||||||
changelog: (
|
|
||||||
<div>
|
|
||||||
<strong className="flex items-center">
|
|
||||||
Version b-0.10.2 (August 18th 2024)
|
|
||||||
</strong>
|
|
||||||
<ul>
|
|
||||||
<li>• Content fades-in on load</li>
|
|
||||||
<li>• Instead of using spinners, now we are using Skeletons</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
),
|
|
||||||
id: "kct29adbp6zug5r3q8",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "v0.10.0",
|
|
||||||
changelog: (
|
|
||||||
<div>
|
|
||||||
<strong className="flex items-center">
|
|
||||||
Version b-0.10.0 (August 17th 2024)
|
|
||||||
</strong>
|
|
||||||
<ul>
|
|
||||||
<li>• Revamped server list button list</li>
|
|
||||||
<li>• Added welcome dialog when first launching</li>
|
|
||||||
<li>
|
|
||||||
• Fixed an issue where servers were still able to be favorited
|
|
||||||
client-side when logged out
|
|
||||||
</li>
|
|
||||||
<li>• Improved MOTD engine</li>
|
|
||||||
</ul>
|
|
||||||
<br />
|
|
||||||
<i>👀</i>
|
|
||||||
{/** Ensure Tailwind pre-renders all grid column types */}
|
|
||||||
<span className="grid-cols-6" />
|
|
||||||
<span className="grid-cols-5" />
|
|
||||||
<span className="grid-cols-4" />
|
|
||||||
</div>
|
|
||||||
),
|
|
||||||
id: "ah6t7c8sfzyrkp3u52",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "v0.9.0",
|
|
||||||
changelog: (
|
|
||||||
<div>
|
|
||||||
<strong className="flex items-center">
|
|
||||||
Version b-0.9.0 (August 15th 2024)
|
|
||||||
</strong>
|
|
||||||
<ul>
|
|
||||||
<li>• Adding favorites sorting option</li>
|
|
||||||
<li>• Fixed right-click context menu on the server list</li>
|
|
||||||
<li>• Fixed metadata bugs</li>
|
|
||||||
</ul>
|
|
||||||
<br />
|
|
||||||
<i>
|
|
||||||
Hey! Update on statistics. Recently, we have figured out the Minehut
|
|
||||||
API is blocked to Vercel servers (atleast the <code>/servers</code>{" "}
|
|
||||||
endpoint). I'm actively trying to find a loop-hole so that statistics
|
|
||||||
works correctly. Thank you {":)"}
|
|
||||||
</i>
|
|
||||||
<br />
|
|
||||||
</div>
|
|
||||||
),
|
|
||||||
id: "kjxnrfazc7hp9q4e82",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "v0.8.0",
|
|
||||||
changelog: (
|
|
||||||
<div>
|
|
||||||
<strong className="flex items-center">
|
|
||||||
Version b-0.8.0 (August 11th 2024)
|
|
||||||
</strong>
|
|
||||||
<ul>
|
|
||||||
<li>• Fixing up command bar</li>
|
|
||||||
<li>• Renaming "Short Term" to "Statistics"</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
),
|
|
||||||
id: "f8rmhwzuxk3qyds542",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "v0.7.2",
|
|
||||||
changelog: (
|
|
||||||
<div>
|
|
||||||
<strong className="flex items-center">
|
|
||||||
Version b-0.7.2 (August 7th 2024)
|
|
||||||
</strong>
|
|
||||||
<ul>
|
|
||||||
<li>• Adding new spinners to pages that needed it</li>
|
|
||||||
<li>• Fixed lots of bugs</li>
|
|
||||||
<li>• Moved from Inngest to Vercel Cron</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
),
|
|
||||||
id: "g2rhxfj6bu8wqk43n7",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "v0.7.0",
|
|
||||||
changelog: (
|
|
||||||
<div>
|
|
||||||
<strong className="flex items-center">
|
|
||||||
Version b-0.7.0 (August 7th 2024)
|
|
||||||
</strong>
|
|
||||||
<ul>
|
|
||||||
<li>• Added customization to servers</li>
|
|
||||||
<li>• New button focus effect</li>
|
|
||||||
<li>• Lots of bugfixes</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
),
|
|
||||||
id: "a5xb97jv3surwmqn62",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "v0.6.0",
|
|
||||||
changelog: (
|
|
||||||
<div>
|
|
||||||
<strong className="flex items-center">
|
|
||||||
Version b-0.6.0 (August 3rd 2024)
|
|
||||||
</strong>
|
|
||||||
<ul>
|
|
||||||
<li>• Enhanced shortcuts</li>
|
|
||||||
<li>• Added gradient beam to player count</li>
|
|
||||||
<li>• Updated loading animations</li>
|
|
||||||
<li>• Lots of bugfixes</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
),
|
|
||||||
id: "u83r5mkea9x4p2fjnb",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "v0.4.5",
|
|
||||||
changelog: (
|
|
||||||
<div>
|
|
||||||
<strong className="flex items-center">
|
|
||||||
Version b-0.4.5 (July 26th 2024):
|
|
||||||
</strong>
|
|
||||||
<ul>
|
|
||||||
<li>• Made charts better</li>
|
|
||||||
<li>• Sorted API endpoints</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
),
|
|
||||||
id: "vu3k2daqj4y68bnwsp",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "v0.4.0",
|
|
||||||
changelog: (
|
|
||||||
<div>
|
|
||||||
<strong className="flex items-center">
|
|
||||||
Version b-0.4 (July 25th 2024):
|
|
||||||
</strong>
|
|
||||||
<ul>
|
|
||||||
<li>• Added Info button</li>
|
|
||||||
<li>• Fixed Clerk in production</li>
|
|
||||||
<li>• Added Turbo for faster builds</li>
|
|
||||||
<li>
|
|
||||||
• <strong>Added historical data</strong>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
),
|
|
||||||
id: "psr9tx5jah74d32vq6",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "v0.3.0",
|
|
||||||
changelog: (
|
|
||||||
<div>
|
|
||||||
<strong className="flex items-center">
|
|
||||||
Version b-0.3 (July 23th 2024):
|
|
||||||
</strong>
|
|
||||||
<ul>
|
|
||||||
<li>
|
|
||||||
• Fixed minor bugs described by <User user="@Tarna" />
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
),
|
|
||||||
id: "m2ngpd6fwtv7xh5zrk",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "v0.2.0",
|
|
||||||
changelog: (
|
|
||||||
<div>
|
|
||||||
<strong className="flex items-center">
|
|
||||||
Version b-0.2 (July 23th 2024):
|
|
||||||
</strong>
|
|
||||||
<ul>
|
|
||||||
<li>• Inital release!</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
),
|
|
||||||
id: "xsfw2rcnv7m3kuhpbq",
|
|
||||||
},
|
|
||||||
];
|
|
||||||
Loading…
Reference in New Issue
Block a user