room directory makeover

This commit is contained in:
Bruno Windels 2019-01-29 15:34:58 +01:00
parent cc2b6f9524
commit 9f1b4ac4cc
13 changed files with 157 additions and 121 deletions

View file

@ -157,7 +157,7 @@ textarea {
font-weight: 300;
font-size: 15px;
position: relative;
padding: 0 58px 36px;
padding: 40px 58px 36px 58px;
width: 60%;
max-width: 704px;
box-shadow: 2px 15px 30px 0 $dialog-shadow-color;
@ -190,15 +190,36 @@ textarea {
pointer-events: none;
}
.mx_Dialog_cancelButton {
position: absolute;
right: 11px;
top: 13px;
cursor: pointer;
.mx_Dialog_header {
position: relative;
}
.mx_Dialog_cancelButton object {
pointer-events: none;
.mx_Dialog_title {
font-weight: bold;
font-size: 22px;
line-height: 36px;
color: $primary-fg-color;
}
.mx_Dialog_header.mx_Dialog_headerWithButton > .mx_Dialog_title {
text-align: center;
}
.mx_Dialog_title.danger {
color: $warning-color;
}
.mx_Dialog_cancelButton {
mask: url('$(res)/img/feather-icons/cancel.svg');
mask-repeat: no-repeat;
mask-position: center;
width: 36px;
height: 36px;
background-color: $primary-fg-color;
cursor: pointer;
position: absolute;
top: 20px;
right: 20px;
}
.mx_Dialog_content {
@ -254,19 +275,6 @@ textarea {
color: $accent-color;
}
.mx_Dialog_title {
min-height: 16px;
padding-top: 40px;
font-weight: bold;
font-size: 22px;
line-height: 1.4;
color: $primary-fg-color;
}
.mx_Dialog_title.danger {
color: $warning-color;
}
.mx_TextInputDialog_label {
text-align: left;
padding-bottom: 12px;

View file

@ -14,29 +14,48 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
.mx_RoomDirectory {
.mx_RoomDirectory_dialogWrapper > .mx_Dialog {
max-width: 960px;
width: 100%;
margin-left: auto;
margin-right: auto;
margin-bottom: 12px;
color: $primary-fg-color;
word-break: break-word;
height: 100%;
padding: 20px;
}
.mx_RoomDirectory_dialog {
height: 100%;
display: flex;
flex-direction: column;
}
.mx_RoomDirectory .mx_RoomHeader_simpleHeader {
margin-left: 0px;
.mx_RoomDirectory {
margin-bottom: 12px;
color: $primary-fg-color;
word-break: break-word;
display: flex;
flex-direction: column;
flex: 1;
}
.mx_RoomDirectory .gm-scroll-view {
// little hack because gemini doesn't seem to detect
// the scrollbar width well in this instance
// when using css scrollbars
scrollbar-width: thin;
}
.mx_RoomDirectory_createRoom {
background-color: $button-bg-color;
border-radius: 4px;
padding: 8px;
color: $button-fg-color;
font-weight: 600;
position: absolute;
top: 0;
left: 0;
}
.mx_RoomDirectory_list {
flex: 1;
display: flex;
flex-direction: column;
}
@ -45,22 +64,17 @@ limitations under the License.
}
.mx_RoomDirectory_listheader {
display: table;
table-layout: fixed;
width: 100%;
display: flex;
margin-top: 12px;
margin-bottom: 12px;
border-spacing: 5px;
}
.mx_RoomDirectory_searchbox {
display: table-cell;
vertical-align: middle;
flex: 1 !important;
}
.mx_RoomDirectory_listheader .mx_NetworkDropdown {
display: table-cell;
width: 200px;
flex: 0 0 200px;
}
.mx_RoomDirectory_tableWrapper {

View file

@ -35,13 +35,13 @@ limitations under the License.
height: 0;
position: absolute;
right: 10px;
top: 14px;
top: 16px;
width: 0
}
.mx_NetworkDropdown_networkoption {
height: 35px;
line-height: 35px;
height: 37px;
line-height: 37px;
padding-left: 8px;
padding-right: 8px;
overflow: hidden;

View file

@ -15,26 +15,10 @@ limitations under the License.
*/
.mx_DirectorySearchBox {
position: relative;
border-radius: 3px;
border: 1px solid $strong-input-border-color;
}
.mx_DirectorySearchBox_container {
display: flex;
padding-left: 9px;
padding-right: 9px;
}
.mx_DirectorySearchBox_input {
flex-grow: 1;
border: 0;
padding: 0;
font-weight: 300;
font-size: 13px;
}
input[type=text].mx_DirectorySearchBox_input:focus {
border: 0;
margin: 0 5px 0 0 !important;
}
.mx_DirectorySearchBox_joinButton {
@ -54,16 +38,12 @@ input[type=text].mx_DirectorySearchBox_input:focus {
cursor: pointer;
}
.mx_DirectorySearchBox_clear_wrapper {
display: table-cell;
}
.mx_DirectorySearchBox_clear {
display: inline-block;
vertical-align: middle;
background: url('$(res)/img/icon_context_delete.svg');
background-position: 0 50%;
background-repeat: no-repeat;
background-color: $warning-color;
mask: url('$(res)/img/cancel.svg');
mask-repeat: no-repeat;
mask-position: center;
mask-size: 10px;
width: 15px;
height: 15px;
cursor: pointer;

View file

@ -243,18 +243,20 @@ $authpage-body-color: #61708b;
// it has the appearance of a text box so the controls
// appear to be part of the input
.mx_MatrixChat {
.mx_Dialog, .mx_MatrixChat {
:not(.mx_textinput):not(.mx_Field) > input[type=text],
:not(.mx_textinput):not(.mx_Field) > input[type=search],
:not(.mx_textinput):not(.mx_Field):not(.mx_no_textinput) > input[type=text],
:not(.mx_textinput):not(.mx_Field):not(.mx_no_textinput) > input[type=search],
.mx_textinput {
display: block;
margin: 9px;
box-sizing: border-box;
background-color: transparent;
color: $input-darker-fg-color;
border-radius: 4px;
border: 1px solid #c1c1c1;
// these things should probably not be defined
// globally
margin: 9px;
flex: 0 0 auto;
}
@ -290,8 +292,8 @@ input[type=password] {
}
.dark-panel {
:not(.mx_textinput):not(.mx_Field) > input[type=text],
:not(.mx_textinput):not(.mx_Field) > input[type=search],
:not(.mx_textinput):not(.mx_Field):not(.mx_no_textinput) > input[type=text],
:not(.mx_textinput):not(.mx_Field):not(.mx_no_textinput) > input[type=search],
.mx_textinput {
color: $input-darker-fg-color;
background-color: $input-darker-bg-color;
@ -300,8 +302,8 @@ input[type=password] {
}
.light-panel {
:not(.mx_textinput):not(.mx_Field) > input[type=text],
:not(.mx_textinput):not(.mx_Field) > input[type=search],
:not(.mx_textinput):not(.mx_Field):not(.mx_no_textinput) > input[type=text],
:not(.mx_textinput):not(.mx_Field):not(.mx_no_textinput) > input[type=search],
.mx_textinput {
color: $input-lighter-fg-color;
background-color: $input-lighter-bg-color;

View file

@ -323,8 +323,6 @@ const LoggedInView = React.createClass({
_onScrollKeyPressed: function(ev) {
if (this.refs.roomView) {
this.refs.roomView.handleScrollKey(ev);
} else if (this.refs.roomDirectory) {
this.refs.roomDirectory.handleScrollKey(ev);
}
},
@ -422,7 +420,6 @@ const LoggedInView = React.createClass({
const LeftPanel = sdk.getComponent('structures.LeftPanel');
const RoomView = sdk.getComponent('structures.RoomView');
const UserSettings = sdk.getComponent('structures.UserSettings');
const RoomDirectory = sdk.getComponent('structures.RoomDirectory');
const HomePage = sdk.getComponent('structures.HomePage');
const GroupView = sdk.getComponent('structures.GroupView');
const MyGroups = sdk.getComponent('structures.MyGroups');
@ -464,10 +461,7 @@ const LoggedInView = React.createClass({
break;
case PageTypes.RoomDirectory:
pageElement = <RoomDirectory
ref="roomDirectory"
config={this.props.config.roomDirectory}
/>;
// handled by MatrixChat for now
break;
case PageTypes.HomePage:

View file

@ -615,8 +615,12 @@ export default React.createClass({
}
break;
case 'view_room_directory':
this._setPage(PageTypes.RoomDirectory);
this.notifyNewScreen('directory');
const RoomDirectory = sdk.getComponent("structures.RoomDirectory");
Modal.createTrackedDialog('Room directory', '', RoomDirectory, {
config: this.props.config,
}, 'mx_RoomDirectory_dialogWrapper');
// this._setPage(PageTypes.RoomDirectory);
// this.notifyNewScreen('directory');
break;
case 'view_my_groups':
this._setPage(PageTypes.MyGroups);

View file

@ -44,6 +44,7 @@ module.exports = React.createClass({
propTypes: {
config: React.PropTypes.object,
onFinished: React.PropTypes.func.isRequired,
},
getDefaultProps: function() {
@ -64,6 +65,16 @@ module.exports = React.createClass({
};
},
childContextTypes: {
matrixClient: React.PropTypes.object,
},
getChildContext: function() {
return {
matrixClient: MatrixClientPeg.get(),
};
},
componentWillMount: function() {
this._unmounted = false;
this.nextBatch = null;
@ -301,6 +312,11 @@ module.exports = React.createClass({
}
},
onCreateRoomClicked: function() {
this.props.onFinished();
dis.dispatch({action: 'view_create_room'});
},
onJoinClick: function(alias) {
// If we don't have a particular instance id selected, just show that rooms alias
if (!this.state.instanceId) {
@ -348,6 +364,7 @@ module.exports = React.createClass({
},
showRoom: function(room, room_alias) {
this.props.onFinished();
const payload = {action: 'view_room'};
if (room) {
// Don't let the user view a room they won't be able to either
@ -496,11 +513,13 @@ module.exports = React.createClass({
render: function() {
const SimpleRoomHeader = sdk.getComponent('rooms.SimpleRoomHeader');
const Loader = sdk.getComponent("elements.Spinner");
const BaseDialog = sdk.getComponent('views.dialogs.BaseDialog');
const AccessibleButton = sdk.getComponent('elements.AccessibleButton');
// TODO: clean this up
if (this.state.protocolsLoading) {
return (
<div className="mx_RoomDirectory">
<SimpleRoomHeader title={ _t('Directory') } />
<Loader />
</div>
);
@ -554,7 +573,7 @@ module.exports = React.createClass({
let placeholder = _t('Search for a room');
if (!this.state.instanceId) {
placeholder = _t('#example') + ':' + this.state.roomServer;
placeholder = _t('Search for a room like #example') + ':' + this.state.roomServer;
} else if (instance_expected_field_type) {
placeholder = instance_expected_field_type.placeholder;
}
@ -567,23 +586,35 @@ module.exports = React.createClass({
}
}
const createRoomButton = (<AccessibleButton
onClick={this.onCreateRoomClicked}
className="mx_RoomDirectory_createRoom"
>{_t("Create new room")}</AccessibleButton>);
const NetworkDropdown = sdk.getComponent('directory.NetworkDropdown');
const DirectorySearchBox = sdk.getComponent('elements.DirectorySearchBox');
return (
<div className="mx_RoomDirectory">
<SimpleRoomHeader title={ _t('Directory') } icon={require("../../../res/img/icons-directory.svg")} />
<div className="mx_RoomDirectory_list">
<div className="mx_RoomDirectory_listheader">
<DirectorySearchBox
className="mx_RoomDirectory_searchbox"
onChange={this.onFilterChange} onClear={this.onFilterClear} onJoinClick={this.onJoinClick}
placeholder={placeholder} showJoinButton={showJoinButton}
/>
<NetworkDropdown config={this.props.config} protocols={this.protocols} onOptionChange={this.onOptionChange} />
<BaseDialog
className={'mx_RoomDirectory_dialog'}
hasCancel={true}
onFinished={this.props.onFinished}
headerButton={createRoomButton}
title={_t("Room directory")}
>
<div className="mx_RoomDirectory">
<div className="mx_RoomDirectory_list">
<div className="mx_RoomDirectory_listheader">
<DirectorySearchBox
className="mx_RoomDirectory_searchbox"
onChange={this.onFilterChange} onClear={this.onFilterClear} onJoinClick={this.onJoinClick}
placeholder={placeholder} showJoinButton={showJoinButton}
/>
<NetworkDropdown config={this.props.config} protocols={this.protocols} onOptionChange={this.onOptionChange} />
</div>
{content}
</div>
{content}
</div>
</div>
</BaseDialog>
);
},
});

View file

@ -111,7 +111,6 @@ export default React.createClass({
let cancelButton;
if (this.props.hasCancel) {
cancelButton = <AccessibleButton onClick={this._onCancelClick} className="mx_Dialog_cancelButton">
<TintableSvg src={require("../../../../res/img/icons-close-button.svg")} width="35" height="35" />
</AccessibleButton>;
}
@ -128,10 +127,15 @@ export default React.createClass({
// AT users can skip its presentation.
aria-describedby={this.props.contentId}
>
{ cancelButton }
<div className={classNames('mx_Dialog_title', this.props.titleClass)} id='mx_BaseDialog_title'>
{ this.props.title }
<div className={classNames('mx_Dialog_header', {
'mx_Dialog_headerWithButton': !!this.props.headerButton,
})}>
<div className={classNames('mx_Dialog_title', this.props.titleClass)} id='mx_BaseDialog_title'>
{ this.props.title }
</div>
{ this.props.headerButton }
</div>
{ cancelButton }
{ this.props.children }
</FocusTrap>
);

View file

@ -232,7 +232,7 @@ export default class NetworkDropdown extends React.Component {
}
return <div className="mx_NetworkDropdown" ref={this.collectRoot}>
<div className="mx_NetworkDropdown_input" onClick={this.onInputClick}>
<div className="mx_NetworkDropdown_input mx_no_textinput" onClick={this.onInputClick}>
{current_value}
<span className="mx_NetworkDropdown_arrow"></span>
{menu}

View file

@ -17,6 +17,8 @@ limitations under the License.
import React from 'react';
import PropTypes from 'prop-types';
import classnames from 'classnames';
import sdk from '../../../index';
import { _t } from '../../../languageHandler';
export default class DirectorySearchBox extends React.Component {
constructor() {
@ -74,6 +76,8 @@ export default class DirectorySearchBox extends React.Component {
}
render() {
const AccessibleButton = sdk.getComponent('elements.AccessibleButton');
const searchbox_classes = {
mx_DirectorySearchBox: true,
};
@ -81,27 +85,21 @@ export default class DirectorySearchBox extends React.Component {
let join_button;
if (this.props.showJoinButton) {
join_button = <span className="mx_DirectorySearchBox_joinButton"
join_button = <AccessibleButton className="mx_DirectorySearchBox_joinButton"
onClick={this._onJoinButtonClick}
>
Join
</span>;
>{_t("Join")}</AccessibleButton>;
}
return <span className={classnames(searchbox_classes)}>
<div className="mx_DirectorySearchBox_container">
return <div className={`mx_DirectorySearchBox ${this.props.className} mx_textinput`}>
<input type="text" name="dirsearch" value={this.state.value}
className="mx_DirectorySearchBox_input"
className="mx_textinput_icon mx_textinput_search"
ref={this._collectInput}
onChange={this._onChange} onKeyUp={this._onKeyUp}
placeholder={this.props.placeholder} autoFocus
/>
{ join_button }
<span className="mx_DirectorySearchBox_clear_wrapper">
<span className="mx_DirectorySearchBox_clear" onClick={this._onClearClick} />
</span>
</div>
</span>;
<AccessibleButton className="mx_DirectorySearchBox_clear" onClick={this._onClearClick}></AccessibleButton>
</div>;
}
}

View file

@ -689,7 +689,7 @@ module.exports = React.createClass({
headerItems: this._getHeaderItems('im.vector.fake.recent'),
order: "recent",
incomingCall: incomingCallIfTaggedAs('im.vector.fake.recent'),
onAddRoom: () => {dis.dispatch({action: 'view_create_room'})},
onAddRoom: () => {dis.dispatch({action: 'view_room_directory'})},
},
];
const tagSubLists = Object.keys(this.state.lists)

View file

@ -1298,7 +1298,7 @@
"Unable to look up room ID from server": "Unable to look up room ID from server",
"Directory": "Directory",
"Search for a room": "Search for a room",
"#example": "#example",
"Search for a room like #example": "Search for a room like #example",
"Message not sent due to unknown devices being present": "Message not sent due to unknown devices being present",
"<showDevicesText>Show devices</showDevicesText>, <sendAnywayText>send anyway</sendAnywayText> or <cancelText>cancel</cancelText>.": "<showDevicesText>Show devices</showDevicesText>, <sendAnywayText>send anyway</sendAnywayText> or <cancelText>cancel</cancelText>.",
"You can't send any messages until you review and agree to <consentLink>our terms and conditions</consentLink>.": "You can't send any messages until you review and agree to <consentLink>our terms and conditions</consentLink>.",
@ -1497,5 +1497,6 @@
"If you didn't remove the recovery method, an attacker may be trying to access your account. Change your account password and set a new recovery method immediately in Settings.": "If you didn't remove the recovery method, an attacker may be trying to access your account. Change your account password and set a new recovery method immediately in Settings.",
"Failed to set direct chat tag": "Failed to set direct chat tag",
"Failed to remove tag %(tagName)s from room": "Failed to remove tag %(tagName)s from room",
"Failed to add tag %(tagName)s to room": "Failed to add tag %(tagName)s to room"
"Failed to add tag %(tagName)s to room": "Failed to add tag %(tagName)s to room",
"Join": "Join"
}