facehash avatars
This commit is contained in:
85
src/components/player-avatar.tsx
Normal file
85
src/components/player-avatar.tsx
Normal file
@@ -0,0 +1,85 @@
|
||||
import { Paper, useMantineTheme } from "@mantine/core";
|
||||
import { Facehash } from "facehash";
|
||||
|
||||
interface PlayerAvatarProps {
|
||||
name?: string;
|
||||
size?: number;
|
||||
disableFullscreen?: boolean;
|
||||
style?: React.CSSProperties;
|
||||
}
|
||||
|
||||
const PlayerAvatar = ({
|
||||
name = "",
|
||||
size = 35,
|
||||
disableFullscreen = false,
|
||||
style,
|
||||
}: PlayerAvatarProps) => {
|
||||
const theme = useMantineTheme();
|
||||
|
||||
const getFacehashSize = (size: number): 32 | 48 | 64 | 80 => {
|
||||
if (size <= 40) return 32;
|
||||
if (size <= 56) return 48;
|
||||
if (size <= 72) return 64;
|
||||
return 80;
|
||||
};
|
||||
|
||||
const facehashSize = getFacehashSize(size);
|
||||
|
||||
const colors = [
|
||||
"hsla(314, 100%, 80%, 1)",
|
||||
"hsla(58, 93%, 72%, 1)",
|
||||
"hsla(218, 92%, 72%, 1)",
|
||||
"hsla(19, 99%, 44%, 1)",
|
||||
"hsla(156, 86%, 40%, 1)",
|
||||
"hsla(314, 100%, 85%, 1)",
|
||||
"hsla(58, 92%, 79%, 1)",
|
||||
"hsla(218, 91%, 78%, 1)",
|
||||
"hsla(19, 99%, 50%, 1)",
|
||||
"hsla(156, 86%, 64%, 1)",
|
||||
];
|
||||
|
||||
return (
|
||||
<Paper
|
||||
p={size / 20}
|
||||
radius="100%"
|
||||
withBorder
|
||||
style={{
|
||||
cursor: !disableFullscreen ? 'pointer' : 'default',
|
||||
transition: 'transform 0.15s ease',
|
||||
...style,
|
||||
}}
|
||||
onMouseEnter={(e) => {
|
||||
if (!disableFullscreen) {
|
||||
e.currentTarget.style.transform = 'scale(1.02)';
|
||||
}
|
||||
}}
|
||||
onMouseLeave={(e) => {
|
||||
e.currentTarget.style.transform = 'scale(1)';
|
||||
}}
|
||||
>
|
||||
<div
|
||||
style={{
|
||||
width: size,
|
||||
height: size,
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
overflow: 'hidden',
|
||||
borderRadius: '100%',
|
||||
}}
|
||||
>
|
||||
<Facehash
|
||||
name={name}
|
||||
size={size}
|
||||
variant="solid"
|
||||
colors={colors}
|
||||
intensity3d="dramatic"
|
||||
enableBlink
|
||||
style={{ borderRadius: '100%', overflow: 'hidden', color: 'black' }}
|
||||
/>
|
||||
</div>
|
||||
</Paper>
|
||||
);
|
||||
};
|
||||
|
||||
export default PlayerAvatar;
|
||||
@@ -5,7 +5,7 @@ import { useAllPlayerStats } from "../queries";
|
||||
import { useSheet } from "@/hooks/use-sheet";
|
||||
import Sheet from "@/components/sheet/sheet";
|
||||
import PlayerHeadToHeadSheet from "./player-head-to-head-sheet";
|
||||
import Avatar from "@/components/avatar";
|
||||
import PlayerAvatar from "@/components/player-avatar";
|
||||
|
||||
const LeagueHeadToHead = () => {
|
||||
const [player1Id, setPlayer1Id] = useState<string | null>(null);
|
||||
@@ -89,7 +89,7 @@ const LeagueHeadToHead = () => {
|
||||
{player1Id ? (
|
||||
<>
|
||||
<Stack gap={4} align="center" style={{ flex: 1 }}>
|
||||
<Avatar name={player1Name} size={36} />
|
||||
<PlayerAvatar name={player1Name} size={36} disableFullscreen />
|
||||
<Text size="xs" fw={600} ta="center" lineClamp={1}>
|
||||
{player1Name}
|
||||
</Text>
|
||||
@@ -110,7 +110,7 @@ const LeagueHeadToHead = () => {
|
||||
</>
|
||||
) : (
|
||||
<Stack gap={4} align="center">
|
||||
<Avatar size={36} />
|
||||
<PlayerAvatar size={36} disableFullscreen />
|
||||
<Text size="xs" c="dimmed" fw={500}>
|
||||
Player 1
|
||||
</Text>
|
||||
@@ -145,7 +145,7 @@ const LeagueHeadToHead = () => {
|
||||
{player2Id ? (
|
||||
<>
|
||||
<Stack gap={4} align="center" style={{ flex: 1 }}>
|
||||
<Avatar name={player2Name} size={36} />
|
||||
<PlayerAvatar name={player2Name} size={36} disableFullscreen />
|
||||
<Text size="xs" fw={600} ta="center" lineClamp={1}>
|
||||
{player2Name}
|
||||
</Text>
|
||||
@@ -166,7 +166,7 @@ const LeagueHeadToHead = () => {
|
||||
</>
|
||||
) : (
|
||||
<Stack gap={4} align="center">
|
||||
<Avatar size={36} />
|
||||
<PlayerAvatar size={36} disableFullscreen />
|
||||
<Text size="xs" c="dimmed" fw={500}>
|
||||
Player 2
|
||||
</Text>
|
||||
@@ -241,7 +241,7 @@ const LeagueHeadToHead = () => {
|
||||
},
|
||||
}}
|
||||
>
|
||||
<Avatar name={player.player_name} size={44} />
|
||||
<PlayerAvatar name={player.player_name} size={44} disableFullscreen />
|
||||
<Box style={{ flex: 1, minWidth: 0 }}>
|
||||
<Text size="sm" fw={600} truncate>
|
||||
{player.player_name}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { List, ListItem, Skeleton, Text } from "@mantine/core";
|
||||
import { useNavigate } from "@tanstack/react-router";
|
||||
import Avatar from "@/components/avatar";
|
||||
import PlayerAvatar from "@/components/player-avatar";
|
||||
import { Player } from "@/features/players/types";
|
||||
import { useCallback } from "react";
|
||||
|
||||
@@ -29,7 +29,7 @@ const PlayerList = ({ players, loading = false }: PlayerListProps) => {
|
||||
{players?.map((player) => (
|
||||
<ListItem key={player.id}
|
||||
py='xs'
|
||||
icon={<Avatar size={40} name={`${player.first_name} ${player.last_name}`} />}
|
||||
icon={<PlayerAvatar size={40} name={`${player.first_name} ${player.last_name}`} disableFullscreen />}
|
||||
style={{ cursor: 'pointer' }}
|
||||
onClick={() => handleClick(player.id)}
|
||||
>
|
||||
|
||||
@@ -22,7 +22,7 @@ import {
|
||||
InfoIcon,
|
||||
} from "@phosphor-icons/react";
|
||||
import { PlayerStats } from "../types";
|
||||
import Avatar from "@/components/avatar";
|
||||
import PlayerAvatar from "@/components/player-avatar";
|
||||
import { useNavigate } from "@tanstack/react-router";
|
||||
import { useAllPlayerStats } from "../queries";
|
||||
|
||||
@@ -93,7 +93,7 @@ const PlayerListItem = memo(({ stat, onPlayerClick, mmr, onRegisterViewport, onU
|
||||
}}
|
||||
>
|
||||
<Group p={0} gap="sm" align="center" w="100%" wrap="nowrap" style={{ overflow: 'hidden' }}>
|
||||
<Avatar name={stat.player_name} size={40} style={{ flexShrink: 0 }} />
|
||||
<PlayerAvatar name={stat.player_name} size={40} style={{ flexShrink: 0 }} disableFullscreen />
|
||||
<Stack gap={2} style={{ flexGrow: 1, overflow: 'hidden', minWidth: 0 }}>
|
||||
<Group gap='xs'>
|
||||
<Text size="sm" fw={600}>
|
||||
|
||||
@@ -4,7 +4,7 @@ import { Flex, Title, ActionIcon, Stack, Button, Box } from "@mantine/core";
|
||||
import { PencilIcon, FootballHelmetIcon } from "@phosphor-icons/react";
|
||||
import { useMemo } from "react";
|
||||
import NameUpdateForm from "./name-form";
|
||||
import Avatar from "@/components/avatar";
|
||||
import PlayerAvatar from "@/components/player-avatar";
|
||||
import { useSheet } from "@/hooks/use-sheet";
|
||||
import { Player } from "../../types";
|
||||
import PlayerHeadToHeadSheet from "../player-head-to-head-sheet";
|
||||
@@ -41,7 +41,7 @@ const Header = ({ player }: HeaderProps) => {
|
||||
<>
|
||||
<Stack gap="sm" align="center" pt="md">
|
||||
<Flex h="15dvh" px='xl' w='100%' align='self-end' gap='md'>
|
||||
<Avatar name={name} size={100} />
|
||||
<PlayerAvatar name={name} size={100} />
|
||||
<Flex align='center' justify='center' gap={4} pb={20} w='100%'>
|
||||
<Title ta='center' style={{ fontSize, lineHeight: 1.2 }}>{name}</Title>
|
||||
<ActionIcon display={owner ? 'block' : 'none'} radius='xl' variant='subtle' onClick={nameSheet.open}>
|
||||
|
||||
Reference in New Issue
Block a user