import { cva } from "class-variance-authority"; import React, { useState } from "react"; import { Tooltip } from "@sparkle/components"; import { UserIcon } from "@sparkle/icons/app"; import { getEmojiAndBackgroundFromUrl } from "@sparkle/lib/avatar/utils"; import { cn } from "@sparkle/lib/utils"; export const AVATAR_SIZES = [ "xxs", "xs", "sm", "md", "lg", "xl", "2xl", "auto", ] as const; export type AvatarSizeType = (typeof AVATAR_SIZES)[number]; export const AVATAR_VARIANTS = ["default", "clickable", "disabled"] as const; export type AvatarVariantType = (typeof AVATAR_VARIANTS)[number]; const avatarVariants = cva( "s-flex s-flex-shrink-0 s-items-center s-justify-center s-overflow-hidden", { variants: { size: { xxs: "s-h-5 s-w-5", xs: "s-h-6 s-w-6", sm: "s-h-8 s-w-8", md: "s-h-10 s-w-10", lg: "s-h-16 s-w-16", xl: "s-h-20 s-w-20", "2xl": "s-h-36 s-w-36", auto: "s-w-full s-relative", }, variant: { default: "", clickable: "s-cursor-pointer hover:s-filter group-hover:s-filter group-hover:s-brightness-110 hover:s-brightness-110 group-active:s-brightness-90 active:s-brightness-90 s-transition s-duration-200 s-ease-out", disabled: "s-opacity-50", }, rounded: { true: "s-rounded-full s-ring-[1px] s-ring-border-dark/50 dark:s-ring-border-dark-night/50", false: "", }, }, compoundVariants: [ { rounded: false, size: "xxs", className: "s-rounded", }, { rounded: false, size: "xs", className: "s-rounded-md", }, { rounded: false, size: "sm", className: "s-rounded-lg", }, { rounded: false, size: "md", className: "s-rounded-xl", }, { rounded: false, size: "lg", className: "s-rounded-2xl", }, { rounded: false, size: "xl", className: "s-rounded-[22px]", }, { rounded: false, size: "2xl", className: "s-rounded-[32px]", }, { rounded: false, size: "auto", className: "s-rounded-[24%]", }, ], defaultVariants: { size: "md", variant: "default", rounded: false, }, } ); const textVariants = cva("s-select-none s-font-semibold", { variants: { size: { xxs: "s-text-[10px]", xs: "s-text-xs", sm: "s-text-sm", md: "s-text-base", lg: "s-text-3xl", xl: "s-text-5xl", "2xl": "s-text-7xl", auto: "s-text-xl", }, }, defaultVariants: { size: "md", }, }); const getColor = (name: string) => { if (/\+/.test(name)) { return "s-bg-primary-300"; } let hash = 0; for (let i = 0; i < name.length; i++) { hash = name.charCodeAt(i) + ((hash << 5) - hash); } const colors = [ "s-bg-blue-300", "s-bg-violet-300", "s-bg-pink-300", "s-bg-red-300", "s-bg-orange-300", "s-bg-golden-300", "s-bg-lime-300", "s-bg-emerald-300", ]; return colors[Math.abs(hash) % colors.length]; }; const getTextVariant = (name: string) => { if (/\+/.test(name)) { return "s-text-muted-foreground"; } let hash = 0; for (let i = 0; i < name.length; i++) { hash = name.charCodeAt(i) + ((hash << 5) - hash); } const txtColors = [ "s-text-blue-700", "s-text-violet-700", "s-text-pink-700", "s-text-red-700", "s-text-orange-700", "s-text-golden-700", "s-text-lime-700", "s-text-emerald-700", ]; return txtColors[Math.abs(hash) % txtColors.length]; }; interface AvatarProps { size?: AvatarSizeType; name?: string; emoji?: string; visual?: string | React.ReactNode; onClick?: () => void; clickable?: boolean; busy?: boolean; isRounded?: boolean; backgroundColor?: string; hexBgColor?: string; className?: string; disabled?: boolean; icon?: React.ComponentType<{ className?: string }>; iconColor?: string; } export function Avatar({ size, name, emoji, visual, onClick, clickable = false, busy = false, isRounded = false, backgroundColor, hexBgColor, disabled = false, className, icon, iconColor = "s-text-foreground", }: AvatarProps) { const normalizedVisual = visual === "" ? null : visual; const emojiInfos = typeof normalizedVisual === "string" && getEmojiAndBackgroundFromUrl(normalizedVisual); const backgroundColorToUse = emojiInfos ? emojiInfos.backgroundColor : backgroundColor; const emojiToUse = emojiInfos ? emojiInfos.skinEmoji : emoji; const visualToUse = emojiInfos ? null : normalizedVisual; const variant: AvatarVariantType = disabled ? "disabled" : (onClick || clickable) && !busy ? "clickable" : "default"; return (