mirror of
https://github.com/discourse/discourse.git
synced 2025-02-25 18:55:32 -06:00
DEV: Minor topic timeline refactor (#15357)
This commit is contained in:
@@ -172,7 +172,7 @@ const SiteHeaderComponent = MountWidget.extend(
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
dockCheck(info) {
|
dockCheck() {
|
||||||
const header = document.querySelector("header.d-header");
|
const header = document.querySelector("header.d-header");
|
||||||
|
|
||||||
if (this.docAt === null) {
|
if (this.docAt === null) {
|
||||||
@@ -182,9 +182,7 @@ const SiteHeaderComponent = MountWidget.extend(
|
|||||||
this.docAt = header.offsetTop;
|
this.docAt = header.offsetTop;
|
||||||
}
|
}
|
||||||
|
|
||||||
const offset = info.offset();
|
|
||||||
const headerRect = header.getBoundingClientRect();
|
const headerRect = header.getBoundingClientRect();
|
||||||
const doc = document.documentElement;
|
|
||||||
let headerOffset = headerRect.top + headerRect.height;
|
let headerOffset = headerRect.top + headerRect.height;
|
||||||
|
|
||||||
if (window.scrollY < 0) {
|
if (window.scrollY < 0) {
|
||||||
@@ -194,10 +192,10 @@ const SiteHeaderComponent = MountWidget.extend(
|
|||||||
const newValue = `${headerOffset}px`;
|
const newValue = `${headerOffset}px`;
|
||||||
if (newValue !== this.currentHeaderOffsetValue) {
|
if (newValue !== this.currentHeaderOffsetValue) {
|
||||||
this.currentHeaderOffsetValue = newValue;
|
this.currentHeaderOffsetValue = newValue;
|
||||||
doc.style.setProperty("--header-offset", newValue);
|
document.documentElement.style.setProperty("--header-offset", newValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (offset >= this.docAt) {
|
if (window.pageYOffset >= this.docAt) {
|
||||||
if (!this.dockedHeader) {
|
if (!this.dockedHeader) {
|
||||||
document.body.classList.add("docked");
|
document.body.classList.add("docked");
|
||||||
this.dockedHeader = true;
|
this.dockedHeader = true;
|
||||||
|
|||||||
@@ -3,22 +3,13 @@ import MountWidget from "discourse/components/mount-widget";
|
|||||||
import { next } from "@ember/runloop";
|
import { next } from "@ember/runloop";
|
||||||
import { observes } from "discourse-common/utils/decorators";
|
import { observes } from "discourse-common/utils/decorators";
|
||||||
import optionalService from "discourse/lib/optional-service";
|
import optionalService from "discourse/lib/optional-service";
|
||||||
import outletHeights from "discourse/lib/header-outlet-height";
|
|
||||||
|
|
||||||
const headerPadding = () => {
|
|
||||||
let topPadding = parseInt($("#main-outlet").css("padding-top"), 10) + 3;
|
|
||||||
const iPadNavHeight = $(".footer-nav-ipad .footer-nav").height();
|
|
||||||
if (iPadNavHeight) {
|
|
||||||
topPadding += iPadNavHeight;
|
|
||||||
}
|
|
||||||
return topPadding;
|
|
||||||
};
|
|
||||||
|
|
||||||
export default MountWidget.extend(Docking, {
|
export default MountWidget.extend(Docking, {
|
||||||
adminTools: optionalService(),
|
adminTools: optionalService(),
|
||||||
widget: "topic-timeline-container",
|
widget: "topic-timeline-container",
|
||||||
dockBottom: null,
|
dockBottom: null,
|
||||||
dockAt: null,
|
dockAt: null,
|
||||||
|
intersectionObserver: null,
|
||||||
|
|
||||||
buildArgs() {
|
buildArgs() {
|
||||||
let attrs = {
|
let attrs = {
|
||||||
@@ -39,8 +30,6 @@ export default MountWidget.extend(Docking, {
|
|||||||
if (this.fullscreen) {
|
if (this.fullscreen) {
|
||||||
attrs.fullScreen = true;
|
attrs.fullScreen = true;
|
||||||
attrs.addShowClass = this.addShowClass;
|
attrs.addShowClass = this.addShowClass;
|
||||||
} else {
|
|
||||||
attrs.top = this.dockAt || headerPadding();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return attrs;
|
return attrs;
|
||||||
@@ -56,38 +45,26 @@ export default MountWidget.extend(Docking, {
|
|||||||
this.queueRerender();
|
this.queueRerender();
|
||||||
},
|
},
|
||||||
|
|
||||||
dockCheck(info) {
|
dockCheck() {
|
||||||
const mainOffset = $("#main").offset();
|
|
||||||
const offsetTop = mainOffset ? mainOffset.top : 0;
|
|
||||||
const topicTop = $(".container.posts").offset().top - offsetTop;
|
|
||||||
const topicBottom =
|
|
||||||
$("#topic-bottom").offset().top - $("#main-outlet").offset().top;
|
|
||||||
const timeline = this.element.querySelector(".timeline-container");
|
const timeline = this.element.querySelector(".timeline-container");
|
||||||
const timelineHeight = (timeline && timeline.offsetHeight) || 400;
|
const timelineHeight = (timeline && timeline.offsetHeight) || 400;
|
||||||
const footerHeight = $(".timeline-footer-controls").outerHeight(true) || 0;
|
|
||||||
|
|
||||||
const prev = this.dockAt;
|
const prev = this.dockAt;
|
||||||
const posTop = headerPadding() + info.offset();
|
const posTop = this.headerOffset() + window.pageYOffset;
|
||||||
const pos = posTop + timelineHeight - outletHeights();
|
const pos = posTop + timelineHeight;
|
||||||
|
|
||||||
this.dockBottom = false;
|
this.dockBottom = false;
|
||||||
if (posTop < topicTop) {
|
if (posTop < this.topicTop) {
|
||||||
this.dockAt = parseInt(topicTop, 10);
|
this.dockAt = parseInt(this.topicTop, 10);
|
||||||
} else if (pos > topicBottom + footerHeight) {
|
} else if (pos > this.topicBottom) {
|
||||||
this.dockAt = parseInt(
|
this.dockAt = parseInt(this.topicBottom - timelineHeight, 10);
|
||||||
topicBottom - timelineHeight + footerHeight + outletHeights(),
|
|
||||||
10
|
|
||||||
);
|
|
||||||
this.dockBottom = true;
|
this.dockBottom = true;
|
||||||
if (this.dockAt < 0) {
|
if (this.dockAt < 0) {
|
||||||
this.dockAt = 0;
|
this.dockAt = 0;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
this.dockAt = null;
|
this.dockAt = null;
|
||||||
this.fastDockAt = parseInt(
|
this.fastDockAt = parseInt(this.topicBottom - timelineHeight, 10);
|
||||||
topicBottom - timelineHeight + footerHeight - offsetTop,
|
|
||||||
10
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.dockAt !== prev) {
|
if (this.dockAt !== prev) {
|
||||||
@@ -95,6 +72,12 @@ export default MountWidget.extend(Docking, {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
headerOffset() {
|
||||||
|
return (
|
||||||
|
parseInt(document.body.style.getPropertyValue("--header-offset"), 10) || 0
|
||||||
|
);
|
||||||
|
},
|
||||||
|
|
||||||
didInsertElement() {
|
didInsertElement() {
|
||||||
this._super(...arguments);
|
this._super(...arguments);
|
||||||
|
|
||||||
@@ -114,6 +97,28 @@ export default MountWidget.extend(Docking, {
|
|||||||
this.appEvents.on("composer:opened", this, this.queueRerender);
|
this.appEvents.on("composer:opened", this, this.queueRerender);
|
||||||
this.appEvents.on("composer:resized", this, this.queueRerender);
|
this.appEvents.on("composer:resized", this, this.queueRerender);
|
||||||
this.appEvents.on("composer:closed", this, this.queueRerender);
|
this.appEvents.on("composer:closed", this, this.queueRerender);
|
||||||
|
if ("IntersectionObserver" in window) {
|
||||||
|
this.intersectionObserver = new IntersectionObserver((entries) => {
|
||||||
|
for (const entry of entries) {
|
||||||
|
const bounds = entry.boundingClientRect;
|
||||||
|
|
||||||
|
if (entry.target.id === "topic-bottom") {
|
||||||
|
this.set("topicBottom", bounds.y + window.scrollY);
|
||||||
|
} else {
|
||||||
|
this.set("topicTop", bounds.y + window.scrollY);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const elements = [
|
||||||
|
document.querySelector(".container.posts"),
|
||||||
|
document.querySelector("#topic-bottom"),
|
||||||
|
];
|
||||||
|
|
||||||
|
for (let i = 0; i < elements.length; i++) {
|
||||||
|
this.intersectionObserver.observe(elements[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -124,6 +129,10 @@ export default MountWidget.extend(Docking, {
|
|||||||
this.appEvents.off("composer:opened", this, this.queueRerender);
|
this.appEvents.off("composer:opened", this, this.queueRerender);
|
||||||
this.appEvents.off("composer:resized", this, this.queueRerender);
|
this.appEvents.off("composer:resized", this, this.queueRerender);
|
||||||
this.appEvents.off("composer:closed", this, this.queueRerender);
|
this.appEvents.off("composer:closed", this, this.queueRerender);
|
||||||
|
if ("IntersectionObserver" in window) {
|
||||||
|
this.intersectionObserver?.disconnect();
|
||||||
|
this.intersectionObserver = null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,22 +0,0 @@
|
|||||||
export default function () {
|
|
||||||
const outletSelector = [
|
|
||||||
".above-site-header-outlet",
|
|
||||||
".below-site-header-outlet",
|
|
||||||
];
|
|
||||||
// If these outlets have height they impact timeline and usercard positioning
|
|
||||||
|
|
||||||
let outletHeights = 0;
|
|
||||||
|
|
||||||
outletSelector.forEach(function (outletClass) {
|
|
||||||
if (document.querySelector(outletClass)) {
|
|
||||||
let outlets = document.querySelectorAll(outletClass);
|
|
||||||
outlets.forEach((outlet) => {
|
|
||||||
if (outlet.offsetHeight) {
|
|
||||||
outletHeights += parseInt(outlet.offsetHeight, 10);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return outletHeights;
|
|
||||||
}
|
|
||||||
@@ -79,10 +79,8 @@ export default class StickyAvatars {
|
|||||||
_initIntersectionObserver() {
|
_initIntersectionObserver() {
|
||||||
schedule("afterRender", () => {
|
schedule("afterRender", () => {
|
||||||
const headerOffset =
|
const headerOffset =
|
||||||
parseInt(
|
parseInt(document.body.style.getPropertyValue("--header-offset"), 10) ||
|
||||||
getComputedStyle(document.body).getPropertyValue("--header-offset"),
|
0;
|
||||||
10
|
|
||||||
) || 0;
|
|
||||||
const headerHeight = Math.max(headerOffset, 0);
|
const headerHeight = Math.max(headerOffset, 0);
|
||||||
|
|
||||||
this.intersectionObserver = new IntersectionObserver(
|
this.intersectionObserver = new IntersectionObserver(
|
||||||
|
|||||||
@@ -2,14 +2,6 @@ import Mixin from "@ember/object/mixin";
|
|||||||
import discourseDebounce from "discourse-common/lib/debounce";
|
import discourseDebounce from "discourse-common/lib/debounce";
|
||||||
import { cancel, later } from "@ember/runloop";
|
import { cancel, later } from "@ember/runloop";
|
||||||
|
|
||||||
const helper = {
|
|
||||||
offset() {
|
|
||||||
const main = document.querySelector("#main");
|
|
||||||
const offsetTop = main ? main.offsetTop : 0;
|
|
||||||
return window.pageYOffset - offsetTop;
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
export default Mixin.create({
|
export default Mixin.create({
|
||||||
queueDockCheck: null,
|
queueDockCheck: null,
|
||||||
_initialTimer: null,
|
_initialTimer: null,
|
||||||
@@ -26,7 +18,7 @@ export default Mixin.create({
|
|||||||
if (this.isDestroyed || this.isDestroying) {
|
if (this.isDestroyed || this.isDestroying) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.dockCheck(helper);
|
this.dockCheck();
|
||||||
},
|
},
|
||||||
|
|
||||||
didInsertElement() {
|
didInsertElement() {
|
||||||
|
|||||||
@@ -6,10 +6,10 @@
|
|||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
z-index: z("timeline");
|
z-index: z("timeline");
|
||||||
-webkit-transform: translate3d(0, 0, 0);
|
-webkit-transform: translate3d(0, 0, 0);
|
||||||
transition: margin-bottom 0.25s ease-in;
|
|
||||||
&.timeline-docked-bottom {
|
&.timeline-docked-bottom {
|
||||||
|
margin-bottom: -4em;
|
||||||
@media screen and (prefers-reduced-motion: no-preference) {
|
@media screen and (prefers-reduced-motion: no-preference) {
|
||||||
margin-bottom: -1.75em; // animate out footer button height
|
transition: margin-bottom 0.5s ease-in;
|
||||||
}
|
}
|
||||||
.timeline-footer-controls {
|
.timeline-footer-controls {
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
@@ -187,7 +187,9 @@
|
|||||||
|
|
||||||
.timeline-footer-controls {
|
.timeline-footer-controls {
|
||||||
margin-top: 1.5em;
|
margin-top: 1.5em;
|
||||||
transition: opacity 0.2s ease-in;
|
@media (prefers-reduced-motion: no-preference) {
|
||||||
|
transition: opacity 0.2s ease-in;
|
||||||
|
}
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
max-width: 9em;
|
max-width: 9em;
|
||||||
|
|||||||
Reference in New Issue
Block a user