From c88967cb6f6f9077cde52ef42df15e11b6d8da35 Mon Sep 17 00:00:00 2001 From: jungwoo choi Date: Sat, 14 Feb 2026 07:42:28 +0900 Subject: [PATCH] =?UTF-8?q?fix:=20=ED=8A=B8=EB=A6=AC=20=EA=B2=BD=EB=A1=9C?= =?UTF-8?q?=20=ED=91=9C=EC=8B=9C=20=EA=B0=9C=EC=84=A0=20-=20=EC=8A=AC?= =?UTF-8?q?=EB=9E=98=EC=8B=9C=20=EC=A0=9C=EA=B1=B0=20+=20=EC=BF=BC?= =?UTF-8?q?=EB=A6=AC=20=ED=8C=8C=EB=9D=BC=EB=AF=B8=ED=84=B0=20=EB=B6=84?= =?UTF-8?q?=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 자식 노드에서 부모와 겹치는 경로 + 앞의 / 제거 /about → about, /about/press → press - 쿼리 파라미터가 있는 URL을 path 하위에 쿼리만 표시 /search?q=foo → search 하위에 q=foo - findPathParent에서 쿼리 URL의 부모를 같은 path로 매핑 Co-Authored-By: Claude Opus 4.6 --- .../components/site-inspection/PageTree.tsx | 30 ++++++++++++---- .../site-inspection/PageTreeNode.tsx | 36 +++++++++++++++---- 2 files changed, 54 insertions(+), 12 deletions(-) diff --git a/frontend/src/components/site-inspection/PageTree.tsx b/frontend/src/components/site-inspection/PageTree.tsx index ad254b3..3e61a75 100644 --- a/frontend/src/components/site-inspection/PageTree.tsx +++ b/frontend/src/components/site-inspection/PageTree.tsx @@ -20,20 +20,38 @@ interface PageTreeProps { /** * URL 경로 기반으로 부모 페이지를 찾는다. - * 경로 세그먼트를 하나씩 올라가며 실제 존재하는 페이지를 찾고, - * 없으면 null (최상위)을 반환한다. + * 1. 쿼리 파라미터가 있으면 같은 path의 쿼리 없는 URL을 부모로 + * 2. 경로 세그먼트를 하나씩 올라가며 실제 존재하는 페이지를 찾음 + * 3. 없으면 null (최상위) * - * 예: /about/press → /about (존재) → 부모 + * 예: /search?q=foo → /search (존재) → 부모 + * /about/press → /about (존재) → 부모 * /howyoutubeworks → / (존재) → 부모 - * /creators/podcasts → / (존재, /creators 없음) → 부모 */ function findPathParent(url: string, pageUrls: Set): string | null { try { const parsed = new URL(url); const path = parsed.pathname; + const hasQuery = !!parsed.search; - // 루트 경로는 부모 없음 - if (path === "/" || path === "") return null; + // 루트 경로 (쿼리 없음)는 부모 없음 + if ((path === "/" || path === "") && !hasQuery) return null; + + // 쿼리가 있으면 같은 path의 쿼리 없는 URL을 부모로 찾기 + if (hasQuery) { + const pathOnlyUrl = `${parsed.origin}${path}`; + if (pageUrls.has(pathOnlyUrl) && pathOnlyUrl !== url) { + return pathOnlyUrl; + } + // 쿼리 없는 같은 path가 없으면 path 기반으로 계속 탐색 + } + + // 루트 경로 + 쿼리인 경우 (예: /?q=foo) → 루트가 부모 + if (path === "/" || path === "") { + const rootWithSlash = `${parsed.origin}/`; + if (pageUrls.has(rootWithSlash) && rootWithSlash !== url) return rootWithSlash; + return null; + } const cleanPath = path.endsWith("/") ? path.slice(0, -1) : path; const segments = cleanPath.split("/").filter(Boolean); diff --git a/frontend/src/components/site-inspection/PageTreeNode.tsx b/frontend/src/components/site-inspection/PageTreeNode.tsx index a2a669f..9e07e71 100644 --- a/frontend/src/components/site-inspection/PageTreeNode.tsx +++ b/frontend/src/components/site-inspection/PageTreeNode.tsx @@ -32,20 +32,44 @@ interface PageTreeNodeProps { /** * URL에서 부모 경로와 겹치는 앞부분을 제거하여 표시명 반환. - * 예: parentPath="/about", url="/about/press" → "/press" - * parentPath="/", url="/about" → "/about" + * 루트만 "/", 나머지는 슬래시 없이 표시. + * 쿼리 파라미터만 다른 URL은 쿼리 부분만 표시. + * + * 예: parentPath="/about", url="/about/press" → "press" + * parentPath="/", url="/about" → "about" + * parentPath="/search", url="/search?q=foo" → "q=foo" * parentPath=undefined, url="/" → "/" */ function getDisplayName(url: string, parentPath?: string): string { try { const parsed = new URL(url); const path = parsed.pathname || "/"; - if (path === "/" || path === "") return "/"; + const query = parsed.search ? parsed.search.slice(1) : ""; // "?" 제거 - if (parentPath && parentPath !== "/" && path.startsWith(parentPath)) { - return path.slice(parentPath.length) || path; + if (path === "/" && !query) return "/"; + + // 같은 경로에 쿼리만 다른 경우 → 쿼리만 표시 + if (parentPath && path === parentPath && query) { + return query; } - return path; + + // 부모 경로 접두사 제거 + let display = path; + if (parentPath && parentPath !== "/" && path.startsWith(parentPath)) { + display = path.slice(parentPath.length); + } + + // 앞의 슬래시 제거 (루트 제외) + if (display.startsWith("/")) { + display = display.slice(1); + } + + // 쿼리가 있으면 붙이기 + if (query) { + display = display ? `${display}?${query}` : query; + } + + return display || "/"; } catch { return url; }