Skip to content

Commit 9a2fa00

Browse files
Add route change loading bar
1 parent 18f698d commit 9a2fa00

File tree

4 files changed

+121
-1
lines changed

4 files changed

+121
-1
lines changed

packages/app/features/home/layout.web.tsx

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
1-
import { Container, ScrollView, type ScrollViewProps, YStack } from '@my/ui'
1+
import { Container, ScrollView, type ScrollViewProps, YStack, PendingIndicatorBar } from '@my/ui'
22
import { HomeSideBarWrapper } from 'app/components/sidebar/HomeSideBar'
33
import { TagSearchProvider } from 'app/provider/tag-search'
44
import { useScrollDirection } from 'app/provider/scroll'
55
import { BOTTOM_NAV_BAR_HEIGHT } from 'app/components/BottomTabBar/BottomNavBar'
66
import { BottomNavBarWrapper } from 'app/components/BottomTabBar/BottomNavBarWrapper'
7+
import { useRouteChange } from 'app/routers/useRouteChange.web'
78

89
export function HomeLayout({
910
children,
@@ -15,11 +16,13 @@ export function HomeLayout({
1516
TopNav?: React.ReactNode
1617
} & ScrollViewProps & { fullHeight?: boolean }) {
1718
const { onScroll, onContentSizeChange, ref } = useScrollDirection()
19+
const isPending = useRouteChange()
1820

1921
return (
2022
<HomeSideBarWrapper>
2123
<BottomNavBarWrapper>
2224
<TagSearchProvider>
25+
<PendingIndicatorBar pending={isPending} />
2326
<ScrollView
2427
ref={ref}
2528
mih="100%"
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import { useRouter } from 'next/router'
2+
import { useEffect, useState } from 'react'
3+
4+
export const useRouteChange = () => {
5+
const router = useRouter()
6+
const [isRouteChanging, setIsRouteChanging] = useState(false)
7+
8+
useEffect(() => {
9+
const handleStart = () => {
10+
setIsRouteChanging(true)
11+
}
12+
13+
const handleComplete = () => {
14+
setIsRouteChanging(false)
15+
}
16+
17+
router.events.on('routeChangeStart', handleStart)
18+
router.events.on('routeChangeComplete', handleComplete)
19+
router.events.on('routeChangeError', handleComplete)
20+
21+
return () => {
22+
router.events.off('routeChangeStart', handleStart)
23+
router.events.off('routeChangeComplete', handleComplete)
24+
router.events.off('routeChangeError', handleComplete)
25+
}
26+
}, [router])
27+
28+
return isRouteChanging
29+
}
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
import { useEffect, useState } from 'react'
2+
import { Stack } from 'tamagui'
3+
4+
const getTimeout = (progress: number): number => {
5+
if (progress < 0.7) {
6+
return 0
7+
}
8+
if (progress < 0.8) {
9+
return 800
10+
}
11+
if (progress < 0.95) {
12+
return 1000
13+
}
14+
return 1500
15+
}
16+
17+
const LoadingBar = ({ visible }: { visible: boolean }) => {
18+
const [render, setRender] = useState(visible)
19+
const [progress, setProgress] = useState(0)
20+
21+
const translate = 100 - progress * 100
22+
23+
useEffect(() => {
24+
if (render) {
25+
const timeoutId = setTimeout(() => {
26+
setProgress((currentProgress) => {
27+
if (currentProgress < 0.7) {
28+
return currentProgress + 0.7
29+
}
30+
if (currentProgress < 0.8) {
31+
return currentProgress + 0.05
32+
}
33+
if (currentProgress < 0.95) {
34+
return currentProgress + 0.025
35+
}
36+
return currentProgress + 0.005
37+
})
38+
}, getTimeout(progress))
39+
return () => clearTimeout(timeoutId)
40+
}
41+
}, [progress, render])
42+
43+
useEffect(() => {
44+
if (!visible) {
45+
const renderTimeoutId = setTimeout(() => {
46+
setRender(false)
47+
}, 200)
48+
const progressTimeoutId = setTimeout(() => {
49+
setProgress(0)
50+
}, 500)
51+
52+
setProgress(1)
53+
return () => {
54+
clearTimeout(renderTimeoutId)
55+
clearTimeout(progressTimeoutId)
56+
}
57+
}
58+
59+
const timeoutId = setTimeout(() => {
60+
setProgress(0)
61+
setRender(true)
62+
}, 300)
63+
64+
return () => clearTimeout(timeoutId)
65+
}, [visible])
66+
67+
return (
68+
<Stack w="100%" h="$0.5" overflow="hidden" position="relative">
69+
<Stack
70+
position="absolute"
71+
top={0}
72+
left={0}
73+
bottom={0}
74+
width="100%"
75+
bc="$primary"
76+
opacity={!render || (render && progress === 0) ? 0 : 1}
77+
style={{ transform: `translateX(-${translate}%)` }}
78+
/>
79+
</Stack>
80+
)
81+
}
82+
83+
export const PendingIndicatorBar = ({ pending }: { pending: boolean }) => (
84+
<Stack position="absolute" left={0} top={0} w="100%" pointerEvents="none" zIndex={20}>
85+
<LoadingBar visible={pending} />
86+
</Stack>
87+
)

packages/ui/src/components/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,3 +20,4 @@ export * from './SafeArea'
2020
export * from './FadeCard'
2121
export * from './LinkBanner'
2222
export { RecyclerList } from './RecyclerList.web'
23+
export * from './PendingIndicatorBar'

0 commit comments

Comments
 (0)