blume 0.1.4 → 0.1.5
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.
|
@@ -104,8 +104,14 @@ Tabs also **scope the sidebar**: when the current route falls under a tab's
|
|
|
104
104
|
`path`, the sidebar shows only that section's pages — so `/adapters/*` lists the
|
|
105
105
|
adapters and nothing else. The folder at a tab's `path` becomes the section, so
|
|
106
106
|
this needs no extra config beyond the tabs themselves; structure your content
|
|
107
|
-
into a folder per tab and point each tab at it.
|
|
108
|
-
|
|
107
|
+
into a folder per tab and point each tab at it.
|
|
108
|
+
|
|
109
|
+
On a route under no tab (or a tab whose `path` is `/`), the sidebar shows the
|
|
110
|
+
pages that _don't_ belong to a tab — each tab's folder is hidden from it, since
|
|
111
|
+
that section already has its own tab in the header. So a root landing page lists
|
|
112
|
+
your loose top-level pages while the sectioned content stays behind its tab,
|
|
113
|
+
mirroring Fumadocs' root folders. If a route has no pages of its own to show
|
|
114
|
+
this way, the full tree is shown instead, so the sidebar is never left blank.
|
|
109
115
|
|
|
110
116
|
## Explicit sidebar
|
|
111
117
|
|
package/package.json
CHANGED
|
@@ -114,13 +114,56 @@ const sectionChildren = (nodes: NavNode[], base: string): NavNode[] | null => {
|
|
|
114
114
|
return null;
|
|
115
115
|
};
|
|
116
116
|
|
|
117
|
+
/** Whether a group maps to a header tab (matched on its path or link route). */
|
|
118
|
+
const isTabSection = (node: NavNode, tabPaths: Set<string>): boolean =>
|
|
119
|
+
node.kind === "group" &&
|
|
120
|
+
((node.path !== undefined && tabPaths.has(node.path)) ||
|
|
121
|
+
(node.route !== undefined && tabPaths.has(node.route)));
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* Drop the groups that already own a header tab from the tree, at any depth —
|
|
125
|
+
* so a root/un-tabbed route lists only the pages outside every tab's section
|
|
126
|
+
* instead of duplicating each tab as a sidebar group. A container left empty by
|
|
127
|
+
* this pruning is dropped too, so no bare heading is stranded. The root tab
|
|
128
|
+
* (`/`) spans everything, so it never removes anything.
|
|
129
|
+
*/
|
|
130
|
+
const withoutTabSections = (nodes: NavNode[], tabs: NavTab[]): NavNode[] => {
|
|
131
|
+
const tabPaths = new Set(
|
|
132
|
+
tabs.filter((tab) => tab.path !== "/").map((tab) => tab.path)
|
|
133
|
+
);
|
|
134
|
+
if (tabPaths.size === 0) {
|
|
135
|
+
return nodes;
|
|
136
|
+
}
|
|
137
|
+
const prune = (items: NavNode[]): NavNode[] => {
|
|
138
|
+
const kept: NavNode[] = [];
|
|
139
|
+
for (const item of items) {
|
|
140
|
+
if (isTabSection(item, tabPaths)) {
|
|
141
|
+
continue;
|
|
142
|
+
}
|
|
143
|
+
if (item.kind === "group") {
|
|
144
|
+
const children = prune(item.children);
|
|
145
|
+
if (children.length === 0) {
|
|
146
|
+
continue;
|
|
147
|
+
}
|
|
148
|
+
kept.push({ ...item, children });
|
|
149
|
+
} else {
|
|
150
|
+
kept.push(item);
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
return kept;
|
|
154
|
+
};
|
|
155
|
+
return prune(nodes);
|
|
156
|
+
};
|
|
157
|
+
|
|
117
158
|
/**
|
|
118
159
|
* Scope the sidebar to the active tab's section. With tabs configured, a route
|
|
119
160
|
* under one tab shows only that tab's group — so a multi-section site (e.g.
|
|
120
161
|
* Adapters / API / AI tabs) drills each tab into its own pages instead of one
|
|
121
|
-
* global tree, the way Fumadocs' root folders do.
|
|
122
|
-
*
|
|
123
|
-
*
|
|
162
|
+
* global tree, the way Fumadocs' root folders do. On a route under no tab (or
|
|
163
|
+
* the root `/` tab), the tab-owned groups are hidden so the root sidebar shows
|
|
164
|
+
* only pages that don't belong to a tab. Falls back to the full sidebar when a
|
|
165
|
+
* matched tab maps to no group, or when hiding the tab sections would blank the
|
|
166
|
+
* sidebar, so a route is never left empty.
|
|
124
167
|
*/
|
|
125
168
|
export const sidebarForRoute = (
|
|
126
169
|
sidebar: NavNode[],
|
|
@@ -128,10 +171,11 @@ export const sidebarForRoute = (
|
|
|
128
171
|
route: string
|
|
129
172
|
): NavNode[] => {
|
|
130
173
|
const tab = activeTab(tabs, route);
|
|
131
|
-
if (
|
|
132
|
-
return sidebar;
|
|
174
|
+
if (tab) {
|
|
175
|
+
return sectionChildren(sidebar, tab.path) ?? sidebar;
|
|
133
176
|
}
|
|
134
|
-
|
|
177
|
+
const scoped = withoutTabSections(sidebar, tabs);
|
|
178
|
+
return scoped.length > 0 ? scoped : sidebar;
|
|
135
179
|
};
|
|
136
180
|
|
|
137
181
|
/** Resolve previous/next pages around the current route. */
|