From 8283d66db66986d6d3a21f7590c814e6b1353b25 Mon Sep 17 00:00:00 2001 From: XingfenD Date: Wed, 16 Sep 2026 15:17:26 +0800 Subject: [PATCH] feat(frontend): shadcn sheet/tabs/slider primitives (B0) --- frontend/src/components/ui/sheet.tsx | 126 ++++++++++++++++++++++++++ frontend/src/components/ui/slider.tsx | 50 ++++++++++ frontend/src/components/ui/tabs.tsx | 39 ++++++++ 3 files changed, 215 insertions(+) create mode 100644 frontend/src/components/ui/sheet.tsx create mode 100644 frontend/src/components/ui/slider.tsx create mode 100644 frontend/src/components/ui/tabs.tsx diff --git a/frontend/src/components/ui/sheet.tsx b/frontend/src/components/ui/sheet.tsx new file mode 100644 index 0000000..0f2993e --- /dev/null +++ b/frontend/src/components/ui/sheet.tsx @@ -0,0 +1,126 @@ +import * as React from "react"; +import { cn } from "@/lib/utils"; +import { XIcon } from "lucide-react"; +import { Dialog as SheetPrimitive } from "radix-ui"; + +function Sheet({ ...props }: React.ComponentProps) { + return ; +} + +function SheetTrigger({ ...props }: React.ComponentProps) { + return ; +} + +function SheetPortal({ ...props }: React.ComponentProps) { + return ; +} + +function SheetClose({ ...props }: React.ComponentProps) { + return ; +} + +function SheetOverlay({ className, ...props }: React.ComponentProps) { + return ( + + ); +} + +const SIDE_CLASSES = { + top: "inset-x-0 top-0 h-auto border-b data-[state=closed]:slide-out-to-top data-[state=open]:slide-in-from-top", + bottom: + "inset-x-0 bottom-0 h-auto border-t data-[state=closed]:slide-out-to-bottom data-[state=open]:slide-in-from-bottom", + left: "inset-y-0 left-0 h-full w-3/4 border-r data-[state=closed]:slide-out-to-left data-[state=open]:slide-in-from-left sm:max-w-sm", + right: + "inset-y-0 right-0 h-full w-3/4 border-l data-[state=closed]:slide-out-to-right data-[state=open]:slide-in-from-right sm:max-w-sm", +} as const; + +function SheetContent({ + className, + children, + side = "right", + showCloseButton = true, + ...props +}: React.ComponentProps & { + side?: "top" | "right" | "bottom" | "left"; + showCloseButton?: boolean; +}) { + return ( + + + + {children} + {showCloseButton && side !== "left" && side !== "bottom" && ( + + + + )} + + + ); +} + +function SheetHeader({ className, ...props }: React.ComponentProps<"div">) { + return
; +} + +function SheetFooter({ className, ...props }: React.ComponentProps<"div">) { + return ( +
+ ); +} + +function SheetTitle({ className, ...props }: React.ComponentProps) { + return ( + + ); +} + +function SheetDescription({ className, ...props }: React.ComponentProps) { + return ( + + ); +} + +export { + Sheet, + SheetClose, + SheetContent, + SheetDescription, + SheetFooter, + SheetHeader, + SheetOverlay, + SheetPortal, + SheetTitle, + SheetTrigger, +}; diff --git a/frontend/src/components/ui/slider.tsx b/frontend/src/components/ui/slider.tsx new file mode 100644 index 0000000..49d4c7d --- /dev/null +++ b/frontend/src/components/ui/slider.tsx @@ -0,0 +1,50 @@ +import * as React from "react"; +import { cn } from "@/lib/utils"; +import { Slider as SliderPrimitive } from "radix-ui"; + +function Slider({ + className, + defaultValue, + value, + min = 0, + max = 100, + ...props +}: React.ComponentProps) { + const thumbs = React.useMemo( + () => (Array.isArray(value) ? value : Array.isArray(defaultValue) ? defaultValue : [min, max]), + [value, defaultValue, min, max], + ); + return ( + + + + + {thumbs.map((_, i) => ( + + ))} + + ); +} + +export { Slider }; diff --git a/frontend/src/components/ui/tabs.tsx b/frontend/src/components/ui/tabs.tsx new file mode 100644 index 0000000..0e47d01 --- /dev/null +++ b/frontend/src/components/ui/tabs.tsx @@ -0,0 +1,39 @@ +import * as React from "react"; +import { cn } from "@/lib/utils"; +import { Tabs as TabsPrimitive } from "radix-ui"; + +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 };