So now let's go ahead and let's create the participants component right here. So in order to do that we are going to need the avatar component from ShadCN. So let's head inside of our terminal here and let me open a new one and we're gonna go ahead and run npx chat-cnui at latest-add avatar and using this basic avatar component we're gonna create a new component called user avatar and then we're going to render them in this list of users in the corner. So let's go ahead and do the following. We're gonna go inside of app folder, dashboard, my apologies, board, board ID components and we're gonna create a new file user avatar.tsx.
And this one is gonna have a hint wrapped around it, which is our reusable hint component but it's also going to use this new components UI avatar which we've just added. So that is an avatar, avatar fallback and avatar image. And now let's create an interface user avatar props to accept a source image which will be an optional string, a name which is also going to be an optional string, a fallback and a border color. So all of these things are going to be optional strings here. And now let's go ahead and export const UserAvatar.
Let's just assign this props UserAvatar.props. Let's destructure them, source, name, fallback, and border color. And then inside of here, we're going to return a hint component with a label of name or teammate. So basically make it match whatever you did in the LiveKit live block out. Right in here, if we don't get the name, we write teammate.
So it makes sense that you also displayed teammate here. If for any reason, we just can't get the name of the user. The side of this tip is going to be on the bottom and the side offset is going to be 18. And now let's go ahead and render the actual avatar component. This avatar component will have a class name height 8, width 8 and border 2.
And for the border color, we're gonna use the style prop because Tailwind uses just in time compiler. So you cannot do dynamic classes in that way. So it's safer to do it using just border color to be border color, or you can use the shorthand operator. And then inside, we're gonna add an avatar image, pass in the source to be the source prop, and an avatar fallback. This one is going to render the fallback, whatever that is.
Well, it's a string, yeah. And a class name for the fallback is going to be text extra small and font semi-bold, like this. Great. So now we have our usable user avatar and we can now head back into the participants.csx right here and we can go ahead and mark this as use client. And let's just refresh our app to ensure that this doesn't break the app like our info component did.
Looks like our fix for the skeleton refactor worked. So now in here we're gonna go ahead and import user avatar from .slash user avatar and we're also going to import useOthers from LiveBlocksConfig and useSelf from LiveBlocksConfig. And then inside of the participants here, we can first get the other users by using useOthers hook, and then we can get const currentUser using useSelf, like this. And let's add a limit to how many users we are gonna show here. So const max shownUsers is gonna be, in my case, two users, like that.
And then let's do const has more users than the limit is going to be users.length is larger than max shown users. There we go. And we already have this ready, so let's remove this text list of users and instead let's add a div with a class name flex and gap x2. And then we can use users.slice and we are going to limit to the max shown users.map and in here we can destructure the connection ID and the info of that user. So let me just see if I can collapse this map like this maybe it's more visible that way and in here we are simply going to return a user avatar.
And let's go ahead and pass the key to be connection ID. Let's pass in the source to be info picture. Let's pass in the name to be info name. And let's pass in the fallback to be the first letter of the name. So info name like that, or we can add a like this.
Actually T as in teammates, right? Right now you should not be seeing anything except if you try and copy this localhost and go in another browser. So let me try doing that. I'm going to go in another browser that I have on the side here and I'm going to log in as the user that has access to this board here. Let me just try this out.
There we go. So now I am in a new account and you can see that, so make sure that you have another browser open and you have to be either in incognito mode or use just a completely different browser like Mozilla or something because you can't have two logged in sessions in the same browser or use like a different session like I do with my Chrome's. So there we go now I'm logged in this is not who I'm logged in as so this is not my user this is the user that is looking at this board at the same time that I am and now besides that we're gonna add ourselves as well. So in order to add ourselves, we're going to go ahead and add the following. So let's just indent this.
We're going to add, if we have the current user, we're gonna go ahead and render the user avatar. And we're gonna pass in the source to be currentUser.infoPicture. And we're gonna pass in the name to be openBackTicks currentUser.infoName. And in parentheses, we're gonna say that is you in case someone has the same name and image as you. And let's go ahead and write a fallback for this also to be currentUser.info.name and the first character like this and there we go.
Now you can see two users here. So one is me and one is the user in my another browser also logged in. Perfect. Now that we have this, let's go ahead and add a third combination, which is if we have more users. So it has more users, we wanna display another user avatar component, which is very simply gonna tell the user how many other users are inside.
So for that we're going to use name backticks users.length minus max shown users more like that so three users more so three more two more that's how it's gonna say and fallback is going to be plus users dot length minus max shown users and in order to see that now change this from 2 to 1 or maybe to 0 and there we go now you can see how it will say one more if you only want to display yourself and no one else So if you change it to one, then it will allow two users to be displayed. If you change it to two, it is gonna allow three users to be displayed. Perfect. So let me just try it out. I'm gonna go ahead and invite another user to this board.
And then we're gonna see three members inside. There we go. So I just joined with a third account and there we go. You can see now it displays three users. So if you don't want to display three users, you can change this to one and then you can see how it's going to look like.
It will only display two users. So I think we can maybe improve this because it kind of doesn't make sense. So how about we do this? I wanna display a maximum of three users. So that currently, or let's say I wanna display a maximum of two users.
Every additional user, I want them to be displayed as a number. So right now I have to put one for that. So it doesn't really make sense, right? So let's see how we can improve this. All right, so the reason this works like that is because I forgot so it actually it should be max shown other users because I forgot that ourselves we are not part of this users dot length so that's why this is confusing because I say okay only show one user but it's showing two users it's not it's only showing one user here but it's only showing the one from the use others hook because we exclude ourselves from that.
So yeah, you have to kind of mentally keep in mind, All right, if you say two users, that means it's only going to display these two users, which are not you, but you don't count in that. So if you want to display a maximum of three users, put the number two. If you want to display a maximum of two users, put the number one because you are the other user. Like that. So pick and choose the one you like.
I think two is just fine and that will allow you for more than three users they're gonna look with the plus number as you just saw it. Great. So one thing that's missing is the border color. So the way we're going to do border colors is we're going to use the user's connection ID to generate a unique color for them. So let's go inside of our lib utils right here.
And in here just go ahead and make an array of colors, as many as you want. So if you want, you can copy these ones from my source code. Just make sure they all look good with the font that's in them like this. So DC2626, D97706, 059669, 7C3AED and DB2777. So that's my choice of color.
So You can add as many as you want. The more you add, the more unique users are going to be. And now what we're going to do is we're simply going to export a function called connection id to color and that's going to accept a connection id which is a type of string, sorry, a type of number. And it's going to return back a string. And let's go ahead and do return from the array of our colors.
Simply do connection ID mod colors dot length. There we go. And now let's head back inside of our participants dot TSX right here. And we're going to do a very simple thing by adding the border color and using the new connection ID to color from our libutils like this So connection ID to color and simply pass in connection ID like this and let's copy this and let's add that to ourselves here and in here we're gonna pass current user connection ID and for the last one we don't need to pass anything. And let's try this out now.
So go into all the browsers that you are and refresh yourself and I think you can get like a new color every time. There we go. So now this one is brown, this one is purple and this one is yellow. And this is going to also match their cursor when they are when later we add matching cursors. Great!
So you successfully added the participants here. You can try it out by adding even more people into this world if you want to. And now what we're gonna do is we're gonna wrap up this toolbox here and then we're finally gonna start selecting the toolbox and rendering some drawings and elements on the canvas. Great great job.