Compare commits

..

1 Commits

Author SHA1 Message Date
damencho
d69710f327 feat(visitors): Logs meetingId change in room. 2026-01-12 10:34:20 -06:00
248 changed files with 2356 additions and 8963 deletions

View File

@@ -7,7 +7,7 @@ jobs:
name: Luacheck
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 #v6.0.1
- uses: actions/checkout@v6
- name: Install luarocks
run: sudo apt-get --install-recommends -y install luarocks

View File

@@ -7,8 +7,8 @@ jobs:
name: Lint
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 #v6.0.1
- uses: actions/setup-node@395ad3262231945c25e8478fd5baf05154b1d79f #v6.1.0
- uses: actions/checkout@v6
- uses: actions/setup-node@v6
with:
node-version-file: '.nvmrc'
cache: 'npm'
@@ -42,8 +42,8 @@ jobs:
matrix:
os: [macos-latest, ubuntu-latest]
steps:
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 #v6.0.1
- uses: actions/setup-node@395ad3262231945c25e8478fd5baf05154b1d79f #v6.1.0
- uses: actions/checkout@v6
- uses: actions/setup-node@v6
with:
node-version-file: '.nvmrc'
cache: 'npm'
@@ -59,8 +59,8 @@ jobs:
name: Build mobile bundle (Android)
runs-on: macos-15
steps:
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 #v6.0.1
- uses: actions/setup-node@395ad3262231945c25e8478fd5baf05154b1d79f #v6.1.0
- uses: actions/checkout@v6
- uses: actions/setup-node@v6
with:
node-version-file: '.nvmrc'
cache: 'npm'
@@ -74,8 +74,8 @@ jobs:
name: Build mobile bundle (iOS)
runs-on: macos-15
steps:
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 #v6.0.1
- uses: actions/setup-node@395ad3262231945c25e8478fd5baf05154b1d79f #v6.1.0
- uses: actions/checkout@v6
- uses: actions/setup-node@v6
with:
node-version-file: '.nvmrc'
cache: 'npm'
@@ -116,8 +116,8 @@ jobs:
rm -rf /host/usr/share/dotnet
rm -rf /host/usr/share/swift
df -h /
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 #v6.0.1
- uses: actions/setup-node@395ad3262231945c25e8478fd5baf05154b1d79f #v6.1.0
- uses: actions/checkout@v6
- uses: actions/setup-node@v6
with:
node-version-file: '.nvmrc'
cache: 'npm'
@@ -137,8 +137,8 @@ jobs:
name: Build mobile SDK (iOS)
runs-on: macos-15
steps:
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 #v6.0.1
- uses: actions/setup-node@395ad3262231945c25e8478fd5baf05154b1d79f #v6.1.0
- uses: actions/checkout@v6
- uses: actions/setup-node@v6
with:
node-version-file: '.nvmrc'
cache: 'npm'
@@ -160,7 +160,7 @@ jobs:
-workspace ios/jitsi-meet.xcworkspace \
-scheme JitsiMeetSDK
- name: setup-cocoapods
uses: ruby/setup-ruby@4fc31e1c823882afd7ef55985266a526c589de90 #v1.282.0
uses: ruby/setup-ruby@v1
with:
ruby-version: '3.4'
bundler-cache: true
@@ -187,8 +187,8 @@ jobs:
name: Test Debian packages build
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 #v6.0.1
- uses: actions/setup-node@395ad3262231945c25e8478fd5baf05154b1d79f #v6.1.0
- uses: actions/checkout@v6
- uses: actions/setup-node@v6
with:
node-version-file: '.nvmrc'
cache: 'npm'

View File

@@ -7,7 +7,7 @@ jobs:
stale:
runs-on: ubuntu-latest
steps:
- uses: actions/stale@5f858e3efba33a5ca4407a664cc011ad407f2008 #v10.1.0
- uses: actions/stale@v8
with:
stale-issue-message: 'This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.'
stale-pr-message: 'This PR has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.'

View File

@@ -927,9 +927,6 @@ var config = {
// [ 'microphone', 'camera' ]
// ],
// Enable reduced UI on web.
// reducedUIEnabled: true,
// Overrides the buttons displayed in the main toolbar for reduced UI.
// When there isn't an override for a certain configuration the default jitsi-meet configuration will be used.
// The order of the buttons in the array is preserved.

View File

@@ -45,7 +45,7 @@ body {
.jitsi-icon {
&-default svg {
fill: var(--icon-default-color, white);
fill: white;
}
}

View File

@@ -1,5 +1,5 @@
.always-on-top-toolbox {
background-color: var(--toolbox-background-color, $newToolbarBackgroundColor);
background-color: $newToolbarBackgroundColor;
border-radius: 3px;
display: flex;
z-index: $toolbarZ;

View File

@@ -2,7 +2,7 @@
* Round badge.
*/
.badge-round {
background-color: var(--toolbar-badge-background, #165ECC);
background-color: #165ECC;
border-radius: 50%;
box-sizing: border-box;
color: #FFFFFF;
@@ -93,7 +93,7 @@
.toolbox-content-wrapper::after {
content: '';
background: var(--toolbox-background-color, $newToolbarBackgroundColor);
background: $newToolbarBackgroundColor;
padding-bottom: env(safe-area-inset-bottom, 0);
}

View File

@@ -60,7 +60,7 @@
}
#notification-participant-list {
background-color: var(--toolbox-background-color, $newToolbarBackgroundColor);
background-color: $newToolbarBackgroundColor;
border: 1px solid rgba(255, 255, 255, .4);
border-radius: 8px;
left: 0;

View File

@@ -1407,7 +1407,7 @@ PODS:
- Yoga
- react-native-performance (5.1.2):
- React-Core
- react-native-safe-area-context (5.6.1):
- react-native-safe-area-context (5.5.2):
- React-Core
- react-native-slider (4.5.6):
- DoubleConversion
@@ -2271,7 +2271,7 @@ SPEC CHECKSUMS:
react-native-orientation-locker: dbd3f6ddbe9e62389cb0807dc2af63f6c36dec36
react-native-pager-view: 11662c698c8f11d39e05891316d2a144fa00adc4
react-native-performance: 125a96c145e29918b55b45ce25cbba54f1e24dcd
react-native-safe-area-context: 2243039f43d10cb1ea30ec5ac57fc6d1448413f4
react-native-safe-area-context: 0f7bf11598f9a61b7ceac8dc3f59ef98697e99e1
react-native-slider: 1205801a8d29b28cacc14eef08cb120015cdafcb
react-native-video: eb861d67a71dfef1bbf6086a811af5f338b13781
react-native-webrtc: e8f0ce746353adc2744a2b933645e1aeb41eaa74

View File

@@ -31,7 +31,6 @@
"it": "Italiano",
"ja": "日本語",
"kab": "Taqbaylit",
"kk": "Қазақша",
"ko": "한국어",
"lt": "Lietuvių",
"lv": "Latviešu",

File diff suppressed because it is too large Load Diff

View File

@@ -126,16 +126,8 @@
"messagebox": "Digita un messaggio",
"newMessages": "Nuovi messaggi",
"nickname": {
"featureChat": "la chat",
"featureClosedCaptions": "i sottotitoli",
"featureFileSharing": "la condivisione file",
"featurePolls": "i sondaggi",
"popover": "Scegli un nickname",
"title": "Inserisci un nickname per usare la chat",
"titleWith1Features": "Inserisci un nickname per usare {{feature1}}",
"titleWith2Features": "Inserisci un nickname per usare {{feature1}} e {{feature2}}",
"titleWith3Features": "Inserisci un nickname per usare {{feature1}}, {{feature2}} e {{feature3}}",
"titleWith4Features": "Inserisci un nickname per usare {{feature1}}, {{feature2}}, {{feature3}} e {{feature4}}",
"titleWithCC": "Inserisci un nickname per usare la chat e i sottotitoli",
"titleWithPolls": "Inserisci un nickname per usare la chat e i sondaggi",
"titleWithPollsAndCC": "Inserisci un nickname per usare la chat, i sondaggi e i sottotitoli",
@@ -167,7 +159,7 @@
"installExtensionText": "Installa un'estensione per integrare Google Calendar e Office 365"
},
"closedCaptionsTab": {
"emptyState": "Il contenuto dei sottotitoli sarà disponibile una volta che un moderatore lo attiverà",
"emptyState": "Il contenuto dei sottotitoli sarà disponibile una volta che l'organizzatore lo attiverà",
"startClosedCaptionsButton": "Attiva sottotitoli"
},
"connectingOverlay": {
@@ -291,9 +283,9 @@
"Submit": "Invia",
"Understand": "Accetto, mantieni microfono e videocamera disattivati per ora",
"UnderstandAndUnmute": "Accetto, riattiva microfono e videocamera",
"WaitForHostNoAuthMsg": "La riunione non è ancora iniziata perché nessun moderatore si è ancora collegato. Si prega di attendere.",
"WaitingForHostButton": "Attendi un moderatore",
"WaitingForHostTitle": "In attesa di un moderatore…",
"WaitForHostNoAuthMsg": "La riunione non è ancora iniziata perché nessun organizzatore si è ancora collegato. Si prega di attendere.",
"WaitingForHostButton": "Attendi l'organizzatore",
"WaitingForHostTitle": "In attesa dell'organizzatore…",
"Yes": "Sì",
"accessibilityLabel": {
"Cancel": "Annulla (chiudi dialogo)",
@@ -356,8 +348,8 @@
"error": "Errore",
"errorRoomCreationRestriction": "Hai provato ad accedere alla riunione troppo presto, torna tra un po'.",
"gracefulShutdown": "Il nostro servizio è al momento inattivo per manutenzione. Si prega di riprovare più tardi.",
"grantModeratorDialog": "Desideri di concedere i permessi da moderatore a {{participantName}}?",
"grantModeratorTitle": "Concedi permessi da moderatore",
"grantModeratorDialog": "Vuoi rendere relatore questo partecipante?",
"grantModeratorTitle": "Fai diventare relatore",
"hide": "Nascondi",
"hideShareAudioHelper": "Non mostrare più questa finestra",
"incorrectPassword": "Nome utente o password errati",
@@ -735,12 +727,12 @@
"emailField": "Inserisci il tuo indirizzo email",
"enableDialogPasswordField": "Imposta password (opzionale)",
"enableDialogSubmit": "Attiva",
"enableDialogText": "La sala d'attesa ti permette di proteggere la riunione concedendo l'accesso solo alle persone autorizzate da un moderatore.",
"enableDialogText": "La sala d'attesa ti permette di proteggere la riunione concedendo l'accesso solo alle persone autorizzate da un organizzatore.",
"enterPasswordButton": "Inserisci password riunione",
"enterPasswordTitle": "Inserisci la password per entrare nella riunione",
"errorMissingPassword": "Inserisci la password della riunione",
"invalidPassword": "Password errata",
"joinRejectedMessage": "La tua richiesta d'accesso è stata respinta da un moderatore.",
"joinRejectedMessage": "La tua richiesta d'accesso è stata respinta da un organizzatore.",
"joinRejectedTitle": "Richiesta d'accesso respinta.",
"joinTitle": "Entra nella riunione",
"joinWithPasswordMessage": "Tentativo di accesso con password in corso, si prega di attendere…",
@@ -762,7 +754,7 @@
"passwordJoinButton": "Entra",
"title": "Sala d'attesa",
"toggleLabel": "Attiva sala d'attesa",
"waitForModerator": "La riunione non è ancora iniziata, perché non è arrivato alcun moderatore. Se vuoi diventarlo autenticati, altrimenti si prega di attendere."
"waitForModerator": "La riunione non è ancora iniziata, perché non è arrivato alcun organizzatore. Se vuoi diventarlo autenticati, altrimenti attendi."
},
"localRecording": {
"clientState": {
@@ -780,11 +772,11 @@
"me": "Io",
"messages": {
"engaged": "Registrazione avviata.",
"finished": "La registrazione della sessione {{token}} è terminata. Invia il file della registrazione al moderatore.",
"finishedModerator": "La registrazione della sessione {{token}} è terminata. La registrazione della traccia locale è stata salvata. Si prega di chiedere ai partecipanti di inviare le loro registrazioni.",
"notModerator": "Non sei un moderatore. Non puoi avviare o interrompere la registrazione."
"finished": "La registrazione della sessione {{token}} è terminata. Invia il file della registrazione all'organizzatore.",
"finishedModerator": "La registrazione della sessione {{token}} è terminata. La registrazione della traccia è stata salvata. Chiedi ai partecipanti di inviare le loro registrazioni.",
"notModerator": "Non sei un relatore. Non puoi avviare o interrompere la registrazione."
},
"moderator": "Moderatore",
"moderator": "Relatore",
"no": "No",
"participant": "Partecipante",
"participantStats": "Statistiche partecipante",
@@ -832,7 +824,7 @@
"focusFail": "{{component}} non disponibile - nuovo tentativo tra {{ms}} sec",
"gifsMenu": "GIPHY",
"groupTitle": "Notifiche",
"hostAskedUnmute": "Il moderatore ti chiede di intervenire.",
"hostAskedUnmute": "Il relatore ti chiede di intervenire.",
"invalidTenant": "Nome non valido",
"invalidTenantHyphenDescription": "Il nome che hai scelto non è valido (inizia o finisce con '-').",
"invalidTenantLengthDescription": "Il nome che hai scelto è troppo lungo.",
@@ -854,17 +846,17 @@
"localRecordingStopped": "{{name}} ha smesso di registrare.",
"me": "Io",
"moderationInEffectCSDescription": "Alza la mano, se vuoi condividere lo schermo.",
"moderationInEffectCSTitle": "La condivisione schermo è stata bloccata dal moderatore",
"moderationInEffectCSTitle": "La condivisione schermo è stata bloccata dal relatore",
"moderationInEffectDescription": "Alza la mano, se vuoi prendere la parola.",
"moderationInEffectTitle": "Il tuo microfono è stato spento dal moderatore",
"moderationInEffectTitle": "Il tuo microfono è stato spento dal relatore",
"moderationInEffectVideoDescription": "Alza la mano, se vuoi avviare la tua videocamera.",
"moderationInEffectVideoTitle": "La tua videocamera è stata spenta dal moderatore",
"moderationRequestFromModerator": "L'organizzatore ti chiede di accendere il microfono",
"moderationInEffectVideoTitle": "La tua videocamera è stata spenta dal relatore",
"moderationRequestFromModerator": "Il relatore vorrebbe che tu accendessi il microfono",
"moderationRequestFromParticipant": "Vuole parlare",
"moderationStartedTitle": "Moderazione in corso",
"moderationStoppedTitle": "Moderazione interrotta",
"moderationToggleDescription": "da {{participantDisplayName}}",
"moderator": "Ora sei un moderatore!",
"moderator": "Ora sei un relatore!",
"muted": "Hai iniziato la conversazione con il microfono disattivato.",
"mutedRemotelyDescription": "Puoi sempre attivare il microfono quando vuoi parlare. Spegni il microfono quando hai finito, per evitare rumori di fondo nella riunione.",
"mutedRemotelyTitle": "{{participantDisplayName}} ti ha spento il microfono",
@@ -1170,7 +1162,7 @@
},
"security": {
"about": "Puoi aggiungere una $t(lockRoomPassword) alla riunione. I partecipanti dovranno inserire la $t(lockRoomPassword) per accedere alla riunione.",
"aboutReadOnly": "I moderatori possono aggiungere una $t(lockRoomPassword) alla riunione. I partecipanti dovranno inserire la $t(lockRoomPassword) per accedere alla riunione.",
"aboutReadOnly": "Gli organizzatori possono aggiungere una $t(lockRoomPassword) alla riunione. I partecipanti dovranno inserire la $t(lockRoomPassword) per accedere alla riunione.",
"insecureRoomNameWarningNative": "Il nome della riunione è troppo semplice. Partecipanti non desiderati potrebbero entrare nella riunione. {{recommendAction}} Per saperne di più sulla sicurezza della tua riunione ",
"insecureRoomNameWarningWeb": "Il nome della riunione è troppo semplice. Partecipanti non desiderati potrebbero entrare nella riunione. {{recommendAction}} Per saperne di più sulla sicurezza della tua riunione <a href=\"{{securityUrl}}\" rel=\"security\" target=\"_blank\">clicca qui</a>.",
"title": "Impostazioni di sicurezza",
@@ -1190,7 +1182,7 @@
"signedIn": "Accesso agli eventi del calendario per {{email}} in corso. Clicca sul pulsante Disconnetti per interrompere laccesso agli eventi sul calendario.",
"title": "Calendario"
},
"chatWithPermissions": "Disattiva la chat per i partecipanti",
"chatWithPermissions": "La chat richiede il permesso",
"desktopShareFramerate": "Frequenza di aggiornamento condivisone schermo",
"desktopShareHighFpsWarning": "Una frequenza di aggiornamento della condivisione dello schermo più alta può influire sulla tua connessione. Devi riavviare la condivisione schermo, per applicare le modifiche.",
"desktopShareWarning": "Devi riavviare la condivisione schermo, per applicare le modifiche.",
@@ -1203,8 +1195,8 @@
"loggedIn": "Connesso come {{name}}",
"maxStageParticipants": "Numero massimo di partecipanti che possono essere messi in evidenza nella schermata principale",
"microphones": "Microfoni",
"moderator": "Moderatore",
"moderatorOptions": "Opzioni moderatore",
"moderator": "Relatore",
"moderatorOptions": "Opzioni relatore",
"more": "Generali",
"name": "Nome",
"noDevice": "Nessuno",
@@ -1333,7 +1325,7 @@
"feedback": "Lascia un feedback",
"fullScreen": "Attiva modalità a schermo intero",
"giphy": "Mostra menu GIPHY",
"grantModerator": "Concedi permessi da moderatore",
"grantModerator": "Concedi permessi da relatore",
"hangup": "Lascia la riunione",
"heading": "Barra degli strumenti",
"help": "Aiuto",
@@ -1358,7 +1350,7 @@
"muteEveryoneElsesVideoStream": "Spegni la videocamera a tutti gli altri",
"muteEveryonesVideoStream": "Spegni la videocamera a tutti",
"muteGUMPending": "Connessione del microfono in corso",
"noiseSuppression": "Cancellazione del rumore",
"noiseSuppression": "Cancellazione del rumore (BETA)",
"openChat": "Apri chat",
"participants": "Apri pannello partecipanti. {{participantsCount}} partecipanti",
"pip": "Attiva modalità Picture-in-Picture",
@@ -1423,21 +1415,20 @@
"closeParticipantsPane": "Chiudi pannello partecipanti",
"closeReactionsMenu": "Chiudi menu reazioni",
"closedCaptions": "Sottotitoli",
"disableNoiseSuppression": "Disattiva cancellazione del rumore",
"disableNoiseSuppression": "Disattiva cancellazione del rumore (BETA)",
"disableReactionSounds": "Puoi disattivare i suoni delle reazioni in questa riunione",
"documentClose": "Chiudi documento condiviso",
"documentOpen": "Apri documento condiviso",
"download": "Scarica le nostre app",
"e2ee": "Crittografia End-to-End",
"embedMeeting": "Incorpora riunione",
"enableNoiseSuppression": "Attiva cancellazione del rumore",
"enableNoiseSuppression": "Attiva cancellazione del rumore (BETA)",
"endConference": "Termina la riunione per tutti",
"enterFullScreen": "Mostra a schermo intero",
"enterTileView": "Mostra vista a mosaico",
"exitFullScreen": "Esci dalla modalità a schermo intero",
"exitTileView": "Esci dalla vista a mosaico",
"feedback": "Lascia un feedback",
"fileSharing": "Condivisione file",
"giphy": "Menu GIPHY",
"hangup": "Lascia la riunione",
"help": "Aiuto",
@@ -1466,14 +1457,13 @@
"noAudioSignalDialInDesc": "Puoi anche chiamare usando:",
"noAudioSignalDialInLinkDesc": "Numeri di telefono",
"noAudioSignalTitle": "Nessun suono rilevato dal tuo microfono!",
"noiseSuppression": "Cancellazione del rumore",
"noiseSuppression": "Cancellazione del rumore (BETA)",
"noisyAudioInputDesc": "Sembra che il tuo microfono faccia rumore, si prega di spegnerlo o cambiarlo.",
"noisyAudioInputTitle": "Il tuo microfono sembra fare rumore!",
"openChat": "Apri chat",
"openReactionsMenu": "Apri il menu reazioni",
"participants": "Partecipanti",
"pip": "Abilita modalità Picture-in-Picture",
"polls": "Sondaggi",
"privateMessage": "Invia un messaggio privato",
"profile": "Modifica profilo",
"raiseHand": "Alza la mano",
@@ -1575,11 +1565,11 @@
"domuteVideo": "Disattiva videocamera",
"domuteVideoOfOthers": "Disattiva videocamera a tutti gli altri",
"flip": "Specchia",
"grantModerator": "Concedi permessi da moderatore",
"grantModerator": "Concedi permessi da relatore",
"hideSelfView": "Nascondi la tua immagine",
"kick": "Espelli",
"mirrorVideo": "Specchia il tuo video",
"moderator": "Moderatore",
"moderator": "Relatore",
"mute": "Il partecipante ha il microfono spento",
"muted": "Microfono spento",
"pinToStage": "Metti in primo piano",
@@ -1626,7 +1616,7 @@
"description": "Adesso sei uno spettatore in questa riunione.",
"raiseHand": "Alza la mano",
"title": "Ingresso nella riunione in corso",
"wishToSpeak": "Per parlare si prega di alzare la mano sotto e aspettare l'autorizzazione del moderatore."
"wishToSpeak": "Se vuoi parlare, si prega di alzare la mano sotto e aspettare l'autorizzazione del relatore."
},
"labelTooltip": "Numero di spettatori: {{count}}",
"notification": {
@@ -1636,7 +1626,7 @@
"noVisitorLobby": "Non puoi partecipare se la sala d'attesa è attiva per la riunione.",
"notAllowedPromotion": "Un partecipante deve autorizzare la tua richiesta prima.",
"requestToJoin": "Mano alzata",
"requestToJoinDescription": "La tua richiesta è stata inviata ai moderatori. Tieni duro!",
"requestToJoinDescription": "La tua richiesta è stata inviata ai relatori. Tieni duro!",
"title": "Sei uno spettatore nella riunione"
},
"waitingMessage": "Ti unirai alla riunione quando inizierà!"
@@ -1677,7 +1667,7 @@
"mobileDownLoadLinkAndroid": "Scarica applicazione per Android",
"mobileDownLoadLinkFDroid": "Scarica applicazione da F-Droid",
"mobileDownLoadLinkIos": "Scarica applicazione per iOS",
"moderatedMessage": "O <a href=\"{{url}}\" rel=\"noopener noreferrer\" target=\"_blank\">prepara un URL di riunione</a> in anticipo, quando sei l'unico moderatore.",
"moderatedMessage": "O <a href=\"{{url}}\" rel=\"noopener noreferrer\" target=\"_blank\">prepara un URL di riunione</a> in anticipo, quando sei l'unico organizzatore.",
"privacy": "Privacy",
"recentList": "Recenti",
"recentListDelete": "Cancella",

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -114,10 +114,6 @@
"error": "Erro: a sua mensagem não foi enviada. Motivo: {{error}}",
"everyone": "Todos",
"fieldPlaceHolder": "Aa",
"fileAccessibleTitle": "{{user}} carregou um ficheiro",
"fileAccessibleTitleMe": "carreguei um arquivo",
"fileDeleted": "Um ficheiro foi eliminado",
"guestsChatIndicator": "(convidado)",
"lobbyChatMessageTo": "Mensagem de chat na sala de espera para {{recipient}}",
"message": "Mensagem",
"messageAccessibleTitle": "{{user}} disse:",
@@ -126,16 +122,8 @@
"messagebox": "Escreva uma mensagem",
"newMessages": "Novas mensagens",
"nickname": {
"featureChat": "chat",
"featureClosedCaptions": "legendas ocultas",
"featureFileSharing": "partilha de ficheiros",
"featurePolls": "sondagens",
"popover": "Escolha um apelido",
"title": "Introduza um apelido para usar o chat",
"titleWith1Features": "Insira um apelido para usar {{feature1}}",
"titleWith2Features": "Insira um apelido para usar {{feature1}} e {{feature2}}",
"titleWith3Features": "Insira um apelido para usar {{feature1}}, {{feature2}} e {{feature3}}",
"titleWith4Features": "Insira um apelido para usar {{feature1}}, {{feature2}}, {{feature3}} e {{feature4}}",
"titleWithCC": "Insira um apelido para usar o chat e as legendas ocultas",
"titleWithPolls": "Digite um apelido para usar o chat e as sondagens",
"titleWithPollsAndCC": "Insira um apelido para utilizar o chat, as sondagens e as legendas ocultas",
@@ -291,6 +279,7 @@
"Submit": "Submeter",
"Understand": "Entendo, mantenha-me em silêncio por enquanto.",
"UnderstandAndUnmute": "Entendo, por favor, desative o silêncio.",
"WaitForHostMsg": "A conferência ainda não começou porque ainda não chegaram moderadores. Se quiser ser um moderador, inicie a sessão. Caso contrário, aguarde.",
"WaitForHostNoAuthMsg": "A conferência ainda não começou porque ainda não chegaram os moderadores. Por favor, aguarde.",
"WaitingForHostButton": "Esperar pelo moderador",
"WaitingForHostTitle": "À espera de um moderador…",
@@ -533,7 +522,6 @@
"tokenAuthFailedWithReasons": "Lamentamos, mas não está autorizado a participar nesta chamada. Razões possíveis: {{reason}}",
"tokenAuthUnsupported": "O URL de token não é suportado.",
"transcribing": "Transcrição",
"unauthenticatedAccessDisabled": "Esta chamada requer autenticação. Por favor, inicie sessão para prosseguir.",
"unlockRoom": "Retirar reunião $t(lockRoomPassword)",
"user": "Utilizador",
"userIdentifier": "Identificador do utilizador",
@@ -578,17 +566,13 @@
"downloadFailedDescription": "Por favor, tente novamente.",
"downloadFailedTitle": "Falha no descarregar",
"downloadFile": "Descarregar",
"downloadStarted": "O download do ficheiro foi iniciado",
"dragAndDrop": "Arraste e solte os ficheiros aqui ou em qualquer lugar do ecrã",
"fileAlreadyUploaded": "O ficheiro já foi carregado para esta reunião.",
"fileRemovedByOther": "O seu ficheiro '{{ fileName }}' foi removido",
"fileTooLargeDescription": "Certifique-se de que o ficheiro não exceda {{ maxFileSize }}.",
"fileTooLargeTitle": "O ficheiro selecionado é muito grande",
"fileUploadProgress": "Progresso do envio do ficheiro",
"fileUploadedSuccessfully": "Ficheiro carregado com sucesso",
"newFileNotification": "{{ participantName }} partilhou '{{ fileName }}'",
"removeFile": "Remover",
"removeFileSuccess": "Ficheiro removido com sucesso",
"uploadFailedDescription": "Por favor, tente novamente.",
"uploadFailedTitle": "Falha ao carregar",
"uploadFile": "Partilhar ficheiro"
@@ -761,8 +745,7 @@
"notificationTitle": "Sala de espera",
"passwordJoinButton": "Solicitar",
"title": "Sala de espera",
"toggleLabel": "Ativar sala de espera",
"waitForModerator": "A conferência ainda não começou porque não chegou nenhum moderador. Se deseja tornar-se um moderador, faça login. Caso contrário, aguarde."
"toggleLabel": "Ativar sala de espera"
},
"localRecording": {
"clientState": {
@@ -879,7 +862,6 @@
"oldElectronClientDescription1": "Parece estar a utilizar uma versão antiga do cliente Jitsi Meet que tem vulnerabilidades de segurança conhecidas. Por favor, certifique-se de que actualiza a nossa ",
"oldElectronClientDescription2": "compilação mais recente",
"oldElectronClientDescription3": " agora!",
"openChat": "Abrir chat",
"participantWantsToJoin": "Deseja juntar-se à reunião",
"participantsWantToJoin": "Desejam juntar-se à reunião",
"passwordRemovedRemotely": "$t(lockRoomPasswordUppercase) removido por outro participante",
@@ -978,9 +960,6 @@
"by": "Por {{ name }}",
"closeButton": "Fechar sondagem",
"create": {
"accessibilityLabel": {
"send": "Enviar sondagem"
},
"addOption": "Adicionar opção",
"answerPlaceholder": "Opção {{index}}",
"cancel": "Cancelar",
@@ -989,7 +968,8 @@
"pollQuestion": "Pergunta de Sondagem",
"questionPlaceholder": "Faça uma pergunta",
"removeOption": "Remover opção",
"save": "Guardar"
"save": "Guardar",
"send": "Enviar"
},
"errors": {
"notUniqueOption": "As opções devem ser únicas"
@@ -1358,7 +1338,7 @@
"muteEveryoneElsesVideo": "Parar o vídeo de todos os outros",
"muteEveryonesVideo": "Parar o vídeo de todos",
"muteGUMPending": "A ligar o seu microfone",
"noiseSuppression": "Supressão extra de ruído",
"noiseSuppression": "Supressão extra de ruído (BETA)",
"openChat": "Abrir chat",
"participants": "Abrir painel de participantes. {{participantsCount}} participantes",
"pip": "Mudar para o modo Picture-in-Picture",
@@ -1396,20 +1376,6 @@
"videounmute": "Iniciar câmara"
},
"addPeople": "Adicione pessoas à sua chamada",
"advancedAudioSettings": {
"aec": {
"label": "Cancelamento de eco acústico"
},
"agc": {
"label": "Controlo automático de ganho"
},
"ns": {
"label": "Supressão de ruído"
},
"stereo": {
"label": "Estéreo"
}
},
"audioOnlyOff": "Desativar modo de largura de banda baixa",
"audioOnlyOn": "Ativar modo de largura de banda baixa",
"audioRoute": "Selecionar o dispositivo de som",
@@ -1423,21 +1389,20 @@
"closeParticipantsPane": "Fechar painel de participantes",
"closeReactionsMenu": "Fechar menu de reações",
"closedCaptions": "Legendas ocultas",
"disableNoiseSuppression": "Desativar supressão de ruído extra",
"disableNoiseSuppression": "Desativar supressão de ruído extra (BETA)",
"disableReactionSounds": "Pode desactivar os sons de reacção para esta reunião",
"documentClose": "Fechar documento partilhado",
"documentOpen": "Abrir documento partilhado",
"download": "Descarregar as nossas aplicações",
"e2ee": "Criptografia ponta a ponta",
"embedMeeting": "Incorporar reunião",
"enableNoiseSuppression": "Ativar supressão extra de ruído",
"enableNoiseSuppression": "Ativar supressão extra de ruído (BETA)",
"endConference": "Terminar reunião para todos",
"enterFullScreen": "Ver em ecrã completo",
"enterTileView": "Ver em quadrícula",
"exitFullScreen": "Sair de ecrã completo",
"exitTileView": "Sair de quadrícula",
"feedback": "Deixar comentários",
"fileSharing": "Partilha de ficheiros",
"giphy": "Ativar/Desativar o menu GIPHY",
"hangup": "Sair da reunião",
"help": "Ajuda",
@@ -1466,14 +1431,13 @@
"noAudioSignalDialInDesc": "Também pode marcar usando:",
"noAudioSignalDialInLinkDesc": "Números de marcação",
"noAudioSignalTitle": "Não há nenhuma entrada vinda do seu microfone!",
"noiseSuppression": "Supressão extra de ruído",
"noiseSuppression": "Supressão extra de ruído (BETA)",
"noisyAudioInputDesc": "Parece que o seu microfone está a fazer barulho, por favor considere silenciar ou mudar de dispositivo.",
"noisyAudioInputTitle": "Seu microfone parece estar barulhento!",
"openChat": "Abrir chat",
"openReactionsMenu": "Abrir menu de reações",
"participants": "Participantes",
"pip": "Entrar no modo Picture-in-Picture",
"polls": "Sondagens",
"privateMessage": "Enviar mensagem privada",
"profile": "Editar o seu perfil",
"raiseHand": "Levantar a mão",
@@ -1483,7 +1447,6 @@
"reactionHeart": "Enviar reação com coração",
"reactionLaugh": "Enviar reação de risos",
"reactionLike": "Enviar reação de aprovado",
"reactionLove": "Enviar reação de amor",
"reactionSilence": "Enviar reação de silêncio",
"reactionSurprised": "Enviar reação de surpreendido",
"reactions": "Reações",
@@ -1635,8 +1598,6 @@
"noMainParticipantsTitle": "Esta reunião ainda não começou.",
"noVisitorLobby": "Não é possível aderir enquanto houver uma sala de espera activada para a reunião.",
"notAllowedPromotion": "É necessário que um participante autorize primeiro o seu pedido.",
"requestToJoin": "Mão levantada",
"requestToJoinDescription": "A sua solicitação foi enviada aos moderadores. Aguarde um momento!",
"title": "É um espectador na reunião"
},
"waitingMessage": "Participará na reunião assim que esta estiver em direto!"

View File

@@ -227,9 +227,6 @@
"video_ssrc": "Video SSRC:",
"yes": "yes"
},
"customPanel": {
"close": "Close"
},
"dateUtils": {
"earlier": "Earlier",
"today": "Today",
@@ -1318,7 +1315,6 @@
"chat": "Open / Close chat",
"clap": "Clap",
"closeChat": "Close chat",
"closeCustomPanel": "Close",
"closeMoreActions": "Close more actions menu",
"closeParticipantsPane": "Close participants pane",
"closedCaptions": "Closed captions",
@@ -1424,11 +1420,9 @@
"chat": "Open / Close chat",
"clap": "Clap",
"closeChat": "Close chat",
"closeCustomPanel": "Close",
"closeParticipantsPane": "Close participants pane",
"closeReactionsMenu": "Close reactions menu",
"closedCaptions": "Closed captions",
"copilot": "Copilot",
"disableNoiseSuppression": "Disable extra noise suppression",
"disableReactionSounds": "You can disable reaction sounds for this meeting",
"documentClose": "Close shared document",

View File

@@ -240,28 +240,14 @@ function initCommands() {
APP.store.dispatch(muteAllParticipants(exclude, muteMediaType));
},
'mute-remote-participant': (participantId, mediaType) => {
const state = APP.store.getState();
const muteMediaType = mediaType ? mediaType : MEDIA_TYPE.AUDIO;
const localParticipant = getLocalParticipant(state);
// Check if targeting the local participant
if (participantId === localParticipant?.id) {
if (muteMediaType === MEDIA_TYPE.AUDIO) {
APP.conference.toggleAudioMuted(false);
} else if (muteMediaType === MEDIA_TYPE.VIDEO) {
APP.conference.toggleVideoMuted(false, true);
}
return;
}
if (!isLocalParticipantModerator(state)) {
if (!isLocalParticipantModerator(APP.store.getState())) {
logger.error('Missing moderator rights to mute remote participant');
return;
}
const muteMediaType = mediaType ? mediaType : MEDIA_TYPE.AUDIO;
APP.store.dispatch(muteRemote(participantId, muteMediaType));
},
'toggle-lobby': isLobbyEnabled => {
@@ -804,7 +790,7 @@ function initCommands() {
}
if (transcription) {
APP.store.dispatch(setRequestingSubtitles(true, false, null, true));
APP.store.dispatch(setRequestingSubtitles(true, false, null));
}
},
@@ -826,7 +812,7 @@ function initCommands() {
}
if (transcription) {
APP.store.dispatch(setRequestingSubtitles(false, false, null, true));
APP.store.dispatch(setRequestingSubtitles(false, false, null));
}
if (mode === 'local') {
@@ -1431,15 +1417,17 @@ class API {
*
* @param {string} participantId - The ID of the participant.
* @param {boolean} isMuted - True if muted, false if unmuted.
* @param {string} mediaType - Media type that was muted ('audio' or 'video').
* @param {string} mediaType - Media type that was muted ('audio', 'video', or 'desktop').
* @param {boolean} isSelfMuted - True if participant muted themselves, false if muted by moderator.
* @returns {void}
*/
notifyParticipantMuted(participantId, isMuted, mediaType) {
notifyParticipantMuted(participantId, isMuted, mediaType, isSelfMuted = true) {
this._sendEvent({
name: 'participant-muted',
id: participantId,
isMuted,
mediaType
mediaType,
isSelfMuted
});
}

View File

@@ -3,7 +3,7 @@
import Logger from '@jitsi/logger';
import $ from 'jquery';
import React from 'react';
import { createRoot } from 'react-dom/client';
import ReactDOM from 'react-dom';
import { I18nextProvider } from 'react-i18next';
import { Provider } from 'react-redux';
@@ -166,8 +166,7 @@ export default class LargeVideoManager {
this.removePresenceLabel();
this._avatarRoot?.unmount();
this._avatarRoot = null;
ReactDOM.unmountComponentAtNode(this._dominantSpeakerAvatarContainer);
this.container.style.display = 'none';
}
@@ -519,16 +518,14 @@ export default class LargeVideoManager {
* Updates the src of the dominant speaker avatar
*/
updateAvatar() {
if (!this._avatarRoot) {
this._avatarRoot = createRoot(this._dominantSpeakerAvatarContainer);
}
this._avatarRoot.render(
ReactDOM.render(
<Provider store = { APP.store }>
<Avatar
id = "dominantSpeakerAvatar"
participantId = { this.id }
size = { 200 } />
</Provider>
</Provider>,
this._dominantSpeakerAvatarContainer
);
}
@@ -562,18 +559,15 @@ export default class LargeVideoManager {
const presenceLabelContainer = document.getElementById('remotePresenceMessage');
if (presenceLabelContainer) {
if (!this._presenceLabelRoot) {
this._presenceLabelRoot = createRoot(presenceLabelContainer);
}
this._presenceLabelRoot.render(
ReactDOM.render(
<Provider store = { APP.store }>
<I18nextProvider i18n = { i18next }>
<PresenceLabel
participantID = { id }
className = 'presence-label' />
</I18nextProvider>
</Provider>
);
</Provider>,
presenceLabelContainer);
}
}
@@ -583,8 +577,11 @@ export default class LargeVideoManager {
* @returns {void}
*/
removePresenceLabel() {
this._presenceLabelRoot?.unmount();
this._presenceLabelRoot = null;
const presenceLabelContainer = document.getElementById('remotePresenceMessage');
if (presenceLabelContainer) {
ReactDOM.unmountComponentAtNode(presenceLabelContainer);
}
}
/**

View File

@@ -4,7 +4,7 @@
import Logger from '@jitsi/logger';
import $ from 'jquery';
import React from 'react';
import { createRoot } from 'react-dom/client';
import ReactDOM from 'react-dom';
import { browser } from '../../../react/features/base/lib-jitsi-meet';
import { FILMSTRIP_BREAKPOINT } from '../../../react/features/filmstrip/constants';
@@ -659,12 +659,7 @@ export class VideoContainer extends LargeContainer {
return;
}
const container = document.getElementById('largeVideoBackgroundContainer');
if (!this._backgroundRoot) {
this._backgroundRoot = createRoot(container);
}
this._backgroundRoot.render(
ReactDOM.render(
<LargeVideoBackground
hidden = { this._hideBackground || this._isHidden }
mirror = {
@@ -674,7 +669,8 @@ export class VideoContainer extends LargeContainer {
}
orientationFit = { this._backgroundOrientation }
videoElement = { this.video }
videoTrack = { this.stream } />
videoTrack = { this.stream } />,
document.getElementById('largeVideoBackgroundContainer')
);
}
}

2133
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -72,7 +72,7 @@
"js-md5": "0.6.1",
"js-sha512": "0.8.0",
"jwt-decode": "2.2.0",
"lib-jitsi-meet": "https://github.com/jitsi/lib-jitsi-meet/releases/download/v2124.0.0+80df84a1/lib-jitsi-meet.tgz",
"lib-jitsi-meet": "https://github.com/jitsi/lib-jitsi-meet/releases/download/v2118.0.0+67fd2c84/lib-jitsi-meet.tgz",
"lodash-es": "4.17.21",
"null-loader": "4.0.1",
"optional-require": "1.0.3",
@@ -97,7 +97,7 @@
"react-native-pager-view": "6.8.1",
"react-native-paper": "5.10.3",
"react-native-performance": "5.1.2",
"react-native-safe-area-context": "5.6.1",
"react-native-safe-area-context": "5.5.2",
"react-native-screens": "4.11.1",
"react-native-sound": "https://github.com/jitsi/react-native-sound.git#ea13c97b5c2a4ff5e0d9bacbd9ff5e4457fe2c3c",
"react-native-splash-view": "0.0.18",
@@ -164,12 +164,12 @@
"@types/w3c-image-capture": "1.0.6",
"@types/w3c-web-hid": "1.0.3",
"@types/zxcvbn": "4.4.1",
"@wdio/allure-reporter": "9.23.2",
"@wdio/cli": "9.23.2",
"@wdio/globals": "9.23.0",
"@wdio/junit-reporter": "9.23.2",
"@wdio/local-runner": "9.23.2",
"@wdio/mocha-framework": "9.23.2",
"@wdio/allure-reporter": "9.22.0",
"@wdio/cli": "9.22.0",
"@wdio/globals": "9.17.0",
"@wdio/junit-reporter": "9.21.0",
"@wdio/local-runner": "9.22.0",
"@wdio/mocha-framework": "9.22.0",
"babel-loader": "9.1.0",
"babel-plugin-optional-require": "0.3.1",
"circular-dependency-plugin": "5.2.0",
@@ -194,7 +194,7 @@
"typescript": "5.7.2",
"unorm": "1.6.0",
"webdriverio": "9.22.0",
"webpack": "5.105.0",
"webpack": "5.95.0",
"webpack-bundle-analyzer": "4.4.2",
"webpack-cli": "5.1.4",
"webpack-dev-server": "5.1.0"

View File

@@ -1,4 +1,4 @@
import { setRoom } from '../base/conference/actions.native';
import { setRoom } from '../base/conference/actions';
import { getConferenceState } from '../base/conference/functions';
import {
configWillLoad,
@@ -29,7 +29,7 @@ import {
} from '../mobile/navigation/rootNavigationContainerRef';
import { screen } from '../mobile/navigation/routes';
import { clearNotifications } from '../notifications/actions';
import { isUnsafeRoomWarningEnabled } from '../prejoin/functions.native';
import { isUnsafeRoomWarningEnabled } from '../prejoin/functions';
import { maybeRedirectToTokenAuthUrl } from './actions.any';
import { addTrackStateToURL, getDefaultURL } from './functions.native';

View File

@@ -26,6 +26,5 @@ import '../face-landmarks/middleware';
import '../gifs/middleware';
import '../whiteboard/middleware.web';
import '../file-sharing/middleware.web';
import '../custom-panel/middleware.web';
import './middlewares.any';

View File

@@ -1,6 +1,5 @@
import '../base/devices/reducer';
import '../base/premeeting/reducer';
import '../custom-panel/reducer';
import '../base/tooltip/reducer';
import '../e2ee/reducer';
import '../face-landmarks/reducer';

View File

@@ -31,7 +31,6 @@ import { IUserInteractionState } from '../base/user-interaction/reducer';
import { IBreakoutRoomsState } from '../breakout-rooms/reducer';
import { ICalendarSyncState } from '../calendar-sync/reducer';
import { IChatState } from '../chat/reducer';
import { ICustomPanelState } from '../custom-panel/reducer';
import { IDeepLinkingState } from '../deep-linking/reducer';
import { IDropboxState } from '../dropbox/reducer';
import { IDynamicBrandingState } from '../dynamic-branding/reducer';
@@ -122,7 +121,6 @@ export interface IReduxState {
'features/calendar-sync': ICalendarSyncState;
'features/call-integration': ICallIntegrationState;
'features/chat': IChatState;
'features/custom-panel': ICustomPanelState;
'features/deep-linking': IDeepLinkingState;
'features/dropbox': IDropboxState;
'features/dynamic-branding': IDynamicBrandingState;

View File

@@ -81,6 +81,7 @@ MiddlewareRegistry.register(({ dispatch, getState }) => next => action => {
break;
}
case LOCAL_PARTICIPANT_MODERATION_NOTIFICATION: {
let descriptionKey;
let titleKey;
let uid = '';
const localParticipant = getLocalParticipant(getState);
@@ -110,6 +111,8 @@ MiddlewareRegistry.register(({ dispatch, getState }) => next => action => {
!raisedHand && dispatch(raiseHand(true));
dispatch(hideNotification(uid));
}) ],
descriptionKey,
sticky: true,
titleKey,
uid
}, NOTIFICATION_TIMEOUT_TYPE.MEDIUM));
@@ -268,6 +271,7 @@ StateListenerRegistry.register(
dispatch(showNotification({
titleKey: 'notify.hostAskedUnmute',
sticky: true,
customActionNameKey,
customActionHandler,
uid: ASKED_TO_UNMUTE_NOTIFICATION_ID

View File

@@ -93,17 +93,10 @@ export function commonUserJoinedHandling(
if (!user.isHidden()) {
const isReplacing = user?.isReplacing();
const isPromoted = conference?.getMetadataHandler().getMetadata()?.visitors?.promoted?.[id];
const userIdentity = user.getIdentity()?.user;
// Map identity from JWT context to userContext for external API
const userContext = userIdentity ? {
id: userIdentity.id,
name: userIdentity.name
} : undefined;
// the identity and avatar come from jwt and never change in the presence
dispatch(participantJoined({
avatarURL: userIdentity?.avatar,
avatarURL: user.getIdentity()?.user?.avatar,
botType: user.getBotType(),
conference,
id,
@@ -112,8 +105,7 @@ export function commonUserJoinedHandling(
role: user.getRole(),
isPromoted,
isReplacing,
sources: user.getSources(),
userContext
sources: user.getSources()
}));
}
}

View File

@@ -559,7 +559,6 @@ export interface IConfig {
skipConsentInMeeting?: boolean;
suggestRecording?: boolean;
};
reducedUIEnabled?: boolean;
reducedUImainToolbarButtons?: Array<string>;
remoteVideoMenu?: {
disableDemote?: boolean;

View File

@@ -215,7 +215,6 @@ export default [
'recordings.showPrejoinWarning',
'recordings.showRecordingLink',
'recordings.suggestRecording',
'reducedUIEnabled',
'reducedUImainToolbarButtons',
'replaceParticipant',
'resolution',

View File

@@ -387,8 +387,7 @@ export function setConfigFromURLParams(
// When not in an iframe, start without media if the pre-join page is not enabled.
if (!isEmbedded()
&& ('config.prejoinConfig' in params || 'config.prejoinConfig.enabled' in params)
&& config.prejoinConfig?.enabled === false) {
&& 'config.prejoinConfig.enabled' in params && config.prejoinConfig?.enabled === false) {
logger.warn('Using prejoinConfig.enabled config URL overwrite implies starting without media.');
config.disableInitialGUM = true;
}

View File

@@ -4,7 +4,6 @@ import { getCustomerDetails } from '../../jaas/actions.any';
import { getJaasJWT, isVpaasMeeting } from '../../jaas/functions';
import { navigateRoot } from '../../mobile/navigation/rootNavigationContainerRef';
import { screen } from '../../mobile/navigation/routes';
import { conferenceWillLeave } from '../conference/actions.native';
import { setJWT } from '../jwt/actions';
import { JitsiConnectionErrors } from '../lib-jitsi-meet';
@@ -59,8 +58,5 @@ export function connect(id?: string, password?: string) {
* @returns {Function}
*/
export function hangup(_requestFeedback = false) {
return (dispatch: IStore['dispatch']) => {
dispatch(conferenceWillLeave());
dispatch(appNavigate(undefined));
};
return (dispatch: IStore['dispatch']) => dispatch(appNavigate(undefined));
}

View File

@@ -8,14 +8,13 @@ import i18next from './i18next';
*
* @param {string} language - The language e.g. 'en', 'fr'.
* @param {string} url - The url of the translation bundle.
* @param {string} ns - The namespace of the translation bundle.
* @returns {void}
*/
export async function changeLanguageBundle(language: string, url: string, ns = 'main') {
export async function changeLanguageBundle(language: string, url: string) {
const res = await fetch(url);
const bundle = await res.json();
i18next.addResourceBundle(language, ns, bundle, true, true);
i18next.addResourceBundle(language, 'main', bundle, true, true);
}
/**

View File

@@ -58,14 +58,6 @@ export const DEFAULT_LANGUAGE = 'en';
*/
export const TRANSLATION_LANGUAGES_HEAD: Array<string> = [ DEFAULT_LANGUAGE ];
/**
* The available/supported i18n namespaces.
*
* @public
* @type {Array<string>}
*/
export const SUPPORTED_NS = [ 'main', 'languages', 'countries', 'translation-languages' ];
/**
* The options to initialize i18next with.
*
@@ -89,7 +81,7 @@ const options: i18next.InitOptions = {
escapeValue: false // not needed for react as it escapes by default
},
load: 'all',
ns: SUPPORTED_NS,
ns: [ 'main', 'languages', 'countries', 'translation-languages' ],
react: {
// re-render when a new resource bundle is added
// @ts-expect-error. Fixed in i18next 19.6.1.

View File

@@ -4,7 +4,7 @@ import MiddlewareRegistry from '../redux/MiddlewareRegistry';
import { I18NEXT_INITIALIZED, LANGUAGE_CHANGED } from './actionTypes';
import { changeLanguageBundle } from './functions';
import i18next, { SUPPORTED_NS } from './i18next';
import i18next from './i18next';
import logger from './logger';
/**
@@ -19,10 +19,9 @@ MiddlewareRegistry.register(store => next => action => {
case LANGUAGE_CHANGED:
case SET_DYNAMIC_BRANDING_DATA: {
const { language } = i18next;
const data = action.type === SET_DYNAMIC_BRANDING_DATA
const { labels } = action.type === SET_DYNAMIC_BRANDING_DATA
? action.value
: store.getState()['features/dynamic-branding'];
const labels = data?.labels;
if (language && labels?.[language]) {
changeLanguageBundle(language, labels[language])
@@ -31,17 +30,6 @@ MiddlewareRegistry.register(store => next => action => {
});
}
SUPPORTED_NS.forEach(ns => {
const nsLabels = data?.[`labels-${ns}`];
if (language && nsLabels?.[language]) {
changeLanguageBundle(language, nsLabels[language], ns)
.catch(err => {
logger.log(`Error setting dynamic language bundle for ${ns}`, err);
});
}
});
// Update transcription language, if applicable.
if (action.type === SET_DYNAMIC_BRANDING_DATA) {
const { defaultTranscriptionLanguage } = action.value;

View File

@@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-sparkles-icon lucide-sparkles"><path d="M11.017 2.814a1 1 0 0 1 1.966 0l1.051 5.558a2 2 0 0 0 1.594 1.594l5.558 1.051a1 1 0 0 1 0 1.966l-5.558 1.051a2 2 0 0 0-1.594 1.594l-1.051 5.558a1 1 0 0 1-1.966 0l-1.051-5.558a2 2 0 0 0-1.594-1.594l-5.558-1.051a1 1 0 0 1 0-1.966l5.558-1.051a2 2 0 0 0 1.594-1.594z"/><path d="M20 2v4"/><path d="M22 4h-4"/><circle cx="4" cy="20" r="2"/></svg>

Before

Width:  |  Height:  |  Size: 582 B

View File

@@ -1,4 +1,3 @@
import { default as IconAI } from './AI.svg';
import { default as IconRecordAccount } from './account-record.svg';
import { default as IconAddUser } from './add-user.svg';
import { default as IconArrowBack } from './arrow-back.svg';
@@ -113,7 +112,6 @@ import { default as IconYahoo } from './yahoo.svg';
*/
export const DEFAULT_ICON: Record<string, any> = {
IconAddUser,
IconAI,
IconArrowBack,
IconArrowDown,
IconArrowDownLarge,

View File

@@ -4,7 +4,6 @@ import { DEFAULT_ICON } from './constants';
const {
IconAddUser,
IconAI,
IconArrowBack,
IconArrowDown,
IconArrowDownLarge,
@@ -124,7 +123,6 @@ const {
export {
IconAddUser,
IconAI,
IconArrowBack,
IconArrowDown,
IconArrowDownLarge,

View File

@@ -10,10 +10,6 @@ import { parseURLParams } from '../util/parseURLParams';
import { JWT_VALIDATION_ERRORS, MEET_FEATURES } from './constants';
import logger from './logger';
/**
* Note that this is just client-side code and it intentionally does not verify the signature of the JWT.
*/
/**
* Retrieves the JSON Web Token (JWT), if any, defined by a specific
* {@link URL}.

View File

@@ -56,9 +56,9 @@ const useStyles = makeStyles()(theme => {
label: {
...theme.typography.labelRegular,
alignItems: 'center',
background: theme.palette.labelBackground,
background: theme.palette.ui04,
borderRadius: '4px',
color: theme.palette.labelText,
color: theme.palette.text01,
display: 'flex',
margin: '0 2px',
padding: '6px',
@@ -72,11 +72,11 @@ const useStyles = makeStyles()(theme => {
cursor: 'pointer'
},
[COLORS.white]: {
background: theme.palette.labelWhiteBackground,
color: theme.palette.labelWhiteText,
background: theme.palette.ui09,
color: theme.palette.text04,
'& svg': {
fill: theme.palette.labelWhiteIcon
fill: theme.palette.icon04
}
},
[COLORS.green]: {

View File

@@ -1,5 +1,4 @@
import { IReduxState, IStore } from '../../app/types';
import { getLocalParticipant } from '../participants/functions';
import StateListenerRegistry from '../redux/StateListenerRegistry';
/**
@@ -14,13 +13,6 @@ StateListenerRegistry.register(
if (muted !== previousMuted) {
APP.API.notifyAudioMutedStatusChanged(muted);
// Also fire the participantMuted event for consistency
const localParticipant = getLocalParticipant(store.getState());
if (localParticipant) {
APP.API.notifyParticipantMuted(localParticipant.id, muted, 'audio');
}
}
}
);

View File

@@ -17,7 +17,7 @@ interface IProps {
/**
* The children component(s) of the Modal, to be rendered.
*/
children?: React.ReactNode;
children: React.ReactNode;
/**
* Additional style to be appended to the KeyboardAvoidingView content container.
@@ -63,7 +63,7 @@ const JitsiScreen = ({
footerComponent,
hasBottomTextInput = false,
hasExtraHeaderHeight = false,
safeAreaInsets = [ 'bottom', 'left', 'right' ],
safeAreaInsets = [ 'left', 'right' ],
style
}: IProps) => {
const renderContent = () => (
@@ -78,8 +78,8 @@ const JitsiScreen = ({
edges = { safeAreaInsets }
style = { styles.safeArea }>
{ children }
{ footerComponent?.() }
</SafeAreaView>
{ footerComponent?.() }
</JitsiKeyboardAvoidingView>
);

View File

@@ -606,21 +606,13 @@ function _e2eeUpdated({ getState, dispatch }: IStore, conference: IJitsiConferen
function _localParticipantJoined({ getState, dispatch }: IStore, next: Function, action: AnyAction) {
const result = next(action);
const state = getState();
const settings = state['features/base/settings'];
const jwtUser = state['features/base/jwt']?.user;
const userContext = jwtUser ? {
id: jwtUser.id,
name: jwtUser.name
} : undefined;
const settings = getState()['features/base/settings'];
dispatch(localParticipantJoined({
avatarURL: settings.avatarURL,
email: settings.email,
name: settings.displayName,
id: '',
userContext
id: ''
}));
return result;

View File

@@ -627,8 +627,7 @@ function _participantJoined({ participant }: { participant: IParticipant; }) {
pinned,
presence,
role,
sources,
userContext
sources
} = participant;
let { conference, id } = participant;
@@ -660,8 +659,7 @@ function _participantJoined({ participant }: { participant: IParticipant; }) {
pinned: pinned || false,
presence,
role: role || PARTICIPANT_ROLE.NONE,
sources,
userContext
sources
};
}

View File

@@ -41,12 +41,6 @@ export interface IParticipant {
role?: string;
sources?: Map<string, Map<string, ISourceInfo>>;
supportsRemoteControl?: boolean;
userContext?: IUserContext;
}
export interface IUserContext {
id?: string;
name?: string;
}
export interface ILocalParticipant extends IParticipant {

View File

@@ -84,7 +84,7 @@ const useStyles = makeStyles()(theme => {
...theme.typography.bodyLongBold,
borderRadius: theme.shape.borderRadius,
boxSizing: 'border-box',
color: theme.palette.actionButtonText,
color: theme.palette.text01,
cursor: 'pointer',
display: 'inline-block',
marginBottom: '16px',
@@ -95,20 +95,20 @@ const useStyles = makeStyles()(theme => {
border: 0,
'&.primary': {
background: theme.palette.prejoinActionButtonPrimary,
color: theme.palette.prejoinActionButtonPrimaryText,
background: theme.palette.action01,
color: theme.palette.text01,
'&:hover': {
backgroundColor: theme.palette.prejoinActionButtonPrimaryHover
backgroundColor: theme.palette.action01Hover
}
},
'&.secondary': {
background: theme.palette.prejoinActionButtonSecondary,
color: theme.palette.prejoinActionButtonSecondaryText,
background: theme.palette.action02,
color: theme.palette.text04,
'&:hover': {
backgroundColor: theme.palette.prejoinActionButtonSecondaryHover
backgroundColor: theme.palette.action02Hover
}
},
@@ -120,7 +120,7 @@ const useStyles = makeStyles()(theme => {
},
'&.disabled': {
background: theme.palette.prejoinActionButtonDisabled,
background: theme.palette.disabled01,
border: '1px solid #5E6D7A',
color: '#AFB6BC',
cursor: 'initial',

View File

@@ -109,7 +109,7 @@ const useStyles = makeStyles()(theme => {
position: 'absolute',
inset: '0 0 0 0',
display: 'flex',
backgroundColor: theme.palette.preMeetingBackground,
backgroundColor: theme.palette.ui01,
zIndex: 252,
'@media (max-width: 720px)': {
@@ -163,7 +163,7 @@ const useStyles = makeStyles()(theme => {
},
title: {
...theme.typography.heading4,
color: theme.palette.prejoinTitleText,
color: `${theme.palette.text01}!important`,
marginBottom: theme.spacing(3),
textAlign: 'center',
@@ -179,7 +179,7 @@ const useStyles = makeStyles()(theme => {
roomName: {
...theme.typography.heading5,
color: theme.palette.prejoinRoomNameText,
color: theme.palette.text01,
display: 'inline-block',
overflow: 'hidden',
textOverflow: 'ellipsis',

View File

@@ -6,7 +6,7 @@ const useStyles = makeStyles()(theme => {
return {
warning: {
bottom: 0,
color: theme.palette.prejoinRecordingWarningText,
color: theme.palette.text03,
display: 'flex',
justifyContent: 'center',
...theme.typography.bodyShortRegular,

View File

@@ -11,8 +11,8 @@ import { setUnsafeRoomConsent } from '../../actions.web';
const useStyles = makeStyles()(theme => {
return {
warning: {
backgroundColor: theme.palette.prejoinWarningBackground,
color: theme.palette.prejoinWarningText,
backgroundColor: theme.palette.warning01,
color: theme.palette.text04,
...theme.typography.bodyShortRegular,
padding: theme.spacing(3),
borderRadius: theme.shape.borderRadius,

View File

@@ -9,11 +9,11 @@ import { getSupportUrl } from '../../functions';
const useStyles = makeStyles()(theme => {
return {
dialog: {
backgroundColor: theme.palette.dialogBackground,
border: `1px solid ${theme.palette.inlineDialogBorder}`,
backgroundColor: theme.palette.ui01,
border: `1px solid ${theme.palette.ui04}`,
borderRadius: `${Number(theme.shape.borderRadius)}px`,
boxShadow: '0px 1px 2px rgba(41, 41, 41, 0.25)',
color: theme.palette.dialogText,
color: theme.palette.text01,
...theme.typography.bodyShortRegular,
padding: `${theme.spacing(3)} 10`,
'& .retry-button': {

View File

@@ -2,7 +2,6 @@ import { batch } from 'react-redux';
import { IStore } from '../../app/types';
import { CHAT_SIZE } from '../../chat/constants';
import { getCustomPanelWidth } from '../../custom-panel/functions';
import { getParticipantsPaneWidth } from '../../participants-pane/functions';
import {
@@ -44,7 +43,6 @@ export function clientResized(clientWidth: number, clientHeight: number) {
if (navigator.product !== 'ReactNative') {
const state = getState();
const { reducedUIEnabled = true } = state['features/base/config'];
const { isOpen: isChatOpen, width } = state['features/chat'];
if (isChatOpen) {
@@ -52,9 +50,8 @@ export function clientResized(clientWidth: number, clientHeight: number) {
}
availableWidth -= getParticipantsPaneWidth(state);
availableWidth -= getCustomPanelWidth(state);
reducedUIEnabled && dispatch(setReducedUI(availableWidth, clientHeight));
dispatch(setReducedUI(availableWidth, clientHeight));
}
batch(() => {
@@ -115,7 +112,7 @@ export function setReducedUI(width: number, height: number) {
const threshold = navigator.product === 'ReactNative'
? REDUCED_UI_THRESHOLD
: WEB_REDUCED_UI_THRESHOLD;
const reducedUI = Math.max(width, height) < threshold;
const reducedUI = Math.min(width, height) < threshold;
if (reducedUI !== getState()['features/base/responsive-ui'].reducedUI) {
return dispatch({

View File

@@ -22,11 +22,11 @@ interface IProps {
const useStyles = makeStyles()(theme => {
return {
container: {
backgroundColor: theme.palette.tooltipBackground,
backgroundColor: theme.palette.uiBackground,
borderRadius: '3px',
padding: theme.spacing(2),
...theme.typography.labelRegular,
color: theme.palette.tooltipText,
color: theme.palette.text01,
position: 'relative',
'&.mounting-animation': {

View File

@@ -29,7 +29,6 @@ import {
TRACK_UPDATED,
TRACK_WILL_CREATE
} from './actionTypes';
import { toggleScreensharing } from './actions';
import {
createLocalTracksF,
getCameraFacingMode,
@@ -386,22 +385,8 @@ export function trackAdded(track: any) {
const mediaType = track.getVideoType() === VIDEO_TYPE.DESKTOP
? MEDIA_TYPE.SCREENSHARE
: track.getType();
let isReceivingData, noDataFromSourceNotificationInfo, participantId;
// Make screen share toggle off listen to MediaStreamTrack "ended" event
// when it's terminated via Android status bar chip.
if (navigator.product === 'ReactNative') {
const mediaStreamTrack = track?.getTrack?.();
if (mediaType === MEDIA_TYPE.SCREENSHARE) {
const onEnded = () => dispatch(toggleScreensharing(false));
mediaStreamTrack.addEventListener('ended', onEnded);
track._onEnded = onEnded;
}
}
if (local) {
// Reset the no data from src notification state when we change the track, as it's context is set
// on a per device basis.
@@ -583,16 +568,6 @@ export function trackRemoved(track: any): {
track.removeAllListeners(JitsiTrackEvents.TRACK_VIDEOTYPE_CHANGED);
track.removeAllListeners(JitsiTrackEvents.NO_DATA_FROM_SOURCE);
// Remove MediaStreamTrack "ended" event.
if (navigator.product === 'ReactNative') {
const mediaStreamTrack = track?.getTrack?.();
if (track._onEnded) {
mediaStreamTrack.removeEventListener('ended', track._onEnded);
delete track._onEnded;
}
}
return {
type: TRACK_REMOVED,
track: {

View File

@@ -51,7 +51,7 @@ import './subscriber.web';
MiddlewareRegistry.register(store => next => action => {
switch (action.type) {
case TRACK_ADDED: {
const { local, jitsiTrack } = action.track;
const { local } = action.track;
// The devices list needs to be refreshed when no initial video permissions
// were granted and a local video track is added by umuting the video.
@@ -65,16 +65,6 @@ MiddlewareRegistry.register(store => next => action => {
if (participantId) {
logTracksForParticipant(store.getState()['features/base/tracks'], participantId, 'Track added');
// Fire participantMuted event for initial state of remote tracks
if (typeof action.track?.muted !== 'undefined' && jitsiTrack) {
const isVideoTrack = jitsiTrack.getType() !== MEDIA_TYPE.AUDIO;
const mediaType = isVideoTrack
? (jitsiTrack.getVideoType() === VIDEO_TYPE.DESKTOP ? 'desktop' : 'video')
: 'audio';
APP.API.notifyParticipantMuted(participantId, action.track.muted, mediaType);
}
}
return result;
@@ -129,16 +119,6 @@ MiddlewareRegistry.register(store => next => action => {
// TODO Remove the following calls to APP.UI once components interested
// in track mute changes are moved into React and/or redux.
const { jitsiTrack } = action.track;
const participantID = jitsiTrack.getParticipantId();
const isVideoTrack = jitsiTrack.type !== MEDIA_TYPE.AUDIO;
const local = jitsiTrack.isLocal();
// Get old muted state BEFORE updating
const tracks = store.getState()['features/base/tracks'];
const oldTrack = tracks.find((t: ITrack) => t.jitsiTrack === jitsiTrack);
const oldMutedState = oldTrack?.muted;
const result = next(action);
const state = store.getState();
@@ -146,6 +126,11 @@ MiddlewareRegistry.register(store => next => action => {
return result;
}
const { jitsiTrack } = action.track;
const participantID = jitsiTrack.getParticipantId();
const isVideoTrack = jitsiTrack.type !== MEDIA_TYPE.AUDIO;
const local = jitsiTrack.isLocal();
if (isVideoTrack) {
if (local && !(jitsiTrack.getVideoType() === VIDEO_TYPE.DESKTOP)) {
APP.conference.setVideoMuteStatus();
@@ -159,14 +144,12 @@ MiddlewareRegistry.register(store => next => action => {
if (typeof action.track?.muted !== 'undefined' && participantID && !local) {
logTracksForParticipant(store.getState()['features/base/tracks'], participantID, 'Track updated');
// Fire participantMuted event only if muted state actually changed
if (oldMutedState !== action.track.muted) {
const mediaType = isVideoTrack
? (jitsiTrack.getVideoType() === VIDEO_TYPE.DESKTOP ? 'desktop' : 'video')
: 'audio';
// Notify external API when remote participant mutes/unmutes themselves
const mediaType = isVideoTrack
? (jitsiTrack.getVideoType() === VIDEO_TYPE.DESKTOP ? 'desktop' : 'video')
: 'audio';
APP.API.notifyParticipantMuted(participantID, action.track.muted, mediaType);
}
APP.API.notifyParticipantMuted(participantID, action.track.muted, mediaType, true);
}
return result;

View File

@@ -4,7 +4,7 @@ import { isEqual, sortBy } from 'lodash-es';
import VideoLayout from '../../../../modules/UI/videolayout/VideoLayout';
import { getAutoPinSetting } from '../../video-layout/functions.any';
import { MEDIA_TYPE } from '../media/constants';
import { getLocalParticipant, getScreenshareParticipantIds } from '../participants/functions';
import { getScreenshareParticipantIds } from '../participants/functions';
import StateListenerRegistry from '../redux/StateListenerRegistry';
import { isLocalTrackMuted } from './functions';
@@ -47,13 +47,6 @@ StateListenerRegistry.register(
/* listener */ (muted, store, previousMuted) => {
if (muted !== previousMuted) {
APP.API.notifyVideoMutedStatusChanged(muted);
// Also fire the participantMuted event for consistency
const localParticipant = getLocalParticipant(store.getState());
if (localParticipant) {
APP.API.notifyParticipantMuted(localParticipant.id, muted, 'video');
}
}
}
);

View File

@@ -1,4 +1,3 @@
/* eslint-disable @stylistic/no-multi-spaces */
// Mapping between the token used and the color
export const colorMap = {
// ----- Surfaces -----
@@ -8,7 +7,7 @@ export const colorMap = {
// - JitsiMeetView.java
uiBackground: 'surface01',
// Container backgrounds (legacy tokens)
// Container backgrounds
ui01: 'surface02',
ui02: 'surface03',
ui03: 'ui02',
@@ -48,426 +47,6 @@ export const colorMap = {
// Focus
focus01: 'focus01',
// ----- Semantic Tokens (component-based, backwards compatible) -----
// Dialog/Modal Components
dialogBackground: 'surface02', // Main dialog background (same as ui01)
dialogOverlay: 'surface03', // Overlay/backdrop (same as ui02)
dialogBorder: 'ui02', // Dialog borders
dialogText: 'textColor01', // Primary dialog text (same as text01)
dialogSecondaryText: 'textColor02', // Secondary dialog text (same as text02)
// Large Video
largeVideoBackground: 'surface03', // Main video area background (same as ui02)
largeVideoPlaceholder: 'surface03', // Placeholder when no video (same as ui02)
// Filmstrip
filmstripBackground: 'surface03', // Filmstrip container background (same as ui02)
filmstripBackgroundHover: 'uiBackground', // Filmstrip background on hover/focus
filmstripDragHandle: 'icon02', // Filmstrip resize drag handle color
filmstripDragHandleHover: 'icon01', // Filmstrip resize drag handle hover color
thumbnailBackground: 'surface03', // Individual thumbnail background (same as ui02)
thumbnailBorder: 'ui03', // Thumbnail borders (same as ui03)
thumbnailHover: 'hover05', // Thumbnail hover state (same as action03Hover)
thumbnailTintBackground: 'uiBackground', // Thumbnail tint overlay background
thumbnailRaisedHandIcon: 'uiBackground', // Thumbnail raised hand indicator icon
thumbnailVideoBackground: 'uiBackground', // Thumbnail video/placeholder background
// Chat
chatBackground: 'surface02', // Chat panel background (same as ui01)
chatBackdrop: 'ui04', // Chat screen background (same as ui10)
chatEmptyText: 'ui03', // Empty component text
chatInputBackground: 'surface03', // Chat input field background (same as ui02)
chatInputBorder: 'surface03', // Chat input border (same as ui02)
chatLink: 'action01', // Chat link color (same as link01)
chatLobbyMessageBubble: 'support06', // Lobby message bubble background
chatLobbyMessageNotice: 'surface01', // Lobby message notice text
chatLobbyRecipientContainer: 'support06', // Lobby recipient container background
chatMessageLocal: 'surface05', // Local participant message bubble (same as ui04)
chatMessagePrivate: 'support05', // Private/DM message bubble
chatMessageRemote: 'surface03', // Remote participant message bubble (same as ui02)
chatMessageText: 'textColor01', // Chat message text
chatPrivateNotice: 'textColor02', // Private message notice text
chatRecipientCancelIcon: 'icon01', // Recipient cancel icon color
chatRecipientContainer: 'support05', // Recipient container background
chatRecipientText: 'textColor01', // Recipient text color
chatReplyIcon: 'icon01', // Reply icon color
chatSenderName: 'textColor02', // Sender display name color
chatTimestamp: 'ui03', // Chat timestamp text
// Toolbox/Toolbar
toolboxBackground: 'surface02', // Main toolbox background
drawerBackground: 'surface02', // Drawer/side panel background
toolboxIconHover: 'surface05', // Toolbox icon hover background
toolboxIconActive: 'ui02', // Toolbox icon active/pressed background
toolboxIconToggled: 'ui02', // Toolbox icon toggled background
toolbarButton: 'action01', // Toolbar button color
toolbarButtonHover: 'hover01', // Toolbar button hover (same as action01Hover)
toolbarButtonActive: 'active01', // Toolbar button active/pressed state
toolbarIcon: 'icon01', // Toolbar icon color
toolbarIconHover: 'icon01', // Toolbar icon hover state
toolbarIconActive: 'action01', // Toolbar icon active/toggled state
// Overflow Menu (More Actions)
overflowMenuBackground: 'surface02', // Overflow menu background
overflowMenuBorder: 'surface05', // Overflow menu border
overflowMenuItemText: 'text01', // Overflow menu item text
overflowMenuItemIcon: 'text01', // Overflow menu item icon
overflowMenuItemHover: 'surface03', // Overflow menu item hover background
overflowMenuItemDisabled: 'text03', // Overflow menu item disabled text/icon
overflowMenuSeparator: 'ui03', // Overflow menu group separator
// Participants Pane
participantsPaneBackground: 'surface02', // Participants list background
participantItemBackground: 'surface03', // Individual participant item background
participantItemHover: 'hover05', // Participant item hover
participantItemBorder: 'ui02', // Participant item border
participantCounterBadge: 'ui02', // Participant counter badge background
participantCounterText: 'text01', // Participant counter text
participantModeratorLabel: 'text03', // Moderator label text
participantSectionText: 'text02', // Section header/subtitle text
participantActionButton: 'action02', // Action button background
participantLinkText: 'link01', // Link text color
participantWarningText: 'warning02', // Warning text color
participantRaisedHandBadge: 'warning02', // Raised hand indicator background
participantRaisedHandIcon: 'icon04', // Raised hand icon color
// Lobby
lobbyBackground: 'surface02', // Lobby screen background (same as ui01)
lobbyPreviewBackground: 'surface03', // Video preview background (same as ui02)
// Speaker Stats
speakerStatsBackground: 'surface02', // Speaker stats panel background
speakerStatsRowBackground: 'ui02', // Individual stat row background
speakerStatsRowAlternate: 'ui03', // Alternate row background
speakerStatsBorder: 'surface03', // Speaker stats borders
speakerStatsHeaderBackground: 'ui09', // Header background
speakerStatsSearchBackground: 'field01', // Search input background
speakerStatsSearchBorder: 'ui05', // Search input border
speakerStatsSearchText: 'text01', // Search input text
speakerStatsSearchPlaceholder: 'text03', // Search placeholder
speakerStatsSearchIcon: 'icon03', // Search icon color
speakerStatsLabelText: 'text03', // Label text color
speakerStatsSuccessBar: 'success02', // Success/progress bar
speakerStatsAvatarLeft: 'surface05', // Avatar background for participants who left
// Pre-meeting/Prejoin
preMeetingBackground: 'surface02', // Pre-meeting screen container background
preMeetingPreview: 'ui01', // Video preview in pre-meeting
prejoinDialogBackground: 'uiBackground', // Prejoin dialog background
prejoinDialogDelimiter: 'ui03', // Prejoin dialog delimiter line
prejoinDialogDelimiterText: 'text01', // Prejoin dialog delimiter text
prejoinTitleText: 'text01', // Prejoin title text color
prejoinRoomNameText: 'text01', // Prejoin room name text color
prejoinWarningBackground: 'warning01', // Warning banner background
prejoinWarningText: 'text04', // Warning banner text
prejoinRecordingWarningText: 'text03', // Recording warning text
prejoinActionButtonPrimary: 'action01', // Primary action button
prejoinActionButtonPrimaryHover: 'action01Hover', // Primary button hover
prejoinActionButtonPrimaryText: 'text01', // Primary button text
prejoinActionButtonSecondary: 'action02', // Secondary action button
prejoinActionButtonSecondaryHover: 'action02Hover', // Secondary button hover
prejoinActionButtonSecondaryText: 'text04', // Secondary button text
prejoinActionButtonDanger: 'actionDanger', // Danger button (leave)
prejoinActionButtonDisabled: 'disabled01', // Disabled button
prejoinCountryPickerBackground: 'ui01', // Country picker background
prejoinCountryPickerBorder: 'ui03', // Country picker border
prejoinCountryPickerText: 'text01', // Country picker text
prejoinCountryRowBackground: 'action03', // Country row background
prejoinCountryRowHover: 'action03Hover', // Country row hover
prejoinDeviceStatusOk: 'success01', // Device status OK background
prejoinDeviceStatusWarning: 'warning01', // Device status warning background
prejoinDeviceStatusText: 'uiBackground', // Device status text
// Notifications
notificationBackground: 'ui04', // Notification background
notificationNormalIcon: 'action01', // Normal notification icon
notificationError: 'iconError', // Error notification icon
notificationSuccess: 'success01', // Success notification icon
notificationWarning: 'warning01', // Warning notification icon
notificationText: 'text04', // Notification text
notificationActionText: 'action01', // Notification action text
notificationErrorText: 'textError', // Error notification text
notificationActionFocus: 'action01', // Notification action focus outline
notificationCloseIcon: 'icon04', // Notification close icon
// Forms/Inputs
inputBackground: 'field01', // Input field background
inputBorder: 'surface03', // Input field border (same as ui02)
inputText: 'textColor01', // Input field text (same as text01)
inputPlaceholder: 'textColor02', // Input placeholder text (same as text02)
// Breakout Rooms
breakoutRoomBackground: 'ui01', // Breakout rooms panel background
breakoutRoomItemBackground: 'surface03', // Individual breakout room background
breakoutRoomArrowBackground: 'ui02', // Breakout room arrow container background
// Settings
settingsBackground: 'ui01', // Settings dialog background
settingsSectionBackground: 'ui02', // Settings section background
settingsTabText: 'text01', // Settings tab text
settingsShortcutKey: 'surface05', // Keyboard shortcut key background
settingsVideoPreviewBorder: 'action01Hover', // Video preview border (selected)
settingsErrorIcon: 'iconError', // Error icon color
// Visitors
visitorsCountBadge: 'warning02', // Visitors count badge background
visitorsCountText: 'uiBackground', // Visitors count badge text
visitorsCountIcon: 'icon04', // Visitors count icon
visitorsQueueBackground: 'ui01', // Visitors queue panel background
visitorsQueueText: 'text01', // Visitors queue text
visitorsArrowBackground: 'ui02', // Visitors arrow container background
// Welcome Page
welcomeBackground: 'surface01', // Welcome page background (same as uiBackground)
welcomeCard: 'ui01', // Welcome page tab bar background
welcomeTabActive: 'icon01', // Welcome page active tab icon
welcomeTabInactive: 'icon03', // Welcome page inactive tab icon
// ----- Form Components -----
// Input
inputLabel: 'text01', // Input field label text
inputFieldBackground: 'ui02', // Input field background color
inputFieldBorder: 'ui02', // Input field border color
inputFieldText: 'text01', // Input field text color
inputFieldPlaceholder: 'text02', // Input field placeholder text
inputFieldDisabled: 'text03', // Input field disabled text
inputFieldError: 'textError', // Input field error state
inputFieldFocus: 'focus01', // Input field focus outline
inputClearButton: 'transparent', // Input clear button background
inputBottomLabel: 'text02', // Input bottom label text
inputBottomLabelError: 'textError', // Input bottom label error text
// Select
selectLabel: 'text01', // Select label text
selectBackground: 'ui02', // Select background color
selectText: 'text01', // Select text color
selectDisabled: 'text03', // Select disabled text
selectError: 'textError', // Select error state
selectFocus: 'focus01', // Select focus outline
selectIcon: 'icon01', // Select dropdown icon (enabled)
selectIconDisabled: 'icon03', // Select dropdown icon (disabled)
selectBottomLabel: 'text02', // Select bottom label text
selectBottomLabelError: 'textError', // Select bottom label error text
// MultiSelect
multiSelectBackground: 'ui01', // MultiSelect dropdown background
multiSelectBorder: 'ui04', // MultiSelect dropdown border
multiSelectItemText: 'text01', // MultiSelect item text
multiSelectItemHover: 'ui02', // MultiSelect item hover background
multiSelectItemDisabled: 'text03', // MultiSelect disabled item text
// Checkbox
checkboxLabel: 'text01', // Checkbox label text
checkboxBorder: 'icon03', // Checkbox border color
checkboxChecked: 'action01', // Checkbox checked background
checkboxDisabledBackground: 'ui02', // Checkbox disabled background
checkboxDisabledBorder: 'surface05', // Checkbox disabled border
checkboxDisabledChecked: 'ui02', // Checkbox disabled checked background
checkboxIcon: 'icon01', // Checkbox check icon (enabled)
checkboxIconDisabled: 'icon03', // Checkbox check icon (disabled)
// Switch
switchBackground: 'ui01', // Switch background (unchecked)
switchBackgroundOn: 'action01', // Switch background (checked)
switchToggle: 'ui04', // Switch toggle circle
switchToggleDisabled: 'ui03', // Switch toggle circle (disabled)
switchFocus: 'focus01', // Switch focus outline
// Tabs
tabText: 'text02', // Tab text (unselected)
tabTextHover: 'text01', // Tab text (hover)
tabTextSelected: 'text01', // Tab text (selected)
tabTextDisabled: 'text03', // Tab text (disabled)
tabBorder: 'ui05', // Tab bottom border (unselected)
tabBorderHover: 'ui10', // Tab bottom border (hover)
tabBorderSelected: 'action01', // Tab bottom border (selected)
tabBorderDisabled: 'ui05', // Tab bottom border (disabled)
tabFocus: 'focus01', // Tab focus outline
tabBadgeBackground: 'warning01', // Tab count badge background
tabBadgeText: 'text04', // Tab count badge text
// ListItem
listItemText: 'text01', // List item text color
listItemBackground: 'ui01', // List item default background
listItemHover: 'surface03', // List item hover background
listItemHighlighted: 'surface03', // List item highlighted/active background
listItemBoxShadow: 'ui02', // List item actions box shadow color
// ClickableIcon
clickableIconBackground: 'transparent', // Clickable icon background
clickableIconHover: 'ui02', // Clickable icon hover background
clickableIconActive: 'ui03', // Clickable icon active/pressed background
clickableIconFocus: 'focus01', // Clickable icon focus outline
// Label
labelBackground: 'ui04', // Label default background
labelText: 'text01', // Label text color
labelWhiteBackground: 'ui08', // Label white variant background
labelWhiteText: 'text04', // Label white variant text
labelWhiteIcon: 'surface01', // Label white variant icon
// Tooltip
tooltipBackground: 'uiBackground', // Tooltip background color
tooltipText: 'text01', // Tooltip text color
// Polls
pollsBackground: 'surface03', // Poll container background
pollsTitle: 'text01', // Poll title text
pollsSubtitle: 'text02', // Poll subtitle/secondary text
pollsQuestion: 'text01', // Poll question text
pollsAnswer: 'text01', // Poll answer text
pollsBarBackground: 'ui03', // Poll results bar background
pollsBarPercentage: 'text01', // Poll results percentage text
pollsVotersBackground: 'ui03', // Poll voters list background
pollsVotersText: 'text01', // Poll voters list text
pollsSeparator: 'ui03', // Poll section separator
pollsSendLabel: 'text01', // Poll send button label
pollsSendDisabled: 'text03', // Poll send button disabled label
pollsPaneBackground: 'ui01', // Poll pane container background
pollsPaneBorder: 'ui05', // Poll pane border
pollsCreateBackground: 'uiBackground', // Poll create dialog background
pollsCreateBorder: 'ui06', // Poll create dialog border
// Video Quality / Slider
sliderKnob: 'text01', // Slider knob/thumb color
sliderTrack: 'text03', // Slider track color
sliderFocus: 'ui06', // Slider focus outline
videoQualityText: 'text01', // Video quality dialog text
videoQualityBackground: 'surface02', // Video quality dialog background
// Connection Indicator
connectionIndicatorLost: 'ui05', // Connection indicator lost status
connectionIndicatorOther: 'action01', // Connection indicator other status
// Device Selection
deviceSelectorBackground: 'ui01', // Device selector background
deviceSelectorText: 'text01', // Device selector text
deviceSelectorBorder: 'ui03', // Device selector border
deviceSelectorTextBackground: 'uiBackground', // Device selector text-only background
deviceSelectorVideoPreview: 'uiBackground', // Device selector video preview background
// Invite / Dial-in
dialInBackground: 'ui01', // Dial-in summary background
dialInText: 'text01', // Dial-in summary text
dialInSecondaryText: 'text02', // Dial-in summary secondary text
// Reactions
reactionsMenuBackground: 'ui01', // Reactions menu background
reactionsMenuBorder: 'ui02', // Reactions menu border
// Recording / Live Stream
recordingBackground: 'ui01', // Recording panel background
recordingText: 'text01', // Recording panel text
recordingHighlightButton: 'ui04', // Recording highlight button background
recordingHighlightButtonDisabled: 'text02', // Recording highlight button disabled background
recordingHighlightButtonIcon: 'ui02', // Recording highlight button icon color
recordingHighlightButtonIconDisabled: 'text03', // Recording highlight button disabled icon color
recordingNotificationText: 'surface01', // Recording notification text color
recordingNotificationAction: 'action01', // Recording notification action color
// Virtual Background
virtualBackgroundBackground: 'ui01', // Virtual background picker background
virtualBackgroundText: 'text01', // Virtual background picker text
virtualBackgroundBorder: 'ui03', // Virtual background item border
virtualBackgroundPreview: 'uiBackground', // Virtual background preview container
// Conference / Meeting
conferenceTimerText: 'text01', // Conference timer text
conferenceSubjectText: 'text01', // Conference subject text
conferenceNoticeBackground: 'uiBackground', // Conference notice background
conferenceNoticeText: 'text01', // Conference notice text
conferenceRaisedHandLabelText: 'uiBackground', // Raised hands count label text
conferenceRaisedHandLabelIcon: 'surface01', // Raised hands count label icon
// Subtitle Messages
subtitleMessageBackground: 'ui02', // Subtitle message background
subtitleMessageText: 'text01', // Subtitle message text
subtitleMessageSender: 'text02', // Subtitle message sender name
subtitleMessageTime: 'text03', // Subtitle message timestamp
// Language Selector
languageSelectorBackground: 'ui01', // Language selector background
languageSelectorText: 'text01', // Language selector text
languageSelectorHover: 'ui02', // Language selector item hover
// Video Menu
videoMenuBackground: 'ui01', // Video menu background
videoMenuBorder: 'ui02', // Video menu border
videoMenuText: 'text01', // Video menu text
videoMenuSliderBackground: 'ui03', // Video menu slider background
// File Sharing
fileSharingBackground: 'ui01', // File sharing panel background
fileSharingText: 'text01', // File sharing text
fileSharingEmptyText: 'text02', // File sharing empty state text
fileSharingEmptyIcon: 'icon03', // File sharing empty state icon
fileSharingItemBackground: 'surface03', // File sharing item background
fileSharingItemBorder: 'ui02', // File sharing item hover/border
// Gifs
gifsBackground: 'ui01', // GIFs panel background
gifsText: 'text01', // GIFs panel text
// Whiteboard
whiteboardBackground: 'ui03', // Whiteboard background
whiteboardText: 'text01', // Whiteboard panel text
// Salesforce
salesforceSearchBackground: 'field01', // Salesforce search input background
salesforceSearchBorder: 'ui05', // Salesforce search input border
salesforceSearchText: 'dialogText', // Salesforce search input text
salesforceSearchPlaceholder: 'text03', // Salesforce search placeholder
salesforceSearchIcon: 'text03', // Salesforce search icon
// Security Dialog
securityDialogBackground: 'ui01', // Security dialog background
securityDialogText: 'text01', // Security dialog text
securityDialogSecondaryText: 'text02', // Security dialog secondary text
securityDialogBorder: 'ui07', // Security dialog border color
// Deep Linking
deepLinkingBackground: 'ui01', // Deep linking page content pane background
deepLinkingBorder: 'ui03', // Deep linking page content pane border
deepLinkingText: 'text01', // Deep linking page text
deepLinkingSeparator: 'ui03', // Deep linking separator line
deepLinkingLabelText: 'text02', // Deep linking label text
deepLinkingLink: 'link01', // Deep linking link color
// Base React Components
baseReactBackground: 'ui01', // Base react component background
baseReactText: 'text01', // Base react component text
baseReactBorder: 'ui03', // Base react component border
// Inline Dialog
inlineDialogBackground: 'ui01', // Inline dialog background
inlineDialogText: 'text01', // Inline dialog text
inlineDialogBorder: 'ui02', // Inline dialog border
// Pre-meeting / Action Button
actionButtonBackground: 'ui01', // Action button background (different from main buttons)
actionButtonText: 'text01', // Action button text
actionButtonBorder: 'ui03', // Action button border
// Audio Route Picker
audioRoutePickerBackground: 'ui01', // Audio route picker background
audioRoutePickerText: 'text01', // Audio route picker text
audioRoutePickerBorder: 'ui03', // Audio route picker border
// Etherpad
etherpadBackground: 'ui01', // Etherpad panel background
etherpadText: 'text01', // Etherpad panel text
// Display Name
displayNameBackground: 'ui01', // Display name background
displayNameText: 'text01', // Display name text
// Car Mode
carModeBackground: 'ui01', // Car mode background
carModeText: 'text01', // Car mode text
carModeBorder: 'ui03', // Car mode border
// ----- Links -----
link01: 'action01',

View File

@@ -14,7 +14,7 @@ const useStyles = makeStyles()(theme => {
width: '100%',
height: '100%',
position: 'fixed',
color: theme.palette.dialogText,
color: theme.palette.text01,
...theme.typography.bodyLongRegular,
top: 0,
left: 0,
@@ -49,13 +49,13 @@ const useStyles = makeStyles()(theme => {
height: '100%',
top: 0,
left: 0,
backgroundColor: theme.palette.dialogOverlay,
backgroundColor: theme.palette.ui02,
opacity: 0.75
},
modal: {
backgroundColor: theme.palette.dialogBackground,
border: `1px solid ${theme.palette.dialogBorder}`,
backgroundColor: theme.palette.ui01,
border: `1px solid ${theme.palette.ui03}`,
boxShadow: '0px 4px 25px 4px rgba(20, 20, 20, 0.6)',
borderRadius: `${theme.shape.borderRadius}px`,
display: 'flex',

View File

@@ -47,7 +47,7 @@ const useStyles = makeStyles()(theme => {
return {
formControl: {
...theme.typography.bodyLongRegular,
color: theme.palette.checkboxLabel,
color: theme.palette.text01,
display: 'inline-flex',
alignItems: 'center',
@@ -76,10 +76,10 @@ const useStyles = makeStyles()(theme => {
backgroundColor: 'transparent',
margin: '3px',
font: 'inherit',
color: theme.palette.checkboxBorder,
color: theme.palette.icon03,
width: '18px',
height: '18px',
border: `2px solid ${theme.palette.checkboxBorder}`,
border: `2px solid ${theme.palette.icon03}`,
borderRadius: '3px',
display: 'grid',
@@ -90,7 +90,7 @@ const useStyles = makeStyles()(theme => {
width: '18px',
height: '18px',
opacity: 0,
backgroundColor: theme.palette.checkboxChecked,
backgroundColor: theme.palette.action01,
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
@@ -104,11 +104,11 @@ const useStyles = makeStyles()(theme => {
},
'&:disabled': {
backgroundColor: theme.palette.checkboxDisabledBackground,
borderColor: theme.palette.checkboxDisabledBorder,
backgroundColor: theme.palette.ui03,
borderColor: theme.palette.ui04,
'&::before': {
backgroundColor: theme.palette.checkboxDisabledChecked
backgroundColor: theme.palette.ui04
}
},
@@ -173,7 +173,7 @@ const Checkbox = ({
<Icon
aria-hidden = { true }
className = 'checkmark'
color = { disabled ? theme.palette.checkboxIconDisabled : theme.palette.checkboxIcon }
color = { disabled ? theme.palette.icon03 : theme.palette.icon01 }
size = { 18 }
src = { IconCheck } />
</div>

View File

@@ -16,22 +16,22 @@ const useStyles = makeStyles()(theme => {
return {
button: {
padding: '2px',
backgroundColor: theme.palette.clickableIconBackground,
backgroundColor: theme.palette.action03,
border: 0,
outline: 0,
borderRadius: `${theme.shape.borderRadius}px`,
'&:hover': {
backgroundColor: theme.palette.clickableIconHover
backgroundColor: theme.palette.ui02
},
'&.focus-visible': {
outline: 0,
boxShadow: `0px 0px 0px 2px ${theme.palette.clickableIconFocus}`
boxShadow: `0px 0px 0px 2px ${theme.palette.focus01}`
},
'&:active': {
backgroundColor: theme.palette.clickableIconActive
backgroundColor: theme.palette.ui03
},
'&.is-mobile': {

View File

@@ -133,11 +133,11 @@ const MAX_HEIGHT = 400;
const useStyles = makeStyles()(theme => {
return {
contextMenu: {
backgroundColor: theme.palette.overflowMenuBackground,
border: `1px solid ${theme.palette.overflowMenuBorder}`,
backgroundColor: theme.palette.ui01,
border: `1px solid ${theme.palette.ui04}`,
borderRadius: `${Number(theme.shape.borderRadius)}px`,
boxShadow: '0px 1px 2px rgba(41, 41, 41, 0.25)',
color: theme.palette.overflowMenuItemText,
color: theme.palette.text01,
...theme.typography.bodyShortRegular,
marginTop: '48px',
position: 'absolute',

View File

@@ -122,11 +122,11 @@ const useStyles = makeStyles()(theme => {
},
'&:hover': {
backgroundColor: theme.palette.overflowMenuItemHover
backgroundColor: theme.palette.ui02
},
'&:active': {
backgroundColor: theme.palette.overflowMenuItemHover
backgroundColor: theme.palette.ui03
},
'&.focus-visible': {
@@ -137,7 +137,7 @@ const useStyles = makeStyles()(theme => {
selected: {
borderLeft: `3px solid ${theme.palette.action01Hover}`,
paddingLeft: '13px',
backgroundColor: theme.palette.overflowMenuItemHover
backgroundColor: theme.palette.ui02
},
contextMenuItemDisabled: {
@@ -146,19 +146,19 @@ const useStyles = makeStyles()(theme => {
contextMenuItemIconDisabled: {
'& svg': {
fill: `${theme.palette.overflowMenuItemDisabled} !important`
fill: `${theme.palette.text03} !important`
}
},
contextMenuItemLabelDisabled: {
color: theme.palette.overflowMenuItemDisabled,
color: theme.palette.text03,
'&:hover': {
background: 'none'
},
'& svg': {
fill: theme.palette.overflowMenuItemDisabled
fill: theme.palette.text03
}
},
@@ -168,13 +168,13 @@ const useStyles = makeStyles()(theme => {
contextMenuItemIcon: {
'& svg': {
fill: theme.palette.overflowMenuItemIcon
fill: theme.palette.icon01
}
},
text: {
...theme.typography.bodyShortRegular,
color: theme.palette.overflowMenuItemText
color: theme.palette.text01
},
drawerText: {

View File

@@ -30,7 +30,7 @@ const useStyles = makeStyles()(theme => {
},
'& + &:not(:empty)': {
borderTop: `1px solid ${theme.palette.overflowMenuSeparator}`
borderTop: `1px solid ${theme.palette.ui03}`
},
'&:first-of-type': {

View File

@@ -24,7 +24,7 @@ const useStyles = makeStyles()(theme => {
},
title: {
color: theme.palette.dialogText,
color: theme.palette.text01,
...theme.typography.heading5,
margin: 0,
padding: 0

View File

@@ -42,7 +42,7 @@ const useStyles = makeStyles()(theme => {
flexDirection: 'column',
minWidth: '211px',
maxWidth: '100%',
borderRight: `1px solid ${theme.palette.dialogBorder}`,
borderRight: `1px solid ${theme.palette.ui03}`,
[`@media (max-width: ${MOBILE_BREAKPOINT}px)`]: {
width: '100%',
@@ -70,7 +70,7 @@ const useStyles = makeStyles()(theme => {
title: {
...theme.typography.heading5,
color: `${theme.palette.dialogText} !important`,
color: `${theme.palette.text01} !important`,
margin: 0,
padding: 0
},
@@ -301,7 +301,7 @@ const DialogWithTabs = ({
}
return null;
}, [ selectedTabIndex, tabStates, tabs ]);
}, [ selectedTabIndex, tabStates ]);
const closeIcon = useMemo(() => (
<ClickableIcon

View File

@@ -49,7 +49,7 @@ const useStyles = makeStyles()(theme => {
},
label: {
color: theme.palette.inputLabel,
color: theme.palette.text01,
...theme.typography.bodyShortRegular,
marginBottom: theme.spacing(2),
@@ -64,9 +64,9 @@ const useStyles = makeStyles()(theme => {
},
input: {
backgroundColor: theme.palette.inputFieldBackground,
background: theme.palette.inputFieldBackground,
color: theme.palette.inputFieldText,
backgroundColor: theme.palette.ui03,
background: theme.palette.ui03,
color: theme.palette.text01,
...theme.typography.bodyShortRegular,
padding: '10px 16px',
borderRadius: theme.shape.borderRadius,
@@ -76,16 +76,16 @@ const useStyles = makeStyles()(theme => {
width: '100%',
'&::placeholder': {
color: theme.palette.inputFieldPlaceholder
color: theme.palette.text02
},
'&:focus': {
outline: 0,
boxShadow: `0px 0px 0px 2px ${theme.palette.inputFieldFocus}`
boxShadow: `0px 0px 0px 2px ${theme.palette.focus01}`
},
'&:disabled': {
color: theme.palette.inputFieldDisabled
color: theme.palette.text03
},
'&.is-mobile': {
@@ -99,7 +99,7 @@ const useStyles = makeStyles()(theme => {
},
'&.error': {
boxShadow: `0px 0px 0px 2px ${theme.palette.inputFieldError}`
boxShadow: `0px 0px 0px 2px ${theme.palette.textError}`
},
'&.clearable-input': {
paddingRight: '46px'
@@ -107,12 +107,12 @@ const useStyles = makeStyles()(theme => {
},
'input::-webkit-outer-spin-button, input::-webkit-inner-spin-button': {
WebkitAppearance: 'none',
'-webkit-appearance': 'none',
margin: 0
},
'input[type=number]': {
MozAppearance: 'textfield'
'-moz-appearance': 'textfield'
},
icon: {
@@ -131,7 +131,7 @@ const useStyles = makeStyles()(theme => {
right: '16px',
top: '10px',
cursor: 'pointer',
backgroundColor: theme.palette.inputClearButton,
backgroundColor: theme.palette.action03,
border: 0,
padding: 0
},
@@ -139,14 +139,14 @@ const useStyles = makeStyles()(theme => {
bottomLabel: {
marginTop: theme.spacing(2),
...theme.typography.labelRegular,
color: theme.palette.inputBottomLabel,
color: theme.palette.text02,
'&.is-mobile': {
...theme.typography.bodyShortRegular
},
'&.error': {
color: theme.palette.inputBottomLabelError
color: theme.palette.textError
}
}
};

View File

@@ -83,7 +83,7 @@ const useStyles = makeStyles()(theme => {
return {
container: {
alignItems: 'center',
color: theme.palette.listItemText,
color: theme.palette.text01,
display: 'flex',
...theme.typography.bodyShortBold,
margin: `0 -${participantsPaneTheme.panePadding}px`,
@@ -93,7 +93,7 @@ const useStyles = makeStyles()(theme => {
minHeight: '40px',
'&:hover, &:focus-within': {
backgroundColor: theme.palette.listItemHover,
backgroundColor: theme.palette.ui02,
'& .indicators': {
display: 'none'
@@ -103,8 +103,8 @@ const useStyles = makeStyles()(theme => {
display: 'flex',
position: 'relative',
top: 'auto',
boxShadow: `-15px 0px 10px -5px ${theme.palette.listItemBoxShadow}`,
backgroundColor: theme.palette.listItemHover
boxShadow: `-15px 0px 10px -5px ${theme.palette.ui02}`,
backgroundColor: theme.palette.ui02
}
},
@@ -115,14 +115,14 @@ const useStyles = makeStyles()(theme => {
},
highlighted: {
backgroundColor: theme.palette.listItemHighlighted,
backgroundColor: theme.palette.ui02,
'& .actions': {
display: 'flex',
position: 'relative',
top: 'auto',
boxShadow: `-15px 0px 10px -5px ${theme.palette.listItemBoxShadow}`,
backgroundColor: theme.palette.listItemHighlighted
boxShadow: `-15px 0px 10px -5px ${theme.palette.ui02}`,
backgroundColor: theme.palette.ui02
}
},
@@ -170,20 +170,20 @@ const useStyles = makeStyles()(theme => {
actionsContainer: {
position: 'absolute',
top: '-1000px',
boxShadow: `-15px 0px 10px -5px ${theme.palette.listItemBoxShadow}`,
backgroundColor: theme.palette.listItemHover
boxShadow: `-15px 0px 10px -5px ${theme.palette.ui02}`,
backgroundColor: theme.palette.ui02
},
actionsPermanent: {
display: 'flex',
boxShadow: `-15px 0px 10px -5px ${theme.palette.listItemBackground}`,
backgroundColor: theme.palette.listItemBackground
boxShadow: `-15px 0px 10px -5px ${theme.palette.ui01}`,
backgroundColor: theme.palette.ui01
},
actionsVisible: {
display: 'flex',
boxShadow: `-15px 0px 10px -5px ${theme.palette.listItemBoxShadow}`,
backgroundColor: theme.palette.listItemHighlighted
boxShadow: `-15px 0px 10px -5px ${theme.palette.ui02}`,
backgroundColor: theme.palette.ui02
}
};
});

View File

@@ -38,8 +38,8 @@ const useStyles = makeStyles()(theme => {
},
marginTop: theme.spacing(2),
width: '100%',
backgroundColor: theme.palette.multiSelectBackground,
border: `1px solid ${theme.palette.multiSelectBorder}`,
backgroundColor: theme.palette.ui01,
border: `1px solid ${theme.palette.ui04}`,
borderRadius: `${Number(theme.shape.borderRadius)}px`,
...theme.typography.bodyShortRegular,
zIndex: 2,
@@ -57,7 +57,7 @@ const useStyles = makeStyles()(theme => {
inlineSize: 'calc(100% - 38px)',
overflowWrap: 'break-word',
marginLeft: theme.spacing(2),
color: theme.palette.multiSelectItemText,
color: theme.palette.text01,
'&.with-remove': {
// 60px because of the icon before the content and the remove button
inlineSize: 'calc(100% - 60px)',
@@ -76,15 +76,15 @@ const useStyles = makeStyles()(theme => {
cursor: 'pointer',
padding: `10px ${theme.spacing(3)}`,
'&:hover': {
backgroundColor: theme.palette.multiSelectItemHover
backgroundColor: theme.palette.ui02
}
},
'&.disabled': {
cursor: 'not-allowed',
'&:hover': {
backgroundColor: theme.palette.multiSelectBackground
backgroundColor: theme.palette.ui01
},
color: theme.palette.multiSelectItemDisabled
color: theme.palette.text03
}
},
errorMessage: {

View File

@@ -70,7 +70,7 @@ const useStyles = makeStyles()(theme => {
},
label: {
color: theme.palette.selectLabel,
color: theme.palette.text01,
...theme.typography.bodyShortRegular,
marginBottom: theme.spacing(2),
@@ -84,11 +84,11 @@ const useStyles = makeStyles()(theme => {
},
select: {
backgroundColor: theme.palette.selectBackground,
backgroundColor: theme.palette.ui03,
borderRadius: `${theme.shape.borderRadius}px`,
width: '100%',
...theme.typography.bodyShortRegular,
color: theme.palette.selectText,
color: theme.palette.text01,
padding: '10px 16px',
paddingRight: '42px',
border: 0,
@@ -99,11 +99,11 @@ const useStyles = makeStyles()(theme => {
'&:focus': {
outline: 0,
boxShadow: `0px 0px 0px 2px ${theme.palette.selectFocus}`
boxShadow: `0px 0px 0px 2px ${theme.palette.focus01}`
},
'&:disabled': {
color: theme.palette.selectDisabled
color: theme.palette.text03
},
'&.is-mobile': {
@@ -113,7 +113,7 @@ const useStyles = makeStyles()(theme => {
},
'&.error': {
boxShadow: `0px 0px 0px 2px ${theme.palette.selectError}`
boxShadow: `0px 0px 0px 2px ${theme.palette.textError}`
}
},
@@ -132,14 +132,14 @@ const useStyles = makeStyles()(theme => {
bottomLabel: {
marginTop: theme.spacing(2),
...theme.typography.labelRegular,
color: theme.palette.selectBottomLabel,
color: theme.palette.text02,
'&.is-mobile': {
...theme.typography.bodyShortRegular
},
'&.error': {
color: theme.palette.selectBottomLabelError
color: theme.palette.textError
}
}
};
@@ -180,7 +180,7 @@ const Select = ({
</select>
<Icon
className = { cx(classes.icon, isMobile && 'is-mobile') }
color = { disabled ? theme.palette.selectIconDisabled : theme.palette.selectIcon }
color = { disabled ? theme.palette.icon03 : theme.palette.icon01 }
size = { 22 }
src = { IconArrowDown } />
</div>

View File

@@ -18,7 +18,7 @@ const useStyles = makeStyles()(theme => {
return {
container: {
position: 'relative',
backgroundColor: theme.palette.switchBackground,
backgroundColor: theme.palette.ui05,
borderRadius: '12px',
width: '40px',
height: '24px',
@@ -29,11 +29,11 @@ const useStyles = makeStyles()(theme => {
display: 'inline-block',
'&.disabled': {
backgroundColor: theme.palette.switchBackground,
backgroundColor: theme.palette.ui05,
cursor: 'default',
'& .toggle': {
backgroundColor: theme.palette.switchToggleDisabled
backgroundColor: theme.palette.ui03
}
},
@@ -45,7 +45,7 @@ const useStyles = makeStyles()(theme => {
},
containerOn: {
backgroundColor: theme.palette.switchBackgroundOn
backgroundColor: theme.palette.action01
},
toggle: {
@@ -55,7 +55,7 @@ const useStyles = makeStyles()(theme => {
zIndex: 5,
top: '4px',
left: '4px',
backgroundColor: theme.palette.switchToggle,
backgroundColor: theme.palette.ui10,
borderRadius: '100%',
transition: '.3s',
@@ -87,7 +87,7 @@ const useStyles = makeStyles()(theme => {
'&.focus-visible + .toggle-checkbox-ring': {
outline: 0,
boxShadow: `0px 0px 0px 2px ${theme.palette.switchFocus}`
boxShadow: `0px 0px 0px 2px ${theme.palette.focus01}`
}
},

View File

@@ -29,13 +29,13 @@ const useStyles = makeStyles()(theme => {
tab: {
...theme.typography.bodyShortBold,
color: theme.palette.tabText,
color: theme.palette.text02,
flex: 1,
padding: '14px',
background: 'none',
border: 0,
appearance: 'none',
borderBottom: `2px solid ${theme.palette.tabBorder}`,
borderBottom: `2px solid ${theme.palette.ui05}`,
transition: 'color, border-color 0.2s',
display: 'flex',
alignItems: 'center',
@@ -43,25 +43,25 @@ const useStyles = makeStyles()(theme => {
borderRadius: 0,
'&:hover': {
color: theme.palette.tabTextHover,
borderColor: theme.palette.tabBorderHover
color: theme.palette.text01,
borderColor: theme.palette.ui10
},
'&.focus-visible': {
outline: 0,
boxShadow: `0px 0px 0px 2px ${theme.palette.tabFocus}`,
boxShadow: `0px 0px 0px 2px ${theme.palette.focus01}`,
border: 0,
color: theme.palette.tabTextSelected
color: theme.palette.text01
},
'&.selected': {
color: theme.palette.tabTextSelected,
borderColor: theme.palette.tabBorderSelected
color: theme.palette.text01,
borderColor: theme.palette.action01
},
'&:disabled': {
color: theme.palette.tabTextDisabled,
borderColor: theme.palette.tabBorderDisabled
color: theme.palette.text03,
borderColor: theme.palette.ui05
},
'&.is-mobile': {
@@ -72,9 +72,9 @@ const useStyles = makeStyles()(theme => {
badge: {
...theme.typography.labelBold,
alignItems: 'center',
backgroundColor: theme.palette.tabBadgeBackground,
backgroundColor: theme.palette.warning01,
borderRadius: theme.spacing(2),
color: theme.palette.tabBadgeText,
color: theme.palette.text04,
display: 'inline-flex',
height: theme.spacing(3),
justifyContent: 'center',

View File

@@ -11,23 +11,6 @@ export * from './constants.any';
*/
export const commonStyles = (theme: Theme) => {
return {
':root': {
// Inject semantic tokens as CSS custom properties for use in SCSS
'--toolbox-background-color': theme.palette.toolboxBackground,
'--drawer-background-color': theme.palette.drawerBackground,
'--toolbar-button-color': theme.palette.toolbarButton,
'--toolbar-button-hover-color': theme.palette.toolbarButtonHover,
'--toolbar-button-active-color': theme.palette.toolbarButtonActive,
'--toolbar-icon-color': theme.palette.toolbarIcon,
'--toolbar-icon-hover-color': theme.palette.toolbarIconHover,
'--toolbar-icon-active-color': theme.palette.toolbarIconActive,
'--overflow-menu-background-color': theme.palette.overflowMenuBackground,
'--overflow-menu-item-text-color': theme.palette.overflowMenuItemText,
'--overflow-menu-item-icon-color': theme.palette.overflowMenuItemIcon,
'--overflow-menu-item-hover-color': theme.palette.overflowMenuItemHover,
'--overflow-menu-item-disabled-color': theme.palette.overflowMenuItemDisabled
},
'.empty-list': {
listStyleType: 'none',
margin: 0,
@@ -56,7 +39,7 @@ export const commonStyles = (theme: Theme) => {
'.overflow-menu-item': {
alignItems: 'center',
color: theme.palette.overflowMenuItemText,
color: theme.palette.text01,
cursor: 'pointer',
display: 'flex',
fontSize: '0.875rem',
@@ -76,20 +59,20 @@ export const commonStyles = (theme: Theme) => {
'&.disabled': {
cursor: 'initial',
color: theme.palette.overflowMenuItemDisabled,
color: theme.palette.text03,
'&:hover': {
background: 'none'
},
'& svg': {
fill: theme.palette.overflowMenuItemDisabled
fill: theme.palette.text03
}
},
'@media (hover: hover) and (pointer: fine)': {
'&:hover': {
background: theme.palette.overflowMenuItemHover
background: theme.palette.action02Hover
},
'&.unclickable:hover': {
background: 'inherit'
@@ -117,14 +100,14 @@ export const commonStyles = (theme: Theme) => {
},
'& svg': {
fill: theme.palette.overflowMenuItemIcon,
fill: theme.palette.text01,
height: 20,
width: 20
}
},
'.prejoin-dialog': {
backgroundColor: theme.palette.prejoinDialogBackground,
backgroundColor: theme.palette.uiBackground,
boxShadow: '0px 2px 20px rgba(0, 0, 0, 0.5)',
borderRadius: theme.shape.borderRadius,
color: '#fff',
@@ -190,7 +173,7 @@ export const commonStyles = (theme: Theme) => {
},
'.prejoin-dialog-delimiter': {
background: theme.palette.prejoinDialogDelimiter,
background: theme.palette.ui03,
border: '0',
height: '1px',
margin: '0',
@@ -211,8 +194,8 @@ export const commonStyles = (theme: Theme) => {
},
'.prejoin-dialog-delimiter-txt': {
background: theme.palette.prejoinDialogBackground,
color: theme.palette.prejoinDialogDelimiterText,
background: theme.palette.uiBackground,
color: theme.palette.text01,
fontSize: '0.75rem',
textTransform: 'uppercase' as const,
padding: `0 ${theme.spacing(2)}`
@@ -236,11 +219,11 @@ export const commonStyles = (theme: Theme) => {
'@media (hover: hover) and (pointer: fine)': {
'&:hover': {
backgroundColor: theme.palette.toolboxIconHover
backgroundColor: theme.palette.ui04
},
'&:active': {
backgroundColor: theme.palette.toolboxIconActive
backgroundColor: theme.palette.ui03
}
},
[theme.breakpoints.down(320)]: {
@@ -249,7 +232,7 @@ export const commonStyles = (theme: Theme) => {
},
'&.toggled': {
backgroundColor: theme.palette.toolboxIconToggled
backgroundColor: theme.palette.ui03
},
'&.disabled': {
@@ -257,13 +240,13 @@ export const commonStyles = (theme: Theme) => {
backgroundColor: `${theme.palette.disabled01} !important`,
'& svg': {
fill: `${theme.palette.icon03} !important`
fill: `${theme.palette.text03} !important`
}
}
},
'.toolbox-button': {
color: theme.palette.toolbarIcon,
color: theme.palette.text01,
cursor: 'pointer',
display: 'inline-block',
lineHeight: '3rem',
@@ -271,7 +254,7 @@ export const commonStyles = (theme: Theme) => {
},
'.toolbox-content-items': {
background: theme.palette.toolboxBackground,
background: theme.palette.ui01,
borderRadius: 6,
margin: '0 auto',
padding: 6,

View File

@@ -1,11 +0,0 @@
import '@mui/material/styles';
import { IPalette, ITypography } from './types';
declare module '@mui/material/styles' {
interface Palette extends IPalette {}
interface PaletteOptions extends Partial<IPalette> {}
interface Typography extends ITypography {}
interface TypographyOptions extends Partial<ITypography> {}
}

View File

@@ -5,7 +5,6 @@ interface ITypographyType {
lineHeight: string;
}
/* eslint-disable typescript-sort-keys/interface */
export interface IPalette {
action01: string;
action01Active: string;
@@ -59,324 +58,6 @@ export interface IPalette {
uiBackground: string;
warning01: string;
warning02: string;
// Semantic tokens (component-based, more descriptive names)
breakoutRoomArrowBackground: string;
breakoutRoomBackground: string;
breakoutRoomItemBackground: string;
chatBackground: string;
chatBackdrop: string;
chatEmptyText: string;
chatInputBackground: string;
chatInputBorder: string;
chatLink: string;
chatLobbyMessageBubble: string;
chatLobbyMessageNotice: string;
chatLobbyRecipientContainer: string;
chatMessageLocal: string;
chatMessagePrivate: string;
chatMessageRemote: string;
chatMessageText: string;
chatPrivateNotice: string;
chatRecipientCancelIcon: string;
chatRecipientContainer: string;
chatRecipientText: string;
chatReplyIcon: string;
chatSenderName: string;
chatTimestamp: string;
dialogBackground: string;
dialogBorder: string;
dialogOverlay: string;
dialogSecondaryText: string;
dialogText: string;
drawerBackground: string;
filmstripBackground: string;
filmstripBackgroundHover: string;
filmstripDragHandle: string;
filmstripDragHandleHover: string;
inputBackground: string;
inputBorder: string;
inputPlaceholder: string;
inputText: string;
largeVideoBackground: string;
largeVideoPlaceholder: string;
lobbyBackground: string;
lobbyPreviewBackground: string;
notificationActionFocus: string;
notificationActionText: string;
notificationBackground: string;
notificationCloseIcon: string;
notificationError: string;
notificationErrorText: string;
notificationNormalIcon: string;
notificationSuccess: string;
notificationText: string;
notificationWarning: string;
overflowMenuBackground: string;
overflowMenuBorder: string;
overflowMenuItemDisabled: string;
overflowMenuItemHover: string;
overflowMenuItemIcon: string;
overflowMenuItemText: string;
overflowMenuSeparator: string;
participantActionButton: string;
participantCounterBadge: string;
participantCounterText: string;
participantItemBackground: string;
participantItemBorder: string;
participantItemHover: string;
participantLinkText: string;
participantModeratorLabel: string;
participantRaisedHandBadge: string;
participantRaisedHandIcon: string;
participantSectionText: string;
participantsPaneBackground: string;
participantWarningText: string;
preMeetingBackground: string;
preMeetingPreview: string;
prejoinActionButtonDanger: string;
prejoinActionButtonDisabled: string;
prejoinActionButtonPrimary: string;
prejoinActionButtonPrimaryHover: string;
prejoinActionButtonPrimaryText: string;
prejoinActionButtonSecondary: string;
prejoinActionButtonSecondaryHover: string;
prejoinActionButtonSecondaryText: string;
prejoinCountryPickerBackground: string;
prejoinCountryPickerBorder: string;
prejoinCountryPickerText: string;
prejoinCountryRowBackground: string;
prejoinCountryRowHover: string;
prejoinDeviceStatusOk: string;
prejoinDeviceStatusText: string;
prejoinDeviceStatusWarning: string;
prejoinDialogBackground: string;
prejoinDialogDelimiter: string;
prejoinDialogDelimiterText: string;
prejoinRecordingWarningText: string;
prejoinRoomNameText: string;
prejoinTitleText: string;
prejoinWarningBackground: string;
prejoinWarningText: string;
settingsBackground: string;
settingsErrorIcon: string;
settingsSectionBackground: string;
settingsShortcutKey: string;
settingsTabText: string;
settingsVideoPreviewBorder: string;
speakerStatsAvatarLeft: string;
speakerStatsBackground: string;
speakerStatsBorder: string;
speakerStatsHeaderBackground: string;
speakerStatsLabelText: string;
speakerStatsRowAlternate: string;
speakerStatsRowBackground: string;
speakerStatsSearchBackground: string;
speakerStatsSearchBorder: string;
speakerStatsSearchIcon: string;
speakerStatsSearchPlaceholder: string;
speakerStatsSearchText: string;
speakerStatsSuccessBar: string;
thumbnailBackground: string;
thumbnailBorder: string;
thumbnailHover: string;
thumbnailRaisedHandIcon: string;
thumbnailTintBackground: string;
thumbnailVideoBackground: string;
toolbarButton: string;
toolbarButtonActive: string;
toolbarButtonHover: string;
toolbarIcon: string;
toolbarIconActive: string;
toolbarIconHover: string;
toolboxBackground: string;
toolboxIconActive: string;
toolboxIconHover: string;
toolboxIconToggled: string;
visitorsArrowBackground: string;
visitorsCountBadge: string;
visitorsCountIcon: string;
visitorsCountText: string;
visitorsQueueBackground: string;
visitorsQueueText: string;
welcomeBackground: string;
welcomeCard: string;
welcomeTabActive: string;
welcomeTabInactive: string;
// Form components
actionButtonBackground: string;
actionButtonBorder: string;
actionButtonText: string;
audioRoutePickerBackground: string;
audioRoutePickerBorder: string;
audioRoutePickerText: string;
baseReactBackground: string;
baseReactBorder: string;
baseReactText: string;
carModeBackground: string;
carModeBorder: string;
carModeText: string;
checkboxBorder: string;
checkboxChecked: string;
checkboxDisabledBackground: string;
checkboxDisabledBorder: string;
checkboxDisabledChecked: string;
checkboxIcon: string;
checkboxIconDisabled: string;
checkboxLabel: string;
clickableIconActive: string;
clickableIconBackground: string;
clickableIconFocus: string;
clickableIconHover: string;
conferenceNoticeBackground: string;
conferenceNoticeText: string;
conferenceRaisedHandLabelIcon: string;
conferenceRaisedHandLabelText: string;
conferenceSubjectText: string;
conferenceTimerText: string;
connectionIndicatorLost: string;
connectionIndicatorOther: string;
deepLinkingBackground: string;
deepLinkingBorder: string;
deepLinkingLabelText: string;
deepLinkingLink: string;
deepLinkingSeparator: string;
deepLinkingText: string;
deviceSelectorBackground: string;
deviceSelectorBorder: string;
deviceSelectorText: string;
deviceSelectorTextBackground: string;
deviceSelectorVideoPreview: string;
dialInBackground: string;
dialInSecondaryText: string;
dialInText: string;
displayNameBackground: string;
displayNameText: string;
etherpadBackground: string;
etherpadText: string;
fileSharingBackground: string;
fileSharingEmptyIcon: string;
fileSharingEmptyText: string;
fileSharingItemBackground: string;
fileSharingItemBorder: string;
fileSharingText: string;
gifsBackground: string;
gifsText: string;
inlineDialogBackground: string;
inlineDialogBorder: string;
inlineDialogText: string;
inputBottomLabel: string;
inputBottomLabelError: string;
inputClearButton: string;
inputFieldBackground: string;
inputFieldBorder: string;
inputFieldDisabled: string;
inputFieldError: string;
inputFieldFocus: string;
inputFieldPlaceholder: string;
inputFieldText: string;
inputLabel: string;
labelBackground: string;
labelText: string;
labelWhiteBackground: string;
labelWhiteIcon: string;
labelWhiteText: string;
languageSelectorBackground: string;
languageSelectorHover: string;
languageSelectorText: string;
listItemBackground: string;
listItemBoxShadow: string;
listItemHighlighted: string;
listItemHover: string;
listItemText: string;
multiSelectBackground: string;
multiSelectBorder: string;
multiSelectItemDisabled: string;
multiSelectItemHover: string;
multiSelectItemText: string;
pollsAnswer: string;
pollsBackground: string;
pollsBarBackground: string;
pollsBarPercentage: string;
pollsCreateBackground: string;
pollsCreateBorder: string;
pollsPaneBackground: string;
pollsPaneBorder: string;
pollsQuestion: string;
pollsSendDisabled: string;
pollsSendLabel: string;
pollsSeparator: string;
pollsSubtitle: string;
pollsTitle: string;
pollsVotersBackground: string;
pollsVotersText: string;
reactionsMenuBackground: string;
reactionsMenuBorder: string;
recordingBackground: string;
recordingHighlightButton: string;
recordingHighlightButtonDisabled: string;
recordingHighlightButtonIcon: string;
recordingHighlightButtonIconDisabled: string;
recordingNotificationAction: string;
recordingNotificationText: string;
recordingText: string;
securityDialogBackground: string;
securityDialogBorder: string;
securityDialogSecondaryText: string;
securityDialogText: string;
selectBackground: string;
selectBottomLabel: string;
selectBottomLabelError: string;
selectDisabled: string;
selectError: string;
selectFocus: string;
selectIcon: string;
selectIconDisabled: string;
selectLabel: string;
selectText: string;
sliderFocus: string;
sliderKnob: string;
sliderTrack: string;
subtitleMessageBackground: string;
subtitleMessageSender: string;
subtitleMessageText: string;
subtitleMessageTime: string;
switchBackground: string;
switchBackgroundOn: string;
switchFocus: string;
switchToggle: string;
switchToggleDisabled: string;
tabBadgeBackground: string;
tabBadgeText: string;
tabBorder: string;
tabBorderDisabled: string;
tabBorderHover: string;
tabBorderSelected: string;
tabFocus: string;
tabText: string;
tabTextDisabled: string;
tabTextHover: string;
tabTextSelected: string;
tooltipBackground: string;
tooltipText: string;
videoMenuBackground: string;
videoMenuBorder: string;
videoMenuSliderBackground: string;
videoMenuText: string;
videoQualityBackground: string;
videoQualityText: string;
virtualBackgroundBackground: string;
virtualBackgroundBorder: string;
virtualBackgroundPreview: string;
virtualBackgroundText: string;
whiteboardBackground: string;
whiteboardText: string;
salesforceSearchBackground: string;
salesforceSearchBorder: string;
salesforceSearchIcon: string;
salesforceSearchPlaceholder: string;
salesforceSearchText: string;
}
export interface ITypography {

View File

@@ -11,49 +11,13 @@ import * as tokens from './tokens.json';
*/
export function createColorTokens(colorMap: Object): any {
const allTokens = merge({}, tokens, jitsiTokens);
const result: any = {};
// First pass: resolve tokens that reference allTokens directly
Object.entries(colorMap).forEach(([ token, value ]: [any, string]) => {
const color = allTokens[value as keyof typeof allTokens] || value;
return Object.entries(colorMap)
.reduce((result, [ token, value ]: [any, string]) => {
const color = allTokens[value as keyof typeof allTokens] || value;
result[token] = color;
});
// Second pass: resolve semantic tokens that reference other colorMap entries
// Recursively resolve until we get actual color values
const resolveToken = (value: string, depth = 0): string => {
// Prevent infinite loops
if (depth > 10) {
return value;
}
// If it's already a color (starts with # or rgb/rgba), return it
if (value.startsWith('#') || value.startsWith('rgb')) {
return value;
}
// Look up in the result map first (for colorMap token references)
if (result[value]) {
return resolveToken(result[value], depth + 1);
}
// Then look up in allTokens
const resolved = allTokens[value as keyof typeof allTokens];
if (resolved && resolved !== value && typeof resolved === 'string') {
return resolveToken(resolved, depth + 1);
}
return value;
};
// Third pass: recursively resolve all values
Object.entries(result).forEach(([ token, value ]) => {
result[token] = resolveToken(String(value));
});
return result;
return Object.assign(result, { [token]: color });
}, {});
}
/**

View File

@@ -8,7 +8,7 @@ export default {
button: {
marginBottom: BaseTheme.spacing[4],
marginHorizontal: BaseTheme.spacing[3]
marginHorizontal: BaseTheme.spacing[2]
},
collapsibleList: {

View File

@@ -44,16 +44,6 @@ export const getMainRoom = (stateful: IStateful) => {
* @returns {IRoomsInfo} The rooms info.
*/
export const getRoomsInfo = (stateful: IStateful) => {
const state = toState(stateful);
const localParticipant = getLocalParticipant(stateful);
const jwtUser = state['features/base/jwt']?.user;
const localUserContext = jwtUser ? {
id: jwtUser.id,
name: jwtUser.name
} : {
id: localParticipant?.jwtId,
name: localParticipant?.name
};
const breakoutRooms = getBreakoutRooms(stateful);
const conference = getCurrentConference(stateful);
@@ -67,6 +57,7 @@ export const getRoomsInfo = (stateful: IStateful) => {
const conferenceParticipants = conference?.getParticipants()
.filter((participant: IJitsiParticipant) => !participant.isHidden());
const localParticipant = getLocalParticipant(stateful);
let localParticipantInfo;
if (localParticipant) {
@@ -74,8 +65,7 @@ export const getRoomsInfo = (stateful: IStateful) => {
role: localParticipant.role,
displayName: localParticipant.name,
avatarUrl: localParticipant.loadableAvatarUrl,
id: localParticipant.id,
userContext: localUserContext
id: localParticipant.id
};
}
@@ -96,8 +86,7 @@ export const getRoomsInfo = (stateful: IStateful) => {
role: participantItem.getRole(),
displayName: participantItem.getDisplayName(),
avatarUrl: storeParticipant?.loadableAvatarUrl,
id: participantItem.getId(),
userContext: storeParticipant?.userContext
id: participantItem.getId()
} as IRoomInfoParticipant;
}) ]
: [ localParticipantInfo ]
@@ -121,18 +110,13 @@ export const getRoomsInfo = (stateful: IStateful) => {
const storeParticipant = getParticipantById(stateful,
ids.length > 1 ? ids[1] : participantItem.jid);
// Check if this is the local participant
const isLocal = storeParticipant?.id === localParticipant?.id;
const userContext = isLocal ? localUserContext : (storeParticipant?.userContext || participantItem.userContext);
return {
jid: participantItem?.jid,
role: participantItem?.role,
displayName: participantItem?.displayName,
avatarUrl: storeParticipant?.loadableAvatarUrl,
id: storeParticipant ? storeParticipant.id
: participantLongId,
userContext
: participantLongId
} as IRoomInfoParticipant;
}) : []
} as IRoomInfo;

View File

@@ -44,59 +44,19 @@ MiddlewareRegistry.register(({ dispatch, getState }) => next => action => {
switch (type) {
case UPDATE_BREAKOUT_ROOMS: {
// Enrich participants with userContext from Redux store
// edit name if it was overwritten
if (!action.updatedNames) {
const state = getState();
const { overwrittenNameList, local: localParticipant } = state['features/base/participants'];
const jwtUser = state['features/base/jwt']?.user;
const localUserContext = jwtUser ? {
id: jwtUser.id,
name: jwtUser.name
} : {
id: localParticipant?.jwtId,
name: localParticipant?.name
};
const { overwrittenNameList } = getState()['features/base/participants'];
// Get existing userContext cache
const existingCache = state['features/breakout-rooms'].userContextCache || {};
const newCache = { ...existingCache };
if (Object.keys(overwrittenNameList).length > 0) {
const newRooms: IRooms = {};
const newRooms: IRooms = {};
Object.entries(action.rooms as IRooms).forEach(([ key, r ]) => {
let participants = r?.participants || {};
let jid;
Object.entries(action.rooms as IRooms).forEach(([ key, r ]) => {
let participants = r?.participants || {};
// Add userContext to each participant
const enhancedParticipants: typeof participants = {};
for (const [ participantJid, participantData ] of Object.entries(participants)) {
const ids = participantJid.split('/');
const participantId = ids.length > 1 ? ids[1] : participantData.jid;
const storeParticipant = getParticipantById(state, participantId);
const isLocal = storeParticipant?.id === localParticipant?.id;
// Try to get userContext from: local, store, cache, or incoming data
const userContext = isLocal
? localUserContext
: (storeParticipant?.userContext || newCache[participantId] || participantData.userContext);
// Update cache if we have userContext
if (userContext && participantId) {
newCache[participantId] = userContext;
}
enhancedParticipants[participantJid] = {
...participantData,
userContext
};
}
participants = enhancedParticipants;
// Apply overwritten display names
if (Object.keys(overwrittenNameList).length > 0) {
for (const id of Object.keys(overwrittenNameList)) {
const jid = Object.keys(participants).find(p => p.slice(p.indexOf('/') + 1) === id);
jid = Object.keys(participants).find(p => p.slice(p.indexOf('/') + 1) === id);
if (jid) {
participants = {
@@ -108,16 +68,15 @@ MiddlewareRegistry.register(({ dispatch, getState }) => next => action => {
};
}
}
}
newRooms[key] = {
...r,
participants
};
});
newRooms[key] = {
...r,
participants
};
});
action.rooms = newRooms;
action.userContextCache = newCache;
action.rooms = newRooms;
}
}
// edit the chat history to match names for participants in breakout rooms

View File

@@ -10,19 +10,12 @@ import { IRooms } from './types';
const DEFAULT_STATE = {
rooms: {},
roomCounter: 0,
userContextCache: {}
roomCounter: 0
};
export interface IBreakoutRoomsState {
roomCounter: number;
rooms: IRooms;
userContextCache: {
[participantId: string]: {
id?: string;
name?: string;
};
};
}
/**
@@ -36,13 +29,12 @@ ReducerRegistry.register<IBreakoutRoomsState>(FEATURE_KEY, (state = DEFAULT_STAT
roomCounter: action.roomCounter
};
case UPDATE_BREAKOUT_ROOMS: {
const { roomCounter, rooms, userContextCache } = action;
const { roomCounter, rooms } = action;
return {
...state,
roomCounter,
rooms,
userContextCache: userContextCache || state.userContextCache
rooms
};
}
case _RESET_BREAKOUT_ROOMS: {

View File

@@ -8,10 +8,6 @@ export interface IRoom {
displayName: string;
jid: string;
role: string;
userContext?: {
id?: string;
name?: string;
};
};
};
}
@@ -37,8 +33,4 @@ export interface IRoomInfoParticipant {
id: string;
jid: string;
role: string;
userContext?: {
id?: string;
name?: string;
};
}

View File

@@ -22,7 +22,7 @@ export function openChat(participant?: IParticipant | undefined | Object, disabl
if (disablePolls) {
navigate(screen.conference.chat);
} else {
navigate(screen.conference.chatTabs.main);
navigate(screen.conference.chatandpolls.main);
}
dispatch(setFocusedTab(ChatTabs.CHAT));

View File

@@ -1,111 +0,0 @@
import React, { ComponentType, useCallback, useEffect, useMemo, useState } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { IReduxState } from '../../app/types';
import { openDialog } from '../../base/dialog/actions';
import { IMessageGroup, groupMessagesBySender } from '../../base/util/messageGrouping';
// @ts-ignore
import { StartRecordingDialog } from '../../recording/components/Recording';
import { setRequestingSubtitles } from '../../subtitles/actions.any';
import { canStartSubtitles } from '../../subtitles/functions.any';
import { ISubtitle } from '../../subtitles/types';
import { isTranscribing } from '../../transcribing/functions';
export type AbstractProps = {
canStartSubtitles: boolean;
filteredSubtitles: ISubtitle[];
groupedSubtitles: IMessageGroup<ISubtitle>[];
isButtonPressed: boolean;
isTranscribing: boolean;
startClosedCaptions: () => void;
};
const AbstractClosedCaptions = (Component: ComponentType<AbstractProps>) => () => {
const dispatch = useDispatch();
const subtitles = useSelector((state: IReduxState) => state['features/subtitles'].subtitlesHistory);
const language = useSelector((state: IReduxState) => state['features/subtitles']._language);
const selectedLanguage = language?.replace('translation-languages:', '');
const _isTranscribing = useSelector(isTranscribing);
const _canStartSubtitles = useSelector(canStartSubtitles);
const [ isButtonPressed, setButtonPressed ] = useState(false);
const subtitlesError = useSelector((state: IReduxState) => state['features/subtitles']._hasError);
const isAsyncTranscriptionEnabled = useSelector((state: IReduxState) =>
state['features/base/conference'].conference?.getMetadataHandler()?.getMetadata()?.asyncTranscription);
const filteredSubtitles = useMemo(() => {
// First, create a map of transcription messages by message ID
const transcriptionMessages = new Map(
subtitles
.filter(s => s.isTranscription)
.map(s => [ s.id, s ])
);
if (!selectedLanguage) {
// When no language is selected, show all original transcriptions
return Array.from(transcriptionMessages.values());
}
// Then, create a map of translation messages by message ID
const translationMessages = new Map(
subtitles
.filter(s => !s.isTranscription && s.language === selectedLanguage)
.map(s => [ s.id, s ])
);
// When a language is selected, for each transcription message:
// 1. Use its translation if available
// 2. Fall back to the original transcription if no translation exists
return Array.from(transcriptionMessages.values())
.filter((m: ISubtitle) => !m.interim)
.map(m => translationMessages.get(m.id) ?? m);
}, [ subtitles, selectedLanguage ]);
const groupedSubtitles = useMemo(() =>
groupMessagesBySender(filteredSubtitles), [ filteredSubtitles ]);
const startClosedCaptions = useCallback(() => {
if (isAsyncTranscriptionEnabled) {
dispatch(openDialog('StartRecordingDialog', StartRecordingDialog, {
recordAudioAndVideo: false
}));
} else {
if (isButtonPressed) {
return;
}
dispatch(setRequestingSubtitles(true, false, null));
setButtonPressed(true);
}
}, [ isAsyncTranscriptionEnabled, dispatch, isButtonPressed, openDialog, setButtonPressed ]);
useEffect(() => {
if (subtitlesError && isButtonPressed && !isAsyncTranscriptionEnabled) {
setButtonPressed(false);
}
}, [ subtitlesError, isButtonPressed, isAsyncTranscriptionEnabled ]);
useEffect(() => {
if (!_isTranscribing && isButtonPressed && !isAsyncTranscriptionEnabled) {
setButtonPressed(false);
}
}, [ _isTranscribing, isButtonPressed, isAsyncTranscriptionEnabled ]);
useEffect(() => {
if (isButtonPressed && !isAsyncTranscriptionEnabled) {
setButtonPressed(false);
}
}, [ isButtonPressed, isAsyncTranscriptionEnabled ]);
return (
<Component
canStartSubtitles = { _canStartSubtitles }
filteredSubtitles = { filteredSubtitles }
groupedSubtitles = { groupedSubtitles }
isButtonPressed = { isButtonPressed }
isTranscribing = { _isTranscribing }
startClosedCaptions = { startClosedCaptions } />
);
};
export default AbstractClosedCaptions;

View File

@@ -1,29 +1,39 @@
/* eslint-disable react/no-multi-comp */
import { Route, useIsFocused } from '@react-navigation/native';
import React, { Component, useEffect } from 'react';
import { connect, useSelector } from 'react-redux';
import { connect } from 'react-redux';
import { IReduxState } from '../../../app/types';
import { translate } from '../../../base/i18n/functions';
import JitsiScreen from '../../../base/modal/components/JitsiScreen';
import { StyleType } from '../../../base/styles/functions.native';
import { TabBarLabelCounter } from '../../../mobile/navigation/components/TabBarLabelCounter';
import { pollsStyles } from '../../../polls/components/native/styles';
import { getUnreadPollCount } from '../../../polls/functions';
import { closeChat, sendMessage } from '../../actions.native';
import { ChatTabs } from '../../constants';
import { getUnreadFilesCount } from '../../functions';
import { IChatProps as AbstractProps } from '../../types';
import ChatInputBar from './ChatInputBar';
import MessageContainer from './MessageContainer';
import MessageRecipient from './MessageRecipient';
import styles from './styles';
interface IProps extends AbstractProps {
/**
* The number of unread file messages.
*/
_unreadFilesCount: number;
/**
* The number of unread messages.
*/
_unreadMessagesCount: number;
/**
* The number of unread polls.
*/
_unreadPollsCount: number;
/**
* Default prop for navigating between screen components(React Navigation).
*/
@@ -52,7 +62,6 @@ class Chat extends Component<IProps> {
// Bind event handlers so they are only bound once per instance.
this._onSendMessage = this._onSendMessage.bind(this);
this._renderFooter = this._renderFooter.bind(this);
}
/**
@@ -67,10 +76,14 @@ class Chat extends Component<IProps> {
return (
<JitsiScreen
disableForcedKeyboardDismiss = { true }
footerComponent = { this._renderFooter }
/* eslint-disable react/jsx-no-bind */
footerComponent = { () =>
<ChatInputBar onSend = { this._onSendMessage } />
}
hasBottomTextInput = { true }
hasExtraHeaderHeight = { true }
style = { pollsStyles.pollPaneContainer as StyleType }>
style = { styles.chatContainer }>
{/* @ts-ignore */}
<MessageContainer messages = { _messages } />
<MessageRecipient privateMessageRecipient = { privateMessageRecipient } />
@@ -78,16 +91,6 @@ class Chat extends Component<IProps> {
);
}
/**
* Renders the footer component.
*
* @private
* @returns {React$Element<*>}
*/
_renderFooter() {
return <ChatInputBar onSend = { this._onSendMessage } />;
}
/**
* Sends a text message.
*
@@ -110,7 +113,9 @@ class Chat extends Component<IProps> {
* @private
* @returns {{
* _messages: Array<Object>,
* _unreadMessagesCount: number
* _unreadMessagesCount: number,
* _unreadPollsCount: number,
* _unreadFilesCount: number
* }}
*/
function _mapStateToProps(state: IReduxState, _ownProps: any) {
@@ -118,34 +123,34 @@ function _mapStateToProps(state: IReduxState, _ownProps: any) {
return {
_messages: messages,
_unreadMessagesCount: unreadMessagesCount
_unreadMessagesCount: unreadMessagesCount,
_unreadPollsCount: getUnreadPollCount(state),
_unreadFilesCount: getUnreadFilesCount(state)
};
}
export default translate(connect(_mapStateToProps)((props: IProps) => {
const { _unreadMessagesCount, dispatch, navigation, t } = props;
const isChatTabFocused = useSelector((state: IReduxState) => state['features/chat'].focusedTab === ChatTabs.CHAT);
const { _unreadMessagesCount, _unreadPollsCount, _unreadFilesCount, dispatch, navigation, t } = props;
const totalUnread = _unreadMessagesCount + _unreadPollsCount + _unreadFilesCount;
const unreadMessagesNr = totalUnread > 0;
const isFocused = useIsFocused();
const activeUnreadMessagesNr = !isChatTabFocused && _unreadMessagesCount > 0;
useEffect(() => {
navigation?.setOptions({
tabBarLabel: () => (
<TabBarLabelCounter
activeUnreadNr = { activeUnreadMessagesNr }
activeUnreadNr = { unreadMessagesNr }
isFocused = { isFocused }
label = { t('chat.tabs.chat') }
unreadCount = { _unreadMessagesCount } />
unreadCount = { totalUnread } />
)
});
return () => {
isFocused && dispatch(closeChat());
};
}, [ isFocused, _unreadMessagesCount ]);
}, [ isFocused, _unreadMessagesCount, _unreadPollsCount, _unreadFilesCount ]);
return (
<Chat { ...props } />

View File

@@ -43,7 +43,7 @@ class ChatButton extends AbstractButton<IProps> {
override _handleClick() {
this.props._isPollsDisabled
? navigate(screen.conference.chat)
: navigate(screen.conference.chatTabs.main);
: navigate(screen.conference.chatandpolls.main);
}
/**

View File

@@ -7,6 +7,7 @@ import { connect } from 'react-redux';
import { IReduxState } from '../../../app/types';
import { translate } from '../../../base/i18n/functions';
import { IconSend } from '../../../base/icons/svg';
import { ASPECT_RATIO_WIDE } from '../../../base/responsive-ui/constants';
import IconButton from '../../../base/ui/components/native/IconButton';
import Input from '../../../base/ui/components/native/Input';
import { BUTTON_TYPES } from '../../../base/ui/constants.native';
@@ -84,6 +85,14 @@ class ChatInputBar extends Component<IProps, IState> {
* @inheritdoc
*/
override render() {
let inputBarStyles;
if (this.props.aspectRatio === ASPECT_RATIO_WIDE) {
inputBarStyles = styles.inputBarWide;
} else {
inputBarStyles = styles.inputBarNarrow;
}
if (this.props._isSendGroupChatDisabled && !this.props._privateMessageRecipientId) {
return (
<View
@@ -100,7 +109,7 @@ class ChatInputBar extends Component<IProps, IState> {
<View
id = 'chat-input'
style = { [
styles.inputBar,
inputBarStyles,
this.state.addPadding ? styles.extraBarPadding : null
] as ViewStyle[] }>
<Input
@@ -120,7 +129,6 @@ class ChatInputBar extends Component<IProps, IState> {
id = { this.props.t('chat.sendButton') }
onPress = { this._onSubmit }
src = { IconSend }
style = { styles.sendButton }
type = { BUTTON_TYPES.PRIMARY } />
</View>
);

View File

@@ -1,130 +0,0 @@
import { useNavigation } from '@react-navigation/native';
import React, { useCallback, useEffect } from 'react';
import { useTranslation } from 'react-i18next';
import { TouchableHighlight, View, ViewStyle } from 'react-native';
import { Text } from 'react-native-paper';
import { useSelector } from 'react-redux';
import { IReduxState } from '../../../app/types';
import Icon from '../../../base/icons/components/Icon';
import { IconArrowRight, IconSubtitles } from '../../../base/icons/svg';
import JitsiScreen from '../../../base/modal/components/JitsiScreen';
import { StyleType } from '../../../base/styles/functions.any';
import BaseTheme from '../../../base/ui/components/BaseTheme.native';
import Button from '../../../base/ui/components/native/Button';
import { BUTTON_TYPES } from '../../../base/ui/constants.native';
import { TabBarLabelCounter } from '../../../mobile/navigation/components/TabBarLabelCounter';
import { navigate } from '../../../mobile/navigation/components/conference/ConferenceNavigationContainerRef';
import { screen } from '../../../mobile/navigation/routes';
import { ChatTabs } from '../../constants';
import AbstractClosedCaptions, { AbstractProps } from '../AbstractClosedCaptions';
import { SubtitlesMessagesContainer } from './SubtitlesMessagesContainer';
import { closedCaptionsStyles } from './styles';
/**
* Component that displays the closed captions interface.
*
* @returns {JSX.Element} - The ClosedCaptions component.
*/
const ClosedCaptions = ({
canStartSubtitles,
filteredSubtitles,
groupedSubtitles,
isButtonPressed,
isTranscribing,
startClosedCaptions
}: AbstractProps): JSX.Element => {
const navigation = useNavigation();
const { t } = useTranslation();
const isCCTabFocused = useSelector((state: IReduxState) => state['features/chat'].focusedTab === ChatTabs.CLOSED_CAPTIONS);
const selectedLanguage = useSelector((state: IReduxState) => state['features/subtitles']._language);
const navigateToLanguageSelect = useCallback(() => {
navigate(screen.conference.subtitles);
}, [ navigation, screen ]);
const isAsyncTranscriptionEnabled = useSelector((state: IReduxState) =>
state['features/base/conference'].conference?.getMetadataHandler()?.getMetadata()?.asyncTranscription);
useEffect(() => {
navigation?.setOptions({
tabBarLabel: () => (
<TabBarLabelCounter
isFocused = { isCCTabFocused }
label = { t('chat.tabs.closedCaptions') } />
)
});
}, [ isCCTabFocused, navigation, t ]);
const getContentContainerStyle = () => {
if (isTranscribing) {
return closedCaptionsStyles.transcribingContainer as StyleType;
}
return closedCaptionsStyles.emptyContentContainer as StyleType;
};
const renderContent = () => {
if (!isTranscribing) {
if (canStartSubtitles) {
return (
<View style = { closedCaptionsStyles.emptyContent as ViewStyle }>
<Button
accessibilityLabel = { t('closedCaptionsTab.startClosedCaptionsButton') }
disabled = { isButtonPressed }
labelKey = 'closedCaptionsTab.startClosedCaptionsButton'
onClick = { startClosedCaptions }
type = { BUTTON_TYPES.PRIMARY } />
</View>
);
}
return (
<View style = { closedCaptionsStyles.emptyContent as ViewStyle }>
<Icon
color = { BaseTheme.palette.icon03 }
size = { 100 }
src = { IconSubtitles } />
<Text style = { [ closedCaptionsStyles.emptyStateText, { marginTop: BaseTheme.spacing[3] } ] }>
{ t('closedCaptionsTab.emptyState') }
</Text>
</View>
);
}
return (
<>
{
// Hide the "Translate to" option when asyncTranscription is enabled
!isAsyncTranscriptionEnabled && <View style = { closedCaptionsStyles.languageButtonContainer as ViewStyle }>
<Text style = { closedCaptionsStyles.languageButtonText }>{ t('transcribing.translateTo') }:</Text>
<TouchableHighlight onPress = { navigateToLanguageSelect }>
<View style = { closedCaptionsStyles.languageButtonContent as ViewStyle }>
<Text style = { closedCaptionsStyles.languageButtonText }>{ t(selectedLanguage ?? 'transcribing.subtitlesOff') }</Text>
<Icon
size = { 24 }
src = { IconArrowRight } />
</View>
</TouchableHighlight>
</View>
}
<View style = { closedCaptionsStyles.messagesContainer as ViewStyle }>
<SubtitlesMessagesContainer
groups = { groupedSubtitles }
messages = { filteredSubtitles } />
</View>
</>
);
};
return (
<JitsiScreen
contentContainerStyle = { getContentContainerStyle() }
disableForcedKeyboardDismiss = { true }
hasExtraHeaderHeight = { true }
style = { closedCaptionsStyles.container as StyleType }>
{ renderContent() }
</JitsiScreen>
);
};
export default AbstractClosedCaptions(ClosedCaptions);

View File

@@ -44,23 +44,19 @@ class MessageContainer extends Component<IProps, any> {
*/
override render() {
const data = this._getMessagesGroupedBySender();
const noMessages = data.length === 0;
return (
<FlatList
ListEmptyComponent = { this._renderListEmptyComponent }
bounces = { false }
// @ts-ignore
contentContainerStyle = { noMessages && styles.emptyListContentContainer }
data = { data }
// Workaround for RN bug:
// https://github.com/facebook/react-native/issues/21196
inverted = { Boolean(data.length) }
keyExtractor = { this._keyExtractor }
keyboardShouldPersistTaps = 'handled'
renderItem = { this._renderMessageGroup }
style = { noMessages && styles.emptyListStyle } />
renderItem = { this._renderMessageGroup } />
);
}

View File

@@ -67,8 +67,8 @@ class PrivateMessageButton extends AbstractButton<IProps, any> {
? navigate(screen.conference.chat, {
privateMessageRecipient: this.props._participant
})
: navigate(screen.conference.chatTabs.main, {
screen: screen.conference.chatTabs.tab.chat,
: navigate(screen.conference.chatandpolls.main, {
screen: screen.conference.chatandpolls.tab.chat,
params: {
privateMessageRecipient: this.props._participant
}

View File

@@ -1,45 +0,0 @@
import React from 'react';
import { Text, View, ViewStyle } from 'react-native';
import { useSelector } from 'react-redux';
import { IReduxState } from '../../../app/types';
import { getParticipantDisplayName } from '../../../base/participants/functions';
import { ISubtitle } from '../../../subtitles/types';
import { closedCaptionsStyles } from './styles';
interface IProps extends ISubtitle {
showDisplayName: boolean;
}
export default function SubtitleMessage({ participantId, text, timestamp, interim, showDisplayName }: IProps) {
const participantName = useSelector((state: IReduxState) =>
getParticipantDisplayName(state, participantId));
const containerStyle: ViewStyle[] = [
closedCaptionsStyles.subtitleMessageContainer as ViewStyle
];
if (interim) {
containerStyle.push(closedCaptionsStyles.subtitleMessageInterim as ViewStyle);
}
return (
<View style = { containerStyle }>
<View style = { closedCaptionsStyles.subtitleMessageContent as ViewStyle }>
{
showDisplayName && (
<Text style = { closedCaptionsStyles.subtitleMessageHeader }>
{ participantName }
</Text>
)
}
<Text style = { closedCaptionsStyles.subtitleMessageText }>{ text }</Text>
<Text style = { closedCaptionsStyles.subtitleMessageTimestamp }>
{ new Date(timestamp).toLocaleTimeString() }
</Text>
</View>
</View>
);
}

View File

@@ -1,40 +0,0 @@
import React from 'react';
import { View, ViewStyle } from 'react-native';
import Avatar from '../../../base/avatar/components/Avatar';
import { ISubtitle } from '../../../subtitles/types';
import SubtitleMessage from './SubtitleMessage';
import { closedCaptionsStyles } from './styles';
interface IProps {
messages: ISubtitle[];
senderId: string;
}
export function SubtitlesGroup({ messages, senderId }: IProps) {
if (!messages.length) {
return null;
}
return (
<View style = { closedCaptionsStyles.subtitlesGroupContainer as ViewStyle }>
<View style = { closedCaptionsStyles.subtitlesGroupAvatar as ViewStyle }>
<Avatar
participantId = { senderId }
size = { 32 } />
</View>
<View style = { closedCaptionsStyles.subtitlesGroupMessagesContainer as ViewStyle }>
{
messages.map((message, index) => (
<SubtitleMessage
key = { `${message.timestamp}-${message.id}` }
showDisplayName = { index === 0 }
{ ...message } />
))
}
</View>
</View>
);
}

View File

@@ -1,105 +0,0 @@
import React, { useCallback, useEffect, useRef, useState } from 'react';
import { NativeScrollEvent, NativeSyntheticEvent, ScrollView, View, ViewStyle } from 'react-native';
import Icon from '../../../base/icons/components/Icon';
import { IconArrowDown } from '../../../base/icons/svg';
import BaseTheme from '../../../base/ui/components/BaseTheme.native';
import Button from '../../../base/ui/components/native/Button';
import { BUTTON_TYPES } from '../../../base/ui/constants.native';
import { ISubtitle } from '../../../subtitles/types';
import { SubtitlesGroup } from './SubtitlesGroup';
import { closedCaptionsStyles } from './styles';
/**
* The threshold value used to determine if the user is at the bottom of the scroll view.
*/
const SCROLL_THRESHOLD = 50;
interface IProps {
groups: Array<{
messages: ISubtitle[];
senderId: string;
}>;
messages: ISubtitle[];
}
export function SubtitlesMessagesContainer({ messages, groups }: IProps) {
const [ hasNewMessages, setHasNewMessages ] = useState(false);
const [ isScrolledToBottom, setIsScrolledToBottom ] = useState(true);
const scrollViewRef = useRef<ScrollView>(null);
const previousMessages = useRef(messages);
const scrollToBottom = useCallback((withAnimation: boolean) => {
scrollViewRef.current?.scrollToEnd({ animated: withAnimation });
}, []);
const handleNewMessagesClick = useCallback(() => {
scrollToBottom(true);
}, [ scrollToBottom ]);
const handleScroll = useCallback((event: NativeSyntheticEvent<NativeScrollEvent>) => {
const { contentOffset, contentSize, layoutMeasurement } = event.nativeEvent;
const isAtBottom = contentOffset.y + layoutMeasurement.height >= contentSize.height - SCROLL_THRESHOLD;
setIsScrolledToBottom(isAtBottom);
if (isAtBottom) {
setHasNewMessages(false);
}
}, []);
useEffect(() => {
scrollToBottom(false);
}, [ scrollToBottom ]);
useEffect(() => {
const newMessages = messages.filter(message => !previousMessages.current.includes(message));
if (newMessages.length > 0) {
if (isScrolledToBottom) {
scrollToBottom(false);
} else {
setHasNewMessages(true);
}
}
previousMessages.current = messages;
}, [ messages, scrollToBottom ]);
return (
<View style = { closedCaptionsStyles.subtitlesMessagesContainer as ViewStyle }>
<ScrollView
contentContainerStyle = { closedCaptionsStyles.subtitlesMessagesList as ViewStyle }
onScroll = { handleScroll }
ref = { scrollViewRef }
scrollEventThrottle = { 16 }>
{
groups.map(group => (
<SubtitlesGroup
key = { `${group.senderId}-${group.messages[0]?.timestamp}` }
messages = { group.messages }
senderId = { group.senderId } />
))
}
</ScrollView>
{
!isScrolledToBottom && hasNewMessages && (
<View style = { closedCaptionsStyles.newMessagesButtonContainer as ViewStyle }>
<Button
accessibilityLabel = 'chat.newMessages'
// eslint-disable-next-line react/jsx-no-bind
icon = { () => (
<Icon
color = { BaseTheme.palette.icon04 }
size = { 20 }
src = { IconArrowDown } />
) }
labelKey = 'chat.newMessages'
onClick = { handleNewMessagesClick }
type = { BUTTON_TYPES.SECONDARY } />
</View>
)
}
</View>
);
}

View File

@@ -14,6 +14,12 @@ const recipientContainer = {
padding: BaseTheme.spacing[2]
};
const inputBar = {
alignItems: 'center',
flexDirection: 'row',
justifyContent: 'space-between'
};
/**
* The styles of the feature chat.
*
@@ -38,8 +44,7 @@ export default {
},
emptyComponentText: {
...BaseTheme.typography.bodyLongBold,
color: BaseTheme.palette.text02,
color: BaseTheme.palette.text03,
textAlign: 'center'
},
@@ -108,20 +113,11 @@ export default {
},
emptyComponentWrapper: {
alignItems: 'center',
justifyContent: 'center',
padding: BoxModel.padding,
maxWidth: '80%'
},
emptyListStyle: {
flex: 1
},
emptyListContentContainer: {
alignItems: 'center',
alignSelf: 'center',
flex: 1,
justifyContent: 'center'
padding: BoxModel.padding,
paddingTop: '8%',
maxWidth: '80%'
},
disabledSendWrapper: {
@@ -137,23 +133,23 @@ export default {
* A special padding to avoid issues on some devices (such as Android devices with custom suggestions bar).
*/
extraBarPadding: {
paddingBottom: BaseTheme.spacing[8]
paddingBottom: 30
},
inputBar: {
alignSelf: 'stretch',
flexDirection: 'row',
width: '100%'
inputBarNarrow: {
...inputBar,
height: 112,
marginHorizontal: BaseTheme.spacing[3]
},
sendButton: {
marginRight: BaseTheme.spacing[5],
marginLeft: BaseTheme.spacing[2]
inputBarWide: {
...inputBar,
height: 88,
marginHorizontal: BaseTheme.spacing[9]
},
customInputContainer: {
marginLeft: BaseTheme.spacing[5],
flex: 1
width: '75%'
},
messageBubble: {
@@ -209,6 +205,11 @@ export default {
fontSize: 13
},
chatContainer: {
backgroundColor: BaseTheme.palette.ui01,
flex: 1
},
tabContainer: {
flexDirection: 'row',
justifyContent: 'center'
@@ -269,128 +270,3 @@ export default {
flex: 1
}
};
/**
* Styles for the ClosedCaptions component.
*/
export const closedCaptionsStyles = {
container: {
backgroundColor: BaseTheme.palette.ui01,
flex: 1
},
emptyContentContainer: {
flex: 1,
justifyContent: 'center',
alignItems: 'center'
},
emptyContent: {
alignItems: 'center',
justifyContent: 'center',
flex: 1,
padding: BaseTheme.spacing[3]
},
emptyStateText: {
...BaseTheme.typography.bodyLongBold,
color: BaseTheme.palette.text02,
textAlign: 'center',
maxWidth: '80%'
},
transcribingContainer: {
flex: 1
},
languageButtonContainer: {
justifyContent: 'space-between',
flexDirection: 'row',
padding: BaseTheme.spacing[3]
},
languageButtonText: {
...BaseTheme.typography.bodyShortRegularLarge,
color: BaseTheme.palette.text01,
marginHorizontal: BaseTheme.spacing[2]
},
languageButtonContent: {
flexDirection: 'row'
},
subtitleMessageContainer: {
backgroundColor: BaseTheme.palette.ui02,
borderRadius: BaseTheme.shape.borderRadius,
padding: BaseTheme.spacing[2],
maxWidth: '100%',
marginTop: BaseTheme.spacing[1]
},
subtitleMessageContent: {
maxWidth: '100%',
flex: 1
},
subtitleMessageHeader: {
...BaseTheme.typography.labelBold,
color: BaseTheme.palette.text02,
marginBottom: BaseTheme.spacing[1],
maxWidth: 130
},
subtitleMessageText: {
...BaseTheme.typography.bodyShortRegular,
color: BaseTheme.palette.text01
},
subtitleMessageTimestamp: {
...BaseTheme.typography.labelRegular,
color: BaseTheme.palette.text03,
marginTop: BaseTheme.spacing[1]
},
subtitleMessageInterim: {
opacity: 0.7
},
subtitlesGroupContainer: {
flexDirection: 'row',
marginBottom: BaseTheme.spacing[3]
},
subtitlesGroupAvatar: {
marginBottom: BaseTheme.spacing[10],
marginRight: BaseTheme.spacing[2],
alignSelf: 'flex-start',
width: 32
},
subtitlesGroupMessagesContainer: {
flexDirection: 'column',
flex: 1,
maxWidth: '100%'
},
subtitlesMessagesContainer: {
flex: 1,
position: 'relative',
height: '100%'
},
subtitlesMessagesList: {
padding: BaseTheme.spacing[4]
},
newMessagesButtonContainer: {
position: 'absolute',
bottom: BaseTheme.spacing[3],
alignSelf: 'center'
},
messagesContainer: {
display: 'flex',
flex: 1,
overflow: 'hidden'
}
};

View File

@@ -107,7 +107,7 @@ interface IProps extends AbstractProps {
const useStyles = makeStyles<{ _isResizing: boolean; width: number; }>()((theme, { _isResizing, width }) => {
return {
container: {
backgroundColor: theme.palette.chatBackground,
backgroundColor: theme.palette.ui01,
flexShrink: 0,
overflow: 'hidden',
position: 'relative',
@@ -132,7 +132,7 @@ const useStyles = makeStyles<{ _isResizing: boolean; width: number; }>()((theme,
'*': {
userSelect: 'text',
WebkitUserSelect: 'text'
'-webkit-user-select': 'text'
}
},
@@ -146,7 +146,7 @@ const useStyles = makeStyles<{ _isResizing: boolean; width: number; }>()((theme,
padding: `${theme.spacing(3)} ${theme.spacing(4)}`,
alignItems: 'center',
boxSizing: 'border-box',
color: theme.palette.chatMessageText,
color: theme.palette.text01,
...theme.typography.heading6,
lineHeight: 'unset',
fontWeight: theme.typography.heading6.fontWeight as any,

View File

@@ -37,7 +37,7 @@ const styles = (_theme: Theme, { _chatWidth }: IProps) => {
}
},
chatDisabled: {
borderTop: `1px solid ${_theme.palette.chatInputBorder}`,
borderTop: `1px solid ${_theme.palette.ui02}`,
boxSizing: 'border-box' as const,
padding: _theme.spacing(4),
textAlign: 'center' as const,

View File

@@ -43,7 +43,7 @@ const useStyles = makeStyles()((theme: Theme) => {
chatMessage: {
display: 'inline-flex',
padding: '12px',
backgroundColor: theme.palette.chatMessageRemote,
backgroundColor: theme.palette.ui02,
borderRadius: '4px 12px 12px 12px',
maxWidth: '100%',
marginTop: '4px',
@@ -66,21 +66,21 @@ const useStyles = makeStyles()((theme: Theme) => {
},
'&.privatemessage': {
backgroundColor: theme.palette.chatMessagePrivate
backgroundColor: theme.palette.support05
},
'&.local': {
backgroundColor: theme.palette.chatMessageLocal,
backgroundColor: theme.palette.ui04,
borderRadius: '12px 4px 12px 12px',
'&.privatemessage': {
backgroundColor: theme.palette.chatMessagePrivate
backgroundColor: theme.palette.support05
},
'&.local': {
backgroundColor: theme.palette.chatMessageLocal,
backgroundColor: theme.palette.ui04,
borderRadius: '12px 4px 12px 12px',
'&.privatemessage': {
backgroundColor: theme.palette.chatMessagePrivate
backgroundColor: theme.palette.support05
}
},
@@ -91,7 +91,7 @@ const useStyles = makeStyles()((theme: Theme) => {
},
'&.lobbymessage': {
backgroundColor: theme.palette.chatMessagePrivate
backgroundColor: theme.palette.support05
}
},
'&.error': {
@@ -100,7 +100,7 @@ const useStyles = makeStyles()((theme: Theme) => {
fontWeight: 100
},
'&.lobbymessage': {
backgroundColor: theme.palette.chatMessagePrivate
backgroundColor: theme.palette.support05
}
},
sideBySideContainer: {
@@ -146,7 +146,7 @@ const useStyles = makeStyles()((theme: Theme) => {
},
displayName: {
...theme.typography.labelBold,
color: theme.palette.chatSenderName,
color: theme.palette.text02,
whiteSpace: 'nowrap',
textOverflow: 'ellipsis',
overflow: 'hidden',
@@ -155,18 +155,18 @@ const useStyles = makeStyles()((theme: Theme) => {
},
userMessage: {
...theme.typography.bodyShortRegular,
color: theme.palette.chatMessageText,
color: theme.palette.text01,
whiteSpace: 'pre-wrap',
wordBreak: 'break-word'
},
privateMessageNotice: {
...theme.typography.labelRegular,
color: theme.palette.chatPrivateNotice,
color: theme.palette.text02,
marginTop: theme.spacing(1)
},
timestamp: {
...theme.typography.labelRegular,
color: theme.palette.chatTimestamp,
color: theme.palette.text03,
marginTop: theme.spacing(1),
marginLeft: theme.spacing(1),
whiteSpace: 'nowrap',
@@ -174,12 +174,12 @@ const useStyles = makeStyles()((theme: Theme) => {
},
reactionsPopover: {
padding: theme.spacing(2),
backgroundColor: theme.palette.chatInputBackground,
backgroundColor: theme.palette.ui03,
borderRadius: theme.shape.borderRadius,
maxWidth: '150px',
maxHeight: '400px',
overflowY: 'auto',
color: theme.palette.chatMessageText
color: theme.palette.text01
},
reactionItem: {
display: 'flex',

View File

@@ -1,13 +1,20 @@
import React from 'react';
import React, { useCallback, useMemo, useState } from 'react';
import { useTranslation } from 'react-i18next';
import { useDispatch, useSelector } from 'react-redux';
import { makeStyles } from 'tss-react/mui';
import { IReduxState } from '../../../app/types';
import { openDialog } from '../../../base/dialog/actions';
import Icon from '../../../base/icons/components/Icon';
import { IconSubtitles } from '../../../base/icons/svg';
import Button from '../../../base/ui/components/web/Button';
import { groupMessagesBySender } from '../../../base/util/messageGrouping';
import { StartRecordingDialog } from '../../../recording/components/Recording';
import { setRequestingSubtitles } from '../../../subtitles/actions.any';
import LanguageSelector from '../../../subtitles/components/web/LanguageSelector';
// @ts-ignore
import AbstractClosedCaptions, { AbstractProps } from '../AbstractClosedCaptions';
import { canStartSubtitles } from '../../../subtitles/functions.any';
import { ISubtitle } from '../../../subtitles/types';
import { isTranscribing } from '../../../transcribing/functions';
import { SubtitlesMessagesContainer } from './SubtitlesMessagesContainer';
@@ -24,7 +31,7 @@ const useStyles = makeStyles()(theme => {
padding: '16px',
flex: 1,
boxSizing: 'border-box',
color: theme.palette.chatMessageText
color: theme.palette.text01
},
container: {
display: 'flex',
@@ -48,7 +55,7 @@ const useStyles = makeStyles()(theme => {
boxSizing: 'border-box',
flexDirection: 'column',
gap: '16px',
color: theme.palette.chatMessageText,
color: theme.palette.text01,
textAlign: 'center'
},
emptyIcon: {
@@ -62,7 +69,7 @@ const useStyles = makeStyles()(theme => {
},
emptyState: {
...theme.typography.bodyLongBold,
color: theme.palette.chatSenderName
color: theme.palette.text02
}
};
});
@@ -72,19 +79,72 @@ const useStyles = makeStyles()(theme => {
*
* @returns {JSX.Element} - The ClosedCaptionsTab component.
*/
const ClosedCaptionsTab = ({
canStartSubtitles,
filteredSubtitles,
groupedSubtitles,
isButtonPressed,
isTranscribing,
startClosedCaptions
}: AbstractProps): JSX.Element => {
export default function ClosedCaptionsTab() {
const { classes, theme } = useStyles();
const dispatch = useDispatch();
const { t } = useTranslation();
const subtitles = useSelector((state: IReduxState) => state['features/subtitles'].subtitlesHistory);
const language = useSelector((state: IReduxState) => state['features/subtitles']._language);
const selectedLanguage = language?.replace('translation-languages:', '');
const _isTranscribing = useSelector(isTranscribing);
const _canStartSubtitles = useSelector(canStartSubtitles);
const [ isButtonPressed, setButtonPressed ] = useState(false);
const subtitlesError = useSelector((state: IReduxState) => state['features/subtitles']._hasError);
const isAsyncTranscriptionEnabled = useSelector((state: IReduxState) =>
state['features/base/conference'].conference?.getMetadataHandler()?.getMetadata()?.asyncTranscription);
if (!isTranscribing) {
if (canStartSubtitles) {
const filteredSubtitles = useMemo(() => {
// First, create a map of transcription messages by message ID
const transcriptionMessages = new Map(
subtitles
.filter(s => s.isTranscription)
.map(s => [ s.id, s ])
);
if (!selectedLanguage) {
// When no language is selected, show all original transcriptions
return Array.from(transcriptionMessages.values());
}
// Then, create a map of translation messages by message ID
const translationMessages = new Map(
subtitles
.filter(s => !s.isTranscription && s.language === selectedLanguage)
.map(s => [ s.id, s ])
);
// When a language is selected, for each transcription message:
// 1. Use its translation if available
// 2. Fall back to the original transcription if no translation exists
return Array.from(transcriptionMessages.values())
.filter((m: ISubtitle) => !m.interim)
.map(m => translationMessages.get(m.id) ?? m);
}, [ subtitles, selectedLanguage ]);
const groupedSubtitles = useMemo(() =>
groupMessagesBySender(filteredSubtitles), [ filteredSubtitles ]);
const startClosedCaptions = useCallback(() => {
if (isAsyncTranscriptionEnabled) {
dispatch(openDialog('StartRecordingDialog', StartRecordingDialog, {
recordAudioAndVideo: false
}));
} else {
if (isButtonPressed) {
return;
}
dispatch(setRequestingSubtitles(true, false, null));
setButtonPressed(true);
}
}, [ isAsyncTranscriptionEnabled, dispatch, isButtonPressed, openDialog, setButtonPressed ]);
if (subtitlesError && isButtonPressed && !isAsyncTranscriptionEnabled) {
setButtonPressed(false);
}
if (!_isTranscribing) {
if (_canStartSubtitles) {
return (
<div className = { classes.emptyContent }>
<Button
@@ -99,11 +159,15 @@ const ClosedCaptionsTab = ({
);
}
if (isButtonPressed && !isAsyncTranscriptionEnabled) {
setButtonPressed(false);
}
return (
<div className = { classes.emptyContent }>
<Icon
className = { classes.emptyIcon }
color = { theme.palette.chatEmptyText }
color = { theme.palette.icon03 }
src = { IconSubtitles } />
<span className = { classes.emptyState }>
{ t('closedCaptionsTab.emptyState') }
@@ -112,6 +176,10 @@ const ClosedCaptionsTab = ({
);
}
if (isButtonPressed && !isAsyncTranscriptionEnabled) {
setButtonPressed(false);
}
return (
<div className = { classes.container }>
<LanguageSelector />
@@ -122,6 +190,4 @@ const ClosedCaptionsTab = ({
</div>
</div>
);
};
export default AbstractClosedCaptions(ClosedCaptionsTab);
}

View File

@@ -12,7 +12,7 @@ const useStyles = makeStyles()((theme: Theme) => {
display: 'flex',
flexDirection: 'row',
borderRadius: '4px',
backgroundColor: theme.palette.chatInputBackground
backgroundColor: theme.palette.ui03
},
emojiButton: {

View File

@@ -46,12 +46,12 @@ const useStyles = makeStyles()(theme => {
// Add background to button container to hide text underneath in chat context
'& > div:last-child': {
backgroundColor: theme.palette.chatMessageRemote,
backgroundColor: theme.palette.ui02,
paddingLeft: theme.spacing(2)
},
'&:hover > div:last-child': {
backgroundColor: theme.palette.chatInputBackground
backgroundColor: theme.palette.ui03
}
},
@@ -66,7 +66,7 @@ const useStyles = makeStyles()(theme => {
deletedFileMessage: {
...theme.typography.bodyShortRegular,
fontStyle: 'italic',
color: theme.palette.fileSharingEmptyText,
color: theme.palette.text02,
padding: theme.spacing(1, 0)
}
};

View File

@@ -39,14 +39,14 @@ const useStyles = makeStyles()(theme => {
}
},
menuPanel: {
backgroundColor: theme.palette.chatInputBackground,
backgroundColor: theme.palette.ui03,
borderRadius: theme.shape.borderRadius,
boxShadow: theme.shadows[3],
overflow: 'hidden'
},
copiedMessage: {
position: 'fixed',
backgroundColor: theme.palette.chatInputBackground,
backgroundColor: theme.palette.ui03,
color: 'white',
padding: '4px 8px',
borderRadius: '4px',

View File

@@ -24,7 +24,7 @@ const useStyles = makeStyles()(theme => {
backgroundColor: theme.palette.support05,
borderRadius: theme.shape.borderRadius,
...theme.typography.bodyShortRegular,
color: theme.palette.chatRecipientText
color: theme.palette.text01
},
text: {

View File

@@ -22,7 +22,7 @@ interface IProps extends ISubtitle {
const useStyles = makeStyles()(theme => {
return {
messageContainer: {
backgroundColor: theme.palette.subtitleMessageBackground,
backgroundColor: theme.palette.ui02,
borderRadius: '4px 12px 12px 12px',
padding: '12px',
maxWidth: '100%',
@@ -39,7 +39,7 @@ const useStyles = makeStyles()(theme => {
messageHeader: {
...theme.typography.labelBold,
color: theme.palette.subtitleMessageSender,
color: theme.palette.text02,
whiteSpace: 'nowrap',
textOverflow: 'ellipsis',
overflow: 'hidden',
@@ -49,14 +49,14 @@ const useStyles = makeStyles()(theme => {
messageText: {
...theme.typography.bodyShortRegular,
color: theme.palette.subtitleMessageText,
color: theme.palette.text01,
whiteSpace: 'pre-wrap',
wordBreak: 'break-word'
},
timestamp: {
...theme.typography.labelRegular,
color: theme.palette.subtitleMessageTime,
color: theme.palette.text03,
marginTop: theme.spacing(1)
},

View File

@@ -21,9 +21,10 @@ const titleBarSafeView = {
export default {
bottomContainer: {
alignItems: 'center',
display: 'flex',
flexDirection: 'column'
flexDirection: 'column',
alignItems: 'center',
bottom: BaseTheme.spacing[8]
},
/**
@@ -100,7 +101,7 @@ export default {
},
soundDeviceButton: {
marginVertical: BaseTheme.spacing[3],
marginBottom: BaseTheme.spacing[3],
width: 240
},
@@ -161,6 +162,7 @@ export default {
videoStoppedLabel: {
...BaseTheme.typography.bodyShortRegularLarge,
color: BaseTheme.palette.text01,
marginBottom: BaseTheme.spacing[3],
textAlign: 'center',
width: '100%'
},

Some files were not shown because too many files have changed in this diff Show More