mirror of
https://github.com/hamster1963/nezha-dash.git
synced 2025-04-24 21:10:45 +08:00
Compare commits
7 Commits
c771162e0b
...
ac5c7e801d
Author | SHA1 | Date | |
---|---|---|---|
|
ac5c7e801d | ||
|
950a20f60c | ||
|
1f4c58457d | ||
|
c40e3706cd | ||
|
3671da354b | ||
|
ccc875fb04 | ||
|
34f29420df |
2
.github/workflows/Deploy.yml
vendored
2
.github/workflows/Deploy.yml
vendored
@ -62,7 +62,7 @@ jobs:
|
|||||||
uses: oven-sh/setup-bun@v1
|
uses: oven-sh/setup-bun@v1
|
||||||
with:
|
with:
|
||||||
bun-version: "latest"
|
bun-version: "latest"
|
||||||
|
|
||||||
- name: Changelog
|
- name: Changelog
|
||||||
run: bun x changelogithub
|
run: bun x changelogithub
|
||||||
env:
|
env:
|
||||||
|
@ -107,12 +107,14 @@ export default function ServerListClient() {
|
|||||||
: filteredServersByStatus.filter((server) => server.tag === tag);
|
: filteredServersByStatus.filter((server) => server.tag === tag);
|
||||||
|
|
||||||
if (filter) {
|
if (filter) {
|
||||||
// 根据使用流量进行从高到低排序
|
|
||||||
filteredServers.sort((a, b) => {
|
filteredServers.sort((a, b) => {
|
||||||
|
if (!a.online_status && b.online_status) return 1;
|
||||||
|
if (a.online_status && !b.online_status) return -1;
|
||||||
|
if (!a.online_status && !b.online_status) return 0;
|
||||||
return (
|
return (
|
||||||
b.status.NetInTransfer +
|
b.status.NetInSpeed +
|
||||||
b.status.NetOutTransfer -
|
b.status.NetOutSpeed -
|
||||||
(a.status.NetInTransfer + b.status.NetOutTransfer)
|
(a.status.NetInSpeed + a.status.NetOutSpeed)
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
import { ServerApi } from "@/app/types/nezha-api";
|
import { ServerApi } from "@/app/types/nezha-api";
|
||||||
import { Loader } from "@/components/loading/Loader";
|
import { Loader } from "@/components/loading/Loader";
|
||||||
import { Card, CardContent } from "@/components/ui/card";
|
import { Card, CardContent } from "@/components/ui/card";
|
||||||
|
import { Separator } from "@/components/ui/separator";
|
||||||
import getEnv from "@/lib/env-entry";
|
import getEnv from "@/lib/env-entry";
|
||||||
import { useFilter } from "@/lib/network-filter-context";
|
import { useFilter } from "@/lib/network-filter-context";
|
||||||
import { useStatus } from "@/lib/status-context";
|
import { useStatus } from "@/lib/status-context";
|
||||||
@ -48,11 +49,14 @@ export default function ServerOverviewClient() {
|
|||||||
setStatus("all");
|
setStatus("all");
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
className={cn("cursor-pointer hover:border-blue-500 transition-all", {
|
className={cn(
|
||||||
"pointer-events-none": global,
|
"cursor-pointer hover:border-blue-500 transition-all min-h-[94px]",
|
||||||
})}
|
{
|
||||||
|
"pointer-events-none": global,
|
||||||
|
},
|
||||||
|
)}
|
||||||
>
|
>
|
||||||
<CardContent className="px-6 py-3">
|
<CardContent className="flex h-full items-center px-6 py-3">
|
||||||
<section className="flex flex-col gap-1">
|
<section className="flex flex-col gap-1">
|
||||||
<p className="text-sm font-medium md:text-base">
|
<p className="text-sm font-medium md:text-base">
|
||||||
{t("p_816-881_Totalservers")}
|
{t("p_816-881_Totalservers")}
|
||||||
@ -82,7 +86,7 @@ export default function ServerOverviewClient() {
|
|||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
className={cn(
|
className={cn(
|
||||||
"cursor-pointer hover:ring-green-500 ring-1 ring-transparent transition-all",
|
"cursor-pointer hover:ring-green-500 ring-1 ring-transparent transition-all min-h-[94px]",
|
||||||
{
|
{
|
||||||
"ring-green-500 ring-2 border-transparent": status === "online",
|
"ring-green-500 ring-2 border-transparent": status === "online",
|
||||||
},
|
},
|
||||||
@ -91,7 +95,7 @@ export default function ServerOverviewClient() {
|
|||||||
},
|
},
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
<CardContent className="px-6 py-3">
|
<CardContent className="flex h-full items-center px-6 py-3">
|
||||||
<section className="flex flex-col gap-1">
|
<section className="flex flex-col gap-1">
|
||||||
<p className="text-sm font-medium md:text-base">
|
<p className="text-sm font-medium md:text-base">
|
||||||
{t("p_1610-1676_Onlineservers")}
|
{t("p_1610-1676_Onlineservers")}
|
||||||
@ -122,7 +126,7 @@ export default function ServerOverviewClient() {
|
|||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
className={cn(
|
className={cn(
|
||||||
"cursor-pointer hover:ring-red-500 ring-1 ring-transparent transition-all",
|
"cursor-pointer hover:ring-red-500 ring-1 ring-transparent transition-all min-h-[94px]",
|
||||||
{
|
{
|
||||||
"ring-red-500 ring-2 border-transparent": status === "offline",
|
"ring-red-500 ring-2 border-transparent": status === "offline",
|
||||||
},
|
},
|
||||||
@ -131,7 +135,7 @@ export default function ServerOverviewClient() {
|
|||||||
},
|
},
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
<CardContent className="px-6 py-3">
|
<CardContent className="flex h-full items-center px-6 py-3">
|
||||||
<section className="flex flex-col gap-1">
|
<section className="flex flex-col gap-1">
|
||||||
<p className="text-sm font-medium md:text-base">
|
<p className="text-sm font-medium md:text-base">
|
||||||
{t("p_2532-2599_Offlineservers")}
|
{t("p_2532-2599_Offlineservers")}
|
||||||
@ -162,7 +166,7 @@ export default function ServerOverviewClient() {
|
|||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
className={cn(
|
className={cn(
|
||||||
"cursor-pointer hover:ring-purple-500 ring-1 ring-transparent transition-all",
|
"cursor-pointer hover:ring-purple-500 ring-1 ring-transparent transition-all min-h-[94px]",
|
||||||
{
|
{
|
||||||
"ring-purple-500 ring-2 border-transparent": filter === true,
|
"ring-purple-500 ring-2 border-transparent": filter === true,
|
||||||
},
|
},
|
||||||
@ -171,20 +175,34 @@ export default function ServerOverviewClient() {
|
|||||||
},
|
},
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
<CardContent className="relative px-6 py-3">
|
<CardContent className="flex h-full items-center relative px-3 py-1 pr-0 sm:px-6 sm:py-3">
|
||||||
<section className="flex flex-col gap-1">
|
<section className="flex flex-col gap-1">
|
||||||
<p className="text-sm font-medium md:text-base">
|
<div className="flex items-center gap-1">
|
||||||
{t("p_3463-3530_Totalbandwidth")}
|
<p className="text-sm font-medium md:text-base">
|
||||||
</p>
|
{t("p_3463-3530_Totalbandwidth")}
|
||||||
|
</p>
|
||||||
|
<Separator orientation="vertical" className="h-4 w-[1px]" />
|
||||||
|
<p className="text-sm font-medium md:text-base">{t("speed")}</p>
|
||||||
|
</div>
|
||||||
{data?.result ? (
|
{data?.result ? (
|
||||||
<section className="flex flex-col sm:flex-row pt-[8px] sm:items-center items-start gap-1">
|
<>
|
||||||
<p className="text-[12px] text-nowrap font-semibold">
|
<section className="flex flex-row sm:items-center items-start gap-1">
|
||||||
↑{formatBytes(data?.total_out_bandwidth)}
|
<p className="sm:text-[12px] text-[10px] text-stone-400 text-nowrap font-medium">
|
||||||
</p>
|
↑{formatBytes(data?.total_out_bandwidth)}
|
||||||
<p className="text-[12px] text-nowrap font-semibold">
|
</p>
|
||||||
↓{formatBytes(data?.total_in_bandwidth)}
|
<p className="sm:text-[12px] text-[10px] text-stone-400 text-nowrap font-medium">
|
||||||
</p>
|
↓{formatBytes(data?.total_in_bandwidth)}
|
||||||
</section>
|
</p>
|
||||||
|
</section>
|
||||||
|
<section className="flex flex-row -mt-1 -mr-1 sm:items-center items-start gap-1">
|
||||||
|
<p className="sm:text-[12px] text-[10px] text-nowrap font-semibold">
|
||||||
|
↑{formatBytes(data?.total_out_speed)}/s
|
||||||
|
</p>
|
||||||
|
<p className="sm:text-[12px] text-[10px] text-nowrap font-semibold">
|
||||||
|
↓{formatBytes(data?.total_in_speed)}/s
|
||||||
|
</p>
|
||||||
|
</section>
|
||||||
|
</>
|
||||||
) : (
|
) : (
|
||||||
<div className="flex h-7 items-center">
|
<div className="flex h-7 items-center">
|
||||||
<Loader visible={true} />
|
<Loader visible={true} />
|
||||||
|
@ -5,8 +5,6 @@ import { Suspense } from "react";
|
|||||||
import ServerGlobal from "./ClientComponents/Global";
|
import ServerGlobal from "./ClientComponents/Global";
|
||||||
import GlobalLoading from "./ClientComponents/GlobalLoading";
|
import GlobalLoading from "./ClientComponents/GlobalLoading";
|
||||||
|
|
||||||
export const runtime = "edge";
|
|
||||||
|
|
||||||
export default async function Home({
|
export default async function Home({
|
||||||
searchParams,
|
searchParams,
|
||||||
}: {
|
}: {
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
// @auto-i18n-check. Please do not delete the line.
|
// @auto-i18n-check. Please do not delete the line.
|
||||||
import { MotionProvider } from "@/components/motion/motion-provider";
|
|
||||||
import { ThemeColorManager } from "@/components/ThemeColorManager";
|
import { ThemeColorManager } from "@/components/ThemeColorManager";
|
||||||
|
import { MotionProvider } from "@/components/motion/motion-provider";
|
||||||
import getEnv from "@/lib/env-entry";
|
import getEnv from "@/lib/env-entry";
|
||||||
import { FilterProvider } from "@/lib/network-filter-context";
|
import { FilterProvider } from "@/lib/network-filter-context";
|
||||||
import { StatusProvider } from "@/lib/status-context";
|
import { StatusProvider } from "@/lib/status-context";
|
||||||
|
@ -4,8 +4,6 @@ import Link from "next/link";
|
|||||||
import Footer from "./(main)/footer";
|
import Footer from "./(main)/footer";
|
||||||
import Header from "./(main)/header";
|
import Header from "./(main)/header";
|
||||||
|
|
||||||
export const runtime = "edge";
|
|
||||||
|
|
||||||
export default function NotFoundPage() {
|
export default function NotFoundPage() {
|
||||||
const t = useTranslations("NotFoundPage");
|
const t = useTranslations("NotFoundPage");
|
||||||
return (
|
return (
|
||||||
|
@ -3,6 +3,8 @@ export type ServerApi = {
|
|||||||
offline_servers: number;
|
offline_servers: number;
|
||||||
total_out_bandwidth: number;
|
total_out_bandwidth: number;
|
||||||
total_in_bandwidth: number;
|
total_in_bandwidth: number;
|
||||||
|
total_out_speed: number;
|
||||||
|
total_in_speed: number;
|
||||||
result: NezhaAPISafe[];
|
result: NezhaAPISafe[];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1,37 +1,40 @@
|
|||||||
'use client';
|
"use client";
|
||||||
|
|
||||||
import { useEffect } from 'react';
|
import { useTheme } from "next-themes";
|
||||||
import { useTheme } from 'next-themes';
|
import { useEffect } from "react";
|
||||||
|
|
||||||
export function ThemeColorManager() {
|
export function ThemeColorManager() {
|
||||||
const { theme, systemTheme } = useTheme();
|
const { theme, systemTheme } = useTheme();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const updateThemeColor = () => {
|
const updateThemeColor = () => {
|
||||||
const currentTheme = theme === 'system' ? systemTheme : theme;
|
const currentTheme = theme === "system" ? systemTheme : theme;
|
||||||
const meta = document.querySelector('meta[name="theme-color"]');
|
const meta = document.querySelector('meta[name="theme-color"]');
|
||||||
|
|
||||||
if (!meta) {
|
if (!meta) {
|
||||||
const newMeta = document.createElement('meta');
|
const newMeta = document.createElement("meta");
|
||||||
newMeta.name = 'theme-color';
|
newMeta.name = "theme-color";
|
||||||
document.head.appendChild(newMeta);
|
document.head.appendChild(newMeta);
|
||||||
}
|
}
|
||||||
|
|
||||||
const themeColor = currentTheme === 'dark'
|
const themeColor =
|
||||||
? 'hsl(30 15% 8%)' // 深色模式背景色
|
currentTheme === "dark"
|
||||||
: 'hsl(0 0% 98%)'; // 浅色模式背景色
|
? "hsl(30 15% 8%)" // 深色模式背景色
|
||||||
|
: "hsl(0 0% 98%)"; // 浅色模式背景色
|
||||||
document.querySelector('meta[name="theme-color"]')?.setAttribute('content', themeColor);
|
|
||||||
|
document
|
||||||
|
.querySelector('meta[name="theme-color"]')
|
||||||
|
?.setAttribute("content", themeColor);
|
||||||
};
|
};
|
||||||
|
|
||||||
// Update on mount and theme change
|
// Update on mount and theme change
|
||||||
updateThemeColor();
|
updateThemeColor();
|
||||||
|
|
||||||
// Listen for system theme changes
|
// Listen for system theme changes
|
||||||
const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)');
|
const mediaQuery = window.matchMedia("(prefers-color-scheme: dark)");
|
||||||
mediaQuery.addEventListener('change', updateThemeColor);
|
mediaQuery.addEventListener("change", updateThemeColor);
|
||||||
|
|
||||||
return () => mediaQuery.removeEventListener('change', updateThemeColor);
|
return () => mediaQuery.removeEventListener("change", updateThemeColor);
|
||||||
}, [theme, systemTheme]);
|
}, [theme, systemTheme]);
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
|
@ -44,6 +44,8 @@ export async function GetNezhaData() {
|
|||||||
offline_servers: 0,
|
offline_servers: 0,
|
||||||
total_out_bandwidth: 0,
|
total_out_bandwidth: 0,
|
||||||
total_in_bandwidth: 0,
|
total_in_bandwidth: 0,
|
||||||
|
total_in_speed: 0,
|
||||||
|
total_out_speed: 0,
|
||||||
result: [],
|
result: [],
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -66,6 +68,8 @@ export async function GetNezhaData() {
|
|||||||
|
|
||||||
data.total_out_bandwidth += element.status.NetOutTransfer;
|
data.total_out_bandwidth += element.status.NetOutTransfer;
|
||||||
data.total_in_bandwidth += element.status.NetInTransfer;
|
data.total_in_bandwidth += element.status.NetInTransfer;
|
||||||
|
data.total_in_speed += element.status.NetInSpeed;
|
||||||
|
data.total_out_speed += element.status.NetOutSpeed;
|
||||||
|
|
||||||
// Remove unwanted properties
|
// Remove unwanted properties
|
||||||
delete element.ipv4;
|
delete element.ipv4;
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
"p_1610-1676_Onlineservers": "Online servers",
|
"p_1610-1676_Onlineservers": "Online servers",
|
||||||
"p_2532-2599_Offlineservers": "Offline servers",
|
"p_2532-2599_Offlineservers": "Offline servers",
|
||||||
"p_3463-3530_Totalbandwidth": "Total bandwidth",
|
"p_3463-3530_Totalbandwidth": "Total bandwidth",
|
||||||
|
"speed": "speed",
|
||||||
"error_message": "Please check your environment variables and review the server console",
|
"error_message": "Please check your environment variables and review the server console",
|
||||||
"no_data_message": "No data"
|
"no_data_message": "No data"
|
||||||
},
|
},
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
"p_1610-1676_Onlineservers": "オンラインサーバー",
|
"p_1610-1676_Onlineservers": "オンラインサーバー",
|
||||||
"p_2532-2599_Offlineservers": "オフラインサーバー",
|
"p_2532-2599_Offlineservers": "オフラインサーバー",
|
||||||
"p_3463-3530_Totalbandwidth": "総流量",
|
"p_3463-3530_Totalbandwidth": "総流量",
|
||||||
|
"speed": "速度",
|
||||||
"error_message": "環境変数を確認し、サーバーコンソールを確認してください",
|
"error_message": "環境変数を確認し、サーバーコンソールを確認してください",
|
||||||
"no_data_message": "データなし"
|
"no_data_message": "データなし"
|
||||||
},
|
},
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
"p_1610-1676_Onlineservers": "在線伺服器",
|
"p_1610-1676_Onlineservers": "在線伺服器",
|
||||||
"p_2532-2599_Offlineservers": "離線伺服器",
|
"p_2532-2599_Offlineservers": "離線伺服器",
|
||||||
"p_3463-3530_Totalbandwidth": "總流量",
|
"p_3463-3530_Totalbandwidth": "總流量",
|
||||||
|
"speed": "速率",
|
||||||
"error_message": "請檢查您的環境變數並檢查伺服器控制台",
|
"error_message": "請檢查您的環境變數並檢查伺服器控制台",
|
||||||
"no_data_message": "無資料"
|
"no_data_message": "無資料"
|
||||||
},
|
},
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
"p_1610-1676_Onlineservers": "在线服务器",
|
"p_1610-1676_Onlineservers": "在线服务器",
|
||||||
"p_2532-2599_Offlineservers": "离线服务器",
|
"p_2532-2599_Offlineservers": "离线服务器",
|
||||||
"p_3463-3530_Totalbandwidth": "总流量",
|
"p_3463-3530_Totalbandwidth": "总流量",
|
||||||
|
"speed": "速率",
|
||||||
"error_message": "请检查您的环境变量并检查服务器控制台",
|
"error_message": "请检查您的环境变量并检查服务器控制台",
|
||||||
"no_data_message": "无数据"
|
"no_data_message": "无数据"
|
||||||
},
|
},
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "nezha-dash",
|
"name": "nezha-dash",
|
||||||
"version": "1.6.6",
|
"version": "1.6.8",
|
||||||
"private": true,
|
"private": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "next dev -p 3040",
|
"dev": "next dev -p 3040",
|
||||||
|
Loading…
Reference in New Issue
Block a user