@windrun-huaiin/third-ui 31.1.0 → 31.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (41) hide show
  1. package/dist/fuma/base/custom-header.d.ts +2 -4
  2. package/dist/fuma/base/custom-header.js +9 -7
  3. package/dist/fuma/base/custom-header.mjs +9 -7
  4. package/dist/fuma/base/custom-home-layout.d.ts +1 -6
  5. package/dist/fuma/base/custom-home-layout.js +3 -6
  6. package/dist/fuma/base/custom-home-layout.mjs +3 -6
  7. package/dist/fuma/base/docs-root-provider.d.ts +3 -1
  8. package/dist/fuma/base/docs-root-provider.js +5 -2
  9. package/dist/fuma/base/docs-root-provider.mjs +5 -2
  10. package/dist/fuma/base/header-theme-switch.d.ts +2 -3
  11. package/dist/fuma/base/header-theme-switch.js +2 -10
  12. package/dist/fuma/base/header-theme-switch.mjs +2 -10
  13. package/dist/fuma/base/site-docs-layout.d.ts +1 -1
  14. package/dist/fuma/base/site-docs-layout.js +3 -22
  15. package/dist/fuma/base/site-docs-layout.mjs +3 -22
  16. package/dist/fuma/base/site-docs-theme-switch.d.ts +2 -0
  17. package/dist/fuma/base/site-docs-theme-switch.js +16 -0
  18. package/dist/fuma/base/site-docs-theme-switch.mjs +14 -0
  19. package/dist/fuma/base/site-home-layout.js +2 -2
  20. package/dist/fuma/base/site-home-layout.mjs +2 -2
  21. package/dist/fuma/base/site-layout-shared.d.ts +1 -2
  22. package/dist/fuma/base/site-theme-context.d.ts +8 -0
  23. package/dist/fuma/base/site-theme-context.js +19 -0
  24. package/dist/fuma/base/site-theme-context.mjs +16 -0
  25. package/dist/fuma/base/site-theme-provider.js +0 -7
  26. package/dist/fuma/base/site-theme-provider.mjs +0 -7
  27. package/dist/fuma/fuma-page-genarator.d.ts +1 -2
  28. package/dist/fuma/fuma-page-genarator.js +4 -3
  29. package/dist/fuma/fuma-page-genarator.mjs +4 -3
  30. package/package.json +2 -2
  31. package/src/fuma/base/custom-header.tsx +10 -12
  32. package/src/fuma/base/custom-home-layout.tsx +0 -12
  33. package/src/fuma/base/docs-root-provider.tsx +9 -1
  34. package/src/fuma/base/header-theme-switch.tsx +2 -32
  35. package/src/fuma/base/site-docs-layout.tsx +7 -22
  36. package/src/fuma/base/site-docs-theme-switch.tsx +15 -0
  37. package/src/fuma/base/site-home-layout.tsx +0 -1
  38. package/src/fuma/base/site-layout-shared.tsx +0 -2
  39. package/src/fuma/base/site-theme-context.tsx +30 -0
  40. package/src/fuma/base/site-theme-provider.tsx +0 -8
  41. package/src/fuma/fuma-page-genarator.tsx +3 -7
@@ -1,12 +1,11 @@
1
1
  import { type CSSProperties } from 'react';
2
2
  import { HomeLayoutProps } from 'fumadocs-ui/layouts/home';
3
- import type { SiteThemeSwitchConfig } from './site-layout-shared';
4
3
  export type NavbarCSSVars = CSSProperties & {
5
4
  '--fd-banner-height'?: string;
6
5
  '--fd-header-height'?: string;
7
6
  '--fd-nav-max-width'?: string;
8
7
  };
9
- export interface CustomHomeHeaderProps extends Omit<HomeLayoutProps, 'themeSwitch'> {
8
+ export interface CustomHomeHeaderProps extends HomeLayoutProps {
10
9
  /**
11
10
  * Banner height in rem units
12
11
  *
@@ -47,9 +46,8 @@ export interface CustomHomeHeaderProps extends Omit<HomeLayoutProps, 'themeSwitc
47
46
  * Control order of utilities inside the mobile dropdown.
48
47
  */
49
48
  mobileMenuActionsOrder?: MobileMenuAction[];
50
- themeSwitch?: SiteThemeSwitchConfig;
51
49
  }
52
50
  export type DesktopAction = 'search' | 'theme' | 'i18n' | 'secondary' | 'github';
53
51
  export type MobileBarAction = 'pinned' | 'search' | 'menu';
54
52
  export type MobileMenuAction = 'secondary' | 'github' | 'separator' | 'i18n' | 'theme';
55
- export declare function CustomHomeHeader({ nav, i18n, links, githubUrl, themeSwitch, searchToggle, bannerHeight, headerHeight, maxContentWidth, navbarClassName, floating, desktopActionsOrder, mobileBarActionsOrder, mobileMenuActionsOrder, }: CustomHomeHeaderProps): import("react/jsx-runtime").JSX.Element;
53
+ export declare function CustomHomeHeader({ nav, i18n, links, githubUrl, searchToggle, bannerHeight, headerHeight, maxContentWidth, navbarClassName, floating, desktopActionsOrder, mobileBarActionsOrder, mobileMenuActionsOrder, }: CustomHomeHeaderProps): import("react/jsx-runtime").JSX.Element;
@@ -15,6 +15,7 @@ var popover = require('fumadocs-ui/components/ui/popover');
15
15
  var button = require('fumadocs-ui/components/ui/button');
16
16
  var i18n = require('fumadocs-ui/contexts/i18n');
17
17
  var headerThemeSwitch = require('./header-theme-switch.js');
18
+ var siteThemeContext = require('./site-theme-context.js');
18
19
 
19
20
  const PrefetchLinkItem = shared.LinkItem;
20
21
  const DEFAULT_DESKTOP_ACTIONS = [
@@ -34,8 +35,9 @@ const DEFAULT_MOBILE_MENU_ACTIONS = [
34
35
  'i18n',
35
36
  'theme',
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
+ function CustomHomeHeader({ nav = {}, i18n = false, links, githubUrl, 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
39
  var _a, _b, _c, _d, _e;
40
+ const themeMode = siteThemeContext.useSiteThemeMode();
39
41
  const finalLinks = React.useMemo(() => shared.resolveLinkItems({ links, githubUrl }), [links, githubUrl]);
40
42
  const navItems = finalLinks.filter((item) => { var _a; return ['nav', 'all'].includes((_a = item.on) !== null && _a !== void 0 ? _a : 'all'); });
41
43
  const menuItems = finalLinks.filter((item) => { var _a; return ['menu', 'all'].includes((_a = item.on) !== null && _a !== void 0 ? _a : 'all'); });
@@ -55,8 +57,8 @@ function CustomHomeHeader({ nav = {}, i18n = false, links, githubUrl, themeSwitc
55
57
  search: searchToggle.enabled !== false
56
58
  ? (_b = (_a = searchToggle.components) === null || _a === void 0 ? void 0 : _a.lg) !== null && _b !== void 0 ? _b : null
57
59
  : null,
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
+ theme: shouldShowThemeSwitch(themeMode)
61
+ ? (jsxRuntime.jsx(headerThemeSwitch.HeaderThemeSwitch, { mode: normalizeThemeSwitchMode() }))
60
62
  : null,
61
63
  i18n: i18n ? (jsxRuntime.jsx(CompactLanguageToggle, { children: jsxRuntime.jsx(icons.LanguagesIcon, { className: "size-5" }) })) : null,
62
64
  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 +80,8 @@ function CustomHomeHeader({ nav = {}, i18n = false, links, githubUrl, themeSwitc
78
80
  github: githubMobileMenuItem ? (jsxRuntime.jsx(MenuLinkItem, { item: githubMobileMenuItem, className: "-me-1.5" })) : null,
79
81
  separator: jsxRuntime.jsx("div", { role: "separator", className: "flex-1" }),
80
82
  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: 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
+ theme: shouldShowThemeSwitch(themeMode)
84
+ ? (jsxRuntime.jsx(headerThemeSwitch.HeaderThemeSwitch, { mode: normalizeThemeSwitchMode() }))
83
85
  : null,
84
86
  };
85
87
  const shouldRenderMobileUtilities = mobileMenuActionsOrder.some((action) => action !== 'separator' && Boolean(mobileMenuActionNodes[action]));
@@ -121,10 +123,10 @@ function CustomHomeHeader({ nav = {}, i18n = false, links, githubUrl, themeSwitc
121
123
  }) })] }));
122
124
  }
123
125
  function shouldShowThemeSwitch(mode) {
124
- return mode === 'light-dark' || mode === 'light-dark-system' || mode == null;
126
+ return mode === 'light-dark-system' || mode == null;
125
127
  }
126
128
  function normalizeThemeSwitchMode(mode) {
127
- return mode === 'light-dark' ? 'light-dark' : 'light-dark-system';
129
+ return 'light-dark-system';
128
130
  }
129
131
  function CustomNavbar(_a) {
130
132
  var { bannerHeight = 0, headerHeight = 2.5, maxContentWidth = 1400, className, style, floating = false } = _a, props = tslib.__rest(_a, ["bannerHeight", "headerHeight", "maxContentWidth", "className", "style", "floating"]);
@@ -13,6 +13,7 @@ import { Popover, PopoverTrigger, PopoverContent } from 'fumadocs-ui/components/
13
13
  import { buttonVariants } from 'fumadocs-ui/components/ui/button';
14
14
  import { useI18n } from 'fumadocs-ui/contexts/i18n';
15
15
  import { HeaderThemeSwitch } from './header-theme-switch.mjs';
16
+ import { useSiteThemeMode } from './site-theme-context.mjs';
16
17
 
17
18
  const PrefetchLinkItem = LinkItem;
18
19
  const DEFAULT_DESKTOP_ACTIONS = [
@@ -32,8 +33,9 @@ const DEFAULT_MOBILE_MENU_ACTIONS = [
32
33
  'i18n',
33
34
  'theme',
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
+ function CustomHomeHeader({ nav = {}, i18n = false, links, githubUrl, 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
37
  var _a, _b, _c, _d, _e;
38
+ const themeMode = useSiteThemeMode();
37
39
  const finalLinks = useMemo(() => resolveLinkItems({ links, githubUrl }), [links, githubUrl]);
38
40
  const navItems = finalLinks.filter((item) => { var _a; return ['nav', 'all'].includes((_a = item.on) !== null && _a !== void 0 ? _a : 'all'); });
39
41
  const menuItems = finalLinks.filter((item) => { var _a; return ['menu', 'all'].includes((_a = item.on) !== null && _a !== void 0 ? _a : 'all'); });
@@ -53,8 +55,8 @@ function CustomHomeHeader({ nav = {}, i18n = false, links, githubUrl, themeSwitc
53
55
  search: searchToggle.enabled !== false
54
56
  ? (_b = (_a = searchToggle.components) === null || _a === void 0 ? void 0 : _a.lg) !== null && _b !== void 0 ? _b : null
55
57
  : null,
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
+ theme: shouldShowThemeSwitch(themeMode)
59
+ ? (jsx(HeaderThemeSwitch, { mode: normalizeThemeSwitchMode() }))
58
60
  : null,
59
61
  i18n: i18n ? (jsx(CompactLanguageToggle, { children: jsx(LanguagesIcon, { className: "size-5" }) })) : null,
60
62
  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 +78,8 @@ function CustomHomeHeader({ nav = {}, i18n = false, links, githubUrl, themeSwitc
76
78
  github: githubMobileMenuItem ? (jsx(MenuLinkItem, { item: githubMobileMenuItem, className: "-me-1.5" })) : null,
77
79
  separator: jsx("div", { role: "separator", className: "flex-1" }),
78
80
  i18n: i18n ? (jsxs(CompactLanguageToggle, { children: [jsx(LanguagesIcon, { className: "size-5" }), jsx(LanguageSelectText, {}), jsx(ChevronDownIcon, { className: "size-3 text-fd-muted-foreground" })] })) : null,
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
+ theme: shouldShowThemeSwitch(themeMode)
82
+ ? (jsx(HeaderThemeSwitch, { mode: normalizeThemeSwitchMode() }))
81
83
  : null,
82
84
  };
83
85
  const shouldRenderMobileUtilities = mobileMenuActionsOrder.some((action) => action !== 'separator' && Boolean(mobileMenuActionNodes[action]));
@@ -119,10 +121,10 @@ function CustomHomeHeader({ nav = {}, i18n = false, links, githubUrl, themeSwitc
119
121
  }) })] }));
120
122
  }
121
123
  function shouldShowThemeSwitch(mode) {
122
- return mode === 'light-dark' || mode === 'light-dark-system' || mode == null;
124
+ return mode === 'light-dark-system' || mode == null;
123
125
  }
124
126
  function normalizeThemeSwitchMode(mode) {
125
- return mode === 'light-dark' ? 'light-dark' : 'light-dark-system';
127
+ return 'light-dark-system';
126
128
  }
127
129
  function CustomNavbar(_a) {
128
130
  var { bannerHeight = 0, headerHeight = 2.5, maxContentWidth = 1400, className, style, floating = false } = _a, props = __rest(_a, ["bannerHeight", "headerHeight", "maxContentWidth", "className", "style", "floating"]);
@@ -1,7 +1,6 @@
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';
5
4
  export interface CustomHomeLayoutProps {
6
5
  locale: string;
7
6
  options: HomeLayoutProps;
@@ -77,10 +76,6 @@ export interface CustomHomeLayoutProps {
77
76
  * The default locale for the application (default: 'en')
78
77
  */
79
78
  defaultLocale?: string;
80
- /**
81
- * Theme mode for this layout group.
82
- */
83
- themeSwitch?: SiteThemeSwitchConfig;
84
79
  children?: ReactNode;
85
80
  }
86
81
  export interface HeaderActionOrders {
@@ -88,7 +83,7 @@ export interface HeaderActionOrders {
88
83
  mobileBar?: MobileBarAction[];
89
84
  mobileMenu?: MobileMenuAction[];
90
85
  }
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;
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;
92
87
  export declare function HomeTitle({ children, className, }: {
93
88
  children: ReactNode;
94
89
  className?: string;
@@ -6,11 +6,9 @@ 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');
10
9
  var customHeader = require('./custom-header.js');
11
10
 
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;
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', }) {
14
12
  const resolvedBannerHeight = bannerHeight !== null && bannerHeight !== void 0 ? bannerHeight : (showBanner ? 3 : 0.5);
15
13
  const resolvedPaddingTop = headerPaddingTop !== null && headerPaddingTop !== void 0 ? headerPaddingTop : (showBanner ? 0 : 0.5);
16
14
  const layoutStyle = Object.assign({ '--fd-banner-height': `${resolvedBannerHeight}rem`, '--fd-header-height': `${headerHeight}rem`, paddingTop: floatingNav
@@ -18,9 +16,8 @@ function CustomHomeLayout({ locale, options, children, showBanner = false, banne
18
16
  : `${resolvedPaddingTop}rem` }, style);
19
17
  const { nav } = options, homeLayoutProps = tslib.__rest(options, ["nav"]);
20
18
  const navOptions = nav !== null && nav !== void 0 ? nav : {};
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] })) })] }));
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
+ return (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [banner !== null && banner !== void 0 ? banner : (jsxRuntime.jsx(fumaBannerSuit.FumaBannerSuit, { locale: locale, showBanner: showBanner, floating: floatingNav })), 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] }))] }));
24
21
  }
25
22
  function HomeTitle({ children, className, }) {
26
23
  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,11 +4,9 @@ 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';
8
7
  import { CustomHomeHeader } from './custom-header.mjs';
9
8
 
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;
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', }) {
12
10
  const resolvedBannerHeight = bannerHeight !== null && bannerHeight !== void 0 ? bannerHeight : (showBanner ? 3 : 0.5);
13
11
  const resolvedPaddingTop = headerPaddingTop !== null && headerPaddingTop !== void 0 ? headerPaddingTop : (showBanner ? 0 : 0.5);
14
12
  const layoutStyle = Object.assign({ '--fd-banner-height': `${resolvedBannerHeight}rem`, '--fd-header-height': `${headerHeight}rem`, paddingTop: floatingNav
@@ -16,9 +14,8 @@ function CustomHomeLayout({ locale, options, children, showBanner = false, banne
16
14
  : `${resolvedPaddingTop}rem` }, style);
17
15
  const { nav } = options, homeLayoutProps = __rest(options, ["nav"]);
18
16
  const navOptions = nav !== null && nav !== void 0 ? nav : {};
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] })) })] }));
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
+ return (jsxs(Fragment, { children: [banner !== null && banner !== void 0 ? banner : (jsx(FumaBannerSuit, { locale: locale, showBanner: showBanner, floating: floatingNav })), 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] }))] }));
22
19
  }
23
20
  function HomeTitle({ children, className, }) {
24
21
  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,14 +1,16 @@
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 { SiteThemeProviderProps } from './site-theme-provider';
4
5
  type NextProviderComponents = {
5
6
  Link?: ComponentProps<typeof NextProvider>['Link'];
6
7
  Image?: ComponentProps<typeof NextProvider>['Image'];
7
8
  };
8
9
  export interface DocsRootProviderProps {
9
10
  i18n: Omit<I18nProviderProps, 'children'>;
11
+ theme?: Omit<SiteThemeProviderProps, 'children'>;
10
12
  components?: NextProviderComponents;
11
13
  children: ReactNode;
12
14
  }
13
- export declare function DocsRootProvider({ i18n, components, children, }: DocsRootProviderProps): import("react/jsx-runtime").JSX.Element;
15
+ export declare function DocsRootProvider({ i18n, theme, components, children, }: DocsRootProviderProps): import("react/jsx-runtime").JSX.Element;
14
16
  export {};
@@ -3,9 +3,12 @@
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 siteThemeContext = require('./site-theme-context.js');
6
7
 
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 })) }));
8
+ function DocsRootProvider({ i18n: i18n$1, theme = {}, components, children, }) {
9
+ var _a;
10
+ const themeMode = (_a = theme.mode) !== null && _a !== void 0 ? _a : 'light-dark-system';
11
+ 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: jsxRuntime.jsx(siteThemeContext.SiteThemeRootProvider, Object.assign({}, theme, { mode: themeMode, children: children })) })) }));
9
12
  }
10
13
 
11
14
  exports.DocsRootProvider = DocsRootProvider;
@@ -1,9 +1,12 @@
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 { SiteThemeRootProvider } from './site-theme-context.mjs';
4
5
 
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 })) }));
6
+ function DocsRootProvider({ i18n, theme = {}, components, children, }) {
7
+ var _a;
8
+ const themeMode = (_a = theme.mode) !== null && _a !== void 0 ? _a : 'light-dark-system';
9
+ 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: jsx(SiteThemeRootProvider, Object.assign({}, theme, { mode: themeMode, children: children })) })) }));
7
10
  }
8
11
 
9
12
  export { DocsRootProvider };
@@ -1,6 +1,5 @@
1
1
  import { type ComponentProps } from 'react';
2
- import type { SiteThemeSwitchMode } from './site-layout-shared';
3
2
  export interface HeaderThemeSwitchProps extends ComponentProps<'div'> {
4
- mode?: Exclude<SiteThemeSwitchMode, 'light-only' | 'dark-only'>;
3
+ mode?: 'light-dark-system';
5
4
  }
6
- export declare function HeaderThemeSwitch({ className, mode, ...props }: HeaderThemeSwitchProps): import("react/jsx-runtime").JSX.Element;
5
+ export declare function HeaderThemeSwitch({ className, ...props }: HeaderThemeSwitchProps): import("react/jsx-runtime").JSX.Element;
@@ -19,22 +19,14 @@ const itemVariants = classVarianceAuthority.cva('inline-flex size-6.5 items-cent
19
19
  });
20
20
  const full = [['light', icons.SunIcon], ['dark', icons.MoonIcon], ['system', icons.AirplayIcon]];
21
21
  function HeaderThemeSwitch(_a) {
22
- var { className, mode = 'light-dark' } = _a, props = tslib.__rest(_a, ["className", "mode"]);
23
- const { setTheme, theme, resolvedTheme } = nextThemes.useTheme();
22
+ var { className } = _a, props = tslib.__rest(_a, ["className"]);
23
+ const { setTheme, theme } = nextThemes.useTheme();
24
24
  const [mounted, setMounted] = React.useState(false);
25
25
  React.useEffect(() => {
26
26
  setMounted(true);
27
27
  }, []);
28
28
  const container = utils.cn('inline-flex items-center rounded-full border p-1 overflow-hidden *:rounded-full', className);
29
29
  const iconClassName = 'size-3.5 text-neutral-600 dark:text-neutral-300';
30
- if (mode === 'light-dark') {
31
- const value = mounted ? resolvedTheme : null;
32
- return (jsxRuntime.jsx("button", { type: "button", className: container, "aria-label": "Toggle Theme", onClick: () => setTheme(value === 'light' ? 'dark' : 'light'), "data-theme-toggle": "", children: full.map(([key, Icon]) => {
33
- if (key === 'system')
34
- return null;
35
- return (jsxRuntime.jsx(Icon, { fill: "currentColor", className: utils.cn(itemVariants({ active: value === key }), iconClassName) }, key));
36
- }) }));
37
- }
38
30
  const value = mounted ? theme : null;
39
31
  return (jsxRuntime.jsx("div", Object.assign({ className: container, "data-theme-toggle": "" }, props, { children: full.map(([key, Icon]) => (jsxRuntime.jsx("button", { type: "button", "aria-label": key, className: utils.cn(itemVariants({ active: value === key })), onClick: () => setTheme(key), children: jsxRuntime.jsx(Icon, { className: iconClassName, fill: "currentColor" }) }, key))) })));
40
32
  }
@@ -17,22 +17,14 @@ const itemVariants = cva('inline-flex size-6.5 items-center justify-center round
17
17
  });
18
18
  const full = [['light', SunIcon], ['dark', MoonIcon], ['system', AirplayIcon]];
19
19
  function HeaderThemeSwitch(_a) {
20
- var { className, mode = 'light-dark' } = _a, props = __rest(_a, ["className", "mode"]);
21
- const { setTheme, theme, resolvedTheme } = useTheme();
20
+ var { className } = _a, props = __rest(_a, ["className"]);
21
+ const { setTheme, theme } = useTheme();
22
22
  const [mounted, setMounted] = useState(false);
23
23
  useEffect(() => {
24
24
  setMounted(true);
25
25
  }, []);
26
26
  const container = cn('inline-flex items-center rounded-full border p-1 overflow-hidden *:rounded-full', className);
27
27
  const iconClassName = 'size-3.5 text-neutral-600 dark:text-neutral-300';
28
- if (mode === 'light-dark') {
29
- const value = mounted ? resolvedTheme : null;
30
- return (jsx("button", { type: "button", className: container, "aria-label": "Toggle Theme", onClick: () => setTheme(value === 'light' ? 'dark' : 'light'), "data-theme-toggle": "", children: full.map(([key, Icon]) => {
31
- if (key === 'system')
32
- return null;
33
- return (jsx(Icon, { fill: "currentColor", className: cn(itemVariants({ active: value === key }), iconClassName) }, key));
34
- }) }));
35
- }
36
28
  const value = mounted ? theme : null;
37
29
  return (jsx("div", Object.assign({ className: container, "data-theme-toggle": "" }, props, { children: full.map(([key, Icon]) => (jsx("button", { type: "button", "aria-label": key, className: cn(itemVariants({ active: value === key })), onClick: () => setTheme(key), children: jsx(Icon, { className: iconClassName, fill: "currentColor" }) }, key))) })));
38
30
  }
@@ -4,7 +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
+ slots?: DocsLayoutProps['slots'];
8
8
  }
9
9
  export declare function SiteDocsLayout({ config, children, }: {
10
10
  config: SiteDocsLayoutConfig;
@@ -3,33 +3,14 @@
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
+ var siteDocsThemeSwitch = require('./site-docs-theme-switch.js');
7
7
 
8
8
  function toDocsLayoutOptions(config) {
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
+ 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 } : {})), { slots: Object.assign(Object.assign({}, config.slots), { themeSwitch: siteDocsThemeSwitch.SiteDocsThemeSwitch }) }), (config.sidebar ? { sidebar: config.sidebar } : {})), { tree: config.tree });
24
10
  }
25
11
  function SiteDocsLayout({ config, children, }) {
26
- var _a, _b;
27
12
  const options = toDocsLayoutOptions(config);
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
+ return jsxRuntime.jsx(docs.DocsLayout, Object.assign({}, options, { children: children }));
33
14
  }
34
15
 
35
16
  exports.SiteDocsLayout = SiteDocsLayout;
@@ -1,33 +1,14 @@
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
+ import { SiteDocsThemeSwitch } from './site-docs-theme-switch.mjs';
5
5
 
6
6
  function toDocsLayoutOptions(config) {
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
+ 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 } : {})), { slots: Object.assign(Object.assign({}, config.slots), { themeSwitch: SiteDocsThemeSwitch }) }), (config.sidebar ? { sidebar: config.sidebar } : {})), { tree: config.tree });
22
8
  }
23
9
  function SiteDocsLayout({ config, children, }) {
24
- var _a, _b;
25
10
  const options = toDocsLayoutOptions(config);
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
+ return jsx(DocsLayout, Object.assign({}, options, { children: children }));
31
12
  }
32
13
 
33
14
  export { SiteDocsLayout };
@@ -0,0 +1,2 @@
1
+ import type { ComponentProps } from 'react';
2
+ export declare function SiteDocsThemeSwitch(props: ComponentProps<'div'>): import("react/jsx-runtime").JSX.Element | null;
@@ -0,0 +1,16 @@
1
+ "use client";
2
+ 'use strict';
3
+
4
+ var jsxRuntime = require('react/jsx-runtime');
5
+ var headerThemeSwitch = require('./header-theme-switch.js');
6
+ var siteThemeContext = require('./site-theme-context.js');
7
+
8
+ function SiteDocsThemeSwitch(props) {
9
+ const themeMode = siteThemeContext.useSiteThemeMode();
10
+ if (themeMode !== 'light-dark-system') {
11
+ return null;
12
+ }
13
+ return jsxRuntime.jsx(headerThemeSwitch.HeaderThemeSwitch, Object.assign({}, props, { mode: "light-dark-system" }));
14
+ }
15
+
16
+ exports.SiteDocsThemeSwitch = SiteDocsThemeSwitch;
@@ -0,0 +1,14 @@
1
+ "use client";
2
+ import { jsx } from 'react/jsx-runtime';
3
+ import { HeaderThemeSwitch } from './header-theme-switch.mjs';
4
+ import { useSiteThemeMode } from './site-theme-context.mjs';
5
+
6
+ function SiteDocsThemeSwitch(props) {
7
+ const themeMode = useSiteThemeMode();
8
+ if (themeMode !== 'light-dark-system') {
9
+ return null;
10
+ }
11
+ return jsx(HeaderThemeSwitch, Object.assign({}, props, { mode: "light-dark-system" }));
12
+ }
13
+
14
+ export { SiteDocsThemeSwitch };
@@ -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(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 } : {}));
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 } : {}));
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(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 } : {}));
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 } : {}));
11
11
  return jsx(CustomHomeLayout, Object.assign({}, layoutProps, { children: children }));
12
12
  }
13
13
 
@@ -47,9 +47,8 @@ export interface SiteBaseLayoutConfig {
47
47
  githubUrl?: string;
48
48
  links?: SiteNavItemConfig[];
49
49
  searchToggle?: HomeLayoutProps['searchToggle'];
50
- themeSwitch?: SiteThemeSwitchConfig;
51
50
  }
52
- export type SiteThemeSwitchMode = 'light-dark-system' | 'light-dark' | 'light-only' | 'dark-only';
51
+ export type SiteThemeSwitchMode = 'light-dark-system' | 'light-only' | 'dark-only';
53
52
  export interface SiteThemeSwitchConfig {
54
53
  mode?: SiteThemeSwitchMode;
55
54
  }
@@ -0,0 +1,8 @@
1
+ import { type ReactNode } from 'react';
2
+ import type { SiteThemeSwitchMode } from './site-layout-shared';
3
+ import { type SiteThemeProviderProps } from './site-theme-provider';
4
+ export declare function useSiteThemeMode(): SiteThemeSwitchMode;
5
+ export interface SiteThemeRootProviderProps extends Omit<SiteThemeProviderProps, 'children'> {
6
+ children: ReactNode;
7
+ }
8
+ export declare function SiteThemeRootProvider({ mode, children, ...props }: SiteThemeRootProviderProps): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,19 @@
1
+ "use client";
2
+ 'use strict';
3
+
4
+ var tslib = require('tslib');
5
+ var jsxRuntime = require('react/jsx-runtime');
6
+ var React = require('react');
7
+ var siteThemeProvider = require('./site-theme-provider.js');
8
+
9
+ const SiteThemeModeContext = React.createContext('light-dark-system');
10
+ function useSiteThemeMode() {
11
+ return React.useContext(SiteThemeModeContext);
12
+ }
13
+ function SiteThemeRootProvider(_a) {
14
+ var { mode = 'light-dark-system', children } = _a, props = tslib.__rest(_a, ["mode", "children"]);
15
+ return (jsxRuntime.jsx(SiteThemeModeContext.Provider, { value: mode, children: jsxRuntime.jsx(siteThemeProvider.SiteThemeProvider, Object.assign({}, props, { mode: mode, children: children })) }));
16
+ }
17
+
18
+ exports.SiteThemeRootProvider = SiteThemeRootProvider;
19
+ exports.useSiteThemeMode = useSiteThemeMode;
@@ -0,0 +1,16 @@
1
+ "use client";
2
+ import { __rest } from 'tslib';
3
+ import { jsx } from 'react/jsx-runtime';
4
+ import { createContext, useContext } from 'react';
5
+ import { SiteThemeProvider } from './site-theme-provider.mjs';
6
+
7
+ const SiteThemeModeContext = createContext('light-dark-system');
8
+ function useSiteThemeMode() {
9
+ return useContext(SiteThemeModeContext);
10
+ }
11
+ function SiteThemeRootProvider(_a) {
12
+ var { mode = 'light-dark-system', children } = _a, props = __rest(_a, ["mode", "children"]);
13
+ return (jsx(SiteThemeModeContext.Provider, { value: mode, children: jsx(SiteThemeProvider, Object.assign({}, props, { mode: mode, children: children })) }));
14
+ }
15
+
16
+ export { SiteThemeRootProvider, useSiteThemeMode };
@@ -24,13 +24,6 @@ function resolveThemeProviderProps(mode) {
24
24
  defaultTheme: 'dark',
25
25
  };
26
26
  }
27
- if (mode === 'light-dark') {
28
- return {
29
- enableSystem: false,
30
- defaultTheme: 'light',
31
- forcedTheme: undefined,
32
- };
33
- }
34
27
  return {
35
28
  enableSystem: true,
36
29
  defaultTheme: 'system',
@@ -22,13 +22,6 @@ function resolveThemeProviderProps(mode) {
22
22
  defaultTheme: 'dark',
23
23
  };
24
24
  }
25
- if (mode === 'light-dark') {
26
- return {
27
- enableSystem: false,
28
- defaultTheme: 'light',
29
- forcedTheme: undefined,
30
- };
31
- }
32
25
  return {
33
26
  enableSystem: true,
34
27
  defaultTheme: 'system',
@@ -5,7 +5,6 @@ interface FumaPageParams {
5
5
  sourceKey: string;
6
6
  mdxContentSource: any | (() => Promise<any>);
7
7
  getMDXComponents: () => any;
8
- mdxSourceDir: string;
9
8
  githubBaseUrl?: string;
10
9
  copyButtonComponent?: ReactElement<LLMCopyButtonProps, typeof LLMCopyButton>;
11
10
  supportedLocales?: string[];
@@ -16,7 +15,7 @@ interface FumaPageParams {
16
15
  localePrefixAsNeeded?: boolean;
17
16
  defaultLocale?: string;
18
17
  }
19
- export declare function createFumaPage({ sourceKey, mdxContentSource, getMDXComponents, mdxSourceDir, githubBaseUrl, copyButtonComponent, supportedLocales, showBreadcrumb, showTableOfContent, tocRenderMode, showTableOfContentPopover, localePrefixAsNeeded, defaultLocale, }: FumaPageParams): {
18
+ export declare function createFumaPage({ sourceKey, mdxContentSource, getMDXComponents, githubBaseUrl, copyButtonComponent, supportedLocales, showBreadcrumb, showTableOfContent, tocRenderMode, showTableOfContentPopover, localePrefixAsNeeded, defaultLocale, }: FumaPageParams): {
20
19
  Page: ({ params }: {
21
20
  params: Promise<{
22
21
  locale: string;
@@ -10,8 +10,9 @@ var navigation = require('next/navigation');
10
10
  var tocClerkPortable = require('./mdx/toc-clerk-portable.js');
11
11
  var lib = require('@windrun-huaiin/base-ui/lib');
12
12
 
13
- function createFumaPage({ sourceKey, mdxContentSource, getMDXComponents, mdxSourceDir, githubBaseUrl, copyButtonComponent, supportedLocales = ['en'], showBreadcrumb = true, showTableOfContent = true, tocRenderMode = 'portable-clerk', showTableOfContentPopover = false, localePrefixAsNeeded = true, defaultLocale = 'en', }) {
13
+ function createFumaPage({ sourceKey, mdxContentSource, getMDXComponents, githubBaseUrl, copyButtonComponent, supportedLocales = ['en'], showBreadcrumb = true, showTableOfContent = true, tocRenderMode = 'portable-clerk', showTableOfContentPopover = false, localePrefixAsNeeded = true, defaultLocale = 'en', }) {
14
14
  var _a;
15
+ const resolvedMdxSourceDir = `src/mdx/${sourceKey}`;
15
16
  const isLocalMdDebugEnabled = ((_a = process.env.LOCAL_MD_DEBUG) === null || _a === void 0 ? void 0 : _a.toLowerCase()) === 'true';
16
17
  const now = () => (typeof performance !== 'undefined' ? performance.now() : Date.now());
17
18
  const durationMs = (startedAt) => Number((now() - startedAt).toFixed(1));
@@ -52,7 +53,7 @@ function createFumaPage({ sourceKey, mdxContentSource, getMDXComponents, mdxSour
52
53
  if (!page$1) {
53
54
  navigation.notFound();
54
55
  }
55
- const path = githubBaseUrl ? `${mdxSourceDir}/${page$1.path}` : undefined;
56
+ const path = githubBaseUrl ? `${resolvedMdxSourceDir}/${page$1.path}` : undefined;
56
57
  const tocFooterElement = (jsxRuntime.jsx(tocFooterWrapper.TocFooterWrapper, { lastModified: page$1.data.date, copyButtonComponent: copyButtonComponent
57
58
  ? React.cloneElement(copyButtonComponent, { sourceKey })
58
59
  : undefined, editPath: path, githubBaseUrl: githubBaseUrl }));
@@ -118,7 +119,7 @@ function createFumaPage({ sourceKey, mdxContentSource, getMDXComponents, mdxSour
118
119
  };
119
120
  }
120
121
  const baseUrl = process.env.NEXT_PUBLIC_BASE_URL;
121
- const baseRoute = mdxSourceDir.replace('src/mdx/', '');
122
+ const baseRoute = resolvedMdxSourceDir.replace('src/mdx/', '');
122
123
  // build the current page path
123
124
  const currentPath = slug ? slug.join('/') : '';
124
125
  const localizedPath = utils.getAsNeededLocalizedUrl(locale || defaultLocale, `/${baseRoute}${currentPath ? `/${currentPath}` : ''}`, localePrefixAsNeeded, defaultLocale);
@@ -8,8 +8,9 @@ import { notFound } from 'next/navigation';
8
8
  import { PortableClerkTOC, PortableClerkTOCTitle } from './mdx/toc-clerk-portable.mjs';
9
9
  import { themeSvgIconColor } from '@windrun-huaiin/base-ui/lib';
10
10
 
11
- function createFumaPage({ sourceKey, mdxContentSource, getMDXComponents, mdxSourceDir, githubBaseUrl, copyButtonComponent, supportedLocales = ['en'], showBreadcrumb = true, showTableOfContent = true, tocRenderMode = 'portable-clerk', showTableOfContentPopover = false, localePrefixAsNeeded = true, defaultLocale = 'en', }) {
11
+ function createFumaPage({ sourceKey, mdxContentSource, getMDXComponents, githubBaseUrl, copyButtonComponent, supportedLocales = ['en'], showBreadcrumb = true, showTableOfContent = true, tocRenderMode = 'portable-clerk', showTableOfContentPopover = false, localePrefixAsNeeded = true, defaultLocale = 'en', }) {
12
12
  var _a;
13
+ const resolvedMdxSourceDir = `src/mdx/${sourceKey}`;
13
14
  const isLocalMdDebugEnabled = ((_a = process.env.LOCAL_MD_DEBUG) === null || _a === void 0 ? void 0 : _a.toLowerCase()) === 'true';
14
15
  const now = () => (typeof performance !== 'undefined' ? performance.now() : Date.now());
15
16
  const durationMs = (startedAt) => Number((now() - startedAt).toFixed(1));
@@ -50,7 +51,7 @@ function createFumaPage({ sourceKey, mdxContentSource, getMDXComponents, mdxSour
50
51
  if (!page) {
51
52
  notFound();
52
53
  }
53
- const path = githubBaseUrl ? `${mdxSourceDir}/${page.path}` : undefined;
54
+ const path = githubBaseUrl ? `${resolvedMdxSourceDir}/${page.path}` : undefined;
54
55
  const tocFooterElement = (jsx(TocFooterWrapper, { lastModified: page.data.date, copyButtonComponent: copyButtonComponent
55
56
  ? cloneElement(copyButtonComponent, { sourceKey })
56
57
  : undefined, editPath: path, githubBaseUrl: githubBaseUrl }));
@@ -116,7 +117,7 @@ function createFumaPage({ sourceKey, mdxContentSource, getMDXComponents, mdxSour
116
117
  };
117
118
  }
118
119
  const baseUrl = process.env.NEXT_PUBLIC_BASE_URL;
119
- const baseRoute = mdxSourceDir.replace('src/mdx/', '');
120
+ const baseRoute = resolvedMdxSourceDir.replace('src/mdx/', '');
120
121
  // build the current page path
121
122
  const currentPath = slug ? slug.join('/') : '';
122
123
  const localizedPath = getAsNeededLocalizedUrl(locale || defaultLocale, `/${baseRoute}${currentPath ? `/${currentPath}` : ''}`, localePrefixAsNeeded, defaultLocale);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@windrun-huaiin/third-ui",
3
- "version": "31.1.0",
3
+ "version": "31.3.0",
4
4
  "description": "Third-party integrated UI components for windrun-huaiin projects",
5
5
  "exports": {
6
6
  "./clerk": {
@@ -245,7 +245,7 @@
245
245
  "zod": "^4.3.6",
246
246
  "@windrun-huaiin/base-ui": "^31.0.0",
247
247
  "@windrun-huaiin/contracts": "^31.0.0",
248
- "@windrun-huaiin/lib": "^31.0.0"
248
+ "@windrun-huaiin/lib": "^31.0.2"
249
249
  },
250
250
  "peerDependencies": {
251
251
  "clsx": "^2.1.1",
@@ -35,9 +35,9 @@ 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 { useSiteThemeMode } from './site-theme-context';
38
39
  import type {
39
40
  ExtendedLinkItem,
40
- SiteThemeSwitchConfig,
41
41
  SiteThemeSwitchMode,
42
42
  } from './site-layout-shared';
43
43
 
@@ -51,8 +51,7 @@ const PrefetchLinkItem = LinkItem as (
51
51
  props: ComponentProps<typeof LinkItem> & { prefetch?: boolean },
52
52
  ) => ReactNode;
53
53
 
54
- export interface CustomHomeHeaderProps
55
- extends Omit<HomeLayoutProps, 'themeSwitch'> {
54
+ export interface CustomHomeHeaderProps extends HomeLayoutProps {
56
55
  /**
57
56
  * Banner height in rem units
58
57
  *
@@ -97,7 +96,6 @@ export interface CustomHomeHeaderProps
97
96
  * Control order of utilities inside the mobile dropdown.
98
97
  */
99
98
  mobileMenuActionsOrder?: MobileMenuAction[];
100
- themeSwitch?: SiteThemeSwitchConfig;
101
99
  }
102
100
 
103
101
  export type DesktopAction =
@@ -137,7 +135,6 @@ export function CustomHomeHeader({
137
135
  i18n = false,
138
136
  links,
139
137
  githubUrl,
140
- themeSwitch = {},
141
138
  searchToggle = {},
142
139
  bannerHeight = 0,
143
140
  headerHeight = 2.5,
@@ -148,6 +145,7 @@ export function CustomHomeHeader({
148
145
  mobileBarActionsOrder = DEFAULT_MOBILE_BAR_ACTIONS,
149
146
  mobileMenuActionsOrder = DEFAULT_MOBILE_MENU_ACTIONS,
150
147
  }: CustomHomeHeaderProps) {
148
+ const themeMode = useSiteThemeMode();
151
149
  const finalLinks = useMemo(
152
150
  () => resolveLinkItems({ links, githubUrl }),
153
151
  [links, githubUrl],
@@ -181,10 +179,10 @@ export function CustomHomeHeader({
181
179
  ? searchToggle.components?.lg ?? null
182
180
  : null,
183
181
  theme:
184
- shouldShowThemeSwitch(themeSwitch?.mode)
182
+ shouldShowThemeSwitch(themeMode)
185
183
  ? (
186
184
  <HeaderThemeSwitch
187
- mode={normalizeThemeSwitchMode(themeSwitch?.mode)}
185
+ mode={normalizeThemeSwitchMode(themeMode)}
188
186
  />
189
187
  )
190
188
  : null,
@@ -248,10 +246,10 @@ export function CustomHomeHeader({
248
246
  </CompactLanguageToggle>
249
247
  ) : null,
250
248
  theme:
251
- shouldShowThemeSwitch(themeSwitch?.mode)
249
+ shouldShowThemeSwitch(themeMode)
252
250
  ? (
253
251
  <HeaderThemeSwitch
254
- mode={normalizeThemeSwitchMode(themeSwitch?.mode)}
252
+ mode={normalizeThemeSwitchMode(themeMode)}
255
253
  />
256
254
  )
257
255
  : null,
@@ -371,13 +369,13 @@ export function CustomHomeHeader({
371
369
  }
372
370
 
373
371
  function shouldShowThemeSwitch(mode?: SiteThemeSwitchMode): boolean {
374
- return mode === 'light-dark' || mode === 'light-dark-system' || mode == null;
372
+ return mode === 'light-dark-system' || mode == null;
375
373
  }
376
374
 
377
375
  function normalizeThemeSwitchMode(
378
376
  mode?: SiteThemeSwitchMode,
379
- ): 'light-dark' | 'light-dark-system' {
380
- return mode === 'light-dark' ? 'light-dark' : 'light-dark-system';
377
+ ): 'light-dark-system' {
378
+ return 'light-dark-system';
381
379
  }
382
380
 
383
381
  interface CustomNavbarProps extends ComponentProps<'div'> {
@@ -3,16 +3,13 @@ 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';
7
6
  import {
8
7
  NavbarCSSVars,
9
8
  CustomHomeHeader,
10
9
  type DesktopAction,
11
10
  type MobileBarAction,
12
11
  type MobileMenuAction,
13
- type CustomHomeHeaderProps,
14
12
  } from './custom-header';
15
- import type { SiteThemeSwitchConfig } from './site-layout-shared';
16
13
 
17
14
  // - Set bannerHeight/headerHeight to the rem values expected by the project. Use bannerHeight = 0 when there is no banner.
18
15
  // - layoutStyle passes the variables to HomeLayout's main element, offsetting content without has-banner/no-banner classes.
@@ -94,10 +91,6 @@ export interface CustomHomeLayoutProps {
94
91
  * The default locale for the application (default: 'en')
95
92
  */
96
93
  defaultLocale?: string;
97
- /**
98
- * Theme mode for this layout group.
99
- */
100
- themeSwitch?: SiteThemeSwitchConfig;
101
94
  children?: ReactNode;
102
95
  }
103
96
 
@@ -126,7 +119,6 @@ export function CustomHomeLayout({
126
119
  actionOrders,
127
120
  localePrefixAsNeeded = true,
128
121
  defaultLocale = 'en',
129
- themeSwitch,
130
122
  }: CustomHomeLayoutProps) {
131
123
  const resolvedBannerHeight = bannerHeight ?? (showBanner ? 3 : 0.5);
132
124
  const resolvedPaddingTop =
@@ -147,7 +139,6 @@ export function CustomHomeLayout({
147
139
  <CustomHomeHeader
148
140
  {...homeLayoutProps}
149
141
  nav={navOptions}
150
- themeSwitch={themeSwitch}
151
142
  bannerHeight={resolvedBannerHeight}
152
143
  headerHeight={headerHeight}
153
144
  navbarClassName={navbarClassName}
@@ -157,7 +148,6 @@ export function CustomHomeLayout({
157
148
  mobileMenuActionsOrder={actionOrders?.mobileMenu}
158
149
  />
159
150
  );
160
- const themeMode = themeSwitch?.mode ?? 'light-dark-system';
161
151
 
162
152
  return (
163
153
  <>
@@ -168,7 +158,6 @@ export function CustomHomeLayout({
168
158
  floating={floatingNav}
169
159
  />
170
160
  )}
171
- <SiteThemeProvider mode={themeMode}>
172
161
  <HomeLayout
173
162
  {...homeLayoutProps}
174
163
  nav={{
@@ -182,7 +171,6 @@ export function CustomHomeLayout({
182
171
  {showFooter ? footer ?? <Footer locale={locale} localePrefixAsNeeded={localePrefixAsNeeded} defaultLocale={defaultLocale} /> : null}
183
172
  {showGoToTop ? goToTop ?? <GoToTop /> : null}
184
173
  </HomeLayout>
185
- </SiteThemeProvider>
186
174
  </>
187
175
  );
188
176
  }
@@ -1,6 +1,8 @@
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 { SiteThemeRootProvider } from './site-theme-context';
5
+ import type { SiteThemeProviderProps } from './site-theme-provider';
4
6
 
5
7
  type NextProviderComponents = {
6
8
  Link?: ComponentProps<typeof NextProvider>['Link'];
@@ -9,22 +11,28 @@ type NextProviderComponents = {
9
11
 
10
12
  export interface DocsRootProviderProps {
11
13
  i18n: Omit<I18nProviderProps, 'children'>;
14
+ theme?: Omit<SiteThemeProviderProps, 'children'>;
12
15
  components?: NextProviderComponents;
13
16
  children: ReactNode;
14
17
  }
15
18
 
16
19
  export function DocsRootProvider({
17
20
  i18n,
21
+ theme = {},
18
22
  components,
19
23
  children,
20
24
  }: DocsRootProviderProps) {
25
+ const themeMode = theme.mode ?? 'light-dark-system';
26
+
21
27
  return (
22
28
  <NextProvider
23
29
  Link={components?.Link}
24
30
  Image={components?.Image}
25
31
  >
26
32
  <I18nProvider {...i18n}>
27
- {children}
33
+ <SiteThemeRootProvider {...theme} mode={themeMode}>
34
+ {children}
35
+ </SiteThemeRootProvider>
28
36
  </I18nProvider>
29
37
  </NextProvider>
30
38
  );
@@ -19,15 +19,14 @@ const itemVariants = cva('inline-flex size-6.5 items-center justify-center round
19
19
  const full = [['light', SunIcon] as const, ['dark', MoonIcon] as const, ['system', AirplayIcon] as const];
20
20
 
21
21
  export interface HeaderThemeSwitchProps extends ComponentProps<'div'> {
22
- mode?: Exclude<SiteThemeSwitchMode, 'light-only' | 'dark-only'>;
22
+ mode?: 'light-dark-system';
23
23
  }
24
24
 
25
25
  export function HeaderThemeSwitch({
26
26
  className,
27
- mode = 'light-dark',
28
27
  ...props
29
28
  }: HeaderThemeSwitchProps) {
30
- const { setTheme, theme, resolvedTheme } = useTheme();
29
+ const { setTheme, theme } = useTheme();
31
30
  const [mounted, setMounted] = useState(false);
32
31
 
33
32
  useEffect(() => {
@@ -40,35 +39,6 @@ export function HeaderThemeSwitch({
40
39
  );
41
40
  const iconClassName = 'size-3.5 text-neutral-600 dark:text-neutral-300';
42
41
 
43
- if (mode === 'light-dark') {
44
- const value = mounted ? resolvedTheme : null;
45
-
46
- return (
47
- <button
48
- type="button"
49
- className={container}
50
- aria-label="Toggle Theme"
51
- onClick={() => setTheme(value === 'light' ? 'dark' : 'light')}
52
- data-theme-toggle=""
53
- >
54
- {full.map(([key, Icon]) => {
55
- if (key === 'system') return null;
56
-
57
- return (
58
- <Icon
59
- key={key}
60
- fill="currentColor"
61
- className={cn(
62
- itemVariants({ active: value === key }),
63
- iconClassName,
64
- )}
65
- />
66
- );
67
- })}
68
- </button>
69
- );
70
- }
71
-
72
42
  const value = mounted ? theme : null;
73
43
 
74
44
  return (
@@ -4,36 +4,25 @@ import {
4
4
  normalizeNavItems,
5
5
  type SiteBaseLayoutConfig,
6
6
  } from './site-layout-shared';
7
- import { SiteThemeProvider } from './site-theme-provider';
7
+ import { SiteDocsThemeSwitch } from './site-docs-theme-switch';
8
8
 
9
9
  export interface SiteDocsLayoutConfig extends SiteBaseLayoutConfig {
10
10
  tree: DocsLayoutProps['tree'];
11
11
  sidebar?: DocsLayoutProps['sidebar'];
12
- themeProvider?: boolean;
12
+ slots?: DocsLayoutProps['slots'];
13
13
  }
14
14
 
15
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');
20
16
  return {
21
17
  ...(config.nav ? { nav: config.nav } : {}),
22
18
  ...(config.i18n ? { i18n: config.i18n } : {}),
23
19
  ...(config.githubUrl ? { githubUrl: config.githubUrl } : {}),
24
20
  ...(config.links ? { links: normalizeNavItems(config.links) } : {}),
25
21
  ...(config.searchToggle ? { searchToggle: config.searchToggle } : {}),
26
- ...(shouldShowThemeSwitch
27
- ? {
28
- themeSwitch: {
29
- mode: themeMode,
30
- },
31
- }
32
- : {
33
- themeSwitch: {
34
- enabled: false,
35
- },
36
- }),
22
+ slots: {
23
+ ...config.slots,
24
+ themeSwitch: SiteDocsThemeSwitch,
25
+ },
37
26
  ...(config.sidebar ? { sidebar: config.sidebar } : {}),
38
27
  tree: config.tree,
39
28
  };
@@ -47,10 +36,6 @@ export function SiteDocsLayout({
47
36
  children: ReactNode;
48
37
  }) {
49
38
  const options = toDocsLayoutOptions(config);
50
- const themeMode = config.themeSwitch?.mode ?? 'light-dark-system';
51
- const body = <DocsLayout {...options}>{children}</DocsLayout>;
52
39
 
53
- if (config.themeProvider === false) return body;
54
-
55
- return <SiteThemeProvider mode={themeMode}>{body}</SiteThemeProvider>;
40
+ return <DocsLayout {...options}>{children}</DocsLayout>;
56
41
  }
@@ -0,0 +1,15 @@
1
+ 'use client';
2
+
3
+ import type { ComponentProps } from 'react';
4
+ import { HeaderThemeSwitch } from './header-theme-switch';
5
+ import { useSiteThemeMode } from './site-theme-context';
6
+
7
+ export function SiteDocsThemeSwitch(props: ComponentProps<'div'>) {
8
+ const themeMode = useSiteThemeMode();
9
+
10
+ if (themeMode !== 'light-dark-system') {
11
+ return null;
12
+ }
13
+
14
+ return <HeaderThemeSwitch {...props} mode="light-dark-system" />;
15
+ }
@@ -72,7 +72,6 @@ export function SiteHomeLayout({
72
72
  ...(showBanner != null ? { showBanner } : {}),
73
73
  ...(showFooter != null ? { showFooter } : {}),
74
74
  ...(showGoToTop != null ? { showGoToTop } : {}),
75
- ...(config.themeSwitch ? { themeSwitch: config.themeSwitch } : {}),
76
75
  };
77
76
 
78
77
  return <CustomHomeLayout {...layoutProps}>{children}</CustomHomeLayout>;
@@ -58,12 +58,10 @@ export interface SiteBaseLayoutConfig {
58
58
  githubUrl?: string;
59
59
  links?: SiteNavItemConfig[];
60
60
  searchToggle?: HomeLayoutProps['searchToggle'];
61
- themeSwitch?: SiteThemeSwitchConfig;
62
61
  }
63
62
 
64
63
  export type SiteThemeSwitchMode =
65
64
  | 'light-dark-system'
66
- | 'light-dark'
67
65
  | 'light-only'
68
66
  | 'dark-only';
69
67
 
@@ -0,0 +1,30 @@
1
+ 'use client';
2
+
3
+ import { createContext, type ReactNode, useContext } from 'react';
4
+ import type { SiteThemeSwitchMode } from './site-layout-shared';
5
+ import { SiteThemeProvider, type SiteThemeProviderProps } from './site-theme-provider';
6
+
7
+ const SiteThemeModeContext = createContext<SiteThemeSwitchMode>('light-dark-system');
8
+
9
+ export function useSiteThemeMode(): SiteThemeSwitchMode {
10
+ return useContext(SiteThemeModeContext);
11
+ }
12
+
13
+ export interface SiteThemeRootProviderProps
14
+ extends Omit<SiteThemeProviderProps, 'children'> {
15
+ children: ReactNode;
16
+ }
17
+
18
+ export function SiteThemeRootProvider({
19
+ mode = 'light-dark-system',
20
+ children,
21
+ ...props
22
+ }: SiteThemeRootProviderProps) {
23
+ return (
24
+ <SiteThemeModeContext.Provider value={mode}>
25
+ <SiteThemeProvider {...props} mode={mode}>
26
+ {children}
27
+ </SiteThemeProvider>
28
+ </SiteThemeModeContext.Provider>
29
+ );
30
+ }
@@ -43,14 +43,6 @@ function resolveThemeProviderProps(mode: SiteThemeSwitchMode): ThemeProviderProp
43
43
  };
44
44
  }
45
45
 
46
- if (mode === 'light-dark') {
47
- return {
48
- enableSystem: false,
49
- defaultTheme: 'light',
50
- forcedTheme: undefined,
51
- };
52
- }
53
-
54
46
  return {
55
47
  enableSystem: true,
56
48
  defaultTheme: 'system',
@@ -25,10 +25,6 @@ interface FumaPageParams {
25
25
  * The mdx components handler, refer to fumadocs
26
26
  */
27
27
  getMDXComponents: () => any;
28
- /*
29
- * The source directory of the mdx content, used to generate the edit path
30
- */
31
- mdxSourceDir: string;
32
28
  /*
33
29
  * The github base url, used to generate the edit path, if not provided, the edit path will not be shown
34
30
  */
@@ -79,7 +75,6 @@ export function createFumaPage({
79
75
  sourceKey,
80
76
  mdxContentSource,
81
77
  getMDXComponents,
82
- mdxSourceDir,
83
78
  githubBaseUrl,
84
79
  copyButtonComponent,
85
80
  supportedLocales = ['en'],
@@ -90,6 +85,7 @@ export function createFumaPage({
90
85
  localePrefixAsNeeded = true,
91
86
  defaultLocale = 'en',
92
87
  }: FumaPageParams) {
88
+ const resolvedMdxSourceDir = `src/mdx/${sourceKey}`;
93
89
  const isLocalMdDebugEnabled = process.env.LOCAL_MD_DEBUG?.toLowerCase() === 'true';
94
90
  const now = () => (typeof performance !== 'undefined' ? performance.now() : Date.now());
95
91
  const durationMs = (startedAt: number) => Number((now() - startedAt).toFixed(1));
@@ -132,7 +128,7 @@ export function createFumaPage({
132
128
  notFound();
133
129
  }
134
130
 
135
- const path = githubBaseUrl ? `${mdxSourceDir}/${page.path}` : undefined;
131
+ const path = githubBaseUrl ? `${resolvedMdxSourceDir}/${page.path}` : undefined;
136
132
  const tocFooterElement = (
137
133
  <TocFooterWrapper
138
134
  lastModified={page.data.date}
@@ -222,7 +218,7 @@ export function createFumaPage({
222
218
  };
223
219
  }
224
220
  const baseUrl = process.env.NEXT_PUBLIC_BASE_URL!;
225
- const baseRoute = mdxSourceDir.replace('src/mdx/', '');
221
+ const baseRoute = resolvedMdxSourceDir.replace('src/mdx/', '');
226
222
  // build the current page path
227
223
  const currentPath = slug ? slug.join('/') : '';
228
224
  const localizedPath = getAsNeededLocalizedUrl(locale || defaultLocale, `/${baseRoute}${currentPath ? `/${currentPath}` : ''}`, localePrefixAsNeeded, defaultLocale);