feat(conference-info) Updated title bar (#10670)
Updated animations Added raised hands counter Added max width to title bar
This commit is contained in:
parent
d22d95e8a5
commit
da2b920dbe
|
@ -1032,7 +1032,7 @@ var config = {
|
|||
// If a label's id is not in any of the 2 arrays, it will not be visible at all on the header.
|
||||
// conferenceInfo: {
|
||||
// // those labels will not be hidden in tandem with the toolbox.
|
||||
// alwaysVisible: ['recording', 'local-recording'],
|
||||
// alwaysVisible: ['recording', 'local-recording', 'raised-hands-count'],
|
||||
// // those labels will be auto-hidden in tandem with the toolbox buttons.
|
||||
// autoHide: [
|
||||
// 'subject',
|
||||
|
|
|
@ -1,11 +1,25 @@
|
|||
.subject {
|
||||
color: #fff;
|
||||
margin-top: -120px;
|
||||
transition: margin-top .3s ease-in;
|
||||
transition: opacity .3s ease-in;
|
||||
z-index: $zindex3;
|
||||
margin-top: 20px;
|
||||
opacity: 0;
|
||||
|
||||
&.visible {
|
||||
margin-top: 20px;
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
&#autoHide.with-always-on {
|
||||
overflow: hidden;
|
||||
animation: hideSubject forwards .3s ease-out;
|
||||
|
||||
& > .subject-info-container {
|
||||
justify-content: flex-start;
|
||||
}
|
||||
|
||||
&.visible {
|
||||
animation: showSubject forwards .3s ease-out;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -36,10 +50,7 @@
|
|||
line-height: 28px;
|
||||
padding: 0 16px;
|
||||
height: 28px;
|
||||
|
||||
@media (max-width: 700px) {
|
||||
max-width: 100px;
|
||||
}
|
||||
max-width: 324px;
|
||||
|
||||
@media (max-width: 300px) {
|
||||
display: none;
|
||||
|
@ -74,8 +85,29 @@
|
|||
position: absolute;
|
||||
top: 0;
|
||||
height: 48px;
|
||||
max-width: calc(100% - 24px);
|
||||
}
|
||||
|
||||
.shift-right .details-container {
|
||||
margin-left: calc(#{$sidebarWidth} / 2);
|
||||
}
|
||||
|
||||
@keyframes hideSubject {
|
||||
0% {
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
100% {
|
||||
max-width: 0;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes showSubject {
|
||||
0% {
|
||||
max-width: 0%;
|
||||
}
|
||||
|
||||
100% {
|
||||
max-width: 100%;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -784,6 +784,7 @@
|
|||
"title": "Profile"
|
||||
},
|
||||
"raisedHand": "Would like to speak",
|
||||
"raisedHandsLabel": "Number of raised hands",
|
||||
"recording": {
|
||||
"limitNotificationDescriptionWeb": "Due to high demand your recording will be limited to {{limit}} min. For unlimited recordings try <a href={{url}} rel='noopener noreferrer' target='_blank'>{{app}}</a>.",
|
||||
"limitNotificationDescriptionNative": "Due to high demand your recording will be limited to {{limit}} min. For unlimited recordings try <3>{{app}}</3>.",
|
||||
|
|
|
@ -34,6 +34,11 @@ type Props = AbstractProps & {
|
|||
*/
|
||||
id: string,
|
||||
|
||||
/**
|
||||
* Color for the icon.
|
||||
*/
|
||||
iconColor?: string,
|
||||
|
||||
/**
|
||||
* Click handler if any.
|
||||
*/
|
||||
|
@ -103,6 +108,7 @@ class Label extends AbstractLabel<Props, *> {
|
|||
className,
|
||||
color,
|
||||
icon,
|
||||
iconColor,
|
||||
id,
|
||||
onClick,
|
||||
text
|
||||
|
@ -120,6 +126,7 @@ class Label extends AbstractLabel<Props, *> {
|
|||
id = { id }
|
||||
onClick = { onClick }>
|
||||
{ icon && <Icon
|
||||
color = { iconColor }
|
||||
size = '16'
|
||||
src = { icon } /> }
|
||||
{ text && <span className = { icon && classes.withIcon }>{text}</span> }
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
export const CONFERENCE_INFO = {
|
||||
alwaysVisible: [ 'recording', 'local-recording' ],
|
||||
alwaysVisible: [ 'recording', 'local-recording', 'raised-hands-count' ],
|
||||
autoHide: [
|
||||
'subject',
|
||||
'conference-timer',
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
export * from './functions.any';
|
|
@ -0,0 +1,14 @@
|
|||
// @flow
|
||||
|
||||
export * from './functions.any';
|
||||
|
||||
/**
|
||||
* Whether or not there are always on labels.
|
||||
*
|
||||
* @returns {boolean}
|
||||
*/
|
||||
export function isAlwaysOnTitleBarEmpty() {
|
||||
const bar = document.querySelector('#alwaysVisible>div');
|
||||
|
||||
return bar?.childNodes.length === 0;
|
||||
}
|
|
@ -18,6 +18,7 @@ import { getConferenceInfo } from '../functions';
|
|||
import ConferenceInfoContainer from './ConferenceInfoContainer';
|
||||
import InsecureRoomNameLabel from './InsecureRoomNameLabel';
|
||||
import ParticipantsCount from './ParticipantsCount';
|
||||
import RaisedHandsCountLabel from './RaisedHandsCountLabel';
|
||||
import SubjectText from './SubjectText';
|
||||
|
||||
/**
|
||||
|
@ -66,6 +67,10 @@ const COMPONENTS = [
|
|||
Component: LocalRecordingLabel,
|
||||
id: 'local-recording'
|
||||
},
|
||||
{
|
||||
Component: RaisedHandsCountLabel,
|
||||
id: 'raised-hands-count'
|
||||
},
|
||||
{
|
||||
Component: TranscribingLabel,
|
||||
id: 'transcribing'
|
||||
|
@ -115,7 +120,9 @@ class ConferenceInfo extends Component<Props> {
|
|||
}
|
||||
|
||||
return (
|
||||
<ConferenceInfoContainer visible = { this.props._visible } >
|
||||
<ConferenceInfoContainer
|
||||
id = 'autoHide'
|
||||
visible = { this.props._visible }>
|
||||
{
|
||||
COMPONENTS
|
||||
.filter(comp => autoHide.includes(comp.id))
|
||||
|
@ -142,7 +149,9 @@ class ConferenceInfo extends Component<Props> {
|
|||
}
|
||||
|
||||
return (
|
||||
<ConferenceInfoContainer visible = { true } >
|
||||
<ConferenceInfoContainer
|
||||
id = 'alwaysVisible'
|
||||
visible = { true } >
|
||||
{
|
||||
COMPONENTS
|
||||
.filter(comp => alwaysVisible.includes(comp.id))
|
||||
|
|
|
@ -2,6 +2,8 @@
|
|||
|
||||
import React from 'react';
|
||||
|
||||
import { isAlwaysOnTitleBarEmpty } from '../functions.web';
|
||||
|
||||
type Props = {
|
||||
|
||||
/**
|
||||
|
@ -9,14 +11,21 @@ type Props = {
|
|||
*/
|
||||
children: React$Node,
|
||||
|
||||
/**
|
||||
* Id of the component.
|
||||
*/
|
||||
id?: string,
|
||||
|
||||
/**
|
||||
* Whether this conference info container should be visible or not.
|
||||
*/
|
||||
visible: boolean
|
||||
}
|
||||
|
||||
export default ({ visible, children }: Props) => (
|
||||
<div className = { `subject${visible ? ' visible' : ''}` }>
|
||||
export default ({ visible, children, id }: Props) => (
|
||||
<div
|
||||
className = { `subject${isAlwaysOnTitleBarEmpty() ? '' : ' with-always-on'}${visible ? ' visible' : ''}` }
|
||||
id = { id }>
|
||||
<div className = { 'subject-info-container' }>
|
||||
{children}
|
||||
</div>
|
||||
|
|
|
@ -0,0 +1,45 @@
|
|||
import { makeStyles } from '@material-ui/styles';
|
||||
import React, { useCallback } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useDispatch, useSelector } from 'react-redux';
|
||||
|
||||
import { IconRaisedHand } from '../../../base/icons';
|
||||
import { Label } from '../../../base/label';
|
||||
import { Tooltip } from '../../../base/tooltip';
|
||||
import BaseTheme from '../../../base/ui/components/BaseTheme';
|
||||
import { open as openParticipantsPane } from '../../../participants-pane/actions';
|
||||
|
||||
const useStyles = makeStyles(theme => {
|
||||
return {
|
||||
label: {
|
||||
backgroundColor: theme.palette.warning02,
|
||||
color: theme.palette.uiBackground,
|
||||
marginRight: theme.spacing(1)
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
const RaisedHandsCountLabel = () => {
|
||||
const styles = useStyles();
|
||||
const dispatch = useDispatch();
|
||||
const raisedHandsCount = useSelector(state =>
|
||||
(state['features/base/participants'].raisedHandsQueue || []).length);
|
||||
const { t } = useTranslation();
|
||||
const onClick = useCallback(() => {
|
||||
dispatch(openParticipantsPane());
|
||||
}, []);
|
||||
|
||||
return raisedHandsCount > 0 && (<Tooltip
|
||||
content = { t('raisedHandsLabel') }
|
||||
position = { 'bottom' }>
|
||||
<Label
|
||||
className = { styles.label }
|
||||
icon = { IconRaisedHand }
|
||||
iconColor = { BaseTheme.palette.uiBackground }
|
||||
id = 'raisedHandsCountLabel'
|
||||
onClick = { onClick }
|
||||
text = { raisedHandsCount } />
|
||||
</Tooltip>);
|
||||
};
|
||||
|
||||
export default RaisedHandsCountLabel;
|
Loading…
Reference in New Issue