@astrojs/starlight 0.1.3 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/404.astro CHANGED
@@ -36,7 +36,7 @@ const { lang = 'en', dir = 'ltr', locale } = config.defaultLocale || {};
36
36
  <Header slot="header" {locale} />
37
37
  <main>
38
38
  <MarkdownContent>
39
- <h1 id="starlight__overview">404</h1>
39
+ <h1 id="_top" data-page-title>404</h1>
40
40
  <p>Houston, we have a problem.</p>
41
41
  <p>
42
42
  We couldn’t find that link. Check the address or
package/CHANGELOG.md CHANGED
@@ -1,5 +1,33 @@
1
1
  # @astrojs/starlight
2
2
 
3
+ ## 0.2.0
4
+
5
+ ### Minor Changes
6
+
7
+ - [#171](https://github.com/withastro/starlight/pull/171) [`198c3f0`](https://github.com/withastro/starlight/commit/198c3f001410f259dab7d085136a37afe863cfa4) Thanks [@delucis](https://github.com/delucis)! - Add Starlight generator tag to HTML output
8
+
9
+ - [#217](https://github.com/withastro/starlight/pull/217) [`490fd98`](https://github.com/withastro/starlight/commit/490fd98d4e7b38ec01c568eee0ab00844e59c53d) Thanks [@delucis](https://github.com/delucis)! - Updated sidebar styles. Sidebars now support top-level links and groups are styled with a subtle border and indentation to improve comprehension of nesting.
10
+
11
+ - [#178](https://github.com/withastro/starlight/pull/178) [`d046c55`](https://github.com/withastro/starlight/commit/d046c55a62290c15f2e09faf4359f02df9492f6d) Thanks [@delucis](https://github.com/delucis)! - Add support for translating the Pagefind search modal
12
+
13
+ - [#210](https://github.com/withastro/starlight/pull/210) [`cb5b121`](https://github.com/withastro/starlight/commit/cb5b1210e23548e2983865a4b38308b0f54dc7ce) Thanks [@delucis](https://github.com/delucis)! - Change page title ID to `_top` for cleaner hash URLs
14
+
15
+ ⚠️ Potentially breaking change if you were linking manually to `#starlight__overview` anywhere. If you were, update these links to use `#_top` instead.
16
+
17
+ ### Patch Changes
18
+
19
+ - [#208](https://github.com/withastro/starlight/pull/208) [`09fc565`](https://github.com/withastro/starlight/commit/09fc565d44bd3abb4508541b458531de8624036f) Thanks [@delucis](https://github.com/delucis)! - Update `@astrojs/mdx` and `@astrojs/sitemap` to latest
20
+
21
+ - [#216](https://github.com/withastro/starlight/pull/216) [`54905c5`](https://github.com/withastro/starlight/commit/54905c502c5e6de5516e36ddcd4969893572baa5) Thanks [@morinokami](https://github.com/morinokami)! - Encode heading id when finding current link
22
+
23
+ ## 0.1.4
24
+
25
+ ### Patch Changes
26
+
27
+ - [#190](https://github.com/withastro/starlight/pull/190) [`a3809e4`](https://github.com/withastro/starlight/commit/a3809e4f1e14f3949e9e25f7ffbdea2920408edb) Thanks [@gabrielemercolino](https://github.com/gabrielemercolino)! - Added Italian language support
28
+
29
+ - [#193](https://github.com/withastro/starlight/pull/193) [`c9ca4eb`](https://github.com/withastro/starlight/commit/c9ca4ebe10f4776999e3fff4ac4c19ac0a714bac) Thanks [@BryceRussell](https://github.com/BryceRussell)! - Fix bottom padding for sidebar on larger screen sizes
30
+
3
31
  ## 0.1.3
4
32
 
5
33
  ### Patch Changes
@@ -5,6 +5,7 @@ import type { HeadConfigSchema } from '../schemas/head';
5
5
  import { createHead } from '../utils/head';
6
6
  import { localizedUrl } from '../utils/localizedUrl';
7
7
  import { fileWithBase } from '../utils/base';
8
+ import { version } from '../package.json';
8
9
 
9
10
  interface Props {
10
11
  data: CollectionEntry<'docs'>['data'];
@@ -28,6 +29,10 @@ const headDefaults: z.input<ReturnType<typeof HeadConfigSchema>> = [
28
29
  { tag: 'title', content: title },
29
30
  { tag: 'link', attrs: { rel: 'canonical', href: canonical?.href } },
30
31
  { tag: 'meta', attrs: { name: 'generator', content: Astro.generator } },
32
+ {
33
+ tag: 'meta',
34
+ attrs: { name: 'generator', content: `Starlight v${version}` },
35
+ },
31
36
  // Favicon
32
37
  {
33
38
  tag: 'link',
@@ -38,7 +38,7 @@ const imageAttrs = {
38
38
  }
39
39
  <div class="flex stack">
40
40
  <div class="flex copy">
41
- <h1 id="starlight__overview" set:html={title} />
41
+ <h1 id="_top" data-page-title set:html={title} />
42
42
  {tagline && <div class="tagline" set:html={tagline} />}
43
43
  </div>
44
44
  {
@@ -8,9 +8,18 @@ interface Props {
8
8
  }
9
9
 
10
10
  const t = useTranslations(Astro.props.locale);
11
+ const pagefindTranslations = {
12
+ placeholder: t('search.label'),
13
+ ...Object.fromEntries(
14
+ Object.entries(t.pick('pagefind.')).map(([key, value]) => [
15
+ key.replace('pagefind.', ''),
16
+ value,
17
+ ])
18
+ ),
19
+ };
11
20
  ---
12
21
 
13
- <site-search>
22
+ <site-search data-translations={JSON.stringify(pagefindTranslations)}>
14
23
  <button data-open-modal disabled>
15
24
  {
16
25
  /* The span is `aria-hidden` because it is not shown on small screens. Instead, the icon label is used for accessibility purposes. */
@@ -96,23 +105,31 @@ const t = useTranslations(Astro.props.locale);
96
105
  e.preventDefault();
97
106
  }
98
107
  });
108
+
109
+ let translations = {};
110
+ try {
111
+ translations = JSON.parse(this.dataset.translations || '{}');
112
+ } catch {}
113
+
114
+ window.addEventListener('DOMContentLoaded', () => {
115
+ if (import.meta.env.DEV) return;
116
+ const onIdle =
117
+ window.requestIdleCallback || ((cb) => setTimeout(cb, 1));
118
+ onIdle(async () => {
119
+ const { PagefindUI } = await import('@pagefind/default-ui');
120
+ new PagefindUI({
121
+ element: '#starlight__search',
122
+ baseUrl: import.meta.env.BASE_URL,
123
+ bundlePath:
124
+ import.meta.env.BASE_URL.replace(/\/$/, '') + '/_pagefind/',
125
+ showImages: false,
126
+ translations,
127
+ });
128
+ });
129
+ });
99
130
  }
100
131
  }
101
132
  customElements.define('site-search', SiteSearch);
102
-
103
- window.addEventListener('DOMContentLoaded', () => {
104
- if (import.meta.env.DEV) return;
105
- const onIdle = window.requestIdleCallback || ((cb) => setTimeout(cb, 1));
106
- onIdle(async () => {
107
- const { PagefindUI } = await import('@pagefind/default-ui');
108
- new PagefindUI({
109
- element: '#starlight__search',
110
- baseUrl: import.meta.env.BASE_URL,
111
- bundlePath: import.meta.env.BASE_URL.replace(/\/$/, '') + '/_pagefind/',
112
- showImages: false,
113
- });
114
- });
115
- });
116
133
  </script>
117
134
 
118
135
  <style>
@@ -28,13 +28,15 @@ const { sidebar, locale } = Astro.props;
28
28
  gap: 1rem;
29
29
  }
30
30
 
31
- .sidebar > :global(:last-child) {
32
- padding-bottom: 1rem;
33
- }
34
-
35
31
  .mobile-preferences {
36
32
  justify-content: space-between;
37
33
  border-top: 1px solid var(--sl-color-gray-6);
38
34
  padding: 0.5rem 0;
39
35
  }
36
+
37
+ @media (min-width: 50rem) {
38
+ .sidebar > :global(:nth-last-child(2)) {
39
+ padding-bottom: 1rem;
40
+ }
41
+ }
40
42
  </style>
@@ -4,24 +4,29 @@ import Icon from './Icon.astro';
4
4
 
5
5
  interface Props {
6
6
  sublist: SidebarEntry[];
7
+ nested?: boolean;
7
8
  }
8
9
  ---
9
10
 
10
- <ul>
11
+ <ul class:list={{ 'top-level': !Astro.props.nested }}>
11
12
  {
12
13
  Astro.props.sublist.map((entry) => (
13
- <li class:list={{ 'sidebar-group': entry.type === 'group' }}>
14
+ <li>
14
15
  {entry.type === 'link' ? (
15
- <a href={entry.href} aria-current={entry.isCurrent && 'page'}>
16
+ <a
17
+ href={entry.href}
18
+ aria-current={entry.isCurrent && 'page'}
19
+ class:list={{ large: !Astro.props.nested }}
20
+ >
16
21
  {entry.label}
17
22
  </a>
18
23
  ) : (
19
24
  <details open>
20
25
  <summary>
21
- <h2>{entry.label}</h2>
26
+ <h2 class="large">{entry.label}</h2>
22
27
  <Icon name="right-caret" class="caret" size="1.25rem" />
23
28
  </summary>
24
- <Astro.self sublist={entry.entries} />
29
+ <Astro.self sublist={entry.entries} nested />
25
30
  </details>
26
31
  )}
27
32
  </li>
@@ -36,13 +41,19 @@ interface Props {
36
41
  padding: 0;
37
42
  }
38
43
 
39
- h2 {
44
+ ul ul li {
45
+ margin-inline-start: var(--sl-sidebar-item-padding-inline);
46
+ border-inline-start: 1px solid var(--sl-color-hairline-light);
47
+ padding-inline-start: var(--sl-sidebar-item-padding-inline);
48
+ }
49
+
50
+ .large {
40
51
  font-size: var(--sl-text-lg);
41
52
  font-weight: 600;
42
53
  color: var(--sl-color-white);
43
54
  }
44
55
 
45
- .sidebar-group + .sidebar-group {
56
+ .top-level > li + li {
46
57
  margin-top: 0.75rem;
47
58
  }
48
59
 
@@ -91,10 +102,10 @@ interface Props {
91
102
  }
92
103
 
93
104
  @media (min-width: 50rem) {
94
- .sidebar-group + .sidebar-group {
105
+ .top-level > li + li {
95
106
  margin-top: 0.5rem;
96
107
  }
97
- h2 {
108
+ .large {
98
109
  font-size: var(--sl-text-base);
99
110
  }
100
111
  a {
@@ -8,7 +8,7 @@ interface Props {
8
8
  const t = useTranslations(Astro.props.locale);
9
9
  ---
10
10
 
11
- <a href="#starlight__overview">{t('skipLink.label')}</a>
11
+ <a href="#_top">{t('skipLink.label')}</a>
12
12
 
13
13
  <style>
14
14
  a {
@@ -25,7 +25,7 @@ export function generateToC(
25
25
  headings: MarkdownHeading[],
26
26
  { minHeadingLevel, maxHeadingLevel, title = 'Overview' }: TocOpts
27
27
  ) {
28
- const overview = { depth: 2, slug: 'starlight__overview', text: title };
28
+ const overview = { depth: 2, slug: '_top', text: title };
29
29
  headings = [
30
30
  overview,
31
31
  ...headings.filter(
@@ -22,7 +22,7 @@ export class StarlightTOC extends HTMLElement {
22
22
  const isHeading = (el: Element): el is HTMLHeadingElement => {
23
23
  if (el instanceof HTMLHeadingElement) {
24
24
  // Special case for page title h1
25
- if (el.id === 'starlight__overview') return true;
25
+ if ('pageTitle' in el.dataset) return true;
26
26
  // Check the heading level is within the user-configured limits for the ToC
27
27
  const level = el.tagName[1];
28
28
  if (level) {
@@ -60,7 +60,7 @@ export class StarlightTOC extends HTMLElement {
60
60
  if (!isIntersecting) continue;
61
61
  const heading = getElementHeading(target);
62
62
  if (!heading) continue;
63
- const link = links.find((link) => link.hash === '#' + heading.id);
63
+ const link = links.find((link) => link.hash === '#' + encodeURIComponent(heading.id));
64
64
  if (link) {
65
65
  this.current = link;
66
66
  break;
package/index.astro CHANGED
@@ -102,7 +102,8 @@ const hasHero = Boolean(entry.data.hero);
102
102
  ) : (
103
103
  <ContentPanel>
104
104
  <h1
105
- id="starlight__overview"
105
+ id="_top"
106
+ data-page-title
106
107
  style="font-size: var(--sl-text-h1); line-height: var(--sl-line-height-headings); font-weight: 600; color: var(--sl-color-white); margin-top: 1rem;"
107
108
  >
108
109
  {entry.data.title}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@astrojs/starlight",
3
- "version": "0.1.3",
3
+ "version": "0.2.0",
4
4
  "description": "Build beautiful, high-performance documentation websites with Astro",
5
5
  "keywords": [
6
6
  "docs",
@@ -34,8 +34,8 @@
34
34
  "astro": "^2.5.0"
35
35
  },
36
36
  "dependencies": {
37
- "@astrojs/mdx": "^0.19.1",
38
- "@astrojs/sitemap": "^1.3.1",
37
+ "@astrojs/mdx": "^0.19.7",
38
+ "@astrojs/sitemap": "^1.3.3",
39
39
  "@pagefind/default-ui": "^1.0.0-alpha.5",
40
40
  "@types/mdast": "^3.0.11",
41
41
  "bcp-47": "^2.1.0",
@@ -47,7 +47,7 @@
47
47
  "unified": "^10.1.2",
48
48
  "unist-util-remove": "^3.1.1",
49
49
  "unist-util-visit": "^4.1.2",
50
- "vfile": "^5.3.7"
50
+ "vfile": "^6.0.0"
51
51
  },
52
52
  "scripts": {}
53
53
  }
package/schemas/i18n.ts CHANGED
@@ -1,6 +1,14 @@
1
1
  import { z } from 'astro/zod';
2
2
 
3
3
  export function i18nSchema() {
4
+ return starlightI18nSchema().merge(pagefindI18nSchema());
5
+ }
6
+
7
+ export function builtinI18nSchema() {
8
+ return starlightI18nSchema().required().strict().merge(pagefindI18nSchema());
9
+ }
10
+
11
+ function starlightI18nSchema() {
4
12
  return z
5
13
  .object({
6
14
  'skipLink.label': z
@@ -89,3 +97,69 @@ export function i18nSchema() {
89
97
  })
90
98
  .partial();
91
99
  }
100
+
101
+ function pagefindI18nSchema() {
102
+ return z
103
+ .object({
104
+ 'pagefind.clear_search': z
105
+ .string()
106
+ .describe(
107
+ 'Pagefind UI translation. English default value: `"Clear"`. See https://pagefind.app/docs/ui/#translations'
108
+ ),
109
+
110
+ 'pagefind.load_more': z
111
+ .string()
112
+ .describe(
113
+ 'Pagefind UI translation. English default value: `"Load more results"`. See https://pagefind.app/docs/ui/#translations'
114
+ ),
115
+
116
+ 'pagefind.search_label': z
117
+ .string()
118
+ .describe(
119
+ 'Pagefind UI translation. English default value: `"Search this site"`. See https://pagefind.app/docs/ui/#translations'
120
+ ),
121
+
122
+ 'pagefind.filters_label': z
123
+ .string()
124
+ .describe(
125
+ 'Pagefind UI translation. English default value: `"Filters"`. See https://pagefind.app/docs/ui/#translations'
126
+ ),
127
+
128
+ 'pagefind.zero_results': z
129
+ .string()
130
+ .describe(
131
+ 'Pagefind UI translation. English default value: `"No results for [SEARCH_TERM]"`. See https://pagefind.app/docs/ui/#translations'
132
+ ),
133
+
134
+ 'pagefind.many_results': z
135
+ .string()
136
+ .describe(
137
+ 'Pagefind UI translation. English default value: `"[COUNT] results for [SEARCH_TERM]"`. See https://pagefind.app/docs/ui/#translations'
138
+ ),
139
+
140
+ 'pagefind.one_result': z
141
+ .string()
142
+ .describe(
143
+ 'Pagefind UI translation. English default value: `"[COUNT] result for [SEARCH_TERM]"`. See https://pagefind.app/docs/ui/#translations'
144
+ ),
145
+
146
+ 'pagefind.alt_search': z
147
+ .string()
148
+ .describe(
149
+ 'Pagefind UI translation. English default value: `"No results for [SEARCH_TERM]. Showing results for [DIFFERENT_TERM] instead"`. See https://pagefind.app/docs/ui/#translations'
150
+ ),
151
+
152
+ 'pagefind.search_suggestion': z
153
+ .string()
154
+ .describe(
155
+ 'Pagefind UI translation. English default value: `"No results for [SEARCH_TERM]. Try one of the following searches:"`. See https://pagefind.app/docs/ui/#translations'
156
+ ),
157
+
158
+ 'pagefind.searching': z
159
+ .string()
160
+ .describe(
161
+ 'Pagefind UI translation. English default value: `"Searching for [SEARCH_TERM]..."`. See https://pagefind.app/docs/ui/#translations'
162
+ ),
163
+ })
164
+ .partial();
165
+ }
package/style/props.css CHANGED
@@ -43,6 +43,7 @@
43
43
  --sl-color-bg-nav: var(--sl-color-gray-6);
44
44
  --sl-color-bg-sidebar: var(--sl-color-gray-6);
45
45
  --sl-color-bg-inline-code: var(--sl-color-gray-5);
46
+ --sl-color-hairline-light: var(--sl-color-gray-5);
46
47
  --sl-color-hairline: var(--sl-color-gray-6);
47
48
  --sl-color-hairline-shade: var(--sl-color-black);
48
49
 
@@ -150,6 +151,7 @@
150
151
  --sl-color-bg-nav: var(--sl-color-gray-7);
151
152
  --sl-color-bg-sidebar: var(--sl-color-bg);
152
153
  --sl-color-bg-inline-code: var(--sl-color-gray-6);
154
+ --sl-color-hairline-light: var(--sl-color-gray-6);
153
155
  --sl-color-hairline-shade: var(--sl-color-gray-6);
154
156
 
155
157
  --sl-color-backdrop-overlay: hsla(225, 9%, 36%, 0.66);
@@ -0,0 +1,14 @@
1
+ # Starlight UI translation files
2
+
3
+ This directory contains translation data for Starlight’s UI.
4
+ Each language has its own JSON file and follows the [translation structure described in Starlight’s docs](https://starlight.astro.build/guides/i18n/#translate-starlights-ui).
5
+
6
+ ## Add a new language
7
+
8
+ 1. Create a JSON file named using the BCP-47 tag for the language, e.g. `en.json` or `ja.json`.
9
+
10
+ 2. Fill the file with translations for each UI string. You can base your translations on [`en.json`](./en.json). Translate only the values, leaving the keys in English (e.g. `"search.label": "Buscar"`).
11
+
12
+ 3. Import your file in [`index.ts`](./index.ts) and add your language to the `Object.entries`.
13
+
14
+ 4. Open a pull request on GitHub to add your file to Starlight!
@@ -1,13 +1,14 @@
1
- import { i18nSchema } from '../schemas/i18n';
1
+ import { builtinI18nSchema } from '../schemas/i18n';
2
2
  import en from './en.json';
3
3
  import es from './es.json';
4
4
  import de from './de.json';
5
5
  import ja from './ja.json';
6
6
  import pt from './pt.json';
7
7
  import fr from './fr.json';
8
+ import it from './it.json';
8
9
 
9
- const parse = i18nSchema().required().strict().parse;
10
+ const { parse } = builtinI18nSchema();
10
11
 
11
12
  export default Object.fromEntries(
12
- Object.entries({ en, es, de, ja, pt, fr }).map(([key, dict]) => [key, parse(dict)])
13
+ Object.entries({ en, es, de, ja, pt, fr, it }).map(([key, dict]) => [key, parse(dict)])
13
14
  );
@@ -0,0 +1,20 @@
1
+ {
2
+ "skipLink.label": "Salta ai contenuti",
3
+ "search.label": "Cerca",
4
+ "search.shortcutLabel": "(Usa / per cercare)",
5
+ "search.cancelLabel": "Cancella",
6
+ "themeSelect.accessibleLabel": "Seleziona tema",
7
+ "themeSelect.dark": "Scuro",
8
+ "themeSelect.light": "Chiaro",
9
+ "themeSelect.auto": "Auto",
10
+ "languageSelect.accessibleLabel": "Seleziona lingua",
11
+ "menuButton.accessibleLabel": "Menu",
12
+ "sidebarNav.accessibleLabel": "Principale",
13
+ "tableOfContents.onThisPage": "In questa pagina",
14
+ "tableOfContents.overview": "Panoramica",
15
+ "i18n.untranslatedContent": "Questi contenuti non sono ancora disponibili nella tua lingua.",
16
+ "page.editLink": "Modifica pagina",
17
+ "page.lastUpdated": "Ultimo aggiornamento:",
18
+ "page.previousLink": "Indietro",
19
+ "page.nextLink": "Avanti"
20
+ }
@@ -38,7 +38,12 @@ export function useTranslations(locale: string | undefined) {
38
38
  builtinTranslations[lang],
39
39
  userTranslations[lang]
40
40
  );
41
- return (key: keyof typeof dictionary) => dictionary[key];
41
+ const t = <K extends keyof typeof dictionary>(key: K) => dictionary[key];
42
+ t.pick = (startOfKey: string) =>
43
+ Object.fromEntries(
44
+ Object.entries(dictionary).filter(([k]) => k.startsWith(startOfKey))
45
+ );
46
+ return t;
42
47
  }
43
48
 
44
49
  /** Build a dictionary by layering preferred translation sources. */
@@ -95,14 +95,6 @@ const SidebarItemSchema = z.union([
95
95
  ]);
96
96
  export type SidebarItem = z.infer<typeof SidebarItemSchema>;
97
97
 
98
- const SidebarGroupSchema: z.ZodType<
99
- | z.output<typeof ManualSidebarGroupSchema>
100
- | z.output<typeof AutoSidebarGroupSchema>,
101
- z.ZodTypeDef,
102
- | z.input<typeof ManualSidebarGroupSchema>
103
- | z.input<typeof AutoSidebarGroupSchema>
104
- > = z.union([ManualSidebarGroupSchema, AutoSidebarGroupSchema]);
105
-
106
98
  const UserConfigSchema = z.object({
107
99
  /** Title for your website. Will be used in metadata and as browser tab title. */
108
100
  title: z
@@ -202,7 +194,7 @@ const UserConfigSchema = z.object({
202
194
  defaultLocale: z.string().optional(),
203
195
 
204
196
  /** Configure your site’s sidebar navigation items. */
205
- sidebar: SidebarGroupSchema.array().optional(),
197
+ sidebar: SidebarItemSchema.array().optional(),
206
198
 
207
199
  /**
208
200
  * Add extra tags to your site’s `<head>`.