Tweak ProfileList design (#7100)
* Remove "No description" * Move Lists about into header * Remove pager with one tab * Layout tweaks
This commit is contained in:
@@ -407,6 +407,7 @@ function Header({
|
|||||||
isOwner={isOwn}
|
isOwner={isOwn}
|
||||||
avatar={undefined}
|
avatar={undefined}
|
||||||
creator={creator}
|
creator={creator}
|
||||||
|
purpose="app.bsky.graph.defs#referencelist"
|
||||||
avatarType="starter-pack">
|
avatarType="starter-pack">
|
||||||
{hasSession ? (
|
{hasSession ? (
|
||||||
<View style={[a.flex_row, a.gap_sm, a.align_center]}>
|
<View style={[a.flex_row, a.gap_sm, a.align_center]}>
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ import {useNonReactiveCallback} from '#/lib/hooks/useNonReactiveCallback'
|
|||||||
import {ScrollProvider} from '#/lib/ScrollContext'
|
import {ScrollProvider} from '#/lib/ScrollContext'
|
||||||
import {isIOS} from '#/platform/detection'
|
import {isIOS} from '#/platform/detection'
|
||||||
import {Pager, PagerRef, RenderTabBarFnProps} from '#/view/com/pager/Pager'
|
import {Pager, PagerRef, RenderTabBarFnProps} from '#/view/com/pager/Pager'
|
||||||
|
import {useTheme} from '#/alf'
|
||||||
import {ListMethods} from '../util/List'
|
import {ListMethods} from '../util/List'
|
||||||
import {PagerHeaderProvider} from './PagerHeaderContext'
|
import {PagerHeaderProvider} from './PagerHeaderContext'
|
||||||
import {TabBar} from './TabBar'
|
import {TabBar} from './TabBar'
|
||||||
@@ -256,6 +257,7 @@ let PagerTabBar = ({
|
|||||||
dragProgress: SharedValue<number>
|
dragProgress: SharedValue<number>
|
||||||
dragState: SharedValue<'idle' | 'dragging' | 'settling'>
|
dragState: SharedValue<'idle' | 'dragging' | 'settling'>
|
||||||
}): React.ReactNode => {
|
}): React.ReactNode => {
|
||||||
|
const t = useTheme()
|
||||||
const [minimumHeaderHeight, setMinimumHeaderHeight] = React.useState(0)
|
const [minimumHeaderHeight, setMinimumHeaderHeight] = React.useState(0)
|
||||||
const headerTransform = useAnimatedStyle(() => {
|
const headerTransform = useAnimatedStyle(() => {
|
||||||
const translateY =
|
const translateY =
|
||||||
@@ -277,7 +279,7 @@ let PagerTabBar = ({
|
|||||||
return (
|
return (
|
||||||
<Animated.View
|
<Animated.View
|
||||||
pointerEvents={isIOS ? 'auto' : 'box-none'}
|
pointerEvents={isIOS ? 'auto' : 'box-none'}
|
||||||
style={[styles.tabBarMobile, headerTransform]}>
|
style={[styles.tabBarMobile, headerTransform, t.atoms.bg]}>
|
||||||
<View
|
<View
|
||||||
ref={headerRef}
|
ref={headerRef}
|
||||||
pointerEvents={isIOS ? 'auto' : 'box-none'}
|
pointerEvents={isIOS ? 'auto' : 'box-none'}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import React from 'react'
|
import React from 'react'
|
||||||
import {Pressable, View} from 'react-native'
|
import {Pressable, View} from 'react-native'
|
||||||
import {MeasuredDimensions, runOnJS, runOnUI} from 'react-native-reanimated'
|
import {MeasuredDimensions, runOnJS, runOnUI} from 'react-native-reanimated'
|
||||||
|
import {AppBskyGraphDefs} from '@atproto/api'
|
||||||
import {msg, Trans} from '@lingui/macro'
|
import {msg, Trans} from '@lingui/macro'
|
||||||
import {useLingui} from '@lingui/react'
|
import {useLingui} from '@lingui/react'
|
||||||
import {useNavigation} from '@react-navigation/native'
|
import {useNavigation} from '@react-navigation/native'
|
||||||
@@ -26,6 +27,7 @@ export function ProfileSubpageHeader({
|
|||||||
title,
|
title,
|
||||||
avatar,
|
avatar,
|
||||||
isOwner,
|
isOwner,
|
||||||
|
purpose,
|
||||||
creator,
|
creator,
|
||||||
avatarType,
|
avatarType,
|
||||||
children,
|
children,
|
||||||
@@ -35,6 +37,7 @@ export function ProfileSubpageHeader({
|
|||||||
title: string | undefined
|
title: string | undefined
|
||||||
avatar: string | undefined
|
avatar: string | undefined
|
||||||
isOwner: boolean | undefined
|
isOwner: boolean | undefined
|
||||||
|
purpose: AppBskyGraphDefs.ListPurpose | undefined
|
||||||
creator:
|
creator:
|
||||||
| {
|
| {
|
||||||
did: string
|
did: string
|
||||||
@@ -105,7 +108,7 @@ export function ProfileSubpageHeader({
|
|||||||
alignItems: 'flex-start',
|
alignItems: 'flex-start',
|
||||||
gap: 10,
|
gap: 10,
|
||||||
paddingTop: 14,
|
paddingTop: 14,
|
||||||
paddingBottom: 6,
|
paddingBottom: 14,
|
||||||
paddingHorizontal: isMobile ? 12 : 14,
|
paddingHorizontal: isMobile ? 12 : 14,
|
||||||
}}>
|
}}>
|
||||||
<View ref={aviRef} collapsable={false}>
|
<View ref={aviRef} collapsable={false}>
|
||||||
@@ -123,7 +126,7 @@ export function ProfileSubpageHeader({
|
|||||||
)}
|
)}
|
||||||
</Pressable>
|
</Pressable>
|
||||||
</View>
|
</View>
|
||||||
<View style={{flex: 1}}>
|
<View style={{flex: 1, gap: 4}}>
|
||||||
{isLoading ? (
|
{isLoading ? (
|
||||||
<LoadingPlaceholder
|
<LoadingPlaceholder
|
||||||
width={200}
|
width={200}
|
||||||
@@ -142,24 +145,50 @@ export function ProfileSubpageHeader({
|
|||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{isLoading ? (
|
{isLoading || !creator ? (
|
||||||
<LoadingPlaceholder width={50} height={8} />
|
<LoadingPlaceholder width={50} height={8} />
|
||||||
) : (
|
) : (
|
||||||
<Text type="xl" style={[pal.textLight]} numberOfLines={1}>
|
<Text type="lg" style={[pal.textLight]} numberOfLines={1}>
|
||||||
{!creator ? (
|
{purpose === 'app.bsky.graph.defs#curatelist' ? (
|
||||||
<Trans>by —</Trans>
|
isOwner ? (
|
||||||
) : isOwner ? (
|
<Trans>List by you</Trans>
|
||||||
<Trans>by you</Trans>
|
) : (
|
||||||
) : (
|
<Trans>
|
||||||
<Trans>
|
List by{' '}
|
||||||
by{' '}
|
<TextLink
|
||||||
<TextLink
|
text={sanitizeHandle(creator.handle || '', '@')}
|
||||||
text={sanitizeHandle(creator.handle, '@')}
|
href={makeProfileLink(creator)}
|
||||||
href={makeProfileLink(creator)}
|
style={pal.textLight}
|
||||||
style={pal.textLight}
|
/>
|
||||||
/>
|
</Trans>
|
||||||
</Trans>
|
)
|
||||||
)}
|
) : purpose === 'app.bsky.graph.defs#modlist' ? (
|
||||||
|
isOwner ? (
|
||||||
|
<Trans>Moderation list by you</Trans>
|
||||||
|
) : (
|
||||||
|
<Trans>
|
||||||
|
Moderation list by{' '}
|
||||||
|
<TextLink
|
||||||
|
text={sanitizeHandle(creator.handle || '', '@')}
|
||||||
|
href={makeProfileLink(creator)}
|
||||||
|
style={pal.textLight}
|
||||||
|
/>
|
||||||
|
</Trans>
|
||||||
|
)
|
||||||
|
) : purpose === 'app.bsky.graph.defs#referencelist' ? (
|
||||||
|
isOwner ? (
|
||||||
|
<Trans>Starter pack by you</Trans>
|
||||||
|
) : (
|
||||||
|
<Trans>
|
||||||
|
Starter pack by{' '}
|
||||||
|
<TextLink
|
||||||
|
text={sanitizeHandle(creator.handle || '', '@')}
|
||||||
|
href={makeProfileLink(creator)}
|
||||||
|
style={pal.textLight}
|
||||||
|
/>
|
||||||
|
</Trans>
|
||||||
|
)
|
||||||
|
) : null}
|
||||||
</Text>
|
</Text>
|
||||||
)}
|
)}
|
||||||
</View>
|
</View>
|
||||||
|
|||||||
+130
-191
@@ -1,5 +1,6 @@
|
|||||||
import React, {useCallback, useMemo} from 'react'
|
import React, {useCallback, useMemo} from 'react'
|
||||||
import {Pressable, StyleSheet, View} from 'react-native'
|
import {Pressable, StyleSheet, View} from 'react-native'
|
||||||
|
import {useAnimatedRef} from 'react-native-reanimated'
|
||||||
import {
|
import {
|
||||||
AppBskyGraphDefs,
|
AppBskyGraphDefs,
|
||||||
AtUri,
|
AtUri,
|
||||||
@@ -19,12 +20,11 @@ import {usePalette} from '#/lib/hooks/usePalette'
|
|||||||
import {useSetTitle} from '#/lib/hooks/useSetTitle'
|
import {useSetTitle} from '#/lib/hooks/useSetTitle'
|
||||||
import {useWebMediaQueries} from '#/lib/hooks/useWebMediaQueries'
|
import {useWebMediaQueries} from '#/lib/hooks/useWebMediaQueries'
|
||||||
import {ComposeIcon2} from '#/lib/icons'
|
import {ComposeIcon2} from '#/lib/icons'
|
||||||
import {makeListLink, makeProfileLink} from '#/lib/routes/links'
|
import {makeListLink} from '#/lib/routes/links'
|
||||||
import {CommonNavigatorParams, NativeStackScreenProps} from '#/lib/routes/types'
|
import {CommonNavigatorParams, NativeStackScreenProps} from '#/lib/routes/types'
|
||||||
import {NavigationProp} from '#/lib/routes/types'
|
import {NavigationProp} from '#/lib/routes/types'
|
||||||
import {shareUrl} from '#/lib/sharing'
|
import {shareUrl} from '#/lib/sharing'
|
||||||
import {cleanError} from '#/lib/strings/errors'
|
import {cleanError} from '#/lib/strings/errors'
|
||||||
import {sanitizeHandle} from '#/lib/strings/handles'
|
|
||||||
import {toShareUrl} from '#/lib/strings/url-helpers'
|
import {toShareUrl} from '#/lib/strings/url-helpers'
|
||||||
import {s} from '#/lib/styles'
|
import {s} from '#/lib/styles'
|
||||||
import {logger} from '#/logger'
|
import {logger} from '#/logger'
|
||||||
@@ -63,14 +63,13 @@ import {
|
|||||||
DropdownItem,
|
DropdownItem,
|
||||||
NativeDropdown,
|
NativeDropdown,
|
||||||
} from '#/view/com/util/forms/NativeDropdown'
|
} from '#/view/com/util/forms/NativeDropdown'
|
||||||
import {TextLink} from '#/view/com/util/Link'
|
|
||||||
import {ListRef} from '#/view/com/util/List'
|
import {ListRef} from '#/view/com/util/List'
|
||||||
import {LoadLatestBtn} from '#/view/com/util/load-latest/LoadLatestBtn'
|
import {LoadLatestBtn} from '#/view/com/util/load-latest/LoadLatestBtn'
|
||||||
import {LoadingScreen} from '#/view/com/util/LoadingScreen'
|
import {LoadingScreen} from '#/view/com/util/LoadingScreen'
|
||||||
import {Text} from '#/view/com/util/text/Text'
|
import {Text} from '#/view/com/util/text/Text'
|
||||||
import * as Toast from '#/view/com/util/Toast'
|
import * as Toast from '#/view/com/util/Toast'
|
||||||
import {ListHiddenScreen} from '#/screens/List/ListHiddenScreen'
|
import {ListHiddenScreen} from '#/screens/List/ListHiddenScreen'
|
||||||
import {atoms as a, useTheme} from '#/alf'
|
import {atoms as a} from '#/alf'
|
||||||
import {useDialogControl} from '#/components/Dialog'
|
import {useDialogControl} from '#/components/Dialog'
|
||||||
import * as Layout from '#/components/Layout'
|
import * as Layout from '#/components/Layout'
|
||||||
import * as Hider from '#/components/moderation/Hider'
|
import * as Hider from '#/components/moderation/Hider'
|
||||||
@@ -78,8 +77,7 @@ 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'
|
||||||
|
|
||||||
const SECTION_TITLES_CURATE = ['Posts', 'About']
|
const SECTION_TITLES_CURATE = ['Posts', 'People']
|
||||||
const SECTION_TITLES_MOD = ['About']
|
|
||||||
|
|
||||||
interface SectionRef {
|
interface SectionRef {
|
||||||
scrollToTop: () => void
|
scrollToTop: () => void
|
||||||
@@ -161,6 +159,7 @@ function ProfileListScreenLoaded({
|
|||||||
const isScreenFocused = useIsFocused()
|
const isScreenFocused = useIsFocused()
|
||||||
const isHidden = list.labels?.findIndex(l => l.val === '!hide') !== -1
|
const isHidden = list.labels?.findIndex(l => l.val === '!hide') !== -1
|
||||||
const isOwner = currentAccount?.did === list.creator.did
|
const isOwner = currentAccount?.did === list.creator.did
|
||||||
|
const scrollElRef = useAnimatedRef()
|
||||||
|
|
||||||
const moderation = React.useMemo(() => {
|
const moderation = React.useMemo(() => {
|
||||||
return moderateUserList(list, moderationOpts)
|
return moderateUserList(list, moderationOpts)
|
||||||
@@ -259,19 +258,13 @@ function ProfileListScreenLoaded({
|
|||||||
</Hider.Mask>
|
</Hider.Mask>
|
||||||
<Hider.Content>
|
<Hider.Content>
|
||||||
<View style={s.hContentRegion}>
|
<View style={s.hContentRegion}>
|
||||||
<PagerWithHeader
|
<Layout.Center>{renderHeader()}</Layout.Center>
|
||||||
items={SECTION_TITLES_MOD}
|
<AboutSection
|
||||||
isHeaderReady={true}
|
list={list}
|
||||||
renderHeader={renderHeader}>
|
scrollElRef={scrollElRef as ListRef}
|
||||||
{({headerHeight, scrollElRef}) => (
|
onPressAddUser={onPressAddUser}
|
||||||
<AboutSection
|
headerHeight={0}
|
||||||
list={list}
|
/>
|
||||||
scrollElRef={scrollElRef as ListRef}
|
|
||||||
onPressAddUser={onPressAddUser}
|
|
||||||
headerHeight={headerHeight}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</PagerWithHeader>
|
|
||||||
<FAB
|
<FAB
|
||||||
testID="composeFAB"
|
testID="composeFAB"
|
||||||
onPress={() => openComposer({})}
|
onPress={() => openComposer({})}
|
||||||
@@ -652,101 +645,124 @@ function Header({
|
|||||||
]
|
]
|
||||||
}, [_, subscribeMutePromptControl.open, subscribeBlockPromptControl.open])
|
}, [_, subscribeMutePromptControl.open, subscribeBlockPromptControl.open])
|
||||||
|
|
||||||
|
const descriptionRT = useMemo(
|
||||||
|
() =>
|
||||||
|
list.description
|
||||||
|
? new RichTextAPI({
|
||||||
|
text: list.description,
|
||||||
|
facets: list.descriptionFacets,
|
||||||
|
})
|
||||||
|
: undefined,
|
||||||
|
[list],
|
||||||
|
)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ProfileSubpageHeader
|
<>
|
||||||
href={makeListLink(list.creator.handle || list.creator.did || '', rkey)}
|
<ProfileSubpageHeader
|
||||||
title={list.name}
|
href={makeListLink(list.creator.handle || list.creator.did || '', rkey)}
|
||||||
avatar={list.avatar}
|
title={list.name}
|
||||||
isOwner={list.creator.did === currentAccount?.did}
|
avatar={list.avatar}
|
||||||
creator={list.creator}
|
isOwner={list.creator.did === currentAccount?.did}
|
||||||
avatarType="list">
|
creator={list.creator}
|
||||||
<ReportDialog
|
purpose={list.purpose}
|
||||||
control={reportDialogControl}
|
avatarType="list">
|
||||||
params={{
|
<ReportDialog
|
||||||
type: 'list',
|
control={reportDialogControl}
|
||||||
uri: list.uri,
|
params={{
|
||||||
cid: list.cid,
|
type: 'list',
|
||||||
}}
|
uri: list.uri,
|
||||||
/>
|
cid: list.cid,
|
||||||
{isCurateList ? (
|
}}
|
||||||
<Button
|
|
||||||
testID={isPinned ? 'unpinBtn' : 'pinBtn'}
|
|
||||||
type={isPinned ? 'default' : 'inverted'}
|
|
||||||
label={isPinned ? _(msg`Unpin`) : _(msg`Pin to home`)}
|
|
||||||
onPress={onTogglePinned}
|
|
||||||
disabled={isPending}
|
|
||||||
/>
|
/>
|
||||||
) : isModList ? (
|
{isCurateList ? (
|
||||||
isBlocking ? (
|
|
||||||
<Button
|
<Button
|
||||||
testID="unblockBtn"
|
testID={isPinned ? 'unpinBtn' : 'pinBtn'}
|
||||||
type="default"
|
type={isPinned ? 'default' : 'inverted'}
|
||||||
label={_(msg`Unblock`)}
|
label={isPinned ? _(msg`Unpin`) : _(msg`Pin to home`)}
|
||||||
onPress={onUnsubscribeBlock}
|
onPress={onTogglePinned}
|
||||||
|
disabled={isPending}
|
||||||
/>
|
/>
|
||||||
) : isMuting ? (
|
) : isModList ? (
|
||||||
<Button
|
isBlocking ? (
|
||||||
testID="unmuteBtn"
|
<Button
|
||||||
type="default"
|
testID="unblockBtn"
|
||||||
label={_(msg`Unmute`)}
|
type="default"
|
||||||
onPress={onUnsubscribeMute}
|
label={_(msg`Unblock`)}
|
||||||
/>
|
onPress={onUnsubscribeBlock}
|
||||||
) : (
|
/>
|
||||||
<NativeDropdown
|
) : isMuting ? (
|
||||||
testID="subscribeBtn"
|
<Button
|
||||||
items={subscribeDropdownItems}
|
testID="unmuteBtn"
|
||||||
accessibilityLabel={_(msg`Subscribe to this list`)}
|
type="default"
|
||||||
accessibilityHint="">
|
label={_(msg`Unmute`)}
|
||||||
<View style={[palInverted.view, styles.btn]}>
|
onPress={onUnsubscribeMute}
|
||||||
<Text style={palInverted.text}>
|
/>
|
||||||
<Trans>Subscribe</Trans>
|
) : (
|
||||||
</Text>
|
<NativeDropdown
|
||||||
</View>
|
testID="subscribeBtn"
|
||||||
</NativeDropdown>
|
items={subscribeDropdownItems}
|
||||||
)
|
accessibilityLabel={_(msg`Subscribe to this list`)}
|
||||||
) : null}
|
accessibilityHint="">
|
||||||
<NativeDropdown
|
<View style={[palInverted.view, styles.btn]}>
|
||||||
testID="headerDropdownBtn"
|
<Text style={palInverted.text}>
|
||||||
items={dropdownItems}
|
<Trans>Subscribe</Trans>
|
||||||
accessibilityLabel={_(msg`More options`)}
|
</Text>
|
||||||
accessibilityHint="">
|
</View>
|
||||||
<View style={[pal.viewLight, styles.btn]}>
|
</NativeDropdown>
|
||||||
<FontAwesomeIcon icon="ellipsis" size={20} color={pal.colors.text} />
|
)
|
||||||
|
) : null}
|
||||||
|
<NativeDropdown
|
||||||
|
testID="headerDropdownBtn"
|
||||||
|
items={dropdownItems}
|
||||||
|
accessibilityLabel={_(msg`More options`)}
|
||||||
|
accessibilityHint="">
|
||||||
|
<View style={[pal.viewLight, styles.btn]}>
|
||||||
|
<FontAwesomeIcon
|
||||||
|
icon="ellipsis"
|
||||||
|
size={20}
|
||||||
|
color={pal.colors.text}
|
||||||
|
/>
|
||||||
|
</View>
|
||||||
|
</NativeDropdown>
|
||||||
|
|
||||||
|
<Prompt.Basic
|
||||||
|
control={deleteListPromptControl}
|
||||||
|
title={_(msg`Delete this list?`)}
|
||||||
|
description={_(
|
||||||
|
msg`If you delete this list, you won't be able to recover it.`,
|
||||||
|
)}
|
||||||
|
onConfirm={onPressDelete}
|
||||||
|
confirmButtonCta={_(msg`Delete`)}
|
||||||
|
confirmButtonColor="negative"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<Prompt.Basic
|
||||||
|
control={subscribeMutePromptControl}
|
||||||
|
title={_(msg`Mute these accounts?`)}
|
||||||
|
description={_(
|
||||||
|
msg`Muting is private. Muted accounts can interact with you, but you will not see their posts or receive notifications from them.`,
|
||||||
|
)}
|
||||||
|
onConfirm={onSubscribeMute}
|
||||||
|
confirmButtonCta={_(msg`Mute list`)}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<Prompt.Basic
|
||||||
|
control={subscribeBlockPromptControl}
|
||||||
|
title={_(msg`Block these accounts?`)}
|
||||||
|
description={_(
|
||||||
|
msg`Blocking is public. Blocked accounts cannot reply in your threads, mention you, or otherwise interact with you.`,
|
||||||
|
)}
|
||||||
|
onConfirm={onSubscribeBlock}
|
||||||
|
confirmButtonCta={_(msg`Block list`)}
|
||||||
|
confirmButtonColor="negative"
|
||||||
|
/>
|
||||||
|
</ProfileSubpageHeader>
|
||||||
|
{descriptionRT ? (
|
||||||
|
<View style={[a.px_lg, a.pt_sm, a.pb_sm, a.gap_md]}>
|
||||||
|
<RichText value={descriptionRT} style={[a.text_md, a.leading_snug]} />
|
||||||
</View>
|
</View>
|
||||||
</NativeDropdown>
|
) : null}
|
||||||
|
</>
|
||||||
<Prompt.Basic
|
|
||||||
control={deleteListPromptControl}
|
|
||||||
title={_(msg`Delete this list?`)}
|
|
||||||
description={_(
|
|
||||||
msg`If you delete this list, you won't be able to recover it.`,
|
|
||||||
)}
|
|
||||||
onConfirm={onPressDelete}
|
|
||||||
confirmButtonCta={_(msg`Delete`)}
|
|
||||||
confirmButtonColor="negative"
|
|
||||||
/>
|
|
||||||
|
|
||||||
<Prompt.Basic
|
|
||||||
control={subscribeMutePromptControl}
|
|
||||||
title={_(msg`Mute these accounts?`)}
|
|
||||||
description={_(
|
|
||||||
msg`Muting is private. Muted accounts can interact with you, but you will not see their posts or receive notifications from them.`,
|
|
||||||
)}
|
|
||||||
onConfirm={onSubscribeMute}
|
|
||||||
confirmButtonCta={_(msg`Mute list`)}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<Prompt.Basic
|
|
||||||
control={subscribeBlockPromptControl}
|
|
||||||
title={_(msg`Block these accounts?`)}
|
|
||||||
description={_(
|
|
||||||
msg`Blocking is public. Blocked accounts cannot reply in your threads, mention you, or otherwise interact with you.`,
|
|
||||||
)}
|
|
||||||
onConfirm={onSubscribeBlock}
|
|
||||||
confirmButtonCta={_(msg`Block list`)}
|
|
||||||
confirmButtonColor="negative"
|
|
||||||
/>
|
|
||||||
</ProfileSubpageHeader>
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -825,25 +841,12 @@ const AboutSection = React.forwardRef<SectionRef, AboutSectionProps>(
|
|||||||
ref,
|
ref,
|
||||||
) {
|
) {
|
||||||
const pal = usePalette('default')
|
const pal = usePalette('default')
|
||||||
const t = useTheme()
|
|
||||||
const {_} = useLingui()
|
const {_} = useLingui()
|
||||||
const {isMobile} = useWebMediaQueries()
|
const {isMobile} = useWebMediaQueries()
|
||||||
const {currentAccount} = useSession()
|
const {currentAccount} = useSession()
|
||||||
const [isScrolledDown, setIsScrolledDown] = React.useState(false)
|
const [isScrolledDown, setIsScrolledDown] = React.useState(false)
|
||||||
const isCurateList = list.purpose === 'app.bsky.graph.defs#curatelist'
|
|
||||||
const isOwner = list.creator.did === currentAccount?.did
|
const isOwner = list.creator.did === currentAccount?.did
|
||||||
|
|
||||||
const descriptionRT = useMemo(
|
|
||||||
() =>
|
|
||||||
list.description
|
|
||||||
? new RichTextAPI({
|
|
||||||
text: list.description,
|
|
||||||
facets: list.descriptionFacets,
|
|
||||||
})
|
|
||||||
: undefined,
|
|
||||||
[list],
|
|
||||||
)
|
|
||||||
|
|
||||||
const onScrollToTop = useCallback(() => {
|
const onScrollToTop = useCallback(() => {
|
||||||
scrollElRef.current?.scrollToOffset({
|
scrollElRef.current?.scrollToOffset({
|
||||||
animated: isNative,
|
animated: isNative,
|
||||||
@@ -856,59 +859,11 @@ const AboutSection = React.forwardRef<SectionRef, AboutSectionProps>(
|
|||||||
}))
|
}))
|
||||||
|
|
||||||
const renderHeader = React.useCallback(() => {
|
const renderHeader = React.useCallback(() => {
|
||||||
|
if (!isOwner) {
|
||||||
|
return <View />
|
||||||
|
}
|
||||||
return (
|
return (
|
||||||
<View>
|
<View style={a.pt_lg}>
|
||||||
<View
|
|
||||||
style={[
|
|
||||||
{
|
|
||||||
borderTopWidth: StyleSheet.hairlineWidth,
|
|
||||||
padding: isMobile ? 14 : 20,
|
|
||||||
gap: 12,
|
|
||||||
},
|
|
||||||
pal.border,
|
|
||||||
]}>
|
|
||||||
{descriptionRT ? (
|
|
||||||
<RichText
|
|
||||||
testID="listDescription"
|
|
||||||
style={[a.text_md]}
|
|
||||||
value={descriptionRT}
|
|
||||||
/>
|
|
||||||
) : (
|
|
||||||
<Text
|
|
||||||
testID="listDescriptionEmpty"
|
|
||||||
type="lg"
|
|
||||||
style={[{fontStyle: 'italic'}, pal.textLight]}>
|
|
||||||
<Trans>No description</Trans>
|
|
||||||
</Text>
|
|
||||||
)}
|
|
||||||
<Text type="md" style={[pal.textLight]} numberOfLines={1}>
|
|
||||||
{isCurateList ? (
|
|
||||||
isOwner ? (
|
|
||||||
<Trans>User list by you</Trans>
|
|
||||||
) : (
|
|
||||||
<Trans>
|
|
||||||
User list by{' '}
|
|
||||||
<TextLink
|
|
||||||
text={sanitizeHandle(list.creator.handle || '', '@')}
|
|
||||||
href={makeProfileLink(list.creator)}
|
|
||||||
style={pal.textLight}
|
|
||||||
/>
|
|
||||||
</Trans>
|
|
||||||
)
|
|
||||||
) : isOwner ? (
|
|
||||||
<Trans>Moderation list by you</Trans>
|
|
||||||
) : (
|
|
||||||
<Trans>
|
|
||||||
Moderation list by{' '}
|
|
||||||
<TextLink
|
|
||||||
text={sanitizeHandle(list.creator.handle || '', '@')}
|
|
||||||
href={makeProfileLink(list.creator)}
|
|
||||||
style={pal.textLight}
|
|
||||||
/>
|
|
||||||
</Trans>
|
|
||||||
)}
|
|
||||||
</Text>
|
|
||||||
</View>
|
|
||||||
<View
|
<View
|
||||||
style={[
|
style={[
|
||||||
{
|
{
|
||||||
@@ -919,9 +874,6 @@ const AboutSection = React.forwardRef<SectionRef, AboutSectionProps>(
|
|||||||
paddingBottom: isMobile ? 14 : 18,
|
paddingBottom: isMobile ? 14 : 18,
|
||||||
},
|
},
|
||||||
]}>
|
]}>
|
||||||
<Text type="lg-bold" style={t.atoms.text}>
|
|
||||||
<Trans>Users</Trans>
|
|
||||||
</Text>
|
|
||||||
{isOwner && (
|
{isOwner && (
|
||||||
<Pressable
|
<Pressable
|
||||||
testID="addUserBtn"
|
testID="addUserBtn"
|
||||||
@@ -943,20 +895,7 @@ const AboutSection = React.forwardRef<SectionRef, AboutSectionProps>(
|
|||||||
</View>
|
</View>
|
||||||
</View>
|
</View>
|
||||||
)
|
)
|
||||||
}, [
|
}, [isMobile, pal.colors.link, pal.link, isOwner, _, onPressAddUser])
|
||||||
isMobile,
|
|
||||||
pal.border,
|
|
||||||
pal.textLight,
|
|
||||||
pal.colors.link,
|
|
||||||
pal.link,
|
|
||||||
descriptionRT,
|
|
||||||
isCurateList,
|
|
||||||
isOwner,
|
|
||||||
list.creator,
|
|
||||||
t.atoms.text,
|
|
||||||
_,
|
|
||||||
onPressAddUser,
|
|
||||||
])
|
|
||||||
|
|
||||||
const renderEmptyState = useCallback(() => {
|
const renderEmptyState = useCallback(() => {
|
||||||
return (
|
return (
|
||||||
|
|||||||
Reference in New Issue
Block a user