mirror of
https://github.com/element-hq/element-web
synced 2024-11-25 02:35:48 +03:00
room directory makeover
This commit is contained in:
parent
cc2b6f9524
commit
9f1b4ac4cc
13 changed files with 157 additions and 121 deletions
|
@ -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;
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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>
|
||||
);
|
||||
},
|
||||
});
|
||||
|
|
|
@ -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>
|
||||
);
|
||||
|
|
|
@ -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}
|
||||
|
|
|
@ -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>;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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"
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue