@x-wave/blog 2.2.8 → 2.3.1
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/AdvancedModeToggle/index.d.ts +5 -0
- package/components/ArticleNavigation/index.d.ts +8 -0
- package/components/BlogRoot/index.d.ts +10 -0
- package/components/BlogSidebar/index.d.ts +1 -0
- package/components/Breadcrumb/index.d.ts +5 -0
- package/components/ContentPage/index.d.ts +6 -0
- package/components/DocumentationLayout/index.d.ts +6 -0
- package/components/DocumentationRoutes/index.d.ts +24 -0
- package/components/Header/index.d.ts +5 -0
- package/components/HomePage/index.d.ts +8 -0
- package/components/Metadata/index.d.ts +5 -0
- package/components/MobileMenu/index.d.ts +6 -0
- package/components/NavigationContent/index.d.ts +17 -0
- package/components/SearchBar/index.d.ts +5 -0
- package/components/Sidebar/index.d.ts +1 -0
- package/components/TableOfContents/index.d.ts +6 -0
- package/components/TagResultsModal/index.d.ts +12 -0
- package/components/Tags/index.d.ts +7 -0
- package/context.d.ts +194 -0
- package/hooks.d.ts +26 -0
- package/index.d.ts +28 -0
- package/loaders.d.ts +92 -0
- package/package.json +3 -4
- package/theme.d.ts +20 -0
- package/utils/links.d.ts +41 -0
- package/utils.d.ts +31 -0
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export interface ArticleNavigationProps {
|
|
2
|
+
prevSlug?: string;
|
|
3
|
+
prevTitle?: string;
|
|
4
|
+
nextSlug?: string;
|
|
5
|
+
nextTitle?: string;
|
|
6
|
+
language: string;
|
|
7
|
+
}
|
|
8
|
+
export declare function ArticleNavigation({ prevSlug, prevTitle, nextSlug, nextTitle, language, }: ArticleNavigationProps): import("react/jsx-runtime").JSX.Element | null;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { ReactNode } from 'react';
|
|
2
|
+
interface BlogRootProps {
|
|
3
|
+
children: ReactNode;
|
|
4
|
+
}
|
|
5
|
+
/**
|
|
6
|
+
* BlogRoot component marks the entry point of the blog framework in the DOM.
|
|
7
|
+
* All blog-specific styles and functionality are scoped within this element.
|
|
8
|
+
*/
|
|
9
|
+
export declare function BlogRoot({ children }: BlogRootProps): import("react/jsx-runtime").JSX.Element;
|
|
10
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function BlogSidebar(): import("react/jsx-runtime").JSX.Element | null;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pre-configured Routes component for documentation pages.
|
|
3
|
+
* Use this inside your router to handle language-specific documentation routing.
|
|
4
|
+
*
|
|
5
|
+
* @example
|
|
6
|
+
* ```tsx
|
|
7
|
+
* import { BlogProvider, DocumentationRoutes } from '@x-wave/blog'
|
|
8
|
+
* import { BrowserRouter, Routes, Route, Navigate } from 'react-router-dom'
|
|
9
|
+
*
|
|
10
|
+
* function App() {
|
|
11
|
+
* return (
|
|
12
|
+
* <BlogProvider config={config} blog={blog}>
|
|
13
|
+
* <BrowserRouter>
|
|
14
|
+
* <Routes>
|
|
15
|
+
* <Route path="/:language/*" element={<DocumentationRoutes />} />
|
|
16
|
+
* <Route path="/" element={<Navigate to="/en/welcome" replace />} />
|
|
17
|
+
* </Routes>
|
|
18
|
+
* </BrowserRouter>
|
|
19
|
+
* </BlogProvider>
|
|
20
|
+
* )
|
|
21
|
+
* }
|
|
22
|
+
* ```
|
|
23
|
+
*/
|
|
24
|
+
export declare function DocumentationRoutes(): import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
interface LanguageSelectorProps {
|
|
2
|
+
styles: Record<string, string>;
|
|
3
|
+
onLanguageChange?: () => void;
|
|
4
|
+
}
|
|
5
|
+
export declare function LanguageSelector({ styles, onLanguageChange, }: LanguageSelectorProps): import("react/jsx-runtime").JSX.Element;
|
|
6
|
+
interface NavigationMenuProps {
|
|
7
|
+
styles: Record<string, string>;
|
|
8
|
+
onLinkClick?: () => void;
|
|
9
|
+
}
|
|
10
|
+
export declare function NavigationMenu({ styles, onLinkClick }: NavigationMenuProps): import("react/jsx-runtime").JSX.Element;
|
|
11
|
+
interface NavigationContentProps {
|
|
12
|
+
styles: Record<string, string>;
|
|
13
|
+
onLinkClick?: () => void;
|
|
14
|
+
onLanguageChange?: () => void;
|
|
15
|
+
}
|
|
16
|
+
export declare function NavigationContent({ styles, onLinkClick, onLanguageChange, }: NavigationContentProps): import("react/jsx-runtime").JSX.Element;
|
|
17
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function Sidebar(): import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
interface TagResult {
|
|
2
|
+
title: string;
|
|
3
|
+
slug: string;
|
|
4
|
+
}
|
|
5
|
+
interface TagResultsModalProps {
|
|
6
|
+
tag: string;
|
|
7
|
+
results: TagResult[];
|
|
8
|
+
language: string;
|
|
9
|
+
onClose: () => void;
|
|
10
|
+
}
|
|
11
|
+
export declare function TagResultsModal({ tag, results, language, onClose, }: TagResultsModalProps): import('react').ReactPortal;
|
|
12
|
+
export {};
|
package/context.d.ts
ADDED
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
import { ReactNode } from 'react';
|
|
2
|
+
import { LoadedContent, NavigationEntry } from 'types';
|
|
3
|
+
/**
|
|
4
|
+
* Configuration for the blog framework, provided once via `BlogProvider`
|
|
5
|
+
* and accessible throughout the component tree via `useBlogConfig()`.
|
|
6
|
+
*/
|
|
7
|
+
export interface BlogConfig {
|
|
8
|
+
/** The blog/docs site title displayed in the sidebar and mobile menu. */
|
|
9
|
+
title: string;
|
|
10
|
+
/**
|
|
11
|
+
* Optional default description for SEO meta tags.
|
|
12
|
+
* Used as fallback description for articles that don't have their own description.
|
|
13
|
+
*/
|
|
14
|
+
description?: string;
|
|
15
|
+
/**
|
|
16
|
+
* An optional SVG React component used as the site logo.
|
|
17
|
+
* Receives a `className` prop for styling.
|
|
18
|
+
* Example: `import CloudSvg from './cloud.svg?react'`
|
|
19
|
+
*/
|
|
20
|
+
logo?: React.ComponentType<{
|
|
21
|
+
className?: string;
|
|
22
|
+
}>;
|
|
23
|
+
/**
|
|
24
|
+
* The list of supported locale codes (e.g. `['en', 'zh', 'es']`).
|
|
25
|
+
* These are used for language validation in routing and the language switcher.
|
|
26
|
+
*/
|
|
27
|
+
supportedLanguages: readonly string[];
|
|
28
|
+
/**
|
|
29
|
+
* Optional base path for all documentation routes.
|
|
30
|
+
* Use this when mounting documentation under a subpath (e.g., '/blog' or '/docs').
|
|
31
|
+
* Default: '' (root path)
|
|
32
|
+
* Example: basePath: '/blog' → routes become /blog/en/welcome
|
|
33
|
+
*/
|
|
34
|
+
basePath?: string;
|
|
35
|
+
/**
|
|
36
|
+
* Optional maximum width for the content area.
|
|
37
|
+
* Default: '80rem'
|
|
38
|
+
* Example: contentMaxWidth: '100rem' or contentMaxWidth: '1400px'
|
|
39
|
+
*/
|
|
40
|
+
contentMaxWidth?: string;
|
|
41
|
+
/**
|
|
42
|
+
* The default route displayed at the root path (/).
|
|
43
|
+
* Use 'latest' to show the home page listing latest articles.
|
|
44
|
+
* Use any slug (e.g., 'welcome', 'getting-started') to display that article.
|
|
45
|
+
* Default: 'latest'
|
|
46
|
+
* Example: defaultRoute: 'welcome' or defaultRoute: 'latest'
|
|
47
|
+
*/
|
|
48
|
+
defaultRoute?: string;
|
|
49
|
+
/**
|
|
50
|
+
* Whether to display the sidebar navigation menu.
|
|
51
|
+
* Default: true
|
|
52
|
+
* Note: This is independent of navigationData. You can have navigationData without showing a sidebar,
|
|
53
|
+
* or show a sidebar with empty navigationData.
|
|
54
|
+
*/
|
|
55
|
+
showSideMenu?: boolean;
|
|
56
|
+
/**
|
|
57
|
+
* Whether to display next/previous article navigation at the bottom of content pages.
|
|
58
|
+
* Useful for guiding readers through sequential content.
|
|
59
|
+
* Default: false
|
|
60
|
+
*/
|
|
61
|
+
showArticleNavigation?: boolean;
|
|
62
|
+
/**
|
|
63
|
+
* Optional default theme for the blog.
|
|
64
|
+
* If set, this will override the user's localStorage preference and system theme.
|
|
65
|
+
* Use this to ensure the blog matches your consuming app's theme.
|
|
66
|
+
* Options: 'light' | 'dark' | 'system' (default: uses localStorage or 'system')
|
|
67
|
+
*/
|
|
68
|
+
defaultTheme?: 'light' | 'dark' | 'system';
|
|
69
|
+
/**
|
|
70
|
+
* Optional header configuration.
|
|
71
|
+
* If omitted entirely, the built-in header component will not be rendered.
|
|
72
|
+
* Use the exported `useTheme()` and `useSearchModal()` hooks to build custom headers.
|
|
73
|
+
*/
|
|
74
|
+
header?: {
|
|
75
|
+
/**
|
|
76
|
+
* Custom navigation links displayed in the header.
|
|
77
|
+
* Example: "Launch App" button or external links.
|
|
78
|
+
*/
|
|
79
|
+
navLinks?: HeaderLink[];
|
|
80
|
+
/**
|
|
81
|
+
* Custom dropdown menu items.
|
|
82
|
+
* If provided, displays a "Support" dropdown with these items.
|
|
83
|
+
*/
|
|
84
|
+
dropdownItems?: HeaderDropdownItem[];
|
|
85
|
+
};
|
|
86
|
+
/**
|
|
87
|
+
* Optional social links displayed in the blog sidebar.
|
|
88
|
+
* These links appear in the "Connect" section on the home page.
|
|
89
|
+
* Example: Discord, GitHub, Email, etc.
|
|
90
|
+
*/
|
|
91
|
+
socialLinks?: HeaderLink[];
|
|
92
|
+
/**
|
|
93
|
+
* Optional React node to render after article content as a Call-to-Action.
|
|
94
|
+
* Appears after the main content but before tags and article navigation.
|
|
95
|
+
* Example: Newsletter signup, related links, promotional content.
|
|
96
|
+
*/
|
|
97
|
+
articleCTA?: React.ReactNode;
|
|
98
|
+
/**
|
|
99
|
+
* Optional custom font CSS property for article titles.
|
|
100
|
+
* Applied to h1 blog titles on ContentPage and title on HomePage.
|
|
101
|
+
* Example: 'Roboto, sans-serif' or '"Segoe UI", sans-serif'
|
|
102
|
+
*/
|
|
103
|
+
articleTitleFont?: string;
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* A navigation link in the header.
|
|
107
|
+
*/
|
|
108
|
+
export interface HeaderLink {
|
|
109
|
+
/** Link text. Can be a string, i18n key, or React element. */
|
|
110
|
+
label: string | React.ReactNode;
|
|
111
|
+
/** Link URL (supports mailto: and other protocols). */
|
|
112
|
+
url: string;
|
|
113
|
+
/** Optional icon component (receives `className` prop for styling). */
|
|
114
|
+
icon?: React.ComponentType<{
|
|
115
|
+
className?: string;
|
|
116
|
+
}>;
|
|
117
|
+
/** Whether to open in new tab. Defaults to `true` for external URLs. */
|
|
118
|
+
target?: '_blank' | '_self';
|
|
119
|
+
/** rel attribute (e.g. 'noopener noreferrer'). Auto-set if target is '_blank'. */
|
|
120
|
+
rel?: string;
|
|
121
|
+
/** Optional CSS class name for custom styling. */
|
|
122
|
+
className?: string;
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* A dropdown menu item in the header support dropdown.
|
|
126
|
+
*/
|
|
127
|
+
export interface HeaderDropdownItem {
|
|
128
|
+
/** Item text. Can be a string, i18n key, or React element. */
|
|
129
|
+
label: string | React.ReactNode;
|
|
130
|
+
/** Item URL (supports mailto: and other protocols). */
|
|
131
|
+
url: string;
|
|
132
|
+
/** Optional icon component (receives `className` prop for styling). */
|
|
133
|
+
icon?: React.ComponentType<{
|
|
134
|
+
className?: string;
|
|
135
|
+
}>;
|
|
136
|
+
/** Whether to open in new tab. Defaults to `true` for external URLs. */
|
|
137
|
+
target?: '_blank' | '_self';
|
|
138
|
+
/** rel attribute (e.g. 'noopener noreferrer'). Auto-set if target is '_blank'. */
|
|
139
|
+
rel?: string;
|
|
140
|
+
}
|
|
141
|
+
export interface BlogContextValue {
|
|
142
|
+
config: BlogConfig & {
|
|
143
|
+
/** Dynamically built tag index from MDX frontmatter, per language */
|
|
144
|
+
tagIndex?: Record<string, Record<string, Array<{
|
|
145
|
+
slug: string;
|
|
146
|
+
title: string;
|
|
147
|
+
}>>>;
|
|
148
|
+
/** Optional navigation data passed to BlogProvider */
|
|
149
|
+
navigationData?: NavigationEntry[];
|
|
150
|
+
};
|
|
151
|
+
loadContent: (language: string, slug: string, advanced?: boolean) => Promise<LoadedContent>;
|
|
152
|
+
loadEnglishContent: (slug: string, advanced?: boolean) => Promise<string>;
|
|
153
|
+
discoverArticles: (language: string) => Promise<Array<{
|
|
154
|
+
slug: string;
|
|
155
|
+
title: string;
|
|
156
|
+
date?: string;
|
|
157
|
+
author?: string;
|
|
158
|
+
description?: string;
|
|
159
|
+
}>>;
|
|
160
|
+
}
|
|
161
|
+
/**
|
|
162
|
+
* Blog utilities object returned from createBlogUtils().
|
|
163
|
+
* Contains MDX files glob and content loaders.
|
|
164
|
+
*/
|
|
165
|
+
export interface BlogUtils {
|
|
166
|
+
mdxFiles: Record<string, () => Promise<unknown>>;
|
|
167
|
+
loadContent: (language: string, slug: string, advanced?: boolean) => Promise<LoadedContent>;
|
|
168
|
+
loadEnglishContent: (slug: string, advanced?: boolean) => Promise<string>;
|
|
169
|
+
discoverArticles: (language: string) => Promise<Array<{
|
|
170
|
+
slug: string;
|
|
171
|
+
title: string;
|
|
172
|
+
date?: string;
|
|
173
|
+
author?: string;
|
|
174
|
+
description?: string;
|
|
175
|
+
}>>;
|
|
176
|
+
}
|
|
177
|
+
export interface BlogProviderProps {
|
|
178
|
+
children: ReactNode;
|
|
179
|
+
config: BlogConfig;
|
|
180
|
+
/**
|
|
181
|
+
* Blog utilities object returned from createBlogUtils().
|
|
182
|
+
* Contains MDX files and content loaders.
|
|
183
|
+
*/
|
|
184
|
+
blog: BlogUtils;
|
|
185
|
+
/**
|
|
186
|
+
* Optional navigation structure for the docs sidebar.
|
|
187
|
+
* If omitted, the sidebar will not be rendered.
|
|
188
|
+
* Entries may be individual items or grouped sections.
|
|
189
|
+
* Titles should be i18n keys resolved at runtime.
|
|
190
|
+
*/
|
|
191
|
+
navigationData?: NavigationEntry[];
|
|
192
|
+
}
|
|
193
|
+
export declare function BlogProvider({ children, config, blog, navigationData, }: BlogProviderProps): import("react/jsx-runtime").JSX.Element;
|
|
194
|
+
export declare function useBlogConfig(): BlogContextValue;
|
package/hooks.d.ts
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Hooks and utilities for custom header implementations.
|
|
3
|
+
* These are the same functions used by the built-in Header component.
|
|
4
|
+
*/
|
|
5
|
+
export type { Theme } from './theme';
|
|
6
|
+
export { useTheme } from './theme';
|
|
7
|
+
/**
|
|
8
|
+
* Hook to control the search modal.
|
|
9
|
+
* Returns functions to open/close the search modal programmatically.
|
|
10
|
+
*/
|
|
11
|
+
export declare function useSearchModal(): {
|
|
12
|
+
openSearchModal: () => void;
|
|
13
|
+
closeSearchModal: () => void;
|
|
14
|
+
};
|
|
15
|
+
/**
|
|
16
|
+
* Hook to change the language.
|
|
17
|
+
* Returns a function that changes the i18n language and navigates to the corresponding route.
|
|
18
|
+
* Preserves search params and hash, and handles basePath correctly.
|
|
19
|
+
*
|
|
20
|
+
* @example
|
|
21
|
+
* ```tsx
|
|
22
|
+
* const changeLanguage = useLanguageChange()
|
|
23
|
+
* <button onClick={() => changeLanguage('es')}>Español</button>
|
|
24
|
+
* ```
|
|
25
|
+
*/
|
|
26
|
+
export declare function useLanguageChange(): (newLanguage: string) => void;
|
package/index.d.ts
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
export { AdvancedModeToggle } from './components/AdvancedModeToggle';
|
|
2
|
+
export type { ArticleNavigationProps } from './components/ArticleNavigation';
|
|
3
|
+
export { ArticleNavigation } from './components/ArticleNavigation';
|
|
4
|
+
export { BlogRoot } from './components/BlogRoot';
|
|
5
|
+
export { BlogSidebar } from './components/BlogSidebar';
|
|
6
|
+
export type { BreadcrumbProps } from './components/Breadcrumb';
|
|
7
|
+
export { Breadcrumb } from './components/Breadcrumb';
|
|
8
|
+
export { ContentPage } from './components/ContentPage';
|
|
9
|
+
export { DocumentationLayout } from './components/DocumentationLayout';
|
|
10
|
+
export { DocumentationRoutes } from './components/DocumentationRoutes';
|
|
11
|
+
export { Header } from './components/Header';
|
|
12
|
+
export { HomePage } from './components/HomePage';
|
|
13
|
+
export type { MetadataProps } from './components/Metadata';
|
|
14
|
+
export { Metadata } from './components/Metadata';
|
|
15
|
+
export { MobileMenu } from './components/MobileMenu';
|
|
16
|
+
export { LanguageSelector, NavigationContent, NavigationMenu, } from './components/NavigationContent';
|
|
17
|
+
export { SearchBar } from './components/SearchBar';
|
|
18
|
+
export { Sidebar } from './components/Sidebar';
|
|
19
|
+
export { TableOfContents } from './components/TableOfContents';
|
|
20
|
+
export { TagResultsModal } from './components/TagResultsModal';
|
|
21
|
+
export { Tags } from './components/Tags';
|
|
22
|
+
export type { BlogConfig, BlogContextValue, BlogProviderProps, BlogUtils, HeaderDropdownItem, HeaderLink, } from './context';
|
|
23
|
+
export { BlogProvider, useBlogConfig } from './context';
|
|
24
|
+
export type { Theme } from './hooks';
|
|
25
|
+
export { useLanguageChange, useSearchModal, useTheme } from './hooks';
|
|
26
|
+
export { createBlogUtils, createContentLoaders } from './loaders';
|
|
27
|
+
export { ThemeProvider } from './theme';
|
|
28
|
+
export { generateHeadingId, getAdjacentArticles, getNavigationData, } from './utils';
|
package/loaders.d.ts
ADDED
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import { LoadedContent } from 'types';
|
|
2
|
+
/**
|
|
3
|
+
* Factory function to create content loader functions from a Vite glob import.
|
|
4
|
+
*
|
|
5
|
+
* The app must handle the `import.meta.glob` call because Vite resolves glob patterns
|
|
6
|
+
* relative to the file that calls them. This function handles all the generic logic:
|
|
7
|
+
* frontmatter parsing and content loading.
|
|
8
|
+
*
|
|
9
|
+
* @param mdxFiles - Object returned from `import.meta.glob('./docs/**\/*.mdx', { ... })`
|
|
10
|
+
* @returns Object with `loadMDXContent` and `loadEnglishContent` functions
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* ```ts
|
|
14
|
+
* const mdxFiles = import.meta.glob('./docs/**\/*.mdx', {
|
|
15
|
+
* query: '?raw',
|
|
16
|
+
* import: 'default',
|
|
17
|
+
* eager: false,
|
|
18
|
+
* })
|
|
19
|
+
*
|
|
20
|
+
* export const { loadMDXContent, loadEnglishContent } = createContentLoaders(mdxFiles)
|
|
21
|
+
* ```
|
|
22
|
+
*/
|
|
23
|
+
export declare function createContentLoaders(mdxFiles: Record<string, () => Promise<unknown>>): {
|
|
24
|
+
/**
|
|
25
|
+
* Load MDX content for a given language and slug.
|
|
26
|
+
* Automatically loads the advanced variant if `advanced` is true.
|
|
27
|
+
*/
|
|
28
|
+
loadMDXContent(language: string, slug: string, advanced?: boolean): Promise<LoadedContent>;
|
|
29
|
+
/**
|
|
30
|
+
* Load English content for generating consistent heading IDs.
|
|
31
|
+
* All heading anchors are derived from English content for stability across translations.
|
|
32
|
+
*/
|
|
33
|
+
loadEnglishContent(slug: string, advanced?: boolean): Promise<string>;
|
|
34
|
+
/**
|
|
35
|
+
* Build a tag index from all MDX files.
|
|
36
|
+
* Uses shared metadata cache to avoid duplicate file processing.
|
|
37
|
+
*
|
|
38
|
+
* @param language - Language code to scan (defaults to 'en')
|
|
39
|
+
* @returns Promise resolving to tag index mapping tag names to document info
|
|
40
|
+
*/
|
|
41
|
+
buildTagIndex(language?: string): Promise<Record<string, Array<{
|
|
42
|
+
slug: string;
|
|
43
|
+
title: string;
|
|
44
|
+
}>>>;
|
|
45
|
+
/**
|
|
46
|
+
* Discover all articles from the file system by scanning MDX files.
|
|
47
|
+
* Uses shared metadata cache to avoid duplicate file processing with buildTagIndex.
|
|
48
|
+
*
|
|
49
|
+
* @param language - Language code to scan
|
|
50
|
+
* @returns Promise resolving to array of articles with metadata, sorted by date (newest first) then title
|
|
51
|
+
*/
|
|
52
|
+
discoverArticles(language: string): Promise<Array<{
|
|
53
|
+
slug: string;
|
|
54
|
+
title: string;
|
|
55
|
+
date?: string;
|
|
56
|
+
author?: string;
|
|
57
|
+
description?: string;
|
|
58
|
+
}>>;
|
|
59
|
+
};
|
|
60
|
+
/**
|
|
61
|
+
* Convenience function to create all blog utilities from a Vite glob import.
|
|
62
|
+
* This bundles mdxFiles, content loaders, and tag indexing into a single export.
|
|
63
|
+
*
|
|
64
|
+
* @param mdxFiles - Object returned from `import.meta.glob('./docs/**\/*.mdx', { ... })`
|
|
65
|
+
* @returns Object with mdxFiles, loadContent, loadEnglishContent, and discoverArticles
|
|
66
|
+
*
|
|
67
|
+
* @example
|
|
68
|
+
* ```ts
|
|
69
|
+
* const mdxFiles = import.meta.glob('./docs/**\/*.mdx', {
|
|
70
|
+
* query: '?raw',
|
|
71
|
+
* import: 'default',
|
|
72
|
+
* eager: false,
|
|
73
|
+
* })
|
|
74
|
+
*
|
|
75
|
+
* export const blog = createBlogUtils(mdxFiles)
|
|
76
|
+
*
|
|
77
|
+
* // In App.tsx:
|
|
78
|
+
* <BlogProvider config={config} blog={blog} />
|
|
79
|
+
* ```
|
|
80
|
+
*/
|
|
81
|
+
export declare function createBlogUtils(mdxFiles: Record<string, () => Promise<unknown>>): {
|
|
82
|
+
mdxFiles: Record<string, () => Promise<unknown>>;
|
|
83
|
+
loadContent: (language: string, slug: string, advanced?: boolean) => Promise<LoadedContent>;
|
|
84
|
+
loadEnglishContent: (slug: string, advanced?: boolean) => Promise<string>;
|
|
85
|
+
discoverArticles: (language: string) => Promise<Array<{
|
|
86
|
+
slug: string;
|
|
87
|
+
title: string;
|
|
88
|
+
date?: string;
|
|
89
|
+
author?: string;
|
|
90
|
+
description?: string;
|
|
91
|
+
}>>;
|
|
92
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@x-wave/blog",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.3.1",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"exports": {
|
|
6
6
|
".": {
|
|
@@ -37,9 +37,7 @@
|
|
|
37
37
|
"@phosphor-icons/react": "^2.1.7",
|
|
38
38
|
"i18next": "^25.8.8",
|
|
39
39
|
"react-markdown": "^10.1.0",
|
|
40
|
-
"remark-gfm": "^4.0.1"
|
|
41
|
-
"styles": "workspace:*",
|
|
42
|
-
"types": "workspace:*"
|
|
40
|
+
"remark-gfm": "^4.0.1"
|
|
43
41
|
},
|
|
44
42
|
"peerDependencies": {
|
|
45
43
|
"react": "^19.0.0",
|
|
@@ -51,6 +49,7 @@
|
|
|
51
49
|
"@vitejs/plugin-react-swc": "^3.10.1",
|
|
52
50
|
"sass": "^1.97.3",
|
|
53
51
|
"vite": "^6.3.5",
|
|
52
|
+
"vite-plugin-dts": "^4.5.4",
|
|
54
53
|
"vite-tsconfig-paths": "^5.1.4"
|
|
55
54
|
}
|
|
56
55
|
}
|
package/theme.d.ts
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { ReactNode } from 'react';
|
|
2
|
+
/**
|
|
3
|
+
* Theme preference options:
|
|
4
|
+
* - `'light'` - always use light theme
|
|
5
|
+
* - `'dark'` - always use dark theme
|
|
6
|
+
* - `'system'` - automatically follow the OS/browser preference
|
|
7
|
+
*/
|
|
8
|
+
export type Theme = 'light' | 'dark' | 'system';
|
|
9
|
+
interface ThemeContextValue {
|
|
10
|
+
theme: Theme;
|
|
11
|
+
setTheme: (theme: Theme) => void;
|
|
12
|
+
effectiveTheme: 'light' | 'dark';
|
|
13
|
+
}
|
|
14
|
+
interface ThemeProviderProps {
|
|
15
|
+
children: ReactNode;
|
|
16
|
+
defaultTheme?: Theme;
|
|
17
|
+
}
|
|
18
|
+
export declare function ThemeProvider({ children, defaultTheme }: ThemeProviderProps): import("react/jsx-runtime").JSX.Element;
|
|
19
|
+
export declare const useTheme: () => ThemeContextValue;
|
|
20
|
+
export {};
|
package/utils/links.d.ts
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* URL and link manipulation utilities for the blog framework
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* Build an internal link with language prefix and optional basePath
|
|
6
|
+
*
|
|
7
|
+
* @param path - The relative path (e.g., 'welcome', 'glossary')
|
|
8
|
+
* @param language - The language code (e.g., 'en', 'es', 'zh')
|
|
9
|
+
* @param basePath - Optional base path prefix
|
|
10
|
+
* @returns The formatted link URL
|
|
11
|
+
*/
|
|
12
|
+
export declare function buildInternalLink(path: string, language: string, basePath?: string): string;
|
|
13
|
+
/**
|
|
14
|
+
* Parse search/query parameters from a URL search string
|
|
15
|
+
*
|
|
16
|
+
* @param search - The search string (with or without leading ?)
|
|
17
|
+
* @returns Object with parsed advanced mode and anchor parameters
|
|
18
|
+
*/
|
|
19
|
+
export declare function parseSearchParams(search: string): {
|
|
20
|
+
advanced: boolean;
|
|
21
|
+
anchor: string;
|
|
22
|
+
};
|
|
23
|
+
/**
|
|
24
|
+
* Smooth scroll to an element by ID
|
|
25
|
+
*
|
|
26
|
+
* @param id - The element ID to scroll to
|
|
27
|
+
* @param headerOffset - Vertical offset to account for sticky header (default: 80px)
|
|
28
|
+
*/
|
|
29
|
+
export declare function scrollToElement(id: string, headerOffset?: number): void;
|
|
30
|
+
/**
|
|
31
|
+
* Update the current URL with an anchor parameter and optional advanced mode flag
|
|
32
|
+
*
|
|
33
|
+
* @param anchorId - The anchor ID to link to
|
|
34
|
+
* @param isAdvancedMode - Whether advanced mode is enabled (default: false)
|
|
35
|
+
*/
|
|
36
|
+
export declare function updateUrlWithAnchor(anchorId: string, isAdvancedMode?: boolean): void;
|
|
37
|
+
/**
|
|
38
|
+
* Scroll to the top of the window
|
|
39
|
+
* @param behavior - Scroll behavior: 'smooth' for animated scroll, 'auto' for instant
|
|
40
|
+
*/
|
|
41
|
+
export declare function scrollToTop(behavior?: 'smooth' | 'auto'): void;
|
package/utils.d.ts
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { LoadedContent, NavigationEntry, NavigationEntryWithTitles, NavigationSection } from 'types';
|
|
2
|
+
export type { Theme } from './theme';
|
|
3
|
+
export { ThemeProvider, useTheme } from './theme';
|
|
4
|
+
export declare const isNavigationSection: (entry: NavigationEntry) => entry is NavigationSection;
|
|
5
|
+
export declare const isNavigationSectionWithTitles: (entry: NavigationEntryWithTitles) => entry is {
|
|
6
|
+
title: string;
|
|
7
|
+
items: Array<{
|
|
8
|
+
title: string;
|
|
9
|
+
slug: string;
|
|
10
|
+
}>;
|
|
11
|
+
};
|
|
12
|
+
export declare const getNavigationData: (navigationData: NavigationEntry[], language: string, loadContent: (language: string, slug: string, advanced?: boolean) => Promise<LoadedContent>) => Promise<NavigationEntryWithTitles[]>;
|
|
13
|
+
export declare const generateHeadingId: (text: string) => string;
|
|
14
|
+
/**
|
|
15
|
+
* Get the next and previous article based on chronological order.
|
|
16
|
+
* Articles are ordered by date (newest first), then alphabetically by title.
|
|
17
|
+
* Prev = newer article, Next = older article.
|
|
18
|
+
*/
|
|
19
|
+
export declare const getAdjacentArticles: (currentSlug: string, articles: Array<{
|
|
20
|
+
slug: string;
|
|
21
|
+
title: string;
|
|
22
|
+
}>) => {
|
|
23
|
+
prev?: {
|
|
24
|
+
slug: string;
|
|
25
|
+
title: string;
|
|
26
|
+
};
|
|
27
|
+
next?: {
|
|
28
|
+
slug: string;
|
|
29
|
+
title: string;
|
|
30
|
+
};
|
|
31
|
+
};
|