diff options
author | Asaad Mahmood <asaadmahmood@users.noreply.github.com> | 2017-07-06 18:07:43 +0500 |
---|---|---|
committer | Joram Wilander <jwawilander@gmail.com> | 2017-07-06 09:07:43 -0400 |
commit | d64d1f4029505f48bb86035a557e2f4229e55443 (patch) | |
tree | eb71e96007d21f96ecc4957f802cb2302748ad4f /webapp/components | |
parent | 97cfe62309d7f94a2ea041bc04a7ff25cb1c91fd (diff) | |
download | chat-d64d1f4029505f48bb86035a557e2f4229e55443.tar.gz chat-d64d1f4029505f48bb86035a557e2f4229e55443.tar.bz2 chat-d64d1f4029505f48bb86035a557e2f4229e55443.zip |
PLT-6905 - Updating channel header design (#6789)
* PLT-6905 - Updating channel header design
* Updating border-radius
* Updating radius for wide icons
* Updating trigger for overlay
* Updating UI for channel header
* Updating channel header sizing
* Updating channel header css
* Updating sidebar css
* Updating status icons
* Adjusting border
* Updating comment
* Removing type from status icon
* Fixing UI issues for the channel header/sidebar
* make "Add a channel description" open the channel header modal
* Updating status and opacity
* Updating stauts icon positioning
* Updating description and heading size
* Updating UI changes
* Updating UI changes
* add a focused class to the parent div .search__form and then remove when hover away
* Fix active state for pinned posts icon
* Updating UI changes
* Update channel header text
Diffstat (limited to 'webapp/components')
21 files changed, 395 insertions, 216 deletions
diff --git a/webapp/components/analytics/table_chart.jsx b/webapp/components/analytics/table_chart.jsx index 408871cb7..5836e09a7 100644 --- a/webapp/components/analytics/table_chart.jsx +++ b/webapp/components/analytics/table_chart.jsx @@ -31,6 +31,7 @@ export default function TableChart(props) { <tr key={'table-entry-' + item.name}> <td> <OverlayTrigger + trigger={['hover', 'focus']} delayShow={Constants.OVERLAY_TIME_DELAY} placement='top' overlay={tooltip} diff --git a/webapp/components/change_url_modal.jsx b/webapp/components/change_url_modal.jsx index ee01ec14f..a94a33ad3 100644 --- a/webapp/components/change_url_modal.jsx +++ b/webapp/components/change_url_modal.jsx @@ -180,6 +180,7 @@ export default class ChangeUrlModal extends React.Component { <div className='col-sm-10'> <div className={urlClass}> <OverlayTrigger + trigger={['hover', 'focus']} delayShow={Constants.OVERLAY_TIME_DELAY} placement='top' overlay={urlTooltip} diff --git a/webapp/components/channel_header.jsx b/webapp/components/channel_header.jsx index b6fcf7ef7..34d58f5aa 100644 --- a/webapp/components/channel_header.jsx +++ b/webapp/components/channel_header.jsx @@ -64,6 +64,7 @@ export default class ChannelHeader extends React.Component { this.hideLeaveChannelModal = this.hideLeaveChannelModal.bind(this); const state = this.getStateFromStores(); + state.showEditChannelHeaderModal = false; state.showEditChannelPurposeModal = false; state.showMembersModal = false; state.showRenameChannelModal = false; @@ -90,7 +91,8 @@ export default class ChannelHeader extends React.Component { enableFormatting: PreferenceStore.getBool(Preferences.CATEGORY_ADVANCED_SETTINGS, 'formatting', true), isBusy: WebrtcStore.isBusy(), isFavorite: channel && ChannelUtils.isFavoriteChannel(channel), - showLeaveChannelModal: false + showLeaveChannelModal: false, + pinsOpen: SearchStore.getIsPinnedPosts() }; } @@ -281,7 +283,8 @@ export default class ChannelHeader extends React.Component { render() { const flagIcon = Constants.FLAG_ICON_SVG; - const pinIcon = Constants.PIN_ICON; + const pinIcon = Constants.PIN_ICON_SVG; + const mentionsIcon = Constants.MENTIONS_ICON_SVG; if (!this.validState()) { // Use an empty div to make sure the header's height stays constant @@ -300,6 +303,15 @@ export default class ChannelHeader extends React.Component { </Tooltip> ); + const pinnedPostTooltip = ( + <Tooltip id='pinnedPostTooltip'> + <FormattedMessage + id='channel_header.pinnedPosts' + defaultMessage='Pinned Posts' + /> + </Tooltip> + ); + const flaggedTooltip = ( <Tooltip id='flaggedTooltip' @@ -382,13 +394,14 @@ export default class ChannelHeader extends React.Component { ); webrtc = ( - <div className='webrtc__header'> + <div className='webrtc__header channel-header__icon'> <a href='#' onClick={() => this.initWebrtc(otherUserId, !isOffline)} disabled={isOffline} > <OverlayTrigger + trigger={['hover', 'focus']} delayShow={Constants.WEBRTC_TIME_DELAY} placement='bottom' overlay={webrtcTooltip} @@ -754,11 +767,62 @@ export default class ChannelHeader extends React.Component { } } - let headerText; - if (this.state.enableFormatting) { - headerText = TextFormatting.formatText(channel.header, {singleline: true, mentionHighlight: false, siteURL: getSiteURL()}); + let headerTextContainer; + if (channel.header) { + let headerTextElement; + if (this.state.enableFormatting) { + headerTextElement = ( + <div + onClick={Utils.handleFormattedTextClick} + className='channel-header__description' + dangerouslySetInnerHTML={{__html: TextFormatting.formatText(channel.header, {singleline: true, mentionHighlight: false, siteURL: getSiteURL()})}} + /> + ); + } else { + headerTextElement = ( + <div + onClick={Utils.handleFormattedTextClick} + className='channel-header__description' + > + {channel.header} + </div> + ); + } + + headerTextContainer = ( + <OverlayTrigger + trigger={'click'} + placement='bottom' + rootClose={true} + overlay={popoverContent} + ref='headerOverlay' + > + {headerTextElement} + </OverlayTrigger> + ); } else { - headerText = channel.header; + headerTextContainer = ( + <a + href='#' + className='channel-header__description light' + onClick={() => this.setState({showEditChannelHeaderModal: true})} + > + <FormattedMessage + id='channel_header.addChannelHeader' + defaultMessage='Add a channel description' + /> + </a> + ); + } + + let editHeaderModal; + if (this.state.showEditChannelHeaderModal) { + editHeaderModal = ( + <EditChannelHeaderModal + onHide={() => this.setState({showEditChannelHeaderModal: false})} + channel={channel} + /> + ); } let toggleFavoriteTooltip; @@ -784,6 +848,7 @@ export default class ChannelHeader extends React.Component { const toggleFavorite = ( <OverlayTrigger + trigger={['hover', 'focus']} delayShow={Constants.OVERLAY_TIME_DELAY} placement='bottom' overlay={toggleFavoriteTooltip} @@ -792,7 +857,7 @@ export default class ChannelHeader extends React.Component { id='toggleFavorite' href='#' onClick={this.toggleFavorite} - className='channel-header__favorites' + className={'channel-header__favorites ' + (this.state.isFavorite ? 'active' : 'inactive')} > <i className={'icon fa ' + (this.state.isFavorite ? 'fa-star' : 'fa-star-o')}/> </a> @@ -822,19 +887,23 @@ export default class ChannelHeader extends React.Component { const leaveChannelModal = this.createLeaveChannelModal(); + let pinnedIconClass = 'channel-header__icon'; + if (this.state.pinsOpen) { + pinnedIconClass += ' active'; + } + return ( <div id='channel-header' - className='channel-header' + className='channel-header alt' > - <table className='channel-header alt'> + <table> <tbody> <tr> <th> <div className='channel-header__info'> - {webrtc} {toggleFavorite} - <div className='dropdown'> + <div className='channel-header__title dropdown'> <a id='channelHeaderDropdown' href='#' @@ -844,7 +913,7 @@ export default class ChannelHeader extends React.Component { aria-expanded='true' > <strong className='heading'>{channelTitle} </strong> - <span className='fa fa-chevron-down header-dropdown__icon'/> + <span className='fa fa-angle-down header-dropdown__icon'/> </a> <ul className='dropdown-menu' @@ -854,35 +923,33 @@ export default class ChannelHeader extends React.Component { {dropdownContents} </ul> </div> - <OverlayTrigger - trigger={'click'} - placement='bottom' - rootClose={true} - overlay={popoverContent} - ref='headerOverlay' - > - <div - onClick={Utils.handleFormattedTextClick} - className='description' - dangerouslySetInnerHTML={{__html: headerText}} - /> - </OverlayTrigger> + {headerTextContainer} </div> </th> - <th className='header-list__right'> + <th> + {webrtc} + </th> + <th> {popoverListMembers} - <a - href='#' - type='button' - id='pinnedPostsButton' - className='pinned-posts-button' - onClick={this.getPinnedPosts} + </th> + <th> + <OverlayTrigger + trigger={['hover', 'focus']} + delayShow={Constants.OVERLAY_TIME_DELAY} + placement='bottom' + overlay={pinnedPostTooltip} > - <span - dangerouslySetInnerHTML={{__html: pinIcon}} - aria-hidden='true' - /> - </a> + <div + className={pinnedIconClass} + onClick={this.getPinnedPosts} + > + <span + className='icon icon__pin' + dangerouslySetInnerHTML={{__html: pinIcon}} + aria-hidden='true' + /> + </div> + </OverlayTrigger> </th> <th className='search-bar__container'> <NavbarSearchBox @@ -891,47 +958,44 @@ export default class ChannelHeader extends React.Component { /> </th> <th> - <div className='dropdown channel-header__links search-btns'> - <OverlayTrigger - delayShow={Constants.OVERLAY_TIME_DELAY} - placement='bottom' - overlay={recentMentionsTooltip} - > - <a - id='searchMentions' - href='#' - type='button' - onClick={this.searchMentions} - > - {'@'} - </a> - </OverlayTrigger> - </div> + <OverlayTrigger + trigger={['hover', 'focus']} + delayShow={Constants.OVERLAY_TIME_DELAY} + placement='bottom' + overlay={recentMentionsTooltip} + > + <div className='channel-header__icon icon--hidden'> + <span + className='icon icon__mentions' + dangerouslySetInnerHTML={{__html: mentionsIcon}} + aria-hidden='true' + /> + </div> + </OverlayTrigger> </th> <th> - <div className='dropdown channel-header__links search-btns'> - <OverlayTrigger - delayShow={Constants.OVERLAY_TIME_DELAY} - placement='bottom' - overlay={flaggedTooltip} + <OverlayTrigger + trigger={['hover', 'focus']} + delayShow={Constants.OVERLAY_TIME_DELAY} + placement='bottom' + overlay={flaggedTooltip} + > + <div + className='channel-header__icon icon--hidden' + onClick={this.getFlagged} + > - <a - id='flaggedPostsButton' - href='#' - type='button' - onClick={this.getFlagged} - > - <span - className='icon icon__flag' - dangerouslySetInnerHTML={{__html: flagIcon}} - /> - </a> - </OverlayTrigger> - </div> + <span + className='icon icon__flag' + dangerouslySetInnerHTML={{__html: flagIcon}} + /> + </div> + </OverlayTrigger> </th> </tr> </tbody> </table> + {editHeaderModal} {editPurposeModal} {channelMembersModal} {leaveChannelModal} diff --git a/webapp/components/channel_info_modal.jsx b/webapp/components/channel_info_modal.jsx index 25824e28c..186dfc5cf 100644 --- a/webapp/components/channel_info_modal.jsx +++ b/webapp/components/channel_info_modal.jsx @@ -29,6 +29,8 @@ export default class ChannelInfoModal extends React.Component { render() { let channel = this.props.channel; let channelIcon; + const globeIcon = Constants.GLOBE_ICON_SVG; + const lockIcon = Constants.LOCK_ICON_SVG; if (!channel) { const notFound = Utils.localizeMessage('channel_info.notFound', 'No Channel Found'); @@ -43,9 +45,19 @@ export default class ChannelInfoModal extends React.Component { } if (channel.type === 'O') { - channelIcon = (<span className='fa fa-globe'/>); + channelIcon = ( + <span + className='icon icon__globe icon--body' + dangerouslySetInnerHTML={{__html: globeIcon}} + /> + ); } else if (channel.type === 'P') { - channelIcon = (<span className='fa fa-lock'/>); + channelIcon = ( + <span + className='icon icon__globe icon--body' + dangerouslySetInnerHTML={{__html: lockIcon}} + /> + ); } const channelURL = TeamStore.getCurrentTeamUrl() + '/channels/' + channel.name; diff --git a/webapp/components/create_team/components/team_url.jsx b/webapp/components/create_team/components/team_url.jsx index baae0e09d..f42dc6e0b 100644 --- a/webapp/components/create_team/components/team_url.jsx +++ b/webapp/components/create_team/components/team_url.jsx @@ -178,6 +178,7 @@ export default class TeamUrl extends React.Component { <div className='col-sm-11'> <div className='input-group input-group--limit'> <OverlayTrigger + trigger={['hover', 'focus']} delayShow={Constants.OVERLAY_TIME_DELAY} placement='top' overlay={urlTooltip} diff --git a/webapp/components/file_attachment.jsx b/webapp/components/file_attachment.jsx index f14718e64..9459c44ef 100644 --- a/webapp/components/file_attachment.jsx +++ b/webapp/components/file_attachment.jsx @@ -105,6 +105,7 @@ export default class FileAttachment extends React.Component { if (this.props.compactDisplay) { filenameOverlay = ( <OverlayTrigger + trigger={['hover', 'focus']} delayShow={1000} placement='top' overlay={<Tooltip id='file-name__tooltip'>{fileName}</Tooltip>} @@ -126,6 +127,7 @@ export default class FileAttachment extends React.Component { } else { filenameOverlay = ( <OverlayTrigger + trigger={['hover', 'focus']} delayShow={1000} placement='top' overlay={<Tooltip id='file-name__tooltip'>{Utils.localizeMessage('file_attachment.download', 'Download') + ' "' + fileName + '"'}</Tooltip>} diff --git a/webapp/components/navbar.jsx b/webapp/components/navbar.jsx index fa759cae7..f61f58a8d 100644 --- a/webapp/components/navbar.jsx +++ b/webapp/components/navbar.jsx @@ -279,6 +279,7 @@ export default class Navbar extends React.Component { createDropdown(channel, channelTitle, isSystemAdmin, isTeamAdmin, isChannelAdmin, isDirect, isGroup, popoverContent) { const isAdmin = isSystemAdmin || isTeamAdmin; + const infoIcon = Constants.INFO_ICON_SVG; if (channel) { let viewInfoOption; @@ -599,7 +600,13 @@ export default class Navbar extends React.Component { className='description' rootClose={true} > - <div className='pull-right description info-popover'/> + <div className='pull-right description navbar-right__icon info-popover'> + <span + className='icon icon__info' + dangerouslySetInnerHTML={{__html: infoIcon}} + aria-hidden='true' + /> + </div> </OverlayTrigger> <a href='#' @@ -652,6 +659,8 @@ export default class Navbar extends React.Component { createCollapseButtons(currentId) { var buttons = []; + const menuIcon = Constants.MENU_ICON_SVG; + if (currentId == null) { buttons.push( <button @@ -688,9 +697,11 @@ export default class Navbar extends React.Component { defaultMessage='Toggle sidebar' /> </span> - <span className='icon-bar'/> - <span className='icon-bar'/> - <span className='icon-bar'/> + <span + className='icon icon__menu' + dangerouslySetInnerHTML={{__html: menuIcon}} + aria-hidden='true' + /> <NotifyCounts/> </button> ); @@ -699,7 +710,7 @@ export default class Navbar extends React.Component { <button key='navbar-toggle-menu' type='button' - className='navbar-toggle menu-toggle pull-right' + className='navbar-toggle navbar-right__icon menu-toggle pull-right' data-toggle='collapse' data-target='#sidebar-nav' onClick={this.toggleRightSidebar} @@ -917,13 +928,18 @@ export default class Navbar extends React.Component { var collapseButtons = this.createCollapseButtons(currentId); + const searchIcon = Constants.SEARCH_ICON_SVG; const searchButton = ( <button type='button' - className='navbar-toggle navbar-search pull-right' + className='navbar-toggle navbar-right__icon navbar-search pull-right' onClick={this.showSearch} > - <span className='fa fa-search icon-search icon--white'/> + <span + className='icon icon__search' + dangerouslySetInnerHTML={{__html: searchIcon}} + aria-hidden='true' + /> </button> ); diff --git a/webapp/components/popover_list_members/popover_list_members.jsx b/webapp/components/popover_list_members/popover_list_members.jsx index 66242e607..c669231f7 100644 --- a/webapp/components/popover_list_members/popover_list_members.jsx +++ b/webapp/components/popover_list_members/popover_list_members.jsx @@ -21,7 +21,7 @@ import {canManageMembers} from 'utils/channel_utils.jsx'; import $ from 'jquery'; import PropTypes from 'prop-types'; import React from 'react'; -import {Popover, Overlay} from 'react-bootstrap'; +import {Tooltip, OverlayTrigger, Popover, Overlay} from 'react-bootstrap'; import {FormattedMessage} from 'react-intl'; import {browserHistory} from 'react-router/es6'; @@ -94,6 +94,7 @@ export default class PopoverListMembers extends React.Component { const isSystemAdmin = UserStore.isSystemAdminForCurrentUser(); const isTeamAdmin = TeamStore.isTeamAdminForCurrentTeam(); const isChannelAdmin = ChannelStore.isChannelAdminForCurrentChannel(); + const membersIcon = Constants.MEMBERS_ICON_SVG; if (members && teamMembers) { members.sort((a, b) => { @@ -104,20 +105,9 @@ export default class PopoverListMembers extends React.Component { }); members.forEach((m, i) => { - let button = ''; + let messageIcon = ''; if (currentUserId !== m.id && this.props.channel.type !== Constants.DM_CHANNEl) { - button = ( - <a - href='#' - className='btn-message' - onClick={(e) => this.handleShowDirectChannel(m, e)} - > - <FormattedMessage - id='members_popover.msg' - defaultMessage='Message' - /> - </a> - ); + messageIcon = Constants.MESSAGE_ICON_SVG; } let name = ''; @@ -129,12 +119,13 @@ export default class PopoverListMembers extends React.Component { popoverHtml.push( <div className='more-modal__row' + onClick={(e) => this.handleShowDirectChannel(m, e)} key={'popover-member-' + i} > <ProfilePicture src={Client4.getProfilePictureUrl(m.id, m.last_picture_update)} - width='26' - height='26' + width='32' + height='32' /> <div className='more-modal__details'> <div @@ -146,7 +137,11 @@ export default class PopoverListMembers extends React.Component { <div className='more-modal__actions' > - {button} + <span + className='icon icon__message' + dangerouslySetInnerHTML={{__html: messageIcon}} + aria-hidden='true' + /> </div> </div> ); @@ -175,21 +170,15 @@ export default class PopoverListMembers extends React.Component { popoverHtml.push( <div - className='more-modal__row' + className='more-modal__row more-modal__row--button' key={'popover-member-more'} > - <div className='more-modal__details text-center'> - <div - className='more-modal__name' - > - <a - href='#' - onClick={this.showMembersModal} - > - {membersName} - </a> - </div> - </div> + <button + className='btn btn-primary' + onClick={this.showMembersModal} + > + {membersName} + </button> </div> ); } @@ -239,23 +228,40 @@ export default class PopoverListMembers extends React.Component { ); } + const channelMembersTooltip = ( + <Tooltip id='channelMembersTooltip'> + <FormattedMessage + id='channel_header.channelMembers' + defaultMessage='Members' + /> + </Tooltip> + ); + return ( - <div className='member-popover__container'> - <div - id='member_popover' - className='member-popover__trigger' - ref='member_popover_target' - onClick={(e) => { - this.setState({popoverTarget: e.target, showPopover: !this.state.showPopover}); - this.props.actions.getProfilesInChannel(this.props.channel.id, 0); - }} + <div className='channel-header__icon wide'> + <OverlayTrigger + trigger={['hover', 'focus']} + delayShow={Constants.OVERLAY_TIME_DELAY} + placement='bottom' + overlay={channelMembersTooltip} > - {countText} - <span - className='fa fa-user' - aria-hidden='true' - /> - </div> + <div + id='member_popover' + className='member-popover__trigger' + ref='member_popover_target' + onClick={(e) => { + this.setState({popoverTarget: e.target, showPopover: !this.state.showPopover}); + this.props.actions.getProfilesInChannel(this.props.channel.id, 0); + }} + > + <span className='icon__text'>{countText}</span> + <span + className='icon icon__members' + dangerouslySetInnerHTML={{__html: membersIcon}} + aria-hidden='true' + /> + </div> + </OverlayTrigger> <Overlay rootClose={true} onHide={this.closePopover} @@ -265,10 +271,17 @@ export default class PopoverListMembers extends React.Component { > <Popover ref='memebersPopover' - title={title} className='member-list__popover' id='member-list-popover' > + <div className='more-modal__header'> + <span + className='icon icon__members' + dangerouslySetInnerHTML={{__html: membersIcon}} + aria-hidden='true' + /> + {title} + </div> <div className='more-modal__list'>{popoverHtml}</div> </Popover> </Overlay> diff --git a/webapp/components/post_view/post_flag_icon.jsx b/webapp/components/post_view/post_flag_icon.jsx index 295bdd116..02f8feb53 100644 --- a/webapp/components/post_view/post_flag_icon.jsx +++ b/webapp/components/post_view/post_flag_icon.jsx @@ -21,11 +21,17 @@ function flagToolTip(isFlagged) { ); } -function flagIcon() { +function flagIcon(isFlagged) { + let flagIconSvg = Constants.FLAG_ICON_SVG; + + if (isFlagged) { + flagIconSvg = Constants.FLAG_FILLED_ICON_SVG; + } + return ( <span className='icon' - dangerouslySetInnerHTML={{__html: Constants.FLAG_ICON_SVG}} + dangerouslySetInnerHTML={{__html: flagIconSvg}} /> ); } @@ -52,6 +58,7 @@ export default function PostFlagIcon(props) { if (!props.isEphemeral) { return ( <OverlayTrigger + trigger={['hover', 'focus']} key={'flagtooltipkey' + flagVisible} delayShow={Constants.OVERLAY_TIME_DELAY} placement='top' @@ -63,7 +70,7 @@ export default function PostFlagIcon(props) { className={'flag-icon__container ' + flagVisible} onClick={flagFunc} > - {flagIcon()} + {flagIcon(props.isFlagged)} </a> </OverlayTrigger> ); diff --git a/webapp/components/post_view/reaction/reaction.jsx b/webapp/components/post_view/reaction/reaction.jsx index 7fad56d62..f256a1fb5 100644 --- a/webapp/components/post_view/reaction/reaction.jsx +++ b/webapp/components/post_view/reaction/reaction.jsx @@ -219,6 +219,7 @@ export default class Reaction extends React.PureComponent { return ( <OverlayTrigger + trigger={['hover', 'focus']} delayShow={1000} placement='top' shouldUpdatePosition={true} diff --git a/webapp/components/rename_channel_modal.jsx b/webapp/components/rename_channel_modal.jsx index 850231aeb..d4cddb9db 100644 --- a/webapp/components/rename_channel_modal.jsx +++ b/webapp/components/rename_channel_modal.jsx @@ -273,6 +273,7 @@ export class RenameChannelModal extends React.Component { <div className='input-group input-group--limit'> <OverlayTrigger + trigger={['hover', 'focus']} delayShow={Constants.OVERLAY_TIME_DELAY} placement='top' overlay={urlTooltip} diff --git a/webapp/components/rhs_header_post.jsx b/webapp/components/rhs_header_post.jsx index 0e7ee786a..1608f90a2 100644 --- a/webapp/components/rhs_header_post.jsx +++ b/webapp/components/rhs_header_post.jsx @@ -136,6 +136,7 @@ export default class RhsHeaderPost extends React.Component { className='sidebar--right__back' > <OverlayTrigger + trigger={['hover', 'focus']} delayShow={Constants.OVERLAY_TIME_DELAY} placement='top' overlay={backToResultsTooltip} @@ -163,6 +164,7 @@ export default class RhsHeaderPost extends React.Component { onClick={this.toggleSize} > <OverlayTrigger + trigger={['hover', 'focus']} delayShow={Constants.OVERLAY_TIME_DELAY} placement='top' overlay={expandSidebarTooltip} @@ -170,6 +172,7 @@ export default class RhsHeaderPost extends React.Component { <i className='fa fa-expand'/> </OverlayTrigger> <OverlayTrigger + trigger={['hover', 'focus']} delayShow={Constants.OVERLAY_TIME_DELAY} placement='top' overlay={shrinkSidebarTooltip} @@ -185,6 +188,7 @@ export default class RhsHeaderPost extends React.Component { > <OverlayTrigger + trigger={['hover', 'focus']} delayShow={Constants.OVERLAY_TIME_DELAY} placement='top' overlay={closeSidebarTooltip} diff --git a/webapp/components/search_bar.jsx b/webapp/components/search_bar.jsx index 94760dfdf..c635c5eb1 100644 --- a/webapp/components/search_bar.jsx +++ b/webapp/components/search_bar.jsx @@ -216,6 +216,9 @@ export default class SearchBar extends React.Component { render() { const flagIcon = Constants.FLAG_ICON_SVG; + const searchIcon = Constants.SEARCH_ICON_SVG; + const mentionsIcon = Constants.MENTIONS_ICON_SVG; + var isSearching = null; if (this.state.isSearching) { isSearching = <span className={'fa fa-refresh fa-refresh-animate icon--refresh icon--rotate'}/>; @@ -253,50 +256,49 @@ export default class SearchBar extends React.Component { var mentionBtnClass = SearchStore.isMentionSearch ? 'active' : ''; mentionBtn = ( - <div - className='dropdown channel-header__links' + <OverlayTrigger + trigger={['hover', 'focus']} + delayShow={Constants.OVERLAY_TIME_DELAY} + placement='bottom' + overlay={recentMentionsTooltip} > - <OverlayTrigger - delayShow={Constants.OVERLAY_TIME_DELAY} - placement='bottom' - overlay={recentMentionsTooltip} + <div + className={'channel-header__icon ' + mentionBtnClass} + onClick={this.searchMentions} > - <a - href='#' - type='button' - onClick={this.searchMentions} - className={mentionBtnClass} - > - {'@'} - </a> - </OverlayTrigger> - </div> + <span + className='icon icon__mentions' + dangerouslySetInnerHTML={{__html: mentionsIcon}} + aria-hidden='true' + /> + </div> + </OverlayTrigger> ); var flagBtnClass = SearchStore.isFlaggedPosts ? 'active' : ''; flagBtn = ( - <div - className='dropdown channel-header__links' + <OverlayTrigger + trigger={['hover', 'focus']} + delayShow={Constants.OVERLAY_TIME_DELAY} + placement='bottom' + overlay={flaggedTooltip} > - <OverlayTrigger - delayShow={Constants.OVERLAY_TIME_DELAY} - placement='bottom' - overlay={flaggedTooltip} + <div + className={'channel-header__icon ' + flagBtnClass} > <a href='#' type='button' onClick={this.getFlagged} - className={flagBtnClass} > <span className='icon icon__flag' dangerouslySetInnerHTML={{__html: flagIcon}} /> </a> - </OverlayTrigger> - </div> + </div> + </OverlayTrigger> ); } @@ -305,55 +307,71 @@ export default class SearchBar extends React.Component { clearClass += ' visible'; } + let searchFormClass = 'search__form'; + if (this.state.focused) { + searchFormClass += ' focused'; + } + return ( - <div> - <div - className='sidebar__collapse' - onClick={this.handleClose} - > - <span className='fa fa-angle-left'/> - </div> - <form - role='form' - className='search__form' - onSubmit={this.handleSubmit} - style={{overflow: 'visible'}} - autoComplete='off' - > - <span className='fa fa-search sidebar__search-icon'/> - <SuggestionBox - ref={(search) => { - this.search = search; - }} - className='form-control search-bar' - placeholder={Utils.localizeMessage('search_bar.search', 'Search')} - value={this.state.searchTerm} - onFocus={this.handleUserFocus} - onBlur={this.handleUserBlur} - onChange={this.handleChange} - onKeyDown={this.handleKeyDown} - listComponent={SearchSuggestionList} - providers={this.suggestionProviders} - type='search' - autoFocus={this.props.isFocus && this.state.searchTerm === ''} - /> + <div className='sidebar-right__table'> + <div className='sidebar-collapse__container'> <div - className={clearClass} - onClick={this.handleClear} + className='sidebar-collapse' + onClick={this.handleClose} + > + <span className='fa fa-chevron-left'/> + </div> + </div> + <div className='search-form__container'> + <form + role='form' + className={searchFormClass} + onSubmit={this.handleSubmit} + style={{overflow: 'visible'}} + autoComplete='off' > <span - className='sidebar__search-clear-x' + className='search__icon' + dangerouslySetInnerHTML={{__html: searchIcon}} aria-hidden='true' + /> + <SuggestionBox + ref={(search) => { + this.search = search; + }} + className='search-bar' + placeholder={Utils.localizeMessage('search_bar.search', 'Search')} + value={this.state.searchTerm} + onFocus={this.handleUserFocus} + onBlur={this.handleUserBlur} + onChange={this.handleChange} + onKeyDown={this.handleKeyDown} + listComponent={SearchSuggestionList} + providers={this.suggestionProviders} + type='search' + autoFocus={this.props.isFocus && this.state.searchTerm === ''} + /> + <div + className={clearClass} + onClick={this.handleClear} > - {'×'} - </span> - </div> - {isSearching} - {this.renderHintPopover(helpClass)} - </form> - - {mentionBtn} - {flagBtn} + <span + className='sidebar__search-clear-x' + aria-hidden='true' + > + {'×'} + </span> + </div> + {isSearching} + {this.renderHintPopover(helpClass)} + </form> + </div> + <div> + {mentionBtn} + </div> + <div> + {flagBtn} + </div> </div> ); } diff --git a/webapp/components/search_results_header.jsx b/webapp/components/search_results_header.jsx index fd2628013..467b77e27 100644 --- a/webapp/components/search_results_header.jsx +++ b/webapp/components/search_results_header.jsx @@ -104,6 +104,7 @@ export default class SearchResultsHeader extends React.Component { onClick={this.toggleSize} > <OverlayTrigger + trigger={['hover', 'focus']} delayShow={Constants.OVERLAY_TIME_DELAY} placement='top' overlay={expandSidebarTooltip} @@ -111,6 +112,7 @@ export default class SearchResultsHeader extends React.Component { <i className='fa fa-expand'/> </OverlayTrigger> <OverlayTrigger + trigger={['hover', 'focus']} delayShow={Constants.OVERLAY_TIME_DELAY} placement='top' overlay={shrinkSidebarTooltip} @@ -126,6 +128,7 @@ export default class SearchResultsHeader extends React.Component { onClick={this.handleClose} > <OverlayTrigger + trigger={['hover', 'focus']} delayShow={Constants.OVERLAY_TIME_DELAY} placement='top' overlay={closeSidebarTooltip} diff --git a/webapp/components/sidebar.jsx b/webapp/components/sidebar.jsx index 8c959c397..16c96f1b6 100644 --- a/webapp/components/sidebar.jsx +++ b/webapp/components/sidebar.jsx @@ -520,7 +520,7 @@ export default class Sidebar extends React.Component { linkClass = 'active'; } - let rowClass = 'sidebar-channel'; + let rowClass = 'sidebar-item'; var unread = false; if (channelMember) { @@ -542,7 +542,7 @@ export default class Sidebar extends React.Component { var badge = null; if (channelMember) { if (unreadCount.mentions) { - badge = <span className='badge pull-right small'>{unreadCount.mentions}</span>; + badge = <span className='badge'>{unreadCount.mentions}</span>; this.badgesActive = true; } } else if (this.state.loadingDMChannel === index && channel.type === Constants.DM_CHANNEL) { @@ -554,17 +554,29 @@ export default class Sidebar extends React.Component { ); } - if (msgCount > 0) { + if (unreadCount.mentions > 0) { rowClass += ' has-badge'; } let displayName = channel.display_name; var icon = null; + const globeIcon = Constants.GLOBE_ICON_SVG; + const lockIcon = Constants.LOCK_ICON_SVG; if (channel.type === Constants.OPEN_CHANNEL) { - icon = <div className='status'><i className='fa fa-globe'/></div>; + icon = ( + <span + className='icon icon__globe' + dangerouslySetInnerHTML={{__html: globeIcon}} + /> + ); } else if (channel.type === Constants.PRIVATE_CHANNEL) { - icon = <div className='status'><i className='fa fa-lock'/></div>; + icon = ( + <span + className='icon icon__lock' + dangerouslySetInnerHTML={{__html: lockIcon}} + /> + ); } else if (channel.type === Constants.GM_CHANNEL) { displayName = ChannelUtils.buildGroupChannelName(channel.id); icon = <div className='status status--group'>{UserStore.getProfileListInChannel(channel.id, true).length}</div>; @@ -589,6 +601,7 @@ export default class Sidebar extends React.Component { if (handleClose && !badge) { closeButton = ( <OverlayTrigger + trigger={['hover', 'focus']} delayShow={1000} placement='top' overlay={removeTooltip} @@ -630,7 +643,7 @@ export default class Sidebar extends React.Component { onClick={this.trackChannelSelectedEvent} > {icon} - {displayName} + <span className='sidebar-item__name'>{displayName}</span> {badge} {closeButton} </Link> @@ -644,6 +657,8 @@ export default class Sidebar extends React.Component { } render() { + const switchChannelIcon = Constants.SWITCH_CHANNEL_ICON_SVG; + // Check if we have all info needed to render if (this.state.currentTeam == null || this.state.currentUser == null) { return (<div/>); @@ -749,8 +764,8 @@ export default class Sidebar extends React.Component { let createPublicChannelIcon = ( <OverlayTrigger + trigger={['hover', 'focus']} delayShow={500} - trigger='hover' placement='top' overlay={createChannelTootlip} > @@ -767,9 +782,9 @@ export default class Sidebar extends React.Component { let createPrivateChannelIcon = ( <OverlayTrigger + trigger={['hover', 'focus']} delayShow={500} placement='top' - trigger='hover' overlay={createGroupTootlip} > <a @@ -866,7 +881,7 @@ export default class Sidebar extends React.Component { <h4> <FormattedMessage id='sidebar.favorite' - defaultMessage='Favorites' + defaultMessage='FAVORITE CHANNELS' /> </h4> </li> @@ -877,7 +892,7 @@ export default class Sidebar extends React.Component { <h4> <FormattedMessage id='sidebar.channels' - defaultMessage='Channels' + defaultMessage='PUBLIC CHANNELS' /> {createPublicChannelIcon} </h4> @@ -903,7 +918,7 @@ export default class Sidebar extends React.Component { <h4> <FormattedMessage id='sidebar.pg' - defaultMessage='Private Channels' + defaultMessage='PRIVATE CHANNELS' /> {createPrivateChannelIcon} </h4> @@ -915,7 +930,7 @@ export default class Sidebar extends React.Component { <h4> <FormattedMessage id='sidebar.direct' - defaultMessage='Direct Messages' + defaultMessage='DIRECT MESSAGES' /> </h4> </li> @@ -928,6 +943,10 @@ export default class Sidebar extends React.Component { className='btn btn-link' onClick={this.openQuickSwitcher} > + <span + className='icon icon__switch' + dangerouslySetInnerHTML={{__html: switchChannelIcon}} + /> <FormattedMessage id={quickSwitchText} defaultMessage='Switch Channels' diff --git a/webapp/components/sidebar_header.jsx b/webapp/components/sidebar_header.jsx index 287945bc5..88fb0d8c4 100644 --- a/webapp/components/sidebar_header.jsx +++ b/webapp/components/sidebar_header.jsx @@ -102,8 +102,8 @@ export default class SidebarHeader extends React.Component { <div className='team__header theme'> {tutorialTip} <div className='header__info'> - <div className='user__name'>{'@' + this.props.currentUser.username}</div> {teamNameWithToolTip} + <div className='user__name'>{'@' + this.props.currentUser.username}</div> </div> <SidebarHeaderDropdown ref='dropdown' diff --git a/webapp/components/sidebar_right/sidebar_right.jsx b/webapp/components/sidebar_right/sidebar_right.jsx index f48bcaa56..21d3df345 100644 --- a/webapp/components/sidebar_right/sidebar_right.jsx +++ b/webapp/components/sidebar_right/sidebar_right.jsx @@ -129,7 +129,7 @@ export default class SidebarRight extends React.Component { const wasOpen = prevState.searchVisible || prevProps.postRightVisible; if (isOpen && !wasOpen) { - postListScrollChange(); + setTimeout(() => postListScrollChange(), 0); } } @@ -210,7 +210,7 @@ export default class SidebarRight extends React.Component { if (this.state.searchVisible) { content = ( <div className='sidebar--right__content'> - <div className='search-bar__container sidebar--right__search-header'>{searchForm}</div> + <div className='search-bar__container channel-header alt'>{searchForm}</div> <SearchResults isMentionSearch={this.state.isMentionSearch} isFlaggedPosts={this.state.isFlaggedPosts} @@ -226,7 +226,7 @@ export default class SidebarRight extends React.Component { content = ( <div className='post-right__container'> <FileUploadOverlay overlayType='right'/> - <div className='search-bar__container sidebar--right__search-header'>{searchForm}</div> + <div className='search-bar__container channel-header alt'>{searchForm}</div> <RhsThread fromFlaggedPosts={this.props.fromFlaggedPosts} fromSearch={this.props.fromSearch} diff --git a/webapp/components/suggestion/switch_channel_provider.jsx b/webapp/components/suggestion/switch_channel_provider.jsx index 346721cd6..ba060d924 100644 --- a/webapp/components/suggestion/switch_channel_provider.jsx +++ b/webapp/components/suggestion/switch_channel_provider.jsx @@ -26,6 +26,8 @@ class SwitchChannelSuggestion extends Suggestion { render() { const {item, isSelection} = this.props; const channel = item.channel; + const globeIcon = Constants.GLOBE_ICON_SVG; + const lockIcon = Constants.LOCK_ICON_SVG; let className = 'mentions__name'; if (isSelection) { @@ -35,9 +37,19 @@ class SwitchChannelSuggestion extends Suggestion { let displayName = channel.display_name; let icon = null; if (channel.type === Constants.OPEN_CHANNEL) { - icon = <div className='status'><i className='fa fa-globe'/></div>; + icon = ( + <span + className='icon icon__globe icon--body' + dangerouslySetInnerHTML={{__html: globeIcon}} + /> + ); } else if (channel.type === Constants.PRIVATE_CHANNEL) { - icon = <div className='status'><i className='fa fa-lock'/></div>; + icon = ( + <span + className='icon icon__lock icon--body' + dangerouslySetInnerHTML={{__html: lockIcon}} + /> + ); } else if (channel.type === Constants.GM_CHANNEL) { displayName = getChannelDisplayName(channel); icon = <div className='status status--group'>{'G'}</div>; diff --git a/webapp/components/team_sidebar/components/team_button.jsx b/webapp/components/team_sidebar/components/team_button.jsx index e0670d6da..57f436eb2 100644 --- a/webapp/components/team_sidebar/components/team_button.jsx +++ b/webapp/components/team_sidebar/components/team_button.jsx @@ -69,6 +69,7 @@ export default class TeamButton extends React.Component { } else { btn = ( <OverlayTrigger + trigger={['hover', 'focus']} delayShow={Constants.OVERLAY_TIME_DELAY} placement={this.props.placement} overlay={ diff --git a/webapp/components/user_settings/custom_theme_chooser.jsx b/webapp/components/user_settings/custom_theme_chooser.jsx index 7a90cc7df..82bf99a0a 100644 --- a/webapp/components/user_settings/custom_theme_chooser.jsx +++ b/webapp/components/user_settings/custom_theme_chooser.jsx @@ -295,6 +295,7 @@ class CustomThemeChooser extends React.Component { {codeThemeOptions} </select> <OverlayTrigger + trigger={['hover', 'focus']} placement='top' overlay={popoverContent} ref='headerOverlay' diff --git a/webapp/components/webrtc/components/webrtc_header.jsx b/webapp/components/webrtc/components/webrtc_header.jsx index cb5172a3c..a5f679da0 100644 --- a/webapp/components/webrtc/components/webrtc_header.jsx +++ b/webapp/components/webrtc/components/webrtc_header.jsx @@ -59,6 +59,7 @@ export default function WebrtcHeader(props) { onClick={props.toggleSize} > <OverlayTrigger + trigger={['hover', 'focus']} delayShow={Constants.OVERLAY_TIME_DELAY} placement='top' overlay={expandSidebarTooltip} @@ -66,6 +67,7 @@ export default function WebrtcHeader(props) { <i className='fa fa-expand'/> </OverlayTrigger> <OverlayTrigger + trigger={['hover', 'focus']} delayShow={Constants.OVERLAY_TIME_DELAY} placement='top' overlay={shrinkSidebarTooltip} |