Repository: scotch-io/meteor-slack Branch: master Commit: 51ec9c40c336 Files: 29 Total size: 18.0 KB Directory structure: gitextract_8ntt3t25/ ├── .meteor/ │ ├── .finished-upgraders │ ├── .gitignore │ ├── .id │ ├── packages │ ├── platforms │ ├── release │ └── versions ├── README.md ├── client/ │ ├── app.js │ ├── components/ │ │ ├── channel.html │ │ ├── footer.html │ │ ├── header.html │ │ ├── listings.html │ │ ├── message.html │ │ └── messages.html │ ├── global.css │ ├── head.html │ ├── input.js │ ├── room.html │ ├── routes.js │ ├── startup/ │ │ └── subscribe.js │ └── stubs.js ├── lib/ │ └── collections/ │ ├── channels.js │ └── messages.js └── server/ ├── accounts.js ├── mail.js ├── methods.js ├── publications.js └── seeder.js ================================================ FILE CONTENTS ================================================ ================================================ FILE: .meteor/.finished-upgraders ================================================ # This file contains information which helps Meteor properly upgrade your # app when you run 'meteor update'. You should check it into version control # with your project. notices-for-0.9.0 notices-for-0.9.1 0.9.4-platform-file notices-for-facebook-graph-api-2 ================================================ FILE: .meteor/.gitignore ================================================ local ================================================ FILE: .meteor/.id ================================================ # This file contains a token that is unique to your project. # Check it into your repository along with the rest of this directory. # It can be used for purposes such as: # - ensuring you don't accidentally deploy one app on top of another # - providing package authors with aggregated statistics 1yevmue1ah7sfon2yoez ================================================ FILE: .meteor/packages ================================================ # Meteor packages used by this project, one per line. # Check this file (and the other files in this directory) into your repository. # # 'meteor add' and 'meteor remove' will edit this file for you, # but you can also edit it by hand. meteor-platform anti:fake dburles:factory accounts-base accounts-password accounts-ui accounts-github email iron:router ================================================ FILE: .meteor/platforms ================================================ server browser ================================================ FILE: .meteor/release ================================================ METEOR@1.1.0.2 ================================================ FILE: .meteor/versions ================================================ accounts-base@1.2.0 accounts-github@1.0.4 accounts-oauth@1.1.5 accounts-password@1.1.1 accounts-ui@1.1.5 accounts-ui-unstyled@1.1.7 anti:fake@0.4.1 autoupdate@1.2.1 base64@1.0.3 binary-heap@1.0.3 blaze@2.1.2 blaze-tools@1.0.3 boilerplate-generator@1.0.3 callback-hook@1.0.3 check@1.0.5 dburles:factory@0.3.10 ddp@1.1.0 deps@1.0.7 ejson@1.0.6 email@1.0.6 fastclick@1.0.3 geojson-utils@1.0.3 github@1.1.3 html-tools@1.0.4 htmljs@1.0.4 http@1.1.0 id-map@1.0.3 iron:controller@1.0.7 iron:core@1.0.7 iron:dynamic-template@1.0.7 iron:layout@1.0.7 iron:location@1.0.7 iron:middleware-stack@1.0.7 iron:router@1.0.7 iron:url@1.0.7 jquery@1.11.3_2 json@1.0.3 launch-screen@1.0.2 less@1.0.14 livedata@1.0.13 localstorage@1.0.3 logging@1.0.7 meteor@1.1.6 meteor-platform@1.2.2 minifiers@1.1.5 minimongo@1.0.8 mobile-status-bar@1.0.3 mongo@1.1.0 npm-bcrypt@0.7.8_2 oauth@1.1.4 oauth2@1.1.3 observe-sequence@1.0.6 ordered-dict@1.0.3 random@1.0.3 reactive-dict@1.1.0 reactive-var@1.0.5 reload@1.1.3 retry@1.0.3 routepolicy@1.0.5 service-configuration@1.0.4 session@1.1.0 sha@1.0.3 spacebars@1.0.6 spacebars-compiler@1.0.6 srp@1.0.3 templating@1.1.1 tracker@1.0.7 ui@1.0.6 underscore@1.0.3 url@1.0.4 webapp@1.2.0 webapp-hashing@1.0.3 ================================================ FILE: README.md ================================================ # Slack Clone Built in Meteor.js Code for the scotch.io tutorial by Daniel (danyll.com) ![](https://cask.scotch.io/2015/05/slack-clone-in-meteor-getting-started.png) ================================================ FILE: client/app.js ================================================ Template.messages.helpers({ messages: Messages.find({}) }); Accounts.ui.config({ passwordSignupFields: 'USERNAME_AND_EMAIL' }); Template.registerHelper('currentChannel', function () { return Session.get('channel'); }); Template.registerHelper("timestampToTime", function (timestamp) { var date = new Date(timestamp); var hours = date.getHours(); var minutes = "0" + date.getMinutes(); var seconds = "0" + date.getSeconds(); return hours + ':' + minutes.substr(minutes.length-2) + ':' + seconds.substr(seconds.length-2); }); Template.registerHelper("usernameFromId", function (userId) { var user = Meteor.users.findOne({_id: userId}); if (typeof user === "undefined") { return "Anonymous"; } if (typeof user.services.github !== "undefined") { return user.services.github.username; } return user.username; }); Template.listings.helpers({ channels: function () { return Channels.find(); } }); Template.channel.helpers({ active: function () { if (Session.get('channel') === this.name) { return "active"; } else { return ""; } } }); ================================================ FILE: client/components/channel.html ================================================ ================================================ FILE: client/components/footer.html ================================================ ================================================ FILE: client/components/header.html ================================================ ================================================ FILE: client/components/listings.html ================================================ ================================================ FILE: client/components/message.html ================================================ ================================================ FILE: client/components/messages.html ================================================ ================================================ FILE: client/global.css ================================================ /* line 5, ../../../../../../var/lib/gems/1.9.1/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */ html, body, div, span, applet, object, iframe, h1, h2, h3, h4, h5, h6, p, blockquote, pre, a, abbr, acronym, address, big, cite, code, del, dfn, em, img, ins, kbd, q, s, samp, small, strike, strong, sub, sup, tt, var, b, u, i, center, dl, dt, dd, ol, ul, li, fieldset, form, label, legend, table, caption, tbody, tfoot, thead, tr, th, td, article, aside, canvas, details, embed, figure, figcaption, footer, header, hgroup, menu, nav, output, ruby, section, summary, time, mark, audio, video { margin: 0; padding: 0; border: 0; font: inherit; font-size: 100%; vertical-align: baseline; } /* line 22, ../../../../../../var/lib/gems/1.9.1/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */ html { line-height: 1; } /* line 24, ../../../../../../var/lib/gems/1.9.1/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */ ol, ul { list-style: none; } /* line 26, ../../../../../../var/lib/gems/1.9.1/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */ table { border-collapse: collapse; border-spacing: 0; } /* line 28, ../../../../../../var/lib/gems/1.9.1/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */ caption, th, td { text-align: left; font-weight: normal; vertical-align: middle; } /* line 30, ../../../../../../var/lib/gems/1.9.1/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */ q, blockquote { quotes: none; } /* line 103, ../../../../../../var/lib/gems/1.9.1/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */ q:before, q:after, blockquote:before, blockquote:after { content: ""; content: none; } /* line 32, ../../../../../../var/lib/gems/1.9.1/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */ a img { border: none; } /* line 116, ../../../../../../var/lib/gems/1.9.1/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */ article, aside, details, figcaption, figure, footer, header, hgroup, main, menu, nav, section, summary { display: block; } /* line 6, ../tests/sass/_layout.scss */ * { box-sizing: border-box; } /* line 10, ../tests/sass/_layout.scss */ html { position: relative; height: 100%; font-size: 16px; font-family: 'Lato', sans-serif; } /* line 16, ../tests/sass/_layout.scss */ body { height: 100%; width: 100%; margin: 0; padding-top: 53px; padding-bottom: 64px; } /* line 23, ../tests/sass/_layout.scss */ .header { position: fixed; top: 0; left: 0; height: 53px; width: 100%; } /* line 31, ../tests/sass/_layout.scss */ .main { height: 100%; } /* line 35, ../tests/sass/_layout.scss */ .footer { position: absolute; left: 0; bottom: 0; height: 64px; width: 100%; } /* line 1, ../tests/sass/components/_header.scss */ .team-menu { position: relative; width: 220px; height: 53px; line-height: 53px; font-weight: 900; padding: 0 1rem; color: #ffffff; background: #3e313c; border-bottom: 2px solid #372c36; float: left; cursor: pointer; } /* line 19, ../tests/sass/components/_header.scss */ .channel-menu_name { display: inline-block; padding: 0 .5rem 0 1.5rem; color: #555459; font-size: 1.4rem; font-weight: 900; line-height: 53px; cursor: pointer; } /* line 29, ../tests/sass/components/_header.scss */ .channel-menu_prefix { color: #9e9ea6; padding-right: .1rem; font-weight: 500; } /* line 1, ../tests/sass/components/_main.scss */ .listings { height: 100%; width: 220px; float: left; color: #ab9ba9; background-color: #4d394b; overflow-y: auto; overflow-x: hidden; } /* line 11, ../tests/sass/components/_main.scss */ .message-history { margin-left: 220px; overflow-y: auto; overflow-x: hidden; height: 100%; padding: 0 18px 1rem 1.5rem; } /* line 4, ../tests/sass/components/_listings.scss */ .listings_channels { margin: 1rem 0 2rem; } /* line 8, ../tests/sass/components/_listings.scss */ .listings_header { text-align: left; font-size: .8rem; line-height: 1.25rem; margin: 0 1rem .1rem; text-transform: uppercase; font-weight: 700; color: #ab9ba9; width: 165px; position: relative; } /* line 20, ../tests/sass/components/_listings.scss */ .channel_list { list-style-type: none; text-align: left; color: #ab9ba9; } /* line 26, ../tests/sass/components/_listings.scss */ .channel { height: 24px; line-height: 24px; -moz-border-radius-topright: 0.25rem; -webkit-border-top-right-radius: 0.25rem; border-top-right-radius: 0.25rem; -moz-border-radius-bottomright: 0.25rem; -webkit-border-bottom-right-radius: 0.25rem; border-bottom-right-radius: 0.25rem; margin-right: 17px; color: #ffffff; padding-left: 1rem; } /* line 35, ../tests/sass/components/_listings.scss */ .unread { color: #ffffff; background: #eb4d5c; border-radius: 9px; padding: 2px 9px; font-size: .8rem; line-height: 14px; font-weight: 700; vertical-align: baseline; white-space: nowrap; text-shadow: 0 1px 0 rgba(0, 0, 0, 0.2); float: right; margin-right: 3px; margin-top: 3px; } /* line 51, ../tests/sass/components/_listings.scss */ .channel.active { background: #4c9689; } /* line 55, ../tests/sass/components/_listings.scss */ .channel_prefix { color: #b2d5c9; } /* line 59, ../tests/sass/components/_listings.scss */ .disclaimer { font-size: 0.8rem; padding-left: 1rem; margin-right: 17px; } /* line 4, ../tests/sass/components/_message.scss */ .message { position: relative; margin-top: .5rem; padding: .25rem 2rem .1rem 3rem; min-height: 36px; } /* line 11, ../tests/sass/components/_message.scss */ .message_profile-pic { position: absolute; left: 0; display: block; -moz-border-radius: 0.2rem; -webkit-border-radius: 0.2rem; border-radius: 0.2rem; width: 36px; height: 36px; background-image: url("http://i.imgur.com/LikUNLc.png"); background-size: cover; } /* line 22, ../tests/sass/components/_message.scss */ .message_username { font-weight: 900; padding-right: .25rem; color: #3d3c40 !important; margin-left: 0; font-style: normal; text-decoration: none; } /* line 31, ../tests/sass/components/_message.scss */ .message_timestamp { text-align: left; display: inline; position: relative; top: 0; left: 0; color: #babbbf; font-size: 12px; line-height: 1.2rem; width: 36px; margin-right: 0; margin-left: 0; } /* line 45, ../tests/sass/components/_message.scss */ .message_content { color: #8b898f; font-style: italic; display: block; min-height: 1rem; } /* line 4, ../tests/sass/components/_user-menu.scss */ .user-menu { float: left; width: 220px; height: 100%; cursor: pointer; background: #3e313c; border-top: 2px solid #372c36; padding: 7px 0 9px 8px; height: 4rem; position: fixed; bottom: 0; left: 0; } /* line 18, ../tests/sass/components/_user-menu.scss */ .user-menu_profile-pic { display: inline-block; float: left; -moz-border-radius: 0.2rem; -webkit-border-radius: 0.2rem; border-radius: 0.2rem; width: 48px; height: 48px; background-image: url("http://i.imgur.com/LikUNLc.png"); background-size: cover; margin-right: 8px; } /* line 29, ../tests/sass/components/_user-menu.scss */ .user-menu_username { display: block; color: #ffffff; font-weight: 900; line-height: 1.5rem; margin-top: .2rem; max-width: 120px; } /* line 38, ../tests/sass/components/_user-menu.scss */ .connection_icon { width: 12px; height: 12px; } /* line 43, ../tests/sass/components/_user-menu.scss */ .connection_status { color: #ab9ba9; } /* line 1, ../tests/sass/components/_input-box.scss */ .input-box { height: 100%; margin-left: 220px; } /* line 6, ../tests/sass/components/_input-box.scss */ .input-box_text { font-size: .95rem; width: 90%; margin-left: 2%; margin-bottom: auto; line-height: 1.2rem; border: 2px solid #e0e0e0; -moz-border-radius: 0.2rem; -webkit-border-radius: 0.2rem; border-radius: 0.2rem; -moz-background-clip: padding-box; -webkit-background-clip: padding-box; background-clip: padding-box; color: #3d3c40; -webkit-appearance: none; -webkit-box-shadow: none; -moz-box-shadow: none; box-shadow: none; outline: 0; bottom: 0; min-height: 41px !important; padding: 9px 5px 9px 8px; } .channel_name { text-decoration: none; color: inherit; } ================================================ FILE: client/head.html ================================================ ================================================ FILE: client/input.js ================================================ Template.footer.events({ 'keypress input': function(e) { var inputVal = $('.input-box_text').val(); if(!!inputVal) { var charCode = (typeof e.which == "number") ? e.which : e.keyCode; if (charCode == 13) { e.stopPropagation(); Meteor.call('newMessage', { text: $('.input-box_text').val(), channel: Session.get('channel') }); $('.input-box_text').val(""); return false; } } } }); ================================================ FILE: client/room.html ================================================ ================================================ FILE: client/routes.js ================================================ Router.configure({ layoutTemplate: 'app' }); Router.route('/:channel', function () { Session.set('channel', this.params.channel); this.render('messages'); }); Router.route('/', function () { this.redirect('/general'); }); ================================================ FILE: client/startup/subscribe.js ================================================ Meteor.subscribe('channels'); Meteor.subscribe('allUsernames'); Template.messages.onCreated(function() { var self = this; self.autorun(function() { self.subscribe('messages', Session.get('channel'), function () { self.autorun(function() { Messages.find({channel: Session.get('channel')}).count(); Meteor.setTimeout(function () { $('.message-history').scrollTop(Number.MAX_VALUE); }, 100); }); }); }); }); ================================================ FILE: client/stubs.js ================================================ Meteor.methods({ newMessage: function (message) { message.timestamp = Date.now(); message.user = Meteor.userId(); Messages.insert(message); } }) ================================================ FILE: lib/collections/channels.js ================================================ Channels = new Mongo.Collection("channels"); ================================================ FILE: lib/collections/messages.js ================================================ Messages = new Mongo.Collection("messages"); ================================================ FILE: server/accounts.js ================================================ Accounts.config({ sendVerificationEmail: true }); ================================================ FILE: server/mail.js ================================================ Meteor.startup(function () { smtp = { username: 'dan@danyll.com', password: 'y3Z8TQxpxCiYsJJsCwyV0A', server: 'smtp.mandrillapp.com', port: 587 }; process.env.MAIL_URL = 'smtp://' + encodeURIComponent(smtp.username) + ':' + encodeURIComponent(smtp.password) + '@' + encodeURIComponent(smtp.server) + ':' + smtp.port; }); ================================================ FILE: server/methods.js ================================================ Meteor.methods({ newMessage: function (message) { message.timestamp = Date.now(); message.user = Meteor.userId(); Messages.insert(message); } }) ================================================ FILE: server/publications.js ================================================ Meteor.publish('messages', function (channel) { return Messages.find({channel: channel}); }); Meteor.publish('channels', function () { return Channels.find(); }); Meteor.publish("allUsernames", function () { return Meteor.users.find({}, {fields: { "username": 1, "services.github.username": 1 }}); }); ================================================ FILE: server/seeder.js ================================================ Meteor.startup(function() { Meteor.users.remove({}); Accounts.createUser({ username: "scotchio", email: "scotch@example.com", password: "dummypassword" }); Factory.define('message', Messages, { text: function() { return Fake.sentence(); }, user: Meteor.users.findOne()._id, timestamp: Date.now(), channel: 'general' }); // Add this if you want to remove all messages before seeding Messages.remove({}); if (Messages.find({}).count() === 0) { _(10).times(function(n) { Factory.create('message'); }); } Channels.remove({}); Channels.insert({ name: "general" }); Channels.insert({ name: "random" }); });