From 132e802d5d27cb6e90ce0f231060c4206f10e501 Mon Sep 17 00:00:00 2001
From: Isaac Janzen <50783505+janzenisaac@users.noreply.github.com>
Date: Fri, 3 Feb 2023 12:01:59 -0600
Subject: [PATCH] DEV: Dock glimmer-topic-timeline with animation (#20166)
- Move docking logic (intersection / dockAt / etc) from `glimmer-topic-timeline` -> `topic-timeline/container` to live alongside the `postScrolled` hook.
- Toggle `timeline-docked` and `timeline-docked-bottom` when we are at the bottom of a topic. This returns the missing animation to the glimmer-topic-timeline (pictured below).
https://user-images.githubusercontent.com/50783505/216655735-906ccd2a-b77e-45af-9a7b-c22680eca2dc.mov
---
.../app/components/glimmer-topic-timeline.hbs | 5 +-
.../app/components/glimmer-topic-timeline.js | 57 ++++++-----------
.../components/topic-timeline/container.hbs | 6 +-
.../components/topic-timeline/container.js | 64 +++++++++++++++++++
4 files changed, 90 insertions(+), 42 deletions(-)
diff --git a/app/assets/javascripts/discourse/app/components/glimmer-topic-timeline.hbs b/app/assets/javascripts/discourse/app/components/glimmer-topic-timeline.hbs
index 73a6033b532..0125a149ebf 100644
--- a/app/assets/javascripts/discourse/app/components/glimmer-topic-timeline.hbs
+++ b/app/assets/javascripts/discourse/app/components/glimmer-topic-timeline.hbs
@@ -1,5 +1,5 @@
@@ -13,7 +13,6 @@
@jumpToPostPrompt={{@jumpToPostPrompt}}
@fullscreen={{@fullscreen}}
@mobileView={{@mobileView}}
- @currentUser={{this.currentUser}}
@toggleMultiSelect={{@toggleMultiSelect}}
@showTopicSlowModeUpdate={{@showTopicSlowModeUpdate}}
@deleteTopic={{@deleteTopic}}
@@ -28,6 +27,8 @@
@convertToPublicTopic={{@convertToPublicTopic}}
@convertToPrivateMessage={{@convertToPrivateMessage}}
@replyToPost={{@replyToPost}}
+ @setDocked={{this.setDocked}}
+ @setDockedBottom={{this.setDockedBottom}}
/>
\ No newline at end of file
diff --git a/app/assets/javascripts/discourse/app/components/glimmer-topic-timeline.js b/app/assets/javascripts/discourse/app/components/glimmer-topic-timeline.js
index ef7b0b592aa..5725c18ee8b 100644
--- a/app/assets/javascripts/discourse/app/components/glimmer-topic-timeline.js
+++ b/app/assets/javascripts/discourse/app/components/glimmer-topic-timeline.js
@@ -4,18 +4,17 @@ import optionalService from "discourse/lib/optional-service";
import { inject as service } from "@ember/service";
import { bind } from "discourse-common/utils/decorators";
import I18n from "I18n";
+import { action } from "@ember/object";
export default class GlimmerTopicTimeline extends Component {
- @service site;
@service siteSettings;
@service currentUser;
- @tracked dockAt = null;
- @tracked dockBottom = null;
@tracked enteredIndex = this.args.enteredIndex;
+ @tracked docked = false;
+ @tracked dockedBottom = false;
adminTools = optionalService();
- intersectionObserver = null;
constructor() {
super(...arguments);
@@ -23,29 +22,6 @@ export default class GlimmerTopicTimeline extends Component {
if (this.args.prevEvent) {
this.enteredIndex = this.args.prevEvent.postIndex - 1;
}
-
- if (!this.site.mobileView) {
- this.intersectionObserver = new IntersectionObserver((entries) => {
- for (const entry of entries) {
- const bounds = entry.boundingClientRect;
-
- if (entry.target.id === "topic-bottom") {
- this.topicBottom = bounds.y + window.scrollY;
- } else {
- this.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]);
- }
- }
}
get displaySummary() {
@@ -57,15 +33,19 @@ export default class GlimmerTopicTimeline extends Component {
);
}
+ get createdAt() {
+ return new Date(this.args.model.created_at);
+ }
+
get classes() {
const classes = [];
if (this.args.fullscreen) {
classes.push("timeline-fullscreen");
}
- if (this.dockAt) {
+ if (this.docked) {
classes.push("timeline-docked");
- if (this.dockBottom) {
+ if (this.dockedBottom) {
classes.push("timeline-docked-bottom");
}
}
@@ -73,10 +53,6 @@ export default class GlimmerTopicTimeline extends Component {
return classes.join(" ");
}
- get createdAt() {
- return new Date(this.args.model.created_at);
- }
-
@bind
addShowClass(element) {
if (this.args.fullscreen && !this.args.addShowClass) {
@@ -96,10 +72,17 @@ export default class GlimmerTopicTimeline extends Component {
});
}
- willDestroy() {
- if (!this.site.mobileView) {
- this.intersectionObserver?.disconnect();
- this.intersectionObserver = null;
+ @action
+ setDocked(value) {
+ if (this.docked !== value) {
+ this.docked = value;
+ }
+ }
+
+ @action
+ setDockedBottom(value) {
+ if (this.dockedBottom !== value) {
+ this.dockedBottom = value;
}
}
}
diff --git a/app/assets/javascripts/discourse/app/components/topic-timeline/container.hbs b/app/assets/javascripts/discourse/app/components/topic-timeline/container.hbs
index 59371e84be7..c97cc815d81 100644
--- a/app/assets/javascripts/discourse/app/components/topic-timeline/container.hbs
+++ b/app/assets/javascripts/discourse/app/components/topic-timeline/container.hbs
@@ -34,7 +34,7 @@
{{/if}}
-{{#if (and (not @fullscreen) @currentUser)}}
+{{#if (and (not @fullscreen) this.currentUser)}}
{{/if}}
- {{#if (and @currentUser (not @fullscreen))}}
+ {{#if (and this.currentUser (not @fullscreen))}}
{{#if this.canCreatePost}}
{{/if}}
- {{#if @currentUser}}
+ {{#if this.currentUser}}
{
+ for (const entry of entries) {
+ const bounds = entry.boundingClientRect;
+
+ if (entry.target.id === "topic-bottom") {
+ this.topicBottom = bounds.y + window.scrollY;
+ } else {
+ this.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]);
+ }
+
this.calculatePosition();
+ this.dockCheck();
}
get displayTimeLineScrollArea() {
@@ -269,6 +295,7 @@ export default class TopicTimelineScrollArea extends Component {
this.current = e.postIndex;
this.percentage = e.percent;
this.calculatePosition();
+ this.dockCheck();
}
@action
@@ -276,6 +303,40 @@ export default class TopicTimelineScrollArea extends Component {
this.args.jumpToIndex(this.lastRead);
}
+ dockCheck() {
+ const timeline = document.querySelector(".timeline-container");
+ const timelineHeight = (timeline && timeline.offsetHeight) || 400;
+
+ const prevDockAt = this.dockAt;
+ const positionTop = headerOffset() + window.pageYOffset;
+ const currentPosition = positionTop + timelineHeight;
+
+ this.dockBottom = false;
+ if (positionTop < this.topicTop) {
+ this.dockAt = parseInt(this.topicTop, 10);
+ } else if (currentPosition > this.topicBottom) {
+ this.dockAt = parseInt(this.topicBottom - timelineHeight, 10);
+ this.dockBottom = true;
+ if (this.dockAt < 0) {
+ this.dockAt = 0;
+ }
+ } else {
+ this.dockAt = null;
+ }
+
+ if (this.dockAt !== prevDockAt) {
+ if (this.dockAt) {
+ this.args.setDocked(true);
+ if (this.dockBottom) {
+ this.args.setDockedBottom(true);
+ }
+ } else {
+ this.args.setDocked(false);
+ this.args.setDockedBottom(false);
+ }
+ }
+ }
+
commit() {
this.calculatePosition();
@@ -298,6 +359,9 @@ export default class TopicTimelineScrollArea extends Component {
willDestroy() {
if (!this.args.mobileView) {
+ this.intersectionObserver?.disconnect();
+ this.intersectionObserver = null;
+
this.appEvents.off("composer:opened", this.calculatePosition);
this.appEvents.off("composer:resized", this.calculatePosition);
this.appEvents.off("composer:closed", this.calculatePosition);