A dialog component in neobrutalism style.
1"use client"
2
3import * as DialogPrimitive from "@radix-ui/react-dialog"
4import { X } from "lucide-react"
5
6import * as React from "react"
7
8import { cn } from "@/lib/utils"
9
10function Dialog({
11 ...props
12}: React.ComponentProps<typeof DialogPrimitive.Root>) {
13 return <DialogPrimitive.Root data-slot="dialog" {...props} />
14}
15
16function DialogTrigger({
17 ...props
18}: React.ComponentProps<typeof DialogPrimitive.Trigger>) {
19 return <DialogPrimitive.Trigger data-slot="dialog-trigger" {...props} />
20}
21
22function DialogPortal({
23 ...props
24}: React.ComponentProps<typeof DialogPrimitive.Portal>) {
25 return <DialogPrimitive.Portal data-slot="dialog-portal" {...props} />
26}
27
28function DialogClose({
29 ...props
30}: React.ComponentProps<typeof DialogPrimitive.Close>) {
31 return <DialogPrimitive.Close data-slot="dialog-close" {...props} />
32}
33
34function DialogOverlay({
35 className,
36 ...props
37}: React.ComponentProps<typeof DialogPrimitive.Overlay>) {
38 return (
39 <DialogPrimitive.Overlay
40 data-slot="dialog-overlay"
41 className={cn(
42 "fixed inset-0 z-50 bg-overlay data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",
43 className,
44 )}
45 {...props}
46 />
47 )
48}
49
50function DialogContent({
51 className,
52 children,
53 ...props
54}: React.ComponentProps<typeof DialogPrimitive.Content>) {
55 return (
56 <DialogPortal>
57 <DialogOverlay />
58 <DialogPrimitive.Content
59 data-slot="dialog-content"
60 className={cn(
61 "bg-background data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 fixed top-[50%] left-[50%] z-50 grid w-full max-w-[calc(100%-2rem)] translate-x-[-50%] translate-y-[-50%] gap-4 rounded-base border-2 border-border p-6 shadow-shadow duration-200 sm:max-w-lg",
62 className,
63 )}
64 {...props}
65 >
66 {children}
67 <DialogPrimitive.Close className="absolute right-4 top-4 rounded-base opacity-100 ring-offset-white focus:outline-hidden focus:ring-2 focus:ring-black focus:ring-offset-2 disabled:pointer-events-none [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4">
68 <X />
69 <span className="sr-only">Close</span>
70 </DialogPrimitive.Close>
71 </DialogPrimitive.Content>
72 </DialogPortal>
73 )
74}
75
76function DialogHeader({ className, ...props }: React.ComponentProps<"div">) {
77 return (
78 <div
79 data-slot="dialog-header"
80 className={cn("flex flex-col gap-2 text-center sm:text-left", className)}
81 {...props}
82 />
83 )
84}
85
86function DialogFooter({ className, ...props }: React.ComponentProps<"div">) {
87 return (
88 <div
89 data-slot="dialog-footer"
90 className={cn(
91 "flex flex-col-reverse gap-3 sm:flex-row sm:justify-end",
92 className,
93 )}
94 {...props}
95 />
96 )
97}
98
99function DialogTitle({
100 className,
101 ...props
102}: React.ComponentProps<typeof DialogPrimitive.Title>) {
103 return (
104 <DialogPrimitive.Title
105 data-slot="dialog-title"
106 className={cn(
107 "text-lg font-heading leading-none tracking-tight",
108 className,
109 )}
110 {...props}
111 />
112 )
113}
114
115function DialogDescription({
116 className,
117 ...props
118}: React.ComponentProps<typeof DialogPrimitive.Description>) {
119 return (
120 <DialogPrimitive.Description
121 data-slot="dialog-description"
122 className={cn("text-sm font-base text-foreground", className)}
123 {...props}
124 />
125 )
126}
127
128export {
129 Dialog,
130 DialogPortal,
131 DialogOverlay,
132 DialogClose,
133 DialogTrigger,
134 DialogContent,
135 DialogHeader,
136 DialogFooter,
137 DialogTitle,
138 DialogDescription,
139}
140