diff --git a/css/_chat.scss b/css/_chat.scss index 233f54ff4..2dd2117d2 100644 --- a/css/_chat.scss +++ b/css/_chat.scss @@ -2,34 +2,39 @@ background-color: $chatBackgroundColor; box-sizing: border-box; color: #FFF; - display: flex; - flex-direction: column; height: 100%; - left: -$sidebarWidth; - overflow: hidden; position: absolute; top: 0; width: $sidebarWidth; z-index: $sideToolbarContainerZ; - /** - * The sidebar (chat) is off-screen when hidden. Move it flush to the left - * side of the window when it should be visible. - */ - &.slideInExt { - left: 0; + @media (max-width: 580px) { + width: 100%; } } +.chat-panel { + display: flex; + flex-direction: column; + // extract header + tabs height + height: calc(100% - 102px); +} + +.chat-panel-no-tabs { + // extract header height + height: calc(100% - 70px); +} + #chatconversation { box-sizing: border-box; flex: 1; font-size: 10pt; + // extract message input height + height: calc(100% - 68px); line-height: 20px; overflow: auto; padding: 16px; text-align: left; - width: $sidebarWidth; word-wrap: break-word; display: flex; @@ -58,28 +63,6 @@ a:active { color: black; } - - &::-webkit-scrollbar { - background: #06a5df; - width: 7px; - } - - &::-webkit-scrollbar-button { - display: none; - } - - &::-webkit-scrollbar-track { - background: black; - } - - &::-webkit-scrollbar-track-piece { - background: black; - } - - &::-webkit-scrollbar-thumb { - background: #06a5df; - border-radius: 4px; - } } #chat-recipient { @@ -319,10 +302,6 @@ text-overflow: ellipsis; overflow: hidden; } - - @media (max-width: 580px) { - display: none !important; - } } .sr-only { diff --git a/css/_polls.scss b/css/_polls.scss index b6e444d0f..cf812fcec 100644 --- a/css/_polls.scss +++ b/css/_polls.scss @@ -238,10 +238,6 @@ ol.poll-result-list { .polls-pane-content { height: calc(100% - 102px); position: relative; - - @media (max-width: 580px) { - height: 100%; - } } .pane-content{ diff --git a/css/_variables.scss b/css/_variables.scss index df4636083..fd1d0aba9 100644 --- a/css/_variables.scss +++ b/css/_variables.scss @@ -122,7 +122,7 @@ $zindex10: 10; $reloadZ: 20; $poweredByZ: 100; $ringingZ: 300; -$sideToolbarContainerZ: 200; +$sideToolbarContainerZ: 300; $toolbarZ: 250; $drawerZ: 351; $tooltipsZ: 401; @@ -269,4 +269,4 @@ $verySmallScreen: 500px; * Prejoin / premeeting screen */ -$prejoinDefaultContentWidth: 336px; \ No newline at end of file +$prejoinDefaultContentWidth: 336px; diff --git a/react/features/chat/components/web/Chat.js b/react/features/chat/components/web/Chat.js index 9ea4f00d2..111b805b7 100644 --- a/react/features/chat/components/web/Chat.js +++ b/react/features/chat/components/web/Chat.js @@ -1,5 +1,6 @@ // @flow +import clsx from 'clsx'; import React from 'react'; import { translate } from '../../../base/i18n'; @@ -11,14 +12,12 @@ import AbstractChat, { type Props } from '../AbstractChat'; -import ChatDialog from './ChatDialog'; -import Header from './ChatDialogHeader'; +import ChatHeader from './ChatHeader'; import ChatInput from './ChatInput'; import DisplayNameForm from './DisplayNameForm'; import KeyboardAvoider from './KeyboardAvoider'; import MessageContainer from './MessageContainer'; import MessageRecipient from './MessageRecipient'; -import TouchmoveHack from './TouchmoveHack'; /** * React Component for holding the chat feature in a side panel that slides in @@ -26,12 +25,6 @@ import TouchmoveHack from './TouchmoveHack'; */ class Chat extends AbstractChat { - /** - * Whether or not the {@code Chat} component is off-screen, having finished - * its hiding animation. - */ - _isExited: boolean; - /** * Reference to the React Component for displaying chat messages. Used for * scrolling to the end of the chat messages. @@ -47,13 +40,13 @@ class Chat extends AbstractChat { constructor(props: Props) { super(props); - this._isExited = true; this._messageContainerRef = React.createRef(); // Bind event handlers so they are only bound once for every instance. - this._renderPanelContent = this._renderPanelContent.bind(this); + this._onChatTabKeyDown = this._onChatTabKeyDown.bind(this); this._onChatInputResize = this._onChatInputResize.bind(this); this._onEscClick = this._onEscClick.bind(this); + this._onPollsTabKeyDown = this._onPollsTabKeyDown.bind(this); this._onToggleChat = this._onToggleChat.bind(this); } @@ -78,21 +71,6 @@ class Chat extends AbstractChat { this._scrollMessageContainerToBottom(false); } } - _onEscClick: (KeyboardEvent) => void; - - /** - * Click handler for the chat sidenav. - * - * @param {KeyboardEvent} event - Esc key click to close the popup. - * @returns {void} - */ - _onEscClick(event) { - if (event.key === 'Escape' && this.props._isOpen) { - event.preventDefault(); - event.stopPropagation(); - this._onToggleChat(); - } - } /** * Implements React's {@link Component#render()}. @@ -101,10 +79,22 @@ class Chat extends AbstractChat { * @returns {ReactElement} */ render() { + const { _isOpen, _isPollsEnabled, _showNamePrompt } = this.props; + return ( - <> - { this._renderPanelContent() } - + _isOpen ?
+ + { _showNamePrompt + ? + : this._renderChat() } +
: null ); } @@ -121,6 +111,54 @@ class Chat extends AbstractChat { this._messageContainerRef.current.maybeUpdateBottomScroll(); } + _onChatTabKeyDown: (KeyboardEvent) => void; + + /** + * Key press handler for the chat tab. + * + * @param {KeyboardEvent} event - The event. + * @returns {void} + */ + _onChatTabKeyDown(event) { + if (event.key === 'Enter' || event.key === ' ') { + event.preventDefault(); + event.stopPropagation(); + this._onToggleChatTab(); + } + } + + _onEscClick: (KeyboardEvent) => void; + + /** + * Click handler for the chat sidenav. + * + * @param {KeyboardEvent} event - Esc key click to close the popup. + * @returns {void} + */ + _onEscClick(event) { + if (event.key === 'Escape' && this.props._isOpen) { + event.preventDefault(); + event.stopPropagation(); + this._onToggleChat(); + } + } + + _onPollsTabKeyDown: (KeyboardEvent) => void; + + /** + * Key press handler for the polls tab. + * + * @param {KeyboardEvent} event - The event. + * @returns {void} + */ + _onPollsTabKeyDown(event) { + if (event.key === 'Enter' || event.key === ' ') { + event.preventDefault(); + event.stopPropagation(); + this._onTogglePollsTab(); + } + } + /** * Returns a React Element for showing chat messages and a form to send new * chat messages. @@ -129,12 +167,18 @@ class Chat extends AbstractChat { * @returns {ReactElement} */ _renderChat() { + const { _isPollsEnabled, _isPollsTabFocused } = this.props; - if (this.props._isPollsTabFocused) { + if (_isPollsTabFocused) { return ( <> - { this.props._isPollsEnabled && this._renderTabs()} - + {_isPollsEnabled && this._renderTabs()} +
+ +
); @@ -142,19 +186,21 @@ class Chat extends AbstractChat { return ( <> - {this.props._isPollsEnabled && this._renderTabs()} - + {_isPollsEnabled && this._renderTabs()} +
- - - - + + + +
); } @@ -166,107 +212,58 @@ class Chat extends AbstractChat { * @returns {ReactElement} */ _renderTabs() { - - return ( -
-
- - {this.props.t('chat.tabs.chat')} - - {this.props._isPollsTabFocused - && this.props._nbUnreadMessages > 0 && ( - - {this.props._nbUnreadMessages} - - )} -
-
- - {this.props.t('chat.tabs.polls')} - - {!this.props._isPollsTabFocused - && this.props._nbUnreadPolls > 0 && ( - - {this.props._nbUnreadPolls} - - )} -
-
- ); - } - - /** - * Instantiates a React Element to display at the top of {@code Chat} to - * close {@code Chat}. - * - * @private - * @returns {ReactElement} - */ - _renderChatHeader() { - return ( -
- ); - } - - _renderPanelContent: () => React$Node | null; - - /** - * Renders the contents of the chat panel. - * - * @private - * @returns {ReactElement | null} - */ - _renderPanelContent() { - const { _isModal, _isOpen, _showNamePrompt } = this.props; - let ComponentToRender = null; - - if (_isOpen) { - if (_isModal) { - ComponentToRender = ( - - { _showNamePrompt - ? - : this._renderChat() } - - ); - } else { - ComponentToRender = ( - <> - { this._renderChatHeader() } - { _showNamePrompt - ? - : this._renderChat() } - - ); - } - } - let className = ''; - - if (_isOpen) { - className = 'slideInExt'; - } else if (this._isExited) { - className = 'invisible'; - } + const { _isPollsEnabled, _isPollsTabFocused, _nbUnreadMessages, _nbUnreadPolls, t } = this.props; return (
- { ComponentToRender } + ariaLabel = { t(_isPollsEnabled ? 'chat.titleWithPolls' : 'chat.title') } + className = { 'chat-tabs-container' } + role = 'tablist'> + +
); } diff --git a/react/features/chat/components/web/ChatDialog.js b/react/features/chat/components/web/ChatDialog.js deleted file mode 100644 index 9e3de4007..000000000 --- a/react/features/chat/components/web/ChatDialog.js +++ /dev/null @@ -1,43 +0,0 @@ -// @flow - -import React from 'react'; - -import { Dialog } from '../../../base/dialog'; - -import Header from './ChatDialogHeader'; - -type Props = { - - /** - * Children of the component. - */ - children: React$Node, - - /** - * Whether the polls feature is enabled or not. - */ - isPollsEnabled: boolean -} - -/** - * Component that renders the content of the chat in a modal. - * - * @returns {React$Element} - */ -function ChatDialog({ children, isPollsEnabled }: Props) { - return ( - -
- {children} -
-
- ); -} - -export default ChatDialog; diff --git a/react/features/chat/components/web/ChatDialogHeader.js b/react/features/chat/components/web/ChatHeader.js similarity index 100% rename from react/features/chat/components/web/ChatDialogHeader.js rename to react/features/chat/components/web/ChatHeader.js