@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
@@ -3,67 +3,63 @@ import Icon from './Icon.astro';
3
3
  import type { Icons } from '../components/Icons';
4
4
 
5
5
  interface Props {
6
- icon?: keyof typeof Icons;
7
- title: string;
6
+ icon?: keyof typeof Icons;
7
+ title: string;
8
8
  }
9
9
 
10
10
  const { icon, title } = Astro.props;
11
11
  ---
12
12
 
13
13
  <article class="card flex">
14
- <p class="title flex">
15
- {icon && <Icon name={icon} class="icon" size="1.333em" />}
16
- <span set:html={title} />
17
- </p>
18
- <div class="body"><slot /></div>
14
+ <p class="title flex">
15
+ {icon && <Icon name={icon} class="icon" size="1.333em" />}
16
+ <span set:html={title} />
17
+ </p>
18
+ <div class="body"><slot /></div>
19
19
  </article>
20
20
 
21
21
  <style>
22
- .card {
23
- --sl-card-border: var(--sl-color-purple);
24
- --sl-card-bg: var(--sl-color-purple-low);
25
- border: 1px solid var(--sl-color-gray-5);
26
- background-color: var(--sl-color-black);
27
- padding: clamp(1rem, calc(0.125rem + 3vw), 2.5rem);
28
- flex-direction: column;
29
- gap: clamp(0.5rem, calc(0.125rem + 1vw), 1rem);
30
- }
31
- .card:nth-child(4n + 1) {
32
- --sl-card-border: var(--sl-color-orange);
33
- --sl-card-bg: var(--sl-color-orange-low);
34
- }
35
- .card:nth-child(4n + 3) {
36
- --sl-card-border: var(--sl-color-green);
37
- --sl-card-bg: var(--sl-color-green-low);
38
- }
39
- .card:nth-child(4n + 4) {
40
- --sl-card-border: var(--sl-color-red);
41
- --sl-card-bg: var(--sl-color-red-low);
42
- }
43
- .card:nth-child(4n + 5) {
44
- --sl-card-border: var(--sl-color-blue);
45
- --sl-card-bg: var(--sl-color-blue-low);
46
- }
47
- .title {
48
- font-weight: 600;
49
- font-size: var(--sl-text-h4);
50
- color: var(--sl-color-white);
51
- line-height: var(--sl-line-height-headings);
52
- gap: 1rem;
53
- align-items: center;
54
- }
55
- .card .icon {
56
- border: 1px solid var(--sl-card-border);
57
- background-color: var(--sl-card-bg);
58
- padding: 0.2em;
59
- border-radius: 0.25rem;
60
- }
61
- .card .body {
62
- margin: 0;
63
- font-size: clamp(
64
- var(--sl-text-sm),
65
- calc(0.5rem + 1vw),
66
- var(--sl-text-body)
67
- );
68
- }
22
+ .card {
23
+ --sl-card-border: var(--sl-color-purple);
24
+ --sl-card-bg: var(--sl-color-purple-low);
25
+ border: 1px solid var(--sl-color-gray-5);
26
+ background-color: var(--sl-color-black);
27
+ padding: clamp(1rem, calc(0.125rem + 3vw), 2.5rem);
28
+ flex-direction: column;
29
+ gap: clamp(0.5rem, calc(0.125rem + 1vw), 1rem);
30
+ }
31
+ .card:nth-child(4n + 1) {
32
+ --sl-card-border: var(--sl-color-orange);
33
+ --sl-card-bg: var(--sl-color-orange-low);
34
+ }
35
+ .card:nth-child(4n + 3) {
36
+ --sl-card-border: var(--sl-color-green);
37
+ --sl-card-bg: var(--sl-color-green-low);
38
+ }
39
+ .card:nth-child(4n + 4) {
40
+ --sl-card-border: var(--sl-color-red);
41
+ --sl-card-bg: var(--sl-color-red-low);
42
+ }
43
+ .card:nth-child(4n + 5) {
44
+ --sl-card-border: var(--sl-color-blue);
45
+ --sl-card-bg: var(--sl-color-blue-low);
46
+ }
47
+ .title {
48
+ font-weight: 600;
49
+ font-size: var(--sl-text-h4);
50
+ color: var(--sl-color-white);
51
+ line-height: var(--sl-line-height-headings);
52
+ gap: 1rem;
53
+ align-items: center;
54
+ }
55
+ .card .icon {
56
+ border: 1px solid var(--sl-card-border);
57
+ background-color: var(--sl-card-bg);
58
+ padding: 0.2em;
59
+ border-radius: 0.25rem;
60
+ }
61
+ .card .body {
62
+ margin: 0;
63
+ font-size: clamp(var(--sl-text-sm), calc(0.5rem + 1vw), var(--sl-text-body));
64
+ }
69
65
  </style>
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  interface Props {
3
- stagger?: boolean;
3
+ stagger?: boolean;
4
4
  }
5
5
 
6
6
  const { stagger = false } = Astro.props;
@@ -9,27 +9,27 @@ const { stagger = false } = Astro.props;
9
9
  <div class:list={['card-grid', { stagger }]}><slot /></div>
10
10
 
11
11
  <style>
12
- .card-grid {
13
- display: grid;
14
- gap: 1rem;
15
- }
12
+ .card-grid {
13
+ display: grid;
14
+ gap: 1rem;
15
+ }
16
16
 
17
- .card-grid > :global(*) {
18
- margin-top: 0 !important;
19
- }
17
+ .card-grid > :global(*) {
18
+ margin-top: 0 !important;
19
+ }
20
20
 
21
- @media (min-width: 50rem) {
22
- .card-grid {
23
- grid-template-columns: 1fr 1fr;
24
- gap: 1.5rem;
25
- }
26
- .stagger {
27
- --stagger-height: 5rem;
28
- padding-bottom: var(--stagger-height);
29
- }
21
+ @media (min-width: 50rem) {
22
+ .card-grid {
23
+ grid-template-columns: 1fr 1fr;
24
+ gap: 1.5rem;
25
+ }
26
+ .stagger {
27
+ --stagger-height: 5rem;
28
+ padding-bottom: var(--stagger-height);
29
+ }
30
30
 
31
- .stagger > :global(*):nth-child(2n) {
32
- transform: translateY(var(--stagger-height));
33
- }
34
- }
31
+ .stagger > :global(*):nth-child(2n) {
32
+ transform: translateY(var(--stagger-height));
33
+ }
34
+ }
35
35
  </style>
@@ -2,34 +2,32 @@
2
2
  import { Icons } from '../components/Icons';
3
3
 
4
4
  interface Props {
5
- name: keyof typeof Icons;
6
- label?: string;
7
- color?: string;
8
- size?: string;
9
- class?: string;
5
+ name: keyof typeof Icons;
6
+ label?: string;
7
+ color?: string;
8
+ size?: string;
9
+ class?: string;
10
10
  }
11
11
 
12
12
  const { name, label, size = '1em', color } = Astro.props;
13
- const a11yAttrs = label
14
- ? ({ 'aria-label': label } as const)
15
- : ({ 'aria-hidden': 'true' } as const);
13
+ const a11yAttrs = label ? ({ 'aria-label': label } as const) : ({ 'aria-hidden': 'true' } as const);
16
14
  ---
17
15
 
18
16
  <svg
19
- {...a11yAttrs}
20
- class={Astro.props.class}
21
- width="16"
22
- height="16"
23
- viewBox="0 0 24 24"
24
- fill="currentColor"
25
- set:html={Icons[name]}
17
+ {...a11yAttrs}
18
+ class={Astro.props.class}
19
+ width="16"
20
+ height="16"
21
+ viewBox="0 0 24 24"
22
+ fill="currentColor"
23
+ set:html={Icons[name]}
26
24
  />
27
25
 
28
26
  <style define:vars={{ 'sl-icon-color': color, 'sl-icon-size': size }}>
29
- svg {
30
- color: var(--sl-icon-color);
31
- font-size: var(--sl-icon-size, 1em);
32
- width: 1em;
33
- height: 1em;
34
- }
27
+ svg {
28
+ color: var(--sl-icon-color);
29
+ font-size: var(--sl-icon-size, 1em);
30
+ width: 1em;
31
+ height: 1em;
32
+ }
35
33
  </style>
@@ -2,16 +2,16 @@
2
2
  import { TabItemTagname } from './rehype-tabs';
3
3
 
4
4
  interface Props {
5
- label: string;
5
+ label: string;
6
6
  }
7
7
 
8
8
  const { label } = Astro.props;
9
9
 
10
10
  if (!label) {
11
- throw new Error('Missing prop `label` on `<TabItem>` component.');
11
+ throw new Error('Missing prop `label` on `<TabItem>` component.');
12
12
  }
13
13
  ---
14
14
 
15
15
  <TabItemTagname data-label={label}>
16
- <slot />
16
+ <slot />
17
17
  </TabItemTagname>
@@ -6,138 +6,134 @@ const { html, panels } = processPanels(panelHtml);
6
6
  ---
7
7
 
8
8
  <starlight-tabs>
9
- {
10
- panels && (
11
- <div class="tablist-wrapper not-content">
12
- <ul role="tablist">
13
- {panels.map(({ label, panelId, tabId }, idx) => (
14
- <li role="presentation" class="tab">
15
- <a
16
- role="tab"
17
- href={'#' + panelId}
18
- id={tabId}
19
- aria-selected={idx === 0 && 'true'}
20
- tabindex={idx !== 0 ? -1 : 0}
21
- >
22
- {label}
23
- </a>
24
- </li>
25
- ))}
26
- </ul>
27
- </div>
28
- )
29
- }
30
- <Fragment set:html={html} />
9
+ {
10
+ panels && (
11
+ <div class="tablist-wrapper not-content">
12
+ <ul role="tablist">
13
+ {panels.map(({ label, panelId, tabId }, idx) => (
14
+ <li role="presentation" class="tab">
15
+ <a
16
+ role="tab"
17
+ href={'#' + panelId}
18
+ id={tabId}
19
+ aria-selected={idx === 0 && 'true'}
20
+ tabindex={idx !== 0 ? -1 : 0}
21
+ >
22
+ {label}
23
+ </a>
24
+ </li>
25
+ ))}
26
+ </ul>
27
+ </div>
28
+ )
29
+ }
30
+ <Fragment set:html={html} />
31
31
  </starlight-tabs>
32
32
 
33
33
  <style>
34
- starlight-tabs {
35
- display: block;
36
- }
34
+ starlight-tabs {
35
+ display: block;
36
+ }
37
37
 
38
- .tablist-wrapper {
39
- overflow-x: auto;
40
- }
38
+ .tablist-wrapper {
39
+ overflow-x: auto;
40
+ }
41
41
 
42
- [role='tablist'] {
43
- display: flex;
44
- list-style: none;
45
- border-bottom: 2px solid var(--sl-color-gray-5);
46
- padding: 0;
47
- }
42
+ [role='tablist'] {
43
+ display: flex;
44
+ list-style: none;
45
+ border-bottom: 2px solid var(--sl-color-gray-5);
46
+ padding: 0;
47
+ }
48
48
 
49
- .tab {
50
- margin-bottom: -2px;
51
- }
52
- .tab > [role='tab'] {
53
- display: block;
54
- padding: 0 1.25rem;
55
- text-decoration: none;
56
- border-bottom: 2px solid var(--sl-color-gray-5);
57
- color: var(--sl-color-gray-3);
58
- outline-offset: var(--sl-outline-offset-inside);
59
- }
60
- .tab [role='tab'][aria-selected] {
61
- color: var(--sl-color-white);
62
- border-color: var(--sl-color-text-accent);
63
- font-weight: 600;
64
- }
49
+ .tab {
50
+ margin-bottom: -2px;
51
+ }
52
+ .tab > [role='tab'] {
53
+ display: block;
54
+ padding: 0 1.25rem;
55
+ text-decoration: none;
56
+ border-bottom: 2px solid var(--sl-color-gray-5);
57
+ color: var(--sl-color-gray-3);
58
+ outline-offset: var(--sl-outline-offset-inside);
59
+ }
60
+ .tab [role='tab'][aria-selected] {
61
+ color: var(--sl-color-white);
62
+ border-color: var(--sl-color-text-accent);
63
+ font-weight: 600;
64
+ }
65
65
 
66
- .tablist-wrapper ~ :global([role='tabpanel']) {
67
- margin-top: 1rem;
68
- }
66
+ .tablist-wrapper ~ :global([role='tabpanel']) {
67
+ margin-top: 1rem;
68
+ }
69
69
  </style>
70
70
 
71
71
  <script>
72
- class StarlightTabs extends HTMLElement {
73
- tabs: HTMLAnchorElement[];
74
- panels: HTMLElement[];
72
+ class StarlightTabs extends HTMLElement {
73
+ tabs: HTMLAnchorElement[];
74
+ panels: HTMLElement[];
75
75
 
76
- constructor() {
77
- super();
78
- const tablist = this.querySelector<HTMLUListElement>('[role="tablist"]')!;
79
- this.tabs = [
80
- ...tablist.querySelectorAll<HTMLAnchorElement>('[role="tab"]'),
81
- ];
82
- this.panels = [
83
- ...this.querySelectorAll<HTMLElement>('[role="tabpanel"]'),
84
- ];
76
+ constructor() {
77
+ super();
78
+ const tablist = this.querySelector<HTMLUListElement>('[role="tablist"]')!;
79
+ this.tabs = [...tablist.querySelectorAll<HTMLAnchorElement>('[role="tab"]')];
80
+ this.panels = [...this.querySelectorAll<HTMLElement>('[role="tabpanel"]')];
85
81
 
86
- this.tabs.forEach((tab, i) => {
87
- // Handle clicks for mouse users
88
- tab.addEventListener('click', (e) => {
89
- e.preventDefault();
90
- const currentTab = tablist.querySelector('[aria-selected]');
91
- if (e.currentTarget !== currentTab) {
92
- this.switchTab(e.currentTarget as HTMLAnchorElement, i);
93
- }
94
- });
82
+ this.tabs.forEach((tab, i) => {
83
+ // Handle clicks for mouse users
84
+ tab.addEventListener('click', (e) => {
85
+ e.preventDefault();
86
+ const currentTab = tablist.querySelector('[aria-selected]');
87
+ if (e.currentTarget !== currentTab) {
88
+ this.switchTab(e.currentTarget as HTMLAnchorElement, i);
89
+ }
90
+ });
95
91
 
96
- // Handle keyboard input
97
- tab.addEventListener('keydown', (e) => {
98
- const index = this.tabs.indexOf(e.currentTarget as any);
99
- // Work out which key the user is pressing and
100
- // Calculate the new tab's index where appropriate
101
- const nextIndex =
102
- e.key === 'ArrowLeft'
103
- ? index - 1
104
- : e.key === 'ArrowRight'
105
- ? index + 1
106
- : e.key === 'Home'
107
- ? 0
108
- : e.key === 'End'
109
- ? this.tabs.length - 1
110
- : null;
111
- if (nextIndex === null) return;
112
- if (this.tabs[nextIndex]) {
113
- e.preventDefault();
114
- this.switchTab(this.tabs[nextIndex], nextIndex);
115
- }
116
- });
117
- });
118
- }
92
+ // Handle keyboard input
93
+ tab.addEventListener('keydown', (e) => {
94
+ const index = this.tabs.indexOf(e.currentTarget as any);
95
+ // Work out which key the user is pressing and
96
+ // Calculate the new tab's index where appropriate
97
+ const nextIndex =
98
+ e.key === 'ArrowLeft'
99
+ ? index - 1
100
+ : e.key === 'ArrowRight'
101
+ ? index + 1
102
+ : e.key === 'Home'
103
+ ? 0
104
+ : e.key === 'End'
105
+ ? this.tabs.length - 1
106
+ : null;
107
+ if (nextIndex === null) return;
108
+ if (this.tabs[nextIndex]) {
109
+ e.preventDefault();
110
+ this.switchTab(this.tabs[nextIndex], nextIndex);
111
+ }
112
+ });
113
+ });
114
+ }
119
115
 
120
- switchTab(newTab: HTMLAnchorElement | null | undefined, index: number) {
121
- if (!newTab) return;
116
+ switchTab(newTab: HTMLAnchorElement | null | undefined, index: number) {
117
+ if (!newTab) return;
122
118
 
123
- // Mark all tabs as unselected and hide all tab panels.
124
- this.tabs.forEach((tab) => {
125
- tab.removeAttribute('aria-selected');
126
- tab.setAttribute('tabindex', '-1');
127
- });
128
- this.panels.forEach((oldPanel) => {
129
- oldPanel.hidden = true;
130
- });
119
+ // Mark all tabs as unselected and hide all tab panels.
120
+ this.tabs.forEach((tab) => {
121
+ tab.removeAttribute('aria-selected');
122
+ tab.setAttribute('tabindex', '-1');
123
+ });
124
+ this.panels.forEach((oldPanel) => {
125
+ oldPanel.hidden = true;
126
+ });
131
127
 
132
- // Show new panel and mark new tab as selected.
133
- const newPanel = this.panels[index];
134
- if (newPanel) newPanel.hidden = false;
135
- // Restore active tab to the default tab order.
136
- newTab.removeAttribute('tabindex');
137
- newTab.setAttribute('aria-selected', 'true');
138
- newTab.focus();
139
- }
140
- }
128
+ // Show new panel and mark new tab as selected.
129
+ const newPanel = this.panels[index];
130
+ if (newPanel) newPanel.hidden = false;
131
+ // Restore active tab to the default tab order.
132
+ newTab.removeAttribute('tabindex');
133
+ newTab.setAttribute('aria-selected', 'true');
134
+ newTab.focus();
135
+ }
136
+ }
141
137
 
142
- customElements.define('starlight-tabs', StarlightTabs);
138
+ customElements.define('starlight-tabs', StarlightTabs);
143
139
  </script>