forked from
jollywhoppers.com/witchsky.app
Bluesky app fork with some witchin' additions 馃挮
1import {StyleSheet} from 'react-native'
2import Animated from 'react-native-reanimated'
3import {useSafeAreaInsets} from 'react-native-safe-area-context'
4import {useMediaQuery} from 'react-responsive'
5
6import {HITSLOP_20} from '#/lib/constants'
7import {PressableScale} from '#/lib/custom-animations/PressableScale'
8import {useMinimalShellFabTransform} from '#/lib/hooks/useMinimalShellTransform'
9import {useWebMediaQueries} from '#/lib/hooks/useWebMediaQueries'
10import {clamp} from '#/lib/numbers'
11import {useDisableTopOfFeedButton} from '#/state/preferences/disable-top-of-feed-button'
12import {useEnableSquareButtons} from '#/state/preferences/enable-square-buttons'
13import {useSession} from '#/state/session'
14import {atoms as a, useLayoutBreakpoints, useTheme, web} from '#/alf'
15import {useInteractionState} from '#/components/hooks/useInteractionState'
16import {ArrowTop_Stroke2_Corner0_Rounded as ArrowIcon} from '#/components/icons/Arrow'
17import {CENTER_COLUMN_OFFSET} from '#/components/Layout'
18import {SubtleHover} from '#/components/SubtleHover'
19
20export function LoadLatestBtn({
21 onPress,
22 label,
23 showIndicator,
24}: {
25 onPress: () => void
26 label: string
27 showIndicator: boolean
28}) {
29 const {hasSession} = useSession()
30 const {isDesktop, isTablet, isMobile, isTabletOrMobile} = useWebMediaQueries()
31 const {centerColumnOffset} = useLayoutBreakpoints()
32 const fabMinimalShellTransform = useMinimalShellFabTransform()
33 const insets = useSafeAreaInsets()
34 const t = useTheme()
35 const disableTopOfFeedButton = useDisableTopOfFeedButton()
36 const enableSquareButtons = useEnableSquareButtons()
37 const {
38 state: hovered,
39 onIn: onHoverIn,
40 onOut: onHoverOut,
41 } = useInteractionState()
42
43 // move button inline if it starts overlapping the left nav
44 const isTallViewport = useMediaQuery({minHeight: 700})
45
46 // Adjust height of the fab if we have a session only on mobile web. If we don't have a session, we want to adjust
47 // it on both tablet and mobile since we are showing the bottom bar (see createNativeStackNavigatorWithAuth)
48 const showBottomBar = hasSession ? isMobile : isTabletOrMobile
49
50 const bottomPosition = isTablet
51 ? {bottom: 50}
52 : {bottom: clamp(insets.bottom, 15, 60) + 15}
53
54 if (disableTopOfFeedButton) {
55 return null
56 }
57
58 return (
59 <Animated.View
60 testID="loadLatestBtn"
61 style={[
62 a.fixed,
63 a.z_20,
64 {left: 18},
65 isDesktop &&
66 (isTallViewport
67 ? styles.loadLatestOutOfLine
68 : styles.loadLatestInline),
69 isTablet &&
70 (centerColumnOffset
71 ? styles.loadLatestInlineOffset
72 : styles.loadLatestInline),
73 bottomPosition,
74 showBottomBar && fabMinimalShellTransform,
75 ]}>
76 <PressableScale
77 style={[
78 {
79 width: 42,
80 height: 42,
81 },
82 enableSquareButtons ? a.rounded_sm : a.rounded_full,
83 a.align_center,
84 a.justify_center,
85 a.border,
86 t.atoms.border_contrast_low,
87 showIndicator ? {backgroundColor: t.palette.primary_50} : t.atoms.bg,
88 ]}
89 onPress={onPress}
90 hitSlop={HITSLOP_20}
91 accessibilityLabel={label}
92 accessibilityHint=""
93 targetScale={0.9}
94 onPointerEnter={onHoverIn}
95 onPointerLeave={onHoverOut}>
96 <SubtleHover
97 hover={hovered}
98 style={[enableSquareButtons ? a.rounded_sm : a.rounded_full]}
99 />
100 <ArrowIcon
101 size="md"
102 style={[
103 a.z_10,
104 showIndicator
105 ? {color: t.palette.primary_500}
106 : t.atoms.text_contrast_medium,
107 ]}
108 />
109 </PressableScale>
110 </Animated.View>
111 )
112}
113
114const styles = StyleSheet.create({
115 loadLatestInline: {
116 left: web('calc(50vw - 282px)'),
117 },
118 loadLatestInlineOffset: {
119 left: web(`calc(50vw - 282px + ${CENTER_COLUMN_OFFSET}px)`),
120 },
121 loadLatestOutOfLine: {
122 left: web('calc(50vw - 382px)'),
123 },
124})