diff --git a/.gitignore b/.gitignore index 59feac0..3f1d839 100644 --- a/.gitignore +++ b/.gitignore @@ -10,7 +10,12 @@ lib-cov pids logs results +.DS_Store npm-debug.log node_modules data +.sass-cache +build/ +lib +public/bootstrap \ No newline at end of file diff --git a/Gruntfile.js b/Gruntfile.js new file mode 100644 index 0000000..bc8b77a --- /dev/null +++ b/Gruntfile.js @@ -0,0 +1,93 @@ +module.exports = function(grunt) { + + grunt.initConfig({ + + pkg: grunt.file.readJSON('package.json'), + + concat: { + dist: { + src: [ + 'pubic/javascripts/libs/*.js', + 'public/javascripts/*.js' + ], + dest: 'public/javascripts/build/production.js', + } + }, + + uglify: { + build: { + src: 'public/javascripts/build/production.js', + dest: 'public/javascripts/build/production.min.js' + } + }, + + sass: { + dist: { + options: { + style: 'compressed' + }, + files: { + 'public/css/build/global.css': 'public/scss/main.scss' + } + } + }, + + watch: { + scripts: { + files: ['public/javascripts/*.js', 'public/javascripts/libs/*.js'], + tasks: ['concat', 'uglify'], + options: { + spawn: false, + livereload: true, + }, + }, + + css: { + files: ['public/scss/*.scss'], + tasks: ['sass'], + options: { + spawn: false, + livereload: true, + } + } + }, + + curl: { + bootstrap_css: { + src: 'http://netdna.bootstrapcdn.com/bootstrap/3.0.3/css/bootstrap.min.css', + dest: 'public/lib/bootstrap/css/bootstrap.min.css' + }, + + bootstrap_js: { + src: 'http://netdna.bootstrapcdn.com/bootstrap/3.0.3/js/bootstrap.min.js', + dest: 'public/lib/bootstrap/js/bootstrap.min.js' + } + }, + + nodemon: { + dev: { + options: { + file: 'app.js', + watchedFolders: ['routes'], + nodeArgs: ['--debug'], + env: { + PORT: '3000' + } + } + } + } + + }); + + grunt.loadNpmTasks('grunt-contrib-concat'); + grunt.loadNpmTasks('grunt-contrib-uglify'); + grunt.loadNpmTasks('grunt-contrib-sass'); + grunt.loadNpmTasks('grunt-contrib-watch'); + grunt.loadNpmTasks('grunt-curl'); + grunt.loadNpmTasks('grunt-nodemon'); + + grunt.registerTask('default', ['concat', 'uglify', 'sass', 'imagemin', 'curl']); + grunt.registerTask('update', ['curl']); + grunt.registerTask('dev', ['watch']); + +}; \ No newline at end of file diff --git a/README.md b/README.md index c4b241b..5eb683a 100644 --- a/README.md +++ b/README.md @@ -10,5 +10,14 @@ Project is in beta. If you find any issues or have any feedback, open an issue. * `git clone git@github.com:a11yproject/Wordcast.git` or download the project * `cd path/to/Wordcast` * `npm install` the required modules +* `grunt` to build the app * `node app.js` to run the app * Open `http://localhost:3000` in two different browser windows. Chrome 25+ required to broadcast. + +## Contributing + +If you'd like to help, fork the repo and make a pull request! To start working on things, simply: + + $ grunt dev + +This will automate the build process, so you don't have to `grunt` everytime you make a change :) diff --git a/app.js b/app.js index 8ebea01..1283b44 100644 --- a/app.js +++ b/app.js @@ -93,7 +93,10 @@ io.sockets.on('connection', function(socket) { var room = getRoomById(data); if (!room) + { + socket.emit("no room exists"); return; + } socket.emit("room name", room.name); } diff --git a/package.json b/package.json index b828b0f..66f3a6d 100644 --- a/package.json +++ b/package.json @@ -1,21 +1,31 @@ { - "name": "Wordcast", - "version": "0.0.1", - "description": "A real-time captioning service over Google Chrome and Socket.IO", - "author": "A11yProject", - "contributors": [ - { - "name": "Jordan Foreman", - "email": "me@jordanforeman.com" - } - ], - "private": true, - "scripts": { - "start": "node app.js" - }, - "dependencies": { - "express": "latest", - "jade": "latest", - "socket.io": "latest" - }, -} \ No newline at end of file + "name": "wordcast", + "version": "0.0.1", + "description": "A real-time captioning service over Google Chrome and Socket.IO", + "author": "A11yProject", + "contributors": [ + { + "name": "Jordan Foreman", + "email": "me@jordanforeman.com" + } + ], + "private": true, + "scripts": { + "start": "node app.js" + }, + "dependencies": { + "express": "latest", + "jade": "latest", + "socket.io": "latest" + }, + "devDependencies": { + "grunt": "~0.4.1", + "grunt-contrib-sass": "~0.6.0", + "grunt-contrib-concat": "~0.3.0", + "grunt-contrib-uglify": "~0.2.7", + "grunt-contrib-imagemin": "~0.4.0", + "grunt-contrib-watch": "~0.5.3", + "grunt-curl": "~1.2.1", + "grunt-nodemon": "~0.1.2" + } +} diff --git a/public/css/main.css b/public/css/main.css deleted file mode 100644 index 29a8127..0000000 --- a/public/css/main.css +++ /dev/null @@ -1 +0,0 @@ -html,body{height:100%;background:#f0f0f0}body{font-family:'Ubuntu', sans-serif;line-height:1.5;padding:4em 1em 1em;text-align:center}ol{padding-left:0}li{list-style-position:inside}#cc{text-align:center;width:80%;left:10%;position:fixed;top:1em}#cc span{display:inline-block;width:auto;margin:0 auto;background:black;color:white;font-size:1.5em;font-family:monospace;padding:0.5em;min-height:1.5em;line-height:1.5em}#cc button{font-family:monospace;appearance:none;border:0;font-size:1em;background:transparent;color:white}#cc abbr{background:white;border-radius:4px;color:black;font-weight:bold;font-family:sans-serif;font-size:0.8em;display:inline-block;padding:0 0.25em} diff --git a/public/fonts/wordcast.eot b/public/fonts/wordcast.eot new file mode 100755 index 0000000..672bbb2 Binary files /dev/null and b/public/fonts/wordcast.eot differ diff --git a/public/fonts/wordcast.svg b/public/fonts/wordcast.svg new file mode 100755 index 0000000..b3657a6 --- /dev/null +++ b/public/fonts/wordcast.svg @@ -0,0 +1,14 @@ + + + +Generated by IcoMoon + + + + + + + + + + \ No newline at end of file diff --git a/public/fonts/wordcast.ttf b/public/fonts/wordcast.ttf new file mode 100755 index 0000000..f97fbd6 Binary files /dev/null and b/public/fonts/wordcast.ttf differ diff --git a/public/fonts/wordcast.woff b/public/fonts/wordcast.woff new file mode 100755 index 0000000..2c8f21e Binary files /dev/null and b/public/fonts/wordcast.woff differ diff --git a/public/javascripts/cc.js b/public/javascripts/listener.js similarity index 65% rename from public/javascripts/cc.js rename to public/javascripts/listener.js index ba7119e..3c018ac 100644 --- a/public/javascripts/cc.js +++ b/public/javascripts/listener.js @@ -3,21 +3,41 @@ var button = document.getElementById('cc-button'); var pathArray = window.location.pathname.split('/'); var roomID = pathArray[2]; +var roomName = document.querySelector("#roomName"); + +//=========================== +// +// Socket +// +//=========================== var socket = io.connect("http://localhost:3000"); -var roomName = document.querySelector("#roomName"); +// Successfully connected to server socket.on("connect", function(){ - socket.emit("get room name", roomID); + socket.emit("get room name", roomID); // get room by id }); +// Get room name from server socket.on("room name", function(data){ console.log("Room Name: " + data); roomName.innerHTML = data; }); -var recognizing = false; +//TODO: more graceful error here +// If page is loaded, but a room doesn't exist +socket.on("no room exists", function(data){ + console.log("no room exists"); + window.location = '../'; +}); + +//=========================== +// +// Voice Recognition +// +//=========================== +var recognizing = false; var recognition = new webkitSpeechRecognition(); recognition.continuous = true; recognition.interimResults = true; @@ -41,6 +61,12 @@ recognition.onresult = function(event) { } }; +//=========================== +// +// Util +// +//=========================== + function capitalize(s) { var first_char = /\S/; return s.replace(first_char, function(m) { @@ -59,4 +85,9 @@ function toggleSpeechRecognition(event) { button.style.display = "none"; recognition.start(); } -} \ No newline at end of file +} + +function dummyMsg(msg){ + var messages = ["here is a caption", "The Lazy Brown Fox", "Wizards", "santa claws"]; + socket.emit("new caption", {text: messages[Math.floor(Math.random()*messages.length)], room: roomID}); +} diff --git a/public/scss/_fonts.scss b/public/scss/_fonts.scss new file mode 100644 index 0000000..bc26be2 --- /dev/null +++ b/public/scss/_fonts.scss @@ -0,0 +1,37 @@ +@font-face { + font-family: 'wordcast'; + src:url('../../fonts/wordcast.eot'); + src:url('../../fonts/wordcast.eot?#iefix') format('embedded-opentype'), + url('../../fonts/wordcast.woff') format('woff'), + url('../../fonts/wordcast.ttf') format('truetype'), + url('../../fonts/wordcast.svg#wordcast') format('svg'); + font-weight: normal; + font-style: normal; +} + +[class^="icon-"], [class*=" icon-"] { + font-family: 'wordcast'; + speak: none; + font-style: normal; + font-weight: normal; + font-variant: normal; + text-transform: none; + line-height: 1; + + /* Better Font Rendering =========== */ + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} + +.icon-microphone:before { + content: "\e600"; +} +.icon-cog:before { + content: "\e601"; +} +.icon-user-add:before { + content: "\e602"; +} +.icon-voicemail:before { + content: "\e603"; +} diff --git a/public/scss/main.scss b/public/scss/main.scss index 0852cc1..be47b9c 100644 --- a/public/scss/main.scss +++ b/public/scss/main.scss @@ -1,3 +1,5 @@ +@import "fonts"; + /* Layout styling */ html, body { @@ -9,7 +11,8 @@ body { font-family: 'Ubuntu', sans-serif; line-height: 1.5; padding: 4em 1em 1em; - text-align: center; + + padding-top: 70px; } ol { @@ -22,11 +25,10 @@ li { /* Caption Styling */ #cc { + display: block; + margin: 0 auto; + text-align: center; - width: 80%; - left: 10%; - position: fixed; - top: 1em; } #cc span { @@ -60,4 +62,9 @@ li { font-size: 0.8em; display: inline-block; padding: 0 0.25em; +} + +.btn-cta { + display: block; + margin: 0 auto; } \ No newline at end of file diff --git a/views/index.jade b/views/index.jade index 05d2b24..53620e6 100644 --- a/views/index.jade +++ b/views/index.jade @@ -1,17 +1,22 @@ extends layout block content - h1= title - p Welcome to #{title} + div(class='jumbotron') + h1= title + p Welcome to #{title}! The best way to serve live captions! From classrooms to boardrooms, Wordcast delivers! Provide almost instant captions to listeners with just an internet connection. - a(href="listener") - | Listener + p + | ...and its completely + strong(style='color: red;') + | Free! - |  |  + | But, - a(href="viewer") - | Viewer + //- Open Source Definition + a(href="http://bit.ly/1ixwz0C") + small + | why? - p - a(href="createRoom") - | Create New Room \ No newline at end of file + p + a(class="btn btn-primary btn-lg btn-cta" href="createRoom" role="button") + | Create Room (Free) \ No newline at end of file diff --git a/views/layout.jade b/views/layout.jade index 25a815f..929e5b3 100644 --- a/views/layout.jade +++ b/views/layout.jade @@ -1,8 +1,32 @@ doctype html html - head - title= title - link(rel='stylesheet', href='/stylesheets/style.css') - link(rel='stylesheet', href='/css/main.css') - body - block content \ No newline at end of file + head + title= title + link(rel='stylesheet', href='/css/build/global.css') + link(rel='stylesheet', href='lib/bootstrap/css/bootstrap.min.css') + script(type='text/javascript', src='http://code.jquery.com/jquery-1.10.2.min.js') + body + + div(class='container') + + header + nav(class='navbar navbar-fixed-top navbar-default', role='navigation') + div(class='navbar-header',) + button(type='button', class="navbar-toggle", data-toggle="collapse", data-target="#bs-example-navbar-collapse-1") + span(class='sr-only')|Toggle navigation + span(class='icon-bar') + span(class='icon-bar') + span(class='icon-bar') + a(class='navbar-brand', href='#')|WordCast + div(class='collapse navbar-collapse', id='bs-example-navbar-collapse-1') + ul(class='nav navbar-nav navbar-right') + li + a(href='#')|Login + li + a(href='#')|Register + + block content + footer + + script(type='text/javascript', src='lib/bootstrap/js/bootstrap.min.js') + block scripts \ No newline at end of file diff --git a/views/listener.jade b/views/listener.jade index f1c5871..2a3a24d 100644 --- a/views/listener.jade +++ b/views/listener.jade @@ -12,7 +12,7 @@ block content article - h1(id="roomName")= title + h1(id="roomName", contenteditable)= title ol li | Open this page in Chrome desktop (25+) @@ -25,5 +25,16 @@ block content li | Click to caption stop - script(type="text/javascript", src="/socket.io/socket.io.js" async) - script(type="text/javascript", src="/javascripts/cc.js" async) + button(class='btn btn-default', onclick="dummyMsg('here is a message')") + | Send Msg + + p + a(href='#') + i(class='icon-cog') + + a(href='#') + i(class='icon-user-add') + +block scripts + script(type='text/javascript', src='/socket.io/socket.io.js', async) + script(type='text/javascript', src='/javascripts/listener.js', async)