+92
-7
src/components/create.tsx
+92
-7
src/components/create.tsx
···
1
1
import { Client } from "@atcute/client";
2
2
import { remove } from "@mary/exif-rm";
3
3
import { useNavigate, useParams } from "@solidjs/router";
4
-
import { createSignal, onCleanup, Show } from "solid-js";
4
+
import { createSignal, onCleanup, onMount, Show } from "solid-js";
5
5
import { Editor, editorView } from "../components/editor.jsx";
6
6
import { agent } from "../components/login.jsx";
7
7
import { setNotif } from "../layout.jsx";
···
128
128
}
129
129
};
130
130
131
+
const dragDiv = (box: HTMLDivElement) => {
132
+
let currentBox: HTMLDivElement | null = null;
133
+
let isDragging = false;
134
+
let offsetX: number;
135
+
let offsetY: number;
136
+
137
+
const handleMouseDown = (e: MouseEvent) => {
138
+
if (!(e.target instanceof HTMLElement)) return;
139
+
140
+
const closestDraggable = e.target.closest("[data-draggable]") as HTMLElement;
141
+
if (closestDraggable && closestDraggable !== box) return;
142
+
143
+
if (
144
+
["INPUT", "SELECT", "BUTTON", "LABEL"].includes(e.target.tagName) ||
145
+
e.target.closest("#editor")
146
+
)
147
+
return;
148
+
149
+
e.preventDefault();
150
+
isDragging = true;
151
+
box.classList.add("cursor-grabbing");
152
+
currentBox = box;
153
+
154
+
const rect = box.getBoundingClientRect();
155
+
156
+
box.style.left = rect.left + "px";
157
+
box.style.top = rect.top + "px";
158
+
159
+
box.classList.remove("-translate-x-1/2");
160
+
161
+
offsetX = e.clientX - rect.left;
162
+
offsetY = e.clientY - rect.top;
163
+
};
164
+
165
+
const handleMouseMove = (e: MouseEvent) => {
166
+
if (isDragging && box === currentBox) {
167
+
let newLeft = e.clientX - offsetX;
168
+
let newTop = e.clientY - offsetY;
169
+
170
+
const boxWidth = box.offsetWidth;
171
+
const boxHeight = box.offsetHeight;
172
+
173
+
const viewportWidth = window.innerWidth;
174
+
const viewportHeight = window.innerHeight;
175
+
176
+
newLeft = Math.max(0, Math.min(newLeft, viewportWidth - boxWidth));
177
+
newTop = Math.max(0, Math.min(newTop, viewportHeight - boxHeight));
178
+
179
+
box.style.left = newLeft + "px";
180
+
box.style.top = newTop + "px";
181
+
}
182
+
};
183
+
184
+
const handleMouseUp = () => {
185
+
if (isDragging && box === currentBox) {
186
+
isDragging = false;
187
+
box.classList.remove("cursor-grabbing");
188
+
currentBox = null;
189
+
}
190
+
};
191
+
192
+
onMount(() => {
193
+
box.addEventListener("mousedown", handleMouseDown);
194
+
document.addEventListener("mousemove", handleMouseMove);
195
+
document.addEventListener("mouseup", handleMouseUp);
196
+
});
197
+
198
+
onCleanup(() => {
199
+
box.removeEventListener("mousedown", handleMouseDown);
200
+
document.removeEventListener("mousemove", handleMouseMove);
201
+
document.removeEventListener("mouseup", handleMouseUp);
202
+
});
203
+
};
204
+
131
205
const FileUpload = (props: { file: File }) => {
132
206
const [uploading, setUploading] = createSignal(false);
133
207
const [error, setError] = createSignal("");
···
175
249
};
176
250
177
251
return (
178
-
<div class="dark:bg-dark-300 dark:shadow-dark-700 absolute top-70 left-[50%] w-[20rem] -translate-x-1/2 rounded-lg border-[0.5px] border-neutral-300 bg-neutral-50 p-4 shadow-md transition-opacity duration-200 dark:border-neutral-700 starting:opacity-0">
252
+
<div
253
+
data-draggable
254
+
class="dark:bg-dark-300 dark:shadow-dark-700 absolute top-70 left-[50%] w-[20rem] -translate-x-1/2 rounded-lg border-[0.5px] border-neutral-300 bg-neutral-50 p-4 shadow-md transition-opacity duration-200 dark:border-neutral-700 starting:opacity-0"
255
+
ref={dragDiv}
256
+
>
179
257
<h2 class="mb-2 font-semibold">Upload blob</h2>
180
258
<div class="flex flex-col gap-2 text-sm">
181
259
<div class="flex flex-col gap-1">
···
229
307
return (
230
308
<>
231
309
<Modal open={openDialog()} onClose={() => setOpenDialog(false)} closeOnClick={false}>
232
-
<div class="dark:bg-dark-300 dark:shadow-dark-700 absolute top-16 left-[50%] w-screen -translate-x-1/2 rounded-lg border-[0.5px] border-neutral-300 bg-neutral-50 p-4 shadow-md transition-opacity duration-200 sm:w-xl lg:w-[48rem] dark:border-neutral-700 starting:opacity-0">
310
+
<div
311
+
data-draggable
312
+
class="dark:bg-dark-300 dark:shadow-dark-700 absolute top-16 left-[50%] w-screen -translate-x-1/2 cursor-grab rounded-lg border-[0.5px] border-neutral-300 bg-neutral-50 p-4 shadow-md transition-opacity duration-200 sm:w-xl lg:w-[48rem] dark:border-neutral-700 starting:opacity-0"
313
+
ref={dragDiv}
314
+
>
233
315
<div class="mb-2 flex w-full justify-between">
234
316
<div class="font-semibold">
235
-
<span>{props.create ? "Creating" : "Editing"} record</span>
317
+
<span class="select-none">{props.create ? "Creating" : "Editing"} record</span>
236
318
</div>
237
319
<button
238
320
onclick={() => setOpenDialog(false)}
···
274
356
<select
275
357
name="validate"
276
358
id="validate"
277
-
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 focus:outline-[1px] focus:outline-neutral-600 dark:border-neutral-600 dark:focus:outline-neutral-400"
359
+
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"
278
360
>
279
361
<option value="unset">Unset</option>
280
362
<option value="true">True</option>
···
296
378
<div class="text-sm text-red-500 dark:text-red-400">{notice()}</div>
297
379
</Show>
298
380
<div class="flex justify-between gap-2">
299
-
<div class="dark:hover:bg-dark-200 dark:shadow-dark-700 dark:active:bg-dark-100 flex w-fit rounded-lg border-[0.5px] border-neutral-300 bg-neutral-50 text-xs shadow-xs hover:bg-neutral-100 active:bg-neutral-200 dark:border-neutral-700 dark:bg-neutral-800">
381
+
<button
382
+
type="button"
383
+
class="dark:hover:bg-dark-200 dark:shadow-dark-700 dark:active:bg-dark-100 flex w-fit rounded-lg border-[0.5px] border-neutral-300 bg-neutral-50 text-xs shadow-xs hover:bg-neutral-100 active:bg-neutral-200 dark:border-neutral-700 dark:bg-neutral-800"
384
+
>
300
385
<input
301
386
type="file"
302
387
id="blob"
···
310
395
<span class="iconify lucide--upload"></span>
311
396
Upload
312
397
</label>
313
-
</div>
398
+
</button>
314
399
<Modal
315
400
open={openUpload()}
316
401
onClose={() => setOpenUpload(false)}
+2
-1
src/components/editor.tsx
+2
-1
src/components/editor.tsx
···
57
57
return (
58
58
<div
59
59
ref={editorDiv}
60
-
class="dark:shadow-dark-700 border-[0.5px] border-neutral-300 shadow-xs dark:border-neutral-700"
60
+
id="editor"
61
+
class="dark:shadow-dark-700 cursor-auto border-[0.5px] border-neutral-300 shadow-xs dark:border-neutral-700"
61
62
></div>
62
63
);
63
64
};