@grove-dev/starlight 0.7.0 → 0.9.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/components/custom/ContainerSection.astro +1 -1
- package/components/custom/LinkButton.astro +7 -7
- package/components/custom/dropdown/Dropdown.astro +5 -5
- package/components/custom/dropdown/DropdownContent.astro +26 -26
- package/components/custom/dropdown/DropdownItem.astro +8 -8
- package/components/custom/dropdown/DropdownLabel.astro +4 -4
- package/components/custom/dropdown/DropdownTrigger.astro +12 -12
- package/components/custom/dropdown/index.ts +14 -14
- package/components/overrides/Footer.astro +3 -3
- package/components/overrides/Header.astro +5 -6
- package/components/overrides/Hero.astro +17 -17
- package/components/overrides/PageFrame.astro +11 -11
- package/components/overrides/PageTitle.astro +3 -3
- package/components/overrides/Search.astro +6 -6
- package/components/overrides/parts/Drawer.astro +5 -5
- package/components/overrides/parts/NavBar.astro +5 -5
- package/components/overrides/parts/SidebarSublist.astro +2 -2
- package/components/overrides/parts/toc/TableOfContentsList.astro +4 -4
- package/components/overrides/parts/toc/starlight-toc.ts +96 -98
- package/core/config/docs-schema.ts +20 -20
- package/core/config/expresive-code.ts +49 -51
- package/core/config/override.ts +36 -36
- package/core/config/schemas.ts +59 -59
- package/core/config/vite.ts +12 -12
- package/core/i18n.ts +113 -113
- package/core/plugin.ts +42 -42
- package/core/sidebar.ts +4 -4
- package/global.d.ts +3 -3
- package/package.json +1 -1
- package/schema.ts +39 -39
- package/styles/base.css +866 -907
- package/styles/theme.css +61 -61
- package/user-components.ts +1 -1
- 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
|
-
|
|
9
|
-
|
|
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
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
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
|
-
|
|
20
|
-
|
|
19
|
+
private onIdle = (cb: IdleRequestCallback) =>
|
|
20
|
+
(window.requestIdleCallback || ((cb) => setTimeout(cb, 1)))(cb);
|
|
21
21
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
22
|
+
constructor() {
|
|
23
|
+
super();
|
|
24
|
+
this.onIdle(() => this.init());
|
|
25
|
+
}
|
|
26
26
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
27
|
+
private init = (): void => {
|
|
28
|
+
/** All the links in the table of contents. */
|
|
29
|
+
const links = [...this.querySelectorAll('a')];
|
|
30
30
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
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
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
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
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
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
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
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
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
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
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
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
|
-
|
|
15
|
+
(globalThis as Record<symbol, unknown>)[LOADED] = true;
|
|
16
16
|
}
|
|
17
17
|
|
|
18
18
|
export function isDocsSchemaExtended(): boolean {
|
|
19
|
-
|
|
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
|
-
|
|
31
|
-
|
|
30
|
+
hero: unknown,
|
|
31
|
+
warn: (message: string) => void = console.warn,
|
|
32
32
|
): boolean {
|
|
33
|
-
|
|
33
|
+
if (warned || hero == null || isDocsSchemaExtended()) return false;
|
|
34
34
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
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
|
-
|
|
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
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
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
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
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
|
-
|
|
14
|
-
|
|
15
|
-
|
|
13
|
+
return `${tagStart} ${sanitizedAttributes.trim()}${tagEnd}`;
|
|
14
|
+
},
|
|
15
|
+
);
|
|
16
16
|
|
|
17
|
-
|
|
17
|
+
return `url("data:image/svg+xml,${encodeURIComponent(inlineSvg)}")`;
|
|
18
18
|
};
|
|
19
19
|
|
|
20
20
|
export const expressiveCode = (
|
|
21
|
-
|
|
21
|
+
config: StarlightUserConfig,
|
|
22
22
|
): boolean | StarlightExpressiveCodeOptions => {
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
? {}
|
|
26
|
-
: config.expressiveCode;
|
|
23
|
+
const userExpressiveCodeConfig =
|
|
24
|
+
config.expressiveCode === false || config.expressiveCode === true ? {} : config.expressiveCode;
|
|
27
25
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
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
|
};
|
package/core/config/override.ts
CHANGED
|
@@ -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
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
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
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
28
|
+
starlightConfig: StarlightUserConfig,
|
|
29
|
+
pluginConfig: GroveStarlightConfig,
|
|
30
|
+
overrides: ComponentOverride[],
|
|
31
|
+
logger: AstroIntegrationLogger,
|
|
32
32
|
): StarlightUserConfig['components'] {
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
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
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
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
|
-
|
|
51
|
+
return components;
|
|
52
52
|
}
|
package/core/config/schemas.ts
CHANGED
|
@@ -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
|
-
|
|
7
|
-
|
|
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
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
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
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
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>;
|