Skip to content

Commit 857eba5

Browse files
feat(docusaurus-theme): swizzle DocCard component
1 parent ad14689 commit 857eba5

File tree

1 file changed

+104
-0
lines changed
  • packages/docusaurus-theme/src/theme/DocCard

1 file changed

+104
-0
lines changed
Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
import { type ReactNode } from 'react';
2+
import {
3+
useDocById,
4+
findFirstSidebarItemLink,
5+
} from '@docusaurus/plugin-content-docs/client';
6+
import { usePluralForm } from '@docusaurus/theme-common';
7+
import isInternalUrl from '@docusaurus/isInternalUrl';
8+
import { translate } from '@docusaurus/Translate';
9+
10+
import type {
11+
PropSidebarItemCategory,
12+
PropSidebarItemLink,
13+
} from '@docusaurus/plugin-content-docs';
14+
15+
import { EuiCard, EuiIcon } from '@elastic/eui';
16+
17+
function useCategoryItemsPlural() {
18+
const { selectMessage } = usePluralForm();
19+
return (count: number) =>
20+
selectMessage(
21+
count,
22+
translate(
23+
{
24+
message: '1 item|{count} items',
25+
id: 'theme.docs.DocCard.categoryDescription.plurals',
26+
description:
27+
'The default description for a category card in the generated index about how many items this category includes',
28+
},
29+
{ count }
30+
)
31+
);
32+
}
33+
34+
function CardLayout({
35+
href,
36+
icon,
37+
title,
38+
description,
39+
}: {
40+
href: string;
41+
icon: string;
42+
title: string;
43+
description?: string;
44+
}): ReactNode {
45+
return (
46+
<EuiCard
47+
icon={<EuiIcon size="l" type={icon} />}
48+
title={title}
49+
description={description || ''}
50+
titleSize="xs"
51+
layout="horizontal"
52+
href={href}
53+
/>
54+
);
55+
}
56+
57+
function CardCategory({ item }: { item: PropSidebarItemCategory }): ReactNode {
58+
const href = findFirstSidebarItemLink(item);
59+
const categoryItemsPlural = useCategoryItemsPlural();
60+
61+
// Unexpected: categories that don't have a link have been filtered upfront
62+
if (!href) {
63+
return null;
64+
}
65+
66+
return (
67+
<CardLayout
68+
href={href}
69+
// Coincidentally, `folderOpen` is the same icon in EUI icon library
70+
icon="folderOpen"
71+
title={item.label}
72+
description={item.description ?? categoryItemsPlural(item.items.length)}
73+
/>
74+
);
75+
}
76+
77+
function CardLink({ item }: { item: PropSidebarItemLink }): ReactNode {
78+
// We update Docusaurus `link` icon to EUI `popout` icon
79+
const icon = isInternalUrl(item.href) ? 'document' : 'popout';
80+
const doc = useDocById(item.docId ?? undefined);
81+
return (
82+
<CardLayout
83+
href={item.href}
84+
icon={icon}
85+
title={item.label}
86+
description={item.description ?? doc?.description}
87+
/>
88+
);
89+
}
90+
91+
export default function DocCard({
92+
item,
93+
}: {
94+
item: PropSidebarItemCategory | PropSidebarItemLink;
95+
}): ReactNode {
96+
switch (item.type) {
97+
case 'link':
98+
return <CardLink item={item} />;
99+
case 'category':
100+
return <CardCategory item={item} />;
101+
default:
102+
throw new Error(`unknown item type ${JSON.stringify(item)}`);
103+
}
104+
}

0 commit comments

Comments
 (0)