Added more details and a landing page
Build, Test & Push Frontend / quality-check (push) Successful in 6s
Build, Test & Push Frontend / docker (push) Successful in 26s

This commit is contained in:
Andreas Dahm committed 2026-05-04 15:13:24 +02:00
1 parent 950f7d2b80
commit 38976e3240
8 files changed
+654 -40

No files matched your search

+120 -2
View File
@@ -1,8 +1,20 @@
import {useTranslation} from 'react-i18next';
import {useTranslation} from 'react-i18next';
import {Link} from 'react-router-dom';
import StatCard from '../components/StatCard.jsx';
import usePublicStats from '../hooks/usePublicStats.js';
const iconUrl = (appid, hash) =>
hash
? `https://cdn.cloudflare.steamstatic.com/steamcommunity/public/images/apps/${appid}/${hash}.jpg`
: null;
export default function LandingPage() {
const {t} = useTranslation();
const {data, isLoading} = usePublicStats();
const auth = data.auth;
const core = data.core;
return (
<div className="grow flex flex-col items-center p-4 md:p-8">
@@ -17,6 +29,112 @@ export default function LandingPage() {
{t('MAIN.GET_STARTED')}
</Link>
</section>
<section className="w-full max-w-5xl mb-16">
<h2 className="text-2xl font-bold text-slate-900 dark:text-white text-center mb-6">
{t('LANDING.STATS_TITLE')}
</h2>
{isLoading ? (
<div className="text-center text-slate-500 dark:text-slate-400">
{t('LANDING.STATS_LOADING')}
</div>
) : (
<div className="grid grid-cols-2 md:grid-cols-4 gap-4">
<StatCard
label={t('LANDING.TOTAL_USERS')}
value={auth?.totalUsers ?? 0}
icon="mdi-account-group"
/>
<StatCard
label={t('LANDING.STEAM_LINKED')}
value={auth?.usersWithSteamLinked ?? 0}
icon="mdi-steam"
/>
<StatCard
label={t('LANDING.TOTAL_GAMES')}
value={core?.totalLibraryEntries ?? 0}
icon="mdi-controller"
/>
<StatCard
label={t('LANDING.GAMES_PLAYED')}
value={core?.totalGamesPlayed ?? 0}
icon="mdi-gamepad-variant"
/>
<StatCard
label={t('LANDING.DISTINCT_GAMES')}
value={core?.totalDistinctGames ?? 0}
icon="mdi-shape"
/>
<StatCard
label={t('LANDING.TOTAL_PLAYTIME_DAYS')}
value={core?.totalPlaytimeDays ?? 0}
icon="mdi-clock-outline"
suffix={` ${t('LANDING.DAYS_SUFFIX')}`}
/>
<StatCard
label={t('LANDING.BIGGEST_LIBRARY')}
value={core?.biggestLibrary ?? 0}
icon="mdi-bookshelf"
/>
<StatCard
label={t('LANDING.BIGGEST_BACKLOG')}
value={core?.biggestBacklog ?? 0}
icon="mdi-archive"
/>
</div>
)}
{core?.topPlayedGames?.length > 0 && (
<div className="mt-10 grid grid-cols-1 md:grid-cols-2 gap-6">
<div className="bg-white dark:bg-slate-800 rounded-xl shadow-sm border border-slate-200 dark:border-slate-700 p-6">
<h3 className="text-lg font-bold text-slate-900 dark:text-white mb-4">
{t('LANDING.TOP_PLAYED')}
</h3>
<ol className="space-y-2">
{core.topPlayedGames.map((g, idx) => (
<li key={g.appid} className="flex items-center gap-3">
<span className="w-6 text-sm font-bold text-slate-400 tabular-nums">{idx + 1}</span>
{iconUrl(g.appid, g.imgIconUrl) ? (
<img src={iconUrl(g.appid, g.imgIconUrl)} alt="" className="w-8 h-8 rounded"/>
) : (
<div className="w-8 h-8 rounded bg-slate-200 dark:bg-slate-700"/>
)}
<span className="flex-1 truncate text-slate-900 dark:text-white">
{g.name ?? `App ${g.appid}`}
</span>
<span className="text-xs text-slate-500 dark:text-slate-400 tabular-nums">
{Math.round(g.value / 60).toLocaleString()}h
</span>
</li>
))}
</ol>
</div>
<div className="bg-white dark:bg-slate-800 rounded-xl shadow-sm border border-slate-200 dark:border-slate-700 p-6">
<h3 className="text-lg font-bold text-slate-900 dark:text-white mb-4">
{t('LANDING.TOP_OWNED')}
</h3>
<ol className="space-y-2">
{core.topOwnedGames.map((g, idx) => (
<li key={g.appid} className="flex items-center gap-3">
<span className="w-6 text-sm font-bold text-slate-400 tabular-nums">{idx + 1}</span>
{iconUrl(g.appid, g.imgIconUrl) ? (
<img src={iconUrl(g.appid, g.imgIconUrl)} alt="" className="w-8 h-8 rounded"/>
) : (
<div className="w-8 h-8 rounded bg-slate-200 dark:bg-slate-700"/>
)}
<span className="flex-1 truncate text-slate-900 dark:text-white">
{g.name ?? `App ${g.appid}`}
</span>
<span className="text-xs text-slate-500 dark:text-slate-400 tabular-nums">
{g.value.toLocaleString()}
</span>
</li>
))}
</ol>
</div>
</div>
)}
</section>
</div>
);
}
}