--- a/src/screens/Profile/Header/ProfileHeaderStandard.tsx 2026-02-16 03:00:07 +++ b/src/screens/Profile/Header/ProfileHeaderStandard.tsx 2026-02-16 03:02:25 @@ -1,5 +1,5 @@ import {memo, useMemo, useState} from 'react' -import {View} from 'react-native' +import {Image, Pressable, View} from 'react-native' import { type AppBskyActorDefs, moderateProfile, @@ -9,9 +9,11 @@ } from '@atproto/api' import {msg, Trans} from '@lingui/macro' import {useLingui} from '@lingui/react' +import {useQuery} from '@tanstack/react-query' import {useActorStatus} from '#/lib/actor-status' import {useHaptics} from '#/lib/haptics' +import {useOpenLink} from '#/lib/hooks/useOpenLink' import {sanitizeDisplayName} from '#/lib/strings/display-names' import {sanitizeHandle} from '#/lib/strings/handles' import {logger} from '#/logger' @@ -20,7 +22,7 @@ useProfileBlockMutationQueue, useProfileFollowMutationQueue, } from '#/state/queries/profile' -import {useRequireAuth, useSession} from '#/state/session' +import {useAgent, useRequireAuth, useSession} from '#/state/session' import {ProfileMenu} from '#/view/com/profile/ProfileMenu' import {atoms as a, platform, useBreakpoints, useTheme} from '#/alf' import {SubscribeProfileButton} from '#/components/activity-notifications/SubscribeProfileButton' @@ -45,6 +47,83 @@ import {ProfileHeaderMetrics} from './Metrics' import {ProfileHeaderShell} from './Shell' import {ProfileHeaderSuggestedFollows} from './SuggestedFollows' + +const SERVICE_FAVICONS: Record = { + 'syui.ai': require('../../../../assets/favicons/syui.ai.png'), + 'bsky.app': require('../../../../assets/favicons/bsky.app.png'), + 'atproto.com': require('../../../../assets/favicons/atproto.com.png'), +} + +function ProfileServiceLinks({ + profile, +}: { + profile: AppBskyActorDefs.ProfileViewDetailed +}) { + const t = useTheme() + const agent = useAgent() + const openLink = useOpenLink() + + const {data: services} = useQuery({ + queryKey: ['profile-services', profile.did], + queryFn: async () => { + const res = await agent.com.atproto.repo.describeRepo({ + repo: profile.did, + }) + const collections: string[] = res.data.collections || [] + const serviceSet = new Set() + for (const nsid of collections) { + const parts = nsid.split('.') + if (parts.length >= 2) { + const domain = parts.slice(0, 2).reverse().join('.') + serviceSet.add(domain) + } + } + return Array.from(serviceSet) + }, + }) + + if (!services || services.length === 0) return null + + return ( + + {services.map(service => ( + + openLink( + `https://at.syu.is/@${profile.handle}/at/service/${service}`, + ) + } + style={[ + a.flex_row, + a.align_center, + a.gap_xs, + a.rounded_full, + t.atoms.bg_contrast_50, + {paddingVertical: 6, paddingHorizontal: 10}, + ]}> + + + {service} + + + ))} + + ) +} interface Props { profile: AppBskyActorDefs.ProfileViewDetailed @@ -151,6 +230,7 @@ {!isPlaceholderProfile && !isBlockedUser && ( + {descriptionRT && !moderation.ui('profileView').blur ? (