about summary refs log tree commit diff
path: root/src/view/com/util/load-latest/LoadLatestBtn.tsx
blob: 89e5784b7a77111efd44da63117468bc29ed8ee4 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
import {StyleSheet, View} from 'react-native'
import Animated from 'react-native-reanimated'
import {useSafeAreaInsets} from 'react-native-safe-area-context'
import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome'
import {useMediaQuery} from 'react-responsive'

import {HITSLOP_20} from '#/lib/constants'
import {PressableScale} from '#/lib/custom-animations/PressableScale'
import {useMinimalShellFabTransform} from '#/lib/hooks/useMinimalShellTransform'
import {usePalette} from '#/lib/hooks/usePalette'
import {useWebMediaQueries} from '#/lib/hooks/useWebMediaQueries'
import {clamp} from '#/lib/numbers'
import {useGate} from '#/lib/statsig/statsig'
import {colors} from '#/lib/styles'
import {isWeb} from '#/platform/detection'
import {useSession} from '#/state/session'
import {useLayoutBreakpoints} from '#/alf'

export function LoadLatestBtn({
  onPress,
  label,
  showIndicator,
}: {
  onPress: () => void
  label: string
  showIndicator: boolean
}) {
  const pal = usePalette('default')
  const {hasSession} = useSession()
  const {isDesktop, isTablet, isMobile, isTabletOrMobile} = useWebMediaQueries()
  const {centerColumnOffset} = useLayoutBreakpoints()
  const fabMinimalShellTransform = useMinimalShellFabTransform()
  const insets = useSafeAreaInsets()

  // move button inline if it starts overlapping the left nav
  const isTallViewport = useMediaQuery({minHeight: 700})

  const gate = useGate()
  if (gate('remove_show_latest_button')) {
    return null
  }

  // 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
  // it on both tablet and mobile since we are showing the bottom bar (see createNativeStackNavigatorWithAuth)
  const showBottomBar = hasSession ? isMobile : isTabletOrMobile

  const bottomPosition = isTablet
    ? {bottom: 50}
    : {bottom: clamp(insets.bottom, 15, 60) + 15}

  return (
    <Animated.View style={[showBottomBar && fabMinimalShellTransform]}>
      <PressableScale
        style={[
          styles.loadLatest,
          isDesktop &&
            (isTallViewport
              ? styles.loadLatestOutOfLine
              : styles.loadLatestInline),
          isTablet &&
            (centerColumnOffset
              ? styles.loadLatestInlineOffset
              : styles.loadLatestInline),
          pal.borderDark,
          pal.view,
          bottomPosition,
        ]}
        onPress={onPress}
        hitSlop={HITSLOP_20}
        accessibilityLabel={label}
        accessibilityHint=""
        targetScale={0.9}>
        <FontAwesomeIcon icon="angle-up" color={pal.colors.text} size={19} />
        {showIndicator && <View style={[styles.indicator, pal.borderDark]} />}
      </PressableScale>
    </Animated.View>
  )
}

const styles = StyleSheet.create({
  loadLatest: {
    zIndex: 20,
    position: isWeb ? 'fixed' : 'absolute',
    left: 18,
    borderWidth: StyleSheet.hairlineWidth,
    width: 52,
    height: 52,
    borderRadius: 26,
    flexDirection: 'row',
    alignItems: 'center',
    justifyContent: 'center',
  },
  loadLatestInline: {
    // @ts-expect-error web only
    left: 'calc(50vw - 282px)',
  },
  loadLatestInlineOffset: {
    // @ts-expect-error web only
    left: 'calc(50vw - 432px)',
  },
  loadLatestOutOfLine: {
    // @ts-expect-error web only
    left: 'calc(50vw - 382px)',
  },
  indicator: {
    position: 'absolute',
    top: 3,
    right: 3,
    backgroundColor: colors.blue3,
    width: 12,
    height: 12,
    borderRadius: 6,
    borderWidth: 1,
  },
})