@windrun-huaiin/third-ui 31.0.1 → 31.1.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/dist/fuma/base/custom-header.d.ts +3 -1
- package/dist/fuma/base/custom-header.js +13 -7
- package/dist/fuma/base/custom-header.mjs +13 -7
- package/dist/fuma/base/custom-home-layout.d.ts +6 -1
- package/dist/fuma/base/custom-home-layout.js +6 -3
- package/dist/fuma/base/custom-home-layout.mjs +6 -3
- package/dist/fuma/base/docs-root-provider.d.ts +1 -6
- package/dist/fuma/base/docs-root-provider.js +2 -8
- package/dist/fuma/base/docs-root-provider.mjs +2 -8
- package/dist/fuma/base/header-theme-switch.d.ts +2 -1
- package/dist/fuma/base/site-docs-layout.d.ts +1 -0
- package/dist/fuma/base/site-docs-layout.js +22 -2
- package/dist/fuma/base/site-docs-layout.mjs +22 -2
- package/dist/fuma/base/site-home-layout.js +2 -2
- package/dist/fuma/base/site-home-layout.mjs +2 -2
- package/dist/fuma/base/site-layout-shared.d.ts +5 -1
- package/dist/fuma/base/site-layout-shared.js +1 -1
- package/dist/fuma/base/site-layout-shared.mjs +1 -1
- package/dist/fuma/base/site-theme-provider.d.ts +8 -0
- package/dist/fuma/base/site-theme-provider.js +41 -0
- package/dist/fuma/base/site-theme-provider.mjs +39 -0
- package/package.json +1 -1
- package/src/fuma/base/custom-header.tsx +30 -6
- package/src/fuma/base/custom-home-layout.tsx +24 -12
- package/src/fuma/base/docs-root-provider.tsx +3 -30
- package/src/fuma/base/header-theme-switch.tsx +2 -1
- package/src/fuma/base/site-docs-layout.tsx +23 -2
- package/src/fuma/base/site-home-layout.tsx +1 -0
- package/src/fuma/base/site-layout-shared.tsx +11 -2
- package/src/fuma/base/site-theme-provider.tsx +59 -0
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import { type CSSProperties } from 'react';
|
|
2
2
|
import { HomeLayoutProps } from 'fumadocs-ui/layouts/home';
|
|
3
|
+
import type { SiteThemeSwitchConfig } from './site-layout-shared';
|
|
3
4
|
export type NavbarCSSVars = CSSProperties & {
|
|
4
5
|
'--fd-banner-height'?: string;
|
|
5
6
|
'--fd-header-height'?: string;
|
|
6
7
|
'--fd-nav-max-width'?: string;
|
|
7
8
|
};
|
|
8
|
-
export interface CustomHomeHeaderProps extends HomeLayoutProps {
|
|
9
|
+
export interface CustomHomeHeaderProps extends Omit<HomeLayoutProps, 'themeSwitch'> {
|
|
9
10
|
/**
|
|
10
11
|
* Banner height in rem units
|
|
11
12
|
*
|
|
@@ -46,6 +47,7 @@ export interface CustomHomeHeaderProps extends HomeLayoutProps {
|
|
|
46
47
|
* Control order of utilities inside the mobile dropdown.
|
|
47
48
|
*/
|
|
48
49
|
mobileMenuActionsOrder?: MobileMenuAction[];
|
|
50
|
+
themeSwitch?: SiteThemeSwitchConfig;
|
|
49
51
|
}
|
|
50
52
|
export type DesktopAction = 'search' | 'theme' | 'i18n' | 'secondary' | 'github';
|
|
51
53
|
export type MobileBarAction = 'pinned' | 'search' | 'menu';
|
|
@@ -35,7 +35,7 @@ const DEFAULT_MOBILE_MENU_ACTIONS = [
|
|
|
35
35
|
'theme',
|
|
36
36
|
];
|
|
37
37
|
function CustomHomeHeader({ nav = {}, i18n = false, links, githubUrl, themeSwitch = {}, searchToggle = {}, bannerHeight = 0, headerHeight = 2.5, maxContentWidth = 1400, navbarClassName, floating = false, desktopActionsOrder = DEFAULT_DESKTOP_ACTIONS, mobileBarActionsOrder = DEFAULT_MOBILE_BAR_ACTIONS, mobileMenuActionsOrder = DEFAULT_MOBILE_MENU_ACTIONS, }) {
|
|
38
|
-
var _a, _b, _c, _d, _e
|
|
38
|
+
var _a, _b, _c, _d, _e;
|
|
39
39
|
const finalLinks = React.useMemo(() => shared.resolveLinkItems({ links, githubUrl }), [links, githubUrl]);
|
|
40
40
|
const navItems = finalLinks.filter((item) => { var _a; return ['nav', 'all'].includes((_a = item.on) !== null && _a !== void 0 ? _a : 'all'); });
|
|
41
41
|
const menuItems = finalLinks.filter((item) => { var _a; return ['menu', 'all'].includes((_a = item.on) !== null && _a !== void 0 ? _a : 'all'); });
|
|
@@ -55,8 +55,8 @@ function CustomHomeHeader({ nav = {}, i18n = false, links, githubUrl, themeSwitc
|
|
|
55
55
|
search: searchToggle.enabled !== false
|
|
56
56
|
? (_b = (_a = searchToggle.components) === null || _a === void 0 ? void 0 : _a.lg) !== null && _b !== void 0 ? _b : null
|
|
57
57
|
: null,
|
|
58
|
-
theme: themeSwitch
|
|
59
|
-
? (
|
|
58
|
+
theme: shouldShowThemeSwitch(themeSwitch === null || themeSwitch === void 0 ? void 0 : themeSwitch.mode)
|
|
59
|
+
? (jsxRuntime.jsx(headerThemeSwitch.HeaderThemeSwitch, { mode: normalizeThemeSwitchMode(themeSwitch === null || themeSwitch === void 0 ? void 0 : themeSwitch.mode) }))
|
|
60
60
|
: null,
|
|
61
61
|
i18n: i18n ? (jsxRuntime.jsx(CompactLanguageToggle, { children: jsxRuntime.jsx(icons.LanguagesIcon, { className: "size-5" }) })) : null,
|
|
62
62
|
secondary: desktopSecondaryDisplayItems.length ? (jsxRuntime.jsx("ul", { className: "flex flex-row gap-2 items-center empty:hidden", children: desktopSecondaryDisplayItems.map((item, i) => (jsxRuntime.jsx(NavbarLinkItem, { item: item, className: utils.cn(item.type === 'icon' && [
|
|
@@ -78,8 +78,8 @@ function CustomHomeHeader({ nav = {}, i18n = false, links, githubUrl, themeSwitc
|
|
|
78
78
|
github: githubMobileMenuItem ? (jsxRuntime.jsx(MenuLinkItem, { item: githubMobileMenuItem, className: "-me-1.5" })) : null,
|
|
79
79
|
separator: jsxRuntime.jsx("div", { role: "separator", className: "flex-1" }),
|
|
80
80
|
i18n: i18n ? (jsxRuntime.jsxs(CompactLanguageToggle, { children: [jsxRuntime.jsx(icons.LanguagesIcon, { className: "size-5" }), jsxRuntime.jsx(languageSelect.LanguageSelectText, {}), jsxRuntime.jsx(icons.ChevronDownIcon, { className: "size-3 text-fd-muted-foreground" })] })) : null,
|
|
81
|
-
theme: themeSwitch
|
|
82
|
-
? (
|
|
81
|
+
theme: shouldShowThemeSwitch(themeSwitch === null || themeSwitch === void 0 ? void 0 : themeSwitch.mode)
|
|
82
|
+
? (jsxRuntime.jsx(headerThemeSwitch.HeaderThemeSwitch, { mode: normalizeThemeSwitchMode(themeSwitch === null || themeSwitch === void 0 ? void 0 : themeSwitch.mode) }))
|
|
83
83
|
: null,
|
|
84
84
|
};
|
|
85
85
|
const shouldRenderMobileUtilities = mobileMenuActionsOrder.some((action) => action !== 'separator' && Boolean(mobileMenuActionNodes[action]));
|
|
@@ -100,7 +100,7 @@ function CustomHomeHeader({ nav = {}, i18n = false, links, githubUrl, themeSwitc
|
|
|
100
100
|
}) })) : null] })] }));
|
|
101
101
|
const mobilePinnedNode = mobilePinnedItems.length > 0 ? (jsxRuntime.jsx(jsxRuntime.Fragment, { children: mobilePinnedItems.map((item, i) => (jsxRuntime.jsx(NavbarLinkItem, { item: item, className: "max-sm:-mr-1" }, `mobile-pinned-${i}`))) })) : null;
|
|
102
102
|
const mobileSearchNode = searchToggle.enabled !== false
|
|
103
|
-
? (
|
|
103
|
+
? (_d = (_c = searchToggle.components) === null || _c === void 0 ? void 0 : _c.sm) !== null && _d !== void 0 ? _d : null
|
|
104
104
|
: null;
|
|
105
105
|
const mobileBarNodes = {
|
|
106
106
|
pinned: mobilePinnedNode,
|
|
@@ -108,7 +108,7 @@ function CustomHomeHeader({ nav = {}, i18n = false, links, githubUrl, themeSwitc
|
|
|
108
108
|
menu: menuNode,
|
|
109
109
|
};
|
|
110
110
|
const getMobileBarNode = (action) => { var _a; return (_a = mobileBarNodes[action]) !== null && _a !== void 0 ? _a : null; };
|
|
111
|
-
return (jsxRuntime.jsxs(CustomNavbar, { bannerHeight: bannerHeight, headerHeight: headerHeight, maxContentWidth: maxContentWidth, className: navbarClassName, floating: floating, children: [jsxRuntime.jsx(Link, { href: (
|
|
111
|
+
return (jsxRuntime.jsxs(CustomNavbar, { bannerHeight: bannerHeight, headerHeight: headerHeight, maxContentWidth: maxContentWidth, className: navbarClassName, floating: floating, children: [jsxRuntime.jsx(Link, { href: (_e = nav.url) !== null && _e !== void 0 ? _e : '/', prefetch: false, className: "inline-flex items-center gap-2.5 font-semibold", children: renderNavTitle(nav.title) }), nav.children, jsxRuntime.jsx("ul", { className: "flex flex-row items-center gap-2 px-6 max-sm:hidden", children: navItems
|
|
112
112
|
.filter((item) => !isSecondary(item))
|
|
113
113
|
.map((item, i) => (jsxRuntime.jsx(NavbarLinkItem, { item: item, className: "text-sm" }, i))) }), jsxRuntime.jsx("div", { className: "flex flex-row items-center justify-end gap-1.5 flex-1 max-lg:hidden", children: desktopActionsOrder.map((action) => {
|
|
114
114
|
const node = desktopActionNodes[action];
|
|
@@ -120,6 +120,12 @@ function CustomHomeHeader({ nav = {}, i18n = false, links, githubUrl, themeSwitc
|
|
|
120
120
|
return node ? (jsxRuntime.jsx(React.Fragment, { children: node }, `mobile-bar-${action}`)) : null;
|
|
121
121
|
}) })] }));
|
|
122
122
|
}
|
|
123
|
+
function shouldShowThemeSwitch(mode) {
|
|
124
|
+
return mode === 'light-dark' || mode === 'light-dark-system' || mode == null;
|
|
125
|
+
}
|
|
126
|
+
function normalizeThemeSwitchMode(mode) {
|
|
127
|
+
return mode === 'light-dark' ? 'light-dark' : 'light-dark-system';
|
|
128
|
+
}
|
|
123
129
|
function CustomNavbar(_a) {
|
|
124
130
|
var { bannerHeight = 0, headerHeight = 2.5, maxContentWidth = 1400, className, style, floating = false } = _a, props = tslib.__rest(_a, ["bannerHeight", "headerHeight", "maxContentWidth", "className", "style", "floating"]);
|
|
125
131
|
const [value, setValue] = React.useState('');
|
|
@@ -33,7 +33,7 @@ const DEFAULT_MOBILE_MENU_ACTIONS = [
|
|
|
33
33
|
'theme',
|
|
34
34
|
];
|
|
35
35
|
function CustomHomeHeader({ nav = {}, i18n = false, links, githubUrl, themeSwitch = {}, searchToggle = {}, bannerHeight = 0, headerHeight = 2.5, maxContentWidth = 1400, navbarClassName, floating = false, desktopActionsOrder = DEFAULT_DESKTOP_ACTIONS, mobileBarActionsOrder = DEFAULT_MOBILE_BAR_ACTIONS, mobileMenuActionsOrder = DEFAULT_MOBILE_MENU_ACTIONS, }) {
|
|
36
|
-
var _a, _b, _c, _d, _e
|
|
36
|
+
var _a, _b, _c, _d, _e;
|
|
37
37
|
const finalLinks = useMemo(() => resolveLinkItems({ links, githubUrl }), [links, githubUrl]);
|
|
38
38
|
const navItems = finalLinks.filter((item) => { var _a; return ['nav', 'all'].includes((_a = item.on) !== null && _a !== void 0 ? _a : 'all'); });
|
|
39
39
|
const menuItems = finalLinks.filter((item) => { var _a; return ['menu', 'all'].includes((_a = item.on) !== null && _a !== void 0 ? _a : 'all'); });
|
|
@@ -53,8 +53,8 @@ function CustomHomeHeader({ nav = {}, i18n = false, links, githubUrl, themeSwitc
|
|
|
53
53
|
search: searchToggle.enabled !== false
|
|
54
54
|
? (_b = (_a = searchToggle.components) === null || _a === void 0 ? void 0 : _a.lg) !== null && _b !== void 0 ? _b : null
|
|
55
55
|
: null,
|
|
56
|
-
theme: themeSwitch
|
|
57
|
-
? (
|
|
56
|
+
theme: shouldShowThemeSwitch(themeSwitch === null || themeSwitch === void 0 ? void 0 : themeSwitch.mode)
|
|
57
|
+
? (jsx(HeaderThemeSwitch, { mode: normalizeThemeSwitchMode(themeSwitch === null || themeSwitch === void 0 ? void 0 : themeSwitch.mode) }))
|
|
58
58
|
: null,
|
|
59
59
|
i18n: i18n ? (jsx(CompactLanguageToggle, { children: jsx(LanguagesIcon, { className: "size-5" }) })) : null,
|
|
60
60
|
secondary: desktopSecondaryDisplayItems.length ? (jsx("ul", { className: "flex flex-row gap-2 items-center empty:hidden", children: desktopSecondaryDisplayItems.map((item, i) => (jsx(NavbarLinkItem, { item: item, className: cn(item.type === 'icon' && [
|
|
@@ -76,8 +76,8 @@ function CustomHomeHeader({ nav = {}, i18n = false, links, githubUrl, themeSwitc
|
|
|
76
76
|
github: githubMobileMenuItem ? (jsx(MenuLinkItem, { item: githubMobileMenuItem, className: "-me-1.5" })) : null,
|
|
77
77
|
separator: jsx("div", { role: "separator", className: "flex-1" }),
|
|
78
78
|
i18n: i18n ? (jsxs(CompactLanguageToggle, { children: [jsx(LanguagesIcon, { className: "size-5" }), jsx(LanguageSelectText, {}), jsx(ChevronDownIcon, { className: "size-3 text-fd-muted-foreground" })] })) : null,
|
|
79
|
-
theme: themeSwitch
|
|
80
|
-
? (
|
|
79
|
+
theme: shouldShowThemeSwitch(themeSwitch === null || themeSwitch === void 0 ? void 0 : themeSwitch.mode)
|
|
80
|
+
? (jsx(HeaderThemeSwitch, { mode: normalizeThemeSwitchMode(themeSwitch === null || themeSwitch === void 0 ? void 0 : themeSwitch.mode) }))
|
|
81
81
|
: null,
|
|
82
82
|
};
|
|
83
83
|
const shouldRenderMobileUtilities = mobileMenuActionsOrder.some((action) => action !== 'separator' && Boolean(mobileMenuActionNodes[action]));
|
|
@@ -98,7 +98,7 @@ function CustomHomeHeader({ nav = {}, i18n = false, links, githubUrl, themeSwitc
|
|
|
98
98
|
}) })) : null] })] }));
|
|
99
99
|
const mobilePinnedNode = mobilePinnedItems.length > 0 ? (jsx(Fragment, { children: mobilePinnedItems.map((item, i) => (jsx(NavbarLinkItem, { item: item, className: "max-sm:-mr-1" }, `mobile-pinned-${i}`))) })) : null;
|
|
100
100
|
const mobileSearchNode = searchToggle.enabled !== false
|
|
101
|
-
? (
|
|
101
|
+
? (_d = (_c = searchToggle.components) === null || _c === void 0 ? void 0 : _c.sm) !== null && _d !== void 0 ? _d : null
|
|
102
102
|
: null;
|
|
103
103
|
const mobileBarNodes = {
|
|
104
104
|
pinned: mobilePinnedNode,
|
|
@@ -106,7 +106,7 @@ function CustomHomeHeader({ nav = {}, i18n = false, links, githubUrl, themeSwitc
|
|
|
106
106
|
menu: menuNode,
|
|
107
107
|
};
|
|
108
108
|
const getMobileBarNode = (action) => { var _a; return (_a = mobileBarNodes[action]) !== null && _a !== void 0 ? _a : null; };
|
|
109
|
-
return (jsxs(CustomNavbar, { bannerHeight: bannerHeight, headerHeight: headerHeight, maxContentWidth: maxContentWidth, className: navbarClassName, floating: floating, children: [jsx(Link, { href: (
|
|
109
|
+
return (jsxs(CustomNavbar, { bannerHeight: bannerHeight, headerHeight: headerHeight, maxContentWidth: maxContentWidth, className: navbarClassName, floating: floating, children: [jsx(Link, { href: (_e = nav.url) !== null && _e !== void 0 ? _e : '/', prefetch: false, className: "inline-flex items-center gap-2.5 font-semibold", children: renderNavTitle(nav.title) }), nav.children, jsx("ul", { className: "flex flex-row items-center gap-2 px-6 max-sm:hidden", children: navItems
|
|
110
110
|
.filter((item) => !isSecondary(item))
|
|
111
111
|
.map((item, i) => (jsx(NavbarLinkItem, { item: item, className: "text-sm" }, i))) }), jsx("div", { className: "flex flex-row items-center justify-end gap-1.5 flex-1 max-lg:hidden", children: desktopActionsOrder.map((action) => {
|
|
112
112
|
const node = desktopActionNodes[action];
|
|
@@ -118,6 +118,12 @@ function CustomHomeHeader({ nav = {}, i18n = false, links, githubUrl, themeSwitc
|
|
|
118
118
|
return node ? (jsx(Fragment$1, { children: node }, `mobile-bar-${action}`)) : null;
|
|
119
119
|
}) })] }));
|
|
120
120
|
}
|
|
121
|
+
function shouldShowThemeSwitch(mode) {
|
|
122
|
+
return mode === 'light-dark' || mode === 'light-dark-system' || mode == null;
|
|
123
|
+
}
|
|
124
|
+
function normalizeThemeSwitchMode(mode) {
|
|
125
|
+
return mode === 'light-dark' ? 'light-dark' : 'light-dark-system';
|
|
126
|
+
}
|
|
121
127
|
function CustomNavbar(_a) {
|
|
122
128
|
var { bannerHeight = 0, headerHeight = 2.5, maxContentWidth = 1400, className, style, floating = false } = _a, props = __rest(_a, ["bannerHeight", "headerHeight", "maxContentWidth", "className", "style", "floating"]);
|
|
123
129
|
const [value, setValue] = useState('');
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { CSSProperties, ReactNode } from 'react';
|
|
2
2
|
import { type HomeLayoutProps } from 'fumadocs-ui/layouts/home';
|
|
3
3
|
import { type DesktopAction, type MobileBarAction, type MobileMenuAction } from './custom-header';
|
|
4
|
+
import type { SiteThemeSwitchConfig } from './site-layout-shared';
|
|
4
5
|
export interface CustomHomeLayoutProps {
|
|
5
6
|
locale: string;
|
|
6
7
|
options: HomeLayoutProps;
|
|
@@ -76,6 +77,10 @@ export interface CustomHomeLayoutProps {
|
|
|
76
77
|
* The default locale for the application (default: 'en')
|
|
77
78
|
*/
|
|
78
79
|
defaultLocale?: string;
|
|
80
|
+
/**
|
|
81
|
+
* Theme mode for this layout group.
|
|
82
|
+
*/
|
|
83
|
+
themeSwitch?: SiteThemeSwitchConfig;
|
|
79
84
|
children?: ReactNode;
|
|
80
85
|
}
|
|
81
86
|
export interface HeaderActionOrders {
|
|
@@ -83,7 +88,7 @@ export interface HeaderActionOrders {
|
|
|
83
88
|
mobileBar?: MobileBarAction[];
|
|
84
89
|
mobileMenu?: MobileMenuAction[];
|
|
85
90
|
}
|
|
86
|
-
export declare function CustomHomeLayout({ locale, options, children, showBanner, bannerHeight, headerHeight, headerPaddingTop, navbarClassName, banner, footer, goToTop, showFooter, showGoToTop, style, floatingNav, actionOrders, localePrefixAsNeeded, defaultLocale, }: CustomHomeLayoutProps): import("react/jsx-runtime").JSX.Element;
|
|
91
|
+
export declare function CustomHomeLayout({ locale, options, children, showBanner, bannerHeight, headerHeight, headerPaddingTop, navbarClassName, banner, footer, goToTop, showFooter, showGoToTop, style, floatingNav, actionOrders, localePrefixAsNeeded, defaultLocale, themeSwitch, }: CustomHomeLayoutProps): import("react/jsx-runtime").JSX.Element;
|
|
87
92
|
export declare function HomeTitle({ children, className, }: {
|
|
88
93
|
children: ReactNode;
|
|
89
94
|
className?: string;
|
|
@@ -6,9 +6,11 @@ var home = require('fumadocs-ui/layouts/home');
|
|
|
6
6
|
var fumaBannerSuit = require('../fuma-banner-suit.js');
|
|
7
7
|
var footer = require('../../main/footer.js');
|
|
8
8
|
var goToTop = require('../../main/go-to-top.js');
|
|
9
|
+
var siteThemeProvider = require('./site-theme-provider.js');
|
|
9
10
|
var customHeader = require('./custom-header.js');
|
|
10
11
|
|
|
11
|
-
function CustomHomeLayout({ locale, options, children, showBanner = false, bannerHeight, headerHeight = 2.5, headerPaddingTop, navbarClassName, banner, footer: footer$1, goToTop: goToTop$1, showFooter = true, showGoToTop = true, style, floatingNav = false, actionOrders, localePrefixAsNeeded = true, defaultLocale = 'en', }) {
|
|
12
|
+
function CustomHomeLayout({ locale, options, children, showBanner = false, bannerHeight, headerHeight = 2.5, headerPaddingTop, navbarClassName, banner, footer: footer$1, goToTop: goToTop$1, showFooter = true, showGoToTop = true, style, floatingNav = false, actionOrders, localePrefixAsNeeded = true, defaultLocale = 'en', themeSwitch, }) {
|
|
13
|
+
var _a;
|
|
12
14
|
const resolvedBannerHeight = bannerHeight !== null && bannerHeight !== void 0 ? bannerHeight : (showBanner ? 3 : 0.5);
|
|
13
15
|
const resolvedPaddingTop = headerPaddingTop !== null && headerPaddingTop !== void 0 ? headerPaddingTop : (showBanner ? 0 : 0.5);
|
|
14
16
|
const layoutStyle = Object.assign({ '--fd-banner-height': `${resolvedBannerHeight}rem`, '--fd-header-height': `${headerHeight}rem`, paddingTop: floatingNav
|
|
@@ -16,8 +18,9 @@ function CustomHomeLayout({ locale, options, children, showBanner = false, banne
|
|
|
16
18
|
: `${resolvedPaddingTop}rem` }, style);
|
|
17
19
|
const { nav } = options, homeLayoutProps = tslib.__rest(options, ["nav"]);
|
|
18
20
|
const navOptions = nav !== null && nav !== void 0 ? nav : {};
|
|
19
|
-
const header = (jsxRuntime.jsx(customHeader.CustomHomeHeader, Object.assign({}, homeLayoutProps, { nav: navOptions, bannerHeight: resolvedBannerHeight, headerHeight: headerHeight, navbarClassName: navbarClassName, floating: floatingNav, desktopActionsOrder: actionOrders === null || actionOrders === void 0 ? void 0 : actionOrders.desktop, mobileBarActionsOrder: actionOrders === null || actionOrders === void 0 ? void 0 : actionOrders.mobileBar, mobileMenuActionsOrder: actionOrders === null || actionOrders === void 0 ? void 0 : actionOrders.mobileMenu })));
|
|
20
|
-
|
|
21
|
+
const header = (jsxRuntime.jsx(customHeader.CustomHomeHeader, Object.assign({}, homeLayoutProps, { nav: navOptions, themeSwitch: themeSwitch, bannerHeight: resolvedBannerHeight, headerHeight: headerHeight, navbarClassName: navbarClassName, floating: floatingNav, desktopActionsOrder: actionOrders === null || actionOrders === void 0 ? void 0 : actionOrders.desktop, mobileBarActionsOrder: actionOrders === null || actionOrders === void 0 ? void 0 : actionOrders.mobileBar, mobileMenuActionsOrder: actionOrders === null || actionOrders === void 0 ? void 0 : actionOrders.mobileMenu })));
|
|
22
|
+
const themeMode = (_a = themeSwitch === null || themeSwitch === void 0 ? void 0 : themeSwitch.mode) !== null && _a !== void 0 ? _a : 'light-dark-system';
|
|
23
|
+
return (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [banner !== null && banner !== void 0 ? banner : (jsxRuntime.jsx(fumaBannerSuit.FumaBannerSuit, { locale: locale, showBanner: showBanner, floating: floatingNav })), jsxRuntime.jsx(siteThemeProvider.SiteThemeProvider, { mode: themeMode, children: jsxRuntime.jsxs(home.HomeLayout, Object.assign({}, homeLayoutProps, { nav: Object.assign(Object.assign({}, navOptions), { component: header }), className: 'bg-neutral-100 dark:bg-neutral-900', style: layoutStyle, children: [children, showFooter ? footer$1 !== null && footer$1 !== void 0 ? footer$1 : jsxRuntime.jsx(footer.Footer, { locale: locale, localePrefixAsNeeded: localePrefixAsNeeded, defaultLocale: defaultLocale }) : null, showGoToTop ? goToTop$1 !== null && goToTop$1 !== void 0 ? goToTop$1 : jsxRuntime.jsx(goToTop.GoToTop, {}) : null] })) })] }));
|
|
21
24
|
}
|
|
22
25
|
function HomeTitle({ children, className, }) {
|
|
23
26
|
return (jsxRuntime.jsx("span", { className: `font-medium in-[.uwu]:hidden in-[header]:text-[clamp(12px,3vw,15px)]! ${className !== null && className !== void 0 ? className : ''}`, children: children }));
|
|
@@ -4,9 +4,11 @@ import { HomeLayout } from 'fumadocs-ui/layouts/home';
|
|
|
4
4
|
import { FumaBannerSuit } from '../fuma-banner-suit.mjs';
|
|
5
5
|
import { Footer } from '../../main/footer.mjs';
|
|
6
6
|
import { GoToTop } from '../../main/go-to-top.mjs';
|
|
7
|
+
import { SiteThemeProvider } from './site-theme-provider.mjs';
|
|
7
8
|
import { CustomHomeHeader } from './custom-header.mjs';
|
|
8
9
|
|
|
9
|
-
function CustomHomeLayout({ locale, options, children, showBanner = false, bannerHeight, headerHeight = 2.5, headerPaddingTop, navbarClassName, banner, footer, goToTop, showFooter = true, showGoToTop = true, style, floatingNav = false, actionOrders, localePrefixAsNeeded = true, defaultLocale = 'en', }) {
|
|
10
|
+
function CustomHomeLayout({ locale, options, children, showBanner = false, bannerHeight, headerHeight = 2.5, headerPaddingTop, navbarClassName, banner, footer, goToTop, showFooter = true, showGoToTop = true, style, floatingNav = false, actionOrders, localePrefixAsNeeded = true, defaultLocale = 'en', themeSwitch, }) {
|
|
11
|
+
var _a;
|
|
10
12
|
const resolvedBannerHeight = bannerHeight !== null && bannerHeight !== void 0 ? bannerHeight : (showBanner ? 3 : 0.5);
|
|
11
13
|
const resolvedPaddingTop = headerPaddingTop !== null && headerPaddingTop !== void 0 ? headerPaddingTop : (showBanner ? 0 : 0.5);
|
|
12
14
|
const layoutStyle = Object.assign({ '--fd-banner-height': `${resolvedBannerHeight}rem`, '--fd-header-height': `${headerHeight}rem`, paddingTop: floatingNav
|
|
@@ -14,8 +16,9 @@ function CustomHomeLayout({ locale, options, children, showBanner = false, banne
|
|
|
14
16
|
: `${resolvedPaddingTop}rem` }, style);
|
|
15
17
|
const { nav } = options, homeLayoutProps = __rest(options, ["nav"]);
|
|
16
18
|
const navOptions = nav !== null && nav !== void 0 ? nav : {};
|
|
17
|
-
const header = (jsx(CustomHomeHeader, Object.assign({}, homeLayoutProps, { nav: navOptions, bannerHeight: resolvedBannerHeight, headerHeight: headerHeight, navbarClassName: navbarClassName, floating: floatingNav, desktopActionsOrder: actionOrders === null || actionOrders === void 0 ? void 0 : actionOrders.desktop, mobileBarActionsOrder: actionOrders === null || actionOrders === void 0 ? void 0 : actionOrders.mobileBar, mobileMenuActionsOrder: actionOrders === null || actionOrders === void 0 ? void 0 : actionOrders.mobileMenu })));
|
|
18
|
-
|
|
19
|
+
const header = (jsx(CustomHomeHeader, Object.assign({}, homeLayoutProps, { nav: navOptions, themeSwitch: themeSwitch, bannerHeight: resolvedBannerHeight, headerHeight: headerHeight, navbarClassName: navbarClassName, floating: floatingNav, desktopActionsOrder: actionOrders === null || actionOrders === void 0 ? void 0 : actionOrders.desktop, mobileBarActionsOrder: actionOrders === null || actionOrders === void 0 ? void 0 : actionOrders.mobileBar, mobileMenuActionsOrder: actionOrders === null || actionOrders === void 0 ? void 0 : actionOrders.mobileMenu })));
|
|
20
|
+
const themeMode = (_a = themeSwitch === null || themeSwitch === void 0 ? void 0 : themeSwitch.mode) !== null && _a !== void 0 ? _a : 'light-dark-system';
|
|
21
|
+
return (jsxs(Fragment, { children: [banner !== null && banner !== void 0 ? banner : (jsx(FumaBannerSuit, { locale: locale, showBanner: showBanner, floating: floatingNav })), jsx(SiteThemeProvider, { mode: themeMode, children: jsxs(HomeLayout, Object.assign({}, homeLayoutProps, { nav: Object.assign(Object.assign({}, navOptions), { component: header }), className: 'bg-neutral-100 dark:bg-neutral-900', style: layoutStyle, children: [children, showFooter ? footer !== null && footer !== void 0 ? footer : jsx(Footer, { locale: locale, localePrefixAsNeeded: localePrefixAsNeeded, defaultLocale: defaultLocale }) : null, showGoToTop ? goToTop !== null && goToTop !== void 0 ? goToTop : jsx(GoToTop, {}) : null] })) })] }));
|
|
19
22
|
}
|
|
20
23
|
function HomeTitle({ children, className, }) {
|
|
21
24
|
return (jsx("span", { className: `font-medium in-[.uwu]:hidden in-[header]:text-[clamp(12px,3vw,15px)]! ${className !== null && className !== void 0 ? className : ''}`, children: children }));
|
|
@@ -1,19 +1,14 @@
|
|
|
1
1
|
import type { ComponentProps, ReactNode } from 'react';
|
|
2
2
|
import { NextProvider } from 'fumadocs-core/framework/next';
|
|
3
3
|
import { type I18nProviderProps } from 'fumadocs-ui/contexts/i18n';
|
|
4
|
-
import { type ThemeProviderProps } from 'next-themes';
|
|
5
4
|
type NextProviderComponents = {
|
|
6
5
|
Link?: ComponentProps<typeof NextProvider>['Link'];
|
|
7
6
|
Image?: ComponentProps<typeof NextProvider>['Image'];
|
|
8
7
|
};
|
|
9
|
-
type ThemeOptions = ThemeProviderProps & {
|
|
10
|
-
enabled?: boolean;
|
|
11
|
-
};
|
|
12
8
|
export interface DocsRootProviderProps {
|
|
13
9
|
i18n: Omit<I18nProviderProps, 'children'>;
|
|
14
|
-
theme?: ThemeOptions;
|
|
15
10
|
components?: NextProviderComponents;
|
|
16
11
|
children: ReactNode;
|
|
17
12
|
}
|
|
18
|
-
export declare function DocsRootProvider({ i18n,
|
|
13
|
+
export declare function DocsRootProvider({ i18n, components, children, }: DocsRootProviderProps): import("react/jsx-runtime").JSX.Element;
|
|
19
14
|
export {};
|
|
@@ -3,15 +3,9 @@
|
|
|
3
3
|
var jsxRuntime = require('react/jsx-runtime');
|
|
4
4
|
var next = require('fumadocs-core/framework/next');
|
|
5
5
|
var i18n = require('fumadocs-ui/contexts/i18n');
|
|
6
|
-
var nextThemes = require('next-themes');
|
|
7
6
|
|
|
8
|
-
function DocsRootProvider({ i18n: i18n$1,
|
|
9
|
-
|
|
10
|
-
if (theme.enabled !== false) {
|
|
11
|
-
body = (jsxRuntime.jsx(nextThemes.ThemeProvider, Object.assign({ attribute: "class", defaultTheme: "system", enableSystem: true, disableTransitionOnChange: true }, theme, { children: body })));
|
|
12
|
-
}
|
|
13
|
-
body = (jsxRuntime.jsx(i18n.I18nProvider, Object.assign({}, i18n$1, { children: body })));
|
|
14
|
-
return (jsxRuntime.jsx(next.NextProvider, { Link: components === null || components === void 0 ? void 0 : components.Link, Image: components === null || components === void 0 ? void 0 : components.Image, children: body }));
|
|
7
|
+
function DocsRootProvider({ i18n: i18n$1, components, children, }) {
|
|
8
|
+
return (jsxRuntime.jsx(next.NextProvider, { Link: components === null || components === void 0 ? void 0 : components.Link, Image: components === null || components === void 0 ? void 0 : components.Image, children: jsxRuntime.jsx(i18n.I18nProvider, Object.assign({}, i18n$1, { children: children })) }));
|
|
15
9
|
}
|
|
16
10
|
|
|
17
11
|
exports.DocsRootProvider = DocsRootProvider;
|
|
@@ -1,15 +1,9 @@
|
|
|
1
1
|
import { jsx } from 'react/jsx-runtime';
|
|
2
2
|
import { NextProvider } from 'fumadocs-core/framework/next';
|
|
3
3
|
import { I18nProvider } from 'fumadocs-ui/contexts/i18n';
|
|
4
|
-
import { ThemeProvider } from 'next-themes';
|
|
5
4
|
|
|
6
|
-
function DocsRootProvider({ i18n,
|
|
7
|
-
|
|
8
|
-
if (theme.enabled !== false) {
|
|
9
|
-
body = (jsx(ThemeProvider, Object.assign({ attribute: "class", defaultTheme: "system", enableSystem: true, disableTransitionOnChange: true }, theme, { children: body })));
|
|
10
|
-
}
|
|
11
|
-
body = (jsx(I18nProvider, Object.assign({}, i18n, { children: body })));
|
|
12
|
-
return (jsx(NextProvider, { Link: components === null || components === void 0 ? void 0 : components.Link, Image: components === null || components === void 0 ? void 0 : components.Image, children: body }));
|
|
5
|
+
function DocsRootProvider({ i18n, components, children, }) {
|
|
6
|
+
return (jsx(NextProvider, { Link: components === null || components === void 0 ? void 0 : components.Link, Image: components === null || components === void 0 ? void 0 : components.Image, children: jsx(I18nProvider, Object.assign({}, i18n, { children: children })) }));
|
|
13
7
|
}
|
|
14
8
|
|
|
15
9
|
export { DocsRootProvider };
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { type ComponentProps } from 'react';
|
|
2
|
+
import type { SiteThemeSwitchMode } from './site-layout-shared';
|
|
2
3
|
export interface HeaderThemeSwitchProps extends ComponentProps<'div'> {
|
|
3
|
-
mode?: 'light-
|
|
4
|
+
mode?: Exclude<SiteThemeSwitchMode, 'light-only' | 'dark-only'>;
|
|
4
5
|
}
|
|
5
6
|
export declare function HeaderThemeSwitch({ className, mode, ...props }: HeaderThemeSwitchProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -4,6 +4,7 @@ import { type SiteBaseLayoutConfig } from './site-layout-shared';
|
|
|
4
4
|
export interface SiteDocsLayoutConfig extends SiteBaseLayoutConfig {
|
|
5
5
|
tree: DocsLayoutProps['tree'];
|
|
6
6
|
sidebar?: DocsLayoutProps['sidebar'];
|
|
7
|
+
themeProvider?: boolean;
|
|
7
8
|
}
|
|
8
9
|
export declare function SiteDocsLayout({ config, children, }: {
|
|
9
10
|
config: SiteDocsLayoutConfig;
|
|
@@ -3,13 +3,33 @@
|
|
|
3
3
|
var jsxRuntime = require('react/jsx-runtime');
|
|
4
4
|
var docs = require('fumadocs-ui/layouts/docs');
|
|
5
5
|
var siteLayoutShared = require('./site-layout-shared.js');
|
|
6
|
+
var siteThemeProvider = require('./site-theme-provider.js');
|
|
6
7
|
|
|
7
8
|
function toDocsLayoutOptions(config) {
|
|
8
|
-
|
|
9
|
+
var _a, _b;
|
|
10
|
+
const themeMode = (_b = (_a = config.themeSwitch) === null || _a === void 0 ? void 0 : _a.mode) !== null && _b !== void 0 ? _b : 'light-dark-system';
|
|
11
|
+
const shouldShowThemeSwitch = config.themeProvider !== false &&
|
|
12
|
+
(themeMode === 'light-dark' || themeMode === 'light-dark-system');
|
|
13
|
+
return Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({}, (config.nav ? { nav: config.nav } : {})), (config.i18n ? { i18n: config.i18n } : {})), (config.githubUrl ? { githubUrl: config.githubUrl } : {})), (config.links ? { links: siteLayoutShared.normalizeNavItems(config.links) } : {})), (config.searchToggle ? { searchToggle: config.searchToggle } : {})), (shouldShowThemeSwitch
|
|
14
|
+
? {
|
|
15
|
+
themeSwitch: {
|
|
16
|
+
mode: themeMode,
|
|
17
|
+
},
|
|
18
|
+
}
|
|
19
|
+
: {
|
|
20
|
+
themeSwitch: {
|
|
21
|
+
enabled: false,
|
|
22
|
+
},
|
|
23
|
+
})), (config.sidebar ? { sidebar: config.sidebar } : {})), { tree: config.tree });
|
|
9
24
|
}
|
|
10
25
|
function SiteDocsLayout({ config, children, }) {
|
|
26
|
+
var _a, _b;
|
|
11
27
|
const options = toDocsLayoutOptions(config);
|
|
12
|
-
|
|
28
|
+
const themeMode = (_b = (_a = config.themeSwitch) === null || _a === void 0 ? void 0 : _a.mode) !== null && _b !== void 0 ? _b : 'light-dark-system';
|
|
29
|
+
const body = jsxRuntime.jsx(docs.DocsLayout, Object.assign({}, options, { children: children }));
|
|
30
|
+
if (config.themeProvider === false)
|
|
31
|
+
return body;
|
|
32
|
+
return jsxRuntime.jsx(siteThemeProvider.SiteThemeProvider, { mode: themeMode, children: body });
|
|
13
33
|
}
|
|
14
34
|
|
|
15
35
|
exports.SiteDocsLayout = SiteDocsLayout;
|
|
@@ -1,13 +1,33 @@
|
|
|
1
1
|
import { jsx } from 'react/jsx-runtime';
|
|
2
2
|
import { DocsLayout } from 'fumadocs-ui/layouts/docs';
|
|
3
3
|
import { normalizeNavItems } from './site-layout-shared.mjs';
|
|
4
|
+
import { SiteThemeProvider } from './site-theme-provider.mjs';
|
|
4
5
|
|
|
5
6
|
function toDocsLayoutOptions(config) {
|
|
6
|
-
|
|
7
|
+
var _a, _b;
|
|
8
|
+
const themeMode = (_b = (_a = config.themeSwitch) === null || _a === void 0 ? void 0 : _a.mode) !== null && _b !== void 0 ? _b : 'light-dark-system';
|
|
9
|
+
const shouldShowThemeSwitch = config.themeProvider !== false &&
|
|
10
|
+
(themeMode === 'light-dark' || themeMode === 'light-dark-system');
|
|
11
|
+
return Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({}, (config.nav ? { nav: config.nav } : {})), (config.i18n ? { i18n: config.i18n } : {})), (config.githubUrl ? { githubUrl: config.githubUrl } : {})), (config.links ? { links: normalizeNavItems(config.links) } : {})), (config.searchToggle ? { searchToggle: config.searchToggle } : {})), (shouldShowThemeSwitch
|
|
12
|
+
? {
|
|
13
|
+
themeSwitch: {
|
|
14
|
+
mode: themeMode,
|
|
15
|
+
},
|
|
16
|
+
}
|
|
17
|
+
: {
|
|
18
|
+
themeSwitch: {
|
|
19
|
+
enabled: false,
|
|
20
|
+
},
|
|
21
|
+
})), (config.sidebar ? { sidebar: config.sidebar } : {})), { tree: config.tree });
|
|
7
22
|
}
|
|
8
23
|
function SiteDocsLayout({ config, children, }) {
|
|
24
|
+
var _a, _b;
|
|
9
25
|
const options = toDocsLayoutOptions(config);
|
|
10
|
-
|
|
26
|
+
const themeMode = (_b = (_a = config.themeSwitch) === null || _a === void 0 ? void 0 : _a.mode) !== null && _b !== void 0 ? _b : 'light-dark-system';
|
|
27
|
+
const body = jsx(DocsLayout, Object.assign({}, options, { children: children }));
|
|
28
|
+
if (config.themeProvider === false)
|
|
29
|
+
return body;
|
|
30
|
+
return jsx(SiteThemeProvider, { mode: themeMode, children: body });
|
|
11
31
|
}
|
|
12
32
|
|
|
13
33
|
export { SiteDocsLayout };
|
|
@@ -8,8 +8,8 @@ var siteLayoutShared = require('./site-layout-shared.js');
|
|
|
8
8
|
function SiteHomeLayout({ locale, config, children, }) {
|
|
9
9
|
const { actionOrders, banner, bannerHeight, defaultLocale, floatingNav, footer, goToTop, headerHeight, headerPaddingTop, localePrefixAsNeeded, navbarClassName, showBanner, showFooter, showGoToTop } = config, baseConfig = tslib.__rest(config, ["actionOrders", "banner", "bannerHeight", "defaultLocale", "floatingNav", "footer", "goToTop", "headerHeight", "headerPaddingTop", "localePrefixAsNeeded", "navbarClassName", "showBanner", "showFooter", "showGoToTop"]);
|
|
10
10
|
const options = siteLayoutShared.toHomeLayoutOptions(baseConfig);
|
|
11
|
-
const layoutProps = Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({ locale,
|
|
12
|
-
options }, (actionOrders ? { actionOrders } : {})), (banner ? { banner } : {})), (bannerHeight != null ? { bannerHeight } : {})), (defaultLocale ? { defaultLocale } : {})), (floatingNav != null ? { floatingNav } : {})), (footer ? { footer } : {})), (goToTop ? { goToTop } : {})), (headerHeight != null ? { headerHeight } : {})), (headerPaddingTop != null ? { headerPaddingTop } : {})), (localePrefixAsNeeded != null ? { localePrefixAsNeeded } : {})), (navbarClassName ? { navbarClassName } : {})), (showBanner != null ? { showBanner } : {})), (showFooter != null ? { showFooter } : {})), (showGoToTop != null ? { showGoToTop } : {}));
|
|
11
|
+
const layoutProps = Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({ locale,
|
|
12
|
+
options }, (actionOrders ? { actionOrders } : {})), (banner ? { banner } : {})), (bannerHeight != null ? { bannerHeight } : {})), (defaultLocale ? { defaultLocale } : {})), (floatingNav != null ? { floatingNav } : {})), (footer ? { footer } : {})), (goToTop ? { goToTop } : {})), (headerHeight != null ? { headerHeight } : {})), (headerPaddingTop != null ? { headerPaddingTop } : {})), (localePrefixAsNeeded != null ? { localePrefixAsNeeded } : {})), (navbarClassName ? { navbarClassName } : {})), (showBanner != null ? { showBanner } : {})), (showFooter != null ? { showFooter } : {})), (showGoToTop != null ? { showGoToTop } : {})), (config.themeSwitch ? { themeSwitch: config.themeSwitch } : {}));
|
|
13
13
|
return jsxRuntime.jsx(customHomeLayout.CustomHomeLayout, Object.assign({}, layoutProps, { children: children }));
|
|
14
14
|
}
|
|
15
15
|
|
|
@@ -6,8 +6,8 @@ import { toHomeLayoutOptions } from './site-layout-shared.mjs';
|
|
|
6
6
|
function SiteHomeLayout({ locale, config, children, }) {
|
|
7
7
|
const { actionOrders, banner, bannerHeight, defaultLocale, floatingNav, footer, goToTop, headerHeight, headerPaddingTop, localePrefixAsNeeded, navbarClassName, showBanner, showFooter, showGoToTop } = config, baseConfig = __rest(config, ["actionOrders", "banner", "bannerHeight", "defaultLocale", "floatingNav", "footer", "goToTop", "headerHeight", "headerPaddingTop", "localePrefixAsNeeded", "navbarClassName", "showBanner", "showFooter", "showGoToTop"]);
|
|
8
8
|
const options = toHomeLayoutOptions(baseConfig);
|
|
9
|
-
const layoutProps = Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({ locale,
|
|
10
|
-
options }, (actionOrders ? { actionOrders } : {})), (banner ? { banner } : {})), (bannerHeight != null ? { bannerHeight } : {})), (defaultLocale ? { defaultLocale } : {})), (floatingNav != null ? { floatingNav } : {})), (footer ? { footer } : {})), (goToTop ? { goToTop } : {})), (headerHeight != null ? { headerHeight } : {})), (headerPaddingTop != null ? { headerPaddingTop } : {})), (localePrefixAsNeeded != null ? { localePrefixAsNeeded } : {})), (navbarClassName ? { navbarClassName } : {})), (showBanner != null ? { showBanner } : {})), (showFooter != null ? { showFooter } : {})), (showGoToTop != null ? { showGoToTop } : {}));
|
|
9
|
+
const layoutProps = Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({ locale,
|
|
10
|
+
options }, (actionOrders ? { actionOrders } : {})), (banner ? { banner } : {})), (bannerHeight != null ? { bannerHeight } : {})), (defaultLocale ? { defaultLocale } : {})), (floatingNav != null ? { floatingNav } : {})), (footer ? { footer } : {})), (goToTop ? { goToTop } : {})), (headerHeight != null ? { headerHeight } : {})), (headerPaddingTop != null ? { headerPaddingTop } : {})), (localePrefixAsNeeded != null ? { localePrefixAsNeeded } : {})), (navbarClassName ? { navbarClassName } : {})), (showBanner != null ? { showBanner } : {})), (showFooter != null ? { showFooter } : {})), (showGoToTop != null ? { showGoToTop } : {})), (config.themeSwitch ? { themeSwitch: config.themeSwitch } : {}));
|
|
11
11
|
return jsx(CustomHomeLayout, Object.assign({}, layoutProps, { children: children }));
|
|
12
12
|
}
|
|
13
13
|
|
|
@@ -47,7 +47,11 @@ export interface SiteBaseLayoutConfig {
|
|
|
47
47
|
githubUrl?: string;
|
|
48
48
|
links?: SiteNavItemConfig[];
|
|
49
49
|
searchToggle?: HomeLayoutProps['searchToggle'];
|
|
50
|
-
themeSwitch?:
|
|
50
|
+
themeSwitch?: SiteThemeSwitchConfig;
|
|
51
|
+
}
|
|
52
|
+
export type SiteThemeSwitchMode = 'light-dark-system' | 'light-dark' | 'light-only' | 'dark-only';
|
|
53
|
+
export interface SiteThemeSwitchConfig {
|
|
54
|
+
mode?: SiteThemeSwitchMode;
|
|
51
55
|
}
|
|
52
56
|
export interface SiteMenuLeafConfig {
|
|
53
57
|
text: ReactNode;
|
|
@@ -38,7 +38,7 @@ function createSiteBaseLayoutConfig(options) {
|
|
|
38
38
|
} }, (options.i18n ? { i18n: options.i18n } : {})), (options.githubUrl ? { githubUrl: options.githubUrl } : {}));
|
|
39
39
|
}
|
|
40
40
|
function toHomeLayoutOptions(config) {
|
|
41
|
-
return Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(
|
|
41
|
+
return Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({}, (config.nav ? { nav: config.nav } : {})), (config.i18n ? { i18n: config.i18n } : {})), (config.githubUrl ? { githubUrl: config.githubUrl } : {})), (config.links ? { links: normalizeNavItems(config.links) } : {})), (config.searchToggle ? { searchToggle: config.searchToggle } : {}));
|
|
42
42
|
}
|
|
43
43
|
|
|
44
44
|
exports.createSiteBaseLayoutConfig = createSiteBaseLayoutConfig;
|
|
@@ -36,7 +36,7 @@ function createSiteBaseLayoutConfig(options) {
|
|
|
36
36
|
} }, (options.i18n ? { i18n: options.i18n } : {})), (options.githubUrl ? { githubUrl: options.githubUrl } : {}));
|
|
37
37
|
}
|
|
38
38
|
function toHomeLayoutOptions(config) {
|
|
39
|
-
return Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(
|
|
39
|
+
return Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({}, (config.nav ? { nav: config.nav } : {})), (config.i18n ? { i18n: config.i18n } : {})), (config.githubUrl ? { githubUrl: config.githubUrl } : {})), (config.links ? { links: normalizeNavItems(config.links) } : {})), (config.searchToggle ? { searchToggle: config.searchToggle } : {}));
|
|
40
40
|
}
|
|
41
41
|
|
|
42
42
|
export { createSiteBaseLayoutConfig, createSiteNavGroup, createSiteNavLink, normalizeNavItems, toHomeLayoutOptions };
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { ReactNode } from 'react';
|
|
2
|
+
import { type ThemeProviderProps } from 'next-themes';
|
|
3
|
+
import type { SiteThemeSwitchMode } from './site-layout-shared';
|
|
4
|
+
export interface SiteThemeProviderProps extends Omit<ThemeProviderProps, 'children'> {
|
|
5
|
+
mode?: SiteThemeSwitchMode;
|
|
6
|
+
children: ReactNode;
|
|
7
|
+
}
|
|
8
|
+
export declare function SiteThemeProvider({ mode, children, ...props }: SiteThemeProviderProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
var tslib = require('tslib');
|
|
5
|
+
var jsxRuntime = require('react/jsx-runtime');
|
|
6
|
+
var nextThemes = require('next-themes');
|
|
7
|
+
|
|
8
|
+
function SiteThemeProvider(_a) {
|
|
9
|
+
var { mode = 'light-dark-system', children } = _a, props = tslib.__rest(_a, ["mode", "children"]);
|
|
10
|
+
return (jsxRuntime.jsx(nextThemes.ThemeProvider, Object.assign({ attribute: "class", disableTransitionOnChange: true }, resolveThemeProviderProps(mode), props, { children: children })));
|
|
11
|
+
}
|
|
12
|
+
function resolveThemeProviderProps(mode) {
|
|
13
|
+
if (mode === 'light-only') {
|
|
14
|
+
return {
|
|
15
|
+
forcedTheme: 'light',
|
|
16
|
+
enableSystem: false,
|
|
17
|
+
defaultTheme: 'light',
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
if (mode === 'dark-only') {
|
|
21
|
+
return {
|
|
22
|
+
forcedTheme: 'dark',
|
|
23
|
+
enableSystem: false,
|
|
24
|
+
defaultTheme: 'dark',
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
if (mode === 'light-dark') {
|
|
28
|
+
return {
|
|
29
|
+
enableSystem: false,
|
|
30
|
+
defaultTheme: 'light',
|
|
31
|
+
forcedTheme: undefined,
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
return {
|
|
35
|
+
enableSystem: true,
|
|
36
|
+
defaultTheme: 'system',
|
|
37
|
+
forcedTheme: undefined,
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
exports.SiteThemeProvider = SiteThemeProvider;
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { __rest } from 'tslib';
|
|
3
|
+
import { jsx } from 'react/jsx-runtime';
|
|
4
|
+
import { ThemeProvider } from 'next-themes';
|
|
5
|
+
|
|
6
|
+
function SiteThemeProvider(_a) {
|
|
7
|
+
var { mode = 'light-dark-system', children } = _a, props = __rest(_a, ["mode", "children"]);
|
|
8
|
+
return (jsx(ThemeProvider, Object.assign({ attribute: "class", disableTransitionOnChange: true }, resolveThemeProviderProps(mode), props, { children: children })));
|
|
9
|
+
}
|
|
10
|
+
function resolveThemeProviderProps(mode) {
|
|
11
|
+
if (mode === 'light-only') {
|
|
12
|
+
return {
|
|
13
|
+
forcedTheme: 'light',
|
|
14
|
+
enableSystem: false,
|
|
15
|
+
defaultTheme: 'light',
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
if (mode === 'dark-only') {
|
|
19
|
+
return {
|
|
20
|
+
forcedTheme: 'dark',
|
|
21
|
+
enableSystem: false,
|
|
22
|
+
defaultTheme: 'dark',
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
if (mode === 'light-dark') {
|
|
26
|
+
return {
|
|
27
|
+
enableSystem: false,
|
|
28
|
+
defaultTheme: 'light',
|
|
29
|
+
forcedTheme: undefined,
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
return {
|
|
33
|
+
enableSystem: true,
|
|
34
|
+
defaultTheme: 'system',
|
|
35
|
+
forcedTheme: undefined,
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export { SiteThemeProvider };
|
package/package.json
CHANGED
|
@@ -35,7 +35,11 @@ import { Popover, PopoverContent, PopoverTrigger } from 'fumadocs-ui/components/
|
|
|
35
35
|
import { buttonVariants } from 'fumadocs-ui/components/ui/button';
|
|
36
36
|
import { useI18n } from 'fumadocs-ui/contexts/i18n';
|
|
37
37
|
import { HeaderThemeSwitch } from './header-theme-switch';
|
|
38
|
-
import type {
|
|
38
|
+
import type {
|
|
39
|
+
ExtendedLinkItem,
|
|
40
|
+
SiteThemeSwitchConfig,
|
|
41
|
+
SiteThemeSwitchMode,
|
|
42
|
+
} from './site-layout-shared';
|
|
39
43
|
|
|
40
44
|
export type NavbarCSSVars = CSSProperties & {
|
|
41
45
|
'--fd-banner-height'?: string;
|
|
@@ -47,7 +51,8 @@ const PrefetchLinkItem = LinkItem as (
|
|
|
47
51
|
props: ComponentProps<typeof LinkItem> & { prefetch?: boolean },
|
|
48
52
|
) => ReactNode;
|
|
49
53
|
|
|
50
|
-
export interface CustomHomeHeaderProps
|
|
54
|
+
export interface CustomHomeHeaderProps
|
|
55
|
+
extends Omit<HomeLayoutProps, 'themeSwitch'> {
|
|
51
56
|
/**
|
|
52
57
|
* Banner height in rem units
|
|
53
58
|
*
|
|
@@ -92,6 +97,7 @@ export interface CustomHomeHeaderProps extends HomeLayoutProps {
|
|
|
92
97
|
* Control order of utilities inside the mobile dropdown.
|
|
93
98
|
*/
|
|
94
99
|
mobileMenuActionsOrder?: MobileMenuAction[];
|
|
100
|
+
themeSwitch?: SiteThemeSwitchConfig;
|
|
95
101
|
}
|
|
96
102
|
|
|
97
103
|
export type DesktopAction =
|
|
@@ -175,8 +181,12 @@ export function CustomHomeHeader({
|
|
|
175
181
|
? searchToggle.components?.lg ?? null
|
|
176
182
|
: null,
|
|
177
183
|
theme:
|
|
178
|
-
themeSwitch
|
|
179
|
-
?
|
|
184
|
+
shouldShowThemeSwitch(themeSwitch?.mode)
|
|
185
|
+
? (
|
|
186
|
+
<HeaderThemeSwitch
|
|
187
|
+
mode={normalizeThemeSwitchMode(themeSwitch?.mode)}
|
|
188
|
+
/>
|
|
189
|
+
)
|
|
180
190
|
: null,
|
|
181
191
|
i18n: i18n ? (
|
|
182
192
|
<CompactLanguageToggle>
|
|
@@ -238,8 +248,12 @@ export function CustomHomeHeader({
|
|
|
238
248
|
</CompactLanguageToggle>
|
|
239
249
|
) : null,
|
|
240
250
|
theme:
|
|
241
|
-
themeSwitch
|
|
242
|
-
?
|
|
251
|
+
shouldShowThemeSwitch(themeSwitch?.mode)
|
|
252
|
+
? (
|
|
253
|
+
<HeaderThemeSwitch
|
|
254
|
+
mode={normalizeThemeSwitchMode(themeSwitch?.mode)}
|
|
255
|
+
/>
|
|
256
|
+
)
|
|
243
257
|
: null,
|
|
244
258
|
};
|
|
245
259
|
const shouldRenderMobileUtilities = mobileMenuActionsOrder.some(
|
|
@@ -356,6 +370,16 @@ export function CustomHomeHeader({
|
|
|
356
370
|
);
|
|
357
371
|
}
|
|
358
372
|
|
|
373
|
+
function shouldShowThemeSwitch(mode?: SiteThemeSwitchMode): boolean {
|
|
374
|
+
return mode === 'light-dark' || mode === 'light-dark-system' || mode == null;
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
function normalizeThemeSwitchMode(
|
|
378
|
+
mode?: SiteThemeSwitchMode,
|
|
379
|
+
): 'light-dark' | 'light-dark-system' {
|
|
380
|
+
return mode === 'light-dark' ? 'light-dark' : 'light-dark-system';
|
|
381
|
+
}
|
|
382
|
+
|
|
359
383
|
interface CustomNavbarProps extends ComponentProps<'div'> {
|
|
360
384
|
bannerHeight?: number;
|
|
361
385
|
headerHeight?: number;
|
|
@@ -3,13 +3,16 @@ import { HomeLayout, type HomeLayoutProps } from 'fumadocs-ui/layouts/home';
|
|
|
3
3
|
import { FumaBannerSuit } from '../fuma-banner-suit';
|
|
4
4
|
import { Footer } from '../../main/footer';
|
|
5
5
|
import { GoToTop } from '../../main/go-to-top';
|
|
6
|
+
import { SiteThemeProvider } from './site-theme-provider';
|
|
6
7
|
import {
|
|
7
8
|
NavbarCSSVars,
|
|
8
9
|
CustomHomeHeader,
|
|
9
10
|
type DesktopAction,
|
|
10
11
|
type MobileBarAction,
|
|
11
12
|
type MobileMenuAction,
|
|
13
|
+
type CustomHomeHeaderProps,
|
|
12
14
|
} from './custom-header';
|
|
15
|
+
import type { SiteThemeSwitchConfig } from './site-layout-shared';
|
|
13
16
|
|
|
14
17
|
// - Set bannerHeight/headerHeight to the rem values expected by the project. Use bannerHeight = 0 when there is no banner.
|
|
15
18
|
// - layoutStyle passes the variables to HomeLayout's main element, offsetting content without has-banner/no-banner classes.
|
|
@@ -91,6 +94,10 @@ export interface CustomHomeLayoutProps {
|
|
|
91
94
|
* The default locale for the application (default: 'en')
|
|
92
95
|
*/
|
|
93
96
|
defaultLocale?: string;
|
|
97
|
+
/**
|
|
98
|
+
* Theme mode for this layout group.
|
|
99
|
+
*/
|
|
100
|
+
themeSwitch?: SiteThemeSwitchConfig;
|
|
94
101
|
children?: ReactNode;
|
|
95
102
|
}
|
|
96
103
|
|
|
@@ -119,6 +126,7 @@ export function CustomHomeLayout({
|
|
|
119
126
|
actionOrders,
|
|
120
127
|
localePrefixAsNeeded = true,
|
|
121
128
|
defaultLocale = 'en',
|
|
129
|
+
themeSwitch,
|
|
122
130
|
}: CustomHomeLayoutProps) {
|
|
123
131
|
const resolvedBannerHeight = bannerHeight ?? (showBanner ? 3 : 0.5);
|
|
124
132
|
const resolvedPaddingTop =
|
|
@@ -139,6 +147,7 @@ export function CustomHomeLayout({
|
|
|
139
147
|
<CustomHomeHeader
|
|
140
148
|
{...homeLayoutProps}
|
|
141
149
|
nav={navOptions}
|
|
150
|
+
themeSwitch={themeSwitch}
|
|
142
151
|
bannerHeight={resolvedBannerHeight}
|
|
143
152
|
headerHeight={headerHeight}
|
|
144
153
|
navbarClassName={navbarClassName}
|
|
@@ -148,6 +157,7 @@ export function CustomHomeLayout({
|
|
|
148
157
|
mobileMenuActionsOrder={actionOrders?.mobileMenu}
|
|
149
158
|
/>
|
|
150
159
|
);
|
|
160
|
+
const themeMode = themeSwitch?.mode ?? 'light-dark-system';
|
|
151
161
|
|
|
152
162
|
return (
|
|
153
163
|
<>
|
|
@@ -158,19 +168,21 @@ export function CustomHomeLayout({
|
|
|
158
168
|
floating={floatingNav}
|
|
159
169
|
/>
|
|
160
170
|
)}
|
|
171
|
+
<SiteThemeProvider mode={themeMode}>
|
|
161
172
|
<HomeLayout
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
173
|
+
{...homeLayoutProps}
|
|
174
|
+
nav={{
|
|
175
|
+
...navOptions,
|
|
176
|
+
component: header,
|
|
177
|
+
}}
|
|
178
|
+
className='bg-neutral-100 dark:bg-neutral-900'
|
|
179
|
+
style={layoutStyle}
|
|
180
|
+
>
|
|
181
|
+
{children}
|
|
182
|
+
{showFooter ? footer ?? <Footer locale={locale} localePrefixAsNeeded={localePrefixAsNeeded} defaultLocale={defaultLocale} /> : null}
|
|
183
|
+
{showGoToTop ? goToTop ?? <GoToTop /> : null}
|
|
184
|
+
</HomeLayout>
|
|
185
|
+
</SiteThemeProvider>
|
|
174
186
|
</>
|
|
175
187
|
);
|
|
176
188
|
}
|
|
@@ -1,58 +1,31 @@
|
|
|
1
1
|
import type { ComponentProps, ReactNode } from 'react';
|
|
2
2
|
import { NextProvider } from 'fumadocs-core/framework/next';
|
|
3
3
|
import { I18nProvider, type I18nProviderProps } from 'fumadocs-ui/contexts/i18n';
|
|
4
|
-
import { ThemeProvider, type ThemeProviderProps } from 'next-themes';
|
|
5
4
|
|
|
6
5
|
type NextProviderComponents = {
|
|
7
6
|
Link?: ComponentProps<typeof NextProvider>['Link'];
|
|
8
7
|
Image?: ComponentProps<typeof NextProvider>['Image'];
|
|
9
8
|
};
|
|
10
9
|
|
|
11
|
-
type ThemeOptions = ThemeProviderProps & {
|
|
12
|
-
enabled?: boolean;
|
|
13
|
-
};
|
|
14
|
-
|
|
15
10
|
export interface DocsRootProviderProps {
|
|
16
11
|
i18n: Omit<I18nProviderProps, 'children'>;
|
|
17
|
-
theme?: ThemeOptions;
|
|
18
12
|
components?: NextProviderComponents;
|
|
19
13
|
children: ReactNode;
|
|
20
14
|
}
|
|
21
15
|
|
|
22
16
|
export function DocsRootProvider({
|
|
23
17
|
i18n,
|
|
24
|
-
theme = {},
|
|
25
18
|
components,
|
|
26
19
|
children,
|
|
27
20
|
}: DocsRootProviderProps) {
|
|
28
|
-
let body = children;
|
|
29
|
-
|
|
30
|
-
if (theme.enabled !== false) {
|
|
31
|
-
body = (
|
|
32
|
-
<ThemeProvider
|
|
33
|
-
attribute="class"
|
|
34
|
-
defaultTheme="system"
|
|
35
|
-
enableSystem
|
|
36
|
-
disableTransitionOnChange
|
|
37
|
-
{...theme}
|
|
38
|
-
>
|
|
39
|
-
{body}
|
|
40
|
-
</ThemeProvider>
|
|
41
|
-
);
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
body = (
|
|
45
|
-
<I18nProvider {...i18n}>
|
|
46
|
-
{body}
|
|
47
|
-
</I18nProvider>
|
|
48
|
-
);
|
|
49
|
-
|
|
50
21
|
return (
|
|
51
22
|
<NextProvider
|
|
52
23
|
Link={components?.Link}
|
|
53
24
|
Image={components?.Image}
|
|
54
25
|
>
|
|
55
|
-
{
|
|
26
|
+
<I18nProvider {...i18n}>
|
|
27
|
+
{children}
|
|
28
|
+
</I18nProvider>
|
|
56
29
|
</NextProvider>
|
|
57
30
|
);
|
|
58
31
|
}
|
|
@@ -5,6 +5,7 @@ import { AirplayIcon, MoonIcon, SunIcon } from '@windrun-huaiin/base-ui/icons';
|
|
|
5
5
|
import { useTheme } from 'next-themes';
|
|
6
6
|
import { type ComponentProps, useEffect, useState } from 'react';
|
|
7
7
|
import { cn } from '@windrun-huaiin/lib/utils';
|
|
8
|
+
import type { SiteThemeSwitchMode } from './site-layout-shared';
|
|
8
9
|
|
|
9
10
|
const itemVariants = cva('inline-flex size-6.5 items-center justify-center rounded-full p-1.5', {
|
|
10
11
|
variants: {
|
|
@@ -18,7 +19,7 @@ const itemVariants = cva('inline-flex size-6.5 items-center justify-center round
|
|
|
18
19
|
const full = [['light', SunIcon] as const, ['dark', MoonIcon] as const, ['system', AirplayIcon] as const];
|
|
19
20
|
|
|
20
21
|
export interface HeaderThemeSwitchProps extends ComponentProps<'div'> {
|
|
21
|
-
mode?: 'light-
|
|
22
|
+
mode?: Exclude<SiteThemeSwitchMode, 'light-only' | 'dark-only'>;
|
|
22
23
|
}
|
|
23
24
|
|
|
24
25
|
export function HeaderThemeSwitch({
|
|
@@ -4,20 +4,36 @@ import {
|
|
|
4
4
|
normalizeNavItems,
|
|
5
5
|
type SiteBaseLayoutConfig,
|
|
6
6
|
} from './site-layout-shared';
|
|
7
|
+
import { SiteThemeProvider } from './site-theme-provider';
|
|
7
8
|
|
|
8
9
|
export interface SiteDocsLayoutConfig extends SiteBaseLayoutConfig {
|
|
9
10
|
tree: DocsLayoutProps['tree'];
|
|
10
11
|
sidebar?: DocsLayoutProps['sidebar'];
|
|
12
|
+
themeProvider?: boolean;
|
|
11
13
|
}
|
|
12
14
|
|
|
13
15
|
function toDocsLayoutOptions(config: SiteDocsLayoutConfig): DocsLayoutProps {
|
|
16
|
+
const themeMode = config.themeSwitch?.mode ?? 'light-dark-system';
|
|
17
|
+
const shouldShowThemeSwitch =
|
|
18
|
+
config.themeProvider !== false &&
|
|
19
|
+
(themeMode === 'light-dark' || themeMode === 'light-dark-system');
|
|
14
20
|
return {
|
|
15
21
|
...(config.nav ? { nav: config.nav } : {}),
|
|
16
22
|
...(config.i18n ? { i18n: config.i18n } : {}),
|
|
17
23
|
...(config.githubUrl ? { githubUrl: config.githubUrl } : {}),
|
|
18
24
|
...(config.links ? { links: normalizeNavItems(config.links) } : {}),
|
|
19
25
|
...(config.searchToggle ? { searchToggle: config.searchToggle } : {}),
|
|
20
|
-
...(
|
|
26
|
+
...(shouldShowThemeSwitch
|
|
27
|
+
? {
|
|
28
|
+
themeSwitch: {
|
|
29
|
+
mode: themeMode,
|
|
30
|
+
},
|
|
31
|
+
}
|
|
32
|
+
: {
|
|
33
|
+
themeSwitch: {
|
|
34
|
+
enabled: false,
|
|
35
|
+
},
|
|
36
|
+
}),
|
|
21
37
|
...(config.sidebar ? { sidebar: config.sidebar } : {}),
|
|
22
38
|
tree: config.tree,
|
|
23
39
|
};
|
|
@@ -31,5 +47,10 @@ export function SiteDocsLayout({
|
|
|
31
47
|
children: ReactNode;
|
|
32
48
|
}) {
|
|
33
49
|
const options = toDocsLayoutOptions(config);
|
|
34
|
-
|
|
50
|
+
const themeMode = config.themeSwitch?.mode ?? 'light-dark-system';
|
|
51
|
+
const body = <DocsLayout {...options}>{children}</DocsLayout>;
|
|
52
|
+
|
|
53
|
+
if (config.themeProvider === false) return body;
|
|
54
|
+
|
|
55
|
+
return <SiteThemeProvider mode={themeMode}>{body}</SiteThemeProvider>;
|
|
35
56
|
}
|
|
@@ -72,6 +72,7 @@ export function SiteHomeLayout({
|
|
|
72
72
|
...(showBanner != null ? { showBanner } : {}),
|
|
73
73
|
...(showFooter != null ? { showFooter } : {}),
|
|
74
74
|
...(showGoToTop != null ? { showGoToTop } : {}),
|
|
75
|
+
...(config.themeSwitch ? { themeSwitch: config.themeSwitch } : {}),
|
|
75
76
|
};
|
|
76
77
|
|
|
77
78
|
return <CustomHomeLayout {...layoutProps}>{children}</CustomHomeLayout>;
|
|
@@ -58,7 +58,17 @@ export interface SiteBaseLayoutConfig {
|
|
|
58
58
|
githubUrl?: string;
|
|
59
59
|
links?: SiteNavItemConfig[];
|
|
60
60
|
searchToggle?: HomeLayoutProps['searchToggle'];
|
|
61
|
-
themeSwitch?:
|
|
61
|
+
themeSwitch?: SiteThemeSwitchConfig;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export type SiteThemeSwitchMode =
|
|
65
|
+
| 'light-dark-system'
|
|
66
|
+
| 'light-dark'
|
|
67
|
+
| 'light-only'
|
|
68
|
+
| 'dark-only';
|
|
69
|
+
|
|
70
|
+
export interface SiteThemeSwitchConfig {
|
|
71
|
+
mode?: SiteThemeSwitchMode;
|
|
62
72
|
}
|
|
63
73
|
|
|
64
74
|
export interface SiteMenuLeafConfig {
|
|
@@ -185,6 +195,5 @@ export function toHomeLayoutOptions(config: SiteBaseLayoutConfig): HomeLayoutPro
|
|
|
185
195
|
...(config.githubUrl ? { githubUrl: config.githubUrl } : {}),
|
|
186
196
|
...(config.links ? { links: normalizeNavItems(config.links) } : {}),
|
|
187
197
|
...(config.searchToggle ? { searchToggle: config.searchToggle } : {}),
|
|
188
|
-
...(config.themeSwitch ? { themeSwitch: config.themeSwitch } : {}),
|
|
189
198
|
};
|
|
190
199
|
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import type { ReactNode } from 'react';
|
|
4
|
+
import { ThemeProvider, type ThemeProviderProps } from 'next-themes';
|
|
5
|
+
import type { SiteThemeSwitchMode } from './site-layout-shared';
|
|
6
|
+
|
|
7
|
+
export interface SiteThemeProviderProps extends Omit<ThemeProviderProps, 'children'> {
|
|
8
|
+
mode?: SiteThemeSwitchMode;
|
|
9
|
+
children: ReactNode;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export function SiteThemeProvider({
|
|
13
|
+
mode = 'light-dark-system',
|
|
14
|
+
children,
|
|
15
|
+
...props
|
|
16
|
+
}: SiteThemeProviderProps) {
|
|
17
|
+
return (
|
|
18
|
+
<ThemeProvider
|
|
19
|
+
attribute="class"
|
|
20
|
+
disableTransitionOnChange
|
|
21
|
+
{...resolveThemeProviderProps(mode)}
|
|
22
|
+
{...props}
|
|
23
|
+
>
|
|
24
|
+
{children}
|
|
25
|
+
</ThemeProvider>
|
|
26
|
+
);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function resolveThemeProviderProps(mode: SiteThemeSwitchMode): ThemeProviderProps {
|
|
30
|
+
if (mode === 'light-only') {
|
|
31
|
+
return {
|
|
32
|
+
forcedTheme: 'light',
|
|
33
|
+
enableSystem: false,
|
|
34
|
+
defaultTheme: 'light',
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
if (mode === 'dark-only') {
|
|
39
|
+
return {
|
|
40
|
+
forcedTheme: 'dark',
|
|
41
|
+
enableSystem: false,
|
|
42
|
+
defaultTheme: 'dark',
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
if (mode === 'light-dark') {
|
|
47
|
+
return {
|
|
48
|
+
enableSystem: false,
|
|
49
|
+
defaultTheme: 'light',
|
|
50
|
+
forcedTheme: undefined,
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
return {
|
|
55
|
+
enableSystem: true,
|
|
56
|
+
defaultTheme: 'system',
|
|
57
|
+
forcedTheme: undefined,
|
|
58
|
+
};
|
|
59
|
+
}
|