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