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
28
pulls
pipelines
adjusting interaction button styles for consistency
cozylittle.house
1 month ago
bea2843d
412de350
+102
-63
5 changed files
expand all
collapse all
unified
split
app
lish
[did]
[publication]
[rkey]
Interactions
Interactions.tsx
page.tsx
components
InteractionsPreview.tsx
PostListing.tsx
RecommendButton.tsx
+49
-38
app/lish/[did]/[publication]/[rkey]/Interactions/Interactions.tsx
···
19
19
import { EditTiny } from "components/Icons/EditTiny";
20
20
import { getPublicationURL } from "app/lish/createPub/getPublicationURL";
21
21
import { RecommendButton } from "components/RecommendButton";
22
22
+
import { ButtonSecondary } from "components/Buttons";
23
23
+
import { Separator } from "components/Layout";
22
24
23
25
export type InteractionState = {
24
26
drawerOpen: undefined | boolean;
···
130
132
const tags = normalizedDocument.tags;
131
133
const tagCount = tags?.length || 0;
132
134
135
135
+
let interactionsAvailable = props.showComments || props.showMentions;
136
136
+
133
137
return (
134
134
-
<div className={`flex gap-2 text-tertiary text-sm ${props.className}`}>
135
135
-
{tagCount > 0 && <TagPopover tags={tags} tagCount={tagCount} />}
136
136
-
137
137
-
<RecommendButton
138
138
-
documentUri={document_uri}
139
139
-
recommendsCount={props.recommendsCount}
140
140
-
/>
138
138
+
<div
139
139
+
className={`flex gap-2 text-tertiary text-sm item-center ${props.className}`}
140
140
+
>
141
141
+
{/*COMMENT BUTTON*/}
142
142
+
{props.showComments === false ? null : (
143
143
+
<button
144
144
+
className="flex gap-2 items-center w-fit"
145
145
+
onClick={() => {
146
146
+
if (!drawerOpen || drawer !== "comments" || pageId !== props.pageId)
147
147
+
openInteractionDrawer("comments", document_uri, props.pageId);
148
148
+
else setInteractionState(document_uri, { drawerOpen: false });
149
149
+
}}
150
150
+
aria-label="Post comments"
151
151
+
>
152
152
+
<CommentTiny aria-hidden /> {props.commentsCount}
153
153
+
</button>
154
154
+
)}
141
155
156
156
+
{/*MENTIONS BUTTON*/}
142
157
{props.quotesCount === 0 || props.showMentions === false ? null : (
143
158
<button
144
159
className="flex w-fit gap-2 items-center"
···
154
169
<QuoteTiny aria-hidden /> {props.quotesCount}
155
170
</button>
156
171
)}
157
157
-
{props.showComments === false ? null : (
158
158
-
<button
159
159
-
className="flex gap-2 items-center w-fit"
160
160
-
onClick={() => {
161
161
-
if (!drawerOpen || drawer !== "comments" || pageId !== props.pageId)
162
162
-
openInteractionDrawer("comments", document_uri, props.pageId);
163
163
-
else setInteractionState(document_uri, { drawerOpen: false });
164
164
-
}}
165
165
-
aria-label="Post comments"
166
166
-
>
167
167
-
<CommentTiny aria-hidden /> {props.commentsCount}
168
168
-
</button>
169
169
-
)}
172
172
+
<RecommendButton
173
173
+
documentUri={document_uri}
174
174
+
recommendsCount={props.recommendsCount}
175
175
+
/>
176
176
+
<Separator classname="h-4!" />
177
177
+
{tagCount > 0 && <TagPopover tags={tags} tagCount={tagCount} />}
170
178
</div>
171
179
);
172
180
};
···
209
217
(s) => s.identity === identity.atp_did,
210
218
);
211
219
212
212
-
let isAuthor =
213
213
-
identity && identity.atp_did === publication?.identity_did && leafletId;
214
214
-
215
220
return (
216
221
<div
217
222
className={`text-tertiary px-3 sm:px-4 flex flex-col ${props.className}`}
···
231
236
<div />
232
237
) : (
233
238
<>
234
234
-
<div className="flex gap-2">
239
239
+
<div className="flex gap-2 sm:flex-row flex-col">
235
240
<RecommendButton
236
241
documentUri={document_uri}
237
242
recommendsCount={props.recommendsCount}
243
243
+
expanded
238
244
/>
239
245
{props.quotesCount === 0 || !props.showMentions ? null : (
240
240
-
<button
241
241
-
className="flex w-fit gap-2 items-center px-1 py-0.5 border border-border-light rounded-lg trasparent-outline selected-outline"
246
246
+
<ButtonSecondary
242
247
onClick={() => {
243
248
if (!drawerOpen || drawer !== "quotes")
244
249
openInteractionDrawer(
···
253
258
onTouchStart={handleQuotePrefetch}
254
259
aria-label="Post quotes"
255
260
>
256
256
-
<QuoteTiny aria-hidden /> {props.quotesCount}{" "}
261
261
+
<QuoteTiny aria-hidden /> {props.quotesCount}
262
262
+
{props.quotesCount > 0 && (
263
263
+
<>
264
264
+
{props.quotesCount}
265
265
+
<Separator classname="h-4! text-accent-contrast!" />
266
266
+
</>
267
267
+
)}
268
268
+
Mention
257
269
<span
258
270
aria-hidden
259
271
>{`Mention${props.quotesCount === 1 ? "" : "s"}`}</span>
260
260
-
</button>
272
272
+
</ButtonSecondary>
261
273
)}
262
274
{!props.showComments ? null : (
263
263
-
<button
264
264
-
className="flex gap-2 items-center w-fit px-1 py-0.5 border border-border-light rounded-lg trasparent-outline selected-outline"
275
275
+
<ButtonSecondary
265
276
onClick={() => {
266
277
if (
267
278
!drawerOpen ||
···
279
290
aria-label="Post comments"
280
291
>
281
292
<CommentTiny aria-hidden />{" "}
282
282
-
{props.commentsCount > 0 ? (
283
283
-
<span aria-hidden>
284
284
-
{`${props.commentsCount} Comment${props.commentsCount === 1 ? "" : "s"}`}
285
285
-
</span>
286
286
-
) : (
287
287
-
"Comment"
293
293
+
{props.commentsCount > 0 && (
294
294
+
<>
295
295
+
{props.commentsCount}
296
296
+
<Separator classname="h-4! text-accent-contrast!" />
297
297
+
</>
288
298
)}
289
289
-
</button>
299
299
+
Comment
300
300
+
</ButtonSecondary>
290
301
)}
291
302
</div>
292
303
</>
···
388
399
return (
389
400
<a
390
401
href={`https://leaflet.pub/${props.leafletId}`}
391
391
-
className="flex gap-2 items-center hover:!no-underline selected-outline px-2 py-0.5 bg-accent-1 text-accent-2 font-bold w-fit rounded-lg !border-accent-1 !outline-accent-1"
402
402
+
className="flex gap-2 items-center hover:!no-underline selected-outline px-2 py-0.5 bg-accent-1 text-accent-2 font-bold w-fit rounded-md !border-accent-1 !outline-accent-1 h-fit"
392
403
>
393
404
<EditTiny /> Edit Post
394
405
</a>
+2
-6
app/lish/[did]/[publication]/page.tsx
···
148
148
</p>
149
149
</SpeedyLink>
150
150
151
151
-
<div className="text-sm text-tertiary flex gap-1 flex-wrap pt-2 items-center">
151
151
+
<div className="justify-between w-full text-sm text-tertiary flex gap-1 flex-wrap pt-2 items-center">
152
152
<p className="text-sm text-tertiary ">
153
153
{doc_record.publishedAt && (
154
154
<LocalizedDate
···
161
161
/>
162
162
)}{" "}
163
163
</p>
164
164
-
{comments > 0 || quotes > 0 || tags.length > 0 ? (
165
165
-
<Separator classname="h-4! mx-1" />
166
166
-
) : (
167
167
-
""
168
168
-
)}
164
164
+
169
165
<InteractionPreview
170
166
quotesCount={quotes}
171
167
commentsCount={comments}
+8
-12
components/InteractionsPreview.tsx
···
30
30
31
31
return (
32
32
<div className={`flex gap-2 text-tertiary text-sm items-center`}>
33
33
-
{tagsCount === 0 ? null : (
34
34
-
<>
35
35
-
<TagPopover tags={props.tags!} />
36
36
-
{interactionsAvailable || props.share ? (
37
37
-
<Separator classname="h-4!" />
38
38
-
) : null}
39
39
-
</>
40
40
-
)}
41
41
-
42
33
<RecommendButton
43
34
documentUri={props.documentUri}
44
35
recommendsCount={props.recommendsCount}
···
62
53
<CommentTiny /> {props.commentsCount}
63
54
</SpeedyLink>
64
55
)}
65
65
-
{interactionsAvailable && props.share ? (
66
66
-
<Separator classname="h-4! !min-h-0" />
67
67
-
) : null}
56
56
+
{tagsCount === 0 ? null : (
57
57
+
<>
58
58
+
{interactionsAvailable ? <Separator classname="h-4!" /> : null}
59
59
+
<TagPopover tags={props.tags!} />
60
60
+
</>
61
61
+
)}
68
62
{props.share && (
69
63
<>
64
64
+
<Separator classname="h-4!" />
65
65
+
70
66
<button
71
67
id={`copy-post-link-${props.postUrl}`}
72
68
className="flex gap-1 items-center hover:text-accent-contrast relative"
+3
-1
components/PostListing.tsx
···
89
89
>
90
90
<h3 className="text-primary truncate">{postRecord.title}</h3>
91
91
92
92
-
<p className="text-secondary italic">{postRecord.description}</p>
92
92
+
<p className="text-secondary italic line-clamp-3">
93
93
+
{postRecord.description}
94
94
+
</p>
93
95
<div className="flex flex-col-reverse md:flex-row md gap-2 text-sm text-tertiary items-center justify-start pt-1.5 md:pt-3 w-full">
94
96
{props.publication && pubRecord && (
95
97
<PubInfo
+40
-6
components/RecommendButton.tsx
···
11
11
import { callRPC } from "app/api/rpc/client";
12
12
import { useToaster } from "./Toast";
13
13
import { OAuthErrorMessage, isOAuthSessionError } from "./OAuthError";
14
14
+
import { ButtonSecondary } from "./Buttons";
15
15
+
import { Separator } from "./Layout";
14
16
15
17
// Create a batcher for recommendation checks
16
18
// Batches requests made within 10ms window
17
19
const recommendationBatcher = create({
18
20
fetcher: async (documentUris: string[]) => {
19
19
-
const response = await callRPC("get_user_recommendations", { documentUris });
21
21
+
const response = await callRPC("get_user_recommendations", {
22
22
+
documentUris,
23
23
+
});
20
24
return response.result;
21
25
},
22
26
resolver: (results, documentUri) => results[documentUri] ?? false,
···
52
56
documentUri: string;
53
57
recommendsCount: number;
54
58
className?: string;
55
55
-
showCount?: boolean;
59
59
+
expanded?: boolean;
56
60
}) {
57
57
-
const { hasRecommended, isLoading } = useUserRecommendation(props.documentUri);
61
61
+
const { hasRecommended, isLoading } = useUserRecommendation(
62
62
+
props.documentUri,
63
63
+
);
58
64
const [count, setCount] = useState(props.recommendsCount);
59
65
const [isPending, setIsPending] = useState(false);
60
66
const [optimisticRecommended, setOptimisticRecommended] = useState<
···
101
107
setIsPending(false);
102
108
};
103
109
104
104
-
const showCount = props.showCount !== false;
110
110
+
if (props.expanded)
111
111
+
return (
112
112
+
<ButtonSecondary
113
113
+
onClick={(e) => {
114
114
+
e.preventDefault();
115
115
+
e.stopPropagation();
116
116
+
handleClick();
117
117
+
}}
118
118
+
>
119
119
+
{displayRecommended ? (
120
120
+
<RecommendTinyFilled className="text-accent-contrast" />
121
121
+
) : (
122
122
+
<RecommendTinyEmpty />
123
123
+
)}
124
124
+
<div className="flex gap-2 items-center">
125
125
+
{count > 0 && (
126
126
+
<>
127
127
+
<span
128
128
+
className={`${displayRecommended && "text-accent-contrast"}`}
129
129
+
>
130
130
+
{count}
131
131
+
</span>
132
132
+
<Separator classname="h-4! text-accent-contrast!" />
133
133
+
</>
134
134
+
)}
135
135
+
{displayRecommended ? "You recommend!" : "Recommend"}
136
136
+
</div>
137
137
+
</ButtonSecondary>
138
138
+
);
105
139
106
140
return (
107
141
<button
···
111
145
handleClick();
112
146
}}
113
147
disabled={isPending || isLoading}
114
114
-
className={`recommendButton flex gap-1 items-center hover:text-accent-contrast ${props.className || ""}`}
148
148
+
className={`recommendButton relative flex gap-1 items-center hover:text-accent-contrast ${props.className || ""}`}
115
149
aria-label={displayRecommended ? "Remove recommend" : "Recommend"}
116
150
>
117
151
{displayRecommended ? (
···
119
153
) : (
120
154
<RecommendTinyEmpty />
121
155
)}
122
122
-
{showCount && count > 0 && (
156
156
+
{count > 0 && (
123
157
<span className={`${displayRecommended && "text-accent-contrast"}`}>
124
158
{count}
125
159
</span>