boltdocs 1.3.0 → 1.3.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{cache-EHR7SXRU.mjs → cache-GQHF6BXI.mjs} +1 -1
- package/dist/{chunk-GSYECEZY.mjs → chunk-CYBWLFOG.mjs} +5 -1
- package/dist/node/index.js +36 -20
- package/dist/node/index.mjs +34 -22
- package/package.json +1 -1
- package/src/client/app/index.tsx +344 -344
- package/src/client/app/preload.tsx +56 -56
- package/src/client/index.ts +40 -40
- package/src/client/ssr.tsx +51 -51
- package/src/client/theme/components/CodeBlock/CodeBlock.tsx +76 -76
- package/src/client/theme/components/CodeBlock/index.ts +1 -1
- package/src/client/theme/components/PackageManagerTabs/PackageManagerTabs.tsx +154 -154
- package/src/client/theme/components/PackageManagerTabs/index.ts +1 -1
- package/src/client/theme/components/PackageManagerTabs/pkg-tabs.css +64 -64
- package/src/client/theme/components/Playground/Playground.tsx +124 -124
- package/src/client/theme/components/Playground/index.ts +1 -1
- package/src/client/theme/components/Playground/playground.css +168 -168
- package/src/client/theme/components/Video/Video.tsx +84 -84
- package/src/client/theme/components/Video/index.ts +1 -1
- package/src/client/theme/components/Video/video.css +41 -41
- package/src/client/theme/components/mdx/Admonition.tsx +80 -80
- package/src/client/theme/components/mdx/Badge.tsx +31 -31
- package/src/client/theme/components/mdx/Button.tsx +50 -50
- package/src/client/theme/components/mdx/Card.tsx +80 -80
- package/src/client/theme/components/mdx/List.tsx +57 -57
- package/src/client/theme/components/mdx/Tabs.tsx +94 -94
- package/src/client/theme/components/mdx/index.ts +18 -18
- package/src/client/theme/components/mdx/mdx-components.css +424 -424
- package/src/client/theme/icons/bun.tsx +62 -62
- package/src/client/theme/icons/deno.tsx +20 -20
- package/src/client/theme/icons/discord.tsx +12 -12
- package/src/client/theme/icons/github.tsx +15 -15
- package/src/client/theme/icons/npm.tsx +13 -13
- package/src/client/theme/icons/pnpm.tsx +72 -72
- package/src/client/theme/icons/twitter.tsx +12 -12
- package/src/client/theme/styles/markdown.css +343 -343
- package/src/client/theme/styles/variables.css +162 -162
- package/src/client/theme/styles.css +37 -37
- package/src/client/theme/ui/BackgroundGradient/BackgroundGradient.tsx +10 -10
- package/src/client/theme/ui/BackgroundGradient/index.ts +1 -1
- package/src/client/theme/ui/Breadcrumbs/Breadcrumbs.tsx +68 -68
- package/src/client/theme/ui/Breadcrumbs/index.ts +1 -1
- package/src/client/theme/ui/Footer/footer.css +32 -32
- package/src/client/theme/ui/Head/Head.tsx +69 -69
- package/src/client/theme/ui/Head/index.ts +1 -1
- package/src/client/theme/ui/LanguageSwitcher/LanguageSwitcher.tsx +125 -125
- package/src/client/theme/ui/LanguageSwitcher/index.ts +1 -1
- package/src/client/theme/ui/LanguageSwitcher/language-switcher.css +98 -98
- package/src/client/theme/ui/Layout/Layout.tsx +202 -202
- package/src/client/theme/ui/Layout/base.css +76 -76
- package/src/client/theme/ui/Layout/index.ts +2 -2
- package/src/client/theme/ui/Layout/pagination.css +72 -72
- package/src/client/theme/ui/Layout/responsive.css +36 -36
- package/src/client/theme/ui/Link/Link.tsx +254 -254
- package/src/client/theme/ui/Link/index.ts +2 -2
- package/src/client/theme/ui/Loading/Loading.tsx +10 -10
- package/src/client/theme/ui/Loading/index.ts +1 -1
- package/src/client/theme/ui/Loading/loading.css +30 -30
- package/src/client/theme/ui/Navbar/GithubStars.tsx +27 -27
- package/src/client/theme/ui/Navbar/Navbar.tsx +145 -145
- package/src/client/theme/ui/Navbar/index.ts +2 -2
- package/src/client/theme/ui/Navbar/navbar.css +233 -233
- package/src/client/theme/ui/NotFound/NotFound.tsx +19 -19
- package/src/client/theme/ui/NotFound/index.ts +1 -1
- package/src/client/theme/ui/NotFound/not-found.css +64 -64
- package/src/client/theme/ui/OnThisPage/OnThisPage.tsx +235 -235
- package/src/client/theme/ui/OnThisPage/index.ts +1 -1
- package/src/client/theme/ui/OnThisPage/toc.css +132 -132
- package/src/client/theme/ui/PoweredBy/PoweredBy.tsx +18 -18
- package/src/client/theme/ui/PoweredBy/index.ts +1 -1
- package/src/client/theme/ui/PoweredBy/powered-by.css +76 -76
- package/src/client/theme/ui/SearchDialog/SearchDialog.tsx +199 -199
- package/src/client/theme/ui/SearchDialog/index.ts +1 -1
- package/src/client/theme/ui/SearchDialog/search.css +152 -152
- package/src/client/theme/ui/Sidebar/Sidebar.tsx +204 -204
- package/src/client/theme/ui/Sidebar/index.ts +1 -1
- package/src/client/theme/ui/Sidebar/sidebar.css +236 -236
- package/src/client/theme/ui/ThemeToggle/ThemeToggle.tsx +69 -69
- package/src/client/theme/ui/ThemeToggle/index.ts +1 -1
- package/src/client/theme/ui/VersionSwitcher/VersionSwitcher.tsx +136 -136
- package/src/client/theme/ui/VersionSwitcher/index.ts +1 -1
- package/src/client/types.ts +50 -50
- package/src/client/utils.ts +26 -26
- package/src/node/cache.ts +408 -408
- package/src/node/config.ts +192 -192
- package/src/node/index.ts +21 -21
- package/src/node/mdx.ts +120 -120
- package/src/node/plugin/entry.ts +58 -58
- package/src/node/plugin/html.ts +55 -55
- package/src/node/plugin/index.ts +193 -193
- package/src/node/plugin/types.ts +11 -11
- package/src/node/routes/cache.ts +28 -28
- package/src/node/routes/index.ts +167 -167
- package/src/node/routes/parser.ts +153 -127
- package/src/node/routes/sorter.ts +42 -42
- package/src/node/routes/types.ts +49 -49
- package/src/node/ssg/index.ts +114 -114
- package/src/node/ssg/meta.ts +33 -34
- package/src/node/ssg/options.ts +13 -13
- package/src/node/ssg/sitemap.ts +55 -54
- package/src/node/utils.ts +145 -134
- package/tsconfig.json +20 -20
- package/tsup.config.ts +22 -22
|
@@ -1,204 +1,204 @@
|
|
|
1
|
-
import React, { useState } from "react";
|
|
2
|
-
import { useLocation } from "react-router-dom";
|
|
3
|
-
import { Link } from "../Link";
|
|
4
|
-
import { BoltdocsConfig } from "../../../../node/config";
|
|
5
|
-
import { PoweredBy } from "../PoweredBy";
|
|
6
|
-
import { ChevronRight, ChevronLeft, PanelLeft } from "lucide-react";
|
|
7
|
-
|
|
8
|
-
interface RouteItem {
|
|
9
|
-
path: string;
|
|
10
|
-
title: string;
|
|
11
|
-
group?: string;
|
|
12
|
-
groupTitle?: string;
|
|
13
|
-
sidebarPosition?: number;
|
|
14
|
-
badge?: string | { text: string; expires?: string };
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
interface SidebarGroup {
|
|
18
|
-
slug: string;
|
|
19
|
-
title: string;
|
|
20
|
-
routes: RouteItem[];
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
/**
|
|
24
|
-
* Renders a small badge next to sidebar items if one exists and hasn't expired.
|
|
25
|
-
*/
|
|
26
|
-
function renderBadge(badgeRaw: RouteItem["badge"]) {
|
|
27
|
-
if (!badgeRaw) return null;
|
|
28
|
-
|
|
29
|
-
let text = "";
|
|
30
|
-
let expires = "";
|
|
31
|
-
|
|
32
|
-
if (typeof badgeRaw === "string") {
|
|
33
|
-
text = badgeRaw;
|
|
34
|
-
} else {
|
|
35
|
-
text = badgeRaw.text;
|
|
36
|
-
expires = badgeRaw.expires || "";
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
// Check expiration
|
|
40
|
-
if (expires) {
|
|
41
|
-
const expireDate = new Date(expires);
|
|
42
|
-
const now = new Date();
|
|
43
|
-
// Reset time components for accurate day comparison
|
|
44
|
-
expireDate.setHours(0, 0, 0, 0);
|
|
45
|
-
now.setHours(0, 0, 0, 0);
|
|
46
|
-
if (now > expireDate) {
|
|
47
|
-
return null;
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
if (!text) return null;
|
|
52
|
-
|
|
53
|
-
if (!text) return null;
|
|
54
|
-
|
|
55
|
-
let typeClass = "badge-default";
|
|
56
|
-
const lowerText = text.toLowerCase();
|
|
57
|
-
if (lowerText === "new") {
|
|
58
|
-
typeClass = "badge-new";
|
|
59
|
-
} else if (lowerText === "experimental") {
|
|
60
|
-
typeClass = "badge-experimental";
|
|
61
|
-
} else if (lowerText === "updated") {
|
|
62
|
-
typeClass = "badge-updated";
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
return <span className={`sidebar-badge ${typeClass}`}>{text}</span>;
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
/**
|
|
69
|
-
* The sidebar navigation component.
|
|
70
|
-
* Groups documentation routes logically based on the `group` property.
|
|
71
|
-
* Highlights the active link based on the current URL path.
|
|
72
|
-
*
|
|
73
|
-
* @param routes - Array of all generated routes to be displayed
|
|
74
|
-
* @param config - Global configuration (which can contain sidebar overrides)
|
|
75
|
-
*/
|
|
76
|
-
export function Sidebar({
|
|
77
|
-
routes,
|
|
78
|
-
config,
|
|
79
|
-
isCollapsed,
|
|
80
|
-
onToggle,
|
|
81
|
-
}: {
|
|
82
|
-
routes: RouteItem[];
|
|
83
|
-
config: BoltdocsConfig;
|
|
84
|
-
isCollapsed?: boolean;
|
|
85
|
-
onToggle?: () => void;
|
|
86
|
-
}) {
|
|
87
|
-
const location = useLocation();
|
|
88
|
-
|
|
89
|
-
const ungrouped: RouteItem[] = [];
|
|
90
|
-
const groupMap = new Map<string, SidebarGroup>();
|
|
91
|
-
|
|
92
|
-
for (const route of routes) {
|
|
93
|
-
if (!route.group) {
|
|
94
|
-
ungrouped.push(route);
|
|
95
|
-
} else {
|
|
96
|
-
if (!groupMap.has(route.group)) {
|
|
97
|
-
groupMap.set(route.group, {
|
|
98
|
-
slug: route.group,
|
|
99
|
-
title: route.groupTitle || route.group,
|
|
100
|
-
routes: [],
|
|
101
|
-
});
|
|
102
|
-
}
|
|
103
|
-
groupMap.get(route.group)!.routes.push(route);
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
const groups = Array.from(groupMap.values());
|
|
108
|
-
|
|
109
|
-
return (
|
|
110
|
-
<aside className="boltdocs-sidebar">
|
|
111
|
-
{onToggle && (
|
|
112
|
-
<div className="sidebar-collapse">
|
|
113
|
-
<button
|
|
114
|
-
className="sidebar-collapse-btn"
|
|
115
|
-
onClick={onToggle}
|
|
116
|
-
aria-label={isCollapsed ? "Expand Sidebar" : "Collapse Sidebar"}
|
|
117
|
-
title={isCollapsed ? "Expand Sidebar" : "Collapse Sidebar"}
|
|
118
|
-
>
|
|
119
|
-
<PanelLeft size={18} />
|
|
120
|
-
</button>
|
|
121
|
-
</div>
|
|
122
|
-
)}
|
|
123
|
-
|
|
124
|
-
{!isCollapsed && (
|
|
125
|
-
<>
|
|
126
|
-
<nav aria-label="Main Navigation">
|
|
127
|
-
<ul className="sidebar-list">
|
|
128
|
-
{ungrouped.map((route) => (
|
|
129
|
-
<li key={route.path}>
|
|
130
|
-
<Link
|
|
131
|
-
to={route.path === "" ? "/" : route.path}
|
|
132
|
-
className={`sidebar-link ${location.pathname === route.path ? "active" : ""}`}
|
|
133
|
-
aria-current={
|
|
134
|
-
location.pathname === route.path ? "page" : undefined
|
|
135
|
-
}
|
|
136
|
-
>
|
|
137
|
-
<div className="sidebar-link-content">
|
|
138
|
-
<span>{route.title}</span>
|
|
139
|
-
{renderBadge(route.badge)}
|
|
140
|
-
</div>
|
|
141
|
-
</Link>
|
|
142
|
-
</li>
|
|
143
|
-
))}
|
|
144
|
-
</ul>
|
|
145
|
-
|
|
146
|
-
{groups.map((group) => (
|
|
147
|
-
<SidebarGroupSection
|
|
148
|
-
key={group.slug}
|
|
149
|
-
group={group}
|
|
150
|
-
currentPath={location.pathname}
|
|
151
|
-
/>
|
|
152
|
-
))}
|
|
153
|
-
</nav>
|
|
154
|
-
{config.themeConfig?.poweredBy !== false && <PoweredBy />}
|
|
155
|
-
</>
|
|
156
|
-
)}
|
|
157
|
-
</aside>
|
|
158
|
-
);
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
function SidebarGroupSection({
|
|
162
|
-
group,
|
|
163
|
-
currentPath,
|
|
164
|
-
}: {
|
|
165
|
-
group: SidebarGroup;
|
|
166
|
-
currentPath: string;
|
|
167
|
-
}) {
|
|
168
|
-
const isActive = group.routes.some((r) => currentPath === r.path);
|
|
169
|
-
const [open, setOpen] = useState(true);
|
|
170
|
-
|
|
171
|
-
return (
|
|
172
|
-
<div className="sidebar-group">
|
|
173
|
-
<button
|
|
174
|
-
className={`sidebar-group-header ${isActive ? "active" : ""}`}
|
|
175
|
-
onClick={() => setOpen(!open)}
|
|
176
|
-
aria-expanded={open}
|
|
177
|
-
aria-controls={`sidebar-group-${group.slug}`}
|
|
178
|
-
>
|
|
179
|
-
<span className="sidebar-group-title">{group.title}</span>
|
|
180
|
-
<span className={`sidebar-group-chevron ${open ? "open" : ""}`}>
|
|
181
|
-
<ChevronRight size={16} />
|
|
182
|
-
</span>
|
|
183
|
-
</button>
|
|
184
|
-
{open && (
|
|
185
|
-
<ul className="sidebar-group-list" id={`sidebar-group-${group.slug}`}>
|
|
186
|
-
{group.routes.map((route) => (
|
|
187
|
-
<li key={route.path}>
|
|
188
|
-
<Link
|
|
189
|
-
to={route.path === "" ? "/" : route.path}
|
|
190
|
-
className={`sidebar-link sidebar-link-nested ${currentPath === route.path ? "active" : ""}`}
|
|
191
|
-
aria-current={currentPath === route.path ? "page" : undefined}
|
|
192
|
-
>
|
|
193
|
-
<div className="sidebar-link-content">
|
|
194
|
-
<span>{route.title}</span>
|
|
195
|
-
{renderBadge(route.badge)}
|
|
196
|
-
</div>
|
|
197
|
-
</Link>
|
|
198
|
-
</li>
|
|
199
|
-
))}
|
|
200
|
-
</ul>
|
|
201
|
-
)}
|
|
202
|
-
</div>
|
|
203
|
-
);
|
|
204
|
-
}
|
|
1
|
+
import React, { useState } from "react";
|
|
2
|
+
import { useLocation } from "react-router-dom";
|
|
3
|
+
import { Link } from "../Link";
|
|
4
|
+
import { BoltdocsConfig } from "../../../../node/config";
|
|
5
|
+
import { PoweredBy } from "../PoweredBy";
|
|
6
|
+
import { ChevronRight, ChevronLeft, PanelLeft } from "lucide-react";
|
|
7
|
+
|
|
8
|
+
interface RouteItem {
|
|
9
|
+
path: string;
|
|
10
|
+
title: string;
|
|
11
|
+
group?: string;
|
|
12
|
+
groupTitle?: string;
|
|
13
|
+
sidebarPosition?: number;
|
|
14
|
+
badge?: string | { text: string; expires?: string };
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
interface SidebarGroup {
|
|
18
|
+
slug: string;
|
|
19
|
+
title: string;
|
|
20
|
+
routes: RouteItem[];
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Renders a small badge next to sidebar items if one exists and hasn't expired.
|
|
25
|
+
*/
|
|
26
|
+
function renderBadge(badgeRaw: RouteItem["badge"]) {
|
|
27
|
+
if (!badgeRaw) return null;
|
|
28
|
+
|
|
29
|
+
let text = "";
|
|
30
|
+
let expires = "";
|
|
31
|
+
|
|
32
|
+
if (typeof badgeRaw === "string") {
|
|
33
|
+
text = badgeRaw;
|
|
34
|
+
} else {
|
|
35
|
+
text = badgeRaw.text;
|
|
36
|
+
expires = badgeRaw.expires || "";
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// Check expiration
|
|
40
|
+
if (expires) {
|
|
41
|
+
const expireDate = new Date(expires);
|
|
42
|
+
const now = new Date();
|
|
43
|
+
// Reset time components for accurate day comparison
|
|
44
|
+
expireDate.setHours(0, 0, 0, 0);
|
|
45
|
+
now.setHours(0, 0, 0, 0);
|
|
46
|
+
if (now > expireDate) {
|
|
47
|
+
return null;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
if (!text) return null;
|
|
52
|
+
|
|
53
|
+
if (!text) return null;
|
|
54
|
+
|
|
55
|
+
let typeClass = "badge-default";
|
|
56
|
+
const lowerText = text.toLowerCase();
|
|
57
|
+
if (lowerText === "new") {
|
|
58
|
+
typeClass = "badge-new";
|
|
59
|
+
} else if (lowerText === "experimental") {
|
|
60
|
+
typeClass = "badge-experimental";
|
|
61
|
+
} else if (lowerText === "updated") {
|
|
62
|
+
typeClass = "badge-updated";
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
return <span className={`sidebar-badge ${typeClass}`}>{text}</span>;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* The sidebar navigation component.
|
|
70
|
+
* Groups documentation routes logically based on the `group` property.
|
|
71
|
+
* Highlights the active link based on the current URL path.
|
|
72
|
+
*
|
|
73
|
+
* @param routes - Array of all generated routes to be displayed
|
|
74
|
+
* @param config - Global configuration (which can contain sidebar overrides)
|
|
75
|
+
*/
|
|
76
|
+
export function Sidebar({
|
|
77
|
+
routes,
|
|
78
|
+
config,
|
|
79
|
+
isCollapsed,
|
|
80
|
+
onToggle,
|
|
81
|
+
}: {
|
|
82
|
+
routes: RouteItem[];
|
|
83
|
+
config: BoltdocsConfig;
|
|
84
|
+
isCollapsed?: boolean;
|
|
85
|
+
onToggle?: () => void;
|
|
86
|
+
}) {
|
|
87
|
+
const location = useLocation();
|
|
88
|
+
|
|
89
|
+
const ungrouped: RouteItem[] = [];
|
|
90
|
+
const groupMap = new Map<string, SidebarGroup>();
|
|
91
|
+
|
|
92
|
+
for (const route of routes) {
|
|
93
|
+
if (!route.group) {
|
|
94
|
+
ungrouped.push(route);
|
|
95
|
+
} else {
|
|
96
|
+
if (!groupMap.has(route.group)) {
|
|
97
|
+
groupMap.set(route.group, {
|
|
98
|
+
slug: route.group,
|
|
99
|
+
title: route.groupTitle || route.group,
|
|
100
|
+
routes: [],
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
groupMap.get(route.group)!.routes.push(route);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
const groups = Array.from(groupMap.values());
|
|
108
|
+
|
|
109
|
+
return (
|
|
110
|
+
<aside className="boltdocs-sidebar">
|
|
111
|
+
{onToggle && (
|
|
112
|
+
<div className="sidebar-collapse">
|
|
113
|
+
<button
|
|
114
|
+
className="sidebar-collapse-btn"
|
|
115
|
+
onClick={onToggle}
|
|
116
|
+
aria-label={isCollapsed ? "Expand Sidebar" : "Collapse Sidebar"}
|
|
117
|
+
title={isCollapsed ? "Expand Sidebar" : "Collapse Sidebar"}
|
|
118
|
+
>
|
|
119
|
+
<PanelLeft size={18} />
|
|
120
|
+
</button>
|
|
121
|
+
</div>
|
|
122
|
+
)}
|
|
123
|
+
|
|
124
|
+
{!isCollapsed && (
|
|
125
|
+
<>
|
|
126
|
+
<nav aria-label="Main Navigation">
|
|
127
|
+
<ul className="sidebar-list">
|
|
128
|
+
{ungrouped.map((route) => (
|
|
129
|
+
<li key={route.path}>
|
|
130
|
+
<Link
|
|
131
|
+
to={route.path === "" ? "/" : route.path}
|
|
132
|
+
className={`sidebar-link ${location.pathname === route.path ? "active" : ""}`}
|
|
133
|
+
aria-current={
|
|
134
|
+
location.pathname === route.path ? "page" : undefined
|
|
135
|
+
}
|
|
136
|
+
>
|
|
137
|
+
<div className="sidebar-link-content">
|
|
138
|
+
<span>{route.title}</span>
|
|
139
|
+
{renderBadge(route.badge)}
|
|
140
|
+
</div>
|
|
141
|
+
</Link>
|
|
142
|
+
</li>
|
|
143
|
+
))}
|
|
144
|
+
</ul>
|
|
145
|
+
|
|
146
|
+
{groups.map((group) => (
|
|
147
|
+
<SidebarGroupSection
|
|
148
|
+
key={group.slug}
|
|
149
|
+
group={group}
|
|
150
|
+
currentPath={location.pathname}
|
|
151
|
+
/>
|
|
152
|
+
))}
|
|
153
|
+
</nav>
|
|
154
|
+
{config.themeConfig?.poweredBy !== false && <PoweredBy />}
|
|
155
|
+
</>
|
|
156
|
+
)}
|
|
157
|
+
</aside>
|
|
158
|
+
);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
function SidebarGroupSection({
|
|
162
|
+
group,
|
|
163
|
+
currentPath,
|
|
164
|
+
}: {
|
|
165
|
+
group: SidebarGroup;
|
|
166
|
+
currentPath: string;
|
|
167
|
+
}) {
|
|
168
|
+
const isActive = group.routes.some((r) => currentPath === r.path);
|
|
169
|
+
const [open, setOpen] = useState(true);
|
|
170
|
+
|
|
171
|
+
return (
|
|
172
|
+
<div className="sidebar-group">
|
|
173
|
+
<button
|
|
174
|
+
className={`sidebar-group-header ${isActive ? "active" : ""}`}
|
|
175
|
+
onClick={() => setOpen(!open)}
|
|
176
|
+
aria-expanded={open}
|
|
177
|
+
aria-controls={`sidebar-group-${group.slug}`}
|
|
178
|
+
>
|
|
179
|
+
<span className="sidebar-group-title">{group.title}</span>
|
|
180
|
+
<span className={`sidebar-group-chevron ${open ? "open" : ""}`}>
|
|
181
|
+
<ChevronRight size={16} />
|
|
182
|
+
</span>
|
|
183
|
+
</button>
|
|
184
|
+
{open && (
|
|
185
|
+
<ul className="sidebar-group-list" id={`sidebar-group-${group.slug}`}>
|
|
186
|
+
{group.routes.map((route) => (
|
|
187
|
+
<li key={route.path}>
|
|
188
|
+
<Link
|
|
189
|
+
to={route.path === "" ? "/" : route.path}
|
|
190
|
+
className={`sidebar-link sidebar-link-nested ${currentPath === route.path ? "active" : ""}`}
|
|
191
|
+
aria-current={currentPath === route.path ? "page" : undefined}
|
|
192
|
+
>
|
|
193
|
+
<div className="sidebar-link-content">
|
|
194
|
+
<span>{route.title}</span>
|
|
195
|
+
{renderBadge(route.badge)}
|
|
196
|
+
</div>
|
|
197
|
+
</Link>
|
|
198
|
+
</li>
|
|
199
|
+
))}
|
|
200
|
+
</ul>
|
|
201
|
+
)}
|
|
202
|
+
</div>
|
|
203
|
+
);
|
|
204
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export { Sidebar } from "./Sidebar";
|
|
1
|
+
export { Sidebar } from "./Sidebar";
|