feat: Add pm
This commit is contained in:
@@ -172,6 +172,7 @@
|
||||
|
||||
<textarea
|
||||
#messageInputRef
|
||||
[attr.data-testid]="textareaTestId()"
|
||||
rows="1"
|
||||
[(ngModel)]="messageContent"
|
||||
(focus)="onInputFocus()"
|
||||
|
||||
@@ -69,6 +69,7 @@ export class ChatMessageComposerComponent implements AfterViewInit, OnDestroy {
|
||||
readonly showKlipyGifPicker = input(false);
|
||||
readonly klipyEnabled = input(false);
|
||||
readonly klipySignalSource = input<RoomSignalSourceInput | null>(null);
|
||||
readonly textareaTestId = input<string | null>(null);
|
||||
|
||||
readonly messageSubmitted = output<ChatMessageComposerSubmitEvent>();
|
||||
readonly typingStarted = output();
|
||||
|
||||
@@ -66,6 +66,7 @@ export class ChatMessageListComponent implements AfterViewChecked, OnDestroy {
|
||||
readonly isAdmin = input(false);
|
||||
readonly bottomPadding = input(120);
|
||||
readonly conversationKey = input.required<string>();
|
||||
readonly userLookupOverrides = input<User[]>([]);
|
||||
|
||||
readonly replyRequested = output<ChatMessageReplyEvent>();
|
||||
readonly deleteRequested = output<ChatMessageDeleteEvent>();
|
||||
@@ -126,6 +127,14 @@ export class ChatMessageListComponent implements AfterViewChecked, OnDestroy {
|
||||
}
|
||||
}
|
||||
|
||||
for (const user of this.userLookupOverrides()) {
|
||||
lookup.set(user.id, user);
|
||||
|
||||
if (user.oderId && user.oderId !== user.id) {
|
||||
lookup.set(user.oderId, user);
|
||||
}
|
||||
}
|
||||
|
||||
return lookup;
|
||||
});
|
||||
|
||||
|
||||
@@ -19,11 +19,10 @@
|
||||
@for (user of onlineUsers(); track user.id) {
|
||||
<div
|
||||
class="group relative flex items-center gap-3 p-2 rounded-lg hover:bg-secondary/50 transition-colors cursor-pointer"
|
||||
(click)="toggleUserMenu(user.id)"
|
||||
(keydown.enter)="toggleUserMenu(user.id)"
|
||||
(keydown.space)="toggleUserMenu(user.id)"
|
||||
(keyup.enter)="toggleUserMenu(user.id)"
|
||||
(keyup.space)="toggleUserMenu(user.id)"
|
||||
[attr.data-testid]="'user-card-' + (user.oderId || user.id)"
|
||||
(click)="openDirectMessage(user)"
|
||||
(keydown.enter)="openDirectMessage(user)"
|
||||
(keydown.space)="openDirectMessage(user)"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
>
|
||||
@@ -70,6 +69,19 @@
|
||||
|
||||
<!-- Voice/Screen Status -->
|
||||
<div class="flex items-center gap-1">
|
||||
<button
|
||||
type="button"
|
||||
class="grid h-7 w-7 place-items-center rounded-md text-muted-foreground transition-colors hover:bg-card hover:text-foreground"
|
||||
[class.hidden]="isCurrentUser(user)"
|
||||
title="Message"
|
||||
(click)="$event.stopPropagation(); openDirectMessage(user)"
|
||||
>
|
||||
<ng-icon
|
||||
name="lucideMessageCircle"
|
||||
class="w-4 h-4"
|
||||
/>
|
||||
</button>
|
||||
|
||||
@if (user.voiceState?.isSpeaking) {
|
||||
<ng-icon
|
||||
name="lucideMic"
|
||||
|
||||
@@ -8,6 +8,7 @@ import {
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { FormsModule } from '@angular/forms';
|
||||
import { Store } from '@ngrx/store';
|
||||
import { Router } from '@angular/router';
|
||||
import { NgIcon, provideIcons } from '@ng-icons/core';
|
||||
import {
|
||||
lucideMic,
|
||||
@@ -19,7 +20,8 @@ import {
|
||||
lucideBan,
|
||||
lucideUserX,
|
||||
lucideVolume2,
|
||||
lucideVolumeX
|
||||
lucideVolumeX,
|
||||
lucideMessageCircle
|
||||
} from '@ng-icons/lucide';
|
||||
|
||||
import { UsersActions } from '../../../../store/users/users.actions';
|
||||
@@ -30,6 +32,7 @@ import {
|
||||
} from '../../../../store/users/users.selectors';
|
||||
import { User } from '../../../../shared-kernel';
|
||||
import { UserAvatarComponent, ConfirmDialogComponent } from '../../../../shared';
|
||||
import { DirectMessageService } from '../../../direct-message';
|
||||
|
||||
@Component({
|
||||
selector: 'app-user-list',
|
||||
@@ -52,7 +55,8 @@ import { UserAvatarComponent, ConfirmDialogComponent } from '../../../../shared'
|
||||
lucideBan,
|
||||
lucideUserX,
|
||||
lucideVolume2,
|
||||
lucideVolumeX
|
||||
lucideVolumeX,
|
||||
lucideMessageCircle
|
||||
})
|
||||
],
|
||||
templateUrl: './user-list.component.html'
|
||||
@@ -62,6 +66,8 @@ import { UserAvatarComponent, ConfirmDialogComponent } from '../../../../shared'
|
||||
*/
|
||||
export class UserListComponent {
|
||||
private store = inject(Store);
|
||||
private router = inject(Router);
|
||||
private directMessages = inject(DirectMessageService);
|
||||
|
||||
onlineUsers = this.store.selectSignal(selectOnlineUsers) as import('@angular/core').Signal<User[]>;
|
||||
voiceUsers = computed(() => this.onlineUsers().filter((user: User) => !!user.voiceState?.isConnected));
|
||||
@@ -84,6 +90,16 @@ export class UserListComponent {
|
||||
return user.id === this.currentUser()?.id;
|
||||
}
|
||||
|
||||
async openDirectMessage(user: User): Promise<void> {
|
||||
if (this.isCurrentUser(user)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const conversation = await this.directMessages.createConversation(user);
|
||||
|
||||
await this.router.navigate(['/dm', conversation.id]);
|
||||
}
|
||||
|
||||
/** Toggle server-side mute on a user (admin action). */
|
||||
muteUser(user: User): void {
|
||||
if (user.voiceState?.isMutedByAdmin) {
|
||||
|
||||
@@ -1,8 +1,23 @@
|
||||
export * from './application/services/klipy.service';
|
||||
export * from './application/services/link-metadata.service';
|
||||
export * from './domain/rules/link-embed.rules';
|
||||
export * from './domain/rules/message.rules';
|
||||
export * from './domain/rules/message-sync.rules';
|
||||
export { ChatMarkdownService } from './feature/chat-messages/services/chat-markdown.service';
|
||||
export { ChatMessagesComponent } from './feature/chat-messages/chat-messages.component';
|
||||
export type { ChatMessageEmbedRemoveEvent } from './feature/chat-messages/models/chat-messages.model';
|
||||
export type {
|
||||
ChatMessageComposerSubmitEvent,
|
||||
ChatMessageDeleteEvent,
|
||||
ChatMessageEditEvent,
|
||||
ChatMessageImageContextMenuEvent,
|
||||
ChatMessageReactionEvent,
|
||||
ChatMessageReplyEvent
|
||||
} from './feature/chat-messages/models/chat-messages.model';
|
||||
export { ChatMessageComposerComponent } from './feature/chat-messages/components/message-composer/chat-message-composer.component';
|
||||
export { ChatMessageListComponent } from './feature/chat-messages/components/message-list/chat-message-list.component';
|
||||
export { ChatMessageOverlaysComponent } from './feature/chat-messages/components/message-overlays/chat-message-overlays.component';
|
||||
export { TypingIndicatorComponent } from './feature/typing-indicator/typing-indicator.component';
|
||||
export { KlipyGifPickerComponent } from './feature/klipy-gif-picker/klipy-gif-picker.component';
|
||||
export { ChatMessageMarkdownComponent } from './feature/chat-messages/components/message-item/chat-message-markdown/chat-message-markdown.component';
|
||||
export { UserListComponent } from './feature/user-list/user-list.component';
|
||||
|
||||
Reference in New Issue
Block a user