Enrich feed card embed on posts

The feed generator embed on posts only showed the avatar, title, and
byline, even though the embed view is fully hydrated with more data. Make
the embed a full card matching the feed discovery card: add the feed
description (clamped to 3 lines), the "Liked by N users" count, and an
interactive Pin/Save button.

Also surface video feeds: add a small "Video feed" badge in
TitleAndByline when contentMode is the video mode, which the discovery
card picks up as well.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011CcnwUeBmYNFzhRGhV4RG5
This commit is contained in:
Claude
2026-06-20 15:18:22 +00:00
parent dd452a4336
commit 72dfec9115
2 changed files with 27 additions and 1 deletions
+20 -1
View File
@@ -1,7 +1,7 @@
import {useCallback, useEffect, useMemo} from 'react' import {useCallback, useEffect, useMemo} from 'react'
import {type GestureResponderEvent, View} from 'react-native' import {type GestureResponderEvent, View} from 'react-native'
import { import {
type AppBskyFeedDefs, AppBskyFeedDefs,
type AppBskyGraphDefs, type AppBskyGraphDefs,
AtUri, AtUri,
RichText as RichTextApi, RichText as RichTextApi,
@@ -28,6 +28,7 @@ import {
} from '#/components/Button' } from '#/components/Button'
import {Live_Stroke2_Corner0_Rounded as LiveIcon} from '#/components/icons/Live' import {Live_Stroke2_Corner0_Rounded as LiveIcon} from '#/components/icons/Live'
import {Pin_Stroke2_Corner0_Rounded as PinIcon} from '#/components/icons/Pin' import {Pin_Stroke2_Corner0_Rounded as PinIcon} from '#/components/icons/Pin'
import {VideoClip_Stroke2_Corner0_Rounded as VideoClipIcon} from '#/components/icons/VideoClip'
import {Link as InternalLink, type LinkProps} from '#/components/Link' import {Link as InternalLink, type LinkProps} from '#/components/Link'
import {Loader} from '#/components/Loader' import {Loader} from '#/components/Loader'
import * as Prompt from '#/components/Prompt' import * as Prompt from '#/components/Prompt'
@@ -54,6 +55,7 @@ export function Default(props: Props) {
title={view.displayName} title={view.displayName}
creator={view.creator} creator={view.creator}
uri={view.uri} uri={view.uri}
contentMode={view.contentMode}
/> />
<SaveButton view={view} pin /> <SaveButton view={view} pin />
</Header> </Header>
@@ -124,13 +126,16 @@ export function TitleAndByline({
title, title,
creator, creator,
uri, uri,
contentMode,
}: { }: {
title: string title: string
creator?: bsky.profile.AnyProfileView creator?: bsky.profile.AnyProfileView
uri?: string uri?: string
contentMode?: AppBskyFeedDefs.GeneratorView['contentMode']
}) { }) {
const t = useTheme() const t = useTheme()
const activeLiveEvents = useActiveLiveEventFeedUris() const activeLiveEvents = useActiveLiveEventFeedUris()
const isVideoFeed = contentMode === AppBskyFeedDefs.CONTENTMODEVIDEO
const liveColor = useMemo( const liveColor = useMemo(
() => () =>
select(t.name, { select(t.name, {
@@ -170,6 +175,20 @@ export function TitleAndByline({
<Trans>Feed by {sanitizeHandle(creator.handle, '@')}</Trans> <Trans>Feed by {sanitizeHandle(creator.handle, '@')}</Trans>
</Text> </Text>
)} )}
{isVideoFeed && (
<View style={[a.flex_row, a.align_center, a.gap_2xs, a.pt_2xs]}>
<VideoClipIcon size="xs" fill={t.atoms.text_contrast_medium.color} />
<Text
style={[
a.text_2xs,
a.font_medium,
a.leading_snug,
t.atoms.text_contrast_medium,
]}>
<Trans>Video feed</Trans>
</Text>
</View>
)}
</View> </View>
) )
} }
+7
View File
@@ -25,8 +25,15 @@ export function FeedEmbed({
title={embed.view.displayName} title={embed.view.displayName}
creator={embed.view.creator} creator={embed.view.creator}
uri={embed.view.uri} uri={embed.view.uri}
contentMode={embed.view.contentMode}
/> />
<FeedCard.SaveButton view={embed.view} pin />
</FeedCard.Header> </FeedCard.Header>
<FeedCard.Description
description={embed.view.description}
numberOfLines={3}
/>
<FeedCard.Likes count={embed.view.likeCount || 0} />
</FeedCard.Outer> </FeedCard.Outer>
</FeedCard.Link> </FeedCard.Link>
) )