diff --git a/src/components/structures/BottomLeftMenu.js b/src/components/structures/BottomLeftMenu.js index 875d92762..77493b17c 100644 --- a/src/components/structures/BottomLeftMenu.js +++ b/src/components/structures/BottomLeftMenu.js @@ -17,31 +17,82 @@ limitations under the License. 'use strict'; var React = require('react'); +var ReactDOM = require('react-dom'); var sdk = require('matrix-react-sdk') var dis = require('matrix-react-sdk/lib/dispatcher'); module.exports = React.createClass({ displayName: 'BottomLeftMenu', + propTypes: { + collapsed: React.PropTypes.bool.isRequired, + }, + + getInitialState: function() { + return({ + directoryHover : false, + roomsHover : false, + peopleHover : false, + settingsHover : false, + }); + }, + + // Room events + onDirectoryClick: function() { + dis.dispatch({ action: 'view_room_directory' }); + }, + + onDirectoryMouseEnter: function() { + this.setState({ directoryHover: true }); + }, + + onDirectoryMouseLeave: function() { + this.setState({ directoryHover: false }); + }, + + onRoomsClick: function() { + dis.dispatch({ action: 'view_create_room' }); + }, + + onRoomsMouseEnter: function() { + this.setState({ roomsHover: true }); + }, + + onRoomsMouseLeave: function() { + this.setState({ roomsHover: false }); + }, + + // People events + onPeopleClick: function() { + dis.dispatch({ action: 'view_create_chat' }); + }, + + onPeopleMouseEnter: function() { + this.setState({ peopleHover: true }); + }, + + onPeopleMouseLeave: function() { + this.setState({ peopleHover: false }); + }, + + // Settings events onSettingsClick: function() { - dis.dispatch({action: 'view_user_settings'}); + dis.dispatch({ action: 'view_user_settings' }); }, - onRoomDirectoryClick: function() { - dis.dispatch({action: 'view_room_directory'}); + onSettingsMouseEnter: function() { + this.setState({ settingsHover: true }); }, - onCreateRoomClick: function() { - dis.dispatch({action: 'view_create_room'}); + onSettingsMouseLeave: function() { + this.setState({ settingsHover: false }); }, - getLabel: function(name) { - if (!this.props.collapsed) { - return
{name}
- } - else if (this.state.hover) { + // Get the label/tooltip to show + getLabel: function(label, show) { + if (show) { var RoomTooltip = sdk.getComponent("rooms.RoomTooltip"); - return ; + return ; } }, @@ -50,14 +101,21 @@ module.exports = React.createClass({ return (
-
- -
-
+
+ { this.getLabel("Room directory", this.state.directoryHover) }
-
- +
+ + { this.getLabel("Create new room", this.state.roomsHover) } +
+
+ + { this.getLabel("New direct message", this.state.peopleHover) } +
+
+ + { this.getLabel("Settings", this.state.settingsHover) }
diff --git a/src/components/structures/RoomSubList.js b/src/components/structures/RoomSubList.js index 651ffae37..224ff2c63 100644 --- a/src/components/structures/RoomSubList.js +++ b/src/components/structures/RoomSubList.js @@ -418,8 +418,18 @@ var RoomSubList = React.createClass({ badge =
{subListNotifCount > 99 ? "99+" : subListNotifCount}
; } + // When collapsed, allow a long hover on the header to show user + // the full tag name and room count + var title; + if (this.props.collapsed) { + title = this.props.label; + if (roomCount !== '') { + title += " [" + roomCount + "]"; + } + } + return ( -
+
{ this.props.collapsed ? '' : this.props.label }
{roomCount}
diff --git a/src/components/views/rooms/RoomTooltip.js b/src/components/views/rooms/RoomTooltip.js index 2f5de8372..bbed5df8a 100644 --- a/src/components/views/rooms/RoomTooltip.js +++ b/src/components/views/rooms/RoomTooltip.js @@ -18,42 +18,79 @@ limitations under the License. var React = require('react'); var ReactDOM = require('react-dom'); - var dis = require('matrix-react-sdk/lib/dispatcher'); module.exports = React.createClass({ displayName: 'RoomTooltip', - componentDidMount: function() { - var tooltip = ReactDOM.findDOMNode(this); - if (!this.props.bottom) { - // tell the roomlist about us so it can position us - dis.dispatch({ - action: 'view_tooltip', - tooltip: tooltip, - }); - } - else { - tooltip.style.top = (70 + tooltip.parentElement.getBoundingClientRect().top) + "px"; - tooltip.style.display = "block"; - } + propTypes: { + // Alllow the tooltip to be styled by the parent element + className: React.PropTypes.string.isRequired, + // The tooltip is derived from either the room name or a label + room: React.PropTypes.object, + label: React.PropTypes.string, }, + // Create a wrapper for the tooltip outside the parent and attach it to the body element + componentDidMount: function() { + this.tooltipContainer = document.createElement("div"); + this.tooltipContainer.className = "mx_RoomTileTooltip_wrapper"; + document.body.appendChild(this.tooltipContainer); + + this._renderTooltip(); + }, + + componentDidUpdate: function() { + this._renderTooltip(); + }, + + // Remove the wrapper element, as the tooltip has finished using it componentWillUnmount: function() { - if (!this.props.bottom) { - dis.dispatch({ - action: 'view_tooltip', - tooltip: null, - }); - } + dis.dispatch({ + action: 'view_tooltip', + tooltip: null, + parent: null, + }); + + ReactDOM.unmountComponentAtNode(this.tooltipContainer); + document.body.removeChild(this.tooltipContainer); + }, + + _renderTooltip: function() { + var label = this.props.room ? this.props.room.name : this.props.label; + + // Add the parent's position to the tooltips, so it's correctly + // positioned, also taking into account any window zoom + // NOTE: The additional 6 pixels for the left position, is to take account of the + // tooltips chevron + var parent = ReactDOM.findDOMNode(this); + var style = {}; + style.top = parent.getBoundingClientRect().top + window.pageYOffset; + style.left = 6 + parent.getBoundingClientRect().right + window.pageXOffset; + style.display = "block"; + + var tooltip = ( +
+
+ { label } +
+ ); + + // Render the tooltip manually, as we wish it not to be rendered within the parent + this.tooltip = ReactDOM.render(tooltip, this.tooltipContainer); + + // Tell the roomlist about us so it can manipulate us if it wishes + dis.dispatch({ + action: 'view_tooltip', + tooltip: this.tooltip, + parent: parent, + }); }, render: function() { - var label = this.props.room ? this.props.room.name : this.props.label; + // Render a placeholder return ( -
- - { label } +
); } diff --git a/src/skins/vector/css/common.css b/src/skins/vector/css/common.css index 9eb67c3c5..d6047ae82 100644 --- a/src/skins/vector/css/common.css +++ b/src/skins/vector/css/common.css @@ -64,6 +64,11 @@ input[type=text]:focus, textarea:focus { box-shadow: none; } +/* Required by Firefox */ +textarea { + font-family: 'Open Sans', Arial, Helvetica, Sans-Serif; +} + /* Prevent ugly dotted highlight around selected elements in Firefox */ ::-moz-focus-inner { border: 0; @@ -198,14 +203,15 @@ input[type=text]:focus, textarea:focus { height: 36px; border-radius: 40px; border: solid 1px #76cfa6; - font-weight: 400; - font-size: 15px; + font-weight: 600; + font-size: 14px; + font-family: 'Open Sans', Arial, Helvetica, Sans-Serif; margin-left: 0px; margin-right: 8px; padding-left: 1.5em; padding-right: 1.5em; outline: none; - + cursor: pointer; color: #76cfa6; background-color: #fff; } diff --git a/src/skins/vector/css/matrix-react-sdk/views/dialogs/ChatInviteDialog.css b/src/skins/vector/css/matrix-react-sdk/views/dialogs/ChatInviteDialog.css new file mode 100644 index 000000000..8dce58a3c --- /dev/null +++ b/src/skins/vector/css/matrix-react-sdk/views/dialogs/ChatInviteDialog.css @@ -0,0 +1,83 @@ +/* +Copyright 2016 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. +*/ + +/* Using a textarea for this element, to circumvent autofill */ +.mx_ChatInviteDialog_input, +.mx_ChatInviteDialog_input:focus +{ + height: 26px; + font-size: 14px; + font-family: 'Open Sans', Arial, Helvetica, Sans-Serif; + padding-left: 12px; + padding-right: 12px; + margin: 0 !important; + border: 0 !important; + outline: 0 !important; + width: 1000%; /* Pretend that this is an "input type=text" */ + resize: none; + overflow: hidden; + vertical-align: middle; + box-sizing: border-box; + word-wrap: nowrap; +} + +.mx_ChatInviteDialog_inputContainer { + border-radius: 3px; + border: solid 1px #f0f0f0; + line-height: 36px; + padding-left: 4px; + padding-right: 4px; + padding-top: 1px; + padding-bottom: 1px; + overflow: hidden; +} + +.mx_ChatInviteDialog_queryList { + position: absolute; + background-color: #fff; + width: 485px; + max-height: 116px; + overflow-y: scroll; + border-radius: 3px; + background-color: #fff; + border: solid 1px #76cfa6; + cursor: pointer; +} + +.mx_ChatInviteDialog_queryListElement .mx_AddressTile { + background-color: #fff; + border: solid 1px #fff; +} + +.mx_ChatInviteDialog_queryListElement.mx_ChatInviteDialog_selected { + background-color: #eaf5f0; /* selected colour */ +} + +.mx_ChatInviteDialog_queryListElement.mx_ChatInviteDialog_selected .mx_AddressTile { + background-color: #eaf5f0; /* selected colour */ + border: solid 1px #eaf5f0; /* selected colour */ +} + +.mx_ChatInviteDialog_cancel { + position: absolute; + right: 11px; + top: 13px; + cursor: pointer; +} + +.mx_ChatInviteDialog_cancel object { + pointer-events: none; +} diff --git a/src/skins/vector/css/matrix-react-sdk/views/elements/AddressTile.css b/src/skins/vector/css/matrix-react-sdk/views/elements/AddressTile.css new file mode 100644 index 000000000..5e22ccaf8 --- /dev/null +++ b/src/skins/vector/css/matrix-react-sdk/views/elements/AddressTile.css @@ -0,0 +1,83 @@ +/* +Copyright 2015, 2016 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_AddressTile { + display: inline-block; + border-radius: 3px; + background-color: rgba(74, 73, 74, 0.1); + border: solid 1px #f0f0f0; + line-height: 26px; + color: #454545; + font-size: 14px; + font-weight: normal; +} + +.mx_AddressTile_network { + display: inline-block; + position: relative; + padding-left: 2px; + padding-right: 4px; + vertical-align: middle; +} + +.mx_AddressTile_avatar { + display: inline-block; + position: relative; + padding-left: 2px; + padding-right: 7px; + vertical-align: middle; +} + +.mx_AddressTile_name { + display: inline-block; + padding-right: 4px; + font-weight: 600; + overflow: hidden; + height: 26px; + vertical-align: middle; +} + +.mx_AddressTile_name.mx_AddressTile_justified { + width: 180px; + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; + vertical-align: middle; +} + +.mx_AddressTile_id { + display: inline-block; + padding-right: 11px; +} + +.mx_AddressTile_id.mx_AddressTile_justified { + width: 200px; + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; + vertical-align: middle; +} + +.mx_AddressTile_dismiss { + display: inline-block; + padding-right: 11px; + padding-left: 1px; + cursor: pointer; +} + +.mx_AddressTile_dismiss object { + pointer-events: none; +} diff --git a/src/skins/vector/css/matrix-react-sdk/views/rooms/RoomList.css b/src/skins/vector/css/matrix-react-sdk/views/rooms/RoomList.css index 4dcda646f..110dcd5b6 100644 --- a/src/skins/vector/css/matrix-react-sdk/views/rooms/RoomList.css +++ b/src/skins/vector/css/matrix-react-sdk/views/rooms/RoomList.css @@ -35,5 +35,5 @@ limitations under the License. /* Make sure the scrollbar is above the sticky headers from RoomList */ .mx_RoomList_scrollbar .gm-scrollbar.-vertical { - z-index: 5; + z-index: 6; } diff --git a/src/skins/vector/css/matrix-react-sdk/views/rooms/RoomTile.css b/src/skins/vector/css/matrix-react-sdk/views/rooms/RoomTile.css index ff302baac..87ce4abba 100644 --- a/src/skins/vector/css/matrix-react-sdk/views/rooms/RoomTile.css +++ b/src/skins/vector/css/matrix-react-sdk/views/rooms/RoomTile.css @@ -22,6 +22,14 @@ limitations under the License. height: 34px; } +.mx_RoomTile_tooltip { + display: inline-block; + position: relative; + top: -62px; + left: 46px; +} + + .mx_RoomTile_nameContainer { display: inline-block; width: 180px; @@ -32,6 +40,10 @@ limitations under the License. width: 170px; } +.mx_RoomTile_avatar_container { + position: relative; +} + .mx_RoomTile_avatar { display: inline-block; padding-top: 5px; @@ -43,6 +55,14 @@ limitations under the License. vertical-align: middle; } +.mx_RoomTile_dm { + display: block; + position: absolute; + bottom: 0; + right: -5px; + z-index: 2; +} + .mx_RoomTile_avatar_container:hover:before, .mx_RoomTile_avatar_container.mx_RoomTile_avatar_roomTagMenu:before { display: block; @@ -51,7 +71,6 @@ limitations under the License. border-radius: 40px; background-image: url("img/icons_ellipsis.svg"); background-size: 25px; - left: 15px; width: 24px; height: 24px; z-index: 4; @@ -64,11 +83,11 @@ limitations under the License. content: ""; border-radius: 40px; background: #4A4A4A; - top: 5px; + bottom: 0; width: 24px; height: 24px; opacity: 0.6; - z-index: 2; + z-index: 1; } .collapsed .mx_RoomTile_avatar_container:hover:before { @@ -117,7 +136,7 @@ limitations under the License. min-width: 12px; border-radius: 16px; padding: 0px 4px 0px 4px; - z-index: 200; + z-index: 3; } /* Hide the bottom of speech bubble */ diff --git a/src/skins/vector/css/vector-web/structures/LeftPanel.css b/src/skins/vector/css/vector-web/structures/LeftPanel.css index fb023ffea..5a71ac28c 100644 --- a/src/skins/vector/css/vector-web/structures/LeftPanel.css +++ b/src/skins/vector/css/vector-web/structures/LeftPanel.css @@ -49,11 +49,11 @@ limitations under the License. flex: 1 1 0; overflow-y: auto; - z-index: 5; + z-index: 6; } .mx_LeftPanel.collapsed .mx_BottomLeftMenu { - flex: 0 0 120px; + flex: 0 0 160px; } .mx_LeftPanel .mx_BottomLeftMenu { @@ -79,15 +79,17 @@ limitations under the License. pointer-events: none; } -.mx_LeftPanel .mx_BottomLeftMenu_createRoom, .mx_LeftPanel .mx_BottomLeftMenu_directory, +.mx_LeftPanel .mx_BottomLeftMenu_createRoom, +.mx_LeftPanel .mx_BottomLeftMenu_people, .mx_LeftPanel .mx_BottomLeftMenu_settings { display: inline-block; cursor: pointer; } -.collapsed .mx_BottomLeftMenu_createRoom, .collapsed .mx_BottomLeftMenu_directory, +.collapsed .mx_BottomLeftMenu_createRoom, +.collapsed .mx_BottomLeftMenu_people, .collapsed .mx_BottomLeftMenu_settings { margin-left: 0px ! important; padding-top: 3px ! important; @@ -95,7 +97,15 @@ limitations under the License. } .mx_LeftPanel .mx_BottomLeftMenu_directory { - margin-left: 10px; + margin-right: 10px; +} + +.mx_LeftPanel .mx_BottomLeftMenu_createRoom { + margin-right: 10px; +} + +.mx_LeftPanel .mx_BottomLeftMenu_people { + margin-right: 10px; } .mx_LeftPanel .mx_BottomLeftMenu_settings { @@ -105,3 +115,10 @@ limitations under the License. .mx_LeftPanel.collapsed .mx_BottomLeftMenu_settings { float: none; } + +.mx_LeftPanel .mx_BottomLeftMenu_tooltip { + display: inline-block; + position: relative; + top: -25px; + left: 6px; +} diff --git a/src/skins/vector/css/vector-web/structures/RoomSubList.css b/src/skins/vector/css/vector-web/structures/RoomSubList.css index 4d9b0668f..9e4162817 100644 --- a/src/skins/vector/css/vector-web/structures/RoomSubList.css +++ b/src/skins/vector/css/vector-web/structures/RoomSubList.css @@ -39,14 +39,14 @@ limitations under the License. padding-top: 6px; padding-bottom: 6px; cursor: pointer; - background-color: rgba(118, 207, 166, 0.2); + background-color: rgba(118, 207, 166, 0.2); /* Should be #d3ede1, but not a magic colour */ border-top: solid 2px #eaf5f0; } .mx_RoomSubList_label.mx_RoomSubList_fixed { position: fixed; top: 0; - z-index: 4; + z-index: 5; /* pointer-events: none; */ } @@ -90,9 +90,11 @@ limitations under the License. background-color: #76cfa6; } +/* .collapsed .mx_RoomSubList_badge { display: none; } +*/ .mx_RoomSubList_badgeHighlight { background-color: #ff0064; diff --git a/src/skins/vector/css/vector-web/views/rooms/RoomTooltip.css b/src/skins/vector/css/vector-web/views/rooms/RoomTooltip.css index deb8cd3f9..bf69f9e7b 100644 --- a/src/skins/vector/css/vector-web/views/rooms/RoomTooltip.css +++ b/src/skins/vector/css/vector-web/views/rooms/RoomTooltip.css @@ -16,17 +16,37 @@ limitations under the License. .mx_RoomTooltip_chevron { position: absolute; - left: -9px; - top: 7px; + left: -8px; + top: 4px; + width: 0; + height: 0; + border-top: 8px solid transparent; + border-right: 8px solid rgba(187, 187, 187, 0.5); + border-bottom: 8px solid transparent; +} + +.mx_RoomTooltip_chevron:after{ + content:''; + width: 0; + height: 0; + border-top: 7px solid transparent; + border-right: 7px solid #fff; + border-bottom: 7px solid transparent; + position:absolute; + top: -7px; + left: 1px; } .mx_RoomTooltip { display: none; position: fixed; - border: 1px solid #a4a4a4; - border-radius: 8px; + border: 1px solid rgba(187, 187, 187, 0.5); + border-radius: 5px; background-color: #fff; z-index: 2000; - left: 52px; - padding: 6px; + padding: 5px; + pointer-events: none; + line-height: 14px; + font-size: 13px; } + diff --git a/src/skins/vector/img/icon-address-delete.svg b/src/skins/vector/img/icon-address-delete.svg new file mode 100644 index 000000000..1289d5aaf --- /dev/null +++ b/src/skins/vector/img/icon-address-delete.svg @@ -0,0 +1,15 @@ + + + + 943783E9-DBD7-4D4E-BAC9-35437C17C2C4 + Created with sketchtool. + + + + + + + + + + diff --git a/src/skins/vector/img/icon_person.svg b/src/skins/vector/img/icon_person.svg new file mode 100644 index 000000000..4be70df0d --- /dev/null +++ b/src/skins/vector/img/icon_person.svg @@ -0,0 +1,23 @@ + + + + 815EF7DE-169A-4322-AE2A-B65CBE91DCED + Created with sketchtool. + + + + + + + + + + + + + + + + + + diff --git a/src/skins/vector/img/icons-close-button.svg b/src/skins/vector/img/icons-close-button.svg new file mode 100644 index 000000000..f17940f58 --- /dev/null +++ b/src/skins/vector/img/icons-close-button.svg @@ -0,0 +1,15 @@ + + + + 206C270A-EB00-48E4-8CC3-5D403C59177C + Created with sketchtool. + + + + + + + + + + diff --git a/src/skins/vector/img/icons-people.svg b/src/skins/vector/img/icons-people.svg index d6867a3f3..885450612 100644 --- a/src/skins/vector/img/icons-people.svg +++ b/src/skins/vector/img/icons-people.svg @@ -1,9 +1,22 @@ - - - - - - - - + + + + 81230A28-D944-4572-B5DB-C03CAA2B1FCA + Created with sketchtool. + + + + + + + + + + + + + + + + diff --git a/src/skins/vector/img/search-icon-vector.svg b/src/skins/vector/img/search-icon-vector.svg new file mode 100644 index 000000000..13728f97a --- /dev/null +++ b/src/skins/vector/img/search-icon-vector.svg @@ -0,0 +1,53 @@ + + + + 2EFF6BB8-D2CC-44E6-85E9-D057E4AE9DF2 + Created with sketchtool. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +