diff --git a/src/app/(main)/layout.tsx b/src/app/(main)/layout.tsx new file mode 100644 index 0000000..a5ceba9 --- /dev/null +++ b/src/app/(main)/layout.tsx @@ -0,0 +1,94 @@ +"use client"; + +import { useState } from "react"; +import { usePathname } from "next/navigation"; +import IconViewSidebar from "@/components/icons/icon-view_sidebar.svg"; +import IPXLogo from "@/components/icons/logo-ipx-char.svg"; +import NewSearch from "@/components/icons/icon-create.svg"; +import Search from "@/components/icons/icon-search.svg"; +import MyProject from "@/components/icons/icon-folder.svg"; +import { SidebarNavItem } from "@/components/sidebar/SidebarNavItem"; +import { PreviousSearchItem } from "@/components/sidebar/PreviousSearchItem"; + +export default function MainLayout({ children }: { children: React.ReactNode }) { + const [openSidebar, setOpenSidebar] = useState(true); + const pathname = usePathname(); + + const PAGE_LABELS: Record = { + "/search": "새로 탐색하기", + "/project": "내 프로젝트", + "/history": "탐색 내역 찾기", + }; + + const pageLabel = PAGE_LABELS[pathname] ?? ""; + + return ( +
+ {/* 사이드바 */} + + + {/* 사이드바를 제외한 영역 */} +
+ {/* 탑바 */} +
+ {pageLabel}{" "} + {/* api 연동 이후 뎁스 추가 예정 */} +
{/* 프로필 영역 추가 예정 */} +
+ + {/* 페이지별 내용 */} +
{children}
+
+
+ ); +} diff --git a/src/app/(main)/page.tsx b/src/app/(main)/page.tsx new file mode 100644 index 0000000..89f19b8 --- /dev/null +++ b/src/app/(main)/page.tsx @@ -0,0 +1,3 @@ +export default function MainPage() { + return <>; +} diff --git a/src/app/(main)/search/page.tsx b/src/app/(main)/search/page.tsx new file mode 100644 index 0000000..b93c9ca --- /dev/null +++ b/src/app/(main)/search/page.tsx @@ -0,0 +1,7 @@ +export default function Search() { + return ( + <> +
+ + ); +} diff --git a/src/components/sidebar/PreviousSearchItem.tsx b/src/components/sidebar/PreviousSearchItem.tsx new file mode 100644 index 0000000..4d78ee1 --- /dev/null +++ b/src/components/sidebar/PreviousSearchItem.tsx @@ -0,0 +1,39 @@ +import Link from "next/link"; +import { cva, type VariantProps } from "class-variance-authority"; +import { cn } from "@/lib/cn"; + +const previousSearchItemVariants = cva( + "flex w-full cursor-pointer items-center px-3 py-2 transition-colors", + { + variants: { + active: { + true: "rounded-lg bg-primary-120 text-primary-50", + false: "text-gray-30 hover:rounded-lg hover:bg-gray-90 text-gray-20", + }, + }, + defaultVariants: { active: false }, + } +); + +export type PreviousSearchItemProps = VariantProps & { + href: string; + label: string; + open?: boolean; + className?: string; +}; + +export function PreviousSearchItem({ + href, + label, + active, + open = true, + className, +}: PreviousSearchItemProps) { + return ( + + {open && {label}} + + ); +} + +PreviousSearchItem.displayName = "PreviousSearchItem"; diff --git a/src/components/sidebar/SidebarNavItem.tsx b/src/components/sidebar/SidebarNavItem.tsx new file mode 100644 index 0000000..a5799a0 --- /dev/null +++ b/src/components/sidebar/SidebarNavItem.tsx @@ -0,0 +1,45 @@ +import Link from "next/link"; +import { cva, type VariantProps } from "class-variance-authority"; +import { cn } from "@/lib/cn"; + +const sidebarNavItemVariants = cva( + "flex w-full cursor-pointer items-center gap-2 px-3 py-2 transition-colors", + { + variants: { + active: { + true: "rounded-lg bg-primary-120 text-primary-50", + false: "text-gray-20 hover:rounded-lg hover:bg-gray-90", + }, + }, + defaultVariants: { active: false }, + } +); + +export type SidebarNavItemProps = VariantProps & { + href: string; + icon: React.ReactNode; + label: string; + open?: boolean; + className?: string; +}; + +export function SidebarNavItem({ + href, + icon, + label, + active, + open = true, + className, +}: SidebarNavItemProps) { + return ( + +
{icon}
+ {open && {label}} + + ); +} + +SidebarNavItem.displayName = "SidebarNavItem";