diff --git a/prisma/seed.js b/prisma/seed.js index 31c7d34..b38d035 100644 --- a/prisma/seed.js +++ b/prisma/seed.js @@ -5,7 +5,7 @@ const prisma = new PrismaClient(); async function upsertCategories() { // 카테고리 트리 (projectmemo 기준 상위 그룹) const categories = [ - { name: "암실소문 (메인)", slug: "main", sortOrder: 1, status: "active" }, + { name: "암실소문", slug: "main", sortOrder: 1, status: "active" }, { name: "명예의 전당", slug: "hall-of-fame", sortOrder: 2, status: "active" }, { name: "주변 제휴업체", slug: "nearby-partners", sortOrder: 3, status: "active" }, { name: "제휴업소 정보", slug: "partner-info", sortOrder: 4, status: "active" }, @@ -128,8 +128,11 @@ async function upsertBoards(admin, categoryMap) { { name: "회원랭킹", slug: "ranking", description: "랭킹", type: "special", sortOrder: 14 }, { name: "무료쿠폰", slug: "free-coupons", description: "쿠폰", type: "special", sortOrder: 15 }, { name: "월간집계", slug: "monthly-stats", description: "월간 통계", type: "special", sortOrder: 16 }, - // 제휴업소 일반(사진) - { name: "제휴업소 일반(사진)", slug: "partners-photos", description: "사진 전용 게시판", type: "general", sortOrder: 17, requiredFields: { imageOnly: true, minImages: 1, maxImages: 10 } }, + // 제휴업소 일반 + { name: "제휴업소", slug: "partners-photos", description: "사진 전용 게시판", type: "general", sortOrder: 17, requiredFields: { imageOnly: true, minImages: 1, maxImages: 10 } }, + // 광고/제휴 + { name: "제휴문의", slug: "partner-contact", description: "제휴문의", type: "general", sortOrder: 18, requiredFields: { imageOnly: true, minImages: 1, maxImages: 10 } }, + { name: "제휴업소 요청", slug: "partner-req", description: "제휴업소 요청", type: "general", sortOrder: 19, requiredFields: { imageOnly: true, minImages: 1, maxImages: 10 } }, ]; const created = []; @@ -159,6 +162,9 @@ async function upsertBoards(admin, categoryMap) { anonymous: "community", "find-therapist": "community", "blue-house": "community", + // 광고/제휴 + "partner-contact": "ads-affiliates", + "partner-req": "ads-affiliates", }; const categorySlug = mapBySlug[b.slug] || "community"; const category = categoryMap[categorySlug]; diff --git a/src/app/components/AppHeader.tsx b/src/app/components/AppHeader.tsx index 878af60..5400967 100644 --- a/src/app/components/AppHeader.tsx +++ b/src/app/components/AppHeader.tsx @@ -18,6 +18,19 @@ export function AppHeader() { const [leftPositions, setLeftPositions] = React.useState>({}); const [panelHeight, setPanelHeight] = React.useState(0); const [blockWidths, setBlockWidths] = React.useState>({}); + const closeTimer = React.useRef(null); + + const cancelClose = React.useCallback(() => { + if (closeTimer.current) { + window.clearTimeout(closeTimer.current); + closeTimer.current = null; + } + }, []); + + const scheduleClose = React.useCallback(() => { + cancelClose(); + closeTimer.current = window.setTimeout(() => setMegaOpen(false), 150); + }, [cancelClose]); // 카테고리 로드 React.useEffect(() => { fetch("/api/categories", { cache: "no-store" }) @@ -120,8 +133,8 @@ export function AppHeader() { {/* 데스크톱 메가메뉴 */}
setMegaOpen(true)} - onMouseLeave={() => setMegaOpen(false)} + onMouseEnter={() => { cancelClose(); setMegaOpen(true); }} + onMouseLeave={() => { scheduleClose(); }} onFocusCapture={() => setMegaOpen(true)} onBlurCapture={(e) => { const next = (e as unknown as React.FocusEvent).relatedTarget as Node | null; @@ -153,8 +166,10 @@ export function AppHeader() { megaOpen ? "opacity-100" : "pointer-events-none opacity-0" }`} style={{ top: headerBottom }} + onMouseEnter={() => { cancelClose(); setMegaOpen(true); }} + onMouseLeave={() => { scheduleClose(); }} > -
+
{categories.map((cat) => (
-
+