From c762d2333e4f4d2b074ef6e7711cd0788324f9f0 Mon Sep 17 00:00:00 2001 From: swve Date: Thu, 17 Oct 2024 21:50:36 +0200 Subject: [PATCH] feat: use shadcn inputs and modal --- .../components/StyledElements/Modal/Modal.tsx | 208 ++++------------ apps/web/components/ui/button.tsx | 57 +++++ apps/web/components/ui/dialog.tsx | 122 ++++++++++ apps/web/components/ui/input.tsx | 25 ++ apps/web/components/ui/label.tsx | 26 ++ apps/web/components/ui/select.tsx | 164 +++++++++++++ apps/web/components/ui/textarea.tsx | 24 ++ apps/web/components/ui/toggle-group.tsx | 61 +++++ apps/web/components/ui/toggle.tsx | 45 ++++ apps/web/package.json | 8 +- apps/web/pnpm-lock.yaml | 230 +++++++++++++++++- 11 files changed, 809 insertions(+), 161 deletions(-) create mode 100644 apps/web/components/ui/button.tsx create mode 100644 apps/web/components/ui/dialog.tsx create mode 100644 apps/web/components/ui/input.tsx create mode 100644 apps/web/components/ui/label.tsx create mode 100644 apps/web/components/ui/select.tsx create mode 100644 apps/web/components/ui/textarea.tsx create mode 100644 apps/web/components/ui/toggle-group.tsx create mode 100644 apps/web/components/ui/toggle.tsx diff --git a/apps/web/components/StyledElements/Modal/Modal.tsx b/apps/web/components/StyledElements/Modal/Modal.tsx index b78350ec..cbfc342f 100644 --- a/apps/web/components/StyledElements/Modal/Modal.tsx +++ b/apps/web/components/StyledElements/Modal/Modal.tsx @@ -1,9 +1,9 @@ 'use client' + import React from 'react' -import * as Dialog from '@radix-ui/react-dialog' -import { styled, keyframes } from '@stitches/react' -import { blackA, mauve } from '@radix-ui/colors' +import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle, DialogTrigger, DialogFooter } from "@/components/ui/dialog" import { ButtonBlack } from '../Form/Form' +import { cn } from "@/lib/utils" type ModalParams = { dialogTitle?: string @@ -12,7 +12,7 @@ type ModalParams = { dialogClose?: React.ReactNode | null dialogTrigger?: React.ReactNode addDefCloseButton?: boolean - onOpenChange: any + onOpenChange: (open: boolean) => void isDialogOpen?: boolean minHeight?: 'sm' | 'md' | 'lg' | 'xl' | 'no-min' minWidth?: 'sm' | 'md' | 'lg' | 'xl' | 'no-min' @@ -20,161 +20,61 @@ type ModalParams = { customWidth?: string } -const Modal = (params: ModalParams) => ( - - {params.dialogTrigger ? ( - {params.dialogTrigger} - ) : null} +const Modal = (params: ModalParams) => { + const getMinHeight = () => { + switch (params.minHeight) { + case 'sm': return 'min-h-[300px]' + case 'md': return 'min-h-[500px]' + case 'lg': return 'min-h-[700px]' + case 'xl': return 'min-h-[900px]' + default: return '' + } + } - - - - {params.dialogTitle && params.dialogDescription && - + const getMinWidth = () => { + switch (params.minWidth) { + case 'sm': return 'min-w-[600px]' + case 'md': return 'min-w-[800px]' + case 'lg': return 'min-w-[1000px]' + case 'xl': return 'min-w-[1200px]' + default: return '' + } + } + + return ( + + {params.dialogTrigger && ( + {params.dialogTrigger} + )} + + {params.dialogTitle && params.dialogDescription && ( + {params.dialogTitle} {params.dialogDescription} - - } - {params.dialogContent} - {params.dialogClose ? ( - - {params.dialogClose} - - ) : null} - {params.addDefCloseButton ? ( - - - + + )} +
+ {params.dialogContent} +
+ {(params.dialogClose || params.addDefCloseButton) && ( + + {params.dialogClose} + {params.addDefCloseButton && ( + Close -
-
- ) : null} + )} + + )}
-
-
-) - -const overlayShow = keyframes({ - '0%': { opacity: 0 }, - '100%': { opacity: 1 }, -}) - -const overlayClose = keyframes({ - '0%': { opacity: 1 }, - '100%': { opacity: 0 }, -}) - -const contentShow = keyframes({ - '0%': { opacity: 0, transform: 'translate(-50%, -50%) scale(.96)' }, - '100%': { opacity: 1, transform: 'translate(-50%, -50%) scale(1)' }, -}) - -const contentClose = keyframes({ - '0%': { opacity: 1, transform: 'translate(-50%, -50%) scale(1)' }, - '100%': { opacity: 0, transform: 'translate(-50%, -52%) scale(.96)' }, -}) - -const DialogOverlay = styled(Dialog.Overlay, { - backgroundColor: blackA.blackA9, - backdropFilter: 'blur(0.6px)', - position: 'fixed', - zIndex: 500, - inset: 0, - animation: `${overlayShow} 150ms cubic-bezier(0.16, 1, 0.3, 1)`, - '&[data-state="closed"]': { - animation: `${overlayClose} 150ms cubic-bezier(0.16, 1, 0.3, 1)`, - }, -}) - -const DialogContent = styled(Dialog.Content, { - variants: { - minHeight: { - 'no-min': { - minHeight: '0px', - }, - sm: { - minHeight: '300px', - }, - md: { - minHeight: '500px', - }, - lg: { - minHeight: '700px', - }, - xl: { - minHeight: '900px', - }, - }, - minWidth: { - 'no-min': { - minWidth: '0px', - }, - sm: { - minWidth: '600px', - }, - md: { - minWidth: '800px', - }, - lg: { - minWidth: '1000px', - }, - xl: { - minWidth: '1200px', - }, - }, - }, - - backgroundColor: 'white', - borderRadius: 18, - zIndex: 501, - boxShadow: - 'hsl(206 22% 7% / 35%) 0px 10px 38px -10px, hsl(206 22% 7% / 20%) 0px 10px 20px -15px', - position: 'fixed', - top: '50%', - left: '50%', - transform: 'translate(-50%, -50%)', - width: '90vw', - maxHeight: '85vh', - minHeight: '300px', - maxWidth: '600px', - padding: 11, - animation: `${contentShow} 150ms cubic-bezier(0.16, 1, 0.3, 1)`, - '&:focus': { outline: 'none' }, - - '&[data-state="closed"]': { - animation: `${contentClose} 150ms cubic-bezier(0.16, 1, 0.3, 1)`, - }, - transition: 'max-height 0.3s ease-out', -}) - -const DialogTopBar = styled('div', { - background: '#F7F7F7', - padding: '8px 14px ', - borderRadius: 14, -}) -const DialogTitle = styled(Dialog.Title, { - margin: 0, - fontWeight: 700, - letterSpacing: '-0.05em', - padding: 0, - color: mauve.mauve12, - fontSize: 21, -}) - -const DialogDescription = styled(Dialog.Description, { - color: mauve.mauve11, - letterSpacing: '-0.03em', - fontSize: 15, - padding: 0, - margin: 0, -}) - -const Flex = styled('div', { display: 'flex' }) + + ) +} export default Modal diff --git a/apps/web/components/ui/button.tsx b/apps/web/components/ui/button.tsx new file mode 100644 index 00000000..ed0f6279 --- /dev/null +++ b/apps/web/components/ui/button.tsx @@ -0,0 +1,57 @@ +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 gap-2 whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0", + { + variants: { + variant: { + default: + "bg-primary text-primary-foreground shadow hover:bg-primary/90", + destructive: + "bg-destructive text-destructive-foreground shadow-sm hover:bg-destructive/90", + outline: + "border border-input bg-background shadow-sm hover:bg-accent hover:text-accent-foreground", + secondary: + "bg-secondary text-secondary-foreground shadow-sm hover:bg-secondary/80", + ghost: "hover:bg-accent hover:text-accent-foreground", + link: "text-primary underline-offset-4 hover:underline", + }, + 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", + }, + } +) + +export interface ButtonProps + extends React.ButtonHTMLAttributes, + VariantProps { + asChild?: boolean +} + +const Button = React.forwardRef( + ({ className, variant, size, asChild = false, ...props }, ref) => { + const Comp = asChild ? Slot : "button" + return ( + + ) + } +) +Button.displayName = "Button" + +export { Button, buttonVariants } diff --git a/apps/web/components/ui/dialog.tsx b/apps/web/components/ui/dialog.tsx new file mode 100644 index 00000000..fe42372d --- /dev/null +++ b/apps/web/components/ui/dialog.tsx @@ -0,0 +1,122 @@ +"use client" + +import * as React from "react" +import * as DialogPrimitive from "@radix-ui/react-dialog" +import { Cross2Icon } from "@radix-ui/react-icons" + +import { cn } from "@/lib/utils" + +const Dialog = DialogPrimitive.Root + +const DialogTrigger = DialogPrimitive.Trigger + +const DialogPortal = DialogPrimitive.Portal + +const DialogClose = DialogPrimitive.Close + +const DialogOverlay = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)) +DialogOverlay.displayName = DialogPrimitive.Overlay.displayName + +const DialogContent = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, children, ...props }, ref) => ( + + + + {children} + + + Close + + + +)) +DialogContent.displayName = DialogPrimitive.Content.displayName + +const DialogHeader = ({ + className, + ...props +}: React.HTMLAttributes) => ( +
+) +DialogHeader.displayName = "DialogHeader" + +const DialogFooter = ({ + className, + ...props +}: React.HTMLAttributes) => ( +
+) +DialogFooter.displayName = "DialogFooter" + +const DialogTitle = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)) +DialogTitle.displayName = DialogPrimitive.Title.displayName + +const DialogDescription = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)) +DialogDescription.displayName = DialogPrimitive.Description.displayName + +export { + Dialog, + DialogPortal, + DialogOverlay, + DialogTrigger, + DialogClose, + DialogContent, + DialogHeader, + DialogFooter, + DialogTitle, + DialogDescription, +} diff --git a/apps/web/components/ui/input.tsx b/apps/web/components/ui/input.tsx new file mode 100644 index 00000000..5af26b2c --- /dev/null +++ b/apps/web/components/ui/input.tsx @@ -0,0 +1,25 @@ +import * as React from "react" + +import { cn } from "@/lib/utils" + +export interface InputProps + extends React.InputHTMLAttributes {} + +const Input = React.forwardRef( + ({ className, type, ...props }, ref) => { + return ( + + ) + } +) +Input.displayName = "Input" + +export { Input } diff --git a/apps/web/components/ui/label.tsx b/apps/web/components/ui/label.tsx new file mode 100644 index 00000000..53418217 --- /dev/null +++ b/apps/web/components/ui/label.tsx @@ -0,0 +1,26 @@ +"use client" + +import * as React from "react" +import * as LabelPrimitive from "@radix-ui/react-label" +import { cva, type VariantProps } from "class-variance-authority" + +import { cn } from "@/lib/utils" + +const labelVariants = cva( + "text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70" +) + +const Label = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef & + VariantProps +>(({ className, ...props }, ref) => ( + +)) +Label.displayName = LabelPrimitive.Root.displayName + +export { Label } diff --git a/apps/web/components/ui/select.tsx b/apps/web/components/ui/select.tsx new file mode 100644 index 00000000..ac2a8f2b --- /dev/null +++ b/apps/web/components/ui/select.tsx @@ -0,0 +1,164 @@ +"use client" + +import * as React from "react" +import { + CaretSortIcon, + CheckIcon, + ChevronDownIcon, + ChevronUpIcon, +} from "@radix-ui/react-icons" +import * as SelectPrimitive from "@radix-ui/react-select" + +import { cn } from "@/lib/utils" + +const Select = SelectPrimitive.Root + +const SelectGroup = SelectPrimitive.Group + +const SelectValue = SelectPrimitive.Value + +const SelectTrigger = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, children, ...props }, ref) => ( + span]:line-clamp-1", + className + )} + {...props} + > + {children} + + + + +)) +SelectTrigger.displayName = SelectPrimitive.Trigger.displayName + +const SelectScrollUpButton = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + + + +)) +SelectScrollUpButton.displayName = SelectPrimitive.ScrollUpButton.displayName + +const SelectScrollDownButton = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + + + +)) +SelectScrollDownButton.displayName = + SelectPrimitive.ScrollDownButton.displayName + +const SelectContent = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, children, position = "popper", ...props }, ref) => ( + + + + + {children} + + + + +)) +SelectContent.displayName = SelectPrimitive.Content.displayName + +const SelectLabel = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)) +SelectLabel.displayName = SelectPrimitive.Label.displayName + +const SelectItem = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, children, ...props }, ref) => ( + + + + + + + {children} + +)) +SelectItem.displayName = SelectPrimitive.Item.displayName + +const SelectSeparator = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)) +SelectSeparator.displayName = SelectPrimitive.Separator.displayName + +export { + Select, + SelectGroup, + SelectValue, + SelectTrigger, + SelectContent, + SelectLabel, + SelectItem, + SelectSeparator, + SelectScrollUpButton, + SelectScrollDownButton, +} diff --git a/apps/web/components/ui/textarea.tsx b/apps/web/components/ui/textarea.tsx new file mode 100644 index 00000000..d1258e47 --- /dev/null +++ b/apps/web/components/ui/textarea.tsx @@ -0,0 +1,24 @@ +import * as React from "react" + +import { cn } from "@/lib/utils" + +export interface TextareaProps + extends React.TextareaHTMLAttributes {} + +const Textarea = React.forwardRef( + ({ className, ...props }, ref) => { + return ( +