tangled
alpha
login
or
join now
olaren.dev
/
pdsls
forked from
pds.ls/pdsls
0
fork
atom
atmosphere explorer
0
fork
atom
overview
issues
pulls
pipelines
fix rounding
handle.invalid
2 months ago
893336b0
3ee6b8b0
verified
This commit was signed with the committer's
known signature
.
handle.invalid
SSH Key Fingerprint:
SHA256:mBrT4x0JdzLpbVR95g1hjI1aaErfC02kmLRkPXwsYCk=
+182
-173
4 changed files
expand all
collapse all
unified
split
src
auth
account.tsx
components
create
index.tsx
search.tsx
layout.tsx
+1
-1
src/auth/account.tsx
···
196
196
</Modal>
197
197
<button
198
198
onclick={() => setOpenManager(true)}
199
199
-
class={`flex items-center rounded-lg ${agent() && avatars[agent()!.sub] ? "p-1.25" : "p-1.5"} hover:bg-neutral-200 active:bg-neutral-300 dark:hover:bg-neutral-700 dark:active:bg-neutral-600`}
199
199
+
class={`flex items-center rounded-md ${agent() && avatars[agent()!.sub] ? "p-1.25" : "p-1.5"} hover:bg-neutral-200 active:bg-neutral-300 dark:hover:bg-neutral-700 dark:active:bg-neutral-600`}
200
200
>
201
201
{agent() && avatars[agent()!.sub] ?
202
202
<img src={getThumbnailUrl(avatars[agent()!.sub])} class="size-5 rounded-full" />
+2
-2
src/components/create/index.tsx
···
463
463
<button
464
464
class={
465
465
hasPermission() ?
466
466
-
`flex items-center p-1.5 hover:bg-neutral-200 active:bg-neutral-300 dark:hover:bg-neutral-700 dark:active:bg-neutral-600 ${props.create ? "rounded-lg" : "rounded-sm"}`
467
467
-
: `flex items-center p-1.5 opacity-40 ${props.create ? "rounded-lg" : "rounded-sm"}`
466
466
+
`flex items-center p-1.5 hover:bg-neutral-200 active:bg-neutral-300 dark:hover:bg-neutral-700 dark:active:bg-neutral-600 ${props.create ? "rounded-md" : "rounded-sm"}`
467
467
+
: `flex items-center p-1.5 opacity-40 ${props.create ? "rounded-md" : "rounded-sm"}`
468
468
}
469
469
onclick={() => {
470
470
if (hasPermission()) {
+178
-169
src/components/search.tsx
···
66
66
return (
67
67
<button
68
68
onclick={() => setShowSearch(!showSearch())}
69
69
-
class="dark:bg-dark-200 dark:hover:bg-dark-100 mr-1 box-border flex h-7.5 items-center gap-1 rounded-lg border-[0.5px] border-neutral-300 bg-white px-2 text-xs text-neutral-500 hover:bg-neutral-100 active:bg-neutral-200 dark:border-neutral-600 dark:text-neutral-400 dark:active:bg-neutral-700"
69
69
+
class="dark:bg-dark-200 dark:hover:bg-dark-100 mr-1 box-border flex h-7.5 items-center gap-1 rounded-md border-[0.5px] border-neutral-300 bg-white px-2 text-xs text-neutral-500 hover:bg-neutral-100 active:bg-neutral-200 dark:border-neutral-600 dark:text-neutral-400 dark:active:bg-neutral-700"
70
70
>
71
71
<span class="iconify lucide--search"></span>
72
72
<span>Search</span>
···
196
196
};
197
197
198
198
return (
199
199
-
<Modal open={showSearch()} onClose={() => setShowSearch(false)} alignTop contentClass="dark:bg-dark-200 dark:shadow-dark-700 pointer-events-auto mx-3 w-full max-w-lg rounded-lg border-[0.5px] border-neutral-300 bg-white shadow-md dark:border-neutral-700">
200
200
-
<form
201
201
-
class="w-full"
202
202
-
onsubmit={(e) => {
203
203
-
e.preventDefault();
204
204
-
processInput(searchInput.value);
205
205
-
}}
199
199
+
<Modal
200
200
+
open={showSearch()}
201
201
+
onClose={() => setShowSearch(false)}
202
202
+
alignTop
203
203
+
contentClass="dark:bg-dark-200 dark:shadow-dark-700 pointer-events-auto mx-3 w-full max-w-lg rounded-lg border-[0.5px] border-neutral-300 bg-white shadow-md dark:border-neutral-700"
204
204
+
>
205
205
+
<form
206
206
+
class="w-full"
207
207
+
onsubmit={(e) => {
208
208
+
e.preventDefault();
209
209
+
processInput(searchInput.value);
210
210
+
}}
211
211
+
>
212
212
+
<label for="input" class="hidden">
213
213
+
PDS URL, AT URI, NSID, DID, or handle
214
214
+
</label>
215
215
+
<div
216
216
+
class={`flex items-center gap-2 px-2 ${
217
217
+
getPrefixSuggestions().length > 0 || search()?.length ? "rounded-t-lg" : "rounded-lg"
218
218
+
}`}
206
219
>
207
207
-
<label for="input" class="hidden">
208
208
-
PDS URL, AT URI, NSID, DID, or handle
209
209
-
</label>
210
210
-
<div
211
211
-
class={`flex items-center gap-2 px-2 ${
212
212
-
getPrefixSuggestions().length > 0 || search()?.length ? "rounded-t-lg" : "rounded-lg"
213
213
-
}`}
214
214
-
>
215
215
-
<label
216
216
-
for="input"
217
217
-
class="iconify lucide--search text-neutral-500 dark:text-neutral-400"
218
218
-
></label>
219
219
-
<input
220
220
-
type="text"
221
221
-
spellcheck={false}
222
222
-
autocapitalize="off"
223
223
-
placeholder="Handle, DID, AT URI, NSID, PDS"
224
224
-
ref={searchInput}
225
225
-
id="input"
226
226
-
class="grow py-2.5 select-none placeholder:text-sm focus:outline-none"
227
227
-
value={input() ?? ""}
228
228
-
onInput={(e) => {
229
229
-
setInput(e.currentTarget.value);
230
230
-
setSelectedIndex(-1);
231
231
-
}}
232
232
-
onBlur={() => setSelectedIndex(-1)}
233
233
-
onKeyDown={(e) => {
234
234
-
const results = search();
235
235
-
const prefixSuggestions = getPrefixSuggestions();
236
236
-
const totalSuggestions = (prefixSuggestions.length || 0) + (results?.length || 0);
220
220
+
<label
221
221
+
for="input"
222
222
+
class="iconify lucide--search text-neutral-500 dark:text-neutral-400"
223
223
+
></label>
224
224
+
<input
225
225
+
type="text"
226
226
+
spellcheck={false}
227
227
+
autocapitalize="off"
228
228
+
placeholder="Handle, DID, AT URI, NSID, PDS"
229
229
+
ref={searchInput}
230
230
+
id="input"
231
231
+
class="grow py-2.5 select-none placeholder:text-sm focus:outline-none"
232
232
+
value={input() ?? ""}
233
233
+
onInput={(e) => {
234
234
+
setInput(e.currentTarget.value);
235
235
+
setSelectedIndex(-1);
236
236
+
}}
237
237
+
onBlur={() => setSelectedIndex(-1)}
238
238
+
onKeyDown={(e) => {
239
239
+
const results = search();
240
240
+
const prefixSuggestions = getPrefixSuggestions();
241
241
+
const totalSuggestions = (prefixSuggestions.length || 0) + (results?.length || 0);
237
242
238
238
-
if (!totalSuggestions) return;
243
243
+
if (!totalSuggestions) return;
239
244
240
240
-
if (e.key === "ArrowDown") {
241
241
-
e.preventDefault();
242
242
-
setSelectedIndex((prev) => (prev === -1 ? 0 : (prev + 1) % totalSuggestions));
243
243
-
} else if (e.key === "ArrowUp") {
245
245
+
if (e.key === "ArrowDown") {
246
246
+
e.preventDefault();
247
247
+
setSelectedIndex((prev) => (prev === -1 ? 0 : (prev + 1) % totalSuggestions));
248
248
+
} else if (e.key === "ArrowUp") {
249
249
+
e.preventDefault();
250
250
+
setSelectedIndex((prev) =>
251
251
+
prev === -1 ?
252
252
+
totalSuggestions - 1
253
253
+
: (prev - 1 + totalSuggestions) % totalSuggestions,
254
254
+
);
255
255
+
} else if (e.key === "Enter") {
256
256
+
const index = selectedIndex();
257
257
+
if (index >= 0) {
244
258
e.preventDefault();
245
245
-
setSelectedIndex((prev) =>
246
246
-
prev === -1 ?
247
247
-
totalSuggestions - 1
248
248
-
: (prev - 1 + totalSuggestions) % totalSuggestions,
249
249
-
);
250
250
-
} else if (e.key === "Enter") {
251
251
-
const index = selectedIndex();
252
252
-
if (index >= 0) {
253
253
-
e.preventDefault();
254
254
-
if (index < prefixSuggestions.length) {
255
255
-
const selectedPrefix = prefixSuggestions[index];
256
256
-
setInput(selectedPrefix.prefix);
257
257
-
setSelectedIndex(-1);
258
258
-
searchInput.focus();
259
259
-
} else {
260
260
-
const adjustedIndex = index - prefixSuggestions.length;
261
261
-
if (results && results[adjustedIndex]) {
262
262
-
setShowSearch(false);
263
263
-
navigate(`/at://${results[adjustedIndex].did}`);
264
264
-
}
259
259
+
if (index < prefixSuggestions.length) {
260
260
+
const selectedPrefix = prefixSuggestions[index];
261
261
+
setInput(selectedPrefix.prefix);
262
262
+
setSelectedIndex(-1);
263
263
+
searchInput.focus();
264
264
+
} else {
265
265
+
const adjustedIndex = index - prefixSuggestions.length;
266
266
+
if (results && results[adjustedIndex]) {
267
267
+
setShowSearch(false);
268
268
+
navigate(`/at://${results[adjustedIndex].did}`);
265
269
}
266
266
-
} else if (results?.length && prefixSuggestions.length === 0) {
267
267
-
e.preventDefault();
268
268
-
setShowSearch(false);
269
269
-
navigate(`/at://${results[0].did}`);
270
270
}
271
271
+
} else if (results?.length && prefixSuggestions.length === 0) {
272
272
+
e.preventDefault();
273
273
+
setShowSearch(false);
274
274
+
navigate(`/at://${results[0].did}`);
271
275
}
272
272
-
}}
273
273
-
/>
274
274
-
<Show when={input()} fallback={ListUrlsTooltip()}>
275
275
-
<button
276
276
-
type="button"
277
277
-
class="dark:hover:bg-dark-100 flex items-center rounded-md p-1 hover:bg-neutral-100 active:bg-neutral-200 dark:active:bg-neutral-700"
278
278
-
onClick={() => setInput(undefined)}
279
279
-
>
280
280
-
<span class="iconify lucide--x"></span>
281
281
-
</button>
282
282
-
</Show>
283
283
-
</div>
276
276
+
}
277
277
+
}}
278
278
+
/>
279
279
+
<Show when={input()} fallback={ListUrlsTooltip()}>
280
280
+
<button
281
281
+
type="button"
282
282
+
class="dark:hover:bg-dark-100 flex items-center rounded-md p-1 hover:bg-neutral-100 active:bg-neutral-200 dark:active:bg-neutral-700"
283
283
+
onClick={() => setInput(undefined)}
284
284
+
>
285
285
+
<span class="iconify lucide--x"></span>
286
286
+
</button>
287
287
+
</Show>
288
288
+
</div>
289
289
+
290
290
+
<Show when={getPrefixSuggestions().length > 0 || (input() && search()?.length)}>
291
291
+
<div
292
292
+
class="flex w-full flex-col border-t border-neutral-200 p-2 dark:border-neutral-700"
293
293
+
onMouseDown={(e) => e.preventDefault()}
294
294
+
>
295
295
+
{/* Prefix suggestions */}
296
296
+
<For each={getPrefixSuggestions()}>
297
297
+
{(prefixItem, index) => (
298
298
+
<button
299
299
+
type="button"
300
300
+
class={`flex items-center rounded-md p-2 ${
301
301
+
index() === selectedIndex() ?
302
302
+
"bg-neutral-200 dark:bg-neutral-700"
303
303
+
: "dark:hover:bg-dark-100 hover:bg-neutral-100 active:bg-neutral-200 dark:active:bg-neutral-700"
304
304
+
}`}
305
305
+
onClick={() => {
306
306
+
setInput(prefixItem.prefix);
307
307
+
setSelectedIndex(-1);
308
308
+
searchInput.focus();
309
309
+
}}
310
310
+
>
311
311
+
<span class={`text-sm font-semibold`}>{prefixItem.prefix}</span>
312
312
+
<span class="text-sm text-neutral-600 dark:text-neutral-400">
313
313
+
{prefixItem.description}
314
314
+
</span>
315
315
+
</button>
316
316
+
)}
317
317
+
</For>
284
318
285
285
-
<Show when={getPrefixSuggestions().length > 0 || (input() && search()?.length)}>
286
286
-
<div
287
287
-
class="flex w-full flex-col border-t border-neutral-200 p-2 dark:border-neutral-700"
288
288
-
onMouseDown={(e) => e.preventDefault()}
289
289
-
>
290
290
-
{/* Prefix suggestions */}
291
291
-
<For each={getPrefixSuggestions()}>
292
292
-
{(prefixItem, index) => (
293
293
-
<button
294
294
-
type="button"
295
295
-
class={`flex items-center rounded-md p-2 ${
296
296
-
index() === selectedIndex() ?
319
319
+
{/* Typeahead results */}
320
320
+
<For each={search()}>
321
321
+
{(actor, index) => {
322
322
+
const adjustedIndex = getPrefixSuggestions().length + index();
323
323
+
return (
324
324
+
<A
325
325
+
class={`flex items-center gap-2 rounded-md p-2 ${
326
326
+
adjustedIndex === selectedIndex() ?
297
327
"bg-neutral-200 dark:bg-neutral-700"
298
328
: "dark:hover:bg-dark-100 hover:bg-neutral-100 active:bg-neutral-200 dark:active:bg-neutral-700"
299
329
}`}
300
300
-
onClick={() => {
301
301
-
setInput(prefixItem.prefix);
302
302
-
setSelectedIndex(-1);
303
303
-
searchInput.focus();
304
304
-
}}
330
330
+
href={`/at://${actor.did}`}
331
331
+
onClick={() => setShowSearch(false)}
305
332
>
306
306
-
<span class={`text-sm font-semibold`}>{prefixItem.prefix}</span>
307
307
-
<span class="text-sm text-neutral-600 dark:text-neutral-400">
308
308
-
{prefixItem.description}
309
309
-
</span>
310
310
-
</button>
311
311
-
)}
312
312
-
</For>
313
313
-
314
314
-
{/* Typeahead results */}
315
315
-
<For each={search()}>
316
316
-
{(actor, index) => {
317
317
-
const adjustedIndex = getPrefixSuggestions().length + index();
318
318
-
return (
319
319
-
<A
320
320
-
class={`flex items-center gap-2 rounded-md p-2 ${
321
321
-
adjustedIndex === selectedIndex() ?
322
322
-
"bg-neutral-200 dark:bg-neutral-700"
323
323
-
: "dark:hover:bg-dark-100 hover:bg-neutral-100 active:bg-neutral-200 dark:active:bg-neutral-700"
324
324
-
}`}
325
325
-
href={`/at://${actor.did}`}
326
326
-
onClick={() => setShowSearch(false)}
327
327
-
>
328
328
-
<img
329
329
-
src={actor.avatar?.replace("img/avatar/", "img/avatar_thumbnail/")}
330
330
-
class="size-9 rounded-full"
331
331
-
/>
332
332
-
<div class="flex min-w-0 flex-col">
333
333
-
<Show when={actor.displayName}>
334
334
-
<span class="truncate text-sm font-medium">{actor.displayName}</span>
335
335
-
</Show>
336
336
-
<span class="truncate text-xs text-neutral-600 dark:text-neutral-400">
337
337
-
@{actor.handle}
338
338
-
</span>
339
339
-
</div>
340
340
-
</A>
341
341
-
);
342
342
-
}}
343
343
-
</For>
344
344
-
</div>
345
345
-
</Show>
346
346
-
</form>
333
333
+
<img
334
334
+
src={actor.avatar?.replace("img/avatar/", "img/avatar_thumbnail/")}
335
335
+
class="size-9 rounded-full"
336
336
+
/>
337
337
+
<div class="flex min-w-0 flex-col">
338
338
+
<Show when={actor.displayName}>
339
339
+
<span class="truncate text-sm font-medium">{actor.displayName}</span>
340
340
+
</Show>
341
341
+
<span class="truncate text-xs text-neutral-600 dark:text-neutral-400">
342
342
+
@{actor.handle}
343
343
+
</span>
344
344
+
</div>
345
345
+
</A>
346
346
+
);
347
347
+
}}
348
348
+
</For>
349
349
+
</div>
350
350
+
</Show>
351
351
+
</form>
347
352
</Modal>
348
353
);
349
354
};
···
359
364
360
365
return (
361
366
<>
362
362
-
<Modal open={openList()} onClose={() => setOpenList(false)} alignTop contentClass="dark:bg-dark-300 dark:shadow-dark-700 pointer-events-auto w-88 rounded-lg border-[0.5px] border-neutral-300 bg-neutral-50 p-4 shadow-md sm:w-104 dark:border-neutral-700">
363
363
-
<div class="mb-2 flex items-center gap-1 font-semibold">
364
364
-
<span class="iconify lucide--link"></span>
365
365
-
<span>Supported URLs</span>
366
366
-
</div>
367
367
-
<div class="mb-2 text-sm text-neutral-600 dark:text-neutral-400">
368
368
-
Links that will be parsed automatically, as long as all the data necessary is on the
369
369
-
URL.
370
370
-
</div>
371
371
-
<div class="flex flex-col gap-2 text-sm">
372
372
-
<For each={Object.entries(appName)}>
373
373
-
{([appView, name]) => {
374
374
-
return (
375
375
-
<div>
376
376
-
<p class="font-semibold">{name}</p>
377
377
-
<div class="grid grid-cols-2 gap-x-4 text-neutral-600 dark:text-neutral-400">
378
378
-
<For each={urls[appView]}>
379
379
-
{(url) => (
380
380
-
<a
381
381
-
href={`${url.startsWith("localhost:") ? "http://" : "https://"}${url}`}
382
382
-
target="_blank"
383
383
-
class="hover:underline active:underline"
384
384
-
>
385
385
-
{url}
386
386
-
</a>
387
387
-
)}
388
388
-
</For>
389
389
-
</div>
367
367
+
<Modal
368
368
+
open={openList()}
369
369
+
onClose={() => setOpenList(false)}
370
370
+
alignTop
371
371
+
contentClass="dark:bg-dark-300 dark:shadow-dark-700 pointer-events-auto w-88 rounded-lg border-[0.5px] border-neutral-300 bg-neutral-50 p-4 shadow-md sm:w-104 dark:border-neutral-700"
372
372
+
>
373
373
+
<div class="mb-2 flex items-center gap-1 font-semibold">
374
374
+
<span class="iconify lucide--link"></span>
375
375
+
<span>Supported URLs</span>
376
376
+
</div>
377
377
+
<div class="mb-2 text-sm text-neutral-600 dark:text-neutral-400">
378
378
+
Links that will be parsed automatically, as long as all the data necessary is on the URL.
379
379
+
</div>
380
380
+
<div class="flex flex-col gap-2 text-sm">
381
381
+
<For each={Object.entries(appName)}>
382
382
+
{([appView, name]) => {
383
383
+
return (
384
384
+
<div>
385
385
+
<p class="font-semibold">{name}</p>
386
386
+
<div class="grid grid-cols-2 gap-x-4 text-neutral-600 dark:text-neutral-400">
387
387
+
<For each={urls[appView]}>
388
388
+
{(url) => (
389
389
+
<a
390
390
+
href={`${url.startsWith("localhost:") ? "http://" : "https://"}${url}`}
391
391
+
target="_blank"
392
392
+
class="hover:underline active:underline"
393
393
+
>
394
394
+
{url}
395
395
+
</a>
396
396
+
)}
397
397
+
</For>
390
398
</div>
391
391
-
);
392
392
-
}}
393
393
-
</For>
394
394
-
</div>
399
399
+
</div>
400
400
+
);
401
401
+
}}
402
402
+
</For>
403
403
+
</div>
395
404
</Modal>
396
405
<button
397
406
type="button"
+1
-1
src/layout.tsx
···
156
156
</Show>
157
157
<AccountManager />
158
158
<MenuProvider>
159
159
-
<DropdownMenu icon="lucide--menu text-lg" buttonClass="rounded-lg p-1.5">
159
159
+
<DropdownMenu icon="lucide--menu text-lg" buttonClass="rounded-md p-1.5">
160
160
<NavMenu href="/jetstream" label="Jetstream" icon="lucide--radio-tower" />
161
161
<NavMenu href="/firehose" label="Firehose" icon="lucide--rss" />
162
162
<NavMenu href="/spacedust" label="Spacedust" icon="lucide--orbit" />