@astrojs/starlight 0.29.3 → 0.30.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 +69 -0
- package/components/Page.astro +6 -8
- package/components/Search.astro +4 -4
- package/index.ts +0 -3
- package/integrations/shared/pathToLocale.ts +4 -4
- package/integrations/virtual-user-config.ts +21 -4
- package/loaders.ts +40 -0
- package/package.json +12 -7
- package/routes/common.astro +2 -1
- package/routes/static/404.astro +12 -10
- package/style/shiki.css +2 -2
- package/translations/ca.json +42 -0
- package/translations/es.json +11 -1
- package/translations/index.ts +2 -0
- package/utils/collection.ts +45 -0
- package/utils/git.ts +6 -4
- package/utils/navigation.ts +21 -7
- package/utils/plugins.ts +0 -9
- package/utils/route-data.ts +3 -7
- package/utils/routing.ts +36 -8
- package/utils/slugs.ts +2 -1
- package/utils/starlight-page.ts +6 -3
- package/virtual-internal.d.ts +1 -0
- package/components/EmptyMarkdown.md +0 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,74 @@
|
|
|
1
1
|
# @astrojs/starlight
|
|
2
2
|
|
|
3
|
+
## 0.30.1
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- [#2688](https://github.com/withastro/starlight/pull/2688) [`5c6996c`](https://github.com/withastro/starlight/commit/5c6996cd248e9da735a14e7fcaf638b51f2796bc) Thanks [@HiDeoo](https://github.com/HiDeoo)! - Fixes an issue with autogenerated sidebars when using Starlight with Astro's new Content Layer API where group names would be sluggified.
|
|
8
|
+
|
|
9
|
+
## 0.30.0
|
|
10
|
+
|
|
11
|
+
### Minor Changes
|
|
12
|
+
|
|
13
|
+
- [#2612](https://github.com/withastro/starlight/pull/2612) [`8d5a4e8`](https://github.com/withastro/starlight/commit/8d5a4e8000d9e3a4bb9ca8178767cf3d8bc48773) Thanks [@HiDeoo](https://github.com/HiDeoo)! - Adds support for Astro v5, drops support for Astro v4.
|
|
14
|
+
|
|
15
|
+
#### Upgrade Astro and dependencies
|
|
16
|
+
|
|
17
|
+
⚠️ **BREAKING CHANGE:** Astro v4 is no longer supported. Make sure you [update Astro](https://docs.astro.build/en/guides/upgrade-to/v5/) and any other official integrations at the same time as updating Starlight:
|
|
18
|
+
|
|
19
|
+
```sh
|
|
20
|
+
npx @astrojs/upgrade
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
_Community Starlight plugins and Astro integrations may also need to be manually updated to work with Astro v5. If you encounter any issues, please reach out to the plugin or integration author to see if it is a known issue or if an updated version is being worked on._
|
|
24
|
+
|
|
25
|
+
#### Update your collections
|
|
26
|
+
|
|
27
|
+
⚠️ **BREAKING CHANGE:** Starlight's internal [content collections](https://docs.astro.build/en/guides/content-collections/), which organize, validate, and render your content, have been updated to use Astro's new Content Layer API and require configuration changes in your project.
|
|
28
|
+
|
|
29
|
+
1. **Move the content config file.** This file no longer lives within the `src/content/config.ts` folder and should now exist at `src/content.config.ts`.
|
|
30
|
+
1. **Edit the collection definition(s).** To update the `docs` collection, a `loader` is now required:
|
|
31
|
+
|
|
32
|
+
```diff
|
|
33
|
+
// src/content.config.ts
|
|
34
|
+
import { defineCollection } from "astro:content";
|
|
35
|
+
+import { docsLoader } from "@astrojs/starlight/loaders";
|
|
36
|
+
import { docsSchema } from "@astrojs/starlight/schema";
|
|
37
|
+
|
|
38
|
+
export const collections = {
|
|
39
|
+
- docs: defineCollection({ schema: docsSchema() }),
|
|
40
|
+
+ docs: defineCollection({ loader: docsLoader(), schema: docsSchema() }),
|
|
41
|
+
};
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
If you are using the [`i18n` collection](https://starlight.astro.build/guides/i18n/#translate-starlights-ui) to provide translations for additional languages you support or override our default labels, you will need to update the collection definition in a similar way and remove the collection `type` which is no longer available:
|
|
45
|
+
|
|
46
|
+
```diff
|
|
47
|
+
// src/content.config.ts
|
|
48
|
+
import { defineCollection } from "astro:content";
|
|
49
|
+
+import { docsLoader, i18nLoader } from "@astrojs/starlight/loaders";
|
|
50
|
+
import { docsSchema, i18nSchema } from "@astrojs/starlight/schema";
|
|
51
|
+
|
|
52
|
+
export const collections = {
|
|
53
|
+
- docs: defineCollection({ schema: docsSchema() }),
|
|
54
|
+
+ docs: defineCollection({ loader: docsLoader(), schema: docsSchema() }),
|
|
55
|
+
- i18n: defineCollection({ type: 'data', schema: i18nSchema() }),
|
|
56
|
+
+ i18n: defineCollection({ loader: i18nLoader(), schema: i18nSchema() }),
|
|
57
|
+
};
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
1. **Update other collections.** To update any other collections you may have, follow the [“Updating existing collections”](https://docs.astro.build/en/guides/upgrade-to/v5/#updating-existing-collections) section in the Astro 5 upgrade guide.
|
|
61
|
+
|
|
62
|
+
If you are unable to make any changes to your collections at this time, including Starlight's default `docs` and `i18n` collections, you can enable the [`legacy.collections` flag](https://docs.astro.build/en/reference/legacy-flags/) to upgrade to v5 without updating your collections. This legacy flag exists to provide temporary backwards compatibility, and will allow you to keep your collections in their current state until the legacy flag is no longer supported.
|
|
63
|
+
|
|
64
|
+
### Patch Changes
|
|
65
|
+
|
|
66
|
+
- [#2669](https://github.com/withastro/starlight/pull/2669) [`310df7d`](https://github.com/withastro/starlight/commit/310df7d6b01f5c4a56540bdba9243fb60dace323) Thanks [@aaronperezaguilera](https://github.com/aaronperezaguilera)! - Adds Catalan UI translations
|
|
67
|
+
|
|
68
|
+
- [#2664](https://github.com/withastro/starlight/pull/2664) [`62ff007`](https://github.com/withastro/starlight/commit/62ff0074d9a3f82e46f5c62db85c04d87ff5e931) Thanks [@HiDeoo](https://github.com/HiDeoo)! - Publishes provenance containing verifiable data to link a package back to its source repository and the specific build instructions used to publish it.
|
|
69
|
+
|
|
70
|
+
- [#2670](https://github.com/withastro/starlight/pull/2670) [`0223b42`](https://github.com/withastro/starlight/commit/0223b425249f8d1fa468e367c632467276c9c208) Thanks [@aaronperezaguilera](https://github.com/aaronperezaguilera)! - Adds Spanish UI translations for the Pagefind search modal
|
|
71
|
+
|
|
3
72
|
## 0.29.3
|
|
4
73
|
|
|
5
74
|
### Patch Changes
|
package/components/Page.astro
CHANGED
|
@@ -35,16 +35,14 @@ const pagefindEnabled =
|
|
|
35
35
|
Astro.props.entry.slug !== '404' &&
|
|
36
36
|
!Astro.props.entry.slug.endsWith('/404') &&
|
|
37
37
|
Astro.props.entry.data.pagefind !== false;
|
|
38
|
+
|
|
39
|
+
const dataAttributes: DOMStringMap = { 'data-theme': 'dark' };
|
|
40
|
+
if (Boolean(Astro.props.toc)) dataAttributes['data-has-toc'] = '';
|
|
41
|
+
if (Astro.props.hasSidebar) dataAttributes['data-has-sidebar'] = '';
|
|
42
|
+
if (Boolean(Astro.props.entry.data.hero)) dataAttributes['data-has-hero'] = '';
|
|
38
43
|
---
|
|
39
44
|
|
|
40
|
-
<html
|
|
41
|
-
lang={Astro.props.lang}
|
|
42
|
-
dir={Astro.props.dir}
|
|
43
|
-
data-has-toc={Boolean(Astro.props.toc)}
|
|
44
|
-
data-has-sidebar={Astro.props.hasSidebar}
|
|
45
|
-
data-has-hero={Boolean(Astro.props.entry.data.hero)}
|
|
46
|
-
data-theme="dark"
|
|
47
|
-
>
|
|
45
|
+
<html lang={Astro.props.lang} dir={Astro.props.dir} {...dataAttributes}>
|
|
48
46
|
<head>
|
|
49
47
|
<Head {...Astro.props} />
|
|
50
48
|
<style>
|
package/components/Search.astro
CHANGED
|
@@ -12,12 +12,12 @@ const pagefindTranslations = {
|
|
|
12
12
|
.map(([key, value]) => [key.replace('pagefind.', ''), value])
|
|
13
13
|
),
|
|
14
14
|
};
|
|
15
|
+
|
|
16
|
+
const dataAttributes: DOMStringMap = { 'data-translations': JSON.stringify(pagefindTranslations) };
|
|
17
|
+
if (project.trailingSlash === 'never') dataAttributes['data-strip-trailing-slash'] = '';
|
|
15
18
|
---
|
|
16
19
|
|
|
17
|
-
<site-search
|
|
18
|
-
data-translations={JSON.stringify(pagefindTranslations)}
|
|
19
|
-
data-strip-trailing-slash={project.trailingSlash === 'never'}
|
|
20
|
-
>
|
|
20
|
+
<site-search class={Astro.props.class} {...dataAttributes}>
|
|
21
21
|
<button
|
|
22
22
|
data-open-modal
|
|
23
23
|
disabled
|
package/index.ts
CHANGED
|
@@ -137,9 +137,6 @@ export default function StarlightIntegration(
|
|
|
137
137
|
scopedStyleStrategy: 'where',
|
|
138
138
|
// If not already configured, default to prefetching all links on hover.
|
|
139
139
|
prefetch: config.prefetch ?? { prefetchAll: true },
|
|
140
|
-
experimental: {
|
|
141
|
-
globalRoutePriority: true,
|
|
142
|
-
},
|
|
143
140
|
i18n: astroI18nConfig,
|
|
144
141
|
});
|
|
145
142
|
},
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { AstroConfig } from 'astro';
|
|
2
2
|
import type { StarlightConfig } from '../../types';
|
|
3
|
+
import { getCollectionPath } from '../../utils/collection';
|
|
3
4
|
import { slugToLocale } from './slugToLocale';
|
|
4
5
|
|
|
5
6
|
/** Get current locale from the full file path. */
|
|
@@ -13,15 +14,14 @@ export function pathToLocale(
|
|
|
13
14
|
astroConfig: { root: AstroConfig['root']; srcDir: AstroConfig['srcDir'] };
|
|
14
15
|
}
|
|
15
16
|
): string | undefined {
|
|
16
|
-
const
|
|
17
|
-
const docsDir = new URL('content/docs/', srcDir);
|
|
17
|
+
const docsPath = getCollectionPath('docs', astroConfig.srcDir);
|
|
18
18
|
// Format path to unix style path.
|
|
19
19
|
path = path?.replace(/\\/g, '/');
|
|
20
20
|
// Ensure that the page path starts with a slash if the docs directory also does,
|
|
21
21
|
// which makes stripping the docs path in the next step work on Windows, too.
|
|
22
|
-
if (path && !path.startsWith('/') &&
|
|
22
|
+
if (path && !path.startsWith('/') && docsPath.startsWith('/')) path = '/' + path;
|
|
23
23
|
// Strip docs path leaving only content collection file ID.
|
|
24
24
|
// Example: /Users/houston/repo/src/content/docs/en/guide.md => en/guide.md
|
|
25
|
-
const slug = path?.replace(
|
|
25
|
+
const slug = path?.replace(docsPath, '');
|
|
26
26
|
return slugToLocale(slug, starlightConfig);
|
|
27
27
|
}
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import type { AstroConfig, HookParameters, ViteUserConfig } from 'astro';
|
|
2
|
+
import { existsSync } from 'node:fs';
|
|
2
3
|
import { resolve } from 'node:path';
|
|
3
4
|
import { fileURLToPath } from 'node:url';
|
|
5
|
+
import { resolveCollectionPath } from '../utils/collection';
|
|
4
6
|
import type { StarlightConfig } from '../utils/user-config';
|
|
5
7
|
import { getAllNewestCommitDate } from '../utils/git';
|
|
6
8
|
import type { PluginTranslations } from '../utils/plugins';
|
|
@@ -15,11 +17,13 @@ export function vitePluginStarlightUserConfig(
|
|
|
15
17
|
opts: StarlightConfig,
|
|
16
18
|
{
|
|
17
19
|
build,
|
|
20
|
+
legacy,
|
|
18
21
|
root,
|
|
19
22
|
srcDir,
|
|
20
23
|
trailingSlash,
|
|
21
24
|
}: Pick<AstroConfig, 'root' | 'srcDir' | 'trailingSlash'> & {
|
|
22
25
|
build: Pick<AstroConfig['build'], 'format'>;
|
|
26
|
+
legacy: Pick<AstroConfig['legacy'], 'collections'>;
|
|
23
27
|
},
|
|
24
28
|
pluginTranslations: PluginTranslations
|
|
25
29
|
): NonNullable<ViteUserConfig['plugins']>[number] {
|
|
@@ -42,7 +46,19 @@ export function vitePluginStarlightUserConfig(
|
|
|
42
46
|
const resolveLocalPath = (path: string) =>
|
|
43
47
|
JSON.stringify(fileURLToPath(new URL(path, import.meta.url)));
|
|
44
48
|
|
|
45
|
-
const
|
|
49
|
+
const rootPath = fileURLToPath(root);
|
|
50
|
+
const docsPath = resolveCollectionPath('docs', srcDir);
|
|
51
|
+
|
|
52
|
+
let collectionConfigImportPath = resolve(
|
|
53
|
+
fileURLToPath(srcDir),
|
|
54
|
+
legacy.collections ? './content/config.ts' : './content.config.ts'
|
|
55
|
+
);
|
|
56
|
+
// If not using legacy collections and the config doesn't exist, fallback to the legacy location.
|
|
57
|
+
// We need to test this ahead of time as we cannot `try/catch` a failing import in the virtual
|
|
58
|
+
// module as this would fail at build time when Rollup tries to resolve a non-existent path.
|
|
59
|
+
if (!legacy.collections && !existsSync(collectionConfigImportPath)) {
|
|
60
|
+
collectionConfigImportPath = resolve(fileURLToPath(srcDir), './content/config.ts');
|
|
61
|
+
}
|
|
46
62
|
|
|
47
63
|
const virtualComponentModules = Object.fromEntries(
|
|
48
64
|
Object.entries(opts.components).map(([name, path]) => [
|
|
@@ -56,6 +72,7 @@ export function vitePluginStarlightUserConfig(
|
|
|
56
72
|
'virtual:starlight/user-config': `export default ${JSON.stringify(opts)}`,
|
|
57
73
|
'virtual:starlight/project-context': `export default ${JSON.stringify({
|
|
58
74
|
build: { format: build.format },
|
|
75
|
+
legacyCollections: legacy.collections,
|
|
59
76
|
root,
|
|
60
77
|
srcDir,
|
|
61
78
|
trailingSlash,
|
|
@@ -63,9 +80,9 @@ export function vitePluginStarlightUserConfig(
|
|
|
63
80
|
'virtual:starlight/git-info':
|
|
64
81
|
(command !== 'build'
|
|
65
82
|
? `import { makeAPI } from ${resolveLocalPath('../utils/git.ts')};` +
|
|
66
|
-
`const api = makeAPI(${JSON.stringify(
|
|
83
|
+
`const api = makeAPI(${JSON.stringify(rootPath)});`
|
|
67
84
|
: `import { makeAPI } from ${resolveLocalPath('../utils/gitInlined.ts')};` +
|
|
68
|
-
`const api = makeAPI(${JSON.stringify(getAllNewestCommitDate(docsPath))});`) +
|
|
85
|
+
`const api = makeAPI(${JSON.stringify(getAllNewestCommitDate(rootPath, docsPath))});`) +
|
|
69
86
|
'export const getNewestCommitDate = api.getNewestCommitDate;',
|
|
70
87
|
'virtual:starlight/user-css': opts.customCss.map((id) => `import ${resolveId(id)};`).join(''),
|
|
71
88
|
'virtual:starlight/user-images': opts.logo
|
|
@@ -79,7 +96,7 @@ export function vitePluginStarlightUserConfig(
|
|
|
79
96
|
: 'export const logos = {};',
|
|
80
97
|
'virtual:starlight/collection-config': `let userCollections;
|
|
81
98
|
try {
|
|
82
|
-
userCollections = (await import(${
|
|
99
|
+
userCollections = (await import(${JSON.stringify(collectionConfigImportPath)})).collections;
|
|
83
100
|
} catch {}
|
|
84
101
|
export const collections = userCollections;`,
|
|
85
102
|
'virtual:starlight/plugin-translations': `export default ${JSON.stringify(pluginTranslations)}`,
|
package/loaders.ts
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { glob, type Loader, type LoaderContext } from 'astro/loaders';
|
|
2
|
+
import { getCollectionPathFromRoot, type StarlightCollection } from './utils/collection';
|
|
3
|
+
|
|
4
|
+
// https://github.com/withastro/astro/blob/main/packages/astro/src/core/constants.ts#L87
|
|
5
|
+
// https://github.com/withastro/astro/blob/main/packages/integrations/mdx/src/index.ts#L59
|
|
6
|
+
const docsExtensions = ['markdown', 'mdown', 'mkdn', 'mkd', 'mdwn', 'md', 'mdx'];
|
|
7
|
+
const i18nExtensions = ['json', 'yml', 'yaml'];
|
|
8
|
+
|
|
9
|
+
export function docsLoader(): Loader {
|
|
10
|
+
return {
|
|
11
|
+
name: 'starlight-docs-loader',
|
|
12
|
+
load: createGlobLoadFn('docs'),
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export function i18nLoader(): Loader {
|
|
17
|
+
return {
|
|
18
|
+
name: 'starlight-i18n-loader',
|
|
19
|
+
load: createGlobLoadFn('i18n'),
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function createGlobLoadFn(collection: StarlightCollection): Loader['load'] {
|
|
24
|
+
return (context: LoaderContext) => {
|
|
25
|
+
const extensions = collection === 'docs' ? docsExtensions : i18nExtensions;
|
|
26
|
+
|
|
27
|
+
if (
|
|
28
|
+
collection === 'docs' &&
|
|
29
|
+
context.config.integrations.find(({ name }) => name === '@astrojs/markdoc')
|
|
30
|
+
) {
|
|
31
|
+
// https://github.com/withastro/astro/blob/main/packages/integrations/markdoc/src/content-entry-type.ts#L28
|
|
32
|
+
extensions.push('mdoc');
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
return glob({
|
|
36
|
+
base: getCollectionPathFromRoot(collection, context.config),
|
|
37
|
+
pattern: `**/[^_]*.{${extensions.join(',')}}`,
|
|
38
|
+
}).load(context);
|
|
39
|
+
};
|
|
40
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@astrojs/starlight",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.30.1",
|
|
4
4
|
"description": "Build beautiful, high-performance documentation websites with Astro",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"docs",
|
|
@@ -158,6 +158,7 @@
|
|
|
158
158
|
"./internal": "./internal.ts",
|
|
159
159
|
"./props": "./props.ts",
|
|
160
160
|
"./schema": "./schema.ts",
|
|
161
|
+
"./loaders": "./loaders.ts",
|
|
161
162
|
"./types": "./types.ts",
|
|
162
163
|
"./expressive-code": {
|
|
163
164
|
"types": "./expressive-code.d.ts",
|
|
@@ -171,19 +172,19 @@
|
|
|
171
172
|
"./style/markdown.css": "./style/markdown.css"
|
|
172
173
|
},
|
|
173
174
|
"peerDependencies": {
|
|
174
|
-
"astro": "^
|
|
175
|
+
"astro": "^5.0.0"
|
|
175
176
|
},
|
|
176
177
|
"devDependencies": {
|
|
177
|
-
"@astrojs/markdown-remark": "^
|
|
178
|
+
"@astrojs/markdown-remark": "^6.0.0",
|
|
178
179
|
"@playwright/test": "^1.45.0",
|
|
179
180
|
"@types/node": "^18.16.19",
|
|
180
|
-
"@vitest/coverage-v8": "
|
|
181
|
-
"astro": "^
|
|
181
|
+
"@vitest/coverage-v8": "2.1.6",
|
|
182
|
+
"astro": "^5.0.2",
|
|
182
183
|
"linkedom": "^0.18.4",
|
|
183
|
-
"vitest": "
|
|
184
|
+
"vitest": "2.1.6"
|
|
184
185
|
},
|
|
185
186
|
"dependencies": {
|
|
186
|
-
"@astrojs/mdx": "^
|
|
187
|
+
"@astrojs/mdx": "^4.0.1",
|
|
187
188
|
"@astrojs/sitemap": "^3.1.6",
|
|
188
189
|
"@pagefind/default-ui": "^1.0.3",
|
|
189
190
|
"@types/hast": "^3.0.4",
|
|
@@ -208,8 +209,12 @@
|
|
|
208
209
|
"unist-util-visit": "^5.0.0",
|
|
209
210
|
"vfile": "^6.0.2"
|
|
210
211
|
},
|
|
212
|
+
"publishConfig": {
|
|
213
|
+
"provenance": true
|
|
214
|
+
},
|
|
211
215
|
"scripts": {
|
|
212
216
|
"test": "vitest",
|
|
217
|
+
"test:legacy": "LEGACY_COLLECTIONS=true vitest",
|
|
213
218
|
"test:coverage": "vitest run --coverage",
|
|
214
219
|
"test:e2e": "playwright install --with-deps chromium && playwright test"
|
|
215
220
|
}
|
package/routes/common.astro
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
---
|
|
2
|
+
import { render } from 'astro:content';
|
|
2
3
|
import { generateRouteData } from '../utils/route-data';
|
|
3
4
|
import type { Route } from '../utils/routing';
|
|
4
5
|
import Page from '../components/Page.astro';
|
|
@@ -9,7 +10,7 @@ export type Props = {
|
|
|
9
10
|
|
|
10
11
|
const { route } = Astro.props;
|
|
11
12
|
|
|
12
|
-
const { Content, headings } = await route.entry
|
|
13
|
+
const { Content, headings } = await render(route.entry);
|
|
13
14
|
const routeData = generateRouteData({ props: { ...route, headings }, url: Astro.url });
|
|
14
15
|
---
|
|
15
16
|
|
package/routes/static/404.astro
CHANGED
|
@@ -1,8 +1,14 @@
|
|
|
1
1
|
---
|
|
2
2
|
import { getEntry } from 'astro:content';
|
|
3
|
+
import project from 'virtual:starlight/project-context';
|
|
3
4
|
import config from 'virtual:starlight/user-config';
|
|
4
|
-
import
|
|
5
|
-
import
|
|
5
|
+
import { getCollectionPathFromRoot } from '../../utils/collection';
|
|
6
|
+
import {
|
|
7
|
+
normalizeCollectionEntry,
|
|
8
|
+
type Route,
|
|
9
|
+
type StarlightDocsCollectionEntry,
|
|
10
|
+
type StarlightDocsEntry,
|
|
11
|
+
} from '../../utils/routing';
|
|
6
12
|
import { BuiltInDefaultLocale } from '../../utils/i18n';
|
|
7
13
|
import CommonPage from '../common.astro';
|
|
8
14
|
|
|
@@ -17,7 +23,7 @@ const entryMeta = { dir, lang, locale };
|
|
|
17
23
|
|
|
18
24
|
const fallbackEntry: StarlightDocsEntry = {
|
|
19
25
|
slug: '404',
|
|
20
|
-
id: '404
|
|
26
|
+
id: '404',
|
|
21
27
|
body: '',
|
|
22
28
|
collection: 'docs',
|
|
23
29
|
data: {
|
|
@@ -30,15 +36,11 @@ const fallbackEntry: StarlightDocsEntry = {
|
|
|
30
36
|
sidebar: { hidden: false, attrs: {} },
|
|
31
37
|
draft: false,
|
|
32
38
|
},
|
|
33
|
-
|
|
34
|
-
Content: EmptyContent,
|
|
35
|
-
headings: [],
|
|
36
|
-
remarkPluginFrontmatter: {},
|
|
37
|
-
}),
|
|
39
|
+
filePath: `${getCollectionPathFromRoot('docs', project)}/404.md`,
|
|
38
40
|
};
|
|
39
41
|
|
|
40
|
-
const userEntry = await getEntry('docs', '404');
|
|
41
|
-
const entry = userEntry
|
|
42
|
+
const userEntry = (await getEntry('docs', '404')) as StarlightDocsCollectionEntry;
|
|
43
|
+
const entry = userEntry ? normalizeCollectionEntry(userEntry) : fallbackEntry;
|
|
42
44
|
const route: Route = { ...entryMeta, entryMeta, entry, id: entry.id, slug: entry.slug };
|
|
43
45
|
---
|
|
44
46
|
|
package/style/shiki.css
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
:root {
|
|
2
|
-
--astro-code-
|
|
3
|
-
--astro-code-
|
|
2
|
+
--astro-code-foreground: var(--sl-color-white);
|
|
3
|
+
--astro-code-background: var(--sl-color-gray-6);
|
|
4
4
|
--astro-code-token-constant: var(--sl-color-blue-high);
|
|
5
5
|
--astro-code-token-string: var(--sl-color-green-high);
|
|
6
6
|
--astro-code-token-comment: var(--sl-color-gray-2);
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
{
|
|
2
|
+
"skipLink.label": "Saltar al contingut",
|
|
3
|
+
"search.label": "Cercar",
|
|
4
|
+
"search.ctrlKey": "Ctrl",
|
|
5
|
+
"search.cancelLabel": "Cancel·lar",
|
|
6
|
+
"search.devWarning": "La cerca només està disponible a les versions de producció. \nProva de construir i previsualitzar el lloc per provar-ho localment.",
|
|
7
|
+
"themeSelect.accessibleLabel": "Seleccionar tema",
|
|
8
|
+
"themeSelect.dark": "Fosc",
|
|
9
|
+
"themeSelect.light": "Clar",
|
|
10
|
+
"themeSelect.auto": "Automàtic",
|
|
11
|
+
"languageSelect.accessibleLabel": "Seleccionar idioma",
|
|
12
|
+
"menuButton.accessibleLabel": "Menú",
|
|
13
|
+
"sidebarNav.accessibleLabel": "Primari",
|
|
14
|
+
"tableOfContents.onThisPage": "En aquesta pàgina",
|
|
15
|
+
"tableOfContents.overview": "Sinopsi",
|
|
16
|
+
"i18n.untranslatedContent": "Aquesta pàgina encara no està disponible en el teu idioma.",
|
|
17
|
+
"page.editLink": "Edita aquesta pàgina",
|
|
18
|
+
"page.lastUpdated": "Última actualització:",
|
|
19
|
+
"page.previousLink": "Pàgina anterior",
|
|
20
|
+
"page.nextLink": "Pàgina següent",
|
|
21
|
+
"page.draft": "Aquest contingut és un esborrany i no s'inclourà en les versions de producció.",
|
|
22
|
+
"404.text": "Pàgina no trobada. Comprova la URL o intenta utilitzar la barra de cerca.",
|
|
23
|
+
"aside.note": "Nota",
|
|
24
|
+
"aside.tip": "Consell",
|
|
25
|
+
"aside.caution": "Precaució",
|
|
26
|
+
"aside.danger": "Perill",
|
|
27
|
+
"expressiveCode.copyButtonCopied": "Copiat!",
|
|
28
|
+
"expressiveCode.copyButtonTooltip": "Copiar al porta-retalls",
|
|
29
|
+
"expressiveCode.terminalWindowFallbackTitle": "Finestra del terminal",
|
|
30
|
+
"fileTree.directory": "Directori",
|
|
31
|
+
"builtWithStarlight.label": "Fet amb Starlight",
|
|
32
|
+
"pagefind.clear_search": "Netejar",
|
|
33
|
+
"pagefind.load_more": "Carregar més resultats",
|
|
34
|
+
"pagefind.search_label": "Cercar pàgina",
|
|
35
|
+
"pagefind.filters_label": "Filtres",
|
|
36
|
+
"pagefind.zero_results": "Cap resultat per a: [SEARCH_TERM]",
|
|
37
|
+
"pagefind.many_results": "[COUNT] resultats per a: [SEARCH_TERM]",
|
|
38
|
+
"pagefind.one_result": "[COUNT] resultat per a: [SEARCH_TERM]",
|
|
39
|
+
"pagefind.alt_search": "Cap resultat per a [SEARCH_TERM]. Mostrant resultats per a: [DIFFERENT_TERM]",
|
|
40
|
+
"pagefind.search_suggestion": "Cap resultat per a [SEARCH_TERM]. Prova alguna d’aquestes cerques:",
|
|
41
|
+
"pagefind.searching": "Cercant [SEARCH_TERM]..."
|
|
42
|
+
}
|
package/translations/es.json
CHANGED
|
@@ -28,5 +28,15 @@
|
|
|
28
28
|
"expressiveCode.copyButtonTooltip": "Copiar al portapapeles",
|
|
29
29
|
"expressiveCode.terminalWindowFallbackTitle": "Ventana de terminal",
|
|
30
30
|
"fileTree.directory": "Directory",
|
|
31
|
-
"builtWithStarlight.label": "Hecho con Starlight"
|
|
31
|
+
"builtWithStarlight.label": "Hecho con Starlight",
|
|
32
|
+
"pagefind.clear_search": "Limpiar",
|
|
33
|
+
"pagefind.load_more": "Cargar más resultados",
|
|
34
|
+
"pagefind.search_label": "Buscar página",
|
|
35
|
+
"pagefind.filters_label": "Filtros",
|
|
36
|
+
"pagefind.zero_results": "Ningún resultado para: [SEARCH_TERM]",
|
|
37
|
+
"pagefind.many_results": "[COUNT] resultados para: [SEARCH_TERM]",
|
|
38
|
+
"pagefind.one_result": "[COUNT] resultado para: [SEARCH_TERM]",
|
|
39
|
+
"pagefind.alt_search": "Ningún resultado para [SEARCH_TERM]. Mostrando resultados para: [DIFFERENT_TERM]",
|
|
40
|
+
"pagefind.search_suggestion": "Ningún resultado para [SEARCH_TERM]. Prueba alguna de estas búsquedas:",
|
|
41
|
+
"pagefind.searching": "Buscando [SEARCH_TERM]..."
|
|
32
42
|
}
|
package/translations/index.ts
CHANGED
|
@@ -2,6 +2,7 @@ import { builtinI18nSchema } from '../schemas/i18n';
|
|
|
2
2
|
import cs from './cs.json';
|
|
3
3
|
import en from './en.json';
|
|
4
4
|
import es from './es.json';
|
|
5
|
+
import ca from './ca.json';
|
|
5
6
|
import de from './de.json';
|
|
6
7
|
import ja from './ja.json';
|
|
7
8
|
import pt from './pt.json';
|
|
@@ -35,6 +36,7 @@ export default Object.fromEntries(
|
|
|
35
36
|
cs,
|
|
36
37
|
en,
|
|
37
38
|
es,
|
|
39
|
+
ca,
|
|
38
40
|
de,
|
|
39
41
|
ja,
|
|
40
42
|
pt,
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { resolve } from 'node:path';
|
|
2
|
+
import { fileURLToPath } from 'node:url';
|
|
3
|
+
|
|
4
|
+
const collectionNames = ['docs', 'i18n'] as const;
|
|
5
|
+
export type StarlightCollection = (typeof collectionNames)[number];
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* We still rely on the content collection folder structure to be fixed for now:
|
|
9
|
+
*
|
|
10
|
+
* - At build time, if the feature is enabled, we get all the last commit dates for each file in
|
|
11
|
+
* the docs folder ahead of time. In the current approach, we cannot know at this time the
|
|
12
|
+
* user-defined content folder path in the integration context as this would only be available
|
|
13
|
+
* from the loader. A potential solution could be to do that from a custom loader re-implementing
|
|
14
|
+
* the glob loader or built on top of it. Although, we don't have access to the Starlight
|
|
15
|
+
* configuration from the loader to even know we should do that.
|
|
16
|
+
* - Remark plugins get passed down an absolute path to a content file and we need to figure out
|
|
17
|
+
* the language from that path. Without knowing the content folder path, we cannot reliably do
|
|
18
|
+
* so.
|
|
19
|
+
*
|
|
20
|
+
* Below are various functions to easily get paths to these collections and avoid having to
|
|
21
|
+
* hardcode them throughout the codebase. When user-defined content folder locations are supported,
|
|
22
|
+
* these helper functions should be updated to reflect that in one place.
|
|
23
|
+
*/
|
|
24
|
+
|
|
25
|
+
export function getCollectionPath(collection: StarlightCollection, srcDir: URL) {
|
|
26
|
+
return new URL(`content/${collection}/`, srcDir).pathname;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export function resolveCollectionPath(collection: StarlightCollection, srcDir: URL) {
|
|
30
|
+
return resolve(fileURLToPath(srcDir), `content/${collection}`);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export function getCollectionPathFromRoot(
|
|
34
|
+
collection: StarlightCollection,
|
|
35
|
+
{ root, srcDir }: { root: URL | string; srcDir: URL | string }
|
|
36
|
+
) {
|
|
37
|
+
return (
|
|
38
|
+
(typeof srcDir === 'string' ? srcDir : srcDir.pathname).replace(
|
|
39
|
+
typeof root === 'string' ? root : root.pathname,
|
|
40
|
+
''
|
|
41
|
+
) +
|
|
42
|
+
'content/' +
|
|
43
|
+
collection
|
|
44
|
+
);
|
|
45
|
+
}
|
package/utils/git.ts
CHANGED
|
@@ -55,8 +55,8 @@ function getRepoRoot(directory: string): string {
|
|
|
55
55
|
}
|
|
56
56
|
}
|
|
57
57
|
|
|
58
|
-
export function getAllNewestCommitDate(
|
|
59
|
-
const repoRoot = getRepoRoot(
|
|
58
|
+
export function getAllNewestCommitDate(rootPath: string, docsPath: string): [string, number][] {
|
|
59
|
+
const repoRoot = getRepoRoot(docsPath);
|
|
60
60
|
|
|
61
61
|
const gitLog = spawnSync(
|
|
62
62
|
'git',
|
|
@@ -67,7 +67,7 @@ export function getAllNewestCommitDate(directory: string): [string, number][] {
|
|
|
67
67
|
// In each entry include the name and status for each modified file
|
|
68
68
|
'--name-status',
|
|
69
69
|
'--',
|
|
70
|
-
|
|
70
|
+
docsPath,
|
|
71
71
|
],
|
|
72
72
|
{
|
|
73
73
|
cwd: repoRoot,
|
|
@@ -105,7 +105,9 @@ export function getAllNewestCommitDate(directory: string): [string, number][] {
|
|
|
105
105
|
|
|
106
106
|
return Array.from(latestDates.entries()).map(([file, date]) => {
|
|
107
107
|
const fileFullPath = resolve(repoRoot, file);
|
|
108
|
-
|
|
108
|
+
let fileInDirectory = relative(rootPath, fileFullPath);
|
|
109
|
+
// Format path to unix style path.
|
|
110
|
+
fileInDirectory = fileInDirectory?.replace(/\\/g, '/');
|
|
109
111
|
|
|
110
112
|
return [fileInDirectory, date];
|
|
111
113
|
});
|
package/utils/navigation.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { AstroError } from 'astro/errors';
|
|
2
2
|
import config from 'virtual:starlight/user-config';
|
|
3
|
+
import project from 'virtual:starlight/project-context';
|
|
3
4
|
import type { Badge, I18nBadge, I18nBadgeConfig } from '../schemas/badge';
|
|
4
5
|
import type { PrevNextLinkConfig } from '../schemas/prevNextLink';
|
|
5
6
|
import type {
|
|
@@ -14,8 +15,9 @@ import { formatPath } from './format-path';
|
|
|
14
15
|
import { BuiltInDefaultLocale, pickLang } from './i18n';
|
|
15
16
|
import { ensureLeadingSlash, ensureTrailingSlash, stripLeadingAndTrailingSlashes } from './path';
|
|
16
17
|
import { getLocaleRoutes, routes, type Route } from './routing';
|
|
17
|
-
import { localeToLang, slugToPathname } from './slugs';
|
|
18
|
+
import { localeToLang, localizedId, slugToPathname } from './slugs';
|
|
18
19
|
import type { StarlightConfig } from './user-config';
|
|
20
|
+
import { getCollectionPathFromRoot } from './collection';
|
|
19
21
|
|
|
20
22
|
const DirKey = Symbol('DirKey');
|
|
21
23
|
const SlugKey = Symbol('SlugKey');
|
|
@@ -108,7 +110,7 @@ function groupFromAutogenerateConfig(
|
|
|
108
110
|
// Match against `foo/anything/else.md`.
|
|
109
111
|
doc.id.startsWith(localeDir + '/')
|
|
110
112
|
);
|
|
111
|
-
const tree = treeify(dirDocs, localeDir);
|
|
113
|
+
const tree = treeify(dirDocs, locale, localeDir);
|
|
112
114
|
const label = pickLang(item.translations, localeToLang(locale)) || item.label;
|
|
113
115
|
return {
|
|
114
116
|
type: 'group',
|
|
@@ -218,16 +220,28 @@ function getBreadcrumbs(path: string, baseDir: string): string[] {
|
|
|
218
220
|
}
|
|
219
221
|
|
|
220
222
|
/** Turn a flat array of routes into a tree structure. */
|
|
221
|
-
function treeify(routes: Route[], baseDir: string): Dir {
|
|
223
|
+
function treeify(routes: Route[], locale: string | undefined, baseDir: string): Dir {
|
|
222
224
|
const treeRoot: Dir = makeDir(baseDir);
|
|
225
|
+
const collectionPathFromRoot = getCollectionPathFromRoot('docs', project);
|
|
223
226
|
routes
|
|
224
227
|
// Remove any entries that should be hidden
|
|
225
228
|
.filter((doc) => !doc.entry.data.sidebar.hidden)
|
|
229
|
+
// Compute the path of each entry from the root of the collection ahead of time.
|
|
230
|
+
.map(
|
|
231
|
+
(doc) =>
|
|
232
|
+
[
|
|
233
|
+
project.legacyCollections
|
|
234
|
+
? doc.id
|
|
235
|
+
: // For collections with a loader, use a localized filePath relative to the collection
|
|
236
|
+
localizedId(doc.entry.filePath.replace(`${collectionPathFromRoot}/`, ''), locale),
|
|
237
|
+
doc,
|
|
238
|
+
] as const
|
|
239
|
+
)
|
|
226
240
|
// Sort by depth, to build the tree depth first.
|
|
227
|
-
.sort((a, b) => b.
|
|
241
|
+
.sort(([a], [b]) => b.split('/').length - a.split('/').length)
|
|
228
242
|
// Build the tree
|
|
229
|
-
.forEach((doc) => {
|
|
230
|
-
const parts = getBreadcrumbs(
|
|
243
|
+
.forEach(([filePathFromContentDir, doc]) => {
|
|
244
|
+
const parts = getBreadcrumbs(filePathFromContentDir, baseDir);
|
|
231
245
|
let currentNode = treeRoot;
|
|
232
246
|
|
|
233
247
|
parts.forEach((part, index) => {
|
|
@@ -374,7 +388,7 @@ function getIntermediateSidebarFromConfig(
|
|
|
374
388
|
if (sidebarConfig) {
|
|
375
389
|
return sidebarConfig.map((group) => configItemToEntry(group, pathname, locale, routes));
|
|
376
390
|
} else {
|
|
377
|
-
const tree = treeify(routes, locale || '');
|
|
391
|
+
const tree = treeify(routes, locale, locale || '');
|
|
378
392
|
return sidebarFromDir(tree, pathname, locale, false);
|
|
379
393
|
}
|
|
380
394
|
}
|
package/utils/plugins.ts
CHANGED
|
@@ -2,7 +2,6 @@ import type { AstroIntegration, HookParameters } from 'astro';
|
|
|
2
2
|
import { z } from 'astro/zod';
|
|
3
3
|
import { StarlightConfigSchema, type StarlightUserConfig } from '../utils/user-config';
|
|
4
4
|
import { parseWithFriendlyErrors } from '../utils/error-map';
|
|
5
|
-
import { AstroError } from 'astro/errors';
|
|
6
5
|
import type { UserI18nSchema } from './translations';
|
|
7
6
|
|
|
8
7
|
/**
|
|
@@ -83,14 +82,6 @@ export async function runPlugins(
|
|
|
83
82
|
});
|
|
84
83
|
}
|
|
85
84
|
|
|
86
|
-
if (context.config.output === 'static' && !starlightConfig.prerender) {
|
|
87
|
-
throw new AstroError(
|
|
88
|
-
'Starlight’s `prerender: false` option requires `output: "hybrid"` or `"server"` in your Astro config.',
|
|
89
|
-
'Either set `output` in your Astro config or set `prerender: true` in the Starlight options.\n\n' +
|
|
90
|
-
'Learn more about rendering modes in the Astro docs: https://docs.astro.build/en/basics/rendering-modes/'
|
|
91
|
-
);
|
|
92
|
-
}
|
|
93
|
-
|
|
94
85
|
return { integrations, starlightConfig, pluginTranslations };
|
|
95
86
|
}
|
|
96
87
|
|
package/utils/route-data.ts
CHANGED
|
@@ -1,12 +1,10 @@
|
|
|
1
1
|
import type { MarkdownHeading } from 'astro';
|
|
2
|
-
import project from 'virtual:starlight/project-context';
|
|
3
2
|
import config from 'virtual:starlight/user-config';
|
|
4
3
|
import { generateToC, type TocItem } from './generateToC';
|
|
5
4
|
import { getNewestCommitDate } from 'virtual:starlight/git-info';
|
|
6
5
|
import { getPrevNextLinks, getSidebar, type SidebarEntry } from './navigation';
|
|
7
6
|
import { ensureTrailingSlash } from './path';
|
|
8
7
|
import type { Route } from './routing';
|
|
9
|
-
import { localizedId } from './slugs';
|
|
10
8
|
import { formatPath } from './format-path';
|
|
11
9
|
import { useTranslations } from './translations';
|
|
12
10
|
import { DeprecatedLabelsPropProxy } from './i18n';
|
|
@@ -85,7 +83,7 @@ function getLastUpdated({ entry }: PageProps): Date | undefined {
|
|
|
85
83
|
try {
|
|
86
84
|
return frontmatterLastUpdated instanceof Date
|
|
87
85
|
? frontmatterLastUpdated
|
|
88
|
-
: getNewestCommitDate(entry.
|
|
86
|
+
: getNewestCommitDate(entry.filePath);
|
|
89
87
|
} catch {
|
|
90
88
|
// If the git command fails, ignore the error.
|
|
91
89
|
return undefined;
|
|
@@ -95,7 +93,7 @@ function getLastUpdated({ entry }: PageProps): Date | undefined {
|
|
|
95
93
|
return undefined;
|
|
96
94
|
}
|
|
97
95
|
|
|
98
|
-
function getEditUrl({ entry
|
|
96
|
+
function getEditUrl({ entry }: PageProps): URL | undefined {
|
|
99
97
|
const { editUrl } = entry.data;
|
|
100
98
|
// If frontmatter value is false, editing is disabled for this page.
|
|
101
99
|
if (editUrl === false) return;
|
|
@@ -105,10 +103,8 @@ function getEditUrl({ entry, id, isFallback }: PageProps): URL | undefined {
|
|
|
105
103
|
// If a URL was provided in frontmatter, use that.
|
|
106
104
|
url = editUrl;
|
|
107
105
|
} else if (config.editLink.baseUrl) {
|
|
108
|
-
const srcPath = project.srcDir.replace(project.root, '');
|
|
109
|
-
const filePath = isFallback ? localizedId(id, config.defaultLocale.locale) : id;
|
|
110
106
|
// If a base URL was added in Starlight config, synthesize the edit URL from it.
|
|
111
|
-
url = ensureTrailingSlash(config.editLink.baseUrl) +
|
|
107
|
+
url = ensureTrailingSlash(config.editLink.baseUrl) + entry.filePath;
|
|
112
108
|
}
|
|
113
109
|
return url ? new URL(url) : undefined;
|
|
114
110
|
}
|
package/utils/routing.ts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import type { GetStaticPathsItem } from 'astro';
|
|
2
2
|
import { type CollectionEntry, getCollection } from 'astro:content';
|
|
3
3
|
import config from 'virtual:starlight/user-config';
|
|
4
|
+
import project from 'virtual:starlight/project-context';
|
|
5
|
+
import { getCollectionPathFromRoot } from './collection';
|
|
4
6
|
import {
|
|
5
7
|
type LocaleData,
|
|
6
8
|
localizedId,
|
|
@@ -15,7 +17,22 @@ import { BuiltInDefaultLocale } from './i18n';
|
|
|
15
17
|
// We do this here so all pages trigger it and at the top level so it runs just once.
|
|
16
18
|
validateLogoImports();
|
|
17
19
|
|
|
18
|
-
|
|
20
|
+
// The type returned from `CollectionEntry` is different for legacy collections and collections
|
|
21
|
+
// using a loader. This type is a common subset of both types.
|
|
22
|
+
export type StarlightDocsCollectionEntry = Omit<
|
|
23
|
+
CollectionEntry<'docs'>,
|
|
24
|
+
'id' | 'filePath' | 'render' | 'slug'
|
|
25
|
+
> & {
|
|
26
|
+
// Update the `id` property to be a string like in the loader type.
|
|
27
|
+
id: string;
|
|
28
|
+
// Add the `filePath` property which is only present in the loader type.
|
|
29
|
+
filePath?: string;
|
|
30
|
+
// Add the `slug` property which is only present in the legacy type.
|
|
31
|
+
slug?: string;
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
export type StarlightDocsEntry = StarlightDocsCollectionEntry & {
|
|
35
|
+
filePath: string;
|
|
19
36
|
slug: string;
|
|
20
37
|
};
|
|
21
38
|
|
|
@@ -24,9 +41,9 @@ export interface Route extends LocaleData {
|
|
|
24
41
|
entry: StarlightDocsEntry;
|
|
25
42
|
/** Locale metadata for the page content. Can be different from top-level locale values when a page is using fallback content. */
|
|
26
43
|
entryMeta: LocaleData;
|
|
27
|
-
/**
|
|
44
|
+
/** @deprecated Migrate to the new Content Layer API and use `id` instead. */
|
|
28
45
|
slug: string;
|
|
29
|
-
/** The unique ID
|
|
46
|
+
/** The slug or unique ID if using the `legacy.collections` flag. */
|
|
30
47
|
id: string;
|
|
31
48
|
/** True if this page is untranslated in the current language and using fallback content from the default locale. */
|
|
32
49
|
isFallback?: true;
|
|
@@ -45,16 +62,27 @@ interface Path extends GetStaticPathsItem {
|
|
|
45
62
|
*/
|
|
46
63
|
const normalizeIndexSlug = (slug: string) => (slug === 'index' ? '' : slug);
|
|
47
64
|
|
|
65
|
+
/** Normalize the different collection entry we can get from a legacy collection or a loader. */
|
|
66
|
+
export function normalizeCollectionEntry(entry: StarlightDocsCollectionEntry): StarlightDocsEntry {
|
|
67
|
+
const slug = normalizeIndexSlug(entry.slug ?? entry.id);
|
|
68
|
+
return {
|
|
69
|
+
...entry,
|
|
70
|
+
// In a collection with a loader, the `id` is a slug and should be normalized.
|
|
71
|
+
id: entry.slug ? entry.id : slug,
|
|
72
|
+
// In a legacy collection, the `filePath` property doesn't exist.
|
|
73
|
+
filePath: entry.filePath ?? `${getCollectionPathFromRoot('docs', project)}/${entry.id}`,
|
|
74
|
+
// In a collection with a loader, the `slug` property is replaced by the `id`.
|
|
75
|
+
slug: normalizeIndexSlug(entry.slug ?? entry.id),
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
|
|
48
79
|
/** All entries in the docs content collection. */
|
|
49
80
|
const docs: StarlightDocsEntry[] = (
|
|
50
81
|
(await getCollection('docs', ({ data }) => {
|
|
51
82
|
// In production, filter out drafts.
|
|
52
83
|
return import.meta.env.MODE !== 'production' || data.draft === false;
|
|
53
84
|
})) ?? []
|
|
54
|
-
).map(
|
|
55
|
-
...entry,
|
|
56
|
-
slug: normalizeIndexSlug(slug),
|
|
57
|
-
}));
|
|
85
|
+
).map(normalizeCollectionEntry);
|
|
58
86
|
|
|
59
87
|
function getRoutes(): Route[] {
|
|
60
88
|
const routes: Route[] = docs.map((entry) => ({
|
|
@@ -79,7 +107,7 @@ function getRoutes(): Route[] {
|
|
|
79
107
|
const localeDocs = getLocaleDocs(locale);
|
|
80
108
|
for (const fallback of defaultLocaleDocs) {
|
|
81
109
|
const slug = localizedSlug(fallback.slug, locale);
|
|
82
|
-
const id = localizedId(fallback.id, locale);
|
|
110
|
+
const id = project.legacyCollections ? localizedId(fallback.id, locale) : slug;
|
|
83
111
|
const doesNotNeedFallback = localeDocs.some((doc) => doc.slug === slug);
|
|
84
112
|
if (doesNotNeedFallback) continue;
|
|
85
113
|
routes.push({
|
package/utils/slugs.ts
CHANGED
|
@@ -82,7 +82,8 @@ export function localizedSlug(slug: string, locale: string | undefined): string
|
|
|
82
82
|
}
|
|
83
83
|
|
|
84
84
|
/**
|
|
85
|
-
* Convert a collection entry ID to a different
|
|
85
|
+
* Convert a legacy collection entry ID or filePath relative to the collection root to a different
|
|
86
|
+
* locale.
|
|
86
87
|
* For example, passing an ID of `en/home.md` and a locale of `fr` results in `fr/home.md`.
|
|
87
88
|
* An undefined locale is treated as the root locale, resulting in `home.md`.
|
|
88
89
|
* @param id A collection entry ID
|
package/utils/starlight-page.ts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { z } from 'astro/zod';
|
|
2
2
|
import { type ContentConfig, type SchemaContext } from 'astro:content';
|
|
3
|
+
import project from 'virtual:starlight/project-context';
|
|
3
4
|
import config from 'virtual:starlight/user-config';
|
|
5
|
+
import { getCollectionPathFromRoot } from './collection';
|
|
4
6
|
import { parseWithFriendlyErrors, parseAsyncWithFriendlyErrors } from './error-map';
|
|
5
7
|
import { stripLeadingAndTrailingSlashes } from './path';
|
|
6
8
|
import {
|
|
@@ -97,8 +99,8 @@ export type StarlightPageProps = Prettify<
|
|
|
97
99
|
*/
|
|
98
100
|
type StarlightPageDocsEntry = Omit<StarlightDocsEntry, 'id' | 'render'> & {
|
|
99
101
|
/**
|
|
100
|
-
* The unique ID for this Starlight page which cannot be
|
|
101
|
-
* collection entries.
|
|
102
|
+
* The unique ID if using the `legacy.collections` for this Starlight page which cannot be
|
|
103
|
+
* inferred from codegen like content collection entries or the slug.
|
|
102
104
|
*/
|
|
103
105
|
id: string;
|
|
104
106
|
};
|
|
@@ -113,7 +115,7 @@ export async function generateStarlightPageRouteData({
|
|
|
113
115
|
const { isFallback, frontmatter, ...routeProps } = props;
|
|
114
116
|
const slug = urlToSlug(url);
|
|
115
117
|
const pageFrontmatter = await getStarlightPageFrontmatter(frontmatter);
|
|
116
|
-
const id = `${stripLeadingAndTrailingSlashes(slug)}.md
|
|
118
|
+
const id = project.legacyCollections ? `${stripLeadingAndTrailingSlashes(slug)}.md` : slug;
|
|
117
119
|
const localeData = slugToLocaleData(slug);
|
|
118
120
|
const sidebar = props.sidebar
|
|
119
121
|
? getSidebarFromConfig(validateSidebarProp(props.sidebar), url.pathname, localeData.locale)
|
|
@@ -124,6 +126,7 @@ export async function generateStarlightPageRouteData({
|
|
|
124
126
|
slug,
|
|
125
127
|
body: '',
|
|
126
128
|
collection: 'docs',
|
|
129
|
+
filePath: `${getCollectionPathFromRoot('docs', project)}/${stripLeadingAndTrailingSlashes(slug)}.md`,
|
|
127
130
|
data: {
|
|
128
131
|
...pageFrontmatter,
|
|
129
132
|
sidebar: {
|
package/virtual-internal.d.ts
CHANGED
|
File without changes
|