mirror of
https://github.com/DeveloLongScript/MHSF.git
synced 2026-05-07 19:44:59 -05:00
feat: progress (2/15)
This commit is contained in:
parent
0f254e09f6
commit
c16341a9d6
@ -246,63 +246,62 @@ export function BrandingGenericIcon(props: SVGProps<SVGSVGElement>) {
|
|||||||
</defs>
|
</defs>
|
||||||
</svg>
|
</svg>
|
||||||
);
|
);
|
||||||
} else {
|
|
||||||
return (
|
|
||||||
<svg
|
|
||||||
width="265"
|
|
||||||
height="265"
|
|
||||||
viewBox="0 0 265 265"
|
|
||||||
fill="none"
|
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
|
||||||
{...props}
|
|
||||||
>
|
|
||||||
<rect
|
|
||||||
x="0.0612793"
|
|
||||||
width="264.939"
|
|
||||||
height="264.939"
|
|
||||||
rx="66"
|
|
||||||
fill="url(#paint0_linear_1_25)"
|
|
||||||
/>
|
|
||||||
<path
|
|
||||||
d="M104.05 123.27H94.4089C91.852 123.27 89.3998 122.254 87.5918 120.446C85.7838 118.638 84.7681 116.186 84.7681 113.629V94.3476C84.7681 91.7907 85.7838 89.3385 87.5918 87.5305C89.3998 85.7225 91.852 84.7068 94.4089 84.7068H171.536C174.092 84.7068 176.545 85.7225 178.353 87.5305C180.161 89.3385 181.176 91.7907 181.176 94.3476V113.629C181.176 116.186 180.161 118.638 178.353 120.446C176.545 122.254 174.092 123.27 171.536 123.27H161.895M104.05 142.552H94.4089C91.852 142.552 89.3998 143.567 87.5918 145.376C85.7838 147.184 84.7681 149.636 84.7681 152.193V171.474C84.7681 174.031 85.7838 176.483 87.5918 178.291C89.3998 180.099 91.852 181.115 94.4089 181.115H171.536C174.092 181.115 176.545 180.099 178.353 178.291C180.161 176.483 181.176 174.031 181.176 171.474V152.193C181.176 149.636 180.161 147.184 178.353 145.376C176.545 143.567 174.092 142.552 171.536 142.552H161.895M104.05 103.988H104.098M104.05 161.833H104.098M137.793 103.988L118.511 132.911H147.433L128.152 161.833"
|
|
||||||
stroke="black"
|
|
||||||
stroke-width="10"
|
|
||||||
stroke-linecap="round"
|
|
||||||
stroke-linejoin="round"
|
|
||||||
/>
|
|
||||||
<circle
|
|
||||||
cx="132.531"
|
|
||||||
cy="132.469"
|
|
||||||
r="91.3779"
|
|
||||||
stroke="url(#paint1_linear_1_25)"
|
|
||||||
stroke-width="8"
|
|
||||||
/>
|
|
||||||
<defs>
|
|
||||||
<linearGradient
|
|
||||||
id="paint0_linear_1_25"
|
|
||||||
x1="107.361"
|
|
||||||
y1="54.754"
|
|
||||||
x2="230.116"
|
|
||||||
y2="225.198"
|
|
||||||
gradientUnits="userSpaceOnUse"
|
|
||||||
>
|
|
||||||
<stop stop-color="white" />
|
|
||||||
</linearGradient>
|
|
||||||
<linearGradient
|
|
||||||
id="paint1_linear_1_25"
|
|
||||||
x1="132.531"
|
|
||||||
y1="37.0914"
|
|
||||||
x2="132.531"
|
|
||||||
y2="227.847"
|
|
||||||
gradientUnits="userSpaceOnUse"
|
|
||||||
>
|
|
||||||
<stop stop-color="#EFEC32" />
|
|
||||||
<stop offset="1" stop-color="#98FF60" />
|
|
||||||
</linearGradient>
|
|
||||||
</defs>
|
|
||||||
</svg>
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
return (
|
||||||
|
<svg
|
||||||
|
width="265"
|
||||||
|
height="265"
|
||||||
|
viewBox="0 0 265 265"
|
||||||
|
fill="none"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
{...props}
|
||||||
|
>
|
||||||
|
<rect
|
||||||
|
x="0.0612793"
|
||||||
|
width="264.939"
|
||||||
|
height="264.939"
|
||||||
|
rx="66"
|
||||||
|
fill="url(#paint0_linear_1_25)"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
d="M104.05 123.27H94.4089C91.852 123.27 89.3998 122.254 87.5918 120.446C85.7838 118.638 84.7681 116.186 84.7681 113.629V94.3476C84.7681 91.7907 85.7838 89.3385 87.5918 87.5305C89.3998 85.7225 91.852 84.7068 94.4089 84.7068H171.536C174.092 84.7068 176.545 85.7225 178.353 87.5305C180.161 89.3385 181.176 91.7907 181.176 94.3476V113.629C181.176 116.186 180.161 118.638 178.353 120.446C176.545 122.254 174.092 123.27 171.536 123.27H161.895M104.05 142.552H94.4089C91.852 142.552 89.3998 143.567 87.5918 145.376C85.7838 147.184 84.7681 149.636 84.7681 152.193V171.474C84.7681 174.031 85.7838 176.483 87.5918 178.291C89.3998 180.099 91.852 181.115 94.4089 181.115H171.536C174.092 181.115 176.545 180.099 178.353 178.291C180.161 176.483 181.176 174.031 181.176 171.474V152.193C181.176 149.636 180.161 147.184 178.353 145.376C176.545 143.567 174.092 142.552 171.536 142.552H161.895M104.05 103.988H104.098M104.05 161.833H104.098M137.793 103.988L118.511 132.911H147.433L128.152 161.833"
|
||||||
|
stroke="black"
|
||||||
|
stroke-width="10"
|
||||||
|
stroke-linecap="round"
|
||||||
|
stroke-linejoin="round"
|
||||||
|
/>
|
||||||
|
<circle
|
||||||
|
cx="132.531"
|
||||||
|
cy="132.469"
|
||||||
|
r="91.3779"
|
||||||
|
stroke="url(#paint1_linear_1_25)"
|
||||||
|
stroke-width="8"
|
||||||
|
/>
|
||||||
|
<defs>
|
||||||
|
<linearGradient
|
||||||
|
id="paint0_linear_1_25"
|
||||||
|
x1="107.361"
|
||||||
|
y1="54.754"
|
||||||
|
x2="230.116"
|
||||||
|
y2="225.198"
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
>
|
||||||
|
<stop stop-color="white" />
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient
|
||||||
|
id="paint1_linear_1_25"
|
||||||
|
x1="132.531"
|
||||||
|
y1="37.0914"
|
||||||
|
x2="132.531"
|
||||||
|
y2="227.847"
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
>
|
||||||
|
<stop stop-color="#EFEC32" />
|
||||||
|
<stop offset="1" stop-color="#98FF60" />
|
||||||
|
</linearGradient>
|
||||||
|
</defs>
|
||||||
|
</svg>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function BadgeOfAffiliation(props: SVGProps<SVGSVGElement>) {
|
export function BadgeOfAffiliation(props: SVGProps<SVGSVGElement>) {
|
||||||
@ -1,5 +1,5 @@
|
|||||||
"use client";
|
"use client";
|
||||||
import { BrandingGenericIcon } from "@/components/icon";
|
import { BrandingGenericIcon } from "@/components/feat/icons/branding-icons";
|
||||||
import { version } from "@/config/version";
|
import { version } from "@/config/version";
|
||||||
import { useScroll } from "@/lib/hooks/use-scroll";
|
import { useScroll } from "@/lib/hooks/use-scroll";
|
||||||
import { cn } from "@/lib/utils";
|
import { cn } from "@/lib/utils";
|
||||||
|
|||||||
@ -25,11 +25,11 @@ export function ServerList() {
|
|||||||
totalPlayers={playerCount}
|
totalPlayers={playerCount}
|
||||||
topServer={servers[0]}
|
topServer={servers[0]}
|
||||||
/>
|
/>
|
||||||
<Separator className="my-3" />
|
<Separator className="my-6" />
|
||||||
<h1 className="scroll-m-20 text-2xl font-extrabold tracking-tight lg:text-4xl">
|
<h1 className="scroll-m-20 text-2xl font-extrabold tracking-tight lg:text-4xl">
|
||||||
Servers
|
Servers
|
||||||
</h1>
|
</h1>
|
||||||
<div className="grid grid-cols-4 gap-2 mt-3">
|
<div className="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-4 gap-2 mt-3">
|
||||||
{servers.map((c) => (
|
{servers.map((c) => (
|
||||||
<ServerCard server={c} key={c.name} />
|
<ServerCard server={c} key={c.name} />
|
||||||
))}
|
))}
|
||||||
|
|||||||
@ -1,5 +1,14 @@
|
|||||||
|
import { FormSpinner } from "@/components/ui/form-spinner";
|
||||||
import { Material } from "@/components/ui/material";
|
import { Material } from "@/components/ui/material";
|
||||||
|
import {
|
||||||
|
Tooltip,
|
||||||
|
TooltipContent,
|
||||||
|
TooltipTrigger,
|
||||||
|
} from "@/components/ui/tooltip";
|
||||||
import type { OnlineServer } from "@/lib/types/mh-server";
|
import type { OnlineServer } from "@/lib/types/mh-server";
|
||||||
|
import { InfoIcon } from "lucide-react";
|
||||||
|
import { useEffect, useState } from "react";
|
||||||
|
import { motion, AnimatePresence } from "framer-motion";
|
||||||
|
|
||||||
export function Statistics({
|
export function Statistics({
|
||||||
totalPlayers,
|
totalPlayers,
|
||||||
@ -10,15 +19,101 @@ export function Statistics({
|
|||||||
totalServers: number;
|
totalServers: number;
|
||||||
topServer: OnlineServer;
|
topServer: OnlineServer;
|
||||||
}) {
|
}) {
|
||||||
|
const [averagesLoading, setAveragesLoading] = useState(true);
|
||||||
|
const [error, setError] = useState(false);
|
||||||
|
const [averages, setAverages] = useState<
|
||||||
|
| {
|
||||||
|
totalServerAverage: number;
|
||||||
|
totalPlayerAverage: number;
|
||||||
|
}
|
||||||
|
| undefined
|
||||||
|
>(undefined);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
try {
|
||||||
|
(async () => {
|
||||||
|
const fetchRes = await fetch("/api/v0/history/meta-daily-avg");
|
||||||
|
const fetchJson: {
|
||||||
|
totalServerAverage: number;
|
||||||
|
totalPlayerAverage: number;
|
||||||
|
} = await fetchRes.json();
|
||||||
|
|
||||||
|
setAveragesLoading(false);
|
||||||
|
setAverages(fetchJson);
|
||||||
|
})();
|
||||||
|
} catch (e) {
|
||||||
|
console.log(e);
|
||||||
|
setError(true);
|
||||||
|
}
|
||||||
|
}, []);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="grid grid-cols-3 gap-2">
|
<div className="grid grid-cols-3 gap-2">
|
||||||
<Material className="gap-2">
|
<Material className="gap-2">
|
||||||
<strong>Total Players</strong> <br />
|
<strong className="flex items-center gap-1">
|
||||||
<span className="text-lg">{totalPlayers}</span>
|
Total Players
|
||||||
|
<Tooltip>
|
||||||
|
<TooltipTrigger>
|
||||||
|
<InfoIcon size={14} />
|
||||||
|
</TooltipTrigger>
|
||||||
|
<TooltipContent>
|
||||||
|
For players, the first number represents the current amount of
|
||||||
|
<br />
|
||||||
|
players, while the second one represents the average of the last
|
||||||
|
<br />
|
||||||
|
100 entries of players.
|
||||||
|
</TooltipContent>
|
||||||
|
</Tooltip>
|
||||||
|
</strong>
|
||||||
|
<span className="text-lg flex items-center gap-1">
|
||||||
|
{totalPlayers}
|
||||||
|
<AnimatePresence>
|
||||||
|
{!averagesLoading && !error && (
|
||||||
|
<motion.span
|
||||||
|
initial={{ opacity: 0, x: -10 }}
|
||||||
|
animate={{ opacity: 1, x: 0 }}
|
||||||
|
transition={{ duration: 0.15 }}
|
||||||
|
className="text-muted-foreground/80"
|
||||||
|
>
|
||||||
|
{Math.round(averages?.totalPlayerAverage as number)}
|
||||||
|
</motion.span>
|
||||||
|
)}
|
||||||
|
</AnimatePresence>
|
||||||
|
{averagesLoading && <FormSpinner />}
|
||||||
|
</span>
|
||||||
</Material>
|
</Material>
|
||||||
<Material className="gap-2">
|
<Material className="gap-2">
|
||||||
<strong>Total Servers</strong> <br />
|
<strong className="flex items-center gap-1">
|
||||||
<span className="text-lg">{totalServers}</span>
|
Total Servers
|
||||||
|
<Tooltip>
|
||||||
|
<TooltipTrigger>
|
||||||
|
<InfoIcon size={14} />
|
||||||
|
</TooltipTrigger>
|
||||||
|
<TooltipContent>
|
||||||
|
For servers, the first number represents the current amount of
|
||||||
|
<br />
|
||||||
|
servers, while the second one represents the average of the last
|
||||||
|
<br />
|
||||||
|
100 entries of servers.
|
||||||
|
</TooltipContent>
|
||||||
|
</Tooltip>
|
||||||
|
</strong>
|
||||||
|
<span className="text-lg flex items-center gap-1">
|
||||||
|
{totalServers}
|
||||||
|
<AnimatePresence>
|
||||||
|
{!averagesLoading && !error && (
|
||||||
|
<motion.span
|
||||||
|
initial={{ opacity: 0, x: -10 }}
|
||||||
|
animate={{ opacity: 1, x: 0 }}
|
||||||
|
transition={{ duration: 0.15 }}
|
||||||
|
className="text-muted-foreground/80"
|
||||||
|
>
|
||||||
|
{Math.round(averages?.totalServerAverage as number)}
|
||||||
|
</motion.span>
|
||||||
|
)}
|
||||||
|
</AnimatePresence>
|
||||||
|
{averagesLoading && <FormSpinner />}
|
||||||
|
</span>
|
||||||
</Material>
|
</Material>
|
||||||
<Material className="gap-2">
|
<Material className="gap-2">
|
||||||
<strong>Top Server</strong> <br />
|
<strong>Top Server</strong> <br />
|
||||||
|
|||||||
54
apps/www/src/pages/api/v0/history/meta-daily-avg.ts
Normal file
54
apps/www/src/pages/api/v0/history/meta-daily-avg.ts
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { MongoClient, type WithId } from "mongodb";
|
||||||
|
import type { NextApiRequest, NextApiResponse } from "next";
|
||||||
|
|
||||||
|
export default async function handler(
|
||||||
|
req: NextApiRequest,
|
||||||
|
res: NextApiResponse,
|
||||||
|
) {
|
||||||
|
const client = new MongoClient(process.env.MONGO_DB as string);
|
||||||
|
const db = client.db("mhsf").collection("mh");
|
||||||
|
const array = (await db.find().toArray()) as WithId<{
|
||||||
|
total_servers: number;
|
||||||
|
total_players: number;
|
||||||
|
date?: Date;
|
||||||
|
}>[];
|
||||||
|
|
||||||
|
const totalServerAverage =
|
||||||
|
array.slice(0, 100).reduce((acc, curr) => acc + curr.total_servers, 0) /
|
||||||
|
array.slice(0, 100).length;
|
||||||
|
const totalPlayerAverage =
|
||||||
|
array.slice(0, 100).reduce((acc, curr) => acc + curr.total_players, 0) /
|
||||||
|
array.slice(0, 100).length;
|
||||||
|
|
||||||
|
res.send({ totalServerAverage, totalPlayerAverage });
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue
Block a user