tangled
alpha
login
or
join now
leaflet.pub
/
leaflet
289
fork
atom
a tool for shared writing and social publishing
289
fork
atom
overview
issues
27
pulls
pipelines
use BskyPostContent in the leaflet as well
cozylittle.house
1 month ago
dad2b37a
b93168fe
+38
-193
5 changed files
expand all
collapse all
unified
split
app
lish
[did]
[publication]
[rkey]
Blocks
PublishBskyPostBlock.tsx
BskyPostContent.tsx
Interactions
Quotes.tsx
ThreadPage.tsx
components
Blocks
BlueskyPostBlock
index.tsx
+13
-113
app/lish/[did]/[publication]/[rkey]/Blocks/PublishBskyPostBlock.tsx
···
13
13
} from "components/Blocks/BlueskyPostBlock/BlueskyEmbed";
14
14
import { BlueskyRichText } from "components/Blocks/BlueskyPostBlock/BlueskyRichText";
15
15
import { openPage } from "../PostPages";
16
16
+
import { BskyPostContent } from "../BskyPostContent";
16
17
17
18
export const PubBlueskyPostBlock = (props: {
18
19
post: PostView;
···
49
50
50
51
//getting the url to the post
51
52
let postId = post.uri.split("/")[4];
53
53
+
let postView = post as PostView;
54
54
+
52
55
let url = `https://bsky.app/profile/${post.author.handle}/post/${postId}`;
53
56
54
57
const parent = props.pageId
···
56
59
: undefined;
57
60
58
61
return (
59
59
-
<div
60
60
-
onClick={handleOpenThread}
61
61
-
className={`
62
62
-
${props.className}
63
63
-
block-border
64
64
-
mb-2
65
65
-
flex flex-col gap-2 relative w-full overflow-hidden group/blueskyPostBlock sm:p-3 p-2 text-sm text-secondary bg-bg-page
66
66
-
cursor-pointer hover:border-accent-contrast
67
67
-
`}
68
68
-
>
69
69
-
{post.author && record && (
70
70
-
<>
71
71
-
<div className="bskyAuthor w-full flex items-center gap-2">
72
72
-
{post.author.avatar && (
73
73
-
<img
74
74
-
src={post.author?.avatar}
75
75
-
alt={`${post.author?.displayName}'s avatar`}
76
76
-
className="shink-0 w-8 h-8 rounded-full border border-border-light"
77
77
-
/>
78
78
-
)}
79
79
-
<div className="grow flex flex-col gap-0.5 leading-tight">
80
80
-
<div className=" font-bold text-secondary">
81
81
-
{post.author?.displayName}
82
82
-
</div>
83
83
-
<a
84
84
-
className="text-xs text-tertiary hover:underline"
85
85
-
target="_blank"
86
86
-
href={`https://bsky.app/profile/${post.author?.handle}`}
87
87
-
onClick={(e) => e.stopPropagation()}
88
88
-
>
89
89
-
@{post.author?.handle}
90
90
-
</a>
91
91
-
</div>
92
92
-
</div>
93
93
-
94
94
-
<div className="flex flex-col gap-2 ">
95
95
-
<div>
96
96
-
<pre className="whitespace-pre-wrap">
97
97
-
{BlueskyRichText({
98
98
-
record: record as AppBskyFeedPost.Record | null,
99
99
-
})}
100
100
-
</pre>
101
101
-
</div>
102
102
-
{post.embed && (
103
103
-
<div onClick={(e) => e.stopPropagation()}>
104
104
-
<BlueskyEmbed embed={post.embed} postUrl={url} />
105
105
-
</div>
106
106
-
)}
107
107
-
</div>
108
108
-
</>
109
109
-
)}
110
110
-
<div className="w-full flex gap-2 items-center justify-between">
111
111
-
<ClientDate date={timestamp} />
112
112
-
<div className="flex gap-2 items-center">
113
113
-
{post.replyCount != null && post.replyCount > 0 && (
114
114
-
<>
115
115
-
<ThreadLink
116
116
-
postUri={post.uri}
117
117
-
parent={parent}
118
118
-
className="flex items-center gap-1 hover:text-accent-contrast"
119
119
-
onClick={(e) => e.stopPropagation()}
120
120
-
>
121
121
-
{post.replyCount}
122
122
-
<CommentTiny />
123
123
-
</ThreadLink>
124
124
-
<Separator classname="h-4" />
125
125
-
</>
126
126
-
)}
127
127
-
{post.quoteCount != null && post.quoteCount > 0 && (
128
128
-
<>
129
129
-
<QuotesLink
130
130
-
postUri={post.uri}
131
131
-
parent={parent}
132
132
-
className="flex items-center gap-1 hover:text-accent-contrast"
133
133
-
onClick={(e) => e.stopPropagation()}
134
134
-
>
135
135
-
{post.quoteCount}
136
136
-
<QuoteTiny />
137
137
-
</QuotesLink>
138
138
-
<Separator classname="h-4" />
139
139
-
</>
140
140
-
)}
141
141
-
142
142
-
<a
143
143
-
className=""
144
144
-
target="_blank"
145
145
-
href={url}
146
146
-
onClick={(e) => e.stopPropagation()}
147
147
-
>
148
148
-
<BlueskyTiny />
149
149
-
</a>
150
150
-
</div>
151
151
-
</div>
152
152
-
</div>
62
62
+
<BskyPostContent
63
63
+
post={postView}
64
64
+
parent={undefined}
65
65
+
showBlueskyLink={true}
66
66
+
showEmbed={true}
67
67
+
avatarSize="large"
68
68
+
quoteEnabled
69
69
+
replyEnabled
70
70
+
className="text-sm text-secondary block-border sm:px-3 sm:py-2 px-2 py-1 bg-bg-page mb-2 hover:border-accent-contrast!"
71
71
+
/>
153
72
);
154
73
}
155
74
};
156
156
-
157
157
-
const ClientDate = (props: { date?: string }) => {
158
158
-
let pageLoaded = useHasPageLoaded();
159
159
-
const formattedDate = useLocalizedDate(
160
160
-
props.date || new Date().toISOString(),
161
161
-
{
162
162
-
month: "short",
163
163
-
day: "numeric",
164
164
-
year: "numeric",
165
165
-
hour: "numeric",
166
166
-
minute: "numeric",
167
167
-
hour12: true,
168
168
-
},
169
169
-
);
170
170
-
171
171
-
if (!pageLoaded) return null;
172
172
-
173
173
-
return <div className="text-xs text-tertiary">{formattedDate}</div>;
174
174
-
};
+11
-7
app/lish/[did]/[publication]/[rkey]/BskyPostContent.tsx
···
19
19
20
20
export function BskyPostContent(props: {
21
21
post: PostView;
22
22
-
parent: OpenPage;
22
22
+
parent: OpenPage | undefined;
23
23
avatarSize?: "tiny" | "small" | "medium" | "large" | "giant";
24
24
className?: string;
25
25
showEmbed?: boolean;
···
87
87
className={`flex flex-col min-w-0 w-full z-0 ${props.replyLine ? "mt-2" : ""}`}
88
88
>
89
89
<button
90
90
-
className="bskyPostTextContent flex flex-col grow mt-1 text-left"
90
90
+
className={`bskyPostTextContent flex flex-col grow text-left ${props.avatarSize === "small" ? "mt-0.5" : props.avatarSize === "large" ? "mt-2" : "mt-1"}`}
91
91
onClick={() => {
92
92
openPage(parent, { type: "thread", uri: post.uri });
93
93
}}
···
99
99
/>
100
100
101
101
<div className={`postContent flex flex-col gap-2 mt-0.5`}>
102
102
-
<div className="text-secondary text-sm">
102
102
+
<div className="text-secondary">
103
103
<BlueskyRichText record={record} />
104
104
</div>
105
105
{showEmbed && post.embed && (
···
133
133
<div className="flex gap-3 items-center">
134
134
{showBlueskyLink && (
135
135
<>
136
136
-
<a className="text-tertiary" target="_blank" href={url}>
136
136
+
<a
137
137
+
className="text-tertiary hover:text-accent-contrast"
138
138
+
target="_blank"
139
139
+
href={url}
140
140
+
>
137
141
<BlueskyLinkTiny />
138
142
</a>
139
143
</>
···
276
280
}) {
277
281
const replyContent = props.post.replyCount != null &&
278
282
props.post.replyCount > 0 && (
279
279
-
<div className="postRepliesCount flex items-center gap-1 text-tertiary text-xs">
283
283
+
<div className="postRepliesCount flex items-center gap-1 text-xs">
280
284
<CommentTiny />
281
285
{props.post.replyCount}
282
286
</div>
···
284
288
285
289
const quoteContent = props.post.quoteCount != null &&
286
290
props.post.quoteCount > 0 && (
287
287
-
<div className="postQuoteCount flex items-center gap-1 text-tertiary text-xs">
291
291
+
<div className="postQuoteCount flex items-center gap-1 text-xs">
288
292
<QuoteTiny />
289
293
{props.post.quoteCount}
290
294
</div>
291
295
);
292
296
293
297
return (
294
294
-
<div className="postCounts flex gap-2 items-center w-full">
298
298
+
<div className="postCounts flex gap-2 items-center w-full text-tertiary">
295
299
{replyContent &&
296
300
(props.replyEnabled ? (
297
301
<ThreadLink
+1
app/lish/[did]/[publication]/[rkey]/Interactions/Quotes.tsx
···
113
113
return (
114
114
<>
115
115
<Quote
116
116
+
key={q.uri}
116
117
q={q}
117
118
index={index}
118
119
did={props.did}
-10
app/lish/[did]/[publication]/[rkey]/ThreadPage.tsx
···
326
326
)}
327
327
</div>
328
328
)}
329
329
-
330
330
-
{hasReplies && props.depth >= 3 && (
331
331
-
<ThreadLink
332
332
-
postUri={props.post.post.uri}
333
333
-
parent={{ type: "thread", uri: pageUri }}
334
334
-
className="text-left ml-10 text-sm text-accent-contrast hover:underline"
335
335
-
>
336
336
-
View more replies
337
337
-
</ThreadLink>
338
338
-
)}
339
329
</div>
340
330
);
341
331
};
+13
-63
components/Blocks/BlueskyPostBlock/index.tsx
···
13
13
import { BlueskyTiny } from "components/Icons/BlueskyTiny";
14
14
import { CommentTiny } from "components/Icons/CommentTiny";
15
15
import { useLocalizedDate } from "src/hooks/useLocalizedDate";
16
16
+
import { BskyPostContent } from "app/lish/[did]/[publication]/[rkey]/BskyPostContent";
17
17
+
import { PostView } from "@atproto/api/dist/client/types/app/bsky/feed/defs";
16
18
17
19
export const BlueskyPostBlock = (props: BlockProps & { preview?: boolean }) => {
18
20
let { permissions } = useEntitySetContext();
···
76
78
77
79
//getting the url to the post
78
80
let postId = post.post.uri.split("/")[4];
81
81
+
let postView = post.post as PostView;
79
82
let url = `https://bsky.app/profile/${post.post.author.handle}/post/${postId}`;
80
83
81
84
return (
82
85
<BlockLayout
83
86
isSelected={!!isSelected}
84
87
hasBackground="page"
85
85
-
className="flex flex-col gap-2 relative overflow-hidden group/blueskyPostBlock text-sm text-secondary"
88
88
+
borderOnHover
89
89
+
className="blueskyPostBlock sm:px-3! sm:py-2! px-2! py-1!"
86
90
>
87
87
-
{post.post.author && record && (
88
88
-
<>
89
89
-
<div className="bskyAuthor w-full flex items-center gap-2">
90
90
-
{post.post.author?.avatar ? (
91
91
-
<img
92
92
-
src={post.post.author?.avatar}
93
93
-
alt={`${post.post.author?.displayName}'s avatar`}
94
94
-
className="shrink-0 w-8 h-8 rounded-full border border-border-light"
95
95
-
/>
96
96
-
) : (
97
97
-
<div className="shrink-0 w-8 h-8 rounded-full border border-border-light bg-border"></div>
98
98
-
)}
99
99
-
<div className="grow flex flex-col gap-0.5 leading-tight">
100
100
-
<div className=" font-bold text-secondary">
101
101
-
{post.post.author?.displayName}
102
102
-
</div>
103
103
-
<a
104
104
-
className="text-xs text-tertiary hover:underline"
105
105
-
target="_blank"
106
106
-
href={`https://bsky.app/profile/${post.post.author?.handle}`}
107
107
-
>
108
108
-
@{post.post.author?.handle}
109
109
-
</a>
110
110
-
</div>
111
111
-
</div>
112
112
-
113
113
-
<div className="flex flex-col gap-2 ">
114
114
-
<div>
115
115
-
<pre className="whitespace-pre-wrap">
116
116
-
{BlueskyRichText({
117
117
-
record: record as AppBskyFeedPost.Record | null,
118
118
-
})}
119
119
-
</pre>
120
120
-
</div>
121
121
-
{post.post.embed && (
122
122
-
<BlueskyEmbed embed={post.post.embed} postUrl={url} />
123
123
-
)}
124
124
-
</div>
125
125
-
</>
126
126
-
)}
127
127
-
<div className="w-full flex gap-2 items-center justify-between">
128
128
-
{timestamp && <PostDate timestamp={timestamp} />}
129
129
-
<div className="flex gap-2 items-center">
130
130
-
{post.post.replyCount != null && post.post.replyCount > 0 && (
131
131
-
<>
132
132
-
<a
133
133
-
className="flex items-center gap-1 hover:no-underline"
134
134
-
target="_blank"
135
135
-
href={url}
136
136
-
>
137
137
-
{post.post.replyCount}
138
138
-
<CommentTiny />
139
139
-
</a>
140
140
-
<Separator classname="h-4" />
141
141
-
</>
142
142
-
)}
143
143
-
144
144
-
<a className="" target="_blank" href={url}>
145
145
-
<BlueskyTiny />
146
146
-
</a>
147
147
-
</div>
148
148
-
</div>
91
91
+
<BskyPostContent
92
92
+
post={postView}
93
93
+
parent={undefined}
94
94
+
showBlueskyLink={true}
95
95
+
showEmbed={true}
96
96
+
avatarSize="large"
97
97
+
className="text-sm text-secondary "
98
98
+
/>
149
99
</BlockLayout>
150
100
);
151
101
}