-
13 |
- Log 14 |
- Play Queue 15 |
- Users 16 |
├── src ├── README.md ├── .nodemonignore ├── app │ ├── views │ │ ├── partials │ │ │ ├── log.ejs │ │ │ ├── users.ejs │ │ │ ├── socket-io.ejs │ │ │ ├── play-queue.ejs │ │ │ ├── banner.ejs │ │ │ ├── currently-playing.ejs │ │ │ ├── room.ejs │ │ │ ├── app-stats.ejs │ │ │ ├── footer.ejs │ │ │ ├── chat-form.ejs │ │ │ ├── noise-box-stats.ejs │ │ │ ├── play-mode-form.ejs │ │ │ └── username-form.ejs │ │ ├── home.ejs │ │ ├── host.ejs │ │ ├── layout.ejs │ │ └── user.ejs │ ├── model │ │ ├── NBUserCollection.js │ │ ├── NBHostModel.js │ │ ├── NBCollection.js │ │ ├── NBHomeCollection.js │ │ ├── NBHostCollection.js │ │ ├── NBTrackCollection.js │ │ ├── NBTrackModel.js │ │ ├── NBUserModel.js │ │ ├── NBHomeModel.js │ │ ├── NBLogModel.js │ │ ├── NBModel.js │ │ └── AppModel.js │ ├── middleware │ │ ├── cache-nuker.js │ │ ├── stats.js │ │ ├── template-options.js │ │ └── error.js │ ├── controllers │ │ ├── boot.js │ │ ├── test.js │ │ ├── home.js │ │ ├── user.js │ │ ├── host.js │ │ └── abstract.js │ └── lib │ │ ├── log.js │ │ ├── noise-box-reaper.js │ │ ├── sfx-metadata-parser.js │ │ └── built-in-sfx.js ├── config.js.sample ├── CBD1F10D3FD257184D2D96073BFF07E7.txt ├── public │ ├── noise │ │ └── alive.mp3 │ ├── img │ │ ├── bg-home │ │ │ ├── bg_home_01.jpg │ │ │ ├── bg_home_02.jpg │ │ │ ├── bg_home_03.jpg │ │ │ ├── bg_home_04.jpg │ │ │ ├── bg_home_05.jpg │ │ │ ├── bg_home_06.jpg │ │ │ ├── bg_home_07.jpg │ │ │ ├── bg_home_08.jpg │ │ │ ├── bg_home_09.jpg │ │ │ ├── bg_home_10.jpg │ │ │ ├── bg_home_11.jpg │ │ │ ├── bg_home_12.jpg │ │ │ ├── bg_home_13.jpg │ │ │ └── bg_home_14.jpg │ │ ├── logo_noisebox_banner_24.png │ │ └── logo_noisebox_large_24.png │ ├── font │ │ └── font-awesome │ │ │ ├── FontAwesome.otf │ │ │ ├── fontawesome-webfont.eot │ │ │ ├── fontawesome-webfont.ttf │ │ │ └── fontawesome-webfont.woff │ ├── less │ │ ├── style.less │ │ ├── _h5bp-top.less │ │ ├── _h5bp-bottom.less │ │ ├── _elements.less │ │ ├── _normalize.less │ │ ├── _font-awesome.less │ │ └── _noisebox.less │ ├── html │ │ └── error.html │ ├── js │ │ ├── HomeClient.js │ │ ├── main.js │ │ ├── nb.js │ │ ├── lib │ │ │ ├── sji.js │ │ │ ├── jquery.stickysectionheaders.js │ │ │ ├── timeago.js │ │ │ ├── bootstrap-tabs.js │ │ │ └── bootstrap-scrollspy.js │ │ ├── const.js │ │ ├── HostClient.js │ │ ├── UserClient.js │ │ └── AbstractClient.js │ └── connection-type │ │ └── index.html ├── index.js ├── package.json └── server.js ├── scripts ├── requirements.txt ├── print_tags.py ├── save_length.py └── set_length_all_files.py ├── .gitignore └── README.md /src/README.md: -------------------------------------------------------------------------------- 1 | :) -------------------------------------------------------------------------------- /src/.nodemonignore: -------------------------------------------------------------------------------- 1 | /public/ -------------------------------------------------------------------------------- /scripts/requirements.txt: -------------------------------------------------------------------------------- 1 | mutagen==1.21 2 | -------------------------------------------------------------------------------- /src/app/views/partials/log.ejs: -------------------------------------------------------------------------------- 1 |
3 | <%= id %> stats: 4 | <%= numHosts %> hosts, 5 | <%= numUsers %> users 6 |
7 |NoiseBox allows anyone to play sound clips through another computer...
4 | -------------------------------------------------------------------------------- /src/app/controllers/test.js: -------------------------------------------------------------------------------- 1 | /*global process*/ 2 | /** 3 | * NoiseBox 4 | * home.js 5 | * 6 | * Home route controller. 7 | */ 8 | 9 | var server = require("./../../server"); 10 | var app = server.app; 11 | var io = server.io; 12 | var model = server.model; 13 | var constants = server.constants; 14 | var templateOptions = require("./../middleware/template-options"); 15 | var stats = require("./../middleware/stats"); 16 | var AbstractController = require("./abstract.js"); 17 | var _ = require("underscore"); 18 | 19 | module.exports = function () { 20 | // Only active in the test environment 21 | console.log('test env is killing the server'); 22 | console.log('goodbye...'); 23 | process.exit(); 24 | }; -------------------------------------------------------------------------------- /src/public/connection-type/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 |Loading...
25 | 26 | -------------------------------------------------------------------------------- /src/app/lib/log.js: -------------------------------------------------------------------------------- 1 | var winston = require("winston"); 2 | var config = require("../../config"); 3 | var server = require("../../server.js"); 4 | 5 | /** 6 | * Usage: 7 | * 8 | * var log = require("./app/lib/log"); 9 | * 10 | * var meta = {}; 11 | * 12 | * log.info("Some informational message",meta); 13 | * log.warn("Some warning message",meta); 14 | * log.error("Some error message",meta); 15 | * 16 | * "meta" parameter is any object you'd like to inspect/print out along with the 17 | * log message string (uses util.inspect). 18 | */ 19 | 20 | var consoleTransport = new (winston.transports.Console)({ 21 | level: "info", 22 | timestamp: true 23 | }); 24 | 25 | var transports = [consoleTransport]; 26 | 27 | module.exports = new (winston.Logger)({transports:transports}); 28 | -------------------------------------------------------------------------------- /src/app/lib/noise-box-reaper.js: -------------------------------------------------------------------------------- 1 | var server = require("../../server"); 2 | var log = require("./log"); 3 | 4 | var reapInterval = 1000*60*60*12; // Reap empty boxes every 12 hours 5 | var staleness = 1000*60*60*6; // Spare a box from a reaping if its had activity within the last 6 hours 6 | 7 | module.exports = function () { 8 | setInterval(function () { 9 | var toRemove = []; 10 | server.model.noiseBoxes.each(function (noiseBox) { 11 | if ( Date.now() > (noiseBox.activityTimestamp+staleness) ) { 12 | toRemove.push(noiseBox); 13 | } 14 | }); 15 | if ( toRemove.length > 0 ) { 16 | log.info("now reaping "+toRemove.length+" stale boxes"); 17 | } 18 | toRemove.forEach(function (noiseBox) { 19 | server.model.noiseBoxes.remove(noiseBox); 20 | }); 21 | },reapInterval); 22 | }; 23 | -------------------------------------------------------------------------------- /src/app/views/partials/username-form.ejs: -------------------------------------------------------------------------------- 1 |Update <%= username %>
4 |") 291 | .addClass("search-results") 292 | .text("no results found") 293 | .appendTo($("#track-list .scrollable")); 294 | } 295 | 296 | // show/hide clear icon 297 | var $searchClear = $(".search-clear"); 298 | if (searchTerm.length < 1) { 299 | $searchClear.remove(); 300 | } else { 301 | if ($searchClear.length < 1) { 302 | $searchClear = $("") 303 | .addClass("search-clear") 304 | .addClass("icon-remove") 305 | .appendTo($(".search-container")); 306 | 307 | $searchClear.on("click", self.clearSearch); 308 | } 309 | } 310 | 311 | // show/hide titles 312 | $(".tracks").each(function(counter) { 313 | var $trackContainer = $(this), 314 | $items = $trackContainer.find("li:not(.hidden)"); 315 | 316 | if ($items.length < 1) { 317 | $trackContainer.addClass("hidden"); 318 | } else { 319 | $trackContainer.removeClass("hidden"); 320 | } 321 | }); 322 | }, 323 | 324 | 325 | clearSearch: function() { 326 | $("#track-search") 327 | .val("") 328 | .trigger("search"); 329 | }, 330 | 331 | 332 | showUsernameForm: function(e) { 333 | e.preventDefault(); 334 | var $form = $("#username-form"); 335 | $form.fadeToggle(); 336 | $form.find("input[type=text]").focus(); 337 | }, 338 | 339 | 340 | bootClient: function(e) { 341 | window.location = '/boot/?m=The host has left, and kicked you out!'; 342 | }, 343 | 344 | 345 | onConnect : function () { 346 | 347 | this._super(); 348 | 349 | this.emit(Const.USER_CONNECT); 350 | }, 351 | 352 | 353 | initSmoothScroll : function() { 354 | 355 | var self = this; 356 | 357 | this.$scrollablePane = $("#track-list .scrollable"); 358 | this.$trackBlocks = this.$scrollablePane.find(".tracks"); 359 | this.trackBlockPositions = {}; 360 | this.$trackBlocks.each(function(counter){ 361 | self.trackBlockPositions[this.id] = $(this).position().top; 362 | }); 363 | 364 | $("#album-list a").on("click", _.bind(this.smoothScroll, this)); 365 | }, 366 | 367 | 368 | smoothScroll : function (e) { 369 | e.preventDefault(); 370 | 371 | var linkHref = e.target.href.split("#")[1], 372 | pos; 373 | 374 | pos = this.trackBlockPositions[linkHref]; 375 | 376 | console.log(linkHref, pos); 377 | 378 | this.$scrollablePane.animate({ 379 | scrollTop: pos 380 | }, 500); 381 | } 382 | }); 383 | }); 384 | -------------------------------------------------------------------------------- /src/public/js/AbstractClient.js: -------------------------------------------------------------------------------- 1 | /** 2 | * NoiseBox 3 | * AbstractClient.js 4 | * 5 | * Abstract parent class for HostClient and HomeClient. Contains shared 6 | * functionality for these two NoiseBox client types. 7 | */ 8 | 9 | define(function (require) { 10 | 11 | var Const = require("constants"); 12 | var $ = require("jquery"); 13 | var _ = require("underscore"); 14 | require("timeago"); 15 | 16 | return Class.extend({ 17 | 18 | init : function () { 19 | 20 | this.users = []; 21 | this.playQueue = []; 22 | this.clientType = $("body").attr("id"); 23 | this.hostURL = $("body").data("host"); 24 | this.noiseBoxID = $("body").data("noise-box-id"); 25 | this.socket = io.connect(this.hostURL); 26 | 27 | console.log("****************"); 28 | console.log("Client init",this.clientType,this.hostURL,this.noiseBoxID===undefined?"":this.noiseBoxID); 29 | 30 | this.addWebSocketConnect(); 31 | 32 | this.flashMessage(); 33 | 34 | this.on(Const.SERVER_SOCKET_CONNECT,this.onConnect); 35 | this.on(Const.SOCKET_DISCONNECT,this.onDisconnect); 36 | 37 | this.on(Const.SERVER_NOISE_BOX_STATS_UPDATED,this.onNoiseBoxStatsUpdated); 38 | this.on(Const.SERVER_ADD_TRACK,this.onServerAddTrack); 39 | this.on(Const.SERVER_REMOVE_TRACK,this.onServerRemoveTrack); 40 | 41 | this.on(Const.USER_CHANGED,this.onUserChanged); 42 | 43 | this.on(Const.LOG_UPDATED,this.onLogUpdated); 44 | 45 | this.on(Const.HOST_TRACK_PLAYING,this.onHostTrackPlaying); 46 | this.on(Const.HOST_TRACK_COMPLETE,this.onHostTrackComplete); 47 | 48 | this.playQueueEl = $("#play-queue ul"); 49 | this.userListEl = $("#users ul"); 50 | this.logEl = $("#log ul"); 51 | this.currentlyPlayingHeaderEl = $("#currently-playing"); 52 | 53 | this.shareLinkEl = $(".share-trigger a"); 54 | this.shareLinkEl.on("click", this.toggleShareLink); 55 | 56 | this.shareEl = $(".share input"); 57 | this.shareEl.on("click", this.selectText); 58 | 59 | // start relative time count 60 | timeAgo.init(); 61 | 62 | // open external links in a new window 63 | $("a[rel='external']").attr("target", "_blank"); 64 | 65 | }, 66 | 67 | addWebSocketConnect : function () { 68 | this.$addWebSocketConnectEl = $("") 69 | .attr("class", "web-socket-connect") 70 | .appendTo($("body")); 71 | 72 | var $p = $("
").text("Connecting").appendTo(this.$addWebSocketConnectEl); 73 | var $i = this.createIcon("loading").prependTo($p); 74 | }, 75 | 76 | onConnect : function () { 77 | this.$addWebSocketConnectEl.fadeOut(500); 78 | console.log("Socket connected"); 79 | 80 | // Check Websockets are available. Don't allow ajax fallback. 81 | console.log("detected transport", this.socket.socket.transport.name); 82 | var transport = this.socket.socket.transport.name; 83 | if (transport !== 'websocket') { 84 | window.location = "/boot?m=Sorry you need a better connection (websockets) to use noisebox. Have you tried using a modern browser or connecting via wifi?"; 85 | } 86 | }, 87 | 88 | onDisconnect : function () { 89 | this.$addWebSocketConnectEl.fadeIn(500); 90 | console.log("Socket disconnected"); 91 | }, 92 | 93 | /** 94 | * A track has been added to the NoiseBox. 95 | */ 96 | onServerAddTrack : function (data) { 97 | 98 | var $li, $icon, $headerLi; 99 | 100 | $icon = this.createIcon("track"); 101 | 102 | $li = $("") 103 | .attr("id",data.cid) 104 | .addClass("log") 105 | .html(data.album+" - "+data.trackName) 106 | .prepend($icon) 107 | .hide() 108 | .slideDown() 109 | .appendTo(this.playQueueEl); 110 | 111 | $headerLi = $("") 112 | .text(data.album + " - " + data.trackName) 113 | .wrapInner("") 114 | .attr("id","header-"+data.cid) 115 | .appendTo(this.currentlyPlayingHeaderEl.find('ul')); 116 | 117 | var liWidth = $headerLi.outerWidth(); 118 | $headerLi.find('span').width(liWidth); 119 | 120 | this.currentlyPlayingHeaderEl.find("h3").css({display:"block"}); 121 | }, 122 | 123 | onHostTrackPlaying : function (track) { 124 | }, 125 | 126 | onHostTrackComplete : function (track) { 127 | var self = this; 128 | 129 | this.playQueueEl.find("li#"+track.cid).slideUp().remove(); 130 | 131 | this.currentlyPlayingHeaderEl.find("li#header-"+track.cid) 132 | .animate({width:0}, 200, function(){ 133 | $(this).remove(); 134 | 135 | if (self.currentlyPlayingHeaderEl.find("li").length < 1) { 136 | self.currentlyPlayingHeaderEl.find("h3").fadeOut(); 137 | } 138 | }); 139 | }, 140 | 141 | onServerRemoveTrack : function (data) { 142 | }, 143 | 144 | onNoiseBoxStatsUpdated : function (data) { 145 | var $hostS = $(".hosts-stats-s"), 146 | $userS = $(".users-stats-s"); 147 | 148 | if (data.numHosts === 1) { 149 | $hostS.css("display","none"); 150 | } else { 151 | $hostS.css("display","inline"); 152 | } 153 | 154 | if (data.numUsers === 1) { 155 | $userS.css("display","none"); 156 | } else { 157 | $userS.css("display","inline"); 158 | } 159 | 160 | $(".hosts-stats-value").text(data.numHosts); 161 | $(".users-stats-value").text(data.numUsers); 162 | }, 163 | 164 | onUserChanged : function(data) { 165 | switch(data.eventType) { 166 | case Const.USER_ADDED: 167 | this.onUserAdded(data); 168 | break; 169 | case Const.USER_UPDATED: 170 | this.onUserUpdated(data); 171 | break; 172 | case Const.USER_REMOVED: 173 | this.onUserRemoved(data); 174 | break; 175 | } 176 | }, 177 | 178 | onUserAdded : function(data) { 179 | if ($("li#"+data.id).length > 0) { return; } 180 | var $i, $li, $icon; 181 | 182 | $icon = this.createIcon("user"); 183 | 184 | $li = $("") 185 | .attr("id", data.id) 186 | .addClass("log") 187 | .text(data.username) 188 | .prepend($icon) 189 | .appendTo(this.userListEl); 190 | }, 191 | 192 | onUserUpdated : function(data) { 193 | var $li, $icon; 194 | 195 | $li = $("li#"+data.id); 196 | $li.text(data.username); 197 | 198 | if ($li.find('i').length < 1) { 199 | $icon = this.createIcon("user"); 200 | $li.prepend($icon); 201 | } 202 | }, 203 | 204 | onUserRemoved : function(data) { 205 | $("li#"+data.id).slideUp().remove(); 206 | }, 207 | 208 | onLogUpdated : function (item) { 209 | var logMessage, $li, $icon; 210 | 211 | switch(item.eventType) { 212 | case "user-added": 213 | logMessage = "" + item.user + " joined the room"; 214 | break; 215 | case "username-updated": 216 | logMessage = item.user + " is now known as " + item.detail + ""; 217 | break; 218 | case "user-removed": 219 | logMessage = item.user + " left the room"; 220 | break; 221 | case "track-added": 222 | logMessage = item.user + " added the track " + item.detail + ""; 223 | break; 224 | case "track-complete": 225 | logMessage = item.detail + " finished playing"; 226 | break; 227 | case "track-removed": 228 | logMessage = item.detail + " was removed from the playlist"; 229 | break; 230 | case "chat": 231 | logMessage = item.user + " says: “" + item.detail + "”"; 232 | break; 233 | case "host-added": 234 | logMessage = "A host has been added"; 235 | break; 236 | case "host-removed": 237 | logMessage = "A host has been removed"; 238 | break; 239 | case "room-created": 240 | logMessage = "Joining NoiseBox room: " + this.noiseBoxID + ""; 241 | break; 242 | case "share-link": 243 | logMessage = "Share this room: " + this.hostURL + "/" + this.noiseBoxID + ""; 244 | break; 245 | case "audio-start-note": 246 | logMessage = "Note: You need to click here to enable sound"; 247 | break; 248 | } 249 | 250 | if (!item.datetime) { 251 | item.datetime = timeAgo.now(); 252 | } 253 | 254 | logMessage += ' 0s'; 255 | 256 | $icon = this.createIcon(item.eventType); 257 | 258 | $li = $("") 259 | .addClass("log") 260 | .html(logMessage) 261 | .prepend($icon) 262 | .appendTo(this.logEl); 263 | 264 | timeAgo.add($li.find('span')); 265 | 266 | // scroll the log to the bottom if we're nearly there anyway... 267 | var $scrollable = this.logEl.closest('.scrollable'); 268 | if (this.logEl.outerHeight() - $scrollable.scrollTop() - $scrollable.outerHeight() < 150) { 269 | $scrollable.animate({ scrollTop: this.logEl.outerHeight() }, 250); 270 | } 271 | }, 272 | 273 | 274 | log : function(msg) { 275 | this.onLogUpdated(msg); 276 | }, 277 | 278 | 279 | createIcon : function(type) { 280 | var icon = "icon-", 281 | $icon; 282 | 283 | switch(type) { 284 | case "user": 285 | case "user-added": 286 | case "username-updated": 287 | case "user-removed": 288 | icon += "user"; 289 | break; 290 | 291 | case "track": 292 | case "track-added": 293 | case "track-complete": 294 | case "track-removed": 295 | icon += "music"; 296 | break; 297 | 298 | case "chat": 299 | icon += "comment-alt"; 300 | break; 301 | 302 | case "host-added": 303 | case "host-removed": 304 | icon += "desktop"; 305 | break; 306 | 307 | case "room-created": 308 | icon += "bullhorn"; 309 | break; 310 | 311 | case "share-link": 312 | icon += "link"; 313 | break; 314 | 315 | case "audio-start-note": 316 | icon += "warning-sign"; 317 | break; 318 | 319 | case "loading": 320 | icon += "refresh icon-spin"; 321 | break; 322 | } 323 | 324 | $icon = $(" ") 325 | .addClass(icon); 326 | 327 | return $icon; 328 | }, 329 | 330 | 331 | // if there is a flash message, display it 332 | flashMessage : function() { 333 | var $flashMessage = $(".flash-message"); 334 | if ($flashMessage.length > 0) { 335 | $flashMessage 336 | .slideDown(250) 337 | .delay(5000) 338 | .slideUp(250, function(){ 339 | $flashMessage.remove(); 340 | }); 341 | } 342 | }, 343 | 344 | 345 | createFlashMessage : function(message) { 346 | var $flashMessage = $(""+message+"
") 350 | .prependTo("#wrapper"); 351 | this.flashMessage(); 352 | }, 353 | 354 | 355 | // share link functionality 356 | toggleShareLink: function(e) { 357 | e.preventDefault(); 358 | var $this = $(this), 359 | $share = $(".share"); 360 | $this.toggleClass("active"); 361 | $share.slideToggle(); 362 | }, 363 | 364 | selectText: function(e) { 365 | e.preventDefault(); 366 | this.select(); 367 | }, 368 | 369 | /** 370 | * Helper function for binding callbacks to socket events from the server. 371 | * 372 | * @param event Server event name string. 373 | * @param callback Callback function reference. 374 | */ 375 | on : function (event,callback) { 376 | 377 | console.log("Listening for '"+event+"'"); 378 | 379 | var self = this; 380 | 381 | this.socket.on(event,function (data) { 382 | 383 | console.log("Received '"+event+"'",typeof data === "undefined"?"":JSON.stringify(data)); 384 | 385 | callback.call(self,data); 386 | }); 387 | }, 388 | 389 | /** 390 | * Helper function for sending socket events to the server. 391 | * 392 | * @param event Client event name string. 393 | */ 394 | emit : function (event,data) { 395 | 396 | data = typeof data !== "undefined" ? data : {}; 397 | 398 | data = _.extend(data,{ 399 | id : this.noiseBoxID, 400 | clientType : this.clientType 401 | }); 402 | 403 | console.log("Emitting '"+event+"'",typeof data === "undefined"?"":JSON.stringify(data)); 404 | 405 | this.socket.emit(event,data); 406 | } 407 | }); 408 | }); 409 | -------------------------------------------------------------------------------- /src/public/less/_font-awesome.less: -------------------------------------------------------------------------------- 1 | /*! 2 | * Font Awesome 3.0.2 3 | * the iconic font designed for use with Twitter Bootstrap 4 | * ------------------------------------------------------- 5 | * The full suite of pictographic icons, examples, and documentation 6 | * can be found at: http://fortawesome.github.com/Font-Awesome/ 7 | * 8 | * License 9 | * ------------------------------------------------------- 10 | * - The Font Awesome font is licensed under the SIL Open Font License - http://scripts.sil.org/OFL 11 | * - Font Awesome CSS, LESS, and SASS files are licensed under the MIT License - 12 | * http://opensource.org/licenses/mit-license.html 13 | * - The Font Awesome pictograms are licensed under the CC BY 3.0 License - http://creativecommons.org/licenses/by/3.0/ 14 | * - Attribution is no longer required in Font Awesome 3.0, but much appreciated: 15 | * "Font Awesome by Dave Gandy - http://fortawesome.github.com/Font-Awesome" 16 | 17 | * Contact 18 | * ------------------------------------------------------- 19 | * Email: dave@davegandy.com 20 | * Twitter: http://twitter.com/fortaweso_me 21 | * Work: Lead Product Designer @ http://kyruus.com 22 | */ 23 | 24 | @FontAwesomePath: "../font/font-awesome"; 25 | @borderColor: #eee; 26 | @iconMuted: #eee; 27 | .border-radius(@radius) { -webkit-border-radius: @radius; -moz-border-radius: @radius; border-radius: @radius; } 28 | 29 | @font-face { 30 | font-family: 'FontAwesome'; 31 | src: url('@{FontAwesomePath}/fontawesome-webfont.eot?v=3.0.1'); 32 | src: url('@{FontAwesomePath}/fontawesome-webfont.eot?#iefix&v=3.0.1') format('embedded-opentype'), 33 | url('@{FontAwesomePath}/fontawesome-webfont.woff?v=3.0.1') format('woff'), 34 | url('@{FontAwesomePath}/fontawesome-webfont.ttf?v=3.0.1') format('truetype'); 35 | // url('@{FontAwesomePath}/fontawesome-webfont.svg#fontawesomeregular?v=3.0.1') format('svg'); 36 | 37 | // src: url('@{FontAwesomePath}/FontAwesome.otf') format('opentype'); 38 | 39 | font-weight: normal; 40 | font-style: normal; 41 | } 42 | 43 | /* Font Awesome styles 44 | ------------------------------------------------------- */ 45 | [class^="icon-"], 46 | [class*=" icon-"] { 47 | font-family: FontAwesome; 48 | font-weight: normal; 49 | font-style: normal; 50 | text-decoration: inherit; 51 | -webkit-font-smoothing: antialiased; 52 | 53 | /* sprites.less reset */ 54 | display: inline; 55 | width: auto; 56 | height: auto; 57 | line-height: normal; 58 | vertical-align: baseline; 59 | background-image: none; 60 | background-position: 0% 0%; 61 | background-repeat: repeat; 62 | margin-top: 0; 63 | } 64 | 65 | /* more sprites.less reset */ 66 | .icon-white, 67 | .nav-pills > .active > a > [class^="icon-"], 68 | .nav-pills > .active > a > [class*=" icon-"], 69 | .nav-list > .active > a > [class^="icon-"], 70 | .nav-list > .active > a > [class*=" icon-"], 71 | .navbar-inverse .nav > .active > a > [class^="icon-"], 72 | .navbar-inverse .nav > .active > a > [class*=" icon-"], 73 | .dropdown-menu > li > a:hover > [class^="icon-"], 74 | .dropdown-menu > li > a:hover > [class*=" icon-"], 75 | .dropdown-menu > .active > a > [class^="icon-"], 76 | .dropdown-menu > .active > a > [class*=" icon-"], 77 | .dropdown-submenu:hover > a > [class^="icon-"], 78 | .dropdown-submenu:hover > a > [class*=" icon-"] { 79 | background-image: none; 80 | } 81 | 82 | [class^="icon-"]:before, 83 | [class*=" icon-"]:before { 84 | text-decoration: inherit; 85 | display: inline-block; 86 | speak: none; 87 | } 88 | 89 | /* makes sure icons active on rollover in links */ 90 | a { 91 | [class^="icon-"], 92 | [class*=" icon-"] { 93 | display: inline-block; 94 | } 95 | } 96 | 97 | /* makes the font 33% larger relative to the icon container */ 98 | .icon-large:before { 99 | vertical-align: -10%; 100 | font-size: 4/3em; 101 | } 102 | 103 | .btn, .nav { 104 | [class^="icon-"], 105 | [class*=" icon-"] { 106 | display: inline; 107 | /* keeps button heights with and without icons the same */ 108 | &.icon-large { line-height: .9em; } 109 | &.icon-spin { display: inline-block; } 110 | } 111 | } 112 | 113 | .nav-tabs, .nav-pills { 114 | [class^="icon-"], 115 | [class*=" icon-"] { 116 | /* keeps button heights with and without icons the same */ 117 | &, &.icon-large { line-height: .9em; } 118 | } 119 | } 120 | 121 | li, .nav li { 122 | [class^="icon-"], 123 | [class*=" icon-"] { 124 | display: inline-block; 125 | width: 1.25em; 126 | text-align: center; 127 | &.icon-large { 128 | /* increased font size for icon-large */ 129 | width: 1.25*1.25em; 130 | } 131 | } 132 | } 133 | 134 | ul.icons { 135 | list-style-type: none; 136 | text-indent: -.75em; 137 | 138 | li { 139 | [class^="icon-"], 140 | [class*=" icon-"] { 141 | width: .75em; 142 | } 143 | } 144 | } 145 | 146 | .icon-muted { 147 | color: @iconMuted; 148 | } 149 | 150 | // Icon Borders 151 | // ------------------------- 152 | 153 | .icon-border { 154 | border: solid 1px @borderColor; 155 | padding: .2em .25em .15em; 156 | .border-radius(3px); 157 | } 158 | 159 | // Icon Sizes 160 | // ------------------------- 161 | 162 | .icon-2x { 163 | font-size: 2em; 164 | &.icon-border { 165 | border-width: 2px; 166 | .border-radius(4px); 167 | } 168 | } 169 | .icon-3x { 170 | font-size: 3em; 171 | &.icon-border { 172 | border-width: 3px; 173 | .border-radius(5px); 174 | } 175 | } 176 | .icon-4x { 177 | font-size: 4em; 178 | &.icon-border { 179 | border-width: 4px; 180 | .border-radius(6px); 181 | } 182 | } 183 | 184 | // Floats 185 | // ------------------------- 186 | 187 | // Quick floats 188 | .pull-right { float: right; } 189 | .pull-left { float: left; } 190 | 191 | [class^="icon-"], 192 | [class*=" icon-"] { 193 | &.pull-left { 194 | margin-right: .3em; 195 | } 196 | &.pull-right { 197 | margin-left: .3em; 198 | } 199 | } 200 | 201 | .btn { 202 | [class^="icon-"], 203 | [class*=" icon-"] { 204 | &.pull-left, &.pull-right { 205 | &.icon-2x { margin-top: .18em; } 206 | } 207 | &.icon-spin.icon-large { line-height: .8em; } 208 | } 209 | } 210 | 211 | .btn.btn-small { 212 | [class^="icon-"], 213 | [class*=" icon-"] { 214 | &.pull-left, &.pull-right { 215 | &.icon-2x { margin-top: .25em; } 216 | } 217 | } 218 | } 219 | 220 | .btn.btn-large { 221 | [class^="icon-"], 222 | [class*=" icon-"] { 223 | margin-top: 0; // overrides bootstrap default 224 | &.pull-left, &.pull-right { 225 | &.icon-2x { margin-top: .05em; } 226 | } 227 | &.pull-left.icon-2x { margin-right: .2em; } 228 | &.pull-right.icon-2x { margin-left: .2em; } 229 | } 230 | } 231 | 232 | 233 | .icon-spin { 234 | display: inline-block; 235 | -moz-animation: spin 2s infinite linear; 236 | -o-animation: spin 2s infinite linear; 237 | -webkit-animation: spin 2s infinite linear; 238 | animation: spin 2s infinite linear; 239 | } 240 | 241 | @-moz-keyframes spin { 242 | 0% { -moz-transform: rotate(0deg); } 243 | 100% { -moz-transform: rotate(359deg); } 244 | } 245 | @-webkit-keyframes spin { 246 | 0% { -webkit-transform: rotate(0deg); } 247 | 100% { -webkit-transform: rotate(359deg); } 248 | } 249 | @-o-keyframes spin { 250 | 0% { -o-transform: rotate(0deg); } 251 | 100% { -o-transform: rotate(359deg); } 252 | } 253 | @-ms-keyframes spin { 254 | 0% { -ms-transform: rotate(0deg); } 255 | 100% { -ms-transform: rotate(359deg); } 256 | } 257 | @keyframes spin { 258 | 0% { transform: rotate(0deg); } 259 | 100% { transform: rotate(359deg); } 260 | } 261 | 262 | @-moz-document url-prefix() { 263 | .icon-spin { height: .9em; } 264 | .btn .icon-spin { height: auto; } 265 | .icon-spin.icon-large { height: 1.25em; } 266 | .btn .icon-spin.icon-large { height: .75em; } 267 | } 268 | 269 | /* Font Awesome uses the Unicode Private Use Area (PUA) to ensure screen 270 | readers do not read off random characters that represent icons */ 271 | .icon-glass:before { content: "\f000"; } 272 | .icon-music:before { content: "\f001"; } 273 | .icon-search:before { content: "\f002"; } 274 | .icon-envelope:before { content: "\f003"; } 275 | .icon-heart:before { content: "\f004"; } 276 | .icon-star:before { content: "\f005"; } 277 | .icon-star-empty:before { content: "\f006"; } 278 | .icon-user:before { content: "\f007"; } 279 | .icon-film:before { content: "\f008"; } 280 | .icon-th-large:before { content: "\f009"; } 281 | .icon-th:before { content: "\f00a"; } 282 | .icon-th-list:before { content: "\f00b"; } 283 | .icon-ok:before { content: "\f00c"; } 284 | .icon-remove:before { content: "\f00d"; } 285 | .icon-zoom-in:before { content: "\f00e"; } 286 | 287 | .icon-zoom-out:before { content: "\f010"; } 288 | .icon-off:before { content: "\f011"; } 289 | .icon-signal:before { content: "\f012"; } 290 | .icon-cog:before { content: "\f013"; } 291 | .icon-trash:before { content: "\f014"; } 292 | .icon-home:before { content: "\f015"; } 293 | .icon-file:before { content: "\f016"; } 294 | .icon-time:before { content: "\f017"; } 295 | .icon-road:before { content: "\f018"; } 296 | .icon-download-alt:before { content: "\f019"; } 297 | .icon-download:before { content: "\f01a"; } 298 | .icon-upload:before { content: "\f01b"; } 299 | .icon-inbox:before { content: "\f01c"; } 300 | .icon-play-circle:before { content: "\f01d"; } 301 | .icon-repeat:before { content: "\f01e"; } 302 | 303 | /* \f020 doesn't work in Safari. all shifted one down */ 304 | .icon-refresh:before { content: "\f021"; } 305 | .icon-list-alt:before { content: "\f022"; } 306 | .icon-lock:before { content: "\f023"; } 307 | .icon-flag:before { content: "\f024"; } 308 | .icon-headphones:before { content: "\f025"; } 309 | .icon-volume-off:before { content: "\f026"; } 310 | .icon-volume-down:before { content: "\f027"; } 311 | .icon-volume-up:before { content: "\f028"; } 312 | .icon-qrcode:before { content: "\f029"; } 313 | .icon-barcode:before { content: "\f02a"; } 314 | .icon-tag:before { content: "\f02b"; } 315 | .icon-tags:before { content: "\f02c"; } 316 | .icon-book:before { content: "\f02d"; } 317 | .icon-bookmark:before { content: "\f02e"; } 318 | .icon-print:before { content: "\f02f"; } 319 | 320 | .icon-camera:before { content: "\f030"; } 321 | .icon-font:before { content: "\f031"; } 322 | .icon-bold:before { content: "\f032"; } 323 | .icon-italic:before { content: "\f033"; } 324 | .icon-text-height:before { content: "\f034"; } 325 | .icon-text-width:before { content: "\f035"; } 326 | .icon-align-left:before { content: "\f036"; } 327 | .icon-align-center:before { content: "\f037"; } 328 | .icon-align-right:before { content: "\f038"; } 329 | .icon-align-justify:before { content: "\f039"; } 330 | .icon-list:before { content: "\f03a"; } 331 | .icon-indent-left:before { content: "\f03b"; } 332 | .icon-indent-right:before { content: "\f03c"; } 333 | .icon-facetime-video:before { content: "\f03d"; } 334 | .icon-picture:before { content: "\f03e"; } 335 | 336 | .icon-pencil:before { content: "\f040"; } 337 | .icon-map-marker:before { content: "\f041"; } 338 | .icon-adjust:before { content: "\f042"; } 339 | .icon-tint:before { content: "\f043"; } 340 | .icon-edit:before { content: "\f044"; } 341 | .icon-share:before { content: "\f045"; } 342 | .icon-check:before { content: "\f046"; } 343 | .icon-move:before { content: "\f047"; } 344 | .icon-step-backward:before { content: "\f048"; } 345 | .icon-fast-backward:before { content: "\f049"; } 346 | .icon-backward:before { content: "\f04a"; } 347 | .icon-play:before { content: "\f04b"; } 348 | .icon-pause:before { content: "\f04c"; } 349 | .icon-stop:before { content: "\f04d"; } 350 | .icon-forward:before { content: "\f04e"; } 351 | 352 | .icon-fast-forward:before { content: "\f050"; } 353 | .icon-step-forward:before { content: "\f051"; } 354 | .icon-eject:before { content: "\f052"; } 355 | .icon-chevron-left:before { content: "\f053"; } 356 | .icon-chevron-right:before { content: "\f054"; } 357 | .icon-plus-sign:before { content: "\f055"; } 358 | .icon-minus-sign:before { content: "\f056"; } 359 | .icon-remove-sign:before { content: "\f057"; } 360 | .icon-ok-sign:before { content: "\f058"; } 361 | .icon-question-sign:before { content: "\f059"; } 362 | .icon-info-sign:before { content: "\f05a"; } 363 | .icon-screenshot:before { content: "\f05b"; } 364 | .icon-remove-circle:before { content: "\f05c"; } 365 | .icon-ok-circle:before { content: "\f05d"; } 366 | .icon-ban-circle:before { content: "\f05e"; } 367 | 368 | .icon-arrow-left:before { content: "\f060"; } 369 | .icon-arrow-right:before { content: "\f061"; } 370 | .icon-arrow-up:before { content: "\f062"; } 371 | .icon-arrow-down:before { content: "\f063"; } 372 | .icon-share-alt:before { content: "\f064"; } 373 | .icon-resize-full:before { content: "\f065"; } 374 | .icon-resize-small:before { content: "\f066"; } 375 | .icon-plus:before { content: "\f067"; } 376 | .icon-minus:before { content: "\f068"; } 377 | .icon-asterisk:before { content: "\f069"; } 378 | .icon-exclamation-sign:before { content: "\f06a"; } 379 | .icon-gift:before { content: "\f06b"; } 380 | .icon-leaf:before { content: "\f06c"; } 381 | .icon-fire:before { content: "\f06d"; } 382 | .icon-eye-open:before { content: "\f06e"; } 383 | 384 | .icon-eye-close:before { content: "\f070"; } 385 | .icon-warning-sign:before { content: "\f071"; } 386 | .icon-plane:before { content: "\f072"; } 387 | .icon-calendar:before { content: "\f073"; } 388 | .icon-random:before { content: "\f074"; } 389 | .icon-comment:before { content: "\f075"; } 390 | .icon-magnet:before { content: "\f076"; } 391 | .icon-chevron-up:before { content: "\f077"; } 392 | .icon-chevron-down:before { content: "\f078"; } 393 | .icon-retweet:before { content: "\f079"; } 394 | .icon-shopping-cart:before { content: "\f07a"; } 395 | .icon-folder-close:before { content: "\f07b"; } 396 | .icon-folder-open:before { content: "\f07c"; } 397 | .icon-resize-vertical:before { content: "\f07d"; } 398 | .icon-resize-horizontal:before { content: "\f07e"; } 399 | 400 | .icon-bar-chart:before { content: "\f080"; } 401 | .icon-twitter-sign:before { content: "\f081"; } 402 | .icon-facebook-sign:before { content: "\f082"; } 403 | .icon-camera-retro:before { content: "\f083"; } 404 | .icon-key:before { content: "\f084"; } 405 | .icon-cogs:before { content: "\f085"; } 406 | .icon-comments:before { content: "\f086"; } 407 | .icon-thumbs-up:before { content: "\f087"; } 408 | .icon-thumbs-down:before { content: "\f088"; } 409 | .icon-star-half:before { content: "\f089"; } 410 | .icon-heart-empty:before { content: "\f08a"; } 411 | .icon-signout:before { content: "\f08b"; } 412 | .icon-linkedin-sign:before { content: "\f08c"; } 413 | .icon-pushpin:before { content: "\f08d"; } 414 | .icon-external-link:before { content: "\f08e"; } 415 | 416 | .icon-signin:before { content: "\f090"; } 417 | .icon-trophy:before { content: "\f091"; } 418 | .icon-github-sign:before { content: "\f092"; } 419 | .icon-upload-alt:before { content: "\f093"; } 420 | .icon-lemon:before { content: "\f094"; } 421 | .icon-phone:before { content: "\f095"; } 422 | .icon-check-empty:before { content: "\f096"; } 423 | .icon-bookmark-empty:before { content: "\f097"; } 424 | .icon-phone-sign:before { content: "\f098"; } 425 | .icon-twitter:before { content: "\f099"; } 426 | .icon-facebook:before { content: "\f09a"; } 427 | .icon-github:before { content: "\f09b"; } 428 | .icon-unlock:before { content: "\f09c"; } 429 | .icon-credit-card:before { content: "\f09d"; } 430 | .icon-rss:before { content: "\f09e"; } 431 | 432 | .icon-hdd:before { content: "\f0a0"; } 433 | .icon-bullhorn:before { content: "\f0a1"; } 434 | .icon-bell:before { content: "\f0a2"; } 435 | .icon-certificate:before { content: "\f0a3"; } 436 | .icon-hand-right:before { content: "\f0a4"; } 437 | .icon-hand-left:before { content: "\f0a5"; } 438 | .icon-hand-up:before { content: "\f0a6"; } 439 | .icon-hand-down:before { content: "\f0a7"; } 440 | .icon-circle-arrow-left:before { content: "\f0a8"; } 441 | .icon-circle-arrow-right:before { content: "\f0a9"; } 442 | .icon-circle-arrow-up:before { content: "\f0aa"; } 443 | .icon-circle-arrow-down:before { content: "\f0ab"; } 444 | .icon-globe:before { content: "\f0ac"; } 445 | .icon-wrench:before { content: "\f0ad"; } 446 | .icon-tasks:before { content: "\f0ae"; } 447 | 448 | .icon-filter:before { content: "\f0b0"; } 449 | .icon-briefcase:before { content: "\f0b1"; } 450 | .icon-fullscreen:before { content: "\f0b2"; } 451 | 452 | .icon-group:before { content: "\f0c0"; } 453 | .icon-link:before { content: "\f0c1"; } 454 | .icon-cloud:before { content: "\f0c2"; } 455 | .icon-beaker:before { content: "\f0c3"; } 456 | .icon-cut:before { content: "\f0c4"; } 457 | .icon-copy:before { content: "\f0c5"; } 458 | .icon-paper-clip:before { content: "\f0c6"; } 459 | .icon-save:before { content: "\f0c7"; } 460 | .icon-sign-blank:before { content: "\f0c8"; } 461 | .icon-reorder:before { content: "\f0c9"; } 462 | .icon-list-ul:before { content: "\f0ca"; } 463 | .icon-list-ol:before { content: "\f0cb"; } 464 | .icon-strikethrough:before { content: "\f0cc"; } 465 | .icon-underline:before { content: "\f0cd"; } 466 | .icon-table:before { content: "\f0ce"; } 467 | 468 | .icon-magic:before { content: "\f0d0"; } 469 | .icon-truck:before { content: "\f0d1"; } 470 | .icon-pinterest:before { content: "\f0d2"; } 471 | .icon-pinterest-sign:before { content: "\f0d3"; } 472 | .icon-google-plus-sign:before { content: "\f0d4"; } 473 | .icon-google-plus:before { content: "\f0d5"; } 474 | .icon-money:before { content: "\f0d6"; } 475 | .icon-caret-down:before { content: "\f0d7"; } 476 | .icon-caret-up:before { content: "\f0d8"; } 477 | .icon-caret-left:before { content: "\f0d9"; } 478 | .icon-caret-right:before { content: "\f0da"; } 479 | .icon-columns:before { content: "\f0db"; } 480 | .icon-sort:before { content: "\f0dc"; } 481 | .icon-sort-down:before { content: "\f0dd"; } 482 | .icon-sort-up:before { content: "\f0de"; } 483 | 484 | .icon-envelope-alt:before { content: "\f0e0"; } 485 | .icon-linkedin:before { content: "\f0e1"; } 486 | .icon-undo:before { content: "\f0e2"; } 487 | .icon-legal:before { content: "\f0e3"; } 488 | .icon-dashboard:before { content: "\f0e4"; } 489 | .icon-comment-alt:before { content: "\f0e5"; } 490 | .icon-comments-alt:before { content: "\f0e6"; } 491 | .icon-bolt:before { content: "\f0e7"; } 492 | .icon-sitemap:before { content: "\f0e8"; } 493 | .icon-umbrella:before { content: "\f0e9"; } 494 | .icon-paste:before { content: "\f0ea"; } 495 | .icon-lightbulb:before { content: "\f0eb"; } 496 | .icon-exchange:before { content: "\f0ec"; } 497 | .icon-cloud-download:before { content: "\f0ed"; } 498 | .icon-cloud-upload:before { content: "\f0ee"; } 499 | 500 | .icon-user-md:before { content: "\f0f0"; } 501 | .icon-stethoscope:before { content: "\f0f1"; } 502 | .icon-suitcase:before { content: "\f0f2"; } 503 | .icon-bell-alt:before { content: "\f0f3"; } 504 | .icon-coffee:before { content: "\f0f4"; } 505 | .icon-food:before { content: "\f0f5"; } 506 | .icon-file-alt:before { content: "\f0f6"; } 507 | .icon-building:before { content: "\f0f7"; } 508 | .icon-hospital:before { content: "\f0f8"; } 509 | .icon-ambulance:before { content: "\f0f9"; } 510 | .icon-medkit:before { content: "\f0fa"; } 511 | .icon-fighter-jet:before { content: "\f0fb"; } 512 | .icon-beer:before { content: "\f0fc"; } 513 | .icon-h-sign:before { content: "\f0fd"; } 514 | .icon-plus-sign-alt:before { content: "\f0fe"; } 515 | 516 | .icon-double-angle-left:before { content: "\f100"; } 517 | .icon-double-angle-right:before { content: "\f101"; } 518 | .icon-double-angle-up:before { content: "\f102"; } 519 | .icon-double-angle-down:before { content: "\f103"; } 520 | .icon-angle-left:before { content: "\f104"; } 521 | .icon-angle-right:before { content: "\f105"; } 522 | .icon-angle-up:before { content: "\f106"; } 523 | .icon-angle-down:before { content: "\f107"; } 524 | .icon-desktop:before { content: "\f108"; } 525 | .icon-laptop:before { content: "\f109"; } 526 | .icon-tablet:before { content: "\f10a"; } 527 | .icon-mobile-phone:before { content: "\f10b"; } 528 | .icon-circle-blank:before { content: "\f10c"; } 529 | .icon-quote-left:before { content: "\f10d"; } 530 | .icon-quote-right:before { content: "\f10e"; } 531 | 532 | .icon-spinner:before { content: "\f110"; } 533 | .icon-circle:before { content: "\f111"; } 534 | .icon-reply:before { content: "\f112"; } 535 | .icon-github-alt:before { content: "\f113"; } 536 | .icon-folder-close-alt:before { content: "\f114"; } 537 | .icon-folder-open-alt:before { content: "\f115"; } 538 | -------------------------------------------------------------------------------- /src/public/less/_noisebox.less: -------------------------------------------------------------------------------- 1 | /* 2 | * Main Noisebox styles 3 | */ 4 | @import "_elements.less"; 5 | 6 | 7 | // the width at which to switch to mobile styles 8 | @mobileWidth: 600px; 9 | @tabletWidth: 750px; 10 | 11 | 12 | 13 | /* default page styles */ 14 | 15 | /* for vert alignment */ 16 | html, 17 | body { 18 | width:100%; 19 | height:100%; 20 | } 21 | 22 | body { 23 | font-family:Helvetica,Arial,sans-serif; 24 | font-size:18px; 25 | line-height:24px; 26 | } 27 | 28 | input[type=text], 29 | input[type=submit] { 30 | -webkit-appearance:none; 31 | padding:10px; 32 | border-radius:5px; 33 | border:none; 34 | outline:none; 35 | } 36 | 37 | input[type=text] { 38 | margin-right:5px; 39 | } 40 | 41 | input[type=submit] { 42 | background:#fff; 43 | } 44 | 45 | 46 | /* re-usable modules/components */ 47 | 48 | /* hide for mobile */ 49 | @media (max-width: @mobileWidth) { 50 | input { 51 | font-size:1rem !important; /* stop zoom on input focus */ 52 | } 53 | 54 | .hide-for-mobile { 55 | display:none; 56 | } 57 | } 58 | 59 | 60 | /* web socket connect - mask everything until web sockets connect */ 61 | .web-socket-connect { 62 | position:fixed; 63 | z-index:1000; 64 | width:100%; 65 | height:100%; 66 | left:0; 67 | top:0; 68 | margin:0; 69 | padding:0; 70 | background:rgba(255,255,255,0.75); 71 | display:table; 72 | 73 | p { 74 | display:table-cell; 75 | text-align:center; 76 | vertical-align:middle; 77 | font-size:2rem; 78 | text-shadow:1px 1px 1px rgba(0,0,0,0.5); 79 | } 80 | 81 | i { 82 | margin-right:10px; 83 | } 84 | } 85 | 86 | 87 | /* flash message */ 88 | .flash-message { 89 | position:absolute; 90 | top:0; 91 | left:0; 92 | right:0; 93 | background-color: deeppink; 94 | color: white; 95 | padding: 10px; 96 | } 97 | 98 | .flash-message p { 99 | margin:0; 100 | font-size:0.9rem; 101 | line-height:1.25; 102 | } 103 | 104 | 105 | /* horizontal lists */ 106 | .horizontal-list { 107 | margin:0; 108 | padding:0; 109 | list-style:none; 110 | } 111 | 112 | .horizontal-list .item { 113 | float:left; 114 | } 115 | 116 | 117 | /* tabs */ 118 | .tab-trigger a, 119 | .tab-trigger span.tab { 120 | float:left; 121 | background:#eee; 122 | text-align:center; 123 | cursor:pointer; 124 | font-size:0.8rem; 125 | line-height:2.5; 126 | color:#000; 127 | text-decoration:none; 128 | .transition(all, 250ms); 129 | } 130 | 131 | .tab-trigger a:hover, 132 | .tab-trigger span.tab:hover { 133 | background-color:#ddd; 134 | } 135 | 136 | .tab-trigger.active a, 137 | .tab-trigger.active span.tab { 138 | color:#fff; 139 | background-color:rgba(66,66,66,1); 140 | } 141 | 142 | .tab-container { 143 | clear:both; 144 | height:100%; 145 | position:relative; 146 | } 147 | 148 | .tab-container .tab { 149 | height:100%; 150 | position:absolute; 151 | left:0; 152 | right:0; 153 | display:none; 154 | } 155 | 156 | .tab-container .tab.active { 157 | display:block; 158 | } 159 | 160 | 161 | /* log messages */ 162 | li.log { 163 | font-size:0.8rem; 164 | 165 | i { 166 | margin-right:5px; 167 | } 168 | 169 | a { 170 | text-decoration:none; 171 | color:#666; 172 | font-weight:bold; 173 | .transition(all, 250ms); 174 | } 175 | 176 | a:hover { 177 | color:#000; 178 | } 179 | 180 | span.datetime { 181 | font-size:0.7rem; 182 | font-style:italic; 183 | font-weight:normal; 184 | color:#999; 185 | } 186 | } 187 | 188 | 189 | 190 | /* page layout */ 191 | 192 | /* page containers */ 193 | #wrapper, 194 | #middle { 195 | height:100%; 196 | } 197 | 198 | 199 | /* header bar - for user / host pages */ 200 | .header { 201 | position:fixed; 202 | top:0; 203 | left:0; 204 | right:0; 205 | min-height:100px; 206 | z-index:3; 207 | 208 | @media(max-width:@mobileWidth) { 209 | min-height:50px; 210 | } 211 | } 212 | 213 | 214 | /* banner bar - for user / host pages */ 215 | .banner { 216 | border-top:1px solid #464646; 217 | height:50px; 218 | .gradient(#000, #000, #444); 219 | position:absolute; 220 | top:0; 221 | left:0; 222 | right:0; 223 | 224 | h1 { 225 | margin:0; 226 | line-height:1; 227 | margin:10px 0 0 10px; 228 | 229 | a { 230 | display:block; 231 | background:url(/img/logo_noisebox_banner_24.png) transparent no-repeat left top; 232 | width:165px; 233 | height:30px; 234 | } 235 | } 236 | } 237 | 238 | 239 | /* room (header share links) - for user / host pages */ 240 | .room { 241 | border:1px solid #d9d9d9; 242 | min-height:50px; 243 | .gradient(#e6e6e6, #e6e6e6, #fff); 244 | position:absolute; 245 | top:50px; 246 | left:0; 247 | right:0; 248 | 249 | h2 { 250 | margin:0.5em 0.5rem 0 0.5em; 251 | float:left; 252 | padding:0; 253 | 254 | font-size:1.33rem; 255 | font-weight:normal; 256 | } 257 | 258 | p { 259 | float:left; 260 | margin:0.7rem 0.5rem 0 0; 261 | } 262 | 263 | a { 264 | display:block; 265 | font-size:0.88rem; 266 | line-height:1.2; 267 | text-decoration:none; 268 | color:#666; 269 | border:1px solid #ccc; 270 | border-radius:3px; 271 | padding:5px 10px; 272 | background-color:rgba(66,66,66,0); 273 | 274 | .transition(all, 250ms); 275 | } 276 | 277 | a:hover, 278 | a.active { 279 | color:#fff; 280 | background-color:rgba(66,66,66,1); 281 | } 282 | 283 | .share { 284 | display:none; 285 | float:left; 286 | 287 | a { 288 | border-color:transparent; 289 | } 290 | 291 | a:hover { 292 | background:none; 293 | color:#000; 294 | } 295 | } 296 | } 297 | 298 | 299 | /* footer - for host / user pages */ 300 | .footer { 301 | clear:both; 302 | background:rgba(0,0,0,0.8); 303 | color:#fff; 304 | font-size:0.8rem; 305 | position:fixed; 306 | z-index:10; 307 | min-height:3rem; 308 | bottom:0; 309 | left:0; 310 | right:0; 311 | 312 | p { 313 | margin:0; 314 | padding:10px; 315 | } 316 | } 317 | 318 | @media(max-width:@mobileWidth) { 319 | .footer { 320 | display:none; 321 | } 322 | } 323 | 324 | 325 | /* main content area - for host / user pages */ 326 | .content, 327 | .content section, 328 | .content .scrollable { 329 | .box-sizing(border-box); 330 | height:100%; 331 | } 332 | 333 | .content .scrollable { 334 | -webkit-overflow-scrolling:touch; 335 | } 336 | 337 | .content { 338 | padding-top:100px; /* header height */ 339 | padding-bottom:3rem; /* footer height */ 340 | } 341 | 342 | .content section { 343 | border-right:1px solid #999; 344 | position:relative; 345 | overflow:hidden; 346 | padding-bottom:3rem; /* footer height */ 347 | } 348 | 349 | @media(max-width:@mobileWidth) { 350 | .content, 351 | .content section { 352 | padding-bottom:0; 353 | } 354 | } 355 | 356 | .content .scrollable { 357 | overflow:auto; 358 | } 359 | 360 | .content h3, 361 | .content h4 { 362 | position:absolute; 363 | z-index:2; 364 | top:0; 365 | left:0; 366 | right:0; 367 | margin:0; 368 | padding:0 10px; 369 | height:3rem; 370 | line-height:3rem; 371 | .box-sizing(border-box); 372 | 373 | font-size:1.2rem; 374 | background:#999; 375 | color:#fff; 376 | font-size:1rem; 377 | text-shadow:1px 1px 1px rgba(0,0,0,0.5); 378 | } 379 | 380 | @media(max-width:@mobileWidth) { 381 | .content h3 { 382 | display:none; 383 | } 384 | } 385 | 386 | .content h4 { 387 | font-size:1rem; 388 | position:static; 389 | background:#bbb; 390 | height:2rem; 391 | line-height:2rem; 392 | } 393 | 394 | .content ul, 395 | .content li { 396 | list-style:none; 397 | margin:0; 398 | padding:0; 399 | } 400 | 401 | 402 | /* individual page styles */ 403 | 404 | /* home page */ 405 | #home { 406 | 407 | body& { 408 | background-color:#000; 409 | background-position:50% 50%; 410 | background-repeat:no-repeat; 411 | background-attachment:fixed; 412 | background-size:cover; 413 | 414 | background-image:url(/img/bg-home/bg_home_01.jpg); 415 | 416 | color:#fff; 417 | text-shadow: 2px 2px 2px rgba(0,0,0,0.5); 418 | } 419 | 420 | #wrapper { 421 | display:table; 422 | width:100%; 423 | height:100%; 424 | padding:0; 425 | } 426 | 427 | #middle { 428 | display:table-cell; 429 | vertical-align:middle; 430 | width:50%; 431 | min-width:300px; 432 | text-align:center; 433 | } 434 | 435 | h1 { 436 | background:url(/img/logo_noisebox_large_24.png) transparent no-repeat left top; 437 | width:300px; 438 | height:50px; 439 | margin-bottom:0; 440 | display:inline-block; 441 | } 442 | 443 | h2, 444 | p { 445 | padding:0 10px; 446 | } 447 | 448 | h2 { 449 | line-height:1.2; 450 | 451 | @media (max-width:@mobileWidth) { 452 | font-size:0.9em; 453 | } 454 | } 455 | 456 | p { 457 | @media (max-width:@mobileWidth) { 458 | font-size:0.7em; 459 | } 460 | } 461 | 462 | form { 463 | background:rgba(0,0,0,0.6); 464 | padding:20px; 465 | 466 | @media (max-width:@mobileWidth) { 467 | padding:10px; 468 | } 469 | } 470 | 471 | legend { 472 | display:none; 473 | } 474 | 475 | .legend, 476 | label { 477 | display:block; 478 | margin-bottom:1em; 479 | } 480 | 481 | .legend { 482 | margin:0 0 0.5em 0; 483 | font-weight:bold; 484 | } 485 | 486 | label { 487 | font-size:0.9rem; 488 | } 489 | 490 | input[type=text] { 491 | width:170px; 492 | } 493 | } 494 | 495 | 496 | /* user page */ 497 | 498 | /* username form */ 499 | #login { 500 | position:absolute; 501 | right:1rem; 502 | top:0.6rem; 503 | z-index:2; 504 | color:#fff; 505 | } 506 | 507 | @media (max-width:@mobileWidth) { 508 | #login { 509 | display:none; 510 | } 511 | } 512 | 513 | #username-display { 514 | text-align:right; 515 | 516 | p { 517 | margin:0; 518 | } 519 | 520 | a { 521 | font-size:0.65rem; 522 | color:#fff; 523 | margin-right:5px; 524 | } 525 | 526 | i { 527 | margin-left:5px; 528 | opacity:0.6; 529 | } 530 | 531 | .default { 532 | opacity:0.3; 533 | } 534 | } 535 | 536 | #username-form { 537 | display:none; 538 | position:relative; 539 | background:#fff; 540 | color:#333; 541 | padding:10px; 542 | margin-top:10px; 543 | border: 4px solid #999; 544 | border-radius:10px; 545 | font-size:0.8rem; 546 | .drop-shadow(0, 1px, 5px, 0.3); 547 | 548 | label { 549 | display:block; 550 | } 551 | 552 | input[type="text"] { 553 | border:1px solid #333; 554 | } 555 | 556 | input[type="submit"] { 557 | background:#333; 558 | color:#fff; 559 | } 560 | } 561 | 562 | /* username form - up arrow */ 563 | #username-form:after, 564 | #username-form:before { 565 | bottom: 100%; 566 | border: solid transparent; 567 | content: " "; 568 | height: 0; 569 | width: 0; 570 | position: absolute; 571 | pointer-events: none; 572 | } 573 | 574 | #username-form:after { 575 | border-color: rgba(255, 255, 255, 0); 576 | border-bottom-color: #ffffff; 577 | border-width: 10px; 578 | left: 85%; 579 | margin-left: -10px; 580 | } 581 | #username-form:before { 582 | border-color: rgba(153, 153, 153, 0); 583 | border-bottom-color: #999; 584 | border-width: 16px; 585 | left: 85%; 586 | margin-left: -16px; 587 | } 588 | 589 | 590 | /* currently playing block */ 591 | #currently-playing { 592 | position:absolute; 593 | top:3.5rem; 594 | right:1rem; 595 | width:50%; 596 | overflow:hidden; 597 | text-align:right; 598 | 599 | @media (max-width:@mobileWidth) { 600 | top:0.3rem; 601 | color:#fff; 602 | } 603 | 604 | h3 { 605 | display:none; 606 | font-size:0.7rem; 607 | line-height:1.2; 608 | margin:0; 609 | } 610 | 611 | ul { 612 | float:right; 613 | width:100000px; /* big enough to keep everything on one line - mostly masked */ 614 | font-size:1rem; 615 | } 616 | 617 | li { 618 | float:right; 619 | margin-left:2rem; 620 | overflow:hidden; 621 | } 622 | 623 | @media(max-width:@mobileWidth) { 624 | /* only show first for mobile */ 625 | li { 626 | display:none; 627 | } 628 | li:first-child { 629 | display:block; 630 | } 631 | } 632 | 633 | span { 634 | float:right; 635 | } 636 | 637 | /* reduce opacity for queued tracks */ 638 | // loop: http://blog.thehippo.de/2012/04/programming/do-a-loop-with-less-css/ 639 | @iterations: 10; 640 | .loopingClass (@index) when (@index > 0) { 641 | (~"li:nth-child(@{index})") { 642 | opacity: ((11-@index)/10); 643 | } 644 | .loopingClass(@index - 1); 645 | } 646 | .loopingClass (0) {} 647 | .loopingClass (@iterations); 648 | } 649 | 650 | 651 | /* columns */ 652 | section#album-list, 653 | section#track-list, 654 | section#stats { 655 | float:left; 656 | overflow:hidden; 657 | .transition(width); 658 | } 659 | 660 | section#album-list { 661 | width:20%; 662 | } 663 | section#track-list, 664 | section#stats { 665 | width:40%; 666 | } 667 | 668 | body#user { 669 | @media (max-width:@tabletWidth) { 670 | section#album-list { 671 | width:0; 672 | border:none; 673 | } 674 | section#track-list, 675 | section#stats { 676 | width:50%; 677 | } 678 | } 679 | 680 | @media (max-width:@mobileWidth) { 681 | section#track-list { 682 | width:100%; 683 | border:none; 684 | float:none; 685 | height:100%; 686 | } 687 | section#stats { 688 | display:none; 689 | } 690 | .room { 691 | display:none; 692 | } 693 | .content { 694 | padding-top:50px; 695 | } 696 | } 697 | } 698 | 699 | 700 | /* column - album list */ 701 | section#album-list { 702 | 703 | .scrollable { 704 | margin-top:3rem; /* height of the main heading */ 705 | } 706 | 707 | li { 708 | &:nth-of-type(odd) a { 709 | background:#f3f3f3; 710 | } 711 | 712 | a { 713 | display:block; 714 | padding:3px 10px; 715 | text-decoration:none; 716 | font-size:0.8em; 717 | color:#000; 718 | text-shadow:0 0 0 rgba(255,255,255,0); 719 | .transition(background); 720 | 721 | &:hover { 722 | background:#e9e9e9; 723 | text-shadow:1px 1px 1px rgba(0,0,0,0.2); 724 | } 725 | } 726 | 727 | &.active a { 728 | background:#666; 729 | color:#fff; 730 | } 731 | } 732 | } 733 | 734 | 735 | /* column - track list */ 736 | section#track-list { 737 | 738 | .search-container { 739 | background:#fff; 740 | position:absolute; 741 | z-index:2; 742 | top:3rem; 743 | left:0; 744 | right:0; 745 | height:2rem; 746 | 747 | @media(max-width:@mobileWidth) { 748 | & { 749 | top:0; 750 | border-bottom:1px solid #999; 751 | } 752 | } 753 | 754 | input { 755 | .box-sizing(border-box); 756 | height:2rem; 757 | padding:5px 10px; 758 | width:100%; 759 | border:0; 760 | font-size:1rem; 761 | .inner-shadow(0, 0, 0, 0); 762 | .transition(background); 763 | 764 | &:focus { 765 | background:#eee; 766 | outline:none; 767 | .inner-shadow(0, 0, 5px, 0.4); 768 | } 769 | } 770 | 771 | .search-clear { 772 | position:absolute; 773 | right:9px; 774 | top:9px; 775 | color:#333; 776 | cursor:pointer; 777 | font-size:0.8rem; 778 | } 779 | } 780 | 781 | /* extra wrapper needed due to sticky header fiddlyness... */ 782 | .scrollable-container { 783 | position:relative; 784 | height:100%; 785 | margin-top:5rem; /* height of the main heading + search box */ 786 | overflow:hidden; 787 | } 788 | 789 | @media(max-width:@mobileWidth) { 790 | .scrollable-container { 791 | margin-top:2rem; 792 | } 793 | } 794 | 795 | .scrollable { 796 | } 797 | 798 | .search-results { 799 | padding:0 10px; 800 | font-weight:bold; 801 | } 802 | 803 | .sticky h4 { 804 | position: absolute; 805 | top:0; 806 | } 807 | 808 | li { 809 | 810 | &:nth-of-type(odd) a { 811 | background:#f9f9f9; 812 | } 813 | 814 | a { 815 | display:block; 816 | padding:1px; 817 | text-decoration:none; 818 | font-size:0.65em; 819 | color:#000; 820 | text-shadow:0 0 0 rgba(255,255,255,0); 821 | .transition(background); 822 | 823 | @media (max-width:@mobileWidth) { 824 | & { 825 | padding:5px 1px; 826 | font-size:0.75em; 827 | } 828 | } 829 | 830 | &:hover { 831 | background:#e9e9e9; 832 | text-shadow:1px 1px 1px rgba(0,0,0,0.2); 833 | } 834 | 835 | .duration { 836 | display:block; 837 | float:right; 838 | padding:1px 5px; 839 | font-size:0.6rem; 840 | color:#999; 841 | } 842 | 843 | .icon { 844 | display:block; 845 | float:left; 846 | padding:1px; 847 | width:15px; 848 | height:12px; 849 | margin:5px 2px 0 0; 850 | color:#ccc; 851 | text-shadow:none; 852 | 853 | &.queued, 854 | &.playing { 855 | color:#4f4; 856 | } 857 | } 858 | } 859 | } 860 | } 861 | 862 | 863 | /* column - stats */ 864 | section#stats { 865 | 866 | /* play mode */ 867 | .play-mode-container { 868 | position:absolute; 869 | z-index:2; 870 | bottom:0; 871 | left:0; 872 | right:0; 873 | height:2rem; 874 | 875 | #play-mode-form { 876 | height:100%; 877 | } 878 | 879 | .play-mode span { 880 | width:50%; 881 | i { 882 | margin-left:5px; 883 | } 884 | } 885 | } 886 | 887 | 888 | /* tabs */ 889 | #stats-tabs { 890 | .box-sizing(border-box); 891 | height:100%; 892 | margin-top:3rem; /* height of the main heading */ 893 | padding-bottom:4rem; /* play mode container + magic */ 894 | } 895 | 896 | @media(max-width:@mobileWidth) { 897 | #stats-tabs { 898 | margin-top:0; 899 | padding-bottom:2rem; 900 | } 901 | } 902 | 903 | .tabs li a { 904 | width:33%; 905 | } 906 | 907 | .tabs li:first-child a { 908 | width:34%; 909 | } 910 | 911 | @media(max-width:@mobileWidth) { 912 | body#user .tabs { 913 | display:none; 914 | } 915 | } 916 | 917 | /* set inner padding for each tab */ 918 | #log, 919 | #play-queue, 920 | #users { 921 | padding:0.5rem; 922 | } 923 | 924 | 925 | /* log tab */ 926 | #tab-log .scrollable { 927 | padding-bottom:3em; /* stop above chat form */ 928 | } 929 | 930 | @media (max-width: @mobileWidth) { 931 | body#user #tab-log .scrollable { 932 | padding-top:3em; 933 | padding-bottom:0; 934 | } 935 | } 936 | 937 | /* log - chat form */ 938 | #chat-form { 939 | position:absolute; 940 | bottom:0; 941 | left:0; 942 | right:0; 943 | background:#fff; 944 | } 945 | 946 | @media (max-width: @mobileWidth) { 947 | #chat-form { 948 | display:none; 949 | } 950 | } 951 | 952 | input[type="text"], 953 | input[type="submit"] { 954 | .box-sizing(border-box); 955 | border-radius:0; 956 | margin:0; 957 | font-size:0.75rem; 958 | } 959 | 960 | input[type="text"] { 961 | padding-top:9px; 962 | padding-bottom:9px; 963 | border-top:1px solid #333; 964 | border-bottom:1px solid #333; 965 | width:75%; 966 | } 967 | 968 | input[type="submit"] { 969 | background:#333; 970 | color:#fff; 971 | width:25%; 972 | 973 | &[disabled] { 974 | background:#ccc; 975 | } 976 | } 977 | } 978 | 979 | 980 | /* host page */ 981 | /* stats - full width */ 982 | #host section#stats { 983 | width:100%; 984 | border:none; 985 | padding:0; 986 | 987 | #stats-tabs { 988 | margin:0; 989 | padding:0; 990 | } 991 | 992 | /* remove tabs for non-mobile */ 993 | @media (min-width: @mobileWidth) { 994 | .tab-trigger a { 995 | padding:0 10px; 996 | height:3rem; 997 | line-height:3rem; 998 | .box-sizing(border-box); 999 | 1000 | font-size:1.2rem; 1001 | font-size:1rem; 1002 | text-shadow:1px 1px 1px rgba(0,0,0,0.5); 1003 | text-align:left; 1004 | cursor:default; 1005 | color:#fff; 1006 | background-color:#999; 1007 | font-weight:bold; 1008 | } 1009 | 1010 | .tab { 1011 | .box-sizing(border-box); 1012 | display:block !important; 1013 | float:left; 1014 | width:33%; 1015 | border-right:1px solid #999; 1016 | position:static; 1017 | } 1018 | 1019 | .tab#tab-log { 1020 | width:34%; 1021 | } 1022 | } 1023 | } 1024 | --------------------------------------------------------------------------------