sendou.ink/app/components/UserLink.tsx
2026-08-05 18:16:24 +03:00

54 lines
1.4 KiB
TypeScript

import clsx from "clsx";
import type * as React from "react";
import { Link } from "react-router";
import type { Tables } from "~/db/tables";
import { userPage } from "~/utils/urls";
import { Avatar } from "./Avatar";
import styles from "./UserLink.module.css";
type UserLinkUser = Pick<
Tables["User"],
"username" | "discordId" | "discordAvatar"
> & {
customUrl?: Tables["User"]["customUrl"];
customAvatarUrl?: string | null;
};
type UnlinkedPlayer = { name: string | null } & {
[K in keyof UserLinkUser]: UserLinkUser[K] | null;
};
/** Link to a user's page showing their avatar and username. Accepts also result players without an account, rendering just their name. */
export function UserLink({
user,
size = "xxs",
direction = "horizontal",
className,
children,
}: {
user: UserLinkUser | UnlinkedPlayer;
size?: React.ComponentProps<typeof Avatar>["size"];
direction?: "horizontal" | "vertical";
className?: string;
/** Replaces the plain username text (avatar is always rendered) */
children?: React.ReactNode;
}) {
if (user.username === null) {
return <>{(user as UnlinkedPlayer).name}</>;
}
const linkedUser = user as UserLinkUser;
return (
<Link
to={userPage(linkedUser)}
className={clsx(styles.userLink, className, {
[styles.vertical]: direction === "vertical",
})}
>
<Avatar user={linkedUser} size={size} />
{children ?? linkedUser.username}
</Link>
);
}