From a3bbd7b2ebcfb1e09b77d9a220c9a87f609964ff Mon Sep 17 00:00:00 2001 From: hamster1963 <1410514192@qq.com> Date: Fri, 6 Dec 2024 22:55:13 +0800 Subject: [PATCH] feat: refactor overview button --- src/components/ServerDetailChart.tsx | 4 +-- src/components/ServerOverview.tsx | 39 ++++++++++++++++++++--- src/context/filter-context.ts | 10 ++++++ src/context/network-filter-context.tsx | 14 ++++++++ src/context/status-context.ts | 12 +++++++ src/context/status-provider.tsx | 14 ++++++++ src/hooks/use-filter.tsx | 12 +++++++ src/hooks/use-status.tsx | 10 ++++++ src/main.tsx | 32 +++++++++++-------- src/pages/Server.tsx | 44 ++++++++++++++++++++++++-- 10 files changed, 170 insertions(+), 21 deletions(-) create mode 100644 src/context/filter-context.ts create mode 100644 src/context/network-filter-context.tsx create mode 100644 src/context/status-context.ts create mode 100644 src/context/status-provider.tsx create mode 100644 src/hooks/use-filter.tsx create mode 100644 src/hooks/use-status.tsx diff --git a/src/components/ServerDetailChart.tsx b/src/components/ServerDetailChart.tsx index 973fb5b..6de61c7 100644 --- a/src/components/ServerDetailChart.tsx +++ b/src/components/ServerDetailChart.tsx @@ -110,8 +110,8 @@ export default function ServerDetailChart({ gpuName={`#${index + 1}`} key={index} /> - ) - )) : ( + )) + ) : ( <>> )} diff --git a/src/components/ServerOverview.tsx b/src/components/ServerOverview.tsx index 623f2c9..f94b942 100644 --- a/src/components/ServerOverview.tsx +++ b/src/components/ServerOverview.tsx @@ -6,6 +6,8 @@ import { ArrowDownCircleIcon, ArrowUpCircleIcon, } from "@heroicons/react/20/solid"; +import { useStatus } from "@/hooks/use-status"; +import useFilter from "@/hooks/use-filter"; type ServerOverviewProps = { online: number; @@ -27,11 +29,19 @@ export default function ServerOverview({ downSpeed, }: ServerOverviewProps) { const { t } = useTranslation(); + const { status, setStatus } = useStatus(); + const { filter, setFilter } = useFilter(); return ( <> - + { + setFilter(false); + setStatus("all"); + }} + className={cn("hover:border-blue-500 cursor-pointer transition-all")} + > @@ -47,8 +57,15 @@ export default function ServerOverview({ { + setFilter(false); + setStatus("online"); + }} className={cn( - " hover:ring-green-500 ring-1 ring-transparent transition-all", + "cursor-pointer hover:ring-green-500 ring-1 ring-transparent transition-all", + { + "ring-green-500 ring-2 border-transparent": status === "online", + }, )} > @@ -68,8 +85,15 @@ export default function ServerOverview({ { + setFilter(false); + setStatus("offline"); + }} className={cn( - " hover:ring-red-500 ring-1 ring-transparent transition-all", + "cursor-pointer hover:ring-red-500 ring-1 ring-transparent transition-all", + { + "ring-red-500 ring-2 border-transparent": status === "offline", + }, )} > @@ -88,8 +112,15 @@ export default function ServerOverview({ { + setStatus("all"); + setFilter(true); + }} className={cn( - " hover:ring-purple-500 ring-1 ring-transparent transition-all", + "cursor-pointer hover:ring-purple-500 ring-1 ring-transparent transition-all", + { + "ring-purple-500 ring-2 border-transparent": filter === true, + }, )} > diff --git a/src/context/filter-context.ts b/src/context/filter-context.ts new file mode 100644 index 0000000..373d41c --- /dev/null +++ b/src/context/filter-context.ts @@ -0,0 +1,10 @@ +import { createContext } from "react"; + +export interface FilterContextType { + filter: boolean; + setFilter: (filter: boolean) => void; +} + +export const FilterContext = createContext( + undefined, +); diff --git a/src/context/network-filter-context.tsx b/src/context/network-filter-context.tsx new file mode 100644 index 0000000..b32ee5d --- /dev/null +++ b/src/context/network-filter-context.tsx @@ -0,0 +1,14 @@ +"use client"; + +import { ReactNode, useState } from "react"; +import { FilterContext } from "./filter-context"; + +export function FilterProvider({ children }: { children: ReactNode }) { + const [filter, setFilter] = useState(false); + + return ( + + {children} + + ); +} diff --git a/src/context/status-context.ts b/src/context/status-context.ts new file mode 100644 index 0000000..3944a14 --- /dev/null +++ b/src/context/status-context.ts @@ -0,0 +1,12 @@ +import { createContext } from "react"; + +export type Status = "all" | "online" | "offline"; + +export interface StatusContextType { + status: Status; + setStatus: (status: Status) => void; +} + +export const StatusContext = createContext( + undefined, +); diff --git a/src/context/status-provider.tsx b/src/context/status-provider.tsx new file mode 100644 index 0000000..4b3d732 --- /dev/null +++ b/src/context/status-provider.tsx @@ -0,0 +1,14 @@ +"use client"; + +import { ReactNode, useState } from "react"; +import { Status, StatusContext } from "./status-context"; + +export function StatusProvider({ children }: { children: ReactNode }) { + const [status, setStatus] = useState("all"); + + return ( + + {children} + + ); +} diff --git a/src/hooks/use-filter.tsx b/src/hooks/use-filter.tsx new file mode 100644 index 0000000..c5d39fb --- /dev/null +++ b/src/hooks/use-filter.tsx @@ -0,0 +1,12 @@ +import { useContext } from "react"; +import { FilterContext, FilterContextType } from "@/context/filter-context"; + +const useFilter = (): FilterContextType => { + const context = useContext(FilterContext); + if (context === undefined) { + throw new Error("useFilter must be used within a FilterProvider"); + } + return context; +}; + +export default useFilter; diff --git a/src/hooks/use-status.tsx b/src/hooks/use-status.tsx new file mode 100644 index 0000000..dddb0c6 --- /dev/null +++ b/src/hooks/use-status.tsx @@ -0,0 +1,10 @@ +import { useContext } from "react"; +import { StatusContext } from "../context/status-context"; + +export function useStatus() { + const context = useContext(StatusContext); + if (context === undefined) { + throw new Error("useStatus must be used within a StatusProvider"); + } + return context; +} diff --git a/src/main.tsx b/src/main.tsx index 644d38b..77d7ed6 100644 --- a/src/main.tsx +++ b/src/main.tsx @@ -9,6 +9,8 @@ import { QueryClient, QueryClientProvider } from "@tanstack/react-query"; import { Toaster } from "sonner"; import { MotionProvider } from "./components/motion/motion-provider"; import { WebSocketProvider } from "./context/websocket-provider"; +import { StatusProvider } from "./context/status-provider"; +import { FilterProvider } from "./context/network-filter-context"; const queryClient = new QueryClient(); @@ -18,19 +20,23 @@ ReactDOM.createRoot(document.getElementById("root")!).render( - - - + + + + + + + diff --git a/src/pages/Server.tsx b/src/pages/Server.tsx index a6fac6d..9633b2d 100644 --- a/src/pages/Server.tsx +++ b/src/pages/Server.tsx @@ -19,6 +19,8 @@ import { ServiceTracker } from "@/components/ServiceTracker"; import ServerCardInline from "@/components/ServerCardInline"; import { Loader } from "@/components/loading/Loader"; import GlobalMap from "@/components/GlobalMap"; +import { useStatus } from "@/hooks/use-status"; +import useFilter from "@/hooks/use-filter"; export default function Servers() { const { t } = useTranslation(); @@ -27,7 +29,8 @@ export default function Servers() { queryFn: () => fetchServerGroup(), }); const { lastMessage, connected } = useWebSocketContext(); - + const { status } = useStatus(); + const { filter } = useFilter(); const [showServices, setShowServices] = useState("0"); const [showMap, setShowMap] = useState("0"); const [inline, setInline] = useState("0"); @@ -83,7 +86,7 @@ export default function Servers() { ); } - const filteredServers = + let filteredServers = nezhaWsData?.servers?.filter((server) => { if (currentGroup === "All") return true; const group = groupData?.data?.find( @@ -138,6 +141,43 @@ export default function Servers() { 0, ) || 0; + filteredServers = + status === "all" + ? filteredServers + : filteredServers.filter((server) => + [status].includes( + formatNezhaInfo(nezhaWsData.now, server).online + ? "online" + : "offline", + ), + ); + + if (filter) { + filteredServers.sort((a, b) => { + if ( + !formatNezhaInfo(nezhaWsData.now, a).online && + formatNezhaInfo(nezhaWsData.now, b).online + ) + return 1; + if ( + formatNezhaInfo(nezhaWsData.now, a).online && + !formatNezhaInfo(nezhaWsData.now, b).online + ) + return -1; + if ( + !formatNezhaInfo(nezhaWsData.now, a).online && + !formatNezhaInfo(nezhaWsData.now, b).online + ) + return 0; + return ( + formatNezhaInfo(nezhaWsData.now, b).state.net_in_speed + + formatNezhaInfo(nezhaWsData.now, b).state.net_out_speed - + (formatNezhaInfo(nezhaWsData.now, a).state.net_in_speed + + formatNezhaInfo(nezhaWsData.now, a).state.net_out_speed) + ); + }); + } + return (
@@ -47,8 +57,15 @@ export default function ServerOverview({