diff --git a/src/web/app/desktop/scripts/scroll-follower.ts b/src/web/app/desktop/scripts/scroll-follower.ts new file mode 100644 index 0000000000..e99f125cc0 --- /dev/null +++ b/src/web/app/desktop/scripts/scroll-follower.ts @@ -0,0 +1,57 @@ +/** + * 要素をスクロールに追従させる + */ +export default class ScrollFollower { + private follower: Element; + private containerTop: number; + private topPadding: number; + + constructor(follower: Element, topPadding: number) { + //#region + this.follow = this.follow.bind(this); + //#endregion + + this.follower = follower; + this.containerTop = follower.getBoundingClientRect().top; + this.topPadding = topPadding; + + window.addEventListener('scroll', this.follow); + window.addEventListener('resize', this.follow); + } + + /** + * 追従解除 + */ + public dispose() { + window.removeEventListener('scroll', this.follow); + window.removeEventListener('resize', this.follow); + } + + private follow() { + const windowBottom = window.scrollY + window.innerHeight; + const windowTop = window.scrollY + this.topPadding; + + const rect = this.follower.getBoundingClientRect(); + //const followerHeight = rect.height + this.containerTop; + const followerBottom = (rect.top + window.scrollY) + rect.height; + + // スクロールの上部(+余白)がフォロワーコンテナの上部よりも上方にある + if (window.scrollY + this.topPadding < this.containerTop) { + // フォロワーをコンテナの最上部に合わせる + (this.follower.parentNode as any).style.marginTop = '0px'; + return; + } + + // スクロールの下部がフォロワーの下部よりも下方にある かつ 表示領域の縦幅がフォロワーの縦幅よりも狭い + if (windowBottom > followerBottom && rect.height > (window.innerHeight - this.topPadding)) { + // フォロワーの下部をスクロール下部に合わせる + const top = (windowBottom - rect.height) - this.containerTop; + (this.follower.parentNode as any).style.marginTop = `${top}px`; + // スクロールの上部(+余白)がフォロワーの上部よりも上方にある または 表示領域の縦幅がフォロワーの縦幅よりも広い + } else if ((windowTop < rect.top + window.scrollY || rect.height < (window.innerHeight - this.topPadding))) { + // フォロワーの上部をスクロール上部(+余白)に合わせる + const top = windowTop - this.containerTop; + (this.follower.parentNode as any).style.marginTop = `${top}px`; + } + } +} diff --git a/src/web/app/desktop/tags/home.tag b/src/web/app/desktop/tags/home.tag index 92f91c0848..a2a372a0e1 100644 --- a/src/web/app/desktop/tags/home.tag +++ b/src/web/app/desktop/tags/home.tag @@ -184,6 +184,7 @@ import uuid from 'uuid'; import Sortable from 'sortablejs'; import dialog from '../scripts/dialog'; + import ScrollFollower from '../scripts/scroll-follower'; this.mixin('i'); this.mixin('api'); @@ -242,11 +243,8 @@ } if (!this.opts.customize) { - this.containerTop = this.refs.main.getBoundingClientRect().top; - this.headerHight = this.root.getBoundingClientRect().top; - - window.addEventListener('scroll', this.followWidgets); - window.addEventListener('resize', this.followWidgets); + this.scrollFollowerLeft = new ScrollFollower(this.refs.left, this.root.getBoundingClientRect().top); + this.scrollFollowerRight = new ScrollFollower(this.refs.right, this.root.getBoundingClientRect().top); } }); @@ -256,8 +254,8 @@ }); if (!this.opts.customize) { - window.removeEventListener('scroll', this.followWidgets); - window.removeEventListener('resize', this.followWidgets); + this.scrollFollowerLeft.dispose(); + this.scrollFollowerRight.dispose(); } }); diff --git a/src/web/app/desktop/tags/user.tag b/src/web/app/desktop/tags/user.tag index d944bb33a7..333dd11a0d 100644 --- a/src/web/app/desktop/tags/user.tag +++ b/src/web/app/desktop/tags/user.tag @@ -607,20 +607,24 @@
- - - -

%i18n:desktop.tags.mk-user.last-used-at%:

+
+ + + +

%i18n:desktop.tags.mk-user.last-used-at%:

+
- - - - +
+ + + + +