Bluesky app fork with some witchin' additions 💫

Fix RTL text rendering for display names (#4747)

* header display name rtl support

* highlighted post rtl

* move `NON_BREAKING_SPACE` to an external constant

* rtl support in search dropdown

* profile card rtl

* old profile card rtl

* hover card

* wizard list card

* new chat

* account card

* chat header

* clean up notifications

* just force LTR on meta display name

authored by hailey.at and committed by

GitHub f8a59e10 d5503d17

+41 -23
+3 -1
src/components/ProfileCard.tsx
··· 166 167 return ( 168 <View style={[a.flex_1]}> 169 - <Text style={[a.text_md, a.font_bold, a.leading_snug]} numberOfLines={1}> 170 {name} 171 </Text> 172 <Text
··· 166 167 return ( 168 <View style={[a.flex_1]}> 169 + <Text 170 + style={[a.text_md, a.font_bold, a.leading_snug, a.self_start]} 171 + numberOfLines={1}> 172 {name} 173 </Text> 174 <Text
+2 -1
src/components/ProfileHoverCard/index.web.tsx
··· 462 463 <Link to={profileURL} label={_(msg`View profile`)} onPress={hide}> 464 <View style={[a.pb_sm, a.flex_1]}> 465 - <Text style={[a.pt_md, a.pb_xs, a.text_lg, a.font_bold]}> 466 {sanitizeDisplayName( 467 profile.displayName || sanitizeHandle(profile.handle), 468 moderation.ui('displayName'),
··· 462 463 <Link to={profileURL} label={_(msg`View profile`)} onPress={hide}> 464 <View style={[a.pb_sm, a.flex_1]}> 465 + <Text 466 + style={[a.pt_md, a.pb_xs, a.text_lg, a.font_bold, a.self_start]}> 467 {sanitizeDisplayName( 468 profile.displayName || sanitizeHandle(profile.handle), 469 moderation.ui('displayName'),
+7 -1
src/components/StarterPack/Wizard/WizardListCard.tsx
··· 78 /> 79 <View style={[a.flex_1, a.gap_2xs]}> 80 <Text 81 - style={[a.flex_1, a.font_bold, a.text_md, a.leading_tight]} 82 numberOfLines={1}> 83 {displayName} 84 </Text>
··· 78 /> 79 <View style={[a.flex_1, a.gap_2xs]}> 80 <Text 81 + style={[ 82 + a.flex_1, 83 + a.font_bold, 84 + a.text_md, 85 + a.leading_tight, 86 + a.self_start, 87 + ]} 88 numberOfLines={1}> 89 {displayName} 90 </Text>
+6 -1
src/components/dms/MessagesListHeader.tsx
··· 168 </View> 169 <View style={a.flex_1}> 170 <Text 171 - style={[a.text_md, a.font_bold, web(a.leading_normal)]} 172 numberOfLines={1}> 173 {displayName} 174 </Text>
··· 168 </View> 169 <View style={a.flex_1}> 170 <Text 171 + style={[ 172 + a.text_md, 173 + a.font_bold, 174 + a.self_start, 175 + web(a.leading_normal), 176 + ]} 177 numberOfLines={1}> 178 {displayName} 179 </Text>
+1 -1
src/components/dms/dialogs/SearchablePeopleList.tsx
··· 395 /> 396 <View style={[a.flex_1, a.gap_2xs]}> 397 <Text 398 - style={[t.atoms.text, a.font_bold, a.leading_tight]} 399 numberOfLines={1}> 400 {displayName} 401 </Text>
··· 395 /> 396 <View style={[a.flex_1, a.gap_2xs]}> 397 <Text 398 + style={[t.atoms.text, a.font_bold, a.leading_tight, a.self_start]} 399 numberOfLines={1}> 400 {displayName} 401 </Text>
+1
src/lib/strings/constants.ts
···
··· 1 + export const NON_BREAKING_SPACE = '\u00A0'
+1 -1
src/screens/Profile/Header/DisplayName.tsx
··· 20 <View pointerEvents="none"> 21 <Text 22 testID="profileHeaderDisplayName" 23 - style={[t.atoms.text, a.text_4xl, {fontWeight: '500'}]}> 24 {sanitizeDisplayName( 25 profile.displayName || sanitizeHandle(profile.handle), 26 moderation.ui('displayName'),
··· 20 <View pointerEvents="none"> 21 <Text 22 testID="profileHeaderDisplayName" 23 + style={[t.atoms.text, a.text_4xl, a.self_start, {fontWeight: '500'}]}> 24 {sanitizeDisplayName( 25 profile.displayName || sanitizeHandle(profile.handle), 26 moderation.ui('displayName'),
+6 -3
src/view/com/notifications/FeedItem.tsx
··· 58 import {parseTenorGif} from '#/lib/strings/embed-player' 59 import {logger} from '#/logger' 60 import {NavigationProp} from 'lib/routes/types' 61 import {DM_SERVICE_HEADERS} from 'state/queries/messages/const' 62 import {useAgent} from 'state/session' 63 import {Button, ButtonText} from '#/components/Button' ··· 274 showDmButton={item.type === 'starterpack-joined' || isFollowBack} 275 /> 276 <ExpandedAuthorsList visible={isAuthorsExpanded} authors={authors} /> 277 - <Text style={styles.meta}> 278 <TextLink 279 key={authors[0].href} 280 style={[pal.text, s.bold]} 281 href={authors[0].href} 282 - text={sanitizeDisplayName( 283 - authors[0].profile.displayName || authors[0].profile.handle, 284 )} 285 disableMismatchWarning 286 />
··· 58 import {parseTenorGif} from '#/lib/strings/embed-player' 59 import {logger} from '#/logger' 60 import {NavigationProp} from 'lib/routes/types' 61 + import {forceLTR} from 'lib/strings/bidi' 62 import {DM_SERVICE_HEADERS} from 'state/queries/messages/const' 63 import {useAgent} from 'state/session' 64 import {Button, ButtonText} from '#/components/Button' ··· 275 showDmButton={item.type === 'starterpack-joined' || isFollowBack} 276 /> 277 <ExpandedAuthorsList visible={isAuthorsExpanded} authors={authors} /> 278 + <Text style={[styles.meta, a.self_start]}> 279 <TextLink 280 key={authors[0].href} 281 style={[pal.text, s.bold]} 282 href={authors[0].href} 283 + text={forceLTR( 284 + sanitizeDisplayName( 285 + authors[0].profile.displayName || authors[0].profile.handle, 286 + ), 287 )} 288 disableMismatchWarning 289 />
+1 -1
src/view/com/post-thread/PostThreadItem.tsx
··· 281 <Link style={s.flex1} href={authorHref} title={authorTitle}> 282 <Text 283 type="xl-bold" 284 - style={[pal.text]} 285 numberOfLines={1} 286 lineHeight={1.2}> 287 {sanitizeDisplayName(
··· 281 <Link style={s.flex1} href={authorHref} title={authorTitle}> 282 <Text 283 type="xl-bold" 284 + style={[pal.text, a.self_start]} 285 numberOfLines={1} 286 lineHeight={1.2}> 287 {sanitizeDisplayName(
+1 -1
src/view/com/profile/ProfileCard.tsx
··· 97 <View style={styles.layoutContent}> 98 <Text 99 type="lg" 100 - style={[s.bold, pal.text]} 101 numberOfLines={1} 102 lineHeight={1.2}> 103 {sanitizeDisplayName(
··· 97 <View style={styles.layoutContent}> 98 <Text 99 type="lg" 100 + style={[s.bold, pal.text, a.self_start]} 101 numberOfLines={1} 102 lineHeight={1.2}> 103 {sanitizeDisplayName(
+8 -10
src/view/com/util/PostMeta.tsx
··· 6 import {precacheProfile} from '#/state/queries/profile' 7 import {usePalette} from 'lib/hooks/usePalette' 8 import {makeProfileLink} from 'lib/routes/links' 9 import {sanitizeDisplayName} from 'lib/strings/display-names' 10 import {sanitizeHandle} from 'lib/strings/handles' 11 import {niceDate} from 'lib/strings/time' ··· 31 onOpenAuthor?: () => void 32 style?: StyleProp<ViewStyle> 33 } 34 - 35 - const NON_BREAKING_SPACE = '\u00A0' 36 37 let PostMeta = (opts: PostMetaOpts): React.ReactNode => { 38 const pal = usePalette('default') ··· 70 style={[pal.text]} 71 lineHeight={1.2} 72 disableMismatchWarning 73 - text={ 74 - <> 75 - {sanitizeDisplayName( 76 - displayName, 77 - opts.moderation?.ui('displayName'), 78 - )} 79 - </> 80 - } 81 href={profileLink} 82 onBeforePress={onBeforePressAuthor} 83 />
··· 6 import {precacheProfile} from '#/state/queries/profile' 7 import {usePalette} from 'lib/hooks/usePalette' 8 import {makeProfileLink} from 'lib/routes/links' 9 + import {forceLTR} from 'lib/strings/bidi' 10 + import {NON_BREAKING_SPACE} from 'lib/strings/constants' 11 import {sanitizeDisplayName} from 'lib/strings/display-names' 12 import {sanitizeHandle} from 'lib/strings/handles' 13 import {niceDate} from 'lib/strings/time' ··· 33 onOpenAuthor?: () => void 34 style?: StyleProp<ViewStyle> 35 } 36 37 let PostMeta = (opts: PostMetaOpts): React.ReactNode => { 38 const pal = usePalette('default') ··· 70 style={[pal.text]} 71 lineHeight={1.2} 72 disableMismatchWarning 73 + text={forceLTR( 74 + sanitizeDisplayName( 75 + displayName, 76 + opts.moderation?.ui('displayName'), 77 + ), 78 + )} 79 href={profileLink} 80 onBeforePress={onBeforePressAuthor} 81 />
+2 -1
src/view/screens/Settings/index.tsx
··· 68 import {Email2FAToggle} from './Email2FAToggle' 69 import {ExportCarDialog} from './ExportCarDialog' 70 import hairlineWidth = StyleSheet.hairlineWidth 71 72 function SettingsAccountCard({ 73 account, ··· 104 /> 105 </View> 106 <View style={[s.flex1]}> 107 - <Text type="md-bold" style={pal.text} numberOfLines={1}> 108 {profile?.displayName || account.handle} 109 </Text> 110 <Text type="sm" style={pal.textLight} numberOfLines={1}>
··· 68 import {Email2FAToggle} from './Email2FAToggle' 69 import {ExportCarDialog} from './ExportCarDialog' 70 import hairlineWidth = StyleSheet.hairlineWidth 71 + import {atoms as a} from '#/alf' 72 73 function SettingsAccountCard({ 74 account, ··· 105 /> 106 </View> 107 <View style={[s.flex1]}> 108 + <Text type="md-bold" style={[pal.text, a.self_start]} numberOfLines={1}> 109 {profile?.displayName || account.handle} 110 </Text> 111 <Text type="sm" style={pal.textLight} numberOfLines={1}>
+2 -1
src/view/shell/desktop/Search.tsx
··· 30 import {Link} from '#/view/com/util/Link' 31 import {UserAvatar} from '#/view/com/util/UserAvatar' 32 import {Text} from 'view/com/util/text/Text' 33 34 let SearchLinkCard = ({ 35 label, ··· 127 <View style={{flex: 1}}> 128 <Text 129 type="lg" 130 - style={[s.bold, pal.text]} 131 numberOfLines={1} 132 lineHeight={1.2}> 133 {sanitizeDisplayName(
··· 30 import {Link} from '#/view/com/util/Link' 31 import {UserAvatar} from '#/view/com/util/UserAvatar' 32 import {Text} from 'view/com/util/text/Text' 33 + import {atoms as a} from '#/alf' 34 35 let SearchLinkCard = ({ 36 label, ··· 128 <View style={{flex: 1}}> 129 <Text 130 type="lg" 131 + style={[s.bold, pal.text, a.self_start]} 132 numberOfLines={1} 133 lineHeight={1.2}> 134 {sanitizeDisplayName(