ソースを参照

feat(prejoin) Update design (#12844)

factor2
Robert Pintilii 2年前
コミット
0d5dae7ab9
コミッターのメールアドレスに関連付けられたアカウントが存在しません

+ 11
- 4
css/premeeting/_prejoin.scss ファイルの表示

@@ -41,11 +41,11 @@
41 41
     &-dropdown-btns {
42 42
         padding: 8px 0;
43 43
     }
44
-  
44
+
45 45
     &-dropdown-container {
46 46
         position: relative;
47 47
         width: 100%;
48
-  
48
+
49 49
         /**
50 50
         * Override default InlineDialog behaviour, since it does not play nicely with relative widths
51 51
         */
@@ -56,5 +56,12 @@
56 56
             width: 100%;
57 57
         }
58 58
     }
59
-  }
60
-  
59
+}
60
+
61
+.prejoin-input {
62
+    margin-bottom: 16px;
63
+
64
+    & input {
65
+        text-align: center;
66
+    }
67
+}

+ 18
- 119
css/premeeting/_premeeting-screens.scss ファイルの表示

@@ -1,14 +1,4 @@
1
- .premeeting-screen {
2
-    background: #292929;
3
-    bottom: 0;
4
-    display: flex;
5
-    font-size: 1.3em;
6
-    left: 0;
7
-    position: absolute;
8
-    right: 0;
9
-    top: 0;
10
-    z-index: $toolbarZ + 2;
11
-
1
+.premeeting-screen {
12 2
     .action-btn {
13 3
         border-radius: 6px;
14 4
         box-sizing: border-box;
@@ -75,129 +65,38 @@
75 65
         }
76 66
     }
77 67
 
78
-    .content {
79
-        align-items: center;
80
-        box-sizing: border-box;
81
-        display: flex;
82
-        flex-direction: column;
83
-        flex-shrink: 0;
84
-        height: 100%;
85
-        margin: 0 30px;
86
-        padding: 24px 0 16px;
68
+    #new-toolbox {
69
+        bottom: 0;
87 70
         position: relative;
88
-        width: $prejoinDefaultContentWidth;
89
-        z-index: $toolbarZ + 2;
90
-
91
-        &-controls {
92
-            align-items: center;
93
-            display: flex;
94
-            flex-direction: column;
95
-            margin: auto;
96
-            width: 100%;
97
-
98
-            .title {
99
-                color: #fff;
100
-                font-size: 28px;
101
-                font-weight: 600;
102
-                letter-spacing: -0.015;
103
-                line-height: 36px;
104
-                margin-bottom: 16px;
105
-                text-align: center;
106
-            }
107
-
108
-            input.field {
109
-                background-color: white;
110
-                border: none;
111
-                outline: none;
112
-                border-radius: 6px;
113
-                font-size: 14px;
114
-                line-height: 20px;
115
-                margin-bottom: 16px;
116
-                color: #1C2025;
117
-                padding: 10px 16px;
118
-                text-align: center;
119
-                width: 100%;
120
-
121
-                &.error {
122
-                    border: 1px solid #E04757;
123
-                }
124
-
125
-                &.focused {
126
-                    box-shadow: 0px 0px 1px 1.5px black, 0px 0px 1.3px 4px white;
127
-                }
128
-            }
129
-
130
-            #new-toolbox {
131
-                bottom: 0;
132
-                position: relative;
133
-                transition: none;
134
-
135
-                .toolbox-content {
136
-                    margin-bottom: 4px;
137
-                }
138
-
139
-                .toolbox-content-items {
140
-                    @include ltr;
141
-                    background: transparent;
142
-                    box-shadow: none;
143
-                    display: flex;
144
-                    justify-content: space-evenly;
145
-                    padding: 8px 0;
146
-                }
71
+        transition: none;
147 72
 
148
-                .toolbox-content,
149
-                .toolbox-content-wrapper,
150
-                .toolbox-content-items {
151
-                    box-sizing: border-box;
152
-                    width: 100%;
153
-                }
154
-            }
73
+        .toolbox-content {
74
+            margin-bottom: 4px;
155 75
         }
156
-    }
157
-
158
-    @media (max-width: 720px) {
159
-        flex-direction: column-reverse;
160 76
 
161
-        .content {
162
-            height: auto;
163
-            margin: 0 auto;
77
+        .toolbox-content-items {
78
+            @include ltr;
79
+            background: transparent;
80
+            box-shadow: none;
81
+            display: flex;
82
+            justify-content: space-between;
83
+            padding: 8px 0;
164 84
         }
165
-    }
166 85
 
167
-    // mobile phone landscape
168
-    @media (max-height: 420px) {
169
-        div.content {
170
-            padding: 16px 16px 0 16px;
86
+        .toolbox-content,
87
+        .toolbox-content-wrapper,
88
+        .toolbox-content-items {
89
+            box-sizing: border-box;
90
+            width: 100%;
171 91
         }
172 92
     }
173 93
 
174 94
     @media (max-width: 400px) {
175
-        .content {
176
-            padding: 16px;
177
-            width: 100%;
178
-
179
-            &-controls {
180
-                input.field {
181
-                    font-size: 16px;
182
-                    padding: 14px 16px;
183
-                }
184
-            }
185
-
186
-            .title {
187
-                display: none;
188
-            }
189
-        }
190
-
191 95
         .device-status-error {
192 96
             border-radius: 0;
193 97
             margin: 0 -16px;
194 98
         }
195 99
 
196
-        input.field {
197
-            font-size: 16px;
198
-            padding: 14px 16px;
199
-        }
200
-
201 100
         .action-btn {
202 101
             font-size: 16px;
203 102
             margin-bottom: 8px;

+ 5
- 6
react/features/base/premeeting/components/web/ConnectionStatus.tsx ファイルの表示

@@ -7,6 +7,7 @@ import { translate } from '../../../i18n/functions';
7 7
 import Icon from '../../../icons/components/Icon';
8 8
 import { IconArrowDown, IconWifi1Bar, IconWifi2Bars, IconWifi3Bars } from '../../../icons/svg';
9 9
 import { connect } from '../../../redux/functions';
10
+import { withPixelLineHeight } from '../../../styles/functions.web';
10 11
 import { PREJOIN_DEFAULT_CONTENT_WIDTH } from '../../../ui/components/variables';
11 12
 import { CONNECTION_TYPE } from '../../constants';
12 13
 import { getConnectionData } from '../../functions';
@@ -27,11 +28,8 @@ interface IProps extends WithTranslation {
27 28
 const useStyles = makeStyles()(theme => {
28 29
     return {
29 30
         connectionStatus: {
30
-            borderRadius: '6px',
31 31
             color: '#fff',
32
-            fontSize: '12px',
33
-            letterSpacing: '0.16px',
34
-            lineHeight: '16px',
32
+            ...withPixelLineHeight(theme.typography.bodyShortRegular),
35 33
             position: 'absolute',
36 34
             width: '100%',
37 35
 
@@ -56,14 +54,15 @@ const useStyles = makeStyles()(theme => {
56 54
                 backgroundColor: 'rgba(0, 0, 0, 0.7)',
57 55
                 alignItems: 'center',
58 56
                 display: 'flex',
59
-                padding: '14px 16px'
57
+                padding: '12px 16px',
58
+                borderRadius: theme.shape.borderRadius
60 59
             },
61 60
 
62 61
             '& .con-status-circle': {
63 62
                 borderRadius: '50%',
64 63
                 display: 'inline-block',
65 64
                 padding: theme.spacing(1),
66
-                marginRight: theme.spacing(3)
65
+                marginRight: theme.spacing(2)
67 66
             },
68 67
 
69 68
             '& .con-status--good': {

+ 68
- 10
react/features/base/premeeting/components/web/PreMeetingScreen.tsx ファイルの表示

@@ -1,5 +1,7 @@
1 1
 /* eslint-disable lines-around-comment */
2
+import clsx from 'clsx';
2 3
 import React, { ReactNode } from 'react';
4
+import { connect } from 'react-redux';
3 5
 import { makeStyles } from 'tss-react/mui';
4 6
 
5 7
 import { IReduxState } from '../../../../app/types';
@@ -9,12 +11,12 @@ import { Toolbox } from '../../../../toolbox/components/web';
9 11
 import { getConferenceName } from '../../../conference/functions';
10 12
 import { PREMEETING_BUTTONS, THIRD_PARTY_PREJOIN_BUTTONS } from '../../../config/constants';
11 13
 import { getToolbarButtons, isToolbarButtonEnabled } from '../../../config/functions.web';
12
-import { connect } from '../../../redux/functions';
13 14
 import { withPixelLineHeight } from '../../../styles/functions.web';
14 15
 
15 16
 import ConnectionStatus from './ConnectionStatus';
16 17
 // @ts-ignore
17 18
 import Preview from './Preview';
19
+/* eslint-enable lines-around-comment */
18 20
 
19 21
 interface IProps {
20 22
 
@@ -51,7 +53,7 @@ interface IProps {
51 53
     /**
52 54
      * Indicates whether the copy url button should be shown.
53 55
      */
54
-    showCopyUrlButton: boolean;
56
+    showCopyUrlButton?: boolean;
55 57
 
56 58
     /**
57 59
      * Indicates whether the device status should be shown.
@@ -86,7 +88,64 @@ interface IProps {
86 88
 
87 89
 const useStyles = makeStyles()(theme => {
88 90
     return {
89
-        subtitle: {
91
+        container: {
92
+            height: '100%',
93
+            position: 'absolute',
94
+            inset: '0 0 0 0',
95
+            display: 'flex',
96
+            backgroundColor: theme.palette.ui01,
97
+            zIndex: 252,
98
+
99
+            '@media (max-width: 720px)': {
100
+                flexDirection: 'column-reverse'
101
+            }
102
+        },
103
+        content: {
104
+            display: 'flex',
105
+            flexDirection: 'column',
106
+            alignItems: 'center',
107
+            flexShrink: 0,
108
+            boxSizing: 'border-box',
109
+            margin: '0 48px',
110
+            padding: '24px 0 16px',
111
+            position: 'relative',
112
+            width: '300px',
113
+            height: '100%',
114
+            zIndex: 252,
115
+
116
+            '@media (max-width: 720px)': {
117
+                height: 'auto',
118
+                margin: '0 auto'
119
+            },
120
+
121
+            // mobile phone landscape
122
+            '@media (max-width: 420px)': {
123
+                padding: '16px 16px 0 16px',
124
+                width: '100%'
125
+            },
126
+
127
+            '@media (max-width: 400px)': {
128
+                padding: '16px'
129
+            }
130
+        },
131
+        contentControls: {
132
+            display: 'flex',
133
+            flexDirection: 'column',
134
+            alignItems: 'center',
135
+            margin: 'auto',
136
+            width: '100%'
137
+        },
138
+        title: {
139
+            ...withPixelLineHeight(theme.typography.heading4),
140
+            color: `${theme.palette.text01}!important`,
141
+            marginBottom: theme.spacing(3),
142
+            textAlign: 'center',
143
+
144
+            '@media (max-width: 400px)': {
145
+                display: 'none'
146
+            }
147
+        },
148
+        roomName: {
90 149
             ...withPixelLineHeight(theme.typography.heading5),
91 150
             color: theme.palette.text01,
92 151
             marginBottom: theme.spacing(4),
@@ -112,7 +171,6 @@ const PreMeetingScreen = ({
112 171
     videoTrack
113 172
 }: IProps) => {
114 173
     const { classes } = useStyles();
115
-    const containerClassName = `premeeting-screen ${className ? className : ''}`;
116 174
     const style = _premeetingBackground ? {
117 175
         background: _premeetingBackground,
118 176
         backgroundPosition: 'center',
@@ -120,17 +178,17 @@ const PreMeetingScreen = ({
120 178
     } : {};
121 179
 
122 180
     return (
123
-        <div className = { containerClassName }>
181
+        <div className = { clsx('premeeting-screen', classes.container, className) }>
124 182
             <div style = { style }>
125
-                <div className = 'content'>
183
+                <div className = { classes.content }>
126 184
                     <ConnectionStatus />
127 185
 
128
-                    <div className = 'content-controls'>
129
-                        <h1 className = 'title'>
186
+                    <div className = { classes.contentControls }>
187
+                        <h1 className = { classes.title }>
130 188
                             {title}
131 189
                         </h1>
132 190
                         {_roomName && (
133
-                            <span className = { classes.subtitle }>
191
+                            <span className = { classes.roomName }>
134 192
                                 {_roomName}
135 193
                             </span>
136 194
                         )}
@@ -175,7 +233,7 @@ function mapStateToProps(state: IReduxState, ownProps: Partial<IProps>) {
175 233
             ? premeetingButtons
176 234
             : premeetingButtons.filter(b => isToolbarButtonEnabled(b, toolbarButtons)),
177 235
         _premeetingBackground: premeetingBackground,
178
-        _roomName: hideConferenceSubject ? undefined : getConferenceName(state)
236
+        _roomName: (hideConferenceSubject ? undefined : getConferenceName(state)) ?? ''
179 237
     };
180 238
 }
181 239
 

+ 0
- 2
react/features/base/ui/Tokens.ts ファイルの表示

@@ -48,7 +48,6 @@ export const colors = {
48 48
     // after we replace them in the components.
49 49
     primary10: '#17A0DB',
50 50
     primary11: '#1081B2',
51
-    primary12: '#B8C7E0',
52 51
     surface00: '#111111',
53 52
     surface12: '#AAAAAA',
54 53
     surface13: '#495258',
@@ -199,7 +198,6 @@ export const colorMap = {
199 198
     border01: 'surface08',
200 199
     border02: 'surface06',
201 200
     border03: 'surface04',
202
-    border04: 'primary12',
203 201
     border05: 'surface07',
204 202
     borderError: 'error06',
205 203
     warning03: 'warning07',

+ 4
- 0
react/features/base/ui/components/web/Input.tsx ファイルの表示

@@ -10,6 +10,7 @@ import { IInputProps } from '../types';
10 10
 
11 11
 interface IProps extends IInputProps {
12 12
     accessibilityLabel?: string;
13
+    autoComplete?: string;
13 14
     autoFocus?: boolean;
14 15
     bottomLabel?: string;
15 16
     className?: string;
@@ -131,6 +132,7 @@ const useStyles = makeStyles()(theme => {
131 132
 
132 133
 const Input = React.forwardRef<any, IProps>(({
133 134
     accessibilityLabel,
135
+    autoComplete,
134 136
     autoFocus,
135 137
     bottomLabel,
136 138
     className,
@@ -175,6 +177,7 @@ const Input = React.forwardRef<any, IProps>(({
175 177
                 {textarea ? (
176 178
                     <TextareaAutosize
177 179
                         aria-label = { accessibilityLabel }
180
+                        autoComplete = { autoComplete }
178 181
                         autoFocus = { autoFocus }
179 182
                         className = { cx(styles.input, isMobile && 'is-mobile',
180 183
                             error && 'error', clearable && styles.clearableInput, icon && 'icon-input') }
@@ -194,6 +197,7 @@ const Input = React.forwardRef<any, IProps>(({
194 197
                 ) : (
195 198
                     <input
196 199
                         aria-label = { accessibilityLabel }
200
+                        autoComplete = { autoComplete }
197 201
                         autoFocus = { autoFocus }
198 202
                         className = { cx(styles.input, isMobile && 'is-mobile',
199 203
                             error && 'error', clearable && styles.clearableInput, icon && 'icon-input') }

+ 1
- 9
react/features/base/ui/constants.web.ts ファイルの表示

@@ -265,15 +265,7 @@ export const commonStyles = (theme: Theme) => {
265 265
             padding: 6,
266 266
             textAlign: 'center' as const,
267 267
             pointerEvents: 'all' as const,
268
-            boxShadow: '0px 2px 8px 4px rgba(0, 0, 0, 0.25), 0px 0px 0px 1px rgba(0, 0, 0, 0.15)',
269
-
270
-            '& > div': {
271
-                marginLeft: 8,
272
-
273
-                '&:first-child': {
274
-                    marginLeft: 0
275
-                }
276
-            }
268
+            boxShadow: '0px 2px 8px 4px rgba(0, 0, 0, 0.25), 0px 0px 0px 1px rgba(0, 0, 0, 0.15)'
277 269
         }
278 270
     };
279 271
 };

react/features/prejoin/components/web/Prejoin.js → react/features/prejoin/components/web/Prejoin.tsx ファイルの表示

@@ -1,25 +1,30 @@
1
-// @flow
2
-
3 1
 import InlineDialog from '@atlaskit/inline-dialog';
4 2
 import React, { Component } from 'react';
3
+import { WithTranslation } from 'react-i18next';
5 4
 
5
+import { IReduxState } from '../../../app/types';
6
+// eslint-disable-next-line lines-around-comment
7
+// @ts-ignore
6 8
 import { Avatar } from '../../../base/avatar';
7
-import { isNameReadOnly } from '../../../base/config';
8
-import { translate } from '../../../base/i18n';
9
-import { IconArrowDown, IconArrowUp, IconPhoneRinging, IconVolumeOff } from '../../../base/icons';
10
-import { isVideoMutedByUser } from '../../../base/media';
11
-import { getLocalParticipant } from '../../../base/participants';
12
-import { ActionButton, InputField, PreMeetingScreen } from '../../../base/premeeting';
13
-import { connect } from '../../../base/redux';
14
-import { getDisplayName, updateSettings } from '../../../base/settings';
15
-import { getLocalJitsiVideoTrack } from '../../../base/tracks';
9
+import { isNameReadOnly } from '../../../base/config/functions.web';
10
+import { translate } from '../../../base/i18n/functions';
11
+import { IconArrowDown, IconArrowUp, IconPhoneRinging, IconVolumeOff } from '../../../base/icons/svg';
12
+import { isVideoMutedByUser } from '../../../base/media/functions';
13
+import { getLocalParticipant } from '../../../base/participants/functions';
14
+import ActionButton from '../../../base/premeeting/components/web/ActionButton';
15
+import PreMeetingScreen from '../../../base/premeeting/components/web/PreMeetingScreen';
16
+import { connect } from '../../../base/redux/functions';
17
+import { updateSettings } from '../../../base/settings/actions';
18
+import { getDisplayName } from '../../../base/settings/functions.web';
19
+import { getLocalJitsiVideoTrack } from '../../../base/tracks/functions.web';
16 20
 import Button from '../../../base/ui/components/web/Button';
21
+import Input from '../../../base/ui/components/web/Input';
17 22
 import { BUTTON_TYPES } from '../../../base/ui/constants.any';
18 23
 import {
19 24
     joinConference as joinConferenceAction,
20 25
     joinConferenceWithoutAudio as joinConferenceWithoutAudioAction,
21 26
     setJoinByPhoneDialogVisiblity as setJoinByPhoneDialogVisiblityAction
22
-} from '../../actions';
27
+} from '../../actions.web';
23 28
 import {
24 29
     isDeviceStatusVisible,
25 30
     isDisplayNameRequired,
@@ -28,114 +33,112 @@ import {
28 33
     isPrejoinDisplayNameVisible
29 34
 } from '../../functions';
30 35
 
36
+// @ts-ignore
31 37
 import JoinByPhoneDialog from './dialogs/JoinByPhoneDialog';
32 38
 
33
-type Props = {
39
+interface IProps extends WithTranslation {
34 40
 
35 41
     /**
36 42
      * Indicates whether the display  name is editable.
37 43
      */
38
-    canEditDisplayName: boolean,
44
+    canEditDisplayName: boolean;
39 45
 
40 46
     /**
41 47
      * Flag signaling if the device status is visible or not.
42 48
      */
43
-    deviceStatusVisible: boolean,
49
+    deviceStatusVisible: boolean;
44 50
 
45 51
     /**
46 52
      * If join by phone button should be visible.
47 53
      */
48
-    hasJoinByPhoneButton: boolean,
54
+    hasJoinByPhoneButton: boolean;
49 55
 
50 56
     /**
51 57
      * Joins the current meeting.
52 58
      */
53
-    joinConference: Function,
59
+    joinConference: Function;
54 60
 
55 61
     /**
56 62
      * Joins the current meeting without audio.
57 63
      */
58
-    joinConferenceWithoutAudio: Function,
64
+    joinConferenceWithoutAudio: Function;
59 65
 
60 66
     /**
61 67
      * Whether conference join is in progress.
62 68
      */
63
-    joiningInProgress: boolean,
69
+    joiningInProgress: boolean;
64 70
 
65 71
     /**
66 72
      * The name of the user that is about to join.
67 73
      */
68
-    name: string,
69
-
70
-    /**
71
-     * Updates settings.
72
-     */
73
-    updateSettings: Function,
74
+    name: string;
74 75
 
75 76
     /**
76 77
      * Local participant id.
77 78
      */
78
-    participantId: string,
79
+    participantId: string;
79 80
 
80 81
     /**
81 82
      * The prejoin config.
82 83
      */
83
-    prejoinConfig?: Object,
84
+    prejoinConfig?: any;
84 85
 
85 86
     /**
86 87
      * Whether the name input should be read only or not.
87 88
      */
88
-    readOnlyName: boolean,
89
+    readOnlyName: boolean;
89 90
 
90 91
     /**
91 92
      * Sets visibility of the 'JoinByPhoneDialog'.
92 93
      */
93
-    setJoinByPhoneDialogVisiblity: Function,
94
+    setJoinByPhoneDialogVisiblity: Function;
94 95
 
95 96
     /**
96 97
      * Flag signaling the visibility of camera preview.
97 98
      */
98
-    showCameraPreview: boolean,
99
+    showCameraPreview: boolean;
99 100
 
100 101
     /**
101
-     * If should show an error when joining without a name.
102
+     * If 'JoinByPhoneDialog' is visible or not.
102 103
      */
103
-    showErrorOnJoin: boolean,
104
+    showDialog: boolean;
104 105
 
105 106
     /**
106
-     * If 'JoinByPhoneDialog' is visible or not.
107
+     * If should show an error when joining without a name.
107 108
      */
108
-    showDialog: boolean,
109
+    showErrorOnJoin: boolean;
109 110
 
110 111
     /**
111
-     * Used for translation.
112
+     * Updates settings.
112 113
      */
113
-    t: Function,
114
+    updateSettings: Function;
114 115
 
115 116
     /**
116 117
      * The JitsiLocalTrack to display.
117 118
      */
118
-    videoTrack: ?Object
119
-};
119
+    videoTrack?: Object;
120
+}
120 121
 
121
-type State = {
122
+interface IState {
122 123
 
123 124
     /**
124 125
      * Flag controlling the visibility of the 'join by phone' buttons.
125 126
      */
126
-    showJoinByPhoneButtons: boolean
127
+    showJoinByPhoneButtons: boolean;
127 128
 }
128 129
 
129 130
 /**
130 131
  * This component is displayed before joining a meeting.
131 132
  */
132
-class Prejoin extends Component<Props, State> {
133
+class Prejoin extends Component<IProps, IState> {
134
+    showDisplayNameField: boolean;
135
+
133 136
     /**
134 137
      * Initializes a new {@code Prejoin} instance.
135 138
      *
136 139
      * @inheritdoc
137 140
      */
138
-    constructor(props) {
141
+    constructor(props: IProps) {
139 142
         super(props);
140 143
 
141 144
         this.state = {
@@ -150,12 +153,11 @@ class Prejoin extends Component<Props, State> {
150 153
         this._setName = this._setName.bind(this);
151 154
         this._onJoinConferenceWithoutAudioKeyPress = this._onJoinConferenceWithoutAudioKeyPress.bind(this);
152 155
         this._showDialogKeyPress = this._showDialogKeyPress.bind(this);
153
-        this._onJoinKeyPress = this._onJoinKeyPress.bind(this);
154 156
         this._getExtraJoinButtons = this._getExtraJoinButtons.bind(this);
157
+        this._onInputKeyPress = this._onInputKeyPress.bind(this);
155 158
 
156 159
         this.showDisplayNameField = props.canEditDisplayName || props.showErrorOnJoin;
157 160
     }
158
-    _onJoinButtonClick: () => void;
159 161
 
160 162
     /**
161 163
      * Handler for the join button.
@@ -170,24 +172,6 @@ class Prejoin extends Component<Props, State> {
170 172
         this.props.joinConference();
171 173
     }
172 174
 
173
-    _onJoinKeyPress: (Object) => void;
174
-
175
-    /**
176
-     * KeyPress handler for accessibility.
177
-     *
178
-     * @param {Object} e - The key event to handle.
179
-     *
180
-     * @returns {void}
181
-     */
182
-    _onJoinKeyPress(e) {
183
-        if (e.key === ' ' || e.key === 'Enter') {
184
-            e.preventDefault();
185
-            this._onJoinButtonClick();
186
-        }
187
-    }
188
-
189
-    _onDropdownClose: () => void;
190
-
191 175
     /**
192 176
      * Closes the dropdown.
193 177
      *
@@ -199,38 +183,32 @@ class Prejoin extends Component<Props, State> {
199 183
         });
200 184
     }
201 185
 
202
-    _onOptionsClick: () => void;
203
-
204 186
     /**
205 187
      * Displays the join by phone buttons dropdown.
206 188
      *
207 189
      * @param {Object} e - The synthetic event.
208 190
      * @returns {void}
209 191
      */
210
-    _onOptionsClick(e) {
211
-        e.stopPropagation();
192
+    _onOptionsClick(e?: React.KeyboardEvent | React.MouseEvent | undefined) {
193
+        e?.stopPropagation();
212 194
 
213 195
         this.setState({
214 196
             showJoinByPhoneButtons: !this.state.showJoinByPhoneButtons
215 197
         });
216 198
     }
217 199
 
218
-    _setName: () => void;
219
-
220 200
     /**
221 201
      * Sets the guest participant name.
222 202
      *
223 203
      * @param {string} displayName - Participant name.
224 204
      * @returns {void}
225 205
      */
226
-    _setName(displayName) {
206
+    _setName(displayName: string) {
227 207
         this.props.updateSettings({
228 208
             displayName
229 209
         });
230 210
     }
231 211
 
232
-    _closeDialog: () => void;
233
-
234 212
     /**
235 213
      * Closes the join by phone dialog.
236 214
      *
@@ -240,8 +218,6 @@ class Prejoin extends Component<Props, State> {
240 218
         this.props.setJoinByPhoneDialogVisiblity(false);
241 219
     }
242 220
 
243
-    _showDialog: () => void;
244
-
245 221
     /**
246 222
      * Displays the dialog for joining a meeting by phone.
247 223
      *
@@ -252,8 +228,6 @@ class Prejoin extends Component<Props, State> {
252 228
         this._onDropdownClose();
253 229
     }
254 230
 
255
-    _showDialogKeyPress: (Object) => void;
256
-
257 231
     /**
258 232
      * KeyPress handler for accessibility.
259 233
      *
@@ -261,15 +235,13 @@ class Prejoin extends Component<Props, State> {
261 235
      *
262 236
      * @returns {void}
263 237
      */
264
-    _showDialogKeyPress(e) {
238
+    _showDialogKeyPress(e: React.KeyboardEvent) {
265 239
         if (e.key === ' ' || e.key === 'Enter') {
266 240
             e.preventDefault();
267 241
             this._showDialog();
268 242
         }
269 243
     }
270 244
 
271
-    _onJoinConferenceWithoutAudioKeyPress: (Object) => void;
272
-
273 245
     /**
274 246
      * KeyPress handler for accessibility.
275 247
      *
@@ -277,7 +249,7 @@ class Prejoin extends Component<Props, State> {
277 249
      *
278 250
      * @returns {void}
279 251
      */
280
-    _onJoinConferenceWithoutAudioKeyPress(e) {
252
+    _onJoinConferenceWithoutAudioKeyPress(e: React.KeyboardEvent) {
281 253
         if (this.props.joinConferenceWithoutAudio
282 254
             && (e.key === ' '
283 255
                 || e.key === 'Enter')) {
@@ -286,8 +258,6 @@ class Prejoin extends Component<Props, State> {
286 258
         }
287 259
     }
288 260
 
289
-    _getExtraJoinButtons: () => Object;
290
-
291 261
     /**
292 262
      * Gets the list of extra join buttons.
293 263
      *
@@ -320,6 +290,20 @@ class Prejoin extends Component<Props, State> {
320 290
         };
321 291
     }
322 292
 
293
+    /**
294
+     * Handle keypress on input.
295
+     *
296
+     * @param {KeyboardEvent} e - Keyboard event.
297
+     * @returns {void}
298
+     */
299
+    _onInputKeyPress(e: React.KeyboardEvent) {
300
+        const { joinConference } = this.props;
301
+
302
+        if (e.key === 'Enter') {
303
+            joinConference();
304
+        }
305
+    }
306
+
323 307
     /**
324 308
      * Implements React's {@link Component#render()}.
325 309
      *
@@ -330,7 +314,6 @@ class Prejoin extends Component<Props, State> {
330 314
         const {
331 315
             deviceStatusVisible,
332 316
             hasJoinByPhoneButton,
333
-            joinConference,
334 317
             joinConferenceWithoutAudio,
335 318
             joiningInProgress,
336 319
             name,
@@ -343,16 +326,16 @@ class Prejoin extends Component<Props, State> {
343 326
             t,
344 327
             videoTrack
345 328
         } = this.props;
346
-        const { _closeDialog, _onDropdownClose, _onJoinButtonClick, _onJoinKeyPress,
347
-            _onOptionsClick, _setName } = this;
329
+        const { _closeDialog, _onDropdownClose, _onJoinButtonClick,
330
+            _onOptionsClick, _setName, _onInputKeyPress } = this;
348 331
 
349 332
         const extraJoinButtons = this._getExtraJoinButtons();
350
-        let extraButtonsToRender = Object.values(extraJoinButtons).filter((val: Object) =>
333
+        let extraButtonsToRender = Object.values(extraJoinButtons).filter((val: any) =>
351 334
             !(prejoinConfig?.hideExtraJoinButtons || []).includes(val.key)
352 335
         );
353 336
 
354 337
         if (!hasJoinByPhoneButton) {
355
-            extraButtonsToRender = extraButtonsToRender.filter((btn: Object) => btn.key !== 'by-phone');
338
+            extraButtonsToRender = extraButtonsToRender.filter((btn: any) => btn.key !== 'by-phone');
356 339
         }
357 340
         const hasExtraJoinButtons = Boolean(extraButtonsToRender.length);
358 341
         const { showJoinByPhoneButtons } = this.state;
@@ -366,14 +349,14 @@ class Prejoin extends Component<Props, State> {
366 349
                 <div
367 350
                     className = 'prejoin-input-area'
368 351
                     data-testid = 'prejoin.screen'>
369
-                    {this.showDisplayNameField ? (<InputField
352
+                    {this.showDisplayNameField ? (<Input
370 353
                         autoComplete = { 'name' }
371 354
                         autoFocus = { true }
372
-                        className = { showErrorOnJoin ? 'error' : '' }
373
-                        hasError = { showErrorOnJoin }
355
+                        className = 'prejoin-input'
356
+                        error = { showErrorOnJoin }
374 357
                         onChange = { _setName }
375
-                        onSubmit = { joinConference }
376
-                        placeHolder = { t('dialog.enterDisplayName') }
358
+                        onKeyPress = { _onInputKeyPress }
359
+                        placeholder = { t('dialog.enterDisplayName') }
377 360
                         readOnly = { readOnlyName }
378 361
                         value = { name } />
379 362
                     ) : (
@@ -394,7 +377,7 @@ class Prejoin extends Component<Props, State> {
394 377
                     <div className = 'prejoin-preview-dropdown-container'>
395 378
                         <InlineDialog
396 379
                             content = { hasExtraJoinButtons && <div className = 'prejoin-preview-dropdown-btns'>
397
-                                {extraButtonsToRender.map(({ key, ...rest }: Object) => (
380
+                                {extraButtonsToRender.map(({ key, ...rest }) => (
398 381
                                     <Button
399 382
                                         disabled = { joiningInProgress }
400 383
                                         fullWidth = { true }
@@ -413,7 +396,6 @@ class Prejoin extends Component<Props, State> {
413 396
                                 disabled = { joiningInProgress }
414 397
                                 hasOptions = { hasExtraJoinButtons }
415 398
                                 onClick = { _onJoinButtonClick }
416
-                                onKeyPress = { _onJoinKeyPress }
417 399
                                 onOptionsClick = { _onOptionsClick }
418 400
                                 role = 'button'
419 401
                                 tabIndex = { 0 }
@@ -440,10 +422,10 @@ class Prejoin extends Component<Props, State> {
440 422
  * @param {Object} state - The redux state.
441 423
  * @returns {Object}
442 424
  */
443
-function mapStateToProps(state): Object {
425
+function mapStateToProps(state: IReduxState) {
444 426
     const name = getDisplayName(state);
445 427
     const showErrorOnJoin = isDisplayNameRequired(state) && !name;
446
-    const { id: participantId } = getLocalParticipant(state);
428
+    const { id: participantId } = getLocalParticipant(state) ?? {};
447 429
     const { joiningInProgress } = state['features/prejoin'];
448 430
 
449 431
     return {

+ 17
- 33
react/features/prejoin/components/web/preview/DeviceStatus.tsx ファイルの表示

@@ -4,9 +4,8 @@ import { makeStyles } from 'tss-react/mui';
4 4
 
5 5
 import { IReduxState } from '../../../../app/types';
6 6
 import { translate } from '../../../../base/i18n/functions';
7
-import Icon from '../../../../base/icons/components/Icon';
8
-import { IconCheck, IconExclamationTriangle } from '../../../../base/icons/svg';
9 7
 import { connect } from '../../../../base/redux/functions';
8
+import { withPixelLineHeight } from '../../../../base/styles/functions.web';
10 9
 import {
11 10
     getDeviceStatusText,
12 11
     getDeviceStatusType
@@ -29,13 +28,12 @@ export interface IProps extends WithTranslation {
29 28
 const useStyles = makeStyles()(theme => {
30 29
     return {
31 30
         deviceStatus: {
31
+            display: 'flex',
32 32
             alignItems: 'center',
33
+            justifyContent: 'center',
34
+            ...withPixelLineHeight(theme.typography.bodyShortRegular),
33 35
             color: '#fff',
34
-            display: 'flex',
35
-            fontSize: '14px',
36
-            lineHeight: '20px',
37
-            padding: '6px',
38
-            textAlign: 'center',
36
+            marginTop: theme.spacing(4),
39 37
 
40 38
             '& span': {
41 39
                 marginLeft: theme.spacing(3)
@@ -47,33 +45,23 @@ const useStyles = makeStyles()(theme => {
47 45
                 borderRadius: '6px',
48 46
                 color: theme.palette.uiBackground,
49 47
                 padding: '12px 16px',
50
-                textAlign: 'left'
51
-            },
52
-            '& .device-icon': {
53
-                backgroundPosition: 'center',
54
-                backgroundRepeat: 'no-repeat',
55
-                display: 'inline-block',
56
-                height: '16px',
57
-                width: '16px'
48
+                textAlign: 'left',
49
+                marginTop: theme.spacing(2)
58 50
             },
59
-            '& .device-icon--ok svg path': {
60
-                fill: '#189B55'
51
+
52
+            '@media (max-width: 720px)': {
53
+                marginTop: 0
61 54
             }
55
+        },
56
+        indicator: {
57
+            width: '16px',
58
+            height: '16px',
59
+            borderRadius: '100%',
60
+            backgroundColor: theme.palette.success01
62 61
         }
63 62
     };
64 63
 });
65 64
 
66
-const iconMap = {
67
-    warning: {
68
-        src: IconExclamationTriangle,
69
-        className: 'device-icon--warning'
70
-    },
71
-    ok: {
72
-        src: IconCheck,
73
-        className: 'device-icon--ok'
74
-    }
75
-};
76
-
77 65
 /**
78 66
  * Strip showing the current status of the devices.
79 67
  * User is informed if there are missing or malfunctioning devices.
@@ -82,7 +70,6 @@ const iconMap = {
82 70
  */
83 71
 function DeviceStatus({ deviceStatusType, deviceStatusText, t }: IProps) {
84 72
     const { classes, cx } = useStyles();
85
-    const { src, className } = iconMap[deviceStatusType as keyof typeof iconMap];
86 73
     const hasError = deviceStatusType === 'warning';
87 74
     const containerClassName = cx(classes.deviceStatus, { 'device-status-error': hasError });
88 75
 
@@ -91,10 +78,7 @@ function DeviceStatus({ deviceStatusType, deviceStatusText, t }: IProps) {
91 78
             className = { containerClassName }
92 79
             role = 'alert'
93 80
             tabIndex = { -1 }>
94
-            <Icon
95
-                className = { `device-icon ${className}` }
96
-                size = { 16 }
97
-                src = { src } />
81
+            {!hasError && <div className = { classes.indicator } />}
98 82
             <span role = 'heading'>
99 83
                 {hasError ? t('prejoin.errorNoPermissions') : t(deviceStatusText ?? '')}
100 84
             </span>

読み込み中…
キャンセル
保存