fix: 트리 경로 표시 개선 - 슬래시 제거 + 쿼리 파라미터 분리
- 자식 노드에서 부모와 겹치는 경로 + 앞의 / 제거 /about → about, /about/press → press - 쿼리 파라미터가 있는 URL을 path 하위에 쿼리만 표시 /search?q=foo → search 하위에 q=foo - findPathParent에서 쿼리 URL의 부모를 같은 path로 매핑 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@ -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>): 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);
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user