Change many border widths from 1 to hairlineWidth (#4294)

* feed items

* update some more

* moar

* profile card

* composer and notifications

* settings screen

* remove border from first item in feeds

* remove border from first item in feeds

* more removal of top border

* fix flatlist rendering

* oops

* scroll to top fab

* a.border

* centeredview/list

* placeholder

* web sidebar

* search posts

* feeds list

* user lists

* list header

* account list width 1

* hide top border feedgens

* same for lists

* fix tab bar web desktop

* wait...

* show the border on desktop web

* fix lists

* fix lists

* round
This commit is contained in:
Hailey 2024-05-30 21:32:54 -07:00 committed by GitHub
parent 8569e2e389
commit 89c9fd3be1
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
33 changed files with 227 additions and 144 deletions

View file

@ -1,7 +1,8 @@
import {Platform} from 'react-native' import {Platform, StyleSheet} from 'react-native'
import * as tokens from '#/alf/tokens' import * as tokens from '#/alf/tokens'
import {native, web} from '#/alf/util/platform' import {native, web} from '#/alf/util/platform'
import hairlineWidth = StyleSheet.hairlineWidth
export const atoms = { export const atoms = {
/* /*
@ -277,19 +278,19 @@ export const atoms = {
borderWidth: 0, borderWidth: 0,
}, },
border: { border: {
borderWidth: 1, borderWidth: hairlineWidth,
}, },
border_t: { border_t: {
borderTopWidth: 1, borderTopWidth: hairlineWidth,
}, },
border_b: { border_b: {
borderBottomWidth: 1, borderBottomWidth: hairlineWidth,
}, },
border_l: { border_l: {
borderLeftWidth: 1, borderLeftWidth: hairlineWidth,
}, },
border_r: { border_r: {
borderRightWidth: 1, borderRightWidth: hairlineWidth,
}, },
/* /*

View file

@ -37,7 +37,7 @@ export function AccountList({
style={[ style={[
a.rounded_md, a.rounded_md,
a.overflow_hidden, a.overflow_hidden,
a.border, {borderWidth: 1},
t.atoms.border_contrast_low, t.atoms.border_contrast_low,
]}> ]}>
{accounts.map(account => ( {accounts.map(account => (
@ -48,7 +48,7 @@ export function AccountList({
isCurrentAccount={account.did === currentAccount?.did} isCurrentAccount={account.did === currentAccount?.did}
isPendingAccount={account.did === pendingDid} 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> </React.Fragment>
))} ))}
<Button <Button

View file

@ -90,6 +90,7 @@ import {SuggestedLanguage} from './select-language/SuggestedLanguage'
import {TextInput, TextInputRef} from './text-input/TextInput' import {TextInput, TextInputRef} from './text-input/TextInput'
import {ThreadgateBtn} from './threadgate/ThreadgateBtn' import {ThreadgateBtn} from './threadgate/ThreadgateBtn'
import {useExternalLinkFetch} from './useExternalLinkFetch' import {useExternalLinkFetch} from './useExternalLinkFetch'
import hairlineWidth = StyleSheet.hairlineWidth
type CancelRef = { type CancelRef = {
onPressCancel: () => void onPressCancel: () => void
@ -657,7 +658,7 @@ const styles = StyleSheet.create({
marginBottom: 6, marginBottom: 6,
}, },
errorIcon: { errorIcon: {
borderWidth: 1, borderWidth: hairlineWidth,
borderColor: colors.red4, borderColor: colors.red4,
color: colors.red4, color: colors.red4,
borderRadius: 30, borderRadius: 30,
@ -692,6 +693,6 @@ const styles = StyleSheet.create({
paddingLeft: 15, paddingLeft: 15,
paddingRight: 20, paddingRight: 20,
alignItems: 'center', alignItems: 'center',
borderTopWidth: 1, borderTopWidth: hairlineWidth,
}, },
}) })

View file

@ -1,13 +1,15 @@
import React from 'react' import React from 'react'
import {StyleSheet, TouchableOpacity} from 'react-native' import {StyleSheet, TouchableOpacity} from 'react-native'
import {UserAvatar} from '../util/UserAvatar' import {msg, Trans} from '@lingui/macro'
import {Text} from '../util/text/Text' import {useLingui} from '@lingui/react'
import {useProfileQuery} from '#/state/queries/profile'
import {useSession} from '#/state/session'
import {usePalette} from 'lib/hooks/usePalette' import {usePalette} from 'lib/hooks/usePalette'
import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries' import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries'
import {Trans, msg} from '@lingui/macro' import {Text} from '../util/text/Text'
import {useLingui} from '@lingui/react' import {UserAvatar} from '../util/UserAvatar'
import {useSession} from '#/state/session' import hairlineWidth = StyleSheet.hairlineWidth
import {useProfileQuery} from '#/state/queries/profile'
export function ComposePrompt({onPressCompose}: {onPressCompose: () => void}) { export function ComposePrompt({onPressCompose}: {onPressCompose: () => void}) {
const {currentAccount} = useSession() const {currentAccount} = useSession()
@ -47,7 +49,7 @@ const styles = StyleSheet.create({
paddingBottom: 10, paddingBottom: 10,
flexDirection: 'row', flexDirection: 'row',
alignItems: 'center', alignItems: 'center',
borderTopWidth: 1, borderTopWidth: hairlineWidth,
}, },
labelMobile: { labelMobile: {
paddingLeft: 12, paddingLeft: 12,

View file

@ -25,6 +25,7 @@ import * as Prompt from '#/components/Prompt'
import {RichText} from '#/components/RichText' import {RichText} from '#/components/RichText'
import {Text} from '../util/text/Text' import {Text} from '../util/text/Text'
import {UserAvatar} from '../util/UserAvatar' import {UserAvatar} from '../util/UserAvatar'
import hairlineWidth = StyleSheet.hairlineWidth
export function FeedSourceCard({ export function FeedSourceCard({
feedUri, feedUri,
@ -34,6 +35,7 @@ export function FeedSourceCard({
showLikes = false, showLikes = false,
pinOnSave = false, pinOnSave = false,
showMinimalPlaceholder, showMinimalPlaceholder,
hideTopBorder,
}: { }: {
feedUri: string feedUri: string
style?: StyleProp<ViewStyle> style?: StyleProp<ViewStyle>
@ -42,6 +44,7 @@ export function FeedSourceCard({
showLikes?: boolean showLikes?: boolean
pinOnSave?: boolean pinOnSave?: boolean
showMinimalPlaceholder?: boolean showMinimalPlaceholder?: boolean
hideTopBorder?: boolean
}) { }) {
const {data: preferences} = usePreferencesQuery() const {data: preferences} = usePreferencesQuery()
const {data: feed} = useFeedSourceInfoQuery({uri: feedUri}) const {data: feed} = useFeedSourceInfoQuery({uri: feedUri})
@ -57,6 +60,7 @@ export function FeedSourceCard({
showLikes={showLikes} showLikes={showLikes}
pinOnSave={pinOnSave} pinOnSave={pinOnSave}
showMinimalPlaceholder={showMinimalPlaceholder} showMinimalPlaceholder={showMinimalPlaceholder}
hideTopBorder={hideTopBorder}
/> />
) )
} }
@ -71,6 +75,7 @@ export function FeedSourceCardLoaded({
showLikes = false, showLikes = false,
pinOnSave = false, pinOnSave = false,
showMinimalPlaceholder, showMinimalPlaceholder,
hideTopBorder,
}: { }: {
feedUri: string feedUri: string
feed?: FeedSourceInfo feed?: FeedSourceInfo
@ -81,6 +86,7 @@ export function FeedSourceCardLoaded({
showLikes?: boolean showLikes?: boolean
pinOnSave?: boolean pinOnSave?: boolean
showMinimalPlaceholder?: boolean showMinimalPlaceholder?: boolean
hideTopBorder?: boolean
}) { }) {
const t = useTheme() const t = useTheme()
const pal = usePalette('default') const pal = usePalette('default')
@ -149,7 +155,7 @@ export function FeedSourceCardLoaded({
style={[ style={[
pal.border, pal.border,
{ {
borderTopWidth: showMinimalPlaceholder ? 0 : 1, borderTopWidth: showMinimalPlaceholder || hideTopBorder ? 0 : 1,
flexDirection: 'row', flexDirection: 'row',
alignItems: 'center', alignItems: 'center',
flex: 1, flex: 1,
@ -191,7 +197,12 @@ export function FeedSourceCardLoaded({
<Pressable <Pressable
testID={`feed-${feed.displayName}`} testID={`feed-${feed.displayName}`}
accessibilityRole="button" accessibilityRole="button"
style={[styles.container, pal.border, style]} style={[
styles.container,
pal.border,
style,
{borderTopWidth: hideTopBorder ? 0 : hairlineWidth},
]}
onPress={() => { onPress={() => {
if (feed.type === 'feed') { if (feed.type === 'feed') {
navigation.push('ProfileFeed', { navigation.push('ProfileFeed', {
@ -295,7 +306,6 @@ const styles = StyleSheet.create({
paddingVertical: 20, paddingVertical: 20,
flexDirection: 'column', flexDirection: 'column',
flex: 1, flex: 1,
borderTopWidth: 1,
gap: 14, gap: 14,
}, },
headerContainer: { headerContainer: {

View file

@ -1,6 +1,7 @@
import React from 'react' import React from 'react'
import { import {
findNodeHandle, findNodeHandle,
ListRenderItemInfo,
StyleProp, StyleProp,
StyleSheet, StyleSheet,
View, View,
@ -134,7 +135,7 @@ export const ProfileFeedgens = React.forwardRef<
// = // =
const renderItemInner = React.useCallback( const renderItemInner = React.useCallback(
({item}: {item: any}) => { ({item, index}: ListRenderItemInfo<any>) => {
if (item === EMPTY) { if (item === EMPTY) {
return ( return (
<View <View
@ -169,6 +170,7 @@ export const ProfileFeedgens = React.forwardRef<
preferences={preferences} preferences={preferences}
style={styles.item} style={styles.item}
showLikes showLikes
hideTopBorder={index === 0}
/> />
) )
} }

View file

@ -1,18 +1,20 @@
import React from 'react' import React from 'react'
import {StyleProp, StyleSheet, View, ViewStyle} from 'react-native' import {StyleProp, StyleSheet, View, ViewStyle} from 'react-native'
import {AtUri, AppBskyGraphDefs, RichText} from '@atproto/api' import {AppBskyGraphDefs, AtUri, RichText} from '@atproto/api'
import {Link} from '../util/Link' import {Trans} from '@lingui/macro'
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 {useSession} from '#/state/session' 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 {sanitizeDisplayName} from 'lib/strings/display-names'
import {sanitizeHandle} from 'lib/strings/handles' import {sanitizeHandle} from 'lib/strings/handles'
import {makeProfileLink} from 'lib/routes/links' import {s} from 'lib/styles'
import {Trans} from '@lingui/macro'
import {atoms as a} from '#/alf' 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 = ({ export const ListCard = ({
testID, testID,
@ -132,7 +134,7 @@ export const ListCard = ({
const styles = StyleSheet.create({ const styles = StyleSheet.create({
outer: { outer: {
borderTopWidth: 1, borderTopWidth: hairlineWidth,
paddingHorizontal: 6, paddingHorizontal: 6,
}, },
outerNoBorder: { outerNoBorder: {

View file

@ -9,17 +9,19 @@ import {
ViewStyle, ViewStyle,
} from 'react-native' } from 'react-native'
import {AppBskyGraphDefs as GraphDefs} from '@atproto/api' 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 {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 {useAnalytics} from 'lib/analytics/analytics'
import {usePalette} from 'lib/hooks/usePalette' import {usePalette} from 'lib/hooks/usePalette'
import {List} from '../util/List'
import {s} from 'lib/styles' import {s} from 'lib/styles'
import {logger} from '#/logger' import {ErrorMessage} from '../util/error/ErrorMessage'
import {Trans} from '@lingui/macro' import {List} from '../util/List'
import {cleanError} from '#/lib/strings/errors' import {Text} from '../util/text/Text'
import {ListCard} from './ListCard'
import hairlineWidth = StyleSheet.hairlineWidth
const LOADING = {_reactKey: '__loading__'} const LOADING = {_reactKey: '__loading__'}
const EMPTY = {_reactKey: '__empty__'} const EMPTY = {_reactKey: '__empty__'}
@ -84,7 +86,7 @@ export function MyLists({
<View <View
key={item._reactKey} key={item._reactKey}
testID="listsEmpty" testID="listsEmpty"
style={[{padding: 18, borderTopWidth: 1}, pal.border]}> style={[{padding: 18, borderTopWidth: hairlineWidth}, pal.border]}>
<Text style={pal.textLight}> <Text style={pal.textLight}>
<Trans>You have no lists.</Trans> <Trans>You have no lists.</Trans>
</Text> </Text>

View file

@ -1,6 +1,7 @@
import React from 'react' import React from 'react'
import { import {
findNodeHandle, findNodeHandle,
ListRenderItemInfo,
StyleProp, StyleProp,
StyleSheet, StyleSheet,
View, View,
@ -138,12 +139,10 @@ export const ProfileLists = React.forwardRef<SectionRef, ProfileListsProps>(
// = // =
const renderItemInner = React.useCallback( const renderItemInner = React.useCallback(
({item}: {item: any}) => { ({item, index}: ListRenderItemInfo<any>) => {
if (item === EMPTY) { if (item === EMPTY) {
return ( return (
<View <View testID="listsEmpty" style={[{padding: 18}, pal.border]}>
testID="listsEmpty"
style={[{padding: 18, borderTopWidth: 1}, pal.border]}>
<Text style={pal.textLight}> <Text style={pal.textLight}>
<Trans>You have no lists.</Trans> <Trans>You have no lists.</Trans>
</Text> </Text>
@ -173,6 +172,7 @@ export const ProfileLists = React.forwardRef<SectionRef, ProfileListsProps>(
list={item} list={item}
testID={`list-${item.name}`} testID={`list-${item.name}`}
style={styles.item} style={styles.item}
noBorder={index === 0}
/> />
) )
}, },

View file

@ -1,5 +1,10 @@
import React from 'react' 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 {msg} from '@lingui/macro'
import {useLingui} from '@lingui/react' import {useLingui} from '@lingui/react'
@ -17,6 +22,9 @@ import {NotificationFeedLoadingPlaceholder} from '../util/LoadingPlaceholder'
import {LoadMoreRetryBtn} from '../util/LoadMoreRetryBtn' import {LoadMoreRetryBtn} from '../util/LoadMoreRetryBtn'
import {CenteredView} from '../util/Views' import {CenteredView} from '../util/Views'
import {FeedItem} from './FeedItem' 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 EMPTY_FEED_ITEM = {_reactKey: '__empty__'}
const LOAD_MORE_ERROR_ITEM = {_reactKey: '__load_more_error__'} const LOAD_MORE_ERROR_ITEM = {_reactKey: '__load_more_error__'}
@ -33,8 +41,11 @@ export function Feed({
onScrolledDownChange: (isScrolledDown: boolean) => void onScrolledDownChange: (isScrolledDown: boolean) => void
ListHeaderComponent?: () => JSX.Element ListHeaderComponent?: () => JSX.Element
}) { }) {
const initialNumToRender = useInitialNumToRender()
const [isPTRing, setIsPTRing] = React.useState(false) const [isPTRing, setIsPTRing] = React.useState(false)
const pal = usePalette('default') const pal = usePalette('default')
const {isTabletOrMobile} = useWebMediaQueries()
const {_} = useLingui() const {_} = useLingui()
const moderationOpts = useModerationOpts() const moderationOpts = useModerationOpts()
@ -97,12 +108,8 @@ export function Feed({
fetchNextPage() fetchNextPage()
}, [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( const renderItem = React.useCallback(
({item}: {item: any}) => { ({item, index}: ListRenderItemInfo<any>) => {
if (item === EMPTY_FEED_ITEM) { if (item === EMPTY_FEED_ITEM) {
return ( return (
<EmptyState <EmptyState
@ -122,14 +129,20 @@ export function Feed({
) )
} else if (item === LOADING_ITEM) { } else if (item === LOADING_ITEM) {
return ( return (
<View style={[pal.border, {borderTopWidth: 1}]}> <View style={[pal.border, {borderTopWidth: hairlineWidth}]}>
<NotificationFeedLoadingPlaceholder /> <NotificationFeedLoadingPlaceholder />
</View> </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( const FeedFooter = React.useCallback(
@ -170,6 +183,8 @@ export function Feed({
contentContainerStyle={s.contentContainer} contentContainerStyle={s.contentContainer}
// @ts-ignore our .web version only -prf // @ts-ignore our .web version only -prf
desktopFixedHeight desktopFixedHeight
initialNumToRender={initialNumToRender}
windowSize={11}
/> />
</View> </View>
) )

View file

@ -47,6 +47,7 @@ import {formatCount} from '../util/numeric/format'
import {Text} from '../util/text/Text' import {Text} from '../util/text/Text'
import {TimeElapsed} from '../util/TimeElapsed' import {TimeElapsed} from '../util/TimeElapsed'
import {PreviewableUserAvatar, UserAvatar} from '../util/UserAvatar' import {PreviewableUserAvatar, UserAvatar} from '../util/UserAvatar'
import hairlineWidth = StyleSheet.hairlineWidth
const MAX_AUTHORS = 5 const MAX_AUTHORS = 5
@ -61,9 +62,11 @@ interface Author {
let FeedItem = ({ let FeedItem = ({
item, item,
moderationOpts, moderationOpts,
hideTopBorder,
}: { }: {
item: FeedNotification item: FeedNotification
moderationOpts: ModerationOpts moderationOpts: ModerationOpts
hideTopBorder?: boolean
}): React.ReactNode => { }): React.ReactNode => {
const queryClient = useQueryClient() const queryClient = useQueryClient()
const pal = usePalette('default') const pal = usePalette('default')
@ -188,6 +191,7 @@ let FeedItem = ({
backgroundColor: pal.colors.unreadNotifBg, backgroundColor: pal.colors.unreadNotifBg,
borderColor: pal.colors.unreadNotifBorder, borderColor: pal.colors.unreadNotifBorder,
}, },
{borderTopWidth: hideTopBorder ? 0 : hairlineWidth},
]} ]}
href={itemHref} href={itemHref}
noFeedback noFeedback
@ -480,7 +484,6 @@ const styles = StyleSheet.create({
outer: { outer: {
padding: 10, padding: 10,
paddingRight: 15, paddingRight: 15,
borderTopWidth: 1,
flexDirection: 'row', flexDirection: 'row',
}, },
layoutIcon: { layoutIcon: {

View file

@ -67,13 +67,13 @@ export const PagerWithHeader = React.forwardRef<PagerRef, PagerWithHeaderProps>(
const height = evt.nativeEvent.layout.height const height = evt.nativeEvent.layout.height
if (height > 0) { if (height > 0) {
// The rounding is necessary to prevent jumps on iOS // The rounding is necessary to prevent jumps on iOS
setTabBarHeight(Math.round(height)) setTabBarHeight(Math.round(height * 2) / 2)
} }
}) })
const onHeaderOnlyLayout = useNonReactiveCallback((height: number) => { const onHeaderOnlyLayout = useNonReactiveCallback((height: number) => {
if (height > 0) { if (height > 0) {
// The rounding is necessary to prevent jumps on iOS // The rounding is necessary to prevent jumps on iOS
setHeaderOnlyHeight(Math.round(height)) setHeaderOnlyHeight(Math.round(height * 2) / 2)
} }
}) })

View file

@ -7,6 +7,7 @@ import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries'
import {PressableWithHover} from '../util/PressableWithHover' import {PressableWithHover} from '../util/PressableWithHover'
import {Text} from '../util/text/Text' import {Text} from '../util/text/Text'
import {DraggableScrollView} from './DraggableScrollView' import {DraggableScrollView} from './DraggableScrollView'
import hairlineWidth = StyleSheet.hairlineWidth
export interface TabBarProps { export interface TabBarProps {
testID?: string testID?: string
@ -207,6 +208,6 @@ const mobileStyles = StyleSheet.create({
left: 0, left: 0,
right: 0, right: 0,
bottom: -1, bottom: -1,
borderBottomWidth: 1, borderBottomWidth: hairlineWidth,
}, },
}) })

View file

@ -50,6 +50,7 @@ import {PostEmbeds} from '../util/post-embeds'
import {PostMeta} from '../util/PostMeta' import {PostMeta} from '../util/PostMeta'
import {Text} from '../util/text/Text' import {Text} from '../util/text/Text'
import {PreviewableUserAvatar} from '../util/UserAvatar' import {PreviewableUserAvatar} from '../util/UserAvatar'
import hairlineWidth = StyleSheet.hairlineWidth
export function PostThreadItem({ export function PostThreadItem({
post, post,
@ -623,7 +624,7 @@ function PostOuterWrapper({
{ {
flexDirection: 'row', flexDirection: 'row',
paddingHorizontal: isMobile ? 10 : 6, paddingHorizontal: isMobile ? 10 : 6,
borderTopWidth: depth === 1 ? 1 : 0, borderTopWidth: depth === 1 ? hairlineWidth : 0,
}, },
]}> ]}>
{Array.from(Array(depth - 1)).map((_, n: number) => ( {Array.from(Array(depth - 1)).map((_, n: number) => (
@ -704,7 +705,7 @@ function ExpandedPostDetails({
const styles = StyleSheet.create({ const styles = StyleSheet.create({
outer: { outer: {
borderTopWidth: 1, borderTopWidth: hairlineWidth,
paddingLeft: 8, paddingLeft: 8,
}, },
outerHighlighted: { outerHighlighted: {
@ -714,7 +715,7 @@ const styles = StyleSheet.create({
paddingRight: 8, paddingRight: 8,
}, },
outerHighlightedRoot: { outerHighlightedRoot: {
borderTopWidth: 1, borderTopWidth: hairlineWidth,
paddingTop: 16, paddingTop: 16,
}, },
noTopBorder: { noTopBorder: {
@ -766,8 +767,8 @@ const styles = StyleSheet.create({
expandedInfo: { expandedInfo: {
flexDirection: 'row', flexDirection: 'row',
padding: 10, padding: 10,
borderTopWidth: 1, borderTopWidth: hairlineWidth,
borderBottomWidth: 1, borderBottomWidth: hairlineWidth,
marginTop: 5, marginTop: 5,
marginBottom: 10, marginBottom: 10,
}, },

View file

@ -36,6 +36,7 @@ import {PostMeta} from '../util/PostMeta'
import {Text} from '../util/text/Text' import {Text} from '../util/text/Text'
import {PreviewableUserAvatar} from '../util/UserAvatar' import {PreviewableUserAvatar} from '../util/UserAvatar'
import {UserInfoText} from '../util/UserInfoText' import {UserInfoText} from '../util/UserInfoText'
import hairlineWidth = StyleSheet.hairlineWidth
export function Post({ export function Post({
post, post,
@ -242,7 +243,7 @@ const styles = StyleSheet.create({
paddingRight: 15, paddingRight: 15,
paddingBottom: 5, paddingBottom: 5,
paddingLeft: 10, paddingLeft: 10,
borderTopWidth: 1, borderTopWidth: hairlineWidth,
// @ts-ignore web only -prf // @ts-ignore web only -prf
cursor: 'pointer', cursor: 'pointer',
}, },

View file

@ -3,6 +3,7 @@ import {
ActivityIndicator, ActivityIndicator,
AppState, AppState,
Dimensions, Dimensions,
ListRenderItemInfo,
StyleProp, StyleProp,
StyleSheet, StyleSheet,
View, View,
@ -31,6 +32,7 @@ import {
import {useSession} from '#/state/session' import {useSession} from '#/state/session'
import {useAnalytics} from 'lib/analytics/analytics' import {useAnalytics} from 'lib/analytics/analytics'
import {useInitialNumToRender} from 'lib/hooks/useInitialNumToRender' import {useInitialNumToRender} from 'lib/hooks/useInitialNumToRender'
import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries'
import {useTheme} from 'lib/ThemeContext' import {useTheme} from 'lib/ThemeContext'
import {List, ListRef} from '../util/List' import {List, ListRef} from '../util/List'
import {PostFeedLoadingPlaceholder} from '../util/LoadingPlaceholder' import {PostFeedLoadingPlaceholder} from '../util/LoadingPlaceholder'
@ -100,6 +102,7 @@ let Feed = ({
const checkForNewRef = React.useRef<(() => void) | null>(null) const checkForNewRef = React.useRef<(() => void) | null>(null)
const lastFetchRef = React.useRef<number>(Date.now()) const lastFetchRef = React.useRef<number>(Date.now())
const [feedType, feedUri] = feed.split('|') const [feedType, feedUri] = feed.split('|')
const {isTabletOrMobile} = useWebMediaQueries()
const opts = React.useMemo( const opts = React.useMemo(
() => ({enabled, ignoreFilterFor}), () => ({enabled, ignoreFilterFor}),
@ -279,7 +282,7 @@ let Feed = ({
// = // =
const renderItem = React.useCallback( const renderItem = React.useCallback(
({item}: {item: any}) => { ({item, index}: ListRenderItemInfo<any>) => {
if (item === EMPTY_FEED_ITEM) { if (item === EMPTY_FEED_ITEM) {
return renderEmptyState() return renderEmptyState()
} else if (item === ERROR_ITEM) { } else if (item === ERROR_ITEM) {
@ -311,17 +314,23 @@ let Feed = ({
// -prf // -prf
return <DiscoverFallbackHeader /> return <DiscoverFallbackHeader />
} }
return <FeedSlice slice={item} /> return (
<FeedSlice
slice={item}
hideTopBorder={index === 0 && isTabletOrMobile}
/>
)
}, },
[ [
isTabletOrMobile,
renderEmptyState,
feed, feed,
feedUri,
error, error,
onPressTryAgain, onPressTryAgain,
onPressRetryLoadMore,
renderEmptyState,
_,
savedFeedConfig, savedFeedConfig,
_,
onPressRetryLoadMore,
feedUri,
], ],
) )

View file

@ -42,6 +42,7 @@ import {PostMeta} from '../util/PostMeta'
import {Text} from '../util/text/Text' import {Text} from '../util/text/Text'
import {PreviewableUserAvatar} from '../util/UserAvatar' import {PreviewableUserAvatar} from '../util/UserAvatar'
import {AviFollowButton} from './AviFollowButton' import {AviFollowButton} from './AviFollowButton'
import hairlineWidth = StyleSheet.hairlineWidth
interface FeedItemProps { interface FeedItemProps {
record: AppBskyFeedPost.Record record: AppBskyFeedPost.Record
@ -53,6 +54,7 @@ interface FeedItemProps {
isThreadLastChild?: boolean isThreadLastChild?: boolean
isThreadParent?: boolean isThreadParent?: boolean
feedContext: string | undefined feedContext: string | undefined
hideTopBorder?: boolean
} }
export function FeedItem({ export function FeedItem({
@ -66,6 +68,7 @@ export function FeedItem({
isThreadChild, isThreadChild,
isThreadLastChild, isThreadLastChild,
isThreadParent, isThreadParent,
hideTopBorder,
}: FeedItemProps & {post: AppBskyFeedDefs.PostView}): React.ReactNode { }: FeedItemProps & {post: AppBskyFeedDefs.PostView}): React.ReactNode {
const postShadowed = usePostShadow(post) const postShadowed = usePostShadow(post)
const richText = useMemo( const richText = useMemo(
@ -95,6 +98,7 @@ export function FeedItem({
isThreadChild={isThreadChild} isThreadChild={isThreadChild}
isThreadLastChild={isThreadLastChild} isThreadLastChild={isThreadLastChild}
isThreadParent={isThreadParent} isThreadParent={isThreadParent}
hideTopBorder={hideTopBorder}
/> />
) )
} }
@ -113,6 +117,7 @@ let FeedItemInner = ({
isThreadChild, isThreadChild,
isThreadLastChild, isThreadLastChild,
isThreadParent, isThreadParent,
hideTopBorder,
}: FeedItemProps & { }: FeedItemProps & {
richText: RichTextAPI richText: RichTextAPI
post: Shadow<AppBskyFeedDefs.PostView> post: Shadow<AppBskyFeedDefs.PostView>
@ -186,8 +191,8 @@ let FeedItemInner = ({
isThreadLastChild || (!isThreadChild && !isThreadParent) isThreadLastChild || (!isThreadChild && !isThreadParent)
? 8 ? 8
: undefined, : undefined,
borderTopWidth: hideTopBorder || isThreadChild ? 0 : hairlineWidth,
}, },
isThreadChild ? styles.outerSmallTop : undefined,
] ]
return ( return (
@ -445,16 +450,12 @@ function ReplyToLabel({profile}: {profile: AppBskyActorDefs.ProfileViewBasic}) {
const styles = StyleSheet.create({ const styles = StyleSheet.create({
outer: { outer: {
borderTopWidth: 1,
paddingLeft: 10, paddingLeft: 10,
paddingRight: 15, paddingRight: 15,
// @ts-ignore web only -prf // @ts-ignore web only -prf
cursor: 'pointer', cursor: 'pointer',
overflow: 'hidden', overflow: 'hidden',
}, },
outerSmallTop: {
borderTopWidth: 0,
},
replyLine: { replyLine: {
width: 2, width: 2,
marginLeft: 'auto', marginLeft: 'auto',

View file

@ -11,7 +11,13 @@ import {Link} from '../util/Link'
import {Text} from '../util/text/Text' import {Text} from '../util/text/Text'
import {FeedItem} from './FeedItem' 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) { if (slice.isThread && slice.items.length > 3) {
const last = slice.items.length - 1 const last = slice.items.length - 1
return ( return (
@ -27,6 +33,7 @@ let FeedSlice = ({slice}: {slice: FeedPostSlice}): React.ReactNode => {
moderation={slice.items[0].moderation} moderation={slice.items[0].moderation}
isThreadParent={isThreadParentAt(slice.items, 0)} isThreadParent={isThreadParentAt(slice.items, 0)}
isThreadChild={isThreadChildAt(slice.items, 0)} isThreadChild={isThreadChildAt(slice.items, 0)}
hideTopBorder={hideTopBorder}
/> />
<FeedItem <FeedItem
key={slice.items[1]._reactKey} key={slice.items[1]._reactKey}
@ -75,6 +82,7 @@ let FeedSlice = ({slice}: {slice: FeedPostSlice}): React.ReactNode => {
isThreadLastChild={ isThreadLastChild={
isThreadChildAt(slice.items, i) && slice.items.length === i + 1 isThreadChildAt(slice.items, i) && slice.items.length === i + 1
} }
hideTopBorder={hideTopBorder && i === 0}
/> />
))} ))}
</> </>

View file

@ -25,6 +25,7 @@ import {Link} from '../util/Link'
import {Text} from '../util/text/Text' import {Text} from '../util/text/Text'
import {PreviewableUserAvatar} from '../util/UserAvatar' import {PreviewableUserAvatar} from '../util/UserAvatar'
import {FollowButton} from './FollowButton' import {FollowButton} from './FollowButton'
import hairlineWidth = StyleSheet.hairlineWidth
export function ProfileCard({ export function ProfileCard({
testID, testID,
@ -280,7 +281,7 @@ export function ProfileCardWithFollowBtn({
const styles = StyleSheet.create({ const styles = StyleSheet.create({
outer: { outer: {
borderTopWidth: 1, borderTopWidth: hairlineWidth,
paddingHorizontal: 6, paddingHorizontal: 6,
paddingVertical: 4, paddingVertical: 4,
}, },

View file

@ -1,24 +1,26 @@
import React from 'react' import React from 'react'
import {Pressable, StyleSheet, View} from 'react-native' import {Pressable, StyleSheet, View} from 'react-native'
import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome' 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 {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 {usePalette} from 'lib/hooks/usePalette'
import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries' 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 {makeProfileLink} from 'lib/routes/links'
import {NavigationProp} from 'lib/routes/types' import {NavigationProp} from 'lib/routes/types'
import {BACK_HITSLOP} from 'lib/constants' import {sanitizeHandle} from 'lib/strings/handles'
import {isNative} from 'platform/detection' import {isNative} from 'platform/detection'
import {useLightboxControls, ImagesLightbox} from '#/state/lightbox' import {TextLink} from '../util/Link'
import {useLingui} from '@lingui/react' import {LoadingPlaceholder} from '../util/LoadingPlaceholder'
import {Trans, msg} from '@lingui/macro' import {Text} from '../util/text/Text'
import {useSetDrawerOpen} from '#/state/shell' import {UserAvatar, UserAvatarType} from '../util/UserAvatar'
import {emitSoftReset} from '#/state/events' import {CenteredView} from '../util/Views'
import hairlineWidth = StyleSheet.hairlineWidth
export function ProfileSubpageHeader({ export function ProfileSubpageHeader({
isLoading, isLoading,
@ -79,7 +81,7 @@ export function ProfileSubpageHeader({
{ {
flexDirection: 'row', flexDirection: 'row',
alignItems: 'center', alignItems: 'center',
borderBottomWidth: 1, borderBottomWidth: hairlineWidth,
paddingTop: isNative ? 0 : 8, paddingTop: isNative ? 0 : 8,
paddingBottom: 8, paddingBottom: 8,
paddingHorizontal: isMobile ? 12 : 14, paddingHorizontal: isMobile ? 12 : 14,

View file

@ -15,6 +15,7 @@ import {useTheme as useTheme_NEW} from '#/alf'
import {Bubble_Stroke2_Corner2_Rounded as Bubble} from '#/components/icons/Bubble' import {Bubble_Stroke2_Corner2_Rounded as Bubble} from '#/components/icons/Bubble'
import {Heart2_Stroke2_Corner0_Rounded as HeartIconOutline} from '#/components/icons/Heart2' import {Heart2_Stroke2_Corner0_Rounded as HeartIconOutline} from '#/components/icons/Heart2'
import {Repost_Stroke2_Corner2_Rounded as Repost} from '#/components/icons/Repost' import {Repost_Stroke2_Corner2_Rounded as Repost} from '#/components/icons/Repost'
import hairlineWidth = StyleSheet.hairlineWidth
export function LoadingPlaceholder({ export function LoadingPlaceholder({
width, width,
@ -233,7 +234,7 @@ export function FeedLoadingPlaceholder({
{ {
paddingHorizontal: 12, paddingHorizontal: 12,
paddingVertical: 18, paddingVertical: 18,
borderTopWidth: showTopBorder ? 1 : 0, borderTopWidth: showTopBorder ? hairlineWidth : 0,
}, },
pal.border, pal.border,
style, style,

View file

@ -15,6 +15,7 @@ import {NavigationProp} from 'lib/routes/types'
import {useTheme} from '#/alf' import {useTheme} from '#/alf'
import {Text} from './text/Text' import {Text} from './text/Text'
import {CenteredView} from './Views' import {CenteredView} from './Views'
import hairlineWidth = StyleSheet.hairlineWidth
const BACK_HITSLOP = {left: 20, top: 20, right: 50, bottom: 20} const BACK_HITSLOP = {left: 20, top: 20, right: 50, bottom: 20}
@ -156,7 +157,7 @@ function DesktopWebHeader({
styles.desktopHeader, styles.desktopHeader,
pal.border, pal.border,
{ {
borderBottomWidth: showBorder ? 1 : 0, borderBottomWidth: showBorder ? hairlineWidth : 0,
}, },
{display: 'flex', flexDirection: 'column'}, {display: 'flex', flexDirection: 'column'},
]}> ]}>
@ -245,7 +246,7 @@ const styles = StyleSheet.create({
marginRight: 'auto', marginRight: 'auto',
}, },
border: { border: {
borderBottomWidth: 1, borderBottomWidth: hairlineWidth,
}, },
titleContainer: { titleContainer: {
marginLeft: 'auto', marginLeft: 'auto',

View file

@ -26,6 +26,7 @@ import Animated from 'react-native-reanimated'
import {usePalette} from 'lib/hooks/usePalette' import {usePalette} from 'lib/hooks/usePalette'
import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries' import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries'
import {addStyle} from 'lib/styles' import {addStyle} from 'lib/styles'
import hairlineWidth = StyleSheet.hairlineWidth
interface AddedProps { interface AddedProps {
desktopFixedHeight?: boolean | number desktopFixedHeight?: boolean | number
@ -46,8 +47,8 @@ export const CenteredView = React.forwardRef(function CenteredView({
} }
if (sideBorders) { if (sideBorders) {
style = addStyle(style, { style = addStyle(style, {
borderLeftWidth: 1, borderLeftWidth: hairlineWidth,
borderRightWidth: 1, borderRightWidth: hairlineWidth,
}) })
style = addStyle(style, pal.border) style = addStyle(style, pal.border)
} }
@ -159,8 +160,8 @@ export const ScrollView = React.forwardRef(function ScrollViewImpl(
const styles = StyleSheet.create({ const styles = StyleSheet.create({
contentContainer: { contentContainer: {
borderLeftWidth: 1, borderLeftWidth: hairlineWidth,
borderRightWidth: 1, borderRightWidth: hairlineWidth,
// @ts-ignore web only // @ts-ignore web only
minHeight: '100vh', minHeight: '100vh',
}, },

View file

@ -13,6 +13,7 @@ import {clamp} from '#/lib/numbers'
import {colors} from '#/lib/styles' import {colors} from '#/lib/styles'
import {isWeb} from '#/platform/detection' import {isWeb} from '#/platform/detection'
import {useSession} from '#/state/session' import {useSession} from '#/state/session'
import hairlineWidth = StyleSheet.hairlineWidth
const AnimatedTouchableOpacity = const AnimatedTouchableOpacity =
Animated.createAnimatedComponent(TouchableOpacity) Animated.createAnimatedComponent(TouchableOpacity)
@ -73,7 +74,7 @@ const styles = StyleSheet.create({
// @ts-ignore 'fixed' is web only -prf // @ts-ignore 'fixed' is web only -prf
position: isWeb ? 'fixed' : 'absolute', position: isWeb ? 'fixed' : 'absolute',
left: 18, left: 18,
borderWidth: 1, borderWidth: hairlineWidth,
width: 52, width: 52,
height: 52, height: 52,
borderRadius: 26, borderRadius: 26,

View file

@ -39,6 +39,7 @@ import {Link} from '../Link'
import {PostMeta} from '../PostMeta' import {PostMeta} from '../PostMeta'
import {Text} from '../text/Text' import {Text} from '../text/Text'
import {PostEmbeds} from '.' import {PostEmbeds} from '.'
import hairlineWidth = StyleSheet.hairlineWidth
export function MaybeQuoteEmbed({ export function MaybeQuoteEmbed({
embed, embed,
@ -247,7 +248,7 @@ const styles = StyleSheet.create({
marginTop: 8, marginTop: 8,
paddingVertical: 12, paddingVertical: 12,
paddingHorizontal: 12, paddingHorizontal: 12,
borderWidth: 1, borderWidth: hairlineWidth,
}, },
quotePost: { quotePost: {
flex: 1, flex: 1,
@ -262,7 +263,7 @@ const styles = StyleSheet.create({
marginTop: 8, marginTop: 8,
paddingVertical: 14, paddingVertical: 14,
paddingHorizontal: 14, paddingHorizontal: 14,
borderWidth: 1, borderWidth: hairlineWidth,
}, },
alert: { alert: {
marginBottom: 6, marginBottom: 6,

View file

@ -27,6 +27,7 @@ import {ImageLayoutGrid} from '../images/ImageLayoutGrid'
import {ExternalLinkEmbed} from './ExternalLinkEmbed' import {ExternalLinkEmbed} from './ExternalLinkEmbed'
import {ListEmbed} from './ListEmbed' import {ListEmbed} from './ListEmbed'
import {MaybeQuoteEmbed} from './QuoteEmbed' import {MaybeQuoteEmbed} from './QuoteEmbed'
import hairlineWidth = StyleSheet.hairlineWidth
type Embed = type Embed =
| AppBskyEmbedRecord.View | AppBskyEmbedRecord.View
@ -187,7 +188,7 @@ const styles = StyleSheet.create({
fontWeight: 'bold', fontWeight: 'bold',
}, },
customFeedOuter: { customFeedOuter: {
borderWidth: 1, borderWidth: hairlineWidth,
borderRadius: 8, borderRadius: 8,
marginTop: 4, marginTop: 4,
paddingHorizontal: 12, paddingHorizontal: 12,

View file

@ -52,6 +52,7 @@ import {IconCircle} from '#/components/IconCircle'
import {FilterTimeline_Stroke2_Corner0_Rounded as FilterTimeline} from '#/components/icons/FilterTimeline' import {FilterTimeline_Stroke2_Corner0_Rounded as FilterTimeline} from '#/components/icons/FilterTimeline'
import {ListMagnifyingGlass_Stroke2_Corner0_Rounded} from '#/components/icons/ListMagnifyingGlass' import {ListMagnifyingGlass_Stroke2_Corner0_Rounded} from '#/components/icons/ListMagnifyingGlass'
import {ListSparkle_Stroke2_Corner0_Rounded} from '#/components/icons/ListSparkle' import {ListSparkle_Stroke2_Corner0_Rounded} from '#/components/icons/ListSparkle'
import hairlineWidth = StyleSheet.hairlineWidth
type Props = NativeStackScreenProps<FeedsTabNavigatorParams, 'Feeds'> type Props = NativeStackScreenProps<FeedsTabNavigatorParams, 'Feeds'>
@ -856,13 +857,13 @@ const styles = StyleSheet.create({
paddingHorizontal: 16, paddingHorizontal: 16,
paddingVertical: 14, paddingVertical: 14,
gap: 12, gap: 12,
borderBottomWidth: 1, borderBottomWidth: hairlineWidth,
}, },
savedFeedMobile: { savedFeedMobile: {
paddingVertical: 10, paddingVertical: 10,
}, },
offlineSlug: { offlineSlug: {
borderWidth: 1, borderWidth: hairlineWidth,
borderRadius: 4, borderRadius: 4,
paddingHorizontal: 4, paddingHorizontal: 4,
paddingVertical: 2, paddingVertical: 2,

View file

@ -1,20 +1,22 @@
import React from 'react' import React from 'react'
import {View} from 'react-native' import {StyleSheet, View} from 'react-native'
import {useFocusEffect, useNavigation} from '@react-navigation/native'
import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome'
import {AtUri} from '@atproto/api' import {AtUri} from '@atproto/api'
import {NativeStackScreenProps, CommonNavigatorParams} from 'lib/routes/types' import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome'
import {MyLists} from '#/view/com/lists/MyLists' import {Trans} from '@lingui/macro'
import {Text} from 'view/com/util/text/Text' import {useFocusEffect, useNavigation} from '@react-navigation/native'
import {Button} from 'view/com/util/forms/Button'
import {NavigationProp} from 'lib/routes/types' import {useModalControls} from '#/state/modals'
import {useSetMinimalShellMode} from '#/state/shell'
import {usePalette} from 'lib/hooks/usePalette' import {usePalette} from 'lib/hooks/usePalette'
import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries' 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 {s} from 'lib/styles'
import {useSetMinimalShellMode} from '#/state/shell' import {MyLists} from '#/view/com/lists/MyLists'
import {useModalControls} from '#/state/modals' import {Button} from 'view/com/util/forms/Button'
import {Trans} from '@lingui/macro' import {SimpleViewHeader} from 'view/com/util/SimpleViewHeader'
import {Text} from 'view/com/util/text/Text'
import hairlineWidth = StyleSheet.hairlineWidth
type Props = NativeStackScreenProps<CommonNavigatorParams, 'Lists'> type Props = NativeStackScreenProps<CommonNavigatorParams, 'Lists'>
export function ListsScreen({}: Props) { export function ListsScreen({}: Props) {
@ -51,7 +53,10 @@ export function ListsScreen({}: Props) {
<SimpleViewHeader <SimpleViewHeader
showBackButton={isMobile} showBackButton={isMobile}
style={ style={
!isMobile && [pal.border, {borderLeftWidth: 1, borderRightWidth: 1}] !isMobile && [
pal.border,
{borderLeftWidth: hairlineWidth, borderRightWidth: hairlineWidth},
]
}> }>
<View style={{flex: 1}}> <View style={{flex: 1}}>
<Text type="title-lg" style={[pal.text, {fontWeight: 'bold'}]}> <Text type="title-lg" style={[pal.text, {fontWeight: 'bold'}]}>

View file

@ -1,37 +1,38 @@
import React from 'react' import React from 'react'
import {View} from 'react-native' import {View} from 'react-native'
import {msg, Trans} from '@lingui/macro'
import {useLingui} from '@lingui/react'
import {useFocusEffect, useIsFocused} from '@react-navigation/native' import {useFocusEffect, useIsFocused} from '@react-navigation/native'
import {useQueryClient} from '@tanstack/react-query' import {useQueryClient} from '@tanstack/react-query'
import {
NativeStackScreenProps, import {useNonReactiveCallback} from '#/lib/hooks/useNonReactiveCallback'
NotificationsTabNavigatorParams,
} from 'lib/routes/types'
import {ViewHeader} from '../com/util/ViewHeader'
import {Feed} from '../com/notifications/Feed'
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 {logger} from '#/logger'
import {useSetMinimalShellMode} from '#/state/shell' import {isNative} from '#/platform/detection'
import {Trans, msg} from '@lingui/macro' import {emitSoftReset, listenSoftReset} from '#/state/events'
import {useLingui} from '@lingui/react' import {RQKEY as NOTIFS_RQKEY} from '#/state/queries/notifications/feed'
import { import {
useUnreadNotifications, useUnreadNotifications,
useUnreadNotificationsApi, useUnreadNotificationsApi,
} from '#/state/queries/notifications/unread' } 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 {truncateAndInvalidate} from '#/state/queries/util'
import {useNonReactiveCallback} from '#/lib/hooks/useNonReactiveCallback' import {useSetMinimalShellMode} from '#/state/shell'
import {isNative} from '#/platform/detection'
import {FAB} from '../com/util/fab/FAB'
import {ComposeIcon2} from 'lib/icons'
import {useComposerControls} from '#/state/shell/composer' 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 {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 {Feed} from '../com/notifications/Feed'
import {FAB} from '../com/util/fab/FAB'
import {MainScrollProvider} from '../com/util/MainScrollProvider'
import {ViewHeader} from '../com/util/ViewHeader'
type Props = NativeStackScreenProps< type Props = NativeStackScreenProps<
NotificationsTabNavigatorParams, NotificationsTabNavigatorParams,
@ -145,7 +146,11 @@ export function NotificationsScreen({}: Props) {
return ( return (
<View testID="notificationsScreen" style={s.hContentRegion}> <View testID="notificationsScreen" style={s.hContentRegion}>
<ViewHeader title={_(msg`Notifications`)} canGoBack={false} /> <ViewHeader
title={_(msg`Notifications`)}
canGoBack={false}
showBorder={true}
/>
<MainScrollProvider> <MainScrollProvider>
<Feed <Feed
onScrolledDownChange={setIsScrolledDown} onScrolledDownChange={setIsScrolledDown}

View file

@ -65,6 +65,7 @@ import {useDialogControl} from '#/components/Dialog'
import * as Prompt from '#/components/Prompt' import * as Prompt from '#/components/Prompt'
import {ReportDialog, useReportDialogControl} from '#/components/ReportDialog' import {ReportDialog, useReportDialogControl} from '#/components/ReportDialog'
import {RichText} from '#/components/RichText' import {RichText} from '#/components/RichText'
import hairlineWidth = StyleSheet.hairlineWidth
const SECTION_TITLES_CURATE = ['Posts', 'About'] const SECTION_TITLES_CURATE = ['Posts', 'About']
const SECTION_TITLES_MOD = ['About'] const SECTION_TITLES_MOD = ['About']
@ -802,7 +803,7 @@ const AboutSection = React.forwardRef<SectionRef, AboutSectionProps>(
<View <View
style={[ style={[
{ {
borderTopWidth: 1, borderTopWidth: hairlineWidth,
padding: isMobile ? 14 : 20, padding: isMobile ? 14 : 20,
gap: 12, gap: 12,
}, },
@ -953,7 +954,7 @@ function ErrorScreen({error}: {error: string}) {
marginTop: 10, marginTop: 10,
paddingHorizontal: 18, paddingHorizontal: 18,
paddingVertical: 14, paddingVertical: 14,
borderTopWidth: 1, borderTopWidth: hairlineWidth,
}, },
]}> ]}>
<Text type="title-lg" style={[pal.text, s.mb10]}> <Text type="title-lg" style={[pal.text, s.mb10]}>

View file

@ -66,6 +66,7 @@ import {BirthDateSettingsDialog} from '#/components/dialogs/BirthDateSettings'
import {navigate, resetToTab} from '#/Navigation' import {navigate, resetToTab} from '#/Navigation'
import {Email2FAToggle} from './Email2FAToggle' import {Email2FAToggle} from './Email2FAToggle'
import {ExportCarDialog} from './ExportCarDialog' import {ExportCarDialog} from './ExportCarDialog'
import hairlineWidth = StyleSheet.hairlineWidth
function SettingsAccountCard({ function SettingsAccountCard({
account, account,
@ -317,7 +318,7 @@ export function SettingsScreen({}: Props) {
showBackButton={isMobile} showBackButton={isMobile}
style={[ style={[
pal.border, pal.border,
{borderBottomWidth: 1}, {borderBottomWidth: hairlineWidth},
!isMobile && {borderLeftWidth: 1, borderRightWidth: 1}, !isMobile && {borderLeftWidth: 1, borderRightWidth: 1},
]}> ]}>
<View style={{flex: 1}}> <View style={{flex: 1}}>

View file

@ -1,6 +1,7 @@
import {StyleSheet} from 'react-native' import {StyleSheet} from 'react-native'
import {colors} from 'lib/styles' import {colors} from 'lib/styles'
import hairlineWidth = StyleSheet.hairlineWidth
export const styles = StyleSheet.create({ export const styles = StyleSheet.create({
bottomBar: { bottomBar: {
@ -9,7 +10,7 @@ export const styles = StyleSheet.create({
left: 0, left: 0,
right: 0, right: 0,
flexDirection: 'row', flexDirection: 'row',
borderTopWidth: 1, borderTopWidth: hairlineWidth,
paddingLeft: 5, paddingLeft: 5,
paddingRight: 10, paddingRight: 10,
}, },

View file

@ -13,6 +13,7 @@ import {TextLink} from 'view/com/util/Link'
import {Text} from 'view/com/util/text/Text' import {Text} from 'view/com/util/text/Text'
import {DesktopFeeds} from './Feeds' import {DesktopFeeds} from './Feeds'
import {DesktopSearch} from './Search' import {DesktopSearch} from './Search'
import hairlineWidth = StyleSheet.hairlineWidth
export function DesktopRightNav({routeName}: {routeName: string}) { export function DesktopRightNav({routeName}: {routeName: string}) {
const pal = usePalette('default') const pal = usePalette('default')
@ -130,8 +131,8 @@ const styles = StyleSheet.create({
marginBottom: 10, marginBottom: 10,
}, },
desktopFeedsContainer: { desktopFeedsContainer: {
borderTopWidth: 1, borderTopWidth: hairlineWidth,
borderBottomWidth: 1, borderBottomWidth: hairlineWidth,
marginTop: 18, marginTop: 18,
marginBottom: 18, marginBottom: 18,
}, },