diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/lib/api/index.ts | 4 | ||||
-rw-r--r-- | src/lib/strings/rich-text-manip.ts | 34 | ||||
-rw-r--r-- | src/lib/strings/url-helpers.ts | 13 | ||||
-rw-r--r-- | src/view/com/composer/Composer.tsx | 39 | ||||
-rw-r--r-- | src/view/com/composer/text-input/TextInput.web.tsx | 1 |
5 files changed, 66 insertions, 25 deletions
diff --git a/src/lib/api/index.ts b/src/lib/api/index.ts index bb4ff8fcb..4ecd32046 100644 --- a/src/lib/api/index.ts +++ b/src/lib/api/index.ts @@ -14,6 +14,7 @@ import {isNetworkError} from 'lib/strings/errors' import {LinkMeta} from '../link-meta/link-meta' import {isWeb} from 'platform/detection' import {ImageModel} from 'state/models/media/image' +import {shortenLinks} from 'lib/strings/rich-text-manip' export interface ExternalEmbedDraft { uri: string @@ -92,7 +93,7 @@ export async function post(store: RootStoreModel, opts: PostOpts) { | AppBskyEmbedRecordWithMedia.Main | undefined let reply - const rt = new RichText( + let rt = new RichText( {text: opts.rawText.trim()}, { cleanNewlines: true, @@ -101,6 +102,7 @@ export async function post(store: RootStoreModel, opts: PostOpts) { opts.onStateChange?.('Processing...') await rt.detectFacets(store.agent) + rt = shortenLinks(rt) // filter out any mention facets that didn't map to a user rt.facets = rt.facets?.filter(facet => { diff --git a/src/lib/strings/rich-text-manip.ts b/src/lib/strings/rich-text-manip.ts new file mode 100644 index 000000000..d9cd8c071 --- /dev/null +++ b/src/lib/strings/rich-text-manip.ts @@ -0,0 +1,34 @@ +import {RichText, UnicodeString} from '@atproto/api' +import {toShortUrl} from './url-helpers' + +export function shortenLinks(rt: RichText): RichText { + if (!rt.facets?.length) { + return rt + } + rt = rt.clone() + // enumerate the link facets + if (rt.facets) { + for (const facet of rt.facets) { + const isLink = !!facet.features.find( + f => f.$type === 'app.bsky.richtext.facet#link', + ) + if (!isLink) { + continue + } + + // extract and shorten the URL + const {byteStart, byteEnd} = facet.index + const url = rt.unicodeText.slice(byteStart, byteEnd) + const shortened = new UnicodeString(toShortUrl(url)) + + // insert the shorten URL + rt.insert(byteStart, shortened.utf16) + // update the facet to cover the new shortened URL + facet.index.byteStart = byteStart + facet.index.byteEnd = byteStart + shortened.length + // remove the old URL + rt.delete(byteStart + shortened.length, byteEnd + shortened.length) + } + } + return rt +} diff --git a/src/lib/strings/url-helpers.ts b/src/lib/strings/url-helpers.ts index 1406e2af0..b509aad01 100644 --- a/src/lib/strings/url-helpers.ts +++ b/src/lib/strings/url-helpers.ts @@ -42,15 +42,12 @@ export function toShortUrl(url: string): string { if (urlp.protocol !== 'http:' && urlp.protocol !== 'https:') { return url } - const shortened = - urlp.host + - (urlp.pathname === '/' ? '' : urlp.pathname) + - urlp.search + - urlp.hash - if (shortened.length > 30) { - return shortened.slice(0, 27) + '...' + const path = + (urlp.pathname === '/' ? '' : urlp.pathname) + urlp.search + urlp.hash + if (path.length > 15) { + return urlp.host + path.slice(0, 13) + '...' } - return shortened ? shortened : url + return urlp.host + path } catch (e) { return url } diff --git a/src/view/com/composer/Composer.tsx b/src/view/com/composer/Composer.tsx index 7d3e27571..f9629797a 100644 --- a/src/view/com/composer/Composer.tsx +++ b/src/view/com/composer/Composer.tsx @@ -32,6 +32,8 @@ import {s, colors, gradients} from 'lib/styles' import {sanitizeDisplayName} from 'lib/strings/display-names' import {sanitizeHandle} from 'lib/strings/handles' import {cleanError} from 'lib/strings/errors' +import {shortenLinks} from 'lib/strings/rich-text-manip' +import {toShortUrl} from 'lib/strings/url-helpers' import {SelectPhotoBtn} from './photos/SelectPhotoBtn' import {OpenCameraBtn} from './photos/OpenCameraBtn' import {usePalette} from 'lib/hooks/usePalette' @@ -63,7 +65,9 @@ export const ComposePost = observer(function ComposePost({ const [processingState, setProcessingState] = useState('') const [error, setError] = useState('') const [richtext, setRichText] = useState(new RichText({text: ''})) - const graphemeLength = useMemo(() => richtext.graphemeLength, [richtext]) + const graphemeLength = useMemo(() => { + return shortenLinks(richtext).graphemeLength + }, [richtext]) const [quote, setQuote] = useState<ComposerOpts['quote'] | undefined>( initQuote, ) @@ -148,7 +152,7 @@ export const ComposePost = observer(function ComposePost({ ) const onPressPublish = async (rt: RichText) => { - if (isProcessing || rt.graphemeLength > MAX_GRAPHEME_LENGTH) { + if (isProcessing || graphemeLength > MAX_GRAPHEME_LENGTH) { return } if (store.preferences.requireAltTextEnabled && gallery.needsAltText) { @@ -352,20 +356,23 @@ export const ComposePost = observer(function ComposePost({ </ScrollView> {!extLink && suggestedLinks.size > 0 ? ( <View style={s.mb5}> - {Array.from(suggestedLinks).map(url => ( - <TouchableOpacity - key={`suggested-${url}`} - testID="addLinkCardBtn" - style={[pal.borderDark, styles.addExtLinkBtn]} - onPress={() => onPressAddLinkCard(url)} - accessibilityRole="button" - accessibilityLabel="Add link card" - accessibilityHint={`Creates a card with a thumbnail. The card links to ${url}`}> - <Text style={pal.text}> - Add link card: <Text style={pal.link}>{url}</Text> - </Text> - </TouchableOpacity> - ))} + {Array.from(suggestedLinks) + .slice(0, 3) + .map(url => ( + <TouchableOpacity + key={`suggested-${url}`} + testID="addLinkCardBtn" + style={[pal.borderDark, styles.addExtLinkBtn]} + onPress={() => onPressAddLinkCard(url)} + accessibilityRole="button" + accessibilityLabel="Add link card" + accessibilityHint={`Creates a card with a thumbnail. The card links to ${url}`}> + <Text style={pal.text}> + Add link card:{' '} + <Text style={pal.link}>{toShortUrl(url)}</Text> + </Text> + </TouchableOpacity> + ))} </View> ) : null} <View style={[pal.border, styles.bottomBar]}> diff --git a/src/view/com/composer/text-input/TextInput.web.tsx b/src/view/com/composer/text-input/TextInput.web.tsx index 245c17b9c..da34a5b9a 100644 --- a/src/view/com/composer/text-input/TextInput.web.tsx +++ b/src/view/com/composer/text-input/TextInput.web.tsx @@ -107,6 +107,7 @@ export const TextInput = React.forwardRef( const json = editorProp.getJSON() const newRt = new RichText({text: editorJsonToText(json).trim()}) + newRt.detectFacetsWithoutResolution() setRichText(newRt) const newSuggestedLinks = new Set(editorJsonToLinks(json)) |