diff --git a/skins/base/css/molecules/MemberInfo.css b/skins/base/css/molecules/MemberInfo.css new file mode 100644 index 00000000..32442305 --- /dev/null +++ b/skins/base/css/molecules/MemberInfo.css @@ -0,0 +1,61 @@ +/* +Copyright 2015 OpenMarket Ltd + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +.mx_MemberInfo { + text-align: center; + border: 1px solid #a9dbf4; + border-radius: 8px; + background-color: #fff; + position: absolute; + width: 200px; + margin-left: -295px; + margin-top: -12px; + z-index: 1000; + padding: 6px; +} + +.mx_MemberInfo_chevron { + padding: 12px; + position: absolute; + right: -21px; + top: 0px; +} + +.mx_MemberInfo_avatar { + padding: 6px; +} + +.mx_MemberInfo_avatarImg { + border-radius: 128px; +} + +.mx_MemberInfo_field { + padding: 6px; + font-weight: bold; +} + +.mx_MemberInfo_button { + vertical-align: middle; + max-width: 100px; + height: 36px; + background-color: #50e3c2; + line-height: 36px; + border-radius: 36px; + color: #fff; + margin: auto; + margin-top: 6px; + margin-bottom: 6px; +} diff --git a/skins/base/css/molecules/RoomTile.css b/skins/base/css/molecules/RoomTile.css index 43f05440..d43945c3 100644 --- a/skins/base/css/molecules/RoomTile.css +++ b/skins/base/css/molecules/RoomTile.css @@ -82,16 +82,12 @@ limitations under the License. bottom: 3px; } -.mx_RoomTile_unread { - font-weight: bold; -} - -.mx_RoomTile_highlight { - font-weight: bold; -} - -.mx_RoomTile_invited { +.mx_RoomTile_unread, +.mx_RoomTile_highlight, +.mx_RoomTile_invited +{ font-weight: bold; + color: #000; } .mx_RoomTile_selected { diff --git a/skins/base/css/organisms/MemberList.css b/skins/base/css/organisms/MemberList.css index f65fec81..b56e3f11 100644 --- a/skins/base/css/organisms/MemberList.css +++ b/skins/base/css/organisms/MemberList.css @@ -39,7 +39,7 @@ limitations under the License. .mx_MemberList_wrapper { display: table; table-layout: fixed; - width: 100%; + width: 100%; } .mx_MemberList h2 { diff --git a/skins/base/img/chevron-right.png b/skins/base/img/chevron-right.png new file mode 100644 index 00000000..1fe5d347 Binary files /dev/null and b/skins/base/img/chevron-right.png differ diff --git a/skins/base/views/molecules/DirectoryMenu.js b/skins/base/views/molecules/DirectoryMenu.js index 461ec1c6..8ffb4180 100644 --- a/skins/base/views/molecules/DirectoryMenu.js +++ b/skins/base/views/molecules/DirectoryMenu.js @@ -29,6 +29,7 @@ module.exports = React.createClass({ displayName: 'DirectoryMenu', // mixins: [DirectoryMenuController], + // FIXME: should these onClicks be in the controller instead? onSettingsClick: function() { dis.dispatch({action: 'view_user_settings'}); }, diff --git a/skins/base/views/molecules/MemberInfo.js b/skins/base/views/molecules/MemberInfo.js new file mode 100644 index 00000000..19e0dc46 --- /dev/null +++ b/skins/base/views/molecules/MemberInfo.js @@ -0,0 +1,50 @@ +/* +Copyright 2015 OpenMarket Ltd + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +'use strict'; + +var React = require('react'); + +var MatrixClientPeg = require("../../../../src/MatrixClientPeg"); +//var MemberInfoController = require("../../../../src/controllers/molecules/MemberInfo"); + +module.exports = React.createClass({ + displayName: 'MemberInfo', + //mixins: [MemberInfoController], + + render: function() { + var power; + if (this.props.member) { + var img = "img/p/p" + Math.floor(20 * this.props.member.powerLevelNorm / 100) + ".png"; + power = <img src={ img } className="mx_MemberTile_power" width="48" height="48" alt=""/>; + } + + return ( + <div className="mx_MemberInfo"> + <img className="mx_MemberInfo_chevron" src="img/chevron-right.png" width="9" height="16" /> + <div className="mx_MemberInfo_avatar"> + <img className="mx_MemberInfo_avatarImg" + src={ this.props.member ? MatrixClientPeg.get().getAvatarUrlForMember(this.props.member, 128, 128, "crop") : null } + width="128" height="128" alt=""/> + </div> + <div className="mx_MemberInfo_field">{this.props.member.userId}</div> + <div className="mx_MemberInfo_field">Presence: {this.props.member.presence}</div> + <div className="mx_MemberInfo_field">Last active: {this.props.member.last_active_ago}</div> + <div className="mx_MemberInfo_button">Start chat</div> + </div> + ); + } +}); diff --git a/skins/base/views/molecules/MemberTile.js b/skins/base/views/molecules/MemberTile.js index 84609932..4e00f2af 100644 --- a/skins/base/views/molecules/MemberTile.js +++ b/skins/base/views/molecules/MemberTile.js @@ -19,11 +19,27 @@ limitations under the License. var React = require('react'); var MatrixClientPeg = require("../../../../src/MatrixClientPeg"); +var ComponentBroker = require('../../../../src/ComponentBroker'); var MemberTileController = require("../../../../src/controllers/molecules/MemberTile"); +var MemberInfo = ComponentBroker.get('molecules/MemberInfo'); module.exports = React.createClass({ displayName: 'MemberTile', mixins: [MemberTileController], + + // XXX: should these be in the controller? + getInitialState: function() { + return { 'hover': false }; + }, + + mouseEnter: function(e) { + this.setState({ 'hover': true }); + }, + + mouseLeave: function(e) { + this.setState({ 'hover': false }); + }, + render: function() { var power; if (this.props.member) { @@ -32,9 +48,17 @@ module.exports = React.createClass({ } return ( - <div className="mx_MemberTile"> - <div className="mx_MemberTile_avatar"><img className="mx_MemberTile_avatarImg" src={ this.props.member ? MatrixClientPeg.get().getAvatarUrlForMember(this.props.member, 40, 40, "crop") : null } width="40" height="40" alt=""/>{ power }</div> - <div className="mx_MemberTile_name">{this.props.member.name}</div> + <div className="mx_MemberTile" onMouseEnter={ this.mouseEnter } onMouseLeave={ this.mouseLeave } > + <div className="mx_MemberTile_avatar"> + <img className="mx_MemberTile_avatarImg" + src={ this.props.member ? MatrixClientPeg.get().getAvatarUrlForMember(this.props.member, 40, 40, "crop") : null } + width="40" height="40" alt=""/> + { power } + </div> + <div className="mx_MemberTile_name"> + { this.state.hover ? <MemberInfo member={this.props.member} /> : null } + {this.props.member.name} + </div> </div> ); } diff --git a/src/ComponentBroker.js b/src/ComponentBroker.js index db1915ea..342a5393 100644 --- a/src/ComponentBroker.js +++ b/src/ComponentBroker.js @@ -107,6 +107,5 @@ require('../skins/base/views/molecules/voip/MCallInviteTile'); require('../skins/base/views/molecules/voip/MCallAnswerTile'); require('../skins/base/views/molecules/voip/MCallHangupTile'); require('../skins/base/views/molecules/EventAsTextTile'); - - +require('../skins/base/views/molecules/MemberInfo'); }