Public Access
feat(ui): make stat numbers clickable to open games
StatDrill context holds one dialog for a page. StatCount wraps a number: total and status counts link to the library filter, other numbers open StatGamesDialog. DrillRow and DrillButton support drill-down in tag bars (genres, platforms, moods) and other stat displays. Dialog shows 40 games per page with bottom-sheet layout on phones, handles pagination and errors (403 not shared, 401 expired, 400 bad argument).
This commit is contained in:
1 parent
ed5df8c40d
commit
777ba87fd6
31 files changed
+1026
-261
No files matched your search
@@ -6,10 +6,12 @@ import {Button} from '@/components/ui/button';
|
||||
import {Card} from '@/components/ui/card';
|
||||
import GameCover from './GameCover.jsx';
|
||||
import PileTrend from './stats/PileTrend.jsx';
|
||||
import {StatCount} from './stats/StatDrill.jsx';
|
||||
import {STATUS_META} from './GameStatusBadge.jsx';
|
||||
import {backlogShare} from '../utils/backlog.js';
|
||||
import {GAME_STATUSES} from '../utils/limits.js';
|
||||
import {formatPlaytime} from '../utils/games.js';
|
||||
import {libraryLink} from '../utils/statGames.js';
|
||||
|
||||
/**
|
||||
* @param trend the TREND group of GET /api/library/stats; the card shows no trend while it is missing
|
||||
@@ -34,17 +36,25 @@ export default function PileOfShameCard({summary, trend, syncing, onShuffle, shu
|
||||
|
||||
<div>
|
||||
<div className="flex items-baseline gap-2">
|
||||
<span className="text-4xl font-bold tabular-nums">{backlog.toLocaleString(i18n.language)}</span>
|
||||
<StatCount to={libraryLink('BACKLOG')} title={t('DASHBOARD.PILE_OF_SHAME')} params={{key: 'PILE'}}
|
||||
label={`${t('BACKLOG.STATUS.BACKLOG')}: ${backlog}`}>
|
||||
<span className="text-4xl font-bold tabular-nums">{backlog.toLocaleString(i18n.language)}</span>
|
||||
</StatCount>
|
||||
<span className="text-sm text-muted-foreground">
|
||||
{t('DASHBOARD.PILE_SHARE', {percent: backlogShare(summary)})}
|
||||
</span>
|
||||
</div>
|
||||
<p className="mt-1 text-sm text-muted-foreground">
|
||||
{t('DASHBOARD.NEVER_PLAYED', {count: summary.neverPlayed})}
|
||||
<StatCount params={summary.neverPlayed > 0 ? {key: 'NEVER_STARTED'} : null}
|
||||
title={t('STATS.OVERVIEW.NEVER_STARTED')}>
|
||||
{t('DASHBOARD.NEVER_PLAYED', {count: summary.neverPlayed})}
|
||||
</StatCount>
|
||||
</p>
|
||||
{summary.backlogMinutes > 0 && (
|
||||
<p className="text-sm text-muted-foreground">
|
||||
{t('DASHBOARD.BACKLOG_HOURS', {time: formatPlaytime(summary.backlogMinutes)})}
|
||||
<StatCount params={{key: 'PILE_TIME_TO_BEAT'}} title={t('STATS.PILE.NORMAL')}>
|
||||
{t('DASHBOARD.BACKLOG_HOURS', {time: formatPlaytime(summary.backlogMinutes)})}
|
||||
</StatCount>
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
@@ -67,7 +77,9 @@ export default function PileOfShameCard({summary, trend, syncing, onShuffle, shu
|
||||
<li key={s} className="flex items-center gap-1.5">
|
||||
<span className={`size-2 rounded-full ${STATUS_META[s].bar}`}/>
|
||||
{t(`BACKLOG.STATUS.${s}`)}
|
||||
<span className="tabular-nums text-foreground">{summary.byStatus[s]}</span>
|
||||
<StatCount to={libraryLink(s)} label={`${t(`BACKLOG.STATUS.${s}`)}: ${summary.byStatus[s]}`}>
|
||||
<span className="tabular-nums text-foreground">{summary.byStatus[s]}</span>
|
||||
</StatCount>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
|
||||
Reference in new issue
Block a user