badge redesign again
This commit is contained in:
@@ -1,45 +1,45 @@
|
|||||||
import { Box, Card, Skeleton, Text } from "@mantine/core";
|
import { Box, Skeleton, Text } from "@mantine/core";
|
||||||
|
|
||||||
const BadgeShowcaseSkeleton = () => {
|
const BadgeShowcaseSkeleton = () => {
|
||||||
return (
|
return (
|
||||||
<Box mb="lg">
|
<Box mb="lg">
|
||||||
<Card
|
<Box
|
||||||
withBorder
|
px="md"
|
||||||
radius="md"
|
|
||||||
p={0}
|
|
||||||
style={{
|
style={{
|
||||||
overflow: 'hidden',
|
maxHeight: '220px',
|
||||||
|
overflowY: 'auto',
|
||||||
|
overflowX: 'hidden',
|
||||||
|
width: '100%',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Box
|
<Box
|
||||||
p="md"
|
|
||||||
style={{
|
|
||||||
background: 'light-dark(var(--mantine-color-gray-1), var(--mantine-color-dark-6))',
|
|
||||||
borderBottom: '1px solid light-dark(var(--mantine-color-gray-3), var(--mantine-color-dark-4))',
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Text size="sm" fw={600} tt="uppercase" c="dimmed" style={{ letterSpacing: '0.5px' }}>
|
|
||||||
Badges
|
|
||||||
</Text>
|
|
||||||
</Box>
|
|
||||||
|
|
||||||
<Box
|
|
||||||
p="md"
|
|
||||||
style={{
|
style={{
|
||||||
display: 'grid',
|
display: 'grid',
|
||||||
gridTemplateColumns: 'repeat(auto-fill, minmax(110px, 1fr))',
|
gridTemplateColumns: 'repeat(auto-fill, minmax(85px, 1fr))',
|
||||||
gap: 'var(--mantine-spacing-sm)',
|
gap: 'var(--mantine-spacing-md)',
|
||||||
|
paddingBottom: 'var(--mantine-spacing-sm)',
|
||||||
|
width: '100%',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{[1, 2, 3, 4, 5, 6].map((i) => (
|
{[1, 2, 3, 4, 5, 6].map((i) => (
|
||||||
<Skeleton
|
<Box
|
||||||
key={i}
|
key={i}
|
||||||
height={70}
|
style={{
|
||||||
radius="md"
|
aspectRatio: '1',
|
||||||
/>
|
position: 'relative',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Skeleton
|
||||||
|
height="100%"
|
||||||
|
radius="12px"
|
||||||
|
style={{
|
||||||
|
aspectRatio: '1',
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</Box>
|
||||||
))}
|
))}
|
||||||
</Box>
|
</Box>
|
||||||
</Card>
|
</Box>
|
||||||
</Box>
|
</Box>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -88,18 +88,13 @@ const BadgeShowcase = ({ playerId }: BadgeShowcaseProps) => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<Box mb="lg">
|
<Box mb="lg">
|
||||||
<Box mb="sm" px="md">
|
|
||||||
<Text size="sm" fw={600} tt="uppercase" c="dimmed" style={{ letterSpacing: '0.5px' }}>
|
|
||||||
Badges
|
|
||||||
</Text>
|
|
||||||
</Box>
|
|
||||||
|
|
||||||
<Box
|
<Box
|
||||||
px="md"
|
px="md"
|
||||||
style={{
|
style={{
|
||||||
maxHeight: '200px',
|
maxHeight: '220px',
|
||||||
overflowY: 'auto',
|
overflowY: 'auto',
|
||||||
overflowX: 'hidden',
|
overflowX: 'hidden',
|
||||||
|
width: '100%',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Box
|
<Box
|
||||||
@@ -108,13 +103,13 @@ const BadgeShowcase = ({ playerId }: BadgeShowcaseProps) => {
|
|||||||
gridTemplateColumns: 'repeat(auto-fill, minmax(85px, 1fr))',
|
gridTemplateColumns: 'repeat(auto-fill, minmax(85px, 1fr))',
|
||||||
gap: 'var(--mantine-spacing-md)',
|
gap: 'var(--mantine-spacing-md)',
|
||||||
paddingBottom: 'var(--mantine-spacing-sm)',
|
paddingBottom: 'var(--mantine-spacing-sm)',
|
||||||
|
width: '100%',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{badgesToDisplay.map((display) => {
|
{badgesToDisplay.map((display) => {
|
||||||
const isStackableBadge = display.badge.criteria?.tournament_wins !== undefined ||
|
const isStackableBadge = ['winner_badge', 'silver_medal_badge', 'bronze_medal_badge'].includes(display.badge.key);
|
||||||
display.badge.criteria?.placement !== undefined;
|
|
||||||
const stackCount = display.earned && isStackableBadge
|
const stackCount = display.earned && isStackableBadge
|
||||||
? Math.floor((display.progress?.progress || 0) / getTargetProgress(display.badge))
|
? (display.progress?.progress || 0)
|
||||||
: 1;
|
: 1;
|
||||||
const showStack = stackCount > 1;
|
const showStack = stackCount > 1;
|
||||||
|
|
||||||
@@ -133,32 +128,32 @@ const BadgeShowcase = ({ playerId }: BadgeShowcaseProps) => {
|
|||||||
{[...Array(Math.min(stackCount - 1, 2))].map((_, i) => (
|
{[...Array(Math.min(stackCount - 1, 2))].map((_, i) => (
|
||||||
<Box
|
<Box
|
||||||
key={i}
|
key={i}
|
||||||
style={(theme) => ({
|
style={{
|
||||||
aspectRatio: '1',
|
aspectRatio: '1',
|
||||||
borderRadius: '12px',
|
borderRadius: '12px',
|
||||||
background: `linear-gradient(135deg, ${theme.colors[theme.primaryColor][5]} 0%, ${theme.colors[theme.primaryColor][7]} 100%)`,
|
background: 'transparent',
|
||||||
border: `2px solid ${theme.colors[theme.primaryColor][6]}`,
|
border: '2px solid var(--mantine-primary-color-5)',
|
||||||
position: 'absolute',
|
position: 'absolute',
|
||||||
top: `${(i + 1) * 3}px`,
|
top: `${(i + 1) * 3}px`,
|
||||||
left: `${(i + 1) * 3}px`,
|
left: `${(i + 1) * 3}px`,
|
||||||
right: `-${(i + 1) * 3}px`,
|
right: `-${(i + 1) * 3}px`,
|
||||||
bottom: `-${(i + 1) * 3}px`,
|
bottom: `-${(i + 1) * 3}px`,
|
||||||
opacity: 0.6 - (i * 0.2),
|
opacity: 0.4 - (i * 0.15),
|
||||||
zIndex: -(i + 1),
|
zIndex: -(i + 1),
|
||||||
})}
|
}}
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<Box
|
<Box
|
||||||
style={(theme) => ({
|
style={{
|
||||||
aspectRatio: '1',
|
aspectRatio: '1',
|
||||||
borderRadius: '12px',
|
borderRadius: '12px',
|
||||||
background: display.earned
|
background: 'light-dark(var(--mantine-color-white), var(--mantine-color-dark-7))',
|
||||||
? `linear-gradient(135deg, ${theme.colors[theme.primaryColor][5]} 0%, ${theme.colors[theme.primaryColor][7]} 100%)`
|
border: display.earned
|
||||||
: 'light-dark(var(--mantine-color-gray-1), var(--mantine-color-dark-6))',
|
? '2px solid var(--mantine-primary-color-6)'
|
||||||
border: `2px solid ${display.earned ? theme.colors[theme.primaryColor][6] : 'light-dark(var(--mantine-color-gray-3), var(--mantine-color-dark-4))'}`,
|
: '2px dashed var(--mantine-primary-color-4)',
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
justifyContent: 'center',
|
justifyContent: 'center',
|
||||||
@@ -167,46 +162,33 @@ const BadgeShowcase = ({ playerId }: BadgeShowcaseProps) => {
|
|||||||
padding: 'var(--mantine-spacing-xs)',
|
padding: 'var(--mantine-spacing-xs)',
|
||||||
position: 'relative',
|
position: 'relative',
|
||||||
boxShadow: display.earned
|
boxShadow: display.earned
|
||||||
? `0 2px 8px ${theme.colors[theme.primaryColor][6]}30`
|
? '0 0 0 1px color-mix(in srgb, var(--mantine-primary-color-6) 20%, transparent)'
|
||||||
: '0 1px 3px rgba(0, 0, 0, 0.1)',
|
: 'none',
|
||||||
opacity: display.earned ? 1 : 0.5,
|
opacity: display.earned ? 1 : 0.4,
|
||||||
zIndex: 1,
|
zIndex: 1,
|
||||||
':hover': {
|
}}
|
||||||
transform: 'translateY(-2px)',
|
|
||||||
boxShadow: display.earned
|
|
||||||
? `0 4px 12px ${theme.colors[theme.primaryColor][6]}40`
|
|
||||||
: '0 2px 6px rgba(0, 0, 0, 0.15)',
|
|
||||||
},
|
|
||||||
})}
|
|
||||||
>
|
>
|
||||||
{display.earned ? (
|
{display.earned ? (
|
||||||
<MedalIcon
|
<MedalIcon
|
||||||
size={32}
|
size={32}
|
||||||
weight="fill"
|
weight="fill"
|
||||||
style={{
|
color="var(--mantine-primary-color-6)"
|
||||||
color: 'white',
|
|
||||||
filter: 'drop-shadow(0 1px 2px rgba(0, 0, 0, 0.3))',
|
|
||||||
}}
|
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
<LockKeyIcon
|
<LockKeyIcon
|
||||||
size={28}
|
size={28}
|
||||||
weight="regular"
|
weight="regular"
|
||||||
style={{
|
color="var(--mantine-color-dimmed)"
|
||||||
color: 'var(--mantine-color-dimmed)',
|
|
||||||
}}
|
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{showStack && (
|
{showStack && (
|
||||||
<Box
|
<Box
|
||||||
style={(theme) => ({
|
style={{
|
||||||
position: 'absolute',
|
position: 'absolute',
|
||||||
top: '4px',
|
top: '4px',
|
||||||
right: '4px',
|
right: '4px',
|
||||||
background: theme.colors[theme.primaryColor][8],
|
color: 'var(--mantine-primary-color-6)',
|
||||||
color: 'white',
|
|
||||||
borderRadius: '50%',
|
|
||||||
width: '20px',
|
width: '20px',
|
||||||
height: '20px',
|
height: '20px',
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
@@ -214,11 +196,9 @@ const BadgeShowcase = ({ playerId }: BadgeShowcaseProps) => {
|
|||||||
justifyContent: 'center',
|
justifyContent: 'center',
|
||||||
fontSize: '10px',
|
fontSize: '10px',
|
||||||
fontWeight: 700,
|
fontWeight: 700,
|
||||||
border: '2px solid white',
|
}}
|
||||||
boxShadow: '0 1px 3px rgba(0, 0, 0, 0.3)',
|
|
||||||
})}
|
|
||||||
>
|
>
|
||||||
{stackCount}
|
x{stackCount}
|
||||||
</Box>
|
</Box>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
@@ -226,10 +206,9 @@ const BadgeShowcase = ({ playerId }: BadgeShowcaseProps) => {
|
|||||||
size="xs"
|
size="xs"
|
||||||
fw={display.earned ? 600 : 500}
|
fw={display.earned ? 600 : 500}
|
||||||
ta="center"
|
ta="center"
|
||||||
c={display.earned ? 'white' : 'dimmed'}
|
c={display.earned ? undefined : 'dimmed'}
|
||||||
style={{
|
style={{
|
||||||
lineHeight: 1.2,
|
lineHeight: 1.2,
|
||||||
textShadow: display.earned ? '0 1px 2px rgba(0, 0, 0, 0.3)' : 'none',
|
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{display.badge.name}
|
{display.badge.name}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { Box } from "@mantine/core";
|
import { Box, Stack, Text, Divider } from "@mantine/core";
|
||||||
import { Suspense } from "react";
|
import { Suspense } from "react";
|
||||||
import Header from "./header";
|
import Header from "./header";
|
||||||
import SwipeableTabs from "@/components/swipeable-tabs";
|
import SwipeableTabs from "@/components/swipeable-tabs";
|
||||||
@@ -21,14 +21,19 @@ const Profile = ({ id }: ProfileProps) => {
|
|||||||
const tabs = [
|
const tabs = [
|
||||||
{
|
{
|
||||||
label: "Overview",
|
label: "Overview",
|
||||||
content: (
|
content: <>
|
||||||
<>
|
<Stack px="md">
|
||||||
|
<Text size="md" fw={700}>Badges</Text>
|
||||||
<Suspense fallback={<BadgeShowcaseSkeleton />}>
|
<Suspense fallback={<BadgeShowcaseSkeleton />}>
|
||||||
<BadgeShowcase playerId={id} />
|
<BadgeShowcase playerId={id} />
|
||||||
</Suspense>
|
</Suspense>
|
||||||
|
</Stack>
|
||||||
|
<Divider my="md" />
|
||||||
|
<Stack>
|
||||||
|
<Text px="md" size="md" fw={700}>Statistics</Text>
|
||||||
<StatsOverview statsData={stats} isLoading={statsLoading} />
|
<StatsOverview statsData={stats} isLoading={statsLoading} />
|
||||||
</>
|
</Stack>
|
||||||
),
|
</>,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: "Matches",
|
label: "Matches",
|
||||||
|
|||||||
Reference in New Issue
Block a user