Bluesky app fork with some witchin' additions 馃挮 witchsky.app
bluesky fork client
119
fork

Configure Feed

Select the types of activity you want to include in your feed.

at a876aae44ea07494ebea9727350aa060b81f317b 178 lines 5.1 kB view raw
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}