Desktop: sidebar reader as short rows with a progress bar; one Refresh (top bar) instead of two; rolling-out tile lists versions on their own lines; cards without screenshots show live versions per store

This commit is contained in:
CRTkafa 2026-10-23 09:43:08 +08:00
parent c36ad87658
commit 83b8ce8869
6 changed files with 67 additions and 17 deletions

View file

@ -286,17 +286,22 @@ export function App({ onTheme }: { onTheme: () => void }) {
);
}
/** The background reader in one line: "Reading 12 of 48 · App Store limit 3 412/3 600 left this hour". */
/** The background reader in the sidebar foot: progress (count + thin bar) and the App Store hourly limit on their own
* short rows, so nothing is cut off; the long wording stays in the tooltip. */
function ReaderLine() {
const d = useData();
const r = d.reader;
const q = Object.values(r.quota).sort((a, b) => a.remaining - b.remaining)[0];
const parts: string[] = [];
if (r.total > 0 && (r.running || r.queued)) parts.push(t('reader.progress', { done: r.done, total: r.total }));
else if (!d.reader.autoRead) parts.push(t('reader.off'));
else if (d.ready && d.apps.length) parts.push(t('reader.upToDate'));
if (Object.keys(r.paused).length) parts.push(t('reader.backoff'));
if (q) parts.push(t('reader.appleQuota', { left: num(q.remaining), limit: num(q.limit) }));
if (!parts.length) return null;
return <div className="row reader-line" data-testid="reader-line" aria-live="polite"><Icon name="refresh" className={`sr-icon${r.running ? ' spin' : ''}`} /><span title={parts.join(' · ')}>{parts.join(' · ')}</span></div>;
const busy = r.total > 0 && (r.running || r.queued);
const head = busy ? t('reader.progress', { done: r.done, total: r.total }) : !d.reader.autoRead ? t('reader.off') : d.ready && d.apps.length ? t('reader.upToDate') : '';
const paused = Object.keys(r.paused).length > 0;
if (!head && !q && !paused) return null;
return (
<div className="reader-line" data-testid="reader-line" aria-live="polite">
{head && <div className="row" title={head}><Icon name="refresh" className={`sr-icon${r.running ? ' spin' : ''}`} /><span>{head}</span></div>}
{busy && <div className="reader-bar" role="progressbar" aria-valuemin={0} aria-valuemax={r.total} aria-valuenow={r.done} aria-label={head}><i style={{ width: `${Math.round((r.done / Math.max(1, r.total)) * 100)}%` }} /></div>}
{paused && <div className="row" title={t('reader.backoff')}><Icon name="pause" className="sr-icon" /><span>{t('reader.backoffShort')}</span></div>}
{q && <div className="row" title={t('reader.appleQuota', { left: num(q.remaining), limit: num(q.limit) })}><Icon name="gauge" className="sr-icon" /><span>{t('reader.appleQuotaShort', { left: num(q.remaining), limit: num(q.limit) })}</span></div>}
</div>
);
}