diff options
Diffstat (limited to 'src')
33 files changed, 226 insertions, 143 deletions
diff --git a/src/alf/atoms.ts b/src/alf/atoms.ts index eb130f3ae..1ccb0460c 100644 --- a/src/alf/atoms.ts +++ b/src/alf/atoms.ts @@ -1,7 +1,8 @@ -import {Platform} from 'react-native' +import {Platform, StyleSheet} from 'react-native' import * as tokens from '#/alf/tokens' import {native, web} from '#/alf/util/platform' +import hairlineWidth = StyleSheet.hairlineWidth export const atoms = { /* @@ -277,19 +278,19 @@ export const atoms = { borderWidth: 0, }, border: { - borderWidth: 1, + borderWidth: hairlineWidth, }, border_t: { - borderTopWidth: 1, + borderTopWidth: hairlineWidth, }, border_b: { - borderBottomWidth: 1, + borderBottomWidth: hairlineWidth, }, border_l: { - borderLeftWidth: 1, + borderLeftWidth: hairlineWidth, }, border_r: { - borderRightWidth: 1, + borderRightWidth: hairlineWidth, }, /* diff --git a/src/components/AccountList.tsx b/src/components/AccountList.tsx index 7d696801e..883c06c14 100644 --- a/src/components/AccountList.tsx +++ b/src/components/AccountList.tsx @@ -37,7 +37,7 @@ export function AccountList({ style={[ a.rounded_md, a.overflow_hidden, - a.border, + {borderWidth: 1}, t.atoms.border_contrast_low, ]}> {accounts.map(account => ( @@ -48,7 +48,7 @@ export function AccountList({ isCurrentAccount={account.did === currentAccount?.did} isPendingAccount={account.did === pendingDid} /> - <View style={[a.border_b, t.atoms.border_contrast_low]} /> + <View style={[{borderBottomWidth: 1}, t.atoms.border_contrast_low]} /> </React.Fragment> ))} <Button diff --git a/src/view/com/composer/Composer.tsx b/src/view/com/composer/Composer.tsx index 2618c51a3..c8bb8d726 100644 --- a/src/view/com/composer/Composer.tsx +++ b/src/view/com/composer/Composer.tsx @@ -90,6 +90,7 @@ import {SuggestedLanguage} from './select-language/SuggestedLanguage' import {TextInput, TextInputRef} from './text-input/TextInput' import {ThreadgateBtn} from './threadgate/ThreadgateBtn' import {useExternalLinkFetch} from './useExternalLinkFetch' +import hairlineWidth = StyleSheet.hairlineWidth type CancelRef = { onPressCancel: () => void @@ -657,7 +658,7 @@ const styles = StyleSheet.create({ marginBottom: 6, }, errorIcon: { - borderWidth: 1, + borderWidth: hairlineWidth, borderColor: colors.red4, color: colors.red4, borderRadius: 30, @@ -692,6 +693,6 @@ const styles = StyleSheet.create({ paddingLeft: 15, paddingRight: 20, alignItems: 'center', - borderTopWidth: 1, + borderTopWidth: hairlineWidth, }, }) diff --git a/src/view/com/composer/Prompt.tsx b/src/view/com/composer/Prompt.tsx index 16d1b6fb9..54defb101 100644 --- a/src/view/com/composer/Prompt.tsx +++ b/src/view/com/composer/Prompt.tsx @@ -1,13 +1,15 @@ import React from 'react' import {StyleSheet, TouchableOpacity} from 'react-native' -import {UserAvatar} from '../util/UserAvatar' -import {Text} from '../util/text/Text' -import {usePalette} from 'lib/hooks/usePalette' -import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries' -import {Trans, msg} from '@lingui/macro' +import {msg, Trans} from '@lingui/macro' import {useLingui} from '@lingui/react' -import {useSession} from '#/state/session' + import {useProfileQuery} from '#/state/queries/profile' +import {useSession} from '#/state/session' +import {usePalette} from 'lib/hooks/usePalette' +import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries' +import {Text} from '../util/text/Text' +import {UserAvatar} from '../util/UserAvatar' +import hairlineWidth = StyleSheet.hairlineWidth export function ComposePrompt({onPressCompose}: {onPressCompose: () => void}) { const {currentAccount} = useSession() @@ -47,7 +49,7 @@ const styles = StyleSheet.create({ paddingBottom: 10, flexDirection: 'row', alignItems: 'center', - borderTopWidth: 1, + borderTopWidth: hairlineWidth, }, labelMobile: { paddingLeft: 12, diff --git a/src/view/com/feeds/FeedSourceCard.tsx b/src/view/com/feeds/FeedSourceCard.tsx index b89a3946e..589f674b4 100644 --- a/src/view/com/feeds/FeedSourceCard.tsx +++ b/src/view/com/feeds/FeedSourceCard.tsx @@ -25,6 +25,7 @@ import * as Prompt from '#/components/Prompt' import {RichText} from '#/components/RichText' import {Text} from '../util/text/Text' import {UserAvatar} from '../util/UserAvatar' +import hairlineWidth = StyleSheet.hairlineWidth export function FeedSourceCard({ feedUri, @@ -34,6 +35,7 @@ export function FeedSourceCard({ showLikes = false, pinOnSave = false, showMinimalPlaceholder, + hideTopBorder, }: { feedUri: string style?: StyleProp<ViewStyle> @@ -42,6 +44,7 @@ export function FeedSourceCard({ showLikes?: boolean pinOnSave?: boolean showMinimalPlaceholder?: boolean + hideTopBorder?: boolean }) { const {data: preferences} = usePreferencesQuery() const {data: feed} = useFeedSourceInfoQuery({uri: feedUri}) @@ -57,6 +60,7 @@ export function FeedSourceCard({ showLikes={showLikes} pinOnSave={pinOnSave} showMinimalPlaceholder={showMinimalPlaceholder} + hideTopBorder={hideTopBorder} /> ) } @@ -71,6 +75,7 @@ export function FeedSourceCardLoaded({ showLikes = false, pinOnSave = false, showMinimalPlaceholder, + hideTopBorder, }: { feedUri: string feed?: FeedSourceInfo @@ -81,6 +86,7 @@ export function FeedSourceCardLoaded({ showLikes?: boolean pinOnSave?: boolean showMinimalPlaceholder?: boolean + hideTopBorder?: boolean }) { const t = useTheme() const pal = usePalette('default') @@ -149,7 +155,7 @@ export function FeedSourceCardLoaded({ style={[ pal.border, { - borderTopWidth: showMinimalPlaceholder ? 0 : 1, + borderTopWidth: showMinimalPlaceholder || hideTopBorder ? 0 : 1, flexDirection: 'row', alignItems: 'center', flex: 1, @@ -191,7 +197,12 @@ export function FeedSourceCardLoaded({ <Pressable testID={`feed-${feed.displayName}`} accessibilityRole="button" - style={[styles.container, pal.border, style]} + style={[ + styles.container, + pal.border, + style, + {borderTopWidth: hideTopBorder ? 0 : hairlineWidth}, + ]} onPress={() => { if (feed.type === 'feed') { navigation.push('ProfileFeed', { @@ -295,7 +306,6 @@ const styles = StyleSheet.create({ paddingVertical: 20, flexDirection: 'column', flex: 1, - borderTopWidth: 1, gap: 14, }, headerContainer: { diff --git a/src/view/com/feeds/ProfileFeedgens.tsx b/src/view/com/feeds/ProfileFeedgens.tsx index a006b11c0..670cd3e11 100644 --- a/src/view/com/feeds/ProfileFeedgens.tsx +++ b/src/view/com/feeds/ProfileFeedgens.tsx @@ -1,6 +1,7 @@ import React from 'react' import { findNodeHandle, + ListRenderItemInfo, StyleProp, StyleSheet, View, @@ -134,7 +135,7 @@ export const ProfileFeedgens = React.forwardRef< // = const renderItemInner = React.useCallback( - ({item}: {item: any}) => { + ({item, index}: ListRenderItemInfo<any>) => { if (item === EMPTY) { return ( <View @@ -169,6 +170,7 @@ export const ProfileFeedgens = React.forwardRef< preferences={preferences} style={styles.item} showLikes + hideTopBorder={index === 0} /> ) } diff --git a/src/view/com/lists/ListCard.tsx b/src/view/com/lists/ListCard.tsx index 19842eb54..3adf5c09d 100644 --- a/src/view/com/lists/ListCard.tsx +++ b/src/view/com/lists/ListCard.tsx @@ -1,18 +1,20 @@ import React from 'react' import {StyleProp, StyleSheet, View, ViewStyle} from 'react-native' -import {AtUri, AppBskyGraphDefs, RichText} from '@atproto/api' -import {Link} from '../util/Link' -import {Text} from '../util/text/Text' -import {RichText as RichTextCom} from '#/components/RichText' -import {UserAvatar} from '../util/UserAvatar' -import {s} from 'lib/styles' -import {usePalette} from 'lib/hooks/usePalette' +import {AppBskyGraphDefs, AtUri, RichText} from '@atproto/api' +import {Trans} from '@lingui/macro' + import {useSession} from '#/state/session' +import {usePalette} from 'lib/hooks/usePalette' +import {makeProfileLink} from 'lib/routes/links' import {sanitizeDisplayName} from 'lib/strings/display-names' import {sanitizeHandle} from 'lib/strings/handles' -import {makeProfileLink} from 'lib/routes/links' -import {Trans} from '@lingui/macro' +import {s} from 'lib/styles' import {atoms as a} from '#/alf' +import {RichText as RichTextCom} from '#/components/RichText' +import {Link} from '../util/Link' +import {Text} from '../util/text/Text' +import {UserAvatar} from '../util/UserAvatar' +import hairlineWidth = StyleSheet.hairlineWidth export const ListCard = ({ testID, @@ -132,7 +134,7 @@ export const ListCard = ({ const styles = StyleSheet.create({ outer: { - borderTopWidth: 1, + borderTopWidth: hairlineWidth, paddingHorizontal: 6, }, outerNoBorder: { diff --git a/src/view/com/lists/MyLists.tsx b/src/view/com/lists/MyLists.tsx index e9d2e4f0f..5ea95971c 100644 --- a/src/view/com/lists/MyLists.tsx +++ b/src/view/com/lists/MyLists.tsx @@ -9,17 +9,19 @@ import { ViewStyle, } from 'react-native' import {AppBskyGraphDefs as GraphDefs} from '@atproto/api' -import {ListCard} from './ListCard' +import {Trans} from '@lingui/macro' + +import {cleanError} from '#/lib/strings/errors' +import {logger} from '#/logger' import {MyListsFilter, useMyListsQuery} from '#/state/queries/my-lists' -import {ErrorMessage} from '../util/error/ErrorMessage' -import {Text} from '../util/text/Text' import {useAnalytics} from 'lib/analytics/analytics' import {usePalette} from 'lib/hooks/usePalette' -import {List} from '../util/List' import {s} from 'lib/styles' -import {logger} from '#/logger' -import {Trans} from '@lingui/macro' -import {cleanError} from '#/lib/strings/errors' +import {ErrorMessage} from '../util/error/ErrorMessage' +import {List} from '../util/List' +import {Text} from '../util/text/Text' +import {ListCard} from './ListCard' +import hairlineWidth = StyleSheet.hairlineWidth const LOADING = {_reactKey: '__loading__'} const EMPTY = {_reactKey: '__empty__'} @@ -84,7 +86,7 @@ export function MyLists({ <View key={item._reactKey} testID="listsEmpty" - style={[{padding: 18, borderTopWidth: 1}, pal.border]}> + style={[{padding: 18, borderTopWidth: hairlineWidth}, pal.border]}> <Text style={pal.textLight}> <Trans>You have no lists.</Trans> </Text> diff --git a/src/view/com/lists/ProfileLists.tsx b/src/view/com/lists/ProfileLists.tsx index 003d1c60e..d1ef05f12 100644 --- a/src/view/com/lists/ProfileLists.tsx +++ b/src/view/com/lists/ProfileLists.tsx @@ -1,6 +1,7 @@ import React from 'react' import { findNodeHandle, + ListRenderItemInfo, StyleProp, StyleSheet, View, @@ -138,12 +139,10 @@ export const ProfileLists = React.forwardRef<SectionRef, ProfileListsProps>( // = const renderItemInner = React.useCallback( - ({item}: {item: any}) => { + ({item, index}: ListRenderItemInfo<any>) => { if (item === EMPTY) { return ( - <View - testID="listsEmpty" - style={[{padding: 18, borderTopWidth: 1}, pal.border]}> + <View testID="listsEmpty" style={[{padding: 18}, pal.border]}> <Text style={pal.textLight}> <Trans>You have no lists.</Trans> </Text> @@ -173,6 +172,7 @@ export const ProfileLists = React.forwardRef<SectionRef, ProfileListsProps>( list={item} testID={`list-${item.name}`} style={styles.item} + noBorder={index === 0} /> ) }, diff --git a/src/view/com/notifications/Feed.tsx b/src/view/com/notifications/Feed.tsx index 15c103bed..e12b63733 100644 --- a/src/view/com/notifications/Feed.tsx +++ b/src/view/com/notifications/Feed.tsx @@ -1,5 +1,10 @@ import React from 'react' -import {ActivityIndicator, StyleSheet, View} from 'react-native' +import { + ActivityIndicator, + ListRenderItemInfo, + StyleSheet, + View, +} from 'react-native' import {msg} from '@lingui/macro' import {useLingui} from '@lingui/react' @@ -17,6 +22,9 @@ import {NotificationFeedLoadingPlaceholder} from '../util/LoadingPlaceholder' import {LoadMoreRetryBtn} from '../util/LoadMoreRetryBtn' import {CenteredView} from '../util/Views' import {FeedItem} from './FeedItem' +import hairlineWidth = StyleSheet.hairlineWidth +import {useInitialNumToRender} from 'lib/hooks/useInitialNumToRender' +import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries' const EMPTY_FEED_ITEM = {_reactKey: '__empty__'} const LOAD_MORE_ERROR_ITEM = {_reactKey: '__load_more_error__'} @@ -33,8 +41,11 @@ export function Feed({ onScrolledDownChange: (isScrolledDown: boolean) => void ListHeaderComponent?: () => JSX.Element }) { + const initialNumToRender = useInitialNumToRender() + const [isPTRing, setIsPTRing] = React.useState(false) const pal = usePalette('default') + const {isTabletOrMobile} = useWebMediaQueries() const {_} = useLingui() const moderationOpts = useModerationOpts() @@ -97,12 +108,8 @@ export function Feed({ fetchNextPage() }, [fetchNextPage]) - // TODO optimize renderItem or FeedItem, we're getting this notice from RN: -prf - // VirtualizedList: You have a large list that is slow to update - make sure your - // renderItem function renders components that follow React performance best practices - // like PureComponent, shouldComponentUpdate, etc const renderItem = React.useCallback( - ({item}: {item: any}) => { + ({item, index}: ListRenderItemInfo<any>) => { if (item === EMPTY_FEED_ITEM) { return ( <EmptyState @@ -122,14 +129,20 @@ export function Feed({ ) } else if (item === LOADING_ITEM) { return ( - <View style={[pal.border, {borderTopWidth: 1}]}> + <View style={[pal.border, {borderTopWidth: hairlineWidth}]}> <NotificationFeedLoadingPlaceholder /> </View> ) } - return <FeedItem item={item} moderationOpts={moderationOpts!} /> + return ( + <FeedItem + item={item} + moderationOpts={moderationOpts!} + hideTopBorder={index === 0 && isTabletOrMobile} + /> + ) }, - [onPressRetryLoadMore, moderationOpts, _, pal.border], + [moderationOpts, isTabletOrMobile, _, onPressRetryLoadMore, pal.border], ) const FeedFooter = React.useCallback( @@ -170,6 +183,8 @@ export function Feed({ contentContainerStyle={s.contentContainer} // @ts-ignore our .web version only -prf desktopFixedHeight + initialNumToRender={initialNumToRender} + windowSize={11} /> </View> ) diff --git a/src/view/com/notifications/FeedItem.tsx b/src/view/com/notifications/FeedItem.tsx index c20a8e9ee..4fe557f40 100644 --- a/src/view/com/notifications/FeedItem.tsx +++ b/src/view/com/notifications/FeedItem.tsx @@ -47,6 +47,7 @@ import {formatCount} from '../util/numeric/format' import {Text} from '../util/text/Text' import {TimeElapsed} from '../util/TimeElapsed' import {PreviewableUserAvatar, UserAvatar} from '../util/UserAvatar' +import hairlineWidth = StyleSheet.hairlineWidth const MAX_AUTHORS = 5 @@ -61,9 +62,11 @@ interface Author { let FeedItem = ({ item, moderationOpts, + hideTopBorder, }: { item: FeedNotification moderationOpts: ModerationOpts + hideTopBorder?: boolean }): React.ReactNode => { const queryClient = useQueryClient() const pal = usePalette('default') @@ -188,6 +191,7 @@ let FeedItem = ({ backgroundColor: pal.colors.unreadNotifBg, borderColor: pal.colors.unreadNotifBorder, }, + {borderTopWidth: hideTopBorder ? 0 : hairlineWidth}, ]} href={itemHref} noFeedback @@ -480,7 +484,6 @@ const styles = StyleSheet.create({ outer: { padding: 10, paddingRight: 15, - borderTopWidth: 1, flexDirection: 'row', }, layoutIcon: { diff --git a/src/view/com/pager/PagerWithHeader.tsx b/src/view/com/pager/PagerWithHeader.tsx index 61e2a4096..7b1d8b78f 100644 --- a/src/view/com/pager/PagerWithHeader.tsx +++ b/src/view/com/pager/PagerWithHeader.tsx @@ -67,13 +67,13 @@ export const PagerWithHeader = React.forwardRef<PagerRef, PagerWithHeaderProps>( const height = evt.nativeEvent.layout.height if (height > 0) { // The rounding is necessary to prevent jumps on iOS - setTabBarHeight(Math.round(height)) + setTabBarHeight(Math.round(height * 2) / 2) } }) const onHeaderOnlyLayout = useNonReactiveCallback((height: number) => { if (height > 0) { // The rounding is necessary to prevent jumps on iOS - setHeaderOnlyHeight(Math.round(height)) + setHeaderOnlyHeight(Math.round(height * 2) / 2) } }) diff --git a/src/view/com/pager/TabBar.tsx b/src/view/com/pager/TabBar.tsx index 5791e26a9..e81d7d44d 100644 --- a/src/view/com/pager/TabBar.tsx +++ b/src/view/com/pager/TabBar.tsx @@ -7,6 +7,7 @@ import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries' import {PressableWithHover} from '../util/PressableWithHover' import {Text} from '../util/text/Text' import {DraggableScrollView} from './DraggableScrollView' +import hairlineWidth = StyleSheet.hairlineWidth export interface TabBarProps { testID?: string @@ -207,6 +208,6 @@ const mobileStyles = StyleSheet.create({ left: 0, right: 0, bottom: -1, - borderBottomWidth: 1, + borderBottomWidth: hairlineWidth, }, }) diff --git a/src/view/com/post-thread/PostThreadItem.tsx b/src/view/com/post-thread/PostThreadItem.tsx index 981b4e72f..096305a23 100644 --- a/src/view/com/post-thread/PostThreadItem.tsx +++ b/src/view/com/post-thread/PostThreadItem.tsx @@ -50,6 +50,7 @@ import {PostEmbeds} from '../util/post-embeds' import {PostMeta} from '../util/PostMeta' import {Text} from '../util/text/Text' import {PreviewableUserAvatar} from '../util/UserAvatar' +import hairlineWidth = StyleSheet.hairlineWidth export function PostThreadItem({ post, @@ -623,7 +624,7 @@ function PostOuterWrapper({ { flexDirection: 'row', paddingHorizontal: isMobile ? 10 : 6, - borderTopWidth: depth === 1 ? 1 : 0, + borderTopWidth: depth === 1 ? hairlineWidth : 0, }, ]}> {Array.from(Array(depth - 1)).map((_, n: number) => ( @@ -704,7 +705,7 @@ function ExpandedPostDetails({ const styles = StyleSheet.create({ outer: { - borderTopWidth: 1, + borderTopWidth: hairlineWidth, paddingLeft: 8, }, outerHighlighted: { @@ -714,7 +715,7 @@ const styles = StyleSheet.create({ paddingRight: 8, }, outerHighlightedRoot: { - borderTopWidth: 1, + borderTopWidth: hairlineWidth, paddingTop: 16, }, noTopBorder: { @@ -766,8 +767,8 @@ const styles = StyleSheet.create({ expandedInfo: { flexDirection: 'row', padding: 10, - borderTopWidth: 1, - borderBottomWidth: 1, + borderTopWidth: hairlineWidth, + borderBottomWidth: hairlineWidth, marginTop: 5, marginBottom: 10, }, diff --git a/src/view/com/post/Post.tsx b/src/view/com/post/Post.tsx index f666e2968..a7ccf0be2 100644 --- a/src/view/com/post/Post.tsx +++ b/src/view/com/post/Post.tsx @@ -36,6 +36,7 @@ import {PostMeta} from '../util/PostMeta' import {Text} from '../util/text/Text' import {PreviewableUserAvatar} from '../util/UserAvatar' import {UserInfoText} from '../util/UserInfoText' +import hairlineWidth = StyleSheet.hairlineWidth export function Post({ post, @@ -242,7 +243,7 @@ const styles = StyleSheet.create({ paddingRight: 15, paddingBottom: 5, paddingLeft: 10, - borderTopWidth: 1, + borderTopWidth: hairlineWidth, // @ts-ignore web only -prf cursor: 'pointer', }, diff --git a/src/view/com/posts/Feed.tsx b/src/view/com/posts/Feed.tsx index 12171dc3b..681670cf7 100644 --- a/src/view/com/posts/Feed.tsx +++ b/src/view/com/posts/Feed.tsx @@ -3,6 +3,7 @@ import { ActivityIndicator, AppState, Dimensions, + ListRenderItemInfo, StyleProp, StyleSheet, View, @@ -31,6 +32,7 @@ import { import {useSession} from '#/state/session' import {useAnalytics} from 'lib/analytics/analytics' import {useInitialNumToRender} from 'lib/hooks/useInitialNumToRender' +import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries' import {useTheme} from 'lib/ThemeContext' import {List, ListRef} from '../util/List' import {PostFeedLoadingPlaceholder} from '../util/LoadingPlaceholder' @@ -100,6 +102,7 @@ let Feed = ({ const checkForNewRef = React.useRef<(() => void) | null>(null) const lastFetchRef = React.useRef<number>(Date.now()) const [feedType, feedUri] = feed.split('|') + const {isTabletOrMobile} = useWebMediaQueries() const opts = React.useMemo( () => ({enabled, ignoreFilterFor}), @@ -279,7 +282,7 @@ let Feed = ({ // = const renderItem = React.useCallback( - ({item}: {item: any}) => { + ({item, index}: ListRenderItemInfo<any>) => { if (item === EMPTY_FEED_ITEM) { return renderEmptyState() } else if (item === ERROR_ITEM) { @@ -311,17 +314,23 @@ let Feed = ({ // -prf return <DiscoverFallbackHeader /> } - return <FeedSlice slice={item} /> + return ( + <FeedSlice + slice={item} + hideTopBorder={index === 0 && isTabletOrMobile} + /> + ) }, [ + isTabletOrMobile, + renderEmptyState, feed, - feedUri, error, onPressTryAgain, - onPressRetryLoadMore, - renderEmptyState, - _, savedFeedConfig, + _, + onPressRetryLoadMore, + feedUri, ], ) diff --git a/src/view/com/posts/FeedItem.tsx b/src/view/com/posts/FeedItem.tsx index b10ffe19f..72c8b8757 100644 --- a/src/view/com/posts/FeedItem.tsx +++ b/src/view/com/posts/FeedItem.tsx @@ -42,6 +42,7 @@ import {PostMeta} from '../util/PostMeta' import {Text} from '../util/text/Text' import {PreviewableUserAvatar} from '../util/UserAvatar' import {AviFollowButton} from './AviFollowButton' +import hairlineWidth = StyleSheet.hairlineWidth interface FeedItemProps { record: AppBskyFeedPost.Record @@ -53,6 +54,7 @@ interface FeedItemProps { isThreadLastChild?: boolean isThreadParent?: boolean feedContext: string | undefined + hideTopBorder?: boolean } export function FeedItem({ @@ -66,6 +68,7 @@ export function FeedItem({ isThreadChild, isThreadLastChild, isThreadParent, + hideTopBorder, }: FeedItemProps & {post: AppBskyFeedDefs.PostView}): React.ReactNode { const postShadowed = usePostShadow(post) const richText = useMemo( @@ -95,6 +98,7 @@ export function FeedItem({ isThreadChild={isThreadChild} isThreadLastChild={isThreadLastChild} isThreadParent={isThreadParent} + hideTopBorder={hideTopBorder} /> ) } @@ -113,6 +117,7 @@ let FeedItemInner = ({ isThreadChild, isThreadLastChild, isThreadParent, + hideTopBorder, }: FeedItemProps & { richText: RichTextAPI post: Shadow<AppBskyFeedDefs.PostView> @@ -186,8 +191,8 @@ let FeedItemInner = ({ isThreadLastChild || (!isThreadChild && !isThreadParent) ? 8 : undefined, + borderTopWidth: hideTopBorder || isThreadChild ? 0 : hairlineWidth, }, - isThreadChild ? styles.outerSmallTop : undefined, ] return ( @@ -445,16 +450,12 @@ function ReplyToLabel({profile}: {profile: AppBskyActorDefs.ProfileViewBasic}) { const styles = StyleSheet.create({ outer: { - borderTopWidth: 1, paddingLeft: 10, paddingRight: 15, // @ts-ignore web only -prf cursor: 'pointer', overflow: 'hidden', }, - outerSmallTop: { - borderTopWidth: 0, - }, replyLine: { width: 2, marginLeft: 'auto', diff --git a/src/view/com/posts/FeedSlice.tsx b/src/view/com/posts/FeedSlice.tsx index 6d8f038b4..aeb24e8bb 100644 --- a/src/view/com/posts/FeedSlice.tsx +++ b/src/view/com/posts/FeedSlice.tsx @@ -11,7 +11,13 @@ import {Link} from '../util/Link' import {Text} from '../util/text/Text' import {FeedItem} from './FeedItem' -let FeedSlice = ({slice}: {slice: FeedPostSlice}): React.ReactNode => { +let FeedSlice = ({ + slice, + hideTopBorder, +}: { + slice: FeedPostSlice + hideTopBorder?: boolean +}): React.ReactNode => { if (slice.isThread && slice.items.length > 3) { const last = slice.items.length - 1 return ( @@ -27,6 +33,7 @@ let FeedSlice = ({slice}: {slice: FeedPostSlice}): React.ReactNode => { moderation={slice.items[0].moderation} isThreadParent={isThreadParentAt(slice.items, 0)} isThreadChild={isThreadChildAt(slice.items, 0)} + hideTopBorder={hideTopBorder} /> <FeedItem key={slice.items[1]._reactKey} @@ -75,6 +82,7 @@ let FeedSlice = ({slice}: {slice: FeedPostSlice}): React.ReactNode => { isThreadLastChild={ isThreadChildAt(slice.items, i) && slice.items.length === i + 1 } + hideTopBorder={hideTopBorder && i === 0} /> ))} </> diff --git a/src/view/com/profile/ProfileCard.tsx b/src/view/com/profile/ProfileCard.tsx index 6c8978946..2b0790002 100644 --- a/src/view/com/profile/ProfileCard.tsx +++ b/src/view/com/profile/ProfileCard.tsx @@ -25,6 +25,7 @@ import {Link} from '../util/Link' import {Text} from '../util/text/Text' import {PreviewableUserAvatar} from '../util/UserAvatar' import {FollowButton} from './FollowButton' +import hairlineWidth = StyleSheet.hairlineWidth export function ProfileCard({ testID, @@ -280,7 +281,7 @@ export function ProfileCardWithFollowBtn({ const styles = StyleSheet.create({ outer: { - borderTopWidth: 1, + borderTopWidth: hairlineWidth, paddingHorizontal: 6, paddingVertical: 4, }, diff --git a/src/view/com/profile/ProfileSubpageHeader.tsx b/src/view/com/profile/ProfileSubpageHeader.tsx index eaf00f3e6..549fc5151 100644 --- a/src/view/com/profile/ProfileSubpageHeader.tsx +++ b/src/view/com/profile/ProfileSubpageHeader.tsx @@ -1,24 +1,26 @@ import React from 'react' import {Pressable, StyleSheet, View} from 'react-native' import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome' +import {msg, Trans} from '@lingui/macro' +import {useLingui} from '@lingui/react' import {useNavigation} from '@react-navigation/native' + +import {emitSoftReset} from '#/state/events' +import {ImagesLightbox, useLightboxControls} from '#/state/lightbox' +import {useSetDrawerOpen} from '#/state/shell' +import {BACK_HITSLOP} from 'lib/constants' import {usePalette} from 'lib/hooks/usePalette' import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries' -import {Text} from '../util/text/Text' -import {TextLink} from '../util/Link' -import {UserAvatar, UserAvatarType} from '../util/UserAvatar' -import {LoadingPlaceholder} from '../util/LoadingPlaceholder' -import {CenteredView} from '../util/Views' -import {sanitizeHandle} from 'lib/strings/handles' import {makeProfileLink} from 'lib/routes/links' import {NavigationProp} from 'lib/routes/types' -import {BACK_HITSLOP} from 'lib/constants' +import {sanitizeHandle} from 'lib/strings/handles' import {isNative} from 'platform/detection' -import {useLightboxControls, ImagesLightbox} from '#/state/lightbox' -import {useLingui} from '@lingui/react' -import {Trans, msg} from '@lingui/macro' -import {useSetDrawerOpen} from '#/state/shell' -import {emitSoftReset} from '#/state/events' +import {TextLink} from '../util/Link' +import {LoadingPlaceholder} from '../util/LoadingPlaceholder' +import {Text} from '../util/text/Text' +import {UserAvatar, UserAvatarType} from '../util/UserAvatar' +import {CenteredView} from '../util/Views' +import hairlineWidth = StyleSheet.hairlineWidth export function ProfileSubpageHeader({ isLoading, @@ -79,7 +81,7 @@ export function ProfileSubpageHeader({ { flexDirection: 'row', alignItems: 'center', - borderBottomWidth: 1, + borderBottomWidth: hairlineWidth, paddingTop: isNative ? 0 : 8, paddingBottom: 8, paddingHorizontal: isMobile ? 12 : 14, diff --git a/src/view/com/util/LoadingPlaceholder.tsx b/src/view/com/util/LoadingPlaceholder.tsx index 33a59be6d..be67d10cb 100644 --- a/src/view/com/util/LoadingPlaceholder.tsx +++ b/src/view/com/util/LoadingPlaceholder.tsx @@ -15,6 +15,7 @@ import {useTheme as useTheme_NEW} from '#/alf' import {Bubble_Stroke2_Corner2_Rounded as Bubble} from '#/components/icons/Bubble' import {Heart2_Stroke2_Corner0_Rounded as HeartIconOutline} from '#/components/icons/Heart2' import {Repost_Stroke2_Corner2_Rounded as Repost} from '#/components/icons/Repost' +import hairlineWidth = StyleSheet.hairlineWidth export function LoadingPlaceholder({ width, @@ -233,7 +234,7 @@ export function FeedLoadingPlaceholder({ { paddingHorizontal: 12, paddingVertical: 18, - borderTopWidth: showTopBorder ? 1 : 0, + borderTopWidth: showTopBorder ? hairlineWidth : 0, }, pal.border, style, diff --git a/src/view/com/util/ViewHeader.tsx b/src/view/com/util/ViewHeader.tsx index 63a2b3de3..4c0f0e3e5 100644 --- a/src/view/com/util/ViewHeader.tsx +++ b/src/view/com/util/ViewHeader.tsx @@ -15,6 +15,7 @@ import {NavigationProp} from 'lib/routes/types' import {useTheme} from '#/alf' import {Text} from './text/Text' import {CenteredView} from './Views' +import hairlineWidth = StyleSheet.hairlineWidth const BACK_HITSLOP = {left: 20, top: 20, right: 50, bottom: 20} @@ -156,7 +157,7 @@ function DesktopWebHeader({ styles.desktopHeader, pal.border, { - borderBottomWidth: showBorder ? 1 : 0, + borderBottomWidth: showBorder ? hairlineWidth : 0, }, {display: 'flex', flexDirection: 'column'}, ]}> @@ -245,7 +246,7 @@ const styles = StyleSheet.create({ marginRight: 'auto', }, border: { - borderBottomWidth: 1, + borderBottomWidth: hairlineWidth, }, titleContainer: { marginLeft: 'auto', diff --git a/src/view/com/util/Views.web.tsx b/src/view/com/util/Views.web.tsx index 0ebd986cb..ffea9fe2e 100644 --- a/src/view/com/util/Views.web.tsx +++ b/src/view/com/util/Views.web.tsx @@ -26,6 +26,7 @@ import Animated from 'react-native-reanimated' import {usePalette} from 'lib/hooks/usePalette' import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries' import {addStyle} from 'lib/styles' +import hairlineWidth = StyleSheet.hairlineWidth interface AddedProps { desktopFixedHeight?: boolean | number @@ -46,8 +47,8 @@ export const CenteredView = React.forwardRef(function CenteredView({ } if (sideBorders) { style = addStyle(style, { - borderLeftWidth: 1, - borderRightWidth: 1, + borderLeftWidth: hairlineWidth, + borderRightWidth: hairlineWidth, }) style = addStyle(style, pal.border) } @@ -159,8 +160,8 @@ export const ScrollView = React.forwardRef(function ScrollViewImpl( const styles = StyleSheet.create({ contentContainer: { - borderLeftWidth: 1, - borderRightWidth: 1, + borderLeftWidth: hairlineWidth, + borderRightWidth: hairlineWidth, // @ts-ignore web only minHeight: '100vh', }, diff --git a/src/view/com/util/load-latest/LoadLatestBtn.tsx b/src/view/com/util/load-latest/LoadLatestBtn.tsx index 7e85e670f..a6b40f9f5 100644 --- a/src/view/com/util/load-latest/LoadLatestBtn.tsx +++ b/src/view/com/util/load-latest/LoadLatestBtn.tsx @@ -13,6 +13,7 @@ import {clamp} from '#/lib/numbers' import {colors} from '#/lib/styles' import {isWeb} from '#/platform/detection' import {useSession} from '#/state/session' +import hairlineWidth = StyleSheet.hairlineWidth const AnimatedTouchableOpacity = Animated.createAnimatedComponent(TouchableOpacity) @@ -73,7 +74,7 @@ const styles = StyleSheet.create({ // @ts-ignore 'fixed' is web only -prf position: isWeb ? 'fixed' : 'absolute', left: 18, - borderWidth: 1, + borderWidth: hairlineWidth, width: 52, height: 52, borderRadius: 26, diff --git a/src/view/com/util/post-embeds/QuoteEmbed.tsx b/src/view/com/util/post-embeds/QuoteEmbed.tsx index 57f1d28ba..019216eca 100644 --- a/src/view/com/util/post-embeds/QuoteEmbed.tsx +++ b/src/view/com/util/post-embeds/QuoteEmbed.tsx @@ -39,6 +39,7 @@ import {Link} from '../Link' import {PostMeta} from '../PostMeta' import {Text} from '../text/Text' import {PostEmbeds} from '.' +import hairlineWidth = StyleSheet.hairlineWidth export function MaybeQuoteEmbed({ embed, @@ -247,7 +248,7 @@ const styles = StyleSheet.create({ marginTop: 8, paddingVertical: 12, paddingHorizontal: 12, - borderWidth: 1, + borderWidth: hairlineWidth, }, quotePost: { flex: 1, @@ -262,7 +263,7 @@ const styles = StyleSheet.create({ marginTop: 8, paddingVertical: 14, paddingHorizontal: 14, - borderWidth: 1, + borderWidth: hairlineWidth, }, alert: { marginBottom: 6, diff --git a/src/view/com/util/post-embeds/index.tsx b/src/view/com/util/post-embeds/index.tsx index 0fc829625..d8ef6e6ab 100644 --- a/src/view/com/util/post-embeds/index.tsx +++ b/src/view/com/util/post-embeds/index.tsx @@ -27,6 +27,7 @@ import {ImageLayoutGrid} from '../images/ImageLayoutGrid' import {ExternalLinkEmbed} from './ExternalLinkEmbed' import {ListEmbed} from './ListEmbed' import {MaybeQuoteEmbed} from './QuoteEmbed' +import hairlineWidth = StyleSheet.hairlineWidth type Embed = | AppBskyEmbedRecord.View @@ -187,7 +188,7 @@ const styles = StyleSheet.create({ fontWeight: 'bold', }, customFeedOuter: { - borderWidth: 1, + borderWidth: hairlineWidth, borderRadius: 8, marginTop: 4, paddingHorizontal: 12, diff --git a/src/view/screens/Feeds.tsx b/src/view/screens/Feeds.tsx index 826f997dd..837e58195 100644 --- a/src/view/screens/Feeds.tsx +++ b/src/view/screens/Feeds.tsx @@ -52,6 +52,7 @@ import {IconCircle} from '#/components/IconCircle' import {FilterTimeline_Stroke2_Corner0_Rounded as FilterTimeline} from '#/components/icons/FilterTimeline' import {ListMagnifyingGlass_Stroke2_Corner0_Rounded} from '#/components/icons/ListMagnifyingGlass' import {ListSparkle_Stroke2_Corner0_Rounded} from '#/components/icons/ListSparkle' +import hairlineWidth = StyleSheet.hairlineWidth type Props = NativeStackScreenProps<FeedsTabNavigatorParams, 'Feeds'> @@ -856,13 +857,13 @@ const styles = StyleSheet.create({ paddingHorizontal: 16, paddingVertical: 14, gap: 12, - borderBottomWidth: 1, + borderBottomWidth: hairlineWidth, }, savedFeedMobile: { paddingVertical: 10, }, offlineSlug: { - borderWidth: 1, + borderWidth: hairlineWidth, borderRadius: 4, paddingHorizontal: 4, paddingVertical: 2, diff --git a/src/view/screens/Lists.tsx b/src/view/screens/Lists.tsx index bdd5dd9b7..0dd2febcb 100644 --- a/src/view/screens/Lists.tsx +++ b/src/view/screens/Lists.tsx @@ -1,20 +1,22 @@ import React from 'react' -import {View} from 'react-native' -import {useFocusEffect, useNavigation} from '@react-navigation/native' -import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome' +import {StyleSheet, View} from 'react-native' import {AtUri} from '@atproto/api' -import {NativeStackScreenProps, CommonNavigatorParams} from 'lib/routes/types' -import {MyLists} from '#/view/com/lists/MyLists' -import {Text} from 'view/com/util/text/Text' -import {Button} from 'view/com/util/forms/Button' -import {NavigationProp} from 'lib/routes/types' +import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome' +import {Trans} from '@lingui/macro' +import {useFocusEffect, useNavigation} from '@react-navigation/native' + +import {useModalControls} from '#/state/modals' +import {useSetMinimalShellMode} from '#/state/shell' import {usePalette} from 'lib/hooks/usePalette' import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries' -import {SimpleViewHeader} from 'view/com/util/SimpleViewHeader' +import {CommonNavigatorParams, NativeStackScreenProps} from 'lib/routes/types' +import {NavigationProp} from 'lib/routes/types' import {s} from 'lib/styles' -import {useSetMinimalShellMode} from '#/state/shell' -import {useModalControls} from '#/state/modals' -import {Trans} from '@lingui/macro' +import {MyLists} from '#/view/com/lists/MyLists' +import {Button} from 'view/com/util/forms/Button' +import {SimpleViewHeader} from 'view/com/util/SimpleViewHeader' +import {Text} from 'view/com/util/text/Text' +import hairlineWidth = StyleSheet.hairlineWidth type Props = NativeStackScreenProps<CommonNavigatorParams, 'Lists'> export function ListsScreen({}: Props) { @@ -51,7 +53,10 @@ export function ListsScreen({}: Props) { <SimpleViewHeader showBackButton={isMobile} style={ - !isMobile && [pal.border, {borderLeftWidth: 1, borderRightWidth: 1}] + !isMobile && [ + pal.border, + {borderLeftWidth: hairlineWidth, borderRightWidth: hairlineWidth}, + ] }> <View style={{flex: 1}}> <Text type="title-lg" style={[pal.text, {fontWeight: 'bold'}]}> diff --git a/src/view/screens/Notifications.tsx b/src/view/screens/Notifications.tsx index 48c834a28..7e2fc68b3 100644 --- a/src/view/screens/Notifications.tsx +++ b/src/view/screens/Notifications.tsx @@ -1,37 +1,38 @@ import React from 'react' import {View} from 'react-native' +import {msg, Trans} from '@lingui/macro' +import {useLingui} from '@lingui/react' import {useFocusEffect, useIsFocused} from '@react-navigation/native' import {useQueryClient} from '@tanstack/react-query' + +import {useNonReactiveCallback} from '#/lib/hooks/useNonReactiveCallback' +import {logger} from '#/logger' +import {isNative} from '#/platform/detection' +import {emitSoftReset, listenSoftReset} from '#/state/events' +import {RQKEY as NOTIFS_RQKEY} from '#/state/queries/notifications/feed' +import { + useUnreadNotifications, + useUnreadNotificationsApi, +} from '#/state/queries/notifications/unread' +import {truncateAndInvalidate} from '#/state/queries/util' +import {useSetMinimalShellMode} from '#/state/shell' +import {useComposerControls} from '#/state/shell/composer' +import {useAnalytics} from 'lib/analytics/analytics' +import {usePalette} from 'lib/hooks/usePalette' +import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries' +import {ComposeIcon2} from 'lib/icons' import { NativeStackScreenProps, NotificationsTabNavigatorParams, } from 'lib/routes/types' -import {ViewHeader} from '../com/util/ViewHeader' -import {Feed} from '../com/notifications/Feed' +import {colors, s} from 'lib/styles' import {TextLink} from 'view/com/util/Link' import {ListMethods} from 'view/com/util/List' import {LoadLatestBtn} from 'view/com/util/load-latest/LoadLatestBtn' -import {MainScrollProvider} from '../com/util/MainScrollProvider' -import {usePalette} from 'lib/hooks/usePalette' -import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries' -import {s, colors} from 'lib/styles' -import {useAnalytics} from 'lib/analytics/analytics' -import {logger} from '#/logger' -import {useSetMinimalShellMode} from '#/state/shell' -import {Trans, msg} from '@lingui/macro' -import {useLingui} from '@lingui/react' -import { - useUnreadNotifications, - useUnreadNotificationsApi, -} from '#/state/queries/notifications/unread' -import {RQKEY as NOTIFS_RQKEY} from '#/state/queries/notifications/feed' -import {listenSoftReset, emitSoftReset} from '#/state/events' -import {truncateAndInvalidate} from '#/state/queries/util' -import {useNonReactiveCallback} from '#/lib/hooks/useNonReactiveCallback' -import {isNative} from '#/platform/detection' +import {Feed} from '../com/notifications/Feed' import {FAB} from '../com/util/fab/FAB' -import {ComposeIcon2} from 'lib/icons' -import {useComposerControls} from '#/state/shell/composer' +import {MainScrollProvider} from '../com/util/MainScrollProvider' +import {ViewHeader} from '../com/util/ViewHeader' type Props = NativeStackScreenProps< NotificationsTabNavigatorParams, @@ -145,7 +146,11 @@ export function NotificationsScreen({}: Props) { return ( <View testID="notificationsScreen" style={s.hContentRegion}> - <ViewHeader title={_(msg`Notifications`)} canGoBack={false} /> + <ViewHeader + title={_(msg`Notifications`)} + canGoBack={false} + showBorder={true} + /> <MainScrollProvider> <Feed onScrolledDownChange={setIsScrolledDown} diff --git a/src/view/screens/ProfileList.tsx b/src/view/screens/ProfileList.tsx index de3c01ea3..0c2cecbfc 100644 --- a/src/view/screens/ProfileList.tsx +++ b/src/view/screens/ProfileList.tsx @@ -65,6 +65,7 @@ import {useDialogControl} from '#/components/Dialog' import * as Prompt from '#/components/Prompt' import {ReportDialog, useReportDialogControl} from '#/components/ReportDialog' import {RichText} from '#/components/RichText' +import hairlineWidth = StyleSheet.hairlineWidth const SECTION_TITLES_CURATE = ['Posts', 'About'] const SECTION_TITLES_MOD = ['About'] @@ -802,7 +803,7 @@ const AboutSection = React.forwardRef<SectionRef, AboutSectionProps>( <View style={[ { - borderTopWidth: 1, + borderTopWidth: hairlineWidth, padding: isMobile ? 14 : 20, gap: 12, }, @@ -953,7 +954,7 @@ function ErrorScreen({error}: {error: string}) { marginTop: 10, paddingHorizontal: 18, paddingVertical: 14, - borderTopWidth: 1, + borderTopWidth: hairlineWidth, }, ]}> <Text type="title-lg" style={[pal.text, s.mb10]}> diff --git a/src/view/screens/Settings/index.tsx b/src/view/screens/Settings/index.tsx index 078ebedab..49702ae47 100644 --- a/src/view/screens/Settings/index.tsx +++ b/src/view/screens/Settings/index.tsx @@ -66,6 +66,7 @@ import {BirthDateSettingsDialog} from '#/components/dialogs/BirthDateSettings' import {navigate, resetToTab} from '#/Navigation' import {Email2FAToggle} from './Email2FAToggle' import {ExportCarDialog} from './ExportCarDialog' +import hairlineWidth = StyleSheet.hairlineWidth function SettingsAccountCard({ account, @@ -317,7 +318,7 @@ export function SettingsScreen({}: Props) { showBackButton={isMobile} style={[ pal.border, - {borderBottomWidth: 1}, + {borderBottomWidth: hairlineWidth}, !isMobile && {borderLeftWidth: 1, borderRightWidth: 1}, ]}> <View style={{flex: 1}}> diff --git a/src/view/shell/bottom-bar/BottomBarStyles.tsx b/src/view/shell/bottom-bar/BottomBarStyles.tsx index 367c204e8..ba8743474 100644 --- a/src/view/shell/bottom-bar/BottomBarStyles.tsx +++ b/src/view/shell/bottom-bar/BottomBarStyles.tsx @@ -1,6 +1,7 @@ import {StyleSheet} from 'react-native' import {colors} from 'lib/styles' +import hairlineWidth = StyleSheet.hairlineWidth export const styles = StyleSheet.create({ bottomBar: { @@ -9,7 +10,7 @@ export const styles = StyleSheet.create({ left: 0, right: 0, flexDirection: 'row', - borderTopWidth: 1, + borderTopWidth: hairlineWidth, paddingLeft: 5, paddingRight: 10, }, diff --git a/src/view/shell/desktop/RightNav.tsx b/src/view/shell/desktop/RightNav.tsx index f0cd4f59a..633f04932 100644 --- a/src/view/shell/desktop/RightNav.tsx +++ b/src/view/shell/desktop/RightNav.tsx @@ -13,6 +13,7 @@ import {TextLink} from 'view/com/util/Link' import {Text} from 'view/com/util/text/Text' import {DesktopFeeds} from './Feeds' import {DesktopSearch} from './Search' +import hairlineWidth = StyleSheet.hairlineWidth export function DesktopRightNav({routeName}: {routeName: string}) { const pal = usePalette('default') @@ -130,8 +131,8 @@ const styles = StyleSheet.create({ marginBottom: 10, }, desktopFeedsContainer: { - borderTopWidth: 1, - borderBottomWidth: 1, + borderTopWidth: hairlineWidth, + borderBottomWidth: hairlineWidth, marginTop: 18, marginBottom: 18, }, |