-
Notifications
You must be signed in to change notification settings - Fork 13.1k
Expand file tree
/
Copy pathSidebarSublist.astro
More file actions
123 lines (114 loc) · 3.8 KB
/
SidebarSublist.astro
File metadata and controls
123 lines (114 loc) · 3.8 KB
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
---
import { Icon, Badge } from "@astrojs/starlight/components";
interface Props {
sublist: any[];
nested?: boolean;
}
const { sublist, nested } = Astro.props;
/** Flatten a sidebar tree into a flat list of link entries. */
function flattenSidebar(entries: any[]): any[] {
return entries.flatMap((entry: any) =>
entry.type === "group" ? flattenSidebar(entry.entries) : entry,
);
}
/**
* SidebarRestorePoint counter — inlined from Starlight's internal component.
* Each <details> needs a unique, incrementing index for the sidebar persister.
*/
const currentGroupIndexSymbol = Symbol.for("starlight-sidebar-group-index");
const locals = Astro.locals as typeof Astro.locals & {
[currentGroupIndexSymbol]: number;
};
function nextRestoreIndex(): number {
const index = locals[currentGroupIndexSymbol] || 0;
locals[currentGroupIndexSymbol] = index + 1;
return index;
}
// Pre-compute restore indices for each group entry in this sublist
const restoreIndices = sublist.map((entry) =>
entry.type === "group" ? nextRestoreIndex() : -1,
);
---
<ul
class:list={[
!nested
? "top-level list-none p-0"
: "mt-0.5 ml-3 list-none border-l border-[var(--sidebar-border)] p-0 pl-2",
]}
>
{
sublist.map((entry, idx) => (
<li class="break-words">
{entry.type === "link" ? (
<a
href={entry.href}
aria-current={entry.isCurrent ? "page" : undefined}
class:list={[
"flex min-h-[2.125rem] items-start rounded-lg px-3 py-1.5 text-sm font-medium no-underline transition-colors duration-150",
"outline-2 outline-offset-0 outline-transparent focus-visible:outline-blue-500 dark:focus-visible:outline-blue-400",
"text-[var(--sidebar-text)] hover:bg-[var(--sidebar-hover-bg)] hover:text-[var(--sidebar-text-strong)]",
entry.isCurrent &&
"!bg-[var(--sidebar-active-bg)] !font-semibold !text-[var(--sidebar-text-strong)]",
!nested && "large",
entry.attrs.class,
]}
{...entry.attrs}
>
<span class="">
{entry.label}
</span>
{entry.badge && (
<Badge
variant={entry.badge.variant}
class={`ml-[0.5em] ${entry.badge.class ?? ""}`}
text={entry.badge.text}
/>
)}
</a>
) : (
<details
open={
flattenSidebar(entry.entries).some((i: any) => i.isCurrent) ||
!entry.collapsed
}
>
<summary class="flex min-h-[2.125rem] cursor-pointer items-start justify-between rounded-lg px-3 py-1.5 text-sm font-medium text-[var(--sidebar-text)] no-underline outline-2 outline-offset-0 outline-transparent transition-colors duration-150 select-none hover:bg-[var(--sidebar-hover-bg)] hover:text-[var(--sidebar-text-strong)] focus-visible:outline-blue-500 dark:focus-visible:outline-blue-400 [&::-webkit-details-marker]:hidden [&::marker]:hidden">
<span class="group-label">
<span class:list={["", !nested && "large"]}>{entry.label}</span>
{entry.badge && (
<Badge
variant={entry.badge.variant}
class={`ml-[0.5em] ${entry.badge.class ?? ""}`}
text={entry.badge.text}
/>
)}
</span>
<Icon
name="right-caret"
class="caret shrink-0 text-base text-[var(--sidebar-text)] opacity-60 transition-transform duration-200"
size="1.25rem"
/>
</summary>
<sl-sidebar-restore data-index={restoreIndices[idx]} />
<Astro.self sublist={entry.entries} nested />
</details>
)}
</li>
))
}
</ul>
<style is:global>
/* Caret rotation — must be global because .caret is on an SVG from a child component */
.sidebar-content [open] > summary .caret {
transform: rotate(90deg);
}
.sidebar-content [dir="rtl"] .caret {
transform: rotateZ(180deg);
}
</style>
<style>
/* Spacing between top-level items */
.top-level > li + li {
margin-top: 1px;
}
</style>