From ff53a94440c8edf9eb487764c46982cd56be0f03 Mon Sep 17 00:00:00 2001 From: Mattias Erming Date: Sun, 16 Mar 2014 20:00:57 +0100 Subject: [PATCH] Added tabs to sidebar --- client/css/bootstrap.css | 239 ++++++++++++++++++++++++++++++++++++- client/css/style.css | 53 +++++--- client/index.html | 16 ++- client/js/chat.js | 12 +- client/js/lib/bootstrap.js | 125 +++++++++++++++++++ 5 files changed, 419 insertions(+), 26 deletions(-) create mode 100644 client/js/lib/bootstrap.js diff --git a/client/css/bootstrap.css b/client/css/bootstrap.css index 69abc025..debcab3a 100644 --- a/client/css/bootstrap.css +++ b/client/css/bootstrap.css @@ -632,6 +632,198 @@ input[type="reset"].btn-block, input[type="button"].btn-block { width: 100%; } +.nav { + margin-bottom: 0; + padding-left: 0; + list-style: none; +} +.nav > li { + position: relative; + display: block; +} +.nav > li > a { + position: relative; + display: block; + padding: 10px 15px; +} +.nav > li > a:hover, +.nav > li > a:focus { + text-decoration: none; + background-color: #eeeeee; +} +.nav > li.disabled > a { + color: #999999; +} +.nav > li.disabled > a:hover, +.nav > li.disabled > a:focus { + color: #999999; + text-decoration: none; + background-color: transparent; + cursor: not-allowed; +} +.nav .open > a, +.nav .open > a:hover, +.nav .open > a:focus { + background-color: #eeeeee; + border-color: #428bca; +} +.nav .nav-divider { + height: 1px; + margin: 9px 0; + overflow: hidden; + background-color: #e5e5e5; +} +.nav > li > a > img { + max-width: none; +} +.nav-tabs { + border-bottom: 1px solid #dddddd; +} +.nav-tabs > li { + float: left; + margin-bottom: -1px; +} +.nav-tabs > li > a { + margin-right: 2px; + line-height: 1.42857143; + border: 1px solid transparent; + border-radius: 2px 2px 0 0; +} +.nav-tabs > li > a:hover { + border-color: #eeeeee #eeeeee #dddddd; +} +.nav-tabs > li.active > a, +.nav-tabs > li.active > a:hover, +.nav-tabs > li.active > a:focus { + color: #555555; + background-color: #ffffff; + border: 1px solid #dddddd; + border-bottom-color: transparent; + cursor: default; +} +.nav-tabs.nav-justified { + width: 100%; + border-bottom: 0; +} +.nav-tabs.nav-justified > li { + float: none; +} +.nav-tabs.nav-justified > li > a { + text-align: center; + margin-bottom: 5px; +} +.nav-tabs.nav-justified > .dropdown .dropdown-menu { + top: auto; + left: auto; +} +@media (min-width: 768px) { + .nav-tabs.nav-justified > li { + display: table-cell; + width: 1%; + } + .nav-tabs.nav-justified > li > a { + margin-bottom: 0; + } +} +.nav-tabs.nav-justified > li > a { + margin-right: 0; + border-radius: 2px; +} +.nav-tabs.nav-justified > .active > a, +.nav-tabs.nav-justified > .active > a:hover, +.nav-tabs.nav-justified > .active > a:focus { + border: 1px solid #dddddd; +} +@media (min-width: 768px) { + .nav-tabs.nav-justified > li > a { + border-bottom: 1px solid #dddddd; + border-radius: 2px 2px 0 0; + } + .nav-tabs.nav-justified > .active > a, + .nav-tabs.nav-justified > .active > a:hover, + .nav-tabs.nav-justified > .active > a:focus { + border-bottom-color: #ffffff; + } +} +.nav-pills > li { + float: left; +} +.nav-pills > li > a { + border-radius: 2px; +} +.nav-pills > li + li { + margin-left: 2px; +} +.nav-pills > li.active > a, +.nav-pills > li.active > a:hover, +.nav-pills > li.active > a:focus { + color: #ffffff; + background-color: #428bca; +} +.nav-stacked > li { + float: none; +} +.nav-stacked > li + li { + margin-top: 2px; + margin-left: 0; +} +.nav-justified { + width: 100%; +} +.nav-justified > li { + float: none; +} +.nav-justified > li > a { + text-align: center; + margin-bottom: 5px; +} +.nav-justified > .dropdown .dropdown-menu { + top: auto; + left: auto; +} +@media (min-width: 768px) { + .nav-justified > li { + display: table-cell; + width: 1%; + } + .nav-justified > li > a { + margin-bottom: 0; + } +} +.nav-tabs-justified { + border-bottom: 0; +} +.nav-tabs-justified > li > a { + margin-right: 0; + border-radius: 2px; +} +.nav-tabs-justified > .active > a, +.nav-tabs-justified > .active > a:hover, +.nav-tabs-justified > .active > a:focus { + border: 1px solid #dddddd; +} +@media (min-width: 768px) { + .nav-tabs-justified > li > a { + border-bottom: 1px solid #dddddd; + border-radius: 2px 2px 0 0; + } + .nav-tabs-justified > .active > a, + .nav-tabs-justified > .active > a:hover, + .nav-tabs-justified > .active > a:focus { + border-bottom-color: #ffffff; + } +} +.tab-content > .tab-pane { + display: none; +} +.tab-content > .active { + display: block; +} +.nav-tabs .dropdown-menu { + margin-top: -1px; + border-top-right-radius: 0; + border-top-left-radius: 0; +} .badge { display: inline-block; min-width: 10px; @@ -644,7 +836,7 @@ input[type="button"].btn-block { white-space: nowrap; text-align: center; background-color: #999999; - border-radius: 2px; + border-radius: 10px; } .badge:empty { display: none; @@ -823,3 +1015,48 @@ a.list-group-item-danger.active:focus { margin-bottom: 0; line-height: 1.3; } +.clearfix:before, +.clearfix:after, +.nav:before, +.nav:after { + content: " "; + display: table; +} +.clearfix:after, +.nav:after { + clear: both; +} +.center-block { + display: block; + margin-left: auto; + margin-right: auto; +} +.pull-right { + float: right !important; +} +.pull-left { + float: left !important; +} +.hide { + display: none !important; +} +.show { + display: block !important; +} +.invisible { + visibility: hidden; +} +.text-hide { + font: 0/0 a; + color: transparent; + text-shadow: none; + background-color: transparent; + border: 0; +} +.hidden { + display: none !important; + visibility: hidden !important; +} +.affix { + position: fixed; +} diff --git a/client/css/style.css b/client/css/style.css index c52a4f75..ffd16906 100644 --- a/client/css/style.css +++ b/client/css/style.css @@ -3,23 +3,37 @@ body { font: 12px Consolas, monospace; height: 100%; } -ul, -li { - list-style: none; - margin: 0; - padding: 0; -} h1, h2 { font: inherit; margin: 0; } #sidebar { - border-right: 1px solid #ccc; + background: #f7f7f9; + border-right: 1px solid #e1e1e8; float: left; height: 100%; width: 200px; } +#sidebar .header { + background: #fff; + height: 43px; + overflow: hidden; + position: relative; +} +#sidebar .header .nav { + bottom: 0; + margin: 0; + padding-left: 10px; + position: absolute; + width: 100%; +} +#sidebar .header .nav a { + line-height: 1em; +} +#sidebar .header .nav .active a { + background: #f7f7f9; +} #sidebar .list-group { margin: 10px 0; padding: 0 10px; @@ -43,9 +57,9 @@ h2 { top: 0; } #chat form { - border-top: 1px solid #ccc; + border-top: 1px solid #ddd; bottom: 0; - height: 32px; + height: 30px; left: 0; position: absolute; right: 0; @@ -53,7 +67,7 @@ h2 { #chat form input { border: 0; font: inherit; - height: 32px; + height: 30px; margin: 0; outline: none; padding: 0 10px; @@ -69,22 +83,25 @@ h2 { #chat .network .users { display: none; } +#chat .network .title, #chat .network .messages { right: 0; } #chat .query .users { display: none; } +#chat .query .title, #chat .query .messages { right: 0; } #chat .title { - border-bottom: 1px solid #ccc; + border-bottom: 1px solid #ddd; height: 43px; + left: 0; padding-left: 10px; position: absolute; + right: 160px; top: 0; - width: 100%; } #chat .title h1 { color: #333; @@ -100,23 +117,23 @@ h2 { outline: none; } #chat .users { - border-left: 1px solid #ccc; - bottom: 32px; + border-left: 1px solid #ddd; + bottom: 30px; overflow-y: auto; padding: 4px 0; position: absolute; - right: 0px; - top: 43px; + right: 0; + top: 0; width: 160px; } #chat .users .user { clear: both; color: #f00; float: left; - padding: 0px 8px; + padding: 0 8px; } #chat .messages { - bottom: 32px; + bottom: 30px; left: 0; overflow-y: auto; padding: 4px 8px; diff --git a/client/index.html b/client/index.html index c7f20631..82960f0e 100644 --- a/client/index.html +++ b/client/index.html @@ -11,14 +11,25 @@ - +
+ diff --git a/client/js/chat.js b/client/js/chat.js index bcb54784..d63e564b 100644 --- a/client/js/chat.js +++ b/client/js/chat.js @@ -37,7 +37,7 @@ $(function() { data.forEach(function(network) { chat.append(Mustache.render(channels, network, partials)); }); - sidebar.html( + sidebar.find(".list").html( Mustache.render(networks, { networks: data }) @@ -71,7 +71,7 @@ $(function() { sidebar.on("click", ".channel", function(e) { e.preventDefault(); - sidebar.find(".active").removeClass("active"); + sidebar.find(".list .active").removeClass("active"); var item = $(this) .addClass("active") .find(".badge") @@ -198,12 +198,14 @@ $(function() { }; $.fn.scrollToBottom = function() { - this.scrollTop(this.prop("scrollHeight")); + return this.each(function() { + this.scrollTop = this.scrollHeight; + }); }; $.fn.isScrollAtBottom = function() { - if ((this.scrollTop() + this.outerHeight()) >= this.prop("scrollHeight")) { + if ((this.scrollTop() + this.outerHeight() + 1) >= this.prop("scrollHeight")) { return true; } }; -})(jQuery); +})(jQuery); \ No newline at end of file diff --git a/client/js/lib/bootstrap.js b/client/js/lib/bootstrap.js new file mode 100644 index 00000000..fa1fcc86 --- /dev/null +++ b/client/js/lib/bootstrap.js @@ -0,0 +1,125 @@ +/* ======================================================================== + * Bootstrap: tab.js v3.1.1 + * http://getbootstrap.com/javascript/#tabs + * ======================================================================== + * Copyright 2011-2014 Twitter, Inc. + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) + * ======================================================================== */ + + ++function ($) { + 'use strict'; + + // TAB CLASS DEFINITION + // ==================== + + var Tab = function (element) { + this.element = $(element) + } + + Tab.prototype.show = function () { + var $this = this.element + var $ul = $this.closest('ul:not(.dropdown-menu)') + var selector = $this.data('target') + + if (!selector) { + selector = $this.attr('href') + selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') //strip for ie7 + } + + if ($this.parent('li').hasClass('active')) return + + var previous = $ul.find('.active:last a')[0] + var e = $.Event('show.bs.tab', { + relatedTarget: previous + }) + + $this.trigger(e) + + if (e.isDefaultPrevented()) return + + var $target = $(selector) + + this.activate($this.parent('li'), $ul) + this.activate($target, $target.parent(), function () { + $this.trigger({ + type: 'shown.bs.tab', + relatedTarget: previous + }) + }) + } + + Tab.prototype.activate = function (element, container, callback) { + var $active = container.find('> .active') + var transition = callback + && $.support.transition + && $active.hasClass('fade') + + function next() { + $active + .removeClass('active') + .find('> .dropdown-menu > .active') + .removeClass('active') + + element.addClass('active') + + if (transition) { + element[0].offsetWidth // reflow for transition + element.addClass('in') + } else { + element.removeClass('fade') + } + + if (element.parent('.dropdown-menu')) { + element.closest('li.dropdown').addClass('active') + } + + callback && callback() + } + + transition ? + $active + .one($.support.transition.end, next) + .emulateTransitionEnd(150) : + next() + + $active.removeClass('in') + } + + + // TAB PLUGIN DEFINITION + // ===================== + + var old = $.fn.tab + + $.fn.tab = function ( option ) { + return this.each(function () { + var $this = $(this) + var data = $this.data('bs.tab') + + if (!data) $this.data('bs.tab', (data = new Tab(this))) + if (typeof option == 'string') data[option]() + }) + } + + $.fn.tab.Constructor = Tab + + + // TAB NO CONFLICT + // =============== + + $.fn.tab.noConflict = function () { + $.fn.tab = old + return this + } + + + // TAB DATA-API + // ============ + + $(document).on('click.bs.tab.data-api', '[data-toggle="tab"], [data-toggle="pill"]', function (e) { + e.preventDefault() + $(this).tab('show') + }) + +}(jQuery); \ No newline at end of file