Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

FEATURE: Scroll-based logo on mobile #6632

Merged
merged 21 commits into from Nov 22, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
56 changes: 54 additions & 2 deletions app/assets/javascripts/discourse/components/discourse-topic.js.es6
Expand Up @@ -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: [
Expand Down Expand Up @@ -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() {
Expand All @@ -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")
Expand All @@ -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") {
Expand Down Expand Up @@ -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;
}
});
35 changes: 26 additions & 9 deletions 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
Expand Down Expand Up @@ -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);
Expand All @@ -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) {
Expand Down
Expand Up @@ -5,9 +5,9 @@ createWidget("header-contents", {
tagName: "div.contents.clearfix",
template: hbs`
{{attach widget="home-logo" attrs=attrs}}
<div class="panel clearfix">{{yield}}</div>
{{#if attrs.topic}}
{{attach widget="header-topic-info" attrs=attrs}}
{{/if}}
<div class="panel clearfix">{{yield}}</div>
`
});
Expand Up @@ -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"))
)
Expand All @@ -47,19 +47,23 @@ export default createWidget("header-topic-info", {

const title = [h("h1", heading)];
const category = topic.get("category");

if (loaded || category) {
if (
category &&
(!category.get("isUncategorizedCategory") ||
!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 = [];
Expand Down
8 changes: 4 additions & 4 deletions app/assets/javascripts/discourse/widgets/home-logo.js.es6
Expand Up @@ -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
}
});
Expand All @@ -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);
Expand Down
114 changes: 106 additions & 8 deletions app/assets/stylesheets/common/base/header.scss
@@ -1,40 +1,53 @@
.d-header {
display: flex;
align-items: center;
width: 100%;
position: absolute;
top: 0;
z-index: z("header");
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;
}

Expand Down Expand Up @@ -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;
}
}
13 changes: 0 additions & 13 deletions app/assets/stylesheets/common/base/tagging.scss
Expand Up @@ -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;
Expand Down