Bluesky app fork with some witchin' additions 💫
0
fork

Configure Feed

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

Add support for web links

+67 -30
+1 -1
src/view/com/composer/ComposePost.tsx
··· 108 108 : undefined 109 109 110 110 const textDecorated = useMemo(() => { 111 - const re = /(@[a-z0-9\.]*)/gi 111 + const re = /(@[a-z0-9\.]*)|(https?:\/\/[\S]+)/gi 112 112 const segments = [] 113 113 let match 114 114 let start = 0
+18 -9
src/view/com/util/Link.tsx
··· 1 1 import React from 'react' 2 2 import {observer} from 'mobx-react-lite' 3 3 import { 4 + Linking, 4 5 StyleProp, 5 6 Text, 6 7 TouchableOpacity, ··· 8 9 ViewStyle, 9 10 } from 'react-native' 10 11 import {useStores} from '../../../state' 12 + import {RootStoreModel} from '../../../state' 11 13 import {LinkActionsModel} from '../../../state/models/shell-ui' 12 14 13 15 export const Link = observer(function Link({ ··· 23 25 }) { 24 26 const store = useStores() 25 27 const onPress = () => { 26 - store.shell.closeModal() // close any active modals 27 - store.nav.navigate(href) 28 + handleLink(store, href, false) 28 29 } 29 30 const onLongPress = () => { 30 - store.shell.closeModal() // close any active modals 31 - store.nav.newTab(href, title) 32 - // store.shell.openModal(new LinkActionsModel(href, title || href)) 31 + handleLink(store, href, true) 33 32 } 34 33 return ( 35 34 <TouchableOpacity ··· 55 54 }) { 56 55 const store = useStores() 57 56 const onPress = () => { 58 - store.shell.closeModal() // close any active modals 59 - store.nav.navigate(href) 57 + handleLink(store, href, false) 60 58 } 61 59 const onLongPress = () => { 62 - store.shell.closeModal() // close any active modals 63 - store.nav.newTab(href, title) 60 + handleLink(store, href, true) 64 61 } 65 62 return ( 66 63 <Text style={style} onPress={onPress} onLongPress={onLongPress}> ··· 68 65 </Text> 69 66 ) 70 67 }) 68 + 69 + function handleLink(store: RootStoreModel, href: string, longPress: boolean) { 70 + if (href.startsWith('http')) { 71 + Linking.openURL(href) 72 + } else if (longPress) { 73 + store.shell.closeModal() // close any active modals 74 + store.nav.newTab(href) 75 + } else { 76 + store.shell.closeModal() // close any active modals 77 + store.nav.navigate(href) 78 + } 79 + }
+19 -8
src/view/com/util/RichText.tsx
··· 32 32 if (typeof segment === 'string') { 33 33 els.push(segment) 34 34 } else { 35 - els.push( 36 - <TextLink 37 - key={key} 38 - text={segment.text} 39 - href={`/profile/${segment.entity.value}`} 40 - style={[style, s.blue3]} 41 - />, 42 - ) 35 + if (segment.entity.type === 'mention') { 36 + els.push( 37 + <TextLink 38 + key={key} 39 + text={segment.text} 40 + href={`/profile/${segment.entity.value}`} 41 + style={[style, s.blue3]} 42 + />, 43 + ) 44 + } else if (segment.entity.type === 'link') { 45 + els.push( 46 + <TextLink 47 + key={key} 48 + text={segment.text} 49 + href={segment.entity.value} 50 + style={[style, s.blue3]} 51 + />, 52 + ) 53 + } 43 54 } 44 55 key++ 45 56 }
+29 -12
src/view/lib/strings.ts
··· 63 63 ): Entity[] | undefined { 64 64 let match 65 65 let ents: Entity[] = [] 66 - const re = /(^|\s)(@)([a-zA-Z0-9\.-]+)(\b)/dg 67 - while ((match = re.exec(text))) { 68 - if (knownHandles && !knownHandles.has(match[3])) { 69 - continue // not a known handle 66 + { 67 + // mentions 68 + const re = /(^|\s)(@)([a-zA-Z0-9\.-]+)(\b)/dg 69 + while ((match = re.exec(text))) { 70 + if (knownHandles && !knownHandles.has(match[3])) { 71 + continue // not a known handle 72 + } 73 + ents.push({ 74 + type: 'mention', 75 + value: match[3], 76 + index: { 77 + start: match.indices[2][0], // skip the (^|\s) but include the '@' 78 + end: match.indices[3][1], 79 + }, 80 + }) 81 + } 82 + } 83 + { 84 + // links 85 + const re = /(^|\s)(https?:\/\/[\S]+)(\b)/dg 86 + while ((match = re.exec(text))) { 87 + ents.push({ 88 + type: 'link', 89 + value: match[2], 90 + index: { 91 + start: match.indices[1][0], // skip the (^|\s) but include the '@' 92 + end: match.indices[2][1], 93 + }, 94 + }) 70 95 } 71 - ents.push({ 72 - type: 'mention', 73 - value: match[3], 74 - index: { 75 - start: match.indices[2][0], // skip the (^|\s) but include the '@' 76 - end: match.indices[3][1], 77 - }, 78 - }) 79 96 } 80 97 return ents.length > 0 ? ents : undefined 81 98 }