1
1
<script lang="ts" setup>
2
- import { computed , watch } from ' vue' ;
2
+ import { computed , ref , watch } from ' vue' ;
3
+
4
+ import type {
5
+ VirtualListRef ,
6
+ VirtualListScrollToOptions ,
7
+ } from ' ~/components/common/list/ListScroll.model' ;
3
8
4
9
import FloatingButton from ' ~/components/common/buttons/FloatingButton.vue' ;
5
- import { useBackToTop } from ' ~/components/common/buttons/use-back-to-top' ;
6
10
import ListScroll from ' ~/components/common/list/ListScroll.vue' ;
7
11
import { useListScroll } from ' ~/components/common/list/use-list-scroll' ;
12
+ import IconChevronDown from ' ~/components/icons/IconChevronDown.vue' ;
13
+ import IconChevronUp from ' ~/components/icons/IconChevronUp.vue' ;
14
+
8
15
import { useCalendarStore , useCalendarStoreRefs } from ' ~/stores/data/calendar.store' ;
9
16
import { useI18n } from ' ~/utils' ;
10
17
import { watchUserChange } from ' ~/utils/store.utils' ;
@@ -16,28 +23,29 @@ const { fetchCalendar, clearState } = useCalendarStore();
16
23
17
24
const list = useListScroll (calendar , ' date' );
18
25
19
- const { scrolled, listRef, onClick } = useBackToTop ();
20
-
21
26
const today = computed (() => {
22
27
return list .value .find (
23
28
item => item .date ?.current .toLocaleDateString () === new Date ().toLocaleDateString (),
24
29
);
25
30
});
26
31
27
- watchUserChange ({
28
- mounted : () => {
29
- const unsub = watch (today , async () => {
30
- if (! today .value ) return ;
31
-
32
- const _listRef = listRef .value ?.list ;
33
- if (! _listRef ) return ;
32
+ const listRef = ref <{ list: VirtualListRef }>();
34
33
35
- await _listRef .$nextTick ();
34
+ const scrollToToday = (options ? : VirtualListScrollToOptions ) => {
35
+ if (! today .value ) return ;
36
+ if (! listRef .value ?.list ) return ;
36
37
37
- _listRef .scrollTo ({
38
- top: today .value .index * 145 ,
39
- });
38
+ listRef .value ?.list .scrollTo ({
39
+ top: today .value .index * 145 ,
40
+ ... options ,
41
+ });
42
+ };
40
43
44
+ watchUserChange ({
45
+ mounted : () => {
46
+ const unsub = watch (today , async () => {
47
+ await listRef .value ?.list .$nextTick ();
48
+ scrollToToday ();
41
49
unsub ();
42
50
});
43
51
},
@@ -47,6 +55,18 @@ watchUserChange({
47
55
if (active ) fetchCalendar ();
48
56
},
49
57
});
58
+
59
+ const scrolledOut = ref (false );
60
+ const scrolledDown = ref (true );
61
+ const onClick = () => scrollToToday ({ behavior: ' smooth' });
62
+ const onScrollIntoOutOfView = (_scrolled : boolean , _itemRef ? : HTMLDivElement ) => {
63
+ scrolledOut .value = _scrolled ;
64
+ if (! _scrolled || ! _itemRef ) return ;
65
+ scrolledDown .value = _itemRef .getBoundingClientRect ().top > 0 ;
66
+ };
67
+ const recenterIcon = computed (() =>
68
+ scrolledDown .value ? IconChevronDown : IconChevronUp ,
69
+ );
50
70
</script >
51
71
52
72
<template >
@@ -57,15 +77,21 @@ watchUserChange({
57
77
:loading =" loading"
58
78
:scroll-threshold =" 300"
59
79
episode
60
- @on-scroll =" scrolled = true"
61
- @on-scroll-top =" scrolled = false"
80
+ :scroll-into-view =" today?.id ? [today?.id] : []"
81
+ @on-scroll-into-view =" e => onScrollIntoOutOfView(false, e.ref)"
82
+ @on-scroll-out-of-view =" e => onScrollIntoOutOfView(true, e.ref)"
62
83
>
63
84
<template #default >
64
85
<!-- TODO buttons here-->
65
86
</template >
66
87
</ListScroll >
67
- <FloatingButton :show =" scrolled" @on-click =" onClick" >
68
- {{ i18n('back_to_top', 'common', 'button') }}
88
+ <FloatingButton
89
+ :show =" scrolledOut"
90
+ width =" 2.5rem"
91
+ :icon =" recenterIcon"
92
+ @on-click =" onClick"
93
+ >
94
+ {{ i18n('recenter', 'common', 'button') }}
69
95
</FloatingButton >
70
96
</div >
71
97
</template >
0 commit comments