feat:美化UI,添加桌面共享/文件字传输UI

This commit is contained in:
MatrixSeven
2025-08-01 17:15:55 +08:00
parent 9e59806192
commit 652dbed722
20 changed files with 8255 additions and 755 deletions

View File

@@ -18,11 +18,11 @@ interface FileReceiveProps {
}
const getFileIcon = (mimeType: string) => {
if (mimeType.startsWith('image/')) return <Image className="w-5 h-5" />;
if (mimeType.startsWith('video/')) return <Video className="w-5 h-5" />;
if (mimeType.startsWith('audio/')) return <Music className="w-5 h-5" />;
if (mimeType.includes('zip') || mimeType.includes('rar')) return <Archive className="w-5 h-5" />;
return <FileText className="w-5 h-5" />;
if (mimeType.startsWith('image/')) return <Image className="w-5 h-5 text-white" />;
if (mimeType.startsWith('video/')) return <Video className="w-5 h-5 text-white" />;
if (mimeType.startsWith('audio/')) return <Music className="w-5 h-5 text-white" />;
if (mimeType.includes('zip') || mimeType.includes('rar')) return <Archive className="w-5 h-5 text-white" />;
return <FileText className="w-5 h-5 text-white" />;
};
const formatFileSize = (bytes: number): string => {
@@ -60,110 +60,163 @@ export function FileReceive({
// 如果已经连接并且有文件列表,显示文件列表
if (files.length > 0) {
return (
<div className="space-y-4">
<Card>
<CardHeader>
<CardTitle> ({files.length})</CardTitle>
<CardDescription>
{isConnected ? (
<span className="text-green-600"> </span>
) : (
<span className="text-yellow-600"> ...</span>
)}
</CardDescription>
</CardHeader>
<CardContent className="space-y-2">
<div className="space-y-4 sm:space-y-6">
<div className="glass-card rounded-2xl p-4 sm:p-6 animate-fade-in-up">
<div className="flex flex-col sm:flex-row sm:items-center justify-between mb-4 sm:mb-6 gap-4">
<div className="flex items-center space-x-3">
<div className="w-10 h-10 bg-gradient-to-br from-emerald-500 to-teal-500 rounded-xl flex items-center justify-center">
<Download className="w-5 h-5 text-white" />
</div>
<div>
<h3 className="text-lg sm:text-xl font-semibold text-slate-800"></h3>
<p className="text-slate-500 text-sm">
{isConnected ? (
<span className="text-emerald-600"> </span>
) : (
<span className="text-amber-600"> ...</span>
)}
</p>
</div>
</div>
<div className="bg-gradient-to-r from-emerald-100 to-teal-100 px-3 sm:px-4 py-2 rounded-full self-start sm:self-center">
<span className="text-emerald-700 font-medium text-sm">{files.length} </span>
</div>
</div>
<div className="space-y-3 sm:space-y-4">
{files.map((file) => {
const progress = transferProgresses.find(p => p.originalFileId === file.id);
const isDownloading = progress && progress.status === 'downloading';
console.log(`文件 ${file.id} 进度状态:`, progress, '是否下载中:', isDownloading);
const isCompleted = progress && progress.status === 'completed';
return (
<div key={file.id} className="space-y-2">
<div className="flex items-center justify-between p-3 bg-muted rounded-lg">
<div className="flex items-center space-x-3 flex-1 min-w-0">
<div className="text-muted-foreground">
<div key={file.id} className="bg-gradient-to-r from-slate-50 to-blue-50 border border-slate-200 rounded-xl p-3 sm:p-4 hover:shadow-md transition-all duration-200">
<div className="flex flex-col sm:flex-row sm:items-center justify-between mb-3 gap-3">
<div className="flex items-center space-x-3 sm:space-x-4 flex-1 min-w-0">
<div className="w-10 h-10 sm:w-12 sm:h-12 bg-gradient-to-br from-blue-500 to-indigo-500 rounded-lg flex items-center justify-center flex-shrink-0">
{getFileIcon(file.type)}
</div>
<div className="flex-1 min-w-0">
<p className="font-medium truncate">{file.name}</p>
<p className="text-sm text-muted-foreground">
{formatFileSize(file.size)}
</p>
<p className="font-medium text-slate-800 truncate text-sm sm:text-base">{file.name}</p>
<p className="text-sm text-slate-500">{formatFileSize(file.size)}</p>
{isCompleted && (
<p className="text-xs text-emerald-600 font-medium"> </p>
)}
</div>
</div>
<Button
onClick={() => onDownloadFile(file.id)}
disabled={!isConnected || isDownloading}
size="sm"
disabled={!isConnected || isDownloading || isCompleted}
className={`px-6 py-2 rounded-lg font-medium shadow-lg transition-all duration-200 hover:shadow-xl ${
isCompleted
? 'bg-slate-300 text-slate-500 cursor-not-allowed'
: 'bg-gradient-to-r from-emerald-500 to-teal-500 hover:from-emerald-600 hover:to-teal-600 text-white'
}`}
>
<Download className="w-4 h-4 mr-2" />
{isDownloading ? '下载中...' : '下载'}
{isDownloading ? '下载中...' : isCompleted ? '已完成' : '下载'}
</Button>
</div>
{progress && progress.status === 'downloading' && (
<div className="px-3">
<div className="flex justify-between text-sm text-muted-foreground mb-1">
<span>...</span>
<span>{progress.progress.toFixed(1)}%</span>
{progress && (progress.status === 'downloading' || progress.status === 'completed') && (
<div className="mt-3 space-y-2">
<div className="flex justify-between text-sm text-slate-600">
<span>{progress.status === 'completed' ? '下载完成' : '正在下载...'}</span>
<span className="font-medium">{progress.progress.toFixed(1)}%</span>
</div>
<Progress value={progress.progress} className="h-2" />
<div className="flex justify-between text-xs text-muted-foreground mt-1">
<div className="w-full bg-slate-200 rounded-full h-2">
<div
className={`h-2 rounded-full transition-all duration-300 ${
progress.status === 'completed'
? 'bg-gradient-to-r from-emerald-500 to-emerald-600'
: 'bg-gradient-to-r from-emerald-500 to-teal-500'
}`}
style={{ width: `${progress.progress}%` }}
></div>
</div>
<div className="flex justify-between text-xs text-slate-500">
<span>{formatFileSize(progress.receivedSize)} / {formatFileSize(progress.totalSize)}</span>
{progress.status === 'downloading' && (
<span> {Math.ceil((progress.totalSize - progress.receivedSize) / 1024 / 1024)} MB</span>
)}
</div>
</div>
)}
{progress && (
<div className="px-3 text-xs text-muted-foreground">
={progress.status}, ={progress.progress}%, ID={progress.originalFileId}
</div>
)}
</div>
);
})}
</CardContent>
</Card>
</div>
</div>
</div>
);
}
// 显示取件码输入界面
return (
<Card>
<CardHeader>
<CardTitle></CardTitle>
<CardDescription>
6
</CardDescription>
</CardHeader>
<CardContent>
<form onSubmit={handleSubmit} className="space-y-4">
<div className="space-y-2">
<div className="glass-card rounded-2xl p-4 sm:p-6 md:p-8 animate-fade-in-up">
<div className="text-center mb-6 sm:mb-8">
<div className="w-12 h-12 sm:w-16 sm:h-16 mx-auto mb-4 bg-gradient-to-br from-emerald-500 to-teal-500 rounded-2xl flex items-center justify-center animate-float">
<Download className="w-6 h-6 sm:w-8 sm:h-8 text-white" />
</div>
<h2 className="text-xl sm:text-2xl font-semibold text-slate-800 mb-2"></h2>
<p className="text-sm sm:text-base text-slate-600">6</p>
</div>
<form onSubmit={handleSubmit} className="space-y-4 sm:space-y-6">
<div className="space-y-3">
<div className="relative">
<Input
value={pickupCode}
onChange={handleInputChange}
placeholder="输入6位取件码"
className="text-center text-2xl tracking-wider font-mono"
placeholder="输入取件码"
className="text-center text-2xl sm:text-3xl tracking-[0.3em] sm:tracking-[0.5em] font-mono h-12 sm:h-16 border-2 border-slate-200 rounded-xl focus:border-emerald-500 focus:ring-emerald-500 bg-white/80 backdrop-blur-sm pb-2 sm:pb-4"
maxLength={6}
disabled={isConnecting}
/>
<p className="text-xs text-muted-foreground text-center">
{pickupCode.length}/6
</p>
<div className="absolute inset-x-0 -bottom-4 sm:-bottom-6 flex justify-center space-x-1 sm:space-x-2">
{[...Array(6)].map((_, i) => (
<div
key={i}
className={`w-1.5 h-1.5 sm:w-2 sm:h-2 rounded-full transition-all duration-200 ${
i < pickupCode.length
? 'bg-emerald-500'
: 'bg-slate-300'
}`}
/>
))}
</div>
</div>
<Button
type="submit"
className="w-full"
disabled={pickupCode.length !== 6 || isConnecting}
>
{isConnecting ? '连接中...' : '连接'}
</Button>
</form>
</CardContent>
</Card>
<div className="h-3 sm:h-4"></div>
<p className="text-center text-xs sm:text-sm text-slate-500">
{pickupCode.length}/6
</p>
</div>
<Button
type="submit"
className="w-full h-10 sm:h-12 bg-gradient-to-r from-emerald-500 to-teal-500 hover:from-emerald-600 hover:to-teal-600 text-white text-base sm:text-lg font-medium rounded-xl shadow-lg transition-all duration-200 hover:shadow-xl hover:scale-105 disabled:opacity-50 disabled:scale-100"
disabled={pickupCode.length !== 6 || isConnecting}
>
{isConnecting ? (
<div className="flex items-center space-x-2">
<div className="w-5 h-5 border-2 border-white border-t-transparent rounded-full animate-spin"></div>
<span>...</span>
</div>
) : (
<div className="flex items-center space-x-2">
<Download className="w-5 h-5" />
<span></span>
</div>
)}
</Button>
</form>
{/* 使用提示 */}
<div className="mt-6 p-4 bg-gradient-to-r from-blue-50 to-indigo-50 rounded-xl border border-blue-200">
<p className="text-sm text-slate-600 text-center">
💡 <span className="font-medium"></span>24
</p>
</div>
</div>
);
}