feat(title-bar) Update design (#12851)

Convert some files to TS
Move some styles from SCSS to JSS
Update design
This commit is contained in:
Robert Pintilii 2023-02-03 13:31:00 +02:00 committed by GitHub
parent a594aac078
commit 09e4696c60
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
25 changed files with 307 additions and 440 deletions

View File

@ -12,7 +12,6 @@
&#autoHide.with-always-on {
overflow: hidden;
animation: hideSubject forwards .6s ease-out;
margin-left: 4px;
& > .subject-info-container {
justify-content: flex-start;
@ -43,43 +42,6 @@
height: 28px;
}
.subject-text {
background: rgba(0, 0, 0, 0.6);
border-radius: 3px 0px 0px 3px;
box-sizing: border-box;
font-size: 14px;
line-height: 28px;
padding: 0 16px;
height: 28px;
max-width: 324px;
@media (max-width: 300px) {
display: none;
}
&--content {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
}
.subject-timer {
background: rgba(0, 0, 0, 0.8);
border-radius: 0px 3px 3px 0px;
box-sizing: border-box;
font-size: 12px;
line-height: 28px;
min-width: 34px;
padding: 0 8px;
height: 28px;
font-variant-numeric: tabular-nums;
@media (max-width: 300px) {
display: none;
}
}
.details-container {
width: 100%;
display: flex;

View File

@ -103,10 +103,6 @@
padding: 11px 16px;
}
}
input::placeholder {
color: #040404;
}
}
#preview {

View File

@ -50,10 +50,10 @@ const useStyles = makeStyles()(theme => {
...withPixelLineHeight(theme.typography.labelRegular),
alignItems: 'center',
background: theme.palette.ui04,
borderRadius: Number(theme.shape.borderRadius) / 2,
borderRadius: '4px',
color: theme.palette.text01,
display: 'flex',
margin: '0 0 4px 4px',
margin: '0 2px',
padding: '6px',
height: 28,
boxSizing: 'border-box'

View File

@ -1,7 +1,6 @@
// @flow
import { PureComponent } from 'react';
import React, { PureComponent } from 'react';
import { IReduxState } from '../../app/types';
import isInsecureRoomName from '../../base/util/isInsecureRoomName';
type Props = {
@ -14,11 +13,11 @@ type Props = {
/**
* Function to be used to translate i18n labels.
*/
t: Function
}
t: Function;
};
/**
* Abstrsact class for the {@Code InsecureRoomNameLabel} component.
* Abstract class for the {@Code InsecureRoomNameLabel} component.
*/
export default class AbstractInsecureRoomNameLabel extends PureComponent<Props> {
/**
@ -39,7 +38,9 @@ export default class AbstractInsecureRoomNameLabel extends PureComponent<Props>
*
* @returns {ReactElement}
*/
_render: () => Object;
_render() {
return <></>;
}
}
/**
@ -48,14 +49,14 @@ export default class AbstractInsecureRoomNameLabel extends PureComponent<Props>
* @param {Object} state - The Redux state.
* @returns {Props}
*/
export function _mapStateToProps(state: Object): $Shape<Props> {
export function _mapStateToProps(state: IReduxState) {
const { locked, room } = state['features/base/conference'];
const { lobbyEnabled } = state['features/lobby'];
const { enableInsecureRoomNameWarning = false } = state['features/base/config'];
return {
_visible: enableInsecureRoomNameWarning
_visible: Boolean(enableInsecureRoomNameWarning
&& room && isInsecureRoomName(room)
&& !(lobbyEnabled || Boolean(locked))
&& !(lobbyEnabled || Boolean(locked)))
};
}

View File

@ -1,180 +0,0 @@
// @flow
import { Component } from 'react';
import { renderConferenceTimer } from '../';
import { getConferenceTimestamp } from '../../base/conference/functions';
import { getLocalizedDurationFormatter } from '../../base/i18n';
import { connect } from '../../base/redux';
/**
* The type of the React {@code Component} props of {@link ConferenceTimer}.
*/
type Props = {
/**
* The UTC timestamp representing the time when first participant joined.
*/
_startTimestamp: ?number,
/**
* Style to be applied to the rendered text.
*/
textStyle: ?Object,
/**
* The redux {@code dispatch} function.
*/
dispatch: Function
};
/**
* The type of the React {@code Component} state of {@link ConferenceTimer}.
*/
type State = {
/**
* Value of current conference time.
*/
timerValue: string
};
/**
* ConferenceTimer react component.
*
* @class ConferenceTimer
* @augments Component
*/
class ConferenceTimer extends Component<Props, State> {
/**
* Handle for setInterval timer.
*/
_interval;
/**
* Initializes a new {@code ConferenceTimer} instance.
*
* @param {Props} props - The read-only properties with which the new
* instance is to be initialized.
*/
constructor(props: Props) {
super(props);
this.state = {
timerValue: getLocalizedDurationFormatter(0)
};
}
/**
* Starts the conference timer when component will be
* mounted.
*
* @inheritdoc
*/
componentDidMount() {
this._startTimer();
}
/**
* Stops the conference timer when component will be
* unmounted.
*
* @inheritdoc
*/
componentWillUnmount() {
this._stopTimer();
}
/**
* Implements React's {@link Component#render()}.
*
* @inheritdoc
* @returns {ReactElement}
*/
render() {
const { timerValue } = this.state;
const { _startTimestamp, textStyle } = this.props;
if (!_startTimestamp) {
return null;
}
return renderConferenceTimer(timerValue, textStyle);
}
/**
* Sets the current state values that will be used to render the timer.
*
* @param {number} refValueUTC - The initial UTC timestamp value.
* @param {number} currentValueUTC - The current UTC timestamp value.
*
* @returns {void}
*/
_setStateFromUTC(refValueUTC, currentValueUTC) {
if (!refValueUTC || !currentValueUTC) {
return;
}
if (currentValueUTC < refValueUTC) {
return;
}
const timerMsValue = currentValueUTC - refValueUTC;
const localizedTime = getLocalizedDurationFormatter(timerMsValue);
this.setState({
timerValue: localizedTime
});
}
/**
* Start conference timer.
*
* @returns {void}
*/
_startTimer() {
if (!this._interval) {
this._setStateFromUTC(this.props._startTimestamp, new Date().getTime());
this._interval = setInterval(() => {
this._setStateFromUTC(this.props._startTimestamp, new Date().getTime());
}, 1000);
}
}
/**
* Stop conference timer.
*
* @returns {void}
*/
_stopTimer() {
if (this._interval) {
clearInterval(this._interval);
}
this.setState({
timerValue: getLocalizedDurationFormatter(0)
});
}
}
/**
* Maps (parts of) the Redux state to the associated
* {@code ConferenceTimer}'s props.
*
* @param {Object} state - The Redux state.
* @private
* @returns {{
* _startTimestamp: number
* }}
*/
export function _mapStateToProps(state: Object) {
return {
_startTimestamp: getConferenceTimestamp(state)
};
}
export default connect(_mapStateToProps)(ConferenceTimer);

View File

@ -0,0 +1,106 @@
import React, { useCallback, useEffect, useRef, useState } from 'react';
import { useSelector } from 'react-redux';
// @ts-ignore
import { ConferenceTimerDisplay } from '..';
import { getConferenceTimestamp } from '../../base/conference/functions';
import { getLocalizedDurationFormatter } from '../../base/i18n/dateUtil';
/**
* The type of the React {@code Component} props of {@link ConferenceTimer}.
*/
interface IProps {
/**
* Style to be applied to the rendered text.
*/
textStyle?: Object;
}
export interface IDisplayProps {
/**
* Style to be applied to text (native only).
*/
textStyle: Object;
/**
* String to display as time.
*/
timerValue: string;
}
const ConferenceTimer = ({ textStyle }: IProps) => {
const startTimestamp = useSelector(getConferenceTimestamp);
const [ timerValue, setTimerValue ] = useState(getLocalizedDurationFormatter(0));
const interval = useRef<number>();
/**
* Sets the current state values that will be used to render the timer.
*
* @param {number} refValueUTC - The initial UTC timestamp value.
* @param {number} currentValueUTC - The current UTC timestamp value.
*
* @returns {void}
*/
const setStateFromUTC = useCallback((refValueUTC, currentValueUTC) => {
if (!refValueUTC || !currentValueUTC) {
return;
}
if (currentValueUTC < refValueUTC) {
return;
}
const timerMsValue = currentValueUTC - refValueUTC;
const localizedTime = getLocalizedDurationFormatter(timerMsValue);
setTimerValue(localizedTime);
}, []);
/**
* Start conference timer.
*
* @returns {void}
*/
const startTimer = useCallback(() => {
if (!interval.current && startTimestamp) {
setStateFromUTC(startTimestamp, new Date().getTime());
interval.current = window.setInterval(() => {
setStateFromUTC(startTimestamp, new Date().getTime());
}, 1000);
}
}, [ startTimestamp, interval ]);
/**
* Stop conference timer.
*
* @returns {void}
*/
const stopTimer = useCallback(() => {
if (interval.current) {
clearInterval(interval.current);
}
setTimerValue(getLocalizedDurationFormatter(0));
}, [ interval ]);
useEffect(() => {
startTimer();
return () => stopTimer();
}, [ startTimestamp ]);
if (!startTimestamp) {
return null;
}
return (<ConferenceTimerDisplay
textStyle = { textStyle }
timerValue = { timerValue } />);
};
export default ConferenceTimer;

View File

@ -1,5 +1,5 @@
export const CONFERENCE_INFO = {
alwaysVisible: [ 'recording', 'raised-hands-count' ],
alwaysVisible: [ 'raised-hands-count', 'recording' ],
autoHide: [
'highlight-moment',
'subject',

View File

@ -1,17 +1,16 @@
// @flow
import React from 'react';
import { Text } from 'react-native';
import { IDisplayProps } from '../ConferenceTimer';
/**
* Returns native element to be rendered.
*
* @param {string} timerValue - String to display as time.
* @param {Object} textStyle - Style to be applied to the text.
* @param {Object} props - Component props.
*
* @returns {ReactElement}
*/
export default function renderConferenceTimer(timerValue: string, textStyle: Object) {
export default function ConferenceTimerDisplay({ timerValue, textStyle }: IDisplayProps) {
return (
<Text
numberOfLines = { 1 }

View File

@ -1,5 +1,5 @@
// @flow
export { default as Conference } from './Conference';
export { default as renderConferenceTimer } from './ConferenceTimerDisplay';
export { default as ConferenceTimerDisplay } from './ConferenceTimerDisplay';
export { default as InsecureRoomNameLabel } from './InsecureRoomNameLabel';

View File

@ -6,12 +6,12 @@ import React, { Component } from 'react';
import { JitsiRecordingConstants } from '../../../base/lib-jitsi-meet';
import { connect } from '../../../base/redux';
import { E2EELabel } from '../../../e2ee';
import { RecordingLabel } from '../../../recording';
import E2EELabel from '../../../e2ee/components/E2EELabel';
import HighlightButton from '../../../recording/components/Recording/web/HighlightButton';
import RecordingLabel from '../../../recording/components/web/RecordingLabel';
import { isToolboxVisible } from '../../../toolbox/functions.web';
import { TranscribingLabel } from '../../../transcribing';
import { VideoQualityLabel } from '../../../video-quality';
import TranscribingLabel from '../../../transcribing/components/TranscribingLabel.web';
import VideoQualityLabel from '../../../video-quality/components/VideoQualityLabel.web';
import ConferenceTimer from '../ConferenceTimer';
import { getConferenceInfo } from '../functions';

View File

@ -1,19 +0,0 @@
// @flow
/* eslint-disable no-unused-vars */
import React from 'react';
/**
* Returns web element to be rendered.
*
* @param {string} timerValue - String to display as time.
* @param {Object} textStyle - Unused on web.
*
* @returns {ReactElement}
*/
export default function renderConferenceTimer(timerValue: string, textStyle: Object) {
return (
<span className = 'subject-timer'>{ timerValue }</span>
);
}

View File

@ -0,0 +1,37 @@
import React from 'react';
import { makeStyles } from 'tss-react/mui';
import { withPixelLineHeight } from '../../../base/styles/functions.web';
import { IDisplayProps } from '../ConferenceTimer';
const useStyles = makeStyles()(theme => {
return {
timer: {
...withPixelLineHeight(theme.typography.labelRegular),
color: theme.palette.text01,
padding: '6px 8px',
backgroundColor: 'rgba(0, 0, 0, 0.8)',
boxSizing: 'border-box',
height: '28px',
borderRadius: `0 ${theme.shape.borderRadius}px ${theme.shape.borderRadius}px 0`,
marginRight: '2px',
'@media (max-width: 300px)': {
display: 'none'
}
}
};
});
/**
* Returns web element to be rendered.
*
* @returns {ReactElement}
*/
export default function ConferenceTimerDisplay({ timerValue, textStyle: _textStyle }: IDisplayProps) {
const { classes } = useStyles();
return (
<span className = { classes.timer }>{ timerValue }</span>
);
}

View File

@ -1,13 +1,11 @@
// @flow
import Tooltip from '@atlaskit/tooltip';
import React from 'react';
import { connect } from 'react-redux';
import { translate } from '../../../base/i18n';
import { translate } from '../../../base/i18n/functions';
import { IconExclamationTriangle } from '../../../base/icons/svg';
import { Label } from '../../../base/label';
import Label from '../../../base/label/components/web/Label';
import { COLORS } from '../../../base/label/constants';
import { connect } from '../../../base/redux';
import AbstractInsecureRoomNameLabel, { _mapStateToProps } from '../AbstractInsecureRoomNameLabel';
/**

View File

@ -15,8 +15,7 @@ const useStyles = makeStyles()(theme => {
return {
label: {
backgroundColor: theme.palette.warning02,
color: theme.palette.uiBackground,
marginRight: theme.spacing(1)
color: theme.palette.uiBackground
}
};
});

View File

@ -1,50 +0,0 @@
/* @flow */
import React from 'react';
import { getConferenceName } from '../../../base/conference/functions';
import { connect } from '../../../base/redux';
import { Tooltip } from '../../../base/tooltip';
type Props = {
/**
* The conference display name.
*/
_subject: string
}
/**
* Label for the conference name.
*
* @param {Props} props - The props of the component.
* @returns {ReactElement}
*/
const SubjectText = ({ _subject }: Props) => (
<div className = 'subject-text'>
<Tooltip
content = { _subject }
position = 'bottom'>
<div className = 'subject-text--content'>{ _subject }</div>
</Tooltip>
</div>
);
/**
* Maps (parts of) the Redux state to the associated
* {@code Subject}'s props.
*
* @param {Object} state - The Redux state.
* @private
* @returns {{
* _subject: string,
* }}
*/
function _mapStateToProps(state) {
return {
_subject: getConferenceName(state)
};
}
export default connect(_mapStateToProps)(SubjectText);

View File

@ -0,0 +1,57 @@
import clsx from 'clsx';
import React from 'react';
import { useSelector } from 'react-redux';
import { makeStyles } from 'tss-react/mui';
import { getConferenceName } from '../../../base/conference/functions';
import { withPixelLineHeight } from '../../../base/styles/functions.web';
// eslint-disable-next-line lines-around-comment
// @ts-ignore
import { Tooltip } from '../../../base/tooltip';
const useStyles = makeStyles()(theme => {
return {
container: {
...withPixelLineHeight(theme.typography.bodyLongRegular),
color: theme.palette.text01,
padding: '2px 16px',
backgroundColor: 'rgba(0, 0, 0, 0.6)',
maxWidth: '324px',
boxSizing: 'border-box',
height: '28px',
borderRadius: `${theme.shape.borderRadius}px 0 0 ${theme.shape.borderRadius}px`,
marginLeft: '2px',
'@media (max-width: 300px)': {
display: 'none'
}
},
content: {
overflow: 'hidden',
textOverflow: 'ellipsis',
whiteSpace: 'nowrap'
}
};
});
/**
* Label for the conference name.
*
* @returns {ReactElement}
*/
const SubjectText = () => {
const subject = useSelector(getConferenceName);
const { classes } = useStyles();
return (
<div className = { classes.container }>
<Tooltip
content = { subject }
position = 'bottom'>
<div className = { clsx('subject-text--content', classes.content) }>{subject}</div>
</Tooltip>
</div>
);
};
export default SubjectText;

View File

@ -1,7 +1,7 @@
// @flow
export { default as Conference } from './Conference';
export { default as renderConferenceTimer } from './ConferenceTimerDisplay';
export { default as ConferenceTimerDisplay } from './ConferenceTimerDisplay';
export { default as InsecureRoomNameLabel } from './InsecureRoomNameLabel';
export { default as ConferenceInfo } from './ConferenceInfo';
export { default as SubjectText } from './SubjectText';

View File

@ -1,32 +1,28 @@
// @flow
import { WithTranslation } from 'react-i18next';
import { IReduxState } from '../../app/types';
export type Props = {
export interface IProps extends WithTranslation {
/**
* Custom e2ee labels.
*/
_e2eeLabels?: Object;
_e2eeLabels?: any;
/**
* True if the label needs to be rendered, false otherwise.
*/
_showLabel: boolean,
/**
* Invoked to obtain translated strings.
*/
t: Function
};
_showLabel?: boolean;
}
/**
* Maps (parts of) the redux state to the associated props of this {@code Component}.
*
* @param {Object} state - The redux state.
* @private
* @returns {Props}
* @returns {IProps}
*/
export function _mapStateToProps(state: Object) {
export function _mapStateToProps(state: IReduxState) {
const { e2ee = {} } = state['features/base/config'];
return {

View File

@ -1,47 +0,0 @@
// @flow
import React, { Component } from 'react';
import { translate } from '../../base/i18n';
import { IconE2EE } from '../../base/icons';
import { Label } from '../../base/label';
import { COLORS } from '../../base/label/constants';
import { connect } from '../../base/redux';
import { Tooltip } from '../../base/tooltip';
import { type Props, _mapStateToProps } from './AbstractE2EELabel';
/**
* React {@code Component} for displaying a label when everyone has E2EE enabled in a conference.
*
* @augments Component
*/
class E2EELabel extends Component<Props> {
/**
* Implements React's {@link Component#render()}.
*
* @inheritdoc
* @returns {ReactElement}
*/
render() {
if (!this.props._showLabel) {
return null;
}
const { _e2eeLabels, t } = this.props;
const content = _e2eeLabels?.labelToolTip || t('e2ee.labelToolTip');
return (
<Tooltip
content = { content }
position = { 'bottom' }>
<Label
color = { COLORS.green }
icon = { IconE2EE } />
</Tooltip>
);
}
}
export default translate(connect(_mapStateToProps)(E2EELabel));

View File

@ -0,0 +1,32 @@
import React from 'react';
import { connect } from 'react-redux';
import { translate } from '../../base/i18n/functions';
import { IconE2EE } from '../../base/icons/svg';
import Label from '../../base/label/components/web/Label';
import { COLORS } from '../../base/label/constants';
// eslint-disable-next-line lines-around-comment
// @ts-ignore
import { Tooltip } from '../../base/tooltip';
import { IProps, _mapStateToProps } from './AbstractE2EELabel';
const E2EELabel = ({ _e2eeLabels, _showLabel, t }: IProps) => {
if (!_showLabel) {
return null;
}
const content = _e2eeLabels?.labelToolTip || t('e2ee.labelToolTip');
return (
<Tooltip
content = { content }
position = { 'bottom' }>
<Label
color = { COLORS.green }
icon = { IconE2EE } />
</Tooltip>
);
};
export default translate(connect(_mapStateToProps)(E2EELabel));

View File

@ -60,12 +60,10 @@ const styles = (theme: Theme) => {
position: 'relative'
},
disabled: {
background: theme.palette.text02,
margin: '0 4px 4px 4px'
background: theme.palette.text02
},
regular: { // @ts-ignore
background: theme.palette.field02,
margin: '0 4px 4px 4px'
background: theme.palette.field02
},
highlightNotification: { // @ts-ignore
backgroundColor: theme.palette.field02,
@ -197,7 +195,6 @@ export class HighlightButton extends AbstractHighlightButton<Props, IState> {
// @ts-ignore
} = this.props;
if (!_visible) {
return null;
}

View File

@ -3,6 +3,7 @@ import { withStyles } from '@mui/styles';
import React from 'react';
import { translate } from '../../../base/i18n/functions';
import { IconRecord, IconSites } from '../../../base/icons/svg';
import Label from '../../../base/label/components/web/Label';
import { JitsiRecordingConstants } from '../../../base/lib-jitsi-meet';
import { connect } from '../../../base/redux/functions';
@ -22,10 +23,10 @@ import AbstractRecordingLabel, {
const styles = (theme: Theme) => {
return {
[JitsiRecordingConstants.mode.STREAM]: {
background: theme.palette.ui03
background: theme.palette.support07
},
[JitsiRecordingConstants.mode.FILE]: {
background: theme.palette.iconError
background: theme.palette.actionDanger
}
};
};
@ -51,15 +52,13 @@ class RecordingLabel extends AbstractRecordingLabel {
}
// @ts-ignore
const { classes, mode, t } = this.props;
const { classes, mode } = this.props;
return (
<div>
<Label
className = { classes?.[mode] }
// @ts-ignore
text = { t(this._getLabelKey()) } />
icon = { mode === JitsiRecordingConstants.mode.FILE ? IconRecord : IconSites } />
</div>
);
}

View File

@ -1,4 +1,4 @@
// @flow
import { IReduxState } from '../../app/types';
/**
* The type of the React {@code Component} props of {@link TranscribingLabel}.
@ -8,12 +8,12 @@ export type Props = {
/**
* True if the label needs to be rendered, false otherwise.
*/
_showLabel: boolean,
_showLabel: boolean;
/**
* Invoked to obtain translated strings.
*/
t: Function
t: Function;
};
/**
@ -26,7 +26,7 @@ export type Props = {
* _showLabel: boolean
* }}
*/
export function _mapStateToProps(state: Object) {
export function _mapStateToProps(state: IReduxState) {
return {
_showLabel: state['features/transcribing'].isTranscribing
};

View File

@ -1,44 +0,0 @@
// @flow
import React, { Component } from 'react';
import { translate } from '../../base/i18n';
import { Label } from '../../base/label';
import { connect } from '../../base/redux';
import { Tooltip } from '../../base/tooltip';
import { type Props, _mapStateToProps } from './AbstractTranscribingLabel';
/**
* React {@code Component} for displaying a label when a transcriber is in the
* conference.
*
* @augments Component
*/
class TranscribingLabel extends Component<Props> {
/**
* Implements React's {@link Component#render()}.
*
* @inheritdoc
* @returns {ReactElement}
*/
render() {
if (!this.props._showLabel) {
return null;
}
return (
<Tooltip
content = { this.props.t('transcribing.labelToolTip') }
position = { 'left' }>
<Label
className = 'recording-label'
text = { this.props.t('transcribing.tr') } />
</Tooltip>
);
}
}
export default translate(connect(_mapStateToProps)(TranscribingLabel));

View File

@ -0,0 +1,28 @@
import React from 'react';
import { connect } from 'react-redux';
import { translate } from '../../base/i18n/functions';
import Label from '../../base/label/components/web/Label';
// eslint-disable-next-line lines-around-comment
// @ts-ignore
import { Tooltip } from '../../base/tooltip';
import { Props, _mapStateToProps } from './AbstractTranscribingLabel';
const TranscribingLabel = ({ _showLabel, t }: Props) => {
if (!_showLabel) {
return null;
}
return (
<Tooltip
content = { t('transcribing.labelToolTip') }
position = { 'left' }>
<Label
className = 'recording-label'
text = { t('transcribing.tr') } />
</Tooltip>
);
};
export default translate(connect(_mapStateToProps)(TranscribingLabel));