mirror of
https://github.com/hamster1963/nezha-dash.git
synced 2025-04-24 21:10:45 +08:00
perf: fully optimize
This commit is contained in:
parent
646354e515
commit
f9f57e4d19
@ -40,7 +40,7 @@ export default function ServerDetailClient({
|
|||||||
if (hasHistory) {
|
if (hasHistory) {
|
||||||
router.back()
|
router.back()
|
||||||
} else {
|
} else {
|
||||||
router.push(`/`)
|
router.push("/")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -120,8 +120,8 @@ export default function ServerDetailClient({
|
|||||||
<div className="text-xs">
|
<div className="text-xs">
|
||||||
{" "}
|
{" "}
|
||||||
{uptime / 86400 >= 1
|
{uptime / 86400 >= 1
|
||||||
? (uptime / 86400).toFixed(0) + " " + t("Days")
|
? `${(uptime / 86400).toFixed(0)} ${t("Days")}`
|
||||||
: (uptime / 3600).toFixed(0) + " " + t("Hours")}{" "}
|
: `${(uptime / 3600).toFixed(0)} ${t("Hours")}`}
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
</CardContent>
|
</CardContent>
|
||||||
|
@ -24,7 +24,7 @@ export default function ServerGlobal() {
|
|||||||
const countryList: string[] = []
|
const countryList: string[] = []
|
||||||
const serverCounts: { [key: string]: number } = {}
|
const serverCounts: { [key: string]: number } = {}
|
||||||
|
|
||||||
nezhaServerList.result.forEach((server) => {
|
for (const server of nezhaServerList.result) {
|
||||||
if (server.host.CountryCode) {
|
if (server.host.CountryCode) {
|
||||||
const countryCode = server.host.CountryCode.toUpperCase()
|
const countryCode = server.host.CountryCode.toUpperCase()
|
||||||
if (!countryList.includes(countryCode)) {
|
if (!countryList.includes(countryCode)) {
|
||||||
@ -32,7 +32,7 @@ export default function ServerGlobal() {
|
|||||||
}
|
}
|
||||||
serverCounts[countryCode] = (serverCounts[countryCode] || 0) + 1
|
serverCounts[countryCode] = (serverCounts[countryCode] || 0) + 1
|
||||||
}
|
}
|
||||||
})
|
}
|
||||||
|
|
||||||
const width = 900
|
const width = 900
|
||||||
const height = 500
|
const height = 500
|
||||||
|
@ -40,6 +40,7 @@ export function InteractiveMap({
|
|||||||
xmlns="http://www.w3.org/2000/svg"
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
className="w-full h-auto"
|
className="w-full h-auto"
|
||||||
>
|
>
|
||||||
|
<title>Interactive Map</title>
|
||||||
<defs>
|
<defs>
|
||||||
<pattern id="dots" width="2" height="2" patternUnits="userSpaceOnUse">
|
<pattern id="dots" width="2" height="2" patternUnits="userSpaceOnUse">
|
||||||
<circle cx="1" cy="1" r="0.5" fill="currentColor" />
|
<circle cx="1" cy="1" r="0.5" fill="currentColor" />
|
||||||
@ -55,14 +56,14 @@ export function InteractiveMap({
|
|||||||
fill="transparent"
|
fill="transparent"
|
||||||
onMouseEnter={() => setTooltipData(null)}
|
onMouseEnter={() => setTooltipData(null)}
|
||||||
/>
|
/>
|
||||||
{filteredFeatures.map((feature, index) => {
|
{filteredFeatures.map((feature) => {
|
||||||
const isHighlighted = countries.includes(feature.properties.iso_a2_eh)
|
const isHighlighted = countries.includes(feature.properties.iso_a2_eh)
|
||||||
|
|
||||||
const serverCount = serverCounts[feature.properties.iso_a2_eh] || 0
|
const serverCount = serverCounts[feature.properties.iso_a2_eh] || 0
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<path
|
<path
|
||||||
key={index}
|
key={feature.properties.iso_a2_eh}
|
||||||
d={path(feature) || ""}
|
d={path(feature) || ""}
|
||||||
className={
|
className={
|
||||||
isHighlighted
|
isHighlighted
|
||||||
|
@ -42,13 +42,13 @@ const MapTooltip = memo(function MapTooltip() {
|
|||||||
overflowY: "auto",
|
overflowY: "auto",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{sortedServers.map((server, index) => (
|
{sortedServers.map((server) => (
|
||||||
<div key={index} className="flex items-center gap-1.5 py-0.5">
|
<div key={server.name} className="flex items-center gap-1.5 py-0.5">
|
||||||
<span
|
<span
|
||||||
className={`w-1.5 h-1.5 shrink-0 rounded-full ${
|
className={`w-1.5 h-1.5 shrink-0 rounded-full ${
|
||||||
server.status ? "bg-green-500" : "bg-red-500"
|
server.status ? "bg-green-500" : "bg-red-500"
|
||||||
}`}
|
}`}
|
||||||
></span>
|
/>
|
||||||
<span className="text-xs">{server.name}</span>
|
<span className="text-xs">{server.name}</span>
|
||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
|
@ -124,16 +124,17 @@ export default function ServerListClient() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const tagCountMap: Record<string, number> = {}
|
const tagCountMap: Record<string, number> = {}
|
||||||
filteredServersByStatus.forEach((server) => {
|
for (const server of filteredServersByStatus) {
|
||||||
if (server.tag) {
|
if (server.tag) {
|
||||||
tagCountMap[server.tag] = (tagCountMap[server.tag] || 0) + 1
|
tagCountMap[server.tag] = (tagCountMap[server.tag] || 0) + 1
|
||||||
}
|
}
|
||||||
})
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<section className="flex items-center gap-2 w-full overflow-hidden">
|
<section className="flex items-center gap-2 w-full overflow-hidden">
|
||||||
<button
|
<button
|
||||||
|
type="button"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
setShowMap(!showMap)
|
setShowMap(!showMap)
|
||||||
}}
|
}}
|
||||||
@ -147,6 +148,7 @@ export default function ServerListClient() {
|
|||||||
<MapIcon className="size-[13px]" />
|
<MapIcon className="size-[13px]" />
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
|
type="button"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
setInline(inline === "0" ? "1" : "0")
|
setInline(inline === "0" ? "1" : "0")
|
||||||
localStorage.setItem("inline", inline === "0" ? "1" : "0")
|
localStorage.setItem("inline", inline === "0" ? "1" : "0")
|
||||||
|
@ -46,7 +46,7 @@ export default function ServerOverviewClient() {
|
|||||||
<p className="text-sm font-medium md:text-base">{t("p_816-881_Totalservers")}</p>
|
<p className="text-sm font-medium md:text-base">{t("p_816-881_Totalservers")}</p>
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
<span className="relative flex h-2 w-2">
|
<span className="relative flex h-2 w-2">
|
||||||
<span className="relative inline-flex h-2 w-2 rounded-full bg-blue-500"></span>
|
<span className="relative inline-flex h-2 w-2 rounded-full bg-blue-500" />
|
||||||
</span>
|
</span>
|
||||||
{data?.result ? (
|
{data?.result ? (
|
||||||
<div className="text-lg font-semibold">{data?.result.length}</div>
|
<div className="text-lg font-semibold">{data?.result.length}</div>
|
||||||
@ -76,8 +76,8 @@ export default function ServerOverviewClient() {
|
|||||||
<p className="text-sm font-medium md:text-base">{t("p_1610-1676_Onlineservers")}</p>
|
<p className="text-sm font-medium md:text-base">{t("p_1610-1676_Onlineservers")}</p>
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
<span className="relative flex h-2 w-2">
|
<span className="relative flex h-2 w-2">
|
||||||
<span className="absolute inline-flex h-full w-full animate-ping rounded-full bg-green-500 opacity-75"></span>
|
<span className="absolute inline-flex h-full w-full animate-ping rounded-full bg-green-500 opacity-75" />
|
||||||
<span className="relative inline-flex h-2 w-2 rounded-full bg-green-500"></span>
|
<span className="relative inline-flex h-2 w-2 rounded-full bg-green-500" />
|
||||||
</span>
|
</span>
|
||||||
{data?.result ? (
|
{data?.result ? (
|
||||||
<div className="text-lg font-semibold">{data?.live_servers}</div>
|
<div className="text-lg font-semibold">{data?.live_servers}</div>
|
||||||
@ -107,8 +107,8 @@ export default function ServerOverviewClient() {
|
|||||||
<p className="text-sm font-medium md:text-base">{t("p_2532-2599_Offlineservers")}</p>
|
<p className="text-sm font-medium md:text-base">{t("p_2532-2599_Offlineservers")}</p>
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
<span className="relative flex h-2 w-2">
|
<span className="relative flex h-2 w-2">
|
||||||
<span className="absolute inline-flex h-full w-full animate-ping rounded-full bg-red-500 opacity-75"></span>
|
<span className="absolute inline-flex h-full w-full animate-ping rounded-full bg-red-500 opacity-75" />
|
||||||
<span className="relative inline-flex h-2 w-2 rounded-full bg-red-500"></span>
|
<span className="relative inline-flex h-2 w-2 rounded-full bg-red-500" />
|
||||||
</span>
|
</span>
|
||||||
{data?.result ? (
|
{data?.result ? (
|
||||||
<div className="text-lg font-semibold">{data?.offline_servers}</div>
|
<div className="text-lg font-semibold">{data?.offline_servers}</div>
|
||||||
|
@ -28,7 +28,7 @@ export async function GET(req: NextRequest) {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
const serverIdNum = Number.parseInt(server_id, 10)
|
const serverIdNum = Number.parseInt(server_id, 10)
|
||||||
if (isNaN(serverIdNum)) {
|
if (Number.isNaN(serverIdNum)) {
|
||||||
return NextResponse.json({ error: "server_id must be a valid number" }, { status: 400 })
|
return NextResponse.json({ error: "server_id must be a valid number" }, { status: 400 })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -28,7 +28,7 @@ export async function GET(req: NextRequest) {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
const serverIdNum = Number.parseInt(server_id, 10)
|
const serverIdNum = Number.parseInt(server_id, 10)
|
||||||
if (isNaN(serverIdNum)) {
|
if (Number.isNaN(serverIdNum)) {
|
||||||
return NextResponse.json({ error: "server_id must be a number" }, { status: 400 })
|
return NextResponse.json({ error: "server_id must be a number" }, { status: 400 })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"$schema": "https://biomejs.dev/schemas/1.9.4/schema.json",
|
"$schema": "https://biomejs.dev/schemas/1.9.4/schema.json",
|
||||||
"vcs": { "enabled": false, "clientKind": "git", "useIgnoreFile": false },
|
"vcs": { "enabled": false, "clientKind": "git", "useIgnoreFile": false },
|
||||||
"files": { "ignoreUnknown": false, "ignore": [".next", "public"] },
|
"files": { "ignoreUnknown": false, "ignore": [".next", "public", "styles/globals.css"] },
|
||||||
"formatter": {
|
"formatter": {
|
||||||
"enabled": true,
|
"enabled": true,
|
||||||
"useEditorconfig": true,
|
"useEditorconfig": true,
|
||||||
@ -20,6 +20,9 @@
|
|||||||
"a11y": {
|
"a11y": {
|
||||||
"useKeyWithClickEvents": "off"
|
"useKeyWithClickEvents": "off"
|
||||||
},
|
},
|
||||||
|
"security": {
|
||||||
|
"noDangerouslySetInnerHtml": "off"
|
||||||
|
},
|
||||||
"complexity": { "noUselessTypeConstraint": "error" },
|
"complexity": { "noUselessTypeConstraint": "error" },
|
||||||
"correctness": {
|
"correctness": {
|
||||||
"noUnusedVariables": "error",
|
"noUnusedVariables": "error",
|
||||||
|
@ -38,6 +38,7 @@ export default function AnimatedCircularProgressBar({
|
|||||||
}
|
}
|
||||||
>
|
>
|
||||||
<svg fill="none" className="size-full" strokeWidth="2" viewBox="0 0 100 100">
|
<svg fill="none" className="size-full" strokeWidth="2" viewBox="0 0 100 100">
|
||||||
|
<title>Circular Progress Bar</title>
|
||||||
{currentPercent <= 90 && currentPercent >= 0 && (
|
{currentPercent <= 90 && currentPercent >= 0 && (
|
||||||
<circle
|
<circle
|
||||||
cx="50"
|
cx="50"
|
||||||
|
@ -49,16 +49,16 @@ export function GetFontLogoClass(platform: string): string {
|
|||||||
) {
|
) {
|
||||||
return platform
|
return platform
|
||||||
}
|
}
|
||||||
if (platform == "darwin") {
|
if (platform === "darwin") {
|
||||||
return "apple"
|
return "apple"
|
||||||
}
|
}
|
||||||
if (["openwrt", "linux", "immortalwrt"].indexOf(platform) > -1) {
|
if (["openwrt", "linux", "immortalwrt"].indexOf(platform) > -1) {
|
||||||
return "tux"
|
return "tux"
|
||||||
}
|
}
|
||||||
if (platform == "amazon") {
|
if (platform === "amazon") {
|
||||||
return "redhat"
|
return "redhat"
|
||||||
}
|
}
|
||||||
if (platform == "arch") {
|
if (platform === "arch") {
|
||||||
return "archlinux"
|
return "archlinux"
|
||||||
}
|
}
|
||||||
if (platform.toLowerCase().includes("opensuse")) {
|
if (platform.toLowerCase().includes("opensuse")) {
|
||||||
@ -112,16 +112,16 @@ export function GetOsName(platform: string): string {
|
|||||||
) {
|
) {
|
||||||
return platform.charAt(0).toUpperCase() + platform.slice(1)
|
return platform.charAt(0).toUpperCase() + platform.slice(1)
|
||||||
}
|
}
|
||||||
if (platform == "darwin") {
|
if (platform === "darwin") {
|
||||||
return "macOS"
|
return "macOS"
|
||||||
}
|
}
|
||||||
if (["openwrt", "linux", "immortalwrt"].indexOf(platform) > -1) {
|
if (["openwrt", "linux", "immortalwrt"].indexOf(platform) > -1) {
|
||||||
return "Linux"
|
return "Linux"
|
||||||
}
|
}
|
||||||
if (platform == "amazon") {
|
if (platform === "amazon") {
|
||||||
return "Redhat"
|
return "Redhat"
|
||||||
}
|
}
|
||||||
if (platform == "arch") {
|
if (platform === "arch") {
|
||||||
return "Archlinux"
|
return "Archlinux"
|
||||||
}
|
}
|
||||||
if (platform.toLowerCase().includes("opensuse")) {
|
if (platform.toLowerCase().includes("opensuse")) {
|
||||||
@ -133,10 +133,11 @@ export function GetOsName(platform: string): string {
|
|||||||
export function MageMicrosoftWindows(props: SVGProps<SVGSVGElement>) {
|
export function MageMicrosoftWindows(props: SVGProps<SVGSVGElement>) {
|
||||||
return (
|
return (
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" viewBox="0 0 24 24" {...props}>
|
<svg xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" viewBox="0 0 24 24" {...props}>
|
||||||
|
<title>Mage Microsoft Windows</title>
|
||||||
<path
|
<path
|
||||||
fill="currentColor"
|
fill="currentColor"
|
||||||
d="M2.75 7.189V2.865c0-.102 0-.115.115-.115h8.622c.128 0 .14 0 .14.128V11.5c0 .128 0 .128-.14.128H2.865c-.102 0-.115 0-.115-.116zM7.189 21.25H2.865c-.102 0-.115 0-.115-.116V12.59c0-.128 0-.128.128-.128h8.635c.102 0 .115 0 .115.115v8.57c0 .09 0 .103-.116.103zM21.25 7.189v4.31c0 .116 0 .116-.116.116h-8.557c-.102 0-.128 0-.128-.115V2.865c0-.09 0-.102.115-.102h8.48c.206 0 .206 0 .206.205zm-8.763 9.661v-4.273c0-.09 0-.115.103-.09h8.621c.026 0 0 .09 0 .142v8.518a.06.06 0 0 1-.017.06a.06.06 0 0 1-.06.017H12.54s-.09 0-.077-.09V16.85z"
|
d="M2.75 7.189V2.865c0-.102 0-.115.115-.115h8.622c.128 0 .14 0 .14.128V11.5c0 .128 0 .128-.14.128H2.865c-.102 0-.115 0-.115-.116zM7.189 21.25H2.865c-.102 0-.115 0-.115-.116V12.59c0-.128 0-.128.128-.128h8.635c.102 0 .115 0 .115.115v8.57c0 .09 0 .103-.116.103zM21.25 7.189v4.31c0 .116 0 .116-.116.116h-8.557c-.102 0-.128 0-.128-.115V2.865c0-.09 0-.102.115-.102h8.48c.206 0 .206 0 .206.205zm-8.763 9.661v-4.273c0-.09 0-.115.103-.09h8.621c.026 0 0 .09 0 .142v8.518a.06.06 0 0 1-.017.06a.06.06 0 0 1-.06.017H12.54s-.09 0-.077-.09V16.85z"
|
||||||
></path>
|
/>
|
||||||
</svg>
|
</svg>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -3,8 +3,8 @@
|
|||||||
@variant dark (&:is(.dark *));
|
@variant dark (&:is(.dark *));
|
||||||
|
|
||||||
@theme {
|
@theme {
|
||||||
--font-sans: var(--font-sans), ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji",
|
--font-sans: var(--font-sans), ui-sans-serif, system-ui, sans-serif,
|
||||||
"Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
|
"Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
|
||||||
|
|
||||||
--color-border: hsl(var(--border));
|
--color-border: hsl(var(--border));
|
||||||
--color-input: hsl(var(--input));
|
--color-input: hsl(var(--input));
|
||||||
|
Loading…
Reference in New Issue
Block a user