starlight-sidebar-topics-dropdown 0.2.0 → 0.2.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/CHANGELOG.md +7 -0
- package/README.md +15 -15
- package/components/Topics.astro +253 -253
- package/index.ts +82 -82
- package/lib/config.ts +74 -74
- package/lib/content.ts +11 -11
- package/lib/i18n.ts +22 -22
- package/lib/pathname.ts +17 -17
- package/lib/plugin.ts +32 -32
- package/lib/sidebar.ts +173 -173
- package/lib/vite.ts +34 -34
- package/overrides/Pagination.astro +18 -18
- package/overrides/Sidebar.astro +27 -27
- package/package.json +46 -46
- package/schema.ts +10 -10
- package/starlight.d.ts +5 -5
- package/virtual.d.ts +5 -5
package/lib/sidebar.ts
CHANGED
|
@@ -1,173 +1,173 @@
|
|
|
1
|
-
import type { Props } from "@astrojs/starlight/props";
|
|
2
|
-
|
|
3
|
-
import type { StarlightSidebarTopicsDropdownSharedConfig } from "./config";
|
|
4
|
-
import { isStarlightEntryWithTopic, type StarlightEntry } from "./content";
|
|
5
|
-
import { getLocaleFromSlug, getLocalizedSlug } from "./i18n";
|
|
6
|
-
import { arePathnamesEqual, stripLeadingAndTrailingSlashes } from "./pathname";
|
|
7
|
-
|
|
8
|
-
const absoluteLinkRegex = /^https?:\/\//;
|
|
9
|
-
|
|
10
|
-
export function getCurrentTopic(
|
|
11
|
-
config: StarlightSidebarTopicsDropdownSharedConfig,
|
|
12
|
-
sidebar: SidebarEntry[],
|
|
13
|
-
currentSlug: string,
|
|
14
|
-
entry: StarlightEntry
|
|
15
|
-
): Topic | undefined {
|
|
16
|
-
// If the current page has a topic ID, use it to find the topic.
|
|
17
|
-
const topicId = getTopicIdFromEntry(entry);
|
|
18
|
-
if (topicId) return getTopicById(config, sidebar, topicId);
|
|
19
|
-
|
|
20
|
-
// Start by checking if the current page is a topic root.
|
|
21
|
-
const topicFromSlug = getTopicFromSlug(config, sidebar, currentSlug);
|
|
22
|
-
if (topicFromSlug) return topicFromSlug;
|
|
23
|
-
|
|
24
|
-
// Otherwise, find the current topic by looking for the current page in the sidebar.
|
|
25
|
-
const currentSidebarTopic = getCurrentSidebarTopic(sidebar);
|
|
26
|
-
if (!currentSidebarTopic) return;
|
|
27
|
-
|
|
28
|
-
const currentTopicConfig = config[Number.parseInt(currentSidebarTopic.label, 10)];
|
|
29
|
-
if (!currentTopicConfig) return;
|
|
30
|
-
|
|
31
|
-
return { config: currentTopicConfig, sidebar: currentSidebarTopic.entries };
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
export function isTopicFirstPage(sidebar: SidebarEntry[], currentSlug: string): boolean {
|
|
35
|
-
const currentSidebarTopic = getCurrentSidebarTopic(sidebar);
|
|
36
|
-
if (!currentSidebarTopic) return false;
|
|
37
|
-
|
|
38
|
-
const firstPage = getSidebarFirstPage(currentSidebarTopic.entries);
|
|
39
|
-
if (!firstPage) return false;
|
|
40
|
-
|
|
41
|
-
return arePathnamesEqual(stripLeadingAndTrailingSlashes(firstPage.href), currentSlug);
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
export function isTopicLastPage(sidebar: SidebarEntry[], currentSlug: string): boolean {
|
|
45
|
-
const currentSidebarTopic = getCurrentSidebarTopic(sidebar);
|
|
46
|
-
if (!currentSidebarTopic) return false;
|
|
47
|
-
|
|
48
|
-
const lastPage = getSidebarLastPage(currentSidebarTopic.entries);
|
|
49
|
-
if (!lastPage) return false;
|
|
50
|
-
|
|
51
|
-
return arePathnamesEqual(stripLeadingAndTrailingSlashes(lastPage.href), currentSlug);
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
function getSidebarFirstPage(sidebar: SidebarEntry[]) {
|
|
55
|
-
const entry = sidebar[0];
|
|
56
|
-
if (!entry) return;
|
|
57
|
-
if (entry.type === "link") return entry;
|
|
58
|
-
|
|
59
|
-
return getSidebarFirstPage(entry.entries);
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
function getSidebarLastPage(sidebar: SidebarEntry[]) {
|
|
63
|
-
const entry = sidebar.at(-1);
|
|
64
|
-
if (!entry) return;
|
|
65
|
-
if (entry.type === "link") return entry;
|
|
66
|
-
|
|
67
|
-
return getSidebarLastPage(entry.entries);
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
function getTopicFromSlug(
|
|
71
|
-
config: StarlightSidebarTopicsDropdownSharedConfig,
|
|
72
|
-
sidebar: SidebarEntry[],
|
|
73
|
-
slug: string
|
|
74
|
-
): Topic | undefined {
|
|
75
|
-
let topicConfig: Topic["config"] | undefined;
|
|
76
|
-
let topicSidebar: Topic["sidebar"] | undefined;
|
|
77
|
-
|
|
78
|
-
// Start by checking if the current page is a topic homepage.
|
|
79
|
-
let groupTopicIndex = -1;
|
|
80
|
-
const slugLocale = getLocaleFromSlug(slug);
|
|
81
|
-
|
|
82
|
-
for (const topic of config) {
|
|
83
|
-
if (topic.type === "group") groupTopicIndex++;
|
|
84
|
-
|
|
85
|
-
if (
|
|
86
|
-
!absoluteLinkRegex.test(topic.link) &&
|
|
87
|
-
arePathnamesEqual(
|
|
88
|
-
getLocalizedSlug(stripLeadingAndTrailingSlashes(topic.link), slugLocale),
|
|
89
|
-
slug
|
|
90
|
-
) &&
|
|
91
|
-
groupTopicIndex !== -1
|
|
92
|
-
) {
|
|
93
|
-
const sidebarTopic = sidebar[groupTopicIndex];
|
|
94
|
-
|
|
95
|
-
if (sidebarTopic?.type === "group") {
|
|
96
|
-
topicConfig = topic;
|
|
97
|
-
topicSidebar = sidebarTopic.entries;
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
break;
|
|
101
|
-
}
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
if (!topicConfig || !topicSidebar) return;
|
|
105
|
-
|
|
106
|
-
return { config: topicConfig, sidebar: topicSidebar };
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
function getTopicById(
|
|
110
|
-
config: StarlightSidebarTopicsDropdownSharedConfig,
|
|
111
|
-
sidebar: SidebarEntry[],
|
|
112
|
-
id: string
|
|
113
|
-
): Topic | undefined {
|
|
114
|
-
let topicConfig: Topic["config"] | undefined;
|
|
115
|
-
let topicSidebar: Topic["sidebar"] | undefined;
|
|
116
|
-
let groupTopicIndex = -1;
|
|
117
|
-
for (const topic of config) {
|
|
118
|
-
if (topic.type === "group") groupTopicIndex++;
|
|
119
|
-
if (topic.type === "group" && topic.id === id) {
|
|
120
|
-
const sidebarTopic = sidebar[groupTopicIndex];
|
|
121
|
-
if (sidebarTopic?.type === "group") {
|
|
122
|
-
topicConfig = topic;
|
|
123
|
-
topicSidebar = sidebarTopic.entries;
|
|
124
|
-
}
|
|
125
|
-
break;
|
|
126
|
-
}
|
|
127
|
-
}
|
|
128
|
-
if (!topicConfig || !topicSidebar) return;
|
|
129
|
-
return { config: topicConfig, sidebar: topicSidebar };
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
function getCurrentSidebarTopic(sidebar: SidebarEntry[]): SidebarTopic | undefined {
|
|
133
|
-
let currentSidebarTopic: SidebarTopic | undefined;
|
|
134
|
-
|
|
135
|
-
for (const topic of sidebar) {
|
|
136
|
-
if (topic.type === "link") continue;
|
|
137
|
-
|
|
138
|
-
const currentSidebarEntry = getCurrentSidebarEntry(topic.entries);
|
|
139
|
-
|
|
140
|
-
if (currentSidebarEntry) {
|
|
141
|
-
currentSidebarTopic = topic;
|
|
142
|
-
break;
|
|
143
|
-
}
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
return currentSidebarTopic;
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
function getCurrentSidebarEntry(sidebar: SidebarEntry[]): SidebarEntry | undefined {
|
|
150
|
-
return sidebar.find((entry) => {
|
|
151
|
-
if (entry.type === "link") {
|
|
152
|
-
return entry.isCurrent;
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
return getCurrentSidebarEntry(entry.entries);
|
|
156
|
-
});
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
function getTopicIdFromEntry(entry: StarlightEntry): string | undefined {
|
|
160
|
-
return isStarlightEntryWithTopic(entry) ? entry.data.topic : undefined;
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
type SidebarEntry = Props["sidebar"][number];
|
|
164
|
-
|
|
165
|
-
interface SidebarTopic {
|
|
166
|
-
label: string;
|
|
167
|
-
entries: SidebarEntry[];
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
export interface Topic {
|
|
171
|
-
config: StarlightSidebarTopicsDropdownSharedConfig[number];
|
|
172
|
-
sidebar: SidebarEntry[];
|
|
173
|
-
}
|
|
1
|
+
import type { Props } from "@astrojs/starlight/props";
|
|
2
|
+
|
|
3
|
+
import type { StarlightSidebarTopicsDropdownSharedConfig } from "./config";
|
|
4
|
+
import { isStarlightEntryWithTopic, type StarlightEntry } from "./content";
|
|
5
|
+
import { getLocaleFromSlug, getLocalizedSlug } from "./i18n";
|
|
6
|
+
import { arePathnamesEqual, stripLeadingAndTrailingSlashes } from "./pathname";
|
|
7
|
+
|
|
8
|
+
const absoluteLinkRegex = /^https?:\/\//;
|
|
9
|
+
|
|
10
|
+
export function getCurrentTopic(
|
|
11
|
+
config: StarlightSidebarTopicsDropdownSharedConfig,
|
|
12
|
+
sidebar: SidebarEntry[],
|
|
13
|
+
currentSlug: string,
|
|
14
|
+
entry: StarlightEntry
|
|
15
|
+
): Topic | undefined {
|
|
16
|
+
// If the current page has a topic ID, use it to find the topic.
|
|
17
|
+
const topicId = getTopicIdFromEntry(entry);
|
|
18
|
+
if (topicId) return getTopicById(config, sidebar, topicId);
|
|
19
|
+
|
|
20
|
+
// Start by checking if the current page is a topic root.
|
|
21
|
+
const topicFromSlug = getTopicFromSlug(config, sidebar, currentSlug);
|
|
22
|
+
if (topicFromSlug) return topicFromSlug;
|
|
23
|
+
|
|
24
|
+
// Otherwise, find the current topic by looking for the current page in the sidebar.
|
|
25
|
+
const currentSidebarTopic = getCurrentSidebarTopic(sidebar);
|
|
26
|
+
if (!currentSidebarTopic) return;
|
|
27
|
+
|
|
28
|
+
const currentTopicConfig = config[Number.parseInt(currentSidebarTopic.label, 10)];
|
|
29
|
+
if (!currentTopicConfig) return;
|
|
30
|
+
|
|
31
|
+
return { config: currentTopicConfig, sidebar: currentSidebarTopic.entries };
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export function isTopicFirstPage(sidebar: SidebarEntry[], currentSlug: string): boolean {
|
|
35
|
+
const currentSidebarTopic = getCurrentSidebarTopic(sidebar);
|
|
36
|
+
if (!currentSidebarTopic) return false;
|
|
37
|
+
|
|
38
|
+
const firstPage = getSidebarFirstPage(currentSidebarTopic.entries);
|
|
39
|
+
if (!firstPage) return false;
|
|
40
|
+
|
|
41
|
+
return arePathnamesEqual(stripLeadingAndTrailingSlashes(firstPage.href), currentSlug);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export function isTopicLastPage(sidebar: SidebarEntry[], currentSlug: string): boolean {
|
|
45
|
+
const currentSidebarTopic = getCurrentSidebarTopic(sidebar);
|
|
46
|
+
if (!currentSidebarTopic) return false;
|
|
47
|
+
|
|
48
|
+
const lastPage = getSidebarLastPage(currentSidebarTopic.entries);
|
|
49
|
+
if (!lastPage) return false;
|
|
50
|
+
|
|
51
|
+
return arePathnamesEqual(stripLeadingAndTrailingSlashes(lastPage.href), currentSlug);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function getSidebarFirstPage(sidebar: SidebarEntry[]) {
|
|
55
|
+
const entry = sidebar[0];
|
|
56
|
+
if (!entry) return;
|
|
57
|
+
if (entry.type === "link") return entry;
|
|
58
|
+
|
|
59
|
+
return getSidebarFirstPage(entry.entries);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
function getSidebarLastPage(sidebar: SidebarEntry[]) {
|
|
63
|
+
const entry = sidebar.at(-1);
|
|
64
|
+
if (!entry) return;
|
|
65
|
+
if (entry.type === "link") return entry;
|
|
66
|
+
|
|
67
|
+
return getSidebarLastPage(entry.entries);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
function getTopicFromSlug(
|
|
71
|
+
config: StarlightSidebarTopicsDropdownSharedConfig,
|
|
72
|
+
sidebar: SidebarEntry[],
|
|
73
|
+
slug: string
|
|
74
|
+
): Topic | undefined {
|
|
75
|
+
let topicConfig: Topic["config"] | undefined;
|
|
76
|
+
let topicSidebar: Topic["sidebar"] | undefined;
|
|
77
|
+
|
|
78
|
+
// Start by checking if the current page is a topic homepage.
|
|
79
|
+
let groupTopicIndex = -1;
|
|
80
|
+
const slugLocale = getLocaleFromSlug(slug);
|
|
81
|
+
|
|
82
|
+
for (const topic of config) {
|
|
83
|
+
if (topic.type === "group") groupTopicIndex++;
|
|
84
|
+
|
|
85
|
+
if (
|
|
86
|
+
!absoluteLinkRegex.test(topic.link) &&
|
|
87
|
+
arePathnamesEqual(
|
|
88
|
+
getLocalizedSlug(stripLeadingAndTrailingSlashes(topic.link), slugLocale),
|
|
89
|
+
slug
|
|
90
|
+
) &&
|
|
91
|
+
groupTopicIndex !== -1
|
|
92
|
+
) {
|
|
93
|
+
const sidebarTopic = sidebar[groupTopicIndex];
|
|
94
|
+
|
|
95
|
+
if (sidebarTopic?.type === "group") {
|
|
96
|
+
topicConfig = topic;
|
|
97
|
+
topicSidebar = sidebarTopic.entries;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
break;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
if (!topicConfig || !topicSidebar) return;
|
|
105
|
+
|
|
106
|
+
return { config: topicConfig, sidebar: topicSidebar };
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
function getTopicById(
|
|
110
|
+
config: StarlightSidebarTopicsDropdownSharedConfig,
|
|
111
|
+
sidebar: SidebarEntry[],
|
|
112
|
+
id: string
|
|
113
|
+
): Topic | undefined {
|
|
114
|
+
let topicConfig: Topic["config"] | undefined;
|
|
115
|
+
let topicSidebar: Topic["sidebar"] | undefined;
|
|
116
|
+
let groupTopicIndex = -1;
|
|
117
|
+
for (const topic of config) {
|
|
118
|
+
if (topic.type === "group") groupTopicIndex++;
|
|
119
|
+
if (topic.type === "group" && topic.id === id) {
|
|
120
|
+
const sidebarTopic = sidebar[groupTopicIndex];
|
|
121
|
+
if (sidebarTopic?.type === "group") {
|
|
122
|
+
topicConfig = topic;
|
|
123
|
+
topicSidebar = sidebarTopic.entries;
|
|
124
|
+
}
|
|
125
|
+
break;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
if (!topicConfig || !topicSidebar) return;
|
|
129
|
+
return { config: topicConfig, sidebar: topicSidebar };
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
function getCurrentSidebarTopic(sidebar: SidebarEntry[]): SidebarTopic | undefined {
|
|
133
|
+
let currentSidebarTopic: SidebarTopic | undefined;
|
|
134
|
+
|
|
135
|
+
for (const topic of sidebar) {
|
|
136
|
+
if (topic.type === "link") continue;
|
|
137
|
+
|
|
138
|
+
const currentSidebarEntry = getCurrentSidebarEntry(topic.entries);
|
|
139
|
+
|
|
140
|
+
if (currentSidebarEntry) {
|
|
141
|
+
currentSidebarTopic = topic;
|
|
142
|
+
break;
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
return currentSidebarTopic;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
function getCurrentSidebarEntry(sidebar: SidebarEntry[]): SidebarEntry | undefined {
|
|
150
|
+
return sidebar.find((entry) => {
|
|
151
|
+
if (entry.type === "link") {
|
|
152
|
+
return entry.isCurrent;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
return getCurrentSidebarEntry(entry.entries);
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
function getTopicIdFromEntry(entry: StarlightEntry): string | undefined {
|
|
160
|
+
return isStarlightEntryWithTopic(entry) ? entry.data.topic : undefined;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
type SidebarEntry = Props["sidebar"][number];
|
|
164
|
+
|
|
165
|
+
interface SidebarTopic {
|
|
166
|
+
label: string;
|
|
167
|
+
entries: SidebarEntry[];
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
export interface Topic {
|
|
171
|
+
config: StarlightSidebarTopicsDropdownSharedConfig[number];
|
|
172
|
+
sidebar: SidebarEntry[];
|
|
173
|
+
}
|
package/lib/vite.ts
CHANGED
|
@@ -1,34 +1,34 @@
|
|
|
1
|
-
import type { ViteUserConfig } from "astro";
|
|
2
|
-
|
|
3
|
-
import type {
|
|
4
|
-
StarlightSidebarTopicsDropdownConfig,
|
|
5
|
-
StarlightSidebarTopicsDropdownSharedConfig,
|
|
6
|
-
} from "./config";
|
|
7
|
-
|
|
8
|
-
const moduleId = "virtual:starlight-sidebar-topics-dropdown/config";
|
|
9
|
-
|
|
10
|
-
export function vitePluginStarlightSidebarTopicsDropdown(
|
|
11
|
-
config: StarlightSidebarTopicsDropdownConfig
|
|
12
|
-
): VitePlugin {
|
|
13
|
-
const resolvedModuleId = `\0${moduleId}`;
|
|
14
|
-
|
|
15
|
-
const sharedConfig: StarlightSidebarTopicsDropdownSharedConfig = config.map((topic) => {
|
|
16
|
-
if (!("items" in topic)) return { ...topic, type: "link" };
|
|
17
|
-
const { items, ...topicWithoutItems } = topic;
|
|
18
|
-
return { ...topicWithoutItems, type: "group" };
|
|
19
|
-
});
|
|
20
|
-
|
|
21
|
-
const moduleContent = `export default ${JSON.stringify(sharedConfig)}`;
|
|
22
|
-
|
|
23
|
-
return {
|
|
24
|
-
name: "vite-plugin-starlight-sidebar-topics-dropdown",
|
|
25
|
-
load(id) {
|
|
26
|
-
return id === resolvedModuleId ? moduleContent : undefined;
|
|
27
|
-
},
|
|
28
|
-
resolveId(id) {
|
|
29
|
-
return id === moduleId ? resolvedModuleId : undefined;
|
|
30
|
-
},
|
|
31
|
-
};
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
type VitePlugin = NonNullable<ViteUserConfig["plugins"]>[number];
|
|
1
|
+
import type { ViteUserConfig } from "astro";
|
|
2
|
+
|
|
3
|
+
import type {
|
|
4
|
+
StarlightSidebarTopicsDropdownConfig,
|
|
5
|
+
StarlightSidebarTopicsDropdownSharedConfig,
|
|
6
|
+
} from "./config";
|
|
7
|
+
|
|
8
|
+
const moduleId = "virtual:starlight-sidebar-topics-dropdown/config";
|
|
9
|
+
|
|
10
|
+
export function vitePluginStarlightSidebarTopicsDropdown(
|
|
11
|
+
config: StarlightSidebarTopicsDropdownConfig
|
|
12
|
+
): VitePlugin {
|
|
13
|
+
const resolvedModuleId = `\0${moduleId}`;
|
|
14
|
+
|
|
15
|
+
const sharedConfig: StarlightSidebarTopicsDropdownSharedConfig = config.map((topic) => {
|
|
16
|
+
if (!("items" in topic)) return { ...topic, type: "link" };
|
|
17
|
+
const { items, ...topicWithoutItems } = topic;
|
|
18
|
+
return { ...topicWithoutItems, type: "group" };
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
const moduleContent = `export default ${JSON.stringify(sharedConfig)}`;
|
|
22
|
+
|
|
23
|
+
return {
|
|
24
|
+
name: "vite-plugin-starlight-sidebar-topics-dropdown",
|
|
25
|
+
load(id) {
|
|
26
|
+
return id === resolvedModuleId ? moduleContent : undefined;
|
|
27
|
+
},
|
|
28
|
+
resolveId(id) {
|
|
29
|
+
return id === moduleId ? resolvedModuleId : undefined;
|
|
30
|
+
},
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
type VitePlugin = NonNullable<ViteUserConfig["plugins"]>[number];
|
|
@@ -1,19 +1,19 @@
|
|
|
1
|
-
---
|
|
2
|
-
import Default from '@astrojs/starlight/components/Pagination.astro'
|
|
3
|
-
import type { Props } from '@astrojs/starlight/props'
|
|
4
|
-
|
|
5
|
-
import { isTopicFirstPage, isTopicLastPage } from '../lib/sidebar'
|
|
6
|
-
|
|
7
|
-
const { pagination, sidebar, slug } = Astro.props
|
|
8
|
-
let { prev, next } = pagination
|
|
9
|
-
|
|
10
|
-
if (isTopicFirstPage(sidebar, slug)) {
|
|
11
|
-
prev = undefined
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
if (isTopicLastPage(sidebar, slug)) {
|
|
15
|
-
next = undefined
|
|
16
|
-
}
|
|
17
|
-
---
|
|
18
|
-
|
|
1
|
+
---
|
|
2
|
+
import Default from '@astrojs/starlight/components/Pagination.astro'
|
|
3
|
+
import type { Props } from '@astrojs/starlight/props'
|
|
4
|
+
|
|
5
|
+
import { isTopicFirstPage, isTopicLastPage } from '../lib/sidebar'
|
|
6
|
+
|
|
7
|
+
const { pagination, sidebar, slug } = Astro.props
|
|
8
|
+
let { prev, next } = pagination
|
|
9
|
+
|
|
10
|
+
if (isTopicFirstPage(sidebar, slug)) {
|
|
11
|
+
prev = undefined
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
if (isTopicLastPage(sidebar, slug)) {
|
|
15
|
+
next = undefined
|
|
16
|
+
}
|
|
17
|
+
---
|
|
18
|
+
|
|
19
19
|
<Default {...Astro.props} pagination={{ prev, next }}><slot /></Default>
|
package/overrides/Sidebar.astro
CHANGED
|
@@ -1,28 +1,28 @@
|
|
|
1
|
-
---
|
|
2
|
-
import Default from '@astrojs/starlight/components/Sidebar.astro'
|
|
3
|
-
import type { Props } from '@astrojs/starlight/props'
|
|
4
|
-
import config from 'virtual:starlight-sidebar-topics-dropdown/config'
|
|
5
|
-
|
|
6
|
-
import Topics from '../components/Topics.astro'
|
|
7
|
-
import { throwPluginError } from '../lib/plugin'
|
|
8
|
-
import { getCurrentTopic, type Topic } from '../lib/sidebar'
|
|
9
|
-
|
|
10
|
-
const { entry, sidebar, slug } = Astro.props
|
|
11
|
-
|
|
12
|
-
let currentSidebar = sidebar
|
|
13
|
-
let currentTopic: Topic | undefined = undefined
|
|
14
|
-
|
|
15
|
-
if (entry['data'].template !== 'splash') {
|
|
16
|
-
currentTopic = getCurrentTopic(config, sidebar, slug, entry)
|
|
17
|
-
if (!currentTopic)
|
|
18
|
-
throwPluginError(
|
|
19
|
-
|
|
20
|
-
`Either include
|
|
21
|
-
Learn more about unlisted pages in the ["Unlisted pages"](https://starlight-sidebar-topics.netlify.app/docs/guides/unlisted-pages/) guide.`,
|
|
22
|
-
)
|
|
23
|
-
currentSidebar = currentTopic.sidebar
|
|
24
|
-
}
|
|
25
|
-
---
|
|
26
|
-
|
|
27
|
-
{entry['data'].template !== 'splash' && currentTopic && <Topics current={currentTopic.config} />}
|
|
1
|
+
---
|
|
2
|
+
import Default from '@astrojs/starlight/components/Sidebar.astro'
|
|
3
|
+
import type { Props } from '@astrojs/starlight/props'
|
|
4
|
+
import config from 'virtual:starlight-sidebar-topics-dropdown/config'
|
|
5
|
+
|
|
6
|
+
import Topics from '../components/Topics.astro'
|
|
7
|
+
import { throwPluginError } from '../lib/plugin'
|
|
8
|
+
import { getCurrentTopic, type Topic } from '../lib/sidebar'
|
|
9
|
+
|
|
10
|
+
const { entry, sidebar, slug } = Astro.props
|
|
11
|
+
|
|
12
|
+
let currentSidebar = sidebar
|
|
13
|
+
let currentTopic: Topic | undefined = undefined
|
|
14
|
+
|
|
15
|
+
if (entry['data'].template !== 'splash') {
|
|
16
|
+
currentTopic = getCurrentTopic(config, sidebar, slug, entry)
|
|
17
|
+
if (!currentTopic)
|
|
18
|
+
throwPluginError(
|
|
19
|
+
`Failed to find the topic for the \`${slug}\` page.`,
|
|
20
|
+
`Either include this page in the sidebar configuration of the desired topic using the \`items\` property or to associate an unlisted page with a topic, use the \`topic\` frontmatter property and set it to the desired topic ID.
|
|
21
|
+
Learn more about unlisted pages in the ["Unlisted pages"](https://starlight-sidebar-topics.netlify.app/docs/guides/unlisted-pages/) guide.`,
|
|
22
|
+
)
|
|
23
|
+
currentSidebar = currentTopic.sidebar
|
|
24
|
+
}
|
|
25
|
+
---
|
|
26
|
+
|
|
27
|
+
{entry['data'].template !== 'splash' && currentTopic && <Topics current={currentTopic.config} />}
|
|
28
28
|
<Default {...Astro.props} sidebar={currentSidebar}><slot /></Default>
|
package/package.json
CHANGED
|
@@ -1,46 +1,46 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "starlight-sidebar-topics-dropdown",
|
|
3
|
-
"version": "0.2.
|
|
4
|
-
"license": "MIT",
|
|
5
|
-
"description": "Starlight plugin to split your docs page into multiple subpages and switch between them with a dropdown menu in the sidebar.",
|
|
6
|
-
"author": "trueberryless (https://trueberryless.org)",
|
|
7
|
-
"type": "module",
|
|
8
|
-
"exports": {
|
|
9
|
-
".": "./index.ts",
|
|
10
|
-
"./overrides/Pagination.astro": "./overrides/Pagination.astro",
|
|
11
|
-
"./overrides/Sidebar.astro": "./overrides/Sidebar.astro",
|
|
12
|
-
"./schema": "./schema.ts",
|
|
13
|
-
"./package.json": "./package.json"
|
|
14
|
-
},
|
|
15
|
-
"devDependencies": {
|
|
16
|
-
"@astrojs/starlight": "^0.28.3",
|
|
17
|
-
"astro": "^4.16.6"
|
|
18
|
-
},
|
|
19
|
-
"peerDependencies": {
|
|
20
|
-
"@astrojs/starlight": ">=0.28"
|
|
21
|
-
},
|
|
22
|
-
"engines": {
|
|
23
|
-
"node": "^18.17.1 || ^20.3.0 || >=21.0.0"
|
|
24
|
-
},
|
|
25
|
-
"packageManager": "pnpm@9.3.0",
|
|
26
|
-
"publishConfig": {
|
|
27
|
-
"access": "public"
|
|
28
|
-
},
|
|
29
|
-
"keywords": [
|
|
30
|
-
"starlight",
|
|
31
|
-
"plugin",
|
|
32
|
-
"sidebar",
|
|
33
|
-
"subpages",
|
|
34
|
-
"sections",
|
|
35
|
-
"dropdown",
|
|
36
|
-
"documentation",
|
|
37
|
-
"astro"
|
|
38
|
-
],
|
|
39
|
-
"homepage": "https://github.com/trueberryless-org/starlight-sidebar-topics-dropdown",
|
|
40
|
-
"repository": {
|
|
41
|
-
"type": "git",
|
|
42
|
-
"url": "https://github.com/trueberryless-org/starlight-sidebar-topics-dropdown.git",
|
|
43
|
-
"directory": "packages/starlight-sidebar-topics-dropdown"
|
|
44
|
-
},
|
|
45
|
-
"bugs": "https://github.com/trueberryless-org/starlight-sidebar-topics-dropdown/issues"
|
|
46
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "starlight-sidebar-topics-dropdown",
|
|
3
|
+
"version": "0.2.2",
|
|
4
|
+
"license": "MIT",
|
|
5
|
+
"description": "Starlight plugin to split your docs page into multiple subpages and switch between them with a dropdown menu in the sidebar.",
|
|
6
|
+
"author": "trueberryless (https://trueberryless.org)",
|
|
7
|
+
"type": "module",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": "./index.ts",
|
|
10
|
+
"./overrides/Pagination.astro": "./overrides/Pagination.astro",
|
|
11
|
+
"./overrides/Sidebar.astro": "./overrides/Sidebar.astro",
|
|
12
|
+
"./schema": "./schema.ts",
|
|
13
|
+
"./package.json": "./package.json"
|
|
14
|
+
},
|
|
15
|
+
"devDependencies": {
|
|
16
|
+
"@astrojs/starlight": "^0.28.3",
|
|
17
|
+
"astro": "^4.16.6"
|
|
18
|
+
},
|
|
19
|
+
"peerDependencies": {
|
|
20
|
+
"@astrojs/starlight": ">=0.28"
|
|
21
|
+
},
|
|
22
|
+
"engines": {
|
|
23
|
+
"node": "^18.17.1 || ^20.3.0 || >=21.0.0"
|
|
24
|
+
},
|
|
25
|
+
"packageManager": "pnpm@9.3.0",
|
|
26
|
+
"publishConfig": {
|
|
27
|
+
"access": "public"
|
|
28
|
+
},
|
|
29
|
+
"keywords": [
|
|
30
|
+
"starlight",
|
|
31
|
+
"plugin",
|
|
32
|
+
"sidebar",
|
|
33
|
+
"subpages",
|
|
34
|
+
"sections",
|
|
35
|
+
"dropdown",
|
|
36
|
+
"documentation",
|
|
37
|
+
"astro"
|
|
38
|
+
],
|
|
39
|
+
"homepage": "https://github.com/trueberryless-org/starlight-sidebar-topics-dropdown",
|
|
40
|
+
"repository": {
|
|
41
|
+
"type": "git",
|
|
42
|
+
"url": "https://github.com/trueberryless-org/starlight-sidebar-topics-dropdown.git",
|
|
43
|
+
"directory": "packages/starlight-sidebar-topics-dropdown"
|
|
44
|
+
},
|
|
45
|
+
"bugs": "https://github.com/trueberryless-org/starlight-sidebar-topics-dropdown/issues"
|
|
46
|
+
}
|
package/schema.ts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import { z } from "astro/zod";
|
|
2
|
-
export const topicSchema = z.object({
|
|
3
|
-
/**
|
|
4
|
-
* ID of the topic to associate with the current page if the page is not listed in any topic sidebar configuration.
|
|
5
|
-
*
|
|
6
|
-
* @see https://starlight-sidebar-topics.netlify.app/docs/guides/unlisted-pages/
|
|
7
|
-
*/
|
|
8
|
-
topic: z.string().optional(),
|
|
9
|
-
});
|
|
10
|
-
export type TopicFrontmatterSchema = z.input<typeof topicSchema>;
|
|
1
|
+
import { z } from "astro/zod";
|
|
2
|
+
export const topicSchema = z.object({
|
|
3
|
+
/**
|
|
4
|
+
* ID of the topic to associate with the current page if the page is not listed in any topic sidebar configuration.
|
|
5
|
+
*
|
|
6
|
+
* @see https://starlight-sidebar-topics.netlify.app/docs/guides/unlisted-pages/
|
|
7
|
+
*/
|
|
8
|
+
topic: z.string().optional(),
|
|
9
|
+
});
|
|
10
|
+
export type TopicFrontmatterSchema = z.input<typeof topicSchema>;
|
package/starlight.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
declare module "virtual:starlight/user-config" {
|
|
2
|
-
const Config: import("@astrojs/starlight/types").StarlightConfig;
|
|
3
|
-
|
|
4
|
-
export default Config;
|
|
5
|
-
}
|
|
1
|
+
declare module "virtual:starlight/user-config" {
|
|
2
|
+
const Config: import("@astrojs/starlight/types").StarlightConfig;
|
|
3
|
+
|
|
4
|
+
export default Config;
|
|
5
|
+
}
|
package/virtual.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
declare module "virtual:starlight-sidebar-topics-dropdown/config" {
|
|
2
|
-
const StarlightSidebarTopicsDropdownConfig: import("./libs/config").StarlightSidebarTopicsDropdownSharedConfig;
|
|
3
|
-
|
|
4
|
-
export default StarlightSidebarTopicsDropdownConfig;
|
|
5
|
-
}
|
|
1
|
+
declare module "virtual:starlight-sidebar-topics-dropdown/config" {
|
|
2
|
+
const StarlightSidebarTopicsDropdownConfig: import("./libs/config").StarlightSidebarTopicsDropdownSharedConfig;
|
|
3
|
+
|
|
4
|
+
export default StarlightSidebarTopicsDropdownConfig;
|
|
5
|
+
}
|