From 0258fcfa5c8da92351371169b66ce30462a34853 Mon Sep 17 00:00:00 2001 From: Asaad Mahmood Date: Mon, 16 May 2016 17:06:26 +0500 Subject: Adding compact layout (#2991) * Adding compact layout * Fixing ESLint error --- webapp/components/file_attachment.jsx | 53 ++++++--- webapp/components/file_attachment_list.jsx | 5 +- webapp/components/post.jsx | 18 +++- webapp/components/post_body.jsx | 9 +- webapp/components/post_header.jsx | 5 +- webapp/components/post_info.jsx | 4 +- webapp/components/posts_view.jsx | 11 +- webapp/components/time_since.jsx | 5 +- .../user_settings/user_settings_display.jsx | 118 ++++++++++++++++++++- webapp/i18n/en.json | 6 +- webapp/sass/components/_modal.scss | 4 +- webapp/sass/layout/_post.scss | 76 ++++++++++++- webapp/sass/responsive/_mobile.scss | 5 + webapp/sass/responsive/_tablet.scss | 114 ++++++++++++++++++++ webapp/utils/constants.jsx | 6 +- webapp/utils/utils.jsx | 2 +- 16 files changed, 409 insertions(+), 32 deletions(-) (limited to 'webapp') diff --git a/webapp/components/file_attachment.jsx b/webapp/components/file_attachment.jsx index c909b9afb..bbd42fc69 100644 --- a/webapp/components/file_attachment.jsx +++ b/webapp/components/file_attachment.jsx @@ -8,6 +8,7 @@ import Client from 'utils/web_client.jsx'; import Constants from 'utils/constants.jsx'; import {intlShape, injectIntl, defineMessages} from 'react-intl'; +import {Tooltip, OverlayTrigger} from 'react-bootstrap'; const holders = defineMessages({ download: { @@ -169,6 +170,42 @@ class FileAttachment extends React.Component { } else { trimmedFilename = filenameString; } + var filenameOverlay = ( + {this.props.intl.formatMessage(holders.download) + ' "' + filenameString + '"'}} + > + + {trimmedFilename} + + + ); + + if (this.props.compactDisplay) { + filenameOverlay = ( + {filenameString}} + > + this.props.handleImageClick(this.props.index)} + className='post-image__name' + rel='noopener noreferrer' + > + {trimmedFilename} + + + ); + } return (
- - {trimmedFilename} - + {filenameOverlay}
); } @@ -60,5 +61,7 @@ FileAttachmentList.propTypes = { channelId: React.PropTypes.string, // the user that owns the post that this is attached to - userId: React.PropTypes.string + userId: React.PropTypes.string, + + compactDisplay: React.PropTypes.bool }; diff --git a/webapp/components/post.jsx b/webapp/components/post.jsx index ae3fa9c98..de32568d1 100644 --- a/webapp/components/post.jsx +++ b/webapp/components/post.jsx @@ -103,6 +103,10 @@ export default class Post extends React.Component { return true; } + if (nextProps.compactDisplay !== this.props.compactDisplay) { + return true; + } + if (!Utils.areObjectsEqual(nextProps.user, this.props.user)) { return true; } @@ -188,7 +192,7 @@ export default class Post extends React.Component { } let profilePic = null; - if (!this.props.hideProfilePic) { + if (!this.props.hideProfilePic || this.props.compactDisplay) { profilePic = (
{profilePic}
@@ -231,6 +240,7 @@ export default class Post extends React.Component { sameUser={this.props.sameUser} user={this.props.user} currentUser={this.props.currentUser} + compactDisplay={this.props.compactDisplay} />
@@ -261,5 +272,6 @@ Post.propTypes = { displayNameType: React.PropTypes.string, hasProfiles: React.PropTypes.bool, currentUser: React.PropTypes.object.isRequired, - center: React.PropTypes.bool + center: React.PropTypes.bool, + compactDisplay: React.PropTypes.bool }; diff --git a/webapp/components/post_body.jsx b/webapp/components/post_body.jsx index 6c4e97d8e..ed0a133b3 100644 --- a/webapp/components/post_body.jsx +++ b/webapp/components/post_body.jsx @@ -24,6 +24,10 @@ export default class PostBody extends React.Component { return true; } + if (!Utils.areObjectsEqual(nextProps.compactDisplay, this.props.compactDisplay)) { + return true; + } + if (nextProps.retryPost.toString() !== this.props.retryPost.toString()) { return true; } @@ -136,9 +140,11 @@ export default class PostBody extends React.Component { if (filenames && filenames.length > 0) { fileAttachmentHolder = ( ); } @@ -189,5 +195,6 @@ PostBody.propTypes = { post: React.PropTypes.object.isRequired, parentPost: React.PropTypes.object, retryPost: React.PropTypes.func.isRequired, - handleCommentClick: React.PropTypes.func.isRequired + handleCommentClick: React.PropTypes.func.isRequired, + compactDisplay: React.PropTypes.bool }; diff --git a/webapp/components/post_header.jsx b/webapp/components/post_header.jsx index 9161d37f9..2b139471d 100644 --- a/webapp/components/post_header.jsx +++ b/webapp/components/post_header.jsx @@ -14,6 +14,7 @@ export default class PostHeader extends React.Component { super(props); this.state = {}; } + render() { const post = this.props.post; @@ -56,6 +57,7 @@ export default class PostHeader extends React.Component { isLastComment={this.props.isLastComment} sameUser={this.props.sameUser} currentUser={this.props.currentUser} + compactDisplay={this.props.compactDisplay} /> @@ -76,5 +78,6 @@ PostHeader.propTypes = { commentCount: React.PropTypes.number.isRequired, isLastComment: React.PropTypes.bool.isRequired, handleCommentClick: React.PropTypes.func.isRequired, - sameUser: React.PropTypes.bool.isRequired + sameUser: React.PropTypes.bool.isRequired, + compactDisplay: React.PropTypes.bool }; diff --git a/webapp/components/post_info.jsx b/webapp/components/post_info.jsx index 50b03c0be..f86c63fd7 100644 --- a/webapp/components/post_info.jsx +++ b/webapp/components/post_info.jsx @@ -219,6 +219,7 @@ export default class PostInfo extends React.Component {
  • @@ -250,5 +251,6 @@ PostInfo.propTypes = { allowReply: React.PropTypes.string.isRequired, handleCommentClick: React.PropTypes.func.isRequired, sameUser: React.PropTypes.bool.isRequired, - currentUser: React.PropTypes.object.isRequired + currentUser: React.PropTypes.object.isRequired, + compactDisplay: React.PropTypes.bool }; diff --git a/webapp/components/posts_view.jsx b/webapp/components/posts_view.jsx index cc9e738bc..74c249356 100644 --- a/webapp/components/posts_view.jsx +++ b/webapp/components/posts_view.jsx @@ -55,6 +55,7 @@ export default class PostsView extends React.Component { this.state = { displayNameType: PreferenceStore.get(Preferences.CATEGORY_DISPLAY_SETTINGS, 'name_format', 'false'), centerPosts: PreferenceStore.get(Preferences.CATEGORY_DISPLAY_SETTINGS, Preferences.CHANNEL_DISPLAY_MODE, Preferences.CHANNEL_DISPLAY_MODE_DEFAULT) === Preferences.CHANNEL_DISPLAY_MODE_CENTERED, + compactPosts: PreferenceStore.get(Preferences.CATEGORY_DISPLAY_SETTINGS, Preferences.MESSAGE_DISPLAY, Preferences.MESSAGE_DISPLAY_DEFAULT) === Preferences.MESSAGE_DISPLAY_COMPACT, isScrolling: false, topPostId: null, currentUser: UserStore.getCurrentUser(), @@ -79,7 +80,8 @@ export default class PostsView extends React.Component { updateState() { this.setState({ displayNameType: PreferenceStore.get(Preferences.CATEGORY_DISPLAY_SETTINGS, 'name_format', 'false'), - centerPosts: PreferenceStore.get(Preferences.CATEGORY_DISPLAY_SETTINGS, Preferences.CHANNEL_DISPLAY_MODE, Preferences.CHANNEL_DISPLAY_MODE_DEFAULT) === Preferences.CHANNEL_DISPLAY_MODE_CENTERED + centerPosts: PreferenceStore.get(Preferences.CATEGORY_DISPLAY_SETTINGS, Preferences.CHANNEL_DISPLAY_MODE, Preferences.CHANNEL_DISPLAY_MODE_DEFAULT) === Preferences.CHANNEL_DISPLAY_MODE_CENTERED, + compactPosts: PreferenceStore.get(Preferences.CATEGORY_DISPLAY_SETTINGS, Preferences.MESSAGE_DISPLAY, Preferences.MESSAGE_DISPLAY_DEFAULT) === Preferences.MESSAGE_DISPLAY_COMPACT }); } onUserChange() { @@ -274,6 +276,7 @@ export default class PostsView extends React.Component { user={profile} currentUser={this.state.currentUser} center={this.state.centerPosts} + compactDisplay={this.state.compactPosts} /> ); @@ -479,6 +482,9 @@ export default class PostsView extends React.Component { if (this.state.centerPosts !== nextState.centerPosts) { return true; } + if (this.state.compactPosts !== nextState.compactPosts) { + return true; + } if (!Utils.areObjectsEqual(this.state.profiles, nextState.profiles)) { return true; } @@ -592,7 +598,8 @@ PostsView.propTypes = { showMoreMessagesBottom: React.PropTypes.bool, channel: React.PropTypes.object, messageSeparatorTime: React.PropTypes.number, - postsToHighlight: React.PropTypes.object + postsToHighlight: React.PropTypes.object, + compactDisplay: React.PropTypes.bool }; function ScrollToBottomArrows({isScrolling, atBottom, onClick}) { diff --git a/webapp/components/time_since.jsx b/webapp/components/time_since.jsx index f715193e2..50a0f7d04 100644 --- a/webapp/components/time_since.jsx +++ b/webapp/components/time_since.jsx @@ -26,7 +26,7 @@ export default class TimeSince extends React.Component { clearInterval(this.intervalId); } render() { - if (this.props.sameUser) { + if (this.props.sameUser || this.props.compactDisplay) { return (
  • @@ -601,6 +711,8 @@ export default class UserSettingsDisplay extends React.Component {
    {nameFormatSection}
    + {messageDisplaySection} +
    {channelDisplayModeSection}
    {languagesSection} diff --git a/webapp/i18n/en.json b/webapp/i18n/en.json index 7e46903db..748a1a657 100644 --- a/webapp/i18n/en.json +++ b/webapp/i18n/en.json @@ -1288,9 +1288,13 @@ "user.settings.developer.thirdParty": "Open to register a new third-party application", "user.settings.developer.title": "Developer Settings", "user.settings.display.channelDisplayTitle": "Channel Display Mode", - "user.settings.display.channeldisplaymode": "Select how text in a channel is displayed.", + "user.settings.display.channeldisplaymode": "Select the width of the center channel.", "user.settings.display.clockDisplay": "Clock Display", "user.settings.display.fixedWidthCentered": "Fixed width, centered", + "user.settings.display.messageDisplayTitle": "Message Display", + "user.settings.display.messageDisplayDescription": "Select how messages in a channel should be displayed.", + "user.settings.display.messageDisplayClean": "Clean", + "user.settings.display.messageDisplayCompact": "Compact", "user.settings.display.fontDesc": "Select the font displayed in the Mattermost user interface.", "user.settings.display.fontTitle": "Display Font", "user.settings.display.fullScreen": "Full width", diff --git a/webapp/sass/components/_modal.scss b/webapp/sass/components/_modal.scss index d53be29dc..3d3a11de0 100644 --- a/webapp/sass/components/_modal.scss +++ b/webapp/sass/components/_modal.scss @@ -448,7 +448,7 @@ @include opacity(.8); float: right; margin-right: 3px; - margin-top: 12px; + margin-top: 8px; } .member-select__container { @@ -459,7 +459,7 @@ select { @include opacity(.8); float: right; - margin: 5px 5px 0 2px; + margin: 1px 5px 0 2px; width: auto; } } diff --git a/webapp/sass/layout/_post.scss b/webapp/sass/layout/_post.scss index a99c6d57c..bfefd08ee 100644 --- a/webapp/sass/layout/_post.scss +++ b/webapp/sass/layout/_post.scss @@ -417,7 +417,8 @@ body.ios { .post-create-footer { @include clearfix; font-size: 13px; - padding: 3px 0 0 0; + padding: 3px 0 0; + .control-label { font-weight: normal; margin-bottom: 0; @@ -482,6 +483,79 @@ body.ios { background-color: beige; } + &.post--compact { + + .markdown__heading { + font-size: 1em; + margin: 0 0 7px; + } + + .post__body { + background: transparent !important; + margin-top: -1px; + padding: 3px 0; + } + + .post-image__columns { + clear: both; + } + + .post-image__column { + @include border-radius(2px); + font-size: .9em; + height: 26px; + line-height: 25px; + padding: 0 7px; + + .post-image__thumbnail { + display: none; + } + + .post-image__details { + background: transparent; + border: none; + padding: 0; + width: 100%; + + > div { + display: none; + } + } + + .post-image__name { + @include clearfix; + display: block; + margin: 0; + padding-right: 10px; + text-overflow: ellipsis; + white-space: nowrap; + + i { + font-size: .9em; + margin-right: 5px; + opacity: .5; + } + } + + a { + &:hover { + text-decoration: none; + } + } + } + + .post__img { + padding-top: 3px; + width: 28px; + + img, + svg { + height: 20px; + width: 20px; + } + } + } + p { font-size: .97em; line-height: 1.6em; diff --git a/webapp/sass/responsive/_mobile.scss b/webapp/sass/responsive/_mobile.scss index cc3d7a4b9..9af77d4f1 100644 --- a/webapp/sass/responsive/_mobile.scss +++ b/webapp/sass/responsive/_mobile.scss @@ -45,6 +45,11 @@ } .post { + &.post--compact { + + + } + .post__dropdown { display: inline-block; height: 20px; diff --git a/webapp/sass/responsive/_tablet.scss b/webapp/sass/responsive/_tablet.scss index 72b4b5aad..f5e341b25 100644 --- a/webapp/sass/responsive/_tablet.scss +++ b/webapp/sass/responsive/_tablet.scss @@ -65,6 +65,7 @@ } } +// Tablet and desktop @media screen and (min-width: 768px) { .second-bar { display: none; @@ -83,6 +84,111 @@ } .post { + &.post--compact { + padding: 5px .5em 0 80px; + + .post__link { + margin: 4px 0 7px; + } + + .post__time { + font-size: .85em; + left: -70px; + position: absolute; + top: 2px; + } + + span { + p { + &:last-child { + margin-bottom: .3em; + } + } + } + + .post__header { + float: left; + height: 18px; + padding-top: 3px; + + .col__name { + font-weight: bold; + } + + .col__reply { + top: 2px; + } + } + + &.other--root { + .post__body { + > div { + &:first-child { + min-height: 21px; + } + } + } + + .post__link + .post__body { + clear: both; + } + + &.post--comment { + .post__header { + .col__reply { + top: 0; + } + } + } + } + + .post-code { + clear: both; + } + + &.same--root { + &.same--user { + padding-left: 80px; + + .post__img { + img { + display: none; + } + } + } + + &.post--comment { + padding-top: 1px; + + .post__img { + img { + display: inline-block; + } + } + + &.same--user { + .post__img { + img { + display: none; + } + } + } + + .post__header { + margin-left: 12px; + } + } + } + + .post__body { + width: 100%; + } + + .post__content { + padding-right: 85px; + } + } + &.same--root { &.same--user { .post__time { @@ -94,6 +200,14 @@ text-rendering: auto; top: -2px; } + + &.post--compact { + .post__time { + font-size: .85em; + left: -70px; + top: -5px; + } + } } } } diff --git a/webapp/utils/constants.jsx b/webapp/utils/constants.jsx index fc5b917d3..e5d927ec1 100644 --- a/webapp/utils/constants.jsx +++ b/webapp/utils/constants.jsx @@ -531,7 +531,11 @@ export default { CHANNEL_DISPLAY_MODE: 'channel_display_mode', CHANNEL_DISPLAY_MODE_CENTERED: 'centered', CHANNEL_DISPLAY_MODE_FULL_SCREEN: 'full', - CHANNEL_DISPLAY_MODE_DEFAULT: 'centered' + CHANNEL_DISPLAY_MODE_DEFAULT: 'centered', + MESSAGE_DISPLAY: 'message_display', + MESSAGE_DISPLAY_CLEAN: 'clean', + MESSAGE_DISPLAY_COMPACT: 'compact', + MESSAGE_DISPLAY_DEFAULT: 'clean' }, TutorialSteps: { INTRO_SCREENS: 0, diff --git a/webapp/utils/utils.jsx b/webapp/utils/utils.jsx index 1f52bb451..596b1ae06 100644 --- a/webapp/utils/utils.jsx +++ b/webapp/utils/utils.jsx @@ -734,7 +734,7 @@ export function applyTheme(theme) { changeCss('.app__body .scrollbar--horizontal, .app__body .scrollbar--vertical', 'background:' + changeOpacity(theme.centerChannelColor, 0.5), 2); changeCss('.app__body .post-list__new-messages-below', 'background:' + changeColor(theme.centerChannelColor, 0.5), 2); changeCss('.app__body .post.post--comment .post__body', 'border-color:' + changeOpacity(theme.centerChannelColor, 0.2), 1); - changeCss('.app__body .post.post--comment.current--user .post__body', 'border-color:' + changeOpacity(theme.centerChannelColor, 0.13), 1); + changeCss('.app__body .post.post--comment.current--user .post__body', 'border-color:' + changeOpacity(theme.centerChannelColor, 0.2), 1); } if (theme.newMessageSeparator) { -- cgit v1.2.3-1-g7c22