Compare commits

...

7 Commits

Author SHA1 Message Date
hamster1963
5a7c716df6 Merge branch 'main' into cloudflare 2024-11-21 10:26:18 +08:00
hamster1963
6a0367c192 update: v1.4.4-fix 2024-11-21 10:26:06 +08:00
hamster1963
3551bc90cd fix: build error 2024-11-21 10:25:37 +08:00
hamster1963
69426de708 Merge branch 'main' into cloudflare 2024-11-21 10:21:13 +08:00
hamster1963
4133a7f5c7 update: v1.4.4 2024-11-21 10:20:26 +08:00
hamster1963
753c7dec10 fix(global): disable overview click event 2024-11-21 10:20:06 +08:00
hamster1963
722ec67091 perf(global): better ux 2024-11-21 10:09:09 +08:00
12 changed files with 114 additions and 40 deletions

View File

@ -1,13 +1,12 @@
import { countryCodeMapping, reverseCountryCodeMapping } from "@/lib/geo";
import { countryCoordinates } from "@/lib/geo-limit";
import { GetNezhaData } from "@/lib/serverFetch";
import { ServerStackIcon } from "@heroicons/react/20/solid";
import * as turf from "@turf/turf";
import DottedMap from "dotted-map/without-countries";
import Link from "next/link";
import { geoJsonString } from "../../../lib/geo-json-string";
import { mapJsonString } from "../../../lib/map-string";
import GlobalInfo from "./GlobalInfo";
interface GlobalProps {
countries?: string[];
@ -30,6 +29,7 @@ export default async function ServerGlobal() {
}
export async function Global({ countries = [] }: GlobalProps) {
// const t = useTranslations("Global");
const map = new DottedMap({ map: JSON.parse(mapJsonString) });
const countries_alpha3 = countries
@ -96,12 +96,7 @@ export async function Global({ countries = [] }: GlobalProps) {
return (
<section className="flex flex-col gap-4 mt-[3.2px]">
<Link
href={`/`}
className="rounded-[50px] w-fit bg-stone-100 p-[10px] transition-all hover:bg-stone-200 dark:hover:bg-stone-700 dark:bg-stone-800"
>
<ServerStackIcon className="size-4" />
</Link>
<GlobalInfo countries={countries} />
<img
src={`data:image/svg+xml;utf8,${encodeURIComponent(finalMap)}`}
alt="World Map with Highlighted Countries"

View File

@ -0,0 +1,20 @@
"use client";
import GlobalBackButton from "@/components/GlobalBackButton";
import { useTranslations } from "next-intl";
type GlobalInfoProps = {
countries: string[];
};
export default function GlobalInfo({ countries }: GlobalInfoProps) {
const t = useTranslations("Global");
return (
<section className="flex items-center justify-between">
<GlobalBackButton />
<p className="text-sm font-medium opacity-40">
{t("Distributions")} {countries.length} {t("Regions")}
</p>
</section>
);
}

View File

@ -0,0 +1,18 @@
"use client";
import GlobalBackButton from "@/components/GlobalBackButton";
import { Loader } from "@/components/loading/Loader";
import { useTranslations } from "next-intl";
export default function GlobalLoading() {
const t = useTranslations("Global");
return (
<section className="flex flex-col gap-4 mt-[3.2px]">
<GlobalBackButton />
<div className="flex min-h-40 flex-col items-center justify-center font-medium text-sm">
{t("Loading")}
<Loader visible={true} />
</div>
</section>
);
}

View File

@ -14,8 +14,8 @@ import { useEffect, useRef, useState } from "react";
import useSWR from "swr";
export default function ServerListClient() {
const { status, setStatus } = useStatus();
const { filter, setFilter } = useFilter();
const { status } = useStatus();
const { filter } = useFilter();
const t = useTranslations("ServerListClient");
const containerRef = useRef<HTMLDivElement>(null);
const defaultTag = "defaultTag";
@ -23,13 +23,11 @@ export default function ServerListClient() {
const [tag, setTag] = useState<string>(defaultTag);
const [isMounted, setIsMounted] = useState(false);
useEffect(() => {
const savedTag = sessionStorage.getItem("selectedTag") || defaultTag;
setTag(savedTag);
restoreScrollPosition();
setIsMounted(true);
}, []);
const handleTagChange = (newTag: string) => {
@ -71,7 +69,7 @@ export default function ServerListClient() {
</div>
);
if (!data?.result || !isMounted) return null;
if (!data?.result) return null;
const { result } = data;
const sortedServers = result.sort((a, b) => {
@ -121,8 +119,6 @@ export default function ServerListClient() {
<section className="flex items-center gap-2 w-full overflow-hidden">
<button
onClick={() => {
setStatus("all");
setFilter(false);
router.push(`/?global=true`);
}}
className="rounded-[50px] bg-stone-100 p-[10px] transition-all hover:bg-stone-200 dark:hover:bg-stone-700 dark:bg-stone-800"

View File

@ -43,12 +43,14 @@ export default function ServerOverviewClient() {
<section className="grid grid-cols-2 gap-4 lg:grid-cols-4">
<Card
onClick={() => {
setFilter(false);
if (!global) {
setFilter(false);
setStatus("all");
}
}}
className="cursor-pointer hover:border-blue-500 transition-all"
className={cn("cursor-pointer hover:border-blue-500 transition-all", {
"pointer-events-none": global,
})}
>
<CardContent className="px-6 py-3">
<section className="flex flex-col gap-1">
@ -74,8 +76,8 @@ export default function ServerOverviewClient() {
</Card>
<Card
onClick={() => {
setFilter(false);
if (!global) {
setFilter(false);
setStatus("online");
}
}}
@ -84,6 +86,9 @@ export default function ServerOverviewClient() {
{
"ring-green-500 ring-2 border-transparent": status === "online",
},
{
"pointer-events-none": global,
},
)}
>
<CardContent className="px-6 py-3">
@ -111,8 +116,8 @@ export default function ServerOverviewClient() {
</Card>
<Card
onClick={() => {
setFilter(false);
if (!global) {
setFilter(false);
setStatus("offline");
}
}}
@ -121,6 +126,9 @@ export default function ServerOverviewClient() {
{
"ring-red-500 ring-2 border-transparent": status === "offline",
},
{
"pointer-events-none": global,
},
)}
>
<CardContent className="px-6 py-3">
@ -148,8 +156,8 @@ export default function ServerOverviewClient() {
</Card>
<Card
onClick={() => {
setStatus("all");
if (!global) {
setStatus("all");
setFilter(true);
}
}}
@ -158,6 +166,9 @@ export default function ServerOverviewClient() {
{
"ring-purple-500 ring-2 border-transparent": filter === true,
},
{
"pointer-events-none": global,
},
)}
>
<CardContent className="relative px-6 py-3">

View File

@ -3,12 +3,10 @@ import ServerOverview from "@/components/ServerOverview";
export const runtime = "edge";
import { Loader } from "@/components/loading/Loader";
import { ServerStackIcon } from "@heroicons/react/20/solid";
import Link from "next/link";
import { Suspense } from "react";
import ServerGlobal from "./ClientComponents/Global";
import GlobalLoading from "./ClientComponents/GlobalLoading";
export default async function Home({
searchParams,
@ -21,22 +19,7 @@ export default async function Home({
<ServerOverview />
{!global && <ServerList />}
{global && (
<Suspense
fallback={
<section className="flex flex-col gap-4 mt-[3.2px]">
<Link
href={`/`}
className="rounded-[50px] w-fit bg-stone-100 p-[10px] transition-all hover:bg-stone-200 dark:hover:bg-stone-700 dark:bg-stone-800"
>
<ServerStackIcon className="size-4" />
</Link>
<div className="flex min-h-40 flex-col items-center justify-center font-medium text-sm">
Loading...
<Loader visible={true} />
</div>
</section>
}
>
<Suspense fallback={<GlobalLoading />}>
<ServerGlobal />
</Suspense>
)}

View File

@ -0,0 +1,31 @@
"use client";
import { useFilter } from "@/lib/network-filter-context";
import { useStatus } from "@/lib/status-context";
import { ServerStackIcon } from "@heroicons/react/20/solid";
import { useRouter } from "next/navigation";
import { useEffect } from "react";
export default function GlobalBackButton() {
const router = useRouter();
const { setStatus } = useStatus();
const { setFilter } = useFilter();
useEffect(() => {
setStatus("all");
setFilter(false);
sessionStorage.removeItem("selectedTag");
router.prefetch(`/`);
}, []);
return (
<button
onClick={() => {
router.push(`/`);
}}
className="rounded-[50px] w-fit bg-stone-100 p-[10px] transition-all hover:bg-stone-200 dark:hover:bg-stone-700 dark:bg-stone-800"
>
<ServerStackIcon className="size-4" />
</button>
);
}

View File

@ -90,6 +90,11 @@
"p_2277-2331_Overview": "👋 Overview",
"p_2390-2457_wherethetimeis": "where the time is"
},
"Global": {
"Loading": "Loading...",
"Distributions": "Servers are distributed in",
"Regions": "Regions"
},
"NotFoundPage": {
"h1_490-590_404NotFound": "404 Not Found",
"p_601-665_TARDISERROR": "TARDIS ERROR!",

View File

@ -90,6 +90,11 @@
"p_2277-2331_Overview": "👋 概要",
"p_2390-2457_wherethetimeis": "現在の時間"
},
"Global": {
"Loading": "Loading...",
"Distributions": "サーバーは",
"Regions": "つの地域に分散されています"
},
"NotFoundPage": {
"h1_490-590_404NotFound": "404 見つかりませんでした",
"p_601-665_TARDISERROR": "ターディスエラー!",

View File

@ -90,6 +90,11 @@
"p_2277-2331_Overview": "👋 概覽",
"p_2390-2457_wherethetimeis": "當前時間"
},
"Global": {
"Loading": "載入中...",
"Distributions": "伺服器分佈在",
"Regions": "個地區"
},
"NotFoundPage": {
"h1_490-590_404NotFound": "404 未找到",
"p_601-665_TARDISERROR": "TARDIS 錯誤!",

View File

@ -90,6 +90,11 @@
"p_2277-2331_Overview": "👋 概览",
"p_2390-2457_wherethetimeis": "当前时间"
},
"Global": {
"Loading": "加载中...",
"Distributions": "服务器分布在",
"Regions": "个地区"
},
"NotFoundPage": {
"h1_490-590_404NotFound": "404 未找到",
"p_601-665_TARDISERROR": "TARDIS 错误!",

View File

@ -1,6 +1,6 @@
{
"name": "nezha-dash",
"version": "1.4.3-fix",
"version": "1.4.4-fix",
"private": true,
"scripts": {
"dev": "next dev -p 3040",