├── .meteor ├── .finished-upgraders ├── .gitignore ├── .id ├── packages ├── platforms ├── release └── versions ├── Message.jsx ├── MessageList.jsx ├── README.md ├── demo.css ├── demo.html ├── demo.jsx └── styles.css /.meteor/.finished-upgraders: -------------------------------------------------------------------------------- 1 | # This file contains information which helps Meteor properly upgrade your 2 | # app when you run 'meteor update'. You should check it into version control 3 | # with your project. 4 | 5 | notices-for-0.9.0 6 | notices-for-0.9.1 7 | 0.9.4-platform-file 8 | notices-for-facebook-graph-api-2 9 | 1.2.0-standard-minifiers-package 10 | 1.2.0-meteor-platform-split 11 | 1.2.0-cordova-changes 12 | 1.2.0-breaking-changes 13 | -------------------------------------------------------------------------------- /.meteor/.gitignore: -------------------------------------------------------------------------------- 1 | local 2 | -------------------------------------------------------------------------------- /.meteor/.id: -------------------------------------------------------------------------------- 1 | # This file contains a token that is unique to your project. 2 | # Check it into your repository along with the rest of this directory. 3 | # It can be used for purposes such as: 4 | # - ensuring you don't accidentally deploy one app on top of another 5 | # - providing package authors with aggregated statistics 6 | 7 | 167vt1x1eciiy71hmasve 8 | -------------------------------------------------------------------------------- /.meteor/packages: -------------------------------------------------------------------------------- 1 | # Meteor packages used by this project, one per line. 2 | # Check this file (and the other files in this directory) into your repository. 3 | # 4 | # 'meteor add' and 'meteor remove' will edit this file for you, 5 | # but you can also edit it by hand. 6 | 7 | meteor-base # Packages every Meteor app needs to have 8 | mobile-experience # Packages for a great mobile UX 9 | mongo # The database Meteor supports right now 10 | blaze-html-templates # Compile .html files into Meteor Blaze views 11 | session # Client-side reactive dictionary for your app 12 | jquery # Helpful client-side library 13 | tracker # Meteor's client-side reactive programming library 14 | 15 | standard-minifiers # JS/CSS minifiers run for production mode 16 | es5-shim # ECMAScript 5 compatibility for older browsers. 17 | ecmascript # Enable ECMAScript2015+ syntax in app code 18 | 19 | autopublish # Publish all data to the clients (for prototyping) 20 | insecure # Allow all DB writes from clients (for prototyping) 21 | react 22 | momentjs:moment 23 | -------------------------------------------------------------------------------- /.meteor/platforms: -------------------------------------------------------------------------------- 1 | server 2 | browser 3 | -------------------------------------------------------------------------------- /.meteor/release: -------------------------------------------------------------------------------- 1 | METEOR@1.2.1 2 | -------------------------------------------------------------------------------- /.meteor/versions: -------------------------------------------------------------------------------- 1 | autopublish@1.0.4 2 | autoupdate@1.2.4 3 | babel-compiler@5.8.24_1 4 | babel-runtime@0.1.4 5 | base64@1.0.4 6 | binary-heap@1.0.4 7 | blaze@2.1.3 8 | blaze-html-templates@1.0.1 9 | blaze-tools@1.0.4 10 | boilerplate-generator@1.0.4 11 | caching-compiler@1.0.0 12 | caching-html-compiler@1.0.2 13 | callback-hook@1.0.4 14 | check@1.1.0 15 | coffeescript@1.0.11 16 | cosmos:browserify@0.9.3 17 | ddp@1.2.2 18 | ddp-client@1.2.1 19 | ddp-common@1.2.2 20 | ddp-server@1.2.2 21 | deps@1.0.9 22 | diff-sequence@1.0.1 23 | ecmascript@0.1.6 24 | ecmascript-runtime@0.2.6 25 | ejson@1.0.7 26 | es5-shim@4.1.14 27 | fastclick@1.0.7 28 | geojson-utils@1.0.4 29 | hot-code-push@1.0.0 30 | html-tools@1.0.5 31 | htmljs@1.0.5 32 | http@1.1.1 33 | id-map@1.0.4 34 | insecure@1.0.4 35 | jquery@1.11.4 36 | jsx@0.2.3 37 | launch-screen@1.0.4 38 | livedata@1.0.15 39 | logging@1.0.8 40 | meteor@1.1.10 41 | meteor-base@1.0.1 42 | minifiers@1.1.7 43 | minimongo@1.0.10 44 | mobile-experience@1.0.1 45 | mobile-status-bar@1.0.6 46 | momentjs:moment@2.11.1 47 | mongo@1.1.3 48 | mongo-id@1.0.1 49 | npm-mongo@1.4.39_1 50 | observe-sequence@1.0.7 51 | ordered-dict@1.0.4 52 | promise@0.5.1 53 | random@1.0.5 54 | react@0.14.3 55 | react-meteor-data@0.2.4 56 | react-runtime@0.14.4 57 | react-runtime-dev@0.14.4 58 | react-runtime-prod@0.14.4 59 | reactive-dict@1.1.3 60 | reactive-var@1.0.6 61 | reload@1.1.4 62 | retry@1.0.4 63 | routepolicy@1.0.6 64 | session@1.1.1 65 | spacebars@1.0.7 66 | spacebars-compiler@1.0.7 67 | standard-minifiers@1.0.2 68 | templating@1.1.5 69 | templating-tools@1.0.0 70 | tracker@1.0.9 71 | ui@1.0.8 72 | underscore@1.0.4 73 | url@1.0.5 74 | webapp@1.2.3 75 | webapp-hashing@1.0.5 76 | -------------------------------------------------------------------------------- /Message.jsx: -------------------------------------------------------------------------------- 1 | Message = React.createClass({ 2 | propTypes: { 3 | message: React.PropTypes.object.isRequired 4 | }, 5 | 6 | formatTime(time) { 7 | return moment(time).format('h:mm A'); 8 | }, 9 | 10 | render() { 11 | return ( 12 |
  • {this.formatTime(this.props.message.time)} - {this.props.message.text}
  • 13 | ); 14 | } 15 | }); 16 | -------------------------------------------------------------------------------- /MessageList.jsx: -------------------------------------------------------------------------------- 1 | MessageList = React.createClass({ 2 | mixins: [ReactMeteorData], 3 | 4 | getMeteorData() { 5 | return { 6 | messages: Messages.find({}).fetch() 7 | } 8 | }, 9 | 10 | renderMessages() { 11 | return this.data.messages.map((message) => { 12 | return ; 13 | }); 14 | }, 15 | 16 | handleSubmit(event) { 17 | event.preventDefault(); 18 | 19 | let message = ReactDOM.findDOMNode(this.refs.textInput).value.trim(); 20 | 21 | Meteor.call("addMessage", message); 22 | 23 | ReactDOM.findDOMNode(this.refs.textInput).value = ""; 24 | }, 25 | 26 | renderForm() { 27 | return
    28 | 33 |
    34 | }, 35 | 36 | render() { 37 | return ( 38 |
    39 |
    40 |

    Messages

    41 |
    42 | 43 | {this.renderForm()} 44 | 45 | 48 |
    49 | ); 50 | } 51 | }); 52 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Meteor + React demo 2 | =================== 3 | 4 | This is the source from a talk at the Toronto React Meetup on January 27, 2016. 5 | 6 | Here is the talk: https://youtu.be/xcej5OboUVM 7 | 8 | Here is a shameless plug for our Meteor + React training: https://www.okgrow.com/training 9 | 10 | Enjoy! 11 | -------------------------------------------------------------------------------- /demo.css: -------------------------------------------------------------------------------- 1 | /* CSS declarations go here */ 2 | -------------------------------------------------------------------------------- /demo.html: -------------------------------------------------------------------------------- 1 | 2 | demo 3 | 4 | 5 | 6 |

    Welcome to Meteor + React!

    7 | 8 |
    9 | 10 | -------------------------------------------------------------------------------- /demo.jsx: -------------------------------------------------------------------------------- 1 | Messages = new Mongo.Collection("Messages", {}); 2 | 3 | Meteor.methods({ 4 | addMessage(text) { 5 | let message = { 6 | time: new Date(), 7 | text: text 8 | }; 9 | 10 | Messages.insert(message); 11 | } 12 | }); 13 | 14 | 15 | if (Meteor.isClient) { 16 | Meteor.startup(function () { 17 | ReactDOM.render(, document.getElementById("render-target")); 18 | }); 19 | } 20 | -------------------------------------------------------------------------------- /styles.css: -------------------------------------------------------------------------------- 1 | body { 2 | width: 500px; 3 | margin: 0 auto; 4 | font-family: sans-serif; 5 | color: #333; 6 | font-weight: 100; 7 | } 8 | 9 | nav { 10 | margin-top: 10px; 11 | background: #f6f8f9; /* Old browsers */ 12 | background: -moz-linear-gradient(top, #f6f8f9 0%, #e5ebee 50%, #d7dee3 51%, #f5f7f9 100%); /* FF3.6+ */ 13 | background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#f6f8f9), color-stop(50%,#e5ebee), color-stop(51%,#d7dee3), color-stop(100%,#f5f7f9)); /* Chrome,Safari4+ */ 14 | background: -webkit-linear-gradient(top, #f6f8f9 0%,#e5ebee 50%,#d7dee3 51%,#f5f7f9 100%); /* Chrome10+,Safari5.1+ */ 15 | background: -o-linear-gradient(top, #f6f8f9 0%,#e5ebee 50%,#d7dee3 51%,#f5f7f9 100%); /* Opera 11.10+ */ 16 | background: -ms-linear-gradient(top, #f6f8f9 0%,#e5ebee 50%,#d7dee3 51%,#f5f7f9 100%); /* IE10+ */ 17 | background: linear-gradient(to bottom, #f6f8f9 0%,#e5ebee 50%,#d7dee3 51%,#f5f7f9 100%); /* W3C */ 18 | filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#f6f8f9', endColorstr='#f5f7f9',GradientType=0 ); /* IE6-9 */ 19 | padding: 10px; 20 | border-radius: 4px; 21 | border: 1px solid #abe; 22 | } 23 | 24 | nav a { 25 | text-decoration: none; 26 | font-family: sans-serif; 27 | color: #567; 28 | font-weight: 400; 29 | font-size: 14px; 30 | } 31 | 32 | nav a:hover { 33 | color: #444; 34 | } 35 | 36 | #login-buttons { 37 | font-weight: 400; 38 | } 39 | #login-buttons a { 40 | text-decoration: none; 41 | } 42 | 43 | h2 { 44 | border-bottom: 1px solid #abe; 45 | font-family: sans-serif; 46 | font-weight: 100; 47 | } 48 | 49 | input[name="message"] { 50 | width: 81%; 51 | padding: 7px 10px; 52 | border-radius: 3px; 53 | border: 1px solid #999; 54 | box-shadow: inset 0px 1px 2px 0px #ccc; 55 | } 56 | 57 | input[value="Send"], 58 | input[value="Delete"], 59 | input[value="Follow"], 60 | input[value="Unfollow"] { 61 | padding: 6px 19px 7px 19px; 62 | color: white; 63 | border-radius: 3px; 64 | cursor: pointer; 65 | } 66 | 67 | input[value="Send"] { 68 | border: 1px solid #3498db; 69 | background-color: #3498db; 70 | } 71 | 72 | input[value="Delete"] { 73 | background-color: #ecf0f1; 74 | border: 1px solid #bdc3c7; 75 | color: #7f8c8d; 76 | text-shadow: 0px 1px 0px #fff; 77 | float: right; 78 | margin-top: -17px; 79 | } 80 | 81 | input[value="Delete"] { 82 | background-color: #ecf0f1; 83 | border: 1px solid #bdc3c7; 84 | color: #7f8c8d; 85 | text-shadow: 0px 1px 0px #fff; 86 | } 87 | 88 | input[value="Follow"] { 89 | background-color: #2ecc71; 90 | border: 1px solid #27ae60; 91 | } 92 | input[value="Unfollow"] { 93 | background-color: #f39c12; 94 | border: 1px solid #e67e22; 95 | } 96 | 97 | input[name="username-search"] { 98 | margin-top: 10px; 99 | width: 477px; 100 | padding: 10px 10px; 101 | border: 1px solid #999; 102 | border-radius: 3px; 103 | font-size: 16px; 104 | box-shadow: inset 0px 1px 3px 0px #ccc; 105 | } 106 | 107 | .countdown { 108 | font-weight: bold; 109 | } 110 | 111 | ul { 112 | list-style-type: none; 113 | padding-left: 0px; 114 | } 115 | 116 | ul li { 117 | min-height: 38px; 118 | line-height: 30px; 119 | } 120 | 121 | ul li input[value="Delete"] { 122 | margin-top: 0px; 123 | } 124 | 125 | ul li a { 126 | font-weight: bold; 127 | text-decoration: none; 128 | color: #2980b9; 129 | } 130 | 131 | h2 a { 132 | font-weight: bold; 133 | text-decoration: none; 134 | color: #333; 135 | } 136 | 137 | #follow input, #unfollow input { 138 | width: 100%; 139 | margin-bottom: 20px; 140 | font-size: 16px; 141 | } 142 | --------------------------------------------------------------------------------