refactor(panel): compact server card layout, denser grid

This commit is contained in:
Lemon-miaow committed 2026-06-27 23:33:18 +08:00
1 parent ae91133ede
commit e1892659ef
1 file changed
+31 -32
+31 -32
View File
@@ -2,7 +2,7 @@ import { useState } from "react";
import { Link } from "react-router-dom"; import { Link } from "react-router-dom";
import { Play, Square, Hand, Users, ExternalLink, Terminal } from "lucide-react"; import { Play, Square, Hand, Users, ExternalLink, Terminal } from "lucide-react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { Card, CardContent, CardFooter, CardHeader } from "@/components/ui/card"; import { Card } from "@/components/ui/card";
import { Button } from "@/components/ui/button"; import { Button } from "@/components/ui/button";
import { PhaseBadge } from "@/components/PhaseBadge"; import { PhaseBadge } from "@/components/PhaseBadge";
import { api, humanizeError } from "@/lib/api"; import { api, humanizeError } from "@/lib/api";
@@ -42,41 +42,40 @@ export function ServerCard({ server, cfg, onChanged }: Props) {
const transitioning = server.phase === "Starting" || server.phase === "Stopping"; const transitioning = server.phase === "Starting" || server.phase === "Stopping";
return ( return (
<Card className="flex flex-col transition-colors hover:border-primary/40"> <Card className="flex flex-col p-4 transition-colors hover:border-primary/40">
<CardHeader className="flex-row items-start justify-between space-y-0"> {/* Header Row */}
<div className="min-w-0"> <div className="flex items-center justify-between gap-2">
<div className="truncate font-semibold"> <span className="truncate text-sm font-semibold text-foreground">
{server.displayName || server.name} {server.displayName || server.name}
</div> </span>
<a
href={`https://${host}`}
target="_blank"
rel="noreferrer"
className="mt-0.5 inline-flex items-center gap-1 text-xs text-muted-foreground hover:text-foreground"
>
{host}
<ExternalLink className="h-3 w-3" />
</a>
</div>
<PhaseBadge phase={server.phase} /> <PhaseBadge phase={server.phase} />
</CardHeader> </div>
<CardContent className="flex-1 text-sm text-muted-foreground"> {/* Info Row */}
<div className="flex items-center gap-1.5"> <div className="mt-2 flex items-center justify-between text-xs text-muted-foreground">
<a
href={`https://${host}`}
target="_blank"
rel="noreferrer"
className="inline-flex items-center gap-1 hover:text-foreground truncate max-w-[70%]"
>
{host}
<ExternalLink className="h-3 w-3 shrink-0" />
</a>
<div className="flex items-center gap-1.5 shrink-0 mr-1">
<span>
{running
? `${server.players ?? 0}${server.maxPlayers ? `/${server.maxPlayers}` : ""}`
: "—"}
</span>
<Users className="h-3.5 w-3.5" /> <Users className="h-3.5 w-3.5" />
{running ? (
<span>
{server.players ?? 0}
{server.maxPlayers ? ` / ${server.maxPlayers}` : ""} {t("online")}
</span>
) : (
<span>—</span>
)}
</div> </div>
{error && <p className="mt-2 text-xs text-destructive">{error}</p>} </div>
</CardContent>
<CardFooter className="flex flex-wrap gap-2"> {error && <p className="mt-2 text-xs text-destructive">{error}</p>}
{/* Action Row */}
<div className="mt-4 flex flex-wrap gap-2 border-t border-border/50 pt-3">
{server.owned && ( {server.owned && (
<Link to={`/servers/${server.name}`}> <Link to={`/servers/${server.name}`}>
<Button variant="ghost" size="sm"> <Button variant="ghost" size="sm">
@@ -114,7 +113,7 @@ export function ServerCard({ server, cfg, onChanged }: Props) {
<Play /> {busy === "wake" ? t("waking") : t("wake")} <Play /> {busy === "wake" ? t("waking") : t("wake")}
</Button> </Button>
))} ))}
</CardFooter> </div>
</Card> </Card>
); );
} }