fix: URL 경로 기반으로 페이지 트리 계층 구성 + 중복 제거
parent_url(크롤링 발견 순서) 대신 URL path 계층으로 트리를 구성하여 /howyoutubeworks가 /about 하위로 잘못 표시되는 문제 수정. 동일 URL 중복 노드도 제거. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@ -18,9 +18,50 @@ interface PageTreeProps {
|
|||||||
aggregateScores: AggregateScores | null;
|
aggregateScores: AggregateScores | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* URL 경로 기반으로 부모 페이지를 찾는다.
|
||||||
|
* 경로 세그먼트를 하나씩 올라가며 실제 존재하는 페이지를 찾고,
|
||||||
|
* 없으면 null (최상위)을 반환한다.
|
||||||
|
*
|
||||||
|
* 예: /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;
|
||||||
|
|
||||||
|
// 루트 경로는 부모 없음
|
||||||
|
if (path === "/" || path === "") return null;
|
||||||
|
|
||||||
|
const cleanPath = path.endsWith("/") ? path.slice(0, -1) : path;
|
||||||
|
const segments = cleanPath.split("/").filter(Boolean);
|
||||||
|
|
||||||
|
// 경로를 한 단계씩 올라가며 존재하는 페이지 찾기
|
||||||
|
for (let i = segments.length - 1; i >= 1; i--) {
|
||||||
|
const parentPath = "/" + segments.slice(0, i).join("/");
|
||||||
|
const parentUrl = `${parsed.origin}${parentPath}`;
|
||||||
|
if (pageUrls.has(parentUrl)) {
|
||||||
|
return parentUrl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 루트 페이지 확인 (trailing slash 유무 모두)
|
||||||
|
const rootWithSlash = `${parsed.origin}/`;
|
||||||
|
const rootWithout = parsed.origin;
|
||||||
|
if (pageUrls.has(rootWithSlash) && rootWithSlash !== url) return rootWithSlash;
|
||||||
|
if (pageUrls.has(rootWithout) && rootWithout !== url) return rootWithout;
|
||||||
|
|
||||||
|
return null;
|
||||||
|
} catch {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 페이지 트리 사이드바 컴포넌트.
|
* 페이지 트리 사이드바 컴포넌트.
|
||||||
* flat 배열을 parent_url 기준으로 트리 구조로 변환하여 렌더링한다.
|
* flat 배열을 URL 경로 계층 기준으로 트리 구조로 변환하여 렌더링한다.
|
||||||
*/
|
*/
|
||||||
export function PageTree({
|
export function PageTree({
|
||||||
pages,
|
pages,
|
||||||
@ -29,25 +70,33 @@ export function PageTree({
|
|||||||
aggregateScores,
|
aggregateScores,
|
||||||
}: PageTreeProps) {
|
}: PageTreeProps) {
|
||||||
/**
|
/**
|
||||||
* flat 배열에서 parent_url → children 맵 구성.
|
* URL 경로 기반으로 트리 구성.
|
||||||
* root 노드(parent_url === null)를 최상위 자식으로 처리.
|
* /about/press → /about 하위, /howyoutubeworks → / 하위
|
||||||
*/
|
*/
|
||||||
const { rootPages, childrenMap, allPagesMap } = useMemo(() => {
|
const { rootPages, childrenMap, allPagesMap } = useMemo(() => {
|
||||||
const childrenMap = new Map<string, DiscoveredPage[]>();
|
const childrenMap = new Map<string, DiscoveredPage[]>();
|
||||||
const allPagesMap = new Map<string, DiscoveredPage>();
|
const allPagesMap = new Map<string, DiscoveredPage>();
|
||||||
const rootPages: DiscoveredPage[] = [];
|
const rootPages: DiscoveredPage[] = [];
|
||||||
|
const pageUrls = new Set<string>();
|
||||||
|
|
||||||
|
// 중복 URL 제거 (첫 번째 등장만 유지)
|
||||||
|
const uniquePages: DiscoveredPage[] = [];
|
||||||
for (const page of pages) {
|
for (const page of pages) {
|
||||||
allPagesMap.set(page.url, page);
|
if (!pageUrls.has(page.url)) {
|
||||||
|
pageUrls.add(page.url);
|
||||||
|
allPagesMap.set(page.url, page);
|
||||||
|
uniquePages.push(page);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const page of pages) {
|
for (const page of uniquePages) {
|
||||||
if (page.parent_url === null) {
|
const parentUrl = findPathParent(page.url, pageUrls);
|
||||||
|
if (parentUrl === null) {
|
||||||
rootPages.push(page);
|
rootPages.push(page);
|
||||||
} else {
|
} else {
|
||||||
const siblings = childrenMap.get(page.parent_url) || [];
|
const siblings = childrenMap.get(parentUrl) || [];
|
||||||
siblings.push(page);
|
siblings.push(page);
|
||||||
childrenMap.set(page.parent_url, siblings);
|
childrenMap.set(parentUrl, siblings);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user