feat: collapse background uploads into a progress circle and fit hero covers
This commit is contained in:
1 parent
69f71cb836
commit
db52a2b589
4 files changed
+174
-5
No files matched your search
@@ -157,12 +157,48 @@ function FloatingUploads() {
|
||||
const { pathname } = useLocation();
|
||||
const { tasks } = useUploads();
|
||||
const { task: translation } = useTranslationRun();
|
||||
const [collapsed, setCollapsed] = useState(false);
|
||||
// on the upload page the uploads are listed in the page itself
|
||||
const uploads = tasks.length > 0 && pathname.replace(/\/$/, "") !== "/games/new";
|
||||
if (!uploads && !translation) return null;
|
||||
return <aside className="upload-floating" aria-label="Фоновые задачи">
|
||||
{uploads && <UploadProgress />}
|
||||
<TranslationProgress />
|
||||
{uploads && <Link to="/games/new" className="btn btn-primary">К загрузкам</Link>}
|
||||
const active = uploads ? tasks.find(task => ["creating", "uploading", "processing"].includes(task.status)) : undefined;
|
||||
const finished = uploads ? tasks.find(task => task.status === "failed") ?? tasks[0] : undefined;
|
||||
const current = active ?? finished;
|
||||
const translationActive = translation?.status === "running" || translation?.status === "stopping";
|
||||
const showTranslation = !active && translationActive || !current;
|
||||
const failed = showTranslation ? translation?.status === "failed" : current?.status === "failed";
|
||||
const done = showTranslation ? translation?.status === "done" || translation?.status === "stopped" : current?.status === "ready";
|
||||
const unknown = showTranslation
|
||||
? !!translationActive && !translation?.progress.total
|
||||
: current?.status === "creating" || current?.status === "processing" || current?.status === "uploading" && current.progress >= 1;
|
||||
const percentage = showTranslation && translation
|
||||
? Math.min(100, Math.round((translation.progress.done + translation.progress.failed) / (translation.progress.total || 1) * 100))
|
||||
: Math.max(0, Math.min(100, Math.round((current?.progress ?? 0) * 100)));
|
||||
const label = failed ? "Ошибка фоновой задачи" : done ? "Фоновые задачи завершены"
|
||||
: unknown ? "Обработка на сервере" : `Прогресс: ${percentage}%`;
|
||||
const count = (uploads ? tasks.length : 0) + (translation ? 1 : 0);
|
||||
const hasError = tasks.some(task => task.status === "failed") || translation?.status === "failed";
|
||||
const circumference = 2 * Math.PI * 25;
|
||||
return <aside className={`upload-floating${collapsed ? " upload-floating-collapsed" : ""}`} aria-label="Фоновые задачи">
|
||||
<button type="button" className={collapsed ? `upload-bubble${failed ? " failed" : done ? " done" : ""}` : "btn btn-ghost btn-icon upload-minimize"}
|
||||
aria-expanded={!collapsed} aria-label={collapsed ? `Развернуть фоновые задачи. ${label}` : "Свернуть фоновые задачи"}
|
||||
title={collapsed ? `${label}. Нажмите, чтобы развернуть` : "Свернуть в круг прогресса"}
|
||||
onClick={() => setCollapsed(value => !value)}>
|
||||
{collapsed ? <>
|
||||
<svg viewBox="0 0 64 64" className={`upload-ring${unknown ? " indeterminate" : ""}`} aria-hidden="true">
|
||||
<circle cx="32" cy="32" r="25" className="upload-ring-track" />
|
||||
<circle cx="32" cy="32" r="25" className="upload-ring-value"
|
||||
strokeDasharray={`${circumference * (unknown ? 0.25 : percentage / 100)} ${circumference}`} />
|
||||
</svg>
|
||||
<span className="upload-bubble-value">{failed ? <Icon name="alert" size={20} /> : done ? <Icon name="check" size={22} />
|
||||
: unknown ? <Icon name="clock" size={20} /> : `${percentage}%`}</span>
|
||||
{(count > 1 || hasError && !failed) && <span className={`upload-bubble-count${hasError ? " has-error" : ""}`}>{count}</span>}
|
||||
</> : <Icon name="minus" size={18} />}
|
||||
</button>
|
||||
{!collapsed && <>
|
||||
{uploads && <UploadProgress />}
|
||||
<TranslationProgress />
|
||||
{uploads && <Link to="/games/new" className="btn btn-primary">К загрузкам</Link>}
|
||||
</>}
|
||||
</aside>;
|
||||
}
|
||||
Reference in new issue
Block a user