Cleaning up comments
This commit is contained in:
@@ -5,24 +5,6 @@ import {
|
||||
HostListener
|
||||
} from '@angular/core';
|
||||
|
||||
/**
|
||||
* Reusable confirmation dialog modal.
|
||||
*
|
||||
* Usage:
|
||||
* ```html
|
||||
* @if (showConfirm()) {
|
||||
* <app-confirm-dialog
|
||||
* title="Delete Room?"
|
||||
* confirmLabel="Delete"
|
||||
* variant="danger"
|
||||
* (confirmed)="onDelete()"
|
||||
* (cancelled)="showConfirm.set(false)"
|
||||
* >
|
||||
* <p>This will permanently delete the room.</p>
|
||||
* </app-confirm-dialog>
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
@Component({
|
||||
selector: 'app-confirm-dialog',
|
||||
standalone: true,
|
||||
@@ -32,19 +14,12 @@ import {
|
||||
}
|
||||
})
|
||||
export class ConfirmDialogComponent {
|
||||
/** Dialog title. */
|
||||
title = input.required<string>();
|
||||
/** Label for the confirm button. */
|
||||
confirmLabel = input<string>('Confirm');
|
||||
/** Label for the cancel button. */
|
||||
cancelLabel = input<string>('Cancel');
|
||||
/** Visual style of the confirm button. */
|
||||
variant = input<'primary' | 'danger'>('primary');
|
||||
/** Tailwind width class for the dialog. */
|
||||
widthClass = input<string>('w-[320px]');
|
||||
/** Emitted when the user confirms. */
|
||||
confirmed = output<undefined>();
|
||||
/** Emitted when the user cancels (backdrop click, Cancel button, or Escape). */
|
||||
cancelled = output<undefined>();
|
||||
|
||||
@HostListener('document:keydown.escape')
|
||||
|
||||
@@ -10,30 +10,6 @@ import {
|
||||
OnInit
|
||||
} from '@angular/core';
|
||||
|
||||
/**
|
||||
* Generic positioned context-menu overlay with automatic viewport clamping.
|
||||
*
|
||||
* Usage:
|
||||
* ```html
|
||||
* @if (showMenu()) {
|
||||
* <app-context-menu [x]="menuX()" [y]="menuY()" (closed)="closeMenu()" [width]="'w-48'">
|
||||
* <button (click)="doSomething()" class="context-menu-item">Action</button>
|
||||
* </app-context-menu>
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* For pixel-based widths (e.g. sliders), use `[widthPx]` instead of `[width]`:
|
||||
* ```html
|
||||
* <app-context-menu [x]="menuX()" [y]="menuY()" [widthPx]="240" (closed)="closeMenu()">
|
||||
* ...custom content...
|
||||
* </app-context-menu>
|
||||
* ```
|
||||
*
|
||||
* Built-in item classes are available via the host styles:
|
||||
* - `.context-menu-item` - normal item
|
||||
* - `.context-menu-item-danger` - destructive (red) item
|
||||
* - `.context-menu-divider` - horizontal separator
|
||||
*/
|
||||
@Component({
|
||||
selector: 'app-context-menu',
|
||||
standalone: true,
|
||||
@@ -42,34 +18,25 @@ import {
|
||||
})
|
||||
/* eslint-disable @typescript-eslint/member-ordering */
|
||||
export class ContextMenuComponent implements OnInit, AfterViewInit {
|
||||
/** Horizontal position (px from left). */
|
||||
// eslint-disable-next-line id-length, id-denylist
|
||||
x = input.required<number>();
|
||||
/** Vertical position (px from top). */
|
||||
// eslint-disable-next-line id-length, id-denylist
|
||||
y = input.required<number>();
|
||||
/** Tailwind width class for the panel (default `w-48`). Ignored when `widthPx` is set. */
|
||||
width = input<string>('w-48');
|
||||
/** Optional fixed width in pixels (overrides `width`). Useful for custom content like sliders. */
|
||||
widthPx = input<number | null>(null);
|
||||
/** Emitted when the menu should close (backdrop click or Escape). */
|
||||
closed = output<undefined>();
|
||||
|
||||
@ViewChild('panel', { static: true }) panelRef!: ElementRef<HTMLDivElement>;
|
||||
|
||||
/** Viewport-clamped X position. */
|
||||
clampedX = signal(0);
|
||||
/** Viewport-clamped Y position. */
|
||||
clampedY = signal(0);
|
||||
|
||||
ngOnInit(): void {
|
||||
// Initial clamp with estimated dimensions
|
||||
this.clampedX.set(this.clampX(this.x(), this.estimateWidth()));
|
||||
this.clampedY.set(this.clampY(this.y(), 80));
|
||||
}
|
||||
|
||||
ngAfterViewInit(): void {
|
||||
// Refine with actual rendered dimensions
|
||||
const rect = this.panelRef.nativeElement.getBoundingClientRect();
|
||||
|
||||
this.clampedX.set(this.clampX(this.x(), rect.width));
|
||||
@@ -87,7 +54,6 @@ export class ContextMenuComponent implements OnInit, AfterViewInit {
|
||||
if (px)
|
||||
return px;
|
||||
|
||||
// Parse Tailwind w-XX class to approximate pixel width
|
||||
const match = this.width().match(/w-(\d+)/);
|
||||
|
||||
return match ? parseInt(match[1], 10) * 4 : 192;
|
||||
|
||||
@@ -13,7 +13,7 @@ import {
|
||||
Room,
|
||||
RoomMember,
|
||||
User
|
||||
} from '../../../core/models';
|
||||
} from '../../../core/models/index';
|
||||
|
||||
export interface LeaveServerDialogResult {
|
||||
nextOwnerKey?: string;
|
||||
|
||||
@@ -1,20 +1,6 @@
|
||||
import { NgOptimizedImage } from '@angular/common';
|
||||
import { Component, input } from '@angular/core';
|
||||
|
||||
/**
|
||||
* Reusable user avatar circle.
|
||||
*
|
||||
* Displays the user's image when `avatarUrl` is provided, otherwise
|
||||
* falls back to a colored circle with the first letter of `name`.
|
||||
*
|
||||
* Optional rings (e.g. voice-state colours) can be applied via `ringClass`.
|
||||
*
|
||||
* Usage:
|
||||
* ```html
|
||||
* <app-user-avatar [name]="user.displayName" [avatarUrl]="user.avatarUrl" size="md" />
|
||||
* <app-user-avatar [name]="user.displayName" size="sm" ringClass="ring-2 ring-green-500" />
|
||||
* ```
|
||||
*/
|
||||
@Component({
|
||||
selector: 'app-user-avatar',
|
||||
standalone: true,
|
||||
@@ -25,22 +11,16 @@ import { Component, input } from '@angular/core';
|
||||
}
|
||||
})
|
||||
export class UserAvatarComponent {
|
||||
/** Display name - first character is used as fallback initial. */
|
||||
name = input.required<string>();
|
||||
/** Optional avatar image URL. */
|
||||
avatarUrl = input<string | undefined | null>();
|
||||
/** Predefined size: `xs` (28px), `sm` (32px), `md` (40px), `lg` (48px). */
|
||||
size = input<'xs' | 'sm' | 'md' | 'lg'>('sm');
|
||||
/** Extra ring classes, e.g. `'ring-2 ring-green-500'`. */
|
||||
ringClass = input<string>('');
|
||||
|
||||
/** Compute the first-letter initial. */
|
||||
initial(): string {
|
||||
return this.name()?.charAt(0)
|
||||
?.toUpperCase() ?? '?';
|
||||
}
|
||||
|
||||
/** Map size token to Tailwind dimension classes. */
|
||||
sizeClasses(): string {
|
||||
switch (this.size()) {
|
||||
case 'xs': return 'w-7 h-7';
|
||||
@@ -50,7 +30,6 @@ export class UserAvatarComponent {
|
||||
}
|
||||
}
|
||||
|
||||
/** Map size token to explicit pixel dimensions for image optimisation. */
|
||||
sizePx(): number {
|
||||
switch (this.size()) {
|
||||
case 'xs': return 28;
|
||||
@@ -60,7 +39,6 @@ export class UserAvatarComponent {
|
||||
}
|
||||
}
|
||||
|
||||
/** Map size token to text size for initials. */
|
||||
textClass(): string {
|
||||
switch (this.size()) {
|
||||
case 'xs': return 'text-xs';
|
||||
|
||||
@@ -11,27 +11,6 @@ import { lucideVolume2, lucideVolumeX } from '@ng-icons/lucide';
|
||||
import { VoicePlaybackService } from '../../../features/voice/voice-controls/services/voice-playback.service';
|
||||
import { ContextMenuComponent } from '../context-menu/context-menu.component';
|
||||
|
||||
/**
|
||||
* Context-menu overlay that lets the local user adjust the playback
|
||||
* volume of a specific remote voice-channel participant (0%-200%)
|
||||
* and toggle per-user mute.
|
||||
*
|
||||
* Wraps `<app-context-menu>` for consistent positioning, backdrop,
|
||||
* escape handling and viewport clamping.
|
||||
*
|
||||
* Usage:
|
||||
* ```html
|
||||
* @if (showVolumeMenu()) {
|
||||
* <app-user-volume-menu
|
||||
* [x]="menuX()"
|
||||
* [y]="menuY()"
|
||||
* [peerId]="targetPeerId()"
|
||||
* [displayName]="targetName()"
|
||||
* (closed)="showVolumeMenu.set(false)"
|
||||
* />
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
@Component({
|
||||
selector: 'app-user-volume-menu',
|
||||
standalone: true,
|
||||
@@ -42,17 +21,12 @@ import { ContextMenuComponent } from '../context-menu/context-menu.component';
|
||||
})
|
||||
/* eslint-disable @typescript-eslint/member-ordering */
|
||||
export class UserVolumeMenuComponent implements OnInit {
|
||||
/** Horizontal position (px from left). */
|
||||
// eslint-disable-next-line id-length, id-denylist
|
||||
x = input.required<number>();
|
||||
/** Vertical position (px from top). */
|
||||
// eslint-disable-next-line id-length, id-denylist
|
||||
y = input.required<number>();
|
||||
/** Remote peer identifier (oderId). */
|
||||
peerId = input.required<string>();
|
||||
/** Display name shown in the header. */
|
||||
displayName = input.required<string>();
|
||||
/** Emitted when the menu should close. */
|
||||
closed = output<undefined>();
|
||||
|
||||
private playback = inject(VoicePlaybackService);
|
||||
|
||||
Reference in New Issue
Block a user