diff --git a/app/assets/javascripts/discourse/components/discourse-topic.js.es6 b/app/assets/javascripts/discourse/components/discourse-topic.js.es6 index 96c11ab7465..15716de7ad3 100644 --- a/app/assets/javascripts/discourse/components/discourse-topic.js.es6 +++ b/app/assets/javascripts/discourse/components/discourse-topic.js.es6 @@ -12,6 +12,9 @@ function highlight(postNumber) { $contents.on("animationend", () => $contents.removeClass("highlighted")); } +// used to determine scroll direction on mobile +let lastScroll, scrollDirection, delta; + export default Ember.Component.extend(AddArchetypeClass, Scrolling, { userFilters: Ember.computed.alias("topic.userFilters"), classNameBindings: [ @@ -94,6 +97,23 @@ export default Ember.Component.extend(AddArchetypeClass, Scrolling, { this.appEvents.trigger("header:hide-topic"); } }); + // setup mobile scroll logo + if (this.site.mobileView) { + this.appEvents.on("topic:scrolled", offset => + this.mobileScrollGaurd(offset) + ); + // used to animate header contents on scroll + this.appEvents.on("header:show-topic", () => { + $("header.d-header") + .removeClass("scroll-up") + .addClass("scroll-down"); + }); + this.appEvents.on("header:hide-topic", () => { + $("header.d-header") + .removeClass("scroll-down") + .addClass("scroll-up"); + }); + } }, willDestroyElement() { @@ -109,6 +129,11 @@ export default Ember.Component.extend(AddArchetypeClass, Scrolling, { // this happens after route exit, stuff could have trickled in this.appEvents.trigger("header:hide-topic"); this.appEvents.off("post:highlight"); + // mobile scroll logo clean up. + if (this.site.mobileView) { + this.appEvents.off("topic:scrolled"); + $("header.d-header").removeClass("scroll-down scroll-up"); + } }, @observes("Discourse.hasFocus") @@ -123,9 +148,18 @@ export default Ember.Component.extend(AddArchetypeClass, Scrolling, { }, showTopicInHeader(topic, offset) { - return offset > this.get("dockAt"); + // conditions for showing topic title in the header for mobile + if ( + this.site.mobileView && + scrollDirection !== "up" && + offset > this.dockAt + ) { + return true; + // condition for desktops + } else { + return offset > this.dockAt; + } }, - // The user has scrolled the window, or it is finished rendering and ready for processing. scrolled() { if (this.isDestroyed || this.isDestroying || this._state !== "inDOM") { @@ -161,5 +195,23 @@ export default Ember.Component.extend(AddArchetypeClass, Scrolling, { // Trigger a scrolled event this.appEvents.trigger("topic:scrolled", offset); + }, + + // determines scroll direction, triggers header topic info on mobile + // and ensures that the switch happens only once per scroll direction change + mobileScrollGaurd(offset) { + // user hasn't scrolled past topic title. + if (offset < this.dockAt) return; + + delta = offset - lastScroll; + // 3px buffer so that the switch doesn't happen with tiny scrolls + if (delta > 3 && scrollDirection !== "down") { + scrollDirection = "down"; + this.appEvents.trigger("header:show-topic", this.topic); + } else if (delta < -3 && scrollDirection !== "up") { + scrollDirection = "up"; + this.appEvents.trigger("header:hide-topic"); + } + lastScroll = offset; } }); diff --git a/app/assets/javascripts/discourse/components/topic-progress.js.es6 b/app/assets/javascripts/discourse/components/topic-progress.js.es6 index eca9ebb1243..1a107c96449 100644 --- a/app/assets/javascripts/discourse/components/topic-progress.js.es6 +++ b/app/assets/javascripts/discourse/components/topic-progress.js.es6 @@ -1,3 +1,4 @@ +import { getOwner } from "discourse-common/lib/get-owner"; import { default as computed, observes @@ -154,15 +155,14 @@ export default Ember.Component.extend({ const $wrapper = this.$(); if (!$wrapper || $wrapper.length === 0) return; - const offset = window.pageYOffset || $("html").scrollTop(); - const progressHeight = this.site.mobileView - ? 0 - : $("#topic-progress").height(); - const maximumOffset = $("#topic-bottom").offset().top + progressHeight; - const windowHeight = $(window).height(); - const composerHeight = $("#reply-control").height() || 0; - const isDocked = offset >= maximumOffset - windowHeight + composerHeight; - const bottom = $("body").height() - maximumOffset; + const offset = window.pageYOffset || $("html").scrollTop(), + progressHeight = this.site.mobileView ? 0 : $("#topic-progress").height(), + maximumOffset = $("#topic-bottom").offset().top + progressHeight, + windowHeight = $(window).height(), + bodyHeight = $("body").height(), + composerHeight = $("#reply-control").height() || 0, + isDocked = offset >= maximumOffset - windowHeight + composerHeight, + bottom = bodyHeight - maximumOffset; if (composerHeight > 0) { $wrapper.css("bottom", isDocked ? bottom : composerHeight); @@ -178,6 +178,23 @@ export default Ember.Component.extend({ } else { $wrapper.css("right", "1em"); } + + // switch mobile scroll logo at the very bottom of topics + const isIOS = this.capabilities.isIOS, + switchHeight = bodyHeight - offset - windowHeight, + appEvents = getOwner(this).lookup("app-events:main"); + + if (isIOS && switchHeight < -10) { + // match elastic-scroll behaviour in iOS + setTimeout(function() { + appEvents.trigger("header:hide-topic"); + }, 300); + } else if (!isIOS && switchHeight < 5) { + // normal switch for everyone else + setTimeout(function() { + appEvents.trigger("header:hide-topic"); + }, 300); + } }, click(e) { diff --git a/app/assets/javascripts/discourse/widgets/header-contents.js.es6 b/app/assets/javascripts/discourse/widgets/header-contents.js.es6 index b339b08b314..82bae85ec42 100644 --- a/app/assets/javascripts/discourse/widgets/header-contents.js.es6 +++ b/app/assets/javascripts/discourse/widgets/header-contents.js.es6 @@ -5,9 +5,9 @@ createWidget("header-contents", { tagName: "div.contents.clearfix", template: hbs` {{attach widget="home-logo" attrs=attrs}} -
{{yield}}
{{#if attrs.topic}} {{attach widget="header-topic-info" attrs=attrs}} {{/if}} +
{{yield}}
` }); diff --git a/app/assets/javascripts/discourse/widgets/header-topic-info.js.es6 b/app/assets/javascripts/discourse/widgets/header-topic-info.js.es6 index e02f388a4a3..6f79883cae6 100644 --- a/app/assets/javascripts/discourse/widgets/header-topic-info.js.es6 +++ b/app/assets/javascripts/discourse/widgets/header-topic-info.js.es6 @@ -20,7 +20,7 @@ export default createWidget("header-topic-info", { if (href) { heading.push( h( - "a", + "a.private-message-glyph-wrapper", { attributes: { href } }, h("span.private-message-glyph", iconNode("envelope")) ) @@ -47,6 +47,7 @@ export default createWidget("header-topic-info", { const title = [h("h1", heading)]; const category = topic.get("category"); + if (loaded || category) { if ( category && @@ -54,12 +55,15 @@ export default createWidget("header-topic-info", { !this.siteSettings.suppress_uncategorized_badge) ) { const parentCategory = category.get("parentCategory"); + const categories = []; if (parentCategory) { - title.push( + categories.push( this.attach("category-link", { category: parentCategory }) ); } - title.push(this.attach("category-link", { category })); + categories.push(this.attach("category-link", { category })); + + title.push(h("div.categories-wrapper", categories)); } let extra = []; diff --git a/app/assets/javascripts/discourse/widgets/home-logo.js.es6 b/app/assets/javascripts/discourse/widgets/home-logo.js.es6 index c0532d14712..5672cff2852 100644 --- a/app/assets/javascripts/discourse/widgets/home-logo.js.es6 +++ b/app/assets/javascripts/discourse/widgets/home-logo.js.es6 @@ -26,15 +26,15 @@ export default createWidget("home-logo", { const logoUrl = siteSettings.site_logo_url || ""; const title = siteSettings.title; - if (!mobileView && this.attrs.minimized) { + if (this.attrs.minimized) { const logoSmallUrl = siteSettings.site_logo_small_url || ""; if (logoSmallUrl.length) { return h("img#site-logo.logo-small", { key: "logo-small", attributes: { src: Discourse.getURL(logoSmallUrl), - width: 33, - height: 33, + width: 36, + height: 36, alt: title } }); @@ -49,7 +49,7 @@ export default createWidget("home-logo", { } else if (logoUrl.length) { return h("img#site-logo.logo-big", { key: "logo-big", - attributes: { src: Discourse.getURL(logoUrl), alt: title } + attributes: { src: Discourse.getURL(logoUrl), height: 36, alt: title } }); } else { return h("h1#site-text-logo.text-logo", { key: "logo-text" }, title); diff --git a/app/assets/stylesheets/common/base/header.scss b/app/assets/stylesheets/common/base/header.scss index ec9313d4dc9..6ed5598e163 100644 --- a/app/assets/stylesheets/common/base/header.scss +++ b/app/assets/stylesheets/common/base/header.scss @@ -1,4 +1,6 @@ .d-header { + display: flex; + align-items: center; width: 100%; position: absolute; top: 0; @@ -6,35 +8,46 @@ background-color: $header_background; box-shadow: shadow("header"); + > .wrap { + width: 100%; + height: 100%; + .contents { + display: flex; + align-items: center; + height: 100%; + } + } + .docked & { position: fixed; backface-visibility: hidden; /** do magic for scrolling performance **/ } - .contents { - margin: 8px 0; - } - .title { - float: left; + display: flex; + align-items: center; + height: 100%; a, a:visited { color: $header_primary; } } + // the logo height is set in the home-logo widget. This ensures we get a scaled + // width that respects the aspect ratio of the image #site-logo { - max-height: 2.8571em; + width: auto; } .d-icon-home { - font-size: 1.643em; + font-size: $font-up-5; } .panel { - float: right; position: relative; display: flex; + flex: 0 0 auto; + margin-left: auto; align-items: center; } @@ -195,3 +208,88 @@ #search-term::-ms-clear { display: none; } + +// topic info in the header +.extra-info-wrapper { + display: flex; + align-items: center; + flex: 1 1 0%; // unit on flex-basis is required for IE11 + height: 100%; + line-height: $line-height-medium; + padding: 0 1.5em 0 0.5em; + // we need to hide overflow in both to truncate the title in a flexbox + overflow: hidden; + .extra-info { + overflow: hidden; + width: 100%; + -webkit-animation: fadein 0.5s; + animation: fadein 0.5s; + } + .topic-link { + color: $header_primary; + display: block; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + } + .topic-statuses { + margin-top: -2px; + float: left; + padding: 0; + i { + color: $header_primary; + } + .d-icon-envelope { + color: $danger; + } + .d-icon-lock { + padding-top: 0.15em; + } + .unpinned { + color: $header_primary; + } + } + h1 { + margin: 0 0 0.25em 0; + font-size: $font-up-3; + width: 100%; + } + .categories-wrapper { + display: inline-flex; + max-width: 100%; + // only truncate the last category name. + > a:last-of-type { + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; + } + } + .badge-wrapper { + margin-right: 8px; + } + .badge-wrapper.bullet { + .badge-category-parent-bg, + .badge-category-bg { + min-width: 5px; + } + } + .topic-header-extra { + display: inline-flex; + align-items: center; + max-width: 100%; + flex: 1 0 0%; // unit on flex-basis is required for IE11 + .discourse-tags { + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; + .discourse-tag { + display: inline; + } + } + } + // if a topic has both categories and tags, the tag container should shrink + // instead of wrapping to the next line. + .categories-wrapper + .topic-header-extra { + min-width: 0; + } +} diff --git a/app/assets/stylesheets/common/base/tagging.scss b/app/assets/stylesheets/common/base/tagging.scss index 5c82fdbd59f..0e2e9346967 100644 --- a/app/assets/stylesheets/common/base/tagging.scss +++ b/app/assets/stylesheets/common/base/tagging.scss @@ -37,19 +37,6 @@ } } -.topic-header-extra .discourse-tag { - -webkit-animation: fadein 0.7s; - animation: fadein 0.7s; -} - -.bullet + .topic-header-extra { - display: block; -} - -.box + .topic-header-extra { - display: inline-block; -} - .topic-category { display: flex; flex-wrap: wrap; diff --git a/app/assets/stylesheets/common/base/topic.scss b/app/assets/stylesheets/common/base/topic.scss index 82233f44ee5..a1c19b57442 100644 --- a/app/assets/stylesheets/common/base/topic.scss +++ b/app/assets/stylesheets/common/base/topic.scss @@ -60,8 +60,6 @@ .title-wrapper { display: flex; flex-wrap: wrap; - width: 90%; - align-items: flex-end; .btn-small { margin: 0 6px 0 0; } @@ -151,12 +149,6 @@ a.badge-category { clear: both; } -.extra-info-wrapper { - .badge-wrapper { - float: left; - } -} - .has-pending-posts { padding: 0.5em; background-color: $highlight-medium; diff --git a/app/assets/stylesheets/desktop/discourse.scss b/app/assets/stylesheets/desktop/discourse.scss index df19506ad8e..1bd3dac3615 100644 --- a/app/assets/stylesheets/desktop/discourse.scss +++ b/app/assets/stylesheets/desktop/discourse.scss @@ -8,10 +8,6 @@ body.widget-dragging { cursor: ns-resize; } -header { - margin-bottom: 15px; -} - // Common classes .boxed { height: 100%; diff --git a/app/assets/stylesheets/desktop/header.scss b/app/assets/stylesheets/desktop/header.scss index e4b20e264f4..3f53844ff4e 100644 --- a/app/assets/stylesheets/desktop/header.scss +++ b/app/assets/stylesheets/desktop/header.scss @@ -4,16 +4,21 @@ .d-header { left: 0; - padding-top: 3px; - height: 4.2857em; - .d-icon-home { - padding: 8px; - font-size: $font-up-5; - } + height: 4.2858em; + margin-bottom: 15px; - .site-text-logo { - position: relative; - top: 10px; + #site-text-logo { + font-size: $font-up-3; + margin: 0; + } + .extra-info { + // header title should not be centered if there's no tags / categories + &:not(.two-rows) { + min-height: 2.75em; + } + h1 { + margin: 0 0 0.125em 0; + } } } @@ -41,11 +46,3 @@ color: dark-light-choose($primary-high, $secondary-low); } } - -header { - #site-text-logo { - font-size: $font-up-3; - margin-top: 0.4em; - line-height: $line-height-medium; - } -} diff --git a/app/assets/stylesheets/desktop/topic-post.scss b/app/assets/stylesheets/desktop/topic-post.scss index cb9dafa3d1f..b81211e5baf 100644 --- a/app/assets/stylesheets/desktop/topic-post.scss +++ b/app/assets/stylesheets/desktop/topic-post.scss @@ -11,14 +11,6 @@ h1 .topic-statuses .topic-status i { vertical-align: middle; } -.logo-small { - margin-right: 8px; - width: auto; - max-width: 80px; - height: auto; - max-height: 40px; -} - .topic-body { padding: 0; &:first-of-type { @@ -506,64 +498,6 @@ video { } } -.extra-info-wrapper { - overflow: hidden; - .badge-wrapper, - i, - .topic-link { - -webkit-animation: fadein 0.7s; - animation: fadein 0.7s; - } - .topic-statuses { - i { - color: $header_primary; - } - .d-icon-envelope { - color: $danger; - } - .d-icon-lock { - padding-top: 0.15em; - } - .unpinned { - color: $header_primary; - } - } - .topic-link { - color: $header_primary; - display: block; - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; - } - .topic-header-extra { - margin: 0 0 0 5px; - } -} - -/* default docked header CSS for all topics, including those without categories */ - -.extra-info { - h1 { - margin: 5px 0 0 0; - font-size: $font-up-3; - line-height: $line-height-large; - width: 100%; - } - .topic-statuses { - margin-top: -2px; - } -} - -/* override docked header CSS for topics with categories */ - -.extra-info.two-rows { - h1 { - line-height: $line-height-medium; - margin: 0; - width: 100%; - } -} - .open > .dropdown-menu { display: block; } diff --git a/app/assets/stylesheets/mobile/discourse.scss b/app/assets/stylesheets/mobile/discourse.scss index e211ebc25b7..ce37c2393d2 100644 --- a/app/assets/stylesheets/mobile/discourse.scss +++ b/app/assets/stylesheets/mobile/discourse.scss @@ -149,9 +149,3 @@ blockquote { #simple-container { width: 90%; } - -// somehow the image logo assumption inherits margins from earlier in the CSS -// stack we must remove margins for text site titles -h1#site-text-logo { - margin: 0 0 0 10px; -} diff --git a/app/assets/stylesheets/mobile/header.scss b/app/assets/stylesheets/mobile/header.scss index e4d2abb9040..49971d56da1 100644 --- a/app/assets/stylesheets/mobile/header.scss +++ b/app/assets/stylesheets/mobile/header.scss @@ -2,37 +2,50 @@ // Discourse header // -------------------------------------------------- -#site-text-logo { - font-size: $font-up-3; -} -@include breakpoint(mobile-small) { - #site-text-logo { - font-size: $font-up-2; - } -} - .d-header { - #site-logo { - max-width: 8.8em; - } + height: 3.66em; // some protection for text-only site titles .title { - max-width: 50%; - height: 39px; + max-width: 75%; + white-space: nowrap; overflow: hidden; - padding: 0; - text-overflow: clip; - display: table; + text-overflow: ellipsis; + -webkit-animation: fadein 0.5s; + animation: fadein 0.5s; a { - display: table-cell; - vertical-align: middle; + display: block; + } + } + #site-text-logo { + margin: 0; + font-size: $font-up-1; + } + .extra-info-wrapper { + .extra-info { + // header title should not be centered if there's no tags / categories + &:not(.two-rows) { + min-height: 2.25em; + } + h1 { + font-size: $font-0; + } + .private-message-glyph-wrapper { + float: left; + } } } - button.sign-up-button { display: none; } + // styles for mobile scroll logo / topic + .panel { + -webkit-animation: fadein 0.5s; + animation: fadein 0.5s; + } + &.scroll-down .panel { + display: none; + } } .d-header-icons { diff --git a/app/assets/stylesheets/mobile/topic-post.scss b/app/assets/stylesheets/mobile/topic-post.scss index 802bc5802d1..6d65d3be04f 100644 --- a/app/assets/stylesheets/mobile/topic-post.scss +++ b/app/assets/stylesheets/mobile/topic-post.scss @@ -1,5 +1,4 @@ /* hide the reply border above the time gap notices */ - .time-gap + .topic-post article { border-top: none; } @@ -319,10 +318,6 @@ iframe { max-width: 100%; } -.extra-info { - display: none; -} - .open > .dropdown-menu { display: block; }