trans2 / ui /components /AppInitializationSkeleton.tsx
Mayo
refactor(ui): menu, settings, welcome, navigator + error/loading chrome
b44b9d7 unverified
'use client'
import { useMemo } from 'react'
import { useTranslation } from 'react-i18next'
import { Progress } from '@/components/ui/progress'
import type { DownloadProgress } from '@/lib/api/schemas'
import { useDownloadsStore } from '@/lib/stores/downloadsStore'
const summarize = (downloads: Record<string, DownloadProgress>) => {
const values = Object.values(downloads)
if (values.length === 0) return null
let total = 0
let downloaded = 0
let active: string | null = null
for (const d of values) {
total += d.total ?? 0
downloaded += d.downloaded
const s = d.status.status
if (s === 'started' || s === 'downloading') active = d.filename
}
return {
filename: active,
percent: total > 0 ? Math.min(100, Math.round((downloaded / total) * 100)) : undefined,
}
}
export function AppInitializationSkeleton() {
const { t } = useTranslation()
const downloads = useDownloadsStore((s) => s.downloads)
const progress = useMemo(() => summarize(downloads), [downloads])
return (
<div className='flex min-h-0 flex-1 items-center justify-center bg-background'>
<div className='flex flex-col items-center gap-6'>
<img
src='/icon-large.png'
alt='Koharu'
className='h-20 w-20 opacity-80'
draggable={false}
/>
<div className='flex flex-col items-center gap-1'>
<h1 className='text-lg font-semibold tracking-widest text-foreground uppercase'>
Koharu
</h1>
<p className='text-xs text-muted-foreground'>{t('common.initializing')}</p>
</div>
<div className='w-56'>
<p className='mb-1.5 h-4 truncate text-center text-[11px] text-muted-foreground'>
{progress?.filename ?? '\u00A0'}
</p>
<Progress
value={progress?.percent ?? 0}
className={`h-1.5 ${progress ? 'visible' : 'invisible'}`}
/>
</div>
</div>
</div>
)
}