feat(points): apply worn effects on covers, details and backgrounds
Build, Test & Push Frontend / quality-check (push) Successful in 28s
Build, Test & Push Frontend / docker (push) Successful in 27s

This commit is contained in:
lobo committed 2026-10-01 15:09:25 +02:00
1 parent dd45c0b5f6
commit 249973dd69
19 files changed
+317 -35

No files matched your search

+14 -3
View File
@@ -6,6 +6,7 @@ import {toast} from 'sonner';
import {Badge} from '@/components/ui/badge';
import {Button} from '@/components/ui/button';
import {Card} from '@/components/ui/card';
import {cn} from '@/lib/utils';
import GameCover from './GameCover.jsx';
import GameStatusBadge from './GameStatusBadge.jsx';
import ProfileArtMenu from './ProfileArtMenu.jsx';
@@ -16,12 +17,15 @@ import {formatPlaytime} from '../utils/games.js';
import {setGameHidden} from '../utils/hiddenGames.js';
import {isSteamKey} from '../utils/manualGames.js';
import {platformLabel} from '../utils/platforms.js';
import {coverEffect, detailEffect} from '../utils/rewards.js';
const SPEEDRUN_PREFIX = 'https://www.speedrun.com/';
// The spans of each completed effect decoration; effects.css places them.
const DETAIL_ELEMENTS = {'fx-detail-gold-shine': 8, 'fx-detail-neon-pulse': 1, 'fx-detail-holo': 1, 'fx-detail-ember': 6};
export default function GameHeroCard({game, manual, auditor, profileStyle, onCorrect, onMerge, onHiddenChanged, onProfileStyleSaved}) {
const {t} = useTranslation();
const {appearance} = usePreferences();
const {appearance, equipped} = usePreferences();
const saveAppearance = useSaveAppearance();
const [hiding, setHiding] = useState(false);
@@ -31,6 +35,7 @@ export default function GameHeroCard({game, manual, auditor, profileStyle, onCor
? game.speedrunUrl : null;
const isBackground = appearance.backgroundAppid === game.appid;
const isBanner = appearance.showBanner && appearance.bannerAppid === game.appid;
const detailFx = detailEffect(equipped, game.status);
const toggleHidden = async () => {
const hidden = !game.hidden;
@@ -54,8 +59,14 @@ export default function GameHeroCard({game, manual, auditor, profileStyle, onCor
return (
<Card className="relative overflow-hidden p-0 gap-0 md:flex-row">
<GameCover appid={game.appid} imageUrl={game.imageUrl} className="w-full rounded-none md:w-96 md:shrink-0"/>
<div className="flex flex-1 flex-col justify-between gap-4 p-6">
{detailFx && (
<div aria-hidden="true" className={cn('fx pointer-events-none absolute inset-0', detailFx)}>
{Array.from({length: DETAIL_ELEMENTS[detailFx]}, (_, i) => <span key={i}/>)}
</div>
)}
<GameCover appid={game.appid} imageUrl={game.imageUrl} fx={coverEffect(equipped, game.status)}
className="w-full rounded-none md:w-96 md:shrink-0"/>
<div className="relative flex flex-1 flex-col justify-between gap-4 p-6">
<div>
<h1 className="text-2xl md:text-3xl font-bold tracking-tight">
{game.name ?? `App ${game.appid}`}