Unverified Commit bd49313e authored by Lemon-miaow's avatar Lemon-miaow
Browse files

refactor(panel): 抽取 10 个公共组件,消除 ~150 处重复代码

新增组件:
- PageHeader: 统一页面头部(14 个页面)
- StatCard: 统一数值统计卡片(6 个页面)
- MessageLine: 统一错误/成功提示条(16 处)
- ConfirmFooter: 统一 Dialog 底部按钮(8 个文件)
- SearchInput: 统一搜索框(5 个页面)
- SubmissionStatusBadge: 统一提交状态徽章
- RoleBadge / UserStatusBadge: 统一用户角色/状态徽章
- BackLink: 统一返回导航链接(5 个页面)
- InlineConfirm: 统一二次确认交互(3 个 section)

修复:
- Pagination 图标尺寸统一 h-4 w-4
- 右上角按钮统一 size=sm gap-1.5
- StatCard 默认值恢复 text-2xl(24px)

States.tsx 新增 NotYours / NotRunning 通用状态组件

已有文件 -659 行,新组件 +353 行,净减 306 行
parent 7d27640c
Loading
Loading
Loading
Loading
+18 −0
Changes for panel/src/components/BackLink.tsx: 18 added lines, 0 removed lines.
Original line number Diff line number Diff line
import { ArrowLeft } from "lucide-react";
import { Link } from "react-router-dom";

interface Props {
  to: string;
  label: string;
}

export function BackLink({ to, label }: Props) {
  return (
    <Link
      to={to}
      className="inline-flex items-center gap-1 text-sm text-muted-foreground hover:text-foreground"
    >
      <ArrowLeft className="h-4 w-4" /> {label}
    </Link>
  );
}
+41 −0
Changes for panel/src/components/ConfirmFooter.tsx: 41 added lines, 0 removed lines.
Original line number Diff line number Diff line
import { Loader2 } from "lucide-react";
import { Button } from "@/components/ui/button";
import { DialogFooter } from "@/components/ui/dialog";

interface Props {
  onCancel: () => void;
  onConfirm: () => void;
  disabled?: boolean;
  loading?: boolean;
  cancelLabel: string;
  confirmLabel: string;
  confirmVariant?: "destructive" | "default" | "outline";
  /** Additional content rendered between the message and buttons */
  children?: React.ReactNode;
  className?: string;
}

export function ConfirmFooter({
  onCancel,
  onConfirm,
  disabled,
  loading,
  cancelLabel,
  confirmLabel,
  confirmVariant = "destructive",
  children,
  className,
}: Props) {
  return (
    <DialogFooter className={className}>
      {children}
      <Button variant="outline" size="sm" onClick={onCancel} disabled={disabled ?? loading}>
        {cancelLabel}
      </Button>
      <Button variant={confirmVariant} size="sm" onClick={onConfirm} disabled={disabled ?? loading}>
        {loading && <Loader2 className="h-4 w-4 animate-spin" />}
        {confirmLabel}
      </Button>
    </DialogFooter>
  );
}
+13 −11
Changes for panel/src/components/CreateServerDialog.tsx: 13 added lines, 11 removed lines.
Original line number Diff line number Diff line
import { useState } from "react";
import { Plus } from "lucide-react";
import { useTranslation } from "react-i18next";
import { ConfirmFooter } from "@/components/ConfirmFooter";
import {
  Dialog,
  DialogContent,
  DialogDescription,
  DialogFooter,
  DialogHeader,
  DialogTitle,
  DialogTrigger,
@@ -104,8 +104,9 @@ export function CreateServerDialog({ cfg, onCreated }: Props) {
  return (
    <Dialog open={open} onOpenChange={setOpen}>
      <DialogTrigger asChild>
        <Button>
          <Plus /> {t("create_server_btn")}
        <Button size="sm" className="gap-1.5">
          <Plus className="h-4 w-4" />
          {t("create_server_btn")}
        </Button>
      </DialogTrigger>
      <DialogContent>
@@ -231,14 +232,15 @@ export function CreateServerDialog({ cfg, onCreated }: Props) {
          {error && <p className="text-sm text-destructive">{error}</p>}
        </div>

        <DialogFooter>
          <Button variant="ghost" onClick={() => setOpen(false)} disabled={submitting}>
            {t("create_server_cancel")}
          </Button>
          <Button onClick={submit} disabled={!canSubmit}>
            {submitting ? t("create_server_creating") : t("create_server_submit")}
          </Button>
        </DialogFooter>
        <ConfirmFooter
          onCancel={() => setOpen(false)}
          onConfirm={submit}
          disabled={!canSubmit}
          loading={submitting}
          cancelLabel={t("create_server_cancel")}
          confirmLabel={t("create_server_submit")}
          confirmVariant="default"
        />
      </DialogContent>
    </Dialog>
  );
+2 −5
Changes for panel/src/components/CreateUserDialog.tsx: 2 added lines, 5 removed lines.
Original line number Diff line number Diff line
@@ -20,6 +20,7 @@ import {
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import { MessageLine } from "@/components/MessageLine";
import { api, humanizeError } from "@/lib/api";

interface Props {
@@ -217,11 +218,7 @@ export function CreateUserDialog({ onCreated }: Props) {
              </span>
            </label>

            {err && (
              <p className="rounded-md border border-destructive/20 bg-destructive/10 p-3 text-sm text-destructive">
                {err}
              </p>
            )}
            {err && <MessageLine kind="error" message={err} />}

            <DialogFooter>
              <Button type="submit" disabled={submitting} className="gap-1.5">
+10 −9
Changes for panel/src/components/EditServerDialog.tsx: 10 added lines, 9 removed lines.
Original line number Diff line number Diff line
import { useState, useEffect } from "react";
import { Settings, ChevronRight } from "lucide-react";
import { useTranslation } from "react-i18next";
import { ConfirmFooter } from "@/components/ConfirmFooter";
import {
  Dialog,
  DialogContent,
  DialogDescription,
  DialogFooter,
  DialogHeader,
  DialogTitle,
  DialogTrigger,
@@ -269,14 +269,15 @@ export function EditServerDialog({
          {error && <p className="text-sm text-destructive">{error}</p>}
        </div>

        <DialogFooter>
          <Button variant="ghost" onClick={() => setOpen(false)} disabled={submitting}>
            {t("create_server_cancel")}
          </Button>
          <Button onClick={submit} disabled={!canSubmit}>
            {submitting ? t("edit_server_updating") : t("edit_server_submit")}
          </Button>
        </DialogFooter>
        <ConfirmFooter
          onCancel={() => setOpen(false)}
          onConfirm={submit}
          disabled={!canSubmit}
          loading={submitting}
          cancelLabel={t("create_server_cancel")}
          confirmLabel={t("edit_server_submit")}
          confirmVariant="default"
        />
      </DialogContent>
    </Dialog>
  );
Loading