forked from
jollywhoppers.com/witchsky.app
Bluesky app fork with some witchin' additions 馃挮
1import {useCallback, useMemo} from 'react'
2import {View} from 'react-native'
3import {msg, Trans} from '@lingui/macro'
4import {useLingui} from '@lingui/react'
5
6import {useOpenLink} from '#/lib/hooks/useOpenLink'
7import {shareUrl} from '#/lib/sharing'
8import {isPossiblyAUrl, splitApexDomain} from '#/lib/strings/url-helpers'
9import {atoms as a, useBreakpoints, useTheme, web} from '#/alf'
10import {Button, ButtonText} from '#/components/Button'
11import * as Dialog from '#/components/Dialog'
12import {Text} from '#/components/Typography'
13import {useGlobalDialogsControlContext} from './Context'
14
15export function LinkWarningDialog() {
16 const {linkWarningDialogControl} = useGlobalDialogsControlContext()
17
18 return (
19 <Dialog.Outer
20 control={linkWarningDialogControl.control}
21 nativeOptions={{preventExpansion: true}}
22 webOptions={{alignCenter: true}}
23 onClose={linkWarningDialogControl.clear}>
24 <Dialog.Handle />
25 <LinkWarningDialogInner link={linkWarningDialogControl.value} />
26 </Dialog.Outer>
27 )
28}
29
30export function CustomLinkWarningDialog({
31 control,
32 link,
33}: {
34 control: Dialog.DialogControlProps
35 link?: {href: string; displayText: string; share?: boolean}
36}) {
37 return (
38 <Dialog.Outer control={control} nativeOptions={{preventExpansion: true}}>
39 <Dialog.Handle />
40 <LinkWarningDialogInner link={link} />
41 </Dialog.Outer>
42 )
43}
44
45function LinkWarningDialogInner({
46 link,
47}: {
48 link?: {href: string; displayText: string; share?: boolean}
49}) {
50 const control = Dialog.useDialogContext()
51 const {_} = useLingui()
52 const t = useTheme()
53 const openLink = useOpenLink()
54 const {gtMobile} = useBreakpoints()
55
56 const potentiallyMisleading = useMemo(
57 () => link && isPossiblyAUrl(link.displayText),
58 [link],
59 )
60
61 const onPressVisit = useCallback(() => {
62 control.close(() => {
63 if (!link) return
64 if (link.share) {
65 shareUrl(link.href)
66 } else {
67 openLink(link.href, undefined, true)
68 }
69 })
70 }, [control, link, openLink])
71
72 const onCancel = useCallback(() => {
73 control.close()
74 }, [control])
75
76 return (
77 <Dialog.ScrollableInner
78 style={web({maxWidth: 450})}
79 label={
80 potentiallyMisleading
81 ? _(msg`Potentially misleading link warning`)
82 : _(msg`Leaving Witchsky`)
83 }>
84 <View style={[a.gap_2xl]}>
85 <View style={[a.gap_sm]}>
86 <Text style={[a.font_bold, a.text_2xl]}>
87 {potentiallyMisleading ? (
88 <Trans>Potentially misleading link</Trans>
89 ) : (
90 <Trans>Leaving Witchsky</Trans>
91 )}
92 </Text>
93 <Text style={[t.atoms.text_contrast_high, a.text_md, a.leading_snug]}>
94 <Trans>This link is taking you to the following website:</Trans>
95 </Text>
96 {link && <LinkBox href={link.href} />}
97 {potentiallyMisleading && (
98 <Text
99 style={[t.atoms.text_contrast_high, a.text_md, a.leading_snug]}>
100 <Trans>Make sure this is where you intend to go!</Trans>
101 </Text>
102 )}
103 </View>
104 <View
105 style={[
106 a.flex_1,
107 a.gap_sm,
108 gtMobile && [a.flex_row_reverse, a.justify_start],
109 ]}>
110 <Button
111 label={link?.share ? _(msg`Share link`) : _(msg`Visit site`)}
112 accessibilityHint={_(msg`Opens link ${link?.href ?? ''}`)}
113 onPress={onPressVisit}
114 size="large"
115 variant="solid"
116 color={potentiallyMisleading ? 'secondary_inverted' : 'primary'}>
117 <ButtonText>
118 {link?.share ? (
119 <Trans>Share link</Trans>
120 ) : (
121 <Trans>Visit site</Trans>
122 )}
123 </ButtonText>
124 </Button>
125 <Button
126 label={_(msg`Go back`)}
127 onPress={onCancel}
128 size="large"
129 variant="ghost"
130 color="secondary">
131 <ButtonText>
132 <Trans>Go back</Trans>
133 </ButtonText>
134 </Button>
135 </View>
136 </View>
137 <Dialog.Close />
138 </Dialog.ScrollableInner>
139 )
140}
141
142function LinkBox({href}: {href: string}) {
143 const t = useTheme()
144 const [scheme, hostname, rest] = useMemo(() => {
145 try {
146 const urlp = new URL(href)
147 const [subdomain, apexdomain] = splitApexDomain(urlp.hostname)
148 return [
149 urlp.protocol + '//' + subdomain,
150 apexdomain,
151 urlp.pathname.replace(/\/$/, '') + urlp.search + urlp.hash,
152 ]
153 } catch {
154 return ['', href, '']
155 }
156 }, [href])
157 return (
158 <View
159 style={[
160 t.atoms.bg,
161 t.atoms.border_contrast_medium,
162 a.px_md,
163 {paddingVertical: 10},
164 a.rounded_sm,
165 a.border,
166 ]}>
167 <Text style={[a.text_md, a.leading_snug, t.atoms.text_contrast_medium]}>
168 {scheme}
169 <Text
170 style={[a.text_md, a.leading_snug, t.atoms.text, a.font_semi_bold]}>
171 {hostname}
172 </Text>
173 {rest}
174 </Text>
175 </View>
176 )
177}