From 2e11b1298e0fed9e8d391715decb99e0228726b1 Mon Sep 17 00:00:00 2001 From: hjlarry Date: Sat, 6 Sep 2025 11:19:47 +0800 Subject: [PATCH] add online users avatar --- web/app/components/base/avatar/index.tsx | 14 +++- .../workflow/header/online-users.tsx | 81 ++++++++++++------- 2 files changed, 65 insertions(+), 30 deletions(-) diff --git a/web/app/components/base/avatar/index.tsx b/web/app/components/base/avatar/index.tsx index 2a08f75f7b..85a024cbbf 100644 --- a/web/app/components/base/avatar/index.tsx +++ b/web/app/components/base/avatar/index.tsx @@ -8,6 +8,7 @@ export type AvatarProps = { size?: number className?: string textClassName?: string + backgroundColor?: string } const Avatar = ({ name, @@ -15,9 +16,18 @@ const Avatar = ({ size = 30, className, textClassName, + backgroundColor, }: AvatarProps) => { - const avatarClassName = 'shrink-0 flex items-center rounded-full bg-primary-600' - const style = { width: `${size}px`, height: `${size}px`, fontSize: `${size}px`, lineHeight: `${size}px` } + const avatarClassName = backgroundColor + ? 'shrink-0 flex items-center rounded-full' + : 'shrink-0 flex items-center rounded-full bg-primary-600' + const style = { + width: `${size}px`, + height: `${size}px`, + fontSize: `${size}px`, + lineHeight: `${size}px`, + ...(backgroundColor && !avatar ? { backgroundColor } : {}), + } const [imgError, setImgError] = useState(false) const handleError = () => { diff --git a/web/app/components/workflow/header/online-users.tsx b/web/app/components/workflow/header/online-users.tsx index 4d868cf57f..a48ae40934 100644 --- a/web/app/components/workflow/header/online-users.tsx +++ b/web/app/components/workflow/header/online-users.tsx @@ -3,6 +3,16 @@ import Avatar from '@/app/components/base/avatar' import { useCollaboration } from '../collaboration/hooks/use-collaboration' import { useStore } from '../store' import cn from '@/utils/classnames' +import { ChevronDown } from '@/app/components/base/icons/src/vender/solid/arrows' + +const getUserColor = (id: string) => { + const colors = ['#3B82F6', '#EF4444', '#10B981', '#F59E0B', '#8B5CF6', '#EC4899', '#06B6D4', '#84CC16'] + const hash = id.split('').reduce((a, b) => { + a = ((a << 5) - a) + b.charCodeAt(0) + return a & a + }, 0) + return colors[Math.abs(hash) % colors.length] +} const OnlineUsers = () => { const appId = useStore(s => s.appId) @@ -11,38 +21,53 @@ const OnlineUsers = () => { if (!onlineUsers || onlineUsers.length === 0) return null - // Show max 2 avatars directly, rest as count - const visibleUsers = onlineUsers.slice(0, 2) - const remainingCount = onlineUsers.length - 2 + // Display logic: + // 1-3 users: show all avatars + // 4+ users: show 2 avatars + count + arrow + const shouldShowCount = onlineUsers.length >= 4 + const maxVisible = shouldShowCount ? 2 : 3 + const visibleUsers = onlineUsers.slice(0, maxVisible) + const remainingCount = onlineUsers.length - maxVisible return ( -
- {visibleUsers.map((user, index) => ( -
- -
- ))} - {remainingCount > 0 && ( -
+
+
+ {visibleUsers.map((user, index) => { + const userColor = getUserColor(user.user_id) + return ( +
+ +
+ ) + })} + {remainingCount > 0 && ( +
+ +{remainingCount} +
)} - > - +{remainingCount}
- )} + {remainingCount > 0 && ( + + )} +
) }