mirror of
https://github.com/Crosstalk-Solutions/project-nomad.git
synced 2026-04-02 06:49:26 +02:00
- Add i18next, react-i18next, i18next-browser-languagedetector packages - Configure i18n initialization with language detector in lib/i18n.ts - Created en/de translation files and moved most hard-coded strings into the files and translated them - Uses locale-aware date formatting where applicable - Added language-specific Wikipedia content files (wikipedia.en.json, wikipedia.de.json) and updated download URLs - Added NOMAD_REPO_URL env variable for fork-friendly URL resolution (easier testing and rollout independent of Crosstalk repo)
80 lines
2.9 KiB
TypeScript
80 lines
2.9 KiB
TypeScript
import useDownloads, { useDownloadsProps } from '~/hooks/useDownloads'
|
|
import HorizontalBarChart from './HorizontalBarChart'
|
|
import { extractFileName } from '~/lib/util'
|
|
import StyledSectionHeader from './StyledSectionHeader'
|
|
import { IconAlertTriangle, IconX } from '@tabler/icons-react'
|
|
import api from '~/lib/api'
|
|
import { useTranslation } from 'react-i18next'
|
|
|
|
interface ActiveDownloadProps {
|
|
filetype?: useDownloadsProps['filetype']
|
|
withHeader?: boolean
|
|
}
|
|
|
|
const ActiveDownloads = ({ filetype, withHeader = false }: ActiveDownloadProps) => {
|
|
const { t } = useTranslation()
|
|
const { data: downloads, invalidate } = useDownloads({ filetype })
|
|
|
|
const handleDismiss = async (jobId: string) => {
|
|
await api.removeDownloadJob(jobId)
|
|
invalidate()
|
|
}
|
|
|
|
return (
|
|
<>
|
|
{withHeader && <StyledSectionHeader title={t('common.activeDownloads')} className="mt-12 mb-4" />}
|
|
<div className="space-y-4">
|
|
{downloads && downloads.length > 0 ? (
|
|
downloads.map((download) => (
|
|
<div
|
|
key={download.jobId}
|
|
className={`bg-desert-white rounded-lg p-4 border shadow-sm hover:shadow-lg transition-shadow ${
|
|
download.status === 'failed'
|
|
? 'border-red-300'
|
|
: 'border-desert-stone-light'
|
|
}`}
|
|
>
|
|
{download.status === 'failed' ? (
|
|
<div className="flex items-center gap-2">
|
|
<IconAlertTriangle className="w-5 h-5 text-red-500 flex-shrink-0" />
|
|
<div className="flex-1 min-w-0">
|
|
<p className="text-sm font-medium text-gray-900 truncate">
|
|
{extractFileName(download.filepath) || download.url}
|
|
</p>
|
|
<p className="text-xs text-red-600 mt-0.5">
|
|
Download failed{download.failedReason ? `: ${download.failedReason}` : ''}
|
|
</p>
|
|
</div>
|
|
<button
|
|
onClick={() => handleDismiss(download.jobId)}
|
|
className="flex-shrink-0 p-1 rounded hover:bg-red-100 transition-colors"
|
|
title="Dismiss failed download"
|
|
>
|
|
<IconX className="w-4 h-4 text-red-400 hover:text-red-600" />
|
|
</button>
|
|
</div>
|
|
) : (
|
|
<HorizontalBarChart
|
|
items={[
|
|
{
|
|
label: extractFileName(download.filepath) || download.url,
|
|
value: download.progress,
|
|
total: '100%',
|
|
used: `${download.progress}%`,
|
|
type: download.filetype,
|
|
},
|
|
]}
|
|
/>
|
|
)}
|
|
</div>
|
|
))
|
|
) : (
|
|
<p className="text-text-muted">{t('common.noActiveDownloads')}</p>
|
|
)}
|
|
</div>
|
|
</>
|
|
)
|
|
}
|
|
|
|
export default ActiveDownloads
|