radix select boxes working
This commit is contained in:
		
							parent
							
								
									87ec3c99c4
								
							
						
					
					
						commit
						4cb077e7b9
					
				|  | @ -15,6 +15,7 @@ | ||||||
|         "@radix-ui/react-label": "^2.0.2", |         "@radix-ui/react-label": "^2.0.2", | ||||||
|         "@radix-ui/react-select": "^2.0.0", |         "@radix-ui/react-select": "^2.0.0", | ||||||
|         "@radix-ui/react-slot": "^1.0.2", |         "@radix-ui/react-slot": "^1.0.2", | ||||||
|  |         "@radix-ui/react-toast": "^1.1.5", | ||||||
|         "@tanstack/react-table": "^8.17.3", |         "@tanstack/react-table": "^8.17.3", | ||||||
|         "class-variance-authority": "^0.7.0", |         "class-variance-authority": "^0.7.0", | ||||||
|         "clsx": "^2.1.1", |         "clsx": "^2.1.1", | ||||||
|  | @ -1076,6 +1077,40 @@ | ||||||
|         } |         } | ||||||
|       } |       } | ||||||
|     }, |     }, | ||||||
|  |     "node_modules/@radix-ui/react-toast": { | ||||||
|  |       "version": "1.1.5", | ||||||
|  |       "resolved": "https://registry.npmjs.org/@radix-ui/react-toast/-/react-toast-1.1.5.tgz", | ||||||
|  |       "integrity": "sha512-fRLn227WHIBRSzuRzGJ8W+5YALxofH23y0MlPLddaIpLpCDqdE0NZlS2NRQDRiptfxDeeCjgFIpexB1/zkxDlw==", | ||||||
|  |       "dependencies": { | ||||||
|  |         "@babel/runtime": "^7.13.10", | ||||||
|  |         "@radix-ui/primitive": "1.0.1", | ||||||
|  |         "@radix-ui/react-collection": "1.0.3", | ||||||
|  |         "@radix-ui/react-compose-refs": "1.0.1", | ||||||
|  |         "@radix-ui/react-context": "1.0.1", | ||||||
|  |         "@radix-ui/react-dismissable-layer": "1.0.5", | ||||||
|  |         "@radix-ui/react-portal": "1.0.4", | ||||||
|  |         "@radix-ui/react-presence": "1.0.1", | ||||||
|  |         "@radix-ui/react-primitive": "1.0.3", | ||||||
|  |         "@radix-ui/react-use-callback-ref": "1.0.1", | ||||||
|  |         "@radix-ui/react-use-controllable-state": "1.0.1", | ||||||
|  |         "@radix-ui/react-use-layout-effect": "1.0.1", | ||||||
|  |         "@radix-ui/react-visually-hidden": "1.0.3" | ||||||
|  |       }, | ||||||
|  |       "peerDependencies": { | ||||||
|  |         "@types/react": "*", | ||||||
|  |         "@types/react-dom": "*", | ||||||
|  |         "react": "^16.8 || ^17.0 || ^18.0", | ||||||
|  |         "react-dom": "^16.8 || ^17.0 || ^18.0" | ||||||
|  |       }, | ||||||
|  |       "peerDependenciesMeta": { | ||||||
|  |         "@types/react": { | ||||||
|  |           "optional": true | ||||||
|  |         }, | ||||||
|  |         "@types/react-dom": { | ||||||
|  |           "optional": true | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|     "node_modules/@radix-ui/react-use-callback-ref": { |     "node_modules/@radix-ui/react-use-callback-ref": { | ||||||
|       "version": "1.0.1", |       "version": "1.0.1", | ||||||
|       "resolved": "https://registry.npmjs.org/@radix-ui/react-use-callback-ref/-/react-use-callback-ref-1.0.1.tgz", |       "resolved": "https://registry.npmjs.org/@radix-ui/react-use-callback-ref/-/react-use-callback-ref-1.0.1.tgz", | ||||||
|  |  | ||||||
|  | @ -17,6 +17,7 @@ | ||||||
|     "@radix-ui/react-label": "^2.0.2", |     "@radix-ui/react-label": "^2.0.2", | ||||||
|     "@radix-ui/react-select": "^2.0.0", |     "@radix-ui/react-select": "^2.0.0", | ||||||
|     "@radix-ui/react-slot": "^1.0.2", |     "@radix-ui/react-slot": "^1.0.2", | ||||||
|  |     "@radix-ui/react-toast": "^1.1.5", | ||||||
|     "@tanstack/react-table": "^8.17.3", |     "@tanstack/react-table": "^8.17.3", | ||||||
|     "class-variance-authority": "^0.7.0", |     "class-variance-authority": "^0.7.0", | ||||||
|     "clsx": "^2.1.1", |     "clsx": "^2.1.1", | ||||||
|  |  | ||||||
|  | @ -0,0 +1,129 @@ | ||||||
|  | "use client" | ||||||
|  | 
 | ||||||
|  | import * as React from "react" | ||||||
|  | import * as ToastPrimitives from "@radix-ui/react-toast" | ||||||
|  | import { cva, type VariantProps } from "class-variance-authority" | ||||||
|  | import { X } from "lucide-react" | ||||||
|  | 
 | ||||||
|  | import { cn } from "@/lib/utils" | ||||||
|  | 
 | ||||||
|  | const ToastProvider = ToastPrimitives.Provider | ||||||
|  | 
 | ||||||
|  | const ToastViewport = React.forwardRef< | ||||||
|  |   React.ElementRef<typeof ToastPrimitives.Viewport>, | ||||||
|  |   React.ComponentPropsWithoutRef<typeof ToastPrimitives.Viewport> | ||||||
|  | >(({ className, ...props }, ref) => ( | ||||||
|  |   <ToastPrimitives.Viewport | ||||||
|  |     ref={ref} | ||||||
|  |     className={cn( | ||||||
|  |       "fixed top-0 z-[100] flex max-h-screen w-full flex-col-reverse p-4 sm:bottom-0 sm:right-0 sm:top-auto sm:flex-col md:max-w-[420px]", | ||||||
|  |       className | ||||||
|  |     )} | ||||||
|  |     {...props} | ||||||
|  |   /> | ||||||
|  | )) | ||||||
|  | ToastViewport.displayName = ToastPrimitives.Viewport.displayName | ||||||
|  | 
 | ||||||
|  | const toastVariants = cva( | ||||||
|  |   "group pointer-events-auto relative flex w-full items-center justify-between space-x-4 overflow-hidden rounded-md border p-6 pr-8 shadow-lg transition-all data-[swipe=cancel]:translate-x-0 data-[swipe=end]:translate-x-[var(--radix-toast-swipe-end-x)] data-[swipe=move]:translate-x-[var(--radix-toast-swipe-move-x)] data-[swipe=move]:transition-none data-[state=open]:animate-in data-[state=closed]:animate-out data-[swipe=end]:animate-out data-[state=closed]:fade-out-80 data-[state=closed]:slide-out-to-right-full data-[state=open]:slide-in-from-top-full data-[state=open]:sm:slide-in-from-bottom-full", | ||||||
|  |   { | ||||||
|  |     variants: { | ||||||
|  |       variant: { | ||||||
|  |         default: "border bg-background text-foreground", | ||||||
|  |         destructive: | ||||||
|  |           "destructive group border-destructive bg-destructive text-destructive-foreground", | ||||||
|  |       }, | ||||||
|  |     }, | ||||||
|  |     defaultVariants: { | ||||||
|  |       variant: "default", | ||||||
|  |     }, | ||||||
|  |   } | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | const Toast = React.forwardRef< | ||||||
|  |   React.ElementRef<typeof ToastPrimitives.Root>, | ||||||
|  |   React.ComponentPropsWithoutRef<typeof ToastPrimitives.Root> & | ||||||
|  |     VariantProps<typeof toastVariants> | ||||||
|  | >(({ className, variant, ...props }, ref) => { | ||||||
|  |   return ( | ||||||
|  |     <ToastPrimitives.Root | ||||||
|  |       ref={ref} | ||||||
|  |       className={cn(toastVariants({ variant }), className)} | ||||||
|  |       {...props} | ||||||
|  |     /> | ||||||
|  |   ) | ||||||
|  | }) | ||||||
|  | Toast.displayName = ToastPrimitives.Root.displayName | ||||||
|  | 
 | ||||||
|  | const ToastAction = React.forwardRef< | ||||||
|  |   React.ElementRef<typeof ToastPrimitives.Action>, | ||||||
|  |   React.ComponentPropsWithoutRef<typeof ToastPrimitives.Action> | ||||||
|  | >(({ className, ...props }, ref) => ( | ||||||
|  |   <ToastPrimitives.Action | ||||||
|  |     ref={ref} | ||||||
|  |     className={cn( | ||||||
|  |       "inline-flex h-8 shrink-0 items-center justify-center rounded-md border bg-transparent px-3 text-sm font-medium ring-offset-background transition-colors hover:bg-secondary focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 group-[.destructive]:border-muted/40 group-[.destructive]:hover:border-destructive/30 group-[.destructive]:hover:bg-destructive group-[.destructive]:hover:text-destructive-foreground group-[.destructive]:focus:ring-destructive", | ||||||
|  |       className | ||||||
|  |     )} | ||||||
|  |     {...props} | ||||||
|  |   /> | ||||||
|  | )) | ||||||
|  | ToastAction.displayName = ToastPrimitives.Action.displayName | ||||||
|  | 
 | ||||||
|  | const ToastClose = React.forwardRef< | ||||||
|  |   React.ElementRef<typeof ToastPrimitives.Close>, | ||||||
|  |   React.ComponentPropsWithoutRef<typeof ToastPrimitives.Close> | ||||||
|  | >(({ className, ...props }, ref) => ( | ||||||
|  |   <ToastPrimitives.Close | ||||||
|  |     ref={ref} | ||||||
|  |     className={cn( | ||||||
|  |       "absolute right-2 top-2 rounded-md p-1 text-foreground/50 opacity-0 transition-opacity hover:text-foreground focus:opacity-100 focus:outline-none focus:ring-2 group-hover:opacity-100 group-[.destructive]:text-red-300 group-[.destructive]:hover:text-red-50 group-[.destructive]:focus:ring-red-400 group-[.destructive]:focus:ring-offset-red-600", | ||||||
|  |       className | ||||||
|  |     )} | ||||||
|  |     toast-close="" | ||||||
|  |     {...props} | ||||||
|  |   > | ||||||
|  |     <X className="h-4 w-4" /> | ||||||
|  |   </ToastPrimitives.Close> | ||||||
|  | )) | ||||||
|  | ToastClose.displayName = ToastPrimitives.Close.displayName | ||||||
|  | 
 | ||||||
|  | const ToastTitle = React.forwardRef< | ||||||
|  |   React.ElementRef<typeof ToastPrimitives.Title>, | ||||||
|  |   React.ComponentPropsWithoutRef<typeof ToastPrimitives.Title> | ||||||
|  | >(({ className, ...props }, ref) => ( | ||||||
|  |   <ToastPrimitives.Title | ||||||
|  |     ref={ref} | ||||||
|  |     className={cn("text-sm font-semibold", className)} | ||||||
|  |     {...props} | ||||||
|  |   /> | ||||||
|  | )) | ||||||
|  | ToastTitle.displayName = ToastPrimitives.Title.displayName | ||||||
|  | 
 | ||||||
|  | const ToastDescription = React.forwardRef< | ||||||
|  |   React.ElementRef<typeof ToastPrimitives.Description>, | ||||||
|  |   React.ComponentPropsWithoutRef<typeof ToastPrimitives.Description> | ||||||
|  | >(({ className, ...props }, ref) => ( | ||||||
|  |   <ToastPrimitives.Description | ||||||
|  |     ref={ref} | ||||||
|  |     className={cn("text-sm opacity-90", className)} | ||||||
|  |     {...props} | ||||||
|  |   /> | ||||||
|  | )) | ||||||
|  | ToastDescription.displayName = ToastPrimitives.Description.displayName | ||||||
|  | 
 | ||||||
|  | type ToastProps = React.ComponentPropsWithoutRef<typeof Toast> | ||||||
|  | 
 | ||||||
|  | type ToastActionElement = React.ReactElement<typeof ToastAction> | ||||||
|  | 
 | ||||||
|  | export { | ||||||
|  |   type ToastProps, | ||||||
|  |   type ToastActionElement, | ||||||
|  |   ToastProvider, | ||||||
|  |   ToastViewport, | ||||||
|  |   Toast, | ||||||
|  |   ToastTitle, | ||||||
|  |   ToastDescription, | ||||||
|  |   ToastClose, | ||||||
|  |   ToastAction, | ||||||
|  | } | ||||||
|  | @ -0,0 +1,35 @@ | ||||||
|  | "use client" | ||||||
|  | 
 | ||||||
|  | import { | ||||||
|  |   Toast, | ||||||
|  |   ToastClose, | ||||||
|  |   ToastDescription, | ||||||
|  |   ToastProvider, | ||||||
|  |   ToastTitle, | ||||||
|  |   ToastViewport, | ||||||
|  | } from "@/components/ui/toast" | ||||||
|  | import { useToast } from "@/components/ui/use-toast" | ||||||
|  | 
 | ||||||
|  | export function Toaster() { | ||||||
|  |   const { toasts } = useToast() | ||||||
|  | 
 | ||||||
|  |   return ( | ||||||
|  |     <ToastProvider> | ||||||
|  |       {toasts.map(function ({ id, title, description, action, ...props }) { | ||||||
|  |         return ( | ||||||
|  |           <Toast key={id} {...props}> | ||||||
|  |             <div className="grid gap-1"> | ||||||
|  |               {title && <ToastTitle>{title}</ToastTitle>} | ||||||
|  |               {description && ( | ||||||
|  |                 <ToastDescription>{description}</ToastDescription> | ||||||
|  |               )} | ||||||
|  |             </div> | ||||||
|  |             {action} | ||||||
|  |             <ToastClose /> | ||||||
|  |           </Toast> | ||||||
|  |         ) | ||||||
|  |       })} | ||||||
|  |       <ToastViewport /> | ||||||
|  |     </ToastProvider> | ||||||
|  |   ) | ||||||
|  | } | ||||||
|  | @ -0,0 +1,194 @@ | ||||||
|  | "use client" | ||||||
|  | 
 | ||||||
|  | // Inspired by react-hot-toast library
 | ||||||
|  | import * as React from "react" | ||||||
|  | 
 | ||||||
|  | import type { | ||||||
|  |   ToastActionElement, | ||||||
|  |   ToastProps, | ||||||
|  | } from "@/components/ui/toast" | ||||||
|  | 
 | ||||||
|  | const TOAST_LIMIT = 1 | ||||||
|  | const TOAST_REMOVE_DELAY = 1000000 | ||||||
|  | 
 | ||||||
|  | type ToasterToast = ToastProps & { | ||||||
|  |   id: string | ||||||
|  |   title?: React.ReactNode | ||||||
|  |   description?: React.ReactNode | ||||||
|  |   action?: ToastActionElement | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | const actionTypes = { | ||||||
|  |   ADD_TOAST: "ADD_TOAST", | ||||||
|  |   UPDATE_TOAST: "UPDATE_TOAST", | ||||||
|  |   DISMISS_TOAST: "DISMISS_TOAST", | ||||||
|  |   REMOVE_TOAST: "REMOVE_TOAST", | ||||||
|  | } as const | ||||||
|  | 
 | ||||||
|  | let count = 0 | ||||||
|  | 
 | ||||||
|  | function genId() { | ||||||
|  |   count = (count + 1) % Number.MAX_SAFE_INTEGER | ||||||
|  |   return count.toString() | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | type ActionType = typeof actionTypes | ||||||
|  | 
 | ||||||
|  | type Action = | ||||||
|  |   | { | ||||||
|  |       type: ActionType["ADD_TOAST"] | ||||||
|  |       toast: ToasterToast | ||||||
|  |     } | ||||||
|  |   | { | ||||||
|  |       type: ActionType["UPDATE_TOAST"] | ||||||
|  |       toast: Partial<ToasterToast> | ||||||
|  |     } | ||||||
|  |   | { | ||||||
|  |       type: ActionType["DISMISS_TOAST"] | ||||||
|  |       toastId?: ToasterToast["id"] | ||||||
|  |     } | ||||||
|  |   | { | ||||||
|  |       type: ActionType["REMOVE_TOAST"] | ||||||
|  |       toastId?: ToasterToast["id"] | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  | interface State { | ||||||
|  |   toasts: ToasterToast[] | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | const toastTimeouts = new Map<string, ReturnType<typeof setTimeout>>() | ||||||
|  | 
 | ||||||
|  | const addToRemoveQueue = (toastId: string) => { | ||||||
|  |   if (toastTimeouts.has(toastId)) { | ||||||
|  |     return | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   const timeout = setTimeout(() => { | ||||||
|  |     toastTimeouts.delete(toastId) | ||||||
|  |     dispatch({ | ||||||
|  |       type: "REMOVE_TOAST", | ||||||
|  |       toastId: toastId, | ||||||
|  |     }) | ||||||
|  |   }, TOAST_REMOVE_DELAY) | ||||||
|  | 
 | ||||||
|  |   toastTimeouts.set(toastId, timeout) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | export const reducer = (state: State, action: Action): State => { | ||||||
|  |   switch (action.type) { | ||||||
|  |     case "ADD_TOAST": | ||||||
|  |       return { | ||||||
|  |         ...state, | ||||||
|  |         toasts: [action.toast, ...state.toasts].slice(0, TOAST_LIMIT), | ||||||
|  |       } | ||||||
|  | 
 | ||||||
|  |     case "UPDATE_TOAST": | ||||||
|  |       return { | ||||||
|  |         ...state, | ||||||
|  |         toasts: state.toasts.map((t) => | ||||||
|  |           t.id === action.toast.id ? { ...t, ...action.toast } : t | ||||||
|  |         ), | ||||||
|  |       } | ||||||
|  | 
 | ||||||
|  |     case "DISMISS_TOAST": { | ||||||
|  |       const { toastId } = action | ||||||
|  | 
 | ||||||
|  |       // ! Side effects ! - This could be extracted into a dismissToast() action,
 | ||||||
|  |       // but I'll keep it here for simplicity
 | ||||||
|  |       if (toastId) { | ||||||
|  |         addToRemoveQueue(toastId) | ||||||
|  |       } else { | ||||||
|  |         state.toasts.forEach((toast) => { | ||||||
|  |           addToRemoveQueue(toast.id) | ||||||
|  |         }) | ||||||
|  |       } | ||||||
|  | 
 | ||||||
|  |       return { | ||||||
|  |         ...state, | ||||||
|  |         toasts: state.toasts.map((t) => | ||||||
|  |           t.id === toastId || toastId === undefined | ||||||
|  |             ? { | ||||||
|  |                 ...t, | ||||||
|  |                 open: false, | ||||||
|  |               } | ||||||
|  |             : t | ||||||
|  |         ), | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |     case "REMOVE_TOAST": | ||||||
|  |       if (action.toastId === undefined) { | ||||||
|  |         return { | ||||||
|  |           ...state, | ||||||
|  |           toasts: [], | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  |       return { | ||||||
|  |         ...state, | ||||||
|  |         toasts: state.toasts.filter((t) => t.id !== action.toastId), | ||||||
|  |       } | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | const listeners: Array<(state: State) => void> = [] | ||||||
|  | 
 | ||||||
|  | let memoryState: State = { toasts: [] } | ||||||
|  | 
 | ||||||
|  | function dispatch(action: Action) { | ||||||
|  |   memoryState = reducer(memoryState, action) | ||||||
|  |   listeners.forEach((listener) => { | ||||||
|  |     listener(memoryState) | ||||||
|  |   }) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | type Toast = Omit<ToasterToast, "id"> | ||||||
|  | 
 | ||||||
|  | function toast({ ...props }: Toast) { | ||||||
|  |   const id = genId() | ||||||
|  | 
 | ||||||
|  |   const update = (props: ToasterToast) => | ||||||
|  |     dispatch({ | ||||||
|  |       type: "UPDATE_TOAST", | ||||||
|  |       toast: { ...props, id }, | ||||||
|  |     }) | ||||||
|  |   const dismiss = () => dispatch({ type: "DISMISS_TOAST", toastId: id }) | ||||||
|  | 
 | ||||||
|  |   dispatch({ | ||||||
|  |     type: "ADD_TOAST", | ||||||
|  |     toast: { | ||||||
|  |       ...props, | ||||||
|  |       id, | ||||||
|  |       open: true, | ||||||
|  |       onOpenChange: (open) => { | ||||||
|  |         if (!open) dismiss() | ||||||
|  |       }, | ||||||
|  |     }, | ||||||
|  |   }) | ||||||
|  | 
 | ||||||
|  |   return { | ||||||
|  |     id: id, | ||||||
|  |     dismiss, | ||||||
|  |     update, | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | function useToast() { | ||||||
|  |   const [state, setState] = React.useState<State>(memoryState) | ||||||
|  | 
 | ||||||
|  |   React.useEffect(() => { | ||||||
|  |     listeners.push(setState) | ||||||
|  |     return () => { | ||||||
|  |       const index = listeners.indexOf(setState) | ||||||
|  |       if (index > -1) { | ||||||
|  |         listeners.splice(index, 1) | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |   }, [state]) | ||||||
|  | 
 | ||||||
|  |   return { | ||||||
|  |     ...state, | ||||||
|  |     toast, | ||||||
|  |     dismiss: (toastId?: string) => dispatch({ type: "DISMISS_TOAST", toastId }), | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | export { useToast, toast } | ||||||
|  | @ -1,5 +1,6 @@ | ||||||
| import type { Metadata } from "next"; | import type { Metadata } from "next"; | ||||||
| import { Inter } from "next/font/google"; | import { Inter } from "next/font/google"; | ||||||
|  | import { Toaster } from "@/components/ui/toaster"; | ||||||
| import "./tailwind.css"; | import "./tailwind.css"; | ||||||
| 
 | 
 | ||||||
| const inter = Inter({ subsets: ["latin"] }); | const inter = Inter({ subsets: ["latin"] }); | ||||||
|  | @ -20,7 +21,10 @@ export default function RootLayout({ | ||||||
|         <div id="sidebar"> |         <div id="sidebar"> | ||||||
|           SIDEBAR |           SIDEBAR | ||||||
|         </div> |         </div> | ||||||
|         {children}</body> |         {children} | ||||||
|  | 
 | ||||||
|  |         <Toaster /> | ||||||
|  |       </body> | ||||||
|     </html> |     </html> | ||||||
|   ); |   ); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -1,6 +1,7 @@ | ||||||
| "use server" | "use server" | ||||||
| import { getPubs, getResponses, getStories } from "app/lib/get"; | import { getPubs, getResponses, getStories } from "app/lib/get"; | ||||||
| import SubmissionForm from "app/ui/forms/sub"; | import SubmissionForm from "app/ui/forms/sub"; | ||||||
|  | import { SelectForm } from "app/ui/forms/selectDemo"; | ||||||
| 
 | 
 | ||||||
| export default async function Page() { | export default async function Page() { | ||||||
| 	const stories = await getStories() | 	const stories = await getStories() | ||||||
|  |  | ||||||
|  | @ -600,6 +600,14 @@ body { | ||||||
|   } |   } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | .pointer-events-auto { | ||||||
|  |   pointer-events: auto; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .fixed { | ||||||
|  |   position: fixed; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| .absolute { | .absolute { | ||||||
|   position: absolute; |   position: absolute; | ||||||
| } | } | ||||||
|  | @ -612,10 +620,26 @@ body { | ||||||
|   left: 0.5rem; |   left: 0.5rem; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | .right-2 { | ||||||
|  |   right: 0.5rem; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .top-0 { | ||||||
|  |   top: 0px; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .top-2 { | ||||||
|  |   top: 0.5rem; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| .z-50 { | .z-50 { | ||||||
|   z-index: 50; |   z-index: 50; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | .z-\[100\] { | ||||||
|  |   z-index: 100; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| .-mx-1 { | .-mx-1 { | ||||||
|   margin-left: -0.25rem; |   margin-left: -0.25rem; | ||||||
|   margin-right: -0.25rem; |   margin-right: -0.25rem; | ||||||
|  | @ -631,6 +655,10 @@ body { | ||||||
|   margin-bottom: 0.25rem; |   margin-bottom: 0.25rem; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | .mb-4 { | ||||||
|  |   margin-bottom: 1rem; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| .ml-2 { | .ml-2 { | ||||||
|   margin-left: 0.5rem; |   margin-left: 0.5rem; | ||||||
| } | } | ||||||
|  | @ -639,18 +667,14 @@ body { | ||||||
|   margin-left: auto; |   margin-left: auto; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| .mt-4 { |  | ||||||
|   margin-top: 1rem; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| .mb-4 { |  | ||||||
|   margin-bottom: 1rem; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| .mt-2 { | .mt-2 { | ||||||
|   margin-top: 0.5rem; |   margin-top: 0.5rem; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | .mt-4 { | ||||||
|  |   margin-top: 1rem; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| .flex { | .flex { | ||||||
|   display: flex; |   display: flex; | ||||||
| } | } | ||||||
|  | @ -667,6 +691,10 @@ body { | ||||||
|   display: table; |   display: table; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | .grid { | ||||||
|  |   display: grid; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| .h-10 { | .h-10 { | ||||||
|   height: 2.5rem; |   height: 2.5rem; | ||||||
| } | } | ||||||
|  | @ -703,18 +731,26 @@ body { | ||||||
|   height: 2.25rem; |   height: 2.25rem; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| .h-px { |  | ||||||
|   height: 1px; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| .h-\[var\(--radix-select-trigger-height\)\] { | .h-\[var\(--radix-select-trigger-height\)\] { | ||||||
|   height: var(--radix-select-trigger-height); |   height: var(--radix-select-trigger-height); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | .h-px { | ||||||
|  |   height: 1px; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .h-8 { | ||||||
|  |   height: 2rem; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| .max-h-96 { | .max-h-96 { | ||||||
|   max-height: 24rem; |   max-height: 24rem; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | .max-h-screen { | ||||||
|  |   max-height: 100vh; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| .w-10 { | .w-10 { | ||||||
|   width: 2.5rem; |   width: 2.5rem; | ||||||
| } | } | ||||||
|  | @ -735,12 +771,16 @@ body { | ||||||
|   width: 1rem; |   width: 1rem; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | .w-\[340px\] { | ||||||
|  |   width: 340px; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| .w-full { | .w-full { | ||||||
|   width: 100%; |   width: 100%; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| .w-\[340px\] { | .w-2\/3 { | ||||||
|   width: 340px; |   width: 66.666667%; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| .min-w-\[8rem\] { | .min-w-\[8rem\] { | ||||||
|  | @ -777,6 +817,10 @@ body { | ||||||
|   flex-direction: row; |   flex-direction: row; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | .flex-col-reverse { | ||||||
|  |   flex-direction: column-reverse; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| .items-start { | .items-start { | ||||||
|   align-items: flex-start; |   align-items: flex-start; | ||||||
| } | } | ||||||
|  | @ -797,12 +841,28 @@ body { | ||||||
|   justify-content: space-between; |   justify-content: space-between; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | .gap-1 { | ||||||
|  |   gap: 0.25rem; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| .space-x-2 > :not([hidden]) ~ :not([hidden]) { | .space-x-2 > :not([hidden]) ~ :not([hidden]) { | ||||||
|   --tw-space-x-reverse: 0; |   --tw-space-x-reverse: 0; | ||||||
|   margin-right: calc(0.5rem * var(--tw-space-x-reverse)); |   margin-right: calc(0.5rem * var(--tw-space-x-reverse)); | ||||||
|   margin-left: calc(0.5rem * calc(1 - var(--tw-space-x-reverse))); |   margin-left: calc(0.5rem * calc(1 - var(--tw-space-x-reverse))); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | .space-x-3 > :not([hidden]) ~ :not([hidden]) { | ||||||
|  |   --tw-space-x-reverse: 0; | ||||||
|  |   margin-right: calc(0.75rem * var(--tw-space-x-reverse)); | ||||||
|  |   margin-left: calc(0.75rem * calc(1 - var(--tw-space-x-reverse))); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .space-y-0 > :not([hidden]) ~ :not([hidden]) { | ||||||
|  |   --tw-space-y-reverse: 0; | ||||||
|  |   margin-top: calc(0px * calc(1 - var(--tw-space-y-reverse))); | ||||||
|  |   margin-bottom: calc(0px * var(--tw-space-y-reverse)); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| .space-y-2 > :not([hidden]) ~ :not([hidden]) { | .space-y-2 > :not([hidden]) ~ :not([hidden]) { | ||||||
|   --tw-space-y-reverse: 0; |   --tw-space-y-reverse: 0; | ||||||
|   margin-top: calc(0.5rem * calc(1 - var(--tw-space-y-reverse))); |   margin-top: calc(0.5rem * calc(1 - var(--tw-space-y-reverse))); | ||||||
|  | @ -815,16 +875,16 @@ body { | ||||||
|   margin-bottom: calc(2rem * var(--tw-space-y-reverse)); |   margin-bottom: calc(2rem * var(--tw-space-y-reverse)); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| .space-x-3 > :not([hidden]) ~ :not([hidden]) { | .space-x-4 > :not([hidden]) ~ :not([hidden]) { | ||||||
|   --tw-space-x-reverse: 0; |   --tw-space-x-reverse: 0; | ||||||
|   margin-right: calc(0.75rem * var(--tw-space-x-reverse)); |   margin-right: calc(1rem * var(--tw-space-x-reverse)); | ||||||
|   margin-left: calc(0.75rem * calc(1 - var(--tw-space-x-reverse))); |   margin-left: calc(1rem * calc(1 - var(--tw-space-x-reverse))); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| .space-y-0 > :not([hidden]) ~ :not([hidden]) { | .space-y-6 > :not([hidden]) ~ :not([hidden]) { | ||||||
|   --tw-space-y-reverse: 0; |   --tw-space-y-reverse: 0; | ||||||
|   margin-top: calc(0px * calc(1 - var(--tw-space-y-reverse))); |   margin-top: calc(1.5rem * calc(1 - var(--tw-space-y-reverse))); | ||||||
|   margin-bottom: calc(0px * var(--tw-space-y-reverse)); |   margin-bottom: calc(1.5rem * var(--tw-space-y-reverse)); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| .overflow-auto { | .overflow-auto { | ||||||
|  | @ -867,6 +927,10 @@ body { | ||||||
|   border-color: hsl(var(--primary)); |   border-color: hsl(var(--primary)); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | .border-destructive { | ||||||
|  |   border-color: hsl(var(--destructive)); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| .bg-background { | .bg-background { | ||||||
|   background-color: hsl(var(--background)); |   background-color: hsl(var(--background)); | ||||||
| } | } | ||||||
|  | @ -900,6 +964,10 @@ body { | ||||||
|   background-color: rgb(2 6 23 / var(--tw-bg-opacity)); |   background-color: rgb(2 6 23 / var(--tw-bg-opacity)); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | .bg-transparent { | ||||||
|  |   background-color: transparent; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| .fill-current { | .fill-current { | ||||||
|   fill: currentColor; |   fill: currentColor; | ||||||
| } | } | ||||||
|  | @ -912,6 +980,10 @@ body { | ||||||
|   padding: 1rem; |   padding: 1rem; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | .p-6 { | ||||||
|  |   padding: 1.5rem; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| .px-2 { | .px-2 { | ||||||
|   padding-left: 0.5rem; |   padding-left: 0.5rem; | ||||||
|   padding-right: 0.5rem; |   padding-right: 0.5rem; | ||||||
|  | @ -965,6 +1037,10 @@ body { | ||||||
|   padding-right: 0.5rem; |   padding-right: 0.5rem; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | .pr-8 { | ||||||
|  |   padding-right: 2rem; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| .text-left { | .text-left { | ||||||
|   text-align: left; |   text-align: left; | ||||||
| } | } | ||||||
|  | @ -982,6 +1058,11 @@ body { | ||||||
|   line-height: 2.25rem; |   line-height: 2.25rem; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | .text-base { | ||||||
|  |   font-size: 1rem; | ||||||
|  |   line-height: 1.5rem; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| .text-sm { | .text-sm { | ||||||
|   font-size: 0.875rem; |   font-size: 0.875rem; | ||||||
|   line-height: 1.25rem; |   line-height: 1.25rem; | ||||||
|  | @ -992,11 +1073,6 @@ body { | ||||||
|   line-height: 1rem; |   line-height: 1rem; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| .text-base { |  | ||||||
|   font-size: 1rem; |  | ||||||
|   line-height: 1.5rem; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| .font-black { | .font-black { | ||||||
|   font-weight: 900; |   font-weight: 900; | ||||||
| } | } | ||||||
|  | @ -1005,14 +1081,14 @@ body { | ||||||
|   font-weight: 500; |   font-weight: 500; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| .font-semibold { |  | ||||||
|   font-weight: 600; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| .font-normal { | .font-normal { | ||||||
|   font-weight: 400; |   font-weight: 400; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | .font-semibold { | ||||||
|  |   font-weight: 600; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| .capitalize { | .capitalize { | ||||||
|   text-transform: capitalize; |   text-transform: capitalize; | ||||||
| } | } | ||||||
|  | @ -1025,6 +1101,10 @@ body { | ||||||
|   letter-spacing: 0.1em; |   letter-spacing: 0.1em; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | .text-current { | ||||||
|  |   color: currentColor; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| .text-destructive { | .text-destructive { | ||||||
|   color: hsl(var(--destructive)); |   color: hsl(var(--destructive)); | ||||||
| } | } | ||||||
|  | @ -1053,15 +1133,19 @@ body { | ||||||
|   color: hsl(var(--secondary-foreground)); |   color: hsl(var(--secondary-foreground)); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| .text-current { |  | ||||||
|   color: currentColor; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| .text-white { | .text-white { | ||||||
|   --tw-text-opacity: 1; |   --tw-text-opacity: 1; | ||||||
|   color: rgb(255 255 255 / var(--tw-text-opacity)); |   color: rgb(255 255 255 / var(--tw-text-opacity)); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | .text-foreground { | ||||||
|  |   color: hsl(var(--foreground)); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .text-foreground\/50 { | ||||||
|  |   color: hsl(var(--foreground) / 0.5); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| .underline { | .underline { | ||||||
|   text-decoration-line: underline; |   text-decoration-line: underline; | ||||||
| } | } | ||||||
|  | @ -1070,12 +1154,20 @@ body { | ||||||
|   text-underline-offset: 4px; |   text-underline-offset: 4px; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | .opacity-50 { | ||||||
|  |   opacity: 0.5; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| .opacity-60 { | .opacity-60 { | ||||||
|   opacity: 0.6; |   opacity: 0.6; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| .opacity-50 { | .opacity-0 { | ||||||
|   opacity: 0.5; |   opacity: 0; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .opacity-90 { | ||||||
|  |   opacity: 0.9; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| .shadow-lg { | .shadow-lg { | ||||||
|  | @ -1113,6 +1205,18 @@ body { | ||||||
|   transition-duration: 150ms; |   transition-duration: 150ms; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | .transition-all { | ||||||
|  |   transition-property: all; | ||||||
|  |   transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1); | ||||||
|  |   transition-duration: 150ms; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .transition-opacity { | ||||||
|  |   transition-property: opacity; | ||||||
|  |   transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1); | ||||||
|  |   transition-duration: 150ms; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| @keyframes enter { | @keyframes enter { | ||||||
|   from { |   from { | ||||||
|     opacity: var(--tw-enter-opacity, 1); |     opacity: var(--tw-enter-opacity, 1); | ||||||
|  | @ -1172,10 +1276,18 @@ body { | ||||||
|   background-color: hsl(var(--secondary) / 0.8); |   background-color: hsl(var(--secondary) / 0.8); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | .hover\:bg-secondary:hover { | ||||||
|  |   background-color: hsl(var(--secondary)); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| .hover\:text-accent-foreground:hover { | .hover\:text-accent-foreground:hover { | ||||||
|   color: hsl(var(--accent-foreground)); |   color: hsl(var(--accent-foreground)); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | .hover\:text-foreground:hover { | ||||||
|  |   color: hsl(var(--foreground)); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| .hover\:underline:hover { | .hover\:underline:hover { | ||||||
|   text-decoration-line: underline; |   text-decoration-line: underline; | ||||||
| } | } | ||||||
|  | @ -1188,6 +1300,10 @@ body { | ||||||
|   color: hsl(var(--accent-foreground)); |   color: hsl(var(--accent-foreground)); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | .focus\:opacity-100:focus { | ||||||
|  |   opacity: 1; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| .focus\:outline-none:focus { | .focus\:outline-none:focus { | ||||||
|   outline: 2px solid transparent; |   outline: 2px solid transparent; | ||||||
|   outline-offset: 2px; |   outline-offset: 2px; | ||||||
|  | @ -1238,6 +1354,49 @@ body { | ||||||
|   opacity: 0.5; |   opacity: 0.5; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | .group:hover .group-hover\:opacity-100 { | ||||||
|  |   opacity: 1; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .group.destructive .group-\[\.destructive\]\:border-muted\/40 { | ||||||
|  |   border-color: hsl(var(--muted) / 0.4); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .group.destructive .group-\[\.destructive\]\:text-red-300 { | ||||||
|  |   --tw-text-opacity: 1; | ||||||
|  |   color: rgb(252 165 165 / var(--tw-text-opacity)); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .group.destructive .group-\[\.destructive\]\:hover\:border-destructive\/30:hover { | ||||||
|  |   border-color: hsl(var(--destructive) / 0.3); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .group.destructive .group-\[\.destructive\]\:hover\:bg-destructive:hover { | ||||||
|  |   background-color: hsl(var(--destructive)); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .group.destructive .group-\[\.destructive\]\:hover\:text-destructive-foreground:hover { | ||||||
|  |   color: hsl(var(--destructive-foreground)); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .group.destructive .group-\[\.destructive\]\:hover\:text-red-50:hover { | ||||||
|  |   --tw-text-opacity: 1; | ||||||
|  |   color: rgb(254 242 242 / var(--tw-text-opacity)); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .group.destructive .group-\[\.destructive\]\:focus\:ring-destructive:focus { | ||||||
|  |   --tw-ring-color: hsl(var(--destructive)); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .group.destructive .group-\[\.destructive\]\:focus\:ring-red-400:focus { | ||||||
|  |   --tw-ring-opacity: 1; | ||||||
|  |   --tw-ring-color: rgb(248 113 113 / var(--tw-ring-opacity)); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .group.destructive .group-\[\.destructive\]\:focus\:ring-offset-red-600:focus { | ||||||
|  |   --tw-ring-offset-color: #dc2626; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| .peer:disabled ~ .peer-disabled\:cursor-not-allowed { | .peer:disabled ~ .peer-disabled\:cursor-not-allowed { | ||||||
|   cursor: not-allowed; |   cursor: not-allowed; | ||||||
| } | } | ||||||
|  | @ -1270,6 +1429,25 @@ body { | ||||||
|   transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); |   transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | .data-\[swipe\=cancel\]\:translate-x-0[data-swipe=cancel] { | ||||||
|  |   --tw-translate-x: 0px; | ||||||
|  |   transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .data-\[swipe\=end\]\:translate-x-\[var\(--radix-toast-swipe-end-x\)\][data-swipe=end] { | ||||||
|  |   --tw-translate-x: var(--radix-toast-swipe-end-x); | ||||||
|  |   transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .data-\[swipe\=move\]\:translate-x-\[var\(--radix-toast-swipe-move-x\)\][data-swipe=move] { | ||||||
|  |   --tw-translate-x: var(--radix-toast-swipe-move-x); | ||||||
|  |   transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .data-\[state\=checked\]\:bg-primary[data-state=checked] { | ||||||
|  |   background-color: hsl(var(--primary)); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| .data-\[state\=open\]\:bg-accent[data-state=open] { | .data-\[state\=open\]\:bg-accent[data-state=open] { | ||||||
|   background-color: hsl(var(--accent)); |   background-color: hsl(var(--accent)); | ||||||
| } | } | ||||||
|  | @ -1278,10 +1456,6 @@ body { | ||||||
|   background-color: hsl(var(--muted)); |   background-color: hsl(var(--muted)); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| .data-\[state\=checked\]\:bg-primary[data-state=checked] { |  | ||||||
|   background-color: hsl(var(--primary)); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| .data-\[state\=checked\]\:text-primary-foreground[data-state=checked] { | .data-\[state\=checked\]\:text-primary-foreground[data-state=checked] { | ||||||
|   color: hsl(var(--primary-foreground)); |   color: hsl(var(--primary-foreground)); | ||||||
| } | } | ||||||
|  | @ -1290,6 +1464,10 @@ body { | ||||||
|   opacity: 0.5; |   opacity: 0.5; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | .data-\[swipe\=move\]\:transition-none[data-swipe=move] { | ||||||
|  |   transition-property: none; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| .data-\[state\=open\]\:animate-in[data-state=open] { | .data-\[state\=open\]\:animate-in[data-state=open] { | ||||||
|   animation-name: enter; |   animation-name: enter; | ||||||
|   animation-duration: 150ms; |   animation-duration: 150ms; | ||||||
|  | @ -1310,6 +1488,16 @@ body { | ||||||
|   --tw-exit-translate-y: initial; |   --tw-exit-translate-y: initial; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | .data-\[swipe\=end\]\:animate-out[data-swipe=end] { | ||||||
|  |   animation-name: exit; | ||||||
|  |   animation-duration: 150ms; | ||||||
|  |   --tw-exit-opacity: initial; | ||||||
|  |   --tw-exit-scale: initial; | ||||||
|  |   --tw-exit-rotate: initial; | ||||||
|  |   --tw-exit-translate-x: initial; | ||||||
|  |   --tw-exit-translate-y: initial; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| .data-\[state\=closed\]\:fade-out-0[data-state=closed] { | .data-\[state\=closed\]\:fade-out-0[data-state=closed] { | ||||||
|   --tw-exit-opacity: 0; |   --tw-exit-opacity: 0; | ||||||
| } | } | ||||||
|  | @ -1318,6 +1506,10 @@ body { | ||||||
|   --tw-enter-opacity: 0; |   --tw-enter-opacity: 0; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | .data-\[state\=closed\]\:fade-out-80[data-state=closed] { | ||||||
|  |   --tw-exit-opacity: 0.8; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| .data-\[state\=closed\]\:zoom-out-95[data-state=closed] { | .data-\[state\=closed\]\:zoom-out-95[data-state=closed] { | ||||||
|   --tw-exit-scale: .95; |   --tw-exit-scale: .95; | ||||||
| } | } | ||||||
|  | @ -1342,6 +1534,42 @@ body { | ||||||
|   --tw-enter-translate-y: 0.5rem; |   --tw-enter-translate-y: 0.5rem; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | .data-\[state\=closed\]\:slide-out-to-right-full[data-state=closed] { | ||||||
|  |   --tw-exit-translate-x: 100%; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .data-\[state\=open\]\:slide-in-from-top-full[data-state=open] { | ||||||
|  |   --tw-enter-translate-y: -100%; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | @media (min-width: 640px) { | ||||||
|  |   .sm\:bottom-0 { | ||||||
|  |     bottom: 0px; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   .sm\:right-0 { | ||||||
|  |     right: 0px; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   .sm\:top-auto { | ||||||
|  |     top: auto; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   .sm\:flex-col { | ||||||
|  |     flex-direction: column; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   .data-\[state\=open\]\:sm\:slide-in-from-bottom-full[data-state=open] { | ||||||
|  |     --tw-enter-translate-y: 100%; | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | @media (min-width: 768px) { | ||||||
|  |   .md\:max-w-\[420px\] { | ||||||
|  |     max-width: 420px; | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | 
 | ||||||
| .\[\&\:has\(\[role\=checkbox\]\)\]\:pr-0:has([role=checkbox]) { | .\[\&\:has\(\[role\=checkbox\]\)\]\:pr-0:has([role=checkbox]) { | ||||||
|   padding-right: 0px; |   padding-right: 0px; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -0,0 +1,86 @@ | ||||||
|  | "use client" | ||||||
|  | 
 | ||||||
|  | import Link from "next/link" | ||||||
|  | import { zodResolver } from "@hookform/resolvers/zod" | ||||||
|  | import { useForm } from "react-hook-form" | ||||||
|  | import { z } from "zod" | ||||||
|  | 
 | ||||||
|  | import { Button } from "@/components/ui/button" | ||||||
|  | import { | ||||||
|  | 	Form, | ||||||
|  | 	FormControl, | ||||||
|  | 	FormDescription, | ||||||
|  | 	FormField, | ||||||
|  | 	FormItem, | ||||||
|  | 	FormLabel, | ||||||
|  | 	FormMessage, | ||||||
|  | } from "@/components/ui/form" | ||||||
|  | import { | ||||||
|  | 	Select, | ||||||
|  | 	SelectContent, | ||||||
|  | 	SelectItem, | ||||||
|  | 	SelectTrigger, | ||||||
|  | 	SelectValue, | ||||||
|  | } from "@/components/ui/select" | ||||||
|  | import { toast } from "@/components/ui/use-toast" | ||||||
|  | 
 | ||||||
|  | const FormSchema = z.object({ | ||||||
|  | 	email: z | ||||||
|  | 		.string({ | ||||||
|  | 			required_error: "Please select an email to display.", | ||||||
|  | 		}) | ||||||
|  | 		.email(), | ||||||
|  | }) | ||||||
|  | 
 | ||||||
|  | export function SelectForm() { | ||||||
|  | 	const form = useForm<z.infer<typeof FormSchema>>({ | ||||||
|  | 		resolver: zodResolver(FormSchema), | ||||||
|  | 	}) | ||||||
|  | 
 | ||||||
|  | 	function onSubmit(data: z.infer<typeof FormSchema>) { | ||||||
|  | 		toast({ | ||||||
|  | 			title: "You submitted the following values:", | ||||||
|  | 			description: ( | ||||||
|  | 				<pre className="mt-2 w-[340px] rounded-md bg-slate-950 p-4"> | ||||||
|  | 					<code className="text-white">{JSON.stringify(data, null, 2)}</code> | ||||||
|  | 				</pre> | ||||||
|  | 			), | ||||||
|  | 		}) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | 	return ( | ||||||
|  | 		<Form {...form}> | ||||||
|  | 			<form onSubmit={form.handleSubmit(onSubmit)} className="w-2/3 space-y-6"> | ||||||
|  | 				<FormField | ||||||
|  | 					control={form.control} | ||||||
|  | 					name="email" | ||||||
|  | 					render={({ field }) => ( | ||||||
|  | 						<FormItem> | ||||||
|  | 							<FormLabel>Email</FormLabel> | ||||||
|  | 							<Select onValueChange={field.onChange} defaultValue={field.value}> | ||||||
|  | 								<FormControl> | ||||||
|  | 									<SelectTrigger> | ||||||
|  | 										<SelectValue placeholder="Select a verified email to display" /> | ||||||
|  | 									</SelectTrigger> | ||||||
|  | 								</FormControl> | ||||||
|  | 								<SelectContent> | ||||||
|  | 									<SelectItem value="m@example.com">m@example.com</SelectItem> | ||||||
|  | 									<SelectItem value="m@google.com">m@google.com</SelectItem> | ||||||
|  | 									<SelectItem value="m@support.com">m@support.com</SelectItem> | ||||||
|  | 								</SelectContent> | ||||||
|  | 							</Select> | ||||||
|  | 							<FormDescription> | ||||||
|  | 								You can manage email addresses in your{" "} | ||||||
|  | 								<Link href="/examples/forms">email settings</Link>. | ||||||
|  | 							</FormDescription> | ||||||
|  | 							<FormMessage /> | ||||||
|  | 						</FormItem> | ||||||
|  | 					)} | ||||||
|  | 				/> | ||||||
|  | 				<Button type="submit">Submit</Button> | ||||||
|  | 			</form> | ||||||
|  | 		</Form> | ||||||
|  | 	) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | @ -4,6 +4,7 @@ import { z } from "zod" | ||||||
| import { zodResolver } from "@hookform/resolvers/zod" | import { zodResolver } from "@hookform/resolvers/zod" | ||||||
| import { useForm } from "react-hook-form" | import { useForm } from "react-hook-form" | ||||||
| import { Button } from "@/components/ui/button" | import { Button } from "@/components/ui/button" | ||||||
|  | import { toast } from "@/components/ui/use-toast" | ||||||
| import { | import { | ||||||
| 	Form, | 	Form, | ||||||
| 	FormItem, | 	FormItem, | ||||||
|  | @ -22,19 +23,21 @@ import { | ||||||
| } from "@/components/ui/select" | } from "@/components/ui/select" | ||||||
| import { ItemText, SelectItemIndicator, SelectItemText } from "@radix-ui/react-select" | import { ItemText, SelectItemIndicator, SelectItemText } from "@radix-ui/react-select" | ||||||
| 
 | 
 | ||||||
| const formSchema = z.object({ | const FormSchema = z.object({ | ||||||
| 	storyId: z.coerce.number(), | 	storyId: z.string(), | ||||||
| 	pubId: z.number(), | 	pubId: z.string(), | ||||||
| 	submitted: z.date(), | 	// submitted: z.date(),
 | ||||||
| 	responded: z.date(), | 	// responded: z.date(),
 | ||||||
| 	responseId: z.number() | 	// responseId: z.string()
 | ||||||
| }) | }) | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| export default function SubmissionForm({ stories, pubs, responses }) { | export default function SubmissionForm({ stories, pubs, responses }) { | ||||||
| 
 | 	const form = useForm<z.infer<typeof FormSchema>>({ | ||||||
|  | 		resolver: zodResolver(FormSchema), | ||||||
|  | 	}) | ||||||
| 	const storiesSelectItems = stories.map(e => ( | 	const storiesSelectItems = stories.map(e => ( | ||||||
| 		<SelectItem value={e.id} textValue={e.title}> | 		<SelectItem value={e.id.toString()} key={e.title}> | ||||||
| 			{e.title} | 			{e.title} | ||||||
| 		</SelectItem> | 		</SelectItem> | ||||||
| 	)) | 	)) | ||||||
|  | @ -50,43 +53,79 @@ export default function SubmissionForm({ stories, pubs, responses }) { | ||||||
| 		</SelectItem> | 		</SelectItem> | ||||||
| 	)) | 	)) | ||||||
| 
 | 
 | ||||||
| 	// 1. Define your form.
 | 
 | ||||||
| 	const form = useForm<z.infer<typeof formSchema>>({ |  | ||||||
| 		resolver: zodResolver(formSchema), |  | ||||||
| 		defaultValues: { |  | ||||||
| 			storyId: stories[0].id, |  | ||||||
| 			pubId: pubs[0].id, |  | ||||||
| 			submitted: new Date(), |  | ||||||
| 			responded: null, |  | ||||||
| 			responseId: responses[0].id |  | ||||||
| 		}, |  | ||||||
| 	}) |  | ||||||
| 	// 2. Define a submit handler.
 | 	// 2. Define a submit handler.
 | ||||||
| 	function onSubmit(values: z.infer<typeof formSchema>) { | 	function onSubmit(values: z.infer<typeof FormSchema>) { | ||||||
| 		// Do something with the form values.
 | 		// Do something with the form values.
 | ||||||
| 		// ✅ This will be type-safe and validated.
 | 		// ✅ This will be type-safe and validated.
 | ||||||
|  | 		toast({ | ||||||
|  | 			title: "You submitted the following values:", | ||||||
|  | 			description: ( | ||||||
|  | 				<pre className="mt-2 w-[340px] rounded-md bg-slate-950 p-4"> | ||||||
|  | 					<code className="text-white">{JSON.stringify(values, null, 2)}</code> | ||||||
|  | 				</pre> | ||||||
|  | 			), | ||||||
|  | 		}) | ||||||
| 		console.log(values) | 		console.log(values) | ||||||
| 	} | 	} | ||||||
|  | 
 | ||||||
|  | 	function onErrors(errors) { | ||||||
|  | 		toast({ | ||||||
|  | 			title: "You have errors", | ||||||
|  | 			description: ( | ||||||
|  | 				<pre className="mt-2 w-[340px] rounded-md bg-slate-950 p-4"> | ||||||
|  | 					<code className="text-white">{JSON.stringify(errors, null, 2)}</code> | ||||||
|  | 				</pre> | ||||||
|  | 			), | ||||||
|  | 		}) | ||||||
|  | 		console.log(JSON.stringify(errors)) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
| 	return ( | 	return ( | ||||||
| 		<Form {...form}> | 		<Form {...form}> | ||||||
| 			<form onSubmit={form.handleSubmit(onSubmit)} className="space-y-8"> | 			<form onSubmit={form.handleSubmit(onSubmit, onErrors)} className="space-y-8"> | ||||||
| 				<FormField | 				<FormField | ||||||
| 					control={form.control} | 					control={form.control} | ||||||
| 					name="storyId" | 					name="storyId" | ||||||
| 					render={({ field }) => ( | 					render={({ field }) => ( | ||||||
| 						<FormItem> | 						<FormItem> | ||||||
| 							<FormLabel>Story</FormLabel> | 							<FormLabel>Story</FormLabel> | ||||||
| 							<Select name="storyId" onValueChange={field.onChange}> | 							<Select onValueChange={field.onChange} defaultValue={field.value}> | ||||||
| 								<FormControl> | 								<FormControl> | ||||||
| 									<SelectTrigger> | 									<SelectTrigger> | ||||||
| 										<SelectValue placeholder="Select the story you have submitted" /> | 										<SelectValue placeholder="Select something"> | ||||||
|  | 											<p>{stories?.find(e => e.id === Number(field.value))?.title ?? null}</p> | ||||||
|  | 										</SelectValue> | ||||||
| 									</SelectTrigger> | 									</SelectTrigger> | ||||||
| 								</FormControl> | 								</FormControl> | ||||||
| 								<SelectContent> | 								<SelectContent> | ||||||
| 									{storiesSelectItems} | 									{storiesSelectItems} | ||||||
| 								</SelectContent> | 								</SelectContent> | ||||||
| 							</Select> | 							</Select> | ||||||
| 							<FormDescription>This is the story you submitted, yeah?</FormDescription> | 							<FormDescription>The piece you submitted</FormDescription> | ||||||
|  | 							<FormMessage /> | ||||||
|  | 						</FormItem> | ||||||
|  | 					)} | ||||||
|  | 				/> | ||||||
|  | 				<FormField | ||||||
|  | 					control={form.control} | ||||||
|  | 					name="pubId" | ||||||
|  | 					render={({ field }) => ( | ||||||
|  | 						<FormItem> | ||||||
|  | 							<FormLabel>Publication</FormLabel> | ||||||
|  | 							<Select onValueChange={field.onChange} defaultValue={field.value}> | ||||||
|  | 								<FormControl> | ||||||
|  | 									<SelectTrigger> | ||||||
|  | 										<SelectValue placeholder="Select something"> | ||||||
|  | 											<p>{pubs?.find(e => e.id === Number(field.value))?.title ?? null}</p> | ||||||
|  | 										</SelectValue> | ||||||
|  | 									</SelectTrigger> | ||||||
|  | 								</FormControl> | ||||||
|  | 								<SelectContent> | ||||||
|  | 									{pubsSelectItems} | ||||||
|  | 								</SelectContent> | ||||||
|  | 							</Select> | ||||||
|  | 							<FormDescription>The market you sent it to</FormDescription> | ||||||
| 							<FormMessage /> | 							<FormMessage /> | ||||||
| 						</FormItem> | 						</FormItem> | ||||||
| 					)} | 					)} | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue