diff --git a/dashboard-ui/css/card.css b/dashboard-ui/css/card.css index c06aafd497..45bd81a679 100644 --- a/dashboard-ui/css/card.css +++ b/dashboard-ui/css/card.css @@ -204,6 +204,16 @@ color: #ddd; } +/*.cardBox:not(.visualCardBox) .outerCardFooter .cardText { + font-size: 14px; + background: rgba(51, 51, 51,.6); + padding: 5px; +}*/ + +.cardBox:not(.visualCardBox) .outerCardFooter .cardText:last-child { + margin-bottom: 2em; +} + @media all and (max-width: 600px) { .packageReviewText { diff --git a/dashboard-ui/css/librarybrowser.css b/dashboard-ui/css/librarybrowser.css index 7fd62c5291..719e1bedb6 100644 --- a/dashboard-ui/css/librarybrowser.css +++ b/dashboard-ui/css/librarybrowser.css @@ -30,7 +30,7 @@ .backdropContainer { position: fixed; - top: 50px; + top: 0; right: 0; left: 0; bottom: 0; @@ -773,7 +773,7 @@ span.itemCommunityRating:not(:empty) + .userDataIcons { } } -@media all and (max-height: 600px), (max-width: 600px) { +@media all and (max-height: 540px), (max-width: 540px) { .itemBackdrop:not(.noBackdrop) { height: 280px; diff --git a/dashboard-ui/css/librarymenu.css b/dashboard-ui/css/librarymenu.css index 5f26e2072f..59291fd075 100644 --- a/dashboard-ui/css/librarymenu.css +++ b/dashboard-ui/css/librarymenu.css @@ -3,7 +3,7 @@ } .libraryPage:not(.metadataEditorPage):not(.noSecondaryNavPage) { - padding-top: 98px !important; + padding-top: 99px !important; } .libraryMenuDivider { @@ -124,7 +124,7 @@ } .libraryViewNav { - height: 48px; + height: 49px; overflow: hidden; position: fixed; right: 0; @@ -132,7 +132,7 @@ top: 50px; z-index: 999; text-align: center; - font-size: 15px; + font-size: 14px; white-space: nowrap; padding: 0 0 0; overflow-x: scroll; @@ -142,7 +142,7 @@ } .viewMenuBar { - background-color: #000; + background-color: #111; } .libraryViewNav { @@ -224,12 +224,12 @@ .libraryViewNav a { display: inline-block; padding: 12px 0 9px; - color: #ddd !important; + color: rgba(255,255,255,.8) !important; text-decoration: none; margin: 0 0; position: relative; font-weight: normal; - border-bottom: 4px solid transparent; + border-bottom: 5px solid transparent; } .libraryViewNav a:not(.ui-btn-active):hover { diff --git a/dashboard-ui/css/livetv.css b/dashboard-ui/css/livetv.css index dbf3a52b2d..75790b092e 100644 --- a/dashboard-ui/css/livetv.css +++ b/dashboard-ui/css/livetv.css @@ -1,4 +1,8 @@ - +.tvGuideHeader.headroom--unpinned { + -webkit-transform: translateY(-98px); + transform: translateY(-98px); +} + .tvProgramSectionHeader { margin: 0; } @@ -90,7 +94,7 @@ } .tvProgram:hover, .tvProgram:hover .tvProgramInfo { - background-color: #4d90fe; + background-color: #444; } .timerCircle { @@ -215,7 +219,7 @@ } .channelHeaderCell:hover { - background-color: #38c; + background-color: #444; } .channelList { @@ -254,7 +258,7 @@ } .programCellInner:hover { - background-color: #38c; + background-color: #444; } .timeslotCellInner { @@ -322,7 +326,7 @@ width: 6500px; } - .channelList, .channelTimeslotHeader .accentButton { + .channelList, .channelTimeslotHeader .accentButton { font-size: 14px; } diff --git a/dashboard-ui/css/site.css b/dashboard-ui/css/site.css index e31df6a6fc..57bd2e4c4d 100644 --- a/dashboard-ui/css/site.css +++ b/dashboard-ui/css/site.css @@ -162,6 +162,30 @@ h1 a:hover { margin: -10px 0 0 -10px; } +/** + * Note: I have omitted any vendor-prefixes for clarity. + * Adding them is left as an exercise for the reader. + */ +.headroom { + -webkit-transition: transform 200ms linear; + transition: transform 200ms linear; +} + +.headroom--pinned { + -webkit-transform: translateY(0%); + transform: translateY(0%); +} + +.headroom--unpinned { + -webkit-transform: translateY(-100%); + transform: translateY(-100%); +} + +.libraryViewNav.headroom--unpinned { + -webkit-transform: translateY(-200%); + transform: translateY(-200%); +} + .largePanel { width: 270px; } @@ -597,7 +621,7 @@ h1 .imageLink { z-index: 1097; color: #fff; border: 0 !important; - background-color: #1a1a1a; + background-color: rgba(26,26,26,.9); } .footerNotification { diff --git a/dashboard-ui/livetvguide.html b/dashboard-ui/livetvguide.html index 07d946cb87..7138729e02 100644 --- a/dashboard-ui/livetvguide.html +++ b/dashboard-ui/livetvguide.html @@ -16,7 +16,7 @@
-
+
diff --git a/dashboard-ui/scripts/backdrops.js b/dashboard-ui/scripts/backdrops.js index e5e0d0e0e8..eb4a00b3d7 100644 --- a/dashboard-ui/scripts/backdrops.js +++ b/dashboard-ui/scripts/backdrops.js @@ -99,12 +99,6 @@ function enabled() { - // Gets real messy and jumps around the page when scrolling - // Can be reviewed later. - if ($.browser.msie) { - return false; - } - var userId = Dashboard.getCurrentUserId(); var val = store.getItem('enableBackdrops-' + userId); diff --git a/dashboard-ui/scripts/librarymenu.js b/dashboard-ui/scripts/librarymenu.js index 9105789dac..a58b6b205b 100644 --- a/dashboard-ui/scripts/librarymenu.js +++ b/dashboard-ui/scripts/librarymenu.js @@ -90,6 +90,13 @@ $('.libraryMenuButton').createHoverTouch().on('hovertouch', showLibraryMenu); $('.dashboardMenuButton').createHoverTouch().on('hovertouch', showDashboardMenu); } + + // grab an element + var viewMenuBar = document.getElementsByClassName("viewMenuBar")[0]; + // construct an instance of Headroom, passing the element + var headroom = new Headroom(viewMenuBar); + // initialise + headroom.init(); } function getItemHref(item, context) { @@ -534,6 +541,15 @@ // Scroll back up so in case vertical scroll was messed with $(document).scrollTop(0); } + + $('.libraryViewNav', page).each(function() { + + // construct an instance of Headroom, passing the element + var headroom = new Headroom(this); + // initialise + headroom.init(); + + }); }); function initializeApiClient(apiClient) { diff --git a/dashboard-ui/scripts/livetvguide.js b/dashboard-ui/scripts/livetvguide.js index 34e2cbdd32..89b1266a34 100644 --- a/dashboard-ui/scripts/livetvguide.js +++ b/dashboard-ui/scripts/livetvguide.js @@ -419,6 +419,15 @@ }); } + $('.tvGuideHeader', page).each(function () { + + // construct an instance of Headroom, passing the element + var headroom = new Headroom(this); + // initialise + headroom.init(); + + }); + }).on('pageshow', "#liveTvGuidePage", function () { var page = this; diff --git a/dashboard-ui/scripts/mypreferenceswebclient.js b/dashboard-ui/scripts/mypreferenceswebclient.js index 2396316d83..71a048e419 100644 --- a/dashboard-ui/scripts/mypreferenceswebclient.js +++ b/dashboard-ui/scripts/mypreferenceswebclient.js @@ -99,12 +99,7 @@ }); - // See backrops.js for comments on this - if ($.browser.msie) { - $('.fldEnableBackdrops', page).hide(); - } else { - $('.fldEnableBackdrops', page).show(); - } + $('.fldEnableBackdrops', page).show(); }); window.WebClientPreferencesPage = { diff --git a/dashboard-ui/scripts/site.js b/dashboard-ui/scripts/site.js index 43493937ae..0802564154 100644 --- a/dashboard-ui/scripts/site.js +++ b/dashboard-ui/scripts/site.js @@ -1327,7 +1327,7 @@ var Dashboard = { var isBackdrop = imageType.toLowerCase() == 'backdrop'; if (isBackdrop) { - quality -= 10; + quality -= 15; } if ($.browser.safari && $.browser.mobile) { diff --git a/dashboard-ui/thirdparty/headroom.js b/dashboard-ui/thirdparty/headroom.js new file mode 100644 index 0000000000..df812cd9ad --- /dev/null +++ b/dashboard-ui/thirdparty/headroom.js @@ -0,0 +1,390 @@ +/*! + * headroom.js v0.7.0 - Give your page some headroom. Hide your header until you need it + * Copyright (c) 2014 Nick Williams - http://wicky.nillia.ms/headroom.js + * License: MIT + */ + +(function(window, document) { + + 'use strict'; + + /* exported features */ + + var features = { + bind : !!(function(){}.bind), + classList : 'classList' in document.documentElement, + rAF : !!(window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame) + }; + window.requestAnimationFrame = window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame; + + /** + * Handles debouncing of events via requestAnimationFrame + * @see http://www.html5rocks.com/en/tutorials/speed/animations/ + * @param {Function} callback The callback to handle whichever event + */ + function Debouncer (callback) { + this.callback = callback; + this.ticking = false; + } + Debouncer.prototype = { + constructor : Debouncer, + + /** + * dispatches the event to the supplied callback + * @private + */ + update : function() { + this.callback && this.callback(); + this.ticking = false; + }, + + /** + * ensures events don't get stacked + * @private + */ + requestTick : function() { + if(!this.ticking) { + requestAnimationFrame(this.rafCallback || (this.rafCallback = this.update.bind(this))); + this.ticking = true; + } + }, + + /** + * Attach this as the event listeners + */ + handleEvent : function() { + this.requestTick(); + } + }; + /** + * Check if object is part of the DOM + * @constructor + * @param {Object} obj element to check + */ + function isDOMElement(obj) { + return obj && typeof window !== 'undefined' && (obj === window || obj.nodeType); + } + + /** + * Helper function for extending objects + */ + function extend (object /*, objectN ... */) { + if(arguments.length <= 0) { + throw new Error('Missing arguments in extend function'); + } + + var result = object || {}, + key, + i; + + for (i = 1; i < arguments.length; i++) { + var replacement = arguments[i] || {}; + + for (key in replacement) { + // Recurse into object except if the object is a DOM element + if(typeof result[key] === 'object' && ! isDOMElement(result[key])) { + result[key] = extend(result[key], replacement[key]); + } + else { + result[key] = result[key] || replacement[key]; + } + } + } + + return result; + } + + /** + * Helper function for normalizing tolerance option to object format + */ + function normalizeTolerance (t) { + return t === Object(t) ? t : { down : t, up : t }; + } + + /** + * UI enhancement for fixed headers. + * Hides header when scrolling down + * Shows header when scrolling up + * @constructor + * @param {DOMElement} elem the header element + * @param {Object} options options for the widget + */ + function Headroom (elem, options) { + options = extend(options, Headroom.options); + + this.lastKnownScrollY = 0; + this.elem = elem; + this.debouncer = new Debouncer(this.update.bind(this)); + this.tolerance = normalizeTolerance(options.tolerance); + this.classes = options.classes; + this.offset = options.offset; + this.scroller = options.scroller; + this.initialised = false; + this.onPin = options.onPin; + this.onUnpin = options.onUnpin; + this.onTop = options.onTop; + this.onNotTop = options.onNotTop; + } + Headroom.prototype = { + constructor : Headroom, + + /** + * Initialises the widget + */ + init : function() { + if(!Headroom.cutsTheMustard) { + return; + } + + this.elem.classList.add(this.classes.initial); + + // defer event registration to handle browser + // potentially restoring previous scroll position + setTimeout(this.attachEvent.bind(this), 100); + + return this; + }, + + /** + * Unattaches events and removes any classes that were added + */ + destroy : function() { + var classes = this.classes; + + this.initialised = false; + this.elem.classList.remove(classes.unpinned, classes.pinned, classes.top, classes.initial); + this.scroller.removeEventListener('scroll', this.debouncer, false); + }, + + /** + * Attaches the scroll event + * @private + */ + attachEvent : function() { + if(!this.initialised){ + this.lastKnownScrollY = this.getScrollY(); + this.initialised = true; + this.scroller.addEventListener('scroll', this.debouncer, false); + + this.debouncer.handleEvent(); + } + }, + + /** + * Unpins the header if it's currently pinned + */ + unpin : function() { + var classList = this.elem.classList, + classes = this.classes; + + if(classList.contains(classes.pinned) || !classList.contains(classes.unpinned)) { + classList.add(classes.unpinned); + classList.remove(classes.pinned); + this.onUnpin && this.onUnpin.call(this); + } + }, + + /** + * Pins the header if it's currently unpinned + */ + pin : function() { + var classList = this.elem.classList, + classes = this.classes; + + if(classList.contains(classes.unpinned)) { + classList.remove(classes.unpinned); + classList.add(classes.pinned); + this.onPin && this.onPin.call(this); + } + }, + + /** + * Handles the top states + */ + top : function() { + var classList = this.elem.classList, + classes = this.classes; + + if(!classList.contains(classes.top)) { + classList.add(classes.top); + classList.remove(classes.notTop); + this.onTop && this.onTop.call(this); + } + }, + + /** + * Handles the not top state + */ + notTop : function() { + var classList = this.elem.classList, + classes = this.classes; + + if(!classList.contains(classes.notTop)) { + classList.add(classes.notTop); + classList.remove(classes.top); + this.onNotTop && this.onNotTop.call(this); + } + }, + + /** + * Gets the Y scroll position + * @see https://developer.mozilla.org/en-US/docs/Web/API/Window.scrollY + * @return {Number} pixels the page has scrolled along the Y-axis + */ + getScrollY : function() { + return (this.scroller.pageYOffset !== undefined) + ? this.scroller.pageYOffset + : (this.scroller.scrollTop !== undefined) + ? this.scroller.scrollTop + : (document.documentElement || document.body.parentNode || document.body).scrollTop; + }, + + /** + * Gets the height of the viewport + * @see http://andylangton.co.uk/blog/development/get-viewport-size-width-and-height-javascript + * @return {int} the height of the viewport in pixels + */ + getViewportHeight : function () { + return window.innerHeight + || document.documentElement.clientHeight + || document.body.clientHeight; + }, + + /** + * Gets the height of the document + * @see http://james.padolsey.com/javascript/get-document-height-cross-browser/ + * @return {int} the height of the document in pixels + */ + getDocumentHeight : function () { + var body = document.body, + documentElement = document.documentElement; + + return Math.max( + body.scrollHeight, documentElement.scrollHeight, + body.offsetHeight, documentElement.offsetHeight, + body.clientHeight, documentElement.clientHeight + ); + }, + + /** + * Gets the height of the DOM element + * @param {Object} elm the element to calculate the height of which + * @return {int} the height of the element in pixels + */ + getElementHeight : function (elm) { + return Math.max( + elm.scrollHeight, + elm.offsetHeight, + elm.clientHeight + ); + }, + + /** + * Gets the height of the scroller element + * @return {int} the height of the scroller element in pixels + */ + getScrollerHeight : function () { + return (this.scroller === window || this.scroller === document.body) + ? this.getDocumentHeight() + : this.getElementHeight(this.scroller); + }, + + /** + * determines if the scroll position is outside of document boundaries + * @param {int} currentScrollY the current y scroll position + * @return {bool} true if out of bounds, false otherwise + */ + isOutOfBounds : function (currentScrollY) { + var pastTop = currentScrollY < 0, + pastBottom = currentScrollY + this.getViewportHeight() > this.getScrollerHeight(); + + return pastTop || pastBottom; + }, + + /** + * determines if the tolerance has been exceeded + * @param {int} currentScrollY the current scroll y position + * @return {bool} true if tolerance exceeded, false otherwise + */ + toleranceExceeded : function (currentScrollY, direction) { + return Math.abs(currentScrollY-this.lastKnownScrollY) >= this.tolerance[direction]; + }, + + /** + * determine if it is appropriate to unpin + * @param {int} currentScrollY the current y scroll position + * @param {bool} toleranceExceeded has the tolerance been exceeded? + * @return {bool} true if should unpin, false otherwise + */ + shouldUnpin : function (currentScrollY, toleranceExceeded) { + var scrollingDown = currentScrollY > this.lastKnownScrollY, + pastOffset = currentScrollY >= this.offset; + + return scrollingDown && pastOffset && toleranceExceeded; + }, + + /** + * determine if it is appropriate to pin + * @param {int} currentScrollY the current y scroll position + * @param {bool} toleranceExceeded has the tolerance been exceeded? + * @return {bool} true if should pin, false otherwise + */ + shouldPin : function (currentScrollY, toleranceExceeded) { + var scrollingUp = currentScrollY < this.lastKnownScrollY, + pastOffset = currentScrollY <= this.offset; + + return (scrollingUp && toleranceExceeded) || pastOffset; + }, + + /** + * Handles updating the state of the widget + */ + update : function() { + var currentScrollY = this.getScrollY(), + scrollDirection = currentScrollY > this.lastKnownScrollY ? 'down' : 'up', + toleranceExceeded = this.toleranceExceeded(currentScrollY, scrollDirection); + + if(this.isOutOfBounds(currentScrollY)) { // Ignore bouncy scrolling in OSX + return; + } + + if (currentScrollY <= this.offset ) { + this.top(); + } else { + this.notTop(); + } + + if(this.shouldUnpin(currentScrollY, toleranceExceeded)) { + this.unpin(); + } + else if(this.shouldPin(currentScrollY, toleranceExceeded)) { + this.pin(); + } + + this.lastKnownScrollY = currentScrollY; + } + }; + /** + * Default options + * @type {Object} + */ + Headroom.options = { + tolerance : { + up : 0, + down : 0 + }, + offset : 0, + scroller: window, + classes : { + pinned : 'headroom--pinned', + unpinned : 'headroom--unpinned', + top : 'headroom--top', + notTop : 'headroom--not-top', + initial : 'headroom' + } + }; + Headroom.cutsTheMustard = typeof features !== 'undefined' && features.rAF && features.bind && features.classList; + + window.Headroom = Headroom; + +}(window, document)); \ No newline at end of file