Bluesky app fork with some witchin' additions 馃挮
witchsky.app
bluesky
fork
client
1import {type ReactNode} from 'react'
2import {ScrollView, View} from 'react-native'
3import {
4 useSafeAreaFrame,
5 useSafeAreaInsets,
6} from 'react-native-safe-area-context'
7import {LinearGradient} from 'expo-linear-gradient'
8import {utils} from '@bsky.app/alf'
9
10import {useA11y} from '#/state/a11y'
11import {atoms as a, useBreakpoints, useTheme, web} from '#/alf'
12import {FocusScope} from '#/components/FocusScope'
13import {LockScroll} from '#/components/LockScroll'
14import {IS_ANDROID, IS_NATIVE} from '#/env'
15
16const GUTTER = 24
17
18export function Overlay({
19 children,
20 label,
21}: {
22 children: ReactNode
23 label: string
24}) {
25 const t = useTheme()
26 const {gtPhone} = useBreakpoints()
27 const {reduceMotionEnabled} = useA11y()
28 const insets = useSafeAreaInsets()
29 const frame = useSafeAreaFrame()
30
31 return (
32 <>
33 <LockScroll />
34
35 <View style={[a.fixed, a.inset_0, !reduceMotionEnabled && a.fade_in]}>
36 {gtPhone ? (
37 <View style={[a.absolute, a.inset_0, {opacity: 0.8}]}>
38 <View
39 style={[
40 a.fixed,
41 a.inset_0,
42 {backgroundColor: t.palette.black},
43 !reduceMotionEnabled && a.fade_in,
44 ]}
45 />
46 </View>
47 ) : (
48 <LinearGradient
49 colors={[
50 utils.alpha(t.atoms.bg.backgroundColor, 0),
51 t.atoms.bg.backgroundColor,
52 t.atoms.bg.backgroundColor,
53 ]}
54 start={[0.5, 0]}
55 end={[0.5, 1]}
56 style={[a.absolute, a.inset_0]}
57 />
58 )}
59 </View>
60
61 <ScrollView
62 showsVerticalScrollIndicator={false}
63 style={[
64 a.z_10,
65 gtPhone &&
66 web({
67 paddingHorizontal: GUTTER,
68 paddingVertical: '10vh',
69 }),
70 ]}
71 contentContainerStyle={[a.align_center]}>
72 {/**
73 * This is needed to prevent centered dialogs from overflowing
74 * above the screen, and provides a "natural" centering so that
75 * stacked dialogs appear relatively aligned.
76 */}
77 <View
78 style={[
79 a.w_full,
80 a.z_20,
81 a.align_center,
82 !gtPhone && [a.justify_end, {minHeight: frame.height}],
83 IS_NATIVE && [
84 {
85 paddingBottom: Math.max(insets.bottom, a.p_2xl.padding),
86 },
87 ],
88 ]}>
89 {!gtPhone && (
90 <View
91 style={[
92 a.flex_1,
93 a.w_full,
94 {
95 minHeight: Math.max(insets.top, a.p_2xl.padding),
96 },
97 ]}>
98 <LinearGradient
99 colors={[
100 utils.alpha(t.atoms.bg.backgroundColor, 0),
101 t.atoms.bg.backgroundColor,
102 ]}
103 start={[0.5, 0]}
104 end={[0.5, 1]}
105 style={[a.absolute, a.inset_0]}
106 />
107 </View>
108 )}
109
110 <FocusScope>
111 <View
112 accessible={IS_ANDROID}
113 role="dialog"
114 aria-role="dialog"
115 aria-label={label}
116 style={[
117 a.relative,
118 a.w_full,
119 a.p_2xl,
120 t.atoms.bg,
121 !reduceMotionEnabled && a.zoom_fade_in,
122 gtPhone && [
123 a.rounded_md,
124 a.border,
125 t.atoms.shadow_lg,
126 t.atoms.border_contrast_low,
127 web({
128 maxWidth: 420,
129 }),
130 ],
131 ]}>
132 {children}
133 </View>
134 </FocusScope>
135 </View>
136 </ScrollView>
137 </>
138 )
139}