diff options
34 files changed, 700 insertions, 800 deletions
diff --git a/doc/help/Messaging.md b/doc/help/Messaging.md index 03adc1ce8..09d35f3b9 100644 --- a/doc/help/Messaging.md +++ b/doc/help/Messaging.md @@ -4,7 +4,7 @@ You can write messages using the input box with the text "Write a message..." at the bottom of Mattermost. -Press **ENTER** to send a message. Use **Ctrl+ENTER** to create a new line without sending a message. +Press **ENTER** to send a message. Use **Shift+ENTER** to create a new line without sending a message. ## Formatting Messages diff --git a/doc/install/Administration.md b/doc/install/Administration.md index 15bd07778..d5e949fa0 100644 --- a/doc/install/Administration.md +++ b/doc/install/Administration.md @@ -94,6 +94,12 @@ To upgrade GitLab Mattermost from the 0.7.1-beta release of Mattermost in GitLab 1. Check that your SSL settings for the SSO provider match the `http://` or `https://` choice selected in `config.json` under `GitLabSettings` 2. Follow steps 1 to 3 of the manual [GitLab SSO configuration procedure](https://github.com/mattermost/platform/blob/master/doc/integrations/Single-Sign-On/Gitlab.md) to confirm your `Secret` and `Id` settings in `config.json` match your GitLab settings, and if they don't, manually update `config.json` to the correct settings and see if this clears the issue. +###### `"The redirect URI included is not valid.` + - This error may be related to SSL configurations in your proxy after a GitLab omnibus upgrade from 8.0, which contained the Mattermost beta version. + - **Solution:** + - Please check that each step of [the procedure for upgrading Mattermost in GitLab 8.0 to GitLab 8.1 was completed](https://github.com/mattermost/platform/blob/master/doc/install/Upgrade-Guide.md#upgrading-mattermost-in-gitlab-80-to-gitlab-81-with-omnibus). Then check upgrades to successive major versions were completed using the procedure in the [Upgrade Guide](https://github.com/mattermost/platform/blob/master/doc/install/Upgrade-Guide.md#upgrading-mattermost-to-next-major-release). + + ###### `We couldn't find the existing account` - This error appears when a user attempts to sign in using a single-sign-on option with an account that was not created using that single-sign-on option. For example, if a user creates Account A using email sign-up, then attempts to sign-in using GitLab SSO, the error appears since Account A was not created using GitLab SSO. - **Solution:** diff --git a/model/utils.go b/model/utils.go index 6d6eb452d..ff26bfc66 100644 --- a/model/utils.go +++ b/model/utils.go @@ -53,7 +53,7 @@ func AppErrorFromJson(data io.Reader) *AppError { if err == nil { return &er } else { - return nil + return NewAppError("AppErrorFromJson", "could not decode", err.Error()) } } diff --git a/web/react/.eslintignore b/web/react/.eslintignore index 5e8e7e0b6..25a7df331 100644 --- a/web/react/.eslintignore +++ b/web/react/.eslintignore @@ -1 +1,3 @@ **/*.json +components/toggle_modal_button.jsx +stores/modal_store.jsx diff --git a/web/react/components/channel_header.jsx b/web/react/components/channel_header.jsx index ffe7cbb5d..e46b2ccd7 100644 --- a/web/react/components/channel_header.jsx +++ b/web/react/components/channel_header.jsx @@ -27,6 +27,7 @@ const ActionTypes = Constants.ActionTypes; const Popover = ReactBootstrap.Popover; const OverlayTrigger = ReactBootstrap.OverlayTrigger; +const Tooltip = ReactBootstrap.Tooltip; export default class ChannelHeader extends React.Component { constructor(props) { @@ -121,6 +122,7 @@ export default class ChannelHeader extends React.Component { } const channel = this.state.channel; + const recentMentionsTooltip = <Tooltip id='recentMentionsTooltip'>{'Recent Mentions'}</Tooltip>; const popoverContent = ( <Popover id='hader-popover' @@ -382,31 +384,19 @@ export default class ChannelHeader extends React.Component { <th className='search-bar__container'><NavbarSearchBox /></th> <th> <div className='dropdown channel-header__links'> - <a - href='#' - className='dropdown-toggle theme' - type='button' - id='channel_header_right_dropdown' - data-toggle='dropdown' - aria-expanded='true' - > - <span dangerouslySetInnerHTML={{__html: Constants.MENU_ICON}} /> - </a> - <ul - className='dropdown-menu dropdown-menu-right' - role='menu' - aria-labelledby='channel_header_right_dropdown' + <OverlayTrigger + delayShow={400} + placement='bottom' + overlay={recentMentionsTooltip} > - <li role='presentation'> - <a - role='menuitem' - href='#' - onClick={this.searchMentions} - > - {'Recent Mentions'} - </a> - </li> - </ul> + <a + href='#' + type='button' + onClick={this.searchMentions} + > + {'@'} + </a> + </OverlayTrigger> </div> </th> </tr> diff --git a/web/react/components/create_post.jsx b/web/react/components/create_post.jsx index 6f25ef608..d823a54f1 100644 --- a/web/react/components/create_post.jsx +++ b/web/react/components/create_post.jsx @@ -383,8 +383,8 @@ export default class CreatePost extends React.Component { screens.push( <div> <h4>{'Sending Messages'}</h4> - <p>{'Type here to write a message.'}</p> - <p>{'Click the attachment button to upload an image or a file.'}</p> + <p>{'Type here to write a message and press '}<strong>{'Enter'}</strong>{' to post it.'}</p> + <p>{'Click the '}<strong>{'Attachment'}</strong>{' button to upload an image or a file.'}</p> </div> ); diff --git a/web/react/components/file_preview.jsx b/web/react/components/file_preview.jsx index df5deb8bc..b8c86ed67 100644 --- a/web/react/components/file_preview.jsx +++ b/web/react/components/file_preview.jsx @@ -8,9 +8,14 @@ export default class FilePreview extends React.Component { super(props); this.handleRemove = this.handleRemove.bind(this); + } - this.state = {}; + componentDidUpdate() { + if (this.props.uploadsInProgress.length > 0) { + ReactDOM.findDOMNode(this.refs[this.props.uploadsInProgress[0]]).scrollIntoView(); + } } + handleRemove(e) { var previewDiv = e.target.parentNode.parentNode; @@ -20,9 +25,10 @@ export default class FilePreview extends React.Component { this.props.onRemove(previewDiv.getAttribute('data-client-id')); } } + render() { var previews = []; - this.props.files.forEach(function setupPreview(fullFilename) { + this.props.files.forEach((fullFilename) => { var filename = fullFilename; var originalFilename = filename; var filenameSplit = filename.split('.'); @@ -72,11 +78,12 @@ export default class FilePreview extends React.Component { </div> ); } - }.bind(this)); + }); - this.props.uploadsInProgress.forEach(function addUploadsInProgress(clientId) { + this.props.uploadsInProgress.forEach((clientId) => { previews.push( <div + ref={clientId} key={clientId} className='preview-div' data-client-id={clientId} @@ -93,7 +100,7 @@ export default class FilePreview extends React.Component { </a> </div> ); - }.bind(this)); + }); return ( <div className='preview-container'> @@ -104,8 +111,8 @@ export default class FilePreview extends React.Component { } FilePreview.defaultProps = { - files: null, - uploadsInProgress: null + files: [], + uploadsInProgress: [] }; FilePreview.propTypes = { onRemove: React.PropTypes.func.isRequired, diff --git a/web/react/components/navbar.jsx b/web/react/components/navbar.jsx index 1fcfabccd..845c33f3b 100644 --- a/web/react/components/navbar.jsx +++ b/web/react/components/navbar.jsx @@ -32,6 +32,7 @@ export default class Navbar extends React.Component { this.onChange = this.onChange.bind(this); this.handleLeave = this.handleLeave.bind(this); + this.showSearch = this.showSearch.bind(this); this.createCollapseButtons = this.createCollapseButtons.bind(this); this.createDropdown = this.createDropdown.bind(this); @@ -100,6 +101,11 @@ export default class Navbar extends React.Component { $('.inner__wrap').toggleClass('move--left-small'); $('.sidebar--menu').toggleClass('move--left'); } + showSearch() { + AppDispatcher.handleServerAction({ + type: ActionTypes.SHOW_SEARCH + }); + } onChange() { this.setState(this.getStateFromStores()); $('#navbar .navbar-brand .description').popover({placement: 'bottom', trigger: 'click', html: true}); @@ -411,6 +417,16 @@ export default class Navbar extends React.Component { var collapseButtons = this.createCollapseButtons(currentId); + const searchButton = ( + <button + type='button' + className='navbar-toggle pull-right' + onClick={this.showSearch} + > + <span className='glyphicon glyphicon-search icon--white' /> + </button> + ); + var channelMenuDropdown = this.createDropdown(channel, channelTitle, isAdmin, isDirect, popoverContent); return ( @@ -422,6 +438,7 @@ export default class Navbar extends React.Component { <div className='container-fluid theme'> <div className='navbar-header'> {collapseButtons} + {searchButton} {channelMenuDropdown} </div> </div> diff --git a/web/react/components/post.jsx b/web/react/components/post.jsx index 2b9586345..7e4af07c4 100644 --- a/web/react/components/post.jsx +++ b/web/react/components/post.jsx @@ -13,8 +13,6 @@ var AsyncClient = require('../utils/async_client.jsx'); var ActionTypes = Constants.ActionTypes; var utils = require('../utils/utils.jsx'); -var PostInfo = require('./post_info.jsx'); - export default class Post extends React.Component { constructor(props) { super(props); @@ -141,6 +139,8 @@ export default class Post extends React.Component { var postType = ''; if (type !== 'Post') { postType = 'post--comment'; + } else if (commentCount > 0) { + postType = 'post--root'; } var currentUserCss = ''; @@ -170,14 +170,11 @@ export default class Post extends React.Component { } profilePic = ( - <div className='post-profile-img__container'> - <img - className='post-profile-img' - src={src} - height='36' - width='36' - /> - </div> + <img + src={src} + height='36' + width='36' + /> ); } @@ -187,32 +184,26 @@ export default class Post extends React.Component { id={'post_' + post.id} className={'post ' + sameUserClass + ' ' + rootUser + ' ' + postType + ' ' + currentUserCss} > - {profilePic} <div className='post__content'> - <PostHeader - ref='header' - post={post} - sameRoot={this.props.sameRoot} - commentCount={commentCount} - handleCommentClick={this.handleCommentClick} - isLastComment={this.props.isLastComment} - /> - <PostBody - post={post} - sameRoot={this.props.sameRoot} - parentPost={parentPost} - posts={posts} - handleCommentClick={this.handleCommentClick} - retryPost={this.retryPost} - /> - <PostInfo - ref='info' - post={post} - sameRoot={this.props.sameRoot} - commentCount={commentCount} - handleCommentClick={this.handleCommentClick} - allowReply='true' - /> + <div className='post__img'>{profilePic}</div> + <div> + <PostHeader + ref='header' + post={post} + sameRoot={this.props.sameRoot} + commentCount={commentCount} + handleCommentClick={this.handleCommentClick} + isLastComment={this.props.isLastComment} + /> + <PostBody + post={post} + sameRoot={this.props.sameRoot} + parentPost={parentPost} + posts={posts} + handleCommentClick={this.handleCommentClick} + retryPost={this.retryPost} + /> + </div> </div> </div> </div> diff --git a/web/react/components/post_body.jsx b/web/react/components/post_body.jsx index 975ac64dc..e1c057775 100644 --- a/web/react/components/post_body.jsx +++ b/web/react/components/post_body.jsx @@ -257,7 +257,7 @@ export default class PostBody extends React.Component { } return ( - <div className='post-comment'> + <div> <h4> <span className='video-type'>{header}</span> <span className='video-title'><a href={link}>{this.state.youtubeTitle}</a></span> @@ -329,7 +329,7 @@ export default class PostBody extends React.Component { } comment = ( - <p className='post-link'> + <div className='post__link'> <span> {'Commented on '}{name}{apostrophe}{' message: '} <a @@ -339,15 +339,13 @@ export default class PostBody extends React.Component { {message} </a> </span> - </p> + </div> ); - - postClass += ' post-comment'; } let loading; if (post.state === Constants.POST_FAILED) { - postClass += ' post-fail'; + postClass += ' post--fail'; loading = ( <a className='theme post-retry pull-right' @@ -379,25 +377,27 @@ export default class PostBody extends React.Component { } return ( - <div className='post-body'> + <div> {comment} - <div - key={`${post.id}_message`} - id={`${post.id}_message`} - className={postClass} - > - {loading} - <span - ref='message_span' - onClick={TextFormatting.handleClick} - dangerouslySetInnerHTML={{__html: TextFormatting.formatText(this.state.message)}} + <div className='post__body'> + <div + key={`${post.id}_message`} + id={`${post.id}_message`} + className={postClass} + > + {loading} + <span + ref='message_span' + onClick={TextFormatting.handleClick} + dangerouslySetInnerHTML={{__html: TextFormatting.formatText(this.state.message)}} + /> + </div> + <PostBodyAdditionalContent + post={this.state.post} /> + {fileAttachmentHolder} + {this.embed} </div> - <PostBodyAdditionalContent - post={this.state.post} - /> - {fileAttachmentHolder} - {this.embed} </div> ); } diff --git a/web/react/components/post_header.jsx b/web/react/components/post_header.jsx index 45e60c767..e8b162fc2 100644 --- a/web/react/components/post_header.jsx +++ b/web/react/components/post_header.jsx @@ -26,14 +26,14 @@ export default class PostHeader extends React.Component { ); } - botIndicator = <li className='post-header-col post-header__name bot-indicator'>{'BOT'}</li>; + botIndicator = <li className='col col__name bot-indicator'>{'BOT'}</li>; } return ( - <ul className='post-header post-header-post'> - <li className='post-header-col post-header__name'><strong>{userProfile}</strong></li> + <ul className='post__header'> + <li className='col col__name'>{userProfile}</li> {botIndicator} - <li className='post-info--hidden'> + <li className='col'> <PostInfo post={post} commentCount={this.props.commentCount} diff --git a/web/react/components/post_info.jsx b/web/react/components/post_info.jsx index fffa5b19a..322834f07 100644 --- a/web/react/components/post_info.jsx +++ b/web/react/components/post_info.jsx @@ -81,7 +81,7 @@ export default class PostInfo extends React.Component { role='presentation' > <a - className='reply-link theme' + className='reply-link visible-xs theme' href='#' onClick={this.props.handleCommentClick} > @@ -99,7 +99,7 @@ export default class PostInfo extends React.Component { <div> <a href='#' - className='dropdown-toggle theme' + className='dropdown-toggle post__dropdown theme' type='button' data-toggle='dropdown' aria-expanded='false' @@ -116,23 +116,27 @@ export default class PostInfo extends React.Component { render() { var post = this.props.post; var comments = ''; - var lastCommentClass = ' comment-icon__container__hide'; - if (this.props.isLastComment) { - lastCommentClass = ' comment-icon__container__show'; + var showCommentClass = ''; + var commentCountText = this.props.commentCount; + + if (this.props.commentCount >= 1) { + showCommentClass = ' icon--show'; + } else { + commentCountText = ''; } - if (this.props.commentCount >= 1 && post.state !== Constants.POST_FAILED && post.state !== Constants.POST_LOADING && post.state !== Constants.POST_DELETED) { + if (post.state !== Constants.POST_FAILED && post.state !== Constants.POST_LOADING && post.state !== Constants.POST_DELETED) { comments = ( <a href='#' - className={'comment-icon__container theme' + lastCommentClass} + className={'comment-icon__container' + showCommentClass} onClick={this.props.handleCommentClick} > <span className='comment-icon' dangerouslySetInnerHTML={{__html: Constants.COMMENT_ICON}} /> - {this.props.commentCount} + {commentCountText} </a> ); } @@ -140,17 +144,17 @@ export default class PostInfo extends React.Component { var dropdown = this.createDropdown(); return ( - <ul className='post-header post-info'> - <li className='post-header-col'> + <ul className='post__header post__header--info'> + <li className='col'> <TimeSince eventTime={post.create_at} /> </li> - <li className='post-header-col post-header__reply'> + <li className='col col__reply'> + {comments} <div className='dropdown'> {dropdown} </div> - {comments} </li> </ul> ); diff --git a/web/react/components/rhs_comment.jsx b/web/react/components/rhs_comment.jsx index c16f9ff0e..a55bf0039 100644 --- a/web/react/components/rhs_comment.jsx +++ b/web/react/components/rhs_comment.jsx @@ -131,7 +131,7 @@ export default class RhsComment extends React.Component { <div className='dropdown'> <a href='#' - className='dropdown-toggle theme' + className='post__dropdown dropdown-toggle' type='button' data-toggle='dropdown' aria-expanded='false' @@ -193,38 +193,39 @@ export default class RhsComment extends React.Component { return ( <div className={'post ' + currentUserCss}> - <div className='post-profile-img__container'> - <img - className='post-profile-img' - src={'/api/v1/users/' + post.user_id + '/image?time=' + timestamp + '&' + Utils.getSessionIndex()} - height='36' - width='36' - /> - </div> <div className='post__content'> - <ul className='post-header'> - <li className='post-header-col'> - <strong><UserProfile userId={post.user_id} /></strong> - </li> - <li className='post-header-col'> - <time className='post-profile-time'> - {Utils.displayCommentDateTime(post.create_at)} - </time> - </li> - <li className='post-header-col post-header__reply'> - {dropdown} - </li> - </ul> - <div className='post-body'> - <div className={postClass}> - {loading} - <div - ref='message_holder' - onClick={TextFormatting.handleClick} - dangerouslySetInnerHTML={{__html: TextFormatting.formatText(post.message)}} - /> + <div className='post__img'> + <img + src={'/api/v1/users/' + post.user_id + '/image?time=' + timestamp + '&' + Utils.getSessionIndex()} + height='36' + width='36' + /> + </div> + <div> + <ul className='post__header'> + <li className='col__name'> + <strong><UserProfile userId={post.user_id} /></strong> + </li> + <li className='col'> + <time className='post__time'> + {Utils.displayCommentDateTime(post.create_at)} + </time> + </li> + <li className='col col__reply'> + {dropdown} + </li> + </ul> + <div className='post__body'> + <div className={postClass}> + {loading} + <div + ref='message_holder' + onClick={TextFormatting.handleClick} + dangerouslySetInnerHTML={{__html: TextFormatting.formatText(post.message)}} + /> + </div> + {fileAttachment} </div> - {fileAttachment} </div> </div> </div> diff --git a/web/react/components/rhs_root_post.jsx b/web/react/components/rhs_root_post.jsx index 84fdc014a..358bf8440 100644 --- a/web/react/components/rhs_root_post.jsx +++ b/web/react/components/rhs_root_post.jsx @@ -66,7 +66,7 @@ export default class RhsRootPost extends React.Component { ownerOptions = ( <div> <a href='#' - className='dropdown-toggle theme' + className='post__dropdown dropdown-toggle' type='button' data-toggle='dropdown' aria-expanded='false' @@ -129,7 +129,7 @@ export default class RhsRootPost extends React.Component { ); } - botIndicator = <li className='post-header-col post-header__name bot-indicator'>{'BOT'}</li>; + botIndicator = <li className='col col__name bot-indicator'>{'BOT'}</li>; } let src = '/api/v1/users/' + post.user_id + '/image?time=' + timestamp + '&' + utils.getSessionIndex(); @@ -140,47 +140,47 @@ export default class RhsRootPost extends React.Component { } const profilePic = ( - <div className='post-profile-img__container'> - <img - className='post-profile-img' - src={src} - height='36' - width='36' - /> - </div> + <img + className='post-profile-img' + src={src} + height='36' + width='36' + /> ); return ( <div className={'post post--root ' + currentUserCss}> <div className='post-right-channel__name'>{channelName}</div> - <div className='post-profile-img__container'> - {profilePic} - </div> <div className='post__content'> - <ul className='post-header'> - <li className='post-header-col'><strong>{userProfile}</strong></li> - {botIndicator} - <li className='post-header-col'> - <time className='post-profile-time'> - {utils.displayCommentDateTime(post.create_at)} - </time> - </li> - <li className='post-header-col post-header__reply'> - <div className='dropdown'> - {ownerOptions} - </div> - </li> - </ul> - <div className='post-body'> - <div - ref='message_holder' - onClick={TextFormatting.handleClick} - dangerouslySetInnerHTML={{__html: TextFormatting.formatText(post.message)}} - /> - <PostBodyAdditionalContent - post={post} - /> - {fileAttachment} + <div className='post__img'> + {profilePic} + </div> + <div> + <ul className='post__header'> + <li className='col__name'>{userProfile}</li> + {botIndicator} + <li className='col'> + <time className='post__time'> + {utils.displayCommentDateTime(post.create_at)} + </time> + </li> + <li className='col col__reply'> + <div className='dropdown'> + {ownerOptions} + </div> + </li> + </ul> + <div className='post__body'> + <div + ref='message_holder' + onClick={TextFormatting.handleClick} + dangerouslySetInnerHTML={{__html: TextFormatting.formatText(post.message)}} + /> + <PostBodyAdditionalContent + post={post} + /> + {fileAttachment} + </div> </div> </div> <hr /> diff --git a/web/react/components/search_results.jsx b/web/react/components/search_results.jsx index f4d8647db..491995087 100644 --- a/web/react/components/search_results.jsx +++ b/web/react/components/search_results.jsx @@ -80,14 +80,27 @@ export default class SearchResults extends React.Component { var ctls = null; - if (noResults) { + if (!searchTerm && noResults) { + ctls = ( + <div className='sidebar--right__subheader'> + <ul> + <li> + {'Use '}<b>{'"quotation marks"'}</b>{' to search for phrases'} + </li> + <li> + {'Use '}<b>{'from:'}</b>{' to find posts from specific users and '}<b>{'in:'}</b>{' to find posts in specific channels'} + </li> + </ul> + </div> + ); + } else if (noResults) { ctls = ( <div className='sidebar--right__subheader'> <h4>{'NO RESULTS'}</h4> <ul> - <li>If you're searching a partial phrase (ex. searching "rea", looking for "reach" or "reaction"), append a * to your search term</li> - <li>Due to the volume of results, two letter searches and common words like "this", "a" and "is" won't appear in search results</li> + <li>{'If you\'re searching a partial phrase (ex. searching "rea", looking for "reach" or "reaction"), append a * to your search term'}</li> + <li>{'Due to the volume of results, two letter searches and common words like "this", "a" and "is" won\'t appear in search results'}</li> </ul> </div> ); diff --git a/web/react/components/search_results_item.jsx b/web/react/components/search_results_item.jsx index a8bd4db2c..52766a8a0 100644 --- a/web/react/components/search_results_item.jsx +++ b/web/react/components/search_results_item.jsx @@ -74,29 +74,30 @@ export default class SearchResultsItem extends React.Component { onClick={this.handleClick} > <div className='search-channel__name'>{channelName}</div> - <div className='post-profile-img__container'> - <img - className='post-profile-img' - src={'/api/v1/users/' + this.props.post.user_id + '/image?time=' + timestamp + '&' + utils.getSessionIndex()} - height='36' - width='36' - /> - </div> <div className='post__content'> - <ul className='post-header'> - <li className='post-header-col'><strong><UserProfile userId={this.props.post.user_id} /></strong></li> - <li className='post-header-col'> - <time className='search-item-time'> - {utils.displayDate(this.props.post.create_at) + ' ' + utils.displayTime(this.props.post.create_at)} - </time> - </li> - </ul> - <div className='search-item-snippet'> - <span - onClick={this.handleClick} - dangerouslySetInnerHTML={{__html: TextFormatting.formatText(this.props.post.message, formattingOptions)}} + <div className='post__img'> + <img + src={'/api/v1/users/' + this.props.post.user_id + '/image?time=' + timestamp + '&' + utils.getSessionIndex()} + height='36' + width='36' /> </div> + <div> + <ul className='post__header'> + <li className='col__name'><strong><UserProfile userId={this.props.post.user_id} /></strong></li> + <li className='col'> + <time className='search-item-time'> + {utils.displayDate(this.props.post.create_at) + ' ' + utils.displayTime(this.props.post.create_at)} + </time> + </li> + </ul> + <div className='search-item-snippet'> + <span + onClick={this.handleClick} + dangerouslySetInnerHTML={{__html: TextFormatting.formatText(this.props.post.message, formattingOptions)}} + /> + </div> + </div> </div> </div> ); diff --git a/web/react/components/sidebar_right.jsx b/web/react/components/sidebar_right.jsx index ab558ad0f..8d16057fc 100644 --- a/web/react/components/sidebar_right.jsx +++ b/web/react/components/sidebar_right.jsx @@ -7,10 +7,6 @@ var SearchStore = require('../stores/search_store.jsx'); var PostStore = require('../stores/post_store.jsx'); var Utils = require('../utils/utils.jsx'); -function getStateFromStores() { - return {search_visible: SearchStore.getSearchResults() != null, post_right_visible: PostStore.getSelectedPost() != null, is_mention_search: SearchStore.getIsMentionSearch()}; -} - export default class SidebarRight extends React.Component { constructor(props) { super(props); @@ -19,19 +15,29 @@ export default class SidebarRight extends React.Component { this.onSelectedChange = this.onSelectedChange.bind(this); this.onSearchChange = this.onSearchChange.bind(this); + this.onShowSearch = this.onShowSearch.bind(this); this.doStrangeThings = this.doStrangeThings.bind(this); - this.state = getStateFromStores(); + this.state = this.getStateFromStores(); + } + getStateFromStores() { + return { + search_visible: SearchStore.getSearchResults() != null, + post_right_visible: PostStore.getSelectedPost() != null, + is_mention_search: SearchStore.getIsMentionSearch() + }; } componentDidMount() { SearchStore.addSearchChangeListener(this.onSearchChange); PostStore.addSelectedPostChangeListener(this.onSelectedChange); + SearchStore.addShowSearchListener(this.onShowSearch); this.doStrangeThings(); } componentWillUnmount() { SearchStore.removeSearchChangeListener(this.onSearchChange); PostStore.removeSelectedPostChangeListener(this.onSelectedChange); + SearchStore.removeShowSearchListener(this.onShowSearch); } componentWillUpdate() { PostStore.jumpPostsViewSidebarOpen(); @@ -64,18 +70,25 @@ export default class SidebarRight extends React.Component { this.doStrangeThings(); } onSelectedChange(fromSearch) { - var newState = getStateFromStores(fromSearch); + var newState = this.getStateFromStores(fromSearch); newState.from_search = fromSearch; if (!Utils.areObjectsEqual(newState, this.state)) { this.setState(newState); } } onSearchChange() { - var newState = getStateFromStores(); + var newState = this.getStateFromStores(); if (!Utils.areObjectsEqual(newState, this.state)) { this.setState(newState); } } + onShowSearch() { + if (!this.state.search_visible) { + this.setState({ + search_visible: true + }); + } + } render() { var content = ''; diff --git a/web/react/components/time_since.jsx b/web/react/components/time_since.jsx index c37739b9c..212beb080 100644 --- a/web/react/components/time_since.jsx +++ b/web/react/components/time_since.jsx @@ -34,7 +34,7 @@ export default class TimeSince extends React.Component { placement='top' overlay={tooltip} > - <time className='post-profile-time'> + <time className='post__time'> {Utils.displayDateTime(this.props.eventTime)} </time> </OverlayTrigger> diff --git a/web/react/components/user_settings/custom_theme_chooser.jsx b/web/react/components/user_settings/custom_theme_chooser.jsx index 3dbed72c3..3d0a2b548 100644 --- a/web/react/components/user_settings/custom_theme_chooser.jsx +++ b/web/react/components/user_settings/custom_theme_chooser.jsx @@ -14,7 +14,10 @@ export default class CustomThemeChooser extends React.Component { this.state = {}; } componentDidMount() { - $('.color-picker').colorpicker().on('changeColor', this.onPickerChange); + $('.color-picker').colorpicker({ + format: 'hex' + }); + $('.color-picker').on('changeColor', this.onPickerChange); } onPickerChange(e) { const theme = this.props.theme; diff --git a/web/react/stores/search_store.jsx b/web/react/stores/search_store.jsx index 95f0ea845..93b89035c 100644 --- a/web/react/stores/search_store.jsx +++ b/web/react/stores/search_store.jsx @@ -14,6 +14,7 @@ var SEARCH_CHANGE_EVENT = 'search_change'; var SEARCH_TERM_CHANGE_EVENT = 'search_term_change'; var MENTION_DATA_CHANGE_EVENT = 'mention_data_change'; var ADD_MENTION_EVENT = 'add_mention'; +var SHOW_SEARCH_EVENT = 'show_search'; class SearchStoreClass extends EventEmitter { constructor() { @@ -35,6 +36,10 @@ class SearchStoreClass extends EventEmitter { this.addMentionDataChangeListener = this.addMentionDataChangeListener.bind(this); this.removeMentionDataChangeListener = this.removeMentionDataChangeListener.bind(this); + this.emitShowSearch = this.emitShowSearch.bind(this); + this.addShowSearchListener = this.addShowSearchListener.bind(this); + this.removeShowSearchListener = this.removeShowSearchListener.bind(this); + this.getSearchResults = this.getSearchResults.bind(this); this.getIsMentionSearch = this.getIsMentionSearch.bind(this); @@ -80,6 +85,18 @@ class SearchStoreClass extends EventEmitter { this.removeListener(SEARCH_TERM_CHANGE_EVENT, callback); } + emitShowSearch() { + this.emit(SHOW_SEARCH_EVENT); + } + + addShowSearchListener(callback) { + this.on(SHOW_SEARCH_EVENT, callback); + } + + removeShowSearchListener(callback) { + this.removeListener(SHOW_SEARCH_EVENT, callback); + } + getSearchResults() { return BrowserStore.getItem('search_results'); } @@ -146,6 +163,9 @@ SearchStore.dispatchToken = AppDispatcher.register((payload) => { case ActionTypes.RECIEVED_ADD_MENTION: SearchStore.emitAddMention(action.id, action.username); break; + case ActionTypes.SHOW_SEARCH: + SearchStore.emitShowSearch(); + break; default: } }); diff --git a/web/react/utils/channel_intro_mssages.jsx b/web/react/utils/channel_intro_mssages.jsx index 11b69e28f..28a458e3f 100644 --- a/web/react/utils/channel_intro_mssages.jsx +++ b/web/react/utils/channel_intro_mssages.jsx @@ -205,6 +205,7 @@ export function createStandardIntroMessage(channel, showInviteModal) { <i className='fa fa-pencil'></i>{'Set a header'} </a> <a + className='intro-links' href='#' onClick={showInviteModal} > diff --git a/web/react/utils/constants.jsx b/web/react/utils/constants.jsx index 6be87254f..80c0cf0ee 100644 --- a/web/react/utils/constants.jsx +++ b/web/react/utils/constants.jsx @@ -39,6 +39,8 @@ module.exports = { RECIEVED_LOGS: null, RECIEVED_ALL_TEAMS: null, + SHOW_SEARCH: null, + TOGGLE_IMPORT_THEME_MODAL: null, TOGGLE_INVITE_MEMBER_MODAL: null, TOGGLE_DELETE_POST_MODAL: null diff --git a/web/react/utils/utils.jsx b/web/react/utils/utils.jsx index 5af837822..cd347f7d6 100644 --- a/web/react/utils/utils.jsx +++ b/web/react/utils/utils.jsx @@ -538,12 +538,11 @@ export function applyTheme(theme) { if (theme.sidebarText) { changeCss('.sidebar--left .nav-pills__container li>a, .sidebar--right, .settings-modal .nav-pills>li a, .sidebar--menu', 'color:' + changeOpacity(theme.sidebarText, 0.6), 1); - changeCss('@media(max-width: 768px){.settings-modal .settings-table .nav>li>a', 'color:' + theme.sidebarText, 1); + changeCss('@media(max-width: 960px){.settings-modal .settings-table .nav>li>a', 'color:' + theme.sidebarText, 1); changeCss('.sidebar--left .nav-pills__container li>h4, .sidebar--left .add-channel-btn', 'color:' + changeOpacity(theme.sidebarText, 0.6), 1); changeCss('.sidebar--left .add-channel-btn:hover, .sidebar--left .add-channel-btn:focus', 'color:' + theme.sidebarText, 1); - changeCss('.sidebar--left, .sidebar--right .sidebar--right__header', 'border-color:' + changeOpacity(theme.sidebarText, 0.2), 1); changeCss('.sidebar--left .status path', 'fill:' + changeOpacity(theme.sidebarText, 0.5), 1); - changeCss('@media(max-width: 768px){.settings-modal .settings-table .nav>li>a', 'border-color:' + changeOpacity(theme.sidebarText, 0.2), 2); + changeCss('@media(max-width: 960px){.settings-modal .settings-table .nav>li>a', 'border-color:' + changeOpacity(theme.sidebarText, 0.2), 2); } if (theme.sidebarUnreadText) { @@ -552,7 +551,7 @@ export function applyTheme(theme) { if (theme.sidebarTextHoverBg) { changeCss('.sidebar--left .nav-pills__container li>a:hover, .sidebar--left .nav-pills__container li>a:focus, .settings-modal .nav-pills>li:hover a, .settings-modal .nav-pills>li:focus a', 'background:' + theme.sidebarTextHoverBg, 1); - changeCss('@media(max-width: 768px){.settings-modal .settings-table .nav>li:hover a', 'background:' + theme.sidebarTextHoverBg, 1); + changeCss('@media(max-width: 960px){.settings-modal .settings-table .nav>li:hover a', 'background:' + theme.sidebarTextHoverBg, 1); } if (theme.sidebarTextActiveBorder) { @@ -562,15 +561,13 @@ export function applyTheme(theme) { if (theme.sidebarTextActiveColor) { changeCss('.sidebar--left .nav-pills__container li.active a, .sidebar--left .nav-pills__container li.active a:hover, .sidebar--left .nav-pills__container li.active a:focus, .settings-modal .nav-pills>li.active a, .settings-modal .nav-pills>li.active a:hover, .settings-modal .nav-pills>li.active a:active', 'color:' + theme.sidebarTextActiveColor, 2); changeCss('.sidebar--left .nav li.active a, .sidebar--left .nav li.active a:hover, .sidebar--left .nav li.active a:focus', 'background:' + changeOpacity(theme.sidebarTextActiveColor, 0.1), 1); - changeCss('.search-help-popover .search-autocomplete__item:hover', 'background:' + changeOpacity(theme.sidebarTextActiveColor, 0.05), 1); - changeCss('.search-help-popover .search-autocomplete__item.selected', 'background:' + changeOpacity(theme.sidebarTextActiveColor, 0.15), 1); } if (theme.sidebarHeaderBg) { changeCss('.sidebar--left .team__header, .sidebar--menu .team__header', 'background:' + theme.sidebarHeaderBg, 1); changeCss('.modal .modal-header', 'background:' + theme.sidebarHeaderBg, 1); changeCss('#navbar .navbar-default', 'background:' + theme.sidebarHeaderBg, 1); - changeCss('@media(max-width: 768px){.search-bar__container', 'background:' + theme.sidebarHeaderBg, 1); + changeCss('@media(max-width: 960px){.search-bar__container', 'background:' + theme.sidebarHeaderBg, 1); changeCss('.attachment .attachment__container', 'border-left-color:' + theme.sidebarHeaderBg, 1); } @@ -581,7 +578,7 @@ export function applyTheme(theme) { changeCss('.modal .modal-header .modal-title, .modal .modal-header .modal-title .name, .modal .modal-header button.close', 'color:' + theme.sidebarHeaderTextColor, 1); changeCss('#navbar .navbar-default .navbar-brand .heading', 'color:' + theme.sidebarHeaderTextColor, 1); changeCss('#navbar .navbar-default .navbar-toggle .icon-bar, ', 'background:' + theme.sidebarHeaderTextColor, 1); - changeCss('@media(max-width: 768px){.search-bar__container', 'color:' + theme.sidebarHeaderTextColor, 2); + changeCss('@media(max-width: 960px){.search-bar__container', 'color:' + theme.sidebarHeaderTextColor, 2); } if (theme.onlineIndicator) { @@ -614,17 +611,16 @@ export function applyTheme(theme) { } if (theme.centerChannelColor) { + changeCss('.sidebar--left, .sidebar--right .sidebar--right__header', 'border-color:' + changeOpacity(theme.centerChannelColor, 0.2), 1); changeCss('.app__content, .post-create__container .post-create-body .btn-file, .post-create__container .post-create-footer .msg-typing, .command-name, .modal .modal-content, .dropdown-menu, .popover, .mentions-name, .tip-overlay', 'color:' + theme.centerChannelColor, 1); changeCss('#post-create', 'color:' + theme.centerChannelColor, 2); - changeCss('.channel-header__links a', 'fill:' + changeOpacity(theme.centerChannelColor, 0.9), 1); - changeCss('.channel-header__links a:hover, .channel-header__links a:active', 'fill:' + theme.centerChannelColor, 2); changeCss('.mentions--top, .command-box', 'box-shadow:' + changeOpacity(theme.centerChannelColor, 0.2) + ' 1px -3px 12px', 3); changeCss('.mentions--top, .command-box', '-webkit-box-shadow:' + changeOpacity(theme.centerChannelColor, 0.2) + ' 1px -3px 12px', 2); changeCss('.mentions--top, .command-box', '-moz-box-shadow:' + changeOpacity(theme.centerChannelColor, 0.2) + ' 1px -3px 12px', 1); changeCss('.dropdown-menu, .popover ', 'box-shadow:' + changeOpacity(theme.centerChannelColor, 0.1) + ' 0px 6px 12px', 3); changeCss('.dropdown-menu, .popover ', '-webkit-box-shadow:' + changeOpacity(theme.centerChannelColor, 0.1) + ' 0px 6px 12px', 2); changeCss('.dropdown-menu, .popover ', '-moz-box-shadow:' + changeOpacity(theme.centerChannelColor, 0.1) + ' 0px 6px 12px', 1); - changeCss('.post-body hr, .loading-screen .loading__content .round, .tutorial__circles .circle', 'background:' + theme.centerChannelColor, 1); + changeCss('.post__body hr, .loading-screen .loading__content .round, .tutorial__circles .circle', 'background:' + theme.centerChannelColor, 1); changeCss('.channel-header .heading', 'color:' + theme.centerChannelColor, 1); changeCss('.markdown__table tbody tr:nth-child(2n)', 'background:' + changeOpacity(theme.centerChannelColor, 0.07), 1); changeCss('.channel-header__info>div.dropdown .header-dropdown__icon', 'color:' + changeOpacity(theme.centerChannelColor, 0.8), 1); @@ -642,26 +638,26 @@ export function applyTheme(theme) { changeCss('.post-image__column .post-image__details', 'color:' + theme.centerChannelColor, 2); changeCss('.post-image__column a, .post-image__column a:hover, .post-image__column a:focus', 'color:' + theme.centerChannelColor, 1); changeCss('.search-bar__container .search__form .search-bar, .form-control', 'color:' + theme.centerChannelColor, 2); - changeCss('@media(max-width: 768px){.search-bar__container .search__form .search-bar', 'background:' + changeOpacity(theme.centerChannelColor, 0.2) + '; color: inherit;', 1); + changeCss('@media(max-width: 960px){.search-bar__container .search__form .search-bar', 'background:' + changeOpacity(theme.centerChannelColor, 0.2) + '; color: inherit;', 1); changeCss('.input-group-addon, .search-bar__container .search__form, .form-control', 'border-color:' + changeOpacity(theme.centerChannelColor, 0.2), 1); - changeCss('.form-control:focus, .channel-header__links', 'border-color:' + changeOpacity(theme.centerChannelColor, 0.3), 1); + changeCss('.form-control:focus', 'border-color:' + changeOpacity(theme.centerChannelColor, 0.3), 1); changeCss('.attachment .attachment__content', 'border-color:' + changeOpacity(theme.centerChannelColor, 0.3), 1); changeCss('.channel-intro .channel-intro__content, .webhooks__container', 'background:' + changeOpacity(theme.centerChannelColor, 0.05), 1); changeCss('.date-separator .separator__text', 'color:' + theme.centerChannelColor, 2); changeCss('.date-separator .separator__hr, .modal-footer, .modal .custom-textarea, .post-right__container .post.post--root hr, .search-item-container', 'border-color:' + changeOpacity(theme.centerChannelColor, 0.2), 1); changeCss('.modal .custom-textarea:focus', 'border-color:' + changeOpacity(theme.centerChannelColor, 0.3), 1); changeCss('.channel-intro, .settings-modal .settings-table .settings-content .divider-dark, hr, .settings-modal .settings-table .settings-links', 'border-color:' + changeOpacity(theme.centerChannelColor, 0.2), 1); - changeCss('.post.current--user .post-body, .post.post--comment.other--root.current--user .post-comment, pre', 'background:' + changeOpacity(theme.centerChannelColor, 0.07), 1); - changeCss('.post.current--user .post-body, .post.post--comment.other--root.current--user .post-comment, .post.post--comment.other--root .post-comment, .post.same--root .post-body, .modal .more-table tbody>tr td, .member-div:first-child, .member-div, .access-history__table .access__report, .activity-log__table', 'border-color:' + changeOpacity(theme.centerChannelColor, 0.1), 2); - changeCss('@media(max-width: 1440px){.post.same--root', 'border-color:' + changeOpacity(theme.centerChannelColor, 0.07), 2); - changeCss('@media(max-width: 1440px){.post.same--root', 'border-color:' + changeOpacity(theme.centerChannelColor, 0.07), 2); + changeCss('.post.current--user .post__body, .post.post--comment.other--root.current--user .post-comment, pre', 'background:' + changeOpacity(theme.centerChannelColor, 0.07), 1); + changeCss('.post.current--user .post__body, .post.post--comment.other--root.current--user .post-comment, .post.same--root.post--comment .post__body, .modal .more-table tbody>tr td, .member-div:first-child, .member-div, .access-history__table .access__report, .activity-log__table', 'border-color:' + changeOpacity(theme.centerChannelColor, 0.1), 2); changeCss('@media(max-width: 1800px){.inner__wrap.move--left .post.post--comment.same--root', 'border-color:' + changeOpacity(theme.centerChannelColor, 0.07), 2); - changeCss('.post:hover, .channel-header__links a:hover, .channel-header__links a:active, .modal .more-table tbody>tr:hover td, .settings-modal .settings-table .settings-content .section-min:hover', 'background:' + changeOpacity(theme.centerChannelColor, 0.07), 1); + changeCss('.post:hover, .modal .more-table tbody>tr:hover td, .settings-modal .settings-table .settings-content .section-min:hover', 'background:' + changeOpacity(theme.centerChannelColor, 0.07), 1); changeCss('.date-separator.hovered--before:after, .date-separator.hovered--after:before, .new-separator.hovered--after:before, .new-separator.hovered--before:after', 'background:' + changeOpacity(theme.centerChannelColor, 0.07), 1); changeCss('.command-name:hover, .mentions-name:hover, .mentions-focus, .dropdown-menu>li>a:focus, .dropdown-menu>li>a:hover, .bot-indicator', 'background:' + changeOpacity(theme.centerChannelColor, 0.15), 1); changeCss('code', 'background:' + changeOpacity(theme.centerChannelColor, 0.1), 1); - changeCss('.post.current--user:hover .post-body ', 'background: none;', 1); + changeCss('@media(min-width: 960px){.post.current--user:hover .post__body ', 'background: none;', 1); changeCss('.sidebar--right', 'color:' + theme.centerChannelColor, 2); + changeCss('.search-help-popover .search-autocomplete__item:hover', 'background:' + changeOpacity(theme.centerChannelColor, 0.05), 1); + changeCss('.search-help-popover .search-autocomplete__item.selected', 'background:' + changeOpacity(theme.centerChannelColor, 0.15), 1); } if (theme.newMessageSeparator) { diff --git a/web/sass-files/sass/partials/_base.scss b/web/sass-files/sass/partials/_base.scss index ad4a65c00..2fc63443e 100644 --- a/web/sass-files/sass/partials/_base.scss +++ b/web/sass-files/sass/partials/_base.scss @@ -85,6 +85,7 @@ img { a { word-break: break-word; color: $primary-color; + cursor: pointer; } a:focus, a:hover { @@ -121,6 +122,10 @@ a:focus, a:hover { } } +select { + -webkit-appearance: none; +} + .form-control { @include border-radius(2px); &:focus { diff --git a/web/sass-files/sass/partials/_headers.scss b/web/sass-files/sass/partials/_headers.scss index 69bc56841..51625afe0 100644 --- a/web/sass-files/sass/partials/_headers.scss +++ b/web/sass-files/sass/partials/_headers.scss @@ -54,9 +54,9 @@ } .channel-intro { - padding-bottom:5px; - margin: 0 1em 35px; - max-width: 850px; + margin: 0 auto 35px; + padding: 0 1em 5px; + max-width: 1000px; border-bottom: 1px solid lightgrey; .intro-links { margin: 0 1.5em 10px 0; @@ -216,7 +216,6 @@ font-size: 14px; line-height: 56px; #member_popover { - margin-right: 5px; width: 45px; color: #999; cursor: pointer; @@ -292,20 +291,21 @@ } .channel-header__links { - height: 32px; - width: 32px; - @include border-radius(50px); - border: 1px solid #ccc; + height: 30px; + width: 24px; + line-height: 26px; margin-right: 10px; + font-size: 22px; > a { - @include border-radius(50px); - height: 100%; - display: block; + color: inherit; + text-decoration: none; + @include opacity(0.6); @include single-transition(all, 0.1s, ease-in); - } - svg { - vertical-align: top; - margin: 7px 0 0 0px; - fill: inherit; + &:hover { + @include opacity(1); + } + &:focus { + color: inherit; + } } } diff --git a/web/sass-files/sass/partials/_markdown.scss b/web/sass-files/sass/partials/_markdown.scss index 8b0a32704..ea5ccd2d2 100644 --- a/web/sass-files/sass/partials/_markdown.scss +++ b/web/sass-files/sass/partials/_markdown.scss @@ -16,7 +16,7 @@ } } -.post-body { +.post__body { hr { height: 4px; padding: 0; diff --git a/web/sass-files/sass/partials/_navbar.scss b/web/sass-files/sass/partials/_navbar.scss index c06feffcf..c570c4663 100644 --- a/web/sass-files/sass/partials/_navbar.scss +++ b/web/sass-files/sass/partials/_navbar.scss @@ -33,6 +33,9 @@ background: #fff; width: 21px; } + .icon--white { + color: #fff; + } &:hover, &:active, &:focus { background: inherit; } diff --git a/web/sass-files/sass/partials/_post.scss b/web/sass-files/sass/partials/_post.scss index fad6f5074..99e985b0c 100644 --- a/web/sass-files/sass/partials/_post.scss +++ b/web/sass-files/sass/partials/_post.scss @@ -47,23 +47,23 @@ body.ios { .textarea-wrapper { position:relative; - .textbox-preview-area { - position: absolute; - z-index: 2; - top: 0; - left: 0; - box-shadow: none; - } + .textbox-preview-area { + position: absolute; + z-index: 2; + top: 0; + left: 0; + box-shadow: none; + } .textbox-preview-link, .textbox-help-link { - position: absolute; - z-index: 3; - bottom: -23px; + position: absolute; + z-index: 3; + bottom: -23px; font-size: 13px; - cursor: pointer; - } - .textbox-preview-link { - right: 45px; - } + cursor: pointer; + } + .textbox-preview-link { + right: 45px; + } .textbox-help-link { right: 0; } @@ -206,6 +206,7 @@ body.ios { @include flex(1 1 auto); position: relative; overflow-y: hidden; + .post-list-holder-by-time { background: #fff; overflow-y: scroll; @@ -224,31 +225,7 @@ body.ios { display: inline; } } - .post-list__table { - display: table; - table-layout: fixed; - width: 100%; - min-height: 100%; - height: 100%; - .post-list__content { - display: table-cell; - vertical-align: bottom; - div { - &:last-child { - .post { - .post-header { - .post-header-col.post-header__reply { - .dropdown-menu { - top: auto; - bottom: 25px; - } - } - } - } - } - } - } - } + .more-messages-text { margin-top: 2px; margin-bottom: 5px; @@ -269,13 +246,13 @@ body.ios { .post-create__container { form { width: 100%; - padding: 0 1em; - margin: 0; + padding: 0.5em 14px 0; + margin: 0 auto; + max-width: 1028px; } .post-create-body { - max-width: 850px; - padding: 0 0 2px; position: relative; + padding: 0 0 2px; .post-body__cell { vertical-align: top; position: relative; @@ -355,95 +332,277 @@ body.ios { } } +.post-list__table { + display: table; + table-layout: fixed; + width: 100%; + min-height: 100%; + height: 100%; + .post-list__content { + display: table-cell; + vertical-align: bottom; + > div:last-child { + .dropdown-menu { + top: auto; + bottom: 25px; + } + } + } +} + .post { word-wrap: break-word; - padding: 8px 1em; + padding: 8px 1em 0; position: relative; max-width: 100%; @include legacy-pie-clearfix; + &:hover { - .post-header .post-header-col.post-header__reply { - .dropdown, .comment-icon__container { - @include opacity(1); - } + .dropdown, .comment-icon__container { + visibility: visible; } - background: #f5f5f5; } - &.current--user { - .post-body { - @include border-radius(4px); - background: rgba(#000, 0.05); + + ul { + margin: 0; + padding: 0; + list-style: none; + } + + p { + margin: 0 0 1em; + line-height: 1.6em; + font-size: 0.97em; + white-space: pre-wrap; + + &:last-child { + margin-bottom: 0.5em; + } + + } + + span { + + p:last-child { + margin-bottom: 0.5em; + } + + } + + &.post--root { + + .comment-icon__container { + visibility: visible; } + } - &.post--comment { - &.other--root { - .post-comment { - border-left: 4px solid #EEE; - padding: 4px 0 6px 10px; - margin: 0 0 0 30px; - @include border-radius(0 4px 4px 0); + + &.same--root { + + &.same--user { + padding: 0 1em; + + &:hover { + + .post__time { + + &:before { + @include opacity(0.5); + } + + } + } - .post-body { - background: transparent; + + .post__header { margin: 0; - padding: 1px 0px; + height: 0; + + .col__name { + display: none; + } + + .col__reply { + top: 6px; + } + } - &.current--user { - .post-comment { - background: #f5f5f5; + + .post__time { + top: 24px; + } + + .post__time { + display: inline-block; + font: normal normal normal 14px/1 FontAwesome; + font-size: inherit; + text-rendering: auto; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; + font-size: 0; + position: absolute; + top: -3px; + left: 17px; + width: 30px; + height: 30px; + line-height: 37px; + + &:before { + @include opacity(0); + content: "\f017"; + content: "\f017"; + font-size: 19px; } + } + } - &.same--root { - .post-body { - @include border-radius(0 4px 4px 0); + + &.post--comment { + + .post__link { + display: none; } - .post-body { - border-left: 4px solid #EEE; - width: 570px; - margin-left: 30px; - padding-left: 10px; - .post-link { + + .post__img { + img { display: none; } } + + } + + &.post--comment { + .post__body { + border-left: 4px solid #ddd; + } } + } - &.same--root { + + &.other--root { + .comment-icon__container { - @include opacity(0); + + &.icon--show { + visibility: visible; + } + } - div.post-profile-img__container { - height: 1px; - .post-profile-img { - visibility: hidden; + + &.post--comment { + + .post__header { + + .col__reply { + top: 53px; + } + } + + } + + } + + .post__content { + margin: 0 auto; + position: relative; + max-width: 1000px; + display: table; + width: 100%; + table-layout: fixed; + + > div { + display: table-cell; + vertical-align: top; } - .post__content { - padding: 0; + + } + + .post__header { + margin-bottom: 2px; + + li { + display: inline-block; } - &.same--user { - .post__content { - padding-left: 46px; + + .col__name { + margin-right: 7px; + font-weight: 600; + } + + .col__reply { + position: absolute; + right: 0; + top: 30px; + width: 60px; + } + + } + + .post__img { + width: 46px; + img { + width: 36px; + height: 36px; + vertical-align: inherit; + @include border-radius(50px); + } + } + + .dropdown { + display: inline-block; + visibility: hidden; + top: -1px; + float: right; + + .dropdown-menu { + right: 0; + left: auto; + min-width: 130px; + padding: 2px 0; + + li { + display: block; + } - .post-header-post { - visibility: hidden; + + a { + padding: 5px 15px; } + } - } - p { - margin: 0 0 1em; - line-height: 1.6em; - font-size: 0.97em; - white-space: pre-wrap; + } - span { - p:last-child { - margin-bottom: 0.5em; + .post__dropdown { + &:after { + content: '[...]'; + top: -1px; + position: relative; } } + .post__body { + word-wrap: break-word; + padding: 0.2em 0.5em 0em; + @include legacy-pie-clearfix; + width: calc(100% - 70px); + } + + .post__link { + margin: 2px 0 5px; + font-size: 13px; + text-overflow: ellipsis; + overflow: hidden; + white-space: nowrap; + } + + .post__time { + font-size: 13px; + @include opacity(0.6); + } + .post-loading-gif { height:10px; width:10px; @@ -459,8 +618,14 @@ body.ios { } .comment-icon__container { - margin-left: 7px; fill: $primary-color; + display: inline-block; + visibility: hidden; + + &.icon--visible { + visibility: visible; + } + .comment-icon { display: inline-block; top: 3px; @@ -468,132 +633,13 @@ body.ios { margin-right: 3px; fill: inherit; } + path { fill: inherit; } + } - > div { - &.post-profile-img__container { - float: left; - .post-profile-img { - width: 36px; - height: 36px; - margin-right: 10px; - vertical-align: inherit; - @include border-radius(50px); - } - } - &.post__content { - padding-left: 46px; - max-width: 100%; - @include legacy-pie-clearfix; - } - } - .post-image__columns { - @include legacy-pie-clearfix; - padding-bottom: 5px; - } - .post-info--hidden { - display: none; - } - .post-body { - position: relative; - z-index: 1; - max-width: 100%; - width: 600px; - float: left; - word-wrap: break-word; - padding: 0.3em 0.5em 0.1em; - margin: -0.3em 0 0; - .post-link { - @include clearfix; - text-overflow: ellipsis; - white-space: nowrap; - cursor: pointer; - } - .post-body--code { - font-size: .97em; - position:relative; - .post-body--code__language { - position: absolute; - right: 0; - background: #fff; - cursor: default; - padding: 0.3em 0.5em 0.1em; - border-bottom-left-radius: 4px; - @include opacity(.3); - } - &.tex .katex-display { - text-align: left; - } - code { - white-space: pre; - } - } - } - .create-reply-form-wrap { - width: 100%; - margin-top: 5px; - form { - padding: 0; - } - .comment-btn { - display: none; - } - } - .post-header { - position: relative; - list-style-type: none; - margin: 0 0 1px; - padding-left: 0px; - &.post-header-post { - position: relative; - z-index: 1; - width: 200px; - text-align: right; - float: left; - padding-right: 15px; - } - &.post-info { - .post-profile-time { - vertical-align: top; - width: 150px; - max-width: 220px; - overflow: hidden; - display: block; - white-space: nowrap; - text-overflow: ellipsis; - margin: 0 0 0 50px; - } - } - .post-header-col { - vertical-align: top; - display: inline-block; - margin-right: 10px; - &.post-header__reply { - position: relative; - top: -1px; - min-width: 70px; - .dropdown-menu { - right: 0; - left: auto; - } - .dropdown { - min-width: 18px; - display: inline-block; - @include opacity(0); - } - .dropdown-toggle:after { - content: '[...]'; - } - } - } - .post-profile-time { - @include opacity(0.5); - } - } - .post-comment { - } + .web-embed-data { padding: 2px 0 0 10px; background: #f9f9f9; @@ -621,22 +667,6 @@ body.ios { display: none; } } - .msg-typing { - margin-top: 2px; - margin-left: 5px; - color: #a8adb7; - } - .post-grey { - color:lightgrey; - } - .post-reply { - clear: both; - width: 100%; - word-break: break-word; - .btn-file { - width: 40px; - } - } } .bot-indicator { diff --git a/web/sass-files/sass/partials/_post_right.scss b/web/sass-files/sass/partials/_post_right.scss index 54c3bcdf8..582b72c90 100644 --- a/web/sass-files/sass/partials/_post_right.scss +++ b/web/sass-files/sass/partials/_post_right.scss @@ -9,28 +9,31 @@ .post-right-comments-container { position: relative; - padding: 0; + padding: 0.7em 0 0; } .post { + &.post--root { - padding: 1em 1em 0; - margin: 0 0 1em; - width: 100%; - hr { - border-color: #DDD; - margin: 1em 0 0 0; - } + padding-bottom: 0; } - .post-header { - .post-profile-time { - width: 200px; - display: inline-block; - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; + + .post__header { + + .col__reply { + top: 0; } + } + + .post__body { + width: 100%; + } + + } + + hr { + margin-bottom: 0; } .post-create__container { diff --git a/web/sass-files/sass/partials/_responsive.scss b/web/sass-files/sass/partials/_responsive.scss index aad991035..00fa7d817 100644 --- a/web/sass-files/sass/partials/_responsive.scss +++ b/web/sass-files/sass/partials/_responsive.scss @@ -8,96 +8,10 @@ } } } - .post { - &.post--comment { - &.same--root { - margin-left: 104px; - padding-left: 10px; - border-left: 4px solid #EEE; - div.post-profile-img__container { - .post-profile-img { - display: none; - } - } - .post__content { - width: 825px; - margin-left: 0; - } - .post-body { - width: 736px; - border: none; - margin: 3px 0 0; - } - } - &.other--root { - .post-comment { - margin-left: 0; - } - } - &.same--root { - margin-top: 10px; - margin-bottom: 10px; - } - } - .post-body { - float: none; - width: 750px; - margin: 3px 0 0; - } - .post__content { - width: 920px; - } - .post-header { - &.post-header-post { - z-index: inherit; - width: auto; - float: none; - text-align: left; - padding-right: 0; - } - &.post-info { - display: none; - float: none; - } - .post-header-col { - &.post-header__reply { - float: right; - text-align: right; - .reply-link { - margin-right: 0; - } - .dropdown { - margin-left: 10px; - } - } - } - .post-info--hidden { - display: inline; - .post-info { - display: inline; - .tooltip { - margin-top: -25px; - margin-left: 40px; - } - .post-profile-time { - margin: 0; - } - } - } - } - } } } } @media screen and (max-width: 1440px) { - .post-create__container { - .post-create-body { - max-width: 810px; - } - } - .channel-intro { - max-width: 810px; - } .date-separator, .new-separator { &.hovered--comment { &:before, &:after { @@ -105,105 +19,6 @@ } } } - .post { - &.same--root.same--user { - .post-header-post { - visibility: hidden; - width: 100%; - position: relative; - top: -5px; - .post-header-col.post-header__name { - display: none; - } - } - .post-body { - top: -15px; - margin-bottom: -10px; - } - &:hover .post-header-post { - visibility: visible; - } - } - - &.post--comment { - &.other--root { - .post-comment { - margin-left: 0; - } - } - &.same--root { - margin-top: 5px; - margin-bottom: 5px; - margin-left: 104px; - padding-left: 10px; - border-left: 4px solid #EEE; - div.post-profile-img__container { - .post-profile-img { - display: none; - } - } - .post-body { - margin-left: 0; - border-left: 0; - } - &.same--user { - .post__content { - margin-left: 0; - padding-left: 0; - } - } - } - .post__content { - width: 810px; - } - .post-body { - width: 736px; - border: none; - margin: 3px 0 0; - } - } - .post__content { - width: 880px; - } - .post-header { - &.post-header-post { - z-index: inherit; - width: auto; - float: none; - text-align: left; - padding-right: 0; - } - &.post-info { - display: none; - float: none; - } - .post-header-col { - &.post-header__reply { - float: right; - margin: 0; - } - } - .post-info--hidden { - display: inline; - .post-info { - display: inline; - .tooltip { - margin-top: -25px; - margin-left: 40px; - } - .post-profile-time { - width: auto; - margin: 0; - } - } - } - } - .post-body { - margin: 3px 0 0; - float: none; - width: 750px; - } - } } @media screen and (max-width: 1140px) { @@ -232,79 +47,83 @@ } } } +} + +@media screen and (max-width: 960px) { + + .signup-team__container { + font-size: 1em; + } + .post { - .post__content { - width: 100%; + + &.same--root { + + &.same--user { + + .post__time { + display: none; + } + + } + } - .post-header { - .post-header-col { - &.post-header__reply { - .reply-link { - margin-right: 0; - } - .dropdown { - margin-left: 10px; + + .post-list__content & { + + &:hover { + background: transparent; + + .comment-icon__container { + visibility: hidden; + + &.icon--show { + visibility: visible; } + } + } + } - } -} -@media screen and (max-width: 960px) { - .post { - .post-header .post-header-col.post-header__reply { - .comment-icon__container__hide { - display: none; - } - .dropdown { - @include opacity(1); - } - .comment-icon__container__show { - @include opacity(1); + .dropdown { + visibility: visible; + } + + .post__dropdown { + line-height: 9px; + text-decoration: none; + width: 20px; + display: inline-block; + text-align: center; + height: 20px; + + &:after { + font-size: 20px; + content: '...' } + } - } - .signup-team__container { - font-size: 1em; - } - .post { - .post-header { - .post-header-col { - &.post-header__reply { - text-align: right; - display: inline-block; - } + + .post__img { + width: 40px; + + img { + width: 32px; + height: 32px; } } - } -} -@media (min-width: 992px){ - .modal-lg { - width: 700px; } -} -@media screen and (min-width: 768px) { - .second-bar { - display: none; + .post-image__column { + width: 200px; + height: 95px; } -} -@media screen and (max-height: 640px) { - .signup-team__container { - padding: 30px 0; - margin-bottom: 30px; - font-size: 0.9em; - .signup-team__name { - font-size: 2em; - } - } -} -@media screen and (max-width: 768px) { .textarea-wrapper { - .textbox-preview-link { + .textbox-preview-link, .textbox-help-link { display: none; } } @@ -385,35 +204,6 @@ } } } - .post { - &:hover { - background: none; - .post-header .post-header-col.post-header__reply { - .dropdown-toggle:after { - content: '...'; - } - } - } - &.post--comment { - &.same--root { - margin-left: 25px; - } - &.other--root { - margin-left: 0; - &:hover { - background: none; - } - } - } - .post-header .post-header-col.post-header__reply { - .dropdown-toggle:after { - content: '...'; - } - } - &.same--root.same--user .post__content{ - padding-left: 0; - } - } .signup-team__container { padding: 30px 0; margin-bottom: 30px; @@ -487,7 +277,8 @@ } .modal-header { display: block; - position: fixed; + position: absolute; + top: 0; width: 100%; z-index: 5; } @@ -613,6 +404,7 @@ #navbar { .navbar-default { .navbar-header { + float: none; margin: 0 -15px; .dropdown__icon { background: url("../images/dropdown-icon.png"); @@ -860,24 +652,6 @@ } } - .post { - .post-profile-img__container { - display: none; - } - &.post--comment { - &.other--root { - .post-comment { - margin-left: 11px; - } - } - } - > div { - &.post__content { - padding: 0; - } - } - } - .post-comments { padding: 9px 21px 10px 10px !important; } @@ -958,3 +732,27 @@ } } } + + +@media (min-width: 992px){ + .modal-lg { + width: 700px; + } +} + +@media screen and (min-width: 768px) { + .second-bar { + display: none; + } +} + +@media screen and (max-height: 640px) { + .signup-team__container { + padding: 30px 0; + margin-bottom: 30px; + font-size: 0.9em; + .signup-team__name { + font-size: 2em; + } + } +}
\ No newline at end of file diff --git a/web/sass-files/sass/partials/_search.scss b/web/sass-files/sass/partials/_search.scss index bedf35376..27b55f214 100644 --- a/web/sass-files/sass/partials/_search.scss +++ b/web/sass-files/sass/partials/_search.scss @@ -1,5 +1,5 @@ #channel-header .search-bar__container { - padding: 0 8px 0 0; + padding: 0 8px 0 3px; } .search-bar__container { padding: 12px 8px 0 0; diff --git a/web/sass-files/sass/partials/_sidebar--right.scss b/web/sass-files/sass/partials/_sidebar--right.scss index 2527eef28..43162831d 100644 --- a/web/sass-files/sass/partials/_sidebar--right.scss +++ b/web/sass-files/sass/partials/_sidebar--right.scss @@ -36,20 +36,6 @@ height: calc(100% - 56px); @include border-radius(2px 0 0 0); } - .post { - .post-header { - .post-header-col { - &.post-header__reply { - min-width: 30px; - text-align: right; - float: right; - } - } - } - .post-body { - margin: 3px 0 0; - } - } .sidebar__overlay { width: 100%; height: 100%; diff --git a/web/sass-files/sass/partials/_tooltips.scss b/web/sass-files/sass/partials/_tooltips.scss new file mode 100644 index 000000000..e018cf13c --- /dev/null +++ b/web/sass-files/sass/partials/_tooltips.scss @@ -0,0 +1,5 @@ +#recentMentionsTooltip { + .tooltip-arrow { + margin-left: 10px; + } +}
\ No newline at end of file diff --git a/web/sass-files/sass/styles.scss b/web/sass-files/sass/styles.scss index 5c83d5c5b..01f654eec 100644 --- a/web/sass-files/sass/styles.scss +++ b/web/sass-files/sass/styles.scss @@ -41,6 +41,9 @@ @import "partials/tutorial"; @import "partials/statistics"; +// Elements +@import "partials/tooltips"; + // Responsive Css @import "partials/responsive"; |