this repo has no description
0
fork

Configure Feed

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

don't compute facets like an idiot

+64 -63
+5 -1
apps/expo/src/app/(tabs)/notifications.tsx
··· 353 353 return ( 354 354 <View className="mt-0.5"> 355 355 <Text className="text-neutral-500"> 356 - <RichText value={post.data.post.record.text} size="sm" /> 356 + <RichText 357 + text={post.data.post.record.text} 358 + facets={post.data.post.record.facets} 359 + size="sm" 360 + /> 357 361 </Text> 358 362 {post.data.post.embed && 359 363 AppBskyEmbedImages.isView(post.data.post.embed) && (
+4 -1
apps/expo/src/components/feed-post.tsx
··· 127 127 {/* text content */} 128 128 <Link href={postHref} asChild> 129 129 <Pressable className="my-0.5"> 130 - <RichText value={item.post.record.text} /> 130 + <RichText 131 + text={item.post.record.text} 132 + facets={item.post.record.facets} 133 + /> 131 134 </Pressable> 132 135 </Link> 133 136 {/* embeds */}
+1 -1
apps/expo/src/components/post.tsx
··· 68 68 </TouchableOpacity> 69 69 </Link> 70 70 {/* text content */} 71 - <RichText value={post.record.text} size="lg" /> 71 + <RichText text={post.record.text} facets={post.record.facets} size="lg" /> 72 72 {/* embeds */} 73 73 {post.embed && ( 74 74 <Embed uri={post.uri} content={post.embed} truncate={false} />
+54 -60
apps/expo/src/components/rich-text.tsx
··· 1 - import { Fragment } from "react"; 1 + import { Fragment, useMemo } from "react"; 2 2 import { Linking, Text } from "react-native"; 3 3 import { useRouter } from "expo-router"; 4 - import { RichText as RichTextHelper } from "@atproto/api"; 5 - import { useQuery } from "@tanstack/react-query"; 4 + import { RichText as RichTextHelper, type Facet } from "@atproto/api"; 6 5 7 - import { useAuthedAgent } from "../lib/agent"; 8 6 import { cx } from "../lib/utils/cx"; 9 7 10 8 interface Props { 11 - value: string; 9 + text: string; 10 + facets?: Facet[]; 12 11 size?: "sm" | "base" | "lg"; 13 12 } 14 13 15 - export const RichText = ({ value, size = "base" }: Props) => { 16 - const agent = useAuthedAgent(); 14 + export const RichText = ({ text, facets, size = "base" }: Props) => { 17 15 const router = useRouter(); 18 16 19 - const { data: segments } = useQuery({ 20 - queryKey: ["richtext", value], 21 - queryFn: async () => { 22 - const rt = new RichTextHelper({ text: value }); 23 - await rt.detectFacets(agent); 24 - const parts = []; 25 - for (const segment of rt.segments()) { 26 - if (segment.isLink()) { 27 - parts.push({ 28 - text: segment.text, 29 - component: ( 30 - <Text 31 - className="text-blue-500" 32 - onPress={(evt) => { 33 - evt.stopPropagation(); 34 - const url = segment.link!.uri; 35 - // TODO: better heuristic? 36 - if (url.startsWith("https://bsky.app/profile")) { 37 - const path = url.slice("https://bsky.app".length); 38 - router.push(path); 39 - } else { 40 - void Linking.openURL(url); 41 - } 42 - }} 43 - > 44 - {segment.text} 45 - </Text> 46 - ), 47 - }); 48 - } else if (segment.isMention()) { 49 - parts.push({ 50 - text: segment.text, 51 - component: ( 52 - <Text 53 - className="text-blue-500" 54 - onPress={(evt) => { 55 - evt.stopPropagation(); 56 - router.push(`/profile/${segment.mention!.did}`); 57 - }} 58 - > 59 - {segment.text} 60 - </Text> 61 - ), 62 - }); 63 - } else { 64 - parts.push({ 65 - text: segment.text, 66 - component: segment.text, 67 - }); 68 - } 17 + const segments = useMemo(() => { 18 + const rt = new RichTextHelper({ text, facets }); 19 + const parts = []; 20 + for (const segment of rt.segments()) { 21 + if (segment.isLink()) { 22 + parts.push({ 23 + text: segment.text, 24 + component: ( 25 + <Text 26 + className="text-blue-500" 27 + onPress={(evt) => { 28 + evt.stopPropagation(); 29 + const url = segment.link!.uri; 30 + // TODO: better heuristic? 31 + if (url.startsWith("https://bsky.app/profile")) { 32 + const path = url.slice("https://bsky.app".length); 33 + router.push(path); 34 + } else { 35 + void Linking.openURL(url); 36 + } 37 + }} 38 + > 39 + {segment.text} 40 + </Text> 41 + ), 42 + }); 43 + } else if (segment.isMention()) { 44 + parts.push({ 45 + text: segment.text, 46 + component: ( 47 + <Text 48 + className="text-blue-500" 49 + onPress={(evt) => { 50 + evt.stopPropagation(); 51 + router.push(`/profile/${segment.mention!.did}`); 52 + }} 53 + > 54 + {segment.text} 55 + </Text> 56 + ), 57 + }); 58 + } else { 59 + parts.push({ 60 + text: segment.text, 61 + component: segment.text, 62 + }); 69 63 } 70 - return parts; 71 - }, 72 - }); 64 + } 65 + return parts; 66 + }, [text, facets]); 73 67 74 68 if (!segments) return null; 75 69