summaryrefslogtreecommitdiff
path: root/components/ui/back-button.tsx
diff options
context:
space:
mode:
Diffstat (limited to 'components/ui/back-button.tsx')
-rw-r--r--components/ui/back-button.tsx112
1 files changed, 112 insertions, 0 deletions
diff --git a/components/ui/back-button.tsx b/components/ui/back-button.tsx
new file mode 100644
index 00000000..364c0b96
--- /dev/null
+++ b/components/ui/back-button.tsx
@@ -0,0 +1,112 @@
+"use client"
+
+import * as React from "react"
+import { useRouter, usePathname } from "next/navigation"
+import { ArrowLeft } from "lucide-react"
+import { Button } from "@/components/ui/button"
+import { cn } from "@/lib/utils"
+
+/**
+ * BackButton 컴포넌트 - 세그먼트를 동적으로 제거하여 상위 경로로 이동
+ *
+ * 사용 예시:
+ *
+ * // 기본 사용 (1개 세그먼트 제거)
+ * <BackButton>목록으로</BackButton>
+ *
+ * // 2개 세그먼트 제거 (/a/b/c/d -> /a/b)
+ * <BackButton segmentsToRemove={2}>상위 목록으로</BackButton>
+ *
+ * // 커스텀 경로로 이동
+ * <BackButton customPath="/dashboard">대시보드로</BackButton>
+ *
+ * // 아이콘 없이 사용
+ * <BackButton showIcon={false}>돌아가기</BackButton>
+ *
+ * // 커스텀 스타일링
+ * <BackButton className="text-blue-600" variant="outline">
+ * 이전 페이지
+ * </BackButton>
+ */
+
+interface BackButtonProps extends React.ComponentPropsWithoutRef<typeof Button> {
+ /**
+ * 제거할 세그먼트 개수 (기본값: 1)
+ * 예: segmentsToRemove=1이면 /a/b/c -> /a/b
+ * segmentsToRemove=2이면 /a/b/c -> /a
+ */
+ segmentsToRemove?: number
+
+ /**
+ * 버튼에 표시할 텍스트 (기본값: "목록으로")
+ */
+ children?: React.ReactNode
+
+ /**
+ * 아이콘을 표시할지 여부 (기본값: true)
+ */
+ showIcon?: boolean
+
+ /**
+ * 커스텀 경로를 지정할 경우 (segmentsToRemove 대신 사용)
+ */
+ customPath?: string
+}
+
+export const BackButton = React.forwardRef<
+ React.ElementRef<typeof Button>,
+ BackButtonProps
+>(({
+ segmentsToRemove = 1,
+ children = "Go Back",
+ showIcon = true,
+ customPath,
+ className,
+ onClick,
+ ...props
+}, ref) => {
+ const router = useRouter()
+ const pathname = usePathname()
+
+ const handleClick = React.useCallback((event: React.MouseEvent<HTMLButtonElement>) => {
+ // 커스텀 onClick이 있으면 먼저 실행
+ if (onClick) {
+ onClick(event)
+ // preventDefault가 호출되었으면 기본 동작 중단
+ if (event.defaultPrevented) {
+ return
+ }
+ }
+
+ let targetPath: string
+
+ if (customPath) {
+ targetPath = customPath
+ } else {
+ // 현재 경로에서 세그먼트 제거
+ const segments = pathname.split('/').filter(Boolean)
+ const newSegments = segments.slice(0, -segmentsToRemove)
+ targetPath = newSegments.length > 0 ? `/${newSegments.join('/')}` : '/'
+ }
+
+ router.push(targetPath)
+ }, [router, pathname, segmentsToRemove, customPath, onClick])
+
+ return (
+ <Button
+ ref={ref}
+ variant="ghost"
+ className={cn(
+ "flex items-center text-primary hover:text-primary/80 transition-colors p-0 h-auto",
+ className
+ )}
+ onClick={handleClick}
+ {...props}
+ >
+ {showIcon && <ArrowLeft className="mr-1 h-4 w-4" />}
+ <span>{children}</span>
+ </Button>
+ )
+})
+
+BackButton.displayName = "BackButton" \ No newline at end of file