diff --git a/examples/trivial/fonts b/examples/trivial/fonts new file mode 120000 index 0000000000..27f04cad54 --- /dev/null +++ b/examples/trivial/fonts @@ -0,0 +1 @@ +../../skins/base/fonts/ \ No newline at end of file diff --git a/skins/base/css/molecules/RoomHeader.css b/skins/base/css/molecules/RoomHeader.css index e13a21df6f..6774387726 100644 --- a/skins/base/css/molecules/RoomHeader.css +++ b/skins/base/css/molecules/RoomHeader.css @@ -86,6 +86,15 @@ limitations under the License. vertical-align: middle; } +.mx_RoomHeader_simpleHeader { + line-height: 88px; + color: #80cef4; + font-weight: 400; + font-size: 20px; + overflow: scroll; + text-overflow: ellipsis; +} + .mx_RoomHeader_name { vertical-align: middle; height: 28px; diff --git a/skins/base/css/organisms/LeftPanel.css b/skins/base/css/organisms/LeftPanel.css index ac10942d2a..bfc4302655 100644 --- a/skins/base/css/organisms/LeftPanel.css +++ b/skins/base/css/organisms/LeftPanel.css @@ -43,7 +43,7 @@ limitations under the License. overflow-y: scroll; } -.mx_LeftPanel .mx_DirectoryMenu { +.mx_LeftPanel .mx_BottomLeftMenu { -webkit-box-ordinal-group: 3; -moz-box-ordinal-group: 3; -ms-flex-order: 3; @@ -56,15 +56,15 @@ limitations under the License. border-top: 1px solid #f3f8fa; } -.mx_LeftPanel .mx_DirectoryMenu .mx_RoomTile { +.mx_LeftPanel .mx_BottomLeftMenu .mx_RoomTile { color: #378bb4; } -.mx_LeftPanel .mx_DirectoryMenu .mx_RoomTile_avatar { +.mx_LeftPanel .mx_BottomLeftMenu .mx_RoomTile_avatar { padding-left: 14px; } -.mx_LeftPanel .mx_DirectoryMenu .mx_DirectoryMenu_options { +.mx_LeftPanel .mx_BottomLeftMenu .mx_BottomLeftMenu_options { margin-top: 12px; width: 100%; } \ No newline at end of file diff --git a/skins/base/css/organisms/RoomDirectory.css b/skins/base/css/organisms/RoomDirectory.css new file mode 100644 index 0000000000..9ca7811f21 --- /dev/null +++ b/skins/base/css/organisms/RoomDirectory.css @@ -0,0 +1,40 @@ +/* +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_RoomDirectory { + max-width: 720px; + margin: auto; +} + +.mx_RoomDirectory_input { + margin: auto; + border-radius: 3px; + border: 1px solid #c7c7c7; + font-weight: 300; + font-size: 14px; + padding: 9px; + margin-top: 12px; + margin-bottom: 12px; +} + +.mx_RoomDirectory_table { + width: 100%; +} + +.mx_RoomDirectory_table td, +.mx_RoomDirectory_table th, { + padding: 6px; +} \ No newline at end of file diff --git a/skins/base/views/molecules/DirectoryMenu.js b/skins/base/views/molecules/BottomLeftMenu.js similarity index 83% rename from skins/base/views/molecules/DirectoryMenu.js rename to skins/base/views/molecules/BottomLeftMenu.js index 8ffb418014..d2340d7bfa 100644 --- a/skins/base/views/molecules/DirectoryMenu.js +++ b/skins/base/views/molecules/BottomLeftMenu.js @@ -21,34 +21,34 @@ var classNames = require('classnames'); var dis = require("../../../../src/dispatcher"); -//var DirectoryMenuController = require("../../../../src/controllers/molecules/DirectoryMenuController"); - var MatrixClientPeg = require("../../../../src/MatrixClientPeg"); module.exports = React.createClass({ - displayName: 'DirectoryMenu', - // mixins: [DirectoryMenuController], + displayName: 'BottomLeftMenu', - // FIXME: should these onClicks be in the controller instead? onSettingsClick: function() { dis.dispatch({action: 'view_user_settings'}); }, + onRoomDirectoryClick: function() { + dis.dispatch({action: 'view_room_directory'}); + }, + onCreateRoomClick: function() { dis.dispatch({action: 'view_create_room'}); }, render: function() { return ( -
-
+
+
Create new room
-
+
diff --git a/skins/base/views/molecules/RoomHeader.js b/skins/base/views/molecules/RoomHeader.js index 6958333bfc..22e05868a9 100644 --- a/skins/base/views/molecules/RoomHeader.js +++ b/skins/base/views/molecules/RoomHeader.js @@ -35,25 +35,34 @@ module.exports = React.createClass({ render: function() { - var topic = this.props.room.currentState.getStateEvents('m.room.topic', ''); - topic = topic ?
{ topic.getContent().topic }
: null; - - var callButtons; - if (this.state) { - switch (this.state.call_state) { - case "ringback": - case "connected": - callButtons = ( -
- End call -
- ); - break; - } + var header; + if (this.props.simpleHeader) { + header = +
+
+ { this.props.simpleHeader } +
+
} + else { + var topic = this.props.room.currentState.getStateEvents('m.room.topic', ''); + topic = topic ?
{ topic.getContent().topic }
: null; - return ( -
+ var callButtons; + if (this.state) { + switch (this.state.call_state) { + case "ringback": + case "connected": + callButtons = ( +
+ End call +
+ ); + break; + } + } + + header =
@@ -82,6 +91,11 @@ module.exports = React.createClass({
+ } + + return ( +
+ { header }
); }, diff --git a/skins/base/views/organisms/LeftPanel.js b/skins/base/views/organisms/LeftPanel.js index 252a5d064d..165759109c 100644 --- a/skins/base/views/organisms/LeftPanel.js +++ b/skins/base/views/organisms/LeftPanel.js @@ -20,7 +20,7 @@ var React = require('react'); var ComponentBroker = require('../../../../src/ComponentBroker'); var RoomList = ComponentBroker.get('organisms/RoomList'); -var DirectoryMenu = ComponentBroker.get('molecules/DirectoryMenu'); +var BottomLeftMenu = ComponentBroker.get('molecules/BottomLeftMenu'); var IncomingCallBox = ComponentBroker.get('molecules/voip/IncomingCallBox'); var RoomCreate = ComponentBroker.get('molecules/RoomCreate'); @@ -33,7 +33,7 @@ module.exports = React.createClass({ < - +
); } diff --git a/skins/base/views/organisms/RightPanel.js b/skins/base/views/organisms/RightPanel.js index e1634adc1e..5b6477a0d0 100644 --- a/skins/base/views/organisms/RightPanel.js +++ b/skins/base/views/organisms/RightPanel.js @@ -24,20 +24,53 @@ var MemberList = ComponentBroker.get('organisms/MemberList'); module.exports = React.createClass({ displayName: 'RightPanel', + Phase : { + Blank: 'Blank', + None: 'None', + MemberList: 'MemberList', + FileList: 'FileList', + }, + + getInitialState: function() { + return { + phase : this.Phase.None + } + }, + + onMemberListButtonClick: function() { + if (this.state.phase == this.Phase.None) { + this.setState({ phase: this.Phase.MemberList }); + } + else { + this.setState({ phase: this.Phase.None }); + } + }, + render: function() { - return ( -
-
+ var buttonGroup; + var panel; + if (this.props.roomId) { + buttonGroup =
Files
-
+
Members
-
+
; + + if (this.state.phase == this.Phase.MemberList) { + panel = + } + } + + return ( +
+
+ { buttonGroup }
- + { panel }
); } diff --git a/skins/base/views/organisms/RoomDirectory.js b/skins/base/views/organisms/RoomDirectory.js new file mode 100644 index 0000000000..7ffb4977ad --- /dev/null +++ b/skins/base/views/organisms/RoomDirectory.js @@ -0,0 +1,130 @@ +/* +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 Modal = require("../../../../src/Modal"); +var ComponentBroker = require('../../../../src/ComponentBroker'); +var ErrorDialog = ComponentBroker.get("organisms/ErrorDialog"); +var RoomHeader = ComponentBroker.get('molecules/RoomHeader'); +var dis = require("../../../../src/dispatcher"); + + +module.exports = React.createClass({ + displayName: 'RoomDirectory', + + getInitialState: function() { + return { + publicRooms: [], + roomAlias: '', + } + }, + + componentDidMount: function() { + var self = this; + MatrixClientPeg.get().publicRooms(function (err, data) { + if (err) { + console.error("Failed to get publicRooms: %s", JSON.stringify(err)); + Modal.createDialog(ErrorDialog, { + title: "Failed to get public room list", + description: err.message + }); + } + else { + self.setState({ + publicRooms: data.chunk + }); + self.forceUpdate(); + } + }); + }, + + joinRoom: function(roomId) { + // XXX: check that JS SDK suppresses duplicate attempts to join the same room + MatrixClientPeg.get().joinRoom(roomId).done(function() { + dis.dispatch({ + action: 'view_room', + room_id: roomId + }); + }, function(err) { + console.error("Failed to join room: %s", JSON.stringify(err)); + Modal.createDialog(ErrorDialog, { + title: "Failed to join room", + description: err.message + }); + }); + }, + + getRows: function(filter) { + if (!this.state.publicRooms) return []; + + var rooms = this.state.publicRooms.filter(function(a) { + // FIXME: if incrementally typing, keep narrowing down the search set + return (a.aliases[0].search(filter) >= 0); + }).sort(function(a,b) { + return a.num_joined_members > b.num_joined_members; + }); + var rows = []; + var self = this; + for (var i = 0; i < rooms.length; i++) { + var name = rooms[i].name; + if (!name) { + if (rooms[i].aliases[0]) name = rooms[i].aliases[0] + } + else { + if (rooms[i].aliases[0]) name += " (" + rooms[i].aliases[0] + ")"; + } + rows.unshift( + + { name } + { rooms[i].topic } + { rooms[i].num_joined_members } + + ); + } + return rows; + }, + + onKeyUp: function(ev) { + this.forceUpdate(); + this.setState({ roomAlias : this.refs.roomAlias.getDOMNode().value }) + if (ev.key == "Enter") { + this.joinRoom(this.refs.roomAlias.getDOMNode().value); + } + if (ev.key == "Down") { + + } + }, + + render: function() { + return ( +
+ +
+ + + + { this.getRows(this.state.roomAlias) } +
RoomTopicUsers
+
+
+ ); + } +}); + diff --git a/skins/base/views/pages/MatrixChat.js b/skins/base/views/pages/MatrixChat.js index 85a29264b3..73af508243 100644 --- a/skins/base/views/pages/MatrixChat.js +++ b/skins/base/views/pages/MatrixChat.js @@ -26,6 +26,7 @@ var Login = ComponentBroker.get('templates/Login'); var UserSettings = ComponentBroker.get('organisms/UserSettings'); var Register = ComponentBroker.get('templates/Register'); var CreateRoom = ComponentBroker.get('organisms/CreateRoom'); +var RoomDirectory = ComponentBroker.get('organisms/RoomDirectory'); var MatrixChatController = require("../../../../src/controllers/pages/MatrixChat"); @@ -59,9 +60,15 @@ module.exports = React.createClass({ break; case this.PageTypes.UserSettings: page_element = + right_panel = break; case this.PageTypes.CreateRoom: page_element = + right_panel = + break; + case this.PageTypes.RoomDirectory: + page_element = + right_panel = break; } diff --git a/src/ComponentBroker.js b/src/ComponentBroker.js index ac82a906b9..49fb487b7b 100644 --- a/src/ComponentBroker.js +++ b/src/ComponentBroker.js @@ -96,9 +96,10 @@ require('../skins/base/views/molecules/ChangePassword'); require('../skins/base/views/organisms/LeftPanel'); require('../skins/base/views/organisms/RightPanel'); require('../skins/base/views/organisms/LogoutPrompt'); +require('../skins/base/views/organisms/RoomDirectory'); require('../skins/base/views/molecules/RoomCreate'); require('../skins/base/views/molecules/RoomDropTarget'); -require('../skins/base/views/molecules/DirectoryMenu'); +require('../skins/base/views/molecules/BottomLeftMenu'); require('../skins/base/views/molecules/DateSeparator'); require('../skins/base/views/atoms/voip/VideoFeed'); require('../skins/base/views/molecules/voip/VideoView'); diff --git a/src/controllers/pages/MatrixChat.js b/src/controllers/pages/MatrixChat.js index 21c40467ac..30135a2b87 100644 --- a/src/controllers/pages/MatrixChat.js +++ b/src/controllers/pages/MatrixChat.js @@ -33,6 +33,7 @@ module.exports = { RoomView: "room_view", UserSettings: "user_settings", CreateRoom: "create_room", + RoomDirectory: "room_directory", }, AuxPanel: { @@ -43,7 +44,7 @@ module.exports = { return { logged_in: !!(MatrixClientPeg.get() && MatrixClientPeg.get().credentials), ready: false, - page_type: this.PageTypes.RoomView, + page_type: MatrixClientPeg.get().getRooms().length ? this.PageTypes.RoomView : this.PageTypes.RoomDirectory, aux_panel: null, }; }, @@ -157,6 +158,11 @@ module.exports = { page_type: this.PageTypes.CreateRoom, }); break; + case 'view_room_directory': + this.setState({ + page_type: this.PageTypes.RoomDirectory, + }); + break; } },