@grove-dev/starlight 0.7.0 → 0.8.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 (34) hide show
  1. package/components/custom/ContainerSection.astro +1 -1
  2. package/components/custom/LinkButton.astro +7 -7
  3. package/components/custom/dropdown/Dropdown.astro +5 -5
  4. package/components/custom/dropdown/DropdownContent.astro +26 -26
  5. package/components/custom/dropdown/DropdownItem.astro +8 -8
  6. package/components/custom/dropdown/DropdownLabel.astro +4 -4
  7. package/components/custom/dropdown/DropdownTrigger.astro +12 -12
  8. package/components/custom/dropdown/index.ts +14 -14
  9. package/components/overrides/Footer.astro +3 -3
  10. package/components/overrides/Header.astro +5 -6
  11. package/components/overrides/Hero.astro +17 -17
  12. package/components/overrides/PageFrame.astro +11 -11
  13. package/components/overrides/PageTitle.astro +3 -3
  14. package/components/overrides/Search.astro +6 -6
  15. package/components/overrides/parts/Drawer.astro +5 -5
  16. package/components/overrides/parts/NavBar.astro +5 -5
  17. package/components/overrides/parts/SidebarSublist.astro +2 -2
  18. package/components/overrides/parts/toc/TableOfContentsList.astro +4 -4
  19. package/components/overrides/parts/toc/starlight-toc.ts +96 -98
  20. package/core/config/docs-schema.ts +20 -20
  21. package/core/config/expresive-code.ts +49 -51
  22. package/core/config/override.ts +36 -36
  23. package/core/config/schemas.ts +59 -59
  24. package/core/config/vite.ts +12 -12
  25. package/core/i18n.ts +113 -113
  26. package/core/plugin.ts +42 -42
  27. package/core/sidebar.ts +4 -4
  28. package/global.d.ts +3 -3
  29. package/package.json +1 -1
  30. package/schema.ts +39 -39
  31. package/styles/base.css +866 -907
  32. package/styles/theme.css +61 -61
  33. package/user-components.ts +1 -1
  34. package/virtual.d.ts +27 -27
@@ -5,115 +5,113 @@
5
5
  import { PAGE_TITLE_ID } from '../../../../core/config/constants';
6
6
 
7
7
  export class StarlightTOC extends HTMLElement {
8
- private _current = this.querySelector<HTMLAnchorElement>('a[aria-current="true"]');
9
- private minH = Number.parseInt(this.dataset.minH || '2', 10);
10
- private maxH = Number.parseInt(this.dataset.maxH || '3', 10);
8
+ private _current = this.querySelector<HTMLAnchorElement>('a[aria-current="true"]');
9
+ private minH = Number.parseInt(this.dataset.minH || '2', 10);
10
+ private maxH = Number.parseInt(this.dataset.maxH || '3', 10);
11
11
 
12
- protected set current(link: HTMLAnchorElement) {
13
- if (link === this._current) return;
14
- if (this._current) this._current.removeAttribute('aria-current');
15
- link.setAttribute('aria-current', 'true');
16
- this._current = link;
17
- }
12
+ protected set current(link: HTMLAnchorElement) {
13
+ if (link === this._current) return;
14
+ if (this._current) this._current.removeAttribute('aria-current');
15
+ link.setAttribute('aria-current', 'true');
16
+ this._current = link;
17
+ }
18
18
 
19
- private onIdle = (cb: IdleRequestCallback) =>
20
- (window.requestIdleCallback || ((cb) => setTimeout(cb, 1)))(cb);
19
+ private onIdle = (cb: IdleRequestCallback) =>
20
+ (window.requestIdleCallback || ((cb) => setTimeout(cb, 1)))(cb);
21
21
 
22
- constructor() {
23
- super();
24
- this.onIdle(() => this.init());
25
- }
22
+ constructor() {
23
+ super();
24
+ this.onIdle(() => this.init());
25
+ }
26
26
 
27
- private init = (): void => {
28
- /** All the links in the table of contents. */
29
- const links = [...this.querySelectorAll('a')];
27
+ private init = (): void => {
28
+ /** All the links in the table of contents. */
29
+ const links = [...this.querySelectorAll('a')];
30
30
 
31
- /** Test if an element is a table-of-contents heading. */
32
- const isHeading = (el: Element): el is HTMLHeadingElement => {
33
- if (el instanceof HTMLHeadingElement) {
34
- // Special case for page title h1
35
- if (el.id === PAGE_TITLE_ID) return true;
36
- // Check the heading level is within the user-configured limits for the ToC
37
- const level = el.tagName[1];
38
- if (level) {
39
- const int = Number.parseInt(level, 10);
40
- if (int >= this.minH && int <= this.maxH) return true;
41
- }
42
- }
43
- return false;
44
- };
45
-
46
- /** Walk up the DOM to find the nearest heading. */
47
- const getElementHeading = (el: Element | null): HTMLHeadingElement | null => {
48
- if (!el) return null;
49
- const origin = el;
50
- while (el) {
51
- if (isHeading(el)) return el;
52
- // Assign the previous sibling’s last, most deeply nested child to el.
53
- el = el.previousElementSibling;
54
- while (el?.lastElementChild) {
55
- el = el.lastElementChild;
56
- }
57
- // Look for headings amongst siblings.
58
- const h = getElementHeading(el);
59
- if (h) return h;
60
- }
61
- // Walk back up the parent.
62
- return getElementHeading(origin.parentElement);
63
- };
31
+ /** Test if an element is a table-of-contents heading. */
32
+ const isHeading = (el: Element): el is HTMLHeadingElement => {
33
+ if (el instanceof HTMLHeadingElement) {
34
+ // Special case for page title h1
35
+ if (el.id === PAGE_TITLE_ID) return true;
36
+ // Check the heading level is within the user-configured limits for the ToC
37
+ const level = el.tagName[1];
38
+ if (level) {
39
+ const int = Number.parseInt(level, 10);
40
+ if (int >= this.minH && int <= this.maxH) return true;
41
+ }
42
+ }
43
+ return false;
44
+ };
64
45
 
65
- /** Handle intersections and set the current link to the heading for the current intersection. */
66
- const setCurrent: IntersectionObserverCallback = (entries) => {
67
- for (const { isIntersecting, target } of entries) {
68
- if (!isIntersecting) continue;
69
- const heading = getElementHeading(target);
70
- if (!heading) continue;
71
- const link = links.find(
72
- (link) => link.hash === `#${encodeURIComponent(heading.id)}`
73
- );
74
- if (link) {
75
- this.current = link;
76
- break;
77
- }
78
- }
79
- };
46
+ /** Walk up the DOM to find the nearest heading. */
47
+ const getElementHeading = (el: Element | null): HTMLHeadingElement | null => {
48
+ if (!el) return null;
49
+ const origin = el;
50
+ while (el) {
51
+ if (isHeading(el)) return el;
52
+ // Assign the previous sibling’s last, most deeply nested child to el.
53
+ el = el.previousElementSibling;
54
+ while (el?.lastElementChild) {
55
+ el = el.lastElementChild;
56
+ }
57
+ // Look for headings amongst siblings.
58
+ const h = getElementHeading(el);
59
+ if (h) return h;
60
+ }
61
+ // Walk back up the parent.
62
+ return getElementHeading(origin.parentElement);
63
+ };
80
64
 
81
- // Observe elements with an `id` (most likely headings) and their siblings.
82
- // Also observe direct children of `.content` to include elements before
83
- // the first heading.
84
- const toObserve = document.querySelectorAll('main [id], main [id] ~ *, main .content > *');
65
+ /** Handle intersections and set the current link to the heading for the current intersection. */
66
+ const setCurrent: IntersectionObserverCallback = (entries) => {
67
+ for (const { isIntersecting, target } of entries) {
68
+ if (!isIntersecting) continue;
69
+ const heading = getElementHeading(target);
70
+ if (!heading) continue;
71
+ const link = links.find((link) => link.hash === `#${encodeURIComponent(heading.id)}`);
72
+ if (link) {
73
+ this.current = link;
74
+ break;
75
+ }
76
+ }
77
+ };
85
78
 
86
- let observer: IntersectionObserver | undefined;
87
- const observe = () => {
88
- if (observer) return;
89
- observer = new IntersectionObserver(setCurrent, { rootMargin: this.getRootMargin() });
90
- toObserve.forEach((h) => observer!.observe(h));
91
- };
92
- observe();
79
+ // Observe elements with an `id` (most likely headings) and their siblings.
80
+ // Also observe direct children of `.content` to include elements before
81
+ // the first heading.
82
+ const toObserve = document.querySelectorAll('main [id], main [id] ~ *, main .content > *');
93
83
 
94
- let timeout: NodeJS.Timeout;
95
- window.addEventListener('resize', () => {
96
- // Disable intersection observer while window is resizing.
97
- if (observer) {
98
- observer.disconnect();
99
- observer = undefined;
100
- }
101
- clearTimeout(timeout);
102
- timeout = setTimeout(() => this.onIdle(observe), 200);
103
- });
84
+ let observer: IntersectionObserver | undefined;
85
+ const observe = () => {
86
+ if (observer) return;
87
+ observer = new IntersectionObserver(setCurrent, { rootMargin: this.getRootMargin() });
88
+ for (const h of toObserve) observer.observe(h);
104
89
  };
90
+ observe();
91
+
92
+ let timeout: NodeJS.Timeout;
93
+ window.addEventListener('resize', () => {
94
+ // Disable intersection observer while window is resizing.
95
+ if (observer) {
96
+ observer.disconnect();
97
+ observer = undefined;
98
+ }
99
+ clearTimeout(timeout);
100
+ timeout = setTimeout(() => this.onIdle(observe), 200);
101
+ });
102
+ };
105
103
 
106
- private getRootMargin(): `-${number}px 0% ${number}px` {
107
- const navBarHeight = document.querySelector('header')?.getBoundingClientRect().height || 0;
108
- // `<summary>` only exists in mobile ToC, so will fall back to 0 in large viewport component.
109
- const mobileTocHeight = this.querySelector('summary')?.getBoundingClientRect().height || 0;
110
- /** Start intersections at nav height + 2rem padding. */
111
- const top = navBarHeight + mobileTocHeight + 32;
112
- /** End intersections `53px` later. This is slightly more than the maximum `margin-top` in Markdown content. */
113
- const bottom = top + 53;
114
- const height = document.documentElement.clientHeight;
115
- return `-${top}px 0% ${bottom - height}px`;
116
- }
104
+ private getRootMargin(): `-${number}px 0% ${number}px` {
105
+ const navBarHeight = document.querySelector('header')?.getBoundingClientRect().height || 0;
106
+ // `<summary>` only exists in mobile ToC, so will fall back to 0 in large viewport component.
107
+ const mobileTocHeight = this.querySelector('summary')?.getBoundingClientRect().height || 0;
108
+ /** Start intersections at nav height + 2rem padding. */
109
+ const top = navBarHeight + mobileTocHeight + 32;
110
+ /** End intersections `53px` later. This is slightly more than the maximum `margin-top` in Markdown content. */
111
+ const bottom = top + 53;
112
+ const height = document.documentElement.clientHeight;
113
+ return `-${top}px 0% ${bottom - height}px`;
114
+ }
117
115
  }
118
116
 
119
117
  customElements.define('starlight-toc', StarlightTOC);
@@ -12,11 +12,11 @@ const LOADED = Symbol.for('@grove-dev/starlight.docs-schema-loaded');
12
12
 
13
13
  /** Called by `@grove-dev/starlight/schema` on import. */
14
14
  export function markDocsSchemaLoaded(): void {
15
- (globalThis as Record<symbol, unknown>)[LOADED] = true;
15
+ (globalThis as Record<symbol, unknown>)[LOADED] = true;
16
16
  }
17
17
 
18
18
  export function isDocsSchemaExtended(): boolean {
19
- return (globalThis as Record<symbol, unknown>)[LOADED] === true;
19
+ return (globalThis as Record<symbol, unknown>)[LOADED] === true;
20
20
  }
21
21
 
22
22
  let warned = false;
@@ -27,32 +27,32 @@ let warned = false;
27
27
  * several splash pages does not repeat the same advice once per page.
28
28
  */
29
29
  export function warnAboutMissingDocsSchemaOnce(
30
- hero: unknown,
31
- warn: (message: string) => void = console.warn
30
+ hero: unknown,
31
+ warn: (message: string) => void = console.warn,
32
32
  ): boolean {
33
- if (warned || hero == null || isDocsSchemaExtended()) return false;
33
+ if (warned || hero == null || isDocsSchemaExtended()) return false;
34
34
 
35
- warned = true;
36
- warn(missingDocsSchemaWarning());
37
- return true;
35
+ warned = true;
36
+ warn(missingDocsSchemaWarning());
37
+ return true;
38
38
  }
39
39
 
40
40
  /** Test seam: clears the once-per-process guard used by {@link warnAboutMissingDocsSchemaOnce}. */
41
41
  export function resetDocsSchemaWarning(): void {
42
- warned = false;
42
+ warned = false;
43
43
  }
44
44
 
45
45
  /** The advice printed when the schema extension is missing. */
46
46
  export function missingDocsSchemaWarning(): string {
47
- return [
48
- '[@grove-dev/starlight] This page sets `hero` frontmatter, but the docs schema is not extended,',
49
- "so Starlight is dropping the theme's hero fields. `hero.layout`, `hero.announcement` and the",
50
- 'extra `hero.actions[].variant` values have no effect until you extend it:',
51
- '',
52
- " import { ExtendDocsSchema } from '@grove-dev/starlight/schema';",
53
- '',
54
- ' schema: docsSchema({ extend: ExtendDocsSchema }),',
55
- '',
56
- 'See https://withgrove.dev/reference/plugin-api/#frontmatter-extension',
57
- ].join('\n');
47
+ return [
48
+ '[@grove-dev/starlight] This page sets `hero` frontmatter, but the docs schema is not extended,',
49
+ "so Starlight is dropping the theme's hero fields. `hero.layout`, `hero.announcement` and the",
50
+ 'extra `hero.actions[].variant` values have no effect until you extend it:',
51
+ '',
52
+ " import { ExtendDocsSchema } from '@grove-dev/starlight/schema';",
53
+ '',
54
+ ' schema: docsSchema({ extend: ExtendDocsSchema }),',
55
+ '',
56
+ 'See https://withgrove.dev/reference/plugin-api/#frontmatter-extension',
57
+ ].join('\n');
58
58
  }
@@ -2,62 +2,60 @@ import type { StarlightExpressiveCodeOptions } from '@astrojs/starlight/expressi
2
2
  import type { StarlightUserConfig } from '@astrojs/starlight/types';
3
3
 
4
4
  const createInlineSvgUrl = (svgContents: string): string => {
5
- const inlineSvg = svgContents.replace(
6
- /^(\s*<svg)\s+([^>]+)\s*(\/?>)/,
7
- (_match, tagStart: string, attributes: string, tagEnd: string) => {
8
- const sanitizedAttributes = attributes.replaceAll(
9
- /(?:width|height)\s*=\s*(?:(["'])[^"']*\1|\d+)\s*/g,
10
- ''
11
- );
5
+ const inlineSvg = svgContents.replace(
6
+ /^(\s*<svg)\s+([^>]+)\s*(\/?>)/,
7
+ (_match, tagStart: string, attributes: string, tagEnd: string) => {
8
+ const sanitizedAttributes = attributes.replaceAll(
9
+ /(?:width|height)\s*=\s*(?:(["'])[^"']*\1|\d+)\s*/g,
10
+ '',
11
+ );
12
12
 
13
- return `${tagStart} ${sanitizedAttributes.trim()}${tagEnd}`;
14
- }
15
- );
13
+ return `${tagStart} ${sanitizedAttributes.trim()}${tagEnd}`;
14
+ },
15
+ );
16
16
 
17
- return `url("data:image/svg+xml,${encodeURIComponent(inlineSvg)}")`;
17
+ return `url("data:image/svg+xml,${encodeURIComponent(inlineSvg)}")`;
18
18
  };
19
19
 
20
20
  export const expressiveCode = (
21
- config: StarlightUserConfig
21
+ config: StarlightUserConfig,
22
22
  ): boolean | StarlightExpressiveCodeOptions => {
23
- const userExpressiveCodeConfig =
24
- config.expressiveCode === false || config.expressiveCode === true
25
- ? {}
26
- : config.expressiveCode;
23
+ const userExpressiveCodeConfig =
24
+ config.expressiveCode === false || config.expressiveCode === true ? {} : config.expressiveCode;
27
25
 
28
- return config.expressiveCode === false
29
- ? false
30
- : {
31
- themes: ['github-dark-default', 'github-light-default'],
32
- ...userExpressiveCodeConfig,
33
- styleOverrides: {
34
- codeBackground: 'var(--code-background)',
35
- borderWidth: '0px',
36
- borderRadius: 'calc(var(--radius) + 4px)',
37
- gutterBorderWidth: '0px',
38
- ...userExpressiveCodeConfig?.styleOverrides,
39
- frames: {
40
- editorBackground: 'var(--code-background)',
41
- editorActiveTabBackground: 'var(--gray-5)',
42
- editorActiveTabForeground: 'var(--foreground)',
43
- editorTabBarBackground: 'var(--gray-6)',
44
- editorTabBarBorderColor: 'var(--border)',
45
- editorTabBarBorderBottomColor: 'var(--border)',
46
- terminalBackground: 'var(--code-background)',
47
- terminalTitlebarBackground: 'var(--gray-6)',
48
- terminalTitlebarBorderBottomColor: 'var(--border)',
49
- terminalTitlebarForeground: 'var(--muted-foreground)',
50
- shadowColor: 'transparent',
51
- copyIcon: createInlineSvgUrl(
52
- `<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-clipboard"><rect width="8" height="4" x="8" y="2" rx="1" ry="1"></rect><path d="M16 4h2a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2V6a2 2 0 0 1 2-2h2"></path></svg>`
53
- ),
54
- ...userExpressiveCodeConfig?.styleOverrides?.frames,
55
- },
56
- textMarkers: {
57
- markBackground: 'var(--mark-background)',
58
- markBorderColor: 'var(--border)',
59
- ...userExpressiveCodeConfig?.styleOverrides?.textMarkers,
60
- },
61
- },
62
- };
26
+ return config.expressiveCode === false
27
+ ? false
28
+ : {
29
+ themes: ['github-dark-default', 'github-light-default'],
30
+ ...userExpressiveCodeConfig,
31
+ styleOverrides: {
32
+ codeBackground: 'var(--code-background)',
33
+ borderWidth: '0px',
34
+ borderRadius: 'calc(var(--radius) + 4px)',
35
+ gutterBorderWidth: '0px',
36
+ ...userExpressiveCodeConfig?.styleOverrides,
37
+ frames: {
38
+ editorBackground: 'var(--code-background)',
39
+ editorActiveTabBackground: 'var(--gray-5)',
40
+ editorActiveTabForeground: 'var(--foreground)',
41
+ editorTabBarBackground: 'var(--gray-6)',
42
+ editorTabBarBorderColor: 'var(--border)',
43
+ editorTabBarBorderBottomColor: 'var(--border)',
44
+ terminalBackground: 'var(--code-background)',
45
+ terminalTitlebarBackground: 'var(--gray-6)',
46
+ terminalTitlebarBorderBottomColor: 'var(--border)',
47
+ terminalTitlebarForeground: 'var(--muted-foreground)',
48
+ shadowColor: 'transparent',
49
+ copyIcon: createInlineSvgUrl(
50
+ `<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-clipboard"><rect width="8" height="4" x="8" y="2" rx="1" ry="1"></rect><path d="M16 4h2a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2V6a2 2 0 0 1 2-2h2"></path></svg>`,
51
+ ),
52
+ ...userExpressiveCodeConfig?.styleOverrides?.frames,
53
+ },
54
+ textMarkers: {
55
+ markBackground: 'var(--mark-background)',
56
+ markBorderColor: 'var(--border)',
57
+ ...userExpressiveCodeConfig?.styleOverrides?.textMarkers,
58
+ },
59
+ },
60
+ };
63
61
  };
@@ -6,47 +6,47 @@ type StarlightUserConfig = HookParameters<'config:setup'>['config'];
6
6
  type ComponentOverride = keyof NonNullable<StarlightUserConfig['components']>;
7
7
 
8
8
  export const COMPONENT_OVERRIDES: ComponentOverride[] = [
9
- 'ThemeSelect',
10
- 'PageFrame',
11
- 'Header',
12
- 'SiteTitle',
13
- 'Sidebar',
14
- 'TwoColumnContent',
15
- 'ContentPanel',
16
- 'PageTitle',
17
- 'MarkdownContent',
18
- 'Hero',
19
- 'Footer',
20
- 'SocialIcons',
21
- 'Pagination',
22
- 'Search',
23
- 'TableOfContents',
24
- 'PageSidebar',
9
+ 'ThemeSelect',
10
+ 'PageFrame',
11
+ 'Header',
12
+ 'SiteTitle',
13
+ 'Sidebar',
14
+ 'TwoColumnContent',
15
+ 'ContentPanel',
16
+ 'PageTitle',
17
+ 'MarkdownContent',
18
+ 'Hero',
19
+ 'Footer',
20
+ 'SocialIcons',
21
+ 'Pagination',
22
+ 'Search',
23
+ 'TableOfContents',
24
+ 'PageSidebar',
25
25
  ];
26
26
 
27
27
  export function override(
28
- starlightConfig: StarlightUserConfig,
29
- pluginConfig: GroveStarlightConfig,
30
- overrides: ComponentOverride[],
31
- logger: AstroIntegrationLogger
28
+ starlightConfig: StarlightUserConfig,
29
+ pluginConfig: GroveStarlightConfig,
30
+ overrides: ComponentOverride[],
31
+ logger: AstroIntegrationLogger,
32
32
  ): StarlightUserConfig['components'] {
33
- const components = { ...starlightConfig.components };
34
- for (const override of overrides) {
35
- if (starlightConfig.components?.[override] != null) {
36
- const fallback = `@grove-dev/starlight/components/overrides/${override}.astro`;
33
+ const components = { ...starlightConfig.components };
34
+ for (const override of overrides) {
35
+ if (starlightConfig.components?.[override] != null) {
36
+ const fallback = `@grove-dev/starlight/components/overrides/${override}.astro`;
37
37
 
38
- if (pluginConfig.warnOverrides) {
39
- logger.warn(
40
- `A \`<${override}>\` component override is already defined in your Starlight configuration.`
41
- );
42
- logger.warn(
43
- `To use \`@grove-dev/starlight/components\`, either remove this override or manually render the content from \`${fallback}\`.`
44
- );
45
- }
46
- continue;
47
- }
48
- components[override] = `@grove-dev/starlight/components/overrides/${override}.astro`;
38
+ if (pluginConfig.warnOverrides) {
39
+ logger.warn(
40
+ `A \`<${override}>\` component override is already defined in your Starlight configuration.`,
41
+ );
42
+ logger.warn(
43
+ `To use \`@grove-dev/starlight/components\`, either remove this override or manually render the content from \`${fallback}\`.`,
44
+ );
45
+ }
46
+ continue;
49
47
  }
48
+ components[override] = `@grove-dev/starlight/components/overrides/${override}.astro`;
49
+ }
50
50
 
51
- return components;
51
+ return components;
52
52
  }
@@ -3,75 +3,75 @@ import type { HTMLAttributes } from 'astro/types';
3
3
  import { z } from 'astro/zod';
4
4
 
5
5
  const linkHTMLAttributesSchema = z.record(
6
- z.string(),
7
- z.union([z.string(), z.number(), z.boolean(), z.undefined()])
6
+ z.string(),
7
+ z.union([z.string(), z.number(), z.boolean(), z.undefined()]),
8
8
  ) as z.Schema<Omit<HTMLAttributes<'a'>, keyof AstroBuiltinAttributes | 'children'>>;
9
9
 
10
10
  const LinkItemHTMLAttributesSchema = () => linkHTMLAttributesSchema.default({});
11
11
 
12
12
  export const linkSchema = z.object({
13
- /**
14
- * An optional badge to display next to the topic label.
15
- *
16
- * This option accepts the same configuration as the Starlight badge sidebar item configuration.
17
- * @see https://starlight.astro.build/guides/sidebar/#badges
18
- */
19
- badge: z.string().optional(),
20
- /**
21
- * The link label.
22
- *
23
- * - A string used as the default-locale label (pair with `translations` for other languages).
24
- * - Or a locale map keyed by BCP-47 tags / locale paths (e.g. `en`, `es`).
25
- *
26
- * @see https://starlight.astro.build/guides/sidebar/#internationalization
27
- */
28
- label: z.union([z.string(), z.record(z.string(), z.string())]),
29
- /**
30
- * Optional labels for other languages when `label` is a string.
31
- * Keys should be BCP-47 tags (e.g. `en`, `es`), matching Starlight sidebar translations.
32
- *
33
- * @see https://starlight.astro.build/guides/sidebar/#internationalization
34
- */
35
- translations: z.record(z.string(), z.string()).optional(),
36
- /**
37
- * The link to the topic’s content which an be a relative link to local files or the full URL of an external page.
38
- *
39
- * For internal links, the link can either be a page included in the items array or a different page acting as the
40
- * topic’s landing page.
41
- */
42
- link: z.string(),
43
- /** HTML attributes to add to the link item. */
44
- attrs: LinkItemHTMLAttributesSchema().optional(),
13
+ /**
14
+ * An optional badge to display next to the topic label.
15
+ *
16
+ * This option accepts the same configuration as the Starlight badge sidebar item configuration.
17
+ * @see https://starlight.astro.build/guides/sidebar/#badges
18
+ */
19
+ badge: z.string().optional(),
20
+ /**
21
+ * The link label.
22
+ *
23
+ * - A string used as the default-locale label (pair with `translations` for other languages).
24
+ * - Or a locale map keyed by BCP-47 tags / locale paths (e.g. `en`, `es`).
25
+ *
26
+ * @see https://starlight.astro.build/guides/sidebar/#internationalization
27
+ */
28
+ label: z.union([z.string(), z.record(z.string(), z.string())]),
29
+ /**
30
+ * Optional labels for other languages when `label` is a string.
31
+ * Keys should be BCP-47 tags (e.g. `en`, `es`), matching Starlight sidebar translations.
32
+ *
33
+ * @see https://starlight.astro.build/guides/sidebar/#internationalization
34
+ */
35
+ translations: z.record(z.string(), z.string()).optional(),
36
+ /**
37
+ * The link to the topic’s content which an be a relative link to local files or the full URL of an external page.
38
+ *
39
+ * For internal links, the link can either be a page included in the items array or a different page acting as the
40
+ * topic’s landing page.
41
+ */
42
+ link: z.string(),
43
+ /** HTML attributes to add to the link item. */
44
+ attrs: LinkItemHTMLAttributesSchema().optional(),
45
45
  });
46
46
 
47
47
  export type Link = z.infer<typeof linkSchema>;
48
48
 
49
49
  export const GroveStarlightConfigSchema = z.object({
50
- /** Array of navigation links for the header/nav bar. */
51
- navLinks: z.array(linkSchema).optional(),
52
- docs: z
53
- .object({
54
- includeAiUtilities: z.boolean().optional().default(false),
55
- })
56
- .optional()
57
- .default({ includeAiUtilities: false }),
58
- /**
59
- * Whether to warn when a component override defined in your Starlight configuration prevents
60
- * the theme from applying its own. Set to `false` to silence those warnings.
61
- */
62
- warnOverrides: z.boolean().optional().default(true),
63
- /**
64
- * Footer Markdown text. Can be a string, or for multilingual sites an object with values for
65
- * each locale. Keys may be BCP-47 tags (e.g. `en`, `es`) or locale paths.
66
- *
67
- * @see https://starlight.astro.build/reference/configuration/#title
68
- */
69
- footerText: z
70
- .union([z.string(), z.record(z.string(), z.string())])
71
- .optional()
72
- .default(
73
- 'Inspired by the [shadcn/ui](https://ui.shadcn.com/) documentation theme and based on [starlight-theme-black](https://github.com/adrian-ub/starlight-theme-black). Originally forked from [lucas-labs/lucode-starlight-theme](https://github.com/lucas-labs/lucode-starlight-theme) and maintained by [grove](https://github.com/tortuvshin/grove).'
74
- ),
50
+ /** Array of navigation links for the header/nav bar. */
51
+ navLinks: z.array(linkSchema).optional(),
52
+ docs: z
53
+ .object({
54
+ includeAiUtilities: z.boolean().optional().default(false),
55
+ })
56
+ .optional()
57
+ .default({ includeAiUtilities: false }),
58
+ /**
59
+ * Whether to warn when a component override defined in your Starlight configuration prevents
60
+ * the theme from applying its own. Set to `false` to silence those warnings.
61
+ */
62
+ warnOverrides: z.boolean().optional().default(true),
63
+ /**
64
+ * Footer Markdown text. Can be a string, or for multilingual sites an object with values for
65
+ * each locale. Keys may be BCP-47 tags (e.g. `en`, `es`) or locale paths.
66
+ *
67
+ * @see https://starlight.astro.build/reference/configuration/#title
68
+ */
69
+ footerText: z
70
+ .union([z.string(), z.record(z.string(), z.string())])
71
+ .optional()
72
+ .default(
73
+ 'Inspired by the [shadcn/ui](https://ui.shadcn.com/) documentation theme and based on [starlight-theme-black](https://github.com/adrian-ub/starlight-theme-black). Originally forked from [lucas-labs/lucode-starlight-theme](https://github.com/lucas-labs/lucode-starlight-theme) and maintained by [grove](https://github.com/tortuvshin/grove).',
74
+ ),
75
75
  });
76
76
 
77
77
  export type GroveStarlightUserConfig = z.input<typeof GroveStarlightConfigSchema>;