feat: restyle StatusView and status page with Tailwind
This commit is contained in:
@@ -15,6 +15,15 @@ type DownloadData = {
|
||||
tokenExpiresAt: string | null
|
||||
}
|
||||
|
||||
function Spinner() {
|
||||
return (
|
||||
<svg className="animate-spin w-8 h-8 text-violet-600 dark:text-violet-400" viewBox="0 0 24 24" fill="none" aria-hidden>
|
||||
<circle className="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" strokeWidth="4" />
|
||||
<path className="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4z" />
|
||||
</svg>
|
||||
)
|
||||
}
|
||||
|
||||
export function StatusView({ uuid }: { uuid: string }) {
|
||||
const t = useTranslations('status')
|
||||
const locale = useLocale()
|
||||
@@ -45,14 +54,33 @@ export function StatusView({ uuid }: { uuid: string }) {
|
||||
return () => { active = false }
|
||||
}, [uuid])
|
||||
|
||||
if (notFound) return <p>{t('notFound')}</p>
|
||||
if (!data) return <p>{t('loading')}</p>
|
||||
const cardClass = 'max-w-md w-full mx-auto rounded-2xl border border-gray-100 dark:border-slate-800 bg-gray-50 dark:bg-slate-900 p-8'
|
||||
|
||||
if (notFound) {
|
||||
return (
|
||||
<div className={cardClass}>
|
||||
<p className="text-gray-600 dark:text-gray-400 text-center">{t('notFound')}</p>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
if (!data) {
|
||||
return (
|
||||
<div className={`${cardClass} flex flex-col items-center gap-4`}>
|
||||
<Spinner />
|
||||
<p className="text-gray-500 dark:text-gray-400 text-sm">{t('loading')}</p>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
if (data.status === 'PENDING' || data.status === 'PROCESSING') {
|
||||
return (
|
||||
<div>
|
||||
<p>{data.status === 'PENDING' ? t('pending') : t('processing')}</p>
|
||||
<p>{t('polling')}</p>
|
||||
<div className={`${cardClass} flex flex-col items-center gap-4`}>
|
||||
<Spinner />
|
||||
<p className="font-medium text-gray-900 dark:text-gray-50">
|
||||
{data.status === 'PENDING' ? t('pending') : t('processing')}
|
||||
</p>
|
||||
<p className="text-sm text-gray-500 dark:text-gray-400 text-center">{t('polling')}</p>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -62,16 +90,24 @@ export function StatusView({ uuid }: { uuid: string }) {
|
||||
? `(${(Number(data.fileSize) / 1_048_576).toFixed(1)} MB)`
|
||||
: ''
|
||||
return (
|
||||
<div>
|
||||
<p>{t('ready')} {sizeMb}</p>
|
||||
<div className={`${cardClass} flex flex-col items-center gap-5`}>
|
||||
<div className="w-12 h-12 rounded-full bg-green-100 dark:bg-green-900/30 flex items-center justify-center">
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" className="text-green-600 dark:text-green-400" aria-hidden>
|
||||
<polyline points="20 6 9 17 4 12"/>
|
||||
</svg>
|
||||
</div>
|
||||
<p className="font-medium text-gray-900 dark:text-gray-50">
|
||||
{t('ready')} {sizeMb}
|
||||
</p>
|
||||
<a
|
||||
href={`/api/download/${data.downloadToken}`}
|
||||
download={data.fileName ?? undefined}
|
||||
className="w-full text-center rounded-xl bg-violet-600 hover:bg-violet-700 dark:bg-violet-500 dark:hover:bg-violet-600 text-white font-medium py-3 transition-colors"
|
||||
>
|
||||
{t('download')} {data.fileName}
|
||||
</a>
|
||||
{data.tokenExpiresAt && (
|
||||
<p style={{ fontSize: '0.85rem', color: '#666' }}>
|
||||
<p className="text-xs text-gray-400 dark:text-slate-500">
|
||||
{t('linkExpires')}{' '}
|
||||
{new Date(data.tokenExpiresAt).toLocaleString(locale)}
|
||||
</p>
|
||||
@@ -82,9 +118,9 @@ export function StatusView({ uuid }: { uuid: string }) {
|
||||
|
||||
if (data.status === 'FAILED') {
|
||||
return (
|
||||
<div>
|
||||
<p>{t('failed')}</p>
|
||||
<pre style={{ background: '#fee', padding: '0.5rem', overflowX: 'auto' }}>
|
||||
<div className={cardClass}>
|
||||
<p className="font-medium text-red-600 dark:text-red-400 mb-3">{t('failed')}</p>
|
||||
<pre className="text-xs bg-red-50 dark:bg-red-950/40 border border-red-100 dark:border-red-900/50 rounded-lg p-4 overflow-x-auto text-red-700 dark:text-red-300 whitespace-pre-wrap">
|
||||
{data.errorMsg}
|
||||
</pre>
|
||||
</div>
|
||||
@@ -92,8 +128,16 @@ export function StatusView({ uuid }: { uuid: string }) {
|
||||
}
|
||||
|
||||
if (data.status === 'FILE_DELETED') {
|
||||
return <p>{t('deleted')}</p>
|
||||
return (
|
||||
<div className={cardClass}>
|
||||
<p className="text-gray-600 dark:text-gray-400 text-center">{t('deleted')}</p>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
return <p>{t('unknown')}: {data.status}</p>
|
||||
return (
|
||||
<div className={cardClass}>
|
||||
<p className="text-gray-500 dark:text-gray-400 text-center">{t('unknown')}: {data.status}</p>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user