@astrojs/starlight 0.38.5 → 0.39.1

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/CHANGELOG.md CHANGED
@@ -1,5 +1,101 @@
1
1
  # @astrojs/starlight
2
2
 
3
+ ## 0.39.1
4
+
5
+ ### Patch Changes
6
+
7
+ - [#3885](https://github.com/withastro/starlight/pull/3885) [`010eed1`](https://github.com/withastro/starlight/commit/010eed1d73d88481a116546caa800385f409ce28) Thanks [@ArmandPhilippot](https://github.com/ArmandPhilippot)! - Fixes the version mentioned in an error message related to autogenerated sidebar groups support.
8
+
9
+ - [#3887](https://github.com/withastro/starlight/pull/3887) [`b3c6990`](https://github.com/withastro/starlight/commit/b3c699042cf0a0f69f6637772275afb4418c6ebf) Thanks [@delucis](https://github.com/delucis)! - Adds 13 new icons: `clock`, `desktop`, `mobile-android`, `window`, `database`, `server`, `code-branch`, `notes`, `question`, `question-circle`, `analytics`, `padlock`, and `solidjs`.
10
+
11
+ ## 0.39.0
12
+
13
+ ### Minor Changes
14
+
15
+ - [#3618](https://github.com/withastro/starlight/pull/3618) [`dcf6d09`](https://github.com/withastro/starlight/commit/dcf6d094bbcfa1f83e45742901f4178df07c2156) Thanks [@HiDeoo](https://github.com/HiDeoo)! - **⚠️ BREAKING CHANGE:** This release changes how autogenerated links work in Starlight’s sidebar configuration.
16
+
17
+ If you have sidebar groups using the `autogenerate` key, you must now wrap that configuration in an `items` array:
18
+
19
+ ```diff
20
+ {
21
+ label: 'My group',
22
+ - autogenerate: { directory: 'some-dir' },
23
+ + items: [{ autogenerate: { directory: 'some-dir' } }],
24
+ }
25
+ ```
26
+
27
+ This change unlocks the possibility to mix autogenerated links and other links in a single group, for example:
28
+
29
+ ```js
30
+ {
31
+ label: 'Mixed group',
32
+ items: [
33
+ 'example-page',
34
+ { autogenerate: { directory: 'examples' } },
35
+ { label: 'More examples', link: 'https://example.com' },
36
+ ],
37
+ }
38
+ ```
39
+
40
+ This release also updates the shape of autogenerated sidebar entries in route data. Autogenerated links and groups in `Astro.locals.starlightRoute.sidebar` now include an `autogenerate` object with the [configured `directory` value](https://starlight.astro.build/guides/sidebar/#autogenerated-groups):
41
+
42
+ ```js
43
+ {
44
+ type: 'link',
45
+ label: 'Example',
46
+ href: '/examples/example/',
47
+ isCurrent: false,
48
+ autogenerate: { directory: 'examples' }
49
+ }
50
+ ```
51
+
52
+ - [#3618](https://github.com/withastro/starlight/pull/3618) [`dcf6d09`](https://github.com/withastro/starlight/commit/dcf6d094bbcfa1f83e45742901f4178df07c2156) Thanks [@HiDeoo](https://github.com/HiDeoo)! - **⚠️ BREAKING CHANGE:** This release changes the default collapsed state of autogenerated sidebar subgroups.
53
+
54
+ Autogenerated subgroups no longer inherit the `collapsed` value from their parent group. They are now expanded by default unless explicitly configured with [`autogenerate.collapsed`](https://starlight.astro.build/reference/configuration/#collapsing-groups).
55
+
56
+ If your sidebar configuration relies on a collapsed parent group to also collapse its autogenerated subgroups, update your configuration to set `autogenerate.collapsed` to `true`:
57
+
58
+ ```diff
59
+ {
60
+ label: 'Reference',
61
+ collapsed: true,
62
+ items: [
63
+ - { autogenerate: { directory: 'reference' } },
64
+ + { autogenerate: { directory: 'reference', collapsed: true } },
65
+ ],
66
+ }
67
+ ```
68
+
69
+ - [#3845](https://github.com/withastro/starlight/pull/3845) [`4d755f5`](https://github.com/withastro/starlight/commit/4d755f591bbca682d01a70162a10c12ab5187c61) Thanks [@delucis](https://github.com/delucis)! - Adds a `<link rel="alternate" hreflang="x-default" href="...">` tag pointing to the default locale in multilingual sites. The `x-default` alternate is used as a signal of which language to fall back to if no other is available. Learn more in Google’s [SEO localization docs](https://developers.google.com/search/docs/specialty/international/localized-versions#xdefault).
70
+
71
+ - [#3862](https://github.com/withastro/starlight/pull/3862) [`ec70630`](https://github.com/withastro/starlight/commit/ec70630cbbe43bb5b026ddabfe7224759c798a4b) Thanks [@itrew](https://github.com/itrew)! - Makes spacing of items in nested lists more consistent
72
+
73
+ - [#3872](https://github.com/withastro/starlight/pull/3872) [`417a66c`](https://github.com/withastro/starlight/commit/417a66c4acf3a7408fc0cea701aa5f143c540e5c) Thanks [@tats-u](https://github.com/tats-u)! - Enables [the CSS property `text-autospace`](https://developer.mozilla.org/docs/Web/CSS/Reference/Properties/text-autospace) in Chinese and Japanese documents.
74
+
75
+ If you would prefer to disable autospacing in Chinese and Japanese pages, you can add the following custom CSS to your site:
76
+
77
+ ```css
78
+ [lang]:where(:lang(zh, ja)) {
79
+ text-autospace: initial;
80
+ }
81
+ ```
82
+
83
+ - [#3797](https://github.com/withastro/starlight/pull/3797) [`9764ebd`](https://github.com/withastro/starlight/commit/9764ebdab8d12983064d11515b6d92355a4d95eb) Thanks [@delucis](https://github.com/delucis)! - Avoids the risk of layout shift when users expand and collapse sidebar groups
84
+
85
+ This release can introduce additional padding to the site sidebar on certain devices to reserve space for scrollbars. You may wish to inspect your site sidebar visually when upgrading.
86
+
87
+ If you would prefer to keep the previous styling, you can add the following custom CSS to your site:
88
+
89
+ ```css
90
+ .sidebar-pane {
91
+ scrollbar-gutter: auto;
92
+ }
93
+ ```
94
+
95
+ - [#3858](https://github.com/withastro/starlight/pull/3858) [`6672c35`](https://github.com/withastro/starlight/commit/6672c35b914cd53f1641a43a7ea8e7ef08d9cc8f) Thanks [@delucis](https://github.com/delucis)! - Updates `i18next`, used for Starlight’s localization APIs, from v23 to v26
96
+
97
+ There should not be any user-facing changes from this update
98
+
3
99
  ## 0.38.5
4
100
 
5
101
  ### Patch Changes
@@ -56,6 +56,7 @@ const { hasSidebar } = Astro.locals.starlightRoute;
56
56
  width: 100%;
57
57
  background-color: var(--sl-color-black);
58
58
  overflow-y: auto;
59
+ scrollbar-gutter: stable;
59
60
  }
60
61
 
61
62
  :global([aria-expanded='true']) ~ .sidebar-pane {
@@ -37,10 +37,26 @@ export const BuiltInIcons = {
37
37
  '<path d="M14.29 17.29 13 18.59V13a1 1 0 0 0-2 0v5.59l-1.29-1.3a1 1 0 0 0-1.42 1.42l3 3a1 1 0 0 0 .33.21.94.94 0 0 0 .76 0 1 1 0 0 0 .33-.21l3-3a1 1 0 0 0-1.42-1.42Zm4.13-11.07A7 7 0 0 0 5.06 8.11 4 4 0 0 0 6 16a1 1 0 0 0 0-2 2 2 0 0 1 0-4 1 1 0 0 0 1-1 5 5 0 0 1 9.73-1.61 1 1 0 0 0 .78.67 3 3 0 0 1 .24 5.84 1 1 0 1 0 .5 1.94 5 5 0 0 0 .17-9.62Z"/>',
38
38
  moon: '<path d="M21.64 13a1 1 0 0 0-1.05-.14 8.049 8.049 0 0 1-3.37.73 8.15 8.15 0 0 1-8.14-8.1 8.59 8.59 0 0 1 .25-2A1 1 0 0 0 8 2.36a10.14 10.14 0 1 0 14 11.69 1 1 0 0 0-.36-1.05Zm-9.5 6.69A8.14 8.14 0 0 1 7.08 5.22v.27a10.15 10.15 0 0 0 10.14 10.14 9.784 9.784 0 0 0 2.1-.22 8.11 8.11 0 0 1-7.18 4.32v-.04Z"/>',
39
39
  sun: '<path d="M5 12a1 1 0 0 0-1-1H3a1 1 0 0 0 0 2h1a1 1 0 0 0 1-1Zm.64 5-.71.71a1 1 0 0 0 0 1.41 1 1 0 0 0 1.41 0l.71-.71A1 1 0 0 0 5.64 17ZM12 5a1 1 0 0 0 1-1V3a1 1 0 0 0-2 0v1a1 1 0 0 0 1 1Zm5.66 2.34a1 1 0 0 0 .7-.29l.71-.71a1 1 0 1 0-1.41-1.41l-.66.71a1 1 0 0 0 0 1.41 1 1 0 0 0 .66.29Zm-12-.29a1 1 0 0 0 1.41 0 1 1 0 0 0 0-1.41l-.71-.71a1.004 1.004 0 1 0-1.43 1.41l.73.71ZM21 11h-1a1 1 0 0 0 0 2h1a1 1 0 0 0 0-2Zm-2.64 6A1 1 0 0 0 17 18.36l.71.71a1 1 0 0 0 1.41 0 1 1 0 0 0 0-1.41l-.76-.66ZM12 6.5a5.5 5.5 0 1 0 5.5 5.5A5.51 5.51 0 0 0 12 6.5Zm0 9a3.5 3.5 0 1 1 0-7 3.5 3.5 0 0 1 0 7Zm0 3.5a1 1 0 0 0-1 1v1a1 1 0 0 0 2 0v-1a1 1 0 0 0-1-1Z"/>',
40
+ clock:
41
+ '<path d="M15.1 12.6 13 11.4V7a1 1 0 0 0-2 0v5a1 1 0 0 0 .5.9l2.6 1.5a1 1 0 1 0 1-1.8M12 2a10 10 0 1 0 10 10A10 10 0 0 0 12 2m0 18a8 8 0 1 1 8-8 8 8 0 0 1-8 8"/>',
40
42
  laptop:
41
43
  '<path d="M21 14h-1V7a3 3 0 0 0-3-3H7a3 3 0 0 0-3 3v7H3a1 1 0 0 0-1 1v2a3 3 0 0 0 3 3h14a3 3 0 0 0 3-3v-2a1 1 0 0 0-1-1ZM6 7a1 1 0 0 1 1-1h10a1 1 0 0 1 1 1v7H6V7Zm14 10a1 1 0 0 1-1 1H5a1 1 0 0 1-1-1v-1h16v1Z"/>',
44
+ desktop:
45
+ '<path d="M19 3H5a3 3 0 0 0-3 3v8a3 3 0 0 0 3 3h6v2H7a1 1 0 0 0 0 2h10a1 1 0 0 0 0-2h-4v-2h6a3 3 0 0 0 3-3V6a3 3 0 0 0-3-3m1 11a1 1 0 0 1-1 1H5a1 1 0 0 1-1-1V6a1 1 0 0 1 1-1h14a1 1 0 0 1 1 1Z"/>',
46
+ 'mobile-android':
47
+ '<path d="m12.71 16.29-.15-.12-.18-.09-.18-.08a1 1 0 0 0-.91.27 1 1 0 0 0-.21.33 1 1 0 0 0 1.3 1.31l.33-.22a1 1 0 0 0 .21-1.09 1 1 0 0 0-.21-.31M16 2H8a3 3 0 0 0-3 3v14a3 3 0 0 0 3 3h8a3 3 0 0 0 3-3V5a3 3 0 0 0-3-3m1 17a1 1 0 0 1-1 1H8a1 1 0 0 1-1-1V5a1 1 0 0 1 1-1h8a1 1 0 0 1 1 1Z"/>',
48
+ window:
49
+ '<path d="M10 5a1 1 0 1 0 1 1 1 1 0 0 0-1-1M6 5a1 1 0 1 0 1 1 1 1 0 0 0-1-1m8 0a1 1 0 1 0 1 1 1 1 0 0 0-1-1m6-4H4a3 3 0 0 0-3 3v16a3 3 0 0 0 3 3h16a3 3 0 0 0 3-3V4a3 3 0 0 0-3-3m1 19a1 1 0 0 1-1 1H4a1 1 0 0 1-1-1v-9h18Zm0-11H3V4a1 1 0 0 1 1-1h16a1 1 0 0 1 1 1Z"/>',
50
+ database:
51
+ '<path d="M8 16.5a1 1 0 1 0 1 1 1 1 0 0 0-1-1M12 2C8 2 4 3.37 4 6v12c0 2.63 4 4 8 4s8-1.37 8-4V6c0-2.63-4-4-8-4m6 16c0 .71-2.28 2-6 2s-6-1.29-6-2v-3.27A13 13 0 0 0 12 16a13 13 0 0 0 6-1.27Zm0-6c0 .71-2.28 2-6 2s-6-1.29-6-2V8.73A13 13 0 0 0 12 10a13 13 0 0 0 6-1.27Zm-6-4C8.28 8 6 6.71 6 6s2.28-2 6-2 6 1.29 6 2-2.28 2-6 2m-4 2.5a1 1 0 1 0 1 1 1 1 0 0 0-1-1"/>',
52
+ server:
53
+ '<path d="M15 17a1 1 0 1 0 1 1 1 1 0 0 0-1-1m-6 0H6a1 1 0 0 0 0 2h3a1 1 0 0 0 0-2m9 0a1 1 0 1 0 1 1 1 1 0 0 0-1-1m-3-6a1 1 0 1 0 1 1 1 1 0 0 0-1-1m-6 0H6a1 1 0 0 0 0 2h3a1 1 0 0 0 0-2m9-6a1 1 0 1 0 1 1 1 1 0 0 0-1-1m0 6a1 1 0 1 0 1 1 1 1 0 0 0-1-1m4-6a3 3 0 0 0-3-3H5a3 3 0 0 0-3 3v2a3 3 0 0 0 .78 2A3 3 0 0 0 2 11v2a3 3 0 0 0 .78 2A3 3 0 0 0 2 17v2a3 3 0 0 0 3 3h14a3 3 0 0 0 3-3v-2a3 3 0 0 0-.78-2 3 3 0 0 0 .78-2v-2a3 3 0 0 0-.78-2A3 3 0 0 0 22 7Zm-2 14a1 1 0 0 1-1 1H5a1 1 0 0 1-1-1v-2a1 1 0 0 1 1-1h14a1 1 0 0 1 1 1Zm0-6a1 1 0 0 1-1 1H5a1 1 0 0 1-1-1v-2a1 1 0 0 1 1-1h14a1 1 0 0 1 1 1Zm0-6a1 1 0 0 1-1 1H5a1 1 0 0 1-1-1V5a1 1 0 0 1 1-1h14a1 1 0 0 1 1 1Zm-5-2a1 1 0 1 0 1 1 1 1 0 0 0-1-1M9 5H6a1 1 0 0 0 0 2h3a1 1 0 0 0 0-2"/>',
54
+ 'code-branch':
55
+ '<path d="M17 6.06a3 3 0 0 0-1.15 5.77A2 2 0 0 1 14 13.06h-4a4 4 0 0 0-2 .56V7.88a3 3 0 1 0-2 0v8.36a3 3 0 1 0 2.16.05A2 2 0 0 1 10 15.06h4a4 4 0 0 0 3.91-3.16A3 3 0 0 0 17 6.06m-10-2a1 1 0 1 1-1 1 1 1 0 0 1 1-1m0 16a1 1 0 1 1 1-1 1 1 0 0 1-1 1m10-10a1 1 0 1 1 1-1 1 1 0 0 1-1 1"/>',
42
56
  'open-book':
43
57
  '<path d="M21.17 2.06A13.1 13.1 0 0 0 19 1.87a12.94 12.94 0 0 0-7 2.05 12.94 12.94 0 0 0-7-2 13.1 13.1 0 0 0-2.17.19 1 1 0 0 0-.83 1v12a1 1 0 0 0 1.17 1 10.9 10.9 0 0 1 8.25 1.91l.12.07h.11a.91.91 0 0 0 .7 0h.11l.12-.07A10.899 10.899 0 0 1 20.83 16 1 1 0 0 0 22 15V3a1 1 0 0 0-.83-.94ZM11 15.35a12.87 12.87 0 0 0-6-1.48H4v-10c.333-.02.667-.02 1 0a10.86 10.86 0 0 1 6 1.8v9.68Zm9-1.44h-1a12.87 12.87 0 0 0-6 1.48V5.67a10.86 10.86 0 0 1 6-1.8c.333-.02.667-.02 1 0v10.04Zm1.17 4.15a13.098 13.098 0 0 0-2.17-.19 12.94 12.94 0 0 0-7 2.05 12.94 12.94 0 0 0-7-2.05c-.727.003-1.453.066-2.17.19A1 1 0 0 0 2 19.21a1 1 0 0 0 1.17.79 10.9 10.9 0 0 1 8.25 1.91 1 1 0 0 0 1.16 0A10.9 10.9 0 0 1 20.83 20a1 1 0 0 0 1.17-.79 1 1 0 0 0-.83-1.15Z"/>',
58
+ notes:
59
+ '<path d="M16 14H8a1 1 0 0 0 0 2h8a1 1 0 0 0 0-2m0-4h-6a1 1 0 0 0 0 2h6a1 1 0 0 0 0-2m4-6h-3V3a1 1 0 0 0-2 0v1h-2V3a1 1 0 0 0-2 0v1H9V3a1 1 0 0 0-2 0v1H4a1 1 0 0 0-1 1v14a3 3 0 0 0 3 3h12a3 3 0 0 0 3-3V5a1 1 0 0 0-1-1m-1 15a1 1 0 0 1-1 1H6a1 1 0 0 1-1-1V6h2v1a1 1 0 0 0 2 0V6h2v1a1 1 0 0 0 2 0V6h2v1a1 1 0 0 0 2 0V6h2Z"/>',
44
60
  information:
45
61
  '<path d="M12 11a1 1 0 0 0-1 1v4a1 1 0 0 0 2 0v-4a1 1 0 0 0-1-1Zm.38-3.92a1 1 0 0 0-.76 0 1 1 0 0 0-.33.21 1.15 1.15 0 0 0-.21.33 1 1 0 0 0 .21 1.09c.097.088.209.16.33.21A1 1 0 0 0 13 8a1.05 1.05 0 0 0-.29-.71 1 1 0 0 0-.33-.21ZM12 2a10 10 0 1 0 0 20 10 10 0 0 0 0-20Zm0 18a8 8 0 1 1 0-16.001A8 8 0 0 1 12 20Z"/>',
46
62
  magnifier:
@@ -57,6 +73,10 @@ export const BuiltInIcons = {
57
73
  '<path d="m14.72 8.79-4.29 4.3-1.65-1.65a1 1 0 1 0-1.41 1.41l2.35 2.36a1 1 0 0 0 1.41 0l5-5a1.002 1.002 0 1 0-1.41-1.42ZM12 2a10 10 0 1 0 0 20 10 10 0 0 0 0-20Zm0 18a8 8 0 1 1 0-16.001A8 8 0 0 1 12 20Z"/>',
58
74
  'approve-check':
59
75
  '<path d="M18.71 7.21a1 1 0 0 0-1.42 0l-7.45 7.46-3.13-3.14A1.02 1.02 0 1 0 5.29 13l3.84 3.84a1.001 1.001 0 0 0 1.42 0l8.16-8.16a1 1 0 0 0 0-1.47Z"/>',
76
+ 'question-circle':
77
+ '<path d="m11.29 15.29-.12.15-.09.18-.06.18v.2a1 1 0 0 0 .08.38 1 1 0 0 0 .54.54 1 1 0 0 0 .76 0 1 1 0 0 0 .54-.54A1 1 0 0 0 13 16a1 1 0 0 0-.29-.71 1 1 0 0 0-1.42 0M12 2a10 10 0 1 0 10 10A10 10 0 0 0 12 2m0 18a8 8 0 1 1 8-8 8 8 0 0 1-8 8m0-13a3 3 0 0 0-2.6 1.5 1 1 0 1 0 1.73 1A1 1 0 0 1 12 9a1 1 0 0 1 0 2 1 1 0 0 0-1 1v1a1 1 0 0 0 2 0v-.18A3 3 0 0 0 12 7"/>',
78
+ question:
79
+ '<path d="M15.33 9.5A3.5 3.5 0 0 0 8.8 7.75a1 1 0 0 0 1.73 1 1.5 1.5 0 0 1 1.3-.75 1.5 1.5 0 1 1 0 3l-.19.04-.2.04-.15.1-.16.11-.12.18-.1.14-.04.21-.04.18v1.51a1 1 0 0 0 1 .99 1 1 0 0 0 1-1v-.66a3.5 3.5 0 0 0 2.5-3.34m-4.2 6.79a1 1 0 0 0 .7 1.71 1 1 0 0 0 .71-.29 1 1 0 0 0 0-1.42 1.03 1.03 0 0 0-1.41 0"/>',
60
80
  rocket:
61
81
  '<path fill-rule="evenodd" d="M1.44 8.855v-.001l3.527-3.516c.34-.344.802-.541 1.285-.548h6.649l.947-.947c3.07-3.07 6.207-3.072 7.62-2.868a1.821 1.821 0 0 1 1.557 1.557c.204 1.413.203 4.55-2.868 7.62l-.946.946v6.649a1.845 1.845 0 0 1-.549 1.286l-3.516 3.528a1.844 1.844 0 0 1-3.11-.944l-.858-4.275-4.52-4.52-2.31-.463-1.964-.394A1.847 1.847 0 0 1 .98 10.693a1.843 1.843 0 0 1 .46-1.838Zm5.379 2.017-3.873-.776L6.32 6.733h4.638l-4.14 4.14Zm8.403-5.655c2.459-2.46 4.856-2.463 5.89-2.33.134 1.035.13 3.432-2.329 5.891l-6.71 6.71-3.561-3.56 6.71-6.711Zm-1.318 15.837-.776-3.873 4.14-4.14v4.639l-3.364 3.374Z" clip-rule="evenodd"/><path d="M9.318 18.345a.972.972 0 0 0-1.86-.561c-.482 1.435-1.687 2.204-2.934 2.619a8.22 8.22 0 0 1-1.23.302c.062-.365.157-.79.303-1.229.415-1.247 1.184-2.452 2.62-2.935a.971.971 0 1 0-.62-1.842c-.12.04-.236.084-.35.13-2.02.828-3.012 2.588-3.493 4.033a10.383 10.383 0 0 0-.51 2.845l-.001.016v.063c0 .536.434.972.97.972H2.24a7.21 7.21 0 0 0 .878-.065c.527-.063 1.248-.19 2.02-.447 1.445-.48 3.205-1.472 4.033-3.494a5.828 5.828 0 0 0 .147-.407Z"/>',
62
82
  star: '<path d="M22 9.67a1 1 0 0 0-.86-.67l-5.69-.83L12.9 3a1 1 0 0 0-1.8 0L8.55 8.16 2.86 9a1 1 0 0 0-.81.68 1 1 0 0 0 .25 1l4.13 4-1 5.68a1 1 0 0 0 1.45 1.07L12 18.76l5.1 2.68c.14.08.3.12.46.12a1 1 0 0 0 .99-1.19l-1-5.68 4.13-4A1 1 0 0 0 22 9.67Zm-6.15 4a1 1 0 0 0-.29.89l.72 4.19-3.76-2a1 1 0 0 0-.94 0l-3.76 2 .72-4.19a1 1 0 0 0-.29-.89l-3-3 4.21-.61a1 1 0 0 0 .76-.55L12 5.7l1.88 3.82a1 1 0 0 0 .76.55l4.21.61-3 2.99Z"/>',
@@ -64,8 +84,12 @@ export const BuiltInIcons = {
64
84
  '<path d="M17 22H5a3 3 0 0 1-3-3V9a3 3 0 0 1 3-3h1a4 4 0 0 1 7.3-2.18c.448.64.692 1.4.7 2.18h3a1 1 0 0 1 1 1v3a4 4 0 0 1 2.18 7.3A3.86 3.86 0 0 1 18 18v3a1 1 0 0 1-1 1ZM5 8a1 1 0 0 0-1 1v10a1 1 0 0 0 1 1h11v-3.18a1 1 0 0 1 1.33-.95 1.77 1.77 0 0 0 1.74-.23 2 2 0 0 0 .93-1.37 2 2 0 0 0-.48-1.59 1.89 1.89 0 0 0-2.17-.55 1 1 0 0 1-1.33-.95V8h-3.2a1 1 0 0 1-1-1.33 1.77 1.77 0 0 0-.23-1.74 1.939 1.939 0 0 0-3-.43A2 2 0 0 0 8 6c.002.23.046.456.13.67A1 1 0 0 1 7.18 8H5Z"/>',
65
85
  'list-format':
66
86
  '<path d="M3.71 16.29a1 1 0 0 0-.33-.21 1 1 0 0 0-.76 0 1 1 0 0 0-.33.21 1 1 0 0 0-.21.33 1 1 0 0 0 .21 1.09c.097.088.209.16.33.21a.94.94 0 0 0 .76 0 1.15 1.15 0 0 0 .33-.21 1 1 0 0 0 .21-1.09 1 1 0 0 0-.21-.33ZM7 8h14a1 1 0 1 0 0-2H7a1 1 0 0 0 0 2Zm-3.29 3.29a1 1 0 0 0-1.09-.21 1.15 1.15 0 0 0-.33.21 1 1 0 0 0-.21.33.94.94 0 0 0 0 .76c.05.121.122.233.21.33.097.088.209.16.33.21a.94.94 0 0 0 .76 0 1.15 1.15 0 0 0 .33-.21 1.15 1.15 0 0 0 .21-.33.94.94 0 0 0 0-.76 1 1 0 0 0-.21-.33ZM21 11H7a1 1 0 0 0 0 2h14a1 1 0 0 0 0-2ZM3.71 6.29a1 1 0 0 0-.33-.21 1 1 0 0 0-1.09.21 1.15 1.15 0 0 0-.21.33.94.94 0 0 0 0 .76c.05.121.122.233.21.33.097.088.209.16.33.21a1 1 0 0 0 1.09-.21 1.15 1.15 0 0 0 .21-.33.94.94 0 0 0 0-.76 1.15 1.15 0 0 0-.21-.33ZM21 16H7a1 1 0 0 0 0 2h14a1 1 0 0 0 0-2Z"/>',
87
+ analytics:
88
+ '<path d="M5 12a1 1 0 0 0-1 1v8a1 1 0 0 0 2 0v-8a1 1 0 0 0-1-1m5-10a1 1 0 0 0-1 1v18a1 1 0 0 0 2 0V3a1 1 0 0 0-1-1m10 14a1 1 0 0 0-1 1v4a1 1 0 0 0 2 0v-4a1 1 0 0 0-1-1m-5-8a1 1 0 0 0-1 1v12a1 1 0 0 0 2 0V9a1 1 0 0 0-1-1"/>',
67
89
  random:
68
90
  '<path d="M8.7 10a1 1 0 0 0 1.41 0 1 1 0 0 0 0-1.41l-6.27-6.3a1 1 0 0 0-1.42 1.42ZM21 14a1 1 0 0 0-1 1v3.59L15.44 14A1 1 0 0 0 14 15.44L18.59 20H15a1 1 0 0 0 0 2h6a1 1 0 0 0 .38-.08 1 1 0 0 0 .54-.54A1 1 0 0 0 22 21v-6a1 1 0 0 0-1-1Zm.92-11.38a1 1 0 0 0-.54-.54A1 1 0 0 0 21 2h-6a1 1 0 0 0 0 2h3.59L2.29 20.29a1 1 0 0 0 0 1.42 1 1 0 0 0 1.42 0L20 5.41V9a1 1 0 0 0 2 0V3a1 1 0 0 0-.08-.38Z"/>',
91
+ padlock:
92
+ '<path d="M12 13a1.5 1.5 0 0 0-1 2.6V17a1 1 0 0 0 2 0v-1.4a1.5 1.5 0 0 0-1-2.6m5-4V7A5 5 0 0 0 7 7v2a3 3 0 0 0-3 3v7a3 3 0 0 0 3 3h10a3 3 0 0 0 3-3v-7a3 3 0 0 0-3-3M9 7a3 3 0 0 1 6 0v2H9Zm9 12a1 1 0 0 1-1 1H7a1 1 0 0 1-1-1v-7a1 1 0 0 1 1-1h10a1 1 0 0 1 1 1Z"/>',
69
93
  comment:
70
94
  '<path d="M12 2A10 10 0 0 0 2 12a9.9 9.9 0 0 0 2.3 6.3l-2 2a1 1 0 0 0-.3 1.1 1 1 0 0 0 1 .6h9a10 10 0 0 0 0-20m0 18H5.4l1-1a1 1 0 0 0 0-1.3A8 8 0 1 1 12 20"/>',
71
95
  'comment-alt':
@@ -145,6 +169,8 @@ export const BuiltInIcons = {
145
169
  '<path d="M12.525.02c1.31-.02 2.61-.01 3.91-.02.08 1.53.63 3.09 1.75 4.17 1.12 1.11 2.7 1.62 4.24 1.79v4.03c-1.44-.05-2.89-.35-4.2-.97-.57-.26-1.1-.59-1.62-.93-.01 2.92.01 5.84-.02 8.75-.08 1.4-.54 2.79-1.35 3.94-1.31 1.92-3.58 3.17-5.91 3.21-1.43.08-2.86-.31-4.08-1.03-2.02-1.19-3.44-3.37-3.65-5.71-.02-.5-.03-1-.01-1.49.18-1.9 1.12-3.72 2.58-4.96 1.66-1.44 3.98-2.13 6.15-1.72.02 1.48-.04 2.96-.04 4.44-.99-.32-2.15-.23-3.02.37-.63.41-1.11 1.04-1.36 1.75-.21.51-.15 1.07-.14 1.61.24 1.64 1.82 3.02 3.5 2.87 1.12-.01 2.19-.66 2.77-1.61.19-.33.4-.67.41-1.06.1-1.79.06-3.57.07-5.36.01-4.03-.01-8.05.02-12.07z"/>',
146
170
  astro:
147
171
  '<path d="M7.233 15.856c-.456 1.5-.132 3.586.948 4.57v-.036l.036-.096c.132-.636.648-1.032 1.309-1.008.612.012.96.336 1.044 1.044.036.264.036.528.048.803v.084c0 .6.168 1.176.504 1.68.3.48.72.851 1.284 1.103l-.024-.048-.024-.096c-.42-1.26-.12-2.135.984-2.879l.336-.227.745-.492a3.647 3.647 0 0 0 1.536-2.603c.06-.456 0-.9-.132-1.331l-.18.12c-1.668.887-3.577 1.2-5.425.84-1.117-.169-2.197-.48-3-1.416l.011-.012ZM2 15.592s3.205-1.559 6.421-1.559l2.437-7.508c.084-.36.348-.6.648-.6.3 0 .552.24.648.612l2.425 7.496c3.816 0 6.421 1.56 6.421 1.56L15.539.72c-.144-.444-.42-.72-.768-.72H8.24c-.348 0-.6.276-.768.72L2 15.592Z"/>',
172
+ solidjs:
173
+ '<path d="M12 1c1.2 0 2.84.43 4.64 1.2 1.83.79 3.9 1.95 5.96 3.5a1 1 0 0 1 .2 1.4l-3 4-.02.02-.03.04-.06.07q-.03 0-.04.03l-.07.05-.04.03-.07.04-.06.03-.06.03h-.02l-.4.14c.7.8 1.07 1.82 1.07 2.92a5 5 0 0 1-.8 2.6l-2.8 3.67q-.32.54-.79.97A5.3 5.3 0 0 1 12 23c-1.21 0-2.7-.45-4.41-1.21a49 49 0 0 1-6.13-3.45l-.02-.01-.04-.03-.04-.03-.02-.02a1 1 0 0 1-.24-.3v-.03l-.05-.12v-.01l-.03-.11v-.02L1 17.53v-.14l.07-.27.01-.01.06-.11v-.01l.06-.09 3-4 .1-.11a1 1 0 0 1 .36-.23l.4-.14-.21-.27A4.6 4.6 0 0 1 4 9.47a5 5 0 0 1 .82-2.79l3-3.8a5 5 0 0 1 1.58-1.4A6 6 0 0 1 12 1m0 15c-1.54 0-4.08.56-7.7 1.76q2.35 1.4 4.11 2.2A10 10 0 0 0 12 21c1.05 0 1.8-.31 2.27-.74q.18-.16.32-.37l.12-.2.02-.02q.26-.51.27-1.17a2.3 2.3 0 0 0-.73-1.76A3.3 3.3 0 0 0 12 16m3-4c-1.46 0-3.8.5-7.11 1.57l-2.27.77-.89 1.18Q9.47 14.01 12 14c1.45 0 2.7.44 3.61 1.26q.8.74 1.14 1.75l.82-1.06q.44-.79.43-1.45a2.3 2.3 0 0 0-1.45-2.21 1 1 0 0 1-.36-.13Q15.68 12 15 12M8.97 7c-1.16-.03-1.86.22-2.26.58-.39.34-.67.91-.7 1.91.02.67.2 1.13.44 1.46q.3.4.93.68 5-1.61 7.62-1.63.93 0 1.72.23l.14-.04-.24-.17C13.53 7.89 10.43 7 9 7zM12 3c-.93 0-1.4.12-1.7.27s-.54.37-.92.85L8.7 5H9c1.9 0 5.24 1.04 8.46 3.17l.3.2.03.02 1 .72 1.8-2.4a27 27 0 0 0-4.73-2.67A11 11 0 0 0 12 3"/>',
148
174
  alpine: '<path d="m18.7 6 5.3 5.3-5.3 5.3-5.4-5.3L18.7 6zM5.3 6l11 11H5.8L0 11.2 5.3 6z"/>',
149
175
  pnpm: '<path d="M0 0v7.5h7.5V0H0Zm8.25 0v7.5h7.498V0H8.25Zm8.25 0v7.5H24V0h-7.5ZM8.25 8.25v7.5h7.498v-7.5H8.25Zm8.25 0v7.5H24v-7.5h-7.5ZM0 16.5V24h7.5v-7.5H0Zm8.25 0V24h7.498v-7.5H8.25Zm8.25 0V24H24v-7.5h-7.5Z"/>',
150
176
  biome:
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@astrojs/starlight",
3
- "version": "0.38.5",
3
+ "version": "0.39.1",
4
4
  "description": "Build beautiful, high-performance documentation websites with Astro",
5
5
  "keywords": [
6
6
  "docs",
@@ -66,7 +66,7 @@
66
66
  "hast-util-select": "^6.0.4",
67
67
  "hast-util-to-string": "^3.0.1",
68
68
  "hastscript": "^9.0.1",
69
- "i18next": "^23.11.5",
69
+ "i18next": "^26.0.7",
70
70
  "js-yaml": "^4.1.1",
71
71
  "klona": "^2.0.6",
72
72
  "magic-string": "^0.30.21",
@@ -50,31 +50,63 @@ const SidebarLinkItemSchema = z.strictObject({
50
50
  });
51
51
  export type SidebarLinkItem = z.infer<typeof SidebarLinkItemSchema>;
52
52
 
53
- const AutoSidebarGroupSchema = z.strictObject({
54
- ...SidebarGroupSchema.shape,
55
- /** Enable autogenerating a sidebar category from a specific docs directory. */
56
- autogenerate: z.object({
57
- /** The directory to generate sidebar items for. */
58
- directory: z.string().transform(stripLeadingAndTrailingSlashes),
53
+ const AutoSidebarEntriesSchema = z
54
+ .object({
59
55
  /**
60
- * Whether the autogenerated subgroups should be collapsed by default.
61
- * Defaults to the `AutoSidebarGroup` `collapsed` value.
56
+ * Explicitly prevent autogenerated groups which are no longer supported as the final type for
57
+ * supported sidebar item is a non-discriminated union where TypeScript will not perform excess
58
+ * property checks. This means that a user could define a sidebar group with an autogenerated
59
+ * property, not getting a TypeScript error, and only have it fail at runtime.
60
+ * @see https://github.com/microsoft/TypeScript/issues/20863
62
61
  */
63
- collapsed: z.boolean().optional(),
64
- /** HTML attributes to add to the autogenerated link items. */
65
- attrs: SidebarLinkItemHTMLAttributesSchema(),
66
- // TODO: not supported by Docusaurus but would be good to have
67
- /** How many directories deep to include from this directory in the sidebar. Default: `Infinity`. */
68
- // depth: z.number().optional(),
69
- }),
70
- });
71
- export type AutoSidebarGroup = z.infer<typeof AutoSidebarGroupSchema>;
62
+ label: z.custom<never>().optional(),
63
+ /** Enable autogenerating entries from a specific docs directory. */
64
+ autogenerate: z.object({
65
+ /** The directory to generate sidebar items for. */
66
+ directory: z.string().transform(stripLeadingAndTrailingSlashes),
67
+ /** Whether the autogenerated subgroups should be collapsed by default. Default: `false`. */
68
+ collapsed: z.boolean().optional(),
69
+ /** HTML attributes to add to the autogenerated link items. */
70
+ attrs: SidebarLinkItemHTMLAttributesSchema(),
71
+ // TODO: not supported by Docusaurus but would be good to have
72
+ /** How many directories deep to include from this directory in the sidebar. Default: `Infinity`. */
73
+ // depth: z.number().optional(),
74
+ }),
75
+ })
76
+ .strict()
77
+ .superRefine((config, ctx) => {
78
+ if (!('label' in config)) return;
79
+
80
+ // TODO: Remove this error message in a future release once most users have migrated
81
+ ctx.addIssue({
82
+ code: 'custom',
83
+ message:
84
+ `Found an \`autogenerate\` object with a \`label\`. Support for autogenerated sidebar groups was removed in Starlight v0.39.0.\n` +
85
+ `You should instead create a group with the desired \`label\` and an \`items\` array containing the autogenerate config:\n\n` +
86
+ `{\n` +
87
+ ` label: '${config.label}',\n` +
88
+ ` items: [{ autogenerate: ${JSON.stringify(
89
+ config.autogenerate,
90
+ // Hide empty attrs object that is automatically added by the schema default value.
91
+ (key, value: unknown) =>
92
+ key === 'attrs' &&
93
+ typeof value === 'object' &&
94
+ value !== null &&
95
+ Object.keys(value).length === 0
96
+ ? undefined
97
+ : value,
98
+ ' '
99
+ ).replace(/\n\s*/g, ' ')} }]\n` +
100
+ `}`,
101
+ });
102
+ });
103
+ export type AutoSidebarEntries = z.infer<typeof AutoSidebarEntriesSchema>;
72
104
 
73
105
  type ManualSidebarGroupInput = z.input<typeof SidebarGroupSchema> & {
74
106
  /** Array of links and subcategories to display in this category. */
75
107
  items: Array<
76
108
  | z.input<typeof SidebarLinkItemSchema>
77
- | z.input<typeof AutoSidebarGroupSchema>
109
+ | z.input<typeof AutoSidebarEntriesSchema>
78
110
  | z.input<typeof InternalSidebarLinkItemSchema>
79
111
  | z.input<typeof InternalSidebarLinkItemShorthandSchema>
80
112
  | ManualSidebarGroupInput
@@ -85,7 +117,7 @@ type ManualSidebarGroupOutput = z.output<typeof SidebarGroupSchema> & {
85
117
  /** Array of links and subcategories to display in this category. */
86
118
  items: Array<
87
119
  | z.output<typeof SidebarLinkItemSchema>
88
- | z.output<typeof AutoSidebarGroupSchema>
120
+ | z.output<typeof AutoSidebarEntriesSchema>
89
121
  | z.output<typeof InternalSidebarLinkItemSchema>
90
122
  | z.output<typeof InternalSidebarLinkItemShorthandSchema>
91
123
  | ManualSidebarGroupOutput
@@ -101,7 +133,7 @@ const ManualSidebarGroupSchema: z.ZodType<ManualSidebarGroupOutput, ManualSideba
101
133
  .union([
102
134
  SidebarLinkItemSchema,
103
135
  ManualSidebarGroupSchema,
104
- AutoSidebarGroupSchema,
136
+ AutoSidebarEntriesSchema,
105
137
  InternalSidebarLinkItemSchema,
106
138
  InternalSidebarLinkItemShorthandSchema,
107
139
  ])
@@ -124,7 +156,7 @@ export type InternalSidebarLinkItem = z.output<typeof InternalSidebarLinkItemSch
124
156
  export const SidebarItemSchema = z.union([
125
157
  SidebarLinkItemSchema,
126
158
  ManualSidebarGroupSchema,
127
- AutoSidebarGroupSchema,
159
+ AutoSidebarEntriesSchema,
128
160
  InternalSidebarLinkItemSchema,
129
161
  InternalSidebarLinkItemShorthandSchema,
130
162
  ]);
@@ -31,31 +31,31 @@
31
31
  overflow-wrap: anywhere;
32
32
  }
33
33
 
34
+ /*
35
+ * This complex selector manages spacing inside lists.
36
+ *
37
+ * - Finds all lists containing items with non-inline direct children (e.g.
38
+ * ul > li > p)
39
+ * - Applies a bottom margin to the last non-inline child of each list item
40
+ * in this list
41
+ *
42
+ * This ensures that even if only one list item contains a block element
43
+ * (most commonly a paragraph), siblings of that list item are spaced
44
+ * consistently.
45
+ */
34
46
  .sl-markdown-content
35
- li
36
- > :is(
37
- :last-child:not(
38
- li,
39
- ul,
40
- ol,
41
- a,
42
- strong,
43
- em,
44
- del,
45
- span,
46
- input,
47
- code,
48
- br,
49
- script,
50
- :where(.not-content *)
51
- ),
52
- /**
53
- * For list items ending with 1 or multiple script elements (`:has(~ script:last-child)`), we
54
- * need to style the last non-script element (`:not(script)`) that doesn't have a subsequent
55
- * sibling that is not a script (`:not(:has(~ :not(script)))`).
47
+ :is(ol, ul):has(> li > :not(a, strong, em, del, span, input, code, br, script, ol, ul))
48
+ > li
49
+ > :is(
50
+ :last-child:not(a, strong, em, del, span, input, code, br, script, :where(.not-content *)),
51
+ /*
52
+ * For list items ending with 1 or multiple script elements (`:has(~
53
+ * script:last-child)`), we need to style the last non-script
54
+ * element (`:not(script)`) that doesn't have a subsequent sibling
55
+ * that is not a script (`:not(:has(~ :not(script)))`).
56
56
  */
57
- :not(script):has(~ script:last-child):not(:has(~ :not(script)))
58
- ) {
57
+ :not(script):has(~ script:last-child):not(:has(~ :not(script)))
58
+ ) {
59
59
  margin-bottom: 1.25rem;
60
60
  }
61
61
 
package/style/reset.css CHANGED
@@ -28,6 +28,21 @@
28
28
  background-color: var(--sl-color-bg);
29
29
  }
30
30
 
31
+ [lang]:where(:lang(zh, ja)) {
32
+ text-autospace: normal;
33
+ }
34
+
35
+ [lang]:where(:not(:lang(zh, ja))) {
36
+ text-autospace: initial;
37
+ }
38
+
39
+ pre,
40
+ code,
41
+ samp,
42
+ kbd {
43
+ text-autospace: no-autospace;
44
+ }
45
+
31
46
  input,
32
47
  button,
33
48
  textarea,
@@ -72,7 +72,11 @@ export async function createTranslationSystem<T extends i18nSchemaOutput>(
72
72
 
73
73
  const t = i18n.getFixedT(lang, I18nextNamespace) as I18nT;
74
74
  t.all = () => i18n.getResourceBundle(lang, I18nextNamespace) as ReturnType<I18nT['all']>;
75
- t.exists = (key, options) => i18n.exists(key, { lng: lang, ns: I18nextNamespace, ...options });
75
+ // Since i18next 25.10.4 the `ExistsFunction` type has a signature including a predicate that
76
+ // TS cannot preserve when composing a new function to add default options.
77
+ // See: https://github.com/i18next/i18next/issues/2425
78
+ t.exists = ((key, options) =>
79
+ i18n.exists(key, { lng: lang, ns: I18nextNamespace, ...options })) as ExistsFunction;
76
80
  t.dir = (dirLang = lang) => i18n.dir(dirLang);
77
81
 
78
82
  return t;
@@ -107,6 +107,12 @@ const errorMap: z.core.$ZodErrorMap = (issue) => {
107
107
  for (const unionError of issue.errors) {
108
108
  const expectedShape: string[] = [];
109
109
  for (const issue of unionError) {
110
+ // We sometimes use `z.NEVER` to explicitly error on certain property combinations in
111
+ // non-discriminated unions to make it easier for users to identify invalid config, e.g.
112
+ // autogenerated groups in the sidebar no longer being supported. Having these properties
113
+ // show up in the error message with an expected type of `never` is noisy and not helpful
114
+ // so we skip them here.
115
+ if (issue.code === 'invalid_type' && issue.expected === 'never') continue;
110
116
  // If the issue is a nested union error, show the associated error message instead of the
111
117
  // base error message.
112
118
  if (issue.code === 'invalid_union') {
package/utils/head.ts CHANGED
@@ -91,6 +91,14 @@ export function getHead(
91
91
  },
92
92
  });
93
93
  }
94
+ headDefaults.push({
95
+ tag: 'link',
96
+ attrs: {
97
+ rel: 'alternate',
98
+ hreflang: 'x-default',
99
+ href: localizedUrl(canonical, config.defaultLocale.locale, project.trailingSlash).href,
100
+ },
101
+ });
94
102
  }
95
103
 
96
104
  // Link to sitemap, but only when `site` is set.
@@ -4,7 +4,7 @@ import config from 'virtual:starlight/user-config';
4
4
  import type { Badge, I18nBadge, I18nBadgeConfig } from '../schemas/badge';
5
5
  import type { PrevNextLinkConfig } from '../schemas/prevNextLink';
6
6
  import type {
7
- AutoSidebarGroup,
7
+ AutoSidebarEntries,
8
8
  InternalSidebarLinkItem,
9
9
  LinkHTMLAttributes,
10
10
  SidebarItem,
@@ -24,9 +24,13 @@ import { getLocaleRoutes, routes } from './routing';
24
24
  import type {
25
25
  SidebarGroup,
26
26
  SidebarLink,
27
+ SidebarManualLink,
27
28
  PaginationLinks,
28
29
  Route,
29
30
  SidebarEntry,
31
+ SidebarAutoLink,
32
+ SidebarAutoGroup,
33
+ SidebarAutogenerateRouteData,
30
34
  } from './routing/types';
31
35
  import { localeToLang, localizedFilePath, slugToPathname } from './slugs';
32
36
  import { isAbsoluteUrl } from './url';
@@ -35,6 +39,8 @@ import type { StarlightConfig } from './user-config';
35
39
  const DirKey = Symbol('DirKey');
36
40
  const SlugKey = Symbol('SlugKey');
37
41
 
42
+ const rootAutogenerate: SidebarAutogenerateRouteData = { directory: '' };
43
+
38
44
  const neverPathFormatter = createPathFormatter({ trailingSlash: 'never' });
39
45
 
40
46
  const docsCollectionPathFromRoot = getCollectionPathFromRoot('docs', project);
@@ -68,14 +74,13 @@ function isDir(data: Record<string, unknown>): data is Dir {
68
74
  /** Convert an item in a user’s sidebar config to a sidebar entry. */
69
75
  function configItemToEntry(
70
76
  item: SidebarItem,
71
- currentPathname: string,
72
77
  locale: string | undefined,
73
78
  routes: Route[]
74
- ): SidebarEntry {
79
+ ): SidebarEntry | SidebarEntry[] {
75
80
  if ('link' in item) {
76
81
  return linkFromSidebarLinkItem(item, locale);
77
82
  } else if ('autogenerate' in item) {
78
- return groupFromAutogenerateConfig(item, locale, routes, currentPathname);
83
+ return entriesFromAutogenerateConfig(item, locale, routes);
79
84
  } else if ('slug' in item) {
80
85
  return linkFromInternalSidebarLinkItem(item, locale);
81
86
  } else {
@@ -83,22 +88,22 @@ function configItemToEntry(
83
88
  return {
84
89
  type: 'group',
85
90
  label,
86
- entries: item.items.map((i) => configItemToEntry(i, currentPathname, locale, routes)),
91
+ entries: item.items.flatMap((i) => configItemToEntry(i, locale, routes)),
87
92
  collapsed: item.collapsed,
88
93
  badge: getSidebarBadge(item.badge, locale, label),
89
94
  };
90
95
  }
91
96
  }
92
97
 
93
- /** Autogenerate a group of links from a user’s sidebar config. */
94
- function groupFromAutogenerateConfig(
95
- item: AutoSidebarGroup,
98
+ /** Autogenerate links and groups from a user’s sidebar config. */
99
+ function entriesFromAutogenerateConfig(
100
+ item: AutoSidebarEntries,
96
101
  locale: string | undefined,
97
- routes: Route[],
98
- currentPathname: string
99
- ): SidebarGroup {
100
- const { attrs, collapsed: subgroupCollapsed, directory } = item.autogenerate;
102
+ routes: Route[]
103
+ ): (SidebarAutoLink | SidebarGroup)[] {
104
+ const { attrs, collapsed, directory } = item.autogenerate;
101
105
  const localeDir = locale ? locale + '/' + directory : directory;
106
+ const autogenerate = { directory };
102
107
  const dirDocs = routes.filter((doc) => {
103
108
  const filePathFromContentDir = getRoutePathRelativeToCollectionRoot(doc, locale);
104
109
  return (
@@ -109,20 +114,7 @@ function groupFromAutogenerateConfig(
109
114
  );
110
115
  });
111
116
  const tree = treeify(dirDocs, locale, localeDir);
112
- const label = pickLang(item.translations, localeToLang(locale)) || item.label;
113
- return {
114
- type: 'group',
115
- label,
116
- entries: sidebarFromDir(
117
- tree,
118
- currentPathname,
119
- locale,
120
- subgroupCollapsed ?? item.collapsed,
121
- attrs
122
- ),
123
- collapsed: item.collapsed,
124
- badge: getSidebarBadge(item.badge, locale, label),
125
- };
117
+ return sidebarFromDir(tree, { collapsed: collapsed ?? false, attrs }, autogenerate);
126
118
  }
127
119
 
128
120
  /** Create a link entry from a manual link item in user config. */
@@ -134,7 +126,12 @@ function linkFromSidebarLinkItem(item: SidebarLinkItem, locale: string | undefin
134
126
  if (locale) href = '/' + locale + href;
135
127
  }
136
128
  const label = pickLang(item.translations, localeToLang(locale)) || item.label;
137
- return makeSidebarLink(href, label, getSidebarBadge(item.badge, locale, label), item.attrs);
129
+ return makeSidebarLink({
130
+ href,
131
+ label,
132
+ badge: getSidebarBadge(item.badge, locale, label),
133
+ attrs: item.attrs,
134
+ });
138
135
  }
139
136
 
140
137
  /** Create a link entry from an automatic internal link item in user config. */
@@ -169,39 +166,44 @@ function linkFromInternalSidebarLinkItem(
169
166
  frontmatter.title;
170
167
  const badge = item.badge ?? frontmatter.sidebar?.badge;
171
168
  const attrs = { ...frontmatter.sidebar?.attrs, ...item.attrs };
172
- return makeSidebarLink(
173
- slugToPathname(route.id),
169
+ return makeSidebarLink({
170
+ href: slugToPathname(route.id),
174
171
  label,
175
- getSidebarBadge(badge, locale, label),
176
- attrs
177
- );
172
+ badge: getSidebarBadge(badge, locale, label),
173
+ attrs,
174
+ });
175
+ }
176
+
177
+ interface MakeLinkOptions {
178
+ autogenerate?: SidebarAutogenerateRouteData | undefined;
179
+ href: string;
180
+ label: string;
181
+ badge?: Badge | undefined;
182
+ attrs?: LinkHTMLAttributes | undefined;
178
183
  }
179
184
 
180
185
  /** Process sidebar link options to create a link entry. */
186
+ function makeSidebarLink(opts: MakeLinkOptions & { autogenerate?: undefined }): SidebarManualLink;
181
187
  function makeSidebarLink(
182
- href: string,
183
- label: string,
184
- badge?: Badge,
185
- attrs?: LinkHTMLAttributes
186
- ): SidebarLink {
188
+ opts: MakeLinkOptions & { autogenerate: SidebarAutogenerateRouteData }
189
+ ): SidebarAutoLink;
190
+ function makeSidebarLink({ attrs, badge, href, label, autogenerate }: MakeLinkOptions) {
187
191
  if (!isAbsoluteUrl(href)) {
188
192
  href = formatPath(href);
189
193
  }
190
- return makeLink({ label, href, badge, attrs });
194
+ return makeLink({ label, href, badge, attrs, autogenerate });
191
195
  }
192
196
 
193
197
  /** Create a link entry */
194
- function makeLink({
195
- attrs = {},
196
- badge = undefined,
197
- ...opts
198
- }: {
199
- label: string;
200
- href: string;
201
- badge?: Badge | undefined;
202
- attrs?: LinkHTMLAttributes | undefined;
203
- }): SidebarLink {
204
- return { type: 'link', ...opts, badge, isCurrent: false, attrs };
198
+ function makeLink({ attrs = {}, badge, autogenerate, ...opts }: MakeLinkOptions): SidebarLink {
199
+ return {
200
+ type: 'link',
201
+ ...opts,
202
+ badge,
203
+ isCurrent: false,
204
+ attrs,
205
+ ...(autogenerate ? { autogenerate } : {}),
206
+ };
205
207
  }
206
208
 
207
209
  /** Test if two paths are equivalent even if formatted differently. */
@@ -273,13 +275,18 @@ function treeify(routes: Route[], locale: string | undefined, baseDir: string):
273
275
  }
274
276
 
275
277
  /** Create a link entry for a given content collection entry. */
276
- function linkFromRoute(route: Route, attrs?: LinkHTMLAttributes): SidebarLink {
277
- return makeSidebarLink(
278
- slugToPathname(route.id),
279
- route.entry.data.sidebar.label || route.entry.data.title,
280
- route.entry.data.sidebar.badge,
281
- { ...attrs, ...route.entry.data.sidebar.attrs }
282
- );
278
+ function linkFromRoute(
279
+ route: Route,
280
+ attrs: LinkHTMLAttributes | undefined,
281
+ autogenerate: SidebarAutogenerateRouteData
282
+ ): SidebarAutoLink {
283
+ return makeSidebarLink({
284
+ href: slugToPathname(route.id),
285
+ label: route.entry.data.sidebar.label || route.entry.data.title,
286
+ badge: route.entry.data.sidebar.badge,
287
+ attrs: { ...attrs, ...route.entry.data.sidebar.attrs },
288
+ autogenerate,
289
+ });
283
290
  }
284
291
 
285
292
  /**
@@ -305,18 +312,22 @@ function sortDirEntries(dir: [string, Dir | Route][]): [string, Dir | Route][] {
305
312
  });
306
313
  }
307
314
 
315
+ interface SidebarDirOptions {
316
+ collapsed: boolean;
317
+ attrs: LinkHTMLAttributes | undefined;
318
+ }
319
+
320
+ interface SidebarDirContext extends SidebarDirOptions {
321
+ fullPath: string;
322
+ dirName: string;
323
+ autogenerate: SidebarAutogenerateRouteData;
324
+ }
325
+
308
326
  /** Create a group entry for a given content collection directory. */
309
- function groupFromDir(
310
- dir: Dir,
311
- fullPath: string,
312
- dirName: string,
313
- currentPathname: string,
314
- locale: string | undefined,
315
- collapsed: boolean,
316
- attrs?: LinkHTMLAttributes
317
- ): SidebarGroup {
327
+ function groupFromDir(dir: Dir, context: SidebarDirContext): SidebarAutoGroup {
328
+ const { fullPath, dirName, collapsed, autogenerate } = context;
318
329
  const entries = sortDirEntries(Object.entries(dir)).map(([key, dirOrRoute]) =>
319
- dirToItem(dirOrRoute, `${fullPath}/${key}`, key, currentPathname, locale, collapsed, attrs)
330
+ dirToItem(dirOrRoute, { ...context, fullPath: `${fullPath}/${key}`, dirName: key })
320
331
  );
321
332
  return {
322
333
  type: 'group',
@@ -324,34 +335,29 @@ function groupFromDir(
324
335
  entries,
325
336
  collapsed,
326
337
  badge: undefined,
338
+ autogenerate,
327
339
  };
328
340
  }
329
341
 
330
342
  /** Create a sidebar entry for a directory or content entry. */
331
343
  function dirToItem(
332
344
  dirOrRoute: Dir[string],
333
- fullPath: string,
334
- dirName: string,
335
- currentPathname: string,
336
- locale: string | undefined,
337
- collapsed: boolean,
338
- attrs?: LinkHTMLAttributes
339
- ): SidebarEntry {
345
+ context: SidebarDirContext
346
+ ): SidebarAutoGroup | SidebarAutoLink {
347
+ const { attrs, autogenerate } = context;
340
348
  return isDir(dirOrRoute)
341
- ? groupFromDir(dirOrRoute, fullPath, dirName, currentPathname, locale, collapsed, attrs)
342
- : linkFromRoute(dirOrRoute, attrs);
349
+ ? groupFromDir(dirOrRoute, context)
350
+ : linkFromRoute(dirOrRoute, attrs, autogenerate);
343
351
  }
344
352
 
345
353
  /** Create a sidebar entry for a given content directory. */
346
354
  function sidebarFromDir(
347
355
  tree: Dir,
348
- currentPathname: string,
349
- locale: string | undefined,
350
- collapsed: boolean,
351
- attrs?: LinkHTMLAttributes
356
+ options: SidebarDirOptions,
357
+ autogenerate: SidebarAutogenerateRouteData = rootAutogenerate
352
358
  ) {
353
359
  return sortDirEntries(Object.entries(tree)).map(([key, dirOrRoute]) =>
354
- dirToItem(dirOrRoute, key, key, currentPathname, locale, collapsed, attrs)
360
+ dirToItem(dirOrRoute, { ...options, fullPath: key, dirName: key, autogenerate })
355
361
  );
356
362
  }
357
363
 
@@ -374,7 +380,7 @@ const lastCurrentEntryByLocale = new Map<string | undefined, SidebarLink>();
374
380
  export function getSidebar(pathname: string, locale: string | undefined): SidebarEntry[] {
375
381
  let intermediateSidebar = intermediateSidebars.get(locale);
376
382
  if (!intermediateSidebar) {
377
- intermediateSidebar = getIntermediateSidebarFromConfig(config.sidebar, pathname, locale);
383
+ intermediateSidebar = getIntermediateSidebarFromConfig(config.sidebar, locale);
378
384
  intermediateSidebars.set(locale, intermediateSidebar);
379
385
  }
380
386
  setIntermediateSidebarCurrentEntry(intermediateSidebar, pathname, locale);
@@ -387,24 +393,23 @@ export function getSidebarFromConfig(
387
393
  pathname: string,
388
394
  locale: string | undefined
389
395
  ): SidebarEntry[] {
390
- const sidebar = getIntermediateSidebarFromConfig(sidebarConfig, pathname, locale);
396
+ const sidebar = getIntermediateSidebarFromConfig(sidebarConfig, locale);
391
397
  const currentEntry = getSidebarCurrentEntry(sidebar, pathname);
392
398
  if (currentEntry) currentEntry.isCurrent = true;
393
399
  return sidebar;
394
400
  }
395
401
 
396
- /** Get the intermediate sidebar for the current page using the specified sidebar config. */
402
+ /** Get the intermediate sidebar for a locale using the specified sidebar config. */
397
403
  function getIntermediateSidebarFromConfig(
398
404
  sidebarConfig: StarlightConfig['sidebar'],
399
- pathname: string,
400
405
  locale: string | undefined
401
406
  ): SidebarEntry[] {
402
407
  const routes = getLocaleRoutes(locale);
403
408
  if (sidebarConfig) {
404
- return sidebarConfig.map((group) => configItemToEntry(group, pathname, locale, routes));
409
+ return sidebarConfig.flatMap((group) => configItemToEntry(group, locale, routes));
405
410
  } else {
406
411
  const tree = treeify(routes, locale, locale || '');
407
- return sidebarFromDir(tree, pathname, locale, false);
412
+ return sidebarFromDir(tree, { collapsed: false, attrs: undefined });
408
413
  }
409
414
  }
410
415
 
@@ -14,7 +14,11 @@ export interface LocaleData {
14
14
  locale: string | undefined;
15
15
  }
16
16
 
17
- export interface SidebarLink {
17
+ export interface SidebarAutogenerateRouteData {
18
+ directory: string;
19
+ }
20
+
21
+ export interface SidebarManualLink {
18
22
  type: 'link';
19
23
  label: string;
20
24
  href: string;
@@ -23,7 +27,11 @@ export interface SidebarLink {
23
27
  attrs: LinkHTMLAttributes;
24
28
  }
25
29
 
26
- export interface SidebarGroup {
30
+ export interface SidebarAutoLink extends SidebarManualLink {
31
+ autogenerate: SidebarAutogenerateRouteData;
32
+ }
33
+
34
+ export interface SidebarManualGroup {
27
35
  type: 'group';
28
36
  label: string;
29
37
  entries: (SidebarLink | SidebarGroup)[];
@@ -31,6 +39,12 @@ export interface SidebarGroup {
31
39
  badge: Badge | undefined;
32
40
  }
33
41
 
42
+ export interface SidebarAutoGroup extends SidebarManualGroup {
43
+ autogenerate: SidebarAutogenerateRouteData;
44
+ }
45
+
46
+ export type SidebarLink = SidebarManualLink | SidebarAutoLink;
47
+ export type SidebarGroup = SidebarManualGroup | SidebarAutoGroup;
34
48
  export type SidebarEntry = SidebarLink | SidebarGroup;
35
49
 
36
50
  export interface PaginationLinks {