ov-components: enhance toolbar panel buttons with responsive design

master
Carlos Santos 2025-09-19 14:50:14 +02:00
parent d223acefcf
commit 6da901e7bb
5 changed files with 282 additions and 52 deletions

View File

@ -96,7 +96,7 @@ export class ToolbarMediaButtonsComponent {
// More options button - always visible when not minimal
readonly showMoreOptionsButtonDirect = computed(() => this.showMoreOptionsButton && !this.isMinimal);
// Leave button - always visible
// Leave button
readonly showLeaveButtonDirect = computed(() => this.showLeaveButton);
// Check if there are active features that should show a badge on More Options

View File

@ -1,3 +1,75 @@
<!-- Responsive container: show individual buttons on larger screens, collapsed menu on smaller screens -->
<ng-container *ngIf="shouldShowCollapsed; else uncollapsedButtons">
<div class="collapsed-menu-container" *ngIf="visibleButtonsCount > 0">
<button
mat-icon-button
class="fab-menu-trigger"
[matMenuTriggerFor]="panelsMenu"
[disabled]="isConnectionLost"
[class.active-btn]="isAnyPanelOpened"
matTooltip="{{ 'TOOLBAR.PANELS' | translate }}"
#menuTrigger="matMenuTrigger"
>
<mat-icon class="material-symbols-outlined" [class.rotated]="menuTrigger.menuOpen">keyboard_arrow_up</mat-icon>
</button>
<!-- Vertical panels menu -->
<mat-menu #panelsMenu="matMenu" class="panels-menu">
<!-- Activities menu item -->
<button
mat-menu-item
class="panel-menu-item"
*ngIf="!isMinimal && showActivitiesPanelButton"
(click)="onToggleActivities()"
[disabled]="isConnectionLost"
[class.active-menu-item]="isActivitiesOpened"
>
<mat-icon>category</mat-icon>
</button>
<!-- Participants menu item -->
<button
mat-menu-item
class="panel-menu-item"
*ngIf="!isMinimal && showParticipantsPanelButton"
(click)="onToggleParticipants()"
[disabled]="isConnectionLost"
[class.active-menu-item]="isParticipantsOpened"
>
<mat-icon>people</mat-icon>
</button>
<!-- Chat menu item -->
<button
mat-menu-item
class="panel-menu-item"
*ngIf="!isMinimal && showChatPanelButton"
(click)="onToggleChat()"
[disabled]="isConnectionLost"
[class.active-menu-item]="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 in menu -->
<ng-container *ngIf="toolbarAdditionalPanelButtonsTemplate">
<ng-container *ngTemplateOutlet="toolbarAdditionalPanelButtonsTemplate"></ng-container>
</ng-container>
</mat-menu>
</div>
</ng-container>
<!-- Collapsed menu template for small screens -->
<ng-template #uncollapsedButtons>
<!-- Default activities button -->
<button
mat-icon-button
@ -53,3 +125,4 @@
<ng-container *ngIf="toolbarAdditionalPanelButtonsTemplate">
<ng-container *ngTemplateOutlet="toolbarAdditionalPanelButtonsTemplate"></ng-container>
</ng-container>
</ng-template>

View File

@ -8,4 +8,136 @@
::ng-deep .active-btn {
background-color: var(--ov-accent-action-color) !important;
}
// Collapsed menu styles for small screens
.collapsed-menu-container {
position: relative;
display: flex;
align-items: center;
}
.fab-menu-trigger:has(.rotated) {
transform: rotate(180deg);
}
// FAB-style trigger button
.fab-menu-trigger {
color: var(--ov-secondary-action-color);
background-color: var(--ov-primary-action-color);
transition: all 0.2s ease-in-out;
height: 36px;
width: 36px;
padding: 8px 0;
transition: transform 0.3s ease;
mat-icon {
font-size: 20px;
}
}
}
// Global styles for the collapsible panels menu
.panels-menu,
::ng-deep .panels-menu,
.panels-menu .mat-mdc-menu-panel,
.panels-menu .mat-mdc-menu-content,
::ng-deep .panels-menu .mat-mdc-menu-panel,
::ng-deep .panels-menu .mat-mdc-menu-content {
background-color: transparent !important;
box-shadow: none !important;
border: none !important;
min-width: 55px !important;
width: 55px !important;
max-width: 55px !important;
padding: 4px 0 !important;
justify-content: flex-end !important;
display: grid !important;
}
.panels-menu,
::ng-deep .panels-menu {
.panel-menu-item {
background-color: var(--ov-primary-action-color) !important;
color: var(--ov-secondary-action-color) !important;
border-radius: var(--ov-toolbar-buttons-radius) !important;
min-height: 36px !important;
padding: 8px !important;
margin: 5px 0;
height: 36px !important;
width: 36px !important;
display: flex !important;
box-shadow: 0 2px 4px color-mix(in srgb, var(--ov-secondary-action-color) 100%, transparent);
transition:
box-shadow 0.2s ease,
transform 0.2s ease;
&.active-menu-item {
background-color: var(--ov-accent-action-color) !important;
color: var(--ov-text-primary-color) !important;
}
&:disabled {
opacity: 0.5;
cursor: not-allowed;
}
mat-icon {
font-size: 20px !important;
width: 20px !important;
height: 20px !important;
margin: 0 !important;
}
// Chat badge adjustments for menu
.mat-badge {
mat-icon {
font-size: 18px !important;
width: 18px !important;
height: 18px !important;
}
}
.mat-badge-content {
background-color: var(--ov-warn-color) !important;
color: var(--ov-text-primary-color) !important;
font-size: 10px !important;
min-width: 14px !important;
height: 14px !important;
line-height: 14px !important;
border-radius: 7px !important;
top: -2px !important;
right: -2px !important;
}
// Remove default mat-menu-item styles
.mat-mdc-menu-item-text {
display: none !important;
}
// Remove focus outline
&:focus {
outline: none !important;
}
// Remove ripple effect
.mat-mdc-menu-ripple {
display: none !important;
}
}
// Custom scrollbar for menu if needed
.mat-mdc-menu-content {
&::-webkit-scrollbar {
width: 4px;
}
&::-webkit-scrollbar-track {
background: transparent;
}
&::-webkit-scrollbar-thumb {
background: rgba(var(--ov-secondary-action-color-rgb), 0.3);
border-radius: 2px;
}
}
}

View File

@ -1,4 +1,5 @@
import { Component, EventEmitter, Input, Output, TemplateRef } from '@angular/core';
import { ViewportService } from '../../../services/viewport/viewport.service';
@Component({
selector: 'ov-toolbar-panel-buttons',
@ -28,6 +29,27 @@ export class ToolbarPanelButtonsComponent {
@Output() toggleParticipantsPanel: EventEmitter<void> = new EventEmitter();
@Output() toggleChatPanel: EventEmitter<void> = new EventEmitter();
constructor(public viewportService: ViewportService) {}
// Computed property to determine if we should show collapsed menu
get shouldShowCollapsed(): boolean {
return this.viewportService.isMobileView() || this.viewportService.isTabletDown();
}
// Get count of visible buttons
get visibleButtonsCount(): number {
let count = 0;
if (!this.isMinimal && this.showActivitiesPanelButton) count++;
if (!this.isMinimal && this.showParticipantsPanelButton) count++;
if (!this.isMinimal && this.showChatPanelButton) count++;
return count;
}
// Check if any panel is currently opened
get isAnyPanelOpened(): boolean {
return this.isActivitiesOpened || this.isParticipantsOpened || this.isChatOpened;
}
// Local methods that emit events
onToggleActivities(expand?: string) {
this.toggleActivitiesPanel.emit(expand);

View File

@ -45,6 +45,9 @@
justify-content: flex-end;
align-items: center;
}
::ng-deep .menu-buttons-container:has(.collapsed-menu-container) {
flex: 0;
}
#info-container > div {
display: flex;