From aa721322da51d5c16094ca919b443d718137a722 Mon Sep 17 00:00:00 2001 From: imnyang Date: Fri, 19 Dec 2025 17:21:23 +0900 Subject: [PATCH] chore: update dependencies and improve UI components - Updated dependencies in bun.lock and package.json to specific versions for better stability. - Added a new Contact component to display contact methods with tooltips. - Introduced a Banner component for notifications with customizable actions. - Enhanced the Dialog, Checkbox, Button, Input, and Label components for better usability and styling. - Integrated react-snowfall for a snow effect in the main page. - Added a Discord SVG icon to the project. --- bun.lock | 129 ++++++++++--------- package.json | 3 +- public/icon/discord.svg | 22 ++++ src/app/page.tsx | 40 +++++- src/components/Contact.tsx | 55 ++++++++ src/components/ui/banner.tsx | 123 ++++++++++++++++++ src/components/ui/button.tsx | 56 ++++----- src/components/ui/checkbox.tsx | 42 +++---- src/components/ui/dialog.tsx | 221 +++++++++++++++------------------ src/components/ui/input.tsx | 34 ++--- src/components/ui/label.tsx | 32 ++--- 11 files changed, 489 insertions(+), 268 deletions(-) create mode 100644 public/icon/discord.svg create mode 100644 src/components/Contact.tsx create mode 100644 src/components/ui/banner.tsx diff --git a/bun.lock b/bun.lock index 9d39e4c..7b90bd3 100644 --- a/bun.lock +++ b/bun.lock @@ -5,69 +5,70 @@ "": { "name": "imnya", "dependencies": { - "@hookform/resolvers": "latest", - "@mdx-js/loader": "latest", - "@mdx-js/react": "latest", - "@next/mdx": "latest", - "@radix-ui/react-accordion": "latest", - "@radix-ui/react-alert-dialog": "latest", - "@radix-ui/react-aspect-ratio": "latest", - "@radix-ui/react-avatar": "latest", - "@radix-ui/react-checkbox": "latest", - "@radix-ui/react-collapsible": "latest", - "@radix-ui/react-context-menu": "latest", - "@radix-ui/react-dialog": "latest", - "@radix-ui/react-dropdown-menu": "latest", - "@radix-ui/react-hover-card": "latest", - "@radix-ui/react-label": "latest", - "@radix-ui/react-menubar": "latest", - "@radix-ui/react-navigation-menu": "latest", - "@radix-ui/react-popover": "latest", - "@radix-ui/react-progress": "latest", - "@radix-ui/react-radio-group": "latest", - "@radix-ui/react-scroll-area": "latest", - "@radix-ui/react-select": "latest", - "@radix-ui/react-separator": "latest", - "@radix-ui/react-slider": "latest", - "@radix-ui/react-slot": "latest", - "@radix-ui/react-switch": "latest", - "@radix-ui/react-tabs": "latest", - "@radix-ui/react-toggle": "latest", - "@radix-ui/react-toggle-group": "latest", - "@radix-ui/react-tooltip": "latest", - "class-variance-authority": "latest", - "clsx": "latest", - "cmdk": "latest", - "date-fns": "latest", - "embla-carousel-react": "latest", - "framer-motion": "latest", - "gray-matter": "latest", - "highlight.js": "latest", - "input-otp": "latest", - "lucide-react": "latest", - "next": "latest", - "next-themes": "latest", - "radix-ui": "latest", - "react": "latest", - "react-day-picker": "latest", - "react-dom": "latest", - "react-hook-form": "latest", - "react-resizable-panels": "latest", - "recharts": "latest", - "sonner": "latest", - "tailwind-merge": "latest", - "vaul": "latest", - "zod": "latest", + "@hookform/resolvers": "^5.2.2", + "@mdx-js/loader": "^3.1.1", + "@mdx-js/react": "^3.1.1", + "@next/mdx": "^16.0.10", + "@radix-ui/react-accordion": "^1.2.12", + "@radix-ui/react-alert-dialog": "^1.1.15", + "@radix-ui/react-aspect-ratio": "^1.1.8", + "@radix-ui/react-avatar": "^1.1.11", + "@radix-ui/react-checkbox": "^1.3.3", + "@radix-ui/react-collapsible": "^1.1.12", + "@radix-ui/react-context-menu": "^2.2.16", + "@radix-ui/react-dialog": "^1.1.15", + "@radix-ui/react-dropdown-menu": "^2.1.16", + "@radix-ui/react-hover-card": "^1.1.15", + "@radix-ui/react-label": "^2.1.8", + "@radix-ui/react-menubar": "^1.1.16", + "@radix-ui/react-navigation-menu": "^1.2.14", + "@radix-ui/react-popover": "^1.1.15", + "@radix-ui/react-progress": "^1.1.8", + "@radix-ui/react-radio-group": "^1.3.8", + "@radix-ui/react-scroll-area": "^1.2.10", + "@radix-ui/react-select": "^2.2.6", + "@radix-ui/react-separator": "^1.1.8", + "@radix-ui/react-slider": "^1.3.6", + "@radix-ui/react-slot": "^1.2.4", + "@radix-ui/react-switch": "^1.2.6", + "@radix-ui/react-tabs": "^1.1.13", + "@radix-ui/react-toggle": "^1.1.10", + "@radix-ui/react-toggle-group": "^1.1.11", + "@radix-ui/react-tooltip": "^1.2.8", + "class-variance-authority": "^0.7.1", + "clsx": "^2.1.1", + "cmdk": "^1.1.1", + "date-fns": "^4.1.0", + "embla-carousel-react": "^8.6.0", + "framer-motion": "^12.23.26", + "gray-matter": "^4.0.3", + "highlight.js": "^11.11.1", + "input-otp": "^1.4.2", + "lucide-react": "^0.562.0", + "next": "16.0.10", + "next-themes": "^0.4.6", + "radix-ui": "^1.4.3", + "react": "19.2.3", + "react-day-picker": "^9.12.0", + "react-dom": "19.2.3", + "react-hook-form": "^7.68.0", + "react-resizable-panels": "^3.0.6", + "react-snowfall": "^2.4.0", + "recharts": "3.5.1", + "sonner": "^2.0.7", + "tailwind-merge": "^3.4.0", + "vaul": "^1.1.2", + "zod": "^4.1.13", }, "devDependencies": { - "@biomejs/biome": "latest", - "@tailwindcss/postcss": "latest", - "@types/node": "latest", - "@types/react": "latest", - "@types/react-dom": "latest", - "tailwindcss": "latest", - "tw-animate-css": "latest", - "typescript": "latest", + "@biomejs/biome": "2.3.8", + "@tailwindcss/postcss": "^4.1.18", + "@types/node": "^25.0.1", + "@types/react": "19.2.2", + "@types/react-dom": "19.2.2", + "tailwindcss": "^4.1.18", + "tw-animate-css": "^1.4.0", + "typescript": "^5.9.3", }, }, }, @@ -580,7 +581,7 @@ "longest-streak": ["longest-streak@3.1.0", "", {}, "sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g=="], - "lucide-react": ["lucide-react@0.560.0", "", { "peerDependencies": { "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-NwKoUA/aBShsdL8WE5lukV2F/tjHzQRlonQs7fkNGI1sCT0Ay4a9Ap3ST2clUUkcY+9eQ0pBe2hybTQd2fmyDA=="], + "lucide-react": ["lucide-react@0.562.0", "", { "peerDependencies": { "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-82hOAu7y0dbVuFfmO4bYF1XEwYk/mEbM5E+b1jgci/udUBEE/R7LF5Ip0CCEmXe8AybRM8L+04eP+LGZeDvkiw=="], "magic-string": ["magic-string@0.30.21", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.5" } }, "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ=="], @@ -688,6 +689,8 @@ "react-dom": ["react-dom@19.2.3", "", { "dependencies": { "scheduler": "^0.27.0" }, "peerDependencies": { "react": "^19.2.3" } }, "sha512-yELu4WmLPw5Mr/lmeEpox5rw3RETacE++JgHqQzd2dg+YbJuat3jH4ingc+WPZhxaoFzdv9y33G+F7Nl5O0GBg=="], + "react-fast-compare": ["react-fast-compare@3.2.2", "", {}, "sha512-nsO+KSNgo1SbJqJEYRE9ERzo7YtYbou/OqjSQKxV7jcKox7+usiUVZOAC+XnDOABXggQTno0Y1CpVnuWEc1boQ=="], + "react-hook-form": ["react-hook-form@7.68.0", "", { "peerDependencies": { "react": "^16.8.0 || ^17 || ^18 || ^19" } }, "sha512-oNN3fjrZ/Xo40SWlHf1yCjlMK417JxoSJVUXQjGdvdRCU07NTFei1i1f8ApUAts+IVh14e4EdakeLEA+BEAs/Q=="], "react-is": ["react-is@18.3.1", "", {}, "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg=="], @@ -700,6 +703,8 @@ "react-resizable-panels": ["react-resizable-panels@3.0.6", "", { "peerDependencies": { "react": "^16.14.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc", "react-dom": "^16.14.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" } }, "sha512-b3qKHQ3MLqOgSS+FRYKapNkJZf5EQzuf6+RLiq1/IlTHw99YrZ2NJZLk4hQIzTnnIkRg2LUqyVinu6YWWpUYew=="], + "react-snowfall": ["react-snowfall@2.4.0", "", { "dependencies": { "react-fast-compare": "^3.2.2" }, "peerDependencies": { "react": "^16.8 || 17.x || 18.x || 19.x", "react-dom": "^16.8 || 17.x || 18.x || 19.x" } }, "sha512-KAPMiGnxt11PEgC2pTVrTQsvk5jt1kLUtG+ZamiKLphTZ7GiYT1Aa5kX6jp4jKWq1kqJHchnGT9CDm4g86A5Gg=="], + "react-style-singleton": ["react-style-singleton@2.2.3", "", { "dependencies": { "get-nonce": "^1.0.0", "tslib": "^2.0.0" }, "peerDependencies": { "@types/react": "*", "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-b6jSvxvVnyptAiLjbkWLE/lOnR4lfTtDAl+eUC7RZy+QQWc6wRzIV2CE6xBuMmDxc2qIihtDCZD5NPOFl7fRBQ=="], "recharts": ["recharts@3.5.1", "", { "dependencies": { "@reduxjs/toolkit": "1.x.x || 2.x.x", "clsx": "^2.1.1", "decimal.js-light": "^2.5.1", "es-toolkit": "^1.39.3", "eventemitter3": "^5.0.1", "immer": "^10.1.1", "react-redux": "8.x.x || 9.x.x", "reselect": "5.1.1", "tiny-invariant": "^1.3.3", "use-sync-external-store": "^1.2.2", "victory-vendor": "^37.0.2" }, "peerDependencies": { "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", "react-dom": "^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", "react-is": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-+v+HJojK7gnEgG6h+b2u7k8HH7FhyFUzAc4+cPrsjL4Otdgqr/ecXzAnHciqlzV1ko064eNcsdzrYOM78kankA=="], diff --git a/package.json b/package.json index 5e314ce..7ce538a 100644 --- a/package.json +++ b/package.json @@ -49,7 +49,7 @@ "gray-matter": "^4.0.3", "highlight.js": "^11.11.1", "input-otp": "^1.4.2", - "lucide-react": "^0.560.0", + "lucide-react": "^0.562.0", "next": "16.0.10", "next-themes": "^0.4.6", "radix-ui": "^1.4.3", @@ -58,6 +58,7 @@ "react-dom": "19.2.3", "react-hook-form": "^7.68.0", "react-resizable-panels": "^3.0.6", + "react-snowfall": "^2.4.0", "recharts": "3.5.1", "sonner": "^2.0.7", "tailwind-merge": "^3.4.0", diff --git a/public/icon/discord.svg b/public/icon/discord.svg new file mode 100644 index 0000000..c5b501c --- /dev/null +++ b/public/icon/discord.svg @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/app/page.tsx b/src/app/page.tsx index 55a24a5..f67eb70 100644 --- a/src/app/page.tsx +++ b/src/app/page.tsx @@ -1,13 +1,25 @@ +'use client'; import Projects from "@/components/Projects"; import TimelineComponent from "@/components/timeline"; import Image from "next/image"; import DraggableWindow from "@/components/DraggableWindow"; import ReadmeWindow from "@/components/ReadmeWindow"; +import Snowfall from 'react-snowfall'; +import { useTheme } from "next-themes"; +import { Banner } from "@/components/ui/banner"; +import { LinkIcon, TreeDeciduous, TreePalmIcon, TreesIcon } from "lucide-react"; +import { useState } from "react"; +import Contact from "@/components/Contact"; + +export default function Page() { + const { theme } = useTheme(); + const [show, setShow] = useState(true); -export default async function BlogIndex() { return (
-
+ + +
logome@imnya.ng
+
+ +
+
+ setShow(false)} + icon={ + + } + title={ + <> + 제 크리스마스 트리를 꾸며주세요! + + } + action={{ + label: "트리 꾸미러 가기", + onClick: () => window.open("https://imnya.ng/tree", "_blank"), + }} + /> +
+ -
+

나의 어두움이 다른 사람들에겐 이 되길 바라는 개발자, 정보보안전문가 남현석입니다.

초등학교 시절 운영체제에 흥미를 느껴 컴퓨터를 시작했고, 이후 프로그래밍에 관심을 갖게 되었습니다.

초등학교 4학년 때 Python으로 프로그래밍을 시작했으며, 현재는 TypeScript를 주로 사용합니다.

diff --git a/src/components/Contact.tsx b/src/components/Contact.tsx new file mode 100644 index 0000000..dd91190 --- /dev/null +++ b/src/components/Contact.tsx @@ -0,0 +1,55 @@ +import { Github, Instagram, MailIcon } from "lucide-react"; +import { + Tooltip, + TooltipContent, + TooltipTrigger, +} from "@/components/ui/tooltip"; +import Image from "next/image"; + +const contact = [ + { + "name": "Email", + "url": "mailto:me@imnya.ng", + "icon": , + }, + { + "name": "GitHub", + "url": "https://github.com/imnyang", + "icon": + }, + { + "name": "Instagram", + "url": "https://instagram.com/imnya.ng", + "icon": + }, + { + "name": "Discord", + "url": "https://imnya.ng/discord", + "icon": Discord + }, + +] + +export default function Contact() { + return ( +
+ {contact.map((method) => ( + + + + {method.icon} + + + +

{method.name}

+
+
+ ))} +
+ ); +} \ No newline at end of file diff --git a/src/components/ui/banner.tsx b/src/components/ui/banner.tsx new file mode 100644 index 0000000..86f88f8 --- /dev/null +++ b/src/components/ui/banner.tsx @@ -0,0 +1,123 @@ +"use client" + +import * as React from "react" +import { X } from "lucide-react" +import { cn } from "@/lib/utils" + +function Grid({ + cellSize = 12, + strokeWidth = 1, + patternOffset = [0, 0], + className, +}: { + cellSize?: number + strokeWidth?: number + patternOffset?: [number, number] + className?: string +}) { + const id = React.useId() + + return ( + + + + + + + + + ) +} + +interface BannerProps { + show: boolean + onHide: () => void + icon?: React.ReactNode + title: React.ReactNode + action: { + label: string + onClick: () => void + } + learnMoreUrl?: string +} + +export function Banner({ + show, + onHide, + icon, + title, + action, + learnMoreUrl, +}: BannerProps) { + if (!show) return null + + return ( +
+ + +
+ {icon && ( +
+ {icon} +
+ )} +

+ {title} + {learnMoreUrl && ( + <> + {" "} + + Learn more + + + )} +

+
+ +
+ +
+ + +
+ ) +} \ No newline at end of file diff --git a/src/components/ui/button.tsx b/src/components/ui/button.tsx index d96719c..ac472bb 100644 --- a/src/components/ui/button.tsx +++ b/src/components/ui/button.tsx @@ -5,54 +5,52 @@ 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 transition-all disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 shrink-0 [&_svg]:shrink-0 outline-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive", + "inline-flex items-center justify-center 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", { variants: { variant: { default: "bg-primary text-primary-foreground hover:bg-primary/90", destructive: - "bg-destructive text-white hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/60", + "bg-destructive text-destructive-foreground hover:bg-destructive/90", outline: - "border bg-background shadow-xs hover:bg-accent hover:text-accent-foreground dark:bg-input/30 dark:border-input dark:hover:bg-input/50", + "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 dark:hover:bg-accent/50", + ghost: "hover:bg-accent hover:text-accent-foreground", link: "text-primary underline-offset-4 hover:underline", }, size: { - default: "h-9 px-4 py-2 has-[>svg]:px-3", - sm: "h-8 rounded-md gap-1.5 px-3 has-[>svg]:px-2.5", - lg: "h-10 rounded-md px-6 has-[>svg]:px-4", - icon: "size-9", + default: "h-10 px-4 py-2", + sm: "h-9 rounded-md px-3", + lg: "h-11 rounded-md px-8", + icon: "h-10 w-10", }, }, defaultVariants: { variant: "default", size: "default", }, - } + }, ) -function Button({ - className, - variant, - size, - asChild = false, - ...props -}: React.ComponentProps<"button"> & - VariantProps & { - asChild?: boolean - }) { - const Comp = asChild ? Slot : "button" - - return ( - - ) +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/src/components/ui/checkbox.tsx b/src/components/ui/checkbox.tsx index fa0e4b5..b8e7c62 100644 --- a/src/components/ui/checkbox.tsx +++ b/src/components/ui/checkbox.tsx @@ -2,31 +2,29 @@ import * as React from "react" import * as CheckboxPrimitive from "@radix-ui/react-checkbox" -import { CheckIcon } from "lucide-react" +import { Check } from "lucide-react" import { cn } from "@/lib/utils" -function Checkbox({ - className, - ...props -}: React.ComponentProps) { - return ( - , + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + + - - - - - ) -} + + + +)) +Checkbox.displayName = CheckboxPrimitive.Root.displayName export { Checkbox } diff --git a/src/components/ui/dialog.tsx b/src/components/ui/dialog.tsx index d9ccec9..817a50d 100644 --- a/src/components/ui/dialog.tsx +++ b/src/components/ui/dialog.tsx @@ -1,143 +1,122 @@ -"use client" +'use client'; -import * as React from "react" -import * as DialogPrimitive from "@radix-ui/react-dialog" -import { XIcon } from "lucide-react" +import * as React from 'react'; +import * as DialogPrimitive from '@radix-ui/react-dialog'; +import { X } from 'lucide-react'; -import { cn } from "@/lib/utils" +import { cn } from '@/lib/utils'; -function Dialog({ - ...props -}: React.ComponentProps) { - return -} +const Dialog = DialogPrimitive.Root; -function DialogTrigger({ - ...props -}: React.ComponentProps) { - return -} +const DialogTrigger = DialogPrimitive.Trigger; -function DialogPortal({ - ...props -}: React.ComponentProps) { - return -} +const DialogPortal = DialogPrimitive.Portal; -function DialogClose({ - ...props -}: React.ComponentProps) { - return -} +const DialogClose = DialogPrimitive.Close; -function DialogOverlay({ - className, - ...props -}: React.ComponentProps) { - return ( - , + 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; -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({ +const DialogHeader = ({ className, ...props -}: React.ComponentProps) { - return ( - - ) -} +}: React.HTMLAttributes) => ( +
+); +DialogHeader.displayName = 'DialogHeader'; -function DialogDescription({ +const DialogFooter = ({ className, ...props -}: React.ComponentProps) { - return ( - - ) -} +}: 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, - DialogClose, - DialogContent, - DialogDescription, - DialogFooter, - DialogHeader, - DialogOverlay, DialogPortal, - DialogTitle, + DialogOverlay, + DialogClose, DialogTrigger, -} + DialogContent, + DialogHeader, + DialogFooter, + DialogTitle, + DialogDescription, +}; \ No newline at end of file diff --git a/src/components/ui/input.tsx b/src/components/ui/input.tsx index 8916905..a921025 100644 --- a/src/components/ui/input.tsx +++ b/src/components/ui/input.tsx @@ -2,20 +2,24 @@ import * as React from "react" import { cn } from "@/lib/utils" -function Input({ className, type, ...props }: React.ComponentProps<"input">) { - return ( - - ) -} +export interface InputProps + extends React.InputHTMLAttributes {} + +const Input = React.forwardRef( + ({ className, type, ...props }, ref) => { + return ( + + ) + } +) +Input.displayName = "Input" export { Input } diff --git a/src/components/ui/label.tsx b/src/components/ui/label.tsx index fb5fbc3..afde563 100644 --- a/src/components/ui/label.tsx +++ b/src/components/ui/label.tsx @@ -2,23 +2,25 @@ 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" -function Label({ - className, - ...props -}: React.ComponentProps) { - return ( - - ) -} +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 }