Skip to content

Commit a1b0973

Browse files
committed
fix unlisted auto-generated category + refactor logic
1 parent 1d5afba commit a1b0973

File tree

10 files changed

+189
-31
lines changed

10 files changed

+189
-31
lines changed

packages/docusaurus-theme-classic/src/theme/DocCard/index.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import React, {type ReactNode} from 'react';
99
import clsx from 'clsx';
1010
import Link from '@docusaurus/Link';
1111
import {
12-
findFirstCategoryLink,
12+
findFirstSidebarItemLink,
1313
useDocById,
1414
} from '@docusaurus/theme-common/internal';
1515
import isInternalUrl from '@docusaurus/isInternalUrl';
@@ -71,7 +71,7 @@ function CardCategory({
7171
}: {
7272
item: PropSidebarItemCategory;
7373
}): JSX.Element | null {
74-
const href = findFirstCategoryLink(item);
74+
const href = findFirstSidebarItemLink(item);
7575

7676
// Unexpected: categories that don't have a link have been filtered upfront
7777
if (!href) {

packages/docusaurus-theme-classic/src/theme/DocSidebarItem/Category/index.tsx

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ import {
1616
} from '@docusaurus/theme-common';
1717
import {
1818
isActiveSidebarItem,
19-
findFirstCategoryLink,
19+
findFirstSidebarItemLink,
2020
useDocSidebarItemsExpandedState,
2121
isSamePath,
2222
} from '@docusaurus/theme-common/internal';
@@ -59,15 +59,12 @@ function useCategoryHrefWithSSRFallback(
5959
): string | undefined {
6060
const isBrowser = useIsBrowser();
6161
return useMemo(() => {
62-
if (item.href && !item.linkUnlisted) {
63-
return item.href;
64-
}
6562
// In these cases, it's not necessary to render a fallback
6663
// We skip the "findFirstCategoryLink" computation
6764
if (isBrowser || !item.collapsible) {
6865
return undefined;
6966
}
70-
return findFirstCategoryLink(item);
67+
return findFirstSidebarItemLink(item);
7168
}, [item, isBrowser]);
7269
}
7370

packages/docusaurus-theme-common/src/internal.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ export {
6767
isDocsPluginEnabled,
6868
useDocById,
6969
findSidebarCategory,
70-
findFirstCategoryLink,
70+
findFirstSidebarItemLink,
7171
isActiveSidebarItem,
7272
isVisibleSidebarItem,
7373
useVisibleSidebarItems,

packages/docusaurus-theme-common/src/utils/__tests__/docsUtils.test.tsx

Lines changed: 127 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import {renderHook} from '@testing-library/react-hooks';
1010
import {StaticRouter} from 'react-router-dom';
1111
import {Context} from '@docusaurus/core/src/client/docusaurusContext';
1212
import {
13-
findFirstCategoryLink,
13+
findFirstSidebarItemLink,
1414
isActiveSidebarItem,
1515
useDocById,
1616
findSidebarCategory,
@@ -64,6 +64,7 @@ function testVersion(data?: Partial<PropVersionMetadata>): PropVersionMetadata {
6464
docsSidebars: {},
6565
isLast: false,
6666
pluginId: 'default',
67+
noIndex: false,
6768
...data,
6869
};
6970
}
@@ -163,9 +164,31 @@ describe('findSidebarCategory', () => {
163164
});
164165

165166
describe('findFirstCategoryLink', () => {
167+
it('works with html item', () => {
168+
const htmlItem = {type: 'html', value: '<div/>'} as const;
169+
expect(findFirstSidebarItemLink(htmlItem)).toBeUndefined();
170+
expect(findFirstSidebarItemLink(htmlItem)).toBeUndefined();
171+
});
172+
173+
it('works with link item', () => {
174+
const linkItem = {
175+
type: 'link',
176+
href: '/linkHref',
177+
label: 'Label',
178+
} as const;
179+
180+
expect(findFirstSidebarItemLink(linkItem)).toBe('/linkHref');
181+
expect(
182+
findFirstSidebarItemLink({
183+
...linkItem,
184+
unlisted: true,
185+
}),
186+
).toBeUndefined();
187+
});
188+
166189
it('works with category without link nor child', () => {
167190
expect(
168-
findFirstCategoryLink(
191+
findFirstSidebarItemLink(
169192
testCategory({
170193
href: undefined,
171194
}),
@@ -175,17 +198,103 @@ describe('findFirstCategoryLink', () => {
175198

176199
it('works with category with link', () => {
177200
expect(
178-
findFirstCategoryLink(
201+
findFirstSidebarItemLink(
179202
testCategory({
180203
href: '/itemPath',
181204
}),
182205
),
183206
).toBe('/itemPath');
184207
});
185208

186-
it('works with category with deeply nested category link', () => {
209+
it('works with deeply nested category', () => {
210+
expect(
211+
findFirstSidebarItemLink(
212+
testCategory({
213+
href: '/category1',
214+
linkUnlisted: true,
215+
items: [
216+
{type: 'html', value: '<p>test1</p>'},
217+
testCategory({
218+
href: '/category2',
219+
linkUnlisted: true,
220+
items: [
221+
{type: 'html', value: '<p>test2</p>'},
222+
testCategory({
223+
href: '/category3',
224+
items: [
225+
{type: 'html', value: '<p>test2</p>'},
226+
testCategory({
227+
href: '/category4',
228+
linkUnlisted: true,
229+
}),
230+
],
231+
}),
232+
],
233+
}),
234+
],
235+
}),
236+
),
237+
).toBe('/category3');
238+
});
239+
240+
it('works with deeply nested link', () => {
187241
expect(
188-
findFirstCategoryLink(
242+
findFirstSidebarItemLink(
243+
testCategory({
244+
href: '/category1',
245+
linkUnlisted: true,
246+
items: [
247+
{
248+
type: 'link',
249+
href: '/itemPathUnlisted',
250+
label: 'Label',
251+
unlisted: true,
252+
},
253+
testCategory({
254+
href: '/category2',
255+
linkUnlisted: true,
256+
items: [
257+
testCategory({
258+
href: '/category3',
259+
linkUnlisted: true,
260+
items: [
261+
{
262+
type: 'link',
263+
href: '/itemPathUnlisted2',
264+
label: 'Label',
265+
unlisted: true,
266+
},
267+
testCategory({
268+
href: '/category4',
269+
linkUnlisted: true,
270+
}),
271+
{
272+
type: 'link',
273+
href: '/itemPathListed1',
274+
label: 'Label',
275+
},
276+
testCategory({
277+
href: '/category5',
278+
}),
279+
{
280+
type: 'link',
281+
href: '/itemPathListed2',
282+
label: 'Label',
283+
unlisted: true,
284+
},
285+
],
286+
}),
287+
],
288+
}),
289+
],
290+
}),
291+
),
292+
).toBe('/itemPathListed1');
293+
});
294+
295+
it('works with category with deeply nested category link unlisted', () => {
296+
expect(
297+
findFirstSidebarItemLink(
189298
testCategory({
190299
href: undefined,
191300
items: [
@@ -196,29 +305,37 @@ describe('findFirstCategoryLink', () => {
196305
{type: 'html', value: '<p>test2</p>'},
197306
testCategory({
198307
href: '/itemPath',
308+
linkUnlisted: true,
199309
}),
200310
],
201311
}),
202312
],
203313
}),
204314
),
205-
).toBe('/itemPath');
315+
).toBeUndefined();
206316
});
207317

208-
it('works with category with deeply nested link', () => {
318+
it('works with category with deeply nested link unlisted', () => {
209319
expect(
210-
findFirstCategoryLink(
320+
findFirstSidebarItemLink(
211321
testCategory({
212322
href: undefined,
213323
items: [
214324
testCategory({
215325
href: undefined,
216-
items: [{type: 'link', href: '/itemPath', label: 'Label'}],
326+
items: [
327+
{
328+
type: 'link',
329+
href: '/itemPath',
330+
label: 'Label',
331+
unlisted: true,
332+
},
333+
],
217334
}),
218335
],
219336
}),
220337
),
221-
).toBe('/itemPath');
338+
).toBeUndefined();
222339
});
223340
});
224341

packages/docusaurus-theme-common/src/utils/docsUtils.tsx

Lines changed: 25 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -79,27 +79,38 @@ export function findSidebarCategory(
7979
* Best effort to assign a link to a sidebar category. If the category doesn't
8080
* have a link itself, we link to the first sub item with a link.
8181
*/
82-
export function findFirstCategoryLink(
82+
export function findFirstSidebarItemCategoryLink(
8383
item: PropSidebarItemCategory,
8484
): string | undefined {
85-
if (item.href) {
85+
if (item.href && !item.linkUnlisted) {
8686
return item.href;
8787
}
8888

8989
for (const subItem of item.items) {
90-
if (subItem.type === 'link') {
91-
return subItem.href;
92-
} else if (subItem.type === 'category') {
93-
const categoryLink = findFirstCategoryLink(subItem);
94-
if (categoryLink) {
95-
return categoryLink;
96-
}
90+
const link = findFirstSidebarItemLink(subItem);
91+
if (link) {
92+
return link;
9793
}
98-
// Could be "html" items
9994
}
10095
return undefined;
10196
}
10297

98+
/**
99+
* Best effort to assign a link to a sidebar item.
100+
*/
101+
export function findFirstSidebarItemLink(
102+
item: PropSidebarItem,
103+
): string | undefined {
104+
if (item.type === 'link' && !item.unlisted) {
105+
return item.href;
106+
}
107+
if (item.type === 'category') {
108+
return findFirstSidebarItemCategoryLink(item);
109+
}
110+
// Other items types, like "html"
111+
return undefined;
112+
}
113+
103114
/**
104115
* Gets the category associated with the current location. Should only be used
105116
* on category index pages.
@@ -391,15 +402,16 @@ export function useDocRootMetadata({route}: DocRootProps): null | {
391402
}
392403

393404
/**
394-
* Filter categories that don't have a link.
405+
* Filter items we don't want to display on the doc card list view
395406
* @param items
396407
*/
397408
export function filterDocCardListItems(
398409
items: PropSidebarItem[],
399410
): PropSidebarItem[] {
400411
return items.filter((item) => {
401-
if (item.type === 'category') {
402-
return !!findFirstCategoryLink(item);
412+
const canHaveLink = item.type === 'category' || item.type === 'link';
413+
if (canHaveLink) {
414+
return !!findFirstSidebarItemLink(item);
403415
}
404416
return true;
405417
});

website/_dogfooding/_docs tests/tests/visibility/index.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,3 +24,11 @@ In production, unlisted items should remain accessible, but be hidden in the sid
2424
- [./some-unlisteds/unlisted1.md](./some-unlisteds/unlisted1.md)
2525
- [./some-unlisteds/unlisted2.md](./some-unlisteds/unlisted2.md)
2626
- [./some-unlisteds/unlisted-subcategory/unlisted3.md](./some-unlisteds/unlisted-subcategory/unlisted3.md)
27+
28+
---
29+
30+
```mdx-code-block
31+
import DocCardList from '@theme/DocCardList';
32+
33+
<DocCardList />
34+
```

website/_dogfooding/_docs tests/tests/visibility/only-drafts/draft-subcategory/index.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,9 @@ tags: [visibility, draft]
66
# Only Drafts - Subcategory index draft
77

88
Doc with draft front matter
9+
10+
```mdx-code-block
11+
import DocCardList from '@theme/DocCardList';
12+
13+
<DocCardList />
14+
```

website/_dogfooding/_docs tests/tests/visibility/only-unlisteds/unlisted-subcategory/index.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,9 @@ tags: [visibility, unlisted]
66
# Only Unlisteds - Subcategory index unlisted
77

88
Doc with unlisted front matter
9+
10+
```mdx-code-block
11+
import DocCardList from '@theme/DocCardList';
12+
13+
<DocCardList />
14+
```

website/_dogfooding/_docs tests/tests/visibility/some-drafts/draft-subcategory/index.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,9 @@ tags: [visibility, draft]
66
# Some Drafts - Subcategory index draft
77

88
Doc with draft front matter
9+
10+
```mdx-code-block
11+
import DocCardList from '@theme/DocCardList';
12+
13+
<DocCardList />
14+
```

website/_dogfooding/_docs tests/tests/visibility/some-unlisteds/unlisted-subcategory/index.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,9 @@ tags: [visibility, unlisted]
66
# Some Unlisteds - Subcategory index unlisted
77

88
Doc with unlisted front matter
9+
10+
```mdx-code-block
11+
import DocCardList from '@theme/DocCardList';
12+
13+
<DocCardList />
14+
```

0 commit comments

Comments
 (0)