diff options
author | Eric Bailey <git@esb.lol> | 2024-09-24 20:10:13 -0500 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-09-24 20:10:13 -0500 |
commit | b38d4697b7a42a5e4c48d86a6528a20ace9c034e (patch) | |
tree | d8f28c858044d45a15aaab741b668e38f8353528 /src | |
parent | 2429d5d1ae51fa21d46970263fa581fd2eb19cdd (diff) | |
download | voidsky-b38d4697b7a42a5e4c48d86a6528a20ace9c034e.tar.zst |
[Neue] Post avi, `PostMeta` cleanup (#5450)
* Support emoji in text with custom font * Add emoji support to elements that need it * Remove unused file causing lint failure * Add web only link variant * Refactor PostMeta * Reduce avi size in feeds * Fix alignment, emoji, in PostMeta * Smaller avis in notifications * Shrink post placeholder avi * Handle the handle again * Link cleanup * Cleanup unused props * Fix text wrapping in timestamp * Fix underline color * Tighten up spacing * Web only whiteSpace
Diffstat (limited to 'src')
-rw-r--r-- | src/App.web.tsx | 4 | ||||
-rw-r--r-- | src/components/Link.tsx | 36 | ||||
-rw-r--r-- | src/screens/Messages/Conversation/MessageInputEmbed.tsx | 1 | ||||
-rw-r--r-- | src/view/com/post-thread/PostThreadItem.tsx | 8 | ||||
-rw-r--r-- | src/view/com/post/Post.tsx | 3 | ||||
-rw-r--r-- | src/view/com/posts/FeedItem.tsx | 5 | ||||
-rw-r--r-- | src/view/com/posts/FeedSlice.tsx | 6 | ||||
-rw-r--r-- | src/view/com/util/LoadingPlaceholder.tsx | 10 | ||||
-rw-r--r-- | src/view/com/util/PostMeta.tsx | 153 | ||||
-rw-r--r-- | src/view/com/util/post-embeds/QuoteEmbed.tsx | 11 |
10 files changed, 120 insertions, 117 deletions
diff --git a/src/App.web.tsx b/src/App.web.tsx index 7d98737a3..1664812d0 100644 --- a/src/App.web.tsx +++ b/src/App.web.tsx @@ -1,5 +1,5 @@ -import 'lib/sentry' // must be near top -import 'view/icons' +import '#/lib/sentry' // must be near top +import '#/view/icons' import './style.css' import React, {useEffect, useState} from 'react' diff --git a/src/components/Link.tsx b/src/components/Link.tsx index 6c25faffb..c80b9f370 100644 --- a/src/components/Link.tsx +++ b/src/components/Link.tsx @@ -9,6 +9,7 @@ import {sanitizeUrl} from '@braintree/sanitize-url' import {StackActions, useLinkProps} from '@react-navigation/native' import {BSKY_DOWNLOAD_URL} from '#/lib/constants' +import {useNavigationDeduped} from '#/lib/hooks/useNavigationDeduped' import {AllNavigatorParams} from '#/lib/routes/types' import {shareUrl} from '#/lib/sharing' import { @@ -17,11 +18,10 @@ import { isExternalUrl, linkRequiresWarning, } from '#/lib/strings/url-helpers' -import {isNative} from '#/platform/detection' +import {isNative, isWeb} from '#/platform/detection' import {shouldClickOpenNewTab} from '#/platform/urls' import {useModalControls} from '#/state/modals' import {useOpenLink} from '#/state/preferences/in-app-browser' -import {useNavigationDeduped} from 'lib/hooks/useNavigationDeduped' import {atoms as a, flatten, TextStyleProp, useTheme, web} from '#/alf' import {Button, ButtonProps} from '#/components/Button' import {useInteractionState} from '#/components/hooks/useInteractionState' @@ -244,7 +244,10 @@ export function Link({ export type InlineLinkProps = React.PropsWithChildren< BaseLinkProps & TextStyleProp & Pick<TextProps, 'selectable'> > & - Pick<ButtonProps, 'label'> + Pick<ButtonProps, 'label'> & { + disableUnderline?: boolean + title?: TextProps['title'] + } export function InlineLinkText({ children, @@ -257,6 +260,7 @@ export function InlineLinkText({ selectable, label, shareOnLongPress, + disableUnderline, ...rest }: InlineLinkProps) { const t = useTheme() @@ -290,11 +294,12 @@ export function InlineLinkText({ {...rest} style={[ {color: t.palette.primary_500}, - (hovered || focused || pressed) && { - ...web({outline: 0}), - textDecorationLine: 'underline', - textDecorationColor: flattenedStyle.color ?? t.palette.primary_500, - }, + (hovered || focused || pressed) && + !disableUnderline && { + ...web({outline: 0}), + textDecorationLine: 'underline', + textDecorationColor: flattenedStyle.color ?? t.palette.primary_500, + }, flattenedStyle, ]} role="link" @@ -365,3 +370,18 @@ export function BaseLink({ </Pressable> ) } + +export function WebOnlyInlineLinkText({ + children, + to, + onPress, + ...props +}: InlineLinkProps) { + return isWeb ? ( + <InlineLinkText {...props} to={to} onPress={onPress}> + {children} + </InlineLinkText> + ) : ( + <Text {...props}>{children}</Text> + ) +} diff --git a/src/screens/Messages/Conversation/MessageInputEmbed.tsx b/src/screens/Messages/Conversation/MessageInputEmbed.tsx index bf28ed4fe..2d1551019 100644 --- a/src/screens/Messages/Conversation/MessageInputEmbed.tsx +++ b/src/screens/Messages/Conversation/MessageInputEmbed.tsx @@ -174,7 +174,6 @@ export function MessageInputEmbed({ showAvatar author={post.author} moderation={moderation} - authorHasWarning={!!post.author.labels?.length} timestamp={post.indexedAt} postHref={itemHref} style={a.flex_0} diff --git a/src/view/com/post-thread/PostThreadItem.tsx b/src/view/com/post-thread/PostThreadItem.tsx index 3fb2309b9..ead9df116 100644 --- a/src/view/com/post-thread/PostThreadItem.tsx +++ b/src/view/com/post-thread/PostThreadItem.tsx @@ -558,18 +558,14 @@ let PostThreadItemLoaded = ({ <PostMeta author={post.author} moderation={moderation} - authorHasWarning={!!post.author.labels?.length} timestamp={post.indexedAt} postHref={postHref} showAvatar={isThreadedChild} avatarModeration={moderation.ui('avatar')} - avatarSize={28} - displayNameType="md-bold" - displayNameStyle={isThreadedChild && s.ml2} + avatarSize={24} style={ isThreadedChild && { - alignItems: 'center', - paddingBottom: isWeb ? 5 : 2, + paddingBottom: isWeb ? 5 : 4, } } /> diff --git a/src/view/com/post/Post.tsx b/src/view/com/post/Post.tsx index 9033fb96f..ec730a5e1 100644 --- a/src/view/com/post/Post.tsx +++ b/src/view/com/post/Post.tsx @@ -163,7 +163,7 @@ function PostInner({ <View style={styles.layoutAvi}> <AviFollowButton author={post.author} moderation={moderation}> <PreviewableUserAvatar - size={52} + size={42} profile={post.author} moderation={moderation.ui('avatar')} type={post.author.associated?.labeler ? 'labeler' : 'user'} @@ -174,7 +174,6 @@ function PostInner({ <PostMeta author={post.author} moderation={moderation} - authorHasWarning={!!post.author.labels?.length} timestamp={post.indexedAt} postHref={itemHref} /> diff --git a/src/view/com/posts/FeedItem.tsx b/src/view/com/posts/FeedItem.tsx index b1509b271..fb9cdb065 100644 --- a/src/view/com/posts/FeedItem.tsx +++ b/src/view/com/posts/FeedItem.tsx @@ -245,7 +245,7 @@ let FeedItemInner = ({ onBeforePress={onBeforePress} dataSet={{feedContext}}> <View style={{flexDirection: 'row', gap: 10, paddingLeft: 8}}> - <View style={{width: 52}}> + <View style={{width: 42}}> {isThreadChild && ( <View style={[ @@ -345,7 +345,7 @@ let FeedItemInner = ({ <View style={styles.layoutAvi}> <AviFollowButton author={post.author} moderation={moderation}> <PreviewableUserAvatar - size={52} + size={42} profile={post.author} moderation={moderation.ui('avatar')} type={post.author.associated?.labeler ? 'labeler' : 'user'} @@ -369,7 +369,6 @@ let FeedItemInner = ({ <PostMeta author={post.author} moderation={moderation} - authorHasWarning={!!post.author.labels?.length} timestamp={post.indexedAt} postHref={href} onOpenAuthor={onOpenAuthor} diff --git a/src/view/com/posts/FeedSlice.tsx b/src/view/com/posts/FeedSlice.tsx index 0920026f6..dc68ee7a1 100644 --- a/src/view/com/posts/FeedSlice.tsx +++ b/src/view/com/posts/FeedSlice.tsx @@ -4,9 +4,9 @@ import Svg, {Circle, Line} from 'react-native-svg' import {AtUri} from '@atproto/api' import {Trans} from '@lingui/macro' +import {usePalette} from '#/lib/hooks/usePalette' +import {makeProfileLink} from '#/lib/routes/links' import {FeedPostSlice} from '#/state/queries/post-feed' -import {usePalette} from 'lib/hooks/usePalette' -import {makeProfileLink} from 'lib/routes/links' import {Link} from '../util/Link' import {Text} from '../util/text/Text' import {FeedItem} from './FeedItem' @@ -146,7 +146,7 @@ const styles = StyleSheet.create({ paddingLeft: 18, }, viewFullThreadDots: { - width: 52, + width: 42, alignItems: 'center', }, }) diff --git a/src/view/com/util/LoadingPlaceholder.tsx b/src/view/com/util/LoadingPlaceholder.tsx index 6e75e88ca..6620eb8e2 100644 --- a/src/view/com/util/LoadingPlaceholder.tsx +++ b/src/view/com/util/LoadingPlaceholder.tsx @@ -7,9 +7,9 @@ import { ViewStyle, } from 'react-native' -import {usePalette} from 'lib/hooks/usePalette' -import {s} from 'lib/styles' -import {useTheme} from 'lib/ThemeContext' +import {usePalette} from '#/lib/hooks/usePalette' +import {s} from '#/lib/styles' +import {useTheme} from '#/lib/ThemeContext' import {atoms as a, useTheme as useTheme_NEW} from '#/alf' import {Bubble_Stroke2_Corner2_Rounded as Bubble} from '#/components/icons/Bubble' import { @@ -53,8 +53,8 @@ export function PostLoadingPlaceholder({ return ( <View style={[styles.post, pal.view, style]}> <LoadingPlaceholder - width={52} - height={52} + width={42} + height={42} style={[ styles.avatar, { diff --git a/src/view/com/util/PostMeta.tsx b/src/view/com/util/PostMeta.tsx index f2d717e96..3f647f978 100644 --- a/src/view/com/util/PostMeta.tsx +++ b/src/view/com/util/PostMeta.tsx @@ -1,44 +1,40 @@ import React, {memo, useCallback} from 'react' -import {StyleProp, StyleSheet, TextStyle, View, ViewStyle} from 'react-native' +import {StyleProp, View, ViewStyle} from 'react-native' import {AppBskyActorDefs, ModerationDecision, ModerationUI} from '@atproto/api' +import {msg} from '@lingui/macro' import {useLingui} from '@lingui/react' import {useQueryClient} from '@tanstack/react-query' -import {usePalette} from '#/lib/hooks/usePalette' import {makeProfileLink} from '#/lib/routes/links' import {forceLTR} from '#/lib/strings/bidi' import {NON_BREAKING_SPACE} from '#/lib/strings/constants' import {sanitizeDisplayName} from '#/lib/strings/display-names' import {sanitizeHandle} from '#/lib/strings/handles' import {niceDate} from '#/lib/strings/time' -import {TypographyVariant} from '#/lib/ThemeContext' -import {isAndroid} from '#/platform/detection' import {precacheProfile} from '#/state/queries/profile' +import {atoms as a, useTheme, web} from '#/alf' +import {WebOnlyInlineLinkText} from '#/components/Link' import {ProfileHoverCard} from '#/components/ProfileHoverCard' -import {TextLinkOnWebOnly} from './Link' -import {Text} from './text/Text' +import {Text} from '#/components/Typography' import {TimeElapsed} from './TimeElapsed' import {PreviewableUserAvatar} from './UserAvatar' interface PostMetaOpts { author: AppBskyActorDefs.ProfileViewBasic moderation: ModerationDecision | undefined - authorHasWarning: boolean postHref: string timestamp: string showAvatar?: boolean avatarModeration?: ModerationUI avatarSize?: number - displayNameType?: TypographyVariant - displayNameStyle?: StyleProp<TextStyle> onOpenAuthor?: () => void style?: StyleProp<ViewStyle> } let PostMeta = (opts: PostMetaOpts): React.ReactNode => { - const {i18n} = useLingui() + const t = useTheme() + const {i18n, _} = useLingui() - const pal = usePalette('default') const displayName = opts.author.displayName || opts.author.handle const handle = opts.author.handle const profileLink = makeProfileLink(opts.author) @@ -53,9 +49,18 @@ let PostMeta = (opts: PostMetaOpts): React.ReactNode => { }, [queryClient, opts.author]) return ( - <View style={[styles.container, opts.style]}> + <View + style={[ + a.flex_1, + a.flex_row, + a.align_center, + a.pb_2xs, + a.gap_xs, + a.z_10, + opts.style, + ]}> {opts.showAvatar && ( - <View style={styles.avatar}> + <View style={[a.self_center, a.mr_2xs]}> <PreviewableUserAvatar size={opts.avatarSize || 16} profile={opts.author} @@ -65,63 +70,67 @@ let PostMeta = (opts: PostMetaOpts): React.ReactNode => { </View> )} <ProfileHoverCard inline did={opts.author.did}> - <Text - numberOfLines={1} - style={[styles.maxWidth, pal.textLight, opts.displayNameStyle]}> - <TextLinkOnWebOnly - type={opts.displayNameType || 'lg-bold'} - style={[pal.text]} - lineHeight={1.2} + <Text numberOfLines={1} style={[a.flex_shrink]}> + <WebOnlyInlineLinkText + to={profileLink} + label={_(msg`View profile`)} disableMismatchWarning - text={ - <Text - type={opts.displayNameType || 'lg-bold'} - emoji - style={[pal.text]} - lineHeight={1.2}> - {forceLTR( - sanitizeDisplayName( - displayName, - opts.moderation?.ui('displayName'), - ), - )} - </Text> - } - href={profileLink} - onBeforePress={onBeforePressAuthor} - /> - <TextLinkOnWebOnly - type="md" + onPress={onBeforePressAuthor} + style={[t.atoms.text]}> + <Text emoji style={[a.text_md, a.font_bold, a.leading_tight]}> + {forceLTR( + sanitizeDisplayName( + displayName, + opts.moderation?.ui('displayName'), + ), + )} + </Text> + </WebOnlyInlineLinkText> + <WebOnlyInlineLinkText + to={profileLink} + label={_(msg`View profile`)} disableMismatchWarning - style={[pal.textLight, {flexShrink: 4}]} - text={ - <Text emoji style={[pal.textLight, {flexShrink: 4}]}> - {NON_BREAKING_SPACE + sanitizeHandle(handle, '@')} - </Text> - } - href={profileLink} - onBeforePress={onBeforePressAuthor} - anchorNoUnderline - /> + disableUnderline + onPress={onBeforePressAuthor} + style={[a.text_md, t.atoms.text_contrast_medium, a.leading_tight]}> + <Text + emoji + style={[ + a.text_md, + t.atoms.text_contrast_medium, + a.leading_tight, + ]}> + {NON_BREAKING_SPACE + sanitizeHandle(handle, '@')} + </Text> + </WebOnlyInlineLinkText> </Text> </ProfileHoverCard> - {!isAndroid && ( - <Text type="md" style={pal.textLight} accessible={false}> - · - </Text> - )} + + <Text + style={[a.text_md, t.atoms.text_contrast_medium]} + accessible={false}> + · + </Text> + <TimeElapsed timestamp={opts.timestamp}> {({timeElapsed}) => ( - <TextLinkOnWebOnly - type="md" - style={pal.textLight} - text={timeElapsed} - accessibilityLabel={niceDate(i18n, opts.timestamp)} + <WebOnlyInlineLinkText + to={opts.postHref} + label={niceDate(i18n, opts.timestamp)} title={niceDate(i18n, opts.timestamp)} - accessibilityHint="" - href={opts.postHref} - onBeforePress={onBeforePressPost} - /> + disableMismatchWarning + disableUnderline + onPress={onBeforePressPost} + style={[ + a.text_md, + t.atoms.text_contrast_medium, + a.leading_tight, + web({ + whiteSpace: 'nowrap', + }), + ]}> + {timeElapsed} + </WebOnlyInlineLinkText> )} </TimeElapsed> </View> @@ -129,21 +138,3 @@ let PostMeta = (opts: PostMetaOpts): React.ReactNode => { } PostMeta = memo(PostMeta) export {PostMeta} - -const styles = StyleSheet.create({ - container: { - flexDirection: 'row', - alignItems: 'flex-end', - paddingBottom: 2, - gap: 4, - zIndex: 1, - flex: 1, - }, - avatar: { - alignSelf: 'center', - }, - maxWidth: { - flex: isAndroid ? 1 : undefined, - flexShrink: isAndroid ? undefined : 1, - }, -}) diff --git a/src/view/com/util/post-embeds/QuoteEmbed.tsx b/src/view/com/util/post-embeds/QuoteEmbed.tsx index 79e326404..3b8152c8b 100644 --- a/src/view/com/util/post-embeds/QuoteEmbed.tsx +++ b/src/view/com/util/post-embeds/QuoteEmbed.tsx @@ -24,15 +24,15 @@ import {useLingui} from '@lingui/react' import {useQueryClient} from '@tanstack/react-query' import {HITSLOP_20} from '#/lib/constants' +import {usePalette} from '#/lib/hooks/usePalette' +import {InfoCircleIcon} from '#/lib/icons' import {moderatePost_wrapped} from '#/lib/moderatePost_wrapped' +import {makeProfileLink} from '#/lib/routes/links' import {s} from '#/lib/styles' import {useModerationOpts} from '#/state/preferences/moderation-opts' +import {precacheProfile} from '#/state/queries/profile' import {useSession} from '#/state/session' -import {usePalette} from 'lib/hooks/usePalette' -import {InfoCircleIcon} from 'lib/icons' -import {makeProfileLink} from 'lib/routes/links' -import {precacheProfile} from 'state/queries/profile' -import {ComposerOptsQuote} from 'state/shell/composer' +import {ComposerOptsQuote} from '#/state/shell/composer' import {atoms as a, useTheme} from '#/alf' import {RichText} from '#/components/RichText' import {ContentHider} from '../../../../components/moderation/ContentHider' @@ -238,7 +238,6 @@ export function QuoteEmbed({ author={quote.author} moderation={moderation} showAvatar - authorHasWarning={false} postHref={itemHref} timestamp={quote.indexedAt} /> |