Factor our feed source model (#1887)
* Refactor first onboarding step * Replace old FeedSourceCard * Clean up CustomFeedEmbed * Remove discover feeds model * Refactor ProfileFeed screen * Remove useCustomFeed * Delete some unused models * Rip out more prefs * Factor out treeView from thread comp * Improve last commit
This commit is contained in:
parent
a01463788d
commit
06eb8b9a4c
21 changed files with 526 additions and 1356 deletions
|
@ -10,10 +10,8 @@ import {Button} from 'view/com/util/forms/Button'
|
|||
import {RecommendedFeedsItem} from './RecommendedFeedsItem'
|
||||
import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries'
|
||||
import {usePalette} from 'lib/hooks/usePalette'
|
||||
import {useQuery} from '@tanstack/react-query'
|
||||
import {useStores} from 'state/index'
|
||||
import {FeedSourceModel} from 'state/models/content/feed-source'
|
||||
import {ErrorMessage} from 'view/com/util/error/ErrorMessage'
|
||||
import {useSuggestedFeedsQuery} from '#/state/queries/suggested-feeds'
|
||||
|
||||
type Props = {
|
||||
next: () => void
|
||||
|
@ -21,35 +19,11 @@ type Props = {
|
|||
export const RecommendedFeeds = observer(function RecommendedFeedsImpl({
|
||||
next,
|
||||
}: Props) {
|
||||
const store = useStores()
|
||||
const pal = usePalette('default')
|
||||
const {isTabletOrMobile} = useWebMediaQueries()
|
||||
const {isLoading, data: recommendedFeeds} = useQuery({
|
||||
staleTime: Infinity, // fixed list rn, never refetch
|
||||
queryKey: ['onboarding', 'recommended_feeds'],
|
||||
async queryFn() {
|
||||
try {
|
||||
const {
|
||||
data: {feeds},
|
||||
success,
|
||||
} = await store.agent.app.bsky.feed.getSuggestedFeeds()
|
||||
const {isLoading, data} = useSuggestedFeedsQuery()
|
||||
|
||||
if (!success) {
|
||||
return []
|
||||
}
|
||||
|
||||
return (feeds.length ? feeds : []).map(feed => {
|
||||
const model = new FeedSourceModel(store, feed.uri)
|
||||
model.hydrateFeedGenerator(feed)
|
||||
return model
|
||||
})
|
||||
} catch (e) {
|
||||
return []
|
||||
}
|
||||
},
|
||||
})
|
||||
|
||||
const hasFeeds = recommendedFeeds && recommendedFeeds.length
|
||||
const hasFeeds = data && data?.pages?.[0]?.feeds?.length
|
||||
|
||||
const title = (
|
||||
<>
|
||||
|
@ -118,7 +92,7 @@ export const RecommendedFeeds = observer(function RecommendedFeedsImpl({
|
|||
contentStyle={{paddingHorizontal: 0}}>
|
||||
{hasFeeds ? (
|
||||
<FlatList
|
||||
data={recommendedFeeds}
|
||||
data={data.pages[0].feeds}
|
||||
renderItem={({item}) => <RecommendedFeedsItem item={item} />}
|
||||
keyExtractor={item => item.uri}
|
||||
style={{flex: 1}}
|
||||
|
@ -146,7 +120,7 @@ export const RecommendedFeeds = observer(function RecommendedFeedsImpl({
|
|||
|
||||
{hasFeeds ? (
|
||||
<FlatList
|
||||
data={recommendedFeeds}
|
||||
data={data.pages[0].feeds}
|
||||
renderItem={({item}) => <RecommendedFeedsItem item={item} />}
|
||||
keyExtractor={item => item.uri}
|
||||
style={{flex: 1}}
|
||||
|
|
|
@ -2,6 +2,7 @@ import React from 'react'
|
|||
import {View} from 'react-native'
|
||||
import {observer} from 'mobx-react-lite'
|
||||
import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome'
|
||||
import {AppBskyFeedDefs, RichText as BskRichText} from '@atproto/api'
|
||||
import {Text} from 'view/com/util/text/Text'
|
||||
import {RichText} from 'view/com/util/text/RichText'
|
||||
import {Button} from 'view/com/util/forms/Button'
|
||||
|
@ -11,33 +12,58 @@ import {HeartIcon} from 'lib/icons'
|
|||
import {usePalette} from 'lib/hooks/usePalette'
|
||||
import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries'
|
||||
import {sanitizeHandle} from 'lib/strings/handles'
|
||||
import {FeedSourceModel} from 'state/models/content/feed-source'
|
||||
import {
|
||||
usePreferencesQuery,
|
||||
usePinFeedMutation,
|
||||
useRemoveFeedMutation,
|
||||
} from '#/state/queries/preferences'
|
||||
import {logger} from '#/logger'
|
||||
|
||||
export const RecommendedFeedsItem = observer(function RecommendedFeedsItemImpl({
|
||||
item,
|
||||
}: {
|
||||
item: FeedSourceModel
|
||||
item: AppBskyFeedDefs.GeneratorView
|
||||
}) {
|
||||
const {isMobile} = useWebMediaQueries()
|
||||
const pal = usePalette('default')
|
||||
if (!item) return null
|
||||
const {data: preferences} = usePreferencesQuery()
|
||||
const {
|
||||
mutateAsync: pinFeed,
|
||||
variables: pinnedFeed,
|
||||
reset: resetPinFeed,
|
||||
} = usePinFeedMutation()
|
||||
const {
|
||||
mutateAsync: removeFeed,
|
||||
variables: removedFeed,
|
||||
reset: resetRemoveFeed,
|
||||
} = useRemoveFeedMutation()
|
||||
|
||||
if (!item || !preferences) return null
|
||||
|
||||
const isPinned =
|
||||
!removedFeed?.uri &&
|
||||
(pinnedFeed?.uri || preferences.feeds.saved.includes(item.uri))
|
||||
|
||||
const onToggle = async () => {
|
||||
if (item.isSaved) {
|
||||
if (isPinned) {
|
||||
try {
|
||||
await item.unsave()
|
||||
await removeFeed({uri: item.uri})
|
||||
resetRemoveFeed()
|
||||
} catch (e) {
|
||||
Toast.show('There was an issue contacting your server')
|
||||
console.error('Failed to unsave feed', {e})
|
||||
logger.error('Failed to unsave feed', {error: e})
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
await item.pin()
|
||||
await pinFeed({uri: item.uri})
|
||||
resetPinFeed()
|
||||
} catch (e) {
|
||||
Toast.show('There was an issue contacting your server')
|
||||
console.error('Failed to pin feed', {e})
|
||||
logger.error('Failed to pin feed', {error: e})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<View testID={`feed-${item.displayName}`}>
|
||||
<View
|
||||
|
@ -66,10 +92,10 @@ export const RecommendedFeedsItem = observer(function RecommendedFeedsItemImpl({
|
|||
</Text>
|
||||
|
||||
<Text style={[pal.textLight, {marginBottom: 8}]} numberOfLines={1}>
|
||||
by {sanitizeHandle(item.creatorHandle, '@')}
|
||||
by {sanitizeHandle(item.creator.handle, '@')}
|
||||
</Text>
|
||||
|
||||
{item.descriptionRT ? (
|
||||
{item.description ? (
|
||||
<RichText
|
||||
type="xl"
|
||||
style={[
|
||||
|
@ -80,7 +106,7 @@ export const RecommendedFeedsItem = observer(function RecommendedFeedsItemImpl({
|
|||
marginBottom: 18,
|
||||
},
|
||||
]}
|
||||
richText={item.descriptionRT}
|
||||
richText={new BskRichText({text: item.description || ''})}
|
||||
numberOfLines={6}
|
||||
/>
|
||||
) : null}
|
||||
|
@ -97,7 +123,7 @@ export const RecommendedFeedsItem = observer(function RecommendedFeedsItemImpl({
|
|||
paddingRight: 2,
|
||||
gap: 6,
|
||||
}}>
|
||||
{item.isSaved ? (
|
||||
{isPinned ? (
|
||||
<>
|
||||
<FontAwesomeIcon
|
||||
icon="check"
|
||||
|
|
|
@ -7,7 +7,6 @@ import {usePalette} from 'lib/hooks/usePalette'
|
|||
import {s} from 'lib/styles'
|
||||
import {UserAvatar} from '../util/UserAvatar'
|
||||
import {observer} from 'mobx-react-lite'
|
||||
import {FeedSourceModel} from 'state/models/content/feed-source'
|
||||
import {useNavigation} from '@react-navigation/native'
|
||||
import {NavigationProp} from 'lib/routes/types'
|
||||
import {pluralize} from 'lib/strings/helpers'
|
||||
|
@ -23,7 +22,7 @@ import {
|
|||
} from '#/state/queries/preferences'
|
||||
import {useFeedSourceInfoQuery} from '#/state/queries/feed'
|
||||
|
||||
export const NewFeedSourceCard = observer(function FeedSourceCardImpl({
|
||||
export const FeedSourceCard = observer(function FeedSourceCardImpl({
|
||||
feedUri,
|
||||
style,
|
||||
showSaveBtn = false,
|
||||
|
@ -162,128 +161,6 @@ export const NewFeedSourceCard = observer(function FeedSourceCardImpl({
|
|||
)
|
||||
})
|
||||
|
||||
export const FeedSourceCard = observer(function FeedSourceCardImpl({
|
||||
item,
|
||||
style,
|
||||
showSaveBtn = false,
|
||||
showDescription = false,
|
||||
showLikes = false,
|
||||
}: {
|
||||
item: FeedSourceModel
|
||||
style?: StyleProp<ViewStyle>
|
||||
showSaveBtn?: boolean
|
||||
showDescription?: boolean
|
||||
showLikes?: boolean
|
||||
}) {
|
||||
const pal = usePalette('default')
|
||||
const navigation = useNavigation<NavigationProp>()
|
||||
const {openModal} = useModalControls()
|
||||
|
||||
const onToggleSaved = React.useCallback(async () => {
|
||||
if (item.isSaved) {
|
||||
openModal({
|
||||
name: 'confirm',
|
||||
title: 'Remove from my feeds',
|
||||
message: `Remove ${item.displayName} from my feeds?`,
|
||||
onPressConfirm: async () => {
|
||||
try {
|
||||
await item.unsave()
|
||||
Toast.show('Removed from my feeds')
|
||||
} catch (e) {
|
||||
Toast.show('There was an issue contacting your server')
|
||||
logger.error('Failed to unsave feed', {error: e})
|
||||
}
|
||||
},
|
||||
})
|
||||
} else {
|
||||
try {
|
||||
await item.save()
|
||||
Toast.show('Added to my feeds')
|
||||
} catch (e) {
|
||||
Toast.show('There was an issue contacting your server')
|
||||
logger.error('Failed to save feed', {error: e})
|
||||
}
|
||||
}
|
||||
}, [openModal, item])
|
||||
|
||||
return (
|
||||
<Pressable
|
||||
testID={`feed-${item.displayName}`}
|
||||
accessibilityRole="button"
|
||||
style={[styles.container, pal.border, style]}
|
||||
onPress={() => {
|
||||
if (item.type === 'feed-generator') {
|
||||
navigation.push('ProfileFeed', {
|
||||
name: item.creatorDid,
|
||||
rkey: new AtUri(item.uri).rkey,
|
||||
})
|
||||
} else if (item.type === 'list') {
|
||||
navigation.push('ProfileList', {
|
||||
name: item.creatorDid,
|
||||
rkey: new AtUri(item.uri).rkey,
|
||||
})
|
||||
}
|
||||
}}
|
||||
key={item.uri}>
|
||||
<View style={[styles.headerContainer]}>
|
||||
<View style={[s.mr10]}>
|
||||
<UserAvatar type="algo" size={36} avatar={item.avatar} />
|
||||
</View>
|
||||
<View style={[styles.headerTextContainer]}>
|
||||
<Text style={[pal.text, s.bold]} numberOfLines={3}>
|
||||
{item.displayName}
|
||||
</Text>
|
||||
<Text style={[pal.textLight]} numberOfLines={3}>
|
||||
by {sanitizeHandle(item.creatorHandle, '@')}
|
||||
</Text>
|
||||
</View>
|
||||
{showSaveBtn && (
|
||||
<View>
|
||||
<Pressable
|
||||
accessibilityRole="button"
|
||||
accessibilityLabel={
|
||||
item.isSaved ? 'Remove from my feeds' : 'Add to my feeds'
|
||||
}
|
||||
accessibilityHint=""
|
||||
onPress={onToggleSaved}
|
||||
hitSlop={15}
|
||||
style={styles.btn}>
|
||||
{item.isSaved ? (
|
||||
<FontAwesomeIcon
|
||||
icon={['far', 'trash-can']}
|
||||
size={19}
|
||||
color={pal.colors.icon}
|
||||
/>
|
||||
) : (
|
||||
<FontAwesomeIcon
|
||||
icon="plus"
|
||||
size={18}
|
||||
color={pal.colors.link}
|
||||
/>
|
||||
)}
|
||||
</Pressable>
|
||||
</View>
|
||||
)}
|
||||
</View>
|
||||
|
||||
{showDescription && item.descriptionRT ? (
|
||||
<RichText
|
||||
style={[pal.textLight, styles.description]}
|
||||
richText={item.descriptionRT}
|
||||
numberOfLines={3}
|
||||
/>
|
||||
) : null}
|
||||
|
||||
{showLikes ? (
|
||||
<Text type="sm-medium" style={[pal.text, pal.textLight]}>
|
||||
Liked by {item.likeCount || 0}{' '}
|
||||
{pluralize(item.likeCount || 0, 'user')}
|
||||
</Text>
|
||||
) : null}
|
||||
</Pressable>
|
||||
)
|
||||
})
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
paddingHorizontal: 18,
|
||||
|
|
|
@ -32,9 +32,12 @@ import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries'
|
|||
import {NavigationProp} from 'lib/routes/types'
|
||||
import {sanitizeDisplayName} from 'lib/strings/display-names'
|
||||
import {cleanError} from '#/lib/strings/errors'
|
||||
import {useStores} from '#/state'
|
||||
import {Trans, msg} from '@lingui/macro'
|
||||
import {useLingui} from '@lingui/react'
|
||||
import {
|
||||
UsePreferencesQueryResponse,
|
||||
usePreferencesQuery,
|
||||
} from '#/state/queries/preferences'
|
||||
|
||||
// const MAINTAIN_VISIBLE_CONTENT_POSITION = {minIndexForVisible: 2} TODO
|
||||
|
||||
|
@ -59,11 +62,9 @@ type YieldedItem =
|
|||
export function PostThread({
|
||||
uri,
|
||||
onPressReply,
|
||||
treeView,
|
||||
}: {
|
||||
uri: string | undefined
|
||||
onPressReply: () => void
|
||||
treeView: boolean
|
||||
}) {
|
||||
const {
|
||||
isLoading,
|
||||
|
@ -74,6 +75,7 @@ export function PostThread({
|
|||
data: thread,
|
||||
dataUpdatedAt,
|
||||
} = usePostThreadQuery(uri)
|
||||
const {data: preferences} = usePreferencesQuery()
|
||||
const rootPost = thread?.type === 'post' ? thread.post : undefined
|
||||
const rootPostRecord = thread?.type === 'post' ? thread.record : undefined
|
||||
|
||||
|
@ -96,7 +98,7 @@ export function PostThread({
|
|||
if (AppBskyFeedDefs.isBlockedPost(thread)) {
|
||||
return <PostThreadBlocked />
|
||||
}
|
||||
if (!thread || isLoading) {
|
||||
if (!thread || isLoading || !preferences) {
|
||||
return (
|
||||
<CenteredView>
|
||||
<View style={s.p20}>
|
||||
|
@ -110,7 +112,7 @@ export function PostThread({
|
|||
thread={thread}
|
||||
isRefetching={isRefetching}
|
||||
dataUpdatedAt={dataUpdatedAt}
|
||||
treeView={treeView}
|
||||
threadViewPrefs={preferences.threadViewPrefs}
|
||||
onRefresh={refetch}
|
||||
onPressReply={onPressReply}
|
||||
/>
|
||||
|
@ -121,20 +123,19 @@ function PostThreadLoaded({
|
|||
thread,
|
||||
isRefetching,
|
||||
dataUpdatedAt,
|
||||
treeView,
|
||||
threadViewPrefs,
|
||||
onRefresh,
|
||||
onPressReply,
|
||||
}: {
|
||||
thread: ThreadNode
|
||||
isRefetching: boolean
|
||||
dataUpdatedAt: number
|
||||
treeView: boolean
|
||||
threadViewPrefs: UsePreferencesQueryResponse['threadViewPrefs']
|
||||
onRefresh: () => void
|
||||
onPressReply: () => void
|
||||
}) {
|
||||
const {_} = useLingui()
|
||||
const pal = usePalette('default')
|
||||
const store = useStores()
|
||||
const {isTablet, isDesktop} = useWebMediaQueries()
|
||||
const ref = useRef<FlatList>(null)
|
||||
// const hasScrolledIntoView = useRef<boolean>(false) TODO
|
||||
|
@ -162,16 +163,14 @@ function PostThreadLoaded({
|
|||
// const highlightedPostIndex = posts.findIndex(post => post._isHighlightedPost)
|
||||
const posts = React.useMemo(() => {
|
||||
let arr = [TOP_COMPONENT].concat(
|
||||
Array.from(
|
||||
flattenThreadSkeleton(sortThread(thread, store.preferences.thread)),
|
||||
),
|
||||
Array.from(flattenThreadSkeleton(sortThread(thread, threadViewPrefs))),
|
||||
)
|
||||
if (arr.length > maxVisible) {
|
||||
arr = arr.slice(0, maxVisible).concat([LOAD_MORE])
|
||||
}
|
||||
arr.push(BOTTOM_COMPONENT)
|
||||
return arr
|
||||
}, [thread, maxVisible, store.preferences.thread])
|
||||
}, [thread, maxVisible, threadViewPrefs])
|
||||
|
||||
// TODO
|
||||
/*const onContentSizeChange = React.useCallback(() => {
|
||||
|
@ -297,7 +296,7 @@ function PostThreadLoaded({
|
|||
post={item.post}
|
||||
record={item.record}
|
||||
dataUpdatedAt={dataUpdatedAt}
|
||||
treeView={treeView}
|
||||
treeView={threadViewPrefs.lab_treeViewEnabled}
|
||||
depth={item.ctx.depth}
|
||||
isHighlightedPost={item.ctx.isHighlightedPost}
|
||||
hasMore={item.ctx.hasMore}
|
||||
|
@ -322,7 +321,7 @@ function PostThreadLoaded({
|
|||
pal.colors.border,
|
||||
posts,
|
||||
onRefresh,
|
||||
treeView,
|
||||
threadViewPrefs.lab_treeViewEnabled,
|
||||
dataUpdatedAt,
|
||||
_,
|
||||
],
|
||||
|
|
|
@ -8,12 +8,12 @@ import {ErrorMessage} from '../util/error/ErrorMessage'
|
|||
import {usePalette} from 'lib/hooks/usePalette'
|
||||
import {useNavigation} from '@react-navigation/native'
|
||||
import {NavigationProp} from 'lib/routes/types'
|
||||
import {useStores} from 'state/index'
|
||||
import {logger} from '#/logger'
|
||||
import {useModalControls} from '#/state/modals'
|
||||
import {FeedDescriptor} from '#/state/queries/post-feed'
|
||||
import {EmptyState} from '../util/EmptyState'
|
||||
import {cleanError} from '#/lib/strings/errors'
|
||||
import {useRemoveFeedMutation} from '#/state/queries/preferences'
|
||||
|
||||
enum KnownError {
|
||||
Block,
|
||||
|
@ -86,12 +86,12 @@ function FeedgenErrorMessage({
|
|||
knownError: KnownError
|
||||
}) {
|
||||
const pal = usePalette('default')
|
||||
const store = useStores()
|
||||
const navigation = useNavigation<NavigationProp>()
|
||||
const msg = MESSAGES[knownError]
|
||||
const [_, uri] = feedDesc.split('|')
|
||||
const [ownerDid] = safeParseFeedgenUri(uri)
|
||||
const {openModal, closeModal} = useModalControls()
|
||||
const {mutateAsync: removeFeed} = useRemoveFeedMutation()
|
||||
|
||||
const onViewProfile = React.useCallback(() => {
|
||||
navigation.navigate('Profile', {name: ownerDid})
|
||||
|
@ -104,7 +104,7 @@ function FeedgenErrorMessage({
|
|||
message: 'Remove this feed from your saved feeds?',
|
||||
async onPressConfirm() {
|
||||
try {
|
||||
await store.preferences.removeSavedFeed(uri)
|
||||
await removeFeed({uri})
|
||||
} catch (err) {
|
||||
Toast.show(
|
||||
'There was an an issue removing this feed. Please check your internet connection and try again.',
|
||||
|
@ -116,7 +116,7 @@ function FeedgenErrorMessage({
|
|||
closeModal()
|
||||
},
|
||||
})
|
||||
}, [store, openModal, closeModal, uri])
|
||||
}, [openModal, closeModal, uri, removeFeed])
|
||||
|
||||
return (
|
||||
<View
|
||||
|
|
|
@ -52,6 +52,7 @@ export function Button({
|
|||
accessibilityLabelledBy,
|
||||
onAccessibilityEscape,
|
||||
withLoading = false,
|
||||
disabled = false,
|
||||
}: React.PropsWithChildren<{
|
||||
type?: ButtonType
|
||||
label?: string
|
||||
|
@ -65,6 +66,7 @@ export function Button({
|
|||
accessibilityLabelledBy?: string
|
||||
onAccessibilityEscape?: () => void
|
||||
withLoading?: boolean
|
||||
disabled?: boolean
|
||||
}>) {
|
||||
const theme = useTheme()
|
||||
const typeOuterStyle = choose<ViewStyle, Record<ButtonType, ViewStyle>>(
|
||||
|
@ -198,7 +200,7 @@ export function Button({
|
|||
<Pressable
|
||||
style={getStyle}
|
||||
onPress={onPressWrapped}
|
||||
disabled={isLoading}
|
||||
disabled={disabled || isLoading}
|
||||
testID={testID}
|
||||
accessibilityRole="button"
|
||||
accessibilityLabel={accessibilityLabel}
|
||||
|
|
|
@ -1,38 +0,0 @@
|
|||
import React, {useMemo} from 'react'
|
||||
import {AppBskyFeedDefs} from '@atproto/api'
|
||||
import {usePalette} from 'lib/hooks/usePalette'
|
||||
import {StyleSheet} from 'react-native'
|
||||
import {useStores} from 'state/index'
|
||||
import {FeedSourceModel} from 'state/models/content/feed-source'
|
||||
import {FeedSourceCard} from 'view/com/feeds/FeedSourceCard'
|
||||
|
||||
export function CustomFeedEmbed({
|
||||
record,
|
||||
}: {
|
||||
record: AppBskyFeedDefs.GeneratorView
|
||||
}) {
|
||||
const pal = usePalette('default')
|
||||
const store = useStores()
|
||||
const item = useMemo(() => {
|
||||
const model = new FeedSourceModel(store, record.uri)
|
||||
model.hydrateFeedGenerator(record)
|
||||
return model
|
||||
}, [store, record])
|
||||
return (
|
||||
<FeedSourceCard
|
||||
item={item}
|
||||
style={[pal.view, pal.border, styles.customFeedOuter]}
|
||||
showLikes
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
customFeedOuter: {
|
||||
borderWidth: 1,
|
||||
borderRadius: 8,
|
||||
marginTop: 4,
|
||||
paddingHorizontal: 12,
|
||||
paddingVertical: 12,
|
||||
},
|
||||
})
|
|
@ -28,9 +28,9 @@ import {ExternalLinkEmbed} from './ExternalLinkEmbed'
|
|||
import {getYoutubeVideoId} from 'lib/strings/url-helpers'
|
||||
import {MaybeQuoteEmbed} from './QuoteEmbed'
|
||||
import {AutoSizedImage} from '../images/AutoSizedImage'
|
||||
import {CustomFeedEmbed} from './CustomFeedEmbed'
|
||||
import {ListEmbed} from './ListEmbed'
|
||||
import {isCauseALabelOnUri} from 'lib/moderation'
|
||||
import {FeedSourceCard} from 'view/com/feeds/FeedSourceCard'
|
||||
|
||||
type Embed =
|
||||
| AppBskyEmbedRecord.View
|
||||
|
@ -72,7 +72,13 @@ export function PostEmbeds({
|
|||
// custom feed embed (i.e. generator view)
|
||||
// =
|
||||
if (AppBskyFeedDefs.isGeneratorView(embed.record)) {
|
||||
return <CustomFeedEmbed record={embed.record} />
|
||||
return (
|
||||
<FeedSourceCard
|
||||
feedUri={embed.record.uri}
|
||||
style={[pal.view, pal.border, styles.customFeedOuter]}
|
||||
showLikes
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
// list embed
|
||||
|
@ -206,4 +212,11 @@ const styles = StyleSheet.create({
|
|||
fontSize: 10,
|
||||
fontWeight: 'bold',
|
||||
},
|
||||
customFeedOuter: {
|
||||
borderWidth: 1,
|
||||
borderRadius: 8,
|
||||
marginTop: 4,
|
||||
paddingHorizontal: 12,
|
||||
paddingVertical: 12,
|
||||
},
|
||||
})
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue