Skip to content

Commit cf2ec2e

Browse files
authored
Improve users avatars (#24)
* chore: initial commit * chore: fix lint issues
1 parent b27465b commit cf2ec2e

File tree

7 files changed

+155
-24
lines changed

7 files changed

+155
-24
lines changed
Lines changed: 118 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,135 @@
11
"use client";
22

33
import React from "react";
4-
import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar"
4+
import Avatar from "boring-avatars";
5+
import { Avatar as AvatarUI, AvatarFallback } from "@/components/ui/avatar";
56
import { WeaveConnectedUsersChanged } from "@inditextech/weavejs-sdk";
7+
import {
8+
Tooltip,
9+
TooltipContent,
10+
TooltipProvider,
11+
TooltipTrigger,
12+
} from "@/components/ui/tooltip";
13+
import { useCollaborationRoom } from "@/store/store";
14+
import { Users } from "lucide-react";
15+
import {
16+
DropdownMenu,
17+
DropdownMenuContent,
18+
DropdownMenuItem,
19+
DropdownMenuTrigger,
20+
} from "@/components/ui/dropdown-menu";
621

722
type ConnectionStatusProps = {
823
connectedUsers: WeaveConnectedUsersChanged;
924
};
1025

11-
export const ConnectedUsers = ({ connectedUsers }: Readonly<ConnectionStatusProps>) => {
26+
export const ConnectedUsers = ({
27+
connectedUsers,
28+
}: Readonly<ConnectionStatusProps>) => {
29+
const user = useCollaborationRoom((state) => state.user);
30+
31+
const connectedUserKey = React.useMemo(() => {
32+
const filterOwnUser = Object.keys(connectedUsers).filter(
33+
(actUser) => actUser === user?.name
34+
);
35+
return filterOwnUser?.[0];
36+
}, [user, connectedUsers]);
37+
38+
const { showUsers, restUsers } = React.useMemo(() => {
39+
const filterOwnUser = Object.keys(connectedUsers).filter(
40+
(actUser) => actUser !== user?.name
41+
);
42+
return {
43+
showUsers: filterOwnUser.slice(0, 6),
44+
restUsers: filterOwnUser.slice(6),
45+
};
46+
}, [user, connectedUsers]);
47+
1248
if (Object.keys(connectedUsers).length === 0) {
1349
return null;
1450
}
1551

1652
return (
17-
<div className="pointer-events-none flex gap-5 justify-start items-center">
18-
{Object.keys(connectedUsers).map((user) => {
19-
const userInfo = connectedUsers[user];
20-
return (
21-
<Avatar key={user} className="w-[32px] h-[32px]">
22-
<AvatarImage src="https://github.com/shadcn.png" />
23-
<AvatarFallback>{userInfo.name.slice(0, 2)}</AvatarFallback>
24-
</Avatar>
25-
);
26-
})}
53+
<div className="w-full min-h-[40px] flex gap-1 justify-start items-center">
54+
<TooltipProvider delayDuration={300}>
55+
{connectedUserKey && (
56+
<Tooltip>
57+
<TooltipTrigger asChild>
58+
<button className="cursor-pointer">
59+
<AvatarUI className="w-[32px] h-[32px]">
60+
<AvatarFallback>
61+
<Avatar name={user?.name} variant="beam" />
62+
</AvatarFallback>
63+
</AvatarUI>
64+
</button>
65+
</TooltipTrigger>
66+
<TooltipContent side="bottom">
67+
<p className="font-noto-sans-mono text-sm">{user?.name}</p>
68+
</TooltipContent>
69+
</Tooltip>
70+
)}
71+
{/* <div className="w-[1px] h-[20px] bg-zinc-200"></div> */}
72+
{showUsers.map((user) => {
73+
const userInfo = connectedUsers[user];
74+
return (
75+
<Tooltip key={user}>
76+
<TooltipTrigger asChild>
77+
<button className="cursor-pointer">
78+
<AvatarUI className="w-[32px] h-[32px]">
79+
<AvatarFallback>
80+
<Avatar name={userInfo?.name} variant="beam" />
81+
</AvatarFallback>
82+
</AvatarUI>
83+
</button>
84+
</TooltipTrigger>
85+
<TooltipContent side="bottom">
86+
<p className="font-noto-sans-mono text-sm">{userInfo.name}</p>
87+
</TooltipContent>
88+
</Tooltip>
89+
);
90+
})}
91+
{restUsers.length > 0 && (
92+
<>
93+
<div className="w-[1px] mx-1 h-[20px] bg-zinc-200"></div>
94+
<Tooltip>
95+
<TooltipTrigger asChild>
96+
<DropdownMenu>
97+
<DropdownMenuTrigger className="rounded-none cursor-pointer p-2 hover:bg-zinc-200 focus:outline-none">
98+
<Users className="rounded-none" />
99+
</DropdownMenuTrigger>
100+
<DropdownMenuContent
101+
align="end"
102+
side="bottom"
103+
alignOffset={-6}
104+
sideOffset={8}
105+
className="font-noto-sans-mono rounded-none"
106+
>
107+
{restUsers.map((user) => {
108+
const userInfo = connectedUsers[user];
109+
return (
110+
<DropdownMenuItem
111+
key={user}
112+
className="text-foreground focus:bg-white hover:rounded-none"
113+
>
114+
<AvatarUI className="w-[32px] h-[32px]">
115+
<AvatarFallback>
116+
<Avatar name={userInfo?.name} variant="beam" />
117+
</AvatarFallback>
118+
</AvatarUI>
119+
{userInfo?.name}
120+
</DropdownMenuItem>
121+
);
122+
})}
123+
</DropdownMenuContent>
124+
</DropdownMenu>
125+
</TooltipTrigger>
126+
<TooltipContent side="bottom">
127+
<p className="font-noto-sans-mono text-sm">More users</p>
128+
</TooltipContent>
129+
</Tooltip>
130+
</>
131+
)}
132+
</TooltipProvider>
27133
</div>
28134
);
29135
};

code/components/room-components/overlay/multiuse-overlay.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ export function MultiuseOverlay() {
6565
return (
6666
<div
6767
className={
68-
"pointer-events-none absolute top-[calc(50px+8px+4px)] right-2 bottom-[calc(50px+8px+4px)] flex flex-col gap-5 justify-center items-center"
68+
"pointer-events-none absolute top-[calc(99px+12px)] right-2 bottom-[calc(50px+8px+4px)] flex flex-col gap-5 justify-center items-center"
6969
}
7070
>
7171
<div className="w-[320px] p-0 h-full bg-white border border-light-border-3 shadow-xs flex justify-start items-center gap-3 overflow-hidden">

code/components/room-components/overlay/room-information-overlay.tsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,13 @@ import {
1515
import { Logo } from "@/components/utils/logo";
1616
import { Image as ImageIcon, FileText, Ellipsis, LogOut } from "lucide-react";
1717
import { WeaveExportStageActionParams } from "@inditextech/weavejs-sdk";
18+
import { ConnectionStatus } from "../connection-status";
1819

1920
export function RoomInformationOverlay() {
2021
const router = useRouter();
2122

2223
const instance = useWeave((state) => state.instance);
24+
const weaveConnectionStatus = useWeave((state) => state.connection.status);
2325

2426
const room = useCollaborationRoom((state) => state.room);
2527

@@ -54,6 +56,7 @@ export function RoomInformationOverlay() {
5456
<div className="p-1 pl-3 bg-white border border-zinc-200 shadow-xs flex justify-start items-center gap-2">
5557
<Logo kind="small" />
5658
<div className="w-[1px] h-4 mx-2 bg-zinc-200"></div>
59+
<ConnectionStatus weaveConnectionStatus={weaveConnectionStatus} />
5760
<div className="flex justify-start items-center font-noto-sans-mono text-foreground !normal-case min-h-[32px] pr-2">
5861
{room}
5962
</div>

code/components/room-components/overlay/room-status-overlay.tsx

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,19 +2,22 @@
22

33
import React from "react";
44
import { ConnectedUsers } from "./../connected-users";
5-
import { ConnectionStatus } from "./../connection-status";
65
import { useWeave } from "@inditextech/weavejs-react";
76

87
export function RoomStatusOverlay() {
9-
const weaveConnectionStatus = useWeave((state) => state.connection.status);
108
const connectedUsers = useWeave((state) => state.users);
119

1210
return (
1311
<div className="absolute top-2 right-2 flex flex-col gap-1 justify-center items-center">
14-
<div className="w-[320px] p-2 bg-white border border-zinc-200 shadow-xs flex flex-col justify-start items-center">
15-
<div className="w-full flex justify-between items-center gap-4">
12+
<div className="w-[320px] min-h-[50px] p-2 bg-white border border-zinc-200 shadow-xs flex flex-col justify-start items-center">
13+
<div className="w-full min-h-[40px] h-full flex flex-col justify-between items-center gap-2">
1614
<ConnectedUsers connectedUsers={connectedUsers} />
17-
<ConnectionStatus weaveConnectionStatus={weaveConnectionStatus} />
15+
<div className="w-full flex justify-center gap-2 items-center text-center font-noto-sans-mono text-xs border-t border-zinc-200 pt-1">
16+
<div className="px-2 mt-1 py-1 bg-accent">
17+
{Object.keys(connectedUsers).length}
18+
</div>
19+
<div>user(s) connected</div>
20+
</div>
1821
</div>
1922
</div>
2023
</div>

code/components/room-components/toolbar/toolbar-button.tsx

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,12 @@
22

33
import React from "react";
44
import { cn } from "@/lib/utils";
5-
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "../../ui/tooltip";
5+
import {
6+
Tooltip,
7+
TooltipContent,
8+
TooltipProvider,
9+
TooltipTrigger,
10+
} from "@/components/ui/tooltip";
611

712
type ToolbarButtonProps = {
813
icon: React.ReactNode;
@@ -13,18 +18,25 @@ type ToolbarButtonProps = {
1318
tooltipSide?: "top" | "bottom" | "left" | "right";
1419
};
1520

16-
export function ToolbarButton({ icon, label = "tool", onClick, disabled = false, active = false, tooltipSide = "right" }: Readonly<ToolbarButtonProps>) {
21+
export function ToolbarButton({
22+
icon,
23+
label = "tool",
24+
onClick,
25+
disabled = false,
26+
active = false,
27+
tooltipSide = "right",
28+
}: Readonly<ToolbarButtonProps>) {
1729
return (
1830
<TooltipProvider delayDuration={300}>
1931
<Tooltip>
2032
<TooltipTrigger asChild>
21-
<button
33+
<button
2234
className={cn(
2335
"pointer-events-auto cursor-pointer hover:bg-zinc-200 px-2 py-2 flex justify-center items-center",
2436
{
2537
["bg-zinc-200"]: active,
2638
["pointer-events-none cursor-default opacity-50"]: disabled,
27-
},
39+
}
2840
)}
2941
disabled={disabled}
3042
onClick={onClick}
@@ -37,5 +49,5 @@ export function ToolbarButton({ icon, label = "tool", onClick, disabled = false,
3749
</TooltipContent>
3850
</Tooltip>
3951
</TooltipProvider>
40-
)
41-
};
52+
);
53+
}

code/package-lock.json

Lines changed: 6 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

code/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@
4141
"@radix-ui/react-slot": "^1.1.2",
4242
"@radix-ui/react-tooltip": "^1.1.8",
4343
"@tanstack/react-query": "^5.67.1",
44+
"boring-avatars": "^1.11.2",
4445
"canvas": "^3.1.0",
4546
"class-variance-authority": "^0.7.1",
4647
"clsx": "^2.1.1",

0 commit comments

Comments
 (0)