user discovery
This commit is contained in:
+140
-13
@@ -2,6 +2,8 @@
|
|||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
|
font-family: Roboto, Arial, sans-serif;
|
||||||
|
text-rendering: optimizeLegibility;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Basic elements defined */
|
/* Basic elements defined */
|
||||||
@@ -9,7 +11,6 @@
|
|||||||
html, body {
|
html, body {
|
||||||
height:100%;
|
height:100%;
|
||||||
width:100%;
|
width:100%;
|
||||||
font-family: 'Roboto', Arial, sans-serif;
|
|
||||||
font-size: 10pt;
|
font-size: 10pt;
|
||||||
color: #666;
|
color: #666;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
@@ -173,6 +174,42 @@ form {
|
|||||||
font-size: 1.2rem;
|
font-size: 1.2rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* BEGIN Popup/dropdown menu */
|
||||||
|
|
||||||
|
ul.menu {
|
||||||
|
position: absolute;
|
||||||
|
left: -1.5rem;
|
||||||
|
top: 1.5rem;
|
||||||
|
list-style: none;
|
||||||
|
width: 12rem;
|
||||||
|
border-radius: 0.2rem;
|
||||||
|
padding-top: 0.35rem;
|
||||||
|
padding-bottom: 0.35rem;
|
||||||
|
box-shadow: 0 1px 6px rgba(0, 0, 0, .45);
|
||||||
|
background-color: white;
|
||||||
|
z-index: 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
ul.menu > li {
|
||||||
|
padding: 0.75rem 0.75rem 0.75rem 1.25rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
ul.menu > li:hover {
|
||||||
|
background-color: #f5f5f5;
|
||||||
|
}
|
||||||
|
|
||||||
|
ul.menu > li.separator {
|
||||||
|
padding: 0;
|
||||||
|
margin: 2px;
|
||||||
|
height: 1px;
|
||||||
|
background-color: #ccc;
|
||||||
|
}
|
||||||
|
|
||||||
|
ul.menu > li.separator:hover {
|
||||||
|
background-color: #ccc;
|
||||||
|
}
|
||||||
|
/* END popup/dropdown menu */
|
||||||
|
|
||||||
/* END of basic elements */
|
/* END of basic elements */
|
||||||
|
|
||||||
#mountPoint {
|
#mountPoint {
|
||||||
@@ -297,18 +334,22 @@ form {
|
|||||||
|
|
||||||
/* Area which displays an error message */
|
/* Area which displays an error message */
|
||||||
#alert-box {
|
#alert-box {
|
||||||
padding: 0.5em;
|
|
||||||
background-color: transparent;
|
background-color: transparent;
|
||||||
|
height: 0;
|
||||||
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
#alert-box.error-alert {
|
#alert-box.error-alert {
|
||||||
|
padding: 0.5em;
|
||||||
background-color: #ffcdd2;
|
background-color: #ffcdd2;
|
||||||
border-color: #d32f2f;
|
border-color: #d32f2f;
|
||||||
color: #600;
|
color: #b71c1c;
|
||||||
|
height: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* List of contacts */
|
/* List of contacts */
|
||||||
#contacts-panel {
|
#contacts-panel {
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
|
margin-top: 1rem;:
|
||||||
margin-bottom: auto;
|
margin-bottom: auto;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
}
|
}
|
||||||
@@ -317,16 +358,15 @@ form {
|
|||||||
list-style: none;
|
list-style: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
#contact-box li {
|
#contact-box > li {
|
||||||
display: flex;
|
display: flex;
|
||||||
padding: 0.35rem 0.25rem 0.5rem 0.35rem;
|
padding: 0.35rem 0.25rem 0.5rem 0.35rem;
|
||||||
min-height: 3.5rem;
|
min-height: 3.5rem;
|
||||||
overflow: hidden;
|
|
||||||
}
|
}
|
||||||
#contact-box li:hover {
|
#contact-box > li:hover {
|
||||||
background-color: #eceff1; /* blue-gray 50 highlight */
|
background-color: #eceff1; /* blue-gray 50 highlight */
|
||||||
}
|
}
|
||||||
#contact-box li.selected {
|
#contact-box > li.selected {
|
||||||
background-color: #cfd8dc; /* blue-gray 100 highlight */
|
background-color: #cfd8dc; /* blue-gray 100 highlight */
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -334,6 +374,26 @@ form {
|
|||||||
font-size: 1.05rem;
|
font-size: 1.05rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* The down arrow head - trigger for context menu in contacts list */
|
||||||
|
#contact-box li .menuTrigger {
|
||||||
|
position: relative;
|
||||||
|
margin-left: auto;
|
||||||
|
width: 1.5rem;
|
||||||
|
height: 1.5rem;
|
||||||
|
border-radius: 50%;
|
||||||
|
background-color: transparent;
|
||||||
|
}
|
||||||
|
#contact-box li:hover .menuTrigger {
|
||||||
|
background-color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
#contact-box li .menuTrigger a {
|
||||||
|
color: transparent;
|
||||||
|
}
|
||||||
|
#contact-box li:hover .menuTrigger a {
|
||||||
|
color: #757575;
|
||||||
|
}
|
||||||
|
|
||||||
/* Avatar and online-offline indicator */
|
/* Avatar and online-offline indicator */
|
||||||
#contact-box .avatar-box {
|
#contact-box .avatar-box {
|
||||||
margin-right: 0.35rem;
|
margin-right: 0.35rem;
|
||||||
@@ -363,26 +423,33 @@ form {
|
|||||||
#contact-box .offline {
|
#contact-box .offline {
|
||||||
color: #888;
|
color: #888;
|
||||||
}
|
}
|
||||||
|
/* END of avatar box */
|
||||||
|
|
||||||
#add-topic {
|
#add-topic {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
right: 1em;
|
right: 1em;
|
||||||
bottom: 1em;
|
bottom: 1em;
|
||||||
}
|
}
|
||||||
/* END of avatar box */
|
|
||||||
|
|
||||||
/* New account panel (signup form) */
|
/* Various forms inside a panel (signup form, new topic form) */
|
||||||
#signup-form {
|
.panel-form {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
}
|
}
|
||||||
|
|
||||||
#signup-form-one {
|
.panel-form-one {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: space-between;
|
justify-content: flex-start;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.panel-form-two {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Styling of avatar upload area in the New Account panel */
|
/* Styling of avatar upload area in the New Account panel */
|
||||||
.avatar-upload {
|
.avatar-upload {
|
||||||
position: relative;
|
position: relative;
|
||||||
@@ -698,9 +765,69 @@ form {
|
|||||||
padding: 0.35rem 1.5rem;
|
padding: 0.35rem 1.5rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* END of modal dialog */
|
/* END of modal dialog */
|
||||||
|
|
||||||
|
/* BEGIN Tabs */
|
||||||
|
.tabbar {
|
||||||
|
padding-top: 1rem;
|
||||||
|
background: #eeeeee; /* #2196f3; */
|
||||||
|
}
|
||||||
|
|
||||||
|
.tabbar > ul {
|
||||||
|
list-style:none;
|
||||||
|
margin:0;
|
||||||
|
width:100%;
|
||||||
|
overflow:hidden;
|
||||||
|
padding:0;
|
||||||
|
margin-left:1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tabbar > ul > li {
|
||||||
|
float: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tabbar > ul > li > a {
|
||||||
|
position: relative;
|
||||||
|
text-decoration: none;
|
||||||
|
text-transform: uppercase;
|
||||||
|
display: block;
|
||||||
|
min-width: 6rem;
|
||||||
|
text-align: center;
|
||||||
|
line-height: 2rem;
|
||||||
|
font-weight: 400;
|
||||||
|
font-size: 1.1rem;
|
||||||
|
color: rgba(33,150,243,0.6);
|
||||||
|
overflow: hidden;
|
||||||
|
box-shadow: inset 0 -2px 2.5px -1px rgba(0,0,0,0.5);
|
||||||
|
}
|
||||||
|
|
||||||
|
.tabbar li.active > a {
|
||||||
|
color: #2196f3;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tabbar li.active > a:after {
|
||||||
|
height:0.15rem;
|
||||||
|
display:block;
|
||||||
|
content:"";
|
||||||
|
bottom:0;
|
||||||
|
left:0;
|
||||||
|
position: absolute;
|
||||||
|
background: #2196f3;
|
||||||
|
animation: tabbar-border-expand 0.2s cubic-bezier(0.4, 0.0, 0.4, 1) 0s alternate forwards;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes tabbar-border-expand {
|
||||||
|
0% {
|
||||||
|
opacity:0;
|
||||||
|
width:0;
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
opacity:1;
|
||||||
|
width:100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* END Tabs */
|
||||||
|
|
||||||
/* Miscellaneous */
|
/* Miscellaneous */
|
||||||
|
|
||||||
/* Badge with the number of unread messages */
|
/* Badge with the number of unread messages */
|
||||||
|
|||||||
+195
-52
@@ -27,8 +27,8 @@
|
|||||||
var APP_NAME = "TinodeReact/0.6";
|
var APP_NAME = "TinodeReact/0.6";
|
||||||
|
|
||||||
// Host name and port to connect to
|
// Host name and port to connect to
|
||||||
var HOST = "api.tinode.co";
|
// var HOST = "api.tinode.co";
|
||||||
// var HOST = "localhost:6060";
|
var HOST = "localhost:6060";
|
||||||
|
|
||||||
// API key. Use https://github.com/tinode/chat/tree/master/keygen to generate your own
|
// API key. Use https://github.com/tinode/chat/tree/master/keygen to generate your own
|
||||||
var API_KEY = "AQEAAAABAAD_rAp4DJh05a1HAwFT3A6K";
|
var API_KEY = "AQEAAAABAAD_rAp4DJh05a1HAwFT3A6K";
|
||||||
@@ -66,6 +66,68 @@
|
|||||||
return photo ? 'data:image/' + photo.type + ';base64,' + photo.data : null;
|
return photo ? 'data:image/' + photo.type + ';base64,' + photo.data : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* BEGIN Popup/dropdown menu */
|
||||||
|
var Menu = React.createClass({
|
||||||
|
getInitialState: function() {
|
||||||
|
return {
|
||||||
|
visible: this.props.visible
|
||||||
|
};
|
||||||
|
},
|
||||||
|
componentWillUnmount: function() {
|
||||||
|
document.removeEventListener('mousedown', this.handlePageClick, false);
|
||||||
|
},
|
||||||
|
componentWillReceiveProps: function(nextProps) {
|
||||||
|
this.setState({visible: nextProps.visible});
|
||||||
|
if (nextProps.visible) {
|
||||||
|
document.addEventListener('mousedown', this.handlePageClick, false);
|
||||||
|
} else {
|
||||||
|
document.removeEventListener('mousedown', this.handlePageClick, false);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
handlePageClick: function(e) {
|
||||||
|
if (ReactDOM.findDOMNode(this).contains(e.target)) {
|
||||||
|
console.log("click in menu, exiting");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
e.stopPropagation();
|
||||||
|
document.removeEventListener('mousedown', this.handlePageClick);
|
||||||
|
console.log("click outside of menu");
|
||||||
|
this.setState({visible: false});
|
||||||
|
},
|
||||||
|
handleClick: function(e) {
|
||||||
|
e.preventDefault();
|
||||||
|
e.stopPropagation();
|
||||||
|
this.setState({visible: false});
|
||||||
|
this.props.onResult(this.props.topic, this.props.items[e.currentTarget.dataset.id]);
|
||||||
|
},
|
||||||
|
render: function() {
|
||||||
|
if (!this.state.visible) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
var count = 0;
|
||||||
|
var menuItems = [];
|
||||||
|
var instance = this;
|
||||||
|
this.props.items.map(function(item) {
|
||||||
|
if (item === "-") {
|
||||||
|
menuItems.push(
|
||||||
|
<li className="separator" key={count} />
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
menuItems.push(
|
||||||
|
<li onClick={instance.handleClick} data-id={count} key={count}>{item}</li>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
count++;
|
||||||
|
});
|
||||||
|
return (
|
||||||
|
<ul className="menu">
|
||||||
|
{menuItems}
|
||||||
|
</ul>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
/* END Popup/dropdown menu */
|
||||||
|
|
||||||
/* BEGIN Login: a login form */
|
/* BEGIN Login: a login form */
|
||||||
var LoginView = React.createClass({
|
var LoginView = React.createClass({
|
||||||
getInitialState: function() {
|
getInitialState: function() {
|
||||||
@@ -179,9 +241,9 @@
|
|||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<form id="signup-form" onSubmit={this.handleSubmit} onCancel={this.props.onCancel}>
|
<form className="panel-form" onSubmit={this.handleSubmit} onCancel={this.props.onCancel}>
|
||||||
<div id="signup-form-one">
|
<div className="panel-form-one">
|
||||||
<div>
|
<div className="panel-form-two">
|
||||||
<input type="text" placeholder="Login"
|
<input type="text" placeholder="Login"
|
||||||
value={this.state.login} onChange={this.handleLoginChange} required autofocus />
|
value={this.state.login} onChange={this.handleLoginChange} required autofocus />
|
||||||
<input type="password" placeholder="Password"
|
<input type="password" placeholder="Password"
|
||||||
@@ -189,7 +251,7 @@
|
|||||||
<input type="password" placeholder="Repeat password"
|
<input type="password" placeholder="Repeat password"
|
||||||
value={this.state.password2} onChange={this.handlePassword2Change} required />
|
value={this.state.password2} onChange={this.handlePassword2Change} required />
|
||||||
</div>
|
</div>
|
||||||
<CreateAccountView.AvatarUpload onImageChanged={this.handleImageChanged} />
|
<AvatarUpload onImageChanged={this.handleImageChanged} />
|
||||||
</div>
|
</div>
|
||||||
<input type="text" placeholder="Full name, e.g. John Doe"
|
<input type="text" placeholder="Full name, e.g. John Doe"
|
||||||
value={this.state.fn} onChange={this.handleFnChange} />
|
value={this.state.fn} onChange={this.handleFnChange} />
|
||||||
@@ -202,7 +264,7 @@
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
CreateAccountView.AvatarUpload = React.createClass({
|
var AvatarUpload = React.createClass({
|
||||||
getInitialState: function() {
|
getInitialState: function() {
|
||||||
return {
|
return {
|
||||||
dataUrl: null
|
dataUrl: null
|
||||||
@@ -248,6 +310,65 @@
|
|||||||
});
|
});
|
||||||
/* END Account registration */
|
/* END Account registration */
|
||||||
|
|
||||||
|
/* BEGIN Create new topic and invite users or send an invite */
|
||||||
|
var NewTopicView = React.createClass({
|
||||||
|
getInitialState: function() {
|
||||||
|
return {
|
||||||
|
tabSelected: "p2p",
|
||||||
|
fn: '', // full/formatted name
|
||||||
|
imageDataUrl: null
|
||||||
|
};
|
||||||
|
},
|
||||||
|
handleTabClick: function(e) {
|
||||||
|
e.preventDefault();
|
||||||
|
this.setState({tabSelected: e.currentTarget.dataset.id});
|
||||||
|
},
|
||||||
|
handleFnChange: function(e) {
|
||||||
|
this.setState({fn: e.target.value});
|
||||||
|
},
|
||||||
|
handleImageChanged: function(img) {
|
||||||
|
this.setState({imageDataUrl: img});
|
||||||
|
},
|
||||||
|
handleGroupSubmit: function(e) {
|
||||||
|
e.preventDefault();
|
||||||
|
},
|
||||||
|
render: function() {
|
||||||
|
var submitClasses = "blue";
|
||||||
|
if (this.props.disabled) {
|
||||||
|
submitClasses += " disabled";
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<div className="tabbar">
|
||||||
|
<ul>
|
||||||
|
<li className={this.state.tabSelected === "p2p" ? "active" : null}>
|
||||||
|
<a href="#" data-id="p2p" onClick={this.handleTabClick}>1:1</a>
|
||||||
|
</li>
|
||||||
|
<li className={this.state.tabSelected === "grp" ? "active" : null}>
|
||||||
|
<a href="#" data-id="grp" onClick={this.handleTabClick}>group</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
{this.state.tabSelected === "grp" ?
|
||||||
|
<form className="panel-form" onSubmit={this.handleGroupSubmit} onCancel={this.props.onCancel}>
|
||||||
|
<div className="panel-form-one">
|
||||||
|
<div className="panel-form-two">
|
||||||
|
<input type="text" placeholder="Name of the topic to create"
|
||||||
|
value={this.state.fn} onChange={this.handleFnChange} autofocus required />
|
||||||
|
<div className="dialog-buttons">
|
||||||
|
<button className={submitClasses} type="submit">Create</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<AvatarUpload onImageChanged={this.handleImageChanged} />
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
: null}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
/* END Create new topic and invite users or send an invite */
|
||||||
|
|
||||||
/* BEGIN Tinode config panel */
|
/* BEGIN Tinode config panel */
|
||||||
var SettingsView = React.createClass({
|
var SettingsView = React.createClass({
|
||||||
getInitialState: function() {
|
getInitialState: function() {
|
||||||
@@ -292,7 +413,7 @@
|
|||||||
});
|
});
|
||||||
/* END Tinode config panel */
|
/* END Tinode config panel */
|
||||||
|
|
||||||
/* BEGIN Manage side panel - handle Login, Account Registration, and Contacts views */
|
/* BEGIN Manage side panel - handle Login, Account Registration, Contacts, NewTopic views */
|
||||||
var SideNavbar = React.createClass({
|
var SideNavbar = React.createClass({
|
||||||
render: function() {
|
render: function() {
|
||||||
var avatar = null;
|
var avatar = null;
|
||||||
@@ -307,14 +428,17 @@
|
|||||||
<div id="sidepanel-title" className="panel-title">{this.props.title}</div>
|
<div id="sidepanel-title" className="panel-title">{this.props.title}</div>
|
||||||
{this.props.state === 'login' ?
|
{this.props.state === 'login' ?
|
||||||
<SideNavbar.MenuStart onSignUp={this.props.onSignUp} onSettings={this.props.onSettings} /> :
|
<SideNavbar.MenuStart onSignUp={this.props.onSignUp} onSettings={this.props.onSettings} /> :
|
||||||
this.props.state === 'settings' ?
|
this.props.state === 'settings' ?
|
||||||
<SideNavbar.MenuCancel onCancel={this.props.onCancel} /> :
|
<SideNavbar.MenuCancel onCancel={this.props.onCancel} /> :
|
||||||
this.props.state === 'edit-account' ?
|
this.props.state === 'edit-account' ?
|
||||||
<SideNavbar.MenuCancel onCancel={this.props.onCancel} /> :
|
<SideNavbar.MenuCancel onCancel={this.props.onCancel} /> :
|
||||||
this.props.state === 'register' ?
|
this.props.state === 'register' ?
|
||||||
<SideNavbar.MenuCancel onCancel={this.props.onCancel} /> :
|
<SideNavbar.MenuCancel onCancel={this.props.onCancel} /> :
|
||||||
this.props.state === 'contacts' ?
|
this.props.state === 'contacts' ?
|
||||||
<SideNavbar.MenuSettings onSettings={this.props.onSettings} /> : null}
|
<SideNavbar.MenuContacts onNewTopic={this.props.onNewTopic} onSettings={this.props.onSettings} /> :
|
||||||
|
this.props.state === 'new-topic' ?
|
||||||
|
<SideNavbar.MenuCancel onCancel={this.props.onCancel} /> :
|
||||||
|
null}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -340,10 +464,14 @@
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
SideNavbar.MenuSettings = React.createClass({
|
SideNavbar.MenuContacts = React.createClass({
|
||||||
render: function() {
|
render: function() {
|
||||||
return (
|
return (
|
||||||
<a href="#" onClick={this.props.onSettings}><i className="material-icons">settings</i></a>
|
<div>
|
||||||
|
<a href="#" onClick={this.props.onNewTopic}><i className="material-icons">add_circle</i></a>
|
||||||
|
|
||||||
|
<a href="#" onClick={this.props.onSettings}><i className="material-icons">settings</i></a>
|
||||||
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@@ -376,6 +504,10 @@
|
|||||||
case 'contacts':
|
case 'contacts':
|
||||||
title = this.props.title;
|
title = this.props.title;
|
||||||
avatar = this.props.avatar;
|
avatar = this.props.avatar;
|
||||||
|
break;
|
||||||
|
case 'new-topic':
|
||||||
|
title = "Start New Chat";
|
||||||
|
break;
|
||||||
default:;
|
default:;
|
||||||
};
|
};
|
||||||
return (
|
return (
|
||||||
@@ -384,6 +516,7 @@
|
|||||||
title={title} avatar={avatar}
|
title={title} avatar={avatar}
|
||||||
onSignUp={this.props.onSignUp}
|
onSignUp={this.props.onSignUp}
|
||||||
onSettings={this.props.onSettings}
|
onSettings={this.props.onSettings}
|
||||||
|
onNewTopic={this.props.onNewTopic}
|
||||||
onCancel={this.props.onCancel} />
|
onCancel={this.props.onCancel} />
|
||||||
|
|
||||||
<SidepanelView.ErrorPanel
|
<SidepanelView.ErrorPanel
|
||||||
@@ -409,8 +542,14 @@
|
|||||||
this.props.state === 'contacts' ?
|
this.props.state === 'contacts' ?
|
||||||
<ContactsView
|
<ContactsView
|
||||||
data={this.props.subscriptions}
|
data={this.props.subscriptions}
|
||||||
onTopicSelected={this.props.onTopicSelected}
|
onTopicSelected={this.props.onTopicSelected} /> :
|
||||||
onNewTopic={this.props.onNewTopic} /> :
|
|
||||||
|
this.props.state === 'new-topic' ?
|
||||||
|
<NewTopicView
|
||||||
|
data={this.props.subscriptions}
|
||||||
|
onContactSelected={this.props.onContactSelected}
|
||||||
|
onStartNewTopic={this.props.onStartNewTopic} /> :
|
||||||
|
|
||||||
null}
|
null}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
@@ -446,35 +585,33 @@
|
|||||||
/* END EditAccount */
|
/* END EditAccount */
|
||||||
|
|
||||||
/* BEGIN Contact list (list of topics) */
|
/* BEGIN Contact list (list of topics) */
|
||||||
|
|
||||||
/* A form for initiating a new topic
|
|
||||||
var NewTopic = React.createClass({
|
|
||||||
render: function() {
|
|
||||||
return (
|
|
||||||
<div className="input-group" id="newTopicInput">
|
|
||||||
<label htmlFor="addTopic" className="sr-only">Add user or topic</label>
|
|
||||||
<input id="addTopic" className="form-control" type="text" placeholder="Add topic" />
|
|
||||||
<span className="input-group-btn"><button className="btn btn-default" type="button">
|
|
||||||
<i className="material-icons">add</i>
|
|
||||||
</button></span>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* A single topic */
|
/* A single topic */
|
||||||
|
var contactMenuItems = ["Delete chat", "Mute", "Block"];
|
||||||
var Contact = React.createClass({
|
var Contact = React.createClass({
|
||||||
handleClick: function() {
|
getInitialState: function() {
|
||||||
this.props.onSelected(this.props.topic);
|
return {
|
||||||
},
|
menuShownFor: null
|
||||||
render: function() {
|
};
|
||||||
var title = this.props.title;
|
},
|
||||||
if (title.length > 30) {
|
handleClick: function() {
|
||||||
title = title.substring(0, 28) + "...";
|
this.props.onSelected(this.props.topic);
|
||||||
}
|
},
|
||||||
var selected = (this.props.selected === this.props.topic) ? "selected" : null;
|
handleContextClick: function(e) {
|
||||||
var avatar = this.props.avatar ?
|
e.preventDefault();
|
||||||
|
e.stopPropagation();
|
||||||
|
this.setState({menuShownFor: this.props.topic});
|
||||||
|
},
|
||||||
|
handleMenuAction: function(topic, action) {
|
||||||
|
console.log("Menu clicked '" + action + "' for topic " + topic);
|
||||||
|
this.setState({menuShownFor: null});
|
||||||
|
},
|
||||||
|
render: function() {
|
||||||
|
var title = this.props.title;
|
||||||
|
if (title.length > 30) {
|
||||||
|
title = title.substring(0, 28) + "...";
|
||||||
|
}
|
||||||
|
var selected = (this.props.selected === this.props.topic) ? "selected" : null;
|
||||||
|
var avatar = this.props.avatar ?
|
||||||
<img src={this.props.avatar} className="avatar" /> :
|
<img src={this.props.avatar} className="avatar" /> :
|
||||||
(Tinode.getTopicType(this.props.topic) === "grp") ?
|
(Tinode.getTopicType(this.props.topic) === "grp") ?
|
||||||
<i className="material-icons">group</i> :
|
<i className="material-icons">group</i> :
|
||||||
@@ -489,9 +626,18 @@
|
|||||||
<span className="contact-title">{title}</span> <Contact.Unread count={this.props.unread} />
|
<span className="contact-title">{title}</span> <Contact.Unread count={this.props.unread} />
|
||||||
<p>{this.props.comment}</p>
|
<p>{this.props.comment}</p>
|
||||||
</div>
|
</div>
|
||||||
|
<span className="menuTrigger">
|
||||||
|
<a href="#" onClick={this.handleContextClick}>
|
||||||
|
<i className="material-icons">arrow_drop_down</i>
|
||||||
|
</a>
|
||||||
|
<Menu items={contactMenuItems}
|
||||||
|
topic={this.props.topic}
|
||||||
|
onResult={this.handleMenuAction}
|
||||||
|
visible={this.state.menuShownFor ? true : false} />
|
||||||
|
</span>
|
||||||
</li>
|
</li>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
/* The counter of unread messages in the topic */
|
/* The counter of unread messages in the topic */
|
||||||
@@ -573,9 +719,6 @@
|
|||||||
<ul id="contact-box">
|
<ul id="contact-box">
|
||||||
{contactNodes}
|
{contactNodes}
|
||||||
</ul>
|
</ul>
|
||||||
<button className="round blue" id="add-topic" onClick={this.props.onNewTopic}>
|
|
||||||
<i className="material-icons big">add</i>
|
|
||||||
</button>
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -1046,7 +1189,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
handleNewTopic: function() {
|
handleNewTopic: function() {
|
||||||
this.setState({dialogSelected: 'new-topic'});
|
this.setState({sidePanelSelected: 'new-topic'});
|
||||||
},
|
},
|
||||||
handleDialogCancel: function() {
|
handleDialogCancel: function() {
|
||||||
this.setState({dialogSelected: null});
|
this.setState({dialogSelected: null});
|
||||||
|
|||||||
Reference in New Issue
Block a user