Public Access
feat(ui): modern shadcn/ui theme with violet accent across all pages
Add shadcn/ui (Radix + Tailwind 4) components, zinc/violet theme tokens and self-hosted Inter. New header with user menu, Steam cover art, skeletons and toasts. Replace @mdi/font with lucide-react. Fix: top-owned list on the landing page only showed with top-played entries; numbers use the app language.
This commit is contained in:
1 parent
76a9ac3e6f
commit
e480369a98
43 files changed
+3804
-979
No files matched your search
@@ -1,43 +1,45 @@
|
||||
import React, {useState, useEffect} from 'react';
|
||||
import {useEffect, useState} from 'react';
|
||||
import {Link} from 'react-router-dom';
|
||||
import {useTranslation} from 'react-i18next';
|
||||
import {ArrowRight, Gamepad2} from 'lucide-react';
|
||||
|
||||
import {Card} from '@/components/ui/card';
|
||||
|
||||
const DURATION_MS = 1000;
|
||||
|
||||
const SteamGameCount = ({targetCount}) => {
|
||||
const {t} = useTranslation();
|
||||
const [count, setCount] = useState(0);
|
||||
|
||||
useEffect(() => {
|
||||
let frame;
|
||||
let startTime;
|
||||
const duration = 1000;
|
||||
const startCount = 0;
|
||||
|
||||
const animate = (timestamp) => {
|
||||
if (!startTime) startTime = timestamp;
|
||||
const progress = Math.min((timestamp - startTime) / duration, 1);
|
||||
|
||||
const currentCount = Math.floor(progress * (targetCount - startCount) + startCount);
|
||||
setCount(currentCount);
|
||||
|
||||
startTime ??= timestamp;
|
||||
const progress = Math.min((timestamp - startTime) / DURATION_MS, 1);
|
||||
setCount(Math.floor(progress * targetCount));
|
||||
if (progress < 1) {
|
||||
requestAnimationFrame(animate);
|
||||
frame = requestAnimationFrame(animate);
|
||||
}
|
||||
};
|
||||
|
||||
requestAnimationFrame(animate);
|
||||
frame = requestAnimationFrame(animate);
|
||||
return () => cancelAnimationFrame(frame);
|
||||
}, [targetCount]);
|
||||
|
||||
return (
|
||||
<Link
|
||||
to="/library"
|
||||
className="flex flex-col items-center justify-center p-6 bg-white dark:bg-slate-800 rounded-xl shadow-sm border border-slate-200 dark:border-slate-700 hover:border-blue-500 dark:hover:border-blue-500 transition-colors"
|
||||
>
|
||||
<div className="text-4xl font-bold text-blue-600 dark:text-blue-400 mb-2">
|
||||
{count}
|
||||
<Card className="relative justify-between overflow-hidden p-6">
|
||||
<div className="absolute -right-6 -top-6 size-32 rounded-full bg-primary/10"/>
|
||||
<div className="flex size-10 items-center justify-center rounded-lg bg-primary/10 text-primary">
|
||||
<Gamepad2 className="size-5"/>
|
||||
</div>
|
||||
<div className="text-sm font-medium text-slate-500 dark:text-slate-400 uppercase tracking-wider">
|
||||
{t('DASHBOARD.STEAM_GAMES')}
|
||||
<div>
|
||||
<div className="text-5xl font-bold tracking-tight tabular-nums">{count}</div>
|
||||
<div className="mt-1 text-sm text-muted-foreground">{t('DASHBOARD.STEAM_GAMES')}</div>
|
||||
</div>
|
||||
</Link>
|
||||
<Link to="/library" className="inline-flex items-center gap-1 text-sm font-medium text-primary hover:underline">
|
||||
{t('DASHBOARD.TO_LIBRARY')} <ArrowRight className="size-4"/>
|
||||
</Link>
|
||||
</Card>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
Reference in new issue
Block a user