@astrojs/starlight 0.10.3 → 0.11.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.
Files changed (58) hide show
  1. package/404.astro +9 -4
  2. package/CHANGELOG.md +73 -0
  3. package/components/Badge.astro +1 -0
  4. package/components/Banner.astro +4 -4
  5. package/components/ContentPanel.astro +4 -0
  6. package/components/EditLink.astro +5 -24
  7. package/components/FallbackContentNotice.astro +2 -5
  8. package/components/Footer.astro +5 -32
  9. package/components/{HeadSEO.astro → Head.astro} +10 -14
  10. package/components/Header.astro +26 -16
  11. package/components/Hero.astro +6 -9
  12. package/components/Icons.ts +9 -0
  13. package/components/LanguageSelect.astro +1 -4
  14. package/components/LastUpdated.astro +5 -24
  15. package/components/MarkdownContent.astro +4 -0
  16. package/components/MobileMenuFooter.astro +17 -0
  17. package/components/MobileMenuToggle.astro +2 -4
  18. package/components/{TableOfContents/MobileTableOfContents.astro → MobileTableOfContents.astro} +26 -29
  19. package/components/Page.astro +120 -0
  20. package/{layout → components}/PageFrame.astro +16 -8
  21. package/components/{RightSidebarPanel.astro → PageSidebar.astro} +21 -9
  22. package/components/PageTitle.astro +16 -0
  23. package/components/{PrevNextLinks.astro → Pagination.astro} +3 -9
  24. package/components/Search.astro +5 -5
  25. package/components/Sidebar.astro +7 -36
  26. package/components/SidebarSublist.astro +8 -2
  27. package/components/SiteTitle.astro +1 -20
  28. package/components/SkipLink.astro +3 -5
  29. package/components/SocialIcons.astro +5 -31
  30. package/components/TableOfContents/TableOfContentsList.astro +1 -1
  31. package/components/TableOfContents/starlight-toc.ts +3 -1
  32. package/components/TableOfContents.astro +12 -15
  33. package/components/ThemeProvider.astro +1 -0
  34. package/components/ThemeSelect.astro +1 -4
  35. package/{layout → components}/TwoColumnContent.astro +2 -4
  36. package/constants.ts +4 -0
  37. package/index.astro +4 -2
  38. package/index.ts +10 -15
  39. package/integrations/virtual-user-config.ts +3 -0
  40. package/package.json +133 -4
  41. package/props.ts +1 -0
  42. package/schema.ts +3 -0
  43. package/schemas/components.ts +256 -0
  44. package/schemas/sidebar.ts +89 -0
  45. package/schemas/social.ts +65 -0
  46. package/style/reset.css +1 -1
  47. package/translations/ar.json +8 -8
  48. package/translations/index.ts +2 -0
  49. package/translations/vi.json +22 -0
  50. package/{components/TableOfContents → utils}/generateToC.ts +2 -1
  51. package/utils/navigation.ts +22 -5
  52. package/utils/route-data.ts +97 -0
  53. package/utils/routing.ts +10 -0
  54. package/utils/user-config.ts +15 -99
  55. package/utils/validateLogoImports.ts +21 -0
  56. package/virtual.d.ts +37 -0
  57. package/components/RightSidebar.astro +0 -36
  58. package/layout/Page.astro +0 -132
@@ -0,0 +1,120 @@
1
+ ---
2
+ import type { Props } from '../props';
3
+
4
+ // Built-in CSS styles.
5
+ import '../style/props.css';
6
+ import '../style/reset.css';
7
+ import '../style/shiki.css';
8
+ import '../style/util.css';
9
+
10
+ // Components — can override built-in CSS, but not user CSS.
11
+ import {
12
+ Banner,
13
+ ContentPanel,
14
+ PageTitle,
15
+ FallbackContentNotice,
16
+ Footer,
17
+ Header,
18
+ Head,
19
+ Hero,
20
+ MarkdownContent,
21
+ PageSidebar,
22
+ Sidebar,
23
+ SkipLink,
24
+ ThemeProvider,
25
+ PageFrame,
26
+ TwoColumnContent,
27
+ } from 'virtual:starlight/components';
28
+
29
+ // Remark component CSS (needs to override `MarkdownContent.astro`)
30
+ import '../style/asides.css';
31
+
32
+ // Important that this is the last import so it can override built-in styles.
33
+ import 'virtual:starlight/user-css';
34
+
35
+ const pagefindEnabled =
36
+ Astro.props.entry.slug !== '404' &&
37
+ !Astro.props.entry.slug.endsWith('/404') &&
38
+ Astro.props.entry.data.pagefind !== false;
39
+ ---
40
+
41
+ <html
42
+ lang={Astro.props.lang}
43
+ dir={Astro.props.dir}
44
+ data-has-toc={Boolean(Astro.props.toc)}
45
+ data-has-sidebar={Astro.props.hasSidebar}
46
+ data-has-hero={Boolean(Astro.props.entry.data.hero)}
47
+ >
48
+ <head>
49
+ <Head {...Astro.props} />
50
+ <style>
51
+ html:not([data-has-toc]) {
52
+ --sl-mobile-toc-height: 0rem;
53
+ }
54
+ html:not([data-has-sidebar]) {
55
+ --sl-content-width: 67.5rem;
56
+ }
57
+ /* Add scroll padding to ensure anchor headings aren't obscured by nav */
58
+ html {
59
+ /* Additional padding is needed to account for the mobile TOC */
60
+ scroll-padding-top: calc(1.5rem + var(--sl-nav-height) + var(--sl-mobile-toc-height));
61
+ }
62
+ main {
63
+ padding-bottom: 3vh;
64
+ }
65
+ @media (min-width: 50em) {
66
+ [data-has-sidebar] {
67
+ --sl-content-inline-start: var(--sl-sidebar-width);
68
+ }
69
+ }
70
+ @media (min-width: 72em) {
71
+ html {
72
+ scroll-padding-top: calc(1.5rem + var(--sl-nav-height));
73
+ }
74
+ }
75
+ </style>
76
+ <ThemeProvider {...Astro.props} />
77
+ </head>
78
+ <body>
79
+ <SkipLink {...Astro.props} />
80
+ <PageFrame {...Astro.props}>
81
+ <Header slot="header" {...Astro.props} />
82
+ {Astro.props.hasSidebar && <Sidebar slot="sidebar" {...Astro.props} />}
83
+ <TwoColumnContent {...Astro.props}>
84
+ <PageSidebar slot="right-sidebar" {...Astro.props} />
85
+ <main
86
+ data-pagefind-body={pagefindEnabled}
87
+ lang={Astro.props.entryMeta.lang}
88
+ dir={Astro.props.entryMeta.dir}
89
+ >
90
+ {/* TODO: Revisit how this logic flows. */}
91
+ <Banner {...Astro.props} />
92
+ {
93
+ Astro.props.entry.data.hero ? (
94
+ <ContentPanel {...Astro.props}>
95
+ <Hero {...Astro.props} />
96
+ <MarkdownContent {...Astro.props}>
97
+ <slot />
98
+ </MarkdownContent>
99
+ <Footer {...Astro.props} />
100
+ </ContentPanel>
101
+ ) : (
102
+ <>
103
+ <ContentPanel {...Astro.props}>
104
+ <PageTitle {...Astro.props} />
105
+ {Astro.props.isFallback && <FallbackContentNotice {...Astro.props} />}
106
+ </ContentPanel>
107
+ <ContentPanel {...Astro.props}>
108
+ <MarkdownContent {...Astro.props}>
109
+ <slot />
110
+ </MarkdownContent>
111
+ <Footer {...Astro.props} />
112
+ </ContentPanel>
113
+ </>
114
+ )
115
+ }
116
+ </main>
117
+ </TwoColumnContent>
118
+ </PageFrame>
119
+ </body>
120
+ </html>
@@ -1,11 +1,8 @@
1
1
  ---
2
- import MobileMenuToggle from '../components/MobileMenuToggle.astro';
2
+ import type { Props } from '../props';
3
3
  import { useTranslations } from '../utils/translations';
4
4
 
5
- interface Props {
6
- hasSidebar: boolean;
7
- locale: string | undefined;
8
- }
5
+ import { MobileMenuToggle } from 'virtual:starlight/components';
9
6
 
10
7
  const { hasSidebar, locale } = Astro.props;
11
8
  const t = useTranslations(locale);
@@ -16,9 +13,9 @@ const t = useTranslations(locale);
16
13
  {
17
14
  hasSidebar && (
18
15
  <nav class="sidebar" aria-label={t('sidebarNav.accessibleLabel')}>
19
- <MobileMenuToggle {locale} />
16
+ <MobileMenuToggle {...Astro.props} />
20
17
  <div id="starlight__sidebar" class="sidebar-pane">
21
- <div class="sidebar-content">
18
+ <div class="sidebar-content sl-flex">
22
19
  <slot name="sidebar" />
23
20
  </div>
24
21
  </div>
@@ -60,6 +57,7 @@ const t = useTranslations(locale);
60
57
  padding-top: var(--sl-nav-height);
61
58
  width: 100%;
62
59
  background-color: var(--sl-color-black);
60
+ overflow-y: auto;
63
61
  }
64
62
 
65
63
  :global([aria-expanded='true']) ~ .sidebar-pane {
@@ -68,7 +66,17 @@ const t = useTranslations(locale);
68
66
 
69
67
  .sidebar-content {
70
68
  height: 100%;
71
- overflow-y: auto;
69
+ min-height: max-content;
70
+ padding: 1rem var(--sl-sidebar-pad-x) 0;
71
+ flex-direction: column;
72
+ gap: 1rem;
73
+ }
74
+
75
+ @media (min-width: 50rem) {
76
+ .sidebar-content::after {
77
+ content: '';
78
+ padding-bottom: 1px;
79
+ }
72
80
  }
73
81
 
74
82
  .main-frame {
@@ -1,16 +1,28 @@
1
- <div class="right-sidebar-panel sl-hidden lg:sl-block">
2
- <div class="sl-container">
3
- <slot />
4
- </div>
5
- </div>
1
+ ---
2
+ import type { Props } from '../props';
3
+
4
+ import { TableOfContents, MobileTableOfContents } from 'virtual:starlight/components';
5
+ ---
6
+
7
+ {
8
+ Astro.props.toc && (
9
+ <>
10
+ <div class="lg:sl-hidden">
11
+ <MobileTableOfContents {...Astro.props} />
12
+ </div>
13
+ <div class="right-sidebar-panel sl-hidden lg:sl-block">
14
+ <div class="sl-container">
15
+ <TableOfContents {...Astro.props} />
16
+ </div>
17
+ </div>
18
+ </>
19
+ )
20
+ }
6
21
 
7
22
  <style>
8
23
  .right-sidebar-panel {
9
24
  padding: 1rem var(--sl-sidebar-pad-x);
10
25
  }
11
- .right-sidebar-panel + .right-sidebar-panel {
12
- border-top: 1px solid var(--sl-color-hairline);
13
- }
14
26
  .sl-container {
15
27
  width: calc(var(--sl-sidebar-width) - 2 * var(--sl-sidebar-pad-x));
16
28
  }
@@ -26,7 +38,7 @@
26
38
  font-size: var(--sl-text-xs);
27
39
  text-decoration: none;
28
40
  color: var(--sl-color-gray-3);
29
- word-break: break-word;
41
+ overflow-wrap: anywhere;
30
42
  }
31
43
  .right-sidebar-panel :global(a:hover) {
32
44
  color: var(--sl-color-white);
@@ -0,0 +1,16 @@
1
+ ---
2
+ import { PAGE_TITLE_ID } from '../constants';
3
+ import type { Props } from '../props';
4
+ ---
5
+
6
+ <h1 id={PAGE_TITLE_ID}>{Astro.props.entry.data.title}</h1>
7
+
8
+ <style>
9
+ h1 {
10
+ margin-top: 1rem;
11
+ font-size: var(--sl-text-h1);
12
+ line-height: var(--sl-line-height-headings);
13
+ font-weight: 600;
14
+ color: var(--sl-color-white);
15
+ }
16
+ </style>
@@ -1,16 +1,10 @@
1
1
  ---
2
- import type { Link } from '../utils/navigation';
3
2
  import { useTranslations } from '../utils/translations';
4
3
  import Icon from '../user-components/Icon.astro';
4
+ import type { Props } from '../props';
5
5
 
6
- interface Props {
7
- prev: Link | undefined;
8
- next: Link | undefined;
9
- dir: 'ltr' | 'rtl';
10
- locale: string | undefined;
11
- }
12
-
13
- const { prev, next, dir, locale } = Astro.props;
6
+ const { dir, locale, pagination } = Astro.props;
7
+ const { prev, next } = pagination;
14
8
  const isRtl = dir === 'rtl';
15
9
  const t = useTranslations(locale);
16
10
  ---
@@ -2,10 +2,7 @@
2
2
  import '@pagefind/default-ui/css/ui.css';
3
3
  import { useTranslations } from '../utils/translations';
4
4
  import Icon from '../user-components/Icon.astro';
5
-
6
- interface Props {
7
- locale: string | undefined;
8
- }
5
+ import type { Props } from '../props';
9
6
 
10
7
  const t = useTranslations(Astro.props.locale);
11
8
  const pagefindTranslations = {
@@ -129,6 +126,9 @@ const pagefindTranslations = {
129
126
  </script>
130
127
 
131
128
  <style>
129
+ site-search {
130
+ display: contents;
131
+ }
132
132
  button[data-open-modal] {
133
133
  display: flex;
134
134
  align-items: center;
@@ -405,7 +405,7 @@ const pagefindTranslations = {
405
405
 
406
406
  #starlight__search .pagefind-ui__result-excerpt {
407
407
  font-size: calc(1rem * var(--pagefind-ui-scale));
408
- word-break: break-word;
408
+ overflow-wrap: anywhere;
409
409
  }
410
410
 
411
411
  #starlight__search mark {
@@ -1,42 +1,13 @@
1
1
  ---
2
- import type { getSidebar } from '../utils/navigation';
3
- import LanguageSelect from './LanguageSelect.astro';
4
- import SidebarSublist from './SidebarSublist.astro';
5
- import ThemeSelect from './ThemeSelect.astro';
2
+ import type { Props } from '../props';
6
3
 
7
- interface Props {
8
- sidebar: ReturnType<typeof getSidebar>;
9
- locale: string | undefined;
10
- }
4
+ import { MobileMenuFooter } from 'virtual:starlight/components';
5
+ import SidebarSublist from './SidebarSublist.astro';
11
6
 
12
- const { sidebar, locale } = Astro.props;
7
+ const { sidebar } = Astro.props;
13
8
  ---
14
9
 
15
- <div class="sidebar sl-flex">
16
- <SidebarSublist sublist={sidebar} />
17
- <div class="mobile-preferences sl-flex md:sl-hidden">
18
- <ThemeSelect {locale} />
19
- <LanguageSelect {locale} />
20
- </div>
10
+ <SidebarSublist sublist={sidebar} />
11
+ <div class="md:sl-hidden">
12
+ <MobileMenuFooter {...Astro.props} />
21
13
  </div>
22
-
23
- <style>
24
- .sidebar {
25
- height: 100%;
26
- padding: 1rem var(--sl-sidebar-pad-x);
27
- flex-direction: column;
28
- gap: 1rem;
29
- }
30
-
31
- .mobile-preferences {
32
- justify-content: space-between;
33
- border-top: 1px solid var(--sl-color-gray-6);
34
- padding: 0.5rem 0;
35
- }
36
-
37
- @media (min-width: 50rem) {
38
- .sidebar > :global(:nth-last-child(2)) {
39
- padding-bottom: 1rem;
40
- }
41
- }
42
- </style>
@@ -17,7 +17,8 @@ interface Props {
17
17
  <a
18
18
  href={entry.href}
19
19
  aria-current={entry.isCurrent && 'page'}
20
- class:list={{ large: !Astro.props.nested }}
20
+ class:list={[{ large: !Astro.props.nested }, entry.attrs.class]}
21
+ {...entry.attrs}
21
22
  >
22
23
  <span>{entry.label}</span>
23
24
  {entry.badge && (
@@ -35,7 +36,7 @@ interface Props {
35
36
  open={flattenSidebar(entry.entries).some((i) => i.isCurrent) || !entry.collapsed}
36
37
  >
37
38
  <summary>
38
- <h2 class="large">{entry.label}</h2>
39
+ <span class="large">{entry.label}</span>
39
40
  <Icon name="right-caret" class="caret" size="1.25rem" />
40
41
  </summary>
41
42
  <Astro.self sublist={entry.entries} nested />
@@ -53,6 +54,10 @@ interface Props {
53
54
  padding: 0;
54
55
  }
55
56
 
57
+ li {
58
+ overflow-wrap: anywhere;
59
+ }
60
+
56
61
  ul ul li {
57
62
  margin-inline-start: var(--sl-sidebar-item-padding-inline);
58
63
  border-inline-start: 1px solid var(--sl-color-hairline-light);
@@ -84,6 +89,7 @@ interface Props {
84
89
 
85
90
  .caret {
86
91
  transition: transform 0.2s ease-in-out;
92
+ flex-shrink: 0;
87
93
  }
88
94
  :global([dir='rtl']) .caret {
89
95
  transform: rotateZ(180deg);
@@ -2,26 +2,7 @@
2
2
  import { logos } from 'virtual:starlight/user-images';
3
3
  import config from 'virtual:starlight/user-config';
4
4
  import { pathWithBase } from '../utils/base';
5
-
6
- interface Props {
7
- locale: string | undefined;
8
- }
9
-
10
- if (config.logo) {
11
- let err: string | undefined;
12
- if ('src' in config.logo) {
13
- if (!logos.dark || !logos.light) {
14
- err = `Could not resolve logo import for "${config.logo.src}" (logo.src)`;
15
- }
16
- } else {
17
- if (!logos.dark) {
18
- err = `Could not resolve logo import for "${config.logo.dark}" (logo.dark)`;
19
- } else if (!logos.light) {
20
- err = `Could not resolve logo import for "${config.logo.light}" (logo.light)`;
21
- }
22
- }
23
- if (err) throw new Error(err);
24
- }
5
+ import type { Props } from '../props';
25
6
 
26
7
  const href = pathWithBase(Astro.props.locale || '/');
27
8
  ---
@@ -1,14 +1,12 @@
1
1
  ---
2
+ import { PAGE_TITLE_ID } from '../constants';
2
3
  import { useTranslations } from '../utils/translations';
3
-
4
- interface Props {
5
- locale: string | undefined;
6
- }
4
+ import type { Props } from '../props';
7
5
 
8
6
  const t = useTranslations(Astro.props.locale);
9
7
  ---
10
8
 
11
- <a href="#_top">{t('skipLink.label')}</a>
9
+ <a href={`#${PAGE_TITLE_ID}`}>{t('skipLink.label')}</a>
12
10
 
13
11
  <style>
14
12
  a {
@@ -1,44 +1,22 @@
1
1
  ---
2
2
  import config from 'virtual:starlight/user-config';
3
3
  import Icon from '../user-components/Icon.astro';
4
+ import type { Props } from '../props';
4
5
 
5
6
  type Platform = keyof NonNullable<typeof config.social>;
6
-
7
- const labels: Record<Platform, string> = {
8
- github: 'GitHub',
9
- gitlab: 'GitLab',
10
- bitbucket: 'Bitbucket',
11
- discord: 'Discord',
12
- gitter: 'Gitter',
13
- twitter: 'Twitter',
14
- mastodon: 'Mastodon',
15
- codeberg: 'Codeberg',
16
- codePen: 'CodePen',
17
- youtube: 'YouTube',
18
- threads: 'Threads',
19
- linkedin: 'LinkedIn',
20
- twitch: 'Twitch',
21
- microsoftTeams: 'Microsoft Teams',
22
- instagram: 'Instagram',
23
- stackOverflow: 'Stack Overflow',
24
- };
25
-
26
- const links = Object.entries(config.social || {}).filter(([, url]) => Boolean(url)) as [
27
- platform: Platform,
28
- url: string,
29
- ][];
7
+ type SocialConfig = NonNullable<NonNullable<typeof config.social>[Platform]>;
8
+ const links = Object.entries(config.social || {}) as [Platform, SocialConfig][];
30
9
  ---
31
10
 
32
11
  {
33
12
  links.length > 0 && (
34
13
  <>
35
- {links.map(([platform, url]) => (
14
+ {links.map(([platform, { label, url }]) => (
36
15
  <a href={url} rel="me" class="sl-flex">
37
- <span class="sr-only">{labels[platform]}</span>
16
+ <span class="sr-only">{label}</span>
38
17
  <Icon name={platform} />
39
18
  </a>
40
19
  ))}
41
- <div class="divider" />
42
20
  </>
43
21
  )
44
22
  }
@@ -50,8 +28,4 @@ const links = Object.entries(config.social || {}).filter(([, url]) => Boolean(ur
50
28
  a:hover {
51
29
  opacity: 0.66;
52
30
  }
53
- .divider {
54
- height: 2rem;
55
- border-inline-end: 1px solid var(--sl-color-gray-5);
56
- }
57
31
  </style>
@@ -1,5 +1,5 @@
1
1
  ---
2
- import type { TocItem } from './generateToC';
2
+ import type { TocItem } from '../../utils/generateToC';
3
3
 
4
4
  interface Props {
5
5
  toc: TocItem[];
@@ -1,3 +1,5 @@
1
+ import { PAGE_TITLE_ID } from '../../constants';
2
+
1
3
  export class StarlightTOC extends HTMLElement {
2
4
  private _current = this.querySelector('a[aria-current="true"]') as HTMLAnchorElement | null;
3
5
  private minH = parseInt(this.dataset.minH || '2', 10);
@@ -20,7 +22,7 @@ export class StarlightTOC extends HTMLElement {
20
22
  const isHeading = (el: Element): el is HTMLHeadingElement => {
21
23
  if (el instanceof HTMLHeadingElement) {
22
24
  // Special case for page title h1
23
- if ('pageTitle' in el.dataset) return true;
25
+ if (el.id === PAGE_TITLE_ID) return true;
24
26
  // Check the heading level is within the user-configured limits for the ToC
25
27
  const level = el.tagName[1];
26
28
  if (level) {
@@ -1,24 +1,21 @@
1
1
  ---
2
2
  import { useTranslations } from '../utils/translations';
3
3
  import TableOfContentsList from './TableOfContents/TableOfContentsList.astro';
4
- import type { TocItem } from './TableOfContents/generateToC';
4
+ import type { Props } from '../props';
5
5
 
6
- interface Props {
7
- toc: TocItem[];
8
- locale: string | undefined;
9
- maxHeadingLevel: number;
10
- minHeadingLevel: number;
11
- }
12
-
13
- const { locale, toc, maxHeadingLevel, minHeadingLevel } = Astro.props;
6
+ const { locale, toc } = Astro.props;
14
7
  const t = useTranslations(locale);
15
8
  ---
16
9
 
17
- <starlight-toc data-min-h={minHeadingLevel} data-max-h={maxHeadingLevel}>
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
- </starlight-toc>
10
+ {
11
+ toc && (
12
+ <starlight-toc data-min-h={toc.minHeadingLevel} data-max-h={toc.maxHeadingLevel}>
13
+ <nav aria-labelledby="starlight__on-this-page">
14
+ <h2 id="starlight__on-this-page">{t('tableOfContents.onThisPage')}</h2>
15
+ <TableOfContentsList toc={toc.items} />
16
+ </nav>
17
+ </starlight-toc>
18
+ )
19
+ }
23
20
 
24
21
  <script src="./TableOfContents/starlight-toc"></script>
@@ -1,4 +1,5 @@
1
1
  ---
2
+ import type { Props } from '../props';
2
3
  import Icon from '../user-components/Icon.astro';
3
4
  ---
4
5
 
@@ -1,10 +1,7 @@
1
1
  ---
2
2
  import { useTranslations } from '../utils/translations';
3
3
  import Select from './Select.astro';
4
-
5
- interface Props {
6
- locale: string | undefined;
7
- }
4
+ import type { Props } from '../props';
8
5
 
9
6
  const t = useTranslations(Astro.props.locale);
10
7
  ---
@@ -1,12 +1,10 @@
1
1
  ---
2
- interface Props {
3
- hasToC: boolean;
4
- }
2
+ import type { Props } from '../props';
5
3
  ---
6
4
 
7
5
  <div class="lg:sl-flex">
8
6
  {
9
- Astro.props.hasToC && (
7
+ Astro.props.toc && (
10
8
  <aside class="right-sidebar-container">
11
9
  <div class="right-sidebar">
12
10
  <slot name="right-sidebar" />
package/constants.ts ADDED
@@ -0,0 +1,4 @@
1
+ // N.B. THIS FILE IS IMPORTED IN BOTH SERVER- AND CLIENT-SIDE CODE.
2
+ // THINK TWICE BEFORE ADDING STUFF AS IT WILL GET SHIPPED TO THE CLIENT.
3
+
4
+ export const PAGE_TITLE_ID = '_top';
package/index.astro CHANGED
@@ -1,8 +1,9 @@
1
1
  ---
2
2
  import type { InferGetStaticPropsType } from 'astro';
3
+ import { generateRouteData } from './utils/route-data';
3
4
  import { paths } from './utils/routing';
4
5
 
5
- import Page from './layout/Page.astro';
6
+ import Page from './components/Page.astro';
6
7
 
7
8
  export async function getStaticPaths() {
8
9
  return paths;
@@ -10,6 +11,7 @@ export async function getStaticPaths() {
10
11
 
11
12
  type Props = InferGetStaticPropsType<typeof getStaticPaths>;
12
13
  const { Content, headings } = await Astro.props.entry.render();
14
+ const route = generateRouteData({ props: { ...Astro.props, headings }, url: Astro.url });
13
15
  ---
14
16
 
15
- <Page {...Astro.props} {headings}><Content /></Page>
17
+ <Page {...route}><Content /></Page>
package/index.ts CHANGED
@@ -10,7 +10,7 @@ import { errorMap } from './utils/error-map';
10
10
  import { StarlightConfigSchema, type StarlightUserConfig } from './utils/user-config';
11
11
  import { rehypeRtlCodeSupport } from './integrations/code-rtl-support';
12
12
 
13
- export default function StarlightIntegration(opts: StarlightUserConfig): AstroIntegration[] {
13
+ export default function StarlightIntegration(opts: StarlightUserConfig): AstroIntegration {
14
14
  const parsedConfig = StarlightConfigSchema.safeParse(opts, { errorMap });
15
15
 
16
16
  if (!parsedConfig.success) {
@@ -34,7 +34,15 @@ export default function StarlightIntegration(opts: StarlightUserConfig): AstroIn
34
34
  pattern: '[...slug]',
35
35
  entryPoint: '@astrojs/starlight/index.astro',
36
36
  });
37
+ const integrations: AstroIntegration[] = [];
38
+ if (!config.integrations.find(({ name }) => name === '@astrojs/sitemap')) {
39
+ integrations.push(starlightSitemap(userConfig));
40
+ }
41
+ if (!config.integrations.find(({ name }) => name === '@astrojs/mdx')) {
42
+ integrations.push(mdx());
43
+ }
37
44
  const newConfig: AstroUserConfig = {
45
+ integrations,
38
46
  vite: {
39
47
  plugins: [vitePluginStarlightUserConfig(userConfig, config)],
40
48
  },
@@ -50,19 +58,6 @@ export default function StarlightIntegration(opts: StarlightUserConfig): AstroIn
50
58
  updateConfig(newConfig);
51
59
  },
52
60
 
53
- 'astro:config:done': ({ config }) => {
54
- const integrations = config.integrations.map(({ name }) => name);
55
- for (const builtin of ['@astrojs/mdx', '@astrojs/sitemap']) {
56
- if (integrations.filter((name) => name === builtin).length > 1) {
57
- throw new Error(
58
- `Found more than one instance of ${builtin}.\n` +
59
- `Starlight includes ${builtin} by default.\n` +
60
- 'Please remove it from your integrations array in astro.config.mjs'
61
- );
62
- }
63
- }
64
- },
65
-
66
61
  'astro:build:done': ({ dir }) => {
67
62
  const targetDir = fileURLToPath(dir);
68
63
  const cwd = dirname(fileURLToPath(import.meta.url));
@@ -78,5 +73,5 @@ export default function StarlightIntegration(opts: StarlightUserConfig): AstroIn
78
73
  },
79
74
  };
80
75
 
81
- return [starlightSitemap(userConfig), Starlight, mdx()];
76
+ return Starlight;
82
77
  }
@@ -29,6 +29,9 @@ export function vitePluginStarlightUserConfig(
29
29
  opts.logo.light
30
30
  )}; export const logos = { dark, light };`
31
31
  : 'export const logos = {};',
32
+ 'virtual:starlight/components': Object.entries(opts.components)
33
+ .map(([name, path]) => `export { default as ${name} } from ${resolveId(path)};`)
34
+ .join(''),
32
35
  } satisfies Record<string, string>;
33
36
 
34
37
  /** Mapping names prefixed with `\0` to their original form. */