Update configuration and README for improved setup and security; disable default API and emoji sync, and enhance Discord permission checks in API routes.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
TheOnlyMace
2026-07-21 16:00:52 +02:00
commit fdfc8de44d
925 changed files with 75254 additions and 0 deletions

View File

@@ -0,0 +1,71 @@
/**
* ╔══════════════════════════════════════════════════════════════════╗
* ║ ║
* ║ ░█▀▀░█▀█░█▀▄░█▀▀░█░█ ░█▀▄░█▀▀░█░█░█▀▀ ║
* ║ ░█░░░█░█░█░█░█▀▀░▄▀▄ ░█░█░█▀▀░▀▄▀░▀▀█ ║
* ║ ░▀▀▀░▀▀▀░▀▀░░▀▀▀░▀░▀ ░▀▀░░▀▀▀░░▀░░▀▀▀ ║
* ║ ║
* ║ © 2026 CodeX Devs — All Rights Reserved ║
* ║ ║
* ║ discord ── https://discord.gg/codexdev ║
* ║ youtube ── https://youtube.com/@CodeXDevs ║
* ║ github ── https://github.com/RayExo ║
* ║ ║
* ╚══════════════════════════════════════════════════════════════════╝
*/
import * as React from "react"
import { Slot } from "@radix-ui/react-slot"
import { cva, type VariantProps } from "class-variance-authority"
import { cn } from "@/lib/utils"
const buttonVariants = cva(
"inline-flex items-center justify-center whitespace-nowrap rounded-xl text-sm font-medium ring-offset-background transition-all focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 active:scale-95",
{
variants: {
variant: {
default: "bg-primary text-white hover:bg-primary-hover shadow-lg shadow-primary/20",
destructive:
"bg-destructive text-destructive-foreground hover:bg-destructive/90 shadow-lg shadow-destructive/20",
outline:
"border border-slate-700 bg-transparent hover:bg-slate-800 hover:text-white hover:border-slate-600",
secondary:
"bg-slate-800 text-slate-200 hover:bg-slate-700 hover:text-white",
ghost: "hover:bg-slate-800 hover:text-white",
link: "text-primary underline-offset-4 hover:underline",
},
size: {
default: "h-11 px-6 py-2",
sm: "h-9 rounded-lg px-3",
lg: "h-12 rounded-2xl px-8",
icon: "h-11 w-11",
},
},
defaultVariants: {
variant: "default",
size: "default",
},
}
)
export interface ButtonProps
extends React.ButtonHTMLAttributes<HTMLButtonElement>,
VariantProps<typeof buttonVariants> {
asChild?: boolean
}
const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
({ className, variant, size, asChild = false, ...props }, ref) => {
const Comp = asChild ? Slot : "button"
return (
<Comp
className={cn(buttonVariants({ variant, size, className }))}
ref={ref}
{...props}
/>
)
}
)
Button.displayName = "Button"
export { Button, buttonVariants }

View File

@@ -0,0 +1,94 @@
/**
* ╔══════════════════════════════════════════════════════════════════╗
* ║ ║
* ║ ░█▀▀░█▀█░█▀▄░█▀▀░█░█ ░█▀▄░█▀▀░█░█░█▀▀ ║
* ║ ░█░░░█░█░█░█░█▀▀░▄▀▄ ░█░█░█▀▀░▀▄▀░▀▀█ ║
* ║ ░▀▀▀░▀▀▀░▀▀░░▀▀▀░▀░▀ ░▀▀░░▀▀▀░░▀░░▀▀▀ ║
* ║ ║
* ║ © 2026 CodeX Devs — All Rights Reserved ║
* ║ ║
* ║ discord ── https://discord.gg/codexdev ║
* ║ youtube ── https://youtube.com/@CodeXDevs ║
* ║ github ── https://github.com/RayExo ║
* ║ ║
* ╚══════════════════════════════════════════════════════════════════╝
*/
import * as React from "react"
import { cn } from "@/lib/utils"
const Card = React.forwardRef<
HTMLDivElement,
React.HTMLAttributes<HTMLDivElement>
>(({ className, ...props }, ref) => (
<div
ref={ref}
className={cn(
"rounded-3xl border border-slate-800 bg-[#141B2D] text-white shadow-xl shadow-black/20",
className
)}
{...props}
/>
))
Card.displayName = "Card"
const CardHeader = React.forwardRef<
HTMLDivElement,
React.HTMLAttributes<HTMLDivElement>
>(({ className, ...props }, ref) => (
<div
ref={ref}
className={cn("flex flex-col space-y-1.5 p-6", className)}
{...props}
/>
))
CardHeader.displayName = "CardHeader"
const CardTitle = React.forwardRef<
HTMLParagraphElement,
React.HTMLAttributes<HTMLHeadingElement>
>(({ className, ...props }, ref) => (
<h3
ref={ref}
className={cn(
"text-xl font-bold text-white tracking-tight",
className
)}
{...props}
/>
))
CardTitle.displayName = "CardTitle"
const CardDescription = React.forwardRef<
HTMLParagraphElement,
React.HTMLAttributes<HTMLParagraphElement>
>(({ className, ...props }, ref) => (
<p
ref={ref}
className={cn("text-sm text-slate-400", className)}
{...props}
/>
))
CardDescription.displayName = "CardDescription"
const CardContent = React.forwardRef<
HTMLDivElement,
React.HTMLAttributes<HTMLDivElement>
>(({ className, ...props }, ref) => (
<div ref={ref} className={cn("p-6 pt-0", className)} {...props} />
))
CardContent.displayName = "CardContent"
const CardFooter = React.forwardRef<
HTMLDivElement,
React.HTMLAttributes<HTMLDivElement>
>(({ className, ...props }, ref) => (
<div
ref={ref}
className={cn("flex items-center p-6 pt-0", className)}
{...props}
/>
))
CardFooter.displayName = "CardFooter"
export { Card, CardHeader, CardFooter, CardTitle, CardDescription, CardContent }

View File

@@ -0,0 +1,40 @@
/**
* ╔══════════════════════════════════════════════════════════════════╗
* ║ ║
* ║ ░█▀▀░█▀█░█▀▄░█▀▀░█░█ ░█▀▄░█▀▀░█░█░█▀▀ ║
* ║ ░█░░░█░█░█░█░█▀▀░▄▀▄ ░█░█░█▀▀░▀▄▀░▀▀█ ║
* ║ ░▀▀▀░▀▀▀░▀▀░░▀▀▀░▀░▀ ░▀▀░░▀▀▀░░▀░░▀▀▀ ║
* ║ ║
* ║ © 2026 CodeX Devs — All Rights Reserved ║
* ║ ║
* ║ discord ── https://discord.gg/codexdev ║
* ║ youtube ── https://youtube.com/@CodeXDevs ║
* ║ github ── https://github.com/RayExo ║
* ║ ║
* ╚══════════════════════════════════════════════════════════════════╝
*/
import * as React from "react"
import { cn } from "@/lib/utils"
export interface InputProps
extends React.InputHTMLAttributes<HTMLInputElement> {}
const Input = React.forwardRef<HTMLInputElement, InputProps>(
({ className, type, ...props }, ref) => {
return (
<input
type={type}
className={cn(
"flex h-12 w-full rounded-xl border border-slate-800 bg-slate-900/50 px-4 py-2 text-sm ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-slate-500 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary/50 focus-visible:ring-offset-0 disabled:cursor-not-allowed disabled:opacity-50 transition-all",
className
)}
ref={ref}
{...props}
/>
)
}
)
Input.displayName = "Input"
export { Input }

View File

@@ -0,0 +1,35 @@
/**
* ╔══════════════════════════════════════════════════════════════════╗
* ║ ║
* ║ ░█▀▀░█▀█░█▀▄░█▀▀░█░█ ░█▀▄░█▀▀░█░█░█▀▀ ║
* ║ ░█░░░█░█░█░█░█▀▀░▄▀▄ ░█░█░█▀▀░▀▄▀░▀▀█ ║
* ║ ░▀▀▀░▀▀▀░▀▀░░▀▀▀░▀░▀ ░▀▀░░▀▀▀░░▀░░▀▀▀ ║
* ║ ║
* ║ © 2026 CodeX Devs — All Rights Reserved ║
* ║ ║
* ║ discord ── https://discord.gg/codexdev ║
* ║ youtube ── https://youtube.com/@CodeXDevs ║
* ║ github ── https://github.com/RayExo ║
* ║ ║
* ╚══════════════════════════════════════════════════════════════════╝
*/
import * as React from "react"
import { cn } from "@/lib/utils"
const Label = React.forwardRef<
HTMLLabelElement,
React.LabelHTMLAttributes<HTMLLabelElement>
>(({ className, ...props }, ref) => (
<label
ref={ref}
className={cn(
"text-sm font-bold leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70 text-slate-300",
className
)}
{...props}
/>
))
Label.displayName = "Label"
export { Label }

View File

@@ -0,0 +1,194 @@
/**
* ╔══════════════════════════════════════════════════════════════════╗
* ║ ║
* ║ ░█▀▀░█▀█░█▀▄░█▀▀░█░█ ░█▀▄░█▀▀░█░█░█▀▀ ║
* ║ ░█░░░█░█░█░█░█▀▀░▄▀▄ ░█░█░█▀▀░▀▄▀░▀▀█ ║
* ║ ░▀▀▀░▀▀▀░▀▀░░▀▀▀░▀░▀ ░▀▀░░▀▀▀░░▀░░▀▀▀ ║
* ║ ║
* ║ © 2026 CodeX Devs — All Rights Reserved ║
* ║ ║
* ║ discord ── https://discord.gg/codexdev ║
* ║ youtube ── https://youtube.com/@CodeXDevs ║
* ║ github ── https://github.com/RayExo ║
* ║ ║
* ╚══════════════════════════════════════════════════════════════════╝
*/
"use client"
import * as React from "react"
import { ChevronDown, Check } from "lucide-react"
import { cn } from "@/lib/utils"
// Context for sub-components
const SelectContext = React.createContext<{
value: string
onValueChange: (value: string) => void
isOpen: boolean
setIsOpen: (open: boolean) => void
} | null>(null)
export interface SelectOption {
value: string
label: string
}
interface SelectProps {
children?: React.ReactNode
value: string
onValueChange: (value: string) => void
// Legacy props compatibility
options?: SelectOption[]
placeholder?: string
className?: string
disabled?: boolean
}
const Select = ({ children, value, onValueChange, options, placeholder, className, disabled }: SelectProps) => {
const [isOpen, setIsOpen] = React.useState(false)
const containerRef = React.useRef<HTMLDivElement>(null)
React.useEffect(() => {
const handleClickOutside = (event: MouseEvent) => {
if (containerRef.current && !containerRef.current.contains(event.target as Node)) {
setIsOpen(false)
}
}
document.addEventListener("mousedown", handleClickOutside)
return () => document.removeEventListener("mousedown", handleClickOutside)
}, [])
// If options are provided, use the legacy rendering
if (options) {
const selectedOption = options.find((opt) => opt.value === value)
return (
<div className={cn("relative w-full", className)} ref={containerRef}>
<button
type="button"
disabled={disabled}
onClick={() => setIsOpen(!isOpen)}
className={cn(
"flex h-10 w-full items-center justify-between rounded-xl border border-slate-800 bg-slate-900/50 px-4 py-2 text-sm transition-all focus:outline-none focus:ring-2 focus:ring-primary/50 disabled:cursor-not-allowed disabled:opacity-50",
isOpen && "ring-2 ring-primary/50 border-slate-700"
)}
>
<span className={cn("truncate", !selectedOption && "text-slate-500")}>
{selectedOption ? selectedOption.label : placeholder}
</span>
<ChevronDown className={cn("h-4 w-4 text-slate-500 transition-transform duration-200", isOpen && "rotate-180")} />
</button>
{isOpen && (
<div className="absolute top-full z-50 mt-2 w-full overflow-hidden rounded-xl border border-slate-800 bg-[#141B2D] p-1 shadow-2xl animate-in fade-in zoom-in-95 duration-200">
<div className="max-h-60 overflow-y-auto overflow-x-hidden no-scrollbar">
{options.map((option) => (
<button
key={option.value}
type="button"
onClick={() => {
onValueChange(option.value)
setIsOpen(false)
}}
className={cn(
"flex w-full items-center justify-between rounded-lg px-3 py-2 text-sm transition-colors hover:bg-slate-800",
value === option.value ? "bg-primary text-white" : "text-slate-300"
)}
>
<span className="truncate">{option.label}</span>
{value === option.value && <Check className="h-4 w-4" />}
</button>
))}
</div>
</div>
)}
</div>
)
}
// Otherwise, use the sub-component pattern
return (
<SelectContext.Provider value={{ value, onValueChange, isOpen, setIsOpen }}>
<div className={cn("relative w-full", className)} ref={containerRef}>
{children}
</div>
</SelectContext.Provider>
)
}
const SelectTrigger = React.forwardRef<
HTMLButtonElement,
React.ButtonHTMLAttributes<HTMLButtonElement>
>(({ className, children, ...props }, ref) => {
const context = React.useContext(SelectContext)
if (!context) return null
return (
<button
ref={ref}
type="button"
onClick={() => context.setIsOpen(!context.isOpen)}
className={cn(
"flex h-10 w-full items-center justify-between rounded-xl border border-slate-800 bg-slate-900/50 px-4 py-2 text-sm transition-all focus:outline-none focus:ring-2 focus:ring-primary/50 disabled:cursor-not-allowed disabled:opacity-50",
context.isOpen && "ring-2 ring-primary/50 border-slate-700",
className
)}
{...props}
>
{children}
<ChevronDown className={cn("h-4 w-4 text-slate-500 transition-transform duration-200", context.isOpen && "rotate-180")} />
</button>
)
})
SelectTrigger.displayName = "SelectTrigger"
const SelectValue = ({ placeholder, className }: { placeholder?: string, className?: string }) => {
const context = React.useContext(SelectContext)
if (!context) return null
return <span className={cn("truncate", !context.value && "text-slate-500", className)}>{context.value || placeholder}</span>
}
const SelectContent = ({ children, className }: { children: React.ReactNode, className?: string }) => {
const context = React.useContext(SelectContext)
if (!context || !context.isOpen) return null
return (
<div className={cn("absolute top-full z-50 mt-2 w-full overflow-hidden rounded-xl border border-slate-800 bg-[#141B2D] p-1 shadow-2xl animate-in fade-in zoom-in-95 duration-200", className)}>
<div className="max-h-60 overflow-y-auto overflow-x-hidden no-scrollbar">
{children}
</div>
</div>
)
}
const SelectItem = React.forwardRef<
HTMLButtonElement,
React.ButtonHTMLAttributes<HTMLButtonElement> & { value: string }
>(({ className, children, value, ...props }, ref) => {
const context = React.useContext(SelectContext)
if (!context) return null
const isSelected = context.value === value
return (
<button
ref={ref}
type="button"
onClick={() => {
context.onValueChange(value)
context.setIsOpen(false)
}}
className={cn(
"flex w-full items-center justify-between rounded-lg px-3 py-2 text-sm transition-colors hover:bg-slate-800",
isSelected ? "bg-primary text-white" : "text-slate-300",
className
)}
{...props}
>
<span className="truncate">{children}</span>
{isSelected && <Check className="h-4 w-4" />}
</button>
)
})
SelectItem.displayName = "SelectItem"
export { Select, SelectTrigger, SelectValue, SelectContent, SelectItem }

View File

@@ -0,0 +1,41 @@
/**
* ╔══════════════════════════════════════════════════════════════════╗
* ║ ║
* ║ ░█▀▀░█▀█░█▀▄░█▀▀░█░█ ░█▀▄░█▀▀░█░█░█▀▀ ║
* ║ ░█░░░█░█░█░█░█▀▀░▄▀▄ ░█░█░█▀▀░▀▄▀░▀▀█ ║
* ║ ░▀▀▀░▀▀▀░▀▀░░▀▀▀░▀░▀ ░▀▀░░▀▀▀░░▀░░▀▀▀ ║
* ║ ║
* ║ © 2026 CodeX Devs — All Rights Reserved ║
* ║ ║
* ║ discord ── https://discord.gg/codexdev ║
* ║ youtube ── https://youtube.com/@CodeXDevs ║
* ║ github ── https://github.com/RayExo ║
* ║ ║
* ╚══════════════════════════════════════════════════════════════════╝
*/
import { Toaster as Sonner } from "sonner";
type ToasterProps = React.ComponentProps<typeof Sonner>;
const Toaster = ({ ...props }: ToasterProps) => {
return (
<Sonner
className="toaster group"
toastOptions={{
classNames: {
toast: "group toast group-[.toaster]:bg-[#141B2D] group-[.toaster]:text-slate-200 group-[.toaster]:border-slate-800 group-[.toaster]:shadow-2xl group-[.toaster]:rounded-2xl group-[.toaster]:p-4",
description: "group-[.toast]:text-slate-500 group-[.toast]:text-[11px] group-[.toast]:font-medium",
actionButton: "group-[.toast]:bg-primary group-[.toast]:text-primary-foreground",
cancelButton: "group-[.toast]:bg-slate-800 group-[.toast]:text-slate-400",
success: "group-[.toaster]:border-emerald-500/50 group-[.toaster]:bg-emerald-500/5",
error: "group-[.toaster]:border-red-500/50 group-[.toaster]:bg-red-500/5",
loading: "group-[.toaster]:border-primary/50 group-[.toaster]:bg-primary/5",
},
}}
{...props}
/>
);
};
export { Toaster };

View File

@@ -0,0 +1,44 @@
/**
* ╔══════════════════════════════════════════════════════════════════╗
* ║ ║
* ║ ░█▀▀░█▀█░█▀▄░█▀▀░█░█ ░█▀▄░█▀▀░█░█░█▀▀ ║
* ║ ░█░░░█░█░█░█░█▀▀░▄▀▄ ░█░█░█▀▀░▀▄▀░▀▀█ ║
* ║ ░▀▀▀░▀▀▀░▀▀░░▀▀▀░▀░▀ ░▀▀░░▀▀▀░░▀░░▀▀▀ ║
* ║ ║
* ║ © 2026 CodeX Devs — All Rights Reserved ║
* ║ ║
* ║ discord ── https://discord.gg/codexdev ║
* ║ youtube ── https://youtube.com/@CodeXDevs ║
* ║ github ── https://github.com/RayExo ║
* ║ ║
* ╚══════════════════════════════════════════════════════════════════╝
*/
"use client";
import * as React from "react"
import * as SwitchPrimitives from "@radix-ui/react-switch"
import { cn } from "@/lib/utils"
const Switch = React.forwardRef<
React.ElementRef<typeof SwitchPrimitives.Root>,
React.ComponentPropsWithoutRef<typeof SwitchPrimitives.Root>
>(({ className, ...props }, ref) => (
<SwitchPrimitives.Root
className={cn(
"peer inline-flex h-6 w-11 shrink-0 cursor-pointer items-center rounded-full border-2 border-transparent transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary focus-visible:ring-offset-2 focus-visible:ring-offset-[#0f172a] disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-primary data-[state=unchecked]:bg-slate-800",
className
)}
{...props}
ref={ref}
>
<SwitchPrimitives.Thumb
className={cn(
"pointer-events-none block h-5 w-5 rounded-full bg-white shadow-lg ring-0 transition-transform data-[state=checked]:translate-x-5 data-[state=unchecked]:translate-x-0"
)}
/>
</SwitchPrimitives.Root>
))
Switch.displayName = SwitchPrimitives.Root.displayName
export { Switch }

View File

@@ -0,0 +1,132 @@
/**
* ╔══════════════════════════════════════════════════════════════════╗
* ║ ║
* ║ ░█▀▀░█▀█░█▀▄░█▀▀░█░█ ░█▀▄░█▀▀░█░█░█▀▀ ║
* ║ ░█░░░█░█░█░█░█▀▀░▄▀▄ ░█░█░█▀▀░▀▄▀░▀▀█ ║
* ║ ░▀▀▀░▀▀▀░▀▀░░▀▀▀░▀░▀ ░▀▀░░▀▀▀░░▀░░▀▀▀ ║
* ║ ║
* ║ © 2026 CodeX Devs — All Rights Reserved ║
* ║ ║
* ║ discord ── https://discord.gg/codexdev ║
* ║ youtube ── https://youtube.com/@CodeXDevs ║
* ║ github ── https://github.com/RayExo ║
* ║ ║
* ╚══════════════════════════════════════════════════════════════════╝
*/
import * as React from "react"
import { cn } from "@/lib/utils"
const Table = React.forwardRef<
HTMLTableElement,
React.TableHTMLAttributes<HTMLTableElement>
>(({ className, ...props }, ref) => (
<div className="relative w-full overflow-auto">
<table
ref={ref}
className={cn("w-full caption-bottom text-sm", className)}
{...props}
/>
</div>
))
Table.displayName = "Table"
const TableHeader = React.forwardRef<
HTMLTableSectionElement,
React.HTMLAttributes<HTMLTableSectionElement>
>(({ className, ...props }, ref) => (
<thead ref={ref} className={cn("[&_tr]:border-b border-slate-800", className)} {...props} />
))
TableHeader.displayName = "TableHeader"
const TableBody = React.forwardRef<
HTMLTableSectionElement,
React.HTMLAttributes<HTMLTableSectionElement>
>(({ className, ...props }, ref) => (
<tbody
ref={ref}
className={cn("[&_tr:last-child]:border-0", className)}
{...props}
/>
))
TableBody.displayName = "TableBody"
const TableFooter = React.forwardRef<
HTMLTableSectionElement,
React.HTMLAttributes<HTMLTableSectionElement>
>(({ className, ...props }, ref) => (
<tfoot
ref={ref}
className={cn(
"border-t border-slate-800 bg-slate-900/50 font-medium [&>tr]:last:border-b-0",
className
)}
{...props}
/>
))
TableFooter.displayName = "TableFooter"
const TableRow = React.forwardRef<
HTMLTableRowElement,
React.HTMLAttributes<HTMLTableRowElement>
>(({ className, ...props }, ref) => (
<tr
ref={ref}
className={cn(
"border-b border-slate-800 transition-colors hover:bg-slate-800/50 data-[state=selected]:bg-slate-800",
className
)}
{...props}
/>
))
TableRow.displayName = "TableRow"
const TableHead = React.forwardRef<
HTMLTableCellElement,
React.ThHTMLAttributes<HTMLTableCellElement>
>(({ className, ...props }, ref) => (
<th
ref={ref}
className={cn(
"h-12 px-4 text-left align-middle font-bold text-slate-400 [&:has([role=checkbox])]:pr-0",
className
)}
{...props}
/>
))
TableHead.displayName = "TableHead"
const TableCell = React.forwardRef<
HTMLTableCellElement,
React.TdHTMLAttributes<HTMLTableCellElement>
>(({ className, ...props }, ref) => (
<td
ref={ref}
className={cn("p-4 align-middle [&:has([role=checkbox])]:pr-0 text-white", className)}
{...props}
/>
))
TableCell.displayName = "TableCell"
const TableCaption = React.forwardRef<
HTMLTableCaptionElement,
React.HTMLAttributes<HTMLTableCaptionElement>
>(({ className, ...props }, ref) => (
<caption
ref={ref}
className={cn("mt-4 text-sm text-slate-500", className)}
{...props}
/>
))
TableCaption.displayName = "TableCaption"
export {
Table,
TableHeader,
TableBody,
TableFooter,
TableHead,
TableRow,
TableCell,
TableCaption,
}

View File

@@ -0,0 +1,39 @@
/**
* ╔══════════════════════════════════════════════════════════════════╗
* ║ ║
* ║ ░█▀▀░█▀█░█▀▄░█▀▀░█░█ ░█▀▄░█▀▀░█░█░█▀▀ ║
* ║ ░█░░░█░█░█░█░█▀▀░▄▀▄ ░█░█░█▀▀░▀▄▀░▀▀█ ║
* ║ ░▀▀▀░▀▀▀░▀▀░░▀▀▀░▀░▀ ░▀▀░░▀▀▀░░▀░░▀▀▀ ║
* ║ ║
* ║ © 2026 CodeX Devs — All Rights Reserved ║
* ║ ║
* ║ discord ── https://discord.gg/codexdev ║
* ║ youtube ── https://youtube.com/@CodeXDevs ║
* ║ github ── https://github.com/RayExo ║
* ║ ║
* ╚══════════════════════════════════════════════════════════════════╝
*/
import * as React from "react"
import { cn } from "@/lib/utils"
export interface TextareaProps
extends React.TextareaHTMLAttributes<HTMLTextAreaElement> {}
const Textarea = React.forwardRef<HTMLTextAreaElement, TextareaProps>(
({ className, ...props }, ref) => {
return (
<textarea
className={cn(
"flex min-h-[80px] w-full rounded-xl border border-slate-800 bg-slate-900/50 px-3 py-2 text-sm text-white placeholder:text-slate-500 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary/50 disabled:cursor-not-allowed disabled:opacity-50",
className
)}
ref={ref}
{...props}
/>
)
}
)
Textarea.displayName = "Textarea"
export { Textarea }