diff --git a/webapp/components/file_attachment.jsx b/webapp/components/file_attachment.jsx
index c909b9afb6..bbd42fc694 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 ae3fa9c981..de32568d18 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 6c4e97d8e9..ed0a133b37 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 9161d37f98..2b139471db 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 50b03c0be2..f86c63fd78 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 cc9e738bc4..74c2493564 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 f715193e2b..50a0f7d04e 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 7e46903db4..748a1a6576 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 d53be29dc9..3d3a11de00 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 a99c6d57c4..bfefd08eef 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 cc3d7a4b9f..9af77d4f10 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 72b4b5aad5..f5e341b25e 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 fc5b917d3c..e5d927ec10 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 1f52bb4519..596b1ae065 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) {