Docs
Realtime Avatar Stack

Realtime Avatar Stack

Avatar stack in realtime

Installation

Folder structure

  • components
  • hooks
  • lib
    • supabase
1import { cva, type VariantProps } from 'class-variance-authority'
2import * as React from 'react'
3
4import { cn } from '@/lib/utils'
5import { Avatar, AvatarFallback, AvatarImage } from '@/components/ui/avatar'
6import { Tooltip, TooltipContent, TooltipTrigger } from '@/components/ui/tooltip'
7
8const avatarStackVariants = cva('flex -space-x-4 -space-y-4', {
9  variants: {
10    orientation: {
11      vertical: 'flex-row',
12      horizontal: 'flex-col',
13    },
14  },
15  defaultVariants: {
16    orientation: 'vertical',
17  },
18})
19
20export interface AvatarStackProps
21  extends React.HTMLAttributes<HTMLDivElement>, VariantProps<typeof avatarStackVariants> {
22  avatars: { name: string; image: string }[]
23  maxAvatarsAmount?: number
24}
25
26const AvatarStack = ({
27  className,
28  orientation,
29  avatars,
30  maxAvatarsAmount = 3,
31  ...props
32}: AvatarStackProps) => {
33  const shownAvatars = avatars.slice(0, maxAvatarsAmount)
34  const hiddenAvatars = avatars.slice(maxAvatarsAmount)
35
36  return (
37    <div
38      className={cn(
39        avatarStackVariants({ orientation }),
40        className,
41        orientation === 'horizontal' ? 'space-x-0' : 'space-y-0'
42      )}
43      {...props}
44    >
45      {shownAvatars.map(({ name, image }, index) => (
46        <Tooltip key={`${name}-${image}-${index}`}>
47          <TooltipTrigger asChild>
48            <Avatar className="hover:z-10">
49              <AvatarImage src={image} />
50              <AvatarFallback>
51                {name
52                  ?.split(' ')
53                  ?.map((word) => word[0])
54                  ?.join('')
55                  ?.toUpperCase()}
56              </AvatarFallback>
57            </Avatar>
58          </TooltipTrigger>
59          <TooltipContent>
60            <p>{name}</p>
61          </TooltipContent>
62        </Tooltip>
63      ))}
64
65      {hiddenAvatars.length ? (
66        <Tooltip key="hidden-avatars">
67          <TooltipTrigger asChild>
68            <Avatar>
69              <AvatarFallback>+{avatars.length - shownAvatars.length}</AvatarFallback>
70            </Avatar>
71          </TooltipTrigger>
72          <TooltipContent>
73            {hiddenAvatars.map(({ name }, index) => (
74              <p key={`${name}-${index}`}>{name}</p>
75            ))}
76          </TooltipContent>
77        </Tooltip>
78      ) : null}
79    </div>
80  )
81}
82
83export { AvatarStack, avatarStackVariants }

Usage

The RealtimeAvatarStack component renders stacked avatars which are connected to Supabase Realtime. It uses the Presence feature of Supabase Realtime. You can use this to show currently online users in a chatroom, game session or collaborative app.

import { RealtimeAvatarStack } from '@/components/realtime-avatar-stack'
 
export default function Page() {
  return (
    <Header className="flex items-center justify-between">
      <h1>Lumon Industries</h1>
      <RealtimeAvatarStack roomName="break_room" />
    </Header>
  )
}

Props

PropTypeDefaultDescription
roomNamestringnullThe name of the Supabase Realtime room to connect to

Further reading