@astrojs/starlight 0.5.6 → 0.6.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 +17 -17
- package/CHANGELOG.md +40 -2
- package/components/CallToAction.astro +32 -35
- package/components/ContentPanel.astro +18 -18
- package/components/EditLink.astro +23 -23
- package/components/FallbackContentNotice.astro +16 -18
- package/components/Footer.astro +28 -34
- package/components/HeadSEO.astro +69 -75
- package/components/Header.astro +47 -51
- package/components/Hero.astro +108 -121
- package/components/Icons.ts +73 -71
- package/components/LanguageSelect.astro +31 -31
- package/components/LastUpdated.astro +16 -18
- package/components/MarkdownContent.astro +105 -117
- package/components/MobileMenuToggle.astro +80 -80
- package/components/PrevNextLinks.astro +60 -60
- package/components/RightSidebar.astro +17 -17
- package/components/RightSidebarPanel.astro +41 -41
- package/components/Search.astro +293 -306
- package/components/Select.astro +64 -65
- package/components/Sidebar.astro +23 -23
- package/components/SidebarSublist.astro +96 -95
- package/components/SiteTitle.astro +65 -63
- package/components/SkipLink.astro +17 -17
- package/components/SocialIcons.astro +36 -34
- package/components/TableOfContents/MobileTableOfContents.astro +124 -124
- package/components/TableOfContents/TableOfContentsList.astro +64 -69
- package/components/TableOfContents/generateToC.ts +41 -43
- package/components/TableOfContents/starlight-toc.ts +84 -90
- package/components/TableOfContents.astro +8 -8
- package/components/ThemeProvider.astro +28 -32
- package/components/ThemeSelect.astro +66 -71
- package/global.d.ts +3 -3
- package/index.astro +1 -1
- package/index.ts +52 -59
- package/integrations/asides.ts +109 -111
- package/integrations/sitemap.ts +10 -13
- package/integrations/virtual-user-config.ts +37 -37
- package/layout/Page.astro +84 -72
- package/layout/PageFrame.astro +67 -69
- package/layout/TwoColumnContent.astro +40 -42
- package/package.json +2 -2
- package/schema.ts +126 -113
- package/schemas/favicon.ts +40 -0
- package/schemas/head.ts +12 -23
- package/schemas/i18n.ts +146 -160
- package/schemas/logo.ts +22 -22
- package/schemas/prevNextLink.ts +14 -14
- package/schemas/tableOfContents.ts +14 -18
- package/style/asides.css +27 -27
- package/style/props.css +168 -172
- package/style/reset.css +13 -13
- package/style/shiki.css +11 -11
- package/style/util.css +30 -30
- package/translations/fr.json +21 -21
- package/translations/index.ts +4 -4
- package/translations/it.json +20 -20
- package/translations/tr.json +1 -1
- package/translations/zh.json +0 -1
- package/user-components/Card.astro +50 -54
- package/user-components/CardGrid.astro +21 -21
- package/user-components/Icon.astro +19 -21
- package/user-components/TabItem.astro +3 -3
- package/user-components/Tabs.astro +113 -117
- package/user-components/rehype-tabs.ts +72 -72
- package/utils/base.ts +6 -6
- package/utils/git.ts +55 -55
- package/utils/head.ts +56 -54
- package/utils/i18n.ts +3 -3
- package/utils/localizedUrl.ts +25 -25
- package/utils/navigation.ts +225 -203
- package/utils/routing.ts +74 -85
- package/utils/slugs.ts +41 -51
- package/utils/translations.ts +26 -32
- package/utils/user-config.ts +278 -278
- package/virtual.d.ts +8 -8
|
@@ -1,103 +1,97 @@
|
|
|
1
1
|
export class StarlightTOC extends HTMLElement {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
private minH = parseInt(this.dataset.minH || '2', 10);
|
|
6
|
-
private maxH = parseInt(this.dataset.maxH || '3', 10);
|
|
2
|
+
private _current = this.querySelector('a[aria-current="true"]') as HTMLAnchorElement | null;
|
|
3
|
+
private minH = parseInt(this.dataset.minH || '2', 10);
|
|
4
|
+
private maxH = parseInt(this.dataset.maxH || '3', 10);
|
|
7
5
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
6
|
+
protected set current(link: HTMLAnchorElement) {
|
|
7
|
+
if (link === this._current) return;
|
|
8
|
+
if (this._current) this._current.removeAttribute('aria-current');
|
|
9
|
+
link.setAttribute('aria-current', 'true');
|
|
10
|
+
this._current = link;
|
|
11
|
+
}
|
|
14
12
|
|
|
15
|
-
|
|
16
|
-
|
|
13
|
+
constructor({ smallViewport = false } = {}) {
|
|
14
|
+
super();
|
|
17
15
|
|
|
18
|
-
|
|
19
|
-
|
|
16
|
+
/** All the links in the table of contents. */
|
|
17
|
+
const links = [...this.querySelectorAll('a')];
|
|
20
18
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
19
|
+
/** Test if an element is a table-of-contents heading. */
|
|
20
|
+
const isHeading = (el: Element): el is HTMLHeadingElement => {
|
|
21
|
+
if (el instanceof HTMLHeadingElement) {
|
|
22
|
+
// Special case for page title h1
|
|
23
|
+
if ('pageTitle' in el.dataset) return true;
|
|
24
|
+
// Check the heading level is within the user-configured limits for the ToC
|
|
25
|
+
const level = el.tagName[1];
|
|
26
|
+
if (level) {
|
|
27
|
+
const int = parseInt(level, 10);
|
|
28
|
+
if (int >= this.minH && int <= this.maxH) return true;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
return false;
|
|
32
|
+
};
|
|
35
33
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
return getElementHeading(origin.parentElement);
|
|
55
|
-
};
|
|
34
|
+
/** Walk up the DOM to find the nearest heading. */
|
|
35
|
+
const getElementHeading = (el: Element | null): HTMLHeadingElement | null => {
|
|
36
|
+
if (!el) return null;
|
|
37
|
+
const origin = el;
|
|
38
|
+
while (el) {
|
|
39
|
+
if (isHeading(el)) return el;
|
|
40
|
+
// Assign the previous sibling’s last, most deeply nested child to el.
|
|
41
|
+
el = el.previousElementSibling;
|
|
42
|
+
while (el?.lastElementChild) {
|
|
43
|
+
el = el.lastElementChild;
|
|
44
|
+
}
|
|
45
|
+
// Look for headings amongst siblings.
|
|
46
|
+
const h = getElementHeading(el);
|
|
47
|
+
if (h) return h;
|
|
48
|
+
}
|
|
49
|
+
// Walk back up the parent.
|
|
50
|
+
return getElementHeading(origin.parentElement);
|
|
51
|
+
};
|
|
56
52
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
53
|
+
/** Handle intersections and set the current link to the heading for the current intersection. */
|
|
54
|
+
const setCurrent: IntersectionObserverCallback = (entries) => {
|
|
55
|
+
for (const { isIntersecting, target } of entries) {
|
|
56
|
+
if (!isIntersecting) continue;
|
|
57
|
+
const heading = getElementHeading(target);
|
|
58
|
+
if (!heading) continue;
|
|
59
|
+
const link = links.find((link) => link.hash === '#' + encodeURIComponent(heading.id));
|
|
60
|
+
if (link) {
|
|
61
|
+
this.current = link;
|
|
62
|
+
break;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
};
|
|
70
66
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
/** End intersections 1.5rem later. */
|
|
80
|
-
const bottom = top + 24;
|
|
67
|
+
// Observe elements with an `id` (most likely headings) and their siblings.
|
|
68
|
+
// Also observe direct children of `.content` to include elements before
|
|
69
|
+
// the first heading.
|
|
70
|
+
const toObserve = document.querySelectorAll('main [id], main [id] ~ *, main .content > *');
|
|
71
|
+
/** Start intersections at nav height + 2rem padding. */
|
|
72
|
+
const top = (smallViewport ? 104 : 64) + 32;
|
|
73
|
+
/** End intersections 1.5rem later. */
|
|
74
|
+
const bottom = top + 24;
|
|
81
75
|
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
76
|
+
let observer: IntersectionObserver | undefined;
|
|
77
|
+
function observe() {
|
|
78
|
+
if (observer) observer.disconnect();
|
|
79
|
+
const height = document.documentElement.clientHeight;
|
|
80
|
+
const rootMargin = `-${top}px 0% ${bottom - height}px`;
|
|
81
|
+
observer = new IntersectionObserver(setCurrent, { rootMargin });
|
|
82
|
+
toObserve.forEach((h) => observer!.observe(h));
|
|
83
|
+
}
|
|
84
|
+
observe();
|
|
91
85
|
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
86
|
+
const onIdle = window.requestIdleCallback || ((cb) => setTimeout(cb, 1));
|
|
87
|
+
let timeout: NodeJS.Timeout;
|
|
88
|
+
window.addEventListener('resize', () => {
|
|
89
|
+
// Disable intersection observer while window is resizing.
|
|
90
|
+
if (observer) observer.disconnect();
|
|
91
|
+
clearTimeout(timeout);
|
|
92
|
+
timeout = setTimeout(() => onIdle(observe), 200);
|
|
93
|
+
});
|
|
94
|
+
}
|
|
101
95
|
}
|
|
102
96
|
|
|
103
97
|
customElements.define('starlight-toc', StarlightTOC);
|
|
@@ -4,10 +4,10 @@ import TableOfContentsList from './TableOfContents/TableOfContentsList.astro';
|
|
|
4
4
|
import type { TocItem } from './TableOfContents/generateToC';
|
|
5
5
|
|
|
6
6
|
interface Props {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
7
|
+
toc: TocItem[];
|
|
8
|
+
locale: string | undefined;
|
|
9
|
+
maxHeadingLevel: number;
|
|
10
|
+
minHeadingLevel: number;
|
|
11
11
|
}
|
|
12
12
|
|
|
13
13
|
const { locale, toc, maxHeadingLevel, minHeadingLevel } = Astro.props;
|
|
@@ -15,10 +15,10 @@ const t = useTranslations(locale);
|
|
|
15
15
|
---
|
|
16
16
|
|
|
17
17
|
<starlight-toc data-min-h={minHeadingLevel} data-max-h={maxHeadingLevel}>
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
18
|
+
<nav aria-labelledby="starlight__on-this-page">
|
|
19
|
+
<h2 id="starlight__on-this-page">{t('tableOfContents.onThisPage')}</h2>
|
|
20
|
+
<TableOfContentsList {toc} />
|
|
21
|
+
</nav>
|
|
22
22
|
</starlight-toc>
|
|
23
23
|
|
|
24
24
|
<script src="./TableOfContents/starlight-toc"></script>
|
|
@@ -4,39 +4,35 @@ import Icon from '../user-components/Icon.astro';
|
|
|
4
4
|
|
|
5
5
|
{/* This is intentionally inlined to avoid FOUC. */}
|
|
6
6
|
<script is:inline>
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
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
|
-
})();
|
|
7
|
+
window.StarlightThemeProvider = (() => {
|
|
8
|
+
const storedTheme =
|
|
9
|
+
typeof localStorage !== 'undefined' && localStorage.getItem('starlight-theme');
|
|
10
|
+
const theme =
|
|
11
|
+
storedTheme ||
|
|
12
|
+
(window.matchMedia('(prefers-color-scheme: light)').matches ? 'light' : 'dark');
|
|
13
|
+
document.documentElement.dataset.theme = theme === 'light' ? 'light' : 'dark';
|
|
14
|
+
return {
|
|
15
|
+
updatePickers(theme = storedTheme || 'auto') {
|
|
16
|
+
document.querySelectorAll('starlight-theme-select').forEach((picker) => {
|
|
17
|
+
const select = picker.querySelector('select');
|
|
18
|
+
if (select) select.value = theme;
|
|
19
|
+
/** @type {HTMLTemplateElement | null} */
|
|
20
|
+
const tmpl = document.querySelector(`#theme-icons`);
|
|
21
|
+
const newIcon = tmpl && tmpl.content.querySelector('.' + theme);
|
|
22
|
+
if (newIcon) {
|
|
23
|
+
const oldIcon = picker.querySelector('svg.label-icon');
|
|
24
|
+
if (oldIcon) {
|
|
25
|
+
oldIcon.replaceChildren(...newIcon.cloneNode(true).childNodes);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
});
|
|
29
|
+
},
|
|
30
|
+
};
|
|
31
|
+
})();
|
|
36
32
|
</script>
|
|
37
33
|
|
|
38
34
|
<template id="theme-icons">
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
35
|
+
<Icon name="sun" class="light" />
|
|
36
|
+
<Icon name="moon" class="dark" />
|
|
37
|
+
<Icon name="laptop" class="auto" />
|
|
42
38
|
</template>
|
|
@@ -3,96 +3,91 @@ import { useTranslations } from '../utils/translations';
|
|
|
3
3
|
import Select from './Select.astro';
|
|
4
4
|
|
|
5
5
|
interface Props {
|
|
6
|
-
|
|
6
|
+
locale: string | undefined;
|
|
7
7
|
}
|
|
8
8
|
|
|
9
9
|
const t = useTranslations(Astro.props.locale);
|
|
10
10
|
---
|
|
11
11
|
|
|
12
12
|
<starlight-theme-select>
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
width="6.25em"
|
|
26
|
-
/>
|
|
13
|
+
{/* TODO: Can we give this select a width that works well for each language’s strings? */}
|
|
14
|
+
<Select
|
|
15
|
+
icon="laptop"
|
|
16
|
+
label={t('themeSelect.accessibleLabel')}
|
|
17
|
+
value="auto"
|
|
18
|
+
options={[
|
|
19
|
+
{ label: t('themeSelect.dark'), selected: false, value: 'dark' },
|
|
20
|
+
{ label: t('themeSelect.light'), selected: false, value: 'light' },
|
|
21
|
+
{ label: t('themeSelect.auto'), selected: true, value: 'auto' },
|
|
22
|
+
]}
|
|
23
|
+
width="6.25em"
|
|
24
|
+
/>
|
|
27
25
|
</starlight-theme-select>
|
|
28
26
|
|
|
29
27
|
{/* Inlined to avoid FOUC. Uses global scope from `ThemeProvider.astro` */}
|
|
30
28
|
<script is:inline>
|
|
31
|
-
|
|
29
|
+
StarlightThemeProvider.updatePickers();
|
|
32
30
|
</script>
|
|
33
31
|
|
|
34
32
|
<script>
|
|
35
|
-
|
|
33
|
+
type Theme = 'auto' | 'dark' | 'light';
|
|
36
34
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
35
|
+
class StarlightThemeSelect extends HTMLElement {
|
|
36
|
+
/** Key in `localStorage` to store color theme preference at. */
|
|
37
|
+
#key = 'starlight-theme';
|
|
40
38
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
39
|
+
constructor() {
|
|
40
|
+
super();
|
|
41
|
+
this.#onThemeChange(this.#loadTheme());
|
|
42
|
+
const select = this.querySelector('select');
|
|
43
|
+
if (select) {
|
|
44
|
+
select.addEventListener('change', (e) => {
|
|
45
|
+
if (e.currentTarget instanceof HTMLSelectElement) {
|
|
46
|
+
this.#onThemeChange(this.#parseTheme(e.currentTarget.value));
|
|
47
|
+
}
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
}
|
|
53
51
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
52
|
+
/** Get a typesafe theme string from any JS value (unknown values are coerced to `'auto'`). */
|
|
53
|
+
#parseTheme(theme: unknown): Theme {
|
|
54
|
+
if (theme === 'auto' || theme === 'dark' || theme === 'light') {
|
|
55
|
+
return theme;
|
|
56
|
+
} else {
|
|
57
|
+
return 'auto';
|
|
58
|
+
}
|
|
59
|
+
}
|
|
62
60
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
: 'dark';
|
|
68
|
-
}
|
|
61
|
+
/** Get the preferred system color scheme. */
|
|
62
|
+
#getPreferredColorScheme(): Theme {
|
|
63
|
+
return matchMedia('(prefers-color-scheme: light)').matches ? 'light' : 'dark';
|
|
64
|
+
}
|
|
69
65
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
66
|
+
/** Update select menu UI, document theme, and local storage state. */
|
|
67
|
+
#onThemeChange(theme: Theme): void {
|
|
68
|
+
StarlightThemeProvider.updatePickers(theme);
|
|
69
|
+
document.documentElement.dataset.theme =
|
|
70
|
+
theme === 'auto' ? this.#getPreferredColorScheme() : theme;
|
|
71
|
+
this.#storeTheme(theme);
|
|
72
|
+
}
|
|
77
73
|
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
74
|
+
/** Store the user’s preference in `localStorage`. */
|
|
75
|
+
#storeTheme(theme: Theme): void {
|
|
76
|
+
if (typeof localStorage !== 'undefined') {
|
|
77
|
+
if (theme === 'light' || theme === 'dark') {
|
|
78
|
+
localStorage.setItem(this.#key, theme);
|
|
79
|
+
} else {
|
|
80
|
+
localStorage.removeItem(this.#key);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
}
|
|
88
84
|
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
}
|
|
85
|
+
/** Load the user’s preference from `localStorage`. */
|
|
86
|
+
#loadTheme(): Theme {
|
|
87
|
+
const theme = typeof localStorage !== 'undefined' && localStorage.getItem(this.#key);
|
|
88
|
+
return this.#parseTheme(theme);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
96
91
|
|
|
97
|
-
|
|
92
|
+
customElements.define('starlight-theme-select', StarlightThemeSelect);
|
|
98
93
|
</script>
|
package/global.d.ts
CHANGED
package/index.astro
CHANGED
package/index.ts
CHANGED
|
@@ -7,69 +7,62 @@ import { starlightAsides } from './integrations/asides';
|
|
|
7
7
|
import { starlightSitemap } from './integrations/sitemap';
|
|
8
8
|
import { vitePluginStarlightUserConfig } from './integrations/virtual-user-config';
|
|
9
9
|
import { errorMap } from './utils/error-map';
|
|
10
|
-
import {
|
|
11
|
-
StarlightConfigSchema,
|
|
12
|
-
StarlightUserConfig,
|
|
13
|
-
} from './utils/user-config';
|
|
10
|
+
import { StarlightConfigSchema, StarlightUserConfig } from './utils/user-config';
|
|
14
11
|
|
|
15
|
-
export default function StarlightIntegration(
|
|
16
|
-
|
|
17
|
-
): AstroIntegration[] {
|
|
18
|
-
const parsedConfig = StarlightConfigSchema.safeParse(opts, { errorMap });
|
|
12
|
+
export default function StarlightIntegration(opts: StarlightUserConfig): AstroIntegration[] {
|
|
13
|
+
const parsedConfig = StarlightConfigSchema.safeParse(opts, { errorMap });
|
|
19
14
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
15
|
+
if (!parsedConfig.success) {
|
|
16
|
+
throw new Error(
|
|
17
|
+
'Invalid config passed to starlight integration\n' +
|
|
18
|
+
parsedConfig.error.issues.map((i) => i.message).join('\n')
|
|
19
|
+
);
|
|
20
|
+
}
|
|
26
21
|
|
|
27
|
-
|
|
22
|
+
const userConfig = parsedConfig.data;
|
|
28
23
|
|
|
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
|
-
updateConfig(newConfig);
|
|
57
|
-
},
|
|
24
|
+
const Starlight: AstroIntegration = {
|
|
25
|
+
name: '@astrojs/starlight',
|
|
26
|
+
hooks: {
|
|
27
|
+
'astro:config:setup': ({ config, injectRoute, updateConfig }) => {
|
|
28
|
+
injectRoute({
|
|
29
|
+
pattern: '404',
|
|
30
|
+
entryPoint: '@astrojs/starlight/404.astro',
|
|
31
|
+
});
|
|
32
|
+
injectRoute({
|
|
33
|
+
pattern: '[...slug]',
|
|
34
|
+
entryPoint: '@astrojs/starlight/index.astro',
|
|
35
|
+
});
|
|
36
|
+
const newConfig: AstroUserConfig = {
|
|
37
|
+
vite: {
|
|
38
|
+
plugins: [vitePluginStarlightUserConfig(userConfig, config)],
|
|
39
|
+
},
|
|
40
|
+
markdown: {
|
|
41
|
+
remarkPlugins: [...starlightAsides()],
|
|
42
|
+
shikiConfig:
|
|
43
|
+
// Configure Shiki theme if the user is using the default github-dark theme.
|
|
44
|
+
config.markdown.shikiConfig.theme !== 'github-dark' ? {} : { theme: 'css-variables' },
|
|
45
|
+
},
|
|
46
|
+
build: { inlineStylesheets: 'auto' },
|
|
47
|
+
experimental: { assets: true, inlineStylesheets: 'auto' },
|
|
48
|
+
};
|
|
49
|
+
updateConfig(newConfig);
|
|
50
|
+
},
|
|
58
51
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
52
|
+
'astro:build:done': ({ dir }) => {
|
|
53
|
+
const targetDir = fileURLToPath(dir);
|
|
54
|
+
const cwd = dirname(fileURLToPath(import.meta.url));
|
|
55
|
+
const relativeDir = relative(cwd, targetDir);
|
|
56
|
+
return new Promise<void>((resolve) => {
|
|
57
|
+
spawn('npx', ['-y', 'pagefind', '--source', relativeDir], {
|
|
58
|
+
stdio: 'inherit',
|
|
59
|
+
shell: true,
|
|
60
|
+
cwd,
|
|
61
|
+
}).on('close', () => resolve());
|
|
62
|
+
});
|
|
63
|
+
},
|
|
64
|
+
},
|
|
65
|
+
};
|
|
73
66
|
|
|
74
|
-
|
|
67
|
+
return [starlightSitemap(userConfig), Starlight, mdx()];
|
|
75
68
|
}
|