+26
-4
src/components/create.tsx
+26
-4
src/components/create.tsx
···
22
22
const [notice, setNotice] = createSignal("");
23
23
const [openUpload, setOpenUpload] = createSignal(false);
24
24
const [validate, setValidate] = createSignal<boolean | undefined>(undefined);
25
+
const [nonBlocking, setNonBlocking] = createSignal(false);
25
26
let blobInput!: HTMLInputElement;
26
27
let formRef!: HTMLFormElement;
27
28
···
324
325
325
326
return (
326
327
<>
327
-
<Modal open={openDialog()} onClose={() => setOpenDialog(false)} closeOnClick={false}>
328
+
<Modal
329
+
open={openDialog()}
330
+
onClose={() => setOpenDialog(false)}
331
+
closeOnClick={false}
332
+
nonBlocking={nonBlocking()}
333
+
>
328
334
<div
329
335
data-draggable
330
-
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"
336
+
classList={{
337
+
"dark:bg-dark-300 dark:shadow-dark-700 pointer-events-auto 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": true,
338
+
"opacity-60 hover:opacity-100": nonBlocking(),
339
+
}}
331
340
ref={dragBox}
332
341
>
333
342
<div class="mb-2 flex w-full justify-between text-base">
334
-
<div class="font-semibold">
335
-
<span class="select-none">{props.create ? "Creating" : "Editing"} record</span>
343
+
<div class="flex items-center gap-2">
344
+
<span class="font-semibold select-none">
345
+
{props.create ? "Creating" : "Editing"} record
346
+
</span>
347
+
<Tooltip text={nonBlocking() ? "Lock" : "Unlock"}>
348
+
<button
349
+
type="button"
350
+
onclick={() => setNonBlocking(!nonBlocking())}
351
+
class="flex items-center rounded-lg p-1 hover:bg-neutral-200 active:bg-neutral-300 dark:hover:bg-neutral-700 dark:active:bg-neutral-600"
352
+
>
353
+
<span
354
+
class={`iconify ${nonBlocking() ? "lucide--lock-open" : "lucide--lock"}`}
355
+
></span>
356
+
</button>
357
+
</Tooltip>
336
358
</div>
337
359
<button
338
360
id="close"
+36
-14
src/components/modal.tsx
+36
-14
src/components/modal.tsx
···
1
-
import { ComponentProps, onCleanup, onMount, Show } from "solid-js";
1
+
import { ComponentProps, createEffect, onCleanup, Show } from "solid-js";
2
2
3
3
export interface ModalProps extends Pick<ComponentProps<"svg">, "children"> {
4
4
open?: boolean;
5
5
onClose?: () => void;
6
6
closeOnClick?: boolean;
7
+
nonBlocking?: boolean;
7
8
}
8
9
9
10
export const Modal = (props: ModalProps) => {
10
11
return (
11
12
<Show when={props.open}>
12
-
<dialog
13
+
<div
14
+
data-modal
15
+
class="fixed inset-0 z-50 h-full max-h-none w-full max-w-none bg-transparent text-neutral-900 dark:text-neutral-200"
16
+
classList={{
17
+
"pointer-events-none": props.nonBlocking,
18
+
}}
13
19
ref={(node) => {
14
-
onMount(() => {
15
-
document.body.style.overflow = "hidden";
16
-
node.showModal();
17
-
(document.activeElement as any).blur();
20
+
const handleEscape = (e: KeyboardEvent) => {
21
+
if (e.key === "Escape") {
22
+
const modals = document.querySelectorAll("[data-modal]");
23
+
const lastModal = modals[modals.length - 1];
24
+
if (lastModal === node) {
25
+
e.preventDefault();
26
+
e.stopPropagation();
27
+
if (props.onClose) props.onClose();
28
+
}
29
+
}
30
+
};
31
+
32
+
createEffect(() => {
33
+
if (!props.nonBlocking) document.body.style.overflow = "hidden";
34
+
else document.body.style.overflow = "auto";
18
35
});
19
-
onCleanup(() => node.close());
36
+
37
+
document.addEventListener("keydown", handleEscape);
38
+
39
+
onCleanup(() => {
40
+
document.body.style.overflow = "auto";
41
+
document.removeEventListener("keydown", handleEscape);
42
+
});
20
43
}}
21
44
onClick={(ev) => {
22
-
if ((props.closeOnClick ?? true) && ev.target === ev.currentTarget) {
45
+
if (
46
+
(props.closeOnClick ?? true) &&
47
+
ev.target === ev.currentTarget &&
48
+
!props.nonBlocking
49
+
) {
23
50
if (props.onClose) props.onClose();
24
51
}
25
52
}}
26
-
onClose={() => {
27
-
document.body.style.overflow = "auto";
28
-
if (props.onClose) props.onClose();
29
-
}}
30
-
class="h-full max-h-none w-full max-w-none bg-transparent text-neutral-900 backdrop:bg-transparent dark:text-neutral-200"
31
53
>
32
54
{props.children}
33
-
</dialog>
55
+
</div>
34
56
</Show>
35
57
);
36
58
};
+1
-1
src/components/search.tsx
+1
-1
src/components/search.tsx
···
15
15
onCleanup(() => window.removeEventListener("keydown", keyEvent));
16
16
17
17
const keyEvent = (ev: KeyboardEvent) => {
18
-
if (document.querySelector("dialog")) return;
18
+
if (document.querySelector("[data-modal]")) return;
19
19
20
20
if ((ev.ctrlKey || ev.metaKey) && ev.key == "k") {
21
21
ev.preventDefault();