@mintlify/astro 0.1.4 → 0.1.5

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.
@@ -0,0 +1,98 @@
1
+ import { type NavigationConfig, type DocsConfig } from '@mintlify/validation';
2
+ export interface NavPage {
3
+ href: string;
4
+ title: string;
5
+ icon?: string;
6
+ tag?: string;
7
+ api?: string;
8
+ deprecated?: boolean;
9
+ }
10
+ export interface NavGroup {
11
+ group: string;
12
+ pages: NavEntry[];
13
+ icon?: string;
14
+ tag?: string;
15
+ }
16
+ export type NavEntry = NavPage | NavGroup;
17
+ export type NavNode = Record<string, unknown>;
18
+ export interface TabInfo {
19
+ name: string;
20
+ href: string;
21
+ isActive: boolean;
22
+ }
23
+ export type Favicons = {
24
+ icons: Array<{
25
+ rel?: string;
26
+ type?: string;
27
+ sizes?: string;
28
+ href?: string;
29
+ media?: string;
30
+ }>;
31
+ };
32
+ export type AnchorItem = {
33
+ name: string;
34
+ href: string;
35
+ icon?: string;
36
+ color?: string;
37
+ };
38
+ export declare function isNavPage(entry: NavEntry): entry is NavPage;
39
+ export declare function isNavGroup(entry: NavEntry): entry is NavGroup;
40
+ /**
41
+ * Decorates a raw `NavigationConfig` from docs.json by resolving string page
42
+ * slugs into `{ href, title }` entries using the provided title map.
43
+ */
44
+ export declare function decorateNavigation(nav: NavigationConfig, titleMap: Record<string, string>): NavNode;
45
+ /**
46
+ * Extracts the sidebar navigation entries for the current page's division.
47
+ */
48
+ export declare function unwrapNav(nav: NavNode, currentPath: string): NavEntry[];
49
+ /**
50
+ * Returns true if the given path is contained within the navigation entries.
51
+ */
52
+ export declare function containsPath(entries: NavEntry[], path: string): boolean;
53
+ /**
54
+ * Builds tab metadata from the top-level `tabs` division of the navigation.
55
+ */
56
+ export declare function getTabsFromNav(nav: NavNode, currentPath: string): TabInfo[] | null;
57
+ /**
58
+ * Returns the previous and next pages relative to the current path,
59
+ * for footer navigation.
60
+ */
61
+ export declare function getFooterPages(entries: NavEntry[], currentPath: string): {
62
+ prev: NavPage | null;
63
+ next: NavPage | null;
64
+ };
65
+ /**
66
+ * Finds the group label that contains the given path.
67
+ */
68
+ export declare function findGroupForPath(entries: NavEntry[], path: string): string | undefined;
69
+ /**
70
+ * Resolves the favicon configuration from docs.json into link element data.
71
+ * Handles both string and `{ light, dark }` formats.
72
+ */
73
+ export declare function getFavicons(config: DocsConfig): Favicons | undefined;
74
+ /**
75
+ * Extracts anchor items from `navigation.global.anchors` in docs.json.
76
+ */
77
+ export declare function getAnchors(config: DocsConfig): AnchorItem[];
78
+ export interface PageData {
79
+ favicons: Favicons | undefined;
80
+ navigation: NavNode;
81
+ sidebarEntries: NavEntry[];
82
+ tabs: TabInfo[] | null;
83
+ footerPages: {
84
+ prev: NavPage | null;
85
+ next: NavPage | null;
86
+ };
87
+ groupName: string | undefined;
88
+ anchors: AnchorItem[];
89
+ }
90
+ /**
91
+ * Resolves the page context from a docs config in a single call.
92
+ * Orchestrates navigation decoration, sidebar entries, tabs, footer pages,
93
+ * group name, and anchors.
94
+ */
95
+ export declare function resolvePageData(config: DocsConfig, options: {
96
+ currentPath: string;
97
+ titleMap: Record<string, string>;
98
+ }): PageData;
@@ -0,0 +1,219 @@
1
+ import { sep } from 'node:path';
2
+ import { divisions } from '@mintlify/validation';
3
+ export function isNavPage(entry) {
4
+ return 'href' in entry && 'title' in entry;
5
+ }
6
+ export function isNavGroup(entry) {
7
+ return 'group' in entry && 'pages' in entry;
8
+ }
9
+ function normalizePath(path) {
10
+ let normalized = sep !== '/' ? path.replaceAll(sep, '/') : path;
11
+ if (normalized.length > 1 && normalized.endsWith('/')) {
12
+ normalized = normalized.slice(0, -1);
13
+ }
14
+ return normalized;
15
+ }
16
+ /**
17
+ * Decorates a raw `NavigationConfig` from docs.json by resolving string page
18
+ * slugs into `{ href, title }` entries using the provided title map.
19
+ */
20
+ export function decorateNavigation(nav, titleMap) {
21
+ return decorateNavNode(nav, titleMap);
22
+ }
23
+ function decorateNavNode(nav, titleMap) {
24
+ const result = { ...nav };
25
+ const pages = result.pages;
26
+ if (Array.isArray(pages) && !result.group) {
27
+ result.pages = pages.map((p) => decorateEntry(p, titleMap));
28
+ }
29
+ const groups = result.groups;
30
+ if (Array.isArray(groups)) {
31
+ result.groups = groups.map((g) => decorateEntry(g, titleMap));
32
+ }
33
+ for (const key of divisions) {
34
+ const division = result[key];
35
+ if (Array.isArray(division)) {
36
+ result[key] = division.map((item) => decorateNavNode(item, titleMap));
37
+ }
38
+ }
39
+ return result;
40
+ }
41
+ function decorateEntry(entry, titleMap) {
42
+ if (typeof entry === 'string') {
43
+ return {
44
+ href: entry === 'index' ? '/' : `/${entry}`,
45
+ title: titleMap[entry] ?? slugToTitle(entry),
46
+ };
47
+ }
48
+ if (typeof entry === 'object' && entry !== null) {
49
+ const node = entry;
50
+ const pages = node.pages;
51
+ if (node.group != null && Array.isArray(pages)) {
52
+ return {
53
+ ...node,
54
+ pages: pages.map((page) => decorateEntry(page, titleMap)),
55
+ };
56
+ }
57
+ }
58
+ return entry;
59
+ }
60
+ function slugToTitle(slug) {
61
+ const last = slug.split('/').pop() ?? slug;
62
+ return last
63
+ .split('-')
64
+ .map((word) => word.charAt(0).toUpperCase() + word.slice(1))
65
+ .join(' ');
66
+ }
67
+ /**
68
+ * Extracts the sidebar navigation entries for the current page's division.
69
+ */
70
+ export function unwrapNav(nav, currentPath) {
71
+ const groups = nav.groups;
72
+ if (Array.isArray(groups))
73
+ return groups;
74
+ const pages = nav.pages;
75
+ if (Array.isArray(pages) && !nav.group)
76
+ return pages;
77
+ for (const key of divisions) {
78
+ const divisionArr = nav[key];
79
+ if (!Array.isArray(divisionArr))
80
+ continue;
81
+ for (const division of divisionArr) {
82
+ const entries = unwrapNav(division, currentPath);
83
+ if (entries.length > 0 && containsPath(entries, currentPath))
84
+ return entries;
85
+ }
86
+ if (divisionArr.length > 0) {
87
+ return unwrapNav(divisionArr[0], currentPath);
88
+ }
89
+ }
90
+ return [];
91
+ }
92
+ /**
93
+ * Returns true if the given path is contained within the navigation entries.
94
+ */
95
+ export function containsPath(entries, path) {
96
+ const normalized = normalizePath(path);
97
+ return entries.some((entry) => isNavPage(entry)
98
+ ? normalizePath(entry.href) === normalized
99
+ : isNavGroup(entry) && containsPath(entry.pages, normalized));
100
+ }
101
+ /**
102
+ * Builds tab metadata from the top-level `tabs` division of the navigation.
103
+ */
104
+ export function getTabsFromNav(nav, currentPath) {
105
+ const tabs = nav.tabs;
106
+ if (!Array.isArray(tabs))
107
+ return null;
108
+ return tabs.map((tab) => {
109
+ const tabNode = tab;
110
+ const entries = unwrapNav(tabNode, currentPath);
111
+ return {
112
+ name: tabNode.tab ?? '',
113
+ href: findFirstPage(entries)?.href ?? '/',
114
+ isActive: containsPath(entries, currentPath),
115
+ };
116
+ });
117
+ }
118
+ function findFirstPage(entries) {
119
+ for (const entry of entries) {
120
+ if (isNavPage(entry))
121
+ return entry;
122
+ if (isNavGroup(entry)) {
123
+ const page = findFirstPage(entry.pages);
124
+ if (page)
125
+ return page;
126
+ }
127
+ }
128
+ return undefined;
129
+ }
130
+ /**
131
+ * Returns the previous and next pages relative to the current path,
132
+ * for footer navigation.
133
+ */
134
+ export function getFooterPages(entries, currentPath) {
135
+ const normalized = normalizePath(currentPath);
136
+ const pages = flattenPages(entries);
137
+ const idx = pages.findIndex((p) => normalizePath(p.href) === normalized);
138
+ return {
139
+ prev: idx > 0 ? pages[idx - 1] : null,
140
+ next: idx < pages.length - 1 ? pages[idx + 1] : null,
141
+ };
142
+ }
143
+ function flattenPages(entries) {
144
+ return entries.flatMap((x) => isNavGroup(x) ? flattenPages(x.pages) : [x]);
145
+ }
146
+ /**
147
+ * Finds the group label that contains the given path.
148
+ */
149
+ export function findGroupForPath(entries, path) {
150
+ const normalized = normalizePath(path);
151
+ for (const entry of entries) {
152
+ if (isNavGroup(entry)) {
153
+ for (const page of entry.pages) {
154
+ if (isNavPage(page) && normalizePath(page.href) === normalized) {
155
+ return entry.group;
156
+ }
157
+ if (isNavGroup(page)) {
158
+ const nested = findGroupForPath([page], normalized);
159
+ if (nested)
160
+ return nested;
161
+ }
162
+ }
163
+ }
164
+ }
165
+ return undefined;
166
+ }
167
+ /**
168
+ * Resolves the favicon configuration from docs.json into link element data.
169
+ * Handles both string and `{ light, dark }` formats.
170
+ */
171
+ export function getFavicons(config) {
172
+ const faviconConfig = config.favicon;
173
+ const faviconHref = typeof faviconConfig === 'string'
174
+ ? faviconConfig
175
+ : (faviconConfig?.light ?? faviconConfig?.dark);
176
+ if (!faviconHref) {
177
+ return undefined;
178
+ }
179
+ return {
180
+ icons: [
181
+ {
182
+ rel: 'icon',
183
+ type: 'image/svg+xml',
184
+ href: faviconHref,
185
+ },
186
+ ],
187
+ };
188
+ }
189
+ /**
190
+ * Extracts anchor items from `navigation.global.anchors` in docs.json.
191
+ */
192
+ export function getAnchors(config) {
193
+ const anchors = config.navigation.global?.anchors ?? [];
194
+ return anchors.map((anchor) => ({
195
+ name: anchor.anchor,
196
+ href: anchor.href,
197
+ icon: typeof anchor.icon === 'string' ? anchor.icon : anchor.icon?.name,
198
+ color: anchor.color?.light ?? anchor.color?.dark,
199
+ }));
200
+ }
201
+ /**
202
+ * Resolves the page context from a docs config in a single call.
203
+ * Orchestrates navigation decoration, sidebar entries, tabs, footer pages,
204
+ * group name, and anchors.
205
+ */
206
+ export function resolvePageData(config, options) {
207
+ const { currentPath, titleMap } = options;
208
+ const decoratedNav = decorateNavigation(config.navigation, titleMap);
209
+ const sidebarEntries = unwrapNav(decoratedNav, currentPath);
210
+ return {
211
+ favicons: getFavicons(config),
212
+ navigation: decoratedNav,
213
+ sidebarEntries,
214
+ tabs: getTabsFromNav(decoratedNav, currentPath),
215
+ footerPages: getFooterPages(sidebarEntries, currentPath),
216
+ groupName: findGroupForPath(sidebarEntries, currentPath),
217
+ anchors: getAnchors(config),
218
+ };
219
+ }
package/dist/index.d.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  import type { AstroIntegration } from 'astro';
2
2
  export type { DocsConfig, NavigationConfig } from './types.js';
3
+ export { readDocsConfig } from './utils/read-docs-config.js';
3
4
  export interface MintlifyOptions {
4
5
  docsDir?: string;
5
6
  }
package/dist/index.js CHANGED
@@ -11,6 +11,7 @@ import { readDocsConfig } from './utils/read-docs-config.js';
11
11
  import { readPageContent } from './utils/read-page-content.js';
12
12
  import { createStaticAssetMiddleware } from './utils/serve-docs-assets.js';
13
13
  import { writePageContent } from './utils/write-page-content.js';
14
+ export { readDocsConfig } from './utils/read-docs-config.js';
14
15
  export function mintlify(options) {
15
16
  let docsDir;
16
17
  let staticDir;
@@ -0,0 +1,5 @@
1
+ import type { AstroIntegration } from 'astro';
2
+ export interface MintlifyOptions {
3
+ docsDir?: string;
4
+ }
5
+ export declare function mintlify(options?: MintlifyOptions): AstroIntegration;
@@ -0,0 +1,67 @@
1
+ import { cp } from 'node:fs/promises';
2
+ import { join, resolve } from 'node:path';
3
+ import { fileURLToPath } from 'node:url';
4
+ import { getAllPathsInDocsNav } from '@mintlify/common';
5
+ import { clearContentDirectory } from './utils/clear-content-directory.js';
6
+ import { copyAssets } from './utils/copy-assets.js';
7
+ import { findUserComponents } from './utils/find-user-components.js';
8
+ import { loadAllSnippets } from './utils/load-all-snippets.js';
9
+ import { initLogger } from './utils/logger.js';
10
+ import { readDocsConfig } from './utils/read-docs-config.js';
11
+ import { readPageContent } from './utils/read-page-content.js';
12
+ import { createStaticAssetMiddleware } from './utils/serve-docs-assets.js';
13
+ import { writePageContent } from './utils/write-page-content.js';
14
+ export function mintlify(options) {
15
+ let docsDir;
16
+ let staticDir;
17
+ return {
18
+ name: '@mintlify/astro',
19
+ hooks: {
20
+ 'astro:config:setup': async ({ config: astroConfig, logger }) => {
21
+ initLogger(logger);
22
+ const rootDir = fileURLToPath(astroConfig.root);
23
+ const contentDir = join(rootDir, '.mintlify', 'docs');
24
+ const componentsDir = join(rootDir, '.mintlify', 'components');
25
+ staticDir = join(rootDir, '.mintlify', 'static');
26
+ docsDir = resolve(rootDir, options?.docsDir ?? './docs');
27
+ await Promise.all([
28
+ clearContentDirectory(contentDir),
29
+ clearContentDirectory(componentsDir),
30
+ clearContentDirectory(staticDir),
31
+ ]);
32
+ const assetCount = await copyAssets(docsDir, staticDir);
33
+ logger.info(`Copied ${assetCount} static assets`);
34
+ const snippets = await loadAllSnippets(docsDir);
35
+ logger.info(`Loaded ${snippets.length} snippet files`);
36
+ const userComponents = await findUserComponents(docsDir);
37
+ const docsConfig = await readDocsConfig(docsDir);
38
+ const pagePaths = getAllPathsInDocsNav(docsConfig.navigation);
39
+ logger.info(`Found ${pagePaths.length} pages to sync`);
40
+ await Promise.all(pagePaths.map(async (pagePath) => {
41
+ try {
42
+ const { content, slug } = await readPageContent(pagePath, docsDir);
43
+ await writePageContent({
44
+ content,
45
+ slug,
46
+ contentDir,
47
+ componentsDir,
48
+ userComponents,
49
+ snippets,
50
+ });
51
+ }
52
+ catch (error) {
53
+ logger.warn(`Failed to read content for ${pagePath}: ${error}`);
54
+ }
55
+ }));
56
+ logger.info(`Synced ${pagePaths.length} pages`);
57
+ },
58
+ 'astro:server:setup': ({ server }) => {
59
+ server.middlewares.use(createStaticAssetMiddleware(staticDir));
60
+ },
61
+ 'astro:build:done': async ({ dir }) => {
62
+ const outputDir = fileURLToPath(dir);
63
+ await cp(staticDir, outputDir, { recursive: true });
64
+ },
65
+ },
66
+ };
67
+ }
@@ -0,0 +1,121 @@
1
+ import type { ReactNode } from 'react';
2
+ import type { MDXComponents } from 'mdx/types';
3
+ export declare const components: {
4
+ Accordion: (({ title, description, defaultOpen, icon, iconType, children, className, _disabled, trackOpen, trackClose, onMount, topOffset, getInitialOpenFromUrl, onUrlStateChange, _onKeyDownCapture, }: import("@mintlify/components").AccordionProps) => import("react/jsx-runtime").JSX.Element) & {
5
+ Group: ({ children, className }: import("@mintlify/components").AccordionGroupProps) => import("react/jsx-runtime").JSX.Element;
6
+ };
7
+ Badge: ({ children, className, color, shape, variant: variantProp, stroke, disabled, size, leadIcon, tailIcon: tailIconProp, icon, iconType, iconLibrary, onClick, href, }: import("@mintlify/components").BadgeProps) => import("react/jsx-runtime").JSX.Element;
8
+ Callout: ({ children, variant, icon, iconType, iconLibrary, color, className, ariaLabel, }: import("@mintlify/components").CalloutProps) => import("react/jsx-runtime").JSX.Element;
9
+ Card: ({ title, icon, iconType, iconLibrary, color, horizontal, href, img, children, disabled, cta, arrow, as, className, }: import("@mintlify/components").CardComponentProps) => import("react/jsx-runtime").JSX.Element;
10
+ Check: (props: {
11
+ children: ReactNode;
12
+ className?: string | undefined;
13
+ color?: string | undefined;
14
+ icon?: ReactNode;
15
+ iconType?: ("brands" | "duotone" | "light" | "regular" | "sharp-duotone-solid" | "sharp-light" | "sharp-regular" | "sharp-solid" | "sharp-thin" | "solid" | "thin") | undefined;
16
+ iconLibrary?: ("fontawesome" | "lucide") | undefined;
17
+ ariaLabel?: string | undefined;
18
+ }) => import("react/jsx-runtime").JSX.Element;
19
+ CodeBlock: (params: import("@mintlify/components").CodeBlockProps) => import("react/jsx-runtime").JSX.Element;
20
+ CodeGroup: ({ children, isSmallText, className, noMargins, dropdown, feedbackModalOpen, anchorRef, codeBlockTheme, codeBlockThemeObject, initialSelectedTab, onSelectedTabChange, askAiButton, feedbackButton, copyButtonProps, }: import("@mintlify/components").CodeGroupProps) => import("react/jsx-runtime").JSX.Element | null;
21
+ Color: {
22
+ ({ children, variant, className }: import("@mintlify/components").ColorProps): import("react/jsx-runtime").JSX.Element;
23
+ Row: ({ children, title }: import("@mintlify/components").ColorRowProps) => import("react/jsx-runtime").JSX.Element;
24
+ Item: ({ name, value }: import("@mintlify/components").ColorItemProps) => import("react/jsx-runtime").JSX.Element;
25
+ };
26
+ Columns: ({ children, className, cols }: import("@mintlify/components").ColumnsProps) => import("react/jsx-runtime").JSX.Element;
27
+ Danger: (props: {
28
+ children: ReactNode;
29
+ className?: string | undefined;
30
+ color?: string | undefined;
31
+ icon?: ReactNode;
32
+ iconType?: ("brands" | "duotone" | "light" | "regular" | "sharp-duotone-solid" | "sharp-light" | "sharp-regular" | "sharp-solid" | "sharp-thin" | "solid" | "thin") | undefined;
33
+ iconLibrary?: ("fontawesome" | "lucide") | undefined;
34
+ ariaLabel?: string | undefined;
35
+ }) => import("react/jsx-runtime").JSX.Element;
36
+ Expandable: ({ title, defaultOpen, onChange: onChangeProp, lazy, className, children, uniqueParamId, onMount, onOpen, onClose, openedText, closedText, hasScrolledToAnchorRef, anchor, }: import("@mintlify/components").ExpandableProps) => import("react/jsx-runtime").JSX.Element;
37
+ Frame: ({ as: Component, title, description, renderDescription, style, className, children, }: import("@mintlify/components").FrameProps) => import("react/jsx-runtime").JSX.Element;
38
+ Icon: ({ icon, iconType, color, colorLight, colorDark, size, className, iconLibrary, basePath, pageType, overrideColor, overrideSize, }: import("@mintlify/components").IconProps) => import("react/jsx-runtime").JSX.Element | null;
39
+ Info: (props: {
40
+ children: ReactNode;
41
+ className?: string | undefined;
42
+ color?: string | undefined;
43
+ icon?: ReactNode;
44
+ iconType?: ("brands" | "duotone" | "light" | "regular" | "sharp-duotone-solid" | "sharp-light" | "sharp-regular" | "sharp-solid" | "sharp-thin" | "solid" | "thin") | undefined;
45
+ iconLibrary?: ("fontawesome" | "lucide") | undefined;
46
+ ariaLabel?: string | undefined;
47
+ }) => import("react/jsx-runtime").JSX.Element;
48
+ Mermaid: ({ chart, className, ariaLabel, placement, actions, }: import("@mintlify/components").MermaidProps) => import("react/jsx-runtime").JSX.Element;
49
+ Note: (props: {
50
+ children: ReactNode;
51
+ className?: string | undefined;
52
+ color?: string | undefined;
53
+ icon?: ReactNode;
54
+ iconType?: ("brands" | "duotone" | "light" | "regular" | "sharp-duotone-solid" | "sharp-light" | "sharp-regular" | "sharp-solid" | "sharp-thin" | "solid" | "thin") | undefined;
55
+ iconLibrary?: ("fontawesome" | "lucide") | undefined;
56
+ ariaLabel?: string | undefined;
57
+ }) => import("react/jsx-runtime").JSX.Element;
58
+ Panel: ({ children, className, ...props }: import("@mintlify/components").PanelProps) => import("react/jsx-runtime").JSX.Element;
59
+ Property: ({ name, type, location, hidden, default: defaultValue, required, deprecated, children, id, pre, post, className, onMount, navigateToHeaderAriaLabel, defaultLabel, requiredLabel, deprecatedLabel, }: import("@mintlify/components").PropertyProps) => import("react/jsx-runtime").JSX.Element | null;
60
+ Steps: {
61
+ ({ children, titleSize, className }: import("@mintlify/components").StepsProps): import("react/jsx-runtime").JSX.Element;
62
+ Item: ({ stepNumber, icon, iconType, iconLibrary, title, children, titleSize, className, isLast, id, noAnchor, scrollElementIntoView, onRegisterHeading, onUnregisterHeading, _hasContext, onCopyAnchorLink, }: import("@mintlify/components").StepsItemProps) => import("react/jsx-runtime").JSX.Element;
63
+ };
64
+ Tabs: (({ children, defaultTabIndex, onTabChange, className, borderBottom, ariaLabel, panelsRef, }: import("@mintlify/components").TabsProps) => import("react/jsx-runtime").JSX.Element) & {
65
+ Item: ({ children }: import("@mintlify/components").TabsItemProps) => import("react/jsx-runtime").JSX.Element;
66
+ };
67
+ Tile: ({ href, children, title, description, className }: import("@mintlify/components").TileProps) => import("react/jsx-runtime").JSX.Element;
68
+ Tip: (props: {
69
+ children: ReactNode;
70
+ className?: string | undefined;
71
+ color?: string | undefined;
72
+ icon?: ReactNode;
73
+ iconType?: ("brands" | "duotone" | "light" | "regular" | "sharp-duotone-solid" | "sharp-light" | "sharp-regular" | "sharp-solid" | "sharp-thin" | "solid" | "thin") | undefined;
74
+ iconLibrary?: ("fontawesome" | "lucide") | undefined;
75
+ ariaLabel?: string | undefined;
76
+ }) => import("react/jsx-runtime").JSX.Element;
77
+ Tooltip: ({ description, children, title, cta, href, className, side, align, }: import("@mintlify/components").TooltipProps) => import("react/jsx-runtime").JSX.Element | null;
78
+ Tree: (({ className, children }: import("@mintlify/components").TreeProps) => import("react/jsx-runtime").JSX.Element) & {
79
+ File: ({ name }: import("@mintlify/components").TreeFileProps) => import("react/jsx-runtime").JSX.Element;
80
+ Folder: ({ name, defaultOpen, children, openable: _openable, }: import("@mintlify/components").TreeFolderProps) => import("react/jsx-runtime").JSX.Element;
81
+ };
82
+ Update: import("react").ForwardRefExoticComponent<{
83
+ id: string;
84
+ label: string;
85
+ description?: string;
86
+ tags?: string[];
87
+ rss?: {
88
+ title?: string;
89
+ description?: string;
90
+ };
91
+ onRegisterHeading?: (id: string, rect: import("react-use-rect").Rect) => void;
92
+ onUnregisterHeading?: (id: string) => void;
93
+ hasContext?: boolean;
94
+ isVisible: boolean;
95
+ onCopyAnchorLink?: (id: string) => void;
96
+ } & Omit<Omit<import("react").DetailedHTMLProps<import("react").HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "ref">, keyof {
97
+ id: string;
98
+ label: string;
99
+ description?: string;
100
+ tags?: string[];
101
+ rss?: {
102
+ title?: string;
103
+ description?: string;
104
+ };
105
+ onRegisterHeading?: (id: string, rect: import("react-use-rect").Rect) => void;
106
+ onUnregisterHeading?: (id: string) => void;
107
+ hasContext?: boolean;
108
+ isVisible: boolean;
109
+ onCopyAnchorLink?: (id: string) => void;
110
+ }> & import("react").RefAttributes<HTMLDivElement>>;
111
+ Warning: (props: {
112
+ children: ReactNode;
113
+ className?: string | undefined;
114
+ color?: string | undefined;
115
+ icon?: ReactNode;
116
+ iconType?: ("brands" | "duotone" | "light" | "regular" | "sharp-duotone-solid" | "sharp-light" | "sharp-regular" | "sharp-solid" | "sharp-thin" | "solid" | "thin") | undefined;
117
+ iconLibrary?: ("fontawesome" | "lucide") | undefined;
118
+ ariaLabel?: string | undefined;
119
+ }) => import("react/jsx-runtime").JSX.Element;
120
+ };
121
+ export declare function useMDXComponents(): MDXComponents;
@@ -0,0 +1,65 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { Accordion, Badge, Callout, Card, Check, CodeBlock, CodeGroup, Color, Columns, Danger, Expandable, Frame, Icon, Info, Mermaid, Note, Panel, Property, Steps, Tabs, Tile, Tip, Tooltip, Tree, Update, Warning, } from '@mintlify/components';
3
+ const Wrapper = ({ children }) => (_jsx("div", { children: children }));
4
+ const MintlifyComponents = {
5
+ Accordion,
6
+ Badge,
7
+ Callout,
8
+ Card,
9
+ Check,
10
+ CodeBlock,
11
+ CodeGroup,
12
+ Color,
13
+ Columns,
14
+ Danger,
15
+ Expandable,
16
+ Frame,
17
+ Icon,
18
+ Info,
19
+ Mermaid,
20
+ Note,
21
+ Panel,
22
+ Property,
23
+ Steps,
24
+ Tabs,
25
+ Tile,
26
+ Tip,
27
+ Tooltip,
28
+ Tree,
29
+ Update,
30
+ Warning,
31
+ };
32
+ const placeholderComponents = {
33
+ AccordionGroup: Wrapper,
34
+ ApiPlayground: Wrapper,
35
+ CardGroup: Wrapper,
36
+ Column: Wrapper,
37
+ CustomCode: Wrapper,
38
+ CustomComponent: Wrapper,
39
+ DynamicCustomComponent: Wrapper,
40
+ Heading: Wrapper,
41
+ Latex: Wrapper,
42
+ Link: Wrapper,
43
+ Loom: Wrapper,
44
+ MDXContentController: Wrapper,
45
+ Param: Wrapper,
46
+ ParamField: Wrapper,
47
+ PreviewButton: Wrapper,
48
+ RequestExample: Wrapper,
49
+ ResponseExample: Wrapper,
50
+ ResponseField: Wrapper,
51
+ Snippet: Wrapper,
52
+ SnippetGroup: Wrapper,
53
+ View: Wrapper,
54
+ };
55
+ export const components = {
56
+ ...MintlifyComponents,
57
+ ...placeholderComponents,
58
+ };
59
+ export function useMDXComponents() {
60
+ return {
61
+ ...components,
62
+ Step: Steps.Item,
63
+ Tab: Tabs.Item,
64
+ };
65
+ }
@@ -0,0 +1,53 @@
1
+ import { type DocsConfig } from '@mintlify/validation';
2
+ export interface NavPage {
3
+ href: string;
4
+ title: string;
5
+ icon?: string;
6
+ tag?: string;
7
+ api?: string;
8
+ deprecated?: boolean;
9
+ }
10
+ export interface NavGroup {
11
+ group: string;
12
+ pages: NavEntry[];
13
+ icon?: string;
14
+ tag?: string;
15
+ }
16
+ export type NavEntry = NavPage | NavGroup;
17
+ export interface TabInfo {
18
+ name: string;
19
+ href: string;
20
+ isActive: boolean;
21
+ }
22
+ export interface PageContext {
23
+ /** Sidebar entries resolved for the current path */
24
+ sidebar: NavEntry[];
25
+ /** Header tabs with active state, or null if nav has no tabs */
26
+ tabs: TabInfo[] | null;
27
+ /** Group name the current page belongs to (for breadcrumb / eyebrow) */
28
+ group: string | null;
29
+ /** Previous page for footer pagination */
30
+ prev: NavPage | null;
31
+ /** Next page for footer pagination */
32
+ next: NavPage | null;
33
+ }
34
+ /**
35
+ * Build the navigation context a page needs from `docs.json`.
36
+ *
37
+ * ```ts
38
+ * const page = createPageContext(docsConfig, titleMap, currentPath);
39
+ *
40
+ * page.sidebar // NavEntry[]
41
+ * page.tabs // TabInfo[] | null
42
+ * page.group // "Getting started"
43
+ * page.prev // NavPage | null
44
+ * page.next // NavPage | null
45
+ * ```
46
+ *
47
+ * @param docsConfig The parsed docs.json object.
48
+ * @param titleMap A slug→title map, typically built from your content collection.
49
+ * @param currentPath The current page path (e.g. `"/"` or `"/quickstart"`).
50
+ */
51
+ export declare function createPageContext(docsConfig: DocsConfig, titleMap: Record<string, string>, currentPath: string): PageContext;
52
+ export declare function isNavPage(entry: NavEntry): entry is NavPage;
53
+ export declare function isNavGroup(entry: NavEntry): entry is NavGroup;
@@ -0,0 +1,157 @@
1
+ import { posix, sep } from 'node:path';
2
+ import { divisions } from '@mintlify/validation';
3
+ /**
4
+ * Build the navigation context a page needs from `docs.json`.
5
+ *
6
+ * ```ts
7
+ * const page = createPageContext(docsConfig, titleMap, currentPath);
8
+ *
9
+ * page.sidebar // NavEntry[]
10
+ * page.tabs // TabInfo[] | null
11
+ * page.group // "Getting started"
12
+ * page.prev // NavPage | null
13
+ * page.next // NavPage | null
14
+ * ```
15
+ *
16
+ * @param docsConfig The parsed docs.json object.
17
+ * @param titleMap A slug→title map, typically built from your content collection.
18
+ * @param currentPath The current page path (e.g. `"/"` or `"/quickstart"`).
19
+ */
20
+ export function createPageContext(docsConfig, titleMap, currentPath) {
21
+ const normalizedPath = normalizePath(currentPath);
22
+ const decoratedNav = decorateNavNode(docsConfig.navigation, titleMap);
23
+ const sidebar = unwrapNav(decoratedNav, normalizedPath);
24
+ const tabs = extractTabs(decoratedNav, normalizedPath);
25
+ const group = findGroup(sidebar, normalizedPath);
26
+ const { prev, next } = footerPages(sidebar, normalizedPath);
27
+ return { sidebar, tabs, group, prev, next };
28
+ }
29
+ export function isNavPage(entry) {
30
+ return 'href' in entry && 'title' in entry;
31
+ }
32
+ export function isNavGroup(entry) {
33
+ return 'group' in entry && 'pages' in entry;
34
+ }
35
+ function normalizePath(path) {
36
+ const normalized = posix.normalize(path.split(sep).join(posix.sep));
37
+ return normalized !== '/' && normalized.endsWith('/')
38
+ ? normalized.slice(0, -1)
39
+ : normalized;
40
+ }
41
+ function decorateNavNode(nav, titleMap) {
42
+ const result = { ...nav };
43
+ if (Array.isArray(result.pages) && !result.group) {
44
+ result.pages = result.pages.map((p) => decorateEntry(p, titleMap));
45
+ }
46
+ if (Array.isArray(result.groups)) {
47
+ result.groups = result.groups.map((g) => decorateEntry(g, titleMap));
48
+ }
49
+ for (const key of divisions) {
50
+ const division = result[key];
51
+ if (Array.isArray(division)) {
52
+ result[key] = division.map((item) => decorateNavNode(item, titleMap));
53
+ }
54
+ }
55
+ return result;
56
+ }
57
+ function decorateEntry(entry, titleMap) {
58
+ if (typeof entry === 'string') {
59
+ return {
60
+ href: entry === 'index' ? '/' : `/${entry}`,
61
+ title: titleMap[entry] ?? slugToTitle(entry),
62
+ };
63
+ }
64
+ if (typeof entry === 'object' && entry !== null) {
65
+ const node = entry;
66
+ if (node.group != null && Array.isArray(node.pages)) {
67
+ return {
68
+ ...node,
69
+ pages: node.pages.map((page) => decorateEntry(page, titleMap)),
70
+ };
71
+ }
72
+ }
73
+ return entry;
74
+ }
75
+ function slugToTitle(slug) {
76
+ const last = slug.split('/').pop() ?? slug;
77
+ return last
78
+ .split('-')
79
+ .map((w) => w.charAt(0).toUpperCase() + w.slice(1))
80
+ .join(' ');
81
+ }
82
+ function unwrapNav(nav, currentPath) {
83
+ if (Array.isArray(nav.groups))
84
+ return nav.groups;
85
+ if (Array.isArray(nav.pages) && !nav.group)
86
+ return nav.pages;
87
+ for (const key of divisions) {
88
+ const arr = nav[key];
89
+ if (!Array.isArray(arr))
90
+ continue;
91
+ for (const item of arr) {
92
+ const entries = unwrapNav(item, currentPath);
93
+ if (entries.length > 0 && containsPath(entries, currentPath))
94
+ return entries;
95
+ }
96
+ if (arr.length > 0)
97
+ return unwrapNav(arr[0], currentPath);
98
+ }
99
+ return [];
100
+ }
101
+ function containsPath(entries, path) {
102
+ return entries.some((e) => isNavPage(e)
103
+ ? e.href === path
104
+ : isNavGroup(e) && containsPath(e.pages, path));
105
+ }
106
+ function extractTabs(nav, currentPath) {
107
+ if (!Array.isArray(nav.tabs))
108
+ return null;
109
+ return nav.tabs.map((tab) => {
110
+ const entries = unwrapNav(tab, currentPath);
111
+ return {
112
+ name: tab.tab ?? '',
113
+ href: findFirstPage(entries)?.href ?? '/',
114
+ isActive: containsPath(entries, currentPath),
115
+ };
116
+ });
117
+ }
118
+ function findFirstPage(entries) {
119
+ for (const entry of entries) {
120
+ if (isNavPage(entry))
121
+ return entry;
122
+ if (isNavGroup(entry)) {
123
+ const page = findFirstPage(entry.pages);
124
+ if (page)
125
+ return page;
126
+ }
127
+ }
128
+ return undefined;
129
+ }
130
+ function findGroup(entries, path) {
131
+ for (const entry of entries) {
132
+ if (isNavGroup(entry)) {
133
+ for (const page of entry.pages) {
134
+ if (isNavPage(page) && page.href === path)
135
+ return entry.group;
136
+ if (isNavGroup(page)) {
137
+ const nested = findGroup([page], path);
138
+ if (nested)
139
+ return nested;
140
+ }
141
+ }
142
+ }
143
+ }
144
+ return null;
145
+ }
146
+ function footerPages(entries, currentPath) {
147
+ const flat = (function flatten(e) {
148
+ return e.flatMap((x) => (isNavGroup(x) ? flatten(x.pages) : [x]));
149
+ })(entries);
150
+ const idx = flat.findIndex((p) => p.href === currentPath);
151
+ if (idx === -1)
152
+ return { prev: null, next: null };
153
+ return {
154
+ prev: idx > 0 ? flat[idx - 1] : null,
155
+ next: idx < flat.length - 1 ? flat[idx + 1] : null,
156
+ };
157
+ }
@@ -12,7 +12,7 @@ export declare const components: {
12
12
  className?: string | undefined;
13
13
  color?: string | undefined;
14
14
  icon?: ReactNode;
15
- iconType?: ("brands" | "duotone" | "light" | "regular" | "sharp-duotone-solid" | "sharp-light" | "sharp-regular" | "sharp-solid" | "sharp-thin" | "solid" | "thin") | undefined;
15
+ iconType?: ("light" | "brands" | "duotone" | "regular" | "sharp-duotone-solid" | "sharp-light" | "sharp-regular" | "sharp-solid" | "sharp-thin" | "solid" | "thin") | undefined;
16
16
  iconLibrary?: ("fontawesome" | "lucide") | undefined;
17
17
  ariaLabel?: string | undefined;
18
18
  }) => import("react/jsx-runtime").JSX.Element;
@@ -29,7 +29,7 @@ export declare const components: {
29
29
  className?: string | undefined;
30
30
  color?: string | undefined;
31
31
  icon?: ReactNode;
32
- iconType?: ("brands" | "duotone" | "light" | "regular" | "sharp-duotone-solid" | "sharp-light" | "sharp-regular" | "sharp-solid" | "sharp-thin" | "solid" | "thin") | undefined;
32
+ iconType?: ("light" | "brands" | "duotone" | "regular" | "sharp-duotone-solid" | "sharp-light" | "sharp-regular" | "sharp-solid" | "sharp-thin" | "solid" | "thin") | undefined;
33
33
  iconLibrary?: ("fontawesome" | "lucide") | undefined;
34
34
  ariaLabel?: string | undefined;
35
35
  }) => import("react/jsx-runtime").JSX.Element;
@@ -41,7 +41,7 @@ export declare const components: {
41
41
  className?: string | undefined;
42
42
  color?: string | undefined;
43
43
  icon?: ReactNode;
44
- iconType?: ("brands" | "duotone" | "light" | "regular" | "sharp-duotone-solid" | "sharp-light" | "sharp-regular" | "sharp-solid" | "sharp-thin" | "solid" | "thin") | undefined;
44
+ iconType?: ("light" | "brands" | "duotone" | "regular" | "sharp-duotone-solid" | "sharp-light" | "sharp-regular" | "sharp-solid" | "sharp-thin" | "solid" | "thin") | undefined;
45
45
  iconLibrary?: ("fontawesome" | "lucide") | undefined;
46
46
  ariaLabel?: string | undefined;
47
47
  }) => import("react/jsx-runtime").JSX.Element;
@@ -51,7 +51,7 @@ export declare const components: {
51
51
  className?: string | undefined;
52
52
  color?: string | undefined;
53
53
  icon?: ReactNode;
54
- iconType?: ("brands" | "duotone" | "light" | "regular" | "sharp-duotone-solid" | "sharp-light" | "sharp-regular" | "sharp-solid" | "sharp-thin" | "solid" | "thin") | undefined;
54
+ iconType?: ("light" | "brands" | "duotone" | "regular" | "sharp-duotone-solid" | "sharp-light" | "sharp-regular" | "sharp-solid" | "sharp-thin" | "solid" | "thin") | undefined;
55
55
  iconLibrary?: ("fontawesome" | "lucide") | undefined;
56
56
  ariaLabel?: string | undefined;
57
57
  }) => import("react/jsx-runtime").JSX.Element;
@@ -70,7 +70,7 @@ export declare const components: {
70
70
  className?: string | undefined;
71
71
  color?: string | undefined;
72
72
  icon?: ReactNode;
73
- iconType?: ("brands" | "duotone" | "light" | "regular" | "sharp-duotone-solid" | "sharp-light" | "sharp-regular" | "sharp-solid" | "sharp-thin" | "solid" | "thin") | undefined;
73
+ iconType?: ("light" | "brands" | "duotone" | "regular" | "sharp-duotone-solid" | "sharp-light" | "sharp-regular" | "sharp-solid" | "sharp-thin" | "solid" | "thin") | undefined;
74
74
  iconLibrary?: ("fontawesome" | "lucide") | undefined;
75
75
  ariaLabel?: string | undefined;
76
76
  }) => import("react/jsx-runtime").JSX.Element;
@@ -113,7 +113,7 @@ export declare const components: {
113
113
  className?: string | undefined;
114
114
  color?: string | undefined;
115
115
  icon?: ReactNode;
116
- iconType?: ("brands" | "duotone" | "light" | "regular" | "sharp-duotone-solid" | "sharp-light" | "sharp-regular" | "sharp-solid" | "sharp-thin" | "solid" | "thin") | undefined;
116
+ iconType?: ("light" | "brands" | "duotone" | "regular" | "sharp-duotone-solid" | "sharp-light" | "sharp-regular" | "sharp-solid" | "sharp-thin" | "solid" | "thin") | undefined;
117
117
  iconLibrary?: ("fontawesome" | "lucide") | undefined;
118
118
  ariaLabel?: string | undefined;
119
119
  }) => import("react/jsx-runtime").JSX.Element;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mintlify/astro",
3
- "version": "0.1.4",
3
+ "version": "0.1.5",
4
4
  "description": "Mintlify integration for Astro",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",
@@ -17,6 +17,10 @@
17
17
  "./components": {
18
18
  "types": "./dist/components.d.ts",
19
19
  "import": "./dist/components.js"
20
+ },
21
+ "./helpers": {
22
+ "types": "./dist/helpers.d.ts",
23
+ "import": "./dist/helpers.js"
20
24
  }
21
25
  },
22
26
  "scripts": {