forked from pdsls.dev/pdsls
this repo has no description

unlock modal button

juli.ee 6e4e65ec 00e9a156

verified
Changed files
+63 -19
src
+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
··· 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
··· 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();