@windrun-huaiin/third-ui 23.1.0 → 24.0.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/fuma-page-genarator.d.ts +3 -1
- package/dist/fuma/fuma-page-genarator.js +33 -6
- package/dist/fuma/fuma-page-genarator.mjs +34 -7
- package/dist/fuma/mdx/index.js +1 -0
- package/dist/fuma/mdx/index.mjs +1 -1
- package/dist/fuma/mdx/toc-clerk-portable.d.ts +1 -0
- package/dist/fuma/mdx/toc-clerk-portable.js +12 -9
- package/dist/fuma/mdx/toc-clerk-portable.mjs +11 -9
- package/package.json +4 -4
- package/src/fuma/fuma-page-genarator.tsx +80 -12
- package/src/fuma/mdx/toc-clerk-portable.tsx +65 -27
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { ReactNode, ReactElement } from 'react';
|
|
2
2
|
import type { LLMCopyButtonProps, LLMCopyButton } from '@third-ui/fuma/mdx/toc-base';
|
|
3
|
+
export type FumaPageTocRenderMode = 'portable-clerk' | 'fumadocs-clerk' | 'fumadocs-normal';
|
|
3
4
|
interface FumaPageParams {
|
|
4
5
|
sourceKey: string;
|
|
5
6
|
mdxContentSource: any | (() => Promise<any>);
|
|
@@ -14,11 +15,12 @@ interface FumaPageParams {
|
|
|
14
15
|
supportedLocales?: string[];
|
|
15
16
|
showBreadcrumb?: boolean;
|
|
16
17
|
showTableOfContent?: boolean;
|
|
18
|
+
tocRenderMode?: FumaPageTocRenderMode;
|
|
17
19
|
showTableOfContentPopover?: boolean;
|
|
18
20
|
localePrefixAsNeeded?: boolean;
|
|
19
21
|
defaultLocale?: string;
|
|
20
22
|
}
|
|
21
|
-
export declare function createFumaPage({ sourceKey, mdxContentSource, getMDXComponents, mdxSourceDir, githubBaseUrl, copyButtonComponent, siteIcon, FallbackPage, supportedLocales, showBreadcrumb, showTableOfContent, showTableOfContentPopover, localePrefixAsNeeded, defaultLocale, }: FumaPageParams): {
|
|
23
|
+
export declare function createFumaPage({ sourceKey, mdxContentSource, getMDXComponents, mdxSourceDir, githubBaseUrl, copyButtonComponent, siteIcon, FallbackPage, supportedLocales, showBreadcrumb, showTableOfContent, tocRenderMode, showTableOfContentPopover, localePrefixAsNeeded, defaultLocale, }: FumaPageParams): {
|
|
22
24
|
Page: ({ params }: {
|
|
23
25
|
params: Promise<{
|
|
24
26
|
locale: string;
|
|
@@ -7,8 +7,9 @@ var React = require('react');
|
|
|
7
7
|
var tocFooterWrapper = require('./mdx/toc-footer-wrapper.js');
|
|
8
8
|
var lib = require('@windrun-huaiin/lib');
|
|
9
9
|
var tocClerkPortable = require('./mdx/toc-clerk-portable.js');
|
|
10
|
+
var lib$1 = require('@windrun-huaiin/base-ui/lib');
|
|
10
11
|
|
|
11
|
-
function createFumaPage({ sourceKey, mdxContentSource, getMDXComponents, mdxSourceDir, githubBaseUrl, copyButtonComponent, siteIcon, FallbackPage, supportedLocales = ['en'], showBreadcrumb = true, showTableOfContent = true, showTableOfContentPopover = false, localePrefixAsNeeded = true, defaultLocale = 'en', }) {
|
|
12
|
+
function createFumaPage({ sourceKey, mdxContentSource, getMDXComponents, mdxSourceDir, githubBaseUrl, copyButtonComponent, siteIcon, FallbackPage, supportedLocales = ['en'], showBreadcrumb = true, showTableOfContent = true, tocRenderMode = 'portable-clerk', showTableOfContentPopover = false, localePrefixAsNeeded = true, defaultLocale = 'en', }) {
|
|
12
13
|
const getSource = () => tslib.__awaiter(this, void 0, void 0, function* () {
|
|
13
14
|
if (typeof mdxContentSource === 'function') {
|
|
14
15
|
return yield mdxContentSource();
|
|
@@ -35,12 +36,14 @@ function createFumaPage({ sourceKey, mdxContentSource, getMDXComponents, mdxSour
|
|
|
35
36
|
body: yield page$1.data.body({ components: getMDXComponents() }),
|
|
36
37
|
toc: (_e = page$1.data.toc) !== null && _e !== void 0 ? _e : [],
|
|
37
38
|
};
|
|
38
|
-
return (jsxRuntime.jsxs(page.DocsPage, { breadcrumb: { enabled: showBreadcrumb }, tableOfContent: {
|
|
39
|
+
return (jsxRuntime.jsxs(page.DocsPage, { breadcrumb: { enabled: showBreadcrumb }, tableOfContent: resolveTableOfContentOptions({
|
|
39
40
|
enabled: showTableOfContent,
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
41
|
+
tocRenderMode,
|
|
42
|
+
toc: content.toc,
|
|
43
|
+
footer: tocFooterElement,
|
|
44
|
+
}), tableOfContentPopover: {
|
|
45
|
+
enabled: showTableOfContentPopover && tocRenderMode !== 'portable-clerk',
|
|
46
|
+
style: tocRenderMode === 'fumadocs-clerk' ? 'clerk' : 'normal',
|
|
44
47
|
}, toc: content.toc, className: "max-sm:pb-16", children: [jsxRuntime.jsx(page.DocsTitle, { children: page$1.data.title }), jsxRuntime.jsx(page.DocsDescription, { className: "mb-2", children: page$1.data.description }), jsxRuntime.jsx(page.DocsBody, { className: "text-fd-foreground/80", children: content.body })] }));
|
|
45
48
|
});
|
|
46
49
|
};
|
|
@@ -87,5 +90,29 @@ function createFumaPage({ sourceKey, mdxContentSource, getMDXComponents, mdxSour
|
|
|
87
90
|
generateMetadata,
|
|
88
91
|
};
|
|
89
92
|
}
|
|
93
|
+
function resolveTableOfContentOptions({ enabled, tocRenderMode, toc, footer, }) {
|
|
94
|
+
if (tocRenderMode === 'portable-clerk') {
|
|
95
|
+
return {
|
|
96
|
+
enabled,
|
|
97
|
+
single: false,
|
|
98
|
+
component: (jsxRuntime.jsx(tocClerkPortable.PortableClerkTOC, { toc: toc, footer: footer })),
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
const themedTocProps = {
|
|
102
|
+
container: {
|
|
103
|
+
className: '[--color-fd-primary:var(--third-ui-toc-primary)] [--color-fd-primary-foreground:var(--third-ui-toc-primary-foreground)] [&_#toc-title]:hidden',
|
|
104
|
+
style: {
|
|
105
|
+
'--third-ui-toc-primary': lib$1.themeSvgIconColor,
|
|
106
|
+
'--third-ui-toc-primary-foreground': '#ffffff',
|
|
107
|
+
},
|
|
108
|
+
},
|
|
109
|
+
header: jsxRuntime.jsx(tocClerkPortable.PortableClerkTOCTitle, {}),
|
|
110
|
+
footer,
|
|
111
|
+
};
|
|
112
|
+
if (tocRenderMode === 'fumadocs-clerk') {
|
|
113
|
+
return Object.assign({ enabled, single: false, style: 'clerk' }, themedTocProps);
|
|
114
|
+
}
|
|
115
|
+
return Object.assign({ enabled, single: false, style: 'normal' }, themedTocProps);
|
|
116
|
+
}
|
|
90
117
|
|
|
91
118
|
exports.createFumaPage = createFumaPage;
|
|
@@ -4,9 +4,10 @@ import { DocsPage, DocsTitle, DocsDescription, DocsBody } from 'fumadocs-ui/page
|
|
|
4
4
|
import { cloneElement } from 'react';
|
|
5
5
|
import { TocFooterWrapper } from './mdx/toc-footer-wrapper.mjs';
|
|
6
6
|
import { getAsNeededLocalizedUrl } from '@windrun-huaiin/lib';
|
|
7
|
-
import { PortableClerkTOC } from './mdx/toc-clerk-portable.mjs';
|
|
7
|
+
import { PortableClerkTOC, PortableClerkTOCTitle } from './mdx/toc-clerk-portable.mjs';
|
|
8
|
+
import { themeSvgIconColor } from '@windrun-huaiin/base-ui/lib';
|
|
8
9
|
|
|
9
|
-
function createFumaPage({ sourceKey, mdxContentSource, getMDXComponents, mdxSourceDir, githubBaseUrl, copyButtonComponent, siteIcon, FallbackPage, supportedLocales = ['en'], showBreadcrumb = true, showTableOfContent = true, showTableOfContentPopover = false, localePrefixAsNeeded = true, defaultLocale = 'en', }) {
|
|
10
|
+
function createFumaPage({ sourceKey, mdxContentSource, getMDXComponents, mdxSourceDir, githubBaseUrl, copyButtonComponent, siteIcon, FallbackPage, supportedLocales = ['en'], showBreadcrumb = true, showTableOfContent = true, tocRenderMode = 'portable-clerk', showTableOfContentPopover = false, localePrefixAsNeeded = true, defaultLocale = 'en', }) {
|
|
10
11
|
const getSource = () => __awaiter(this, void 0, void 0, function* () {
|
|
11
12
|
if (typeof mdxContentSource === 'function') {
|
|
12
13
|
return yield mdxContentSource();
|
|
@@ -33,12 +34,14 @@ function createFumaPage({ sourceKey, mdxContentSource, getMDXComponents, mdxSour
|
|
|
33
34
|
body: yield page.data.body({ components: getMDXComponents() }),
|
|
34
35
|
toc: (_e = page.data.toc) !== null && _e !== void 0 ? _e : [],
|
|
35
36
|
};
|
|
36
|
-
return (jsxs(DocsPage, { breadcrumb: { enabled: showBreadcrumb }, tableOfContent: {
|
|
37
|
+
return (jsxs(DocsPage, { breadcrumb: { enabled: showBreadcrumb }, tableOfContent: resolveTableOfContentOptions({
|
|
37
38
|
enabled: showTableOfContent,
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
39
|
+
tocRenderMode,
|
|
40
|
+
toc: content.toc,
|
|
41
|
+
footer: tocFooterElement,
|
|
42
|
+
}), tableOfContentPopover: {
|
|
43
|
+
enabled: showTableOfContentPopover && tocRenderMode !== 'portable-clerk',
|
|
44
|
+
style: tocRenderMode === 'fumadocs-clerk' ? 'clerk' : 'normal',
|
|
42
45
|
}, toc: content.toc, className: "max-sm:pb-16", children: [jsx(DocsTitle, { children: page.data.title }), jsx(DocsDescription, { className: "mb-2", children: page.data.description }), jsx(DocsBody, { className: "text-fd-foreground/80", children: content.body })] }));
|
|
43
46
|
});
|
|
44
47
|
};
|
|
@@ -85,5 +88,29 @@ function createFumaPage({ sourceKey, mdxContentSource, getMDXComponents, mdxSour
|
|
|
85
88
|
generateMetadata,
|
|
86
89
|
};
|
|
87
90
|
}
|
|
91
|
+
function resolveTableOfContentOptions({ enabled, tocRenderMode, toc, footer, }) {
|
|
92
|
+
if (tocRenderMode === 'portable-clerk') {
|
|
93
|
+
return {
|
|
94
|
+
enabled,
|
|
95
|
+
single: false,
|
|
96
|
+
component: (jsx(PortableClerkTOC, { toc: toc, footer: footer })),
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
const themedTocProps = {
|
|
100
|
+
container: {
|
|
101
|
+
className: '[--color-fd-primary:var(--third-ui-toc-primary)] [--color-fd-primary-foreground:var(--third-ui-toc-primary-foreground)] [&_#toc-title]:hidden',
|
|
102
|
+
style: {
|
|
103
|
+
'--third-ui-toc-primary': themeSvgIconColor,
|
|
104
|
+
'--third-ui-toc-primary-foreground': '#ffffff',
|
|
105
|
+
},
|
|
106
|
+
},
|
|
107
|
+
header: jsx(PortableClerkTOCTitle, {}),
|
|
108
|
+
footer,
|
|
109
|
+
};
|
|
110
|
+
if (tocRenderMode === 'fumadocs-clerk') {
|
|
111
|
+
return Object.assign({ enabled, single: false, style: 'clerk' }, themedTocProps);
|
|
112
|
+
}
|
|
113
|
+
return Object.assign({ enabled, single: false, style: 'normal' }, themedTocProps);
|
|
114
|
+
}
|
|
88
115
|
|
|
89
116
|
export { createFumaPage };
|
package/dist/fuma/mdx/index.js
CHANGED
|
@@ -28,5 +28,6 @@ exports.PortableClerkTOC = tocClerkPortable.PortableClerkTOC;
|
|
|
28
28
|
exports.PortableClerkTOCItems = tocClerkPortable.PortableClerkTOCItems;
|
|
29
29
|
exports.PortableClerkTOCPopover = tocClerkPortable.PortableClerkTOCPopover;
|
|
30
30
|
exports.PortableClerkTOCScrollArea = tocClerkPortable.PortableClerkTOCScrollArea;
|
|
31
|
+
exports.PortableClerkTOCTitle = tocClerkPortable.PortableClerkTOCTitle;
|
|
31
32
|
exports.Banner = banner.Banner;
|
|
32
33
|
exports.SunoEmbed = sunoEmbed.SunoEmbed;
|
package/dist/fuma/mdx/index.mjs
CHANGED
|
@@ -6,6 +6,6 @@ export { EditOnGitHub, LLMCopyButton, LastUpdatedDate } from './toc-base.mjs';
|
|
|
6
6
|
export { FumaGithubInfo } from './fuma-github-info.mjs';
|
|
7
7
|
export { ZiaFile, ZiaFolder } from './zia-file.mjs';
|
|
8
8
|
export { TocFooterWrapper } from './toc-footer-wrapper.mjs';
|
|
9
|
-
export { PortableClerkTOC, PortableClerkTOCItems, PortableClerkTOCPopover, PortableClerkTOCScrollArea } from './toc-clerk-portable.mjs';
|
|
9
|
+
export { PortableClerkTOC, PortableClerkTOCItems, PortableClerkTOCPopover, PortableClerkTOCScrollArea, PortableClerkTOCTitle } from './toc-clerk-portable.mjs';
|
|
10
10
|
export { Banner } from './banner.mjs';
|
|
11
11
|
export { SunoEmbed } from './suno-embed.mjs';
|
|
@@ -15,6 +15,7 @@ type PortableClerkTOCProps = {
|
|
|
15
15
|
};
|
|
16
16
|
export declare function PortableClerkTOC({ toc, header, footer, title, emptyLabel, className, }: PortableClerkTOCProps): import("react/jsx-runtime").JSX.Element;
|
|
17
17
|
export declare function PortableClerkTOCPopover({ toc, header, footer, emptyLabel, }: Omit<PortableClerkTOCProps, 'title' | 'className'>): import("react/jsx-runtime").JSX.Element;
|
|
18
|
+
export declare function PortableClerkTOCTitle({ className, ...props }: ComponentProps<'h3'>): import("react/jsx-runtime").JSX.Element;
|
|
18
19
|
export declare function PortableClerkTOCScrollArea({ ref, className, ...props }: ComponentProps<'div'>): import("react/jsx-runtime").JSX.Element;
|
|
19
20
|
export declare function PortableClerkTOCItems({ toc, emptyLabel, ref, className, ...props }: ComponentProps<'div'> & {
|
|
20
21
|
toc: TOCItemType[];
|
|
@@ -4,9 +4,11 @@
|
|
|
4
4
|
var tslib = require('tslib');
|
|
5
5
|
var jsxRuntime = require('react/jsx-runtime');
|
|
6
6
|
var Primitive = require('fumadocs-core/toc');
|
|
7
|
-
var
|
|
7
|
+
var i18n = require('fumadocs-ui/contexts/i18n');
|
|
8
|
+
var collapsible = require('fumadocs-ui/components/ui/collapsible');
|
|
8
9
|
var React = require('react');
|
|
9
10
|
var lib = require('@windrun-huaiin/base-ui/lib');
|
|
11
|
+
var icons = require('@windrun-huaiin/base-ui/icons');
|
|
10
12
|
|
|
11
13
|
function _interopNamespaceDefault(e) {
|
|
12
14
|
var n = Object.create(null);
|
|
@@ -49,15 +51,15 @@ const CLERK_STEP_BADGE_RADIUS = 7;
|
|
|
49
51
|
const CLERK_DEPTH_GROUP_LINE_OFFSETS = [6, 18, 30, 42];
|
|
50
52
|
// Max number of characters rendered for a TOC label before trimming with ellipsis.
|
|
51
53
|
const CLERK_MAX_LABEL_LENGTH = 44;
|
|
52
|
-
function PortableClerkTOC({ toc
|
|
53
|
-
return (jsxRuntime.
|
|
54
|
-
children: jsxRuntime.jsx(PortableClerkTOCItems, { toc: toc$1, emptyLabel: emptyLabel }),
|
|
55
|
-
} }));
|
|
54
|
+
function PortableClerkTOC({ toc, header, footer, title, emptyLabel = 'No headings', className, }) {
|
|
55
|
+
return (jsxRuntime.jsxs("div", { id: "nd-toc", className: cn('sticky top-(--fd-docs-row-1) h-[calc(var(--fd-docs-height)-var(--fd-docs-row-1))] flex flex-col [grid-area:toc] w-(--fd-toc-width) pt-12 pe-4 pb-2 max-xl:hidden', className), children: [header, title !== null && title !== void 0 ? title : jsxRuntime.jsx(PortableClerkTOCTitle, {}), jsxRuntime.jsx(PortableClerkTOCScrollArea, { children: jsxRuntime.jsx(PortableClerkTOCItems, { toc: toc, emptyLabel: emptyLabel }) }), footer] }));
|
|
56
56
|
}
|
|
57
|
-
function PortableClerkTOCPopover({ toc
|
|
58
|
-
return (jsxRuntime.jsx(
|
|
59
|
-
|
|
60
|
-
|
|
57
|
+
function PortableClerkTOCPopover({ toc, header, footer, emptyLabel = 'No headings', }) {
|
|
58
|
+
return (jsxRuntime.jsx(collapsible.Collapsible, { "data-toc-popover": "", className: "sticky top-(--fd-docs-row-2) z-10 [grid-area:toc-popover] h-(--fd-toc-popover-height) xl:hidden max-xl:layout:[--fd-toc-popover-height:--spacing(10)]", children: jsxRuntime.jsxs("header", { className: "border-b bg-fd-background/80 backdrop-blur-sm transition-colors", children: [jsxRuntime.jsxs(collapsible.CollapsibleTrigger, { "data-toc-popover-trigger": "", className: "flex w-full h-10 items-center text-sm text-fd-muted-foreground gap-2.5 px-4 py-2.5 text-start focus-visible:outline-none [&_svg]:size-4 md:px-6", children: [jsxRuntime.jsx(icons.NotepadTextIcon, { className: "shrink-0" }), jsxRuntime.jsx("span", { className: "flex-1 truncate", children: jsxRuntime.jsx(i18n.I18nLabel, { label: "toc" }) }), jsxRuntime.jsx(icons.ChevronDownIcon, { className: "shrink-0 transition-transform mx-0.5" })] }), jsxRuntime.jsx(collapsible.CollapsibleContent, { "data-toc-popover-content": "", children: jsxRuntime.jsxs("div", { className: "flex max-h-[50vh] flex-col px-4 md:px-6", children: [header, jsxRuntime.jsx(PortableClerkTOCScrollArea, { children: jsxRuntime.jsx(PortableClerkTOCItems, { toc: toc, emptyLabel: emptyLabel }) }), footer] }) })] }) }));
|
|
59
|
+
}
|
|
60
|
+
function PortableClerkTOCTitle(_a) {
|
|
61
|
+
var { className } = _a, props = tslib.__rest(_a, ["className"]);
|
|
62
|
+
return (jsxRuntime.jsxs("h3", Object.assign({ id: "toc-title", className: cn('inline-flex items-center gap-1.5 text-sm text-fd-muted-foreground', className) }, props, { children: [jsxRuntime.jsx(icons.NotepadTextIcon, { className: cn('size-4', lib.themeIconColor) }), jsxRuntime.jsx(i18n.I18nLabel, { label: "toc" })] })));
|
|
61
63
|
}
|
|
62
64
|
function PortableClerkTOCScrollArea(_a) {
|
|
63
65
|
var { ref, className } = _a, props = tslib.__rest(_a, ["ref", "className"]);
|
|
@@ -390,3 +392,4 @@ exports.PortableClerkTOC = PortableClerkTOC;
|
|
|
390
392
|
exports.PortableClerkTOCItems = PortableClerkTOCItems;
|
|
391
393
|
exports.PortableClerkTOCPopover = PortableClerkTOCPopover;
|
|
392
394
|
exports.PortableClerkTOCScrollArea = PortableClerkTOCScrollArea;
|
|
395
|
+
exports.PortableClerkTOCTitle = PortableClerkTOCTitle;
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { __rest } from 'tslib';
|
|
3
|
-
import {
|
|
3
|
+
import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
|
|
4
4
|
import * as Primitive from 'fumadocs-core/toc';
|
|
5
|
-
import {
|
|
5
|
+
import { I18nLabel } from 'fumadocs-ui/contexts/i18n';
|
|
6
|
+
import { Collapsible, CollapsibleTrigger, CollapsibleContent } from 'fumadocs-ui/components/ui/collapsible';
|
|
6
7
|
import { useRef, useState, useMemo, useLayoutEffect, useEffect } from 'react';
|
|
7
8
|
import { themeSvgIconColor, themeIconColor } from '@windrun-huaiin/base-ui/lib';
|
|
9
|
+
import { NotepadTextIcon, ChevronDownIcon } from '@windrun-huaiin/base-ui/icons';
|
|
8
10
|
|
|
9
11
|
// Base stroke width for both the inactive rail and the active highlight path.
|
|
10
12
|
const CLERK_PATH_STROKE_WIDTH = 1;
|
|
@@ -29,14 +31,14 @@ const CLERK_DEPTH_GROUP_LINE_OFFSETS = [6, 18, 30, 42];
|
|
|
29
31
|
// Max number of characters rendered for a TOC label before trimming with ellipsis.
|
|
30
32
|
const CLERK_MAX_LABEL_LENGTH = 44;
|
|
31
33
|
function PortableClerkTOC({ toc, header, footer, title, emptyLabel = 'No headings', className, }) {
|
|
32
|
-
return (
|
|
33
|
-
children: jsx(PortableClerkTOCItems, { toc: toc, emptyLabel: emptyLabel }),
|
|
34
|
-
} }));
|
|
34
|
+
return (jsxs("div", { id: "nd-toc", className: cn('sticky top-(--fd-docs-row-1) h-[calc(var(--fd-docs-height)-var(--fd-docs-row-1))] flex flex-col [grid-area:toc] w-(--fd-toc-width) pt-12 pe-4 pb-2 max-xl:hidden', className), children: [header, title !== null && title !== void 0 ? title : jsx(PortableClerkTOCTitle, {}), jsx(PortableClerkTOCScrollArea, { children: jsx(PortableClerkTOCItems, { toc: toc, emptyLabel: emptyLabel }) }), footer] }));
|
|
35
35
|
}
|
|
36
36
|
function PortableClerkTOCPopover({ toc, header, footer, emptyLabel = 'No headings', }) {
|
|
37
|
-
return (jsx(
|
|
38
|
-
|
|
39
|
-
|
|
37
|
+
return (jsx(Collapsible, { "data-toc-popover": "", className: "sticky top-(--fd-docs-row-2) z-10 [grid-area:toc-popover] h-(--fd-toc-popover-height) xl:hidden max-xl:layout:[--fd-toc-popover-height:--spacing(10)]", children: jsxs("header", { className: "border-b bg-fd-background/80 backdrop-blur-sm transition-colors", children: [jsxs(CollapsibleTrigger, { "data-toc-popover-trigger": "", className: "flex w-full h-10 items-center text-sm text-fd-muted-foreground gap-2.5 px-4 py-2.5 text-start focus-visible:outline-none [&_svg]:size-4 md:px-6", children: [jsx(NotepadTextIcon, { className: "shrink-0" }), jsx("span", { className: "flex-1 truncate", children: jsx(I18nLabel, { label: "toc" }) }), jsx(ChevronDownIcon, { className: "shrink-0 transition-transform mx-0.5" })] }), jsx(CollapsibleContent, { "data-toc-popover-content": "", children: jsxs("div", { className: "flex max-h-[50vh] flex-col px-4 md:px-6", children: [header, jsx(PortableClerkTOCScrollArea, { children: jsx(PortableClerkTOCItems, { toc: toc, emptyLabel: emptyLabel }) }), footer] }) })] }) }));
|
|
38
|
+
}
|
|
39
|
+
function PortableClerkTOCTitle(_a) {
|
|
40
|
+
var { className } = _a, props = __rest(_a, ["className"]);
|
|
41
|
+
return (jsxs("h3", Object.assign({ id: "toc-title", className: cn('inline-flex items-center gap-1.5 text-sm text-fd-muted-foreground', className) }, props, { children: [jsx(NotepadTextIcon, { className: cn('size-4', themeIconColor) }), jsx(I18nLabel, { label: "toc" })] })));
|
|
40
42
|
}
|
|
41
43
|
function PortableClerkTOCScrollArea(_a) {
|
|
42
44
|
var { ref, className } = _a, props = __rest(_a, ["ref", "className"]);
|
|
@@ -365,4 +367,4 @@ function mergeRefs(...refs) {
|
|
|
365
367
|
};
|
|
366
368
|
}
|
|
367
369
|
|
|
368
|
-
export { PortableClerkTOC, PortableClerkTOCItems, PortableClerkTOCPopover, PortableClerkTOCScrollArea };
|
|
370
|
+
export { PortableClerkTOC, PortableClerkTOCItems, PortableClerkTOCPopover, PortableClerkTOCScrollArea, PortableClerkTOCTitle };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@windrun-huaiin/third-ui",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "24.0.0",
|
|
4
4
|
"description": "Third-party integrated UI components for windrun-huaiin projects",
|
|
5
5
|
"exports": {
|
|
6
6
|
"./clerk": {
|
|
@@ -137,9 +137,9 @@
|
|
|
137
137
|
"tslib": "^2.8.1",
|
|
138
138
|
"unified": "^11.0.5",
|
|
139
139
|
"zod": "^4.3.6",
|
|
140
|
-
"@windrun-huaiin/
|
|
141
|
-
"@windrun-huaiin/
|
|
142
|
-
"@windrun-huaiin/lib": "^
|
|
140
|
+
"@windrun-huaiin/contracts": "^24.0.0",
|
|
141
|
+
"@windrun-huaiin/base-ui": "^24.0.0",
|
|
142
|
+
"@windrun-huaiin/lib": "^24.0.0"
|
|
143
143
|
},
|
|
144
144
|
"peerDependencies": {
|
|
145
145
|
"clsx": "^2.1.1",
|
|
@@ -1,9 +1,15 @@
|
|
|
1
1
|
import { DocsBody, DocsDescription, DocsPage, DocsTitle } from 'fumadocs-ui/page';
|
|
2
|
-
import { ReactNode, ReactElement, cloneElement } from 'react';
|
|
2
|
+
import { ReactNode, ReactElement, cloneElement, type CSSProperties } from 'react';
|
|
3
3
|
import { TocFooterWrapper } from '@third-ui/fuma/mdx/toc-footer-wrapper';
|
|
4
4
|
import type { LLMCopyButtonProps, LLMCopyButton } from '@third-ui/fuma/mdx/toc-base';
|
|
5
5
|
import { getAsNeededLocalizedUrl } from '@windrun-huaiin/lib';
|
|
6
|
-
import { PortableClerkTOC } from '@third-ui/fuma/mdx/toc-clerk-portable';
|
|
6
|
+
import { PortableClerkTOC, PortableClerkTOCTitle } from '@third-ui/fuma/mdx/toc-clerk-portable';
|
|
7
|
+
import { themeSvgIconColor } from '@windrun-huaiin/base-ui/lib';
|
|
8
|
+
|
|
9
|
+
export type FumaPageTocRenderMode =
|
|
10
|
+
| 'portable-clerk'
|
|
11
|
+
| 'fumadocs-clerk'
|
|
12
|
+
| 'fumadocs-normal';
|
|
7
13
|
|
|
8
14
|
interface FumaPageParams {
|
|
9
15
|
/*
|
|
@@ -49,6 +55,17 @@ interface FumaPageParams {
|
|
|
49
55
|
// default true
|
|
50
56
|
showTableOfContent?: boolean;
|
|
51
57
|
|
|
58
|
+
/*
|
|
59
|
+
* Controls which TOC renderer is used.
|
|
60
|
+
*
|
|
61
|
+
* - portable-clerk: use @third-ui's custom Clerk-like TOC renderer.
|
|
62
|
+
* - fumadocs-clerk: use fumadocs-ui's built-in clerk slot renderer.
|
|
63
|
+
* - fumadocs-normal: use fumadocs-ui's built-in normal slot renderer.
|
|
64
|
+
*
|
|
65
|
+
* @defaultValue 'portable-clerk'
|
|
66
|
+
*/
|
|
67
|
+
tocRenderMode?: FumaPageTocRenderMode;
|
|
68
|
+
|
|
52
69
|
/*
|
|
53
70
|
* @deprecated Mobile TOC popover is no longer used.
|
|
54
71
|
*/
|
|
@@ -77,6 +94,7 @@ export function createFumaPage({
|
|
|
77
94
|
supportedLocales = ['en'],
|
|
78
95
|
showBreadcrumb = true,
|
|
79
96
|
showTableOfContent = true,
|
|
97
|
+
tocRenderMode = 'portable-clerk',
|
|
80
98
|
showTableOfContentPopover = false,
|
|
81
99
|
localePrefixAsNeeded = true,
|
|
82
100
|
defaultLocale = 'en',
|
|
@@ -123,18 +141,15 @@ export function createFumaPage({
|
|
|
123
141
|
return (
|
|
124
142
|
<DocsPage
|
|
125
143
|
breadcrumb={{enabled: showBreadcrumb}}
|
|
126
|
-
tableOfContent={{
|
|
144
|
+
tableOfContent={resolveTableOfContentOptions({
|
|
127
145
|
enabled: showTableOfContent,
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
footer={tocFooterElement}
|
|
133
|
-
/>
|
|
134
|
-
),
|
|
135
|
-
}}
|
|
146
|
+
tocRenderMode,
|
|
147
|
+
toc: content.toc,
|
|
148
|
+
footer: tocFooterElement,
|
|
149
|
+
})}
|
|
136
150
|
tableOfContentPopover={{
|
|
137
|
-
enabled:
|
|
151
|
+
enabled: showTableOfContentPopover && tocRenderMode !== 'portable-clerk',
|
|
152
|
+
style: tocRenderMode === 'fumadocs-clerk' ? 'clerk' : 'normal',
|
|
138
153
|
}}
|
|
139
154
|
toc={content.toc}
|
|
140
155
|
className="max-sm:pb-16"
|
|
@@ -194,3 +209,56 @@ export function createFumaPage({
|
|
|
194
209
|
generateMetadata,
|
|
195
210
|
};
|
|
196
211
|
}
|
|
212
|
+
|
|
213
|
+
function resolveTableOfContentOptions({
|
|
214
|
+
enabled,
|
|
215
|
+
tocRenderMode,
|
|
216
|
+
toc,
|
|
217
|
+
footer,
|
|
218
|
+
}: {
|
|
219
|
+
enabled: boolean;
|
|
220
|
+
tocRenderMode: FumaPageTocRenderMode;
|
|
221
|
+
toc: any[];
|
|
222
|
+
footer: ReactNode;
|
|
223
|
+
}) {
|
|
224
|
+
if (tocRenderMode === 'portable-clerk') {
|
|
225
|
+
return {
|
|
226
|
+
enabled,
|
|
227
|
+
single: false,
|
|
228
|
+
component: (
|
|
229
|
+
<PortableClerkTOC
|
|
230
|
+
toc={toc}
|
|
231
|
+
footer={footer}
|
|
232
|
+
/>
|
|
233
|
+
),
|
|
234
|
+
};
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
const themedTocProps = {
|
|
238
|
+
container: {
|
|
239
|
+
className: '[--color-fd-primary:var(--third-ui-toc-primary)] [--color-fd-primary-foreground:var(--third-ui-toc-primary-foreground)] [&_#toc-title]:hidden',
|
|
240
|
+
style: {
|
|
241
|
+
'--third-ui-toc-primary': themeSvgIconColor,
|
|
242
|
+
'--third-ui-toc-primary-foreground': '#ffffff',
|
|
243
|
+
} as CSSProperties,
|
|
244
|
+
},
|
|
245
|
+
header: <PortableClerkTOCTitle />,
|
|
246
|
+
footer,
|
|
247
|
+
};
|
|
248
|
+
|
|
249
|
+
if (tocRenderMode === 'fumadocs-clerk') {
|
|
250
|
+
return {
|
|
251
|
+
enabled,
|
|
252
|
+
single: false,
|
|
253
|
+
style: 'clerk',
|
|
254
|
+
...themedTocProps,
|
|
255
|
+
} as const;
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
return {
|
|
259
|
+
enabled,
|
|
260
|
+
single: false,
|
|
261
|
+
style: 'normal',
|
|
262
|
+
...themedTocProps,
|
|
263
|
+
} as const;
|
|
264
|
+
}
|
|
@@ -5,12 +5,12 @@
|
|
|
5
5
|
* https://github.com/fuma-nama/fumadocs/blob/dev/packages/radix-ui/src/components/toc/clerk.tsx
|
|
6
6
|
*/
|
|
7
7
|
import * as Primitive from 'fumadocs-core/toc';
|
|
8
|
+
import { I18nLabel } from 'fumadocs-ui/contexts/i18n';
|
|
8
9
|
import {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
} from 'fumadocs-ui/layouts/docs/page/slots/toc';
|
|
10
|
+
Collapsible,
|
|
11
|
+
CollapsibleContent,
|
|
12
|
+
CollapsibleTrigger,
|
|
13
|
+
} from 'fumadocs-ui/components/ui/collapsible';
|
|
14
14
|
import {
|
|
15
15
|
type ComponentProps,
|
|
16
16
|
type ReactNode,
|
|
@@ -24,6 +24,7 @@ import {
|
|
|
24
24
|
themeIconColor,
|
|
25
25
|
themeSvgIconColor,
|
|
26
26
|
} from '@windrun-huaiin/base-ui/lib';
|
|
27
|
+
import { ChevronDownIcon, NotepadTextIcon } from '@windrun-huaiin/base-ui/icons';
|
|
27
28
|
|
|
28
29
|
type TOCItemType = Primitive.TOCItemType;
|
|
29
30
|
|
|
@@ -84,20 +85,20 @@ export function PortableClerkTOC({
|
|
|
84
85
|
className,
|
|
85
86
|
}: PortableClerkTOCProps) {
|
|
86
87
|
return (
|
|
87
|
-
<
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
}
|
|
100
|
-
|
|
88
|
+
<div
|
|
89
|
+
id="nd-toc"
|
|
90
|
+
className={cn(
|
|
91
|
+
'sticky top-(--fd-docs-row-1) h-[calc(var(--fd-docs-height)-var(--fd-docs-row-1))] flex flex-col [grid-area:toc] w-(--fd-toc-width) pt-12 pe-4 pb-2 max-xl:hidden',
|
|
92
|
+
className,
|
|
93
|
+
)}
|
|
94
|
+
>
|
|
95
|
+
{header}
|
|
96
|
+
{title ?? <PortableClerkTOCTitle />}
|
|
97
|
+
<PortableClerkTOCScrollArea>
|
|
98
|
+
<PortableClerkTOCItems toc={toc} emptyLabel={emptyLabel} />
|
|
99
|
+
</PortableClerkTOCScrollArea>
|
|
100
|
+
{footer}
|
|
101
|
+
</div>
|
|
101
102
|
);
|
|
102
103
|
}
|
|
103
104
|
|
|
@@ -108,14 +109,51 @@ export function PortableClerkTOCPopover({
|
|
|
108
109
|
emptyLabel = 'No headings',
|
|
109
110
|
}: Omit<PortableClerkTOCProps, 'title' | 'className'>) {
|
|
110
111
|
return (
|
|
111
|
-
<
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
112
|
+
<Collapsible
|
|
113
|
+
data-toc-popover=""
|
|
114
|
+
className="sticky top-(--fd-docs-row-2) z-10 [grid-area:toc-popover] h-(--fd-toc-popover-height) xl:hidden max-xl:layout:[--fd-toc-popover-height:--spacing(10)]"
|
|
115
|
+
>
|
|
116
|
+
<header className="border-b bg-fd-background/80 backdrop-blur-sm transition-colors">
|
|
117
|
+
<CollapsibleTrigger
|
|
118
|
+
data-toc-popover-trigger=""
|
|
119
|
+
className="flex w-full h-10 items-center text-sm text-fd-muted-foreground gap-2.5 px-4 py-2.5 text-start focus-visible:outline-none [&_svg]:size-4 md:px-6"
|
|
120
|
+
>
|
|
121
|
+
<NotepadTextIcon className="shrink-0" />
|
|
122
|
+
<span className="flex-1 truncate">
|
|
123
|
+
<I18nLabel label="toc" />
|
|
124
|
+
</span>
|
|
125
|
+
<ChevronDownIcon className="shrink-0 transition-transform mx-0.5" />
|
|
126
|
+
</CollapsibleTrigger>
|
|
127
|
+
<CollapsibleContent data-toc-popover-content="">
|
|
128
|
+
<div className="flex max-h-[50vh] flex-col px-4 md:px-6">
|
|
129
|
+
{header}
|
|
130
|
+
<PortableClerkTOCScrollArea>
|
|
131
|
+
<PortableClerkTOCItems toc={toc} emptyLabel={emptyLabel} />
|
|
132
|
+
</PortableClerkTOCScrollArea>
|
|
133
|
+
{footer}
|
|
134
|
+
</div>
|
|
135
|
+
</CollapsibleContent>
|
|
136
|
+
</header>
|
|
137
|
+
</Collapsible>
|
|
138
|
+
);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
export function PortableClerkTOCTitle({
|
|
142
|
+
className,
|
|
143
|
+
...props
|
|
144
|
+
}: ComponentProps<'h3'>) {
|
|
145
|
+
return (
|
|
146
|
+
<h3
|
|
147
|
+
id="toc-title"
|
|
148
|
+
className={cn(
|
|
149
|
+
'inline-flex items-center gap-1.5 text-sm text-fd-muted-foreground',
|
|
150
|
+
className,
|
|
151
|
+
)}
|
|
152
|
+
{...props}
|
|
153
|
+
>
|
|
154
|
+
<NotepadTextIcon className={cn('size-4', themeIconColor)} />
|
|
155
|
+
<I18nLabel label="toc" />
|
|
156
|
+
</h3>
|
|
119
157
|
);
|
|
120
158
|
}
|
|
121
159
|
|