77 lines
1.8 KiB
TypeScript
77 lines
1.8 KiB
TypeScript
import { ReactNode } from 'react';
|
|
import { Box } from './Box';
|
|
import { Surface } from './Surface';
|
|
import { Group } from './Group';
|
|
|
|
export interface LeaderboardRowProps {
|
|
rank: ReactNode;
|
|
identity: ReactNode;
|
|
stats: ReactNode;
|
|
onClick?: () => void;
|
|
}
|
|
|
|
/**
|
|
* LeaderboardRow is a semantic UI component for displaying an entry in a leaderboard.
|
|
* It follows the "Modern Precision" theme with obsessive detail.
|
|
*/
|
|
export const LeaderboardRow = ({
|
|
rank,
|
|
identity,
|
|
stats,
|
|
onClick
|
|
}: LeaderboardRowProps) => {
|
|
return (
|
|
<Surface
|
|
as={onClick ? 'button' : 'div'}
|
|
variant="precision"
|
|
onClick={onClick}
|
|
padding="none"
|
|
cursor={onClick ? 'pointer' : 'default'}
|
|
width="full"
|
|
textAlign="left"
|
|
transition="all 0.2s cubic-bezier(0.4, 0, 0.2, 1)"
|
|
hoverBg="rgba(25, 140, 255, 0.04)"
|
|
display="block"
|
|
style={{
|
|
border: 'none',
|
|
borderBottom: '1px solid var(--ui-color-border-muted)',
|
|
background: 'transparent',
|
|
position: 'relative'
|
|
}}
|
|
className="group"
|
|
>
|
|
<Box
|
|
display="flex"
|
|
alignItems="center"
|
|
gap={6}
|
|
paddingX={6}
|
|
paddingY={4}
|
|
className="transition-transform duration-200 group-hover:translate-x-1"
|
|
>
|
|
<Box width="10" display="flex" justifyContent="center" flexShrink={0}>
|
|
{rank}
|
|
</Box>
|
|
|
|
<Box flexGrow={1} minWidth="0">
|
|
{identity}
|
|
</Box>
|
|
|
|
<Group gap={8}>
|
|
{stats}
|
|
</Group>
|
|
</Box>
|
|
|
|
{/* Hover indicator */}
|
|
<Box
|
|
position="absolute"
|
|
left={0}
|
|
top={0}
|
|
bottom={0}
|
|
width={1}
|
|
bg="var(--ui-color-intent-primary)"
|
|
className="opacity-0 transition-opacity duration-200 group-hover:opacity-100"
|
|
/>
|
|
</Surface>
|
|
);
|
|
};
|