Badge images!

This commit is contained in:
yohlo
2025-10-06 02:13:51 -05:00
parent af0ec85811
commit afd0b692fa
27 changed files with 111 additions and 37 deletions

View File

@@ -1,8 +1,8 @@
import { Box, Text, Popover, Progress, Title } from "@mantine/core";
import { Box, Text, Popover, Progress, Title, Image } from "@mantine/core";
import { usePlayerBadges, useAllBadges } from "../queries";
import { useAuth } from "@/contexts/auth-context";
import { Badge, BadgeProgress } from "../types";
import { useMemo } from "react";
import { useMemo, useState } from "react";
import { MedalIcon, LockKeyIcon } from "@phosphor-icons/react";
interface BadgeShowcaseProps {
@@ -16,6 +16,47 @@ interface BadgeDisplay {
progressText: string;
}
interface BadgeIconProps {
badge: Badge;
earned: boolean;
}
const BadgeIcon = ({ badge, earned }: BadgeIconProps) => {
const [imageError, setImageError] = useState(false);
const imagePath = `/static/img/${badge.key}.png`;
if (imageError) {
// Fallback to icon if image fails to load
return earned ? (
<MedalIcon
size={48}
weight="fill"
color="var(--mantine-primary-color-6)"
/>
) : (
<LockKeyIcon
size={44}
weight="regular"
color="var(--mantine-color-dimmed)"
/>
);
}
return (
<Image
src={imagePath}
alt={badge.name}
width={48}
height={48}
onError={() => setImageError(true)}
style={{
objectFit: 'contain',
opacity: earned ? 1 : 0.4,
}}
/>
);
};
const BadgeShowcase = ({ playerId }: BadgeShowcaseProps) => {
const { user } = useAuth();
const { data: badgeProgress } = usePlayerBadges(playerId);
@@ -35,6 +76,15 @@ const BadgeShowcase = ({ playerId }: BadgeShowcaseProps) => {
continue;
}
const isVeteranBadge = /^veteran_\d+_badge$/.test(badge.key);
if (isVeteranBadge && !earned) {
continue;
}
if (badge.key === 'new_player_badge') {
continue;
}
let progressText = "";
if (progress) {
const target = getTargetProgress(badge);
@@ -129,15 +179,14 @@ const BadgeShowcase = ({ playerId }: BadgeShowcaseProps) => {
<Box
key={i}
style={{
aspectRatio: '1',
width: '85px',
height: '85px',
borderRadius: '12px',
background: 'transparent',
border: '2px solid var(--mantine-primary-color-5)',
position: 'absolute',
top: `${(i + 1) * 3}px`,
left: `${(i + 1) * 3}px`,
right: `-${(i + 1) * 3}px`,
bottom: `-${(i + 1) * 3}px`,
opacity: 0.4 - (i * 0.15),
zIndex: -(i + 1),
}}
@@ -148,9 +197,10 @@ const BadgeShowcase = ({ playerId }: BadgeShowcaseProps) => {
<Box
style={{
aspectRatio: '1',
width: '100px',
height: '100px',
borderRadius: '12px',
background: 'light-dark(var(--mantine-color-white), var(--mantine-color-dark-7))',
background: 'light-dark(var(--mantine-color-white), var(--mantine-color-dark-6))',
border: display.earned
? '2px solid var(--mantine-primary-color-6)'
: '2px dashed var(--mantine-primary-color-4)',
@@ -159,7 +209,6 @@ const BadgeShowcase = ({ playerId }: BadgeShowcaseProps) => {
justifyContent: 'center',
flexDirection: 'column',
gap: '4px',
padding: 'var(--mantine-spacing-xs)',
position: 'relative',
boxShadow: display.earned
? '0 0 0 1px color-mix(in srgb, var(--mantine-primary-color-6) 20%, transparent)'
@@ -168,19 +217,7 @@ const BadgeShowcase = ({ playerId }: BadgeShowcaseProps) => {
zIndex: 1,
}}
>
{display.earned ? (
<MedalIcon
size={32}
weight="fill"
color="var(--mantine-primary-color-6)"
/>
) : (
<LockKeyIcon
size={28}
weight="regular"
color="var(--mantine-color-dimmed)"
/>
)}
<BadgeIcon badge={display.badge} earned={display.earned} />
{showStack && (
<Box
@@ -202,15 +239,15 @@ const BadgeShowcase = ({ playerId }: BadgeShowcaseProps) => {
</Box>
)}
<Title
order={6}
<Text
size="xs"
fw={display.earned ? 600 : 500}
ta="center"
c={display.earned ? undefined : 'dimmed'}
style={{ lineHeight: 1.1 }}
>
{display.badge.name}
</Title>
</Text>
</Box>
</Box>
</Popover.Target>