いい感じに
This commit is contained in:
parent
6ed694a3f5
commit
fda4003ba4
57
src/web/app/desktop/scripts/scroll-follower.ts
Normal file
57
src/web/app/desktop/scripts/scroll-follower.ts
Normal file
@ -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`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -184,6 +184,7 @@
|
|||||||
import uuid from 'uuid';
|
import uuid from 'uuid';
|
||||||
import Sortable from 'sortablejs';
|
import Sortable from 'sortablejs';
|
||||||
import dialog from '../scripts/dialog';
|
import dialog from '../scripts/dialog';
|
||||||
|
import ScrollFollower from '../scripts/scroll-follower';
|
||||||
|
|
||||||
this.mixin('i');
|
this.mixin('i');
|
||||||
this.mixin('api');
|
this.mixin('api');
|
||||||
@ -242,11 +243,8 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!this.opts.customize) {
|
if (!this.opts.customize) {
|
||||||
this.containerTop = this.refs.main.getBoundingClientRect().top;
|
this.scrollFollowerLeft = new ScrollFollower(this.refs.left, this.root.getBoundingClientRect().top);
|
||||||
this.headerHight = this.root.getBoundingClientRect().top;
|
this.scrollFollowerRight = new ScrollFollower(this.refs.right, this.root.getBoundingClientRect().top);
|
||||||
|
|
||||||
window.addEventListener('scroll', this.followWidgets);
|
|
||||||
window.addEventListener('resize', this.followWidgets);
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -256,8 +254,8 @@
|
|||||||
});
|
});
|
||||||
|
|
||||||
if (!this.opts.customize) {
|
if (!this.opts.customize) {
|
||||||
window.removeEventListener('scroll', this.followWidgets);
|
this.scrollFollowerLeft.dispose();
|
||||||
window.removeEventListener('resize', this.followWidgets);
|
this.scrollFollowerRight.dispose();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -607,21 +607,25 @@
|
|||||||
|
|
||||||
<mk-user-home>
|
<mk-user-home>
|
||||||
<div>
|
<div>
|
||||||
|
<div ref="left">
|
||||||
<mk-user-profile user={ user }/>
|
<mk-user-profile user={ user }/>
|
||||||
<mk-user-photos user={ user }/>
|
<mk-user-photos user={ user }/>
|
||||||
<mk-user-followers-you-know if={ SIGNIN && I.id !== user.id } user={ user }/>
|
<mk-user-followers-you-know if={ SIGNIN && I.id !== user.id } user={ user }/>
|
||||||
<p>%i18n:desktop.tags.mk-user.last-used-at%: <b><mk-time time={ user.last_used_at }/></b></p>
|
<p>%i18n:desktop.tags.mk-user.last-used-at%: <b><mk-time time={ user.last_used_at }/></b></p>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
<main>
|
<main>
|
||||||
<mk-post-detail if={ user.pinned_post } post={ user.pinned_post } compact={ true }/>
|
<mk-post-detail if={ user.pinned_post } post={ user.pinned_post } compact={ true }/>
|
||||||
<mk-user-timeline ref="tl" user={ user }/>
|
<mk-user-timeline ref="tl" user={ user }/>
|
||||||
</main>
|
</main>
|
||||||
<div>
|
<div>
|
||||||
|
<div ref="right">
|
||||||
<mk-calendar-widget warp={ warp } start={ new Date(user.created_at) }/>
|
<mk-calendar-widget warp={ warp } start={ new Date(user.created_at) }/>
|
||||||
<mk-activity-widget user={ user }/>
|
<mk-activity-widget user={ user }/>
|
||||||
<mk-user-frequently-replied-users user={ user }/>
|
<mk-user-frequently-replied-users user={ user }/>
|
||||||
<div class="nav"><mk-nav-links/></div>
|
<div class="nav"><mk-nav-links/></div>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
<style>
|
<style>
|
||||||
:scope
|
:scope
|
||||||
display flex
|
display flex
|
||||||
@ -629,7 +633,8 @@
|
|||||||
margin 0 auto
|
margin 0 auto
|
||||||
max-width 1200px
|
max-width 1200px
|
||||||
|
|
||||||
> *
|
> main
|
||||||
|
> div > div
|
||||||
> *:not(:last-child)
|
> *:not(:last-child)
|
||||||
margin-bottom 16px
|
margin-bottom 16px
|
||||||
|
|
||||||
@ -645,7 +650,7 @@
|
|||||||
width 275px
|
width 275px
|
||||||
margin 0
|
margin 0
|
||||||
|
|
||||||
&:first-child
|
&:first-child > div
|
||||||
padding 16px 0 16px 16px
|
padding 16px 0 16px 16px
|
||||||
|
|
||||||
> p
|
> p
|
||||||
@ -656,7 +661,7 @@
|
|||||||
font-size 0.8em
|
font-size 0.8em
|
||||||
color #aaa
|
color #aaa
|
||||||
|
|
||||||
&:last-child
|
&:last-child > div
|
||||||
padding 16px 16px 16px 0
|
padding 16px 16px 16px 0
|
||||||
|
|
||||||
> .nav
|
> .nav
|
||||||
@ -675,6 +680,8 @@
|
|||||||
|
|
||||||
</style>
|
</style>
|
||||||
<script>
|
<script>
|
||||||
|
import ScrollFollower from '../scripts/scroll-follower';
|
||||||
|
|
||||||
this.mixin('i');
|
this.mixin('i');
|
||||||
|
|
||||||
this.user = this.opts.user;
|
this.user = this.opts.user;
|
||||||
@ -683,6 +690,14 @@
|
|||||||
this.refs.tl.on('loaded', () => {
|
this.refs.tl.on('loaded', () => {
|
||||||
this.trigger('loaded');
|
this.trigger('loaded');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
this.scrollFollowerLeft = new ScrollFollower(this.refs.left, this.parent.root.getBoundingClientRect().top);
|
||||||
|
this.scrollFollowerRight = new ScrollFollower(this.refs.right, this.parent.root.getBoundingClientRect().top);
|
||||||
|
});
|
||||||
|
|
||||||
|
this.on('unmount', () => {
|
||||||
|
this.scrollFollowerLeft.dispose();
|
||||||
|
this.scrollFollowerRight.dispose();
|
||||||
});
|
});
|
||||||
|
|
||||||
this.warp = date => {
|
this.warp = date => {
|
||||||
|
Loading…
Reference in New Issue
Block a user