151 lines
4.5 KiB
TypeScript
151 lines
4.5 KiB
TypeScript
import { Stack, Group, Text, ThemeIcon } from "@mantine/core";
|
|
import { CrownIcon, MedalIcon } from "@phosphor-icons/react";
|
|
import { TeamInfo } from "@/features/teams/types";
|
|
import { Tournament } from "../types";
|
|
import { msg } from "@lingui/core/macro";
|
|
import { useLingui } from "@lingui/react/macro";
|
|
import type { MessageDescriptor } from "@lingui/core";
|
|
|
|
interface PodiumProps {
|
|
tournament: Tournament;
|
|
}
|
|
|
|
type PodiumTier = "first" | "second" | "third";
|
|
|
|
const tierStyles: Record<PodiumTier, React.CSSProperties> = {
|
|
first: {
|
|
background:
|
|
"light-dark(color-mix(in srgb, var(--mantine-color-yellow-4) 10%, var(--mantine-color-white)), color-mix(in srgb, var(--mantine-color-yellow-8) 16%, var(--mantine-color-dark-6)))",
|
|
border:
|
|
"1px solid light-dark(color-mix(in srgb, var(--mantine-color-yellow-6) 45%, var(--mantine-color-gray-3)), color-mix(in srgb, var(--mantine-color-yellow-6) 35%, var(--mantine-color-dark-4)))",
|
|
borderRadius: "var(--mantine-radius-md)",
|
|
boxShadow: "var(--mantine-shadow-md)",
|
|
},
|
|
second: {
|
|
background:
|
|
"light-dark(color-mix(in srgb, var(--mantine-color-gray-5) 10%, var(--mantine-color-white)), color-mix(in srgb, var(--mantine-color-gray-5) 10%, var(--mantine-color-dark-6)))",
|
|
border:
|
|
"1px solid light-dark(var(--mantine-color-gray-4), var(--mantine-color-dark-4))",
|
|
borderRadius: "var(--mantine-radius-md)",
|
|
boxShadow: "var(--mantine-shadow-xs)",
|
|
},
|
|
third: {
|
|
background:
|
|
"light-dark(color-mix(in srgb, var(--mantine-color-orange-5) 8%, var(--mantine-color-white)), color-mix(in srgb, var(--mantine-color-orange-9) 14%, var(--mantine-color-dark-6)))",
|
|
border:
|
|
"1px solid light-dark(color-mix(in srgb, var(--mantine-color-orange-6) 35%, var(--mantine-color-gray-3)), color-mix(in srgb, var(--mantine-color-orange-7) 30%, var(--mantine-color-dark-4)))",
|
|
borderRadius: "var(--mantine-radius-md)",
|
|
boxShadow: "var(--mantine-shadow-xs)",
|
|
},
|
|
};
|
|
|
|
const tierConfig: Record<
|
|
PodiumTier,
|
|
{
|
|
color: string;
|
|
label: MessageDescriptor;
|
|
labelColor: string;
|
|
icon: React.ReactNode;
|
|
iconSize: "xl" | "lg";
|
|
padding: "md" | "xs";
|
|
nameSize: "md" | "sm";
|
|
}
|
|
> = {
|
|
first: {
|
|
color: "yellow",
|
|
label: msg`Champions`,
|
|
labelColor:
|
|
"light-dark(var(--mantine-color-yellow-8), var(--mantine-color-yellow-4))",
|
|
icon: <CrownIcon size={24} />,
|
|
iconSize: "xl",
|
|
padding: "md",
|
|
nameSize: "md",
|
|
},
|
|
second: {
|
|
color: "gray",
|
|
label: msg`2nd place`,
|
|
labelColor:
|
|
"light-dark(var(--mantine-color-gray-6), var(--mantine-color-gray-4))",
|
|
icon: <MedalIcon size={20} />,
|
|
iconSize: "lg",
|
|
padding: "xs",
|
|
nameSize: "sm",
|
|
},
|
|
third: {
|
|
color: "orange",
|
|
label: msg`3rd place`,
|
|
labelColor:
|
|
"light-dark(var(--mantine-color-orange-8), var(--mantine-color-orange-4))",
|
|
icon: <MedalIcon size={18} />,
|
|
iconSize: "lg",
|
|
padding: "xs",
|
|
nameSize: "sm",
|
|
},
|
|
};
|
|
|
|
const PodiumRow = ({ team, tier }: { team: TeamInfo; tier: PodiumTier }) => {
|
|
const { t } = useLingui();
|
|
const config = tierConfig[tier];
|
|
|
|
return (
|
|
<Group gap="md" p={config.padding} style={tierStyles[tier]}>
|
|
<ThemeIcon
|
|
size={config.iconSize}
|
|
color={config.color}
|
|
variant="light"
|
|
radius="xl"
|
|
>
|
|
{config.icon}
|
|
</ThemeIcon>
|
|
<Stack gap={4} style={{ flex: 1 }}>
|
|
<Text size={config.nameSize} fw={tier === "first" ? 700 : 600}>
|
|
{team.name}
|
|
</Text>
|
|
<Group gap="xs">
|
|
{team.players?.map((player) => (
|
|
<Text
|
|
key={player.id}
|
|
size={tier === "first" ? "sm" : "xs"}
|
|
c="dimmed"
|
|
>
|
|
{player.first_name} {player.last_name}
|
|
</Text>
|
|
))}
|
|
</Group>
|
|
</Stack>
|
|
<Text
|
|
size="10px"
|
|
fw={700}
|
|
tt="uppercase"
|
|
style={{
|
|
letterSpacing: "0.08em",
|
|
alignSelf: "flex-start",
|
|
color: config.labelColor,
|
|
}}
|
|
mt={4}
|
|
mr={4}
|
|
>
|
|
{t(config.label)}
|
|
</Text>
|
|
</Group>
|
|
);
|
|
};
|
|
|
|
export const Podium = ({ tournament }: PodiumProps) => {
|
|
if (!tournament.first_place) return;
|
|
|
|
return (
|
|
<Stack gap="xs" px="md">
|
|
{tournament.first_place && (
|
|
<PodiumRow team={tournament.first_place} tier="first" />
|
|
)}
|
|
{tournament.second_place && (
|
|
<PodiumRow team={tournament.second_place} tier="second" />
|
|
)}
|
|
{tournament.third_place && (
|
|
<PodiumRow team={tournament.third_place} tier="third" />
|
|
)}
|
|
</Stack>
|
|
);
|
|
};
|