112 lines
3.6 KiB
TypeScript
112 lines
3.6 KiB
TypeScript
"use client";
|
||
|
||
import { Copy, Pencil, Sparkles, Trash2, Video } from "lucide-react";
|
||
import { Button } from "@/components/ui/button";
|
||
import { Badge } from "@/components/ui/badge";
|
||
import { cn } from "@/lib/utils";
|
||
import type { AgentPreset } from "@/types/agent";
|
||
|
||
interface AgentPresetCardProps {
|
||
preset: AgentPreset;
|
||
selected?: boolean;
|
||
onSelect: (presetId: string) => void;
|
||
onFork?: (preset: AgentPreset) => void;
|
||
onEdit?: (preset: AgentPreset) => void;
|
||
onDelete?: (preset: AgentPreset) => void;
|
||
}
|
||
|
||
export function AgentPresetCard({
|
||
preset,
|
||
selected = false,
|
||
onSelect,
|
||
onFork,
|
||
onEdit,
|
||
onDelete,
|
||
}: AgentPresetCardProps) {
|
||
return (
|
||
<div
|
||
className={cn(
|
||
"rounded-2xl border p-3 transition-colors",
|
||
selected ? "border-primary bg-primary/5" : "border-border bg-background hover:bg-muted/30"
|
||
)}
|
||
>
|
||
<div className="flex items-start justify-between gap-3">
|
||
<div className="min-w-0">
|
||
<div className="flex items-center gap-2">
|
||
{preset.type === "video" ? (
|
||
<Video className="h-4 w-4 text-violet-500" />
|
||
) : (
|
||
<Sparkles className="h-4 w-4 text-amber-500" />
|
||
)}
|
||
<h4 className="truncate text-sm font-semibold">{preset.name}</h4>
|
||
</div>
|
||
<div className="mt-2 flex flex-wrap gap-1.5">
|
||
<Badge variant="outline">{preset.type === "video" ? "视频" : "生图"}</Badge>
|
||
<Badge variant="outline">{preset.visibility === "public" ? "公共" : "私有"}</Badge>
|
||
{preset.category?.name ? (
|
||
<Badge variant="outline">{preset.category.name}</Badge>
|
||
) : null}
|
||
</div>
|
||
</div>
|
||
{preset.avatarUrl || preset.referenceAssets?.[0]?.thumbnailUrl || preset.referenceAssets?.[0]?.originalUrl ? (
|
||
<img
|
||
src={
|
||
preset.avatarUrl ||
|
||
preset.referenceAssets?.[0]?.thumbnailUrl ||
|
||
preset.referenceAssets?.[0]?.originalUrl ||
|
||
""
|
||
}
|
||
alt={preset.name}
|
||
className="h-12 w-12 rounded-xl border object-cover"
|
||
/>
|
||
) : null}
|
||
</div>
|
||
|
||
<div className="mt-3 space-y-1 text-xs text-muted-foreground">
|
||
<div>模型:{preset.defaultModel?.displayName || "未设置"}</div>
|
||
<div>槽位:{preset.slotCount} 个</div>
|
||
<div>需上传:{preset.requiredUploadCount} 张</div>
|
||
</div>
|
||
|
||
<div className="mt-3 flex items-center gap-2">
|
||
<Button size="sm" className="h-8 flex-1" onClick={() => onSelect(preset.id)}>
|
||
{selected ? "已选中" : "使用"}
|
||
</Button>
|
||
{preset.visibility === "private" && onEdit ? (
|
||
<Button
|
||
size="sm"
|
||
variant="outline"
|
||
className="h-8"
|
||
onClick={() => onEdit(preset)}
|
||
>
|
||
<Pencil className="mr-1 h-3.5 w-3.5" />
|
||
编辑
|
||
</Button>
|
||
) : null}
|
||
{preset.visibility === "private" && onDelete ? (
|
||
<Button
|
||
size="sm"
|
||
variant="outline"
|
||
className="h-8 text-destructive hover:text-destructive"
|
||
onClick={() => onDelete(preset)}
|
||
>
|
||
<Trash2 className="mr-1 h-3.5 w-3.5" />
|
||
删除
|
||
</Button>
|
||
) : null}
|
||
{preset.visibility === "public" && onFork ? (
|
||
<Button
|
||
size="sm"
|
||
variant="outline"
|
||
className="h-8"
|
||
onClick={() => onFork(preset)}
|
||
>
|
||
<Copy className="mr-1 h-3.5 w-3.5" />
|
||
另存
|
||
</Button>
|
||
) : null}
|
||
</div>
|
||
</div>
|
||
);
|
||
}
|