From 779ecd6da640c9f2ff0393355f5cd97db290776b Mon Sep 17 00:00:00 2001 From: Robert Pintilii Date: Wed, 21 Sep 2022 14:57:59 +0300 Subject: [PATCH] feat(ui-components) Add Tabs component (#12199) --- css/_chat.scss | 40 +----- css/_polls.scss | 2 +- .../features/base/ui/components/web/Tabs.tsx | 117 ++++++++++++++++++ react/features/chat/components/web/Chat.js | 82 +++++------- react/features/chat/constants.ts | 5 + 5 files changed, 156 insertions(+), 90 deletions(-) create mode 100644 react/features/base/ui/components/web/Tabs.tsx diff --git a/css/_chat.scss b/css/_chat.scss index 50e48a95a..33fb7e0fb 100644 --- a/css/_chat.scss +++ b/css/_chat.scss @@ -22,7 +22,7 @@ display: flex; flex-direction: column; // extract header + tabs height - height: calc(100% - 102px); + height: calc(100% - 119px); } .chat-panel-no-tabs { @@ -531,41 +531,3 @@ background: #36383C; border-radius: 3px; } - -.chat-tabs-container { - width: 100%; - border-bottom: thin solid #292929; - display: flex; - justify-content: space-around; -} - -.chat-tab { - font-size: 1.2em; - padding-bottom: 0.5em; - width: 50%; - text-align: center; - color: #8B8B8B; - cursor: pointer; -} - -.chat-tab-focus { - border-bottom-style: solid; - color: #FFF; -} - -.chat-tab-title { - margin-right: 8px; -} - -.chat-tab-badge { - background-color: #165ecc; - border-radius: 50%; - box-sizing: border-box; - font-weight: 700; - overflow: hidden; - text-align: center; - text-overflow: ellipsis; - vertical-align: middle; - padding: 0 4px; - color: #FFF; -} diff --git a/css/_polls.scss b/css/_polls.scss index 75c5c8d04..4fbc8b511 100644 --- a/css/_polls.scss +++ b/css/_polls.scss @@ -310,7 +310,7 @@ ol.poll-result-list { } #polls-panel { - height: calc(100% - 102px); + height: calc(100% - 119px); } .poll-container { diff --git a/react/features/base/ui/components/web/Tabs.tsx b/react/features/base/ui/components/web/Tabs.tsx new file mode 100644 index 000000000..e5d8e3dc8 --- /dev/null +++ b/react/features/base/ui/components/web/Tabs.tsx @@ -0,0 +1,117 @@ +import { Theme } from '@mui/material'; +import React, { useCallback } from 'react'; +import { makeStyles } from 'tss-react/mui'; + +import { isMobileBrowser } from '../../../environment/utils'; +import { withPixelLineHeight } from '../../../styles/functions.web'; + +interface TabProps { + accessibilityLabel: string; + onChange: (id: string) => void; + selected: string; + tabs: Array<{ + accessibilityLabel: string; + countBadge?: number; + disabled?: boolean; + id: string; + label: string; + }>; +} + +const useStyles = makeStyles()((theme: Theme) => { + return { + container: { + display: 'flex' + }, + + tab: { + ...withPixelLineHeight(theme.typography.bodyShortBold), + color: theme.palette.text02, + flex: 1, + padding: '14px', + background: 'none', + border: 0, + appearance: 'none', + borderBottom: `2px solid ${theme.palette.ui05}`, + transition: 'color, border-color 0.2s', + display: 'flex', + alignItems: 'center', + justifyContent: 'center', + borderRadius: 0, + + '&:hover': { + color: theme.palette.text01, + borderColor: theme.palette.ui10 + }, + + '&:focus': { + outline: 0, + boxShadow: `0px 0px 0px 2px ${theme.palette.focus01}`, + border: 0, + color: theme.palette.text01 + }, + + '&.selected': { + color: theme.palette.text01, + borderColor: theme.palette.action01 + }, + + '&:disabled': { + color: theme.palette.text03, + borderColor: theme.palette.ui05 + }, + + '&.is-mobile': { + ...withPixelLineHeight(theme.typography.bodyShortBoldLarge) + } + }, + + badge: { + ...withPixelLineHeight(theme.typography.labelBold), + color: theme.palette.text04, + padding: `0 ${theme.spacing(1)}`, + borderRadius: '100%', + backgroundColor: theme.palette.warning01, + marginLeft: theme.spacing(2) + } + }; +}); + + +const Tabs = ({ + tabs, + onChange, + selected, + accessibilityLabel +}: TabProps) => { + const { classes, cx } = useStyles(); + const isMobile = isMobileBrowser(); + + const handleChange = useCallback((e: React.MouseEvent) => { + onChange(e.currentTarget.id); + }, []); + + return ( +
+ {tabs.map(tab => ( + + ))} +
+ ); +}; + +export default Tabs; diff --git a/react/features/chat/components/web/Chat.js b/react/features/chat/components/web/Chat.js index 6b4f7d1ab..3646a2760 100644 --- a/react/features/chat/components/web/Chat.js +++ b/react/features/chat/components/web/Chat.js @@ -5,8 +5,10 @@ import React from 'react'; import { translate } from '../../../base/i18n'; import { connect } from '../../../base/redux'; +import Tabs from '../../../base/ui/components/web/Tabs'; import { PollsPane } from '../../../polls/components'; import { toggleChat } from '../../actions.web'; +import { CHAT_TABS } from '../../constants'; import AbstractChat, { _mapStateToProps, type Props @@ -47,6 +49,7 @@ class Chat extends AbstractChat { this._onEscClick = this._onEscClick.bind(this); this._onPollsTabKeyDown = this._onPollsTabKeyDown.bind(this); this._onToggleChat = this._onToggleChat.bind(this); + this._onChangeTab = this._onChangeTab.bind(this); } /** @@ -138,7 +141,7 @@ class Chat extends AbstractChat { <> { _isPollsEnabled && this._renderTabs() }
@@ -152,7 +155,7 @@ class Chat extends AbstractChat { <> { _isPollsEnabled && this._renderTabs() }
@@ -178,54 +181,22 @@ class Chat extends AbstractChat { const { _isPollsEnabled, _isPollsTabFocused, _nbUnreadMessages, _nbUnreadPolls, t } = this.props; return ( -
- - -
+ 0 ? _nbUnreadMessages : undefined, + id: CHAT_TABS.CHAT, + label: t('chat.tabs.chat') + }, { + accessibilityLabel: t('chat.tabs.polls'), + countBadge: !_isPollsTabFocused && _nbUnreadPolls > 0 ? _nbUnreadPolls : undefined, + id: CHAT_TABS.POLLS, + label: t('chat.tabs.polls') + } + ] } /> ); } @@ -243,6 +214,17 @@ class Chat extends AbstractChat { } _onTogglePollsTab: () => void; _onToggleChatTab: () => void; + _onChangeTab: (string) => void; + + /** + * Change selected tab. + * + * @param {string} id - Id of the clicked tab. + * @returns {void} + */ + _onChangeTab(id) { + id === CHAT_TABS.CHAT ? this._onToggleChatTab() : this._onTogglePollsTab(); + } } export default translate(connect(_mapStateToProps)(Chat)); diff --git a/react/features/chat/constants.ts b/react/features/chat/constants.ts index d929081fa..9570f82aa 100644 --- a/react/features/chat/constants.ts +++ b/react/features/chat/constants.ts @@ -35,3 +35,8 @@ export const SMALL_WIDTH_THRESHOLD = 580; * Lobby message type. */ export const LOBBY_CHAT_MESSAGE = 'LOBBY_CHAT_MESSAGE'; + +export const CHAT_TABS = { + POLLS: 'polls-tab', + CHAT: 'chat-tab' +};