Merge branch 'main' into cloudflare

This commit is contained in:
hamster1963 2024-10-22 11:51:36 +08:00
commit 1976bce1c4
15 changed files with 1681 additions and 16 deletions

View File

@ -16,7 +16,7 @@
| ------------------------------ | ------------------------ | ------------------------------------------------------------- | | ------------------------------ | ------------------------ | ------------------------------------------------------------- |
| NezhaBaseUrl | nezha 面板地址 | http://120.x.x.x:8008 | | NezhaBaseUrl | nezha 面板地址 | http://120.x.x.x:8008 |
| NezhaAuth | nezha 面板 API Token | 5hAY3QX6Nl9B3Uxxxx26KMvOMyXS1Udi | | NezhaAuth | nezha 面板 API Token | 5hAY3QX6Nl9B3Uxxxx26KMvOMyXS1Udi |
| SitePassword | 页面密码 | 123456 | | SitePassword | 页面密码 | **默认**:无密码 |
| DefaultLocale | 面板默认显示语言 | **默认**en [简中:zh 繁中:zh-t 英语:en 日语:ja] | | DefaultLocale | 面板默认显示语言 | **默认**en [简中:zh 繁中:zh-t 英语:en 日语:ja] |
| ForceShowAllServers | 是否强制显示所有服务器 | **默认**false | | ForceShowAllServers | 是否强制显示所有服务器 | **默认**false |
| NEXT_PUBLIC_NezhaFetchInterval | 获取数据间隔(毫秒) | **默认**2000 | | NEXT_PUBLIC_NezhaFetchInterval | 获取数据间隔(毫秒) | **默认**2000 |

View File

@ -3,6 +3,7 @@
import { ServerDetailLoading } from "@/app/[locale]/(main)/ClientComponents/ServerDetailLoading"; import { ServerDetailLoading } from "@/app/[locale]/(main)/ClientComponents/ServerDetailLoading";
import { NezhaAPISafe } from "@/app/[locale]/types/nezha-api"; import { NezhaAPISafe } from "@/app/[locale]/types/nezha-api";
import { BackIcon } from "@/components/Icon"; import { BackIcon } from "@/components/Icon";
import ServerFlag from "@/components/ServerFlag";
import { Badge } from "@/components/ui/badge"; import { Badge } from "@/components/ui/badge";
import { Card, CardContent } from "@/components/ui/card"; import { Card, CardContent } from "@/components/ui/card";
import getEnv from "@/lib/env-entry"; import getEnv from "@/lib/env-entry";
@ -60,7 +61,7 @@ export default function ServerDetailClient({
<p className="text-xs text-muted-foreground">{t("status")}</p> <p className="text-xs text-muted-foreground">{t("status")}</p>
<Badge <Badge
className={cn( className={cn(
"text-[10px] rounded-[6px] w-fit px-1 py-0 dark:text-white", "text-[9px] rounded-[6px] w-fit px-1 py-0 -mt-[0.3px] dark:text-white",
{ {
" bg-green-800": data?.online_status, " bg-green-800": data?.online_status,
" bg-red-600": !data?.online_status, " bg-red-600": !data?.online_status,
@ -115,6 +116,22 @@ export default function ServerDetailClient({
</section> </section>
</CardContent> </CardContent>
</Card> </Card>
<Card className="rounded-[10px] bg-transparent border-none shadow-none">
<CardContent className="px-1.5 py-1">
<section className="flex flex-col items-start gap-0.5">
<p className="text-xs text-muted-foreground">{t("Region")}</p>
<section className="flex items-start gap-1">
<div className="text-xs text-start">
{data?.host.CountryCode.toUpperCase()}
</div>
<ServerFlag
className="text-[11px] -mt-[1px]"
country_code={data?.host.CountryCode}
/>
</section>
</section>
</CardContent>
</Card>
</section> </section>
<section className="flex flex-wrap gap-2 mt-1"> <section className="flex flex-wrap gap-2 mt-1">
<Card className="rounded-[10px] bg-transparent border-none shadow-none"> <Card className="rounded-[10px] bg-transparent border-none shadow-none">

View File

@ -1,5 +1,4 @@
// @auto-i18n-check. Please do not delete the line. // @auto-i18n-check. Please do not delete the line.
import { auth } from "@/auth";
import { locales } from "@/i18n-metadata"; import { locales } from "@/i18n-metadata";
import getEnv from "@/lib/env-entry"; import getEnv from "@/lib/env-entry";
import { cn } from "@/lib/utils"; import { cn } from "@/lib/utils";
@ -13,8 +12,6 @@ import { ThemeProvider } from "next-themes";
import { Inter as FontSans } from "next/font/google"; import { Inter as FontSans } from "next/font/google";
import React from "react"; import React from "react";
import "/node_modules/flag-icons/css/flag-icons.min.css";
const fontSans = FontSans({ const fontSans = FontSans({
subsets: ["latin"], subsets: ["latin"],
variable: "--font-sans", variable: "--font-sans",
@ -65,6 +62,10 @@ export default function LocaleLayout({
<html lang={locale} suppressHydrationWarning> <html lang={locale} suppressHydrationWarning>
<head> <head>
<PublicEnvScript /> <PublicEnvScript />
<link
rel="stylesheet"
href="https://cdn.jsdelivr.net/gh/lipis/flag-icons@7.0.0/css/flag-icons.min.css"
/>
</head> </head>
<body <body
className={cn( className={cn(

View File

@ -16,7 +16,7 @@ interface NezhaDataResponse {
export const GET = auth(async function GET(req) { export const GET = auth(async function GET(req) {
if (!req.auth && getEnv("SitePassword")) { if (!req.auth && getEnv("SitePassword")) {
redirect("/api/auth/signin"); redirect("/");
} }
const { searchParams } = new URL(req.url); const { searchParams } = new URL(req.url);

View File

@ -16,7 +16,7 @@ interface NezhaDataResponse {
export const GET = auth(async function GET(req) { export const GET = auth(async function GET(req) {
if (!req.auth && getEnv("SitePassword")) { if (!req.auth && getEnv("SitePassword")) {
redirect("/api/auth/signin"); redirect("/");
} }
const { searchParams } = new URL(req.url); const { searchParams } = new URL(req.url);

View File

@ -16,7 +16,7 @@ interface NezhaDataResponse {
export const GET = auth(async function GET(req) { export const GET = auth(async function GET(req) {
if (!req.auth && getEnv("SitePassword")) { if (!req.auth && getEnv("SitePassword")) {
redirect("/api/auth/signin"); redirect("/");
} }
const response = (await GetNezhaData()) as NezhaDataResponse; const response = (await GetNezhaData()) as NezhaDataResponse;

View File

@ -1,8 +1,15 @@
import getEnv from "@/lib/env-entry"; import getEnv from "@/lib/env-entry";
import { cn } from "@/lib/utils";
import getUnicodeFlagIcon from "country-flag-icons/unicode"; import getUnicodeFlagIcon from "country-flag-icons/unicode";
import { useEffect, useState } from "react"; import { useEffect, useState } from "react";
export default function ServerFlag({ country_code }: { country_code: string }) { export default function ServerFlag({
country_code,
className,
}: {
country_code: string;
className?: string;
}) {
const [supportsEmojiFlags, setSupportsEmojiFlags] = useState(false); const [supportsEmojiFlags, setSupportsEmojiFlags] = useState(false);
const useSvgFlag = getEnv("NEXT_PUBLIC_ForceUseSvgFlag") === "true"; const useSvgFlag = getEnv("NEXT_PUBLIC_ForceUseSvgFlag") === "true";
@ -38,9 +45,9 @@ export default function ServerFlag({ country_code }: { country_code: string }) {
} }
return ( return (
<span className="text-[12px] text-muted-foreground"> <span className={cn("text-[12px] text-muted-foreground", className)}>
{useSvgFlag || !supportsEmojiFlags ? ( {useSvgFlag || !supportsEmojiFlags ? (
<span className={`fi fi-${country_code}`}></span> <span className={`fi fi-${country_code}`} />
) : ( ) : (
getUnicodeFlagIcon(country_code) getUnicodeFlagIcon(country_code)
)} )}

View File

@ -36,12 +36,10 @@ export function SignIn() {
}); });
if (res?.error) { if (res?.error) {
console.log("login error"); console.log("login error");
console.log(res);
setErrorState(true); setErrorState(true);
setSuccessState(false); setSuccessState(false);
} else { } else {
console.log("login success"); console.log("login success");
console.log(res);
setErrorState(false); setErrorState(false);
setSuccessState(true); setSuccessState(true);
router.push("/"); router.push("/");
@ -75,7 +73,7 @@ export function SignIn() {
/> />
</label> </label>
<button <button
className=" px-1.5 py-0.5 w-fit flex items-center gap-1 text-sm font-semibold rounded-[8px] border bg-card hover:brightness-95 transition-all text-card-foreground shadow-lg shadow-neutral-200/40 dark:shadow-none" className="px-1.5 py-0.5 w-fit flex items-center gap-1 text-sm font-semibold rounded-[8px] border bg-card hover:brightness-95 transition-all text-card-foreground shadow-lg shadow-neutral-200/40 dark:shadow-none"
disabled={loading} disabled={loading}
> >
{t("Submit")} {t("Submit")}

View File

@ -14,7 +14,7 @@ export default function TabSwitch({
setCurrentTab: (tab: string) => void; setCurrentTab: (tab: string) => void;
}) { }) {
return ( return (
<div className="z-50 flex flex-col items-start overflow-x-scroll rounded-[50px]"> <div className="z-50 flex flex-col items-start rounded-[50px]">
<div className="flex items-center gap-1 rounded-[50px] bg-stone-100 p-[3px] dark:bg-stone-800"> <div className="flex items-center gap-1 rounded-[50px] bg-stone-100 p-[3px] dark:bg-stone-800">
{tabs.map((tab: string) => ( {tabs.map((tab: string) => (
<div <div

View File

@ -58,6 +58,7 @@
"Arch": "Arch", "Arch": "Arch",
"Mem": "Mem", "Mem": "Mem",
"Disk": "Disk", "Disk": "Disk",
"Region": "Region",
"System": "System", "System": "System",
"CPU": "CPU" "CPU": "CPU"
}, },

View File

@ -58,6 +58,7 @@
"Arch": "アーキテクチャ", "Arch": "アーキテクチャ",
"Mem": "メモリ", "Mem": "メモリ",
"Disk": "ディスク", "Disk": "ディスク",
"Region": "地域",
"System": "システム", "System": "システム",
"CPU": "CPU" "CPU": "CPU"
}, },

View File

@ -58,6 +58,7 @@
"Arch": "架構", "Arch": "架構",
"Mem": "記憶體", "Mem": "記憶體",
"Disk": "磁碟", "Disk": "磁碟",
"Region": "地區",
"System": "系統", "System": "系統",
"CPU": "CPU" "CPU": "CPU"
}, },

View File

@ -58,6 +58,7 @@
"Arch": "架构", "Arch": "架构",
"Mem": "内存", "Mem": "内存",
"Disk": "磁盘", "Disk": "磁盘",
"Region": "地区",
"System": "系统", "System": "系统",
"CPU": "CPU" "CPU": "CPU"
}, },

View File

@ -3,7 +3,7 @@
"version": "0.1.0", "version": "0.1.0",
"private": true, "private": true,
"scripts": { "scripts": {
"dev": "next dev -p 3020", "dev": "next dev -p 3020 --turbo",
"start": "node .next/standalone/server.js", "start": "node .next/standalone/server.js",
"lint": "next lint", "lint": "next lint",
"build": "next build && cp -r .next/static .next/standalone/.next/ && cp -r public .next/standalone/", "build": "next build && cp -r .next/static .next/standalone/.next/ && cp -r public .next/standalone/",

1638
styles/flag-icons.min.css vendored Normal file

File diff suppressed because it is too large Load Diff