Bluesky app fork with some witchin' additions 💫

ALF Notifications screen (#8208)

* alf notifs page

* Stop propagation

* Ok safari wants preventDefault too

* Fix lint

---------

Co-authored-by: Eric Bailey <git@esb.lol>

authored by samuel.fm

Eric Bailey and committed by
GitHub
fb8ab9f2 fa0b1bc1

+196 -208
+6 -6
src/components/Link.tsx
··· 1 1 import React from 'react' 2 - import {GestureResponderEvent} from 'react-native' 2 + import {type GestureResponderEvent} from 'react-native' 3 3 import {sanitizeUrl} from '@braintree/sanitize-url' 4 4 import {StackActions, useLinkProps} from '@react-navigation/native' 5 5 6 6 import {BSKY_DOWNLOAD_URL} from '#/lib/constants' 7 7 import {useNavigationDeduped} from '#/lib/hooks/useNavigationDeduped' 8 8 import {useOpenLink} from '#/lib/hooks/useOpenLink' 9 - import {AllNavigatorParams} from '#/lib/routes/types' 9 + import {type AllNavigatorParams} from '#/lib/routes/types' 10 10 import {shareUrl} from '#/lib/sharing' 11 11 import { 12 12 convertBskyAppUrlIfNeeded, ··· 16 16 } from '#/lib/strings/url-helpers' 17 17 import {isNative, isWeb} from '#/platform/detection' 18 18 import {useModalControls} from '#/state/modals' 19 - import {atoms as a, flatten, TextStyleProp, useTheme, web} from '#/alf' 20 - import {Button, ButtonProps} from '#/components/Button' 19 + import {atoms as a, flatten, type TextStyleProp, useTheme, web} from '#/alf' 20 + import {Button, type ButtonProps} from '#/components/Button' 21 21 import {useInteractionState} from '#/components/hooks/useInteractionState' 22 - import {Text, TextProps} from '#/components/Typography' 22 + import {Text, type TextProps} from '#/components/Typography' 23 23 import {router} from '#/routes' 24 24 25 25 /** ··· 267 267 export type InlineLinkProps = React.PropsWithChildren< 268 268 BaseLinkProps & 269 269 TextStyleProp & 270 - Pick<TextProps, 'selectable' | 'numberOfLines'> & 270 + Pick<TextProps, 'selectable' | 'numberOfLines' | 'emoji'> & 271 271 Pick<ButtonProps, 'label' | 'accessibilityHint'> & { 272 272 disableUnderline?: boolean 273 273 title?: TextProps['title']
+190 -202
src/view/com/notifications/NotificationFeedItem.tsx
··· 1 - import React, { 1 + import { 2 2 memo, 3 3 type ReactElement, 4 + useCallback, 4 5 useEffect, 5 6 useMemo, 6 7 useState, 7 8 } from 'react' 8 9 import { 9 10 Animated, 11 + type GestureResponderEvent, 10 12 Pressable, 11 13 StyleSheet, 12 14 TouchableOpacity, 13 15 View, 14 16 } from 'react-native' 15 17 import { 16 - AppBskyActorDefs, 17 - AppBskyFeedDefs, 18 + type AppBskyActorDefs, 19 + type AppBskyFeedDefs, 18 20 AppBskyFeedPost, 19 21 AppBskyGraphFollow, 20 22 moderateProfile, 21 - ModerationDecision, 22 - ModerationOpts, 23 + type ModerationDecision, 24 + type ModerationOpts, 23 25 } from '@atproto/api' 24 26 import {AtUri} from '@atproto/api' 25 27 import {TID} from '@atproto/common-web' ··· 31 33 import {useAnimatedValue} from '#/lib/hooks/useAnimatedValue' 32 34 import {usePalette} from '#/lib/hooks/usePalette' 33 35 import {makeProfileLink} from '#/lib/routes/links' 34 - import {NavigationProp} from '#/lib/routes/types' 36 + import {type NavigationProp} from '#/lib/routes/types' 35 37 import {forceLTR} from '#/lib/strings/bidi' 36 38 import {sanitizeDisplayName} from '#/lib/strings/display-names' 37 39 import {sanitizeHandle} from '#/lib/strings/handles' 38 40 import {niceDate} from '#/lib/strings/time' 39 - import {colors, s} from '#/lib/styles' 41 + import {s} from '#/lib/styles' 40 42 import {logger} from '#/logger' 41 - import {isWeb} from '#/platform/detection' 42 43 import {DM_SERVICE_HEADERS} from '#/state/queries/messages/const' 43 - import {FeedNotification} from '#/state/queries/notifications/feed' 44 - import {precacheProfile} from '#/state/queries/profile' 44 + import {type FeedNotification} from '#/state/queries/notifications/feed' 45 + import {unstableCacheProfileView} from '#/state/queries/unstable-profile-cache' 45 46 import {useAgent} from '#/state/session' 47 + import {FeedSourceCard} from '#/view/com/feeds/FeedSourceCard' 48 + import {Post} from '#/view/com/post/Post' 49 + import {formatCount} from '#/view/com/util/numeric/format' 50 + import {TimeElapsed} from '#/view/com/util/TimeElapsed' 51 + import {PreviewableUserAvatar, UserAvatar} from '#/view/com/util/UserAvatar' 46 52 import {atoms as a, useTheme} from '#/alf' 47 53 import {Button, ButtonText} from '#/components/Button' 48 54 import { ··· 53 59 import {PersonPlus_Filled_Stroke2_Corner0_Rounded as PersonPlusIcon} from '#/components/icons/Person' 54 60 import {Repost_Stroke2_Corner2_Rounded as RepostIcon} from '#/components/icons/Repost' 55 61 import {StarterPack} from '#/components/icons/StarterPack' 56 - import {Link as NewLink} from '#/components/Link' 62 + import {InlineLinkText, Link} from '#/components/Link' 57 63 import * as MediaPreview from '#/components/MediaPreview' 58 64 import {ProfileHoverCard} from '#/components/ProfileHoverCard' 59 65 import {Notification as StarterPackCard} from '#/components/StarterPack/StarterPackCard' 60 66 import {SubtleWebHover} from '#/components/SubtleWebHover' 67 + import {Text} from '#/components/Typography' 61 68 import * as bsky from '#/types/bsky' 62 - import {FeedSourceCard} from '../feeds/FeedSourceCard' 63 - import {Post} from '../post/Post' 64 - import {Link, TextLink} from '../util/Link' 65 - import {formatCount} from '../util/numeric/format' 66 - import {Text} from '../util/text/Text' 67 - import {TimeElapsed} from '../util/TimeElapsed' 68 - import {PreviewableUserAvatar, UserAvatar} from '../util/UserAvatar' 69 69 70 70 const MAX_AUTHORS = 5 71 71 ··· 90 90 }): React.ReactNode => { 91 91 const queryClient = useQueryClient() 92 92 const pal = usePalette('default') 93 - const {_, i18n} = useLingui() 94 93 const t = useTheme() 94 + const {_, i18n} = useLingui() 95 95 const [isAuthorsExpanded, setAuthorsExpanded] = useState<boolean>(false) 96 96 const itemHref = useMemo(() => { 97 97 if (item.type === 'post-like' || item.type === 'repost') { ··· 116 116 return '' 117 117 }, [item]) 118 118 119 - const onToggleAuthorsExpanded = () => { 119 + const onToggleAuthorsExpanded = (e?: GestureResponderEvent) => { 120 + if (e) { 121 + e.preventDefault() 122 + e.stopPropagation() 123 + } 120 124 setAuthorsExpanded(currentlyExpanded => !currentlyExpanded) 121 125 } 122 126 123 - const onBeforePress = React.useCallback(() => { 124 - precacheProfile(queryClient, item.notification.author) 127 + const onBeforePress = useCallback(() => { 128 + unstableCacheProfileView(queryClient, item.notification.author) 125 129 }, [queryClient, item.notification.author]) 126 130 127 131 const authors: Author[] = useMemo(() => { ··· 139 143 ] 140 144 }, [item, moderationOpts]) 141 145 142 - const [hover, setHover] = React.useState(false) 146 + const niceTimestamp = niceDate(i18n, item.notification.indexedAt) 147 + const firstAuthor = authors[0] 148 + const firstAuthorName = sanitizeDisplayName( 149 + firstAuthor.profile.displayName || firstAuthor.profile.handle, 150 + ) 143 151 144 152 if (item.subjectUri && !item.subject && item.type !== 'feedgen-like') { 145 153 // don't render anything if the target post was deleted or unfindable ··· 156 164 } 157 165 const isHighlighted = highlightUnread && !item.notification.isRead 158 166 return ( 159 - <Link 160 - testID={`feedItem-by-${item.notification.author.handle}`} 161 - href={itemHref} 162 - noFeedback 163 - accessible={false}> 164 - <Post 165 - post={item.subject} 166 - style={ 167 - isHighlighted && { 168 - backgroundColor: pal.colors.unreadNotifBg, 169 - borderColor: pal.colors.unreadNotifBorder, 170 - } 167 + <Post 168 + post={item.subject} 169 + style={ 170 + isHighlighted && { 171 + backgroundColor: pal.colors.unreadNotifBg, 172 + borderColor: pal.colors.unreadNotifBorder, 171 173 } 172 - hideTopBorder={hideTopBorder} 173 - /> 174 - </Link> 174 + } 175 + hideTopBorder={hideTopBorder} 176 + /> 175 177 ) 176 178 } 177 179 178 - const niceTimestamp = niceDate(i18n, item.notification.indexedAt) 179 - const firstAuthor = authors[0] 180 - const firstAuthorName = sanitizeDisplayName( 181 - firstAuthor.profile.displayName || firstAuthor.profile.handle, 182 - ) 183 180 const firstAuthorLink = ( 184 - <TextLink 181 + <InlineLinkText 185 182 key={firstAuthor.href} 186 - style={[pal.text, s.bold]} 187 - href={firstAuthor.href} 188 - text={ 189 - <Text emoji style={[pal.text, s.bold]}> 190 - {forceLTR(firstAuthorName)} 191 - </Text> 192 - } 183 + style={[t.atoms.text, a.font_bold, a.text_md, a.leading_tight]} 184 + to={firstAuthor.href} 193 185 disableMismatchWarning 194 - /> 186 + emoji 187 + label={_(msg`Go to ${firstAuthorName}'s profile`)}> 188 + {forceLTR(firstAuthorName)} 189 + </InlineLinkText> 195 190 ) 196 191 const additionalAuthorsCount = authors.length - 1 197 192 const hasMultipleAuthors = additionalAuthorsCount > 0 ··· 223 218 notificationContent = hasMultipleAuthors ? ( 224 219 <Trans> 225 220 {firstAuthorLink} and{' '} 226 - <Text style={[pal.text, s.bold]}> 221 + <Text style={[a.text_md, a.font_bold, a.leading_snug]}> 227 222 <Plural 228 223 value={additionalAuthorsCount} 229 224 one={`${formattedAuthorsCount} other`} ··· 247 242 notificationContent = hasMultipleAuthors ? ( 248 243 <Trans> 249 244 {firstAuthorLink} and{' '} 250 - <Text style={[pal.text, s.bold]}> 245 + <Text style={[a.text_md, a.font_bold, a.leading_snug]}> 251 246 <Plural 252 247 value={additionalAuthorsCount} 253 248 one={`${formattedAuthorsCount} other`} ··· 304 299 notificationContent = hasMultipleAuthors ? ( 305 300 <Trans> 306 301 {firstAuthorLink} and{' '} 307 - <Text style={[pal.text, s.bold]}> 302 + <Text style={[a.text_md, a.font_bold, a.leading_snug]}> 308 303 <Plural 309 304 value={additionalAuthorsCount} 310 305 one={`${formattedAuthorsCount} other`} ··· 330 325 notificationContent = hasMultipleAuthors ? ( 331 326 <Trans> 332 327 {firstAuthorLink} and{' '} 333 - <Text style={[pal.text, s.bold]}> 328 + <Text style={[a.text_md, a.font_bold, a.leading_snug]}> 334 329 <Plural 335 330 value={additionalAuthorsCount} 336 331 one={`${formattedAuthorsCount} other`} ··· 354 349 notificationContent = hasMultipleAuthors ? ( 355 350 <Trans> 356 351 {firstAuthorLink} and{' '} 357 - <Text style={[pal.text, s.bold]}> 352 + <Text style={[a.text_md, a.font_bold, a.leading_snug]}> 358 353 <Plural 359 354 value={additionalAuthorsCount} 360 355 one={`${formattedAuthorsCount} other`} ··· 378 373 379 374 return ( 380 375 <Link 376 + label={a11yLabel} 381 377 testID={`feedItem-by-${item.notification.author.handle}`} 382 378 style={[ 383 - styles.outer, 384 - pal.border, 379 + a.flex_row, 380 + a.align_start, 381 + {padding: 10}, 382 + a.pr_lg, 383 + t.atoms.border_contrast_low, 385 384 item.notification.isRead 386 385 ? undefined 387 386 : { 388 387 backgroundColor: pal.colors.unreadNotifBg, 389 388 borderColor: pal.colors.unreadNotifBorder, 390 389 }, 391 - {borderTopWidth: hideTopBorder ? 0 : StyleSheet.hairlineWidth}, 390 + !hideTopBorder && a.border_t, 392 391 a.overflow_hidden, 393 392 ]} 394 - href={itemHref} 395 - noFeedback 396 - accessibilityHint="" 397 - accessibilityLabel={a11yLabel} 393 + to={itemHref} 398 394 accessible={!isAuthorsExpanded} 399 395 accessibilityActions={ 400 396 hasMultipleAuthors ··· 424 420 if (e.nativeEvent.actionName === 'toggleAuthorsExpanded') { 425 421 onToggleAuthorsExpanded() 426 422 } 427 - }} 428 - onPointerEnter={() => { 429 - setHover(true) 430 - }} 431 - onPointerLeave={() => { 432 - setHover(false) 433 423 }}> 434 - <SubtleWebHover hover={hover} /> 435 - <View style={[styles.layoutIcon, a.pr_sm]}> 436 - {/* TODO: Prevent conditional rendering and move toward composable 437 - notifications for clearer accessibility labeling */} 438 - {icon} 439 - </View> 440 - <View style={styles.layoutContent}> 441 - <ExpandListPressable 442 - hasMultipleAuthors={hasMultipleAuthors} 443 - onToggleAuthorsExpanded={onToggleAuthorsExpanded}> 444 - <CondensedAuthorsList 445 - visible={!isAuthorsExpanded} 446 - authors={authors} 447 - onToggleAuthorsExpanded={onToggleAuthorsExpanded} 448 - showDmButton={item.type === 'starterpack-joined'} 449 - /> 450 - <ExpandedAuthorsList visible={isAuthorsExpanded} authors={authors} /> 451 - <Text 452 - style={[styles.meta, a.self_start, pal.text]} 453 - accessibilityHint="" 454 - accessibilityLabel={a11yLabel}> 455 - {notificationContent} 456 - <TimeElapsed timestamp={item.notification.indexedAt}> 457 - {({timeElapsed}) => ( 458 - <> 459 - {/* make sure there's whitespace around the middot -sfn */} 460 - <Text style={[pal.textLight]}> &middot; </Text> 461 - <Text style={[pal.textLight]} title={niceTimestamp}> 462 - {timeElapsed} 463 - </Text> 464 - </> 465 - )} 466 - </TimeElapsed> 467 - </Text> 468 - </ExpandListPressable> 469 - {item.type === 'post-like' || item.type === 'repost' ? ( 470 - <AdditionalPostText post={item.subject} /> 471 - ) : null} 472 - {item.type === 'feedgen-like' && item.subjectUri ? ( 473 - <FeedSourceCard 474 - feedUri={item.subjectUri} 475 - style={[ 476 - t.atoms.bg, 477 - t.atoms.border_contrast_low, 478 - a.border, 479 - styles.feedcard, 480 - ]} 481 - showLikes 482 - /> 483 - ) : null} 484 - {item.type === 'starterpack-joined' ? ( 485 - <View> 486 - <View 487 - style={[ 488 - a.border, 489 - a.p_sm, 490 - a.rounded_sm, 491 - a.mt_sm, 492 - t.atoms.border_contrast_low, 493 - ]}> 494 - <StarterPackCard starterPack={item.subject} /> 495 - </View> 424 + {({hovered}) => ( 425 + <> 426 + <SubtleWebHover hover={hovered} /> 427 + <View style={[styles.layoutIcon, a.pr_sm]}> 428 + {/* TODO: Prevent conditional rendering and move toward composable 429 + notifications for clearer accessibility labeling */} 430 + {icon} 496 431 </View> 497 - ) : null} 498 - </View> 432 + <View style={[a.flex_1]}> 433 + <ExpandListPressable 434 + hasMultipleAuthors={hasMultipleAuthors} 435 + onToggleAuthorsExpanded={onToggleAuthorsExpanded}> 436 + <CondensedAuthorsList 437 + visible={!isAuthorsExpanded} 438 + authors={authors} 439 + onToggleAuthorsExpanded={onToggleAuthorsExpanded} 440 + showDmButton={item.type === 'starterpack-joined'} 441 + /> 442 + <ExpandedAuthorsList 443 + visible={isAuthorsExpanded} 444 + authors={authors} 445 + /> 446 + <Text 447 + style={[ 448 + a.flex_row, 449 + a.flex_wrap, 450 + a.pb_2xs, 451 + {paddingTop: 6}, 452 + a.self_start, 453 + a.text_md, 454 + a.leading_snug, 455 + ]} 456 + accessibilityHint="" 457 + accessibilityLabel={a11yLabel}> 458 + {notificationContent} 459 + <TimeElapsed timestamp={item.notification.indexedAt}> 460 + {({timeElapsed}) => ( 461 + <> 462 + {/* make sure there's whitespace around the middot -sfn */} 463 + <Text style={[a.text_md, t.atoms.text_contrast_medium]}> 464 + {' '} 465 + &middot;{' '} 466 + </Text> 467 + <Text 468 + style={[a.text_md, t.atoms.text_contrast_medium]} 469 + title={niceTimestamp}> 470 + {timeElapsed} 471 + </Text> 472 + </> 473 + )} 474 + </TimeElapsed> 475 + </Text> 476 + </ExpandListPressable> 477 + {item.type === 'post-like' || item.type === 'repost' ? ( 478 + <AdditionalPostText post={item.subject} /> 479 + ) : null} 480 + {item.type === 'feedgen-like' && item.subjectUri ? ( 481 + <FeedSourceCard 482 + feedUri={item.subjectUri} 483 + style={[ 484 + t.atoms.bg, 485 + t.atoms.border_contrast_low, 486 + a.border, 487 + styles.feedcard, 488 + ]} 489 + showLikes 490 + /> 491 + ) : null} 492 + {item.type === 'starterpack-joined' ? ( 493 + <View> 494 + <View 495 + style={[ 496 + a.border, 497 + a.p_sm, 498 + a.rounded_sm, 499 + a.mt_sm, 500 + t.atoms.border_contrast_low, 501 + ]}> 502 + <StarterPackCard starterPack={item.subject} /> 503 + </View> 504 + </View> 505 + ) : null} 506 + </View> 507 + </> 508 + )} 499 509 </Link> 500 510 ) 501 511 } ··· 509 519 }: { 510 520 hasMultipleAuthors: boolean 511 521 children: React.ReactNode 512 - onToggleAuthorsExpanded: () => void 522 + onToggleAuthorsExpanded: (e: GestureResponderEvent) => void 513 523 }) { 514 524 if (hasMultipleAuthors) { 515 525 return ( ··· 529 539 const {_} = useLingui() 530 540 const agent = useAgent() 531 541 const navigation = useNavigation<NavigationProp>() 532 - const [isLoading, setIsLoading] = React.useState(false) 542 + const [isLoading, setIsLoading] = useState(false) 533 543 534 544 if ( 535 545 profile.associated?.chat?.allowIncoming === 'none' || ··· 580 590 }: { 581 591 visible: boolean 582 592 authors: Author[] 583 - onToggleAuthorsExpanded: () => void 593 + onToggleAuthorsExpanded: (e: GestureResponderEvent) => void 584 594 showDmButton?: boolean 585 595 }) { 586 - const pal = usePalette('default') 596 + const t = useTheme() 587 597 const {_} = useLingui() 588 598 589 599 if (!visible) { 590 600 return ( 591 - <View style={styles.avis}> 601 + <View style={[a.flex_row, a.align_center]}> 592 602 <TouchableOpacity 593 603 style={styles.expandedAuthorsCloseBtn} 594 604 onPress={onToggleAuthorsExpanded} ··· 599 609 )}> 600 610 <ChevronUpIcon 601 611 size="md" 602 - style={[styles.expandedAuthorsCloseBtnIcon, pal.text]} 612 + style={[a.ml_xs, a.mr_md, t.atoms.text_contrast_high]} 603 613 /> 604 - <Text type="sm-medium" style={pal.text}> 614 + <Text style={[a.text_md, t.atoms.text_contrast_high]}> 605 615 <Trans context="action">Hide</Trans> 606 616 </Text> 607 617 </TouchableOpacity> ··· 610 620 } 611 621 if (authors.length === 1) { 612 622 return ( 613 - <View style={[styles.avis]}> 623 + <View style={[a.flex_row, a.align_center]}> 614 624 <PreviewableUserAvatar 615 625 size={35} 616 626 profile={authors[0].profile} ··· 625 635 <TouchableOpacity 626 636 accessibilityRole="none" 627 637 onPress={onToggleAuthorsExpanded}> 628 - <View style={styles.avis}> 638 + <View style={[a.flex_row, a.align_center]}> 629 639 {authors.slice(0, MAX_AUTHORS).map(author => ( 630 640 <View key={author.href} style={s.mr5}> 631 641 <PreviewableUserAvatar ··· 637 647 </View> 638 648 ))} 639 649 {authors.length > MAX_AUTHORS ? ( 640 - <Text style={[styles.aviExtraCount, pal.textLight]}> 650 + <Text 651 + style={[ 652 + a.font_bold, 653 + {paddingLeft: 6}, 654 + t.atoms.text_contrast_medium, 655 + ]}> 641 656 +{authors.length - MAX_AUTHORS} 642 657 </Text> 643 658 ) : undefined} 644 659 <ChevronDownIcon 645 660 size="md" 646 - style={[styles.expandedAuthorsCloseBtnIcon, pal.textLight]} 661 + style={[a.mx_xs, t.atoms.text_contrast_medium]} 647 662 /> 648 663 </View> 649 664 </TouchableOpacity> ··· 658 673 authors: Author[] 659 674 }) { 660 675 const {_} = useLingui() 661 - const pal = usePalette('default') 676 + const t = useTheme() 662 677 const heightInterp = useAnimatedValue(visible ? 1 : 0) 663 678 const targetHeight = 664 679 authors.length * (EXPANDED_AUTHOR_EL_HEIGHT + 10) /*10=margin*/ ··· 677 692 <Animated.View style={[a.overflow_hidden, heightStyle]}> 678 693 {visible && 679 694 authors.map(author => ( 680 - <NewLink 695 + <Link 681 696 key={author.profile.did} 682 697 label={author.profile.displayName || author.profile.handle} 683 698 accessibilityHint={_(msg`Opens this profile`)} ··· 686 701 handle: author.profile.handle, 687 702 })} 688 703 style={styles.expandedAuthor}> 689 - <View style={styles.expandedAuthorAvi}> 704 + <View style={[a.mr_sm]}> 690 705 <ProfileHoverCard did={author.profile.did}> 691 706 <UserAvatar 692 707 size={35} ··· 696 711 /> 697 712 </ProfileHoverCard> 698 713 </View> 699 - <View style={s.flex1}> 700 - <Text 701 - type="lg-bold" 702 - numberOfLines={1} 703 - style={pal.text} 704 - lineHeight={1.2}> 705 - <Text emoji type="lg-bold" style={pal.text} lineHeight={1.2}> 714 + <View style={[a.flex_1]}> 715 + <View style={[a.flex_row, a.align_end]}> 716 + <Text 717 + numberOfLines={1} 718 + emoji 719 + style={[ 720 + a.text_md, 721 + a.font_bold, 722 + a.leading_tight, 723 + {maxWidth: '70%'}, 724 + ]}> 706 725 {sanitizeDisplayName( 707 726 author.profile.displayName || author.profile.handle, 708 727 )} 709 - </Text>{' '} 710 - <Text style={[pal.textLight]} lineHeight={1.2}> 728 + </Text> 729 + <Text 730 + numberOfLines={1} 731 + style={[ 732 + a.pl_xs, 733 + a.text_md, 734 + a.leading_tight, 735 + a.flex_shrink, 736 + t.atoms.text_contrast_medium, 737 + ]}> 711 738 {sanitizeHandle(author.profile.handle, '@')} 712 739 </Text> 713 - </Text> 740 + </View> 714 741 </View> 715 - </NewLink> 742 + </Link> 716 743 ))} 717 744 </Animated.View> 718 745 ) 719 746 } 720 747 721 748 function AdditionalPostText({post}: {post?: AppBskyFeedDefs.PostView}) { 722 - const pal = usePalette('default') 749 + const t = useTheme() 723 750 if ( 724 751 post && 725 752 bsky.dangerousIsType<AppBskyFeedPost.Record>( ··· 732 759 return ( 733 760 <> 734 761 {text?.length > 0 && ( 735 - <Text emoji style={pal.textLight}> 762 + <Text 763 + emoji 764 + style={[a.text_md, a.leading_snug, t.atoms.text_contrast_medium]}> 736 765 {text} 737 766 </Text> 738 767 )} ··· 746 775 } 747 776 748 777 const styles = StyleSheet.create({ 749 - pointer: isWeb 750 - ? { 751 - // @ts-ignore web only 752 - cursor: 'pointer', 753 - } 754 - : {}, 755 - 756 - outer: { 757 - padding: 10, 758 - paddingRight: 15, 759 - flexDirection: 'row', 760 - }, 761 778 layoutIcon: { 762 779 width: 60, 763 780 alignItems: 'flex-end', ··· 767 784 marginRight: 10, 768 785 marginTop: 4, 769 786 }, 770 - layoutContent: { 771 - flex: 1, 772 - }, 773 - avis: { 774 - flexDirection: 'row', 775 - alignItems: 'center', 776 - }, 777 - aviExtraCount: { 778 - fontWeight: '600', 779 - paddingLeft: 6, 780 - }, 781 - meta: { 782 - flexDirection: 'row', 783 - flexWrap: 'wrap', 784 - paddingTop: 6, 785 - paddingBottom: 2, 786 - }, 787 - postText: { 788 - paddingBottom: 5, 789 - color: colors.black, 790 - }, 791 787 additionalPostImages: { 792 788 marginTop: 5, 793 789 marginLeft: 2, ··· 798 794 paddingVertical: 12, 799 795 marginTop: 6, 800 796 }, 801 - 802 797 addedContainer: { 803 798 paddingTop: 4, 804 799 paddingLeft: 36, ··· 812 807 paddingTop: 10, 813 808 paddingBottom: 6, 814 809 }, 815 - expandedAuthorsCloseBtnIcon: { 816 - marginLeft: 4, 817 - marginRight: 4, 818 - }, 819 810 expandedAuthor: { 820 811 flexDirection: 'row', 821 812 alignItems: 'center', 822 813 marginTop: 10, 823 814 height: EXPANDED_AUTHOR_EL_HEIGHT, 824 - }, 825 - expandedAuthorAvi: { 826 - marginRight: 5, 827 815 }, 828 816 })