231 lines
7.6 KiB
HTML
231 lines
7.6 KiB
HTML
<!DOCTYPE html>
|
|
<html>
|
|
<head>
|
|
<meta charset="utf-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
<title>React Tutorial</title>
|
|
<!-- Not present in the tutorial. Just for basic styling. -->
|
|
<link rel="stylesheet" href="css/bootstrap.css" />
|
|
<link rel="stylesheet" href="css/base.css" />
|
|
<script src="https://fb.me/react-0.14.5.js"></script>
|
|
<script src="https://fb.me/react-dom-0.14.5.js"></script>
|
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/babel-core/5.8.23/browser.min.js"></script>
|
|
</head>
|
|
</head>
|
|
<body>
|
|
<div id="mountPoint"></div>
|
|
<script type="text/babel">
|
|
var LoginNavbar = React.createClass({
|
|
render: function() {
|
|
return (
|
|
<nav className="navbar navbar-inverse">
|
|
<div className="container-fluid">
|
|
<div className="navbar-header">
|
|
<a className="navbar-brand" href="#">Tinode Demo Chat</a>
|
|
</div>
|
|
<div>
|
|
<ul className="nav navbar-nav navbar-right">
|
|
<li><a href="#"><big><span className="glyphicon glyphicon-option-vertical"></span></big></a></li>
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
</nav>
|
|
);
|
|
}
|
|
})
|
|
|
|
var LoginForm = React.createClass({
|
|
handleSubmit: function(e) {
|
|
e.preventDefault();
|
|
this.props.onLogin(true);
|
|
},
|
|
render: function() {
|
|
return (
|
|
<div className="container-fluid">
|
|
<form className="form-signin" onSubmit={this.handleSubmit}>
|
|
<label htmlFor="inputLogin" className="sr-only">Login</label>
|
|
<input type="text" id="inputLogin" className="form-control" placeholder="Login (alice, bob, carol, dave, frank)" required autofocus />
|
|
<label htmlFor="inputPassword" className="sr-only">Password</label>
|
|
<input type="password" id="inputPassword" className="form-control" placeholder="Password (alice123, bob123, ...)" required />
|
|
<br />
|
|
<button className="btn btn-lg btn-primary btn-block" type="submit">Sign in</button>
|
|
</form>
|
|
</div>
|
|
);
|
|
}
|
|
})
|
|
|
|
var LoginView = React.createClass({
|
|
render: function() {
|
|
return (
|
|
<div>
|
|
<LoginNavbar />
|
|
<LoginForm onLogin={this.props.onLogin} />
|
|
</div>
|
|
);
|
|
}
|
|
})
|
|
|
|
var CurrentUser = React.createClass({
|
|
render: function() {
|
|
return (
|
|
<nav id="main-navbar" className="navbar navbar-inverse">
|
|
<div className="container-fluid">
|
|
<div className="navbar-header">
|
|
<a href="#" className="pull-left"><img id="self-avatar" className="avatar" alt="avatar" src="avatar.svg" /></a>
|
|
<span className="navbar-brand" href="#">Alice Johnson</span>
|
|
</div>
|
|
<div>
|
|
<ul className="nav navbar-nav navbar-right">
|
|
<li><a href="#"><big><span className="glyphicon glyphicon-cog"></span></big></a></li>
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
</nav>
|
|
);
|
|
}
|
|
});
|
|
|
|
var NewTopic = React.createClass({
|
|
render: function() {
|
|
return (
|
|
<div className="input-group">
|
|
<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="glyphicon glyphicon-plus-sign"></i>
|
|
</button></span>
|
|
</div>
|
|
);
|
|
}
|
|
});
|
|
|
|
var contactsData = [
|
|
{id: "usrBOB", public: "Bob Smith", comment: "This is another comment", online: {now: true}, unread: 0},
|
|
{id: "usrCAROL", public: "Carol Xmas", comment: "No comments", online: {now: false, when: "1 hour ago"}, unread: 2},
|
|
{id: "usrDAVE", public: "Dave Goliaphsson", comment: "This is a comment", online: {now: false, when: "30 min ago"}, unread: 0}
|
|
];
|
|
|
|
var Contact = React.createClass({
|
|
render: function() {
|
|
return (
|
|
<li className="media contact">
|
|
<a href="#" className="pull-left"><img src="avatar.svg" className="avatar img-circle" alt="" /></a>
|
|
<div className="media-body">
|
|
<Contact.Online when={this.props.when} now={this.props.now} />
|
|
<strong>{this.props.public}</strong> <Contact.Unread count={this.props.unread} />
|
|
<p>{this.props.comment}</p>
|
|
</div>
|
|
</li>
|
|
);
|
|
}
|
|
});
|
|
|
|
Contact.Unread = React.createClass({
|
|
render: function() {
|
|
var showUnreadBadge;
|
|
if (this.props.count > 0) {
|
|
showUnreadBadge = <span className="label label-success label-as-badge">{this.props.count}</span>;
|
|
}
|
|
return (
|
|
<span> {showUnreadBadge}</span>
|
|
);
|
|
}
|
|
})
|
|
|
|
Contact.Online = React.createClass({
|
|
render: function() {
|
|
var lastOnline = '';
|
|
if (!this.props.online && this.props.when) {
|
|
lastOnline = this.props.when;
|
|
} else {
|
|
lastOnline = 'online';
|
|
}
|
|
|
|
return (
|
|
<span className="text-muted pull-right">
|
|
<span className={this.props.now ? "online" : "offline"}>●</span> <small className="text-muted"> {lastOnline}</small>
|
|
</span>
|
|
);
|
|
}
|
|
})
|
|
|
|
var ContactList = React.createClass({
|
|
render: function() {
|
|
var contactNodes = this.props.data.map(function(c) {
|
|
return (
|
|
<Contact public={c.public} comment={c.comment} unread={c.unread}
|
|
when={c.online.when} now={c.online.now} key={c.id} />
|
|
);
|
|
});
|
|
return (
|
|
<div className="contactList">
|
|
<ul className="media-list">
|
|
{contactNodes}
|
|
</ul>
|
|
</div>
|
|
);
|
|
}
|
|
});
|
|
|
|
var ContactsView = React.createClass({
|
|
getInitialState: function() {
|
|
return {contacts: []};
|
|
},
|
|
componentDidMount: function() {
|
|
this.setState({contacts: contactsData});
|
|
},
|
|
render: function() {
|
|
return (
|
|
<div className="contactBox">
|
|
<CurrentUser />
|
|
<div className="container-fluid">
|
|
<NewTopic />
|
|
<ContactList data={this.state.contacts} />
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|
|
});
|
|
|
|
var AppView = React.createClass({
|
|
getInitialState: function() {
|
|
return {loggedIn: false};
|
|
},
|
|
handleLogin: function(ok) {
|
|
this.setState({loggedIn: ok});
|
|
},
|
|
render: function() {
|
|
return (
|
|
<div className="container-fluid">
|
|
<div className="row">
|
|
<div className="menuContainer">
|
|
{this.state.loggedIn ? <ContactsView data={contactsData} /> : <LoginView onLogin={this.handleLogin} />}
|
|
</div>
|
|
<div className="col-md-12 messagesContainer">
|
|
<div className="row">
|
|
<div class="panel panel-default">
|
|
<div class="panel-heading">
|
|
<h3 class="panel-title">Chat with X</h3>
|
|
</div>
|
|
<div class="panel-body">
|
|
Messages go here
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|
|
})
|
|
|
|
ReactDOM.render(
|
|
<AppView />,
|
|
document.getElementById('mountPoint')
|
|
);
|
|
</script>
|
|
|
|
</body>
|
|
</html>
|