@astrojs/starlight 0.38.1 → 0.38.3

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,23 @@
1
1
  # @astrojs/starlight
2
2
 
3
+ ## 0.38.3
4
+
5
+ ### Patch Changes
6
+
7
+ - [#3799](https://github.com/withastro/starlight/pull/3799) [`313611b`](https://github.com/withastro/starlight/commit/313611b1cd9c1f38688cb98cc103ddd758e80ec2) Thanks [@JosefJezek](https://github.com/JosefJezek)! - Improves Czech UI translations
8
+
9
+ - [#3770](https://github.com/withastro/starlight/pull/3770) [`6e7bed1`](https://github.com/withastro/starlight/commit/6e7bed1e6b3b586b9719c620924f60d3678a1f83) Thanks [@gameroman](https://github.com/gameroman)! - Adds examples to the inline documentation for `title` in the Starlight configuration object
10
+
11
+ - [#3801](https://github.com/withastro/starlight/pull/3801) [`fedd48b`](https://github.com/withastro/starlight/commit/fedd48b701ea9ca764b19139404c744099565f4c) Thanks [@delucis](https://github.com/delucis)! - Fixes missing draft content warning in dev on pages using the hero layout
12
+
13
+ ## 0.38.2
14
+
15
+ ### Patch Changes
16
+
17
+ - [#3759](https://github.com/withastro/starlight/pull/3759) [`f24ce99`](https://github.com/withastro/starlight/commit/f24ce99a1a859920152e177f73afddce5c11902e) Thanks [@MilesChou](https://github.com/MilesChou)! - Fixes an issue where monolingual sites using a region-specific locale (e.g., `zh-TW`) as the default would incorrectly display base language translations (e.g., `zh` Simplified Chinese) instead of the region-specific ones (e.g., `zh-TW` Traditional Chinese).
18
+
19
+ - [#3768](https://github.com/withastro/starlight/pull/3768) [`a4c6c20`](https://github.com/withastro/starlight/commit/a4c6c20e67c76caf1dfdb0c67b0fa1df15ef52b7) Thanks [@delucis](https://github.com/delucis)! - Improves performance of sidebar generation for sites with very large sidebars
20
+
3
21
  ## 0.38.1
4
22
 
5
23
  ### Patch Changes
@@ -28,6 +28,7 @@ const { icon, label } = Astro.props;
28
28
  gap: 0.75em;
29
29
  font-size: var(--sl-text-body-sm);
30
30
  line-height: var(--sl-line-height-headings);
31
+ text-align: start;
31
32
  }
32
33
  }
33
34
  </style>
@@ -1,5 +1,6 @@
1
1
  ---
2
2
  import { Image } from 'astro:assets';
3
+ import DraftContentNotice from 'virtual:starlight/components/DraftContentNotice';
3
4
  import { PAGE_TITLE_ID } from '../constants';
4
5
  import LinkButton from '../user-components/LinkButton.astro';
5
6
 
@@ -44,6 +45,7 @@ if (image) {
44
45
  <div class="sl-flex stack">
45
46
  <div class="sl-flex copy">
46
47
  <h1 id={PAGE_TITLE_ID} data-page-title set:html={title} />
48
+ {data.draft && <DraftContentNotice />}
47
49
  {tagline && <div class="tagline" set:html={tagline} />}
48
50
  </div>
49
51
  {
@@ -67,6 +69,7 @@ if (image) {
67
69
  @layer starlight.core {
68
70
  .hero {
69
71
  display: grid;
72
+ grid-template-columns: 100%;
70
73
  align-items: center;
71
74
  gap: 1rem;
72
75
  padding-bottom: 1rem;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@astrojs/starlight",
3
- "version": "0.38.1",
3
+ "version": "0.38.3",
4
4
  "description": "Build beautiful, high-performance documentation websites with Astro",
5
5
  "keywords": [
6
6
  "docs",
@@ -47,10 +47,10 @@
47
47
  "devDependencies": {
48
48
  "@playwright/test": "^1.57.0",
49
49
  "@types/node": "^22.19.3",
50
- "@vitest/coverage-v8": "^4.1.0-beta.6",
50
+ "@vitest/coverage-v8": "^4.1.0",
51
51
  "astro": "^6.0.1",
52
52
  "linkedom": "^0.18.4",
53
- "vitest": "^4.1.0-beta.6"
53
+ "vitest": "^4.1.0"
54
54
  },
55
55
  "dependencies": {
56
56
  "@astrojs/markdown-remark": "^7.0.0",
@@ -15,19 +15,19 @@
15
15
  "tableOfContents.overview": "Přehled",
16
16
  "i18n.untranslatedContent": "Tento obsah zatím není dostupný ve vašem jazyce.",
17
17
  "page.editLink": "Upravit stránku",
18
- "page.lastUpdated": "Poslední aktualizace:",
18
+ "page.lastUpdated": "Aktualizováno:",
19
19
  "page.previousLink": "Předchozí",
20
20
  "page.nextLink": "Další",
21
21
  "page.draft": "Tento obsah je koncept a nebude zahrnutý v produkčním sestavení.",
22
- "404.text": "Stránka nenalezena. Zkontrolujte adresu nebo zkuste použít vyhledávač",
22
+ "404.text": "Stránka nenalezena. Zkontrolujte adresu nebo zkuste použít vyhledávač.",
23
23
  "aside.note": "Poznámka",
24
24
  "aside.tip": "Tip",
25
25
  "aside.caution": "Upozornění",
26
26
  "aside.danger": "Nebezpečí",
27
27
  "fileTree.directory": "Adresář",
28
- "builtWithStarlight.label": "Postavené s Starlight",
28
+ "builtWithStarlight.label": "Postaveno se Starlight",
29
29
  "expressiveCode.copyButtonCopied": "Zkopírováno!",
30
- "expressiveCode.copyButtonTooltip": "Kopíruj do schránky",
30
+ "expressiveCode.copyButtonTooltip": "Kopírovat do schránky",
31
31
  "expressiveCode.terminalWindowFallbackTitle": "Terminál",
32
32
  "pagefind.clear_search": "Vyčistit",
33
33
  "pagefind.load_more": "Načíst další výsledky",
@@ -39,5 +39,5 @@
39
39
  "pagefind.alt_search": "Žádné výsledky pro [SEARCH_TERM]. Namísto toho zobrazuji výsledky pro: [DIFFERENT_TERM]",
40
40
  "pagefind.search_suggestion": "Žádný výsledek pro [SEARCH_TERM]. Zkus nějaké z těchto hledání:",
41
41
  "pagefind.searching": "Hledám [SEARCH_TERM]...",
42
- "heading.anchorLabel": "Section titled “{{title}}”"
42
+ "heading.anchorLabel": "Sekce “{{title}}”"
43
43
  }
@@ -22,8 +22,7 @@ export async function createTranslationSystem<T extends i18nSchemaOutput>(
22
22
 
23
23
  const translations = {
24
24
  [defaultLocale]: buildResources(
25
- builtinTranslations[defaultLocale],
26
- builtinTranslations[stripLangRegion(defaultLocale)],
25
+ builtinTranslations[defaultLocale] || builtinTranslations[stripLangRegion(defaultLocale)],
27
26
  pluginTranslations[defaultLocale],
28
27
  userTranslations[defaultLocale]
29
28
  ),
@@ -357,14 +357,18 @@ function sidebarFromDir(
357
357
 
358
358
  /**
359
359
  * Intermediate sidebar represents sidebar entries generated from the user config for a specific
360
- * locale and do not contain any information about the current page.
361
- * These representations are cached per locale to avoid regenerating them for each page.
362
- * When generating the final sidebar for a page, the intermediate sidebar is cloned and the current
363
- * page is marked as such.
360
+ * locale. These representations are cached per locale to avoid regenerating them for each page.
361
+ * When generating the final sidebar for a page, the current page entry in the sidebar is marked
362
+ * with `isCurrent` and cached. Subsequent runs then reset the previous current entry before marking
363
+ * the new current page.
364
+ *
365
+ * Sidebars, like all route data, are deep cloned before the data is passed to users for mutation,
366
+ * so optimising with a single mutable object per locale is safe.
364
367
  *
365
368
  * @see getSidebarFromIntermediateSidebar
366
369
  */
367
370
  const intermediateSidebars = new Map<string | undefined, SidebarEntry[]>();
371
+ const lastCurrentEntryByLocale = new Map<string | undefined, SidebarLink>();
368
372
 
369
373
  /** Get the sidebar for the current page using the global config. */
370
374
  export function getSidebar(pathname: string, locale: string | undefined): SidebarEntry[] {
@@ -373,7 +377,8 @@ export function getSidebar(pathname: string, locale: string | undefined): Sideba
373
377
  intermediateSidebar = getIntermediateSidebarFromConfig(config.sidebar, pathname, locale);
374
378
  intermediateSidebars.set(locale, intermediateSidebar);
375
379
  }
376
- return getSidebarFromIntermediateSidebar(intermediateSidebar, pathname);
380
+ setIntermediateSidebarCurrentEntry(intermediateSidebar, pathname, locale);
381
+ return intermediateSidebar;
377
382
  }
378
383
 
379
384
  /** Get the sidebar for the current page using the specified sidebar config. */
@@ -382,8 +387,10 @@ export function getSidebarFromConfig(
382
387
  pathname: string,
383
388
  locale: string | undefined
384
389
  ): SidebarEntry[] {
385
- const intermediateSidebar = getIntermediateSidebarFromConfig(sidebarConfig, pathname, locale);
386
- return getSidebarFromIntermediateSidebar(intermediateSidebar, pathname);
390
+ const sidebar = getIntermediateSidebarFromConfig(sidebarConfig, pathname, locale);
391
+ const currentEntry = getSidebarCurrentEntry(sidebar, pathname);
392
+ if (currentEntry) currentEntry.isCurrent = true;
393
+ return sidebar;
387
394
  }
388
395
 
389
396
  /** Get the intermediate sidebar for the current page using the specified sidebar config. */
@@ -401,32 +408,39 @@ function getIntermediateSidebarFromConfig(
401
408
  }
402
409
  }
403
410
 
404
- /** Transform an intermediate sidebar into a sidebar for the current page. */
405
- function getSidebarFromIntermediateSidebar(
411
+ /** Marks the current page in an intermediate sidebar. */
412
+ function setIntermediateSidebarCurrentEntry(
406
413
  intermediateSidebar: SidebarEntry[],
407
- pathname: string
408
- ): SidebarEntry[] {
409
- const sidebar = structuredClone(intermediateSidebar);
410
- setIntermediateSidebarCurrentEntry(sidebar, pathname);
411
- return sidebar;
414
+ pathname: string,
415
+ locale: string | undefined
416
+ ): void {
417
+ // Reset the `isCurrent` flag in this sidebar if it was previously set.
418
+ const lastCurrentEntry = lastCurrentEntryByLocale.get(locale);
419
+ if (lastCurrentEntry) {
420
+ lastCurrentEntry.isCurrent = false;
421
+ }
422
+ // Find the new current entry.
423
+ const entry = getSidebarCurrentEntry(intermediateSidebar, pathname);
424
+ // Mark it as current and store it to be reset later.
425
+ if (entry) {
426
+ entry.isCurrent = true;
427
+ lastCurrentEntryByLocale.set(locale, entry);
428
+ }
412
429
  }
413
430
 
414
- /** Marks the current page as such in an intermediate sidebar. */
415
- function setIntermediateSidebarCurrentEntry(
416
- intermediateSidebar: SidebarEntry[],
417
- pathname: string
418
- ): boolean {
419
- for (const entry of intermediateSidebar) {
431
+ /** Finds the current page in a sidebar. */
432
+ function getSidebarCurrentEntry(sidebar: SidebarEntry[], pathname: string): SidebarLink | null {
433
+ for (const entry of sidebar) {
420
434
  if (entry.type === 'link' && pathsMatch(encodeURI(entry.href), pathname)) {
421
- entry.isCurrent = true;
422
- return true;
435
+ return entry;
423
436
  }
424
437
 
425
- if (entry.type === 'group' && setIntermediateSidebarCurrentEntry(entry.entries, pathname)) {
426
- return true;
438
+ if (entry.type === 'group') {
439
+ const currentEntry = getSidebarCurrentEntry(entry.entries, pathname);
440
+ if (currentEntry) return currentEntry;
427
441
  }
428
442
  }
429
- return false;
443
+ return null;
430
444
  }
431
445
 
432
446
  /** Generates a deterministic string based on the content of the passed sidebar. */
@@ -22,7 +22,15 @@ const LocaleSchema = z.object({
22
22
  });
23
23
 
24
24
  const UserConfigSchema = z.object({
25
- /** Title for your website. Will be used in metadata and as browser tab title. */
25
+ /**
26
+ * Title for your website. Will be used in metadata and as browser tab title.
27
+ *
28
+ * @example
29
+ * title: 'My Docs'
30
+ *
31
+ * @example
32
+ * title: { en: 'My Docs' }
33
+ */
26
34
  title: TitleConfigSchema(),
27
35
 
28
36
  /** Description metadata for your website. Can be used in page metadata. */