summaryrefslogtreecommitdiffstats
path: root/webapp/components
diff options
context:
space:
mode:
authorAsaad Mahmood <asaadmahmoodspin@users.noreply.github.com>2016-05-16 17:06:26 +0500
committerChristopher Speller <crspeller@gmail.com>2016-05-16 08:06:26 -0400
commit0258fcfa5c8da92351371169b66ce30462a34853 (patch)
treed69803cff43a633202b877738e514867f4424e0c /webapp/components
parent565b111234f5566da632533109e1b4f4044e7116 (diff)
downloadchat-0258fcfa5c8da92351371169b66ce30462a34853.tar.gz
chat-0258fcfa5c8da92351371169b66ce30462a34853.tar.bz2
chat-0258fcfa5c8da92351371169b66ce30462a34853.zip
Adding compact layout (#2991)
* Adding compact layout * Fixing ESLint error
Diffstat (limited to 'webapp/components')
-rw-r--r--webapp/components/file_attachment.jsx53
-rw-r--r--webapp/components/file_attachment_list.jsx5
-rw-r--r--webapp/components/post.jsx18
-rw-r--r--webapp/components/post_body.jsx9
-rw-r--r--webapp/components/post_header.jsx5
-rw-r--r--webapp/components/post_info.jsx4
-rw-r--r--webapp/components/posts_view.jsx11
-rw-r--r--webapp/components/time_since.jsx5
-rw-r--r--webapp/components/user_settings/user_settings_display.jsx118
9 files changed, 202 insertions, 26 deletions
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 = (
+ <OverlayTrigger
+ delayShow={1000}
+ placement='top'
+ overlay={<Tooltip id='file-name__tooltip'>{this.props.intl.formatMessage(holders.download) + ' "' + filenameString + '"'}</Tooltip>}
+ >
+ <a
+ href={fileUrl}
+ download={filenameString}
+ className='post-image__name'
+ target='_blank'
+ rel='noopener noreferrer'
+ >
+ {trimmedFilename}
+ </a>
+ </OverlayTrigger>
+ );
+
+ if (this.props.compactDisplay) {
+ filenameOverlay = (
+ <OverlayTrigger
+ delayShow={1000}
+ placement='top'
+ overlay={<Tooltip id='file-name__tooltip'>{filenameString}</Tooltip>}
+ >
+ <a
+ href='#'
+ onClick={() => this.props.handleImageClick(this.props.index)}
+ className='post-image__name'
+ rel='noopener noreferrer'
+ >
+ <i className='glyphicon glyphicon-paperclip'/>{trimmedFilename}
+ </a>
+ </OverlayTrigger>
+ );
+ }
return (
<div
@@ -183,17 +220,7 @@ class FileAttachment extends React.Component {
{thumbnail}
</a>
<div className='post-image__details'>
- <a
- href={fileUrl}
- download={filenameString}
- data-toggle='tooltip'
- title={this.props.intl.formatMessage(holders.download) + ' "' + filenameString + '"'}
- className='post-image__name'
- target='_blank'
- rel='noopener noreferrer'
- >
- {trimmedFilename}
- </a>
+ {filenameOverlay}
<div>
<a
href={fileUrl}
@@ -225,7 +252,9 @@ FileAttachment.propTypes = {
index: React.PropTypes.number.isRequired,
// handler for when the thumbnail is clicked passed the index above
- handleImageClick: React.PropTypes.func
+ handleImageClick: React.PropTypes.func,
+
+ compactDisplay: React.PropTypes.bool
};
export default injectIntl(FileAttachment);
diff --git a/webapp/components/file_attachment_list.jsx b/webapp/components/file_attachment_list.jsx
index 59fd56bc3..e4b841769 100644
--- a/webapp/components/file_attachment_list.jsx
+++ b/webapp/components/file_attachment_list.jsx
@@ -29,6 +29,7 @@ export default class FileAttachmentList extends React.Component {
filename={filenames[i]}
index={i}
handleImageClick={this.handleImageClick}
+ compactDisplay={this.props.compactDisplay}
/>
);
}
@@ -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 = (
<img
src={Utils.getProfilePicSrcForPost(post, timestamp)}
@@ -212,11 +216,16 @@ export default class Post extends React.Component {
centerClass = 'center';
}
+ let compactClass = '';
+ if (this.props.compactDisplay) {
+ compactClass = 'post--compact';
+ }
+
return (
<div>
<div
id={'post_' + post.id}
- className={'post ' + sameUserClass + ' ' + rootUser + ' ' + postType + ' ' + currentUserCss + ' ' + shouldHighlightClass + ' ' + systemMessageClass}
+ className={'post ' + sameUserClass + ' ' + compactClass + ' ' + rootUser + ' ' + postType + ' ' + currentUserCss + ' ' + shouldHighlightClass + ' ' + systemMessageClass}
>
<div className={'post__content ' + centerClass}>
<div className='post__img'>{profilePic}</div>
@@ -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}
/>
<PostBody
post={post}
@@ -239,6 +249,7 @@ export default class Post extends React.Component {
posts={posts}
handleCommentClick={this.handleCommentClick}
retryPost={this.retryPost}
+ compactDisplay={this.props.compactDisplay}
/>
</div>
</div>
@@ -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 = (
<FileAttachmentList
+
filenames={filenames}
channelId={post.channel_id}
userId={post.user_id}
+ compactDisplay={this.props.compactDisplay}
/>
);
}
@@ -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}
/>
</li>
</ul>
@@ -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 {
<TimeSince
eventTime={post.create_at}
sameUser={this.props.sameUser}
+ compactDisplay={this.props.compactDisplay}
/>
</li>
<li className='col col__reply'>
@@ -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 (
<time className='post__time'>
{Utils.displayTimeFormatted(this.props.eventTime)}
@@ -69,5 +69,6 @@ TimeSince.defaultProps = {
TimeSince.propTypes = {
eventTime: React.PropTypes.number.isRequired,
- sameUser: React.PropTypes.bool
+ sameUser: React.PropTypes.bool,
+ compactDisplay: React.PropTypes.bool
};
diff --git a/webapp/components/user_settings/user_settings_display.jsx b/webapp/components/user_settings/user_settings_display.jsx
index c4af57d4c..fa0118d1e 100644
--- a/webapp/components/user_settings/user_settings_display.jsx
+++ b/webapp/components/user_settings/user_settings_display.jsx
@@ -23,7 +23,8 @@ function getDisplayStateFromStores() {
militaryTime: PreferenceStore.get(Preferences.CATEGORY_DISPLAY_SETTINGS, 'use_military_time', 'false'),
nameFormat: PreferenceStore.get(Preferences.CATEGORY_DISPLAY_SETTINGS, 'name_format', 'username'),
selectedFont: PreferenceStore.get(Preferences.CATEGORY_DISPLAY_SETTINGS, 'selected_font', Constants.DEFAULT_FONT),
- channelDisplayMode: PreferenceStore.get(Preferences.CATEGORY_DISPLAY_SETTINGS, Preferences.CHANNEL_DISPLAY_MODE, Preferences.CHANNEL_DISPLAY_MODE_DEFAULT)
+ channelDisplayMode: PreferenceStore.get(Preferences.CATEGORY_DISPLAY_SETTINGS, Preferences.CHANNEL_DISPLAY_MODE, Preferences.CHANNEL_DISPLAY_MODE_DEFAULT),
+ messageDisplay: PreferenceStore.get(Preferences.CATEGORY_DISPLAY_SETTINGS, Preferences.MESSAGE_DISPLAY, Preferences.MESSAGE_DISPLAY_DEFAULT)
};
}
@@ -70,8 +71,14 @@ export default class UserSettingsDisplay extends React.Component {
name: Preferences.CHANNEL_DISPLAY_MODE,
value: this.state.channelDisplayMode
};
+ const messageDisplayPreference = {
+ user_id: userId,
+ category: Preferences.CATEGORY_DISPLAY_SETTINGS,
+ name: Preferences.MESSAGE_DISPLAY,
+ value: this.state.messageDisplay
+ };
- AsyncClient.savePreferences([timePreference, namePreference, fontPreference, channelDisplayModePreference],
+ AsyncClient.savePreferences([timePreference, namePreference, fontPreference, channelDisplayModePreference, messageDisplayPreference],
() => {
this.updateSection('');
},
@@ -89,6 +96,9 @@ export default class UserSettingsDisplay extends React.Component {
handleChannelDisplayModeRadio(channelDisplayMode) {
this.setState({channelDisplayMode});
}
+ handlemessageDisplayRadio(messageDisplay) {
+ this.setState({messageDisplay});
+ }
handleFont(selectedFont) {
Utils.applyFont(selectedFont);
this.setState({selectedFont});
@@ -115,6 +125,7 @@ export default class UserSettingsDisplay extends React.Component {
let channelDisplayModeSection;
let fontSection;
let languagesSection;
+ let messageDisplaySection;
if (this.props.activeSection === 'clock') {
const clockFormat = [false, false];
@@ -350,6 +361,105 @@ export default class UserSettingsDisplay extends React.Component {
);
}
+ if (this.props.activeSection === Preferences.MESSAGE_DISPLAY) {
+ const messageDisplay = [false, false];
+ if (this.state.messageDisplay === Preferences.MESSAGE_DISPLAY_CLEAN) {
+ messageDisplay[0] = true;
+ } else {
+ messageDisplay[1] = true;
+ }
+
+ const inputs = [
+ <div key='userDisplayNameOptions'>
+ <div className='radio'>
+ <label>
+ <input
+ type='radio'
+ checked={messageDisplay[0]}
+ onChange={this.handlemessageDisplayRadio.bind(this, Preferences.MESSAGE_DISPLAY_CLEAN)}
+ />
+ <FormattedMessage
+ id='user.settings.display.messageDisplayClean'
+ defaultMessage='Clean'
+ />
+ </label>
+ <br/>
+ </div>
+ <div className='radio'>
+ <label>
+ <input
+ type='radio'
+ checked={messageDisplay[1]}
+ onChange={this.handlemessageDisplayRadio.bind(this, Preferences.MESSAGE_DISPLAY_COMPACT)}
+ />
+ <FormattedMessage
+ id='user.settings.display.messageDisplayCompact'
+ defaultMessage='Compact'
+ />
+ </label>
+ <br/>
+ </div>
+ <div>
+ <br/>
+ <FormattedMessage
+ id='user.settings.display.messageDisplayDescription'
+ defaultMessage='Select how messages in a channel should be displayed.'
+ />
+ </div>
+ </div>
+ ];
+
+ messageDisplaySection = (
+ <SettingItemMax
+ title={
+ <FormattedMessage
+ id='user.settings.display.messageDisplayTitle'
+ defaultMessage='Message Display'
+ />
+ }
+ inputs={inputs}
+ submit={this.handleSubmit}
+ server_error={serverError}
+ updateSection={(e) => {
+ this.updateSection('');
+ e.preventDefault();
+ }}
+ />
+ );
+ } else {
+ let describe;
+ if (this.state.messageDisplay === Preferences.MESSAGE_DISPLAY_CLEAN) {
+ describe = (
+ <FormattedMessage
+ id='user.settings.display.messageDisplayClean'
+ defaultMessage='Clean'
+ />
+ );
+ } else {
+ describe = (
+ <FormattedMessage
+ id='user.settings.display.messageDisplayCompact'
+ defaultMessage='Compact'
+ />
+ );
+ }
+
+ messageDisplaySection = (
+ <SettingItemMin
+ title={
+ <FormattedMessage
+ id='user.settings.display.messageDisplayTitle'
+ defaultMessage='Message Display'
+ />
+ }
+ describe={describe}
+ updateSection={() => {
+ this.props.updateSection(Preferences.MESSAGE_DISPLAY);
+ }}
+ />
+ );
+ }
+
if (this.props.activeSection === Preferences.CHANNEL_DISPLAY_MODE) {
const channelDisplayMode = [false, false];
if (this.state.channelDisplayMode === Preferences.CHANNEL_DISPLAY_MODE_CENTERED) {
@@ -392,7 +502,7 @@ export default class UserSettingsDisplay extends React.Component {
<br/>
<FormattedMessage
id='user.settings.display.channeldisplaymode'
- defaultMessage='Select how text in a channel is displayed.'
+ defaultMessage='Select the width of the center channel.'
/>
</div>
</div>
@@ -601,6 +711,8 @@ export default class UserSettingsDisplay extends React.Component {
<div className='divider-dark'/>
{nameFormatSection}
<div className='divider-dark'/>
+ {messageDisplaySection}
+ <div className='divider-dark'/>
{channelDisplayModeSection}
<div className='divider-dark'/>
{languagesSection}