나의 어두움이 다른 사람들에겐 빛이 되길 바라는 개발자, 정보보안전문가 남현석입니다.
초등학교 시절 운영체제에 흥미를 느껴 컴퓨터를 시작했고, 이후 프로그래밍에 관심을 갖게 되었습니다.
초등학교 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":
+ },
+
+]
+
+export default function Contact() {
+ return (
+
+ );
+}
\ 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 }