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
fix placeholder and positioning for bsky mention popover
awarm.space
3 months ago
6ba8aeaa
6f65facb
+85
-70
2 changed files
expand all
collapse all
unified
split
app
[leaflet_id]
publish
BskyPostEditorProsemirror.tsx
components
Mention.tsx
+18
-4
app/[leaflet_id]/publish/BskyPostEditorProsemirror.tsx
···
148
148
const pos = view.state.selection.from;
149
149
setMentionInsertPos(pos);
150
150
const coords = view.coordsAtPos(pos - 1);
151
151
-
setMentionCoords({
152
152
-
top: coords.bottom + window.scrollY,
153
153
-
left: coords.left + window.scrollX,
154
154
-
});
151
151
+
152
152
+
// Get coordinates relative to the positioned parent container
153
153
+
const editorEl = view.dom;
154
154
+
const container = editorEl.closest(".relative") as HTMLElement | null;
155
155
+
156
156
+
if (container) {
157
157
+
const containerRect = container.getBoundingClientRect();
158
158
+
setMentionCoords({
159
159
+
top: coords.bottom - containerRect.top,
160
160
+
left: coords.left - containerRect.left,
161
161
+
});
162
162
+
} else {
163
163
+
setMentionCoords({
164
164
+
top: coords.bottom,
165
165
+
left: coords.left,
166
166
+
});
167
167
+
}
155
168
setMentionOpen(true);
156
169
}, []);
157
170
···
270
283
view={viewRef}
271
284
onSelect={handleMentionSelect}
272
285
coords={mentionCoords}
286
286
+
placeholder="Search people..."
273
287
/>
274
288
{editorState?.doc.textContent.length === 0 && (
275
289
<div className="italic text-tertiary absolute top-0 left-0 pointer-events-none">
+67
-66
components/Mention.tsx
···
18
18
view: React.RefObject<EditorView | null>;
19
19
onSelect: (mention: Mention) => void;
20
20
coords: { top: number; left: number } | null;
21
21
+
placeholder?: string;
21
22
}) {
22
23
const [searchQuery, setSearchQuery] = useState("");
23
24
const [noResults, setNoResults] = useState(false);
···
207
208
placeholder={
208
209
scope.type === "publication"
209
210
? "Search posts..."
210
210
-
: "Search people & publications..."
211
211
+
: props.placeholder ?? "Search people & publications..."
211
212
}
212
213
className="flex-1 w-full min-w-0 bg-transparent border-none outline-none text-sm placeholder:text-tertiary"
213
214
/>
···
219
220
No results found
220
221
</div>
221
222
)}
222
222
-
<ul className="list-none p-0 text-sm flex flex-col group-data-[side=top]/mention-menu:flex-col-reverse">
223
223
-
{sortedSuggestions.map((result, index) => {
224
224
-
const prevResult = sortedSuggestions[index - 1];
225
225
-
const showHeader =
226
226
-
index === 0 ||
227
227
-
(prevResult && prevResult.type !== result.type);
223
223
+
<ul className="list-none p-0 text-sm flex flex-col group-data-[side=top]/mention-menu:flex-col-reverse">
224
224
+
{sortedSuggestions.map((result, index) => {
225
225
+
const prevResult = sortedSuggestions[index - 1];
226
226
+
const showHeader =
227
227
+
index === 0 ||
228
228
+
(prevResult && prevResult.type !== result.type);
228
229
229
229
-
return (
230
230
-
<Fragment
231
231
-
key={result.type === "did" ? result.did : result.uri}
232
232
-
>
233
233
-
{showHeader && (
234
234
-
<>
235
235
-
{index > 0 && (
236
236
-
<hr className="border-border-light mx-1 my-1" />
237
237
-
)}
238
238
-
<div className="text-xs text-tertiary font-bold pt-1 px-2">
239
239
-
{getHeader(result.type, scope)}
240
240
-
</div>
241
241
-
</>
242
242
-
)}
243
243
-
{result.type === "did" ? (
244
244
-
<DidResult
245
245
-
onClick={() => {
246
246
-
props.onSelect(result);
247
247
-
props.onOpenChange(false);
248
248
-
}}
249
249
-
onMouseDown={(e) => e.preventDefault()}
250
250
-
displayName={result.displayName}
251
251
-
handle={result.handle}
252
252
-
avatar={result.avatar}
253
253
-
selected={index === suggestionIndex}
254
254
-
/>
255
255
-
) : result.type === "publication" ? (
256
256
-
<PublicationResult
257
257
-
onClick={() => {
258
258
-
props.onSelect(result);
259
259
-
props.onOpenChange(false);
260
260
-
}}
261
261
-
onMouseDown={(e) => e.preventDefault()}
262
262
-
pubName={result.name}
263
263
-
uri={result.uri}
264
264
-
selected={index === suggestionIndex}
265
265
-
onPostsClick={() => {
266
266
-
handleScopeChange({
267
267
-
type: "publication",
268
268
-
uri: result.uri,
269
269
-
name: result.name,
270
270
-
});
271
271
-
}}
272
272
-
/>
273
273
-
) : (
274
274
-
<PostResult
275
275
-
onClick={() => {
276
276
-
props.onSelect(result);
277
277
-
props.onOpenChange(false);
278
278
-
}}
279
279
-
onMouseDown={(e) => e.preventDefault()}
280
280
-
title={result.title}
281
281
-
selected={index === suggestionIndex}
282
282
-
/>
283
283
-
)}
284
284
-
</Fragment>
285
285
-
);
286
286
-
})}
287
287
-
</ul>
230
230
+
return (
231
231
+
<Fragment
232
232
+
key={result.type === "did" ? result.did : result.uri}
233
233
+
>
234
234
+
{showHeader && (
235
235
+
<>
236
236
+
{index > 0 && (
237
237
+
<hr className="border-border-light mx-1 my-1" />
238
238
+
)}
239
239
+
<div className="text-xs text-tertiary font-bold pt-1 px-2">
240
240
+
{getHeader(result.type, scope)}
241
241
+
</div>
242
242
+
</>
243
243
+
)}
244
244
+
{result.type === "did" ? (
245
245
+
<DidResult
246
246
+
onClick={() => {
247
247
+
props.onSelect(result);
248
248
+
props.onOpenChange(false);
249
249
+
}}
250
250
+
onMouseDown={(e) => e.preventDefault()}
251
251
+
displayName={result.displayName}
252
252
+
handle={result.handle}
253
253
+
avatar={result.avatar}
254
254
+
selected={index === suggestionIndex}
255
255
+
/>
256
256
+
) : result.type === "publication" ? (
257
257
+
<PublicationResult
258
258
+
onClick={() => {
259
259
+
props.onSelect(result);
260
260
+
props.onOpenChange(false);
261
261
+
}}
262
262
+
onMouseDown={(e) => e.preventDefault()}
263
263
+
pubName={result.name}
264
264
+
uri={result.uri}
265
265
+
selected={index === suggestionIndex}
266
266
+
onPostsClick={() => {
267
267
+
handleScopeChange({
268
268
+
type: "publication",
269
269
+
uri: result.uri,
270
270
+
name: result.name,
271
271
+
});
272
272
+
}}
273
273
+
/>
274
274
+
) : (
275
275
+
<PostResult
276
276
+
onClick={() => {
277
277
+
props.onSelect(result);
278
278
+
props.onOpenChange(false);
279
279
+
}}
280
280
+
onMouseDown={(e) => e.preventDefault()}
281
281
+
title={result.title}
282
282
+
selected={index === suggestionIndex}
283
283
+
/>
284
284
+
)}
285
285
+
</Fragment>
286
286
+
);
287
287
+
})}
288
288
+
</ul>
288
289
</div>
289
290
</Popover.Content>
290
291
</Popover.Portal>