푸터조금 메가메뉴 조금금
This commit is contained in:
File diff suppressed because one or more lines are too long
|
Before Width: | Height: | Size: 795 KiB After Width: | Height: | Size: 795 KiB |
@@ -4,9 +4,9 @@ export function AppFooter() {
|
|||||||
<div className="text-[#626262] text-[16px] leading-[14px] flex flex-row mb-[30px]">
|
<div className="text-[#626262] text-[16px] leading-[14px] flex flex-row mb-[30px]">
|
||||||
<div className="flex-1"></div>
|
<div className="flex-1"></div>
|
||||||
<div className="border-r border-dotted border-[#626262] px-[8px] cursor-pointer hover:text-[#2BAF7E]">개인정보처리방침</div>
|
<div className="border-r border-dotted border-[#626262] px-[8px] cursor-pointer hover:text-[#2BAF7E]">개인정보처리방침</div>
|
||||||
<div className="border-r border-dotted border-[#626262] px-[8px] cursor-pointer hover:text-[#2BAF7E]">이메일 무단수집거부</div>
|
<div className="hidden lg:block border-r border-dotted border-[#626262] px-[8px] cursor-pointer hover:text-[#2BAF7E]">이메일 무단수집거부</div>
|
||||||
<div className="border-r border-dotted border-[#626262] px-[8px] cursor-pointer hover:text-[#2BAF7E]">책임의 한계와 법적고지</div>
|
<div className=" border-r border-dotted border-[#626262] px-[8px] cursor-pointer hover:text-[#2BAF7E]">책임의 한계와 법적고지</div>
|
||||||
<div className="border-r border-dotted border-[#626262] px-[8px] cursor-pointer hover:text-[#2BAF7E]">이용안내</div>
|
<div className="hidden lg:block border-r border-dotted border-[#626262] px-[8px] cursor-pointer hover:text-[#2BAF7E]">이용안내</div>
|
||||||
<div className="px-[8px] cursor-pointer hover:text-[#2BAF7E]">문의하기</div>
|
<div className="px-[8px] cursor-pointer hover:text-[#2BAF7E]">문의하기</div>
|
||||||
<div className="flex-1"></div>
|
<div className="flex-1"></div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import Image from "next/image";
|
|||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
import { SearchBar } from "@/app/components/SearchBar";
|
import { SearchBar } from "@/app/components/SearchBar";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
|
import { usePathname, useSearchParams } from "next/navigation";
|
||||||
|
|
||||||
export function AppHeader() {
|
export function AppHeader() {
|
||||||
const [categories, setCategories] = React.useState<Array<{ id: string; name: string; slug: string; boards: Array<{ id: string; name: string; slug: string }> }>>([]);
|
const [categories, setCategories] = React.useState<Array<{ id: string; name: string; slug: string; boards: Array<{ id: string; name: string; slug: string }> }>>([]);
|
||||||
@@ -20,6 +21,26 @@ export function AppHeader() {
|
|||||||
const [blockWidths, setBlockWidths] = React.useState<Record<string, number>>({});
|
const [blockWidths, setBlockWidths] = React.useState<Record<string, number>>({});
|
||||||
const closeTimer = React.useRef<number | null>(null);
|
const closeTimer = React.useRef<number | null>(null);
|
||||||
|
|
||||||
|
// 현재 경로 기반 활성 보드/카테고리 계산
|
||||||
|
const pathname = usePathname();
|
||||||
|
const searchParams = useSearchParams();
|
||||||
|
const activeBoardId = React.useMemo(() => {
|
||||||
|
if (!pathname) return null;
|
||||||
|
const parts = pathname.split("/").filter(Boolean);
|
||||||
|
if (parts[0] === "boards" && parts[1]) return parts[1];
|
||||||
|
return null;
|
||||||
|
}, [pathname]);
|
||||||
|
const activeCategorySlug = React.useMemo(() => {
|
||||||
|
if (activeBoardId) {
|
||||||
|
const found = categories.find((c) => c.boards.some((b) => b.id === activeBoardId));
|
||||||
|
return found?.slug ?? null;
|
||||||
|
}
|
||||||
|
if (pathname === "/boards") {
|
||||||
|
return searchParams?.get("category") ?? null;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}, [activeBoardId, pathname, searchParams, categories]);
|
||||||
|
|
||||||
const cancelClose = React.useCallback(() => {
|
const cancelClose = React.useCallback(() => {
|
||||||
if (closeTimer.current) {
|
if (closeTimer.current) {
|
||||||
window.clearTimeout(closeTimer.current);
|
window.clearTimeout(closeTimer.current);
|
||||||
@@ -83,16 +104,19 @@ export function AppHeader() {
|
|||||||
});
|
});
|
||||||
setLeftPositions(nextPositions);
|
setLeftPositions(nextPositions);
|
||||||
|
|
||||||
// 각 블록의 가로 폭 = 다음 항목의 left까지 남은 거리 (마지막은 컨테이너 오른쪽 끝)
|
// 각 블록의 가로 폭 = 다음 항목의 left까지 남은 거리
|
||||||
|
// 마지막 항목은 컨테이너 끝까지 확장되지 않도록 width를 지정하지 않음
|
||||||
const nextWidths: Record<string, number> = {};
|
const nextWidths: Record<string, number> = {};
|
||||||
const ordered = categories
|
const ordered = categories
|
||||||
.filter((c) => typeof nextPositions[c.slug] === "number")
|
.filter((c) => typeof nextPositions[c.slug] === "number")
|
||||||
.sort((a, b) => (nextPositions[a.slug]! - nextPositions[b.slug]!));
|
.sort((a, b) => (nextPositions[a.slug]! - nextPositions[b.slug]!));
|
||||||
ordered.forEach((cat, idx) => {
|
ordered.forEach((cat, idx) => {
|
||||||
const currentLeft = nextPositions[cat.slug]!;
|
const currentLeft = nextPositions[cat.slug]!;
|
||||||
const nextLeft = idx < ordered.length - 1 ? nextPositions[ordered[idx + 1].slug]! : containerRect.width;
|
if (idx < ordered.length - 1) {
|
||||||
|
const nextLeft = nextPositions[ordered[idx + 1].slug]!;
|
||||||
const width = Math.max(0, nextLeft - currentLeft);
|
const width = Math.max(0, nextLeft - currentLeft);
|
||||||
nextWidths[cat.slug] = width;
|
nextWidths[cat.slug] = width;
|
||||||
|
}
|
||||||
});
|
});
|
||||||
setBlockWidths(nextWidths);
|
setBlockWidths(nextWidths);
|
||||||
|
|
||||||
@@ -143,10 +167,12 @@ export function AppHeader() {
|
|||||||
>
|
>
|
||||||
<div className="flex items-center gap-8">
|
<div className="flex items-center gap-8">
|
||||||
{categories.map((cat) => (
|
{categories.map((cat) => (
|
||||||
<div key={cat.id} className="relative group" onMouseEnter={() => setOpenSlug(cat.slug)}>
|
<div key={cat.id} className="relative group min-w-[80px] text-center" onMouseEnter={() => setOpenSlug(cat.slug)}>
|
||||||
<Link
|
<Link
|
||||||
href={`/boards?category=${cat.slug}`}
|
href={cat.boards?.[0]?.id ? `/boards/${cat.boards[0].id}` : `/boards?category=${cat.slug}`}
|
||||||
className="px-2 py-2 text-sm font-medium text-neutral-700 transition-colors duration-200 hover:text-neutral-900"
|
className={`px-2 py-2 text-sm font-medium transition-colors duration-200 hover:text-neutral-900 ${
|
||||||
|
activeCategorySlug === cat.slug ? "text-neutral-900" : "text-neutral-700"
|
||||||
|
}`}
|
||||||
ref={(el) => {
|
ref={(el) => {
|
||||||
navRefs.current[cat.slug] = el;
|
navRefs.current[cat.slug] = el;
|
||||||
}}
|
}}
|
||||||
@@ -155,7 +181,9 @@ export function AppHeader() {
|
|||||||
</Link>
|
</Link>
|
||||||
<span
|
<span
|
||||||
className={`pointer-events-none absolute left-1 right-1 -bottom-0.5 h-0.5 origin-left rounded bg-neutral-900 transition-all duration-200 ${
|
className={`pointer-events-none absolute left-1 right-1 -bottom-0.5 h-0.5 origin-left rounded bg-neutral-900 transition-all duration-200 ${
|
||||||
openSlug === cat.slug ? "scale-x-100 opacity-100" : "scale-x-0 opacity-0 group-hover:opacity-100 group-hover:scale-x-100"
|
openSlug === cat.slug || activeCategorySlug === cat.slug
|
||||||
|
? "scale-x-100 opacity-100"
|
||||||
|
: "scale-x-0 opacity-0 group-hover:opacity-100 group-hover:scale-x-100"
|
||||||
}`}
|
}`}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
@@ -186,7 +214,10 @@ export function AppHeader() {
|
|||||||
<Link
|
<Link
|
||||||
key={b.id}
|
key={b.id}
|
||||||
href={`/boards/${b.id}`}
|
href={`/boards/${b.id}`}
|
||||||
className="rounded px-2 py-1 text-sm text-neutral-700 transition-colors duration-150 hover:bg-neutral-100 hover:text-neutral-900"
|
className={`rounded px-2 py-1 text-sm transition-colors duration-150 hover:bg-neutral-100 hover:text-neutral-900 text-center ${
|
||||||
|
activeBoardId === b.id ? "bg-neutral-100 text-neutral-900 font-medium" : "text-neutral-700"
|
||||||
|
}`}
|
||||||
|
aria-current={activeBoardId === b.id ? "page" : undefined}
|
||||||
>
|
>
|
||||||
{b.name}
|
{b.name}
|
||||||
</Link>
|
</Link>
|
||||||
|
|||||||
Reference in New Issue
Block a user