grain.social is a photo sharing platform built on atproto.
at main 133 lines 3.7 kB view raw
1import { cn } from "@bigmoves/bff/components"; 2import type { FunctionalComponent, JSX } from "preact"; 3import { Button, ButtonProps } from "./Button.tsx"; 4 5type DialogProps = JSX.HTMLAttributes<HTMLDivElement> & { _?: string } & { 6 children: preact.ComponentChildren; 7}; 8 9type DialogContentProps = JSX.HTMLAttributes<HTMLDivElement> & { 10 children: preact.ComponentChildren; 11}; 12 13type DialogTitleProps = { 14 children: preact.ComponentChildren; 15}; 16 17type DialogCloseProps = JSX.HTMLAttributes<HTMLButtonElement> & ButtonProps & { 18 children: preact.ComponentChildren; 19}; 20 21type DialogXProps = JSX.HTMLAttributes<HTMLButtonElement>; 22 23const _closeOnClick = "on click trigger closeDialog"; 24 25const Dialog: FunctionalComponent<DialogProps> & { 26 Content: FunctionalComponent<DialogContentProps>; 27 Title: FunctionalComponent<DialogTitleProps>; 28 Close: FunctionalComponent<DialogCloseProps>; 29 X: FunctionalComponent<DialogXProps>; 30 _closeOnClick: string; 31} = ({ children, class: classProp, _ = "", ...props }) => { 32 return ( 33 <div 34 class={cn( 35 "fixed top-0 bottom-0 right-0 left-0 flex items-center justify-center z-100", 36 classProp, 37 )} 38 {...{ 39 _: `on closeDialog 40 remove me 41 remove .pointer-events-none from document.body 42 remove [@data-scroll-locked] from document.body 43 on keyup[key is 'Escape'] from <body/> trigger closeDialog 44 init 45 add .pointer-events-none to document.body 46 add .pointer-events-auto to me 47 add [@data-scroll-locked=true] to document.body 48 ${_}`, 49 }} 50 {...props} 51 > 52 <div 53 class="absolute top-0 left-0 right-0 bottom-0 bg-black/80" 54 {...{ 55 _: _closeOnClick, 56 }} 57 /> 58 {children} 59 </div> 60 ); 61}; 62 63const DialogContent: FunctionalComponent<DialogContentProps> = ( 64 { children, class: classProp, ...props }, 65) => { 66 return ( 67 <div 68 class={cn( 69 "w-[400px] bg-white dark:bg-zinc-900 rounded-md flex flex-col p-4 max-h-[calc(100vh-100px)] overflow-y-auto z-20 relative", 70 classProp, 71 )} 72 {...props} 73 > 74 {children} 75 </div> 76 ); 77}; 78 79const DialogTitle: FunctionalComponent<DialogTitleProps> = ({ children }) => { 80 return ( 81 <h1 class="text-lg font-semibold text-center w-full mb-2"> 82 {children} 83 </h1> 84 ); 85}; 86 87const DialogX: FunctionalComponent<DialogXProps> = ({ 88 class: classProp, 89}) => { 90 return ( 91 <button 92 type="button" 93 class={cn( 94 "absolute top-4 right-4 h-4 w-4 cursor-pointer z-30 fill-white", 95 classProp, 96 )} 97 {...{ 98 _: _closeOnClick, 99 }} 100 > 101 <svg 102 xmlns="http://www.w3.org/2000/svg" 103 viewBox="0 0 384 512" 104 > 105 {/* <!--!Font Awesome Free 6.7.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2025 Fonticons, Inc.-->*/} 106 <path d="M342.6 150.6c12.5-12.5 12.5-32.8 0-45.3s-32.8-12.5-45.3 0L192 210.7 86.6 105.4c-12.5-12.5-32.8-12.5-45.3 0s-12.5 32.8 0 45.3L146.7 256 41.4 361.4c-12.5 12.5-12.5 32.8 0 45.3s32.8 12.5 45.3 0L192 301.3 297.4 406.6c12.5 12.5 32.8 12.5 45.3 0s12.5-32.8 0-45.3L237.3 256 342.6 150.6z" /> 107 </svg> 108 </button> 109 ); 110}; 111 112const DialogClose: FunctionalComponent<DialogCloseProps> = ( 113 { children, ...props }, 114) => { 115 return ( 116 <Button 117 {...{ 118 _: _closeOnClick, 119 }} 120 {...props} 121 > 122 {children} 123 </Button> 124 ); 125}; 126 127Dialog.Content = DialogContent; 128Dialog.Title = DialogTitle; 129Dialog.Close = DialogClose; 130Dialog.X = DialogX; 131Dialog._closeOnClick = _closeOnClick; 132 133export { Dialog };