feat: add global auth settings and pending users

This commit is contained in:
2026-07-02 06:27:32 -07:00
parent f6b7924d0c
commit 4bb4312b08
24 changed files with 2831 additions and 23 deletions

View File

@@ -0,0 +1,63 @@
import { cn } from "@/lib/utils";
type UserAvatarProps = {
name: string;
avatarUrl?: string;
size?: "sm" | "md" | "lg";
className?: string;
};
const sizeClasses: Record<NonNullable<UserAvatarProps["size"]>, string> = {
sm: "size-9 text-xs",
md: "size-10 text-sm",
lg: "size-14 text-lg",
};
function getInitial(name: string): string {
const trimmedName = name.trim();
if (!trimmedName) {
return "用";
}
return trimmedName.slice(0, 1).toUpperCase();
}
function isSupportedAvatarUrl(avatarUrl: string | undefined): avatarUrl is string {
if (!avatarUrl) {
return false;
}
return avatarUrl.startsWith("https://") || avatarUrl.startsWith("http://") || avatarUrl.startsWith("data:image/");
}
export function UserAvatar({
name,
avatarUrl,
size = "md",
className,
}: UserAvatarProps): React.ReactElement {
const hasAvatar = isSupportedAvatarUrl(avatarUrl);
return (
<span
aria-label={`${name || "用户"}头像`}
className={cn(
"inline-flex shrink-0 items-center justify-center overflow-hidden rounded-md border bg-secondary font-semibold text-primary",
sizeClasses[size],
className,
)}
role="img"
style={
hasAvatar
? {
backgroundImage: `url(${avatarUrl})`,
backgroundPosition: "center",
backgroundSize: "cover",
}
: undefined
}
>
{hasAvatar ? <span className="sr-only">{name}</span> : getInitial(name)}
</span>
);
}