@astrojs/starlight 0.28.6 → 0.29.1
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 +34 -0
- package/components/Icons.ts +4 -0
- package/integrations/asides.ts +4 -4
- package/integrations/expressive-code/index.ts +5 -1
- package/package.json +10 -6
- package/schemas/social.ts +4 -0
- package/user-components/Aside.astro +2 -2
- package/user-components/CardGrid.astro +1 -0
- package/user-components/rehype-tabs.ts +3 -3
- package/utils/createTranslationSystem.ts +5 -1
- package/utils/i18n.ts +1 -1
- package/utils/navigation.ts +78 -39
- package/utils/starlight-page.ts +4 -6
- package/utils/translations.ts +6 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,39 @@
|
|
|
1
1
|
# @astrojs/starlight
|
|
2
2
|
|
|
3
|
+
## 0.29.1
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- [#2611](https://github.com/withastro/starlight/pull/2611) [`6059d96`](https://github.com/withastro/starlight/commit/6059d961a6b31fd7848b0c59411fc6370e62abab) Thanks [@HiDeoo](https://github.com/HiDeoo)! - Fixes a UI string type issue in projects with multiple data content collections.
|
|
8
|
+
|
|
9
|
+
- [#2606](https://github.com/withastro/starlight/pull/2606) [`10b15a7`](https://github.com/withastro/starlight/commit/10b15a7fcda4805dda622f893b6671b96a349161) Thanks [@delucis](https://github.com/delucis)! - Makes `<CardGrid>` more resilient to complex child content on smaller viewports
|
|
10
|
+
|
|
11
|
+
- [#2605](https://github.com/withastro/starlight/pull/2605) [`ec7ab4f`](https://github.com/withastro/starlight/commit/ec7ab4f1df83052aa00c5f560adf7e7b8d61c9db) Thanks [@brianzelip](https://github.com/brianzelip)! - Exposes `SidebarPersister` component in package exports for use in custom overrides
|
|
12
|
+
|
|
13
|
+
- [#2614](https://github.com/withastro/starlight/pull/2614) [`9a31980`](https://github.com/withastro/starlight/commit/9a319807c698f65b461f456c54c413081ab551f0) Thanks [@HiDeoo](https://github.com/HiDeoo)! - Fixes an issue with custom pages using the `<StarlightPage />` component and a custom sidebar missing highlighting for the active page and navigation links.
|
|
14
|
+
|
|
15
|
+
- [#2600](https://github.com/withastro/starlight/pull/2600) [`49aef17`](https://github.com/withastro/starlight/commit/49aef173811d05ae132729c92c3920a142ceeb7d) Thanks [@jdevega](https://github.com/jdevega)! - Adds Backstage social icon
|
|
16
|
+
|
|
17
|
+
- [#2613](https://github.com/withastro/starlight/pull/2613) [`a73780f`](https://github.com/withastro/starlight/commit/a73780fb280feb5b96ffa94539633b2930bd8e76) Thanks [@delucis](https://github.com/delucis)! - Fixes support for `sidebar` frontmatter options in sidebar entries using `slug` or the string shorthand for internal links
|
|
18
|
+
|
|
19
|
+
## 0.29.0
|
|
20
|
+
|
|
21
|
+
### Minor Changes
|
|
22
|
+
|
|
23
|
+
- [#2551](https://github.com/withastro/starlight/pull/2551) [`154c8e3`](https://github.com/withastro/starlight/commit/154c8e337819c7d7ebf4ff4dd55db0d10607620b) Thanks [@hippotastic](https://github.com/hippotastic)! - Updates the `astro-expressive-code` dependency to the latest version (0.38).
|
|
24
|
+
|
|
25
|
+
The new version allows using `ec.config.mjs` to selectively override individual Expressive Code styles and settings provided by Starlight themes and plugins, speeds up Shiki language loading, and adds the config option `expressiveCode.shiki.injectLangsIntoNestedCodeBlocks`. See the [Expressive Code release notes](https://expressive-code.com/releases/#0380) for full details.
|
|
26
|
+
|
|
27
|
+
- [#2252](https://github.com/withastro/starlight/pull/2252) [`6116db0`](https://github.com/withastro/starlight/commit/6116db03a4157c0f0caa210690ef0dcdd001a287) Thanks [@HiDeoo](https://github.com/HiDeoo)! - Improves build performance for sites with large sidebars
|
|
28
|
+
|
|
29
|
+
This release adds a caching layer to Starlight’s sidebar generation logic, reducing the number of times sidebars need to be regenerated while building a site. Some benchmarks for projects with a complex sidebar saw builds complete more than 35% faster with this change.
|
|
30
|
+
|
|
31
|
+
- [#2503](https://github.com/withastro/starlight/pull/2503) [`a4c8edd`](https://github.com/withastro/starlight/commit/a4c8eddc53993068c0f60159fecc123013827ef0) Thanks [@HiDeoo](https://github.com/HiDeoo)! - Improves the accessibility of asides and tabs by removing some unnecessary HTML landmarks.
|
|
32
|
+
|
|
33
|
+
### Patch Changes
|
|
34
|
+
|
|
35
|
+
- [#2579](https://github.com/withastro/starlight/pull/2579) [`241966b`](https://github.com/withastro/starlight/commit/241966bd0523a2e82891d622b2a97b2f3646bc41) Thanks [@RafidMuhymin](https://github.com/RafidMuhymin)! - Adds social link icon for Nostr
|
|
36
|
+
|
|
3
37
|
## 0.28.6
|
|
4
38
|
|
|
5
39
|
### Patch Changes
|
package/components/Icons.ts
CHANGED
|
@@ -158,6 +158,10 @@ export const BuiltInIcons = {
|
|
|
158
158
|
'<path d="M6.49 19.04h-.23L5.13 17.9v-.23l1.73-1.71h1.2l.15.15v1.2L6.5 19.04ZM5.13 6.31V6.1l1.13-1.13h.23L8.2 6.68v1.2l-.15.15h-1.2zm9.96 9.09h-1.65l-.14-.13v-3.83c0-.68-.27-1.2-1.1-1.23c-.42 0-.9 0-1.43.02l-.07.08v4.96l-.14.14H8.9l-.13-.14V8.73l.13-.14h3.7a2.6 2.6 0 0 1 2.61 2.6v4.08l-.13.14Zm-8.37-2.44H.14L0 12.82v-1.64l.14-.14h6.58l.14.14v1.64zm17.14 0h-6.58l-.14-.14v-1.64l.14-.14h6.58l.14.14v1.64zM11.05 6.55V1.64l.14-.14h1.65l.14.14v4.9l-.14.14h-1.65zm0 15.81v-4.9l.14-.14h1.65l.14.13v4.91l-.14.14h-1.65z"/>',
|
|
159
159
|
deno: '<path d="M12 0a12 12 0 1 1 0 24 12 12 0 0 1 0-24m-.47 6.8c-3.49 0-6.2 2.19-6.2 4.92 0 2.58 2.5 4.23 6.37 4.15h.12l.42-.02-.1.28v.03l.09.22v.03l.02.04.02.07.02.04.01.05.02.05.02.07.02.08.02.06.02.08.02.09.02.09.03.1.01.06.03.1.02.1.03.15.02.07.02.11.03.12.02.12.04.17.02.15.04.2.02.1.03.15.03.15.04.22.04.23.04.23.04.24.04.24.04.26.04.26.04.2.05.34.02.14.06.36.04.3.04.22.04.31.03.16a10.76 10.76 0 0 0 6.53-3.41l.05-.06-.24-.89-.64-2.37-.39-1.47-.35-1.3-.21-.78-.14-.5-.08-.3-.07-.26-.03-.11-.02-.07-.01-.03v-.03a6.04 6.04 0 0 0-2.05-2.97 6.75 6.75 0 0 0-4.25-1.35M8.47 19.3a.59.59 0 0 0-.72.4v.01l-.53 1.96q.5.24 1.01.43l.08.03.57-2.11V20a.59.59 0 0 0-.41-.7m3.26-1.43a.59.59 0 0 0-.71.4v.01l-.8 2.96v.01a.59.59 0 0 0 1.12.3l.8-2.96v-.02l.02-.06v-.02l-.02-.1-.02-.14-.02-.08a.58.58 0 0 0-.37-.3Zm-5.55-3.04a1 1 0 0 0-.04.09v.02l-.8 2.95v.02a.59.59 0 0 0 1.13.3v-.01l.72-2.68a5.3 5.3 0 0 1-1.01-.7Zm-1.9-3.4a.59.59 0 0 0-.72.4v.02l-.8 2.95v.01a.59.59 0 0 0 1.13.3l.8-2.96v-.01a.59.59 0 0 0-.41-.7m17.87-.68a.59.59 0 0 0-.72.4v.02l-.8 2.95v.01a.59.59 0 0 0 1.13.3l.8-2.96v-.01a.59.59 0 0 0-.41-.7M2.55 6.81a10.7 10.7 0 0 0-1.26 3.93.59.59 0 0 0 1-.22v-.02l.8-2.95v-.01a.59.59 0 0 0-.55-.73m17.59.02a.59.59 0 0 0-.72.4v.01l-.8 2.96v.01a.59.59 0 0 0 1.13.3l.8-2.96v-.01a.59.59 0 0 0-.41-.7Zm-7.85 1.93a.75.75 0 1 1 0 1.5.75.75 0 0 1 0-1.5M6.01 4.03a.59.59 0 0 0-.71.4v.02L4.5 7.4v.01a.59.59 0 0 0 1.12.3l.8-2.96v-.01a.59.59 0 0 0-.41-.7Zm10.24.56a.59.59 0 0 0-.71.4V5L15 7q.52.26.99.6l.05.04.62-2.32V5.3a.59.59 0 0 0-.41-.7m-5.21-3.34a11 11 0 0 0-1.12.16l-.07.01L9.1 4.2v.01a.59.59 0 0 0 1.13.3l.8-2.96v-.01a.6.6 0 0 0 0-.27m7.34 2.04-.16.58v.02a.59.59 0 0 0 1.13.3V4.2l.02-.07a11 11 0 0 0-.92-.77zm-4.64-1.94-.28 1.05a.59.59 0 0 0 1.13.31v-.01l.3-1.1q-.52-.15-1.06-.24z"/>',
|
|
160
160
|
jsr: '<path d="M3.7 5.54v3.7H0v7.38h7.38v1.84h12.93v-3.7H24V7.39h-7.38V5.54Zm1.84 1.85h1.85v7.38H1.84v-3.7h1.84v1.85h1.85zm3.7 0h5.53v1.84h-3.7v1.85h3.7v5.53H9.23v-1.84h3.7v-1.85h-3.7Zm7.38 1.84h5.53v3.7h-1.84v-1.85h-1.85v5.54h-1.84z"/>',
|
|
161
|
+
nostr:
|
|
162
|
+
'<path d="M21.6 10.6v9.7a.7.7 0 0 1-.6.6h-8a.7.7 0 0 1-.6-.6v-1.8c0-2.2.3-4.4.8-5.3a2 2 0 0 1 1.3-1c1-.4 2.9-.2 3.7-.2 0 0 2.3 0 2.3-1.3 0-1-1-1-1-1-1.2 0-2 0-2.6-.2-1-.4-1-1.1-1-1.3 0-2.7-4-3-7.5-2.4-3.9.7 0 6.2 0 13.5v1a.7.7 0 0 1-.7.6H3.8a.7.7 0 0 1-.6-.6V3.5a.7.7 0 0 1 .6-.6h3.7a.7.7 0 0 1 .7.6c0 .6.6.9 1 .6 1.3-1 3-1.5 5-1.5 4.2 0 7.4 2.5 7.4 8zm-7-2a1.4 1.4 0 1 0-2.9 0 1.4 1.4 0 0 0 2.9 0z"/>',
|
|
163
|
+
backstage:
|
|
164
|
+
'<path d="M18.4 9.3a4.4 4.4 0 0 0 .7-.5l.1-.1a4.5 4.5 0 0 0 .8-1.1l.3-1c0-1-.6-2-2-3L12.7.4 6 6.6l-4.3 4 6 3.7a6.1 6.1 0 0 0 3 .9c1.5 0 2.8-.5 3.7-1.4 1-1 1.4-2.3.8-3.4a2.8 2.8 0 0 0-.4-.5l1 .1a4.6 4.6 0 0 0 1.8-.3 4.5 4.5 0 0 0 .7-.3zm-5.5 3.3c-1 1-2.8 1.2-4.2.4l-4.1-2.5 3.7-3.6 4.2 2.6c1.5.9 1.4 2.1.4 3.1zm.5-4.5-4-2.3L13 2.4l3.8 2.3c1.4.9 1.6 2 .6 3a3.3 3.3 0 0 1-4 .4zM15 18.5c-1 1-2.5 1.6-4.1 1.6a6.8 6.8 0 0 1-3.5-1l-5.6-3.4v1.4l6 3.6a6.1 6.1 0 0 0 3 .9c1.5 0 2.8-.5 3.7-1.4.7-.7 1.1-1.5 1.1-2.3l-.6.6zm0-2.1c-1 1-2.5 1.6-4.1 1.6a6.8 6.8 0 0 1-3.5-1l-5.6-3.4V15l6 3.6a6.1 6.1 0 0 0 3 .9c1.5 0 2.8-.5 3.7-1.4.7-.7 1.1-1.5 1.1-2.3v-.1l-.6.7zm0-2.1c-1 1-2.5 1.6-4.1 1.6a6.8 6.8 0 0 1-3.5-1l-5.6-3.4v1.3l6 3.6a6.1 6.1 0 0 0 3 1c1.5 0 2.8-.6 3.7-1.5.7-.7 1.1-1.5 1.1-2.3l-.6.7zm4.6 1.4a5.2 5.2 0 0 1-3.3 1.4v1.5a4.5 4.5 0 0 0 2.8-1.3c.8-.7 1.2-1.5 1.2-2.3v-.1l-.7.8zm-4.6 5c-1 1-2.5 1.6-4.1 1.6a6.8 6.8 0 0 1-3.5-1l-5.6-3.4v1.3l6 3.6a6.1 6.1 0 0 0 3 1c1.5 0 2.8-.5 3.7-1.5.7-.6 1.1-1.5 1.1-2.2V20l-.6.7zM19.7 9l-.1.2-1.2.8a5.2 5.2 0 0 1-1.5.5 5.2 5.2 0 0 1-.8 0l.1.4V12a4.6 4.6 0 0 0 1.5-.3A4.4 4.4 0 0 0 19 11l.1-.1a4.5 4.5 0 0 0 .8-1.1 2.6 2.6 0 0 0 .3-1.1v-.1l-.2.1-.4.6zm0 4.3a6 6 0 0 1-.1.1 5.2 5.2 0 0 1-3.3 1.5v1.4a4.5 4.5 0 0 0 2.8-1.2l1-1.2.2-1v-.1l-.2.2a4.8 4.8 0 0 1-.4.5zm0-2.1-.1.1a4.8 4.8 0 0 1-.6.5 5.2 5.2 0 0 1-2.7 1v1.4A4.5 4.5 0 0 0 19 13h.1a4.2 4.2 0 0 0 .8-1.2l.3-.9v-.3a4 4 0 0 1-.2.2l-.4.5z"/>',
|
|
161
165
|
};
|
|
162
166
|
|
|
163
167
|
export const Icons = {
|
package/integrations/asides.ts
CHANGED
|
@@ -107,10 +107,10 @@ function transformUnhandledDirective(
|
|
|
107
107
|
* ```astro
|
|
108
108
|
* <aside class="starlight-aside starlight-aside--tip" aria-label="Did you know?">
|
|
109
109
|
* <p class="starlight-aside__title" aria-hidden="true">Did you know?</p>
|
|
110
|
-
* <
|
|
110
|
+
* <div class="starlight-aside__content">
|
|
111
111
|
* <p>Astro helps you build faster websites with “Islands Architecture”.</p>
|
|
112
|
-
* </
|
|
113
|
-
* </
|
|
112
|
+
* </div>
|
|
113
|
+
* </aside>
|
|
114
114
|
* ```
|
|
115
115
|
*/
|
|
116
116
|
function remarkAsides(options: AsidesOptions): Plugin<[], Root> {
|
|
@@ -204,7 +204,7 @@ function remarkAsides(options: AsidesOptions): Plugin<[], Root> {
|
|
|
204
204
|
),
|
|
205
205
|
...titleNode,
|
|
206
206
|
]),
|
|
207
|
-
h('
|
|
207
|
+
h('div', { class: 'starlight-aside__content' }, node.children),
|
|
208
208
|
]
|
|
209
209
|
);
|
|
210
210
|
|
|
@@ -8,6 +8,7 @@ import type { AstroIntegration } from 'astro';
|
|
|
8
8
|
import type { StarlightConfig } from '../../types';
|
|
9
9
|
import type { createTranslationSystemFromFs } from '../../utils/translations-fs';
|
|
10
10
|
import { pathToLocale } from '../shared/pathToLocale';
|
|
11
|
+
import { slugToLocale } from '../shared/slugToLocale';
|
|
11
12
|
import {
|
|
12
13
|
applyStarlightUiThemeColors,
|
|
13
14
|
preprocessThemes,
|
|
@@ -152,7 +153,10 @@ export function getStarlightEcConfigPreprocessor({
|
|
|
152
153
|
},
|
|
153
154
|
...otherStyleOverrides,
|
|
154
155
|
},
|
|
155
|
-
getBlockLocale: ({ file }) =>
|
|
156
|
+
getBlockLocale: ({ file }) =>
|
|
157
|
+
file.url
|
|
158
|
+
? slugToLocale(file.url.pathname.slice(1), starlightConfig)
|
|
159
|
+
: pathToLocale(file.path, { starlightConfig, astroConfig }),
|
|
156
160
|
plugins,
|
|
157
161
|
...rest,
|
|
158
162
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@astrojs/starlight",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.29.1",
|
|
4
4
|
"description": "Build beautiful, high-performance documentation websites with Astro",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"docs",
|
|
@@ -47,6 +47,10 @@
|
|
|
47
47
|
"types": "./components/MarkdownContent.astro.tsx",
|
|
48
48
|
"import": "./components/MarkdownContent.astro"
|
|
49
49
|
},
|
|
50
|
+
"./components/SidebarPersister.astro": {
|
|
51
|
+
"types": "./components/SidebarPersister.astro.tsx",
|
|
52
|
+
"import": "./components/SidebarPersister.astro"
|
|
53
|
+
},
|
|
50
54
|
"./components/SidebarSublist.astro": {
|
|
51
55
|
"types": "./components/SidebarSublist.astro.tsx",
|
|
52
56
|
"import": "./components/SidebarSublist.astro"
|
|
@@ -170,14 +174,14 @@
|
|
|
170
174
|
"astro": "^4.14.0"
|
|
171
175
|
},
|
|
172
176
|
"devDependencies": {
|
|
173
|
-
"@astrojs/markdown-remark": "^5.
|
|
177
|
+
"@astrojs/markdown-remark": "^5.3.0",
|
|
174
178
|
"@playwright/test": "^1.45.0",
|
|
175
179
|
"@types/js-yaml": "^4.0.9",
|
|
176
180
|
"@types/node": "^18.16.19",
|
|
177
181
|
"@vitest/coverage-v8": "^1.6.0",
|
|
178
|
-
"astro": "^4.
|
|
179
|
-
"
|
|
180
|
-
"
|
|
182
|
+
"astro": "^4.16.10",
|
|
183
|
+
"linkedom": "^0.18.4",
|
|
184
|
+
"vitest": "^1.6.0"
|
|
181
185
|
},
|
|
182
186
|
"dependencies": {
|
|
183
187
|
"@astrojs/mdx": "^3.1.3",
|
|
@@ -185,7 +189,7 @@
|
|
|
185
189
|
"@pagefind/default-ui": "^1.0.3",
|
|
186
190
|
"@types/hast": "^3.0.4",
|
|
187
191
|
"@types/mdast": "^4.0.4",
|
|
188
|
-
"astro-expressive-code": "^0.
|
|
192
|
+
"astro-expressive-code": "^0.38.3",
|
|
189
193
|
"bcp-47": "^2.1.0",
|
|
190
194
|
"hast-util-from-html": "^2.0.1",
|
|
191
195
|
"hast-util-select": "^6.0.2",
|
package/schemas/social.ts
CHANGED
|
@@ -35,6 +35,8 @@ export const socialLinks = [
|
|
|
35
35
|
'zulip',
|
|
36
36
|
'pinterest',
|
|
37
37
|
'tiktok',
|
|
38
|
+
'nostr',
|
|
39
|
+
'backstage',
|
|
38
40
|
] as const;
|
|
39
41
|
|
|
40
42
|
export const SocialLinksSchema = () =>
|
|
@@ -85,6 +87,8 @@ export const SocialLinksSchema = () =>
|
|
|
85
87
|
zulip: 'Zulip',
|
|
86
88
|
pinterest: 'Pinterest',
|
|
87
89
|
tiktok: 'TikTok',
|
|
90
|
+
nostr: 'Nostr',
|
|
91
|
+
backstage: 'Backstage',
|
|
88
92
|
}[key];
|
|
89
93
|
labelledLinks[key] = { label, url };
|
|
90
94
|
}
|
|
@@ -29,7 +29,7 @@ if (!title) {
|
|
|
29
29
|
<p class="starlight-aside__title" aria-hidden="true">
|
|
30
30
|
<Icon name={icons[type]} class="starlight-aside__icon" />{title}
|
|
31
31
|
</p>
|
|
32
|
-
<
|
|
32
|
+
<div class="starlight-aside__content">
|
|
33
33
|
<slot />
|
|
34
|
-
</
|
|
34
|
+
</div>
|
|
35
35
|
</aside>
|
|
@@ -47,7 +47,7 @@ const getIDs = () => {
|
|
|
47
47
|
|
|
48
48
|
/**
|
|
49
49
|
* Rehype processor to extract tab panel data and turn each
|
|
50
|
-
* `<starlight-tab-item>` into a `<
|
|
50
|
+
* `<starlight-tab-item>` into a `<div>` with the necessary
|
|
51
51
|
* attributes.
|
|
52
52
|
*/
|
|
53
53
|
const tabsProcessor = rehype()
|
|
@@ -73,8 +73,8 @@ const tabsProcessor = rehype()
|
|
|
73
73
|
// Remove `<TabItem>` props
|
|
74
74
|
delete node.properties.dataLabel;
|
|
75
75
|
delete node.properties.dataIcon;
|
|
76
|
-
// Turn into `<
|
|
77
|
-
node.tagName = '
|
|
76
|
+
// Turn into `<div>` with required attributes
|
|
77
|
+
node.tagName = 'div';
|
|
78
78
|
node.properties.id = ids.panelId;
|
|
79
79
|
node.properties['aria-labelledby'] = ids.tabId;
|
|
80
80
|
node.properties.role = 'tabpanel';
|
|
@@ -121,7 +121,11 @@ function buildResources<T extends Record<string, string | undefined>>(
|
|
|
121
121
|
return { [I18nextNamespace]: dictionary as BuiltInStrings & T };
|
|
122
122
|
}
|
|
123
123
|
|
|
124
|
-
|
|
124
|
+
// `keyof BuiltInStrings` and `UserI18nKeys` may contain some identical keys, e.g. the built-in UI
|
|
125
|
+
// strings. We let TypeScript merge them into a single union type so that plugins with a TypeScript
|
|
126
|
+
// configuration preventing `UserI18nKeys` to be properly inferred can still get auto-completion
|
|
127
|
+
// for built-in UI strings.
|
|
128
|
+
export type I18nKeys = keyof BuiltInStrings | UserI18nKeys | keyof StarlightApp.I18n;
|
|
125
129
|
|
|
126
130
|
export type I18nT = TFunction<'starlight', undefined> & {
|
|
127
131
|
all: () => UserI18nSchema;
|
package/utils/i18n.ts
CHANGED
|
@@ -79,7 +79,7 @@ function getAstroI18nConfig(config: StarlightConfig): NonNullable<AstroConfig['i
|
|
|
79
79
|
? Object.entries(config.locales).map(([locale, localeConfig]) => {
|
|
80
80
|
return {
|
|
81
81
|
codes: [localeConfig?.lang ?? locale],
|
|
82
|
-
path: locale === 'root' ? localeConfig?.lang ?? BuiltInDefaultLocale.lang : locale,
|
|
82
|
+
path: locale === 'root' ? (localeConfig?.lang ?? BuiltInDefaultLocale.lang) : locale,
|
|
83
83
|
};
|
|
84
84
|
})
|
|
85
85
|
: [config.defaultLocale.lang],
|
package/utils/navigation.ts
CHANGED
|
@@ -20,6 +20,8 @@ import type { StarlightConfig } from './user-config';
|
|
|
20
20
|
const DirKey = Symbol('DirKey');
|
|
21
21
|
const SlugKey = Symbol('SlugKey');
|
|
22
22
|
|
|
23
|
+
const neverPathFormatter = createPathFormatter({ trailingSlash: 'never' });
|
|
24
|
+
|
|
23
25
|
export interface Link {
|
|
24
26
|
type: 'link';
|
|
25
27
|
label: string;
|
|
@@ -73,11 +75,11 @@ function configItemToEntry(
|
|
|
73
75
|
routes: Route[]
|
|
74
76
|
): SidebarEntry {
|
|
75
77
|
if ('link' in item) {
|
|
76
|
-
return linkFromSidebarLinkItem(item, locale
|
|
78
|
+
return linkFromSidebarLinkItem(item, locale);
|
|
77
79
|
} else if ('autogenerate' in item) {
|
|
78
80
|
return groupFromAutogenerateConfig(item, locale, routes, currentPathname);
|
|
79
81
|
} else if ('slug' in item) {
|
|
80
|
-
return linkFromInternalSidebarLinkItem(item, locale
|
|
82
|
+
return linkFromInternalSidebarLinkItem(item, locale);
|
|
81
83
|
} else {
|
|
82
84
|
const label = pickLang(item.translations, localeToLang(locale)) || item.label;
|
|
83
85
|
return {
|
|
@@ -121,11 +123,7 @@ function groupFromAutogenerateConfig(
|
|
|
121
123
|
const isAbsolute = (link: string) => /^https?:\/\//.test(link);
|
|
122
124
|
|
|
123
125
|
/** Create a link entry from a manual link item in user config. */
|
|
124
|
-
function linkFromSidebarLinkItem(
|
|
125
|
-
item: SidebarLinkItem,
|
|
126
|
-
locale: string | undefined,
|
|
127
|
-
currentPathname: string
|
|
128
|
-
) {
|
|
126
|
+
function linkFromSidebarLinkItem(item: SidebarLinkItem, locale: string | undefined) {
|
|
129
127
|
let href = item.link;
|
|
130
128
|
if (!isAbsolute(href)) {
|
|
131
129
|
href = ensureLeadingSlash(href);
|
|
@@ -133,26 +131,19 @@ function linkFromSidebarLinkItem(
|
|
|
133
131
|
if (locale) href = '/' + locale + href;
|
|
134
132
|
}
|
|
135
133
|
const label = pickLang(item.translations, localeToLang(locale)) || item.label;
|
|
136
|
-
return makeSidebarLink(
|
|
137
|
-
href,
|
|
138
|
-
label,
|
|
139
|
-
currentPathname,
|
|
140
|
-
getSidebarBadge(item.badge, locale, label),
|
|
141
|
-
item.attrs
|
|
142
|
-
);
|
|
134
|
+
return makeSidebarLink(href, label, getSidebarBadge(item.badge, locale, label), item.attrs);
|
|
143
135
|
}
|
|
144
136
|
|
|
145
137
|
/** Create a link entry from an automatic internal link item in user config. */
|
|
146
138
|
function linkFromInternalSidebarLinkItem(
|
|
147
139
|
item: InternalSidebarLinkItem,
|
|
148
|
-
locale: string | undefined
|
|
149
|
-
currentPathname: string
|
|
140
|
+
locale: string | undefined
|
|
150
141
|
) {
|
|
151
142
|
// Astro passes root `index.[md|mdx]` entries with a slug of `index`
|
|
152
143
|
const slug = item.slug === 'index' ? '' : item.slug;
|
|
153
144
|
const localizedSlug = locale ? (slug ? locale + '/' + slug : locale) : slug;
|
|
154
|
-
const
|
|
155
|
-
if (!
|
|
145
|
+
const route = routes.find((entry) => localizedSlug === entry.slug);
|
|
146
|
+
if (!route) {
|
|
156
147
|
const hasExternalSlashes = item.slug.at(0) === '/' || item.slug.at(-1) === '/';
|
|
157
148
|
if (hasExternalSlashes) {
|
|
158
149
|
throw new AstroError(
|
|
@@ -167,52 +158,47 @@ function linkFromInternalSidebarLinkItem(
|
|
|
167
158
|
);
|
|
168
159
|
}
|
|
169
160
|
}
|
|
161
|
+
const frontmatter = route.entry.data;
|
|
170
162
|
const label =
|
|
171
|
-
pickLang(item.translations, localeToLang(locale)) ||
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
);
|
|
163
|
+
pickLang(item.translations, localeToLang(locale)) ||
|
|
164
|
+
item.label ||
|
|
165
|
+
frontmatter.sidebar?.label ||
|
|
166
|
+
frontmatter.title;
|
|
167
|
+
const badge = item.badge ?? frontmatter.sidebar?.badge;
|
|
168
|
+
const attrs = { ...frontmatter.sidebar?.attrs, ...item.attrs };
|
|
169
|
+
return makeSidebarLink(route.slug, label, getSidebarBadge(badge, locale, label), attrs);
|
|
179
170
|
}
|
|
180
171
|
|
|
181
172
|
/** Process sidebar link options to create a link entry. */
|
|
182
173
|
function makeSidebarLink(
|
|
183
174
|
href: string,
|
|
184
175
|
label: string,
|
|
185
|
-
currentPathname: string,
|
|
186
176
|
badge?: Badge,
|
|
187
177
|
attrs?: LinkHTMLAttributes
|
|
188
178
|
): Link {
|
|
189
179
|
if (!isAbsolute(href)) {
|
|
190
180
|
href = formatPath(href);
|
|
191
181
|
}
|
|
192
|
-
|
|
193
|
-
return makeLink({ label, href, isCurrent, badge, attrs });
|
|
182
|
+
return makeLink({ label, href, badge, attrs });
|
|
194
183
|
}
|
|
195
184
|
|
|
196
185
|
/** Create a link entry */
|
|
197
186
|
function makeLink({
|
|
198
|
-
isCurrent = false,
|
|
199
187
|
attrs = {},
|
|
200
188
|
badge = undefined,
|
|
201
189
|
...opts
|
|
202
190
|
}: {
|
|
203
191
|
label: string;
|
|
204
192
|
href: string;
|
|
205
|
-
isCurrent?: boolean;
|
|
206
193
|
badge?: Badge | undefined;
|
|
207
194
|
attrs?: LinkHTMLAttributes | undefined;
|
|
208
195
|
}): Link {
|
|
209
|
-
return { type: 'link', ...opts, badge, isCurrent, attrs };
|
|
196
|
+
return { type: 'link', ...opts, badge, isCurrent: false, attrs };
|
|
210
197
|
}
|
|
211
198
|
|
|
212
199
|
/** Test if two paths are equivalent even if formatted differently. */
|
|
213
200
|
function pathsMatch(pathA: string, pathB: string) {
|
|
214
|
-
|
|
215
|
-
return format(pathA) === format(pathB);
|
|
201
|
+
return neverPathFormatter(pathA) === neverPathFormatter(pathB);
|
|
216
202
|
}
|
|
217
203
|
|
|
218
204
|
/** Get the segments leading to a page. */
|
|
@@ -268,11 +254,10 @@ function treeify(routes: Route[], baseDir: string): Dir {
|
|
|
268
254
|
}
|
|
269
255
|
|
|
270
256
|
/** Create a link entry for a given content collection entry. */
|
|
271
|
-
function linkFromRoute(route: Route
|
|
257
|
+
function linkFromRoute(route: Route): Link {
|
|
272
258
|
return makeSidebarLink(
|
|
273
259
|
slugToPathname(route.slug),
|
|
274
260
|
route.entry.data.sidebar.label || route.entry.data.title,
|
|
275
|
-
currentPathname,
|
|
276
261
|
route.entry.data.sidebar.badge,
|
|
277
262
|
route.entry.data.sidebar.attrs
|
|
278
263
|
);
|
|
@@ -286,7 +271,7 @@ function getOrder(routeOrDir: Route | Dir): number {
|
|
|
286
271
|
return isDir(routeOrDir)
|
|
287
272
|
? Math.min(...Object.values(routeOrDir).flatMap(getOrder))
|
|
288
273
|
: // If no order value is found, set it to the largest number possible.
|
|
289
|
-
routeOrDir.entry.data.sidebar.order ?? Number.MAX_VALUE;
|
|
274
|
+
(routeOrDir.entry.data.sidebar.order ?? Number.MAX_VALUE);
|
|
290
275
|
}
|
|
291
276
|
|
|
292
277
|
/** Sort a directory’s entries by user-specified order or alphabetically if no order specified. */
|
|
@@ -333,7 +318,7 @@ function dirToItem(
|
|
|
333
318
|
): SidebarEntry {
|
|
334
319
|
return isDir(dirOrRoute)
|
|
335
320
|
? groupFromDir(dirOrRoute, fullPath, dirName, currentPathname, locale, collapsed)
|
|
336
|
-
: linkFromRoute(dirOrRoute
|
|
321
|
+
: linkFromRoute(dirOrRoute);
|
|
337
322
|
}
|
|
338
323
|
|
|
339
324
|
/** Create a sidebar entry for a given content directory. */
|
|
@@ -348,9 +333,25 @@ function sidebarFromDir(
|
|
|
348
333
|
);
|
|
349
334
|
}
|
|
350
335
|
|
|
336
|
+
/**
|
|
337
|
+
* Intermediate sidebar represents sidebar entries generated from the user config for a specific
|
|
338
|
+
* locale and do not contain any information about the current page.
|
|
339
|
+
* These representations are cached per locale to avoid regenerating them for each page.
|
|
340
|
+
* When generating the final sidebar for a page, the intermediate sidebar is cloned and the current
|
|
341
|
+
* page is marked as such.
|
|
342
|
+
*
|
|
343
|
+
* @see getSidebarFromIntermediateSidebar
|
|
344
|
+
*/
|
|
345
|
+
const intermediateSidebars = new Map<string | undefined, SidebarEntry[]>();
|
|
346
|
+
|
|
351
347
|
/** Get the sidebar for the current page using the global config. */
|
|
352
348
|
export function getSidebar(pathname: string, locale: string | undefined): SidebarEntry[] {
|
|
353
|
-
|
|
349
|
+
let intermediateSidebar = intermediateSidebars.get(locale);
|
|
350
|
+
if (!intermediateSidebar) {
|
|
351
|
+
intermediateSidebar = getIntermediateSidebarFromConfig(config.sidebar, pathname, locale);
|
|
352
|
+
intermediateSidebars.set(locale, intermediateSidebar);
|
|
353
|
+
}
|
|
354
|
+
return getSidebarFromIntermediateSidebar(intermediateSidebar, pathname);
|
|
354
355
|
}
|
|
355
356
|
|
|
356
357
|
/** Get the sidebar for the current page using the specified sidebar config. */
|
|
@@ -358,6 +359,16 @@ export function getSidebarFromConfig(
|
|
|
358
359
|
sidebarConfig: StarlightConfig['sidebar'],
|
|
359
360
|
pathname: string,
|
|
360
361
|
locale: string | undefined
|
|
362
|
+
): SidebarEntry[] {
|
|
363
|
+
const intermediateSidebar = getIntermediateSidebarFromConfig(sidebarConfig, pathname, locale);
|
|
364
|
+
return getSidebarFromIntermediateSidebar(intermediateSidebar, pathname);
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
/** Get the intermediate sidebar for the current page using the specified sidebar config. */
|
|
368
|
+
function getIntermediateSidebarFromConfig(
|
|
369
|
+
sidebarConfig: StarlightConfig['sidebar'],
|
|
370
|
+
pathname: string,
|
|
371
|
+
locale: string | undefined
|
|
361
372
|
): SidebarEntry[] {
|
|
362
373
|
const routes = getLocaleRoutes(locale);
|
|
363
374
|
if (sidebarConfig) {
|
|
@@ -368,6 +379,34 @@ export function getSidebarFromConfig(
|
|
|
368
379
|
}
|
|
369
380
|
}
|
|
370
381
|
|
|
382
|
+
/** Transform an intermediate sidebar into a sidebar for the current page. */
|
|
383
|
+
function getSidebarFromIntermediateSidebar(
|
|
384
|
+
intermediateSidebar: SidebarEntry[],
|
|
385
|
+
pathname: string
|
|
386
|
+
): SidebarEntry[] {
|
|
387
|
+
const sidebar = structuredClone(intermediateSidebar);
|
|
388
|
+
setIntermediateSidebarCurrentEntry(sidebar, pathname);
|
|
389
|
+
return sidebar;
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
/** Marks the current page as such in an intermediate sidebar. */
|
|
393
|
+
function setIntermediateSidebarCurrentEntry(
|
|
394
|
+
intermediateSidebar: SidebarEntry[],
|
|
395
|
+
pathname: string
|
|
396
|
+
): boolean {
|
|
397
|
+
for (const entry of intermediateSidebar) {
|
|
398
|
+
if (entry.type === 'link' && pathsMatch(encodeURI(entry.href), pathname)) {
|
|
399
|
+
entry.isCurrent = true;
|
|
400
|
+
return true;
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
if (entry.type === 'group' && setIntermediateSidebarCurrentEntry(entry.entries, pathname)) {
|
|
404
|
+
return true;
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
return false;
|
|
408
|
+
}
|
|
409
|
+
|
|
371
410
|
/** Generates a deterministic string based on the content of the passed sidebar. */
|
|
372
411
|
export function getSidebarHash(sidebar: SidebarEntry[]): string {
|
|
373
412
|
let hash = 0;
|
package/utils/starlight-page.ts
CHANGED
|
@@ -12,7 +12,7 @@ import {
|
|
|
12
12
|
} from './route-data';
|
|
13
13
|
import type { StarlightDocsEntry } from './routing';
|
|
14
14
|
import { slugToLocaleData, urlToSlug } from './slugs';
|
|
15
|
-
import { getPrevNextLinks, getSidebarFromConfig } from './navigation';
|
|
15
|
+
import { getPrevNextLinks, getSidebar, getSidebarFromConfig } from './navigation';
|
|
16
16
|
import { docsSchema } from '../schema';
|
|
17
17
|
import type { Prettify, RemoveIndexSignature } from './types';
|
|
18
18
|
import { DeprecatedLabelsPropProxy } from './i18n';
|
|
@@ -115,11 +115,9 @@ export async function generateStarlightPageRouteData({
|
|
|
115
115
|
const pageFrontmatter = await getStarlightPageFrontmatter(frontmatter);
|
|
116
116
|
const id = `${stripLeadingAndTrailingSlashes(slug)}.md`;
|
|
117
117
|
const localeData = slugToLocaleData(slug);
|
|
118
|
-
const sidebar =
|
|
119
|
-
|
|
120
|
-
url.pathname,
|
|
121
|
-
localeData.locale
|
|
122
|
-
);
|
|
118
|
+
const sidebar = props.sidebar
|
|
119
|
+
? getSidebarFromConfig(validateSidebarProp(props.sidebar), url.pathname, localeData.locale)
|
|
120
|
+
: getSidebar(url.pathname, localeData.locale);
|
|
123
121
|
const headings = props.headings ?? [];
|
|
124
122
|
const pageDocsEntry: StarlightPageDocsEntry = {
|
|
125
123
|
id,
|
package/utils/translations.ts
CHANGED
|
@@ -5,8 +5,13 @@ import type { i18nSchemaOutput } from '../schemas/i18n';
|
|
|
5
5
|
import { createTranslationSystem } from './createTranslationSystem';
|
|
6
6
|
import type { RemoveIndexSignature } from './types';
|
|
7
7
|
|
|
8
|
+
// @ts-ignore - This may be a type error in projects without an i18n collection and running
|
|
9
|
+
// `tsc --noEmit` in their project. Note that it is not possible to inline this type in
|
|
10
|
+
// `UserI18nSchema` because this would break types for users having multiple data collections.
|
|
11
|
+
type i18nCollection = CollectionEntry<'i18n'>;
|
|
12
|
+
|
|
8
13
|
export type UserI18nSchema = 'i18n' extends DataCollectionKey
|
|
9
|
-
?
|
|
14
|
+
? i18nCollection extends { data: infer T }
|
|
10
15
|
? i18nSchemaOutput & T
|
|
11
16
|
: i18nSchemaOutput
|
|
12
17
|
: i18nSchemaOutput;
|