Merge branch 'main' into cloudflare

This commit is contained in:
hamster1963 2024-11-19 14:38:14 +08:00
commit 16b08888bc
9 changed files with 80 additions and 18 deletions

View File

@ -12,7 +12,7 @@ NEXT_PUBLIC_FixedTopServerName=false
NEXT_PUBLIC_CustomLogo=https://nezha-cf.buycoffee.top/apple-touch-icon.png NEXT_PUBLIC_CustomLogo=https://nezha-cf.buycoffee.top/apple-touch-icon.png
NEXT_PUBLIC_CustomTitle=NezhaDash NEXT_PUBLIC_CustomTitle=NezhaDash
NEXT_PUBLIC_CustomDescription=NezhaDash is a dashboard for Nezha. NEXT_PUBLIC_CustomDescription=NezhaDash is a dashboard for Nezha.
NEXT_PUBLIC_Links=[{"link":"https://baidu.com","name":"Baidu"},{"link":"https://google.com","name":"Google"}] NEXT_PUBLIC_Links="[{"link":"https://github.com/hamster1963/nezha-dash","name":"GitHub"},{"link":"https://buycoffee.top/coffee","name":"Buycoffee☕"}]"
NEXT_PUBLIC_DisableIndex=false NEXT_PUBLIC_DisableIndex=false
NEXT_PUBLIC_BASE_PATH=/ NEXT_PUBLIC_BASE_PATH=/
NEXT_PUBLIC_ShowTagCount=false NEXT_PUBLIC_ShowTagCount=false

View File

@ -4,12 +4,14 @@ import { ServerApi } from "@/app/types/nezha-api";
import ServerCard from "@/components/ServerCard"; import ServerCard from "@/components/ServerCard";
import Switch from "@/components/Switch"; import Switch from "@/components/Switch";
import getEnv from "@/lib/env-entry"; import getEnv from "@/lib/env-entry";
import { useStatus } from "@/lib/status-context";
import { nezhaFetcher } from "@/lib/utils"; import { nezhaFetcher } from "@/lib/utils";
import { useTranslations } from "next-intl"; import { useTranslations } from "next-intl";
import { useEffect, useRef, useState } from "react"; import { useEffect, useRef, useState } from "react";
import useSWR from "swr"; import useSWR from "swr";
export default function ServerListClient() { export default function ServerListClient() {
const { status } = useStatus();
const t = useTranslations("ServerListClient"); const t = useTranslations("ServerListClient");
const containerRef = useRef<HTMLDivElement>(null); const containerRef = useRef<HTMLDivElement>(null);
const defaultTag = "defaultTag"; const defaultTag = "defaultTag";
@ -73,17 +75,26 @@ export default function ServerListClient() {
return a.id - b.id; return a.id - b.id;
}); });
const allTag = sortedServers.map((server) => server.tag).filter(Boolean); const filteredServersByStatus =
status === "all"
? sortedServers
: sortedServers.filter((server) =>
[status].includes(server.online_status ? "online" : "offline"),
);
const allTag = filteredServersByStatus
.map((server) => server.tag)
.filter(Boolean);
const uniqueTags = [...new Set(allTag)]; const uniqueTags = [...new Set(allTag)];
uniqueTags.unshift(defaultTag); uniqueTags.unshift(defaultTag);
const filteredServers = const filteredServers =
tag === defaultTag tag === defaultTag
? sortedServers ? filteredServersByStatus
: sortedServers.filter((server) => server.tag === tag); : filteredServersByStatus.filter((server) => server.tag === tag);
const tagCountMap: Record<string, number> = {}; const tagCountMap: Record<string, number> = {};
sortedServers.forEach((server) => { filteredServersByStatus.forEach((server) => {
if (server.tag) { if (server.tag) {
tagCountMap[server.tag] = (tagCountMap[server.tag] || 0) + 1; tagCountMap[server.tag] = (tagCountMap[server.tag] || 0) + 1;
} }
@ -91,7 +102,7 @@ export default function ServerListClient() {
return ( return (
<> <>
{getEnv("NEXT_PUBLIC_ShowTag") === "true" && uniqueTags.length > 1 && ( {getEnv("NEXT_PUBLIC_ShowTag") === "true" && (
<Switch <Switch
allTag={uniqueTags} allTag={uniqueTags}
nowTag={tag} nowTag={tag}

View File

@ -4,13 +4,15 @@ 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 getEnv from "@/lib/env-entry"; import getEnv from "@/lib/env-entry";
import { formatBytes, nezhaFetcher } from "@/lib/utils"; import { useStatus } from "@/lib/status-context";
import { cn, formatBytes, nezhaFetcher } from "@/lib/utils";
import blogMan from "@/public/blog-man.webp"; import blogMan from "@/public/blog-man.webp";
import { useTranslations } from "next-intl"; import { useTranslations } from "next-intl";
import Image from "next/image"; import Image from "next/image";
import useSWR from "swr"; import useSWR from "swr";
export default function ServerOverviewClient() { export default function ServerOverviewClient() {
const { status, setStatus } = useStatus();
const t = useTranslations("ServerOverviewClient"); const t = useTranslations("ServerOverviewClient");
const { data, error, isLoading } = useSWR<ServerApi>( const { data, error, isLoading } = useSWR<ServerApi>(
"/api/server", "/api/server",
@ -32,7 +34,10 @@ export default function ServerOverviewClient() {
return ( return (
<> <>
<section className="grid grid-cols-2 gap-4 lg:grid-cols-4"> <section className="grid grid-cols-2 gap-4 lg:grid-cols-4">
<Card> <Card
onClick={() => setStatus("all")}
className="cursor-pointer hover:border-blue-500 transition-all"
>
<CardContent className="px-6 py-3"> <CardContent className="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">
@ -55,7 +60,15 @@ export default function ServerOverviewClient() {
</section> </section>
</CardContent> </CardContent>
</Card> </Card>
<Card> <Card
onClick={() => setStatus("online")}
className={cn(
"cursor-pointer hover:ring-green-500 ring-1 ring-transparent transition-all",
{
"ring-green-500 ring-2 border-transparent": status === "online",
},
)}
>
<CardContent className="px-6 py-3"> <CardContent className="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">
@ -79,7 +92,15 @@ export default function ServerOverviewClient() {
</section> </section>
</CardContent> </CardContent>
</Card> </Card>
<Card> <Card
onClick={() => setStatus("offline")}
className={cn(
"cursor-pointer hover:ring-red-500 ring-1 ring-transparent transition-all",
{
"ring-red-500 ring-2 border-transparent": status === "offline",
},
)}
>
<CardContent className="px-6 py-3"> <CardContent className="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">

View File

@ -71,8 +71,6 @@ function Links() {
const links: links[] | null = linksEnv ? JSON.parse(linksEnv) : null; const links: links[] | null = linksEnv ? JSON.parse(linksEnv) : null;
console.log(links);
if (!links) return null; if (!links) return null;
return ( return (

View File

@ -1,6 +1,7 @@
// @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 { MotionProvider } from "@/components/motion/motion-provider";
import getEnv from "@/lib/env-entry"; import getEnv from "@/lib/env-entry";
import { StatusProvider } from "@/lib/status-context";
import { cn } from "@/lib/utils"; import { cn } from "@/lib/utils";
import "@/styles/globals.css"; import "@/styles/globals.css";
import type { Metadata } from "next"; import type { Metadata } from "next";
@ -78,7 +79,7 @@ export default async function LocaleLayout({
disableTransitionOnChange disableTransitionOnChange
> >
<NextIntlClientProvider messages={messages}> <NextIntlClientProvider messages={messages}>
{children} <StatusProvider>{children}</StatusProvider>
</NextIntlClientProvider> </NextIntlClientProvider>
</ThemeProvider> </ThemeProvider>
</MotionProvider> </MotionProvider>

BIN
bun.lockb

Binary file not shown.

View File

@ -12,5 +12,6 @@ NEXT_PUBLIC_FixedTopServerName=false
NEXT_PUBLIC_CustomLogo=https://nezha-cf.buycoffee.top/apple-touch-icon.png NEXT_PUBLIC_CustomLogo=https://nezha-cf.buycoffee.top/apple-touch-icon.png
NEXT_PUBLIC_CustomTitle=NezhaDash NEXT_PUBLIC_CustomTitle=NezhaDash
NEXT_PUBLIC_CustomDescription=NezhaDash is a dashboard for Nezha. NEXT_PUBLIC_CustomDescription=NezhaDash is a dashboard for Nezha.
NEXT_PUBLIC_Links="[{"link":"https://github.com/hamster1963/nezha-dash","name":"GitHub"},{"link":"https://buycoffee.top/coffee","name":"Buycoffee☕"}]"
NEXT_PUBLIC_DisableIndex=false NEXT_PUBLIC_DisableIndex=false
NEXT_PUBLIC_ShowTagCount=false NEXT_PUBLIC_ShowTagCount=false

30
lib/status-context.tsx Normal file
View File

@ -0,0 +1,30 @@
"use client";
import React, { ReactNode, createContext, useContext, useState } from "react";
type Status = "all" | "online" | "offline";
interface StatusContextType {
status: Status;
setStatus: (status: Status) => void;
}
const StatusContext = createContext<StatusContextType | undefined>(undefined);
export function StatusProvider({ children }: { children: ReactNode }) {
const [status, setStatus] = useState<Status>("all");
return (
<StatusContext.Provider value={{ status, setStatus }}>
{children}
</StatusContext.Provider>
);
}
export function useStatus() {
const context = useContext(StatusContext);
if (context === undefined) {
throw new Error("useStatus must be used within a StatusProvider");
}
return context;
}

View File

@ -1,6 +1,6 @@
{ {
"name": "nezha-dash", "name": "nezha-dash",
"version": "1.3.1", "version": "1.3.2",
"private": true, "private": true,
"scripts": { "scripts": {
"dev": "next dev -p 3020", "dev": "next dev -p 3020",
@ -12,7 +12,7 @@
}, },
"dependencies": { "dependencies": {
"@ducanh2912/next-pwa": "^10.2.9", "@ducanh2912/next-pwa": "^10.2.9",
"@heroicons/react": "^2.1.5", "@heroicons/react": "^2.2.0",
"@radix-ui/react-dialog": "^1.1.2", "@radix-ui/react-dialog": "^1.1.2",
"@radix-ui/react-dropdown-menu": "^2.1.2", "@radix-ui/react-dropdown-menu": "^2.1.2",
"@radix-ui/react-navigation-menu": "^1.2.1", "@radix-ui/react-navigation-menu": "^1.2.1",
@ -23,7 +23,7 @@
"@radix-ui/react-tooltip": "^1.1.4", "@radix-ui/react-tooltip": "^1.1.4",
"@trivago/prettier-plugin-sort-imports": "^4.3.0", "@trivago/prettier-plugin-sort-imports": "^4.3.0",
"@types/luxon": "^3.4.2", "@types/luxon": "^3.4.2",
"@typescript-eslint/eslint-plugin": "^8.14.0", "@typescript-eslint/eslint-plugin": "^8.15.0",
"caniuse-lite": "^1.0.30001680", "caniuse-lite": "^1.0.30001680",
"class-variance-authority": "^0.7.0", "class-variance-authority": "^0.7.0",
"clsx": "^2.1.1", "clsx": "^2.1.1",
@ -48,7 +48,7 @@
"swr": "^2.2.6-beta.4", "swr": "^2.2.6-beta.4",
"tailwind-merge": "^2.5.4", "tailwind-merge": "^2.5.4",
"tailwindcss-animate": "^1.0.7", "tailwindcss-animate": "^1.0.7",
"typescript-eslint": "^8.14.0" "typescript-eslint": "^8.15.0"
}, },
"devDependencies": { "devDependencies": {
"eslint-plugin-turbo": "^2.3.0", "eslint-plugin-turbo": "^2.3.0",