diff --git a/src/components/structures/BottomLeftMenu.js b/src/components/structures/BottomLeftMenu.js index f378cac628c693fcec8f692db1533f7ca1a3ee66..63dfac60d88c6bfd3c39a3cc55bdc0796d1a83a7 100644 --- a/src/components/structures/BottomLeftMenu.js +++ b/src/components/structures/BottomLeftMenu.js @@ -1,5 +1,6 @@ /* Copyright 2015, 2016 OpenMarket 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. @@ -14,13 +15,8 @@ See the License for the specific language governing permissions and 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'); -var AccessibleButton = require('matrix-react-sdk/lib/components/views/elements/AccessibleButton'); +import React from 'react'; +import sdk from 'matrix-react-sdk'; module.exports = React.createClass({ displayName: 'BottomLeftMenu', @@ -30,121 +26,28 @@ module.exports = React.createClass({ teamToken: React.PropTypes.string, }, - getInitialState: function() { - return({ - directoryHover : false, - roomsHover : false, - homeHover: 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 }); - }, - - // Home button events - onHomeClick: function() { - dis.dispatch({ action: 'view_home_page' }); - }, - - onHomeMouseEnter: function() { - this.setState({ homeHover: true }); - }, - - onHomeMouseLeave: function() { - this.setState({ homeHover: 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' }); - }, - - onSettingsMouseEnter: function() { - this.setState({ settingsHover: true }); - }, - - onSettingsMouseLeave: function() { - this.setState({ settingsHover: false }); - }, - - // Get the label/tooltip to show - getLabel: function(label, show) { - if (show) { - var RoomTooltip = sdk.getComponent("rooms.RoomTooltip"); - return <RoomTooltip className="mx_BottomLeftMenu_tooltip" label={label} />; - } - }, - render: function() { - var TintableSvg = sdk.getComponent('elements.TintableSvg'); + const HomeButton = sdk.getComponent('elements.HomeButton'); + const StartChatButton = sdk.getComponent('elements.StartChatButton'); + const RoomDirectoryButton = sdk.getComponent('elements.RoomDirectoryButton'); + const CreateRoomButton = sdk.getComponent('elements.CreateRoomButton'); + const SettingsButton = sdk.getComponent('elements.SettingsButton'); var homeButton; if (this.props.teamToken) { - homeButton = ( - <AccessibleButton className="mx_BottomLeftMenu_homePage" onClick={ this.onHomeClick } onMouseEnter={ this.onHomeMouseEnter } onMouseLeave={ this.onHomeMouseLeave } > - <TintableSvg src="img/icons-home.svg" width="25" height="25" /> - { this.getLabel("Welcome page", this.state.homeHover) } - </AccessibleButton> - ); + homeButton = <HomeButton tooltip={true} />; } return ( <div className="mx_BottomLeftMenu"> <div className="mx_BottomLeftMenu_options"> { homeButton } - <AccessibleButton className="mx_BottomLeftMenu_people" onClick={ this.onPeopleClick } onMouseEnter={ this.onPeopleMouseEnter } onMouseLeave={ this.onPeopleMouseLeave } > - <TintableSvg src="img/icons-people.svg" width="25" height="25" /> - { this.getLabel("Start chat", this.state.peopleHover) } - </AccessibleButton> - <AccessibleButton className="mx_BottomLeftMenu_directory" onClick={ this.onDirectoryClick } onMouseEnter={ this.onDirectoryMouseEnter } onMouseLeave={ this.onDirectoryMouseLeave } > - <TintableSvg src="img/icons-directory.svg" width="25" height="25"/> - { this.getLabel("Room directory", this.state.directoryHover) } - </AccessibleButton> - <AccessibleButton className="mx_BottomLeftMenu_createRoom" onClick={ this.onRoomsClick } onMouseEnter={ this.onRoomsMouseEnter } onMouseLeave={ this.onRoomsMouseLeave } > - <TintableSvg src="img/icons-create-room.svg" width="25" height="25" /> - { this.getLabel("Create new room", this.state.roomsHover) } - </AccessibleButton> - <AccessibleButton className="mx_BottomLeftMenu_settings" onClick={ this.onSettingsClick } onMouseEnter={ this.onSettingsMouseEnter } onMouseLeave={ this.onSettingsMouseLeave } > - <TintableSvg src="img/icons-settings.svg" width="25" height="25" /> - { this.getLabel("Settings", this.state.settingsHover) } - </AccessibleButton> + <StartChatButton tooltip={true} /> + <RoomDirectoryButton tooltip={true} /> + <CreateRoomButton tooltip={true} /> + <span className="mx_BottomLeftMenu_settings"> + <SettingsButton tooltip={true} /> + </span> </div> </div> ); diff --git a/src/components/structures/RoomSubList.js b/src/components/structures/RoomSubList.js index c315ae46e9a23c4571ca966189dc9f4d5250dd3f..ab6c4422d19ceeb176761c67e12e190e84ddec0d 100644 --- a/src/components/structures/RoomSubList.js +++ b/src/components/structures/RoomSubList.js @@ -1,4 +1,5 @@ /* +Copyright 2017 Vector Creations Ltd Copyright 2015, 2016 OpenMarket Ltd Licensed under the Apache License, Version 2.0 (the "License"); @@ -83,6 +84,8 @@ var RoomSubList = React.createClass({ incomingCall: React.PropTypes.object, onShowMoreRooms: React.PropTypes.func, searchFilter: React.PropTypes.string, + emptyContent: React.PropTypes.node, // content shown if the list is empty + headerItems: React.PropTypes.node, // content shown in the sublist header }, getInitialState: function() { @@ -469,16 +472,15 @@ var RoomSubList = React.createClass({ render: function() { var connectDropTarget = this.props.connectDropTarget; - var RoomDropTarget = sdk.getComponent('rooms.RoomDropTarget'); var TruncatedList = sdk.getComponent('elements.TruncatedList'); var label = this.props.collapsed ? null : this.props.label; - //console.log("render: " + JSON.stringify(this.state.sortedList)); - - var target; - if (this.state.sortedList.length == 0 && this.props.editable) { - target = <RoomDropTarget label={ 'Drop here to ' + this.props.verb }/>; + let content; + if (this.state.sortedList.length == 0) { + content = this.props.emptyContent; + } else { + content = this.makeRoomTiles(); } var roomCount = this.props.list.length > 0 ? this.props.list.length : ''; @@ -498,8 +500,7 @@ var RoomSubList = React.createClass({ if (!this.state.hidden) { subList = <TruncatedList className={ classes } truncateAt={this.state.truncateAt} createOverflowElement={this._createOverflowTile} > - { target } - { this.makeRoomTiles() } + { content } </TruncatedList>; } else { @@ -521,6 +522,7 @@ var RoomSubList = React.createClass({ roomNotificationCount={ this.roomNotificationCount() } onClick={ this.onClick } onHeaderClick={ this.props.onHeaderClick } + headerItems={this.props.headerItems} /> { subList } </div> @@ -542,6 +544,7 @@ var RoomSubList = React.createClass({ roomNotificationCount={ this.roomNotificationCount() } onClick={ this.onClick } onHeaderClick={ this.props.onHeaderClick } + headerItems={this.props.headerItems} /> : undefined } { (this.props.showSpinner && !this.state.hidden) ? <Loader /> : undefined } diff --git a/src/components/structures/RoomSubListHeader.js b/src/components/structures/RoomSubListHeader.js index ad9aff5f704452c0682493a7dcec7545ff1fa668..74094ae0bab1d0b44fc58388a1d914db5eb1ad8e 100644 --- a/src/components/structures/RoomSubListHeader.js +++ b/src/components/structures/RoomSubListHeader.js @@ -14,16 +14,11 @@ See the License for the specific language governing permissions and limitations under the License. */ -'use strict'; - -var React = require('react'); -var ReactDOM = require('react-dom'); -var classNames = require('classnames'); -var sdk = require('matrix-react-sdk') -var FormattingUtils = require('matrix-react-sdk/lib/utils/FormattingUtils'); -var RoomNotifs = require('matrix-react-sdk/lib/RoomNotifs'); -var AccessibleButton = require('matrix-react-sdk/lib/components/views/elements/AccessibleButton'); -var ConstantTimeDispatcher = require('matrix-react-sdk/lib/ConstantTimeDispatcher'); +import React from 'react'; +import classNames from 'classnames'; +import sdk from 'matrix-react-sdk'; +import { formatCount } from 'matrix-react-sdk/lib/utils/FormattingUtils'; +import AccessibleButton from 'matrix-react-sdk/lib/components/views/elements/AccessibleButton'; module.exports = React.createClass({ displayName: 'RoomSubListHeader', @@ -42,6 +37,7 @@ module.exports = React.createClass({ hidden: React.PropTypes.bool, onClick: React.PropTypes.func, onHeaderClick: React.PropTypes.func, + headerItems: React.PropTypes.node, // content shown in the sublist header }, getDefaultProps: function() { @@ -63,35 +59,34 @@ module.exports = React.createClass({ // }, render: function() { - var TintableSvg = sdk.getComponent("elements.TintableSvg"); + const TintableSvg = sdk.getComponent("elements.TintableSvg"); - var subListNotifications = this.props.roomNotificationCount; - var subListNotifCount = subListNotifications[0]; - var subListNotifHighlight = subListNotifications[1]; + const subListNotifications = this.props.roomNotificationCount; + const subListNotifCount = subListNotifications[0]; + const subListNotifHighlight = subListNotifications[1]; - var chevronClasses = classNames({ + const chevronClasses = classNames({ 'mx_RoomSubList_chevron': true, 'mx_RoomSubList_chevronRight': this.props.hidden, 'mx_RoomSubList_chevronDown': !this.props.hidden, }); - var badgeClasses = classNames({ + const badgeClasses = classNames({ 'mx_RoomSubList_badge': true, 'mx_RoomSubList_badgeHighlight': subListNotifHighlight, }); - var badge; + let badge; if (subListNotifCount > 0) { - badge = <div className={badgeClasses}>{ FormattingUtils.formatCount(subListNotifCount) }</div>; - } - else if (subListNotifHighlight) { + badge = <div className={badgeClasses}>{ formatCount(subListNotifCount) }</div>; + } else if (subListNotifHighlight) { badge = <div className={badgeClasses}>!</div>; } // When collapsed, allow a long hover on the header to show user // the full tag name and room count - var title; - var roomCount = this.props.roomCount; + let title; + const roomCount = this.props.roomCount; if (this.props.collapsed) { title = this.props.label; if (roomCount !== '') { @@ -99,9 +94,9 @@ module.exports = React.createClass({ } } - var incomingCall; + let incomingCall; if (this.props.isIncomingCallRoom) { - var IncomingCallBox = sdk.getComponent("voip.IncomingCallBox"); + const IncomingCallBox = sdk.getComponent("voip.IncomingCallBox"); incomingCall = <IncomingCallBox className="mx_RoomSubList_incomingCall" incomingCall={ this.props.incomingCall }/>; } @@ -109,6 +104,7 @@ module.exports = React.createClass({ <div className="mx_RoomSubList_labelContainer" title={ title } ref="header"> <AccessibleButton onClick={ this.props.onClick } className="mx_RoomSubList_label" tabIndex="0"> { this.props.collapsed ? '' : this.props.label } + {this.props.headerItems} <div className="mx_RoomSubList_roomCount">{ roomCount }</div> <div className={chevronClasses}></div> { badge } diff --git a/src/skins/vector/css/_components.scss b/src/skins/vector/css/_components.scss index df3c4600eb45aec426ff848d77dd8362a1d063c8..5b23bb82f8d73975ed9cfd066dfb1534eb4bdf28 100644 --- a/src/skins/vector/css/_components.scss +++ b/src/skins/vector/css/_components.scss @@ -27,6 +27,7 @@ @import "./matrix-react-sdk/views/elements/_MemberEventListSummary.scss"; @import "./matrix-react-sdk/views/elements/_ProgressBar.scss"; @import "./matrix-react-sdk/views/elements/_RichText.scss"; +@import "./matrix-react-sdk/views/elements/_RoleButton.scss"; @import "./matrix-react-sdk/views/login/_InteractiveAuthEntryComponents.scss"; @import "./matrix-react-sdk/views/login/_ServerConfig.scss"; @import "./matrix-react-sdk/views/messages/_MEmoteBody.scss"; diff --git a/src/skins/vector/css/matrix-react-sdk/views/elements/_RoleButton.scss b/src/skins/vector/css/matrix-react-sdk/views/elements/_RoleButton.scss new file mode 100644 index 0000000000000000000000000000000000000000..094e0b9b1b7d94c1ac472bcd8b8fa1dd002aa34c --- /dev/null +++ b/src/skins/vector/css/matrix-react-sdk/views/elements/_RoleButton.scss @@ -0,0 +1,33 @@ +/* +Copyright 2107 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. +*/ + +.mx_RoleButton { + margin-left: 4px; + margin-right: 4px; + cursor: pointer; + display: inline-block; +} + +.mx_RoleButton object { + pointer-events: none; +} + +.mx_RoleButton_tooltip { + display: inline-block; + position: relative; + top: -25px; + left: 6px; +} diff --git a/src/skins/vector/css/matrix-react-sdk/views/rooms/_RoomList.scss b/src/skins/vector/css/matrix-react-sdk/views/rooms/_RoomList.scss index 110dcd5b6b0947300f44a1b44ca28089f2421705..35787ca0c48d0022153b348c60cd336d0049415a 100644 --- a/src/skins/vector/css/matrix-react-sdk/views/rooms/_RoomList.scss +++ b/src/skins/vector/css/matrix-react-sdk/views/rooms/_RoomList.scss @@ -1,5 +1,6 @@ /* Copyright 2015, 2016 OpenMarket Ltd +Copyright 2107 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. @@ -37,3 +38,25 @@ limitations under the License. .mx_RoomList_scrollbar .gm-scrollbar.-vertical { z-index: 6; } + +.mx_RoomList_emptySubListTip { + font-size: 13px; + margin-left: 18px; + margin-right: 18px; + margin-top: 8px; + margin-bottom: 7px; + padding: 5px; + border: 1px dashed $accent-color; + color: $primary-fg-color; + background-color: $droptarget-bg-color; + border-radius: 4px; +} + +.mx_RoomList_emptySubListTip .mx_RoleButton { + vertical-align: -3px; +} + +.mx_RoomList_headerButtons { + position: absolute; + right: 60px; +} diff --git a/src/skins/vector/css/vector-web/structures/_LeftPanel.scss b/src/skins/vector/css/vector-web/structures/_LeftPanel.scss index d3bbce1b19466b7f6f713495e334f9f6cedc594d..f171591cd60813d6e6685c331038715c3d842858 100644 --- a/src/skins/vector/css/vector-web/structures/_LeftPanel.scss +++ b/src/skins/vector/css/vector-web/structures/_LeftPanel.scss @@ -64,43 +64,25 @@ limitations under the License. pointer-events: none; } -.mx_LeftPanel .mx_BottomLeftMenu_homePage, -.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_homePage, -.collapsed .mx_BottomLeftMenu_directory, -.collapsed .mx_BottomLeftMenu_createRoom, -.collapsed .mx_BottomLeftMenu_people, -.collapsed .mx_BottomLeftMenu_settings { +.collapsed .mx_RoleButton { margin-right: 0px ! important; padding-top: 3px ! important; padding-bottom: 3px ! important; } -.mx_LeftPanel .mx_BottomLeftMenu_homePage, -.mx_LeftPanel .mx_BottomLeftMenu_directory, -.mx_LeftPanel .mx_BottomLeftMenu_createRoom, -.mx_LeftPanel .mx_BottomLeftMenu_people { +.mx_BottomLeftMenu_options .mx_RoleButton { + margin-left: 0px; margin-right: 10px; } -.mx_LeftPanel .mx_BottomLeftMenu_settings { +.mx_BottomLeftMenu_options .mx_BottomLeftMenu_settings { float: right; } -.mx_LeftPanel.collapsed .mx_BottomLeftMenu_settings { - float: none; +.mx_BottomLeftMenu_options .mx_BottomLeftMenu_settings .mx_RoleButton { + margin-right: 0px; } -.mx_LeftPanel .mx_BottomLeftMenu_tooltip { - display: inline-block; - position: relative; - top: -25px; - left: 6px; +.mx_LeftPanel.collapsed .mx_BottomLeftMenu_settings { + float: none; }