From 2991b91f35da85f4cc92fd64e14d5654c2e1d422 Mon Sep 17 00:00:00 2001 From: UUBulb <35923940+uubulb@users.noreply.github.com> Date: Fri, 22 Nov 2024 22:15:41 +0800 Subject: [PATCH] feat: responsive fm card (#11) * feat: responsive fm card * delete meaningless words * fix joinIP --- src/components/cron.tsx | 2 +- src/components/fm.tsx | 80 +++++++++++++++----- src/components/xui/virtulized-data-table.tsx | 12 ++- src/lib/utils.ts | 14 +++- src/routes/server.tsx | 5 +- src/types/api.ts | 15 +++- 6 files changed, 98 insertions(+), 30 deletions(-) diff --git a/src/components/cron.tsx b/src/components/cron.tsx index 0fe03d0..931adb0 100644 --- a/src/components/cron.tsx +++ b/src/components/cron.tsx @@ -213,7 +213,7 @@ export const CronCard: React.FC = ({ data, mutate }) => { name="servers" render={({ field }) => ( - Specific Servers (Separate with comma) + Specific Servers { const [fm, setFM] = useState(null); const [init, setInit] = useState(false); + const isDesktop = useMediaQuery("(min-width: 640px)"); + const fetchFM = async () => { if (id) { try { @@ -363,25 +373,55 @@ export const FMCard = ({ id }: { id?: string }) => { } } - return ( - { if (isOpen) setOpen(true); }}> - - - - -
- - - - - {fm?.session_id && init - ? - - : -

The server does not exist, or have not been connected yet.

- } -
-
-
+ return (isDesktop ? + ( + { if (isOpen) setOpen(true); }} + > + + + + +
+ + + + + {fm?.session_id && init + ? + + : +

The server does not exist, or have not been connected yet.

+ } +
+
+
+ ) + : ( + + + + + +
+ + + + + {fm?.session_id && init + ? + + : +

The server does not exist, or have not been connected yet.

+ } +
+
+
+ ) ) } diff --git a/src/components/xui/virtulized-data-table.tsx b/src/components/xui/virtulized-data-table.tsx index f35309d..ce15b21 100644 --- a/src/components/xui/virtulized-data-table.tsx +++ b/src/components/xui/virtulized-data-table.tsx @@ -16,6 +16,7 @@ import { HTMLAttributes, forwardRef, useState, useRef, useEffect } from "react"; import { TableVirtuoso } from "react-virtuoso"; import { cn } from "@/lib/utils" import { ScrollArea } from "@/components/ui/scroll-area"; +import { useMediaQuery } from "@/hooks/useMediaQuery"; // Original Table is wrapped with a
(see https://ui.shadcn.com/docs/components/table#radix-:r24:-content-manual), // but here we don't want it, so let's use a new component with only tag @@ -99,6 +100,8 @@ export function DataTable({ const [heightState, setHeight] = useState(0) const ref = useRef(null); + const isDesktop = useMediaQuery("(min-width: 640px)"); + useEffect(() => { const calculateHeight = () => { if (ref.current) { @@ -118,11 +121,14 @@ export function DataTable({ setHeight(calculatedHeight); } }; - window.addEventListener('resize', calculateHeight); calculateHeight(); // Initial calculation - return () => window.removeEventListener('resize', calculateHeight); - }, []); + if (isDesktop) { + window.addEventListener('resize', calculateHeight); + } + + return () => { if (isDesktop) window.removeEventListener('resize', calculateHeight); } + }, [isDesktop]); return (
diff --git a/src/lib/utils.ts b/src/lib/utils.ts index ecfb83d..4d08200 100644 --- a/src/lib/utils.ts +++ b/src/lib/utils.ts @@ -1,7 +1,7 @@ import { clsx, type ClassValue } from "clsx" import { twMerge } from "tailwind-merge" import { z } from "zod" -import { FMEntry, FMOpcode } from "@/types" +import { FMEntry, FMOpcode, ModelIP } from "@/types" import FMWorker from "./fm?worker" export function cn(...inputs: ClassValue[]) { @@ -127,3 +127,15 @@ export const fmWorker = new FMWorker(); export function formatPath(path: string) { return path.replace(/\/{2,}/g, '/'); } + +export function joinIP(p?: ModelIP) { + if (p) { + if (p.ipv4_addr && p.ipv6_addr) { + return `${p.ipv4_addr}/${p.ipv6_addr}`; + } else if (p.ipv4_addr) { + return p.ipv4_addr; + } + return p.ipv6_addr; + } + return ''; +} diff --git a/src/routes/server.tsx b/src/routes/server.tsx index 615f9af..a95c5b5 100644 --- a/src/routes/server.tsx +++ b/src/routes/server.tsx @@ -16,6 +16,7 @@ import { InstallCommandsMenu } from "@/components/install-commands" import { NoteMenu } from "@/components/note-menu" import { TerminalButton } from "@/components/terminal" import { useServer } from "@/hooks/useServer" +import { joinIP } from "@/lib/utils" export default function ServerPage() { const { data, mutate, error, isLoading } = useSWR('/api/v1/server', swrFetcher); @@ -81,13 +82,11 @@ export default function ServerPage() { { id: "ip", header: "IP", - accessorKey: "host.ip", - accessorFn: row => row.host?.ip, cell: ({ row }) => { const s = row.original; return (
- {s.host.ip} + {joinIP(s.geoip?.ip)}
) } diff --git a/src/types/api.ts b/src/types/api.ts index 670c4a0..67a2369 100644 --- a/src/types/api.ts +++ b/src/types/api.ts @@ -180,6 +180,8 @@ export interface ModelConfig { listen_port: number; /** 时区,默认为 Asia/Shanghai */ location: string; + /** 真实IP */ + real_ip_header: string; site_name: string; tls: boolean; } @@ -291,14 +293,17 @@ export interface ModelForceUpdateResponse { success?: number[]; } +export interface ModelGeoIP { + country_code: string; + ip: ModelIP; +} + export interface ModelHost { arch: string; boot_time: number; - country_code: string; cpu: string[]; disk_total: number; gpu: string[]; - ip: string; mem_total: number; platform: string; platform_version: string; @@ -327,6 +332,11 @@ export interface ModelHostState { uptime: number; } +export interface ModelIP { + ipv4_addr: string; + ipv6_addr: string; +} + export interface ModelLoginRequest { password: string; username: string; @@ -439,6 +449,7 @@ export interface ModelServer { display_index: number; /** 启用DDNS */ enable_ddns: boolean; + geoip: ModelGeoIP; /** 对游客隐藏 */ hide_for_guest: boolean; host: ModelHost;