DetailModal.tsx
5.72 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
import React from 'react';
import { ImageItem, ImageGenerationParams } from '../types';
import { X, Copy, Download, Edit3, Heart, Zap } from 'lucide-react';
interface DetailModalProps {
image: ImageItem | null;
onClose: () => void;
onEdit?: (image: ImageItem) => void;
onGenerateSimilar?: (params: ImageGenerationParams) => void;
}
const DetailModal: React.FC<DetailModalProps> = ({ image, onClose, onEdit, onGenerateSimilar }) => {
if (!image) return null;
const copyToClipboard = (text: string) => {
navigator.clipboard.writeText(text);
};
const handleGenerateSimilar = () => {
if (onGenerateSimilar) {
const params: ImageGenerationParams = {
prompt: image.prompt,
width: image.width,
height: image.height,
num_inference_steps: image.num_inference_steps,
guidance_scale: image.guidance_scale,
seed: image.seed
};
onGenerateSimilar(params);
onClose();
}
};
return (
<div className="fixed inset-0 z-[100] flex items-center justify-center p-4 md:p-8">
<div className="absolute inset-0 bg-black/90 backdrop-blur-sm transition-opacity" onClick={onClose}/>
<div className="relative bg-white dark:bg-gray-900 w-full max-w-6xl max-h-[90vh] rounded-2xl overflow-hidden shadow-2xl flex flex-col md:flex-row animate-fade-in">
<button onClick={onClose} className="absolute top-4 right-4 z-10 p-2 bg-black/50 rounded-full text-white md:hidden"><X size={20} /></button>
<div className="w-full md:w-2/3 bg-black flex items-center justify-center overflow-hidden h-[50vh] md:h-auto relative group">
<img src={image.url} alt={image.prompt} className="max-w-full max-h-full object-contain" />
</div>
<div className="w-full md:w-1/3 p-6 md:p-8 flex flex-col overflow-y-auto">
<div className="flex justify-between items-start mb-6">
<h2 className="text-2xl font-bold text-gray-800 dark:text-white">参数详情</h2>
<div className="flex gap-2">
{onEdit && (
<button
onClick={() => onEdit(image)}
className="p-2 bg-gray-100 hover:bg-gray-200 dark:bg-gray-800 rounded-full transition-colors"
title="管理"
>
<Edit3 size={18} />
</button>
)}
<button onClick={onClose} className="hidden md:block p-2 hover:bg-gray-100 dark:hover:bg-gray-800 rounded-full transition-colors"><X size={24} /></button>
</div>
</div>
<div className="space-y-6">
<div className="flex items-center gap-2 text-red-500 font-medium">
<Heart size={18} fill="currentColor" />
<span>{image.likes || 0} Likes</span>
</div>
<div>
<label className="block text-xs font-semibold text-gray-400 uppercase tracking-wider mb-2">提示词 (Prompt)</label>
<div className="relative group">
<p className="text-gray-700 dark:text-gray-200 text-sm leading-relaxed p-3 bg-gray-50 dark:bg-gray-800 rounded-lg border border-gray-100 dark:border-gray-700">
{image.prompt}
</p>
<button
onClick={() => copyToClipboard(image.prompt)}
className="absolute top-2 right-2 p-1.5 bg-white dark:bg-gray-700 rounded-md shadow-sm opacity-0 group-hover:opacity-100 transition-opacity text-gray-500 hover:text-blue-500"
title="复制提示词"
>
<Copy size={14} />
</button>
</div>
</div>
<div className="grid grid-cols-2 gap-4">
<div>
<label className="block text-xs font-semibold text-gray-400 uppercase mb-1">分辨率</label>
<p className="text-gray-800 dark:text-gray-200 font-mono">{image.width} x {image.height}</p>
</div>
<div>
<label className="block text-xs font-semibold text-gray-400 uppercase mb-1">随机种子</label>
<p className="text-gray-800 dark:text-gray-200 font-mono">{image.seed}</p>
</div>
<div>
<label className="block text-xs font-semibold text-gray-400 uppercase mb-1">生成步数</label>
<p className="text-gray-800 dark:text-gray-200 font-mono">{image.num_inference_steps}</p>
</div>
<div>
<label className="block text-xs font-semibold text-gray-400 uppercase mb-1">引导系数</label>
<p className="text-gray-800 dark:text-gray-200 font-mono">{image.guidance_scale.toFixed(1)}</p>
</div>
</div>
<div className="pt-6 mt-auto space-y-3">
<button
onClick={handleGenerateSimilar}
className="flex items-center justify-center w-full py-3 bg-purple-600 text-white rounded-xl font-bold hover:bg-purple-700 transition-colors gap-2 shadow-lg shadow-purple-200 dark:shadow-none"
>
<Zap size={18} fill="currentColor" />
生成同款
</button>
<a
href={image.url}
target="_blank"
rel="noopener noreferrer"
download={`z-image-${image.id}.png`}
className="flex items-center justify-center w-full py-3 bg-black dark:bg-white text-white dark:text-black rounded-xl font-medium hover:opacity-90 transition-opacity gap-2"
>
<Download size={18} />
下载原图
</a>
</div>
</div>
</div>
</div>
</div>
);
};
export default DetailModal;