This repository has no description
3.2 kB
109 lines
1'use client';
2
3import { AppBskyFeedDefs, AppBskyFeedPost } from '@atproto/api';
4import { ReactElement } from 'react';
5import {
6 Group,
7 Stack,
8 Text,
9 Avatar,
10 Box,
11 Image,
12 Anchor,
13 Tooltip,
14} from '@mantine/core';
15import RichTextRenderer from '@/components/contentDisplay/richTextRenderer/RichTextRenderer';
16import useGetBlueskyPost from '../../lib/queries/useGetBlueskyPost';
17import PostEmbed from '../postEmbed/PostEmbed';
18import { FaBluesky } from 'react-icons/fa6';
19import { detectUrlPlatform, SupportedPlatform } from '@/lib/utils/link';
20import { getPostUriFromUrl } from '@/lib/utils/atproto';
21import BlackskyLogo from '@/assets/icons/blacksky-logo.svg';
22import BlackskyLogoWhite from '@/assets/icons/blacksky-logo-white.svg';
23import { useUserSettings } from '@/features/settings/lib/queries/useUserSettings';
24
25interface Props {
26 url: string;
27 fallbackCardContent: ReactElement;
28}
29
30export default function BlueskyPost(props: Props) {
31 const { settings } = useUserSettings();
32 const uri = getPostUriFromUrl(props.url);
33 const { data, error } = useGetBlueskyPost({ uri });
34 const showEmbed = settings.cardView !== 'list';
35 const platform = detectUrlPlatform(props.url);
36 const platformIcon =
37 platform.type === SupportedPlatform.BLUESKY_POST ? (
38 <FaBluesky fill="#0085ff" size={18} />
39 ) : (
40 <>
41 <Image
42 src={BlackskyLogo.src}
43 alt="Blacksky logo"
44 w={18}
45 h={'auto'}
46 darkHidden
47 />
48 <Image
49 src={BlackskyLogoWhite.src}
50 alt="Blacksky logo"
51 w={18}
52 h={'auto'}
53 lightHidden
54 />
55 </>
56 );
57
58 if (
59 !data.thread ||
60 !AppBskyFeedDefs.isThreadViewPost(data.thread) ||
61 AppBskyFeedDefs.isNotFoundPost(data.thread.post) ||
62 AppBskyFeedDefs.isBlockedPost(data.thread.post) ||
63 error
64 ) {
65 return props.fallbackCardContent;
66 }
67
68 const post = data.thread.post;
69 const record = post.record as AppBskyFeedPost.Record;
70
71 return (
72 <Stack justify="space-between" gap="xs">
73 <Group gap="xs" justify="space-between" wrap="nowrap" w={'100%'}>
74 <Group gap={'xs'} wrap="nowrap">
75 <Avatar
76 src={post.author.avatar?.replace('avatar', 'avatar_thumbnail')}
77 alt={`${post.author.handle} avatar`}
78 size={'sm'}
79 radius="xl"
80 />
81
82 <Text c="bright" lineClamp={1} fw={500}>
83 {post.author.displayName || post.author.handle}
84 </Text>
85 </Group>
86 <Tooltip
87 label={`View on ${platform.type === SupportedPlatform.BLUESKY_POST ? 'Bluesky' : 'Blacksky'}`}
88 >
89 <Anchor
90 href={props.url}
91 target="_blank"
92 onClick={(e) => e.stopPropagation()}
93 >
94 {platformIcon}
95 </Anchor>
96 </Tooltip>
97 </Group>
98 <Stack gap={'xs'} w={'100%'}>
99 <Box>
100 <RichTextRenderer
101 text={record.text}
102 textProps={{ lineClamp: settings.cardView === 'list' ? 1 : 3 }}
103 />
104 </Box>
105 {post.embed && showEmbed && <PostEmbed embed={post.embed} />}
106 </Stack>
107 </Stack>
108 );
109}