starlight-sidebar-topics-dropdown 0.1.0 → 0.2.0
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/lib/config.ts +5 -0
- package/lib/content.ts +11 -0
- package/lib/sidebar.ts +35 -2
- package/overrides/Sidebar.astro +9 -3
- package/package.json +3 -1
- package/schema.ts +10 -0
package/lib/config.ts
CHANGED
|
@@ -43,6 +43,11 @@ const sidebarTopicBaseSchema = z.object({
|
|
|
43
43
|
const sidebarTopicLinkSchema = sidebarTopicBaseSchema;
|
|
44
44
|
|
|
45
45
|
const sidebarTopicGroupSchema = sidebarTopicBaseSchema.extend({
|
|
46
|
+
/**
|
|
47
|
+
* An optional unique identifier for the topic that can be used to associate content pages that are not listed in any
|
|
48
|
+
* topic sidebar configuration with this topic.
|
|
49
|
+
*/
|
|
50
|
+
id: z.string().optional(),
|
|
46
51
|
/**
|
|
47
52
|
* The sidebar items (links and subcategories) to display for this topic.
|
|
48
53
|
*
|
package/lib/content.ts
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { Props } from "@astrojs/starlight/props";
|
|
2
|
+
import type { TopicFrontmatterSchema } from "../schema";
|
|
3
|
+
export function isStarlightEntryWithTopic(entry: StarlightEntry): entry is StarlightEntryWithTopic {
|
|
4
|
+
return (
|
|
5
|
+
"data" in entry &&
|
|
6
|
+
"topic" in (entry as StarlightEntryWithTopic).data &&
|
|
7
|
+
typeof (entry as StarlightEntryWithTopic).data.topic === "string"
|
|
8
|
+
);
|
|
9
|
+
}
|
|
10
|
+
export type StarlightEntry = Props["entry"];
|
|
11
|
+
export type StarlightEntryWithTopic = StarlightEntry & { data: TopicFrontmatterSchema };
|
package/lib/sidebar.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { Props } from "@astrojs/starlight/props";
|
|
2
2
|
|
|
3
3
|
import type { StarlightSidebarTopicsDropdownSharedConfig } from "./config";
|
|
4
|
+
import { isStarlightEntryWithTopic, type StarlightEntry } from "./content";
|
|
4
5
|
import { getLocaleFromSlug, getLocalizedSlug } from "./i18n";
|
|
5
6
|
import { arePathnamesEqual, stripLeadingAndTrailingSlashes } from "./pathname";
|
|
6
7
|
|
|
@@ -9,8 +10,13 @@ const absoluteLinkRegex = /^https?:\/\//;
|
|
|
9
10
|
export function getCurrentTopic(
|
|
10
11
|
config: StarlightSidebarTopicsDropdownSharedConfig,
|
|
11
12
|
sidebar: SidebarEntry[],
|
|
12
|
-
currentSlug: string
|
|
13
|
+
currentSlug: string,
|
|
14
|
+
entry: StarlightEntry
|
|
13
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
|
+
|
|
14
20
|
// Start by checking if the current page is a topic root.
|
|
15
21
|
const topicFromSlug = getTopicFromSlug(config, sidebar, currentSlug);
|
|
16
22
|
if (topicFromSlug) return topicFromSlug;
|
|
@@ -100,6 +106,29 @@ function getTopicFromSlug(
|
|
|
100
106
|
return { config: topicConfig, sidebar: topicSidebar };
|
|
101
107
|
}
|
|
102
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
|
+
|
|
103
132
|
function getCurrentSidebarTopic(sidebar: SidebarEntry[]): SidebarTopic | undefined {
|
|
104
133
|
let currentSidebarTopic: SidebarTopic | undefined;
|
|
105
134
|
|
|
@@ -127,6 +156,10 @@ function getCurrentSidebarEntry(sidebar: SidebarEntry[]): SidebarEntry | undefin
|
|
|
127
156
|
});
|
|
128
157
|
}
|
|
129
158
|
|
|
159
|
+
function getTopicIdFromEntry(entry: StarlightEntry): string | undefined {
|
|
160
|
+
return isStarlightEntryWithTopic(entry) ? entry.data.topic : undefined;
|
|
161
|
+
}
|
|
162
|
+
|
|
130
163
|
type SidebarEntry = Props["sidebar"][number];
|
|
131
164
|
|
|
132
165
|
interface SidebarTopic {
|
|
@@ -134,7 +167,7 @@ interface SidebarTopic {
|
|
|
134
167
|
entries: SidebarEntry[];
|
|
135
168
|
}
|
|
136
169
|
|
|
137
|
-
interface Topic {
|
|
170
|
+
export interface Topic {
|
|
138
171
|
config: StarlightSidebarTopicsDropdownSharedConfig[number];
|
|
139
172
|
sidebar: SidebarEntry[];
|
|
140
173
|
}
|
package/overrides/Sidebar.astro
CHANGED
|
@@ -5,15 +5,21 @@ import config from 'virtual:starlight-sidebar-topics-dropdown/config'
|
|
|
5
5
|
|
|
6
6
|
import Topics from '../components/Topics.astro'
|
|
7
7
|
import { throwPluginError } from '../lib/plugin'
|
|
8
|
-
import { getCurrentTopic } from '../lib/sidebar'
|
|
8
|
+
import { getCurrentTopic, type Topic } from '../lib/sidebar'
|
|
9
9
|
|
|
10
10
|
const { entry, sidebar, slug } = Astro.props
|
|
11
11
|
|
|
12
12
|
let currentSidebar = sidebar
|
|
13
|
-
|
|
13
|
+
let currentTopic: Topic | undefined = undefined
|
|
14
14
|
|
|
15
15
|
if (entry['data'].template !== 'splash') {
|
|
16
|
-
|
|
16
|
+
currentTopic = getCurrentTopic(config, sidebar, slug, entry)
|
|
17
|
+
if (!currentTopic)
|
|
18
|
+
throwPluginError(
|
|
19
|
+
'Failed to find the topic for the current page.',
|
|
20
|
+
`Either include the 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
|
+
)
|
|
17
23
|
currentSidebar = currentTopic.sidebar
|
|
18
24
|
}
|
|
19
25
|
---
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "starlight-sidebar-topics-dropdown",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"description": "Starlight plugin to split your docs page into multiple subpages and switch between them with a dropdown menu in the sidebar.",
|
|
6
6
|
"author": "trueberryless (https://trueberryless.org)",
|
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
".": "./index.ts",
|
|
10
10
|
"./overrides/Pagination.astro": "./overrides/Pagination.astro",
|
|
11
11
|
"./overrides/Sidebar.astro": "./overrides/Sidebar.astro",
|
|
12
|
+
"./schema": "./schema.ts",
|
|
12
13
|
"./package.json": "./package.json"
|
|
13
14
|
},
|
|
14
15
|
"devDependencies": {
|
|
@@ -21,6 +22,7 @@
|
|
|
21
22
|
"engines": {
|
|
22
23
|
"node": "^18.17.1 || ^20.3.0 || >=21.0.0"
|
|
23
24
|
},
|
|
25
|
+
"packageManager": "pnpm@9.3.0",
|
|
24
26
|
"publishConfig": {
|
|
25
27
|
"access": "public"
|
|
26
28
|
},
|
package/schema.ts
ADDED
|
@@ -0,0 +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>;
|