first commit
This commit is contained in:
@@ -0,0 +1,72 @@
|
||||
import type { ReactNode } from "react";
|
||||
|
||||
interface ConfirmDialogProps {
|
||||
open: boolean;
|
||||
title: string;
|
||||
description: ReactNode;
|
||||
confirmLabel: string;
|
||||
danger?: boolean;
|
||||
busy?: boolean;
|
||||
onConfirm: () => void;
|
||||
onCancel: () => void;
|
||||
children?: ReactNode;
|
||||
}
|
||||
|
||||
export function ConfirmDialog({ open, title, description, confirmLabel, danger, busy, onConfirm, onCancel, children }: ConfirmDialogProps) {
|
||||
if (!open) {
|
||||
return null;
|
||||
}
|
||||
return (
|
||||
<div className="confirm-backdrop" role="presentation" onClick={onCancel}>
|
||||
<div className="confirm-panel" role="dialog" aria-modal="true" aria-label={title} onClick={(event) => event.stopPropagation()}>
|
||||
<h2>{title}</h2>
|
||||
<p>{description}</p>
|
||||
{children}
|
||||
<div className="confirm-actions">
|
||||
<button type="button" onClick={onCancel} disabled={busy}>
|
||||
取消
|
||||
</button>
|
||||
<button type="button" className={danger ? "confirm-danger" : "confirm-primary"} onClick={onConfirm} disabled={busy}>
|
||||
{busy ? "提交中…" : confirmLabel}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
interface UsageMeterProps {
|
||||
label: string;
|
||||
percent?: number;
|
||||
}
|
||||
|
||||
export function UsageMeter({ label, percent }: UsageMeterProps) {
|
||||
const known = typeof percent === "number" && Number.isFinite(percent);
|
||||
const clamped = known ? Math.max(0, Math.min(100, percent)) : 0;
|
||||
return (
|
||||
<div className="usage-meter">
|
||||
<span>{label}</span>
|
||||
<span className="usage-meter-track" role="img" aria-label={known ? `${label} ${Math.round(clamped)}%` : `${label} 暂无数据`}>
|
||||
{known && <span className={`usage-meter-fill${clamped >= 85 ? " usage-high" : ""}`} style={{ width: `${clamped}%` }} />}
|
||||
</span>
|
||||
<span className="usage-meter-value">{known ? `${Math.round(clamped)}%` : "--"}</span>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
interface DiffViewProps {
|
||||
lines: Array<{ kind: "same" | "added" | "removed"; text: string }>;
|
||||
}
|
||||
|
||||
export function DiffView({ lines }: DiffViewProps) {
|
||||
return (
|
||||
<div className="diff-view" role="figure" aria-label="配置变更对比">
|
||||
{lines.map((line, index) => (
|
||||
<span key={`${index}-${line.text}`} className={`diff-line diff-line-${line.kind}`}>
|
||||
<span aria-hidden="true">{line.kind === "added" ? "+" : line.kind === "removed" ? "-" : " "}</span>
|
||||
<span>{line.text || " "}</span>
|
||||
</span>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user