]> git.zarvox.org Git - imoo.git/commitdiff
A mostly-working three-panel page
authorDrew Fisher <drew.m.fisher@gmail.com>
Wed, 14 May 2014 08:06:38 +0000 (01:06 -0700)
committerDrew Fisher <drew.m.fisher@gmail.com>
Thu, 15 May 2014 06:12:54 +0000 (23:12 -0700)
I think I'm finally getting the hang of React.

reactornado/dispatcher.js
reactornado/index.html
reactornado/main.js
reactornado/style.css
reactornado/widgets.js

index cca1a46b1dc421ca30bc22eb6197e54ee5833e65..46677579a2b627dc32a1cb1e51c114e692d1f019 100644 (file)
@@ -36,7 +36,7 @@ var Dispatcher = {
             console.log(url);
             window.blist[bid].bicon_url = url;
         }
-        window.buddy_list.onChange(window.blist);
+        window.reactor.refs.buddy_list.onChange(window.blist);
     },
     handle_conversations_message: function(method, params) {
         console.log("conversations:", method, params);
index bc028bbd18b34eba29a82cbfb373b2f53204d4b5..994bd01fe94ef57f10543be5fd058b24305fa090 100644 (file)
                <script type="text/javascript" src="main.js"></script>
        </head>
        <body>
-               <!-- A div for the initial login form -->
-               <div id="loginform"></div>
-               <!-- A div for the buddy list -->
-               <div id="buddy_list"></div>
-               <!-- A div for the tabbed chat view -->
-               <div id="chats"></div>
        </body>
 </html>
index 02a81762e6b968b0227c40a8e7ef8b51d38b4868..3c2147a7b55a8c9ddbd843f6afc52337534a69e3 100644 (file)
@@ -21,14 +21,9 @@ window.onload = function () {
     window.ws_conn = ws;
 
     // Attach React-rendered components
-    React.renderComponent(
-        window.widgets.LoginForm(),
-        document.getElementById('loginform')
-    );
-
-    window.buddy_list = React.renderComponent(
-        window.widgets.BuddyList(),
-        document.getElementById('buddy_list')
+    window.reactor = React.renderComponent(
+        window.widgets.ReactContainer(),
+        document.body
     );
     console.log("loaded");
 };
index f4bebfe958900ae897c260b747fd22c92a2a15a2..e8b865b1cc75b9ccf418de48368959c842c0504e 100644 (file)
@@ -4,8 +4,11 @@ body {
        min-height: 100vh;
 }
 
-.form {
-       float: left;
+#react-container {
+       height: 100vh;
+       width: 100vw;
+       display: -webkit-flex;
+       -webkit-flex-direction: row;
 }
 
 .form > label {
@@ -16,13 +19,15 @@ body {
        margin-bottom: 20px;
 }
 
-#buddy_list {
-       float: right;
+.buddy_list {
+       min-width: 20vw;
+       max-height: 100vh;
+       overflow: auto;
 }
 
 /* buddy list things */
 .buddy {
-       width: 200px;
+       min-width: 200px;
        height: 48px;
        font-size: small;
 }
@@ -50,3 +55,59 @@ body {
        white-space: nowrap;
        width: 100%;
 }
+
+/* Things related to the conversation tabbar, backlog, and text input */
+
+.conversations {
+       -webkit-flex: 1;
+       min-height: 100vh;
+       width: 80%;
+       min-height: 100vh;
+       display: -webkit-flex;
+       -webkit-flex-direction: column;
+       //width: 80%;
+}
+
+.conv-tabbar {
+       display: block;
+       margin: 0px;
+}
+
+.conv-tab {
+       display: inline-block;
+       border-width: 2px 2px 0px 2px;
+       border-color: black;
+       border-style: solid;
+       outline: 2px;
+}
+
+.conv-active {
+       background-color: #f80;
+}
+
+.conv-tab-content {
+       display: -webkit-flex;
+       -webkit-flex-direction: column;
+       -webkit-flex: 1;
+       width: 100%;
+}
+
+/* Pack the individual chat lines tightly */
+.conv-log {
+       -webkit-flex: 1;
+}
+.conv-log > p {
+       margin: 0px;
+       padding: 0px;
+}
+
+.conv-input-container {
+       width: 100%;
+}
+
+.conv-input {
+       letter-spacing: normal;
+       word-spacing: normal;
+       word-wrap: break-word;
+       width: 95%;
+}
index a1202dd8470e45fb46e8c8a425e82cd27cc2b76f..4ced81cbae33b262e287ace79ee39268130613be 100644 (file)
@@ -33,6 +33,12 @@ var LoginForm = React.createClass({
     handleLogin: function () {
         console.log("Imma log in now");
         window.Dispatcher.send_msg("accounts", "create_account", this.state);
+        this.setState(this.getInitialState());
+    },
+    checkSubmit: function(e) {
+        if (e && e.keyCode == 13) {
+            this.handleLogin();
+        }
     },
 
     render: function () {
@@ -42,8 +48,8 @@ var LoginForm = React.createClass({
             <option value="prpl-jabber">Jabber</option>
             <option value="prpl-aim">AIM</option>
         </select></label>
-        <label>Username:<input type="text" id="username" valueLink={this.linkState('username')} /></label>
-        <label>Password:<input type="password" id="password" valueLink={this.linkState('password')} /></label>
+        <label>Username:<input type="text" id="username" valueLink={this.linkState('username')} onKeyPress={this.checkSubmit} /></label>
+        <label>Password:<input type="password" id="password" valueLink={this.linkState('password')} onKeyPress={this.checkSubmit} /></label>
         <input type="button" id="login" value="Login" onClick={this.handleLogin} />
         </form>
         );
@@ -96,11 +102,102 @@ var BuddyList = React.createClass({
     }
 });
 
+var ConversationTab = React.createClass({
+    render: function() {
+        var classname = "conv-tab";
+        if (this.props.active) {
+            classname = classname + " conv-active";
+        }
+        return <li className={classname}>{this.props.buddy}</li>;
+    }
+});
+
+var ConversationTabBar = React.createClass({
+    render: function() {
+        var tabs = [];
+        for (var i = 0 ; i < this.props.tabs.length ; i++) {
+            tabs.push(ConversationTab(this.props.tabs[i]));
+        }
+        return <ul className="conv-tabbar">{ tabs }</ul>;
+    }
+});
+
+var ConversationTextEntry = React.createClass({
+    mixins: [React.addons.LinkedStateMixin],
+    getInitialState: function() {
+        return {"text": ""};
+    },
+    checkSubmit: function(e) {
+        if (e && e.keyCode == 13) {
+            // TODO: do this only if Shift not currently pressed? (awkward...)
+            e.preventDefault();
+            // TODO: do something with this.state.text - window.Dispatcher.send_im?
+            this.setState(this.getInitialState());
+        }
+        // TODO: close window when Escape pressed?
+        // TODO: change tabs when Tab pressed?
+    },
+    render: function() {
+        return <footer className="conv-input-container"><textarea className="conv-input" rows="4" valueLink={this.linkState('text')} onKeyPress={this.checkSubmit} ></textarea></footer>;
+    }
+});
+
+var ConversationTabContent = React.createClass({
+    render: function() {
+        var messages = [];
+        for (var i = 0 ; i < this.props.messages.length ; i++) {
+            var msg = this.props.messages[i];
+            var msgclass = "msg " + msg.direction;
+            messages.push(<p>
+                <span className="timestamp">{msg.timestamp}</span>
+                <span className="sender">{msg.sender}</span>
+                <span className={msgclass}>{msg.text}</span>
+                </p>);
+        }
+        return <div className="conv-tab-content">
+                <div className="conv-log">{ messages }</div>
+                <ConversationTextEntry />
+               </div>;
+    }
+});
+
+var Conversations = React.createClass({
+    render: function() {
+        // TODO: pull data from this.state and provide a method to handle
+        // dispatcher-sent messages
+        var conv_tabs = [ {"active": true, "buddy": "Drew Fisher"},
+                          {"active": false, "buddy": "Kate Harrison"},
+                          {"active": false, "buddy": "Matt Mullins"}
+               ];
+        var active_pane_messages = [ {"direction": "incoming",
+                               "sender": "nobody",
+                               "timestamp": "10:41",
+                               "text": "this is a test message"
+                              } ];
+        return <div className="conversations">
+                <ConversationTabBar tabs={conv_tabs} />
+                <ConversationTabContent messages={active_pane_messages} />
+               </div>;
+    }
+});
+
+var ReactContainer = React.createClass({
+    render: function() {
+        return <div id="react-container">
+                 <LoginForm ref="login_form" />
+                 <Conversations ref="conversations" />
+                 <BuddyList ref="buddy_list" />
+               </div>;
+    }
+});
+
 // integration for now:
 window.widgets = {
     "List": List,
     "ListItem": ListItem,
     "BuddyListItem": BuddyListItem,
     "LoginForm": LoginForm,
-    "BuddyList": BuddyList
+    "BuddyList": BuddyList,
+    "Conversations": Conversations,
+    "ReactContainer": ReactContainer
 };