@astrojs/starlight 0.13.0 → 0.14.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/404.astro +1 -1
- package/CHANGELOG.md +26 -0
- package/components/EditLink.astro +2 -4
- package/components/FallbackContentNotice.astro +2 -3
- package/components/Header.astro +8 -1
- package/components/LanguageSelect.astro +2 -3
- package/components/LastUpdated.astro +2 -4
- package/components/MobileMenuToggle.astro +2 -4
- package/components/MobileTableOfContents.astro +2 -4
- package/components/PageFrame.astro +3 -6
- package/components/Pagination.astro +3 -5
- package/components/Search.astro +16 -10
- package/components/SidebarSublist.astro +5 -3
- package/components/SkipLink.astro +2 -3
- package/components/TableOfContents.astro +2 -4
- package/components/ThemeSelect.astro +5 -6
- package/index.ts +39 -36
- package/package.json +2 -2
- package/schema.ts +149 -96
- package/schemas/i18n.ts +26 -2
- package/translations/hi.json +1 -1
- package/types.ts +1 -0
- package/utils/createTranslationSystem.ts +8 -3
- package/utils/plugins.ts +226 -0
- package/utils/route-data.ts +3 -0
- package/utils/user-config.ts +7 -0
package/404.astro
CHANGED
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,31 @@
|
|
|
1
1
|
# @astrojs/starlight
|
|
2
2
|
|
|
3
|
+
## 0.14.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- [#1144](https://github.com/withastro/starlight/pull/1144) [`7c0b8cb`](https://github.com/withastro/starlight/commit/7c0b8cb334c501678f7ab87cce372cddfdde34ed) Thanks [@delucis](https://github.com/delucis)! - Adds a configuration option to disable site indexing with Pagefind and the default search UI
|
|
8
|
+
|
|
9
|
+
- [#942](https://github.com/withastro/starlight/pull/942) [`efd7fdc`](https://github.com/withastro/starlight/commit/efd7fdcb55b39988f157c1a4b2c368c86a39520f) Thanks [@HiDeoo](https://github.com/HiDeoo)! - Adds plugin API
|
|
10
|
+
|
|
11
|
+
See the [plugins reference](https://starlight.astro.build/reference/plugins/) to learn more about creating plugins for Starlight using this new API.
|
|
12
|
+
|
|
13
|
+
- [#1135](https://github.com/withastro/starlight/pull/1135) [`e5a863a`](https://github.com/withastro/starlight/commit/e5a863a98b2e5335e122ca440dcb84e9426939b4) Thanks [@delucis](https://github.com/delucis)! - Exposes localized UI strings in route data
|
|
14
|
+
|
|
15
|
+
Component overrides can now access a `labels` object in their props which includes all the localized UI strings for the current page.
|
|
16
|
+
|
|
17
|
+
- [#1162](https://github.com/withastro/starlight/pull/1162) [`00d101b`](https://github.com/withastro/starlight/commit/00d101b159bfa4bb307a66ccae53dd417d9564e0) Thanks [@delucis](https://github.com/delucis)! - Adds support for extending Starlight’s content collection schemas
|
|
18
|
+
|
|
19
|
+
## 0.13.1
|
|
20
|
+
|
|
21
|
+
### Patch Changes
|
|
22
|
+
|
|
23
|
+
- [#1111](https://github.com/withastro/starlight/pull/1111) [`cb19d07`](https://github.com/withastro/starlight/commit/cb19d07d6192ffb732ac6fcf9df04d4f098bfc1f) Thanks [@at-the-vr](https://github.com/at-the-vr)! - Fix minor punctuation typo in Hindi UI string
|
|
24
|
+
|
|
25
|
+
- [#1156](https://github.com/withastro/starlight/pull/1156) [`631c5ae`](https://github.com/withastro/starlight/commit/631c5aeccba60254ff649712f93ba30495775edf) Thanks [@votemike](https://github.com/votemike)! - Updates `@astrojs/sitemap` dependency to the latest version
|
|
26
|
+
|
|
27
|
+
- [#1109](https://github.com/withastro/starlight/pull/1109) [`0c25c1f`](https://github.com/withastro/starlight/commit/0c25c1f33bbfe311724784530c30ada44eb5de19) Thanks [@HiDeoo](https://github.com/HiDeoo)! - Internal: fix import issue with expressive-code
|
|
28
|
+
|
|
3
29
|
## 0.13.0
|
|
4
30
|
|
|
5
31
|
### Minor Changes
|
|
@@ -1,17 +1,15 @@
|
|
|
1
1
|
---
|
|
2
2
|
import Icon from '../user-components/Icon.astro';
|
|
3
3
|
import type { Props } from '../props';
|
|
4
|
-
import { useTranslations } from '../utils/translations';
|
|
5
4
|
|
|
6
|
-
const
|
|
7
|
-
const { editUrl } = Astro.props;
|
|
5
|
+
const { editUrl, labels } = Astro.props;
|
|
8
6
|
---
|
|
9
7
|
|
|
10
8
|
{
|
|
11
9
|
editUrl && (
|
|
12
10
|
<a href={editUrl} class="sl-flex">
|
|
13
11
|
<Icon name="pencil" size="1.2em" />
|
|
14
|
-
{
|
|
12
|
+
{labels['page.editLink']}
|
|
15
13
|
</a>
|
|
16
14
|
)
|
|
17
15
|
}
|
|
@@ -1,14 +1,13 @@
|
|
|
1
1
|
---
|
|
2
2
|
import Icon from '../user-components/Icon.astro';
|
|
3
3
|
import type { Props } from '../props';
|
|
4
|
-
import { useTranslations } from '../utils/translations';
|
|
5
4
|
|
|
6
|
-
const
|
|
5
|
+
const { labels } = Astro.props;
|
|
7
6
|
---
|
|
8
7
|
|
|
9
8
|
<p class="sl-flex">
|
|
10
9
|
<Icon name={'warning'} size="1.5em" color="var(--sl-color-orange-high)" /><span
|
|
11
|
-
>{
|
|
10
|
+
>{labels['i18n.untranslatedContent']}</span
|
|
12
11
|
>
|
|
13
12
|
</p>
|
|
14
13
|
|
package/components/Header.astro
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
---
|
|
2
|
+
import config from 'virtual:starlight/user-config';
|
|
2
3
|
import type { Props } from '../props';
|
|
3
4
|
|
|
4
5
|
import {
|
|
@@ -8,6 +9,12 @@ import {
|
|
|
8
9
|
SocialIcons,
|
|
9
10
|
ThemeSelect,
|
|
10
11
|
} from 'virtual:starlight/components';
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Render the `Search` component if Pagefind is enabled or the default search component has been overridden.
|
|
15
|
+
*/
|
|
16
|
+
const shouldRenderSearch =
|
|
17
|
+
config.pagefind || config.components.Search !== '@astrojs/starlight/components/Search.astro';
|
|
11
18
|
---
|
|
12
19
|
|
|
13
20
|
<div class="header sl-flex">
|
|
@@ -15,7 +22,7 @@ import {
|
|
|
15
22
|
<SiteTitle {...Astro.props} />
|
|
16
23
|
</div>
|
|
17
24
|
<div class="sl-flex">
|
|
18
|
-
<Search {...Astro.props} />
|
|
25
|
+
{shouldRenderSearch && <Search {...Astro.props} />}
|
|
19
26
|
</div>
|
|
20
27
|
<div class="sl-hidden md:sl-flex right-group">
|
|
21
28
|
<div class="sl-flex social-icons">
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
import config from 'virtual:starlight/user-config';
|
|
3
3
|
import { localizedUrl } from '../utils/localizedUrl';
|
|
4
|
-
import { useTranslations } from '../utils/translations';
|
|
5
4
|
import Select from './Select.astro';
|
|
6
5
|
import type { Props } from '../props';
|
|
7
6
|
|
|
@@ -12,7 +11,7 @@ function localizedPathname(locale: string | undefined): string {
|
|
|
12
11
|
return localizedUrl(Astro.url, locale).pathname;
|
|
13
12
|
}
|
|
14
13
|
|
|
15
|
-
const
|
|
14
|
+
const { labels } = Astro.props;
|
|
16
15
|
---
|
|
17
16
|
|
|
18
17
|
{
|
|
@@ -20,7 +19,7 @@ const t = useTranslations(Astro.props.locale);
|
|
|
20
19
|
<starlight-lang-select>
|
|
21
20
|
<Select
|
|
22
21
|
icon="translate"
|
|
23
|
-
label={
|
|
22
|
+
label={labels['languageSelect.accessibleLabel']}
|
|
24
23
|
value={localizedPathname(Astro.props.locale)}
|
|
25
24
|
options={Object.entries(config.locales).map(([code, locale]) => ({
|
|
26
25
|
value: localizedPathname(code),
|
|
@@ -1,15 +1,13 @@
|
|
|
1
1
|
---
|
|
2
2
|
import type { Props } from '../props';
|
|
3
|
-
import { useTranslations } from '../utils/translations';
|
|
4
3
|
|
|
5
|
-
const { lang, lastUpdated
|
|
6
|
-
const t = useTranslations(locale);
|
|
4
|
+
const { labels, lang, lastUpdated } = Astro.props;
|
|
7
5
|
---
|
|
8
6
|
|
|
9
7
|
{
|
|
10
8
|
lastUpdated && (
|
|
11
9
|
<p>
|
|
12
|
-
{
|
|
10
|
+
{labels['page.lastUpdated']}{' '}
|
|
13
11
|
<time datetime={lastUpdated.toISOString()}>
|
|
14
12
|
{lastUpdated.toLocaleDateString(lang, { dateStyle: 'medium' })}
|
|
15
13
|
</time>
|
|
@@ -1,16 +1,14 @@
|
|
|
1
1
|
---
|
|
2
2
|
import type { Props } from '../props';
|
|
3
|
-
import { useTranslations } from '../utils/translations';
|
|
4
|
-
|
|
5
3
|
import Icon from '../user-components/Icon.astro';
|
|
6
4
|
|
|
7
|
-
const
|
|
5
|
+
const { labels } = Astro.props;
|
|
8
6
|
---
|
|
9
7
|
|
|
10
8
|
<starlight-menu-button>
|
|
11
9
|
<button
|
|
12
10
|
aria-expanded="false"
|
|
13
|
-
aria-label={
|
|
11
|
+
aria-label={labels['menuButton.accessibleLabel']}
|
|
14
12
|
aria-controls="starlight__sidebar"
|
|
15
13
|
class="sl-flex md:sl-hidden"
|
|
16
14
|
>
|
|
@@ -1,11 +1,9 @@
|
|
|
1
1
|
---
|
|
2
|
-
import { useTranslations } from '../utils/translations';
|
|
3
2
|
import Icon from '../user-components/Icon.astro';
|
|
4
3
|
import TableOfContentsList from './TableOfContents/TableOfContentsList.astro';
|
|
5
4
|
import type { Props } from '../props';
|
|
6
5
|
|
|
7
|
-
const {
|
|
8
|
-
const t = useTranslations(locale);
|
|
6
|
+
const { labels, toc } = Astro.props;
|
|
9
7
|
---
|
|
10
8
|
|
|
11
9
|
{
|
|
@@ -15,7 +13,7 @@ const t = useTranslations(locale);
|
|
|
15
13
|
<details id="starlight__mobile-toc">
|
|
16
14
|
<summary id="starlight__on-this-page--mobile" class="sl-flex">
|
|
17
15
|
<div class="toggle sl-flex">
|
|
18
|
-
{
|
|
16
|
+
{labels['tableOfContents.onThisPage']}
|
|
19
17
|
<Icon name={'right-caret'} class="caret" size="1rem" />
|
|
20
18
|
</div>
|
|
21
19
|
<span class="display-current" />
|
|
@@ -1,18 +1,15 @@
|
|
|
1
1
|
---
|
|
2
|
-
import type { Props } from '../props';
|
|
3
|
-
import { useTranslations } from '../utils/translations';
|
|
4
|
-
|
|
5
2
|
import { MobileMenuToggle } from 'virtual:starlight/components';
|
|
3
|
+
import type { Props } from '../props';
|
|
6
4
|
|
|
7
|
-
const { hasSidebar,
|
|
8
|
-
const t = useTranslations(locale);
|
|
5
|
+
const { hasSidebar, labels } = Astro.props;
|
|
9
6
|
---
|
|
10
7
|
|
|
11
8
|
<div class="page sl-flex">
|
|
12
9
|
<header class="header"><slot name="header" /></header>
|
|
13
10
|
{
|
|
14
11
|
hasSidebar && (
|
|
15
|
-
<nav class="sidebar" aria-label={
|
|
12
|
+
<nav class="sidebar" aria-label={labels['sidebarNav.accessibleLabel']}>
|
|
16
13
|
<MobileMenuToggle {...Astro.props} />
|
|
17
14
|
<div id="starlight__sidebar" class="sidebar-pane">
|
|
18
15
|
<div class="sidebar-content sl-flex">
|
|
@@ -1,12 +1,10 @@
|
|
|
1
1
|
---
|
|
2
|
-
import { useTranslations } from '../utils/translations';
|
|
3
2
|
import Icon from '../user-components/Icon.astro';
|
|
4
3
|
import type { Props } from '../props';
|
|
5
4
|
|
|
6
|
-
const { dir,
|
|
5
|
+
const { dir, labels, pagination } = Astro.props;
|
|
7
6
|
const { prev, next } = pagination;
|
|
8
7
|
const isRtl = dir === 'rtl';
|
|
9
|
-
const t = useTranslations(locale);
|
|
10
8
|
---
|
|
11
9
|
|
|
12
10
|
<div class="pagination-links" dir={dir}>
|
|
@@ -15,7 +13,7 @@ const t = useTranslations(locale);
|
|
|
15
13
|
<a href={prev.href} rel="prev">
|
|
16
14
|
<Icon name={isRtl ? 'right-arrow' : 'left-arrow'} size="1.5rem" />
|
|
17
15
|
<span>
|
|
18
|
-
{
|
|
16
|
+
{labels['page.previousLink']}
|
|
19
17
|
<br />
|
|
20
18
|
<span class="link-title">{prev.label}</span>
|
|
21
19
|
</span>
|
|
@@ -27,7 +25,7 @@ const t = useTranslations(locale);
|
|
|
27
25
|
<a href={next.href} rel="next">
|
|
28
26
|
<Icon name={isRtl ? 'left-arrow' : 'right-arrow'} size="1.5rem" />
|
|
29
27
|
<span>
|
|
30
|
-
{
|
|
28
|
+
{labels['page.nextLink']}
|
|
31
29
|
<br />
|
|
32
30
|
<span class="link-title">{next.label}</span>
|
|
33
31
|
</span>
|
package/components/Search.astro
CHANGED
|
@@ -1,14 +1,16 @@
|
|
|
1
1
|
---
|
|
2
2
|
import '@pagefind/default-ui/css/ui.css';
|
|
3
|
-
import { useTranslations } from '../utils/translations';
|
|
4
3
|
import Icon from '../user-components/Icon.astro';
|
|
5
4
|
import type { Props } from '../props';
|
|
6
5
|
|
|
7
|
-
const
|
|
6
|
+
const { labels } = Astro.props;
|
|
7
|
+
|
|
8
8
|
const pagefindTranslations = {
|
|
9
|
-
placeholder:
|
|
9
|
+
placeholder: labels['search.label'],
|
|
10
10
|
...Object.fromEntries(
|
|
11
|
-
Object.entries(
|
|
11
|
+
Object.entries(labels)
|
|
12
|
+
.filter(([key]) => key.startsWith('pagefind.'))
|
|
13
|
+
.map(([key, value]) => [key.replace('pagefind.', ''), value])
|
|
12
14
|
),
|
|
13
15
|
};
|
|
14
16
|
---
|
|
@@ -18,23 +20,27 @@ const pagefindTranslations = {
|
|
|
18
20
|
{
|
|
19
21
|
/* The span is `aria-hidden` because it is not shown on small screens. Instead, the icon label is used for accessibility purposes. */
|
|
20
22
|
}
|
|
21
|
-
<Icon name="magnifier" label={
|
|
22
|
-
<span class="sl-hidden md:sl-block" aria-hidden="true">{
|
|
23
|
-
<Icon
|
|
23
|
+
<Icon name="magnifier" label={labels['search.label']} />
|
|
24
|
+
<span class="sl-hidden md:sl-block" aria-hidden="true">{labels['search.label']}</span>
|
|
25
|
+
<Icon
|
|
26
|
+
name="forward-slash"
|
|
27
|
+
class="sl-hidden md:sl-block"
|
|
28
|
+
label={labels['search.shortcutLabel']}
|
|
29
|
+
/>
|
|
24
30
|
</button>
|
|
25
31
|
|
|
26
|
-
<dialog style="padding:0" aria-label={
|
|
32
|
+
<dialog style="padding:0" aria-label={labels['search.label']}>
|
|
27
33
|
<div class="dialog-frame sl-flex">
|
|
28
34
|
{
|
|
29
35
|
/* TODO: Make the layout of this button flexible to accommodate different word lengths. Currently hard-coded for English: “Cancel” */
|
|
30
36
|
}
|
|
31
37
|
<button data-close-modal class="sl-flex md:sl-hidden">
|
|
32
|
-
{
|
|
38
|
+
{labels['search.cancelLabel']}
|
|
33
39
|
</button>
|
|
34
40
|
{
|
|
35
41
|
import.meta.env.DEV ? (
|
|
36
42
|
<div style="margin: auto; text-align: center; white-space: pre-line;" dir="ltr">
|
|
37
|
-
<p>{
|
|
43
|
+
<p>{labels['search.devWarning']}</p>
|
|
38
44
|
</div>
|
|
39
45
|
) : (
|
|
40
46
|
<div class="search-container">
|
|
@@ -7,17 +7,19 @@ interface Props {
|
|
|
7
7
|
sublist: SidebarEntry[];
|
|
8
8
|
nested?: boolean;
|
|
9
9
|
}
|
|
10
|
+
|
|
11
|
+
const { sublist, nested } = Astro.props;
|
|
10
12
|
---
|
|
11
13
|
|
|
12
|
-
<ul class:list={{ 'top-level': !
|
|
14
|
+
<ul class:list={{ 'top-level': !nested }}>
|
|
13
15
|
{
|
|
14
|
-
|
|
16
|
+
sublist.map((entry) => (
|
|
15
17
|
<li>
|
|
16
18
|
{entry.type === 'link' ? (
|
|
17
19
|
<a
|
|
18
20
|
href={entry.href}
|
|
19
21
|
aria-current={entry.isCurrent && 'page'}
|
|
20
|
-
class:list={[{ large: !
|
|
22
|
+
class:list={[{ large: !nested }, entry.attrs.class]}
|
|
21
23
|
{...entry.attrs}
|
|
22
24
|
>
|
|
23
25
|
<span>{entry.label}</span>
|
|
@@ -1,12 +1,11 @@
|
|
|
1
1
|
---
|
|
2
2
|
import { PAGE_TITLE_ID } from '../constants';
|
|
3
|
-
import { useTranslations } from '../utils/translations';
|
|
4
3
|
import type { Props } from '../props';
|
|
5
4
|
|
|
6
|
-
const
|
|
5
|
+
const { labels } = Astro.props;
|
|
7
6
|
---
|
|
8
7
|
|
|
9
|
-
<a href={`#${PAGE_TITLE_ID}`}>{
|
|
8
|
+
<a href={`#${PAGE_TITLE_ID}`}>{labels['skipLink.label']}</a>
|
|
10
9
|
|
|
11
10
|
<style>
|
|
12
11
|
a {
|
|
@@ -1,17 +1,15 @@
|
|
|
1
1
|
---
|
|
2
|
-
import { useTranslations } from '../utils/translations';
|
|
3
2
|
import TableOfContentsList from './TableOfContents/TableOfContentsList.astro';
|
|
4
3
|
import type { Props } from '../props';
|
|
5
4
|
|
|
6
|
-
const {
|
|
7
|
-
const t = useTranslations(locale);
|
|
5
|
+
const { labels, toc } = Astro.props;
|
|
8
6
|
---
|
|
9
7
|
|
|
10
8
|
{
|
|
11
9
|
toc && (
|
|
12
10
|
<starlight-toc data-min-h={toc.minHeadingLevel} data-max-h={toc.maxHeadingLevel}>
|
|
13
11
|
<nav aria-labelledby="starlight__on-this-page">
|
|
14
|
-
<h2 id="starlight__on-this-page">{
|
|
12
|
+
<h2 id="starlight__on-this-page">{labels['tableOfContents.onThisPage']}</h2>
|
|
15
13
|
<TableOfContentsList toc={toc.items} />
|
|
16
14
|
</nav>
|
|
17
15
|
</starlight-toc>
|
|
@@ -1,21 +1,20 @@
|
|
|
1
1
|
---
|
|
2
|
-
import { useTranslations } from '../utils/translations';
|
|
3
2
|
import Select from './Select.astro';
|
|
4
3
|
import type { Props } from '../props';
|
|
5
4
|
|
|
6
|
-
const
|
|
5
|
+
const { labels } = Astro.props;
|
|
7
6
|
---
|
|
8
7
|
|
|
9
8
|
<starlight-theme-select>
|
|
10
9
|
{/* TODO: Can we give this select a width that works well for each language’s strings? */}
|
|
11
10
|
<Select
|
|
12
11
|
icon="laptop"
|
|
13
|
-
label={
|
|
12
|
+
label={labels['themeSelect.accessibleLabel']}
|
|
14
13
|
value="auto"
|
|
15
14
|
options={[
|
|
16
|
-
{ label:
|
|
17
|
-
{ label:
|
|
18
|
-
{ label:
|
|
15
|
+
{ label: labels['themeSelect.dark'], selected: false, value: 'dark' },
|
|
16
|
+
{ label: labels['themeSelect.light'], selected: false, value: 'light' },
|
|
17
|
+
{ label: labels['themeSelect.auto'], selected: true, value: 'auto' },
|
|
19
18
|
]}
|
|
20
19
|
width="6.25em"
|
|
21
20
|
/>
|
package/index.ts
CHANGED
|
@@ -4,31 +4,41 @@ import { spawn } from 'node:child_process';
|
|
|
4
4
|
import { dirname, relative } from 'node:path';
|
|
5
5
|
import { fileURLToPath } from 'node:url';
|
|
6
6
|
import { starlightAsides } from './integrations/asides';
|
|
7
|
-
import { starlightExpressiveCode } from './integrations/expressive-code';
|
|
7
|
+
import { starlightExpressiveCode } from './integrations/expressive-code/index';
|
|
8
8
|
import { starlightSitemap } from './integrations/sitemap';
|
|
9
9
|
import { vitePluginStarlightUserConfig } from './integrations/virtual-user-config';
|
|
10
|
-
import { errorMap } from './utils/error-map';
|
|
11
|
-
import { StarlightConfigSchema, type StarlightUserConfig } from './utils/user-config';
|
|
12
10
|
import { rehypeRtlCodeSupport } from './integrations/code-rtl-support';
|
|
13
11
|
import { createTranslationSystemFromFs } from './utils/translations-fs';
|
|
12
|
+
import { runPlugins, type StarlightUserConfigWithPlugins } from './utils/plugins';
|
|
13
|
+
import type { StarlightConfig } from './types';
|
|
14
14
|
|
|
15
|
-
export default function StarlightIntegration(
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
parsedConfig.error.issues.map((i) => i.message).join('\n')
|
|
22
|
-
);
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
const userConfig = parsedConfig.data;
|
|
26
|
-
|
|
27
|
-
const Starlight: AstroIntegration = {
|
|
15
|
+
export default function StarlightIntegration({
|
|
16
|
+
plugins,
|
|
17
|
+
...opts
|
|
18
|
+
}: StarlightUserConfigWithPlugins): AstroIntegration {
|
|
19
|
+
let userConfig: StarlightConfig;
|
|
20
|
+
return {
|
|
28
21
|
name: '@astrojs/starlight',
|
|
29
22
|
hooks: {
|
|
30
|
-
'astro:config:setup': ({
|
|
31
|
-
|
|
23
|
+
'astro:config:setup': async ({
|
|
24
|
+
command,
|
|
25
|
+
config,
|
|
26
|
+
injectRoute,
|
|
27
|
+
isRestart,
|
|
28
|
+
logger,
|
|
29
|
+
updateConfig,
|
|
30
|
+
}) => {
|
|
31
|
+
// Run plugins to get the final configuration and any extra Astro integrations to load.
|
|
32
|
+
const { integrations, starlightConfig } = await runPlugins(opts, plugins, {
|
|
33
|
+
command,
|
|
34
|
+
config,
|
|
35
|
+
isRestart,
|
|
36
|
+
logger,
|
|
37
|
+
});
|
|
38
|
+
userConfig = starlightConfig;
|
|
39
|
+
|
|
40
|
+
const useTranslations = createTranslationSystemFromFs(starlightConfig, config);
|
|
41
|
+
|
|
32
42
|
injectRoute({
|
|
33
43
|
pattern: '404',
|
|
34
44
|
entryPoint: '@astrojs/starlight/404.astro',
|
|
@@ -37,34 +47,28 @@ export default function StarlightIntegration(opts: StarlightUserConfig): AstroIn
|
|
|
37
47
|
pattern: '[...slug]',
|
|
38
48
|
entryPoint: '@astrojs/starlight/index.astro',
|
|
39
49
|
});
|
|
40
|
-
|
|
41
|
-
|
|
50
|
+
// Add built-in integrations only if they are not already added by the user through the
|
|
51
|
+
// config or by a plugin.
|
|
52
|
+
const allIntegrations = [...config.integrations, ...integrations];
|
|
53
|
+
if (!allIntegrations.find(({ name }) => name === 'astro-expressive-code')) {
|
|
42
54
|
integrations.push(
|
|
43
|
-
...starlightExpressiveCode({
|
|
44
|
-
starlightConfig: userConfig,
|
|
45
|
-
astroConfig: config,
|
|
46
|
-
useTranslations,
|
|
47
|
-
})
|
|
55
|
+
...starlightExpressiveCode({ starlightConfig, astroConfig: config, useTranslations })
|
|
48
56
|
);
|
|
49
57
|
}
|
|
50
|
-
if (!
|
|
51
|
-
integrations.push(starlightSitemap(
|
|
58
|
+
if (!allIntegrations.find(({ name }) => name === '@astrojs/sitemap')) {
|
|
59
|
+
integrations.push(starlightSitemap(starlightConfig));
|
|
52
60
|
}
|
|
53
|
-
if (!
|
|
61
|
+
if (!allIntegrations.find(({ name }) => name === '@astrojs/mdx')) {
|
|
54
62
|
integrations.push(mdx());
|
|
55
63
|
}
|
|
56
64
|
const newConfig: AstroUserConfig = {
|
|
57
65
|
integrations,
|
|
58
66
|
vite: {
|
|
59
|
-
plugins: [vitePluginStarlightUserConfig(
|
|
67
|
+
plugins: [vitePluginStarlightUserConfig(starlightConfig, config)],
|
|
60
68
|
},
|
|
61
69
|
markdown: {
|
|
62
70
|
remarkPlugins: [
|
|
63
|
-
...starlightAsides({
|
|
64
|
-
starlightConfig: userConfig,
|
|
65
|
-
astroConfig: config,
|
|
66
|
-
useTranslations,
|
|
67
|
-
}),
|
|
71
|
+
...starlightAsides({ starlightConfig, astroConfig: config, useTranslations }),
|
|
68
72
|
],
|
|
69
73
|
rehypePlugins: [rehypeRtlCodeSupport()],
|
|
70
74
|
shikiConfig:
|
|
@@ -77,6 +81,7 @@ export default function StarlightIntegration(opts: StarlightUserConfig): AstroIn
|
|
|
77
81
|
},
|
|
78
82
|
|
|
79
83
|
'astro:build:done': ({ dir }) => {
|
|
84
|
+
if (!userConfig.pagefind) return;
|
|
80
85
|
const targetDir = fileURLToPath(dir);
|
|
81
86
|
const cwd = dirname(fileURLToPath(import.meta.url));
|
|
82
87
|
const relativeDir = relative(cwd, targetDir);
|
|
@@ -90,6 +95,4 @@ export default function StarlightIntegration(opts: StarlightUserConfig): AstroIn
|
|
|
90
95
|
},
|
|
91
96
|
},
|
|
92
97
|
};
|
|
93
|
-
|
|
94
|
-
return Starlight;
|
|
95
98
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@astrojs/starlight",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.14.0",
|
|
4
4
|
"description": "Build beautiful, high-performance documentation websites with Astro",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"docs",
|
|
@@ -170,7 +170,7 @@
|
|
|
170
170
|
},
|
|
171
171
|
"dependencies": {
|
|
172
172
|
"@astrojs/mdx": "^1.1.0",
|
|
173
|
-
"@astrojs/sitemap": "^3.0.
|
|
173
|
+
"@astrojs/sitemap": "^3.0.3",
|
|
174
174
|
"@pagefind/default-ui": "^1.0.3",
|
|
175
175
|
"@types/mdast": "^3.0.11",
|
|
176
176
|
"astro-expressive-code": "^0.29.0",
|
package/schema.ts
CHANGED
|
@@ -8,100 +8,153 @@ import { HeroSchema } from './schemas/hero';
|
|
|
8
8
|
import { SidebarLinkItemHTMLAttributesSchema } from './schemas/sidebar';
|
|
9
9
|
export { i18nSchema } from './schemas/i18n';
|
|
10
10
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
11
|
+
/** Default content collection schema for Starlight’s `docs` collection. */
|
|
12
|
+
const StarlightFrontmatterSchema = (context: SchemaContext) =>
|
|
13
|
+
z.object({
|
|
14
|
+
/** The title of the current page. Required. */
|
|
15
|
+
title: z.string(),
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* A short description of the current page’s content. Optional, but recommended.
|
|
19
|
+
* A good description is 150–160 characters long and outlines the key content
|
|
20
|
+
* of the page in a clear and engaging way.
|
|
21
|
+
*/
|
|
22
|
+
description: z.string().optional(),
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Custom URL where a reader can edit this page.
|
|
26
|
+
* Overrides the `editLink.baseUrl` global config if set.
|
|
27
|
+
*
|
|
28
|
+
* Can also be set to `false` to disable showing an edit link on this page.
|
|
29
|
+
*/
|
|
30
|
+
editUrl: z.union([z.string().url(), z.boolean()]).optional().default(true),
|
|
31
|
+
|
|
32
|
+
/** Set custom `<head>` tags just for this page. */
|
|
33
|
+
head: HeadConfigSchema(),
|
|
34
|
+
|
|
35
|
+
/** Override global table of contents configuration for this page. */
|
|
36
|
+
tableOfContents: TableOfContentsSchema().optional(),
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Set the layout style for this page.
|
|
40
|
+
* Can be `'doc'` (the default) or `'splash'` for a wider layout without any sidebars.
|
|
41
|
+
*/
|
|
42
|
+
template: z.enum(['doc', 'splash']).default('doc'),
|
|
43
|
+
|
|
44
|
+
/** Display a hero section on this page. */
|
|
45
|
+
hero: HeroSchema(context).optional(),
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* The last update date of the current page.
|
|
49
|
+
* Overrides the `lastUpdated` global config or the date generated from the Git history.
|
|
50
|
+
*/
|
|
51
|
+
lastUpdated: z.union([z.date(), z.boolean()]).optional(),
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* The previous navigation link configuration.
|
|
55
|
+
* Overrides the `pagination` global config or the link text and/or URL.
|
|
56
|
+
*/
|
|
57
|
+
prev: PrevNextLinkConfigSchema(),
|
|
58
|
+
/**
|
|
59
|
+
* The next navigation link configuration.
|
|
60
|
+
* Overrides the `pagination` global config or the link text and/or URL.
|
|
61
|
+
*/
|
|
62
|
+
next: PrevNextLinkConfigSchema(),
|
|
63
|
+
|
|
64
|
+
sidebar: z
|
|
65
|
+
.object({
|
|
66
|
+
/**
|
|
67
|
+
* The order of this page in the navigation.
|
|
68
|
+
* Pages are sorted by this value in ascending order. Then by slug.
|
|
69
|
+
* If not provided, pages will be sorted alphabetically by slug.
|
|
70
|
+
* If two pages have the same order value, they will be sorted alphabetically by slug.
|
|
71
|
+
*/
|
|
72
|
+
order: z.number().optional(),
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* The label for this page in the navigation.
|
|
76
|
+
* Defaults to the page `title` if not set.
|
|
77
|
+
*/
|
|
78
|
+
label: z.string().optional(),
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Prevents this page from being included in autogenerated sidebar groups.
|
|
82
|
+
*/
|
|
83
|
+
hidden: z.boolean().default(false),
|
|
84
|
+
/**
|
|
85
|
+
* Adds a badge to the sidebar link.
|
|
86
|
+
* Can be a string or an object with a variant and text.
|
|
87
|
+
* Variants include 'note', 'tip', 'caution', 'danger', 'success', and 'default'.
|
|
88
|
+
* Passing only a string defaults to the 'default' variant which uses the site accent color.
|
|
89
|
+
*/
|
|
90
|
+
badge: BadgeConfigSchema(),
|
|
91
|
+
/** HTML attributes to add to the sidebar link. */
|
|
92
|
+
attrs: SidebarLinkItemHTMLAttributesSchema(),
|
|
93
|
+
})
|
|
94
|
+
.default({}),
|
|
95
|
+
|
|
96
|
+
/** Display an announcement banner at the top of this page. */
|
|
97
|
+
banner: z
|
|
98
|
+
.object({
|
|
99
|
+
/** The content of the banner. Supports HTML syntax. */
|
|
100
|
+
content: z.string(),
|
|
101
|
+
})
|
|
102
|
+
.optional(),
|
|
103
|
+
|
|
104
|
+
/** Pagefind indexing for this page - set to false to disable. */
|
|
105
|
+
pagefind: z.boolean().default(true),
|
|
106
|
+
});
|
|
107
|
+
/** Type of Starlight’s default frontmatter schema. */
|
|
108
|
+
type DefaultSchema = ReturnType<typeof StarlightFrontmatterSchema>;
|
|
109
|
+
|
|
110
|
+
/** Plain object, union, and intersection Zod types. */
|
|
111
|
+
type BaseSchemaWithoutEffects =
|
|
112
|
+
| z.AnyZodObject
|
|
113
|
+
| z.ZodUnion<[BaseSchemaWithoutEffects, ...BaseSchemaWithoutEffects[]]>
|
|
114
|
+
| z.ZodDiscriminatedUnion<string, z.AnyZodObject[]>
|
|
115
|
+
| z.ZodIntersection<BaseSchemaWithoutEffects, BaseSchemaWithoutEffects>;
|
|
116
|
+
/** Base subset of Zod types that we support passing to the `extend` option. */
|
|
117
|
+
type BaseSchema = BaseSchemaWithoutEffects | z.ZodEffects<BaseSchemaWithoutEffects>;
|
|
118
|
+
|
|
119
|
+
/** Type that extends Starlight’s default schema with an optional, user-defined schema. */
|
|
120
|
+
type ExtendedSchema<T extends BaseSchema> = T extends BaseSchema
|
|
121
|
+
? z.ZodIntersection<DefaultSchema, T>
|
|
122
|
+
: DefaultSchema;
|
|
123
|
+
|
|
124
|
+
interface DocsSchemaOpts<T extends BaseSchema> {
|
|
125
|
+
/**
|
|
126
|
+
* Extend Starlight’s schema with additional fields.
|
|
127
|
+
*
|
|
128
|
+
* @example
|
|
129
|
+
* // Extend the built-in schema with a Zod schema.
|
|
130
|
+
* docsSchema({
|
|
131
|
+
* extend: z.object({
|
|
132
|
+
* // Add a new field to the schema.
|
|
133
|
+
* category: z.enum(['tutorial', 'guide', 'reference']).optional(),
|
|
134
|
+
* }),
|
|
135
|
+
* })
|
|
136
|
+
*
|
|
137
|
+
* // Use the Astro image helper.
|
|
138
|
+
* docsSchema({
|
|
139
|
+
* extend: ({ image }) => {
|
|
140
|
+
* return z.object({
|
|
141
|
+
* cover: image(),
|
|
142
|
+
* });
|
|
143
|
+
* },
|
|
144
|
+
* })
|
|
145
|
+
*/
|
|
146
|
+
extend?: T | ((context: SchemaContext) => T);
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/** Content collection schema for Starlight’s `docs` collection. */
|
|
150
|
+
export function docsSchema<T extends BaseSchema>({ extend }: DocsSchemaOpts<T> = {}) {
|
|
151
|
+
return (context: SchemaContext): ExtendedSchema<T> => {
|
|
152
|
+
const UserSchema = typeof extend === 'function' ? extend(context) : extend;
|
|
153
|
+
|
|
154
|
+
return (
|
|
155
|
+
UserSchema
|
|
156
|
+
? StarlightFrontmatterSchema(context).and(UserSchema)
|
|
157
|
+
: StarlightFrontmatterSchema(context)
|
|
158
|
+
) as ExtendedSchema<T>;
|
|
159
|
+
};
|
|
107
160
|
}
|
package/schemas/i18n.ts
CHANGED
|
@@ -1,7 +1,31 @@
|
|
|
1
1
|
import { z } from 'astro/zod';
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
3
|
+
interface i18nSchemaOpts<T extends z.AnyZodObject = z.ZodObject<{}>> {
|
|
4
|
+
/**
|
|
5
|
+
* Extend Starlight’s i18n schema with additional fields.
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* // Add two optional fields to the default schema.
|
|
9
|
+
* i18nSchema({
|
|
10
|
+
* extend: z
|
|
11
|
+
* .object({
|
|
12
|
+
* 'customUi.heading': z.string(),
|
|
13
|
+
* 'customUi.text': z.string(),
|
|
14
|
+
* })
|
|
15
|
+
* .partial(),
|
|
16
|
+
* })
|
|
17
|
+
*/
|
|
18
|
+
extend?: T;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/** Content collection schema for Starlight’s optional `i18n` collection. */
|
|
22
|
+
export function i18nSchema<T extends z.AnyZodObject = z.ZodObject<{}>>({
|
|
23
|
+
extend = z.object({}) as T,
|
|
24
|
+
}: i18nSchemaOpts<T> = {}) {
|
|
25
|
+
return starlightI18nSchema()
|
|
26
|
+
.merge(pagefindI18nSchema())
|
|
27
|
+
.merge(expressiveCodeI18nSchema())
|
|
28
|
+
.merge(extend);
|
|
5
29
|
}
|
|
6
30
|
export type i18nSchemaOutput = z.output<ReturnType<typeof i18nSchema>>;
|
|
7
31
|
|
package/translations/hi.json
CHANGED
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
"sidebarNav.accessibleLabel": "मुख्य",
|
|
14
14
|
"tableOfContents.onThisPage": "इस पृष्ठ पर",
|
|
15
15
|
"tableOfContents.overview": "अवलोकन",
|
|
16
|
-
"i18n.untranslatedContent": "यह कंटेंट अभी तक आपकी भाषा में उपलब्ध नहीं
|
|
16
|
+
"i18n.untranslatedContent": "यह कंटेंट अभी तक आपकी भाषा में उपलब्ध नहीं है।",
|
|
17
17
|
"page.editLink": "पृष्ठ संपादित करें",
|
|
18
18
|
"page.lastUpdated": "आखिरी अद्यतन:",
|
|
19
19
|
"page.previousLink": "पिछला",
|
package/types.ts
CHANGED
|
@@ -19,10 +19,16 @@ export function createTranslationSystem(
|
|
|
19
19
|
|
|
20
20
|
/**
|
|
21
21
|
* Generate a utility function that returns UI strings for the given `locale`.
|
|
22
|
+
*
|
|
23
|
+
* Also includes an `all()` method for getting the entire dictionary.
|
|
24
|
+
*
|
|
22
25
|
* @param {string | undefined} [locale]
|
|
23
26
|
* @example
|
|
24
27
|
* const t = useTranslations('en');
|
|
25
|
-
* const label = t('search.label');
|
|
28
|
+
* const label = t('search.label');
|
|
29
|
+
* // => 'Search'
|
|
30
|
+
* const dictionary = t.all();
|
|
31
|
+
* // => { 'skipLink.label': 'Skip to content', 'search.label': 'Search', ... }
|
|
26
32
|
*/
|
|
27
33
|
return function useTranslations(locale: string | undefined) {
|
|
28
34
|
const lang = localeToLang(locale, config.locales, config.defaultLocale);
|
|
@@ -32,8 +38,7 @@ export function createTranslationSystem(
|
|
|
32
38
|
userTranslations[lang]
|
|
33
39
|
);
|
|
34
40
|
const t = <K extends keyof typeof dictionary>(key: K) => dictionary[key];
|
|
35
|
-
t.
|
|
36
|
-
Object.fromEntries(Object.entries(dictionary).filter(([k]) => k.startsWith(startOfKey)));
|
|
41
|
+
t.all = () => dictionary;
|
|
37
42
|
return t;
|
|
38
43
|
};
|
|
39
44
|
}
|
package/utils/plugins.ts
ADDED
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
import type { AstroIntegration } from 'astro';
|
|
2
|
+
import { z } from 'astro/zod';
|
|
3
|
+
import { StarlightConfigSchema, type StarlightUserConfig } from '../utils/user-config';
|
|
4
|
+
import { errorMap } from '../utils/error-map';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Runs Starlight plugins in the order that they are configured after validating the user-provided
|
|
8
|
+
* configuration and returns the final validated user config that may have been updated by the
|
|
9
|
+
* plugins and a list of any integrations added by the plugins.
|
|
10
|
+
*/
|
|
11
|
+
export async function runPlugins(
|
|
12
|
+
starlightUserConfig: StarlightUserConfig,
|
|
13
|
+
pluginsUserConfig: StarlightPluginsUserConfig,
|
|
14
|
+
context: StarlightPluginContext
|
|
15
|
+
) {
|
|
16
|
+
// Validate the user-provided configuration.
|
|
17
|
+
let userConfig = starlightUserConfig;
|
|
18
|
+
let starlightConfig = StarlightConfigSchema.safeParse(userConfig, { errorMap });
|
|
19
|
+
|
|
20
|
+
if (!starlightConfig.success) {
|
|
21
|
+
throwValidationError(starlightConfig.error, 'Invalid config passed to starlight integration');
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
// Validate the user-provided plugins configuration.
|
|
25
|
+
const pluginsConfig = starlightPluginsConfigSchema.safeParse(pluginsUserConfig, {
|
|
26
|
+
errorMap,
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
if (!pluginsConfig.success) {
|
|
30
|
+
throwValidationError(
|
|
31
|
+
pluginsConfig.error,
|
|
32
|
+
'Invalid plugins config passed to starlight integration'
|
|
33
|
+
);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// A list of Astro integrations added by the various plugins.
|
|
37
|
+
const integrations: AstroIntegration[] = [];
|
|
38
|
+
|
|
39
|
+
for (const {
|
|
40
|
+
name,
|
|
41
|
+
hooks: { setup },
|
|
42
|
+
} of pluginsConfig.data) {
|
|
43
|
+
await setup({
|
|
44
|
+
config: pluginsUserConfig ? { ...userConfig, plugins: pluginsUserConfig } : userConfig,
|
|
45
|
+
updateConfig(newConfig) {
|
|
46
|
+
// Ensure that plugins do not update the `plugins` config key.
|
|
47
|
+
if ('plugins' in newConfig) {
|
|
48
|
+
throw new Error(
|
|
49
|
+
`The '${name}' plugin tried to update the 'plugins' config key which is not supported.`
|
|
50
|
+
);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// If the plugin is updating the user config, re-validate it.
|
|
54
|
+
const mergedUserConfig = { ...userConfig, ...newConfig };
|
|
55
|
+
const mergedConfig = StarlightConfigSchema.safeParse(mergedUserConfig, { errorMap });
|
|
56
|
+
|
|
57
|
+
if (!mergedConfig.success) {
|
|
58
|
+
throwValidationError(
|
|
59
|
+
mergedConfig.error,
|
|
60
|
+
`Invalid config update provided by the '${name}' plugin`
|
|
61
|
+
);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// If the updated config is valid, keep track of both the user config and parsed config.
|
|
65
|
+
userConfig = mergedUserConfig;
|
|
66
|
+
starlightConfig = mergedConfig;
|
|
67
|
+
},
|
|
68
|
+
addIntegration(integration) {
|
|
69
|
+
// Collect any Astro integrations added by the plugin.
|
|
70
|
+
integrations.push(integration);
|
|
71
|
+
},
|
|
72
|
+
astroConfig: {
|
|
73
|
+
...context.config,
|
|
74
|
+
integrations: [...context.config.integrations, ...integrations],
|
|
75
|
+
},
|
|
76
|
+
command: context.command,
|
|
77
|
+
isRestart: context.isRestart,
|
|
78
|
+
logger: context.logger.fork(name),
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
return { integrations, starlightConfig: starlightConfig.data };
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
function throwValidationError(error: z.ZodError, message: string): never {
|
|
86
|
+
throw new Error(`${message}\n${error.issues.map((i) => i.message).join('\n')}`);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// https://github.com/withastro/astro/blob/910eb00fe0b70ca80bd09520ae100e8c78b675b5/packages/astro/src/core/config/schema.ts#L113
|
|
90
|
+
const astroIntegrationSchema = z.object({
|
|
91
|
+
name: z.string(),
|
|
92
|
+
hooks: z.object({}).passthrough().default({}),
|
|
93
|
+
}) as z.Schema<AstroIntegration>;
|
|
94
|
+
|
|
95
|
+
const baseStarlightPluginSchema = z.object({
|
|
96
|
+
/** Name of the Starlight plugin. */
|
|
97
|
+
name: z.string(),
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* A plugin `config` and `updateConfig` argument are purposely not validated using the Starlight
|
|
102
|
+
* user config schema but properly typed for user convenience because we do not want to run any of
|
|
103
|
+
* the Zod `transform`s used in the user config schema when running plugins.
|
|
104
|
+
*/
|
|
105
|
+
const starlightPluginSchema = baseStarlightPluginSchema.extend({
|
|
106
|
+
/** The different hooks available to the plugin. */
|
|
107
|
+
hooks: z.object({
|
|
108
|
+
/**
|
|
109
|
+
* Plugin setup function called with an object containing various values that can be used by
|
|
110
|
+
* the plugin to interact with Starlight.
|
|
111
|
+
*/
|
|
112
|
+
setup: z.function(
|
|
113
|
+
z.tuple([
|
|
114
|
+
z.object({
|
|
115
|
+
/**
|
|
116
|
+
* A read-only copy of the user-supplied Starlight configuration.
|
|
117
|
+
*
|
|
118
|
+
* Note that this configuration may have been updated by other plugins configured
|
|
119
|
+
* before this one.
|
|
120
|
+
*/
|
|
121
|
+
config: z.any() as z.Schema<
|
|
122
|
+
// The configuration passed to plugins should contains the list of plugins.
|
|
123
|
+
StarlightUserConfig & { plugins?: z.input<typeof baseStarlightPluginSchema>[] }
|
|
124
|
+
>,
|
|
125
|
+
/**
|
|
126
|
+
* A callback function to update the user-supplied Starlight configuration.
|
|
127
|
+
*
|
|
128
|
+
* You only need to provide the configuration values that you want to update but no deep
|
|
129
|
+
* merge is performed.
|
|
130
|
+
*
|
|
131
|
+
* @example
|
|
132
|
+
* {
|
|
133
|
+
* name: 'My Starlight Plugin',
|
|
134
|
+
* hooks: {
|
|
135
|
+
* setup({ updateConfig }) {
|
|
136
|
+
* updateConfig({
|
|
137
|
+
* description: 'Custom description',
|
|
138
|
+
* });
|
|
139
|
+
* }
|
|
140
|
+
* }
|
|
141
|
+
* }
|
|
142
|
+
*/
|
|
143
|
+
updateConfig: z.function(
|
|
144
|
+
z.tuple([z.record(z.any()) as z.Schema<Partial<StarlightUserConfig>>]),
|
|
145
|
+
z.void()
|
|
146
|
+
),
|
|
147
|
+
/**
|
|
148
|
+
* A callback function to add an Astro integration required by this plugin.
|
|
149
|
+
*
|
|
150
|
+
* @see https://docs.astro.build/en/reference/integrations-reference/
|
|
151
|
+
*
|
|
152
|
+
* @example
|
|
153
|
+
* {
|
|
154
|
+
* name: 'My Starlight Plugin',
|
|
155
|
+
* hooks: {
|
|
156
|
+
* setup({ addIntegration }) {
|
|
157
|
+
* addIntegration({
|
|
158
|
+
* name: 'My Plugin Astro Integration',
|
|
159
|
+
* hooks: {
|
|
160
|
+
* 'astro:config:setup': () => {
|
|
161
|
+
* // …
|
|
162
|
+
* },
|
|
163
|
+
* },
|
|
164
|
+
* });
|
|
165
|
+
* }
|
|
166
|
+
* }
|
|
167
|
+
* }
|
|
168
|
+
*/
|
|
169
|
+
addIntegration: z.function(z.tuple([astroIntegrationSchema]), z.void()),
|
|
170
|
+
/**
|
|
171
|
+
* A read-only copy of the user-supplied Astro configuration.
|
|
172
|
+
*
|
|
173
|
+
* Note that this configuration is resolved before any other integrations have run.
|
|
174
|
+
*
|
|
175
|
+
* @see https://docs.astro.build/en/reference/integrations-reference/#config-option
|
|
176
|
+
*/
|
|
177
|
+
astroConfig: z.any() as z.Schema<StarlightPluginContext['config']>,
|
|
178
|
+
/**
|
|
179
|
+
* The command used to run Starlight.
|
|
180
|
+
*
|
|
181
|
+
* @see https://docs.astro.build/en/reference/integrations-reference/#command-option
|
|
182
|
+
*/
|
|
183
|
+
command: z.any() as z.Schema<StarlightPluginContext['command']>,
|
|
184
|
+
/**
|
|
185
|
+
* `false` when the dev server starts, `true` when a reload is triggered.
|
|
186
|
+
*
|
|
187
|
+
* @see https://docs.astro.build/en/reference/integrations-reference/#isrestart-option
|
|
188
|
+
*/
|
|
189
|
+
isRestart: z.any() as z.Schema<StarlightPluginContext['isRestart']>,
|
|
190
|
+
/**
|
|
191
|
+
* An instance of the Astro integration logger with all logged messages prefixed with the
|
|
192
|
+
* plugin name.
|
|
193
|
+
*
|
|
194
|
+
* @see https://docs.astro.build/en/reference/integrations-reference/#astrointegrationlogger
|
|
195
|
+
*/
|
|
196
|
+
logger: z.any() as z.Schema<StarlightPluginContext['logger']>,
|
|
197
|
+
}),
|
|
198
|
+
]),
|
|
199
|
+
z.union([z.void(), z.promise(z.void())])
|
|
200
|
+
),
|
|
201
|
+
}),
|
|
202
|
+
});
|
|
203
|
+
|
|
204
|
+
const starlightPluginsConfigSchema = z.array(starlightPluginSchema).default([]);
|
|
205
|
+
|
|
206
|
+
type StarlightPluginsUserConfig = z.input<typeof starlightPluginsConfigSchema>;
|
|
207
|
+
|
|
208
|
+
export type StarlightPlugin = z.input<typeof starlightPluginSchema>;
|
|
209
|
+
|
|
210
|
+
export type StarlightUserConfigWithPlugins = StarlightUserConfig & {
|
|
211
|
+
/**
|
|
212
|
+
* A list of plugins to extend Starlight with.
|
|
213
|
+
*
|
|
214
|
+
* @example
|
|
215
|
+
* // Add Starlight Algolia plugin.
|
|
216
|
+
* starlight({
|
|
217
|
+
* plugins: [starlightAlgolia({ … })],
|
|
218
|
+
* })
|
|
219
|
+
*/
|
|
220
|
+
plugins?: StarlightPluginsUserConfig;
|
|
221
|
+
};
|
|
222
|
+
|
|
223
|
+
export type StarlightPluginContext = Pick<
|
|
224
|
+
Parameters<NonNullable<AstroIntegration['hooks']['astro:config:setup']>>[0],
|
|
225
|
+
'command' | 'config' | 'isRestart' | 'logger'
|
|
226
|
+
>;
|
package/utils/route-data.ts
CHANGED
|
@@ -29,6 +29,8 @@ export interface StarlightRouteData extends Route {
|
|
|
29
29
|
lastUpdated: Date | undefined;
|
|
30
30
|
/** URL object for the address where this page can be edited if enabled. */
|
|
31
31
|
editUrl: URL | undefined;
|
|
32
|
+
/** Record of UI strings localized for the current page. */
|
|
33
|
+
labels: ReturnType<ReturnType<typeof useTranslations>['all']>;
|
|
32
34
|
}
|
|
33
35
|
|
|
34
36
|
export function generateRouteData({
|
|
@@ -48,6 +50,7 @@ export function generateRouteData({
|
|
|
48
50
|
toc: getToC(props),
|
|
49
51
|
lastUpdated: getLastUpdated(props),
|
|
50
52
|
editUrl: getEditUrl(props),
|
|
53
|
+
labels: useTranslations(locale).all(),
|
|
51
54
|
};
|
|
52
55
|
}
|
|
53
56
|
|
package/utils/user-config.ts
CHANGED
|
@@ -190,6 +190,13 @@ const UserConfigSchema = z.object({
|
|
|
190
190
|
*/
|
|
191
191
|
expressiveCode: ExpressiveCodeSchema(),
|
|
192
192
|
|
|
193
|
+
/**
|
|
194
|
+
* Define whether Starlight’s default site search provider Pagefind is enabled.
|
|
195
|
+
* Set to `false` to disable indexing your site with Pagefind.
|
|
196
|
+
* This will also hide the default search UI if in use.
|
|
197
|
+
*/
|
|
198
|
+
pagefind: z.boolean().default(true),
|
|
199
|
+
|
|
193
200
|
/** Specify paths to components that should override Starlight’s default components */
|
|
194
201
|
components: ComponentConfigSchema(),
|
|
195
202
|
|