+2
-1
src/components/account.tsx
+2
-1
src/components/account.tsx
···
14
14
import { agent, Login, retrieveSession, Sessions, setAgent } from "./login.jsx";
15
15
import { Modal } from "./modal.jsx";
16
16
17
+
export const [sessions, setSessions] = createStore<Sessions>();
18
+
17
19
export const AccountManager = () => {
18
20
const [openManager, setOpenManager] = createSignal(false);
19
-
const [sessions, setSessions] = createStore<Sessions>();
20
21
const [avatars, setAvatars] = createStore<Record<Did, string>>();
21
22
22
23
onMount(async () => {
+69
-47
src/components/create.tsx
+69
-47
src/components/create.tsx
···
1
1
import { Client } from "@atcute/client";
2
+
import { Did } from "@atcute/lexicons";
3
+
import { getSession, OAuthUserAgent } from "@atcute/oauth-browser-client";
2
4
import { remove } from "@mary/exif-rm";
3
5
import { useNavigate, useParams } from "@solidjs/router";
4
-
import { createSignal, onCleanup, onMount, Show } from "solid-js";
6
+
import { createSignal, For, onCleanup, onMount, Show } from "solid-js";
5
7
import { Editor, editorView } from "../components/editor.jsx";
6
8
import { agent } from "../components/login.jsx";
7
9
import { setNotif } from "../layout.jsx";
10
+
import { sessions } from "./account.jsx";
8
11
import { Button } from "./button.jsx";
9
12
import { Modal } from "./modal.jsx";
10
13
import { TextInput } from "./text-input.jsx";
···
18
21
const [openDialog, setOpenDialog] = createSignal(false);
19
22
const [notice, setNotice] = createSignal("");
20
23
const [openUpload, setOpenUpload] = createSignal(false);
24
+
const [validate, setValidate] = createSignal<boolean | undefined>(undefined);
21
25
let blobInput!: HTMLInputElement;
22
26
let formRef!: HTMLFormElement;
23
27
···
36
40
langs: ["en"],
37
41
createdAt: new Date().toISOString(),
38
42
};
43
+
};
44
+
45
+
const getValidateIcon = () => {
46
+
return (
47
+
validate() === true ? "lucide--circle-check"
48
+
: validate() === false ? "lucide--circle-x"
49
+
: "lucide--circle"
50
+
);
51
+
};
52
+
53
+
const getValidateLabel = () => {
54
+
return (
55
+
validate() === true ? "True"
56
+
: validate() === false ? "False"
57
+
: "Unset"
58
+
);
39
59
};
40
60
41
61
const createRecord = async (formData: FormData) => {
42
-
const rpc = new Client({ handler: agent()! });
62
+
const repo = formData.get("repo")?.toString();
63
+
if (!repo) return;
64
+
const rpc = new Client({ handler: new OAuthUserAgent(await getSession(repo as Did)) });
43
65
const collection = formData.get("collection");
44
66
const rkey = formData.get("rkey");
45
-
const validate = formData.get("validate")?.toString();
46
67
let record: any;
47
68
try {
48
69
record = JSON.parse(editorView.state.doc.toString());
···
52
73
}
53
74
const res = await rpc.post("com.atproto.repo.createRecord", {
54
75
input: {
55
-
repo: agent()!.sub,
76
+
repo: repo as Did,
56
77
collection: collection ? collection.toString() : record.$type,
57
78
rkey: rkey?.toString().length ? rkey?.toString() : undefined,
58
79
record: record,
59
-
validate:
60
-
validate === "true" ? true
61
-
: validate === "false" ? false
62
-
: undefined,
80
+
validate: validate(),
63
81
},
64
82
});
65
83
if (!res.ok) {
···
71
89
navigate(`/${res.data.uri}`);
72
90
};
73
91
74
-
const editRecord = async (formData: FormData, recreate?: boolean) => {
92
+
const editRecord = async (recreate?: boolean) => {
75
93
const record = editorView.state.doc.toString();
76
-
const validate =
77
-
formData.get("validate")?.toString() === "true" ? true
78
-
: formData.get("validate")?.toString() === "false" ? false
79
-
: undefined;
80
94
if (!record) return;
81
95
const rpc = new Client({ handler: agent()! });
82
96
try {
···
85
99
const res = await rpc.post("com.atproto.repo.applyWrites", {
86
100
input: {
87
101
repo: agent()!.sub,
88
-
validate: validate,
102
+
validate: validate(),
89
103
writes: [
90
104
{
91
105
collection: params.collection as `${string}.${string}.${string}`,
···
112
126
collection: params.collection as `${string}.${string}.${string}`,
113
127
rkey: params.rkey,
114
128
record: editedRecord,
115
-
validate: validate,
129
+
validate: validate(),
116
130
},
117
131
});
118
132
if (!res.ok) {
···
326
340
</div>
327
341
<form ref={formRef} class="flex flex-col gap-y-2">
328
342
<div class="flex w-fit flex-col gap-y-1 text-sm">
329
-
<Show when={props.create}>
330
-
<div class="flex items-center gap-x-2">
331
-
<label for="collection" class="min-w-20 select-none">
332
-
Collection
333
-
</label>
343
+
<div class="flex flex-wrap items-center gap-1">
344
+
<Show when={props.create}>
345
+
<span>at://</span>
346
+
<select
347
+
class="dark:bg-dark-100 dark:shadow-dark-700 max-w-[10rem] truncate rounded-lg border-[0.5px] border-neutral-300 bg-white px-1 py-1 shadow-xs select-none focus:outline-[1px] focus:outline-neutral-600 dark:border-neutral-600 dark:focus:outline-neutral-400"
348
+
name="repo"
349
+
id="repo"
350
+
>
351
+
<For each={Object.keys(sessions)}>
352
+
{(session) => (
353
+
<option value={session} selected={session === agent()?.sub}>
354
+
{sessions[session].handle ?? session}
355
+
</option>
356
+
)}
357
+
</For>
358
+
</select>
359
+
<span>/</span>
334
360
<TextInput
335
361
id="collection"
336
362
name="collection"
337
363
placeholder="Optional (default: $type)"
338
-
class="w-[15rem]"
364
+
class="w-[10rem] placeholder:text-xs lg:w-[13rem]"
339
365
/>
340
-
</div>
341
-
<div class="flex items-center gap-x-2">
342
-
<label for="rkey" class="min-w-20 select-none">
343
-
Record key
344
-
</label>
366
+
<span>/</span>
345
367
<TextInput
346
368
id="rkey"
347
369
name="rkey"
348
370
placeholder="Optional (default: TID)"
349
-
class="w-[15rem]"
371
+
class="w-[10rem] placeholder:text-xs lg:w-[13rem]"
350
372
/>
351
-
</div>
352
-
</Show>
353
-
<div class="flex items-center gap-x-2">
354
-
<label for="validate" class="min-w-20 select-none">
355
-
Validate
356
-
</label>
357
-
<select
358
-
name="validate"
359
-
id="validate"
360
-
class="dark:bg-dark-100 dark:shadow-dark-700 rounded-lg border-[0.5px] border-neutral-300 bg-white px-1 py-1 shadow-xs select-none focus:outline-[1px] focus:outline-neutral-600 dark:border-neutral-600 dark:focus:outline-neutral-400"
373
+
</Show>
374
+
</div>
375
+
<div class="flex items-center gap-1">
376
+
<button
377
+
type="button"
378
+
class="flex items-center gap-1 rounded-sm p-1 hover:bg-neutral-200 active:bg-neutral-300 dark:hover:bg-neutral-700 dark:active:bg-neutral-600"
379
+
onClick={() =>
380
+
setValidate(
381
+
validate() === true ? false
382
+
: validate() === false ? undefined
383
+
: true,
384
+
)
385
+
}
361
386
>
362
-
<option value="unset">Unset</option>
363
-
<option value="true">True</option>
364
-
<option value="false">False</option>
365
-
</select>
387
+
<Tooltip text={getValidateLabel()}>
388
+
<span class={`iconify text-base ${getValidateIcon()}`}></span>
389
+
</Tooltip>
390
+
<span>Validate</span>
391
+
</button>
366
392
</div>
367
393
</div>
368
394
<Editor
···
406
432
</Modal>
407
433
<div class="flex items-center justify-end gap-2">
408
434
<Show when={!props.create}>
409
-
<Button onClick={() => editRecord(new FormData(formRef), true)}>
410
-
Recreate
411
-
</Button>
435
+
<Button onClick={() => editRecord(true)}>Recreate</Button>
412
436
</Show>
413
437
<Button
414
438
onClick={() =>
415
-
props.create ?
416
-
createRecord(new FormData(formRef))
417
-
: editRecord(new FormData(formRef))
439
+
props.create ? createRecord(new FormData(formRef)) : editRecord()
418
440
}
419
441
>
420
442
{props.create ? "Create" : "Edit"}