parent
4b98992257
commit
ab11f206d8
12 changed files with 58 additions and 23 deletions
|
@ -3,6 +3,7 @@ import {AppBskyEmbedImages} from '@atproto/api'
|
||||||
import {RootStoreModel} from 'state/models/root-store'
|
import {RootStoreModel} from 'state/models/root-store'
|
||||||
import {NotificationsFeedItemModel} from 'state/models/feeds/notifications'
|
import {NotificationsFeedItemModel} from 'state/models/feeds/notifications'
|
||||||
import {enforceLen} from 'lib/strings/helpers'
|
import {enforceLen} from 'lib/strings/helpers'
|
||||||
|
import {sanitizeDisplayName} from './strings/display-names'
|
||||||
import {resetToTab} from '../Navigation'
|
import {resetToTab} from '../Navigation'
|
||||||
|
|
||||||
export function init(store: RootStoreModel) {
|
export function init(store: RootStoreModel) {
|
||||||
|
@ -42,7 +43,9 @@ export function displayNotification(
|
||||||
export function displayNotificationFromModel(
|
export function displayNotificationFromModel(
|
||||||
notif: NotificationsFeedItemModel,
|
notif: NotificationsFeedItemModel,
|
||||||
) {
|
) {
|
||||||
let author = notif.author.displayName || notif.author.handle
|
let author = sanitizeDisplayName(
|
||||||
|
notif.author.displayName || notif.author.handle,
|
||||||
|
)
|
||||||
let title: string
|
let title: string
|
||||||
let body: string = ''
|
let body: string = ''
|
||||||
if (notif.isLike) {
|
if (notif.isLike) {
|
||||||
|
|
12
src/lib/strings/display-names.ts
Normal file
12
src/lib/strings/display-names.ts
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
// \u2705 = ✅
|
||||||
|
// \u2713 = ✓
|
||||||
|
// \u2714 = ✔
|
||||||
|
// \u2611 = ☑
|
||||||
|
const CHECK_MARKS_RE = /[\u2705\u2713\u2714\u2611]/gu
|
||||||
|
|
||||||
|
export function sanitizeDisplayName(str: string): string {
|
||||||
|
if (typeof str === 'string') {
|
||||||
|
return str.replace(CHECK_MARKS_RE, '')
|
||||||
|
}
|
||||||
|
return ''
|
||||||
|
}
|
|
@ -26,6 +26,7 @@ import {useStores} from 'state/index'
|
||||||
import * as apilib from 'lib/api/index'
|
import * as apilib from 'lib/api/index'
|
||||||
import {ComposerOpts} from 'state/models/ui/shell'
|
import {ComposerOpts} from 'state/models/ui/shell'
|
||||||
import {s, colors, gradients} from 'lib/styles'
|
import {s, colors, gradients} from 'lib/styles'
|
||||||
|
import {sanitizeDisplayName} from 'lib/strings/display-names'
|
||||||
import {cleanError} from 'lib/strings/errors'
|
import {cleanError} from 'lib/strings/errors'
|
||||||
import {SelectPhotoBtn} from './photos/SelectPhotoBtn'
|
import {SelectPhotoBtn} from './photos/SelectPhotoBtn'
|
||||||
import {OpenCameraBtn} from './photos/OpenCameraBtn'
|
import {OpenCameraBtn} from './photos/OpenCameraBtn'
|
||||||
|
@ -265,7 +266,9 @@ export const ComposePost = observer(function ComposePost({
|
||||||
<UserAvatar avatar={replyTo.author.avatar} size={50} />
|
<UserAvatar avatar={replyTo.author.avatar} size={50} />
|
||||||
<View style={styles.replyToPost}>
|
<View style={styles.replyToPost}>
|
||||||
<Text type="xl-medium" style={[pal.text]}>
|
<Text type="xl-medium" style={[pal.text]}>
|
||||||
{replyTo.author.displayName || replyTo.author.handle}
|
{sanitizeDisplayName(
|
||||||
|
replyTo.author.displayName || replyTo.author.handle,
|
||||||
|
)}
|
||||||
</Text>
|
</Text>
|
||||||
<Text type="post-text" style={pal.text} numberOfLines={6}>
|
<Text type="post-text" style={pal.text} numberOfLines={6}>
|
||||||
{replyTo.text}
|
{replyTo.text}
|
||||||
|
|
|
@ -18,6 +18,7 @@ import {NotificationsFeedItemModel} from 'state/models/feeds/notifications'
|
||||||
import {PostThreadModel} from 'state/models/content/post-thread'
|
import {PostThreadModel} from 'state/models/content/post-thread'
|
||||||
import {s, colors} from 'lib/styles'
|
import {s, colors} from 'lib/styles'
|
||||||
import {ago} from 'lib/strings/time'
|
import {ago} from 'lib/strings/time'
|
||||||
|
import {sanitizeDisplayName} from 'lib/strings/display-names'
|
||||||
import {pluralize} from 'lib/strings/helpers'
|
import {pluralize} from 'lib/strings/helpers'
|
||||||
import {HeartIconSolid} from 'lib/icons'
|
import {HeartIconSolid} from 'lib/icons'
|
||||||
import {Text} from '../util/text/Text'
|
import {Text} from '../util/text/Text'
|
||||||
|
@ -187,7 +188,9 @@ export const FeedItem = observer(function FeedItem({
|
||||||
key={authors[0].href}
|
key={authors[0].href}
|
||||||
style={[pal.text, s.bold, styles.metaItem]}
|
style={[pal.text, s.bold, styles.metaItem]}
|
||||||
href={authors[0].href}
|
href={authors[0].href}
|
||||||
text={authors[0].displayName || authors[0].handle}
|
text={sanitizeDisplayName(
|
||||||
|
authors[0].displayName || authors[0].handle,
|
||||||
|
)}
|
||||||
/>
|
/>
|
||||||
{authors.length > 1 ? (
|
{authors.length > 1 ? (
|
||||||
<>
|
<>
|
||||||
|
@ -310,7 +313,7 @@ function ExpandedAuthorsList({
|
||||||
<Link
|
<Link
|
||||||
key={author.href}
|
key={author.href}
|
||||||
href={author.href}
|
href={author.href}
|
||||||
title={author.displayName || author.handle}
|
title={sanitizeDisplayName(author.displayName || author.handle)}
|
||||||
style={styles.expandedAuthor}
|
style={styles.expandedAuthor}
|
||||||
asAnchor>
|
asAnchor>
|
||||||
<View style={styles.expandedAuthorAvi}>
|
<View style={styles.expandedAuthorAvi}>
|
||||||
|
@ -322,7 +325,7 @@ function ExpandedAuthorsList({
|
||||||
numberOfLines={1}
|
numberOfLines={1}
|
||||||
style={pal.text}
|
style={pal.text}
|
||||||
lineHeight={1.2}>
|
lineHeight={1.2}>
|
||||||
{author.displayName || author.handle}
|
{sanitizeDisplayName(author.displayName || author.handle)}
|
||||||
|
|
||||||
<Text style={[pal.textLight]} lineHeight={1.2}>
|
<Text style={[pal.textLight]} lineHeight={1.2}>
|
||||||
{author.handle}
|
{author.handle}
|
||||||
|
|
|
@ -15,6 +15,7 @@ import {CenteredView} from '../util/Views.web'
|
||||||
import {useStores} from 'state/index'
|
import {useStores} from 'state/index'
|
||||||
import {usePalette} from 'lib/hooks/usePalette'
|
import {usePalette} from 'lib/hooks/usePalette'
|
||||||
import {s} from 'lib/styles'
|
import {s} from 'lib/styles'
|
||||||
|
import {sanitizeDisplayName} from 'lib/strings/display-names'
|
||||||
|
|
||||||
export const InvitedUsers = observer(() => {
|
export const InvitedUsers = observer(() => {
|
||||||
const store = useStores()
|
const store = useStores()
|
||||||
|
@ -65,7 +66,7 @@ function InvitedUser({
|
||||||
type="md-bold"
|
type="md-bold"
|
||||||
style={pal.text}
|
style={pal.text}
|
||||||
href={`/profile/${profile.handle}`}
|
href={`/profile/${profile.handle}`}
|
||||||
text={profile.displayName || profile.handle}
|
text={sanitizeDisplayName(profile.displayName || profile.handle)}
|
||||||
/>{' '}
|
/>{' '}
|
||||||
joined using your invite code!
|
joined using your invite code!
|
||||||
</Text>
|
</Text>
|
||||||
|
|
|
@ -16,6 +16,7 @@ import * as Toast from '../util/Toast'
|
||||||
import {UserAvatar} from '../util/UserAvatar'
|
import {UserAvatar} from '../util/UserAvatar'
|
||||||
import {s} from 'lib/styles'
|
import {s} from 'lib/styles'
|
||||||
import {ago} from 'lib/strings/time'
|
import {ago} from 'lib/strings/time'
|
||||||
|
import {sanitizeDisplayName} from 'lib/strings/display-names'
|
||||||
import {pluralize} from 'lib/strings/helpers'
|
import {pluralize} from 'lib/strings/helpers'
|
||||||
import {useStores} from 'state/index'
|
import {useStores} from 'state/index'
|
||||||
import {PostMeta} from '../util/PostMeta'
|
import {PostMeta} from '../util/PostMeta'
|
||||||
|
@ -151,7 +152,9 @@ export const PostThreadItem = observer(function PostThreadItem({
|
||||||
style={[pal.text]}
|
style={[pal.text]}
|
||||||
numberOfLines={1}
|
numberOfLines={1}
|
||||||
lineHeight={1.2}>
|
lineHeight={1.2}>
|
||||||
{item.post.author.displayName || item.post.author.handle}
|
{sanitizeDisplayName(
|
||||||
|
item.post.author.displayName || item.post.author.handle,
|
||||||
|
)}
|
||||||
</Text>
|
</Text>
|
||||||
</Link>
|
</Link>
|
||||||
<Text type="md" style={[styles.metaItem, pal.textLight]}>
|
<Text type="md" style={[styles.metaItem, pal.textLight]}>
|
||||||
|
|
|
@ -22,6 +22,7 @@ import {s} from 'lib/styles'
|
||||||
import {useStores} from 'state/index'
|
import {useStores} from 'state/index'
|
||||||
import {usePalette} from 'lib/hooks/usePalette'
|
import {usePalette} from 'lib/hooks/usePalette'
|
||||||
import {useAnalytics} from 'lib/analytics'
|
import {useAnalytics} from 'lib/analytics'
|
||||||
|
import {sanitizeDisplayName} from 'lib/strings/display-names'
|
||||||
|
|
||||||
export const FeedItem = observer(function ({
|
export const FeedItem = observer(function ({
|
||||||
item,
|
item,
|
||||||
|
@ -151,9 +152,9 @@ export const FeedItem = observer(function ({
|
||||||
<Link
|
<Link
|
||||||
style={styles.includeReason}
|
style={styles.includeReason}
|
||||||
href={`/profile/${item.reasonRepost.by.handle}`}
|
href={`/profile/${item.reasonRepost.by.handle}`}
|
||||||
title={
|
title={sanitizeDisplayName(
|
||||||
item.reasonRepost.by.displayName || item.reasonRepost.by.handle
|
item.reasonRepost.by.displayName || item.reasonRepost.by.handle,
|
||||||
}>
|
)}>
|
||||||
<FontAwesomeIcon
|
<FontAwesomeIcon
|
||||||
icon="retweet"
|
icon="retweet"
|
||||||
style={[
|
style={[
|
||||||
|
@ -172,10 +173,10 @@ export const FeedItem = observer(function ({
|
||||||
style={pal.textLight}
|
style={pal.textLight}
|
||||||
lineHeight={1.2}
|
lineHeight={1.2}
|
||||||
numberOfLines={1}
|
numberOfLines={1}
|
||||||
text={
|
text={sanitizeDisplayName(
|
||||||
item.reasonRepost.by.displayName ||
|
item.reasonRepost.by.displayName ||
|
||||||
item.reasonRepost.by.handle
|
item.reasonRepost.by.handle,
|
||||||
}
|
)}
|
||||||
href={`/profile/${item.reasonRepost.by.handle}`}
|
href={`/profile/${item.reasonRepost.by.handle}`}
|
||||||
/>
|
/>
|
||||||
</Text>
|
</Text>
|
||||||
|
|
|
@ -9,6 +9,7 @@ import {s} from 'lib/styles'
|
||||||
import {usePalette} from 'lib/hooks/usePalette'
|
import {usePalette} from 'lib/hooks/usePalette'
|
||||||
import {useStores} from 'state/index'
|
import {useStores} from 'state/index'
|
||||||
import {FollowButton} from './FollowButton'
|
import {FollowButton} from './FollowButton'
|
||||||
|
import {sanitizeDisplayName} from 'lib/strings/display-names'
|
||||||
|
|
||||||
export function ProfileCard({
|
export function ProfileCard({
|
||||||
testID,
|
testID,
|
||||||
|
@ -57,7 +58,7 @@ export function ProfileCard({
|
||||||
style={[s.bold, pal.text]}
|
style={[s.bold, pal.text]}
|
||||||
numberOfLines={1}
|
numberOfLines={1}
|
||||||
lineHeight={1.2}>
|
lineHeight={1.2}>
|
||||||
{displayName || handle}
|
{sanitizeDisplayName(displayName || handle)}
|
||||||
</Text>
|
</Text>
|
||||||
<Text type="md" style={[pal.textLight]} numberOfLines={1}>
|
<Text type="md" style={[pal.textLight]} numberOfLines={1}>
|
||||||
@{handle}
|
@{handle}
|
||||||
|
|
|
@ -18,6 +18,7 @@ import {useStores} from 'state/index'
|
||||||
import {ProfileImageLightbox} from 'state/models/ui/shell'
|
import {ProfileImageLightbox} from 'state/models/ui/shell'
|
||||||
import {pluralize} from 'lib/strings/helpers'
|
import {pluralize} from 'lib/strings/helpers'
|
||||||
import {toShareUrl} from 'lib/strings/url-helpers'
|
import {toShareUrl} from 'lib/strings/url-helpers'
|
||||||
|
import {sanitizeDisplayName} from 'lib/strings/display-names'
|
||||||
import {s, colors} from 'lib/styles'
|
import {s, colors} from 'lib/styles'
|
||||||
import {DropdownButton, DropdownItem} from '../util/forms/DropdownButton'
|
import {DropdownButton, DropdownItem} from '../util/forms/DropdownButton'
|
||||||
import * as Toast from '../util/Toast'
|
import * as Toast from '../util/Toast'
|
||||||
|
@ -58,7 +59,7 @@ export const ProfileHeader = observer(
|
||||||
</View>
|
</View>
|
||||||
<View style={styles.displayNameLine}>
|
<View style={styles.displayNameLine}>
|
||||||
<Text type="title-2xl" style={[pal.text, styles.title]}>
|
<Text type="title-2xl" style={[pal.text, styles.title]}>
|
||||||
{view.displayName || view.handle}
|
{sanitizeDisplayName(view.displayName || view.handle)}
|
||||||
</Text>
|
</Text>
|
||||||
</View>
|
</View>
|
||||||
</View>
|
</View>
|
||||||
|
@ -108,9 +109,9 @@ const ProfileHeaderLoaded = observer(function ProfileHeaderLoaded({
|
||||||
view?.toggleFollowing().then(
|
view?.toggleFollowing().then(
|
||||||
() => {
|
() => {
|
||||||
Toast.show(
|
Toast.show(
|
||||||
`${view.viewer.following ? 'Following' : 'No longer following'} ${
|
`${
|
||||||
view.displayName || view.handle
|
view.viewer.following ? 'Following' : 'No longer following'
|
||||||
}`,
|
} ${sanitizeDisplayName(view.displayName || view.handle)}`,
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
err => store.log.error('Failed to toggle follow', err),
|
err => store.log.error('Failed to toggle follow', err),
|
||||||
|
@ -266,7 +267,7 @@ const ProfileHeaderLoaded = observer(function ProfileHeaderLoaded({
|
||||||
testID="profileHeaderDisplayName"
|
testID="profileHeaderDisplayName"
|
||||||
type="title-2xl"
|
type="title-2xl"
|
||||||
style={[pal.text, styles.title]}>
|
style={[pal.text, styles.title]}>
|
||||||
{view.displayName || view.handle}
|
{sanitizeDisplayName(view.displayName || view.handle)}
|
||||||
</Text>
|
</Text>
|
||||||
</View>
|
</View>
|
||||||
<View style={styles.handleLine}>
|
<View style={styles.handleLine}>
|
||||||
|
|
|
@ -5,6 +5,7 @@ import {FoafsModel} from 'state/models/discovery/foafs'
|
||||||
import {SuggestedActorsModel} from 'state/models/discovery/suggested-actors'
|
import {SuggestedActorsModel} from 'state/models/discovery/suggested-actors'
|
||||||
import {SuggestedFollows} from 'view/com/discover/SuggestedFollows'
|
import {SuggestedFollows} from 'view/com/discover/SuggestedFollows'
|
||||||
import {ProfileCardFeedLoadingPlaceholder} from 'view/com/util/LoadingPlaceholder'
|
import {ProfileCardFeedLoadingPlaceholder} from 'view/com/util/LoadingPlaceholder'
|
||||||
|
import {sanitizeDisplayName} from 'lib/strings/display-names'
|
||||||
|
|
||||||
export const Suggestions = observer(
|
export const Suggestions = observer(
|
||||||
({
|
({
|
||||||
|
@ -43,7 +44,9 @@ export const Suggestions = observer(
|
||||||
return (
|
return (
|
||||||
<View key={`sf-${item.did}`} style={styles.suggestions}>
|
<View key={`sf-${item.did}`} style={styles.suggestions}>
|
||||||
<SuggestedFollows
|
<SuggestedFollows
|
||||||
title={`Followed by ${item.displayName || item.handle}`}
|
title={`Followed by ${sanitizeDisplayName(
|
||||||
|
item.displayName || item.handle,
|
||||||
|
)}`}
|
||||||
suggestions={item.follows.slice(0, 10)}
|
suggestions={item.follows.slice(0, 10)}
|
||||||
/>
|
/>
|
||||||
</View>
|
</View>
|
||||||
|
|
|
@ -9,6 +9,7 @@ import {UserAvatar} from './UserAvatar'
|
||||||
import {observer} from 'mobx-react-lite'
|
import {observer} from 'mobx-react-lite'
|
||||||
import {FollowButton} from '../profile/FollowButton'
|
import {FollowButton} from '../profile/FollowButton'
|
||||||
import {FollowState} from 'state/models/cache/my-follows'
|
import {FollowState} from 'state/models/cache/my-follows'
|
||||||
|
import {sanitizeDisplayName} from 'lib/strings/display-names'
|
||||||
|
|
||||||
interface PostMetaOpts {
|
interface PostMetaOpts {
|
||||||
authorAvatar?: string
|
authorAvatar?: string
|
||||||
|
@ -52,7 +53,7 @@ export const PostMeta = observer(function (opts: PostMetaOpts) {
|
||||||
style={pal.text}
|
style={pal.text}
|
||||||
numberOfLines={1}
|
numberOfLines={1}
|
||||||
lineHeight={1.2}
|
lineHeight={1.2}
|
||||||
text={displayName}
|
text={sanitizeDisplayName(displayName)}
|
||||||
href={`/profile/${opts.authorHandle}`}
|
href={`/profile/${opts.authorHandle}`}
|
||||||
/>
|
/>
|
||||||
<Text type="md" style={pal.textLight} lineHeight={1.2}>
|
<Text type="md" style={pal.textLight} lineHeight={1.2}>
|
||||||
|
@ -103,7 +104,7 @@ export const PostMeta = observer(function (opts: PostMetaOpts) {
|
||||||
lineHeight={1.2}
|
lineHeight={1.2}
|
||||||
text={
|
text={
|
||||||
<>
|
<>
|
||||||
{displayName}
|
{sanitizeDisplayName(displayName)}
|
||||||
<Text type="md" style={[pal.textLight]}>
|
<Text type="md" style={[pal.textLight]}>
|
||||||
{handle}
|
{handle}
|
||||||
</Text>
|
</Text>
|
||||||
|
|
|
@ -6,6 +6,7 @@ import {Text} from './text/Text'
|
||||||
import {LoadingPlaceholder} from './LoadingPlaceholder'
|
import {LoadingPlaceholder} from './LoadingPlaceholder'
|
||||||
import {useStores} from 'state/index'
|
import {useStores} from 'state/index'
|
||||||
import {TypographyVariant} from 'lib/ThemeContext'
|
import {TypographyVariant} from 'lib/ThemeContext'
|
||||||
|
import {sanitizeDisplayName} from 'lib/strings/display-names'
|
||||||
|
|
||||||
export function UserInfoText({
|
export function UserInfoText({
|
||||||
type = 'md',
|
type = 'md',
|
||||||
|
@ -68,7 +69,9 @@ export function UserInfoText({
|
||||||
lineHeight={1.2}
|
lineHeight={1.2}
|
||||||
numberOfLines={1}
|
numberOfLines={1}
|
||||||
href={`/profile/${profile.handle}`}
|
href={`/profile/${profile.handle}`}
|
||||||
text={`${prefix || ''}${profile[attr] || profile.handle}`}
|
text={`${prefix || ''}${sanitizeDisplayName(
|
||||||
|
profile[attr] || profile.handle,
|
||||||
|
)}`}
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue