From 12c50df6a71016e2c17549f1d87b880df8991a93 Mon Sep 17 00:00:00 2001 From: Sagit Date: Thu, 19 Feb 2026 05:14:42 +0000 Subject: [PATCH] feat(frontend): add shadcn ui primitives and compatibility bridge --- vite-frontend/components.json | 21 ++ vite-frontend/src/components/ui/accordion.tsx | 59 +++++ vite-frontend/src/components/ui/alert.tsx | 54 +++++ vite-frontend/src/components/ui/badge.tsx | 39 +++ vite-frontend/src/components/ui/button.tsx | 52 ++++ vite-frontend/src/components/ui/card.tsx | 64 +++++ vite-frontend/src/components/ui/checkbox.tsx | 27 +++ vite-frontend/src/components/ui/dialog.tsx | 123 ++++++++++ .../src/components/ui/dropdown-menu.tsx | 220 +++++++++++++++++ vite-frontend/src/components/ui/input.tsx | 19 ++ vite-frontend/src/components/ui/label.tsx | 19 ++ vite-frontend/src/components/ui/progress.tsx | 30 +++ .../src/components/ui/radio-group.tsx | 37 +++ vite-frontend/src/components/ui/select.tsx | 162 +++++++++++++ vite-frontend/src/components/ui/separator.tsx | 27 +++ vite-frontend/src/components/ui/switch.tsx | 26 ++ vite-frontend/src/components/ui/table.tsx | 91 +++++++ vite-frontend/src/components/ui/tabs.tsx | 48 ++++ vite-frontend/src/components/ui/textarea.tsx | 18 ++ vite-frontend/src/lib/utils.ts | 6 + .../src/shadcn-bridge/heroui/accordion.tsx | 47 ++++ .../src/shadcn-bridge/heroui/alert.tsx | 52 ++++ .../src/shadcn-bridge/heroui/button.tsx | 105 +++++++++ .../src/shadcn-bridge/heroui/card.tsx | 20 ++ .../src/shadcn-bridge/heroui/checkbox.tsx | 43 ++++ .../src/shadcn-bridge/heroui/chip.tsx | 56 +++++ .../src/shadcn-bridge/heroui/date-picker.tsx | 90 +++++++ .../src/shadcn-bridge/heroui/divider.tsx | 7 + .../src/shadcn-bridge/heroui/dropdown.tsx | 81 +++++++ .../src/shadcn-bridge/heroui/input.tsx | 157 ++++++++++++ .../src/shadcn-bridge/heroui/link.tsx | 24 ++ .../src/shadcn-bridge/heroui/modal.tsx | 161 +++++++++++++ .../src/shadcn-bridge/heroui/navbar.tsx | 90 +++++++ .../src/shadcn-bridge/heroui/progress.tsx | 57 +++++ .../src/shadcn-bridge/heroui/radio.tsx | 63 +++++ .../src/shadcn-bridge/heroui/select.tsx | 223 ++++++++++++++++++ .../src/shadcn-bridge/heroui/shared.tsx | 62 +++++ .../src/shadcn-bridge/heroui/spinner.tsx | 31 +++ .../src/shadcn-bridge/heroui/switch.tsx | 31 +++ .../src/shadcn-bridge/heroui/system.tsx | 11 + .../src/shadcn-bridge/heroui/table.tsx | 140 +++++++++++ .../src/shadcn-bridge/heroui/tabs.tsx | 87 +++++++ .../src/shadcn-bridge/heroui/use-theme.tsx | 59 +++++ 43 files changed, 2839 insertions(+) create mode 100644 vite-frontend/components.json create mode 100644 vite-frontend/src/components/ui/accordion.tsx create mode 100644 vite-frontend/src/components/ui/alert.tsx create mode 100644 vite-frontend/src/components/ui/badge.tsx create mode 100644 vite-frontend/src/components/ui/button.tsx create mode 100644 vite-frontend/src/components/ui/card.tsx create mode 100644 vite-frontend/src/components/ui/checkbox.tsx create mode 100644 vite-frontend/src/components/ui/dialog.tsx create mode 100644 vite-frontend/src/components/ui/dropdown-menu.tsx create mode 100644 vite-frontend/src/components/ui/input.tsx create mode 100644 vite-frontend/src/components/ui/label.tsx create mode 100644 vite-frontend/src/components/ui/progress.tsx create mode 100644 vite-frontend/src/components/ui/radio-group.tsx create mode 100644 vite-frontend/src/components/ui/select.tsx create mode 100644 vite-frontend/src/components/ui/separator.tsx create mode 100644 vite-frontend/src/components/ui/switch.tsx create mode 100644 vite-frontend/src/components/ui/table.tsx create mode 100644 vite-frontend/src/components/ui/tabs.tsx create mode 100644 vite-frontend/src/components/ui/textarea.tsx create mode 100644 vite-frontend/src/lib/utils.ts create mode 100644 vite-frontend/src/shadcn-bridge/heroui/accordion.tsx create mode 100644 vite-frontend/src/shadcn-bridge/heroui/alert.tsx create mode 100644 vite-frontend/src/shadcn-bridge/heroui/button.tsx create mode 100644 vite-frontend/src/shadcn-bridge/heroui/card.tsx create mode 100644 vite-frontend/src/shadcn-bridge/heroui/checkbox.tsx create mode 100644 vite-frontend/src/shadcn-bridge/heroui/chip.tsx create mode 100644 vite-frontend/src/shadcn-bridge/heroui/date-picker.tsx create mode 100644 vite-frontend/src/shadcn-bridge/heroui/divider.tsx create mode 100644 vite-frontend/src/shadcn-bridge/heroui/dropdown.tsx create mode 100644 vite-frontend/src/shadcn-bridge/heroui/input.tsx create mode 100644 vite-frontend/src/shadcn-bridge/heroui/link.tsx create mode 100644 vite-frontend/src/shadcn-bridge/heroui/modal.tsx create mode 100644 vite-frontend/src/shadcn-bridge/heroui/navbar.tsx create mode 100644 vite-frontend/src/shadcn-bridge/heroui/progress.tsx create mode 100644 vite-frontend/src/shadcn-bridge/heroui/radio.tsx create mode 100644 vite-frontend/src/shadcn-bridge/heroui/select.tsx create mode 100644 vite-frontend/src/shadcn-bridge/heroui/shared.tsx create mode 100644 vite-frontend/src/shadcn-bridge/heroui/spinner.tsx create mode 100644 vite-frontend/src/shadcn-bridge/heroui/switch.tsx create mode 100644 vite-frontend/src/shadcn-bridge/heroui/system.tsx create mode 100644 vite-frontend/src/shadcn-bridge/heroui/table.tsx create mode 100644 vite-frontend/src/shadcn-bridge/heroui/tabs.tsx create mode 100644 vite-frontend/src/shadcn-bridge/heroui/use-theme.tsx diff --git a/vite-frontend/components.json b/vite-frontend/components.json new file mode 100644 index 0000000..3154a3d --- /dev/null +++ b/vite-frontend/components.json @@ -0,0 +1,21 @@ +{ + "$schema": "https://ui.shadcn.com/schema.json", + "style": "new-york", + "rsc": false, + "tsx": true, + "tailwind": { + "config": "tailwind.config.js", + "css": "src/styles/globals.css", + "baseColor": "neutral", + "cssVariables": true, + "prefix": "" + }, + "aliases": { + "components": "@/components", + "utils": "@/lib/utils", + "ui": "@/components/ui", + "lib": "@/lib", + "hooks": "@/hooks" + }, + "iconLibrary": "lucide" +} diff --git a/vite-frontend/src/components/ui/accordion.tsx b/vite-frontend/src/components/ui/accordion.tsx new file mode 100644 index 0000000..eba1eae --- /dev/null +++ b/vite-frontend/src/components/ui/accordion.tsx @@ -0,0 +1,59 @@ +import * as React from "react"; +import * as AccordionPrimitive from "@radix-ui/react-accordion"; +import { ChevronDownIcon } from "lucide-react"; + +import { cn } from "@/lib/utils"; + +function Accordion({ ...props }: React.ComponentProps) { + return ; +} + +function AccordionItem({ className, ...props }: React.ComponentProps) { + return ( + + ); +} + +function AccordionTrigger({ + className, + children, + ...props +}: React.ComponentProps) { + return ( + + svg]:rotate-180", + className, + )} + data-slot="accordion-trigger" + {...props} + > + {children} + + + + ); +} + +function AccordionContent({ + className, + children, + ...props +}: React.ComponentProps) { + return ( + +
{children}
+
+ ); +} + +export { Accordion, AccordionContent, AccordionItem, AccordionTrigger }; diff --git a/vite-frontend/src/components/ui/alert.tsx b/vite-frontend/src/components/ui/alert.tsx new file mode 100644 index 0000000..96ed73d --- /dev/null +++ b/vite-frontend/src/components/ui/alert.tsx @@ -0,0 +1,54 @@ +import * as React from "react"; +import { cva, type VariantProps } from "class-variance-authority"; + +import { cn } from "@/lib/utils"; + +const alertVariants = cva( + "relative w-full rounded-lg border px-4 py-3 text-sm", + { + variants: { + variant: { + default: "border-default-200 bg-default-50/70 text-foreground", + destructive: "border-danger-200 bg-danger-50 text-danger-700 dark:text-danger-300", + success: "border-success-200 bg-success-50 text-success-700 dark:text-success-300", + warning: "border-warning-200 bg-warning-50 text-warning-700 dark:text-warning-300", + }, + }, + defaultVariants: { + variant: "default", + }, + }, +); + +function Alert({ + className, + variant, + ...props +}: React.ComponentProps<"div"> & VariantProps) { + return ( +
+ ); +} + +function AlertTitle({ className, ...props }: React.ComponentProps<"h5">) { + return ( +
+ ); +} + +function AlertDescription({ className, ...props }: React.ComponentProps<"div">) { + return ( +
+ ); +} + +export { Alert, AlertDescription, AlertTitle }; diff --git a/vite-frontend/src/components/ui/badge.tsx b/vite-frontend/src/components/ui/badge.tsx new file mode 100644 index 0000000..b13a087 --- /dev/null +++ b/vite-frontend/src/components/ui/badge.tsx @@ -0,0 +1,39 @@ +import * as React from "react"; +import { cva, type VariantProps } from "class-variance-authority"; + +import { cn } from "@/lib/utils"; + +const badgeVariants = cva( + "inline-flex items-center rounded-full border px-2.5 py-0.5 text-xs font-semibold transition-colors", + { + variants: { + variant: { + default: "border-transparent bg-primary text-primary-foreground", + secondary: "border-transparent bg-secondary text-secondary-foreground", + destructive: "border-transparent bg-danger text-white", + outline: "text-foreground", + success: "border-transparent bg-success text-white", + warning: "border-transparent bg-warning text-white", + }, + }, + defaultVariants: { + variant: "default", + }, + }, +); + +function Badge({ + className, + variant, + ...props +}: React.ComponentProps<"span"> & VariantProps) { + return ( + + ); +} + +export { Badge, badgeVariants }; diff --git a/vite-frontend/src/components/ui/button.tsx b/vite-frontend/src/components/ui/button.tsx new file mode 100644 index 0000000..6c22b2f --- /dev/null +++ b/vite-frontend/src/components/ui/button.tsx @@ -0,0 +1,52 @@ +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-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50", + { + variants: { + variant: { + default: "bg-primary text-primary-foreground hover:bg-primary/90", + destructive: "bg-danger text-white hover:bg-danger/90", + outline: "border border-input bg-background hover:bg-accent hover:text-accent-foreground", + secondary: "bg-secondary text-secondary-foreground hover:bg-secondary/80", + ghost: "hover:bg-accent hover:text-accent-foreground", + link: "text-primary underline-offset-4 hover:underline", + light: "bg-transparent hover:bg-default-100 dark:hover:bg-default-200/40", + flat: "bg-default-100 text-foreground hover:bg-default-200 dark:bg-default-100/40", + }, + size: { + default: "h-9 px-4 py-2", + sm: "h-8 rounded-md px-3 text-xs", + lg: "h-10 rounded-md px-8", + icon: "h-9 w-9", + }, + }, + defaultVariants: { + variant: "default", + size: "default", + }, + }, +); + +type ButtonProps = React.ComponentProps<"button"> & + VariantProps & { + asChild?: boolean; + }; + +function Button({ asChild = false, className, size, variant, ...props }: ButtonProps) { + const Comp = asChild ? Slot : "button"; + + return ( + + ); +} + +export { Button, buttonVariants }; diff --git a/vite-frontend/src/components/ui/card.tsx b/vite-frontend/src/components/ui/card.tsx new file mode 100644 index 0000000..7d031ab --- /dev/null +++ b/vite-frontend/src/components/ui/card.tsx @@ -0,0 +1,64 @@ +import * as React from "react"; + +import { cn } from "@/lib/utils"; + +function Card({ className, ...props }: React.ComponentProps<"div">) { + return ( +
+ ); +} + +function CardHeader({ className, ...props }: React.ComponentProps<"div">) { + return ( +
+ ); +} + +function CardTitle({ className, ...props }: React.ComponentProps<"h3">) { + return ( +

+ ); +} + +function CardDescription({ className, ...props }: React.ComponentProps<"p">) { + return ( +

+ ); +} + +function CardContent({ className, ...props }: React.ComponentProps<"div">) { + return ( +

+ ); +} + +function CardFooter({ className, ...props }: React.ComponentProps<"div">) { + return ( +
+ ); +} + +export { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle }; diff --git a/vite-frontend/src/components/ui/checkbox.tsx b/vite-frontend/src/components/ui/checkbox.tsx new file mode 100644 index 0000000..7a48c1c --- /dev/null +++ b/vite-frontend/src/components/ui/checkbox.tsx @@ -0,0 +1,27 @@ +import * as React from "react"; +import * as CheckboxPrimitive from "@radix-ui/react-checkbox"; +import { CheckIcon } from "lucide-react"; + +import { cn } from "@/lib/utils"; + +function Checkbox({ className, ...props }: React.ComponentProps) { + return ( + + + + + + ); +} + +export { Checkbox }; diff --git a/vite-frontend/src/components/ui/dialog.tsx b/vite-frontend/src/components/ui/dialog.tsx new file mode 100644 index 0000000..13c9357 --- /dev/null +++ b/vite-frontend/src/components/ui/dialog.tsx @@ -0,0 +1,123 @@ +import * as React from "react"; +import * as DialogPrimitive from "@radix-ui/react-dialog"; +import { XIcon } from "lucide-react"; + +import { cn } from "@/lib/utils"; + +function Dialog({ ...props }: React.ComponentProps) { + return ; +} + +function DialogTrigger({ ...props }: React.ComponentProps) { + return ; +} + +function DialogPortal({ ...props }: React.ComponentProps) { + return ; +} + +function DialogClose({ ...props }: React.ComponentProps) { + return ; +} + +function DialogOverlay({ className, ...props }: React.ComponentProps) { + return ( + + ); +} + +function DialogContent({ + className, + children, + showCloseButton = true, + ...props +}: React.ComponentProps & { + showCloseButton?: boolean; +}) { + return ( + + + + {children} + {showCloseButton && ( + + + Close + + )} + + + ); +} + +function DialogHeader({ className, ...props }: React.ComponentProps<"div">) { + return ( +
+ ); +} + +function DialogFooter({ className, ...props }: React.ComponentProps<"div">) { + return ( +
+ ); +} + +function DialogTitle({ className, ...props }: React.ComponentProps) { + return ( + + ); +} + +function DialogDescription({ + className, + ...props +}: React.ComponentProps) { + return ( + + ); +} + +export { + Dialog, + DialogClose, + DialogContent, + DialogDescription, + DialogFooter, + DialogHeader, + DialogOverlay, + DialogPortal, + DialogTitle, + DialogTrigger, +}; diff --git a/vite-frontend/src/components/ui/dropdown-menu.tsx b/vite-frontend/src/components/ui/dropdown-menu.tsx new file mode 100644 index 0000000..5ac423c --- /dev/null +++ b/vite-frontend/src/components/ui/dropdown-menu.tsx @@ -0,0 +1,220 @@ +import * as React from "react"; +import * as DropdownMenuPrimitive from "@radix-ui/react-dropdown-menu"; +import { CheckIcon, ChevronRightIcon, CircleIcon } from "lucide-react"; + +import { cn } from "@/lib/utils"; + +function DropdownMenu({ ...props }: React.ComponentProps) { + return ; +} + +function DropdownMenuTrigger({ + ...props +}: React.ComponentProps) { + return ; +} + +function DropdownMenuGroup({ ...props }: React.ComponentProps) { + return ; +} + +function DropdownMenuPortal({ ...props }: React.ComponentProps) { + return ; +} + +function DropdownMenuSub({ ...props }: React.ComponentProps) { + return ; +} + +function DropdownMenuRadioGroup({ + ...props +}: React.ComponentProps) { + return ; +} + +function DropdownMenuSubTrigger({ + className, + inset, + children, + ...props +}: React.ComponentProps & { + inset?: boolean; +}) { + return ( + + {children} + + + ); +} + +function DropdownMenuSubContent({ + className, + ...props +}: React.ComponentProps) { + return ( + + ); +} + +function DropdownMenuContent({ + className, + sideOffset = 6, + ...props +}: React.ComponentProps) { + return ( + + + + ); +} + +function DropdownMenuItem({ + className, + inset, + ...props +}: React.ComponentProps & { + inset?: boolean; +}) { + return ( + + ); +} + +function DropdownMenuCheckboxItem({ + className, + children, + checked, + ...props +}: React.ComponentProps) { + return ( + + + + + + + {children} + + ); +} + +function DropdownMenuRadioItem({ + className, + children, + ...props +}: React.ComponentProps) { + return ( + + + + + + + {children} + + ); +} + +function DropdownMenuLabel({ + className, + inset, + ...props +}: React.ComponentProps & { + inset?: boolean; +}) { + return ( + + ); +} + +function DropdownMenuSeparator({ + className, + ...props +}: React.ComponentProps) { + return ( + + ); +} + +function DropdownMenuShortcut({ className, ...props }: React.ComponentProps<"span">) { + return ( + + ); +} + +export { + DropdownMenu, + DropdownMenuCheckboxItem, + DropdownMenuContent, + DropdownMenuGroup, + DropdownMenuItem, + DropdownMenuLabel, + DropdownMenuPortal, + DropdownMenuRadioGroup, + DropdownMenuRadioItem, + DropdownMenuSeparator, + DropdownMenuShortcut, + DropdownMenuSub, + DropdownMenuSubContent, + DropdownMenuSubTrigger, + DropdownMenuTrigger, +}; diff --git a/vite-frontend/src/components/ui/input.tsx b/vite-frontend/src/components/ui/input.tsx new file mode 100644 index 0000000..d238a6d --- /dev/null +++ b/vite-frontend/src/components/ui/input.tsx @@ -0,0 +1,19 @@ +import * as React from "react"; + +import { cn } from "@/lib/utils"; + +function Input({ className, type, ...props }: React.ComponentProps<"input">) { + return ( + + ); +} + +export { Input }; diff --git a/vite-frontend/src/components/ui/label.tsx b/vite-frontend/src/components/ui/label.tsx new file mode 100644 index 0000000..9391551 --- /dev/null +++ b/vite-frontend/src/components/ui/label.tsx @@ -0,0 +1,19 @@ +import * as React from "react"; +import * as LabelPrimitive from "@radix-ui/react-label"; + +import { cn } from "@/lib/utils"; + +function Label({ className, ...props }: React.ComponentProps) { + return ( + + ); +} + +export { Label }; diff --git a/vite-frontend/src/components/ui/progress.tsx b/vite-frontend/src/components/ui/progress.tsx new file mode 100644 index 0000000..95e9898 --- /dev/null +++ b/vite-frontend/src/components/ui/progress.tsx @@ -0,0 +1,30 @@ +import * as React from "react"; +import * as ProgressPrimitive from "@radix-ui/react-progress"; + +import { cn } from "@/lib/utils"; + +function Progress({ + className, + value, + indicatorClassName, + ...props +}: React.ComponentProps & { + indicatorClassName?: string; +}) { + return ( + + + + ); +} + +export { Progress }; diff --git a/vite-frontend/src/components/ui/radio-group.tsx b/vite-frontend/src/components/ui/radio-group.tsx new file mode 100644 index 0000000..34ad09c --- /dev/null +++ b/vite-frontend/src/components/ui/radio-group.tsx @@ -0,0 +1,37 @@ +import * as React from "react"; +import * as RadioGroupPrimitive from "@radix-ui/react-radio-group"; +import { CircleIcon } from "lucide-react"; + +import { cn } from "@/lib/utils"; + +function RadioGroup({ className, ...props }: React.ComponentProps) { + return ( + + ); +} + +function RadioGroupItem({ + className, + ...props +}: React.ComponentProps) { + return ( + + + + + + ); +} + +export { RadioGroup, RadioGroupItem }; diff --git a/vite-frontend/src/components/ui/select.tsx b/vite-frontend/src/components/ui/select.tsx new file mode 100644 index 0000000..9a28ac6 --- /dev/null +++ b/vite-frontend/src/components/ui/select.tsx @@ -0,0 +1,162 @@ +import * as React from "react"; +import * as SelectPrimitive from "@radix-ui/react-select"; +import { CheckIcon, ChevronDownIcon, ChevronUpIcon } from "lucide-react"; + +import { cn } from "@/lib/utils"; + +function Select({ ...props }: React.ComponentProps) { + return ; +} + +function SelectGroup({ ...props }: React.ComponentProps) { + return ; +} + +function SelectValue({ ...props }: React.ComponentProps) { + return ; +} + +function SelectTrigger({ + className, + children, + ...props +}: React.ComponentProps) { + return ( + + {children} + + + + + ); +} + +function SelectScrollUpButton({ + className, + ...props +}: React.ComponentProps) { + return ( + + + + ); +} + +function SelectScrollDownButton({ + className, + ...props +}: React.ComponentProps) { + return ( + + + + ); +} + +function SelectContent({ + className, + children, + position = "popper", + ...props +}: React.ComponentProps) { + return ( + + + + + {children} + + + + + ); +} + +function SelectLabel({ className, ...props }: React.ComponentProps) { + return ( + + ); +} + +function SelectItem({ + className, + children, + ...props +}: React.ComponentProps) { + return ( + + + + + + + {children} + + ); +} + +function SelectSeparator({ + className, + ...props +}: React.ComponentProps) { + return ( + + ); +} + +export { + Select, + SelectContent, + SelectGroup, + SelectItem, + SelectLabel, + SelectSeparator, + SelectTrigger, + SelectValue, +}; diff --git a/vite-frontend/src/components/ui/separator.tsx b/vite-frontend/src/components/ui/separator.tsx new file mode 100644 index 0000000..0dd4c82 --- /dev/null +++ b/vite-frontend/src/components/ui/separator.tsx @@ -0,0 +1,27 @@ +import * as React from "react"; +import * as SeparatorPrimitive from "@radix-ui/react-separator"; + +import { cn } from "@/lib/utils"; + +function Separator({ + className, + decorative = true, + orientation = "horizontal", + ...props +}: React.ComponentProps) { + return ( + + ); +} + +export { Separator }; diff --git a/vite-frontend/src/components/ui/switch.tsx b/vite-frontend/src/components/ui/switch.tsx new file mode 100644 index 0000000..c75163e --- /dev/null +++ b/vite-frontend/src/components/ui/switch.tsx @@ -0,0 +1,26 @@ +import * as React from "react"; +import * as SwitchPrimitive from "@radix-ui/react-switch"; + +import { cn } from "@/lib/utils"; + +function Switch({ className, ...props }: React.ComponentProps) { + return ( + + + + ); +} + +export { Switch }; diff --git a/vite-frontend/src/components/ui/table.tsx b/vite-frontend/src/components/ui/table.tsx new file mode 100644 index 0000000..3ac5fa2 --- /dev/null +++ b/vite-frontend/src/components/ui/table.tsx @@ -0,0 +1,91 @@ +import * as React from "react"; + +import { cn } from "@/lib/utils"; + +function Table({ className, ...props }: React.ComponentProps<"table">) { + return ( +
+ + + ); +} + +function TableHeader({ className, ...props }: React.ComponentProps<"thead">) { + return ( + + ); +} + +function TableBody({ className, ...props }: React.ComponentProps<"tbody">) { + return ( + + ); +} + +function TableFooter({ className, ...props }: React.ComponentProps<"tfoot">) { + return ( + tr]:last:border-b-0", className)} + data-slot="table-footer" + {...props} + /> + ); +} + +function TableRow({ className, ...props }: React.ComponentProps<"tr">) { + return ( + + ); +} + +function TableHead({ className, ...props }: React.ComponentProps<"th">) { + return ( +
+ ); +} + +function TableCell({ className, ...props }: React.ComponentProps<"td">) { + return ( + + ); +} + +function TableCaption({ className, ...props }: React.ComponentProps<"caption">) { + return ( +
+ ); +} + +export { + Table, + TableBody, + TableCaption, + TableCell, + TableFooter, + TableHead, + TableHeader, + TableRow, +}; diff --git a/vite-frontend/src/components/ui/tabs.tsx b/vite-frontend/src/components/ui/tabs.tsx new file mode 100644 index 0000000..e57c653 --- /dev/null +++ b/vite-frontend/src/components/ui/tabs.tsx @@ -0,0 +1,48 @@ +import * as React from "react"; +import * as TabsPrimitive from "@radix-ui/react-tabs"; + +import { cn } from "@/lib/utils"; + +function Tabs({ className, ...props }: React.ComponentProps) { + return ( + + ); +} + +function TabsList({ className, ...props }: React.ComponentProps) { + return ( + + ); +} + +function TabsTrigger({ className, ...props }: React.ComponentProps) { + return ( + + ); +} + +function TabsContent({ className, ...props }: React.ComponentProps) { + return ( + + ); +} + +export { Tabs, TabsContent, TabsList, TabsTrigger }; diff --git a/vite-frontend/src/components/ui/textarea.tsx b/vite-frontend/src/components/ui/textarea.tsx new file mode 100644 index 0000000..cd7d5d4 --- /dev/null +++ b/vite-frontend/src/components/ui/textarea.tsx @@ -0,0 +1,18 @@ +import * as React from "react"; + +import { cn } from "@/lib/utils"; + +function Textarea({ className, ...props }: React.ComponentProps<"textarea">) { + return ( +