frontend: Revamp video room access UI with new design and navigation features
This commit is contained in:
parent
a3560ee845
commit
0cf5eba604
@ -1,53 +1,106 @@
|
||||
@if (!showRoom) {
|
||||
<div class="form-container">
|
||||
<div class="card-wrapper">
|
||||
<mat-card class="form-card">
|
||||
<h2 class="form-title">
|
||||
Access room <strong>{{ roomId }}</strong>
|
||||
</h2>
|
||||
<form [formGroup]="participantForm" (ngSubmit)="submitAccessRoom()">
|
||||
<mat-form-field appearance="outline" class="full-width">
|
||||
<mat-label>Name</mat-label>
|
||||
<input
|
||||
id="participant-name-input"
|
||||
matInput
|
||||
placeholder="Enter your name"
|
||||
formControlName="name"
|
||||
required
|
||||
/>
|
||||
@if (participantForm.get('name')?.hasError('minlength')) {
|
||||
<mat-error> The name must be at least <strong>4 characters</strong> </mat-error>
|
||||
}
|
||||
@if (participantForm.get('name')?.hasError('required')) {
|
||||
<mat-error> The name is <strong>required</strong> </mat-error>
|
||||
}
|
||||
@if (participantForm.get('name')?.hasError('participantExists')) {
|
||||
<mat-error>
|
||||
The name is already taken. <strong> Please choose another name </strong>
|
||||
</mat-error>
|
||||
}
|
||||
</mat-form-field>
|
||||
|
||||
<button
|
||||
mat-raised-button
|
||||
color="primary"
|
||||
id="participant-name-submit"
|
||||
class="full-width"
|
||||
[disabled]="participantForm.invalid"
|
||||
>
|
||||
Continue to room
|
||||
</button>
|
||||
</form>
|
||||
</mat-card>
|
||||
|
||||
<mat-card class="recordings-card">
|
||||
<div class="recordings-content">
|
||||
<h3>View recordings</h3>
|
||||
<button id="view-recordings-btn" mat-stroked-button color="accent" (click)="goToRecordings()">
|
||||
Go to recordings
|
||||
</button>
|
||||
<div class="ov-page-container">
|
||||
<div class="room-access-container fade-in">
|
||||
<!-- Header Section -->
|
||||
<div class="room-header">
|
||||
<mat-icon class="ov-room-icon room-icon">video_chat</mat-icon>
|
||||
<div class="room-info">
|
||||
<h1 class="room-title">{{ roomId }}</h1>
|
||||
<p class="room-subtitle">Choose how you want to proceed</p>
|
||||
</div>
|
||||
</mat-card>
|
||||
</div>
|
||||
|
||||
<!-- Action Cards Grid -->
|
||||
<div class="action-cards-grid">
|
||||
<!-- Join Room Card -->
|
||||
<mat-card class="action-card primary-card fade-in">
|
||||
<mat-card-header class="card-header">
|
||||
<mat-icon class="ov-room-icon card-icon">meeting_room</mat-icon>
|
||||
<div class="card-title-group">
|
||||
<mat-card-title>Join Meeting</mat-card-title>
|
||||
<mat-card-subtitle>Enter the room and start connecting</mat-card-subtitle>
|
||||
</div>
|
||||
</mat-card-header>
|
||||
|
||||
<mat-card-content class="card-content">
|
||||
<form [formGroup]="participantForm" (ngSubmit)="submitAccessRoom()" class="join-form">
|
||||
<mat-form-field appearance="outline" class="name-field">
|
||||
<mat-label>Your display name</mat-label>
|
||||
<input
|
||||
id="participant-name-input"
|
||||
matInput
|
||||
placeholder="Enter your name"
|
||||
formControlName="name"
|
||||
required
|
||||
/>
|
||||
<mat-icon matSuffix class="ov-action-icon">person</mat-icon>
|
||||
@if (participantForm.get('name')?.hasError('minlength')) {
|
||||
<mat-error> The name must be at least <strong>4 characters</strong> </mat-error>
|
||||
}
|
||||
@if (participantForm.get('name')?.hasError('required')) {
|
||||
<mat-error> The name is <strong>required</strong> </mat-error>
|
||||
}
|
||||
@if (participantForm.get('name')?.hasError('participantExists')) {
|
||||
<mat-error>
|
||||
The name is already taken. <strong> Please choose another name </strong>
|
||||
</mat-error>
|
||||
}
|
||||
</mat-form-field>
|
||||
|
||||
<button
|
||||
mat-raised-button
|
||||
color="primary"
|
||||
id="participant-name-submit"
|
||||
type="submit"
|
||||
class="join-button"
|
||||
[disabled]="participantForm.invalid"
|
||||
>
|
||||
<span>Join Meeting</span>
|
||||
</button>
|
||||
</form>
|
||||
</mat-card-content>
|
||||
</mat-card>
|
||||
|
||||
<!-- View Recordings Card -->
|
||||
@if (showRecordingCard) {
|
||||
<mat-card class="action-card secondary-card fade-in-delayed">
|
||||
<mat-card-header class="card-header">
|
||||
<mat-icon class="ov-recording-icon card-icon">video_library</mat-icon>
|
||||
<div class="card-title-group">
|
||||
<mat-card-title>View Recordings</mat-card-title>
|
||||
<mat-card-subtitle>Browse and manage past recordings</mat-card-subtitle>
|
||||
</div>
|
||||
</mat-card-header>
|
||||
|
||||
<mat-card-content class="card-content">
|
||||
<div class="recordings-info">
|
||||
<p class="recordings-description">
|
||||
Access previously recorded meetings from this room. You can watch, download, or
|
||||
manage existing recordings.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<button
|
||||
id="view-recordings-btn"
|
||||
mat-stroked-button
|
||||
color="accent"
|
||||
(click)="goToRecordings()"
|
||||
class="recordings-button"
|
||||
>
|
||||
<span>Browse Recordings</span>
|
||||
</button>
|
||||
</mat-card-content>
|
||||
</mat-card>
|
||||
}
|
||||
</div>
|
||||
|
||||
<!-- Quick Actions -->
|
||||
<div class="quick-actions fade-in-delayed-more">
|
||||
<button mat-button class="quick-action-button" (click)="goBack()">
|
||||
<mat-icon>arrow_back</mat-icon>
|
||||
<span>Back to Rooms</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
} @else {
|
||||
|
||||
@ -1,81 +1,264 @@
|
||||
.form-container {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
height: 100vh;
|
||||
background-color: var(--ov-meet-surface-background);
|
||||
padding: 20px;
|
||||
@import '../../../../../../src/assets/styles/design-tokens';
|
||||
|
||||
.card-wrapper {
|
||||
display: flex;
|
||||
gap: 40px;
|
||||
flex-wrap: wrap;
|
||||
justify-content: center;
|
||||
align-items: flex-start;
|
||||
// Room Access Container - Main layout using design tokens
|
||||
.room-access-container {
|
||||
@include ov-container;
|
||||
@include ov-page-content;
|
||||
min-height: 100vh;
|
||||
padding-top: var(--ov-meet-spacing-xxl);
|
||||
background: var(--ov-meet-background-color);
|
||||
gap: 0;
|
||||
}
|
||||
|
||||
// Room Header - Clean title section
|
||||
.room-header {
|
||||
@include ov-flex-center;
|
||||
flex-direction: column;
|
||||
gap: var(--ov-meet-spacing-md);
|
||||
margin-bottom: var(--ov-meet-spacing-xxl);
|
||||
text-align: center;
|
||||
|
||||
.room-icon {
|
||||
@include ov-icon(xl);
|
||||
color: var(--ov-meet-icon-rooms);
|
||||
margin-bottom: var(--ov-meet-spacing-sm);
|
||||
}
|
||||
|
||||
.form-card {
|
||||
width: 400px;
|
||||
padding: 20px;
|
||||
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.1);
|
||||
border-radius: var(--ov-meet-surface-radius);
|
||||
background-color: var(--ov-meet-surface-primary);
|
||||
.room-info {
|
||||
.room-title {
|
||||
margin: 0;
|
||||
font-size: var(--ov-meet-font-size-hero);
|
||||
font-weight: var(--ov-meet-font-weight-light);
|
||||
color: var(--ov-meet-text-primary);
|
||||
line-height: var(--ov-meet-line-height-tight);
|
||||
}
|
||||
|
||||
.room-subtitle {
|
||||
margin: var(--ov-meet-spacing-xs) 0 0 0;
|
||||
font-size: var(--ov-meet-font-size-lg);
|
||||
color: var(--ov-meet-text-secondary);
|
||||
line-height: var(--ov-meet-line-height-normal);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Action Cards Grid - Responsive layout
|
||||
.action-cards-grid {
|
||||
@include ov-grid-responsive(320px);
|
||||
gap: var(--ov-meet-spacing-xl);
|
||||
margin-bottom: var(--ov-meet-spacing-xxl);
|
||||
justify-content: center;
|
||||
|
||||
// When there's only one card, limit its width to maintain visual consistency
|
||||
&:has(.action-card:only-child) {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
|
||||
.action-card {
|
||||
max-width: 400px;
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
@include ov-tablet-down {
|
||||
grid-template-columns: 1fr;
|
||||
gap: var(--ov-meet-spacing-lg);
|
||||
|
||||
// On tablets and mobile, single cards should use full width
|
||||
&:has(.action-card:only-child) {
|
||||
.action-card {
|
||||
max-width: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Action Card Base - Consistent card styling
|
||||
.action-card {
|
||||
@include ov-card;
|
||||
@include ov-hover-lift(-4px);
|
||||
@include ov-theme-transition;
|
||||
padding: 0;
|
||||
overflow: hidden;
|
||||
min-height: 300px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
// Card Header
|
||||
.card-header {
|
||||
padding: var(--ov-meet-spacing-lg);
|
||||
border-bottom: 1px solid var(--ov-meet-border-color-light);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: var(--ov-meet-spacing-md);
|
||||
flex-shrink: 0;
|
||||
|
||||
.card-icon {
|
||||
@include ov-icon(lg);
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.card-title-group {
|
||||
flex: 1;
|
||||
|
||||
.mat-mdc-card-title {
|
||||
margin: 0;
|
||||
font-size: var(--ov-meet-font-size-xl);
|
||||
font-weight: var(--ov-meet-font-weight-semibold);
|
||||
color: var(--ov-meet-text-primary);
|
||||
line-height: var(--ov-meet-line-height-tight);
|
||||
}
|
||||
|
||||
.mat-mdc-card-subtitle {
|
||||
margin: var(--ov-meet-spacing-xs) 0 0 0;
|
||||
font-size: var(--ov-meet-font-size-sm);
|
||||
color: var(--ov-meet-text-secondary);
|
||||
line-height: var(--ov-meet-line-height-normal);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Card Content
|
||||
.card-content {
|
||||
padding: var(--ov-meet-spacing-lg);
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
}
|
||||
}
|
||||
|
||||
.recordings-card {
|
||||
padding: 16px;
|
||||
box-shadow: 0 4px 10px rgba(0, 0, 0, 0.05);
|
||||
border-radius: var(--ov-meet-surface-radius);
|
||||
background-color: var(--ov-meet-surface-primary);
|
||||
width: fit-content;
|
||||
align-self: center;
|
||||
}
|
||||
|
||||
.recordings-content {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.form-title {
|
||||
text-align: center;
|
||||
margin-bottom: 20px;
|
||||
color: var(--ov-meet-text-primary);
|
||||
|
||||
strong {
|
||||
font-style: italic;
|
||||
}
|
||||
}
|
||||
|
||||
.full-width {
|
||||
width: 100%;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
button {
|
||||
height: 56px;
|
||||
border-radius: var(--ov-meet-surface-radius);
|
||||
}
|
||||
|
||||
button:not([disabled]) {
|
||||
background-color: var(--ov-meet-color-accent);
|
||||
color: var(--ov-meet-text-on-accent);
|
||||
// Primary Card - Join meeting styling
|
||||
.primary-card {
|
||||
.card-header {
|
||||
background: linear-gradient(135deg, var(--ov-meet-surface-color) 0%, var(--ov-meet-color-primary-light) 180%);
|
||||
color: var(--ov-meet-text-on-primary);
|
||||
}
|
||||
}
|
||||
|
||||
// Secondary Card - Recordings styling
|
||||
.secondary-card {
|
||||
.card-header {
|
||||
background: linear-gradient(135deg, var(--ov-meet-surface-color) 0%, var(--ov-meet-color-accent) 180%);
|
||||
}
|
||||
}
|
||||
|
||||
// Join Form - Form styling
|
||||
.join-form {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: var(--ov-meet-spacing-lg);
|
||||
flex: 1;
|
||||
|
||||
.name-field {
|
||||
width: 100%;
|
||||
|
||||
.mat-mdc-form-field-icon-suffix {
|
||||
color: var(--ov-meet-text-hint);
|
||||
}
|
||||
}
|
||||
|
||||
.join-button {
|
||||
@include ov-button-base;
|
||||
height: 56px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: var(--ov-meet-spacing-sm);
|
||||
margin-top: auto;
|
||||
background-color: var(--ov-meet-color-secondary);
|
||||
color: var(--ov-meet-text-on-secondary);
|
||||
}
|
||||
}
|
||||
|
||||
// Recordings Info - Content for recordings card
|
||||
.recordings-info {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: var(--ov-meet-spacing-lg);
|
||||
|
||||
.recordings-description {
|
||||
margin: 0;
|
||||
font-size: var(--ov-meet-font-size-md);
|
||||
color: var(--ov-meet-text-secondary);
|
||||
line-height: var(--ov-meet-line-height-relaxed);
|
||||
}
|
||||
}
|
||||
|
||||
.recordings-button {
|
||||
@include ov-button-base;
|
||||
height: 56px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: var(--ov-meet-spacing-sm);
|
||||
margin-top: auto;
|
||||
}
|
||||
|
||||
// Quick Actions - Footer actions
|
||||
.quick-actions {
|
||||
@include ov-flex-center;
|
||||
margin-top: var(--ov-meet-spacing-xl);
|
||||
|
||||
.quick-action-button {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: var(--ov-meet-spacing-sm);
|
||||
color: var(--ov-meet-text-secondary);
|
||||
@include ov-theme-transition;
|
||||
|
||||
&:hover {
|
||||
color: var(--ov-meet-text-primary);
|
||||
background-color: var(--ov-meet-surface-hover);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Responsive adjustments
|
||||
@include ov-mobile-down {
|
||||
.room-access-container {
|
||||
padding: var(--ov-meet-spacing-lg);
|
||||
padding-top: var(--ov-meet-spacing-xl);
|
||||
}
|
||||
|
||||
.room-header {
|
||||
margin-bottom: var(--ov-meet-spacing-xl);
|
||||
|
||||
.room-info .room-title {
|
||||
font-size: var(--ov-meet-font-size-xxl);
|
||||
}
|
||||
}
|
||||
|
||||
.action-card {
|
||||
min-height: auto;
|
||||
|
||||
.card-header {
|
||||
padding: var(--ov-meet-spacing-md);
|
||||
|
||||
.card-title-group {
|
||||
.mat-mdc-card-title {
|
||||
font-size: var(--ov-meet-font-size-lg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.card-content {
|
||||
padding: var(--ov-meet-spacing-md);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Custom leave button styling (existing functionality)
|
||||
::ng-deep {
|
||||
#media-buttons-container .custom-leave-btn > button {
|
||||
&:hover {
|
||||
background-color: var(--ov-error-color) !important;
|
||||
background-color: var(--ov-meet-color-error) !important;
|
||||
}
|
||||
text-align: center;
|
||||
background-color: var(--ov-error-color) !important;
|
||||
color: var(--ov-secondary-action-color);
|
||||
border-radius: var(--ov-leave-button-radius) !important;
|
||||
background-color: var(--ov-meet-color-error) !important;
|
||||
color: var(--ov-meet-text-on-primary);
|
||||
border-radius: var(--ov-meet-radius-sm) !important;
|
||||
width: 65px !important;
|
||||
margin: 0px !important;
|
||||
}
|
||||
|
||||
@ -61,7 +61,7 @@ export class VideoRoomComponent implements OnInit, OnDestroy {
|
||||
name: new FormControl('', [Validators.required, Validators.minLength(4)])
|
||||
});
|
||||
showRoom = false;
|
||||
|
||||
showRecordingCard = false;
|
||||
roomId = '';
|
||||
roomSecret = '';
|
||||
participantName = '';
|
||||
@ -90,6 +90,14 @@ export class VideoRoomComponent implements OnInit, OnDestroy {
|
||||
this.roomId = this.roomService.getRoomId();
|
||||
this.roomSecret = this.roomService.getRoomSecret();
|
||||
|
||||
const { recordings } = await this.recManagerService.listRecordings({
|
||||
maxItems: 1,
|
||||
roomId: this.roomId,
|
||||
fields: 'recordingId'
|
||||
});
|
||||
|
||||
this.showRecordingCard = recordings.length > 0;
|
||||
|
||||
await this.initializeParticipantName();
|
||||
}
|
||||
|
||||
@ -224,6 +232,14 @@ export class VideoRoomComponent implements OnInit, OnDestroy {
|
||||
}
|
||||
}
|
||||
|
||||
async goBack() {
|
||||
try {
|
||||
await this.navigationService.navigateTo('rooms');
|
||||
} catch (error) {
|
||||
console.error('Error navigating back to rooms:', error);
|
||||
}
|
||||
}
|
||||
|
||||
onParticipantConnected(event: ParticipantModel) {
|
||||
const message: WebComponentOutboundEventMessage = {
|
||||
event: WebComponentEvent.JOIN,
|
||||
|
||||
@ -7,6 +7,8 @@
|
||||
--ov-meet-color-primary: #1976d2;
|
||||
--ov-meet-color-primary-light: #42a5f5;
|
||||
--ov-meet-color-primary-dark: #1565c0;
|
||||
--ov-meet-color-secondary: #585858;
|
||||
--ov-meet-color-secondary-light: #b0a7a8;
|
||||
--ov-meet-color-accent: #7b1fa2;
|
||||
--ov-meet-color-accent-light: #9c27b0;
|
||||
--ov-meet-color-accent-dark: #6a1b9a;
|
||||
|
||||
@ -17,6 +17,7 @@
|
||||
--ov-meet-text-hint: #9e9e9e;
|
||||
--ov-meet-text-disabled: #bdbdbd;
|
||||
--ov-meet-text-on-primary: #ffffff;
|
||||
--ov-meet-text-on-secondary: #ffffff;
|
||||
--ov-meet-text-on-accent: #ffffff;
|
||||
--ov-meet-text-on-surface: #212121;
|
||||
--ov-meet-text-on-background: #212121;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user