mirror of
https://github.com/facebook/docusaurus.git
synced 2025-12-25 17:22:50 +00:00
fix(docs): prioritize category href over links in sidebar breadcrumb search
When a sidebar link in one category points to a generated-index page URL from another category, the breadcrumb search would incorrectly return the link's parent category instead of the category that owns the URL. This fix uses a two-pass approach when searching for the current sidebar category: 1. First pass: Look for categories that directly own the URL (category.href) 2. Second pass: If not found, fall back to finding via links (for doc pages) This ensures generated-index pages display their correct category's items even when another category has a link pointing to the same URL. Closes #11612
This commit is contained in:
parent
d4a66aa2ed
commit
3d28a9e798
|
|
@ -780,6 +780,43 @@ describe('useCurrentSidebarCategory', () => {
|
|||
`"Unexpected: cant find current sidebar in context"`,
|
||||
);
|
||||
});
|
||||
|
||||
// Regression test for https://github.com/facebook/docusaurus/issues/11612
|
||||
// When a link in Category A points to a generated-index URL owned by
|
||||
// Category B, useCurrentSidebarCategory should return Category B (the owner),
|
||||
// not Category A (which merely has a link pointing to it).
|
||||
it('returns the category that owns the URL, not a category with a link pointing to it', () => {
|
||||
// Category B is the actual owner of /category-b (its generated-index href)
|
||||
const categoryB: PropSidebarItemCategory = testCategory({
|
||||
label: 'Category B',
|
||||
href: '/category-b',
|
||||
items: [
|
||||
testLink({href: '/category-b/item1', label: 'Item 1'}),
|
||||
testLink({href: '/category-b/item2', label: 'Item 2'}),
|
||||
],
|
||||
});
|
||||
|
||||
// Category A contains a link that points to Category B's URL
|
||||
const categoryA: PropSidebarItemCategory = testCategory({
|
||||
label: 'Category A',
|
||||
href: '/category-a',
|
||||
items: [
|
||||
testLink({href: '/category-a/doc1', label: 'Doc 1'}),
|
||||
testLink({href: '/category-a/doc2', label: 'Doc 2'}),
|
||||
// This link points to Category B's generated-index
|
||||
testLink({href: '/category-b', label: 'Go to Category B'}),
|
||||
],
|
||||
});
|
||||
|
||||
const sidebar: PropSidebar = [categoryA, categoryB];
|
||||
|
||||
const mockUseCurrentSidebarCategory =
|
||||
createUseCurrentSidebarCategoryMock(sidebar);
|
||||
|
||||
// When visiting /category-b, we should get Category B (the owner),
|
||||
// not Category A (which just has a link to it)
|
||||
expect(mockUseCurrentSidebarCategory('/category-b')).toEqual(categoryB);
|
||||
});
|
||||
});
|
||||
|
||||
describe('useCurrentSidebarSiblings', () => {
|
||||
|
|
|
|||
|
|
@ -234,11 +234,40 @@ function getSidebarBreadcrumbs({
|
|||
}): PropSidebarBreadcrumbsItem[] {
|
||||
const breadcrumbs: PropSidebarBreadcrumbsItem[] = [];
|
||||
|
||||
function extract(items: PropSidebarItem[]) {
|
||||
// When onlyCategories is true (e.g., for useCurrentSidebarCategory), we need
|
||||
// to distinguish between:
|
||||
// 1. A category that directly owns this URL (category.href === pathname)
|
||||
// 2. A link that happens to point to this URL
|
||||
//
|
||||
// We should prefer (1) over (2) to fix the bug where a generated-index page
|
||||
// shows items from the wrong category when another category has a link
|
||||
// pointing to it. See https://github.com/facebook/docusaurus/issues/11612
|
||||
//
|
||||
// We use a two-pass approach:
|
||||
// - First pass: Only look for categories that directly own the URL
|
||||
// - Second pass: If not found, look for links (to support doc pages)
|
||||
|
||||
function extractCategoryOnly(items: PropSidebarItem[]): boolean {
|
||||
for (const item of items) {
|
||||
if (item.type === 'category') {
|
||||
if (isSamePath(item.href, pathname)) {
|
||||
breadcrumbs.unshift(item);
|
||||
return true;
|
||||
}
|
||||
if (extractCategoryOnly(item.items)) {
|
||||
breadcrumbs.unshift(item);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function extractWithLinks(items: PropSidebarItem[]): boolean {
|
||||
for (const item of items) {
|
||||
if (
|
||||
(item.type === 'category' &&
|
||||
(isSamePath(item.href, pathname) || extract(item.items))) ||
|
||||
(isSamePath(item.href, pathname) || extractWithLinks(item.items))) ||
|
||||
(item.type === 'link' && isSamePath(item.href, pathname))
|
||||
) {
|
||||
const filtered = onlyCategories && item.type !== 'category';
|
||||
|
|
@ -248,11 +277,19 @@ function getSidebarBreadcrumbs({
|
|||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
extract(sidebarItems);
|
||||
if (onlyCategories) {
|
||||
// First try to find a category that directly owns this URL
|
||||
if (!extractCategoryOnly(sidebarItems)) {
|
||||
// Fall back to finding via links (for doc pages in a category)
|
||||
extractWithLinks(sidebarItems);
|
||||
}
|
||||
} else {
|
||||
// For breadcrumbs, use the original behavior (links included)
|
||||
extractWithLinks(sidebarItems);
|
||||
}
|
||||
|
||||
return breadcrumbs;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue