From 5531f274354df79980152d05521a23114cb5d25b Mon Sep 17 00:00:00 2001 From: David Baker Date: Wed, 26 Apr 2017 18:59:16 +0100 Subject: [PATCH 01/13] Make the left panel more friendly to new users https://github.com/vector-im/riot-web/issues/3609 Conflicts: src/components/views/rooms/RoomList.js cherry-picking commit f5f35e3. --- src/components/views/rooms/RoomList.js | 163 +++++++++++++++++++------ 1 file changed, 124 insertions(+), 39 deletions(-) diff --git a/src/components/views/rooms/RoomList.js b/src/components/views/rooms/RoomList.js index 760b0543c6..9dfa99fb44 100644 --- a/src/components/views/rooms/RoomList.js +++ b/src/components/views/rooms/RoomList.js @@ -29,7 +29,14 @@ var Rooms = require('../../../Rooms'); import DMRoomMap from '../../../utils/DMRoomMap'; var Receipt = require('../../../utils/Receipt'); -var HIDE_CONFERENCE_CHANS = true; +const HIDE_CONFERENCE_CHANS = true; + +const VERBS = { + 'm.favourite': 'favourite', + 'im.vector.fake.direct': 'tag direct chat', + 'im.vector.fake.recent': 'restore', + 'm.lowpriority': 'demote', +}; module.exports = React.createClass({ displayName: 'RoomList', @@ -44,6 +51,7 @@ module.exports = React.createClass({ getInitialState: function() { return { isLoadingLeftRooms: false, + totalRoomCount: null, lists: {}, incomingCall: null, }; @@ -63,8 +71,17 @@ module.exports = React.createClass({ cli.on("RoomMember.name", this.onRoomMemberName); cli.on("accountData", this.onAccountData); - var s = this.getRoomLists(); - this.setState(s); + // lookup for which lists a given roomId is currently in. + this.listsForRoomId = {}; + + this.refreshRoomList(); + + // order of the sublists + //this.listOrder = []; + + // loop count to stop a stack overflow if the user keeps waggling the + // mouse for >30s in a row, or if running under mocha + this._delayedRefreshRoomListLoopCount = 0 }, componentDidMount: function() { @@ -202,31 +219,33 @@ module.exports = React.createClass({ }, 500), refreshRoomList: function() { - // console.log("DEBUG: Refresh room list delta=%s ms", - // (!this._lastRefreshRoomListTs ? "-" : (Date.now() - this._lastRefreshRoomListTs)) - // ); - - // TODO: rather than bluntly regenerating and re-sorting everything - // every time we see any kind of room change from the JS SDK - // we could do incremental updates on our copy of the state - // based on the room which has actually changed. This would stop - // us re-rendering all the sublists every time anything changes anywhere - // in the state of the client. - this.setState(this.getRoomLists()); + // TODO: ideally we'd calculate this once at start, and then maintain + // any changes to it incrementally, updating the appropriate sublists + // as needed. + // Alternatively we'd do something magical with Immutable.js or similar. + const lists = this.getRoomLists(); + let totalRooms = 0; + for (const l of Object.values(lists)) { + totalRooms += l.length; + } + this.setState({ + lists: this.getRoomLists(), + totalRoomCount: totalRooms, + }); // this._lastRefreshRoomListTs = Date.now(); }, getRoomLists: function() { var self = this; - var s = { lists: {} }; + const lists = {}; - s.lists["im.vector.fake.invite"] = []; - s.lists["m.favourite"] = []; - s.lists["im.vector.fake.recent"] = []; - s.lists["im.vector.fake.direct"] = []; - s.lists["m.lowpriority"] = []; - s.lists["im.vector.fake.archived"] = []; + lists["im.vector.fake.invite"] = []; + lists["m.favourite"] = []; + lists["im.vector.fake.recent"] = []; + lists["im.vector.fake.direct"] = []; + lists["m.lowpriority"] = []; + lists["im.vector.fake.archived"] = []; const dmRoomMap = new DMRoomMap(MatrixClientPeg.get()); @@ -240,7 +259,8 @@ module.exports = React.createClass({ // ", prevMembership = " + me.events.member.getPrevContent().membership); if (me.membership == "invite") { - s.lists["im.vector.fake.invite"].push(room); + self.listsForRoomId[room.roomId].push("im.vector.fake.invite"); + lists["im.vector.fake.invite"].push(room); } else if (HIDE_CONFERENCE_CHANS && Rooms.isConfCallRoom(room, me, self.props.ConferenceHandler)) { // skip past this room & don't put it in any lists @@ -254,48 +274,55 @@ module.exports = React.createClass({ if (tagNames.length) { for (var i = 0; i < tagNames.length; i++) { var tagName = tagNames[i]; - s.lists[tagName] = s.lists[tagName] || []; - s.lists[tagNames[i]].push(room); + lists[tagName] = lists[tagName] || []; + lists[tagName].push(room); + self.listsForRoomId[room.roomId].push(tagName); + otherTagNames[tagName] = 1; } } else if (dmRoomMap.getUserIdForRoomId(room.roomId)) { // "Direct Message" rooms (that we're still in and that aren't otherwise tagged) - s.lists["im.vector.fake.direct"].push(room); + self.listsForRoomId[room.roomId].push("im.vector.fake.direct"); + lists["im.vector.fake.direct"].push(room); } else { - s.lists["im.vector.fake.recent"].push(room); + self.listsForRoomId[room.roomId].push("im.vector.fake.recent"); + lists["im.vector.fake.recent"].push(room); } } else if (me.membership === "leave") { - s.lists["im.vector.fake.archived"].push(room); + self.listsForRoomId[room.roomId].push("im.vector.fake.archived"); + lists["im.vector.fake.archived"].push(room); } else { console.error("unrecognised membership: " + me.membership + " - this should never happen"); } }); - if (s.lists["im.vector.fake.direct"].length == 0 && + if (lists["im.vector.fake.direct"].length == 0 && MatrixClientPeg.get().getAccountData('m.direct') === undefined && !MatrixClientPeg.get().isGuest()) { // scan through the 'recents' list for any rooms which look like DM rooms // and make them DM rooms - const oldRecents = s.lists["im.vector.fake.recent"]; - s.lists["im.vector.fake.recent"] = []; + const oldRecents = lists["im.vector.fake.recent"]; + lists["im.vector.fake.recent"] = []; for (const room of oldRecents) { const me = room.getMember(MatrixClientPeg.get().credentials.userId); if (me && Rooms.looksLikeDirectMessageRoom(room, me)) { - s.lists["im.vector.fake.direct"].push(room); + self.listsForRoomId[room.roomId].push("im.vector.fake.direct"); + lists["im.vector.fake.direct"].push(room); } else { - s.lists["im.vector.fake.recent"].push(room); + self.listsForRoomId[room.roomId].push("im.vector.fake.recent"); + lists["im.vector.fake.recent"].push(room); } } // save these new guessed DM rooms into the account data const newMDirectEvent = {}; - for (const room of s.lists["im.vector.fake.direct"]) { + for (const room of lists["im.vector.fake.direct"]) { const me = room.getMember(MatrixClientPeg.get().credentials.userId); const otherPerson = Rooms.getOnlyOtherMember(room, me); if (!otherPerson) continue; @@ -313,7 +340,22 @@ module.exports = React.createClass({ // we actually apply the sorting to this when receiving the prop in RoomSubLists. - return s; + // we'll need this when we get to iterating through lists programatically - e.g. ctrl-shift-up/down +/* + this.listOrder = [ + "im.vector.fake.invite", + "m.favourite", + "im.vector.fake.recent", + "im.vector.fake.direct", + Object.keys(otherTagNames).filter(tagName=>{ + return (!tagName.match(/^m\.(favourite|lowpriority)$/)); + }).sort(), + "m.lowpriority", + "im.vector.fake.archived" + ]; +*/ + + return lists; }, _getScrollNode: function() { @@ -467,6 +509,49 @@ module.exports = React.createClass({ this.refs.gemscroll.forceUpdate(); }, + _getEmptyContent: function(section) { + let greyed = false; + if (this.state.totalRoomCount === 0) { + const TintableSvg = sdk.getComponent('elements.TintableSvg'); + switch (section) { + case 'm.favourite': + case 'm.lowpriority': + greyed = true; + break; + case 'im.vector.fake.direct': + return
+
+ +
+ Use the button below to chat with someone! +
; + case 'im.vector.fake.recent': + return
+
+ +
+ Use the button below to browse the room directory +

+
+ +
+ or this button to start a new one! +
; + } + } + const RoomDropTarget = sdk.getComponent('rooms.RoomDropTarget'); + + const labelText = 'Drop here to ' + (VERBS[section] || 'tag ' + section); + + let label; + if (greyed) { + label = {labelText}; + } else { + label = labelText; + } + return ; + }, + render: function() { var RoomSubList = sdk.getComponent('structures.RoomSubList'); var self = this; @@ -489,7 +574,7 @@ module.exports = React.createClass({ Date: Fri, 28 Apr 2017 11:20:29 +0100 Subject: [PATCH 02/13] Other empty sections no longer need to be greyed --- src/components/views/rooms/RoomList.js | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/src/components/views/rooms/RoomList.js b/src/components/views/rooms/RoomList.js index 9dfa99fb44..e285c1841e 100644 --- a/src/components/views/rooms/RoomList.js +++ b/src/components/views/rooms/RoomList.js @@ -510,14 +510,9 @@ module.exports = React.createClass({ }, _getEmptyContent: function(section) { - let greyed = false; if (this.state.totalRoomCount === 0) { const TintableSvg = sdk.getComponent('elements.TintableSvg'); switch (section) { - case 'm.favourite': - case 'm.lowpriority': - greyed = true; - break; case 'im.vector.fake.direct': return
@@ -543,13 +538,7 @@ module.exports = React.createClass({ const labelText = 'Drop here to ' + (VERBS[section] || 'tag ' + section); - let label; - if (greyed) { - label = {labelText}; - } else { - label = labelText; - } - return ; + return ; }, render: function() { From bff0577cb61bfb8095c23254f618d9bb9a42a131 Mon Sep 17 00:00:00 2001 From: David Baker Date: Thu, 4 May 2017 13:55:52 +0100 Subject: [PATCH 03/13] Add buttons to room sub list headers Conflicts: src/component-index.js src/components/views/rooms/RoomList.js cherry-picking commit ce119a6. --- src/components/views/elements/RoleButton.js | 75 +++++++++++++++++++++ src/components/views/rooms/RoomList.js | 40 +++++++---- 2 files changed, 102 insertions(+), 13 deletions(-) create mode 100644 src/components/views/elements/RoleButton.js diff --git a/src/components/views/elements/RoleButton.js b/src/components/views/elements/RoleButton.js new file mode 100644 index 0000000000..06006a5779 --- /dev/null +++ b/src/components/views/elements/RoleButton.js @@ -0,0 +1,75 @@ +/* +Copyright Vector Creations 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. +*/ + +import React from 'react'; +import PropTypes from 'prop-types'; +import AccessibleButton from './AccessibleButton'; +import dis from '../../../dispatcher'; +import sdk from '../../../index'; + +export default React.createClass({ + displayName: 'RoleButton', + + propTypes: { + role: PropTypes.string.isRequired, + size: PropTypes.string, + }, + + getDefaultProps: function() { + return { + size: 25, + }; + }, + + _onClick: function(ev) { + ev.stopPropagation(); + + let action; + switch(this.props.role) { + case 'start_chat': + action = 'view_create_chat'; + break; + case 'room_directory': + action = 'view_room_directory'; + break; + case 'create_room': + action = 'view_create_room'; + break; + } + if (action) dis.dispatch({action: action}); + }, + + _getIconPath() { + switch(this.props.role) { + case 'start_chat': + return 'img/icons-people.svg'; + case 'room_directory': + return 'img/icons-directory.svg'; + case 'create_room': + return 'img/icons-create-room.svg'; + } + }, + + render: function() { + const TintableSvg = sdk.getComponent("elements.TintableSvg"); + + return ( + + + + ); + } +}); diff --git a/src/components/views/rooms/RoomList.js b/src/components/views/rooms/RoomList.js index e285c1841e..9a64c16239 100644 --- a/src/components/views/rooms/RoomList.js +++ b/src/components/views/rooms/RoomList.js @@ -1,5 +1,6 @@ /* Copyright 2015, 2016 OpenMarket Ltd +Copyright Vector Creations Ltd Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -510,27 +511,23 @@ module.exports = React.createClass({ }, _getEmptyContent: function(section) { + const RoleButton = sdk.getComponent('elements.RoleButton'); if (this.state.totalRoomCount === 0) { const TintableSvg = sdk.getComponent('elements.TintableSvg'); switch (section) { case 'im.vector.fake.direct': return
-
- -
- Use the button below to chat with someone! + Press + + to start a chat with someone
; case 'im.vector.fake.recent': return
-
- -
- Use the button below to browse the room directory -

-
- -
- or this button to start a new one! + You're not in any rooms yet! Press + + to make a room or + + to browse the directory
; } } @@ -541,6 +538,21 @@ module.exports = React.createClass({ return ; }, + _getHeaderItems: function(section) { + const RoleButton = sdk.getComponent('elements.RoleButton'); + switch (section) { + case 'im.vector.fake.direct': + return + + ; + case 'im.vector.fake.recent': + return + + + ; + } + }, + render: function() { var RoomSubList = sdk.getComponent('structures.RoomSubList'); var self = this; @@ -577,6 +589,7 @@ module.exports = React.createClass({ label="People" tagName="im.vector.fake.direct" emptyContent={this._getEmptyContent('im.vector.fake.direct')} + headerItems={this._getHeaderItems('im.vector.fake.direct')} editable={ true } order="recent" selectedRoom={ self.props.selectedRoom } @@ -591,6 +604,7 @@ module.exports = React.createClass({ label="Rooms" editable={ true } emptyContent={this._getEmptyContent('im.vector.fake.recent')} + headerItems={this._getHeaderItems('im.vector.fake.recent')} order="recent" selectedRoom={ self.props.selectedRoom } incomingCall={ self.state.incomingCall } From 54af06e8e12bfe86f11b4a3131ea155b8e161f3c Mon Sep 17 00:00:00 2001 From: David Baker Date: Thu, 4 May 2017 15:02:21 +0100 Subject: [PATCH 04/13] What year is it? Who's the president? --- src/components/views/elements/RoleButton.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/views/elements/RoleButton.js b/src/components/views/elements/RoleButton.js index 06006a5779..f20b4c6b88 100644 --- a/src/components/views/elements/RoleButton.js +++ b/src/components/views/elements/RoleButton.js @@ -1,5 +1,5 @@ /* -Copyright Vector Creations Ltd +Copyright 2017 Vector Creations Ltd Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. From a996f52ea34c0d4c7cc072c7cf068baf3b9cde1b Mon Sep 17 00:00:00 2001 From: David Baker Date: Thu, 4 May 2017 15:38:09 +0100 Subject: [PATCH 05/13] Make bottom left menu buttons use RoleButton too --- src/components/views/elements/RoleButton.js | 53 ++++++++++++++++++++- 1 file changed, 52 insertions(+), 1 deletion(-) diff --git a/src/components/views/elements/RoleButton.js b/src/components/views/elements/RoleButton.js index f20b4c6b88..60f227a067 100644 --- a/src/components/views/elements/RoleButton.js +++ b/src/components/views/elements/RoleButton.js @@ -31,6 +31,13 @@ export default React.createClass({ getDefaultProps: function() { return { size: 25, + tooltip: false, + }; + }, + + getInitialState: function() { + return { + showTooltip: false, }; }, @@ -48,10 +55,39 @@ export default React.createClass({ case 'create_room': action = 'view_create_room'; break; + case 'home_page': + action = 'view_home_page'; + break; + case 'settings': + action = 'view_user_settings'; + break; } if (action) dis.dispatch({action: action}); }, + _onMouseEnter: function() { + if (this.props.tooltip) this.setState({showTooltip: true}); + }, + + _onMouseLeave: function() { + this.setState({showTooltip: false}); + }, + + _getLabel() { + switch(this.props.role) { + case 'start_chat': + return 'Start chat'; + case 'room_directory': + return 'Room directory'; + case 'create_room': + return 'Create new room'; + case 'home_page': + return 'Welcome page'; + case 'settings': + return 'Settings'; + } + }, + _getIconPath() { switch(this.props.role) { case 'start_chat': @@ -60,15 +96,30 @@ export default React.createClass({ return 'img/icons-directory.svg'; case 'create_room': return 'img/icons-create-room.svg'; + case 'home_page': + return 'img/icons-home.svg'; + case 'settings': + return 'img/icons-settings.svg'; } }, render: function() { const TintableSvg = sdk.getComponent("elements.TintableSvg"); + let tooltip; + if (this.state.showTooltip) { + const RoomTooltip = sdk.getComponent("rooms.RoomTooltip"); + tooltip = ; + } + return ( - + + {tooltip} ); } From 3d3d89202e01100f1162d30542b59c8826c19e29 Mon Sep 17 00:00:00 2001 From: David Baker Date: Thu, 4 May 2017 15:46:24 +0100 Subject: [PATCH 06/13] Year --- src/components/views/rooms/RoomList.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/views/rooms/RoomList.js b/src/components/views/rooms/RoomList.js index 9a64c16239..ecb178d145 100644 --- a/src/components/views/rooms/RoomList.js +++ b/src/components/views/rooms/RoomList.js @@ -1,6 +1,6 @@ /* Copyright 2015, 2016 OpenMarket Ltd -Copyright Vector Creations Ltd +Copyright 2017 Vector Creations Ltd Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. From 99efbbee5e23913221d95bc9d8457bed24a4e0ae Mon Sep 17 00:00:00 2001 From: David Baker Date: Thu, 4 May 2017 16:22:06 +0100 Subject: [PATCH 07/13] Depend on prop-types module So we can start writing code compatible with new React --- package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/package.json b/package.json index 059fdd390f..572dcddeb5 100644 --- a/package.json +++ b/package.json @@ -65,6 +65,7 @@ "lodash": "^4.13.1", "matrix-js-sdk": "0.7.8", "optimist": "^0.6.1", + "prop-types": "^15.5.8", "q": "^1.4.1", "react": "^15.4.0", "react-addons-css-transition-group": "15.3.2", From dc2274df54896b48f836854cf46cd10b525d41c8 Mon Sep 17 00:00:00 2001 From: David Baker Date: Thu, 4 May 2017 18:08:04 +0100 Subject: [PATCH 08/13] Hide empty tips if collapsed --- src/components/views/rooms/RoomList.js | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/components/views/rooms/RoomList.js b/src/components/views/rooms/RoomList.js index ecb178d145..2dce02cc78 100644 --- a/src/components/views/rooms/RoomList.js +++ b/src/components/views/rooms/RoomList.js @@ -511,6 +511,12 @@ module.exports = React.createClass({ }, _getEmptyContent: function(section) { + const RoomDropTarget = sdk.getComponent('rooms.RoomDropTarget'); + + if (this.props.collapsed) { + return ; + } + const RoleButton = sdk.getComponent('elements.RoleButton'); if (this.state.totalRoomCount === 0) { const TintableSvg = sdk.getComponent('elements.TintableSvg'); @@ -531,7 +537,6 @@ module.exports = React.createClass({
; } } - const RoomDropTarget = sdk.getComponent('rooms.RoomDropTarget'); const labelText = 'Drop here to ' + (VERBS[section] || 'tag ' + section); From 9337158a470e2d23d16cce0054a931e5f97a3b0d Mon Sep 17 00:00:00 2001 From: David Baker Date: Fri, 5 May 2017 14:25:18 +0100 Subject: [PATCH 09/13] Separate classes for the different buttons Also rename RoleButton to ActionButton because it's not being given a Role any more. Conflicts: src/component-index.js cherry-picking commit 4a5821e. --- .../{RoleButton.js => ActionButton.js} | 60 +++---------------- .../views/elements/CreateRoomButton.js | 37 ++++++++++++ src/components/views/elements/HomeButton.js | 37 ++++++++++++ .../views/elements/RoomDirectoryButton.js | 37 ++++++++++++ .../views/elements/SettingsButton.js | 37 ++++++++++++ .../views/elements/StartChatButton.js | 37 ++++++++++++ src/components/views/rooms/RoomList.js | 20 ++++--- 7 files changed, 204 insertions(+), 61 deletions(-) rename src/components/views/elements/{RoleButton.js => ActionButton.js} (54%) create mode 100644 src/components/views/elements/CreateRoomButton.js create mode 100644 src/components/views/elements/HomeButton.js create mode 100644 src/components/views/elements/RoomDirectoryButton.js create mode 100644 src/components/views/elements/SettingsButton.js create mode 100644 src/components/views/elements/StartChatButton.js diff --git a/src/components/views/elements/RoleButton.js b/src/components/views/elements/ActionButton.js similarity index 54% rename from src/components/views/elements/RoleButton.js rename to src/components/views/elements/ActionButton.js index 60f227a067..6d6289ddab 100644 --- a/src/components/views/elements/RoleButton.js +++ b/src/components/views/elements/ActionButton.js @@ -24,8 +24,11 @@ export default React.createClass({ displayName: 'RoleButton', propTypes: { - role: PropTypes.string.isRequired, size: PropTypes.string, + tooltip: PropTypes.bool, + action: PropTypes.string.isRequired, + label: PropTypes.string.isRequired, + iconPath: PropTypes.string.isRequired, }, getDefaultProps: function() { @@ -43,26 +46,7 @@ export default React.createClass({ _onClick: function(ev) { ev.stopPropagation(); - - let action; - switch(this.props.role) { - case 'start_chat': - action = 'view_create_chat'; - break; - case 'room_directory': - action = 'view_room_directory'; - break; - case 'create_room': - action = 'view_create_room'; - break; - case 'home_page': - action = 'view_home_page'; - break; - case 'settings': - action = 'view_user_settings'; - break; - } - if (action) dis.dispatch({action: action}); + dis.dispatch({action: this.props.action}); }, _onMouseEnter: function() { @@ -73,43 +57,13 @@ export default React.createClass({ this.setState({showTooltip: false}); }, - _getLabel() { - switch(this.props.role) { - case 'start_chat': - return 'Start chat'; - case 'room_directory': - return 'Room directory'; - case 'create_room': - return 'Create new room'; - case 'home_page': - return 'Welcome page'; - case 'settings': - return 'Settings'; - } - }, - - _getIconPath() { - switch(this.props.role) { - case 'start_chat': - return 'img/icons-people.svg'; - case 'room_directory': - return 'img/icons-directory.svg'; - case 'create_room': - return 'img/icons-create-room.svg'; - case 'home_page': - return 'img/icons-home.svg'; - case 'settings': - return 'img/icons-settings.svg'; - } - }, - render: function() { const TintableSvg = sdk.getComponent("elements.TintableSvg"); let tooltip; if (this.state.showTooltip) { const RoomTooltip = sdk.getComponent("rooms.RoomTooltip"); - tooltip = ; + tooltip = ; } return ( @@ -118,7 +72,7 @@ export default React.createClass({ onMouseEnter={this._onMouseEnter} onMouseLeave={this._onMouseLeave} > - + {tooltip} ); diff --git a/src/components/views/elements/CreateRoomButton.js b/src/components/views/elements/CreateRoomButton.js new file mode 100644 index 0000000000..d6b6526d6c --- /dev/null +++ b/src/components/views/elements/CreateRoomButton.js @@ -0,0 +1,37 @@ +/* +Copyright 2017 Vector Creations 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. +*/ + +import sdk from '../../../index'; +import PropTypes from 'prop-types'; + +const CreateRoomButton = function(props) { + const ActionButton = sdk.getComponent('elements.ActionButton'); + return ( + + ); +}; + +CreateRoomButton.propTypes = { + size: PropTypes.string, + tooltip: PropTypes.bool, +}; + +export default CreateRoomButton; diff --git a/src/components/views/elements/HomeButton.js b/src/components/views/elements/HomeButton.js new file mode 100644 index 0000000000..4c7f295c87 --- /dev/null +++ b/src/components/views/elements/HomeButton.js @@ -0,0 +1,37 @@ +/* +Copyright 2017 Vector Creations 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. +*/ + +import sdk from '../../../index'; +import PropTypes from 'prop-types'; + +const HomeButton = function(props) { + const ActionButton = sdk.getComponent('elements.ActionButton'); + return ( + + ); +}; + +HomeButton.propTypes = { + size: PropTypes.string, + tooltip: PropTypes.bool, +}; + +export default HomeButton; diff --git a/src/components/views/elements/RoomDirectoryButton.js b/src/components/views/elements/RoomDirectoryButton.js new file mode 100644 index 0000000000..651dd8edd0 --- /dev/null +++ b/src/components/views/elements/RoomDirectoryButton.js @@ -0,0 +1,37 @@ +/* +Copyright 2017 Vector Creations 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. +*/ + +import sdk from '../../../index'; +import PropTypes from 'prop-types'; + +const RoomDirectoryButton = function(props) { + const ActionButton = sdk.getComponent('elements.ActionButton'); + return ( + + ); +}; + +RoomDirectoryButton.propTypes = { + size: PropTypes.string, + tooltip: PropTypes.bool, +}; + +export default RoomDirectoryButton; diff --git a/src/components/views/elements/SettingsButton.js b/src/components/views/elements/SettingsButton.js new file mode 100644 index 0000000000..51da6e3fd1 --- /dev/null +++ b/src/components/views/elements/SettingsButton.js @@ -0,0 +1,37 @@ +/* +Copyright 2017 Vector Creations 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. +*/ + +import sdk from '../../../index'; +import PropTypes from 'prop-types'; + +const SettingsButton = function(props) { + const ActionButton = sdk.getComponent('elements.ActionButton'); + return ( + + ); +}; + +SettingsButton.propTypes = { + size: PropTypes.string, + tooltip: PropTypes.bool, +}; + +export default SettingsButton; diff --git a/src/components/views/elements/StartChatButton.js b/src/components/views/elements/StartChatButton.js new file mode 100644 index 0000000000..66cd911754 --- /dev/null +++ b/src/components/views/elements/StartChatButton.js @@ -0,0 +1,37 @@ +/* +Copyright 2017 Vector Creations 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. +*/ + +import sdk from '../../../index'; +import PropTypes from 'prop-types'; + +const StartChatButton = function(props) { + const ActionButton = sdk.getComponent('elements.ActionButton'); + return ( + + ); +}; + +StartChatButton.propTypes = { + size: PropTypes.string, + tooltip: PropTypes.bool, +}; + +export default StartChatButton; diff --git a/src/components/views/rooms/RoomList.js b/src/components/views/rooms/RoomList.js index 2dce02cc78..8c8fd3ea86 100644 --- a/src/components/views/rooms/RoomList.js +++ b/src/components/views/rooms/RoomList.js @@ -517,22 +517,24 @@ module.exports = React.createClass({ return ; } - const RoleButton = sdk.getComponent('elements.RoleButton'); + const StartChatButton = sdk.getComponent('elements.StartChatButton'); + const RoomDirectoryButton = sdk.getComponent('elements.RoomDirectoryButton'); + const CreateRoomButton = sdk.getComponent('elements.CreateRoomButton'); if (this.state.totalRoomCount === 0) { const TintableSvg = sdk.getComponent('elements.TintableSvg'); switch (section) { case 'im.vector.fake.direct': return
Press - + to start a chat with someone
; case 'im.vector.fake.recent': return
You're not in any rooms yet! Press - + to make a room or - + to browse the directory
; } @@ -544,16 +546,18 @@ module.exports = React.createClass({ }, _getHeaderItems: function(section) { - const RoleButton = sdk.getComponent('elements.RoleButton'); + const StartChatButton = sdk.getComponent('elements.StartChatButton'); + const RoomDirectoryButton = sdk.getComponent('elements.RoomDirectoryButton'); + const CreateRoomButton = sdk.getComponent('elements.CreateRoomButton'); switch (section) { case 'im.vector.fake.direct': return - + ; case 'im.vector.fake.recent': return - - + + ; } }, From 5e855e6fee3c5cf068263967baa6d0c544c2a32c Mon Sep 17 00:00:00 2001 From: David Baker Date: Fri, 5 May 2017 14:56:26 +0100 Subject: [PATCH 10/13] Size is a string, import react React gets put in by the JSX transpile --- src/components/views/elements/ActionButton.js | 2 +- src/components/views/elements/CreateRoomButton.js | 1 + src/components/views/elements/HomeButton.js | 1 + src/components/views/elements/RoomDirectoryButton.js | 1 + src/components/views/elements/SettingsButton.js | 1 + src/components/views/elements/StartChatButton.js | 1 + 6 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/components/views/elements/ActionButton.js b/src/components/views/elements/ActionButton.js index 6d6289ddab..267388daf6 100644 --- a/src/components/views/elements/ActionButton.js +++ b/src/components/views/elements/ActionButton.js @@ -33,7 +33,7 @@ export default React.createClass({ getDefaultProps: function() { return { - size: 25, + size: "25", tooltip: false, }; }, diff --git a/src/components/views/elements/CreateRoomButton.js b/src/components/views/elements/CreateRoomButton.js index d6b6526d6c..e7e526d36b 100644 --- a/src/components/views/elements/CreateRoomButton.js +++ b/src/components/views/elements/CreateRoomButton.js @@ -14,6 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ +import React from 'react'; import sdk from '../../../index'; import PropTypes from 'prop-types'; diff --git a/src/components/views/elements/HomeButton.js b/src/components/views/elements/HomeButton.js index 4c7f295c87..5c446f24c9 100644 --- a/src/components/views/elements/HomeButton.js +++ b/src/components/views/elements/HomeButton.js @@ -14,6 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ +import React from 'react'; import sdk from '../../../index'; import PropTypes from 'prop-types'; diff --git a/src/components/views/elements/RoomDirectoryButton.js b/src/components/views/elements/RoomDirectoryButton.js index 651dd8edd0..5e68776a15 100644 --- a/src/components/views/elements/RoomDirectoryButton.js +++ b/src/components/views/elements/RoomDirectoryButton.js @@ -14,6 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ +import React from 'react'; import sdk from '../../../index'; import PropTypes from 'prop-types'; diff --git a/src/components/views/elements/SettingsButton.js b/src/components/views/elements/SettingsButton.js index 51da6e3fd1..c6438da277 100644 --- a/src/components/views/elements/SettingsButton.js +++ b/src/components/views/elements/SettingsButton.js @@ -14,6 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ +import React from 'react'; import sdk from '../../../index'; import PropTypes from 'prop-types'; diff --git a/src/components/views/elements/StartChatButton.js b/src/components/views/elements/StartChatButton.js index 66cd911754..02d5677a7c 100644 --- a/src/components/views/elements/StartChatButton.js +++ b/src/components/views/elements/StartChatButton.js @@ -14,6 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ +import React from 'react'; import sdk from '../../../index'; import PropTypes from 'prop-types'; From 548f319816d94955fc45fc68f51da5f6dcc2787e Mon Sep 17 00:00:00 2001 From: David Baker Date: Fri, 5 May 2017 17:51:14 +0100 Subject: [PATCH 11/13] Remove redundant role elements --- src/components/views/rooms/RoomList.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/components/views/rooms/RoomList.js b/src/components/views/rooms/RoomList.js index 8c8fd3ea86..cde2bec7da 100644 --- a/src/components/views/rooms/RoomList.js +++ b/src/components/views/rooms/RoomList.js @@ -552,12 +552,12 @@ module.exports = React.createClass({ switch (section) { case 'im.vector.fake.direct': return - + ; case 'im.vector.fake.recent': return - - + + ; } }, From 3185d3ed41d376d52d65583247a08a74a12f1983 Mon Sep 17 00:00:00 2001 From: Luke Barnard Date: Thu, 25 May 2017 13:54:59 +0100 Subject: [PATCH 12/13] Re-add bouncing/callout animation to action buttons --- src/components/views/elements/ActionButton.js | 4 ++++ src/components/views/elements/CreateRoomButton.js | 1 + src/components/views/elements/RoomDirectoryButton.js | 1 + src/components/views/elements/StartChatButton.js | 3 ++- src/components/views/rooms/RoomList.js | 6 +++--- 5 files changed, 11 insertions(+), 4 deletions(-) diff --git a/src/components/views/elements/ActionButton.js b/src/components/views/elements/ActionButton.js index 267388daf6..08fb6faa1d 100644 --- a/src/components/views/elements/ActionButton.js +++ b/src/components/views/elements/ActionButton.js @@ -27,6 +27,7 @@ export default React.createClass({ size: PropTypes.string, tooltip: PropTypes.bool, action: PropTypes.string.isRequired, + mouseOverAction: PropTypes.string, label: PropTypes.string.isRequired, iconPath: PropTypes.string.isRequired, }, @@ -51,6 +52,9 @@ export default React.createClass({ _onMouseEnter: function() { if (this.props.tooltip) this.setState({showTooltip: true}); + if (this.props.mouseOverAction) { + dis.dispatch({action: this.props.mouseOverAction}); + } }, _onMouseLeave: function() { diff --git a/src/components/views/elements/CreateRoomButton.js b/src/components/views/elements/CreateRoomButton.js index e7e526d36b..82643559b3 100644 --- a/src/components/views/elements/CreateRoomButton.js +++ b/src/components/views/elements/CreateRoomButton.js @@ -22,6 +22,7 @@ const CreateRoomButton = function(props) { const ActionButton = sdk.getComponent('elements.ActionButton'); return ( Press - + to start a chat with someone
; case 'im.vector.fake.recent': return
You're not in any rooms yet! Press - + to make a room or - + to browse the directory
; } From 7900bf1c7de0d170b3ca055332d4bebb3f10f4ef Mon Sep 17 00:00:00 2001 From: Luke Barnard Date: Thu, 25 May 2017 13:55:37 +0100 Subject: [PATCH 13/13] Don't show "Drop to ..." if total rooms = 0 --- src/components/views/rooms/RoomList.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/components/views/rooms/RoomList.js b/src/components/views/rooms/RoomList.js index 98a5229d6a..216dd972cf 100644 --- a/src/components/views/rooms/RoomList.js +++ b/src/components/views/rooms/RoomList.js @@ -540,6 +540,10 @@ module.exports = React.createClass({ } } + if (this.state.totalRoomCount === 0) { + return null; + } + const labelText = 'Drop here to ' + (VERBS[section] || 'tag ' + section); return ;