ov-components: add toolbar panel buttons component with event handling and styling

master
Carlos Santos 2025-09-19 11:56:10 +02:00
parent 41152de276
commit d223acefcf
7 changed files with 190 additions and 123 deletions

View File

@ -0,0 +1,55 @@
<!-- Default activities button -->
<button
mat-icon-button
id="activities-panel-btn"
class="panel-button"
*ngIf="!isMinimal && showActivitiesPanelButton"
matTooltip="{{ 'TOOLBAR.ACTIVITIES' | translate }}"
(click)="onToggleActivities()"
[disabled]="isConnectionLost"
[class.active-btn]="isActivitiesOpened"
>
<mat-icon>category</mat-icon>
</button>
<!-- Default participants button -->
<button
mat-icon-button
class="panel-button"
id="participants-panel-btn"
*ngIf="!isMinimal && showParticipantsPanelButton"
matTooltip="{{ 'TOOLBAR.PARTICIPANTS' | translate }}"
(click)="onToggleParticipants()"
[disabled]="isConnectionLost"
[class.active-btn]="isParticipantsOpened"
>
<mat-icon>people</mat-icon>
</button>
<!-- Default chat button -->
<button
mat-icon-button
class="panel-button"
id="chat-panel-btn"
*ngIf="!isMinimal && showChatPanelButton"
matTooltip="{{ 'TOOLBAR.CHAT' | translate }}"
(click)="onToggleChat()"
[disabled]="isConnectionLost"
[class.active-btn]="isChatOpened"
>
<mat-icon
matBadge="{{ unreadMessages }}"
[matBadgeHidden]="unreadMessages === 0"
matBadgePosition="above before"
matBadgeSize="small"
matBadgeColor="accent"
aria-hidden="false"
>
chat
</mat-icon>
</button>
<!-- External additional panel buttons -->
<ng-container *ngIf="toolbarAdditionalPanelButtonsTemplate">
<ng-container *ngTemplateOutlet="toolbarAdditionalPanelButtonsTemplate"></ng-container>
</ng-container>

View File

@ -0,0 +1,11 @@
:host {
.panel-button {
border-radius: var(--ov-toolbar-buttons-radius);
color: var(--ov-secondary-action-color);
}
.active-btn,
::ng-deep .active-btn {
background-color: var(--ov-accent-action-color) !important;
}
}

View File

@ -0,0 +1,43 @@
import { Component, EventEmitter, Input, Output, TemplateRef } from '@angular/core';
@Component({
selector: 'ov-toolbar-panel-buttons',
templateUrl: './toolbar-panel-buttons.component.html',
styleUrl: './toolbar-panel-buttons.component.scss',
standalone: false
})
export class ToolbarPanelButtonsComponent {
// Inputs from toolbar
@Input() isMinimal: boolean = false;
@Input() isConnectionLost: boolean = false;
@Input() isActivitiesOpened: boolean = false;
@Input() isParticipantsOpened: boolean = false;
@Input() isChatOpened: boolean = false;
@Input() unreadMessages: number = 0;
@Input() showActivitiesPanelButton: boolean = true;
@Input() showParticipantsPanelButton: boolean = true;
@Input() showChatPanelButton: boolean = true;
@Input() recordingStatus: any;
@Input() broadcastingStatus: any;
@Input() _recordingStatus: any;
@Input() _broadcastingStatus: any;
@Input() toolbarAdditionalPanelButtonsTemplate: TemplateRef<any> | undefined;
// Outputs back to toolbar
@Output() toggleActivitiesPanel: EventEmitter<string | undefined> = new EventEmitter();
@Output() toggleParticipantsPanel: EventEmitter<void> = new EventEmitter();
@Output() toggleChatPanel: EventEmitter<void> = new EventEmitter();
// Local methods that emit events
onToggleActivities(expand?: string) {
this.toggleActivitiesPanel.emit(expand);
}
onToggleParticipants() {
this.toggleParticipantsPanel.emit();
}
onToggleChat() {
this.toggleChatPanel.emit();
}
}

View File

@ -85,63 +85,26 @@
></ov-toolbar-media-buttons>
</div>
<!-- Panel buttons (chat, participants, activities) -->
<!-- Panel buttons -->
<div class="menu-buttons-container" id="menu-buttons-container">
<!-- Default activities button -->
<button
mat-icon-button
id="activities-panel-btn"
*ngIf="!isMinimal && showActivitiesPanelButton"
matTooltip="{{ 'TOOLBAR.ACTIVITIES' | translate }}"
(click)="toggleActivitiesPanel()"
[disabled]="isConnectionLost"
[ngClass]="{
'blinking-recording-button': !isActivitiesOpened && recordingStatus === _recordingStatus.STARTED,
'blinking-broadcasting-button': !isActivitiesOpened && broadcastingStatus === _broadcastingStatus.STARTED,
'active-btn': isActivitiesOpened
}"
>
<mat-icon>category</mat-icon>
</button>
<!-- Default participants button -->
<button
mat-icon-button
id="participants-panel-btn"
*ngIf="!isMinimal && showParticipantsPanelButton"
matTooltip="{{ 'TOOLBAR.PARTICIPANTS' | translate }}"
(click)="toggleParticipantsPanel()"
[disabled]="isConnectionLost"
[class.active-btn]="isParticipantsOpened"
>
<mat-icon>people</mat-icon>
</button>
<!-- Default chat button -->
<button
mat-icon-button
id="chat-panel-btn"
*ngIf="!isMinimal && showChatPanelButton"
matTooltip="{{ 'TOOLBAR.CHAT' | translate }}"
(click)="toggleChatPanel()"
[disabled]="isConnectionLost"
[class.active-btn]="isChatOpened"
>
<mat-icon
matBadge="{{ unreadMessages }}"
[matBadgeHidden]="unreadMessages === 0"
matBadgePosition="above before"
matBadgeSize="small"
matBadgeColor="accent"
aria-hidden="false"
>
chat
</mat-icon>
</button>
<!-- External additional panel buttons -->
<ng-container *ngIf="toolbarAdditionalPanelButtonsTemplate">
<ng-container *ngTemplateOutlet="toolbarAdditionalPanelButtonsTemplate"></ng-container>
</ng-container>
<ov-toolbar-panel-buttons
[isMinimal]="isMinimal"
[isConnectionLost]="isConnectionLost"
[isActivitiesOpened]="isActivitiesOpened"
[isParticipantsOpened]="isParticipantsOpened"
[isChatOpened]="isChatOpened"
[unreadMessages]="unreadMessages"
[showActivitiesPanelButton]="showActivitiesPanelButton"
[showParticipantsPanelButton]="showParticipantsPanelButton"
[showChatPanelButton]="showChatPanelButton"
[recordingStatus]="recordingStatus"
[broadcastingStatus]="broadcastingStatus"
[_recordingStatus]="_recordingStatus"
[_broadcastingStatus]="_broadcastingStatus"
[toolbarAdditionalPanelButtonsTemplate]="toolbarAdditionalPanelButtonsTemplate"
(toggleActivitiesPanel)="toggleActivitiesPanel($event)"
(toggleParticipantsPanel)="toggleParticipantsPanel()"
(toggleChatPanel)="toggleChatPanel()"
></ov-toolbar-panel-buttons>
</div>
</mat-toolbar>

View File

@ -54,11 +54,6 @@
max-height: 100% !important;
}
#menu-buttons-container button {
border-radius: var(--ov-toolbar-buttons-radius);
color: var(--ov-secondary-action-color);
}
#branding-logo {
background-color: var(--ov-primary-action-color);
border-radius: var(--ov-surface-radius);
@ -122,8 +117,6 @@
animation: blinker 1.5s linear infinite;
}
::ng-deep .mat-badge-content {
background-color: var(--ov-warn-color);
}

View File

@ -1,4 +1,3 @@
import { CommonModule } from '@angular/common';
import { NgModule } from '@angular/core';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
@ -12,6 +11,7 @@ import { SessionComponent } from './components/session/session.component';
import { StreamComponent } from './components/stream/stream.component';
import { ToolbarComponent } from './components/toolbar/toolbar.component';
import { ToolbarMediaButtonsComponent } from './components/toolbar/toolbar-media-buttons/toolbar-media-buttons.component';
import { ToolbarPanelButtonsComponent } from './components/toolbar/toolbar-panel-buttons/toolbar-panel-buttons.component';
import { MediaElementComponent } from './components/media-element/media-element.component';
import { LinkifyPipe } from './pipes/linkify.pipe';
@ -48,68 +48,69 @@ import { OpenViduComponentsDirectiveModule } from './directives/template/openvid
import { AppMaterialModule } from './openvidu-components-angular.material.module';
const publicComponents = [
AdminDashboardComponent,
AdminLoginComponent,
VideoconferenceComponent,
ToolbarComponent,
PanelComponent,
ActivitiesPanelComponent,
RecordingActivityComponent,
BroadcastingActivityComponent,
ParticipantsPanelComponent,
ParticipantPanelItemComponent,
ChatPanelComponent,
StreamComponent,
LayoutComponent
AdminDashboardComponent,
AdminLoginComponent,
VideoconferenceComponent,
ToolbarComponent,
PanelComponent,
ActivitiesPanelComponent,
RecordingActivityComponent,
BroadcastingActivityComponent,
ParticipantsPanelComponent,
ParticipantPanelItemComponent,
ChatPanelComponent,
StreamComponent,
LayoutComponent
];
const privateComponents = [
PreJoinComponent,
SessionComponent,
BackgroundEffectsPanelComponent,
SettingsPanelComponent,
AudioWaveComponent,
DialogTemplateComponent,
ProFeatureDialogTemplateComponent,
RecordingDialogComponent,
DeleteDialogComponent,
AvatarProfileComponent,
MediaElementComponent,
VideoDevicesComponent,
AudioDevicesComponent,
ParticipantNameInputComponent,
LangSelectorComponent,
ToolbarMediaButtonsComponent
PreJoinComponent,
SessionComponent,
BackgroundEffectsPanelComponent,
SettingsPanelComponent,
AudioWaveComponent,
DialogTemplateComponent,
ProFeatureDialogTemplateComponent,
RecordingDialogComponent,
DeleteDialogComponent,
AvatarProfileComponent,
MediaElementComponent,
VideoDevicesComponent,
AudioDevicesComponent,
ParticipantNameInputComponent,
LangSelectorComponent,
ToolbarMediaButtonsComponent,
ToolbarPanelButtonsComponent
];
@NgModule({
declarations: [
...publicComponents,
...privateComponents,
LinkifyPipe,
RemoteParticipantTracksPipe,
DurationFromSecondsPipe,
SearchByStringPropertyPipe,
ThumbnailFromUrlPipe,
TrackPublishedTypesPipe,
TranslatePipe
],
imports: [
CommonModule,
FormsModule,
ReactiveFormsModule,
AppMaterialModule,
OpenViduComponentsDirectiveModule,
ApiDirectiveModule,
DragDropModule
],
exports: [
...publicComponents,
RemoteParticipantTracksPipe,
DurationFromSecondsPipe,
TrackPublishedTypesPipe,
TranslatePipe,
OpenViduComponentsDirectiveModule,
ApiDirectiveModule
]
declarations: [
...publicComponents,
...privateComponents,
LinkifyPipe,
RemoteParticipantTracksPipe,
DurationFromSecondsPipe,
SearchByStringPropertyPipe,
ThumbnailFromUrlPipe,
TrackPublishedTypesPipe,
TranslatePipe
],
imports: [
CommonModule,
FormsModule,
ReactiveFormsModule,
AppMaterialModule,
OpenViduComponentsDirectiveModule,
ApiDirectiveModule,
DragDropModule
],
exports: [
...publicComponents,
RemoteParticipantTracksPipe,
DurationFromSecondsPipe,
TrackPublishedTypesPipe,
TranslatePipe,
OpenViduComponentsDirectiveModule,
ApiDirectiveModule
]
})
export class OpenViduComponentsUiModule {}

View File

@ -16,6 +16,7 @@ export * from './lib/components/panel/participants-panel/participants-panel/part
export * from './lib/components/stream/stream.component';
export * from './lib/components/toolbar/toolbar.component';
export * from './lib/components/toolbar/toolbar-media-buttons/toolbar-media-buttons.component';
export * from './lib/components/toolbar/toolbar-panel-buttons/toolbar-panel-buttons.component';
export * from './lib/components/videoconference/videoconference.component';
export * from './lib/config/openvidu-components-angular.config';
// Directives