From de0863c8ad8b33fd803045347d7e518a7b82877a Mon Sep 17 00:00:00 2001 From: jungwoo choi Date: Sat, 14 Feb 2026 07:29:22 +0900 Subject: [PATCH] =?UTF-8?q?fix:=20=ED=8A=B8=EB=A6=AC=20=EB=85=B8=EB=93=9C?= =?UTF-8?q?=EC=97=90=EC=84=9C=20=EB=B6=80=EB=AA=A8=EC=99=80=20=EA=B2=B9?= =?UTF-8?q?=EC=B9=98=EB=8A=94=20=EA=B2=BD=EB=A1=9C=20=EC=A0=91=EB=91=90?= =?UTF-8?q?=EC=82=AC=EB=A7=8C=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit /about/press → /press (부모 /about 제거) /about → /about (루트 직속은 전체 경로) / → / Co-Authored-By: Claude Opus 4.6 --- .../site-inspection/PageTreeNode.tsx | 37 +++++++++++++------ 1 file changed, 26 insertions(+), 11 deletions(-) diff --git a/frontend/src/components/site-inspection/PageTreeNode.tsx b/frontend/src/components/site-inspection/PageTreeNode.tsx index dba5f20..a2a669f 100644 --- a/frontend/src/components/site-inspection/PageTreeNode.tsx +++ b/frontend/src/components/site-inspection/PageTreeNode.tsx @@ -26,28 +26,40 @@ interface PageTreeNodeProps { onSelectPage: (url: string) => void; /** 들여쓰기 레벨 */ level: number; + /** 부모 노드의 경로 (중복 경로 제거용) */ + parentPath?: string; } /** - * URL에서 마지막 경로 세그먼트만 반환. - * 루트는 "/", 나머지는 마지막 세그먼트만 표시. - * 예: "https://example.com/" -> "/" - * "https://example.com/about" -> "about" - * "https://example.com/about/press" -> "press" + * URL에서 부모 경로와 겹치는 앞부분을 제거하여 표시명 반환. + * 예: parentPath="/about", url="/about/press" → "/press" + * parentPath="/", url="/about" → "/about" + * parentPath=undefined, url="/" → "/" */ -function getDisplayName(url: string): string { +function getDisplayName(url: string, parentPath?: string): string { try { const parsed = new URL(url); - const path = parsed.pathname; + const path = parsed.pathname || "/"; if (path === "/" || path === "") return "/"; - const clean = path.endsWith("/") ? path.slice(0, -1) : path; - const segments = clean.split("/").filter(Boolean); - return segments[segments.length - 1] || "/"; + + if (parentPath && parentPath !== "/" && path.startsWith(parentPath)) { + return path.slice(parentPath.length) || path; + } + return path; } catch { return url; } } +/** URL에서 pathname만 추출 */ +function getPathFromUrl(url: string): string { + try { + return new URL(url).pathname || "/"; + } catch { + return "/"; + } +} + /** 페이지 트리 노드 (재귀 컴포넌트) */ export function PageTreeNode({ page, @@ -56,12 +68,14 @@ export function PageTreeNode({ selectedUrl, onSelectPage, level, + parentPath, }: PageTreeNodeProps) { const [isExpanded, setIsExpanded] = useState(level < 2); const children = childrenPages.get(page.url) || []; const hasChildren = children.length > 0; const isSelected = selectedUrl === page.url; - const displayPath = getDisplayName(page.url); + const currentPath = getPathFromUrl(page.url); + const displayPath = getDisplayName(page.url, parentPath); return (
@@ -137,6 +151,7 @@ export function PageTreeNode({ selectedUrl={selectedUrl} onSelectPage={onSelectPage} level={level + 1} + parentPath={currentPath} /> ))}