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