@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.
Files changed (76) hide show
  1. package/404.astro +17 -17
  2. package/CHANGELOG.md +40 -2
  3. package/components/CallToAction.astro +32 -35
  4. package/components/ContentPanel.astro +18 -18
  5. package/components/EditLink.astro +23 -23
  6. package/components/FallbackContentNotice.astro +16 -18
  7. package/components/Footer.astro +28 -34
  8. package/components/HeadSEO.astro +69 -75
  9. package/components/Header.astro +47 -51
  10. package/components/Hero.astro +108 -121
  11. package/components/Icons.ts +73 -71
  12. package/components/LanguageSelect.astro +31 -31
  13. package/components/LastUpdated.astro +16 -18
  14. package/components/MarkdownContent.astro +105 -117
  15. package/components/MobileMenuToggle.astro +80 -80
  16. package/components/PrevNextLinks.astro +60 -60
  17. package/components/RightSidebar.astro +17 -17
  18. package/components/RightSidebarPanel.astro +41 -41
  19. package/components/Search.astro +293 -306
  20. package/components/Select.astro +64 -65
  21. package/components/Sidebar.astro +23 -23
  22. package/components/SidebarSublist.astro +96 -95
  23. package/components/SiteTitle.astro +65 -63
  24. package/components/SkipLink.astro +17 -17
  25. package/components/SocialIcons.astro +36 -34
  26. package/components/TableOfContents/MobileTableOfContents.astro +124 -124
  27. package/components/TableOfContents/TableOfContentsList.astro +64 -69
  28. package/components/TableOfContents/generateToC.ts +41 -43
  29. package/components/TableOfContents/starlight-toc.ts +84 -90
  30. package/components/TableOfContents.astro +8 -8
  31. package/components/ThemeProvider.astro +28 -32
  32. package/components/ThemeSelect.astro +66 -71
  33. package/global.d.ts +3 -3
  34. package/index.astro +1 -1
  35. package/index.ts +52 -59
  36. package/integrations/asides.ts +109 -111
  37. package/integrations/sitemap.ts +10 -13
  38. package/integrations/virtual-user-config.ts +37 -37
  39. package/layout/Page.astro +84 -72
  40. package/layout/PageFrame.astro +67 -69
  41. package/layout/TwoColumnContent.astro +40 -42
  42. package/package.json +2 -2
  43. package/schema.ts +126 -113
  44. package/schemas/favicon.ts +40 -0
  45. package/schemas/head.ts +12 -23
  46. package/schemas/i18n.ts +146 -160
  47. package/schemas/logo.ts +22 -22
  48. package/schemas/prevNextLink.ts +14 -14
  49. package/schemas/tableOfContents.ts +14 -18
  50. package/style/asides.css +27 -27
  51. package/style/props.css +168 -172
  52. package/style/reset.css +13 -13
  53. package/style/shiki.css +11 -11
  54. package/style/util.css +30 -30
  55. package/translations/fr.json +21 -21
  56. package/translations/index.ts +4 -4
  57. package/translations/it.json +20 -20
  58. package/translations/tr.json +1 -1
  59. package/translations/zh.json +0 -1
  60. package/user-components/Card.astro +50 -54
  61. package/user-components/CardGrid.astro +21 -21
  62. package/user-components/Icon.astro +19 -21
  63. package/user-components/TabItem.astro +3 -3
  64. package/user-components/Tabs.astro +113 -117
  65. package/user-components/rehype-tabs.ts +72 -72
  66. package/utils/base.ts +6 -6
  67. package/utils/git.ts +55 -55
  68. package/utils/head.ts +56 -54
  69. package/utils/i18n.ts +3 -3
  70. package/utils/localizedUrl.ts +25 -25
  71. package/utils/navigation.ts +225 -203
  72. package/utils/routing.ts +74 -85
  73. package/utils/slugs.ts +41 -51
  74. package/utils/translations.ts +26 -32
  75. package/utils/user-config.ts +278 -278
  76. package/virtual.d.ts +8 -8
@@ -2,83 +2,82 @@
2
2
  import Icon from '../user-components/Icon.astro';
3
3
 
4
4
  interface Props {
5
- label: string;
6
- value: string;
7
- icon: Parameters<typeof Icon>[0]['name'];
8
- width?: string;
9
- options: Array<{
10
- label: string;
11
- value: string;
12
- selected: boolean;
13
- }>;
5
+ label: string;
6
+ value: string;
7
+ icon: Parameters<typeof Icon>[0]['name'];
8
+ width?: string;
9
+ options: Array<{
10
+ label: string;
11
+ value: string;
12
+ selected: boolean;
13
+ }>;
14
14
  }
15
15
  ---
16
16
 
17
17
  <label style={`--sl-select-width: ${Astro.props.width}`}>
18
- <span class="sr-only">{Astro.props.label}</span>
19
- <Icon name={Astro.props.icon} class="icon label-icon" />
20
- <select value={Astro.props.value}>
21
- {
22
- Astro.props.options.map(({ value, selected, label }) => (
23
- <option value={value} selected={selected} set:html={label} />
24
- ))
25
- }
26
- </select>
27
- <Icon name="down-caret" class="icon caret" />
18
+ <span class="sr-only">{Astro.props.label}</span>
19
+ <Icon name={Astro.props.icon} class="icon label-icon" />
20
+ <select value={Astro.props.value}>
21
+ {
22
+ Astro.props.options.map(({ value, selected, label }) => (
23
+ <option value={value} selected={selected} set:html={label} />
24
+ ))
25
+ }
26
+ </select>
27
+ <Icon name="down-caret" class="icon caret" />
28
28
  </label>
29
29
 
30
30
  <style>
31
- label {
32
- --sl-label-icon-size: 0.875rem;
33
- --sl-caret-size: 1.25rem;
34
- position: relative;
35
- display: flex;
36
- align-items: center;
37
- gap: 0.25rem;
38
- color: var(--sl-color-gray-1);
39
- }
31
+ label {
32
+ --sl-label-icon-size: 0.875rem;
33
+ --sl-caret-size: 1.25rem;
34
+ position: relative;
35
+ display: flex;
36
+ align-items: center;
37
+ gap: 0.25rem;
38
+ color: var(--sl-color-gray-1);
39
+ }
40
40
 
41
- label:hover {
42
- color: var(--sl-color-gray-2);
43
- }
41
+ label:hover {
42
+ color: var(--sl-color-gray-2);
43
+ }
44
44
 
45
- .icon {
46
- position: absolute;
47
- top: 50%;
48
- transform: translateY(-50%);
49
- pointer-events: none;
50
- }
45
+ .icon {
46
+ position: absolute;
47
+ top: 50%;
48
+ transform: translateY(-50%);
49
+ pointer-events: none;
50
+ }
51
51
 
52
- .label-icon {
53
- font-size: var(--sl-label-icon-size);
54
- inset-inline-start: 0;
55
- }
52
+ .label-icon {
53
+ font-size: var(--sl-label-icon-size);
54
+ inset-inline-start: 0;
55
+ }
56
56
 
57
- .caret {
58
- font-size: var(--sl-caret-size);
59
- inset-inline-end: 0;
60
- }
57
+ .caret {
58
+ font-size: var(--sl-caret-size);
59
+ inset-inline-end: 0;
60
+ }
61
61
 
62
- select {
63
- border: 0;
64
- padding-block: 0.625rem;
65
- padding-inline: calc(var(--sl-label-icon-size) + 0.25rem)
66
- calc(var(--sl-caret-size) + 0.25rem);
67
- width: var(--sl-select-width);
68
- background-color: transparent;
69
- text-overflow: ellipsis;
70
- color: inherit;
71
- cursor: pointer;
72
- appearance: none;
73
- }
62
+ select {
63
+ border: 0;
64
+ padding-block: 0.625rem;
65
+ padding-inline: calc(var(--sl-label-icon-size) + 0.25rem) calc(var(--sl-caret-size) + 0.25rem);
66
+ width: var(--sl-select-width);
67
+ background-color: transparent;
68
+ text-overflow: ellipsis;
69
+ color: inherit;
70
+ cursor: pointer;
71
+ appearance: none;
72
+ }
74
73
 
75
- option {
76
- background-color: var(--sl-color-bg-nav);
77
- }
74
+ option {
75
+ background-color: var(--sl-color-bg-nav);
76
+ }
78
77
 
79
- @media (min-width: 50rem) {
80
- select {
81
- font-size: var(--sl-text-sm);
82
- }
83
- }
78
+ @media (min-width: 50rem) {
79
+ select {
80
+ font-size: var(--sl-text-sm);
81
+ }
82
+ }
84
83
  </style>
@@ -5,38 +5,38 @@ import SidebarSublist from './SidebarSublist.astro';
5
5
  import ThemeSelect from './ThemeSelect.astro';
6
6
 
7
7
  interface Props {
8
- sidebar: ReturnType<typeof getSidebar>;
9
- locale: string | undefined;
8
+ sidebar: ReturnType<typeof getSidebar>;
9
+ locale: string | undefined;
10
10
  }
11
11
 
12
12
  const { sidebar, locale } = Astro.props;
13
13
  ---
14
14
 
15
15
  <div class="sidebar flex">
16
- <SidebarSublist sublist={sidebar} />
17
- <div class="mobile-preferences flex md:hidden">
18
- <ThemeSelect {locale} />
19
- <LanguageSelect {locale} />
20
- </div>
16
+ <SidebarSublist sublist={sidebar} />
17
+ <div class="mobile-preferences flex md:hidden">
18
+ <ThemeSelect {locale} />
19
+ <LanguageSelect {locale} />
20
+ </div>
21
21
  </div>
22
22
 
23
23
  <style>
24
- .sidebar {
25
- height: 100%;
26
- padding: 1rem var(--sl-sidebar-pad-x);
27
- flex-direction: column;
28
- gap: 1rem;
29
- }
24
+ .sidebar {
25
+ height: 100%;
26
+ padding: 1rem var(--sl-sidebar-pad-x);
27
+ flex-direction: column;
28
+ gap: 1rem;
29
+ }
30
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
- }
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
36
 
37
- @media (min-width: 50rem) {
38
- .sidebar > :global(:nth-last-child(2)) {
39
- padding-bottom: 1rem;
40
- }
41
- }
37
+ @media (min-width: 50rem) {
38
+ .sidebar > :global(:nth-last-child(2)) {
39
+ padding-bottom: 1rem;
40
+ }
41
+ }
42
42
  </style>
@@ -3,115 +3,116 @@ import { flattenSidebar, type SidebarEntry } from '../utils/navigation';
3
3
  import Icon from '../user-components/Icon.astro';
4
4
 
5
5
  interface Props {
6
- sublist: SidebarEntry[];
7
- nested?: boolean;
6
+ sublist: SidebarEntry[];
7
+ nested?: boolean;
8
8
  }
9
9
  ---
10
10
 
11
11
  <ul class:list={{ 'top-level': !Astro.props.nested }}>
12
- {
13
- Astro.props.sublist.map((entry) => (
14
- <li>
15
- {entry.type === 'link' ? (
16
- <a
17
- href={entry.href}
18
- aria-current={entry.isCurrent && 'page'}
19
- class:list={{ large: !Astro.props.nested }}
20
- >
21
- {entry.label}
22
- </a>
23
- ) : (
24
- <details
25
- open={flattenSidebar(entry.entries).some(i => i.isCurrent) || !entry.collapsed}
26
- >
27
- <summary>
28
- <h2 class="large">{entry.label}</h2>
29
- <Icon name="right-caret" class="caret" size="1.25rem" />
30
- </summary>
31
- <Astro.self sublist={entry.entries} nested />
32
- </details>
33
- )}
34
- </li>
35
- ))
36
- }
12
+ {
13
+ Astro.props.sublist.map((entry) => (
14
+ <li>
15
+ {entry.type === 'link' ? (
16
+ <a
17
+ href={entry.href}
18
+ aria-current={entry.isCurrent && 'page'}
19
+ class:list={{ large: !Astro.props.nested }}
20
+ >
21
+ {entry.label}
22
+ </a>
23
+ ) : (
24
+ <details
25
+ open={flattenSidebar(entry.entries).some((i) => i.isCurrent) || !entry.collapsed}
26
+ >
27
+ <summary>
28
+ <h2 class="large">{entry.label}</h2>
29
+ <Icon name="right-caret" class="caret" size="1.25rem" />
30
+ </summary>
31
+ <Astro.self sublist={entry.entries} nested />
32
+ </details>
33
+ )}
34
+ </li>
35
+ ))
36
+ }
37
37
  </ul>
38
38
 
39
39
  <style>
40
- ul {
41
- --sl-sidebar-item-padding-inline: 0.5rem;
42
- list-style: none;
43
- padding: 0;
44
- }
40
+ ul {
41
+ --sl-sidebar-item-padding-inline: 0.5rem;
42
+ list-style: none;
43
+ padding: 0;
44
+ }
45
45
 
46
- ul ul li {
47
- margin-inline-start: var(--sl-sidebar-item-padding-inline);
48
- border-inline-start: 1px solid var(--sl-color-hairline-light);
49
- padding-inline-start: var(--sl-sidebar-item-padding-inline);
50
- }
46
+ ul ul li {
47
+ margin-inline-start: var(--sl-sidebar-item-padding-inline);
48
+ border-inline-start: 1px solid var(--sl-color-hairline-light);
49
+ padding-inline-start: var(--sl-sidebar-item-padding-inline);
50
+ }
51
51
 
52
- .large {
53
- font-size: var(--sl-text-lg);
54
- font-weight: 600;
55
- color: var(--sl-color-white);
56
- }
52
+ .large {
53
+ font-size: var(--sl-text-lg);
54
+ font-weight: 600;
55
+ color: var(--sl-color-white);
56
+ }
57
57
 
58
- .top-level > li + li {
59
- margin-top: 0.75rem;
60
- }
58
+ .top-level > li + li {
59
+ margin-top: 0.75rem;
60
+ }
61
61
 
62
- summary {
63
- display: flex;
64
- align-items: center;
65
- justify-content: space-between;
66
- padding-inline: var(--sl-sidebar-item-padding-inline);
67
- cursor: pointer;
68
- user-select: none;
69
- }
70
- summary::marker,
71
- summary::-webkit-details-marker {
72
- display: none;
73
- }
62
+ summary {
63
+ display: flex;
64
+ align-items: center;
65
+ justify-content: space-between;
66
+ padding-inline: var(--sl-sidebar-item-padding-inline);
67
+ cursor: pointer;
68
+ user-select: none;
69
+ }
70
+ summary::marker,
71
+ summary::-webkit-details-marker {
72
+ display: none;
73
+ }
74
74
 
75
- .caret {
76
- transition: transform 0.2s ease-in-out;
77
- }
78
- :global([dir='rtl']) .caret {
79
- transform: rotateZ(180deg);
80
- }
81
- [open] > summary .caret {
82
- transform: rotateZ(90deg);
83
- }
75
+ .caret {
76
+ transition: transform 0.2s ease-in-out;
77
+ }
78
+ :global([dir='rtl']) .caret {
79
+ transform: rotateZ(180deg);
80
+ }
81
+ [open] > summary .caret {
82
+ transform: rotateZ(90deg);
83
+ }
84
84
 
85
- a {
86
- display: block;
87
- border-radius: 0.25rem;
88
- text-decoration: none;
89
- color: var(--sl-color-gray-2);
90
- padding: 0.1em var(--sl-sidebar-item-padding-inline);
91
- }
85
+ a {
86
+ display: block;
87
+ border-radius: 0.25rem;
88
+ text-decoration: none;
89
+ color: var(--sl-color-gray-2);
90
+ padding: 0.3em var(--sl-sidebar-item-padding-inline);
91
+ line-height: 1.4;
92
+ }
92
93
 
93
- a:hover,
94
- a:focus {
95
- color: var(--sl-color-white);
96
- }
94
+ a:hover,
95
+ a:focus {
96
+ color: var(--sl-color-white);
97
+ }
97
98
 
98
- [aria-current='page'],
99
- [aria-current='page']:hover,
100
- [aria-current='page']:focus {
101
- font-weight: 600;
102
- color: var(--sl-color-text-invert);
103
- background-color: var(--sl-color-text-accent);
104
- }
99
+ [aria-current='page'],
100
+ [aria-current='page']:hover,
101
+ [aria-current='page']:focus {
102
+ font-weight: 600;
103
+ color: var(--sl-color-text-invert);
104
+ background-color: var(--sl-color-text-accent);
105
+ }
105
106
 
106
- @media (min-width: 50rem) {
107
- .top-level > li + li {
108
- margin-top: 0.5rem;
109
- }
110
- .large {
111
- font-size: var(--sl-text-base);
112
- }
113
- a {
114
- font-size: var(--sl-text-sm);
115
- }
116
- }
107
+ @media (min-width: 50rem) {
108
+ .top-level > li + li {
109
+ margin-top: 0.5rem;
110
+ }
111
+ .large {
112
+ font-size: var(--sl-text-base);
113
+ }
114
+ a {
115
+ font-size: var(--sl-text-sm);
116
+ }
117
+ }
117
118
  </style>
@@ -4,79 +4,81 @@ import config from 'virtual:starlight/user-config';
4
4
  import { pathWithBase } from '../utils/base';
5
5
 
6
6
  interface Props {
7
- locale: string | undefined;
7
+ locale: string | undefined;
8
8
  }
9
9
 
10
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);
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
24
  }
25
25
 
26
26
  const href = pathWithBase(Astro.props.locale || '/');
27
27
  ---
28
28
 
29
29
  <a {href} class="site-title flex">
30
- {
31
- config.logo && logos.dark && (
32
- <>
33
- <img
34
- class:list={{ 'dark-only': !('src' in config.logo) }}
35
- alt={config.logo.alt}
36
- src={logos.dark.src}
37
- width={logos.dark.width}
38
- height={logos.dark.height}
39
- />
40
- {/* Show light alternate if a user configure both light and dark logos. */}
41
- {!('src' in config.logo) && (
42
- <img
43
- class="light-only"
44
- alt={config.logo.alt}
45
- src={logos.light?.src}
46
- width={logos.light?.width}
47
- height={logos.light?.height}
48
- />
49
- )}
50
- </>
51
- )
52
- }
53
- <span class:list={{ 'sr-only': config.logo?.replacesTitle }}>
54
- {config.title}
55
- </span>
30
+ {
31
+ config.logo && logos.dark && (
32
+ <>
33
+ <img
34
+ class:list={{ 'dark-only': !('src' in config.logo) }}
35
+ alt={config.logo.alt}
36
+ src={logos.dark.src}
37
+ width={logos.dark.width}
38
+ height={logos.dark.height}
39
+ />
40
+ {/* Show light alternate if a user configure both light and dark logos. */}
41
+ {!('src' in config.logo) && (
42
+ <img
43
+ class="light-only"
44
+ alt={config.logo.alt}
45
+ src={logos.light?.src}
46
+ width={logos.light?.width}
47
+ height={logos.light?.height}
48
+ />
49
+ )}
50
+ </>
51
+ )
52
+ }
53
+ <span class:list={{ 'sr-only': config.logo?.replacesTitle }}>
54
+ {config.title}
55
+ </span>
56
56
  </a>
57
57
 
58
58
  <style>
59
- .site-title {
60
- justify-self: flex-start;
61
- align-items: center;
62
- gap: var(--sl-nav-gap);
63
- font-size: var(--sl-text-h4);
64
- font-weight: 600;
65
- color: var(--sl-color-text-accent);
66
- text-decoration: none;
67
- white-space: nowrap;
68
- }
69
- img {
70
- height: calc(var(--sl-nav-height) - 2 * var(--sl-nav-pad-y));
71
- width: auto;
72
- max-width: 100%;
73
- object-fit: contain;
74
- object-position: 0 50%;
75
- }
76
- :global([data-theme='light']) .dark-only {
77
- display: none;
78
- }
79
- :global([data-theme='dark']) .light-only {
80
- display: none;
81
- }
59
+ .site-title {
60
+ justify-self: flex-start;
61
+ max-width: 100%;
62
+ overflow: hidden;
63
+ align-items: center;
64
+ gap: var(--sl-nav-gap);
65
+ font-size: var(--sl-text-h4);
66
+ font-weight: 600;
67
+ color: var(--sl-color-text-accent);
68
+ text-decoration: none;
69
+ white-space: nowrap;
70
+ }
71
+ img {
72
+ height: calc(var(--sl-nav-height) - 2 * var(--sl-nav-pad-y));
73
+ width: auto;
74
+ max-width: 100%;
75
+ object-fit: contain;
76
+ object-position: 0 50%;
77
+ }
78
+ :global([data-theme='light']) .dark-only {
79
+ display: none;
80
+ }
81
+ :global([data-theme='dark']) .light-only {
82
+ display: none;
83
+ }
82
84
  </style>
@@ -2,7 +2,7 @@
2
2
  import { useTranslations } from '../utils/translations';
3
3
 
4
4
  interface Props {
5
- locale: string | undefined;
5
+ locale: string | undefined;
6
6
  }
7
7
 
8
8
  const t = useTranslations(Astro.props.locale);
@@ -11,20 +11,20 @@ const t = useTranslations(Astro.props.locale);
11
11
  <a href="#_top">{t('skipLink.label')}</a>
12
12
 
13
13
  <style>
14
- a {
15
- clip: rect(0, 0, 0, 0);
16
- position: fixed;
17
- top: 0.75rem;
18
- inset-inline-start: 0.75rem;
19
- }
20
- a:focus {
21
- clip: unset;
22
- z-index: var(--sl-z-index-skiplink);
23
- display: block;
24
- padding: 0.5rem 1rem;
25
- text-decoration: none;
26
- color: var(--sl-color-text-invert);
27
- background-color: var(--sl-color-text-accent);
28
- box-shadow: var(--sl-shadow-lg);
29
- }
14
+ a {
15
+ clip: rect(0, 0, 0, 0);
16
+ position: fixed;
17
+ top: 0.75rem;
18
+ inset-inline-start: 0.75rem;
19
+ }
20
+ a:focus {
21
+ clip: unset;
22
+ z-index: var(--sl-z-index-skiplink);
23
+ display: block;
24
+ padding: 0.5rem 1rem;
25
+ text-decoration: none;
26
+ color: var(--sl-color-text-invert);
27
+ background-color: var(--sl-color-text-accent);
28
+ box-shadow: var(--sl-shadow-lg);
29
+ }
30
30
  </style>