summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--README.md10
-rw-r--r--api/post.go2
-rw-r--r--api/templates/error.html2
-rw-r--r--model/user.go2
-rw-r--r--web/react/components/channel_notifications.jsx6
-rw-r--r--web/react/components/get_link_modal.jsx2
-rw-r--r--web/react/components/more_direct_channels.jsx2
-rw-r--r--web/react/components/post.jsx18
-rw-r--r--web/react/components/post_list.jsx109
-rw-r--r--web/react/components/post_right.jsx20
-rw-r--r--web/react/components/search_results.jsx8
-rw-r--r--web/react/components/sidebar.jsx11
-rw-r--r--web/react/components/team_settings.jsx7
-rw-r--r--web/react/components/user_settings.jsx19
-rw-r--r--web/react/utils/utils.jsx20
-rw-r--r--web/sass-files/sass/partials/_base.scss22
-rw-r--r--web/sass-files/sass/partials/_headers.scss4
-rw-r--r--web/sass-files/sass/partials/_loading.scss68
-rw-r--r--web/sass-files/sass/partials/_mentions.scss2
-rw-r--r--web/sass-files/sass/partials/_modal.scss7
-rw-r--r--web/sass-files/sass/partials/_post.scss16
-rw-r--r--web/sass-files/sass/partials/_responsive.scss21
-rw-r--r--web/sass-files/sass/partials/_search.scss2
-rw-r--r--web/sass-files/sass/partials/_settings.scss4
-rw-r--r--web/sass-files/sass/partials/_sidebar--left.scss3
-rw-r--r--web/sass-files/sass/styles.scss1
-rw-r--r--web/templates/channel.html2
-rw-r--r--web/templates/find_team.html1
-rw-r--r--web/templates/head.html2
-rw-r--r--web/templates/home.html1
-rw-r--r--web/templates/login.html1
-rw-r--r--web/templates/password_reset.html1
-rw-r--r--web/templates/signup_team.html1
-rw-r--r--web/templates/signup_team_complete.html1
-rw-r--r--web/templates/signup_team_confirm.html1
-rw-r--r--web/templates/signup_user_complete.html1
-rw-r--r--web/templates/verify.html1
-rw-r--r--web/templates/welcome.html1
38 files changed, 283 insertions, 119 deletions
diff --git a/README.md b/README.md
index 08d2f4210..b12581444 100644
--- a/README.md
+++ b/README.md
@@ -10,13 +10,21 @@ Mattermost is a team communication service. It brings team messaging and file sh
We built Mattermost to help teams focus on what matters most to them. It works for us, we hope it works for you too.
+Learn More
+==========
+<ul>
+<li/>Ask the core team anything at: http://forum.mattermost.org</li>
+<li/>Share feature requests and upvotes: http://www.mattermost.org/feature-requests/</li>
+<li/>File bugs: http://www.mattermost.org/filing-issues/</li>
+<li/>Make a pull request: http://www.mattermost.org/contribute-to-mattermost/</li>
+</ul>
Installing the Mattermost
=========================
You're installing "Mattermost Preview", a pre-released 0.50 version intended for an early look at what we're building. While SpinPunch runs this version internally, it's not recommended for production deployments since we can't guarantee API stability or backwards compatibility until our 1.0 version release.
-That said, any issues at all, please let us know on the Mattermost forum at: http://discourse.mattermost.org
+That said, any issues at all, please let us know on the Mattermost forum at: http://forum.mattermost.org
Local Machine Setup (Docker)
-----------------------------
diff --git a/api/post.go b/api/post.go
index 2d812e8de..650f47062 100644
--- a/api/post.go
+++ b/api/post.go
@@ -227,7 +227,7 @@ func fireAndForgetNotifications(post *model.Post, teamId, teamUrl string) {
channel = result.Data.(*model.Channel)
if channel.Type == model.CHANNEL_DIRECT {
bodyText = "You have one new message."
- subjectText = "New Direct Message"
+ subjectText = "New Private Message"
} else {
bodyText = "You have one new mention."
subjectText = "New Mention"
diff --git a/api/templates/error.html b/api/templates/error.html
index ab4d91378..f38bb81a1 100644
--- a/api/templates/error.html
+++ b/api/templates/error.html
@@ -5,7 +5,7 @@
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.1/css/bootstrap.min.css">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.1/js/bootstrap.min.js"></script>
- <link href='https://fonts.googleapis.com/css?family=Lato:400,700,900' rel='stylesheet' type='text/css'>
+ <link href='http://fonts.googleapis.com/css?family=Open+Sans:400,600,700' rel='stylesheet' type='text/css'>
<link rel="stylesheet" href="/static/css/styles.css">
</head>
<body class="white error">
diff --git a/model/user.go b/model/user.go
index 18fbb0d2a..c516fae78 100644
--- a/model/user.go
+++ b/model/user.go
@@ -16,7 +16,7 @@ const (
ROLE_SYSTEM_ADMIN = "system_admin"
ROLE_SYSTEM_SUPPORT = "system_support"
USER_AWAY_TIMEOUT = 5 * 60 * 1000 // 5 minutes
- USER_OFFLINE_TIMEOUT = 5 * 60 * 1000 // 5 minutes
+ USER_OFFLINE_TIMEOUT = 1 * 60 * 1000 // 1 minute
USER_OFFLINE = "offline"
USER_AWAY = "away"
USER_ONLINE = "online"
diff --git a/web/react/components/channel_notifications.jsx b/web/react/components/channel_notifications.jsx
index fa9ab42ae..638d16576 100644
--- a/web/react/components/channel_notifications.jsx
+++ b/web/react/components/channel_notifications.jsx
@@ -97,7 +97,7 @@ module.exports = React.createClass({
var inputs = [];
inputs.push(
- <div className="col-sm-12">
+ <div>
<div className="radio">
<label>
<input type="radio" checked={notifyActive[0]} onClick={function(){self.handleRadioClick("all")}}>For all activity</input>
@@ -158,7 +158,7 @@ module.exports = React.createClass({
var inputs = [];
inputs.push(
- <div className="col-sm-12">
+ <div>
<div className="btn-group" data-toggle="buttons-radio">
<button className={"btn btn-default "+quietActive[0]} onClick={function(){self.handleQuietToggle(true)}}>On</button>
<button className={"btn btn-default "+quietActive[1]} onClick={function(){self.handleQuietToggle(false)}}>Off</button>
@@ -167,7 +167,7 @@ module.exports = React.createClass({
);
inputs.push(
- <div className="col-sm-12">
+ <div>
<br/>
Enabling quiet mode will turn off desktop notifications and only mark the channel as unread if you have been mentioned.
</div>
diff --git a/web/react/components/get_link_modal.jsx b/web/react/components/get_link_modal.jsx
index 334591ee3..69e565185 100644
--- a/web/react/components/get_link_modal.jsx
+++ b/web/react/components/get_link_modal.jsx
@@ -42,7 +42,7 @@ module.exports = React.createClass({
</div>
<div className="modal-footer">
<button type="button" className="btn btn-default" data-dismiss="modal">Close</button>
- <button data-copy-btn type="button" className="btn btn-primary" data-clipboard-text={this.state.value}>Copy Link</button>
+ <button data-copy-btn type="button" className="btn btn-primary pull-left" data-clipboard-text={this.state.value}>Copy Link</button>
</div>
</div>
</div>
diff --git a/web/react/components/more_direct_channels.jsx b/web/react/components/more_direct_channels.jsx
index 2785dc8e0..182d8884d 100644
--- a/web/react/components/more_direct_channels.jsx
+++ b/web/react/components/more_direct_channels.jsx
@@ -49,7 +49,7 @@ module.exports = React.createClass({
<span aria-hidden="true">&times;</span>
<span className="sr-only">Close</span>
</button>
- <h4 className="modal-title">More Direct Messages</h4>
+ <h4 className="modal-title">More Private Messages</h4>
</div>
<div className="modal-body">
<ul className="nav nav-pills nav-stacked">
diff --git a/web/react/components/post.jsx b/web/react/components/post.jsx
index afe978495..04b5ba082 100644
--- a/web/react/components/post.jsx
+++ b/web/react/components/post.jsx
@@ -6,13 +6,14 @@ var PostBody = require('./post_body.jsx');
var PostInfo = require('./post_info.jsx');
var AppDispatcher = require('../dispatcher/app_dispatcher.jsx');
var Constants = require('../utils/constants.jsx');
+var UserStore = require('../stores/user_store.jsx');
var ActionTypes = Constants.ActionTypes;
module.exports = React.createClass({
componentDidMount: function() {
- $('.edit-modal').on('show.bs.modal', function () {
- $('.edit-modal .edit-modal-body').css('overflow-y', 'auto');
- $('.edit-modal .edit-modal-body').css('max-height', $(window).height() * 0.7);
+ $('.modal').on('show.bs.modal', function () {
+ $('.modal-body').css('overflow-y', 'auto');
+ $('.modal-body').css('max-height', $(window).height() * 0.7);
});
},
handleCommentClick: function(e) {
@@ -56,7 +57,7 @@ module.exports = React.createClass({
var error = this.state.error ? <div className='form-group has-error'><label className='control-label'>{ this.state.error }</label></div> : null;
- if(this.props.sameRoot){
+ if (this.props.sameRoot){
rootUser = "same--root";
}
else {
@@ -64,13 +65,18 @@ module.exports = React.createClass({
}
var postType = "";
- if(type != "Post"){
+ if (type != "Post"){
postType = "post--comment";
}
+ var currentUserCss = "";
+ if (UserStore.getCurrentId() === post.user_id) {
+ currentUserCss = "current--user";
+ }
+
return (
<div>
- <div id={post.id} className={"post " + this.props.sameUser + " " + rootUser + " " + postType}>
+ <div id={post.id} className={"post " + this.props.sameUser + " " + rootUser + " " + postType + " " + currentUserCss}>
{ !this.props.hideProfilePic ?
<div className="post-profile-img__container">
<img className="post-profile-img" src={"/api/v1/users/" + post.user_id + "/image"} height="36" width="36" />
diff --git a/web/react/components/post_list.jsx b/web/react/components/post_list.jsx
index e37de8d88..169efc766 100644
--- a/web/react/components/post_list.jsx
+++ b/web/react/components/post_list.jsx
@@ -295,7 +295,7 @@ module.exports = React.createClass({
},
render: function() {
var order = [];
- var posts = {};
+ var posts;
var last_viewed = Number.MAX_VALUE;
@@ -324,13 +324,7 @@ module.exports = React.createClass({
if (order.length > 0 && order.length % Constants.POST_CHUNK_SIZE === 0) {
more_messages = <a ref="loadmore" className="more-messages-text theme" href="#" onClick={this.getMorePosts}>Load more messages</a>;
} else if (channel.type === 'D') {
- var userIds = channel.name.split('__');
- var teammate;
- if (userIds.length === 2 && userIds[0] === user_id) {
- teammate = UserStore.getProfile(userIds[1]);
- } else if (userIds.length === 2 && userIds[1] === user_id) {
- teammate = UserStore.getProfile(userIds[0]);
- }
+ var teammate = utils.getDirectTeammate(channel.id)
if (teammate) {
var teammate_name = teammate.full_name.length > 0 ? teammate.full_name : teammate.username;
@@ -342,13 +336,13 @@ module.exports = React.createClass({
<div className="channel-intro-profile">
<strong><UserProfile userId={teammate.id} /></strong>
</div>
- <p className="channel-intro-text">{"This is the start of your direct message history with " + teammate_name + "." }<br/>{"Direct messages and files shared here are not shown to people outside this area."}</p>
+ <p className="channel-intro-text">{"This is the start of your private message history with " + teammate_name + "." }<br/>{"Private messages and files shared here are not shown to people outside this area."}</p>
</div>
);
} else {
more_messages = (
<div className="channel-intro">
- <p className="channel-intro-text">{"This is the start of your direct message history with this " + strings.Team + "mate. Direct messages and files shared here are not shown to people outside this area."}</p>
+ <p className="channel-intro-text">{"This is the start of your private message history with this " + strings.Team + "mate. Private messages and files shared here are not shown to people outside this area."}</p>
</div>
);
}
@@ -414,55 +408,70 @@ module.exports = React.createClass({
}
var postCtls = [];
- var previousPostDay = posts[order[order.length-1]] ? utils.getDateForUnixTicks(posts[order[order.length-1]].create_at): new Date();
- var currentPostDay = new Date();
- for (var i = order.length-1; i >= 0; i--) {
- var post = posts[order[i]];
- var parentPost;
+ if (posts != undefined) {
+ var previousPostDay = posts[order[order.length-1]] ? utils.getDateForUnixTicks(posts[order[order.length-1]].create_at): new Date();
+ var currentPostDay = new Date();
- if (post.parent_id) {
- parentPost = posts[post.parent_id];
- } else {
- parentPost = null;
- }
+ for (var i = order.length-1; i >= 0; i--) {
+ var post = posts[order[i]];
+ var parentPost;
- var sameUser = i < order.length-1 && posts[order[i+1]].user_id === post.user_id && post.create_at - posts[order[i+1]].create_at <= 1000*60*5 ? "same--user" : "";
- var sameRoot = i < order.length-1 && post.root_id != "" && (posts[order[i+1]].id === post.root_id || posts[order[i+1]].root_id === post.root_id) ? true : false;
+ if (post.parent_id) {
+ parentPost = posts[post.parent_id];
+ } else {
+ parentPost = null;
+ }
- // we only hide the profile pic if the previous post is not a comment, the current post is not a comment, and the previous post was made by the same user as the current post
- var hideProfilePic = i < order.length-1 && posts[order[i+1]].user_id === post.user_id && posts[order[i+1]].root_id === '' && post.root_id === '';
+ var sameUser = i < order.length-1 && posts[order[i+1]].user_id === post.user_id && post.create_at - posts[order[i+1]].create_at <= 1000*60*5 ? "same--user" : "";
+ var sameRoot = i < order.length-1 && post.root_id != "" && (posts[order[i+1]].id === post.root_id || posts[order[i+1]].root_id === post.root_id) ? true : false;
- // check if it's the last comment in a consecutive string of comments on the same post
- var isLastComment = false;
- if (utils.isComment(post)) {
- // it is the last comment if it is last post in the channel or the next post has a different root post
- isLastComment = (i === 0 || posts[order[i-1]].root_id != post.root_id);
- }
+ // we only hide the profile pic if the previous post is not a comment, the current post is not a comment, and the previous post was made by the same user as the current post
+ var hideProfilePic = i < order.length-1 && posts[order[i+1]].user_id === post.user_id && posts[order[i+1]].root_id === '' && post.root_id === '';
- var postCtl = <Post sameUser={sameUser} sameRoot={sameRoot} post={post} parentPost={parentPost} key={post.id} posts={posts} hideProfilePic={hideProfilePic} isLastComment={isLastComment} />;
+ // check if it's the last comment in a consecutive string of comments on the same post
+ var isLastComment = false;
+ if (utils.isComment(post)) {
+ // it is the last comment if it is last post in the channel or the next post has a different root post
+ isLastComment = (i === 0 || posts[order[i-1]].root_id != post.root_id);
+ }
- currentPostDay = utils.getDateForUnixTicks(post.create_at);
- if(currentPostDay.getDate() !== previousPostDay.getDate() || currentPostDay.getMonth() !== previousPostDay.getMonth() || currentPostDay.getFullYear() !== previousPostDay.getFullYear()) {
- postCtls.push(
- <div className="date-separator">
- <hr className="separator__hr" />
- <div className="separator__text">{currentPostDay.toDateString()}</div>
- </div>
- );
- }
+ var postCtl = <Post sameUser={sameUser} sameRoot={sameRoot} post={post} parentPost={parentPost} key={post.id} posts={posts} hideProfilePic={hideProfilePic} isLastComment={isLastComment} />;
- if (post.create_at > last_viewed && !rendered_last_viewed) {
- rendered_last_viewed = true;
- postCtls.push(
- <div className="new-separator">
- <hr id="new_message" className="separator__hr" />
- <div className="separator__text">New Messages</div>
- </div>
- );
+ currentPostDay = utils.getDateForUnixTicks(post.create_at);
+ if(currentPostDay.getDate() !== previousPostDay.getDate() || currentPostDay.getMonth() !== previousPostDay.getMonth() || currentPostDay.getFullYear() !== previousPostDay.getFullYear()) {
+ postCtls.push(
+ <div className="date-separator">
+ <hr className="separator__hr" />
+ <div className="separator__text">{currentPostDay.toDateString()}</div>
+ </div>
+ );
+ }
+
+ if (post.create_at > last_viewed && !rendered_last_viewed) {
+ rendered_last_viewed = true;
+ postCtls.push(
+ <div className="new-separator">
+ <hr id="new_message" className="separator__hr" />
+ <div className="separator__text">New Messages</div>
+ </div>
+ );
+ }
+ postCtls.push(postCtl);
+ previousPostDay = utils.getDateForUnixTicks(post.create_at);
}
- postCtls.push(postCtl);
- previousPostDay = utils.getDateForUnixTicks(post.create_at);
+ }
+ else {
+ postCtls.push(
+ <div ref="loadingscreen" className="loading-screen">
+ <div className="loading__content">
+ <h3>Loading</h3>
+ <div id="round_1" className="round"></div>
+ <div id="round_2" className="round"></div>
+ <div id="round_3" className="round"></div>
+ </div>
+ </div>
+ );
}
return (
diff --git a/web/react/components/post_right.jsx b/web/react/components/post_right.jsx
index 43be60afa..2c28c5d9f 100644
--- a/web/react/components/post_right.jsx
+++ b/web/react/components/post_right.jsx
@@ -68,9 +68,14 @@ RootPost = React.createClass({
var filenames = this.props.post.filenames;
var isOwner = UserStore.getCurrentId() == this.props.post.user_id;
- var type = "Post"
+ var type = "Post";
if (this.props.post.root_id.length > 0) {
- type = "Comment"
+ type = "Comment";
+ }
+
+ var currentUserCss = "";
+ if (UserStore.getCurrentId() === this.props.post.user_id) {
+ currentUserCss = "current--user";
}
if (filenames) {
@@ -84,7 +89,7 @@ RootPost = React.createClass({
if (fileSplit.length < 2) continue;
var ext = fileSplit[fileSplit.length-1];
- fileSplit.splice(fileSplit.length-1,1)
+ fileSplit.splice(fileSplit.length-1,1);
var filePath = fileSplit.join('.');
var filename = filePath.split('/')[filePath.split('/').length-1];
@@ -111,7 +116,7 @@ RootPost = React.createClass({
}
return (
- <div className="post post--root">
+ <div className={"post post--root " + currentUserCss}>
<div className="post-profile-img__container">
<img className="post-profile-img" src={"/api/v1/users/" + this.props.post.user_id + "/image"} height="36" width="36" />
</div>
@@ -170,6 +175,11 @@ CommentPost = React.createClass({
var commentClass = "post";
+ var currentUserCss = "";
+ if (UserStore.getCurrentId() === this.props.post.user_id) {
+ currentUserCss = "current--user";
+ }
+
var postImageModalId = "rhs_comment_view_image_modal_" + this.props.post.id;
var filenames = this.props.post.filenames;
var isOwner = UserStore.getCurrentId() == this.props.post.user_id;
@@ -219,7 +229,7 @@ CommentPost = React.createClass({
var message = utils.textToJsx(this.props.post.message);
return (
- <div className={commentClass}>
+ <div className={commentClass + " " + currentUserCss}>
<div className="post-profile-img__container">
<img className="post-profile-img" src={"/api/v1/users/" + this.props.post.user_id + "/image"} height="36" width="36" />
</div>
diff --git a/web/react/components/search_results.jsx b/web/react/components/search_results.jsx
index 51aefd3b8..003a38b7e 100644
--- a/web/react/components/search_results.jsx
+++ b/web/react/components/search_results.jsx
@@ -43,6 +43,7 @@ SearchItem = React.createClass({
e.preventDefault();
var self = this;
+
client.getPost(
this.props.post.channel_id,
this.props.post.id,
@@ -64,6 +65,11 @@ SearchItem = React.createClass({
dispatchError(err, "getPost");
}
);
+
+ var postChannel = ChannelStore.get(this.props.post.channel_id);
+ var teammate = postChannel.type === 'D' ? utils.getDirectTeammate(this.props.post.channel_id).username : "";
+
+ utils.switchChannel(postChannel,teammate);
},
render: function() {
@@ -73,7 +79,7 @@ SearchItem = React.createClass({
if (channel) {
if (channel.type === 'D') {
- channelName = "Direct Message";
+ channelName = "Private Message";
} else {
channelName = channel.display_name;
}
diff --git a/web/react/components/sidebar.jsx b/web/react/components/sidebar.jsx
index 10017c7ee..0e4d38fe0 100644
--- a/web/react/components/sidebar.jsx
+++ b/web/react/components/sidebar.jsx
@@ -269,13 +269,8 @@ var SidebarLoggedIn = React.createClass({
var channel = ChannelStore.getCurrent();
if (channel) {
if (channel.type === 'D') {
- userIds = channel.name.split('__');
- if (userIds.length < 2) return;
- if (userIds[0] == UserStore.getCurrentId() && UserStore.getProfile(userIds[1])) {
- document.title = UserStore.getProfile(userIds[1]).username + " " + document.title.substring(document.title.lastIndexOf("-"));
- } else if (userIds[1] == UserStore.getCurrentId() && UserStore.getProfile(userIds[0])) {
- document.title = UserStore.getProfile(userIds[0]).username + " " + document.title.substring(document.title.lastIndexOf("-"));
- }
+ var teammate_username = utils.getDirectTeammate(channel.id).username
+ document.title = teammate_username + " " + document.title.substring(document.title.lastIndexOf("-"));
} else {
document.title = channel.display_name + " " + document.title.substring(document.title.lastIndexOf("-"))
}
@@ -414,7 +409,7 @@ var SidebarLoggedIn = React.createClass({
{privateChannelItems}
</ul>
<ul className="nav nav-pills nav-stacked">
- <li><h4>Direct Messages</h4></li>
+ <li><h4>Private Messages</h4></li>
{directMessageItems}
{ this.state.hideDirectChannels.length > 0 ?
<li><a href="#" data-toggle="modal" className="nav-more" data-target="#more_direct_channels" data-channels={JSON.stringify(this.state.hideDirectChannels)}>{"More ("+this.state.hideDirectChannels.length+")"}</a></li>
diff --git a/web/react/components/team_settings.jsx b/web/react/components/team_settings.jsx
index a43e5d2f0..166b1f38b 100644
--- a/web/react/components/team_settings.jsx
+++ b/web/react/components/team_settings.jsx
@@ -78,13 +78,14 @@ var FeatureTab = React.createClass({
<button className={"btn btn-default "+valetActive[0]} onClick={function(){self.handleValetRadio("true")}}>On</button>
<button className={"btn btn-default "+valetActive[1]} onClick={function(){self.handleValetRadio("false")}}>Off</button>
</div>
- <div><br/>Warning: Turning on the Valet feature and using it with any third party software increases the risk of a security breach.</div>
+ <div><br/>Valet is a preview feature for enabling a non-user account limited to basic member permissions that can be manipulated by 3rd parties.<br/><br/>IMPORTANT: The preview version of Valet should not be used without a secure connection and a trusted 3rd party, since user credentials are used to connect. OAuth2 will be used in the final release.</div>
+ <br></br>
</div>
);
valetSection = (
<SettingItemMax
- title="Valet"
+ title="Valet (Preview - EXPERTS ONLY)"
inputs={inputs}
submit={this.submitValetFeature}
server_error={server_error}
@@ -102,7 +103,7 @@ var FeatureTab = React.createClass({
valetSection = (
<SettingItemMin
- title="Valet"
+ title="Valet (Preview - EXPERTS ONLY)"
describe={describe}
updateSection={function(){self.props.updateSection("valet");}}
/>
diff --git a/web/react/components/user_settings.jsx b/web/react/components/user_settings.jsx
index f97a06db3..b4c3747af 100644
--- a/web/react/components/user_settings.jsx
+++ b/web/react/components/user_settings.jsx
@@ -179,7 +179,7 @@ var NotificationsTab = React.createClass({
</div>
<div className="radio">
<label>
- <input type="radio" checked={notifyActive[1]} onClick={function(){self.handleNotifyRadio("mention")}}>Only for mentions and direct messages</input>
+ <input type="radio" checked={notifyActive[1]} onClick={function(){self.handleNotifyRadio("mention")}}>Only for mentions and private messages</input>
</label>
<br/>
</div>
@@ -203,7 +203,7 @@ var NotificationsTab = React.createClass({
} else {
var describe = "";
if (this.state.notify_level === "mention") {
- describe = "Only for mentions and direct messages";
+ describe = "Only for mentions and private messages";
} else if (this.state.notify_level === "none") {
describe = "Never";
} else {
@@ -282,7 +282,7 @@ var NotificationsTab = React.createClass({
<button className={"btn btn-default "+emailActive[0]} onClick={function(){self.handleEmailRadio("true")}}>On</button>
<button className={"btn btn-default "+emailActive[1]} onClick={function(){self.handleEmailRadio("false")}}>Off</button>
</div>
- <div><br/>{"Email notifications are sent for mentions and direct messages after you have been away from " + config.SiteName + " for 5 minutes."}</div>
+ <div><br/>{"Email notifications are sent for mentions and private messages after you have been away from " + config.SiteName + " for 5 minutes."}</div>
</div>
);
@@ -809,6 +809,11 @@ var GeneralTab = React.createClass({
if(!this.submitActive) return;
+ if(this.state.picture.type !== "image/jpeg") {
+ this.setState({client_error: "Only JPG images may be used for profile pictures"});
+ return;
+ }
+
formData = new FormData();
formData.append('image', this.state.picture, this.state.picture.name);
@@ -839,11 +844,13 @@ var GeneralTab = React.createClass({
updatePicture: function(e) {
if (e.target.files && e.target.files[0]) {
this.setState({ picture: e.target.files[0] });
+
+ this.submitActive = true;
+ this.setState({client_error:null})
+
} else {
this.setState({ picture: null });
}
-
- this.submitActive = true
},
updateSection: function(section) {
this.setState({client_error:""})
@@ -984,7 +991,7 @@ var GeneralTab = React.createClass({
submit={this.submitPicture}
src={"/api/v1/users/" + user.id + "/image"}
server_error={server_error}
- client_error={email_error}
+ client_error={client_error}
updateSection={function(e){self.updateSection("");e.preventDefault();}}
picture={this.state.picture}
pictureChange={this.updatePicture}
diff --git a/web/react/utils/utils.jsx b/web/react/utils/utils.jsx
index 70a47742f..f8a7d6450 100644
--- a/web/react/utils/utils.jsx
+++ b/web/react/utils/utils.jsx
@@ -2,6 +2,7 @@
// See License.txt for license information.
var AppDispatcher = require('../dispatcher/app_dispatcher.jsx');
+var ChannelStore = require('../stores/channel_store.jsx')
var UserStore = require('../stores/user_store.jsx');
var Constants = require('../utils/constants.jsx');
var ActionTypes = Constants.ActionTypes;
@@ -726,6 +727,25 @@ module.exports.isComment = function(post) {
return false;
}
+module.exports.getDirectTeammate = function(channel_id) {
+ var userIds = ChannelStore.get(channel_id).name.split('__');
+ var curUserId = UserStore.getCurrentId();
+ var teammate = {};
+
+ if(userIds.length != 2 || userIds.indexOf(curUserId) === -1) {
+ return teammate;
+ }
+
+ for (var idx in userIds) {
+ if(userIds[idx] !== curUserId) {
+ teammate = UserStore.getProfile(userIds[idx]);
+ break;
+ }
+ }
+
+ return teammate;
+}
+
Image.prototype.load = function(url, progressCallback) {
var thisImg = this;
var xmlHTTP = new XMLHttpRequest();
diff --git a/web/sass-files/sass/partials/_base.scss b/web/sass-files/sass/partials/_base.scss
index 5808aeb44..cf28e44e8 100644
--- a/web/sass-files/sass/partials/_base.scss
+++ b/web/sass-files/sass/partials/_base.scss
@@ -3,7 +3,7 @@ html, body {
}
body {
- font-family: 'Lato', sans-serif;
+ font-family: 'Open Sans', sans-serif;
-webkit-font-smoothing: antialiased;
background: #e9e9e9;
position: relative;
@@ -11,21 +11,29 @@ body {
&.white {
background: #fff;
.inner__wrap {
- height: 100%;
+ > .row.content {
+ min-height: 100%;
+ margin-bottom: -89px;
+ }
}
- .row.content {
- min-height: 100%;
- height: auto !important;
+ }
+ .inner__wrap {
+ height: 100%;
+ > .row.main {
height: 100%;
- margin-bottom: -89px;
}
}
> .container-fluid {
@include clearfix;
+ height: 100%;
position: relative;
}
}
+b, strong {
+ font-weight: 600;
+}
+
a {
word-break: break-word;
}
@@ -142,7 +150,7 @@ div.theme {
top: 0;
color: #FFF;
font-size: 20px;
- font-weight: bold;
+ font-weight: 600;
text-decoration: none;
padding: 0 10px;
}
diff --git a/web/sass-files/sass/partials/_headers.scss b/web/sass-files/sass/partials/_headers.scss
index 89bbaef2b..1ec1109a5 100644
--- a/web/sass-files/sass/partials/_headers.scss
+++ b/web/sass-files/sass/partials/_headers.scss
@@ -65,7 +65,7 @@
float:left;
}
.channel-intro-title {
- font-weight:bold;
+ font-weight:600;
}
.channel-intro-text {
margin-top:35px;
@@ -88,7 +88,7 @@
}
.dropdown-menu {
li a {
- padding: 3 20px;
+ padding: 3px 20px;
color: #555;
}
}
diff --git a/web/sass-files/sass/partials/_loading.scss b/web/sass-files/sass/partials/_loading.scss
new file mode 100644
index 000000000..185a42180
--- /dev/null
+++ b/web/sass-files/sass/partials/_loading.scss
@@ -0,0 +1,68 @@
+.loading-screen {
+ display: table;
+ width: 100%;
+ height: 100%;
+ position: absolute;
+ @include box-sizing(border-box);
+ text-align: center;
+ .loading__content {
+ display: table-cell;
+ vertical-align: middle;
+ h3 {
+ font-weight: 400;
+ margin: 0 0.2em 0;
+ display: inline-block;
+ }
+ }
+}
+
+.loading-screen {
+ .loading__content {
+ .round {
+ background-color: #444;
+ width: 4px;
+ height: 4px;
+ display: inline-block;
+ margin: 0 1px;
+ opacity: 0.1;
+ @include border-radius(10px);
+ -moz-animation: move 0.75s infinite linear;
+ -webkit-animation: move 0.75s infinite linear;
+ }
+
+ #round_1 {
+ -moz-animation-delay: .2s;
+ -webkit-animation-delay: .2s;
+ }
+
+ #round_2 {
+ -moz-animation-delay: .4s;
+ -webkit-animation-delay: .4s;
+ }
+
+ #round_3 {
+ -moz-animation-delay: .6s;
+ -webkit-animation-delay: .6s;
+ }
+
+ @-moz-keyframes move {
+ 0% {
+ opacity: 1;
+ }
+
+ 100% {
+ opacity: 0.1;
+ };
+ }
+
+ @-webkit-keyframes move {
+ 0% {
+ opacity: 1;
+ }
+
+ 100% {
+ opacity: 0.1;
+ };
+ }
+ }
+}
diff --git a/web/sass-files/sass/partials/_mentions.scss b/web/sass-files/sass/partials/_mentions.scss
index ee254b546..d6e2ab368 100644
--- a/web/sass-files/sass/partials/_mentions.scss
+++ b/web/sass-files/sass/partials/_mentions.scss
@@ -9,7 +9,7 @@
.mentions--top {
position: absolute;
- z-index: 1040;
+ z-index: 1060;
.mentions-box {
position:absolute;
background-color:#fff;
diff --git a/web/sass-files/sass/partials/_modal.scss b/web/sass-files/sass/partials/_modal.scss
index 4427cb7dd..971ed0935 100644
--- a/web/sass-files/sass/partials/_modal.scss
+++ b/web/sass-files/sass/partials/_modal.scss
@@ -8,7 +8,7 @@
}
}
.info__label {
- font-weight: bold;
+ font-weight: 600;
text-align: right;
padding-right: 0;
}
@@ -21,7 +21,6 @@
margin-right: auto;
}
.modal-body {
- max-height: 75%;
overflow: auto;
}
.modal-push-down {
@@ -66,7 +65,6 @@
}
}
.btn {
- margin-right: 10px;
&.btn-primary {
float: right;
margin-top: -4px;
@@ -120,7 +118,7 @@
}
.more-channel-name {
color: #444;
- font-weight: bold;
+ font-weight: 600;
font-size: 0.95em;
}
tbody {
@@ -145,6 +143,7 @@
.modal-image {
position:relative;
width:100%;
+ height: 100%;
margin: 0 auto;
.image-wrapper {
background: #FFF;
diff --git a/web/sass-files/sass/partials/_post.scss b/web/sass-files/sass/partials/_post.scss
index 745d50173..769cb1091 100644
--- a/web/sass-files/sass/partials/_post.scss
+++ b/web/sass-files/sass/partials/_post.scss
@@ -86,10 +86,11 @@ body.ios {
background: #FFF;
display: inline-block;
padding: 0 1em;
- font-weight: 900;
+ font-weight: 700;
@include border-radius(50px);
position: relative;
z-index: 5;
+ font-size: 13px;
}
}
.new-separator {
@@ -212,6 +213,12 @@ body.ios {
}
}
}
+ &.current--user {
+ .post-body {
+ @include border-radius(0 4px 4px 0);
+ background: #f5f5f5;
+ }
+ }
&.same--root {
.comment-icon__container {
@include opacity(0);
@@ -249,6 +256,7 @@ body.ios {
}
p {
margin: 0 0 5px;
+ font-size: 0.97em;
white-space: pre-wrap;
}
.comment-icon__container {
@@ -269,7 +277,7 @@ body.ios {
float: left;
.post-profile-img {
margin-right: 10px;
- @include border-radius(3px);
+ @include border-radius(50px);
}
}
&.post__content {
@@ -290,6 +298,8 @@ body.ios {
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;
@@ -359,7 +369,7 @@ body.ios {
.embed-title {
margin: 3px 0 1px;
color: #555;
- font-weight: bold;
+ font-weight: 600;
white-space: nowrap;
text-overflow: ellipsis;
overflow: hidden;
diff --git a/web/sass-files/sass/partials/_responsive.scss b/web/sass-files/sass/partials/_responsive.scss
index 25533c770..0037879cf 100644
--- a/web/sass-files/sass/partials/_responsive.scss
+++ b/web/sass-files/sass/partials/_responsive.scss
@@ -5,7 +5,7 @@
&.post--comment {
&.other--root {
.post-comment {
- margin-left: 0;
+ margin-left: -7px;
}
}
}
@@ -22,11 +22,16 @@
width: 825px;
}
.post-body {
- padding-left: 0;
+ width: 736px;
border: none;
margin: 0;
}
}
+ .post-body {
+ float: none;
+ width: 750px;
+ margin: 0;
+ }
.post__content {
width: 920px;
}
@@ -63,10 +68,6 @@
}
}
}
- .post-body {
- float: none;
- width: 750px;
- }
}
}
}
@@ -81,7 +82,7 @@
&.post--comment {
&.other--root {
.post-comment {
- margin-left: 0;
+ margin-left: -7px;
}
}
}
@@ -89,6 +90,7 @@
margin-left: 60px;
padding-left: 10px;
border-left: 4px solid #EEE;
+ margin-bottom: 10px;
div.post-profile-img__container {
.post-profile-img {
display: none;
@@ -98,7 +100,7 @@
width: 825px;
}
.post-body {
- padding-left: 0;
+ width: 736px;
border: none;
margin: 0;
}
@@ -135,6 +137,7 @@
}
}
.post-body {
+ margin: 0;
float: none;
width: 750px;
}
@@ -575,7 +578,7 @@
&.post--comment {
&.other--root {
.post-comment {
- margin-left: 11px;
+ margin-left: 4px;
}
}
}
diff --git a/web/sass-files/sass/partials/_search.scss b/web/sass-files/sass/partials/_search.scss
index ca5d25720..8d51d00c0 100644
--- a/web/sass-files/sass/partials/_search.scss
+++ b/web/sass-files/sass/partials/_search.scss
@@ -77,7 +77,7 @@
border: none;
}
.search-channel__name {
- font-weight: bold;
+ font-weight: 600;
margin: 0 0 10px 0;
}
}
diff --git a/web/sass-files/sass/partials/_settings.scss b/web/sass-files/sass/partials/_settings.scss
index dbaab8b58..af759c650 100644
--- a/web/sass-files/sass/partials/_settings.scss
+++ b/web/sass-files/sass/partials/_settings.scss
@@ -56,7 +56,7 @@
.section-title {
margin-bottom: 5px;
- font-weight: bold;
+ font-weight: 600;
}
.section-edit {
@@ -172,7 +172,7 @@
border-top:1px solid lightgrey;
}
.post-profile-img {
- @include border-radius(3px);
+ @include border-radius(50px);
margin-right: 8px;
}
.member-name {
diff --git a/web/sass-files/sass/partials/_sidebar--left.scss b/web/sass-files/sass/partials/_sidebar--left.scss
index b1dd470d2..89d1ff416 100644
--- a/web/sass-files/sass/partials/_sidebar--left.scss
+++ b/web/sass-files/sass/partials/_sidebar--left.scss
@@ -59,7 +59,7 @@
color: #999;
&.unread-title {
color: #333;
- font-weight: bold;
+ font-weight: 600;
}
&:hover, &:focus {
background: #e6f2fa;
@@ -70,6 +70,7 @@
color: #111;
background-color: #e1e1e1;
border-radius: 0;
+ font-weight: 400;
}
}
}
diff --git a/web/sass-files/sass/styles.scss b/web/sass-files/sass/styles.scss
index 8446f1c01..9cc26320c 100644
--- a/web/sass-files/sass/styles.scss
+++ b/web/sass-files/sass/styles.scss
@@ -29,6 +29,7 @@
@import "partials/modal";
@import "partials/mentions";
@import "partials/error";
+@import "partials/loading";
// Responsive Css
@import "partials/responsive";
diff --git a/web/templates/channel.html b/web/templates/channel.html
index d10ae2304..d96aee3d4 100644
--- a/web/templates/channel.html
+++ b/web/templates/channel.html
@@ -1,4 +1,6 @@
+
{{define "channel"}}
+<!DOCTYPE html>
<html>
{{template "head" . }}
<body>
diff --git a/web/templates/find_team.html b/web/templates/find_team.html
index c731f7a8f..9acf3ac64 100644
--- a/web/templates/find_team.html
+++ b/web/templates/find_team.html
@@ -1,4 +1,5 @@
{{define "find_team"}}
+<!DOCTYPE html>
<html>
{{template "head" . }}
<body class="white">
diff --git a/web/templates/head.html b/web/templates/head.html
index 5eb7a7333..9c025d1f9 100644
--- a/web/templates/head.html
+++ b/web/templates/head.html
@@ -14,7 +14,7 @@
<link id="favicon" rel="icon" href="/static/images/favicon.ico" type="image/x-icon">
<link rel="shortcut icon" href="/static/images/favicon.ico" type="image/x-icon">
- <link href='https://fonts.googleapis.com/css?family=Lato:400,700,900' rel='stylesheet' type='text/css'>
+ <link href='http://fonts.googleapis.com/css?family=Open+Sans:400,600,700' rel='stylesheet' type='text/css'>
<link rel="stylesheet" href="/static/css/styles.css">
<script src="/static/js/min/perfect-scrollbar.min.js"></script>
diff --git a/web/templates/home.html b/web/templates/home.html
index 74f7a015b..abf8062f2 100644
--- a/web/templates/home.html
+++ b/web/templates/home.html
@@ -1,4 +1,5 @@
{{define "home"}}
+<!DOCTYPE html>
<html>
{{template "head" . }}
<body>
diff --git a/web/templates/login.html b/web/templates/login.html
index 1bc5394ab..c107e1ad5 100644
--- a/web/templates/login.html
+++ b/web/templates/login.html
@@ -1,4 +1,5 @@
{{define "login"}}
+<!DOCTYPE html>
<html>
{{template "head" . }}
<body class="white">
diff --git a/web/templates/password_reset.html b/web/templates/password_reset.html
index 1c5485e33..8b63556b1 100644
--- a/web/templates/password_reset.html
+++ b/web/templates/password_reset.html
@@ -1,4 +1,5 @@
{{define "password_reset"}}
+<!DOCTYPE html>
<html>
{{template "head" . }}
<body class="white">
diff --git a/web/templates/signup_team.html b/web/templates/signup_team.html
index f7e277340..fad332bee 100644
--- a/web/templates/signup_team.html
+++ b/web/templates/signup_team.html
@@ -1,4 +1,5 @@
{{define "signup_team"}}
+<!DOCTYPE html>
<html>
{{template "head" . }}
<body class="white">
diff --git a/web/templates/signup_team_complete.html b/web/templates/signup_team_complete.html
index aad521cb3..59f49cdbd 100644
--- a/web/templates/signup_team_complete.html
+++ b/web/templates/signup_team_complete.html
@@ -1,4 +1,5 @@
{{define "signup_team_complete"}}
+<!DOCTYPE html>
<html>
{{template "head" . }}
<body class="white">
diff --git a/web/templates/signup_team_confirm.html b/web/templates/signup_team_confirm.html
index a34c39ab6..9e21126da 100644
--- a/web/templates/signup_team_confirm.html
+++ b/web/templates/signup_team_confirm.html
@@ -1,4 +1,5 @@
{{define "signup_team_confirm"}}
+<!DOCTYPE html>
<html>
{{template "head" . }}
<body class="white">
diff --git a/web/templates/signup_user_complete.html b/web/templates/signup_user_complete.html
index a6827bc3a..5fe907ba7 100644
--- a/web/templates/signup_user_complete.html
+++ b/web/templates/signup_user_complete.html
@@ -1,4 +1,5 @@
{{define "signup_user_complete"}}
+<!DOCTYPE html>
<html>
{{template "head" . }}
<body class="white">
diff --git a/web/templates/verify.html b/web/templates/verify.html
index 60a7990f0..a61964bb3 100644
--- a/web/templates/verify.html
+++ b/web/templates/verify.html
@@ -1,4 +1,5 @@
{{define "verify"}}
+<!DOCTYPE html>
<html>
{{template "head" . }}
<body>
diff --git a/web/templates/welcome.html b/web/templates/welcome.html
index 27bf4bcaf..bab7a135d 100644
--- a/web/templates/welcome.html
+++ b/web/templates/welcome.html
@@ -1,4 +1,5 @@
{{define "welcome"}}
+<!DOCTYPE html>
<html>
{{template "head" . }}
<body>