| import { useTranslation } from "react-i18next"; | |
| import { I18nKey } from "#/i18n/declaration"; | |
| export interface DownloadProgressState { | |
| filesTotal: number; | |
| filesDownloaded: number; | |
| currentFile: string; | |
| totalBytesDownloaded: number; | |
| bytesDownloadedPerSecond: number; | |
| isDiscoveringFiles: boolean; | |
| } | |
| interface DownloadProgressProps { | |
| progress: DownloadProgressState; | |
| onCancel: () => void; | |
| } | |
| export function DownloadProgress({ | |
| progress, | |
| onCancel, | |
| }: DownloadProgressProps) { | |
| const { t } = useTranslation(); | |
| const formatBytes = (bytes: number) => { | |
| const units = ["B", "KB", "MB", "GB"]; | |
| let size = bytes; | |
| let unitIndex = 0; | |
| while (size >= 1024 && unitIndex < units.length - 1) { | |
| size /= 1024; | |
| unitIndex += 1; | |
| } | |
| return `${size.toFixed(1)} ${units[unitIndex]}`; | |
| }; | |
| return ( | |
| <div className="fixed inset-0 bg-black/50 flex items-center justify-center z-20"> | |
| <div className="bg-[#1C1C1C] rounded-lg p-6 max-w-md w-full mx-4 border border-[#525252]"> | |
| <div className="mb-4"> | |
| <h3 className="text-lg font-semibold mb-2 text-white"> | |
| {progress.isDiscoveringFiles | |
| ? t(I18nKey.DOWNLOAD$PREPARING) | |
| : t(I18nKey.DOWNLOAD$DOWNLOADING)} | |
| </h3> | |
| <p className="text-sm text-gray-400 truncate"> | |
| {progress.isDiscoveringFiles | |
| ? t(I18nKey.DOWNLOAD$FOUND_FILES, { count: progress.filesTotal }) | |
| : progress.currentFile} | |
| </p> | |
| </div> | |
| <div className="mb-4"> | |
| <div className="h-2 bg-[#2C2C2C] rounded-full overflow-hidden"> | |
| {progress.isDiscoveringFiles ? ( | |
| <div | |
| className="h-full bg-blue-500 animate-pulse" | |
| style={{ width: "100%" }} | |
| /> | |
| ) : ( | |
| <div | |
| className="h-full bg-blue-500 transition-all duration-300" | |
| style={{ | |
| width: `${(progress.filesDownloaded / progress.filesTotal) * 100}%`, | |
| }} | |
| /> | |
| )} | |
| </div> | |
| </div> | |
| <div className="flex justify-between text-sm text-gray-400"> | |
| <span> | |
| {progress.isDiscoveringFiles | |
| ? t(I18nKey.DOWNLOAD$SCANNING) | |
| : t(I18nKey.DOWNLOAD$FILES_PROGRESS, { | |
| downloaded: progress.filesDownloaded, | |
| total: progress.filesTotal, | |
| })} | |
| </span> | |
| {!progress.isDiscoveringFiles && ( | |
| <span>{formatBytes(progress.bytesDownloadedPerSecond)}/s</span> | |
| )} | |
| </div> | |
| <div className="mt-4 flex justify-end"> | |
| <button | |
| type="button" | |
| onClick={onCancel} | |
| className="px-4 py-2 text-sm text-gray-400 hover:text-white transition-colors" | |
| > | |
| {t(I18nKey.DOWNLOAD$CANCEL)} | |
| </button> | |
| </div> | |
| </div> | |
| </div> | |
| ); | |
| } | |