ov-components: Add participant badges directive for enhanced participant panel functionality

master
Carlos Santos 2025-08-05 17:39:29 +02:00
parent 00fcb0b115
commit b1d0269211
5 changed files with 90 additions and 41 deletions

View File

@ -18,6 +18,11 @@
<span *ngIf="isLocalParticipant" class="local-indicator"> <span *ngIf="isLocalParticipant" class="local-indicator">
{{ 'PANEL.PARTICIPANTS.YOU' | translate }} {{ 'PANEL.PARTICIPANTS.YOU' | translate }}
</span> </span>
<!-- Participant badges -->
<div class="participant-badges">
<ng-container *ngTemplateOutlet="participantBadgeTemplate"></ng-container>
</div>
</div> </div>
<div class="participant-subtitle"> <div class="participant-subtitle">
@ -62,15 +67,5 @@
</div> </div>
</div> </div>
</div> </div>
<!-- Content after local participant (only for local participant) -->
<!-- <div
class="after-local-content"
*ngIf="hasAfterLocalContent"
role="region"
[attr.aria-label]="'Additional content for local participant'"
>
<ng-container *ngTemplateOutlet="afterLocalParticipantTemplate"></ng-container>
</div> -->
</mat-list-item> </mat-list-item>
</mat-list> </mat-list>

View File

@ -209,6 +209,30 @@
} }
} }
// Participant badges container
.participant-badges {
display: flex;
align-items: center;
gap: 6px;
flex-wrap: wrap;
// Badge styling
::ng-deep .badge {
// Badge variants
&.moderator {
color: var(--ov-warning-color, #f57c00);
}
&.speaker {
color: var(--ov-primary-color, #1976d2);
}
&.host {
color: var(--ov-success-color, #4caf50);
}
}
}
// After local participant content area // After local participant content area
.after-local-content { .after-local-content {
margin-top: 12px; margin-top: 12px;

View File

@ -1,7 +1,7 @@
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, ContentChild, Input, OnDestroy, OnInit, TemplateRef } from '@angular/core'; import { ChangeDetectionStrategy, ChangeDetectorRef, Component, ContentChild, Input, OnDestroy, OnInit, TemplateRef } from '@angular/core';
import { Subscription } from 'rxjs'; import { Subscription } from 'rxjs';
import { ParticipantPanelItemElementsDirective } from '../../../../directives/template/openvidu-components-angular.directive'; import { ParticipantPanelItemElementsDirective } from '../../../../directives/template/openvidu-components-angular.directive';
// import { ParticipantPanelAfterLocalParticipantDirective } from '../../../../directives/template/internals.directive'; import { ParticipantPanelParticipantBadgeDirective } from '../../../../directives/template/internals.directive';
import { ParticipantModel } from '../../../../models/participant.model'; import { ParticipantModel } from '../../../../models/participant.model';
import { OpenViduComponentsConfigService } from '../../../../services/config/directive-config.service'; import { OpenViduComponentsConfigService } from '../../../../services/config/directive-config.service';
import { ParticipantService } from '../../../../services/participant/participant.service'; import { ParticipantService } from '../../../../services/participant/participant.service';
@ -42,16 +42,16 @@ export class ParticipantPanelItemComponent implements OnInit, OnDestroy {
} }
} }
// /** /**
// * @ignore * @ignore
// */ */
// @ContentChild(ParticipantPanelAfterLocalParticipantDirective) @ContentChild(ParticipantPanelParticipantBadgeDirective)
// set externalAfterLocalParticipant(afterLocalParticipant: ParticipantPanelAfterLocalParticipantDirective) { set externalParticipantBadge(participantBadge: ParticipantPanelParticipantBadgeDirective) {
// this._externalAfterLocalParticipant = afterLocalParticipant; this._externalParticipantBadge = participantBadge;
// if (afterLocalParticipant) { if (participantBadge) {
// this.updateTemplatesAndMarkForCheck(); this.updateTemplatesAndMarkForCheck();
// } }
// } }
/** /**
* @internal * @internal
@ -61,7 +61,7 @@ export class ParticipantPanelItemComponent implements OnInit, OnDestroy {
// Store directive references for template setup // Store directive references for template setup
private _externalItemElements?: ParticipantPanelItemElementsDirective; private _externalItemElements?: ParticipantPanelItemElementsDirective;
// private _externalAfterLocalParticipant?: ParticipantPanelAfterLocalParticipantDirective; private _externalParticipantBadge?: ParticipantPanelParticipantBadgeDirective;
/** /**
* The participant to be displayed * The participant to be displayed
@ -119,11 +119,11 @@ export class ParticipantPanelItemComponent implements OnInit, OnDestroy {
} }
/** /**
* Gets the template for content after local participant * Gets the template for local participant badge
*/ */
// get afterLocalParticipantTemplate(): TemplateRef<any> | undefined { get participantBadgeTemplate(): TemplateRef<any> | undefined {
// return this._externalAfterLocalParticipant?.template; return this._externalParticipantBadge?.template;
// } }
/** /**
* Checks if the current participant is the local participant * Checks if the current participant is the local participant
@ -146,21 +146,12 @@ export class ParticipantPanelItemComponent implements OnInit, OnDestroy {
return !!this.participantPanelItemElementsTemplate; return !!this.participantPanelItemElementsTemplate;
} }
/**
* Checks if after local participant content is available
*/
// get hasAfterLocalContent(): boolean {
// return this.isLocalParticipant && !!this.afterLocalParticipantTemplate;
// }
/** /**
* @internal * @internal
* Sets up all templates using the template manager service * Sets up all templates using the template manager service
*/ */
private setupTemplates(): void { private setupTemplates(): void {
this.templateConfig = this.templateManagerService.setupParticipantPanelItemTemplates( this.templateConfig = this.templateManagerService.setupParticipantPanelItemTemplates(this._externalItemElements);
this._externalItemElements
);
// Apply templates to component properties for backward compatibility // Apply templates to component properties for backward compatibility
this.applyTemplateConfiguration(); this.applyTemplateConfiguration();

View File

@ -194,7 +194,6 @@ export class PreJoinDirective {
) {} ) {}
} }
/** /**
* The ***ovParticipantPanelAfterLocalParticipant** directive allows you to inject custom HTML or Angular templates * The ***ovParticipantPanelAfterLocalParticipant** directive allows you to inject custom HTML or Angular templates
* immediately after the local participant item in the participant panel. * immediately after the local participant item in the participant panel.
@ -249,4 +248,37 @@ export class LayoutAdditionalElementsDirective {
public template: TemplateRef<any>, public template: TemplateRef<any>,
public container: ViewContainerRef public container: ViewContainerRef
) {} ) {}
} }
/**
* The ***ovParticipantPanelParticipantBadge** directive allows you to inject custom badges or indicators
* in the participant panel.
* This enables you to add role indicators, status badges, or other visual elements.
*
* Usage example:
* ```html
* <ov-participants-panel>
* <div *ovParticipantPanelItem="let participant">
* <ov-participant-panel-item [participant]="participant">
* <!-- Custom badge for local participant only -->
* <ng-container *ovParticipantPanelParticipantBadge>
* <span class="moderator-badge">
* <mat-icon>admin_panel_settings</mat-icon>
* Moderator
* </span>
* </ng-container>
* </ov-participant-panel-item>
* </div>
* </ov-participants-panel>
* ```
*/
@Directive({
selector: '[ovParticipantPanelParticipantBadge]',
standalone: false
})
export class ParticipantPanelParticipantBadgeDirective {
constructor(
public template: TemplateRef<any>,
public container: ViewContainerRef
) {}
}

View File

@ -14,7 +14,12 @@ import {
ActivitiesPanelDirective, ActivitiesPanelDirective,
BackgroundEffectsPanelDirective BackgroundEffectsPanelDirective
} from './openvidu-components-angular.directive'; } from './openvidu-components-angular.directive';
import { LayoutAdditionalElementsDirective, ParticipantPanelAfterLocalParticipantDirective, PreJoinDirective } from './internals.directive'; import {
LayoutAdditionalElementsDirective,
ParticipantPanelAfterLocalParticipantDirective,
ParticipantPanelParticipantBadgeDirective,
PreJoinDirective
} from './internals.directive';
@NgModule({ @NgModule({
declarations: [ declarations: [
@ -32,7 +37,8 @@ import { LayoutAdditionalElementsDirective, ParticipantPanelAfterLocalParticipan
ActivitiesPanelDirective, ActivitiesPanelDirective,
PreJoinDirective, PreJoinDirective,
ParticipantPanelAfterLocalParticipantDirective, ParticipantPanelAfterLocalParticipantDirective,
LayoutAdditionalElementsDirective LayoutAdditionalElementsDirective,
ParticipantPanelParticipantBadgeDirective
// BackgroundEffectsPanelDirective // BackgroundEffectsPanelDirective
], ],
exports: [ exports: [
@ -50,7 +56,8 @@ import { LayoutAdditionalElementsDirective, ParticipantPanelAfterLocalParticipan
ActivitiesPanelDirective, ActivitiesPanelDirective,
PreJoinDirective, PreJoinDirective,
ParticipantPanelAfterLocalParticipantDirective, ParticipantPanelAfterLocalParticipantDirective,
LayoutAdditionalElementsDirective LayoutAdditionalElementsDirective,
ParticipantPanelParticipantBadgeDirective
// BackgroundEffectsPanelDirective // BackgroundEffectsPanelDirective
] ]
}) })