forked from denoland/docs
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathBreadcrumbs.tsx
147 lines (137 loc) · 4.28 KB
/
Breadcrumbs.tsx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
import type {
BreadcrumbItem,
Sidebar as Sidebar_,
SidebarItem,
} from "../types.ts";
import { isSidebarCategory, isSidebarDoc, isSidebarLink } from "../types.ts";
export function generateCrumbs(
url: string,
title: string,
items: SidebarItem[],
current: BreadcrumbItem[] = [],
): BreadcrumbItem[] {
for (const item of items) {
const foundTargetPage = (typeof item === "string" && item === url) ||
(isSidebarDoc(item) && item.id === url) ||
(isSidebarLink(item) && item.href === url);
if (foundTargetPage) {
current.push({ label: title });
return current;
}
if (isSidebarCategory(item)) {
const childItems: BreadcrumbItem[] = [];
generateCrumbs(url, title, item.items, childItems);
if (childItems.length > 0) {
if (item.href) {
current.push({ label: item.label, href: item.href });
}
current.push(...childItems);
return current;
}
}
}
return current;
}
export function Breadcrumbs(props: {
title: string;
sidebar: Sidebar_;
url: string;
sectionTitle: string;
sectionHref: string;
}) {
const crumbs: BreadcrumbItem[] = [];
for (const section of props.sidebar) {
if (section.href === props.url) {
crumbs.push({ label: props.title });
break;
}
const rootItem = { label: section.title, href: section.href };
const potentialCrumbs = generateCrumbs(
props.url,
props.title,
section.items,
[rootItem],
);
if (potentialCrumbs.length > 1) {
crumbs.push(...potentialCrumbs);
break;
}
}
return (
<nav class="mb-4">
<ul
class="flex flex-wrap text-foreground-secondary items-center -ml-3"
itemscope
itemtype="https://schema.org/BreadcrumbList"
>
<li
itemprop="itemListElement"
itemscope
itemtype="https://schema.org/ListItem"
>
<a
class="block px-3 py-1.5 underline underline-offset-4 decoration-foreground-tertiary hover:text-foreground-secondary hover:underline-medium hover:bg-foreground-tertiary dark:hover:bg-background-secondary dark:hover:text-foreground-primary rounded transition duration-100 text-sm"
itemprop="item"
href={props.sectionHref}
>
<span itemprop="name">{props.sectionTitle}</span>
</a>
<meta itemprop="position" content="1" />
</li>
<li>
<svg
class="size-4 text-foreground-secondary rotate-90"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
>
<path
fill="currentColor"
d="M7.41 15.41L12 10.83l4.59 4.58L18 14l-6-6-6 6z"
/>
</svg>
</li>
{crumbs.map((crumb, i) => (
<>
<li
itemprop="itemListElement"
itemscope
itemtype="https://schema.org/ListItem"
>
{crumb.href
? (
<a
href={crumb.href}
itemprop="item"
class="block px-3 py-1.5 underline underline-offset-4 decoration-foreground-tertiary hover:text-foreground-secondary hover:underline-medium hover:bg-foreground-tertiary dark:hover:bg-background-secondary dark:hover:text-foreground-primary rounded transition duration-100 text-sm"
>
<span itemprop="name">{crumb.label}</span>
</a>
)
: (
<span itemprop="name" class="block px-3 py-1.5 text-sm">
{crumb.label}
</span>
)}
<meta itemprop="position" content={String(i + 2)} />
</li>
{i < crumbs.length - 1 && (
<li>
<svg
class="size-4 text-foreground-secondary rotate-90"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
>
<path
fill="currentColor"
d="M7.41 15.41L12 10.83l4.59 4.58L18 14l-6-6-6 6z"
>
</path>
</svg>
</li>
)}
</>
))}
</ul>
</nav>
);
}