diff options
Diffstat (limited to 'web')
-rw-r--r-- | web/react/components/channel_header.jsx | 2 | ||||
-rw-r--r-- | web/react/components/mention_list.jsx | 6 | ||||
-rw-r--r-- | web/react/components/new_channel.jsx | 2 | ||||
-rw-r--r-- | web/react/components/post_list.jsx | 15 | ||||
-rw-r--r-- | web/react/components/setting_picture.jsx | 30 | ||||
-rw-r--r-- | web/react/components/sidebar_header.jsx | 117 | ||||
-rw-r--r-- | web/react/components/signup_team_complete.jsx | 6 | ||||
-rw-r--r-- | web/react/components/user_profile.jsx | 3 | ||||
-rw-r--r-- | web/react/components/user_settings.jsx | 107 | ||||
-rw-r--r-- | web/sass-files/sass/partials/_base.scss | 10 | ||||
-rw-r--r-- | web/sass-files/sass/partials/_files.scss | 68 | ||||
-rw-r--r-- | web/sass-files/sass/partials/_headers.scss | 14 | ||||
-rw-r--r-- | web/sass-files/sass/partials/_modal.scss | 9 | ||||
-rw-r--r-- | web/sass-files/sass/partials/_navbar.scss | 1 | ||||
-rw-r--r-- | web/sass-files/sass/partials/_popover.scss | 7 | ||||
-rw-r--r-- | web/sass-files/sass/partials/_responsive.scss | 10 | ||||
-rw-r--r-- | web/sass-files/sass/partials/_signup.scss | 22 | ||||
-rw-r--r-- | web/templates/channel.html | 4 | ||||
-rw-r--r-- | web/templates/signup_team.html | 2 |
19 files changed, 279 insertions, 156 deletions
diff --git a/web/react/components/channel_header.jsx b/web/react/components/channel_header.jsx index b6182cfa5..a79d3547f 100644 --- a/web/react/components/channel_header.jsx +++ b/web/react/components/channel_header.jsx @@ -67,7 +67,7 @@ var PopoverListMembers = React.createClass({ return ( <div id='member_popover' data-toggle='popover' data-content={popoverHtml} data-original-title='Members' > - <div id='member_tooltip' data-toggle='tooltip' title='View Channel Members'> + <div id='member_tooltip' data-placement='left' data-toggle='tooltip' title='View Channel Members'> {count} <span className='glyphicon glyphicon-user' aria-hidden='true'></span> </div> </div> diff --git a/web/react/components/mention_list.jsx b/web/react/components/mention_list.jsx index a0f68df98..5f1bb6d0e 100644 --- a/web/react/components/mention_list.jsx +++ b/web/react/components/mention_list.jsx @@ -20,6 +20,12 @@ module.exports = React.createClass({ PostStore.addMentionDataChangeListener(this.onListenerChange); var self = this; + $('.post-right__scroll').scroll(function(){ + if($('.mentions--top').length){ + $('#reply_mention_tab .mentions--top').css({ bottom: $(window).height() - $('.post-right__scroll #reply_textbox').offset().top }); + } + }); + $('body').on('keydown.mentionlist', '#' + this.props.id, function(e) { if (!self.isEmpty() && self.state.mentionText !== '-1' && (e.which === 13 || e.which === 9)) { diff --git a/web/react/components/new_channel.jsx b/web/react/components/new_channel.jsx index 6cf195795..93884f6eb 100644 --- a/web/react/components/new_channel.jsx +++ b/web/react/components/new_channel.jsx @@ -53,7 +53,7 @@ module.exports = React.createClass({ channel.team_id = cu.team_id; channel.description = this.refs.channel_desc.getDOMNode().value.trim(); - channel.type = this.state.channel_type; + channel.type = this.state.channelType; var self = this; client.createChannel(channel, diff --git a/web/react/components/post_list.jsx b/web/react/components/post_list.jsx index 3f59d5843..bb1b1704c 100644 --- a/web/react/components/post_list.jsx +++ b/web/react/components/post_list.jsx @@ -37,15 +37,23 @@ module.exports = React.createClass({ componentDidMount: function() { var user = UserStore.getCurrentUser(); if (user.props && user.props.theme) { - utils.changeCss('a.theme', 'color:'+user.props.theme+'; fill:'+user.props.theme+'!important;'); utils.changeCss('div.theme', 'background-color:'+user.props.theme+';'); utils.changeCss('.btn.btn-primary', 'background: ' + user.props.theme+';'); - utils.changeCss('.btn.btn-primary:hover, .btn.btn-primary:active, .btn.btn-primary:focus', 'background: ' + utils.changeColor(user.props.theme, -10) +';'); utils.changeCss('.modal .modal-header', 'background: ' + user.props.theme+';'); utils.changeCss('.mention', 'background: ' + user.props.theme+';'); utils.changeCss('.mention-link', 'color: ' + user.props.theme+';'); utils.changeCss('@media(max-width: 768px){.search-bar__container', 'background: ' + user.props.theme+';}'); } + if (user.props.theme != '#000000' && user.props.theme != '#585858') { + utils.changeCss('.btn.btn-primary:hover, .btn.btn-primary:active, .btn.btn-primary:focus', 'background: ' + utils.changeColor(user.props.theme, -10) +';'); + utils.changeCss('a.theme', 'color:'+user.props.theme+'; fill:'+user.props.theme+'!important;'); + } else if (user.props.theme == '#000000') { + utils.changeCss('.btn.btn-primary:hover, .btn.btn-primary:active, .btn.btn-primary:focus', 'background: ' + utils.changeColor(user.props.theme, +50) +';'); + $('.team__header').addClass('theme--black'); + } else if (user.props.theme == '#585858') { + utils.changeCss('.btn.btn-primary:hover, .btn.btn-primary:active, .btn.btn-primary:focus', 'background: ' + utils.changeColor(user.props.theme, +10) +';'); + $('.team__header').addClass('theme--gray'); + } PostStore.addChangeListener(this._onChange); ChannelStore.addChangeListener(this._onChange); @@ -311,7 +319,6 @@ module.exports = React.createClass({ } else if (channel.type === 'D') { var teammate = utils.getDirectTeammate(channel.id) - if (teammate) { var teammate_name = teammate.nickname.length > 0 ? teammate.nickname : teammate.username; more_messages = ( @@ -399,7 +406,7 @@ module.exports = React.createClass({ var postCtls = []; if (posts) { - var previousPostDay = posts[order[order.length-1]] ? utils.getDateForUnixTicks(posts[order[order.length-1]].create_at): new Date(); + var previousPostDay = new Date(0); var currentPostDay; for (var i = order.length-1; i >= 0; i--) { diff --git a/web/react/components/setting_picture.jsx b/web/react/components/setting_picture.jsx index fa4c8bb62..e97b67706 100644 --- a/web/react/components/setting_picture.jsx +++ b/web/react/components/setting_picture.jsx @@ -20,8 +20,14 @@ module.exports = React.createClass({ } }, render: function() { - var client_error = this.props.client_error ? <div className='form-group has-error'><label className='control-label'>{ this.props.client_error }</label></div> : null; - var server_error = this.props.server_error ? <div className='form-group has-error'><label className='control-label'>{ this.props.server_error }</label></div> : null; + var clientError = null; + if (this.props.client_error) { + clientError = <div className='form-group has-error'><label className='control-label'>{this.props.client_error}</label></div>; + } + var serverError = null; + if (this.props.server_error) { + serverError = <div className='form-group has-error'><label className='control-label'>{this.props.server_error}</label></div>; + } var img = null; if (this.props.picture) { @@ -30,8 +36,20 @@ module.exports = React.createClass({ img = (<img ref='image' className='profile-img' src={this.props.src}/>); } - var self = this; + var confirmButton; + if (this.props.loadingPicture) { + confirmButton = <img className='spinner' src='/static/images/load.gif'/>; + } else { + var confirmButtonClass = 'btn btn-sm'; + if (this.props.submitActive) { + confirmButtonClass += ' btn-primary'; + } else { + confirmButtonClass += ' btn-inactive disabled'; + } + confirmButton = <a className={confirmButtonClass} onClick={this.props.submit}>Save</a>; + } + var self = this; return ( <ul className='section-max'> <li className='col-xs-12 section-title'>{this.props.title}</li> @@ -41,10 +59,10 @@ module.exports = React.createClass({ {img} </li> <li className='setting-list-item'> - {server_error} - {client_error} + {serverError} + {clientError} <span className='btn btn-sm btn-primary btn-file sel-btn'>Select<input ref='input' accept='.jpg,.png,.bmp' type='file' onChange={this.props.pictureChange}/></span> - <a className={this.props.submitActive ? 'btn btn-sm btn-primary' : 'btn btn-sm btn-inactive disabled'} onClick={this.props.submit}>Save</a> + {confirmButton} <a className='btn btn-sm theme' href='#' onClick={self.props.updateSection}>Cancel</a> </li> </ul> diff --git a/web/react/components/sidebar_header.jsx b/web/react/components/sidebar_header.jsx index e01ddcd05..ba8f9bacd 100644 --- a/web/react/components/sidebar_header.jsx +++ b/web/react/components/sidebar_header.jsx @@ -1,15 +1,15 @@ // Copyright (c) 2015 Spinpunch, Inc. All Rights Reserved. // See License.txt for license information. - var utils = require('../utils/utils.jsx'); var client = require('../utils/client.jsx'); var UserStore = require('../stores/user_store.jsx'); +var TeamStore = require('../stores/team_store.jsx'); var Constants = require('../utils/constants.jsx'); function getStateFromStores() { - return { teams: UserStore.getTeams() }; + return {teams: UserStore.getTeams(), currentTeam: TeamStore.getCurrent()}; } var NavbarDropdown = React.createClass({ @@ -19,20 +19,24 @@ var NavbarDropdown = React.createClass({ }, blockToggle: false, componentDidMount: function() { - UserStore.addTeamsChangeListener(this._onChange); + UserStore.addTeamsChangeListener(this.onListenerChange); + TeamStore.addChangeListener(this.onListenerChange); var self = this; - $(this.refs.dropdown.getDOMNode()).on('hide.bs.dropdown', function(e) { + $(this.refs.dropdown.getDOMNode()).on('hide.bs.dropdown', function() { self.blockToggle = true; - setTimeout(function(){self.blockToggle = false;}, 100); + setTimeout(function() { + self.blockToggle = false; + }, 100); }); }, componentWillUnmount: function() { - UserStore.removeTeamsChangeListener(this._onChange); + UserStore.removeTeamsChangeListener(this.onListenerChange); + TeamStore.removeChangeListener(this.onListenerChange); $(this.refs.dropdown.getDOMNode()).off('hide.bs.dropdown'); }, - _onChange: function() { + onListenerChange: function() { if (this.isMounted()) { var newState = getStateFromStores(); if (!utils.areStatesEqual(newState, this.state)) { @@ -44,62 +48,65 @@ var NavbarDropdown = React.createClass({ return getStateFromStores(); }, render: function() { - var team_link = ""; - var invite_link = ""; - var manage_link = ""; - var rename_link = ""; + var teamLink = ''; + var inviteLink = ''; + var manageLink = ''; + var renameLink = ''; var currentUser = UserStore.getCurrentUser(); var isAdmin = false; + var teamSettings = null; if (currentUser != null) { - isAdmin = currentUser.roles.indexOf("admin") > -1; + isAdmin = currentUser.roles.indexOf('admin') > -1; - invite_link = ( <li> <a href="#" data-toggle="modal" data-target="#invite_member">Invite New Member</a> </li>); + inviteLink = (<li> <a href='#' data-toggle='modal' data-target='#invite_member'>Invite New Member</a> </li>); - if (this.props.teamType == "O") { - team_link = ( + if (this.props.teamType === 'O') { + teamLink = ( <li> - <a href="#" data-toggle="modal" data-target="#get_link" data-title="Team Invite" data-value={location.origin+"/signup_user_complete/?id="+currentUser.team_id}>Get Team Invite Link</a> + <a href='#' data-toggle='modal' data-target='#get_link' data-title='Team Invite' data-value={location.origin + '/signup_user_complete/?id=' + currentUser.team_id}>Get Team Invite Link</a> </li> ); } } if (isAdmin) { - manage_link = ( <li> <a href="#" data-toggle="modal" data-target="#team_members">Manage Team</a> </li>); - rename_link = ( <li> <a href="#" data-toggle="modal" data-target="#rename_team_link">Rename</a> </li>); + manageLink = (<li> <a href='#' data-toggle='modal' data-target='#team_members'>Manage Team</a> </li>); + renameLink = (<li> <a href='#' data-toggle='modal' data-target='#rename_team_link'>Rename</a> </li>); + teamSettings = (<li> <a href='#' data-toggle='modal' data-target='#team_settings'>Team Settings</a> </li>); } var teams = []; - teams.push(<li className="divider" key="div"></li>); - if (this.state.teams.length > 1) { - for (var i = 0; i < this.state.teams.length; i++) { - var teamName = this.state.teams[i]; - - teams.push(<li key={ teamName }><a href={utils.getWindowLocationOrigin() + "/" + teamName }>Switch to { teamName }</a></li>); - } + teams.push(<li className='divider' key='div'></li>); + if (this.state.teams.length > 1 && this.state.currentTeam) { + var curTeamName = this.state.currentTeam.name; + this.state.teams.forEach(function(teamName) { + if (teamName !== curTeamName) { + teams.push(<li key={teamName}><a href={utils.getWindowLocationOrigin() + '/' + teamName}>Switch to {teamName}</a></li>); + } + }); } - teams.push(<li><a href={utils.getWindowLocationOrigin() + "/signup_team" }>Create a New Team</a></li>); + teams.push(<li><a href={utils.getWindowLocationOrigin() + '/signup_team'}>Create a New Team</a></li>); return ( - <ul className="nav navbar-nav navbar-right"> - <li ref="dropdown" className="dropdown"> - <a href="#" className="dropdown-toggle" data-toggle="dropdown" role="button" aria-expanded="false"> - <span className="dropdown__icon" dangerouslySetInnerHTML={{__html: Constants.MENU_ICON }} /> + <ul className='nav navbar-nav navbar-right'> + <li ref='dropdown' className='dropdown'> + <a href='#' className='dropdown-toggle' data-toggle='dropdown' role='button' aria-expanded='false'> + <span className='dropdown__icon' dangerouslySetInnerHTML={{__html: Constants.MENU_ICON}} /> </a> - <ul className="dropdown-menu" role="menu"> - <li><a href="#" data-toggle="modal" data-target="#user_settings1">Account Settings</a></li> - { isAdmin ? <li><a href="#" data-toggle="modal" data-target="#team_settings">Team Settings</a></li> : null } - { invite_link } - { team_link } - { manage_link } - { rename_link } - <li><a href="#" onClick={this.handleLogoutClick}>Logout</a></li> - { teams } - <li className="divider"></li> - <li><a target="_blank" href={config.HelpLink}>Help</a></li> - <li><a target="_blank" href={config.ReportProblemLink}>Report a Problem</a></li> + <ul className='dropdown-menu' role='menu'> + <li><a href='#' data-toggle='modal' data-target='#user_settings1'>Account Settings</a></li> + {teamSettings} + {inviteLink} + {teamLink} + {manageLink} + {renameLink} + <li><a href='#' onClick={this.handleLogoutClick}>Logout</a></li> + {teams} + <li className='divider'></li> + <li><a target='_blank' href={config.HelpLink}>Help</a></li> + <li><a target='_blank' href={config.ReportProblemLink}>Report a Problem</a></li> </ul> </li> </ul> @@ -109,14 +116,13 @@ var NavbarDropdown = React.createClass({ module.exports = React.createClass({ displayName: 'SidebarHeader', - getDefaultProps: function() { return { teamDisplayName: config.SiteName }; }, - toggleDropdown: function(e) { + toggleDropdown: function() { if (this.refs.dropdown.blockToggle) { this.refs.dropdown.blockToggle = false; return; @@ -126,25 +132,26 @@ module.exports = React.createClass({ render: function() { var me = UserStore.getCurrentUser(); + var profilePicture = null; if (!me) { return null; } + if (me.last_picture_update) { + profilePicture = (<img className='user__picture' src={'/api/v1/users/' + me.id + '/image?time=' + me.update_at} />); + } + return ( - <div className="team__header theme"> - <a href="#" onClick={this.toggleDropdown}> - { me.last_picture_update ? - <img className="user__picture" src={"/api/v1/users/" + me.id + "/image?time=" + me.update_at} /> - : - null - } - <div className="header__info"> - <div className="user__name">{ '@' + me.username}</div> - <div className="team__name">{ this.props.teamDisplayName }</div> + <div className='team__header theme'> + <a href='#' onClick={this.toggleDropdown}> + {profilePicture} + <div className='header__info'> + <div className='user__name'>{'@' + me.username}</div> + <div className='team__name'>{this.props.teamDisplayName }</div> </div> </a> - <NavbarDropdown ref="dropdown" teamType={this.props.teamType} /> + <NavbarDropdown ref='dropdown' teamType={this.props.teamType} /> </div> ); } diff --git a/web/react/components/signup_team_complete.jsx b/web/react/components/signup_team_complete.jsx index 447a405bd..3f35a5912 100644 --- a/web/react/components/signup_team_complete.jsx +++ b/web/react/components/signup_team_complete.jsx @@ -248,6 +248,8 @@ TeamURLPage = React.createClass({ }, render: function() { + $('body').tooltip( {selector: '[data-toggle=tooltip]', trigger: 'hover click'} ); + client.track('signup', 'signup_team_03_url'); var name_error = this.state.name_error ? <label className="control-label">{ this.state.name_error }</label> : null; @@ -260,8 +262,8 @@ TeamURLPage = React.createClass({ <div className={ name_error ? "form-group has-error" : "form-group" }> <div className="row"> <div className="col-sm-11"> - <div className="input-group"> - <span className="input-group-addon">{ utils.getWindowLocationOrigin() + "/" }</span> + <div className="input-group input-group--limit"> + <span data-toggle="tooltip" title={ utils.getWindowLocationOrigin() + "/" } className="input-group-addon">{ utils.getWindowLocationOrigin() + "/" }</span> <input type="text" ref="name" className="form-control" placeholder="" maxLength="128" defaultValue={this.props.state.team.name} autoFocus={true} onFocus={this.handleFocus}/> </div> </div> diff --git a/web/react/components/user_profile.jsx b/web/react/components/user_profile.jsx index 65f025919..5c4d26a23 100644 --- a/web/react/components/user_profile.jsx +++ b/web/react/components/user_profile.jsx @@ -28,6 +28,7 @@ module.exports = React.createClass({ componentDidMount: function() { UserStore.addChangeListener(this._onChange); $("#profile_" + this.uniqueId).popover({placement : 'right', container: 'body', trigger: 'hover', html: true, delay: { "show": 200, "hide": 100 }}); + $('body').tooltip( {selector: '[data-toggle=tooltip]', trigger: 'hover click'} ); }, componentWillUnmount: function() { UserStore.removeChangeListener(this._onChange); @@ -57,7 +58,7 @@ module.exports = React.createClass({ if (!config.ShowEmail) { data_content += "<div class='text-nowrap'>Email not shared</div>"; } else { - data_content += "<div><a href='mailto:" + this.state.profile.email + "' class='text-nowrap text-lowercase'>" + this.state.profile.email + "</a></div>"; + data_content += "<div data-toggle='tooltip' title= '" + this.state.profile.email + "'><a href='mailto:" + this.state.profile.email + "' class='text-nowrap text-lowercase user-popover__email'>" + this.state.profile.email + "</a></div>"; } return ( diff --git a/web/react/components/user_settings.jsx b/web/react/components/user_settings.jsx index c574d2365..e224f2a87 100644 --- a/web/react/components/user_settings.jsx +++ b/web/react/components/user_settings.jsx @@ -5,8 +5,6 @@ var UserStore = require('../stores/user_store.jsx'); var SettingItemMin = require('./setting_item_min.jsx'); var SettingItemMax = require('./setting_item_max.jsx'); var SettingPicture = require('./setting_picture.jsx'); -var AccessHistoryModal = require('./access_history_modal.jsx'); -var ActivityLogModal = require('./activity_log_modal.jsx'); var client = require('../utils/client.jsx'); var AsyncClient = require('../utils/async_client.jsx'); var utils = require('../utils/utils.jsx'); @@ -642,17 +640,17 @@ var GeneralTab = React.createClass({ var user = this.props.user; var username = this.state.username.trim(); - var username_error = utils.isValidUsername(username); - if (username_error === 'Cannot use a reserved word as a username.') { - this.setState({client_error: 'This username is reserved, please choose a new one.' }); + var usernameError = utils.isValidUsername(username); + if (usernameError === 'Cannot use a reserved word as a username.') { + this.setState({clientError: 'This username is reserved, please choose a new one.'}); return; - } else if (username_error) { - this.setState({client_error: "Username must begin with a letter, and contain between 3 to 15 lowercase characters made up of numbers, letters, and the symbols '.', '-' and '_'." }); + } else if (usernameError) { + this.setState({clientError: "Username must begin with a letter, and contain between 3 to 15 lowercase characters made up of numbers, letters, and the symbols '.', '-' and '_'."}); return; } if (user.username === username) { - this.setState({client_error: 'You must submit a new username'}); + this.setState({clientError: 'You must submit a new username'}); return; } @@ -667,7 +665,7 @@ var GeneralTab = React.createClass({ var nickname = this.state.nickname.trim(); if (user.nickname === nickname) { - this.setState({client_error: 'You must submit a new nickname'}) + this.setState({clientError: 'You must submit a new nickname'}); return; } @@ -679,11 +677,11 @@ var GeneralTab = React.createClass({ e.preventDefault(); var user = UserStore.getCurrentUser(); - var firstName = this.state.first_name.trim(); - var lastName = this.state.last_name.trim(); + var firstName = this.state.firstName.trim(); + var lastName = this.state.lastName.trim(); if (user.first_name === firstName && user.last_name === lastName) { - this.setState({client_error: 'You must submit a new first or last name'}) + this.setState({clientError: 'You must submit a new first or last name'}); return; } @@ -703,7 +701,7 @@ var GeneralTab = React.createClass({ } if (email === '' || !utils.isEmail(email)) { - this.setState({ email_error: 'Please enter a valid email address' }); + this.setState({emailError: 'Please enter a valid email address'}); return; } @@ -718,11 +716,11 @@ var GeneralTab = React.createClass({ AsyncClient.getMe(); }.bind(this), function(err) { - state = this.getInitialState(); + var state = this.getInitialState(); if (err.message) { - state.server_error = err.message; + state.serverError = err.message; } else { - state.server_error = err; + state.serverError = err; } this.setState(state); }.bind(this) @@ -742,12 +740,13 @@ var GeneralTab = React.createClass({ var picture = this.state.picture; if (picture.type !== 'image/jpeg' && picture.type !== 'image/png') { - this.setState({client_error: 'Only JPG or PNG images may be used for profile pictures'}); + this.setState({clientError: 'Only JPG or PNG images may be used for profile pictures'}); return; } var formData = new FormData(); formData.append('image', picture, picture.name); + this.setState({loadingPicture: true}); client.uploadProfileImage(formData, function() { @@ -756,8 +755,8 @@ var GeneralTab = React.createClass({ window.location.reload(); }.bind(this), function(err) { - state = this.getInitialState(); - state.server_error = err; + var state = this.getInitialState(); + state.serverError = err; this.setState(state); }.bind(this) ); @@ -766,10 +765,10 @@ var GeneralTab = React.createClass({ this.setState({username: e.target.value}); }, updateFirstName: function(e) { - this.setState({first_name: e.target.value}); + this.setState({firstName: e.target.value}); }, updateLastName: function(e) { - this.setState({last_name: e.target.value}); + this.setState({lastName: e.target.value}); }, updateNickname: function(e) { this.setState({nickname: e.target.value}); @@ -779,17 +778,16 @@ var GeneralTab = React.createClass({ }, updatePicture: function(e) { if (e.target.files && e.target.files[0]) { - this.setState({ picture: e.target.files[0] }); + this.setState({picture: e.target.files[0]}); this.submitActive = true; - this.setState({client_error: null}); - + this.setState({clientError: null}); } else { this.setState({picture: null}); } }, updateSection: function(section) { - this.setState({client_error:''}); + this.setState({clientError: ''}); this.submitActive = false; this.props.updateSection(section); }, @@ -798,7 +796,7 @@ var GeneralTab = React.createClass({ this.value = ''; }); - this.setState(assign({}, this.getInitialState(), {client_error: null, server_error: null, email_error: null})); + this.setState(assign({}, this.getInitialState(), {clientError: null, serverError: null, emailError: null})); this.props.updateSection(''); }, componentDidMount: function() { @@ -810,15 +808,24 @@ var GeneralTab = React.createClass({ getInitialState: function() { var user = this.props.user; - return { username: user.username, first_name: user.first_name, last_name: user.last_name, nickname: user.nickname, - email: user.email, picture: null }; + return {username: user.username, firstName: user.first_name, lastName: user.last_name, nickname: user.nickname, + email: user.email, picture: null, loadingPicture: false}; }, render: function() { var user = this.props.user; - var client_error = this.state.client_error ? this.state.client_error : null; - var server_error = this.state.server_error ? this.state.server_error : null; - var email_error = this.state.email_error ? this.state.email_error : null; + var clientError = null; + if (this.state.clientError) { + clientError = this.state.clientError; + } + var serverError = null; + if (this.state.serverError) { + serverError = this.state.serverError; + } + var emailError = null; + if (this.state.emailError) { + emailError = this.state.emailError; + } var nameSection; var self = this; @@ -829,7 +836,7 @@ var GeneralTab = React.createClass({ <div className='form-group'> <label className='col-sm-5 control-label'>First Name</label> <div className='col-sm-7'> - <input className='form-control' type='text' onChange={this.updateFirstName} value={this.state.first_name}/> + <input className='form-control' type='text' onChange={this.updateFirstName} value={this.state.firstName}/> </div> </div> ); @@ -838,7 +845,7 @@ var GeneralTab = React.createClass({ <div className='form-group'> <label className='col-sm-5 control-label'>Last Name</label> <div className='col-sm-7'> - <input className='form-control' type='text' onChange={this.updateLastName} value={this.state.last_name}/> + <input className='form-control' type='text' onChange={this.updateLastName} value={this.state.lastName}/> </div> </div> ); @@ -848,8 +855,8 @@ var GeneralTab = React.createClass({ title='Full Name' inputs={inputs} submit={this.submitName} - server_error={server_error} - client_error={client_error} + server_error={serverError} + client_error={clientError} updateSection={function(e) { self.updateSection(''); e.preventDefault(); @@ -857,20 +864,20 @@ var GeneralTab = React.createClass({ /> ); } else { - var full_name = ''; + var fullName = ''; if (user.first_name && user.last_name) { - full_name = user.first_name + ' ' + user.last_name; + fullName = user.first_name + ' ' + user.last_name; } else if (user.first_name) { - full_name = user.first_name; + fullName = user.first_name; } else if (user.last_name) { - full_name = user.last_name; + fullName = user.last_name; } nameSection = ( <SettingItemMin title='Full Name' - describe={full_name} + describe={fullName} updateSection={function() { self.updateSection('name'); }} @@ -880,7 +887,6 @@ var GeneralTab = React.createClass({ var nicknameSection; if (this.props.activeSection === 'nickname') { - inputs.push( <div className='form-group'> <label className='col-sm-5 control-label'>{utils.isMobile() ? '' : 'Nickname'}</label> @@ -895,8 +901,8 @@ var GeneralTab = React.createClass({ title='Nickname' inputs={inputs} submit={this.submitNickname} - server_error={server_error} - client_error={client_error} + server_error={serverError} + client_error={clientError} updateSection={function(e) { self.updateSection(''); e.preventDefault(); @@ -919,7 +925,7 @@ var GeneralTab = React.createClass({ if (this.props.activeSection === 'username') { inputs.push( <div className='form-group'> - <label className='col-sm-5 control-label'>{utils.isMobile() ? '': 'Username'}</label> + <label className='col-sm-5 control-label'>{utils.isMobile() ? '' : 'Username'}</label> <div className='col-sm-7'> <input className='form-control' type='text' onChange={this.updateUsername} value={this.state.username}/> </div> @@ -931,8 +937,8 @@ var GeneralTab = React.createClass({ title='Username' inputs={inputs} submit={this.submitUsername} - server_error={server_error} - client_error={client_error} + server_error={serverError} + client_error={clientError} updateSection={function(e) { self.updateSection(''); e.preventDefault(); @@ -966,8 +972,8 @@ var GeneralTab = React.createClass({ title='Email' inputs={inputs} submit={this.submitEmail} - server_error={server_error} - client_error={email_error} + server_error={serverError} + client_error={emailError} updateSection={function(e) { self.updateSection(''); e.preventDefault(); @@ -993,8 +999,8 @@ var GeneralTab = React.createClass({ title='Profile Picture' submit={this.submitPicture} src={'/api/v1/users/' + user.id + '/image?time=' + user.last_picture_update} - server_error={server_error} - client_error={client_error} + server_error={serverError} + client_error={clientError} updateSection={function(e) { self.updateSection(''); e.preventDefault(); @@ -1002,6 +1008,7 @@ var GeneralTab = React.createClass({ picture={this.state.picture} pictureChange={this.updatePicture} submitActive={this.submitActive} + loadingPicture={this.state.loadingPicture} /> ); } else { diff --git a/web/sass-files/sass/partials/_base.scss b/web/sass-files/sass/partials/_base.scss index 52659521d..78006ff18 100644 --- a/web/sass-files/sass/partials/_base.scss +++ b/web/sass-files/sass/partials/_base.scss @@ -49,6 +49,12 @@ div.theme { background-color: $primary-color; } +.tooltip { + .tooltip-inner { + word-break: break-word; + } +} + .nopadding { padding: 0; margin: 0; @@ -61,6 +67,10 @@ div.theme { } } +.form-control[disabled], .form-control[readonly], fieldset[disabled] .form-control { + cursor: auto; +} + .form-group { &.form-group--small { margin-bottom: 10px; diff --git a/web/sass-files/sass/partials/_files.scss b/web/sass-files/sass/partials/_files.scss index ddc5e98bb..65775f01e 100644 --- a/web/sass-files/sass/partials/_files.scss +++ b/web/sass-files/sass/partials/_files.scss @@ -4,7 +4,8 @@ max-height: 110px; height: 110px; white-space: nowrap; - overflow: auto; + overflow-x: auto; + overflow-y: hidden; .preview-div { display: inline-block; width: 120px; @@ -28,9 +29,9 @@ } } .preview-img { - display: block; - height: auto; - max-width: 100%; + display: block; + height: auto; + max-width: 100%; } .remove-preview { position: absolute; @@ -114,8 +115,7 @@ height: 100px; float: left; margin: 5px 10px 5px 0; - @include display-flex; - display: -ms-flexbox; + display: table; border: 1px solid lightgrey; .post__load { height: 100%; @@ -130,17 +130,23 @@ background-color: #FFF; background-repeat: no-repeat; &.small { - background-position: center; + background-position: center; } &.normal { - background-position: top left; + background-position: top left; } } .post-image__thumbnail { + display: table-cell; + vertical-align: top; width: 50%; height: 100%; + cursor: zoom-in; + cursor: -webkit-zoom-in; } .post-image__details { + display: table-cell; + vertical-align: top; width: 50%; height: 100%; background: white; @@ -165,34 +171,34 @@ } .file-details__container { - @include display-flex; - display: -ms-flexbox; + @include display-flex; + display: -ms-flexbox; - .file-details { - width: 320px; - height: 270px; - padding: 14px; - text-align: left; - vertical-align: top; + .file-details { + width: 320px; + height: 270px; + padding: 14px; + text-align: left; + vertical-align: top; - .file-details__name { - font-size: 16px; - } - .file-details__info { - color: grey; - } + .file-details__name { + font-size: 16px; + } + .file-details__info { + color: grey; } - .file-details__preview { - width: 320px; - height: 270px; - border-right: 1px solid #ddd; - vertical-align: center; + } + .file-details__preview { + width: 320px; + height: 270px; + border-right: 1px solid #ddd; + vertical-align: center; // helper to center the image icon in the preview window .file-details__preview-helper { - height: 100%; - display: inline-block; - vertical-align: middle; + height: 100%; + display: inline-block; + vertical-align: middle; } + } } -} diff --git a/web/sass-files/sass/partials/_headers.scss b/web/sass-files/sass/partials/_headers.scss index fb37c43eb..da648a170 100644 --- a/web/sass-files/sass/partials/_headers.scss +++ b/web/sass-files/sass/partials/_headers.scss @@ -110,6 +110,20 @@ } } } + &.theme--black { + &:hover { + &:before { + background: rgba(white, 0.2); + } + } + } + &.theme--gray { + &:hover { + &:before { + background: rgba(white, 0.1); + } + } + } a { color: #fff; } diff --git a/web/sass-files/sass/partials/_modal.scss b/web/sass-files/sass/partials/_modal.scss index f359037c5..014f834ed 100644 --- a/web/sass-files/sass/partials/_modal.scss +++ b/web/sass-files/sass/partials/_modal.scss @@ -15,10 +15,13 @@ } .remove__member { float: right; - color: #E56565; + color: #999; font-size: 20px; line-height: 0; padding: 6px; + &:hover { + color: #E56565; + } } .modal-dialog { max-width: 95%; @@ -151,10 +154,9 @@ height: 100%; margin: 0 auto; .image-wrapper { - background: #FFF; position: relative; max-width: 90%; - min-height: 50px; + min-height: 100px; min-width: 320px; @include border-radius(3px); display: table; @@ -182,6 +184,7 @@ z-index: 9999; } > a { + background: #FFF; display: table-cell; vertical-align: middle; } diff --git a/web/sass-files/sass/partials/_navbar.scss b/web/sass-files/sass/partials/_navbar.scss index 905907d84..2e78a8728 100644 --- a/web/sass-files/sass/partials/_navbar.scss +++ b/web/sass-files/sass/partials/_navbar.scss @@ -19,6 +19,7 @@ } } .navbar-toggle { + width: 43px; float: left; border-color: transparent; border-radius: 0; diff --git a/web/sass-files/sass/partials/_popover.scss b/web/sass-files/sass/partials/_popover.scss index fa1b44841..5008331b4 100644 --- a/web/sass-files/sass/partials/_popover.scss +++ b/web/sass-files/sass/partials/_popover.scss @@ -6,4 +6,11 @@ .user-popover__image { margin: 0 0 10px; @include border-radius(128px); +} + +.user-popover__email { + max-width: 200px; + overflow: hidden; + text-overflow: ellipsis; + display: block; }
\ No newline at end of file diff --git a/web/sass-files/sass/partials/_responsive.scss b/web/sass-files/sass/partials/_responsive.scss index e3f140413..47b2b6bd7 100644 --- a/web/sass-files/sass/partials/_responsive.scss +++ b/web/sass-files/sass/partials/_responsive.scss @@ -229,6 +229,16 @@ } } +@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) { .date-separator, .new-separator { &.hovered--after { diff --git a/web/sass-files/sass/partials/_signup.scss b/web/sass-files/sass/partials/_signup.scss index 4b6ee79a1..3a6f73316 100644 --- a/web/sass-files/sass/partials/_signup.scss +++ b/web/sass-files/sass/partials/_signup.scss @@ -54,6 +54,28 @@ margin-bottom: 1em; } + .input-group { + &.input-group--limit { + table-layout: fixed; + width: 100%; + .tooltip-inner { + word-wrap: break-word; + } + .form-control { + text-align: left; + display: table-cell; + width: 100%; + } + .input-group-addon { + text-align: left; + width: 50%; + display: table-cell; + overflow: hidden; + text-overflow: ellipsis; + } + } + } + .inner__content { padding: 0 15px; margin: 30px 0 20px; diff --git a/web/templates/channel.html b/web/templates/channel.html index 6325069ee..da6fed97d 100644 --- a/web/templates/channel.html +++ b/web/templates/channel.html @@ -49,7 +49,9 @@ <div id="activity_log_modal"></div> <div id="removed_from_channel_modal"></div> <script> -window.setup_channel_page('{{ .Props.TeamDisplayName }}', '{{ .Props.TeamType }}', '{{ .Props.TeamId }}', '{{ .Props.ChannelName }}', '{{ .Props.ChannelId }}'); + window.setup_channel_page('{{ .Props.TeamDisplayName }}', '{{ .Props.TeamType }}', '{{ .Props.TeamId }}', '{{ .Props.ChannelName }}', '{{ .Props.ChannelId }}'); + $('body').tooltip( {selector: '[data-toggle=tooltip]'} ); + $('.modal-body').perfectScrollbar(); </script> </body> </html> diff --git a/web/templates/signup_team.html b/web/templates/signup_team.html index b84b8e486..313ed9d5f 100644 --- a/web/templates/signup_team.html +++ b/web/templates/signup_team.html @@ -10,7 +10,7 @@ <div class="signup-team__container"> <img class="signup-team-logo" src="/static/images/logo.png" /> <h1>Mattermost</h1> - <h4 class="color--light">All team communication in one place, searchable and accesible anywhere</h4> + <h4 class="color--light">All team communication in one place, searchable and accessible anywhere</h4> <div id="signup-team"></div> </div> </div> |