feat: Add user statuses and cards
This commit is contained in:
@@ -164,7 +164,10 @@
|
||||
</button>
|
||||
<!-- Voice users connected to this channel -->
|
||||
@if (voiceUsersInRoom(ch.id).length > 0) {
|
||||
<div class="ml-5 mt-1 space-y-1 border-l border-border pb-1 pl-2">
|
||||
<div
|
||||
class="mt-1 space-y-1 border-l border-border pb-1 pl-2"
|
||||
style="margin-left: 0.91rem"
|
||||
>
|
||||
@for (u of voiceUsersInRoom(ch.id); track u.id) {
|
||||
<div
|
||||
class="flex items-center gap-2 rounded-md px-2 py-1.5 transition-colors hover:bg-secondary/50"
|
||||
@@ -241,15 +244,17 @@
|
||||
@if (currentUser()) {
|
||||
<div class="mb-4">
|
||||
<h4 class="text-xs uppercase tracking-wide text-muted-foreground font-medium mb-2 px-1">You</h4>
|
||||
<div class="flex items-center gap-2 rounded-md bg-secondary/60 px-3 py-2">
|
||||
<div class="relative">
|
||||
<app-user-avatar
|
||||
[name]="currentUser()?.displayName || '?'"
|
||||
[avatarUrl]="currentUser()?.avatarUrl"
|
||||
size="sm"
|
||||
/>
|
||||
<span class="absolute bottom-0 right-0 w-2.5 h-2.5 rounded-full bg-green-500 ring-2 ring-card"></span>
|
||||
</div>
|
||||
<div
|
||||
class="flex items-center gap-2 rounded-md bg-secondary/60 px-3 py-2 hover:bg-secondary/80 transition-colors cursor-pointer"
|
||||
(click)="openProfileCard($event, currentUser()!, true); $event.stopPropagation()"
|
||||
>
|
||||
<app-user-avatar
|
||||
[name]="currentUser()?.displayName || '?'"
|
||||
[avatarUrl]="currentUser()?.avatarUrl"
|
||||
size="sm"
|
||||
[status]="currentUser()?.status"
|
||||
[showStatusBadge]="true"
|
||||
/>
|
||||
<div class="flex-1 min-w-0">
|
||||
<p class="text-sm text-foreground truncate">{{ currentUser()?.displayName }}</p>
|
||||
<div class="flex items-center gap-2">
|
||||
@@ -287,17 +292,17 @@
|
||||
<div class="space-y-1">
|
||||
@for (user of onlineRoomUsers(); track user.id) {
|
||||
<div
|
||||
class="group/user flex items-center gap-2 rounded-md px-3 py-2 transition-colors hover:bg-secondary/50"
|
||||
class="group/user flex items-center gap-2 rounded-md px-3 py-2 transition-colors hover:bg-secondary/50 cursor-pointer"
|
||||
(contextmenu)="openUserContextMenu($event, user)"
|
||||
(click)="openProfileCard($event, user, false); $event.stopPropagation()"
|
||||
>
|
||||
<div class="relative">
|
||||
<app-user-avatar
|
||||
[name]="user.displayName"
|
||||
[avatarUrl]="user.avatarUrl"
|
||||
size="sm"
|
||||
/>
|
||||
<span class="absolute bottom-0 right-0 w-2.5 h-2.5 rounded-full bg-green-500 ring-2 ring-card"></span>
|
||||
</div>
|
||||
<app-user-avatar
|
||||
[name]="user.displayName"
|
||||
[avatarUrl]="user.avatarUrl"
|
||||
size="sm"
|
||||
[status]="user.status"
|
||||
[showStatusBadge]="true"
|
||||
/>
|
||||
<div class="flex-1 min-w-0">
|
||||
<div class="flex items-center gap-1.5">
|
||||
<p class="text-sm text-foreground truncate">{{ user.displayName }}</p>
|
||||
@@ -345,15 +350,17 @@
|
||||
<h4 class="text-xs uppercase tracking-wide text-muted-foreground font-medium mb-2 px-1">Offline - {{ offlineRoomMembers().length }}</h4>
|
||||
<div class="space-y-1">
|
||||
@for (member of offlineRoomMembers(); track member.oderId || member.id) {
|
||||
<div class="flex items-center gap-2 rounded-md px-3 py-2 opacity-80">
|
||||
<div class="relative">
|
||||
<app-user-avatar
|
||||
[name]="member.displayName"
|
||||
[avatarUrl]="member.avatarUrl"
|
||||
size="sm"
|
||||
/>
|
||||
<span class="absolute bottom-0 right-0 w-2.5 h-2.5 rounded-full bg-gray-500 ring-2 ring-card"></span>
|
||||
</div>
|
||||
<div
|
||||
class="flex items-center gap-2 rounded-md px-3 py-2 opacity-80 hover:bg-secondary/30 transition-colors cursor-pointer"
|
||||
(click)="openProfileCardForMember($event, member); $event.stopPropagation()"
|
||||
>
|
||||
<app-user-avatar
|
||||
[name]="member.displayName"
|
||||
[avatarUrl]="member.avatarUrl"
|
||||
size="sm"
|
||||
status="disconnected"
|
||||
[showStatusBadge]="true"
|
||||
/>
|
||||
<div class="flex-1 min-w-0">
|
||||
<div class="flex items-center gap-1.5">
|
||||
<p class="text-sm text-foreground/80 truncate">{{ member.displayName }}</p>
|
||||
|
||||
@@ -50,7 +50,8 @@ import {
|
||||
ContextMenuComponent,
|
||||
UserAvatarComponent,
|
||||
ConfirmDialogComponent,
|
||||
UserVolumeMenuComponent
|
||||
UserVolumeMenuComponent,
|
||||
ProfileCardService
|
||||
} from '../../../shared';
|
||||
import {
|
||||
Channel,
|
||||
@@ -101,6 +102,7 @@ export class RoomsSidePanelComponent {
|
||||
private voiceSessionService = inject(VoiceSessionFacade);
|
||||
private voiceWorkspace = inject(VoiceWorkspaceService);
|
||||
private voicePlayback = inject(VoicePlaybackService);
|
||||
private profileCard = inject(ProfileCardService);
|
||||
voiceActivity = inject(VoiceActivityService);
|
||||
|
||||
readonly panelMode = input<PanelMode>('channels');
|
||||
@@ -184,6 +186,28 @@ export class RoomsSidePanelComponent {
|
||||
draggedVoiceUserId = signal<string | null>(null);
|
||||
dragTargetVoiceChannelId = signal<string | null>(null);
|
||||
|
||||
openProfileCard(event: MouseEvent, user: User, editable: boolean): void {
|
||||
event.stopPropagation();
|
||||
const el = event.currentTarget as HTMLElement;
|
||||
|
||||
this.profileCard.open(el, user, { placement: 'left', editable });
|
||||
}
|
||||
|
||||
openProfileCardForMember(event: MouseEvent, member: RoomMember): void {
|
||||
const user: User = {
|
||||
id: member.id,
|
||||
oderId: member.oderId || member.id,
|
||||
username: member.username,
|
||||
displayName: member.displayName,
|
||||
avatarUrl: member.avatarUrl,
|
||||
status: 'disconnected',
|
||||
role: member.role,
|
||||
joinedAt: member.joinedAt
|
||||
};
|
||||
|
||||
this.openProfileCard(event, user, false);
|
||||
}
|
||||
|
||||
private roomMemberKey(member: RoomMember): string {
|
||||
return member.oderId || member.id;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user