improve collapsed LHS implementation - split the tooltip into its own component; position it with javascript as overflow-y + position absolute = clipping hell; preserve the collapse state between MatrixChat re-renders; fix positioning of the 'show' button; switch to dispatcher for show/hide LHS; remove errant scrollbars

This commit is contained in:
Matthew Hodgson 2015-10-11 13:54:38 +01:00
parent 8bdb5c0745
commit 93de2307c1
12 changed files with 128 additions and 62 deletions

View File

@ -52,6 +52,11 @@ module.exports = {
case 'call_state': case 'call_state':
this._recheckCallElement(this.props.selectedRoom); this._recheckCallElement(this.props.selectedRoom);
break; break;
case 'view_tooltip':
this.tooltip = payload.tooltip;
this._repositionTooltip();
if (this.tooltip) this.tooltip.style.display = 'block';
break
} }
}, },
@ -150,6 +155,13 @@ module.exports = {
}); });
}, },
_repositionTooltip: function(e) {
if (this.tooltip && this.tooltip.parentElement) {
var scroll = this.getDOMNode();
this.tooltip.style.top = (scroll.parentElement.offsetTop + this.tooltip.parentElement.offsetTop - scroll.scrollTop) + "px";
}
},
makeRoomTiles: function() { makeRoomTiles: function() {
var self = this; var self = this;
var RoomTile = sdk.getComponent("molecules.RoomTile"); var RoomTile = sdk.getComponent("molecules.RoomTile");

View File

@ -16,7 +16,7 @@ limitations under the License.
.mx_RoomTile { .mx_RoomTile {
cursor: pointer; cursor: pointer;
display: table-row; /* display: table-row; */
color: #818794; color: #818794;
} }
@ -45,27 +45,6 @@ limitations under the License.
padding-right: 16px; padding-right: 16px;
} }
.mx_RoomTile_tooltip {
border: 1px solid #a9dbf4;
border-radius: 8px;
background-color: #fff;
position: absolute;
z-index: 1000;
margin-top: 6px;
left: 64px;
padding: 6px;
}
.mx_RoomTile_chevron {
position: absolute;
left: -9px;
top: 8px;
}
.mx_RoomTile_tooltip {
position: absolute;
}
.collapsed .mx_RoomTile_name { .collapsed .mx_RoomTile_name {
display: none; display: none;
} }

View File

@ -0,0 +1,33 @@
/*
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_RoomTooltip {
display: none;
position: fixed;
border: 1px solid #a9dbf4;
border-radius: 8px;
background-color: #fff;
z-index: 1000;
margin-top: 6px;
left: 64px;
padding: 6px;
}
.mx_RoomTooltip_chevron {
position: absolute;
left: -9px;
top: 8px;
}

View File

@ -33,13 +33,6 @@ limitations under the License.
cursor: pointer; cursor: pointer;
} }
.mx_LeftPanel_showButton {
position: absolute;
top: 18px;
left: 16px;
cursor: pointer;
}
.mx_LeftPanel .mx_RoomList { .mx_LeftPanel .mx_RoomList {
-webkit-box-ordinal-group: 1; -webkit-box-ordinal-group: 1;
-moz-box-ordinal-group: 1; -moz-box-ordinal-group: 1;
@ -47,7 +40,7 @@ limitations under the License.
-webkit-order: 1; -webkit-order: 1;
order: 1; order: 1;
overflow-y: scroll; overflow-y: auto;
-webkit-flex: 1 1 0; -webkit-flex: 1 1 0;
flex: 1 1 0; flex: 1 1 0;
} }
@ -69,10 +62,6 @@ limitations under the License.
color: #378bb4; color: #378bb4;
} }
.mx_LeftPanel .mx_BottomLeftMenu .mx_RoomTile_avatar {
padding-left: 14px;
}
.mx_LeftPanel .mx_BottomLeftMenu .mx_BottomLeftMenu_options { .mx_LeftPanel .mx_BottomLeftMenu .mx_BottomLeftMenu_options {
margin-top: 12px; margin-top: 12px;
width: 100%; width: 100%;

View File

@ -57,7 +57,7 @@ limitations under the License.
} }
.mx_RoomDirectory_tableWrapper { .mx_RoomDirectory_tableWrapper {
overflow-y: scroll; overflow-y: auto;
-webkit-flex: 1 1 0; -webkit-flex: 1 1 0;
flex: 1 1 0; flex: 1 1 0;
} }

View File

@ -109,7 +109,7 @@ limitations under the License.
margin-top: 18px; margin-top: 18px;
margin-bottom: 18px; margin-bottom: 18px;
overflow-y: scroll; overflow-y: auto;
} }
.mx_RoomView_messageListWrapper { .mx_RoomView_messageListWrapper {

View File

@ -57,6 +57,7 @@ skin['molecules.RoomDropTarget'] = require('./views/molecules/RoomDropTarget');
skin['molecules.RoomHeader'] = require('./views/molecules/RoomHeader'); skin['molecules.RoomHeader'] = require('./views/molecules/RoomHeader');
skin['molecules.RoomSettings'] = require('./views/molecules/RoomSettings'); skin['molecules.RoomSettings'] = require('./views/molecules/RoomSettings');
skin['molecules.RoomTile'] = require('./views/molecules/RoomTile'); skin['molecules.RoomTile'] = require('./views/molecules/RoomTile');
skin['molecules.RoomTooltip'] = require('./views/molecules/RoomTooltip');
skin['molecules.SenderProfile'] = require('./views/molecules/SenderProfile'); skin['molecules.SenderProfile'] = require('./views/molecules/SenderProfile');
skin['molecules.ServerConfig'] = require('./views/molecules/ServerConfig'); skin['molecules.ServerConfig'] = require('./views/molecules/ServerConfig');
skin['molecules.UnknownMessageTile'] = require('./views/molecules/UnknownMessageTile'); skin['molecules.UnknownMessageTile'] = require('./views/molecules/UnknownMessageTile');

View File

@ -71,15 +71,13 @@ module.exports = React.createClass({
} }
*/ */
var nameElement; var label;
if (!this.props.collapsed) { if (!this.props.collapsed) {
nameElement = <div className="mx_RoomTile_name">{name}</div>; label = <div className="mx_RoomTile_name">{name}</div>;
} }
else if (this.state.hover) { else if (this.state.hover) {
nameElement = <div className="mx_RoomTile_tooltip"> var RoomTooltip = sdk.getComponent("molecules.RoomTooltip");
<img className="mx_RoomTile_chevron" src="img/chevron-left.png" width="9" height="16"/> label = <RoomTooltip room={this.props.room} ref="roomTooltip"/>;
{ name }
</div>;
} }
var RoomAvatar = sdk.getComponent('atoms.RoomAvatar'); var RoomAvatar = sdk.getComponent('atoms.RoomAvatar');
@ -89,7 +87,7 @@ module.exports = React.createClass({
<RoomAvatar room={this.props.room} /> <RoomAvatar room={this.props.room} />
{ badge } { badge }
</div> </div>
{ nameElement } { label }
</div> </div>
); );
} }

View File

@ -0,0 +1,53 @@
/*
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 classNames = require('classnames');
var MatrixClientPeg = require('matrix-react-sdk/lib/MatrixClientPeg');
var sdk = require('matrix-react-sdk')
var dis = require('matrix-react-sdk/lib/dispatcher');
module.exports = React.createClass({
displayName: 'RoomTooltip',
componentDidMount: function() {
// tell the roomlist about us
dis.dispatch({
action: 'view_tooltip',
tooltip: this.getDOMNode(),
});
},
componentDidUnmount: function() {
dis.dispatch({
action: 'view_tooltip',
tooltip: null,
});
},
render: function() {
return (
<div className="mx_RoomTooltip">
<img className="mx_RoomTooltip_chevron" src="img/chevron-left.png" width="9" height="16"/>
{ this.props.room.name }
</div>
);
}
});

View File

@ -18,22 +18,15 @@ limitations under the License.
var React = require('react'); var React = require('react');
var sdk = require('matrix-react-sdk') var sdk = require('matrix-react-sdk')
var dis = require('matrix-react-sdk/lib/dispatcher');
module.exports = React.createClass({ module.exports = React.createClass({
displayName: 'LeftPanel', displayName: 'LeftPanel',
getInitialState: function() {
return {
collapsed: false,
};
},
onShowClick: function() {
this.setState({ collapsed : false });
},
onHideClick: function() { onHideClick: function() {
this.setState({ collapsed : true }); dis.dispatch({
action: 'hide_left_panel',
});
}, },
render: function() { render: function() {
@ -43,9 +36,8 @@ module.exports = React.createClass({
var collapseButton; var collapseButton;
var classes = "mx_LeftPanel"; var classes = "mx_LeftPanel";
if (this.state.collapsed) { if (this.props.collapsed) {
classes += " collapsed"; classes += " collapsed";
collapseButton = <img className="mx_LeftPanel_showButton" onClick={ this.onShowClick } src="img/menu.png" width="27" height="20" alt=">"/>
} }
else { else {
collapseButton = <img className="mx_LeftPanel_hideButton" onClick={ this.onHideClick } src="img/hide.png" width="12" height="20" alt="<"/> collapseButton = <img className="mx_LeftPanel_hideButton" onClick={ this.onHideClick } src="img/hide.png" width="12" height="20" alt="<"/>
@ -55,7 +47,7 @@ module.exports = React.createClass({
<aside className={classes}> <aside className={classes}>
{ collapseButton } { collapseButton }
<IncomingCallBox /> <IncomingCallBox />
<RoomList selectedRoom={this.props.selectedRoom} collapsed={this.state.collapsed}/> <RoomList selectedRoom={this.props.selectedRoom} collapsed={this.props.collapsed}/>
<BottomLeftMenu /> <BottomLeftMenu />
</aside> </aside>
); );

View File

@ -18,6 +18,7 @@ limitations under the License.
var React = require('react'); var React = require('react');
var sdk = require('matrix-react-sdk') var sdk = require('matrix-react-sdk')
var dis = require('matrix-react-sdk/lib/dispatcher');
var RoomListController = require('../../../../controllers/organisms/RoomList') var RoomListController = require('../../../../controllers/organisms/RoomList')
@ -25,6 +26,12 @@ module.exports = React.createClass({
displayName: 'RoomList', displayName: 'RoomList',
mixins: [RoomListController], mixins: [RoomListController],
onShowClick: function() {
dis.dispatch({
action: 'show_left_panel',
});
},
render: function() { render: function() {
var CallView = sdk.getComponent('molecules.voip.CallView'); var CallView = sdk.getComponent('molecules.voip.CallView');
var RoomDropTarget = sdk.getComponent('molecules.RoomDropTarget'); var RoomDropTarget = sdk.getComponent('molecules.RoomDropTarget');
@ -34,15 +41,17 @@ module.exports = React.createClass({
callElement = <CallView className="mx_MatrixChat_callView"/> callElement = <CallView className="mx_MatrixChat_callView"/>
} }
var recentsLabel = this.props.collapsed ? "" : "Recents"; var recentsLabel = this.props.collapsed ?
<img onClick={ this.onShowClick } src="img/menu.png" width="27" height="20" alt=">"/> :
"Recents";
return ( return (
<div className="mx_RoomList"> <div className="mx_RoomList" onScroll={this._repositionTooltip}>
{callElement} {callElement}
<h2 className="mx_RoomList_favourites_label">Favourites</h2> <h2 className="mx_RoomList_favourites_label">Favourites</h2>
<RoomDropTarget text="Drop here to favourite"/> <RoomDropTarget text="Drop here to favourite"/>
<h2 className="mx_RoomList_recents_label">{ recentsLabel }&nbsp;</h2> <h2 className="mx_RoomList_recents_label">{ recentsLabel }</h2>
<div className="mx_RoomList_recents"> <div className="mx_RoomList_recents">
{this.makeRoomTiles()} {this.makeRoomTiles()}
</div> </div>

View File

@ -79,7 +79,7 @@ module.exports = React.createClass({
<div className="mx_MatrixChat_wrapper"> <div className="mx_MatrixChat_wrapper">
<MatrixToolbar /> <MatrixToolbar />
<div className="mx_MatrixChat mx_MatrixChat_toolbarShowing"> <div className="mx_MatrixChat mx_MatrixChat_toolbarShowing">
<LeftPanel selectedRoom={this.state.currentRoom} /> <LeftPanel selectedRoom={this.state.currentRoom} collapsed={this.state.collapse_lhs} />
<main className="mx_MatrixChat_middlePanel"> <main className="mx_MatrixChat_middlePanel">
{page_element} {page_element}
</main> </main>
@ -91,7 +91,7 @@ module.exports = React.createClass({
else { else {
return ( return (
<div className="mx_MatrixChat"> <div className="mx_MatrixChat">
<LeftPanel selectedRoom={this.state.currentRoom} /> <LeftPanel selectedRoom={this.state.currentRoom} collapsed={this.state.collapse_lhs} />
<main className="mx_MatrixChat_middlePanel"> <main className="mx_MatrixChat_middlePanel">
{page_element} {page_element}
</main> </main>