@windrun-huaiin/third-ui 15.1.1 → 16.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/LICENSE +1 -1
- package/dist/ai/ai-chat-composer.d.ts +2 -0
- package/dist/ai/ai-chat-composer.js +47 -0
- package/dist/ai/ai-chat-composer.mjs +45 -0
- package/dist/ai/ai-markdown.d.ts +2 -0
- package/dist/ai/ai-markdown.js +36 -0
- package/dist/ai/ai-markdown.mjs +34 -0
- package/dist/ai/ai-message-actions.d.ts +2 -0
- package/dist/ai/ai-message-actions.js +14 -0
- package/dist/ai/ai-message-actions.mjs +12 -0
- package/dist/ai/ai-message-bubble.d.ts +2 -0
- package/dist/ai/ai-message-bubble.js +66 -0
- package/dist/ai/ai-message-bubble.mjs +64 -0
- package/dist/ai/ai-message-content.d.ts +2 -0
- package/dist/ai/ai-message-content.js +63 -0
- package/dist/ai/ai-message-content.mjs +61 -0
- package/dist/ai/ai-message-list.d.ts +2 -0
- package/dist/ai/ai-message-list.js +24 -0
- package/dist/ai/ai-message-list.mjs +22 -0
- package/dist/ai/ai-message-meta.d.ts +2 -0
- package/dist/ai/ai-message-meta.js +38 -0
- package/dist/ai/ai-message-meta.mjs +36 -0
- package/dist/ai/ai-status-indicator.d.ts +2 -0
- package/dist/ai/ai-status-indicator.js +51 -0
- package/dist/ai/ai-status-indicator.mjs +49 -0
- package/dist/ai/index.d.ts +11 -0
- package/dist/ai/index.js +33 -0
- package/dist/ai/index.mjs +11 -0
- package/dist/ai/types.d.ts +110 -0
- package/dist/ai/use-ai-conversation.d.ts +13 -0
- package/dist/ai/use-ai-conversation.js +276 -0
- package/dist/ai/use-ai-conversation.mjs +274 -0
- package/dist/clerk/clerk-organization-client.js +2 -2
- package/dist/clerk/clerk-organization-client.mjs +2 -2
- package/dist/clerk/clerk-page-generator.d.ts +1 -1
- package/dist/clerk/clerk-user-client.js +2 -2
- package/dist/clerk/clerk-user-client.mjs +2 -2
- package/dist/clerk/fingerprint/fingerprint-provider.js +9 -9
- package/dist/clerk/fingerprint/fingerprint-provider.mjs +9 -9
- package/dist/fuma/base/custom-header.js +4 -4
- package/dist/fuma/base/custom-header.mjs +4 -4
- package/dist/fuma/mdx/banner.js +3 -3
- package/dist/fuma/mdx/banner.mjs +3 -3
- package/dist/fuma/mdx/fuma-github-info.js +3 -3
- package/dist/fuma/mdx/fuma-github-info.mjs +3 -3
- package/dist/fuma/mdx/gradient-button.js +3 -3
- package/dist/fuma/mdx/gradient-button.mjs +3 -3
- package/dist/fuma/mdx/index.d.ts +1 -0
- package/dist/fuma/mdx/index.js +2 -0
- package/dist/fuma/mdx/index.mjs +1 -0
- package/dist/fuma/mdx/markdown-component-map.d.ts +3 -0
- package/dist/fuma/mdx/markdown-component-map.js +73 -0
- package/dist/fuma/mdx/markdown-component-map.mjs +71 -0
- package/dist/fuma/mdx/mermaid.d.ts +2 -1
- package/dist/fuma/mdx/mermaid.js +130 -6
- package/dist/fuma/mdx/mermaid.mjs +130 -6
- package/dist/fuma/mdx/toc-base.js +4 -4
- package/dist/fuma/mdx/toc-base.mjs +4 -4
- package/dist/fuma/mdx/trophy-card.js +2 -2
- package/dist/fuma/mdx/trophy-card.mjs +2 -2
- package/dist/fuma/mdx/zia-card.js +3 -3
- package/dist/fuma/mdx/zia-card.mjs +3 -3
- package/dist/fuma/mdx/zia-file.js +3 -3
- package/dist/fuma/mdx/zia-file.mjs +3 -3
- package/dist/main/ads-alert-dialog.js +2 -2
- package/dist/main/ads-alert-dialog.mjs +2 -2
- package/dist/main/credit/credit-nav-button.js +2 -2
- package/dist/main/credit/credit-nav-button.mjs +2 -2
- package/dist/main/credit/credit-overview-client.js +4 -4
- package/dist/main/credit/credit-overview-client.mjs +4 -4
- package/dist/main/footer.js +2 -2
- package/dist/main/footer.mjs +2 -2
- package/dist/main/go-to-top.js +2 -2
- package/dist/main/go-to-top.mjs +2 -2
- package/dist/main/index.d.ts +1 -0
- package/dist/main/index.js +2 -0
- package/dist/main/index.mjs +1 -0
- package/dist/main/info-tooltip.d.ts +8 -0
- package/dist/main/info-tooltip.js +48 -0
- package/dist/main/info-tooltip.mjs +46 -0
- package/dist/main/pill-select/x-pill-select.js +2 -2
- package/dist/main/pill-select/x-pill-select.mjs +2 -2
- package/dist/main/pill-select/x-token-input.js +2 -2
- package/dist/main/pill-select/x-token-input.mjs +2 -2
- package/dist/main/x-button.js +3 -3
- package/dist/main/x-button.mjs +3 -3
- package/package.json +16 -3
- package/src/ai/ai-chat-composer.tsx +187 -0
- package/src/ai/ai-markdown.tsx +45 -0
- package/src/ai/ai-message-actions.tsx +16 -0
- package/src/ai/ai-message-bubble.tsx +138 -0
- package/src/ai/ai-message-content.tsx +149 -0
- package/src/ai/ai-message-list.tsx +59 -0
- package/src/ai/ai-message-meta.tsx +56 -0
- package/src/ai/ai-status-indicator.tsx +61 -0
- package/src/ai/index.ts +13 -0
- package/src/ai/types.ts +131 -0
- package/src/ai/use-ai-conversation.ts +422 -0
- package/src/clerk/clerk-organization-client.tsx +5 -5
- package/src/clerk/clerk-page-generator.tsx +1 -1
- package/src/clerk/clerk-user-client.tsx +4 -4
- package/src/clerk/fingerprint/fingerprint-provider.tsx +34 -22
- package/src/fuma/base/custom-header.tsx +5 -5
- package/src/fuma/mdx/banner.tsx +3 -3
- package/src/fuma/mdx/fuma-github-info.tsx +4 -4
- package/src/fuma/mdx/gradient-button.tsx +3 -3
- package/src/fuma/mdx/index.ts +2 -1
- package/src/fuma/mdx/markdown-component-map.tsx +174 -0
- package/src/fuma/mdx/mermaid.tsx +145 -10
- package/src/fuma/mdx/toc-base.tsx +5 -5
- package/src/fuma/mdx/trophy-card.tsx +2 -2
- package/src/fuma/mdx/zia-card.tsx +3 -3
- package/src/fuma/mdx/zia-file.tsx +3 -3
- package/src/main/ads-alert-dialog.tsx +5 -5
- package/src/main/credit/credit-nav-button.tsx +3 -3
- package/src/main/credit/credit-overview-client.tsx +15 -7
- package/src/main/features.tsx +5 -3
- package/src/main/footer.tsx +4 -5
- package/src/main/go-to-top.tsx +2 -2
- package/src/main/index.ts +2 -0
- package/src/main/info-tooltip.tsx +99 -0
- package/src/main/language-detector.tsx +4 -4
- package/src/main/pill-select/x-pill-select.tsx +2 -2
- package/src/main/pill-select/x-token-input.tsx +2 -2
- package/src/main/x-button.tsx +4 -4
package/dist/fuma/mdx/mermaid.js
CHANGED
|
@@ -3,9 +3,10 @@
|
|
|
3
3
|
|
|
4
4
|
var tslib = require('tslib');
|
|
5
5
|
var jsxRuntime = require('react/jsx-runtime');
|
|
6
|
-
var
|
|
6
|
+
var icons = require('@windrun-huaiin/base-ui/icons');
|
|
7
7
|
var utils = require('@windrun-huaiin/lib/utils');
|
|
8
8
|
var nextThemes = require('next-themes');
|
|
9
|
+
var rough = require('roughjs');
|
|
9
10
|
var React = require('react');
|
|
10
11
|
var lib = require('@windrun-huaiin/base-ui/lib');
|
|
11
12
|
|
|
@@ -15,7 +16,7 @@ function sanitizeFilename(name) {
|
|
|
15
16
|
.replace(/\s+/g, '_')
|
|
16
17
|
.slice(0, 120);
|
|
17
18
|
}
|
|
18
|
-
function Mermaid({ chart, title, watermarkEnabled, watermarkText, enablePreview = true }) {
|
|
19
|
+
function Mermaid({ chart, title, watermarkEnabled, watermarkText, handDrawn = true, enablePreview = true }) {
|
|
19
20
|
const id = React.useId();
|
|
20
21
|
const [svg, setSvg] = React.useState('');
|
|
21
22
|
const { resolvedTheme } = nextThemes.useTheme();
|
|
@@ -45,9 +46,9 @@ function Mermaid({ chart, title, watermarkEnabled, watermarkText, enablePreview
|
|
|
45
46
|
try {
|
|
46
47
|
mermaid.initialize(mermaidConfig);
|
|
47
48
|
const { svg } = yield mermaid.render(id.replaceAll(':', ''), chart.replaceAll('\\n', '\n'));
|
|
48
|
-
let svgWithWatermark = svg;
|
|
49
|
+
let svgWithWatermark = handDrawn ? applyHandDrawnStyle(svg) : svg;
|
|
49
50
|
if (watermarkEnabled && watermarkText) {
|
|
50
|
-
svgWithWatermark = addWatermarkToSvg(
|
|
51
|
+
svgWithWatermark = addWatermarkToSvg(svgWithWatermark, watermarkText, lib.themeSvgIconColor);
|
|
51
52
|
}
|
|
52
53
|
if (isMounted)
|
|
53
54
|
setSvg(svgWithWatermark);
|
|
@@ -61,7 +62,7 @@ function Mermaid({ chart, title, watermarkEnabled, watermarkText, enablePreview
|
|
|
61
62
|
isMounted = false;
|
|
62
63
|
setSvg('');
|
|
63
64
|
};
|
|
64
|
-
}, [chart, id, resolvedTheme, watermarkEnabled, watermarkText]);
|
|
65
|
+
}, [chart, id, resolvedTheme, watermarkEnabled, watermarkText, handDrawn]);
|
|
65
66
|
// helpers for preview zoom
|
|
66
67
|
const clamp = (v, min, max) => Math.min(Math.max(v, min), max);
|
|
67
68
|
const resetTransform = React.useCallback(() => {
|
|
@@ -213,7 +214,7 @@ function Mermaid({ chart, title, watermarkEnabled, watermarkText, enablePreview
|
|
|
213
214
|
window.scrollTo(0, scrollY);
|
|
214
215
|
};
|
|
215
216
|
}, [open]);
|
|
216
|
-
return (jsxRuntime.jsxs("div", { children: [jsxRuntime.jsxs("div", { className: enablePreview ? 'group relative cursor-zoom-in' : undefined, onClick: () => enablePreview && svg && setOpen(true), children: [jsxRuntime.jsx("div", { dangerouslySetInnerHTML: { __html: svg } }), enablePreview && svg && (jsxRuntime.jsx("div", { className: "pointer-events-none absolute right-2 top-2 hidden rounded bg-black/50 px-2 py-0.5 text-[12px] text-white group-hover:block", children: "Preview Chart" }))] }), title && (jsxRuntime.jsxs("div", { className: utils.cn("mt-2 flex items-center justify-center text-center text-[13px] font-italic", lib.themeIconColor), children: [jsxRuntime.jsx(
|
|
217
|
+
return (jsxRuntime.jsxs("div", { children: [jsxRuntime.jsxs("div", { className: enablePreview ? 'group relative cursor-zoom-in' : undefined, onClick: () => enablePreview && svg && setOpen(true), children: [jsxRuntime.jsx("div", { dangerouslySetInnerHTML: { __html: svg } }), enablePreview && svg && (jsxRuntime.jsx("div", { className: "pointer-events-none absolute right-2 top-2 hidden rounded bg-black/50 px-2 py-0.5 text-[12px] text-white group-hover:block", children: "Preview Chart" }))] }), title && (jsxRuntime.jsxs("div", { className: utils.cn("mt-2 flex items-center justify-center text-center text-[13px] font-italic", lib.themeIconColor), children: [jsxRuntime.jsx(icons.MmdIcon, { className: 'mr-1 h-4 w-4' }), jsxRuntime.jsx("span", { children: title })] })), enablePreview && open && (jsxRuntime.jsxs("div", { role: "dialog", "aria-modal": "true", "aria-label": typeof title === 'string' ? title : 'Mermaid Preview', className: "fixed inset-0 z-9999 flex items-center justify-center", children: [jsxRuntime.jsx("div", { className: "absolute inset-0 bg-black/60", onClick: () => { setOpen(false); resetTransform(); }, onWheel: (e) => { e.preventDefault(); e.stopPropagation(); }, onTouchMove: (e) => { e.preventDefault(); e.stopPropagation(); } }), jsxRuntime.jsxs("div", { className: "relative z-1 max-w-[95vw] w-[95vw] h-[88vh] p-0 bg-white dark:bg-neutral-900 border border-neutral-200 dark:border-neutral-700 rounded-md shadow-2xl overflow-hidden", children: [jsxRuntime.jsxs("div", { className: "flex items-center justify-between gap-3 px-3 py-2 border-b border-neutral-200 dark:border-neutral-700", children: [jsxRuntime.jsxs("div", { className: utils.cn("min-w-0 flex items-center gap-2 text-sm", lib.themeIconColor), children: [jsxRuntime.jsx(icons.MmdIcon, { className: "h-4 w-4" }), jsxRuntime.jsx("span", { className: "truncate max-w-[50vw]", children: title !== null && title !== void 0 ? title : 'Mermaid Preview' })] }), jsxRuntime.jsxs("div", { className: "flex shrink-0 items-center gap-0.5", children: [jsxRuntime.jsx("button", { "aria-label": "Zoom out", className: "hidden h-6 w-6 items-center justify-center rounded border border-neutral-300 text-[13px] transition-colors hover:bg-neutral-100 active:bg-neutral-200 hover:border-neutral-400 active:border-neutral-500 dark:border-neutral-600 dark:hover:bg-neutral-700 dark:active:bg-neutral-600 dark:hover:border-neutral-500 dark:active:border-neutral-400 sm:flex", onClick: () => zoomBy(-0.5), children: "\uFF0D" }), jsxRuntime.jsxs("span", { className: "mx-0.5 w-12 text-center text-[12px] select-none", children: [Math.round(scale * 100), "%"] }), jsxRuntime.jsx("button", { "aria-label": "Zoom in", className: "hidden h-6 w-6 items-center justify-center rounded border border-neutral-300 text-[13px] transition-colors hover:bg-neutral-100 active:bg-neutral-200 hover:border-neutral-400 active:border-neutral-500 dark:border-neutral-600 dark:hover:bg-neutral-700 dark:active:bg-neutral-600 dark:hover:border-neutral-500 dark:active:border-neutral-400 sm:flex", onClick: () => zoomBy(0.5), children: "\uFF0B" }), jsxRuntime.jsx("div", { className: "mx-1 hidden h-4 w-px bg-neutral-300 dark:bg-neutral-700 sm:block" }), jsxRuntime.jsx("button", { "aria-label": "Zoom 100%", className: "hidden h-6 min-w-8 items-center justify-center rounded border border-neutral-300 px-1.5 text-[12px] transition-colors hover:bg-neutral-100 active:bg-neutral-200 hover:border-neutral-400 active:border-neutral-500 dark:border-neutral-600 dark:hover:bg-neutral-700 dark:active:bg-neutral-600 dark:hover:border-neutral-500 dark:active:border-neutral-400 sm:inline-flex", onClick: () => setScale(1), children: "X1" }), jsxRuntime.jsx("button", { "aria-label": "Zoom 200%", className: "ml-1 hidden h-6 min-w-8 items-center justify-center rounded border border-neutral-300 px-1.5 text-[12px] transition-colors hover:bg-neutral-100 active:bg-neutral-200 hover:border-neutral-400 active:border-neutral-500 dark:border-neutral-600 dark:hover:bg-neutral-700 dark:active:bg-neutral-600 dark:hover:border-neutral-500 dark:active:border-neutral-400 sm:inline-flex", onClick: () => setScale(2), children: "X2" }), jsxRuntime.jsx("button", { "aria-label": "Zoom 300%", className: "ml-1 hidden h-6 min-w-8 items-center justify-center rounded border border-neutral-300 px-1.5 text-[12px] transition-colors hover:bg-neutral-100 active:bg-neutral-200 hover:border-neutral-400 active:border-neutral-500 dark:border-neutral-600 dark:hover:bg-neutral-700 dark:active:bg-neutral-600 dark:hover:border-neutral-500 dark:active:border-neutral-400 sm:inline-flex", onClick: () => setScale(3), children: "X3" }), jsxRuntime.jsx("button", { "aria-label": "Zoom 1000%", className: "ml-1 hidden h-6 min-w-10 items-center justify-center rounded border border-neutral-300 px-1.5 text-[12px] transition-colors hover:bg-neutral-100 active:bg-neutral-200 hover:border-neutral-400 active:border-neutral-500 dark:border-neutral-600 dark:hover:bg-neutral-700 dark:active:bg-neutral-600 dark:hover:border-neutral-500 dark:active:border-neutral-400 sm:inline-flex", onClick: () => setScale(10), children: "X10" }), jsxRuntime.jsx("button", { "aria-label": "Reset", className: utils.cn("ml-1 flex h-6 w-6 items-center justify-center rounded transition-colors hover:bg-neutral-100 active:bg-neutral-200 dark:hover:bg-neutral-700 dark:active:bg-neutral-600", lib.themeIconColor), onClick: resetTransform, children: jsxRuntime.jsx(icons.RefreshCcwIcon, { className: "h-3.5 w-3.5" }) }), jsxRuntime.jsx("button", { "aria-label": "Download SVG", className: utils.cn("ml-1 flex h-6 w-6 items-center justify-center rounded transition-colors hover:bg-neutral-100 active:bg-neutral-200 dark:hover:bg-neutral-700 dark:active:bg-neutral-600", lib.themeIconColor), onClick: handleDownload, children: jsxRuntime.jsx(icons.DownloadIcon, { className: "h-3.5 w-3.5" }) }), jsxRuntime.jsx("button", { "aria-label": "Close", className: utils.cn("ml-1 flex h-6 w-6 items-center justify-center rounded transition-colors hover:bg-neutral-100 active:bg-neutral-200 dark:hover:bg-neutral-700 dark:active:bg-neutral-600", lib.themeIconColor), onClick: () => { setOpen(false); resetTransform(); }, children: jsxRuntime.jsx(icons.XIcon, { className: "h-3.5 w-3.5" }) })] })] }), jsxRuntime.jsxs("div", { className: "relative h-[calc(88vh-40px)] w-full overflow-hidden bg-white dark:bg-neutral-900 overscroll-contain touch-none", onWheel: onWheel, onPointerDown: onPointerDown, onPointerMove: onPointerMove, onPointerUp: onPointerUp, onPointerCancel: onPointerCancel, children: [jsxRuntime.jsx("div", { className: "absolute left-1/2 top-1/2", style: { transform: `translate(-50%, -50%) translate(${translate.x}px, ${translate.y}px)` }, children: jsxRuntime.jsx("div", { style: { transform: `scale(${scale})`, transformOrigin: '50% 50%' }, dangerouslySetInnerHTML: { __html: svg } }) }), jsxRuntime.jsxs("div", { className: "absolute inset-x-3 bottom-3 rounded-md bg-white/92 px-3 py-2 shadow-sm backdrop-blur sm:hidden dark:bg-neutral-900/92", children: [jsxRuntime.jsxs("label", { className: "mb-1 flex items-center justify-between text-[11px] text-neutral-600 dark:text-neutral-300", children: [jsxRuntime.jsx("span", { children: "Zoom" }), jsxRuntime.jsxs("span", { children: [Math.round(scale * 100), "%"] })] }), jsxRuntime.jsx("input", { "aria-label": "Zoom slider", className: "block w-full", type: "range", min: "25", max: "1000", step: "5", value: Math.round(scale * 100), style: { accentColor: lib.themeSvgIconColor }, onChange: (e) => setScale(clamp(Number(e.target.value) / 100, 0.25, 10)) })] }), jsxRuntime.jsx("div", { className: "pointer-events-none absolute bottom-2 right-3 hidden rounded bg-black/40 px-2 py-1 text-xs text-white sm:block", children: "Drag to pan, click button to zoom-out or zoom-in" }), jsxRuntime.jsx("div", { className: "pointer-events-none absolute left-3 top-3 rounded bg-black/40 px-2 py-1 text-[11px] text-white sm:hidden", children: "Drag to pan, pinch to zoom-out or zoom-in" })] })] })] }))] }));
|
|
217
218
|
}
|
|
218
219
|
function addWatermarkToSvg(svg, watermark, watermarkColor) {
|
|
219
220
|
const watermarkText = `
|
|
@@ -232,5 +233,128 @@ function addWatermarkToSvg(svg, watermark, watermarkColor) {
|
|
|
232
233
|
`;
|
|
233
234
|
return svg.replace('</svg>', `${watermarkText}</svg>`);
|
|
234
235
|
}
|
|
236
|
+
function applyHandDrawnStyle(svg) {
|
|
237
|
+
if (typeof window === 'undefined')
|
|
238
|
+
return svg;
|
|
239
|
+
try {
|
|
240
|
+
const parser = new DOMParser();
|
|
241
|
+
const doc = parser.parseFromString(svg, 'image/svg+xml');
|
|
242
|
+
const svgElement = doc.documentElement;
|
|
243
|
+
if (!svgElement || svgElement.tagName.toLowerCase() !== 'svg')
|
|
244
|
+
return svg;
|
|
245
|
+
const rc = rough.svg(svgElement);
|
|
246
|
+
const serializer = new XMLSerializer();
|
|
247
|
+
const getNumber = (value) => Number.parseFloat(value !== null && value !== void 0 ? value : '') || 0;
|
|
248
|
+
const getStyleValue = (element, name) => {
|
|
249
|
+
const inlineStyle = element.getAttribute('style');
|
|
250
|
+
if (inlineStyle) {
|
|
251
|
+
const match = inlineStyle.match(new RegExp(`(?:^|;)\\s*${name}\\s*:\\s*([^;]+)`));
|
|
252
|
+
if (match === null || match === void 0 ? void 0 : match[1])
|
|
253
|
+
return match[1].trim();
|
|
254
|
+
}
|
|
255
|
+
return element.getAttribute(name);
|
|
256
|
+
};
|
|
257
|
+
const applyAttributes = (source, target) => {
|
|
258
|
+
var _a;
|
|
259
|
+
for (const attr of source.getAttributeNames()) {
|
|
260
|
+
if (attr === 'x' || attr === 'y' || attr === 'x1' || attr === 'y1' || attr === 'x2' || attr === 'y2' || attr === 'width' || attr === 'height' || attr === 'rx' || attr === 'ry' || attr === 'points' || attr === 'd')
|
|
261
|
+
continue;
|
|
262
|
+
target.setAttribute(attr, (_a = source.getAttribute(attr)) !== null && _a !== void 0 ? _a : '');
|
|
263
|
+
}
|
|
264
|
+
};
|
|
265
|
+
const createOptions = (element) => {
|
|
266
|
+
var _a, _b;
|
|
267
|
+
const stroke = (_a = getStyleValue(element, 'stroke')) !== null && _a !== void 0 ? _a : '#000';
|
|
268
|
+
const fill = (_b = getStyleValue(element, 'fill')) !== null && _b !== void 0 ? _b : 'none';
|
|
269
|
+
const strokeWidth = getNumber(getStyleValue(element, 'stroke-width')) || 1.5;
|
|
270
|
+
return {
|
|
271
|
+
stroke,
|
|
272
|
+
fill: fill === 'none' ? undefined : fill,
|
|
273
|
+
strokeWidth,
|
|
274
|
+
roughness: 1.6,
|
|
275
|
+
bowing: 1.25,
|
|
276
|
+
fillStyle: fill === 'none' ? 'hachure' : 'solid',
|
|
277
|
+
fillWeight: 0.8,
|
|
278
|
+
hachureGap: 10,
|
|
279
|
+
preserveVertices: true,
|
|
280
|
+
seed: 7,
|
|
281
|
+
};
|
|
282
|
+
};
|
|
283
|
+
const replaceShape = (element, node) => {
|
|
284
|
+
var _a, _b;
|
|
285
|
+
if (!node || !element.parentNode)
|
|
286
|
+
return;
|
|
287
|
+
applyAttributes(element, node);
|
|
288
|
+
if (element.getAttribute('class')) {
|
|
289
|
+
node.setAttribute('class', (_a = element.getAttribute('class')) !== null && _a !== void 0 ? _a : '');
|
|
290
|
+
}
|
|
291
|
+
if (element.getAttribute('style')) {
|
|
292
|
+
node.setAttribute('style', (_b = element.getAttribute('style')) !== null && _b !== void 0 ? _b : '');
|
|
293
|
+
}
|
|
294
|
+
element.parentNode.replaceChild(node, element);
|
|
295
|
+
};
|
|
296
|
+
svgElement.querySelectorAll('rect').forEach((element) => {
|
|
297
|
+
const x = getNumber(element.getAttribute('x'));
|
|
298
|
+
const y = getNumber(element.getAttribute('y'));
|
|
299
|
+
const width = getNumber(element.getAttribute('width'));
|
|
300
|
+
const height = getNumber(element.getAttribute('height'));
|
|
301
|
+
const rx = getNumber(element.getAttribute('rx'));
|
|
302
|
+
const ry = getNumber(element.getAttribute('ry'));
|
|
303
|
+
const node = rx > 0 || ry > 0
|
|
304
|
+
? rc.path(`M ${x + rx} ${y}
|
|
305
|
+
H ${x + width - rx}
|
|
306
|
+
Q ${x + width} ${y} ${x + width} ${y + ry}
|
|
307
|
+
V ${y + height - ry}
|
|
308
|
+
Q ${x + width} ${y + height} ${x + width - rx} ${y + height}
|
|
309
|
+
H ${x + rx}
|
|
310
|
+
Q ${x} ${y + height} ${x} ${y + height - ry}
|
|
311
|
+
V ${y + ry}
|
|
312
|
+
Q ${x} ${y} ${x + rx} ${y}
|
|
313
|
+
Z`, createOptions(element))
|
|
314
|
+
: rc.rectangle(x, y, width, height, createOptions(element));
|
|
315
|
+
replaceShape(element, node);
|
|
316
|
+
});
|
|
317
|
+
svgElement.querySelectorAll('line').forEach((element) => {
|
|
318
|
+
const node = rc.line(getNumber(element.getAttribute('x1')), getNumber(element.getAttribute('y1')), getNumber(element.getAttribute('x2')), getNumber(element.getAttribute('y2')), createOptions(element));
|
|
319
|
+
replaceShape(element, node);
|
|
320
|
+
});
|
|
321
|
+
svgElement.querySelectorAll('polyline').forEach((element) => {
|
|
322
|
+
var _a;
|
|
323
|
+
const points = ((_a = element.getAttribute('points')) !== null && _a !== void 0 ? _a : '')
|
|
324
|
+
.trim()
|
|
325
|
+
.split(/\s+/)
|
|
326
|
+
.map((pair) => pair.split(',').map(Number))
|
|
327
|
+
.filter((point) => point.length === 2 && Number.isFinite(point[0]) && Number.isFinite(point[1]));
|
|
328
|
+
if (points.length < 2)
|
|
329
|
+
return;
|
|
330
|
+
const node = rc.linearPath(points, createOptions(element));
|
|
331
|
+
replaceShape(element, node);
|
|
332
|
+
});
|
|
333
|
+
svgElement.querySelectorAll('polygon').forEach((element) => {
|
|
334
|
+
var _a;
|
|
335
|
+
const points = ((_a = element.getAttribute('points')) !== null && _a !== void 0 ? _a : '')
|
|
336
|
+
.trim()
|
|
337
|
+
.split(/\s+/)
|
|
338
|
+
.map((pair) => pair.split(',').map(Number))
|
|
339
|
+
.filter((point) => point.length === 2 && Number.isFinite(point[0]) && Number.isFinite(point[1]));
|
|
340
|
+
if (points.length < 2)
|
|
341
|
+
return;
|
|
342
|
+
const node = rc.polygon(points, createOptions(element));
|
|
343
|
+
replaceShape(element, node);
|
|
344
|
+
});
|
|
345
|
+
svgElement.querySelectorAll('path').forEach((element) => {
|
|
346
|
+
const d = element.getAttribute('d');
|
|
347
|
+
if (!d)
|
|
348
|
+
return;
|
|
349
|
+
const node = rc.path(d, createOptions(element));
|
|
350
|
+
replaceShape(element, node);
|
|
351
|
+
});
|
|
352
|
+
return serializer.serializeToString(svgElement);
|
|
353
|
+
}
|
|
354
|
+
catch (error) {
|
|
355
|
+
console.error('Error while applying hand-drawn mermaid style', error);
|
|
356
|
+
return svg;
|
|
357
|
+
}
|
|
358
|
+
}
|
|
235
359
|
|
|
236
360
|
exports.Mermaid = Mermaid;
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { __awaiter } from 'tslib';
|
|
3
3
|
import { jsxs, jsx } from 'react/jsx-runtime';
|
|
4
|
-
import {
|
|
4
|
+
import { MmdIcon, RefreshCcwIcon, DownloadIcon, XIcon } from '@windrun-huaiin/base-ui/icons';
|
|
5
5
|
import { cn } from '@windrun-huaiin/lib/utils';
|
|
6
6
|
import { useTheme } from 'next-themes';
|
|
7
|
+
import rough from 'roughjs';
|
|
7
8
|
import { useId, useState, useRef, useEffect, useCallback } from 'react';
|
|
8
9
|
import { themeSvgIconColor, themeIconColor } from '@windrun-huaiin/base-ui/lib';
|
|
9
10
|
|
|
@@ -13,7 +14,7 @@ function sanitizeFilename(name) {
|
|
|
13
14
|
.replace(/\s+/g, '_')
|
|
14
15
|
.slice(0, 120);
|
|
15
16
|
}
|
|
16
|
-
function Mermaid({ chart, title, watermarkEnabled, watermarkText, enablePreview = true }) {
|
|
17
|
+
function Mermaid({ chart, title, watermarkEnabled, watermarkText, handDrawn = true, enablePreview = true }) {
|
|
17
18
|
const id = useId();
|
|
18
19
|
const [svg, setSvg] = useState('');
|
|
19
20
|
const { resolvedTheme } = useTheme();
|
|
@@ -43,9 +44,9 @@ function Mermaid({ chart, title, watermarkEnabled, watermarkText, enablePreview
|
|
|
43
44
|
try {
|
|
44
45
|
mermaid.initialize(mermaidConfig);
|
|
45
46
|
const { svg } = yield mermaid.render(id.replaceAll(':', ''), chart.replaceAll('\\n', '\n'));
|
|
46
|
-
let svgWithWatermark = svg;
|
|
47
|
+
let svgWithWatermark = handDrawn ? applyHandDrawnStyle(svg) : svg;
|
|
47
48
|
if (watermarkEnabled && watermarkText) {
|
|
48
|
-
svgWithWatermark = addWatermarkToSvg(
|
|
49
|
+
svgWithWatermark = addWatermarkToSvg(svgWithWatermark, watermarkText, themeSvgIconColor);
|
|
49
50
|
}
|
|
50
51
|
if (isMounted)
|
|
51
52
|
setSvg(svgWithWatermark);
|
|
@@ -59,7 +60,7 @@ function Mermaid({ chart, title, watermarkEnabled, watermarkText, enablePreview
|
|
|
59
60
|
isMounted = false;
|
|
60
61
|
setSvg('');
|
|
61
62
|
};
|
|
62
|
-
}, [chart, id, resolvedTheme, watermarkEnabled, watermarkText]);
|
|
63
|
+
}, [chart, id, resolvedTheme, watermarkEnabled, watermarkText, handDrawn]);
|
|
63
64
|
// helpers for preview zoom
|
|
64
65
|
const clamp = (v, min, max) => Math.min(Math.max(v, min), max);
|
|
65
66
|
const resetTransform = useCallback(() => {
|
|
@@ -211,7 +212,7 @@ function Mermaid({ chart, title, watermarkEnabled, watermarkText, enablePreview
|
|
|
211
212
|
window.scrollTo(0, scrollY);
|
|
212
213
|
};
|
|
213
214
|
}, [open]);
|
|
214
|
-
return (jsxs("div", { children: [jsxs("div", { className: enablePreview ? 'group relative cursor-zoom-in' : undefined, onClick: () => enablePreview && svg && setOpen(true), children: [jsx("div", { dangerouslySetInnerHTML: { __html: svg } }), enablePreview && svg && (jsx("div", { className: "pointer-events-none absolute right-2 top-2 hidden rounded bg-black/50 px-2 py-0.5 text-[12px] text-white group-hover:block", children: "Preview Chart" }))] }), title && (jsxs("div", { className: cn("mt-2 flex items-center justify-center text-center text-[13px] font-italic", themeIconColor), children: [jsx(
|
|
215
|
+
return (jsxs("div", { children: [jsxs("div", { className: enablePreview ? 'group relative cursor-zoom-in' : undefined, onClick: () => enablePreview && svg && setOpen(true), children: [jsx("div", { dangerouslySetInnerHTML: { __html: svg } }), enablePreview && svg && (jsx("div", { className: "pointer-events-none absolute right-2 top-2 hidden rounded bg-black/50 px-2 py-0.5 text-[12px] text-white group-hover:block", children: "Preview Chart" }))] }), title && (jsxs("div", { className: cn("mt-2 flex items-center justify-center text-center text-[13px] font-italic", themeIconColor), children: [jsx(MmdIcon, { className: 'mr-1 h-4 w-4' }), jsx("span", { children: title })] })), enablePreview && open && (jsxs("div", { role: "dialog", "aria-modal": "true", "aria-label": typeof title === 'string' ? title : 'Mermaid Preview', className: "fixed inset-0 z-9999 flex items-center justify-center", children: [jsx("div", { className: "absolute inset-0 bg-black/60", onClick: () => { setOpen(false); resetTransform(); }, onWheel: (e) => { e.preventDefault(); e.stopPropagation(); }, onTouchMove: (e) => { e.preventDefault(); e.stopPropagation(); } }), jsxs("div", { className: "relative z-1 max-w-[95vw] w-[95vw] h-[88vh] p-0 bg-white dark:bg-neutral-900 border border-neutral-200 dark:border-neutral-700 rounded-md shadow-2xl overflow-hidden", children: [jsxs("div", { className: "flex items-center justify-between gap-3 px-3 py-2 border-b border-neutral-200 dark:border-neutral-700", children: [jsxs("div", { className: cn("min-w-0 flex items-center gap-2 text-sm", themeIconColor), children: [jsx(MmdIcon, { className: "h-4 w-4" }), jsx("span", { className: "truncate max-w-[50vw]", children: title !== null && title !== void 0 ? title : 'Mermaid Preview' })] }), jsxs("div", { className: "flex shrink-0 items-center gap-0.5", children: [jsx("button", { "aria-label": "Zoom out", className: "hidden h-6 w-6 items-center justify-center rounded border border-neutral-300 text-[13px] transition-colors hover:bg-neutral-100 active:bg-neutral-200 hover:border-neutral-400 active:border-neutral-500 dark:border-neutral-600 dark:hover:bg-neutral-700 dark:active:bg-neutral-600 dark:hover:border-neutral-500 dark:active:border-neutral-400 sm:flex", onClick: () => zoomBy(-0.5), children: "\uFF0D" }), jsxs("span", { className: "mx-0.5 w-12 text-center text-[12px] select-none", children: [Math.round(scale * 100), "%"] }), jsx("button", { "aria-label": "Zoom in", className: "hidden h-6 w-6 items-center justify-center rounded border border-neutral-300 text-[13px] transition-colors hover:bg-neutral-100 active:bg-neutral-200 hover:border-neutral-400 active:border-neutral-500 dark:border-neutral-600 dark:hover:bg-neutral-700 dark:active:bg-neutral-600 dark:hover:border-neutral-500 dark:active:border-neutral-400 sm:flex", onClick: () => zoomBy(0.5), children: "\uFF0B" }), jsx("div", { className: "mx-1 hidden h-4 w-px bg-neutral-300 dark:bg-neutral-700 sm:block" }), jsx("button", { "aria-label": "Zoom 100%", className: "hidden h-6 min-w-8 items-center justify-center rounded border border-neutral-300 px-1.5 text-[12px] transition-colors hover:bg-neutral-100 active:bg-neutral-200 hover:border-neutral-400 active:border-neutral-500 dark:border-neutral-600 dark:hover:bg-neutral-700 dark:active:bg-neutral-600 dark:hover:border-neutral-500 dark:active:border-neutral-400 sm:inline-flex", onClick: () => setScale(1), children: "X1" }), jsx("button", { "aria-label": "Zoom 200%", className: "ml-1 hidden h-6 min-w-8 items-center justify-center rounded border border-neutral-300 px-1.5 text-[12px] transition-colors hover:bg-neutral-100 active:bg-neutral-200 hover:border-neutral-400 active:border-neutral-500 dark:border-neutral-600 dark:hover:bg-neutral-700 dark:active:bg-neutral-600 dark:hover:border-neutral-500 dark:active:border-neutral-400 sm:inline-flex", onClick: () => setScale(2), children: "X2" }), jsx("button", { "aria-label": "Zoom 300%", className: "ml-1 hidden h-6 min-w-8 items-center justify-center rounded border border-neutral-300 px-1.5 text-[12px] transition-colors hover:bg-neutral-100 active:bg-neutral-200 hover:border-neutral-400 active:border-neutral-500 dark:border-neutral-600 dark:hover:bg-neutral-700 dark:active:bg-neutral-600 dark:hover:border-neutral-500 dark:active:border-neutral-400 sm:inline-flex", onClick: () => setScale(3), children: "X3" }), jsx("button", { "aria-label": "Zoom 1000%", className: "ml-1 hidden h-6 min-w-10 items-center justify-center rounded border border-neutral-300 px-1.5 text-[12px] transition-colors hover:bg-neutral-100 active:bg-neutral-200 hover:border-neutral-400 active:border-neutral-500 dark:border-neutral-600 dark:hover:bg-neutral-700 dark:active:bg-neutral-600 dark:hover:border-neutral-500 dark:active:border-neutral-400 sm:inline-flex", onClick: () => setScale(10), children: "X10" }), jsx("button", { "aria-label": "Reset", className: cn("ml-1 flex h-6 w-6 items-center justify-center rounded transition-colors hover:bg-neutral-100 active:bg-neutral-200 dark:hover:bg-neutral-700 dark:active:bg-neutral-600", themeIconColor), onClick: resetTransform, children: jsx(RefreshCcwIcon, { className: "h-3.5 w-3.5" }) }), jsx("button", { "aria-label": "Download SVG", className: cn("ml-1 flex h-6 w-6 items-center justify-center rounded transition-colors hover:bg-neutral-100 active:bg-neutral-200 dark:hover:bg-neutral-700 dark:active:bg-neutral-600", themeIconColor), onClick: handleDownload, children: jsx(DownloadIcon, { className: "h-3.5 w-3.5" }) }), jsx("button", { "aria-label": "Close", className: cn("ml-1 flex h-6 w-6 items-center justify-center rounded transition-colors hover:bg-neutral-100 active:bg-neutral-200 dark:hover:bg-neutral-700 dark:active:bg-neutral-600", themeIconColor), onClick: () => { setOpen(false); resetTransform(); }, children: jsx(XIcon, { className: "h-3.5 w-3.5" }) })] })] }), jsxs("div", { className: "relative h-[calc(88vh-40px)] w-full overflow-hidden bg-white dark:bg-neutral-900 overscroll-contain touch-none", onWheel: onWheel, onPointerDown: onPointerDown, onPointerMove: onPointerMove, onPointerUp: onPointerUp, onPointerCancel: onPointerCancel, children: [jsx("div", { className: "absolute left-1/2 top-1/2", style: { transform: `translate(-50%, -50%) translate(${translate.x}px, ${translate.y}px)` }, children: jsx("div", { style: { transform: `scale(${scale})`, transformOrigin: '50% 50%' }, dangerouslySetInnerHTML: { __html: svg } }) }), jsxs("div", { className: "absolute inset-x-3 bottom-3 rounded-md bg-white/92 px-3 py-2 shadow-sm backdrop-blur sm:hidden dark:bg-neutral-900/92", children: [jsxs("label", { className: "mb-1 flex items-center justify-between text-[11px] text-neutral-600 dark:text-neutral-300", children: [jsx("span", { children: "Zoom" }), jsxs("span", { children: [Math.round(scale * 100), "%"] })] }), jsx("input", { "aria-label": "Zoom slider", className: "block w-full", type: "range", min: "25", max: "1000", step: "5", value: Math.round(scale * 100), style: { accentColor: themeSvgIconColor }, onChange: (e) => setScale(clamp(Number(e.target.value) / 100, 0.25, 10)) })] }), jsx("div", { className: "pointer-events-none absolute bottom-2 right-3 hidden rounded bg-black/40 px-2 py-1 text-xs text-white sm:block", children: "Drag to pan, click button to zoom-out or zoom-in" }), jsx("div", { className: "pointer-events-none absolute left-3 top-3 rounded bg-black/40 px-2 py-1 text-[11px] text-white sm:hidden", children: "Drag to pan, pinch to zoom-out or zoom-in" })] })] })] }))] }));
|
|
215
216
|
}
|
|
216
217
|
function addWatermarkToSvg(svg, watermark, watermarkColor) {
|
|
217
218
|
const watermarkText = `
|
|
@@ -230,5 +231,128 @@ function addWatermarkToSvg(svg, watermark, watermarkColor) {
|
|
|
230
231
|
`;
|
|
231
232
|
return svg.replace('</svg>', `${watermarkText}</svg>`);
|
|
232
233
|
}
|
|
234
|
+
function applyHandDrawnStyle(svg) {
|
|
235
|
+
if (typeof window === 'undefined')
|
|
236
|
+
return svg;
|
|
237
|
+
try {
|
|
238
|
+
const parser = new DOMParser();
|
|
239
|
+
const doc = parser.parseFromString(svg, 'image/svg+xml');
|
|
240
|
+
const svgElement = doc.documentElement;
|
|
241
|
+
if (!svgElement || svgElement.tagName.toLowerCase() !== 'svg')
|
|
242
|
+
return svg;
|
|
243
|
+
const rc = rough.svg(svgElement);
|
|
244
|
+
const serializer = new XMLSerializer();
|
|
245
|
+
const getNumber = (value) => Number.parseFloat(value !== null && value !== void 0 ? value : '') || 0;
|
|
246
|
+
const getStyleValue = (element, name) => {
|
|
247
|
+
const inlineStyle = element.getAttribute('style');
|
|
248
|
+
if (inlineStyle) {
|
|
249
|
+
const match = inlineStyle.match(new RegExp(`(?:^|;)\\s*${name}\\s*:\\s*([^;]+)`));
|
|
250
|
+
if (match === null || match === void 0 ? void 0 : match[1])
|
|
251
|
+
return match[1].trim();
|
|
252
|
+
}
|
|
253
|
+
return element.getAttribute(name);
|
|
254
|
+
};
|
|
255
|
+
const applyAttributes = (source, target) => {
|
|
256
|
+
var _a;
|
|
257
|
+
for (const attr of source.getAttributeNames()) {
|
|
258
|
+
if (attr === 'x' || attr === 'y' || attr === 'x1' || attr === 'y1' || attr === 'x2' || attr === 'y2' || attr === 'width' || attr === 'height' || attr === 'rx' || attr === 'ry' || attr === 'points' || attr === 'd')
|
|
259
|
+
continue;
|
|
260
|
+
target.setAttribute(attr, (_a = source.getAttribute(attr)) !== null && _a !== void 0 ? _a : '');
|
|
261
|
+
}
|
|
262
|
+
};
|
|
263
|
+
const createOptions = (element) => {
|
|
264
|
+
var _a, _b;
|
|
265
|
+
const stroke = (_a = getStyleValue(element, 'stroke')) !== null && _a !== void 0 ? _a : '#000';
|
|
266
|
+
const fill = (_b = getStyleValue(element, 'fill')) !== null && _b !== void 0 ? _b : 'none';
|
|
267
|
+
const strokeWidth = getNumber(getStyleValue(element, 'stroke-width')) || 1.5;
|
|
268
|
+
return {
|
|
269
|
+
stroke,
|
|
270
|
+
fill: fill === 'none' ? undefined : fill,
|
|
271
|
+
strokeWidth,
|
|
272
|
+
roughness: 1.6,
|
|
273
|
+
bowing: 1.25,
|
|
274
|
+
fillStyle: fill === 'none' ? 'hachure' : 'solid',
|
|
275
|
+
fillWeight: 0.8,
|
|
276
|
+
hachureGap: 10,
|
|
277
|
+
preserveVertices: true,
|
|
278
|
+
seed: 7,
|
|
279
|
+
};
|
|
280
|
+
};
|
|
281
|
+
const replaceShape = (element, node) => {
|
|
282
|
+
var _a, _b;
|
|
283
|
+
if (!node || !element.parentNode)
|
|
284
|
+
return;
|
|
285
|
+
applyAttributes(element, node);
|
|
286
|
+
if (element.getAttribute('class')) {
|
|
287
|
+
node.setAttribute('class', (_a = element.getAttribute('class')) !== null && _a !== void 0 ? _a : '');
|
|
288
|
+
}
|
|
289
|
+
if (element.getAttribute('style')) {
|
|
290
|
+
node.setAttribute('style', (_b = element.getAttribute('style')) !== null && _b !== void 0 ? _b : '');
|
|
291
|
+
}
|
|
292
|
+
element.parentNode.replaceChild(node, element);
|
|
293
|
+
};
|
|
294
|
+
svgElement.querySelectorAll('rect').forEach((element) => {
|
|
295
|
+
const x = getNumber(element.getAttribute('x'));
|
|
296
|
+
const y = getNumber(element.getAttribute('y'));
|
|
297
|
+
const width = getNumber(element.getAttribute('width'));
|
|
298
|
+
const height = getNumber(element.getAttribute('height'));
|
|
299
|
+
const rx = getNumber(element.getAttribute('rx'));
|
|
300
|
+
const ry = getNumber(element.getAttribute('ry'));
|
|
301
|
+
const node = rx > 0 || ry > 0
|
|
302
|
+
? rc.path(`M ${x + rx} ${y}
|
|
303
|
+
H ${x + width - rx}
|
|
304
|
+
Q ${x + width} ${y} ${x + width} ${y + ry}
|
|
305
|
+
V ${y + height - ry}
|
|
306
|
+
Q ${x + width} ${y + height} ${x + width - rx} ${y + height}
|
|
307
|
+
H ${x + rx}
|
|
308
|
+
Q ${x} ${y + height} ${x} ${y + height - ry}
|
|
309
|
+
V ${y + ry}
|
|
310
|
+
Q ${x} ${y} ${x + rx} ${y}
|
|
311
|
+
Z`, createOptions(element))
|
|
312
|
+
: rc.rectangle(x, y, width, height, createOptions(element));
|
|
313
|
+
replaceShape(element, node);
|
|
314
|
+
});
|
|
315
|
+
svgElement.querySelectorAll('line').forEach((element) => {
|
|
316
|
+
const node = rc.line(getNumber(element.getAttribute('x1')), getNumber(element.getAttribute('y1')), getNumber(element.getAttribute('x2')), getNumber(element.getAttribute('y2')), createOptions(element));
|
|
317
|
+
replaceShape(element, node);
|
|
318
|
+
});
|
|
319
|
+
svgElement.querySelectorAll('polyline').forEach((element) => {
|
|
320
|
+
var _a;
|
|
321
|
+
const points = ((_a = element.getAttribute('points')) !== null && _a !== void 0 ? _a : '')
|
|
322
|
+
.trim()
|
|
323
|
+
.split(/\s+/)
|
|
324
|
+
.map((pair) => pair.split(',').map(Number))
|
|
325
|
+
.filter((point) => point.length === 2 && Number.isFinite(point[0]) && Number.isFinite(point[1]));
|
|
326
|
+
if (points.length < 2)
|
|
327
|
+
return;
|
|
328
|
+
const node = rc.linearPath(points, createOptions(element));
|
|
329
|
+
replaceShape(element, node);
|
|
330
|
+
});
|
|
331
|
+
svgElement.querySelectorAll('polygon').forEach((element) => {
|
|
332
|
+
var _a;
|
|
333
|
+
const points = ((_a = element.getAttribute('points')) !== null && _a !== void 0 ? _a : '')
|
|
334
|
+
.trim()
|
|
335
|
+
.split(/\s+/)
|
|
336
|
+
.map((pair) => pair.split(',').map(Number))
|
|
337
|
+
.filter((point) => point.length === 2 && Number.isFinite(point[0]) && Number.isFinite(point[1]));
|
|
338
|
+
if (points.length < 2)
|
|
339
|
+
return;
|
|
340
|
+
const node = rc.polygon(points, createOptions(element));
|
|
341
|
+
replaceShape(element, node);
|
|
342
|
+
});
|
|
343
|
+
svgElement.querySelectorAll('path').forEach((element) => {
|
|
344
|
+
const d = element.getAttribute('d');
|
|
345
|
+
if (!d)
|
|
346
|
+
return;
|
|
347
|
+
const node = rc.path(d, createOptions(element));
|
|
348
|
+
replaceShape(element, node);
|
|
349
|
+
});
|
|
350
|
+
return serializer.serializeToString(svgElement);
|
|
351
|
+
}
|
|
352
|
+
catch (error) {
|
|
353
|
+
console.error('Error while applying hand-drawn mermaid style', error);
|
|
354
|
+
return svg;
|
|
355
|
+
}
|
|
356
|
+
}
|
|
233
357
|
|
|
234
358
|
export { Mermaid };
|
|
@@ -8,7 +8,7 @@ var navigation = require('next/navigation');
|
|
|
8
8
|
var nextIntl = require('next-intl');
|
|
9
9
|
var useCopyButton = require('fumadocs-ui/utils/use-copy-button');
|
|
10
10
|
var Link = require('fumadocs-core/link');
|
|
11
|
-
var
|
|
11
|
+
var icons = require('@windrun-huaiin/base-ui/icons');
|
|
12
12
|
var ui = require('@windrun-huaiin/base-ui/ui');
|
|
13
13
|
|
|
14
14
|
const cache = new Map();
|
|
@@ -57,17 +57,17 @@ function LLMCopyButton({ llmApiUrl, sourceKey } = {}) {
|
|
|
57
57
|
}));
|
|
58
58
|
return (jsxRuntime.jsx(ui.Button, { variant: "ghost", size: "sm", loading: isLoading,
|
|
59
59
|
// force button to left align
|
|
60
|
-
className: "justify-start px-0 text-stone-600 hover:text-stone-500 dark:text-stone-400 dark:hover:text-stone-300", onClick: onClick, children: checked ? (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx(
|
|
60
|
+
className: "justify-start px-0 text-stone-600 hover:text-stone-500 dark:text-stone-400 dark:hover:text-stone-300", onClick: onClick, children: checked ? (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx(icons.CheckIcon, {}), t('copyMarkdownDone')] })) : (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx(icons.MarkdownIcon, {}), t('copyMarkdown')] })) }));
|
|
61
61
|
}
|
|
62
62
|
function EditOnGitHub({ url }) {
|
|
63
63
|
const t = nextIntl.useTranslations('fuma');
|
|
64
|
-
return (jsxRuntime.jsxs(Link, { className: "flex items-center gap-x-2 text-stone-600 hover:text-stone-500 dark:text-stone-400 dark:hover:text-stone-300 text-sm", href: url, children: [jsxRuntime.jsx(
|
|
64
|
+
return (jsxRuntime.jsxs(Link, { className: "flex items-center gap-x-2 text-stone-600 hover:text-stone-500 dark:text-stone-400 dark:hover:text-stone-300 text-sm", href: url, children: [jsxRuntime.jsx(icons.GitHubIcon, {}), t('editOnGithub')] }));
|
|
65
65
|
}
|
|
66
66
|
// New component for displaying the last updated date with an icon
|
|
67
67
|
function LastUpdatedDate({ date }) {
|
|
68
68
|
const t = nextIntl.useTranslations('fuma');
|
|
69
69
|
const viewDate = date ? `${t('lastUpdate')} ${date}` : `${t('emptyLastUpdate')}`;
|
|
70
|
-
return (jsxRuntime.jsxs("div", { className: "flex items-center gap-x-2 text-stone-600 dark:text-stone-400 text-sm", children: [jsxRuntime.jsx(
|
|
70
|
+
return (jsxRuntime.jsxs("div", { className: "flex items-center gap-x-2 text-stone-600 dark:text-stone-400 text-sm", children: [jsxRuntime.jsx(icons.LastUpdatedIcon, {}), viewDate] }));
|
|
71
71
|
}
|
|
72
72
|
|
|
73
73
|
exports.EditOnGitHub = EditOnGitHub;
|
|
@@ -6,7 +6,7 @@ import { useParams } from 'next/navigation';
|
|
|
6
6
|
import { useTranslations } from 'next-intl';
|
|
7
7
|
import { useCopyButton } from 'fumadocs-ui/utils/use-copy-button';
|
|
8
8
|
import Link from 'fumadocs-core/link';
|
|
9
|
-
import {
|
|
9
|
+
import { CheckIcon, MarkdownIcon, GitHubIcon, LastUpdatedIcon } from '@windrun-huaiin/base-ui/icons';
|
|
10
10
|
import { Button } from '@windrun-huaiin/base-ui/ui';
|
|
11
11
|
|
|
12
12
|
const cache = new Map();
|
|
@@ -55,17 +55,17 @@ function LLMCopyButton({ llmApiUrl, sourceKey } = {}) {
|
|
|
55
55
|
}));
|
|
56
56
|
return (jsx(Button, { variant: "ghost", size: "sm", loading: isLoading,
|
|
57
57
|
// force button to left align
|
|
58
|
-
className: "justify-start px-0 text-stone-600 hover:text-stone-500 dark:text-stone-400 dark:hover:text-stone-300", onClick: onClick, children: checked ? (jsxs(Fragment, { children: [jsx(
|
|
58
|
+
className: "justify-start px-0 text-stone-600 hover:text-stone-500 dark:text-stone-400 dark:hover:text-stone-300", onClick: onClick, children: checked ? (jsxs(Fragment, { children: [jsx(CheckIcon, {}), t('copyMarkdownDone')] })) : (jsxs(Fragment, { children: [jsx(MarkdownIcon, {}), t('copyMarkdown')] })) }));
|
|
59
59
|
}
|
|
60
60
|
function EditOnGitHub({ url }) {
|
|
61
61
|
const t = useTranslations('fuma');
|
|
62
|
-
return (jsxs(Link, { className: "flex items-center gap-x-2 text-stone-600 hover:text-stone-500 dark:text-stone-400 dark:hover:text-stone-300 text-sm", href: url, children: [jsx(
|
|
62
|
+
return (jsxs(Link, { className: "flex items-center gap-x-2 text-stone-600 hover:text-stone-500 dark:text-stone-400 dark:hover:text-stone-300 text-sm", href: url, children: [jsx(GitHubIcon, {}), t('editOnGithub')] }));
|
|
63
63
|
}
|
|
64
64
|
// New component for displaying the last updated date with an icon
|
|
65
65
|
function LastUpdatedDate({ date }) {
|
|
66
66
|
const t = useTranslations('fuma');
|
|
67
67
|
const viewDate = date ? `${t('lastUpdate')} ${date}` : `${t('emptyLastUpdate')}`;
|
|
68
|
-
return (jsxs("div", { className: "flex items-center gap-x-2 text-stone-600 dark:text-stone-400 text-sm", children: [jsx(
|
|
68
|
+
return (jsxs("div", { className: "flex items-center gap-x-2 text-stone-600 dark:text-stone-400 text-sm", children: [jsx(LastUpdatedIcon, {}), viewDate] }));
|
|
69
69
|
}
|
|
70
70
|
|
|
71
71
|
export { EditOnGitHub, LLMCopyButton, LastUpdatedDate };
|
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
'use strict';
|
|
3
3
|
|
|
4
4
|
var jsxRuntime = require('react/jsx-runtime');
|
|
5
|
-
var
|
|
5
|
+
var icons = require('@windrun-huaiin/base-ui/icons');
|
|
6
6
|
|
|
7
|
-
function TrophyCard({ icon = jsxRuntime.jsx(
|
|
7
|
+
function TrophyCard({ icon = jsxRuntime.jsx(icons.StarIcon, {}), title, children, }) {
|
|
8
8
|
return (jsxRuntime.jsxs("div", { className: "\n border-2 rounded-xl px-4 py-2\n border-purple-200 dark:border-gray-500\n ", children: [jsxRuntime.jsxs("div", { className: "flex items-center font-bold text-sm", children: [jsxRuntime.jsx("span", { className: "mr-2", children: icon }), jsxRuntime.jsx("span", { children: title })] }), jsxRuntime.jsx("div", { className: "text-sm -mt-1 leading-none", children: children })] }));
|
|
9
9
|
}
|
|
10
10
|
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { jsxs, jsx } from 'react/jsx-runtime';
|
|
3
|
-
import {
|
|
3
|
+
import { StarIcon } from '@windrun-huaiin/base-ui/icons';
|
|
4
4
|
|
|
5
|
-
function TrophyCard({ icon = jsx(
|
|
5
|
+
function TrophyCard({ icon = jsx(StarIcon, {}), title, children, }) {
|
|
6
6
|
return (jsxs("div", { className: "\n border-2 rounded-xl px-4 py-2\n border-purple-200 dark:border-gray-500\n ", children: [jsxs("div", { className: "flex items-center font-bold text-sm", children: [jsx("span", { className: "mr-2", children: icon }), jsx("span", { children: title })] }), jsx("div", { className: "text-sm -mt-1 leading-none", children: children })] }));
|
|
7
7
|
}
|
|
8
8
|
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
|
|
4
4
|
var tslib = require('tslib');
|
|
5
5
|
var jsxRuntime = require('react/jsx-runtime');
|
|
6
|
-
var
|
|
6
|
+
var icons = require('@windrun-huaiin/base-ui/icons');
|
|
7
7
|
var utils = require('@windrun-huaiin/lib/utils');
|
|
8
8
|
var Link = require('next/link');
|
|
9
9
|
|
|
@@ -12,9 +12,9 @@ function ZiaCard(_a) {
|
|
|
12
12
|
const validHref = typeof props.href === 'string' && props.href.trim() !== '';
|
|
13
13
|
const validDescription = typeof description === 'string' && (description === null || description === void 0 ? void 0 : description.trim()) !== '';
|
|
14
14
|
if (validHref) {
|
|
15
|
-
return (jsxRuntime.jsxs(Link, Object.assign({ href: props.href, "data-card": true, className: utils.cn('block rounded-lg border bg-fd-card p-4 text-fd-card-foreground shadow-md transition-colors @max-lg:col-span-full', 'hover:bg-fd-accent/80', props.className) }, props, { children: [jsxRuntime.jsx("div", { className: "not-prose mb-2 w-fit rounded-md border bg-fd-muted p-1.5 text-fd-muted-foreground [&_svg]:size-4", children: icon ? icon : jsxRuntime.jsx(
|
|
15
|
+
return (jsxRuntime.jsxs(Link, Object.assign({ href: props.href, "data-card": true, className: utils.cn('block rounded-lg border bg-fd-card p-4 text-fd-card-foreground shadow-md transition-colors @max-lg:col-span-full', 'hover:bg-fd-accent/80', props.className) }, props, { children: [jsxRuntime.jsx("div", { className: "not-prose mb-2 w-fit rounded-md border bg-fd-muted p-1.5 text-fd-muted-foreground [&_svg]:size-4", children: icon ? icon : jsxRuntime.jsx(icons.CircleSmallIcon, {}) }), jsxRuntime.jsx("h3", { className: "not-prose mb-1 text-sm font-medium line-clamp-2 min-h-10", children: title }), validDescription ? (jsxRuntime.jsx("p", { className: "my-0! text-sm text-fd-muted-foreground", children: description })) : (jsxRuntime.jsx("p", { className: "my-0! text-sm text-fd-muted-foreground opacity-0 select-none", children: "\u00A0" })), props.children ? (jsxRuntime.jsx("div", { className: "text-sm text-fd-muted-foreground prose-no-margin", children: props.children })) : null] })));
|
|
16
16
|
}
|
|
17
|
-
return (jsxRuntime.jsxs("div", Object.assign({ "data-card": true, className: utils.cn('block rounded-lg border bg-fd-card p-4 text-fd-card-foreground shadow-md transition-colors @max-lg:col-span-full', props.className) }, props, { children: [jsxRuntime.jsx("div", { className: "not-prose mb-2 w-fit rounded-md border bg-fd-muted p-1.5 text-fd-muted-foreground [&_svg]:size-4", children: icon ? icon : jsxRuntime.jsx(
|
|
17
|
+
return (jsxRuntime.jsxs("div", Object.assign({ "data-card": true, className: utils.cn('block rounded-lg border bg-fd-card p-4 text-fd-card-foreground shadow-md transition-colors @max-lg:col-span-full', props.className) }, props, { children: [jsxRuntime.jsx("div", { className: "not-prose mb-2 w-fit rounded-md border bg-fd-muted p-1.5 text-fd-muted-foreground [&_svg]:size-4", children: icon ? icon : jsxRuntime.jsx(icons.CircleSmallIcon, {}) }), jsxRuntime.jsx("h3", { className: "not-prose mb-1 text-sm font-medium line-clamp-2 min-h-10", children: title }), validDescription ? (jsxRuntime.jsx("p", { className: "my-0! text-sm text-fd-muted-foreground", children: description })) : (jsxRuntime.jsx("p", { className: "my-0! text-sm text-fd-muted-foreground opacity-0 select-none", children: "\u00A0" })), props.children ? (jsxRuntime.jsx("div", { className: "text-sm text-fd-muted-foreground prose-no-margin", children: props.children })) : null] })));
|
|
18
18
|
}
|
|
19
19
|
|
|
20
20
|
exports.ZiaCard = ZiaCard;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { __rest } from 'tslib';
|
|
3
3
|
import { jsxs, jsx } from 'react/jsx-runtime';
|
|
4
|
-
import {
|
|
4
|
+
import { CircleSmallIcon } from '@windrun-huaiin/base-ui/icons';
|
|
5
5
|
import { cn } from '@windrun-huaiin/lib/utils';
|
|
6
6
|
import Link from 'next/link';
|
|
7
7
|
|
|
@@ -10,9 +10,9 @@ function ZiaCard(_a) {
|
|
|
10
10
|
const validHref = typeof props.href === 'string' && props.href.trim() !== '';
|
|
11
11
|
const validDescription = typeof description === 'string' && (description === null || description === void 0 ? void 0 : description.trim()) !== '';
|
|
12
12
|
if (validHref) {
|
|
13
|
-
return (jsxs(Link, Object.assign({ href: props.href, "data-card": true, className: cn('block rounded-lg border bg-fd-card p-4 text-fd-card-foreground shadow-md transition-colors @max-lg:col-span-full', 'hover:bg-fd-accent/80', props.className) }, props, { children: [jsx("div", { className: "not-prose mb-2 w-fit rounded-md border bg-fd-muted p-1.5 text-fd-muted-foreground [&_svg]:size-4", children: icon ? icon : jsx(
|
|
13
|
+
return (jsxs(Link, Object.assign({ href: props.href, "data-card": true, className: cn('block rounded-lg border bg-fd-card p-4 text-fd-card-foreground shadow-md transition-colors @max-lg:col-span-full', 'hover:bg-fd-accent/80', props.className) }, props, { children: [jsx("div", { className: "not-prose mb-2 w-fit rounded-md border bg-fd-muted p-1.5 text-fd-muted-foreground [&_svg]:size-4", children: icon ? icon : jsx(CircleSmallIcon, {}) }), jsx("h3", { className: "not-prose mb-1 text-sm font-medium line-clamp-2 min-h-10", children: title }), validDescription ? (jsx("p", { className: "my-0! text-sm text-fd-muted-foreground", children: description })) : (jsx("p", { className: "my-0! text-sm text-fd-muted-foreground opacity-0 select-none", children: "\u00A0" })), props.children ? (jsx("div", { className: "text-sm text-fd-muted-foreground prose-no-margin", children: props.children })) : null] })));
|
|
14
14
|
}
|
|
15
|
-
return (jsxs("div", Object.assign({ "data-card": true, className: cn('block rounded-lg border bg-fd-card p-4 text-fd-card-foreground shadow-md transition-colors @max-lg:col-span-full', props.className) }, props, { children: [jsx("div", { className: "not-prose mb-2 w-fit rounded-md border bg-fd-muted p-1.5 text-fd-muted-foreground [&_svg]:size-4", children: icon ? icon : jsx(
|
|
15
|
+
return (jsxs("div", Object.assign({ "data-card": true, className: cn('block rounded-lg border bg-fd-card p-4 text-fd-card-foreground shadow-md transition-colors @max-lg:col-span-full', props.className) }, props, { children: [jsx("div", { className: "not-prose mb-2 w-fit rounded-md border bg-fd-muted p-1.5 text-fd-muted-foreground [&_svg]:size-4", children: icon ? icon : jsx(CircleSmallIcon, {}) }), jsx("h3", { className: "not-prose mb-1 text-sm font-medium line-clamp-2 min-h-10", children: title }), validDescription ? (jsx("p", { className: "my-0! text-sm text-fd-muted-foreground", children: description })) : (jsx("p", { className: "my-0! text-sm text-fd-muted-foreground opacity-0 select-none", children: "\u00A0" })), props.children ? (jsx("div", { className: "text-sm text-fd-muted-foreground prose-no-margin", children: props.children })) : null] })));
|
|
16
16
|
}
|
|
17
17
|
|
|
18
18
|
export { ZiaCard };
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
var tslib = require('tslib');
|
|
4
4
|
var jsxRuntime = require('react/jsx-runtime');
|
|
5
|
-
var
|
|
5
|
+
var icons = require('@windrun-huaiin/base-ui/icons');
|
|
6
6
|
var React = require('react');
|
|
7
7
|
var utils = require('@windrun-huaiin/lib/utils');
|
|
8
8
|
var collapsible = require('fumadocs-ui/components/ui/collapsible');
|
|
@@ -11,7 +11,7 @@ var Link = require('next/link');
|
|
|
11
11
|
const itemVariants = 'flex flex-row items-center gap-2 rounded-md px-2 py-1.5 text-sm hover:bg-fd-accent hover:text-fd-accent-foreground [&_svg]:size-4';
|
|
12
12
|
const anotionClass = 'ms-2 px-2 py-0.5 rounded text-xs font-semibold bg-fd-accent/80 text-fd-accent-foreground dark:bg-white/20 dark:text-white';
|
|
13
13
|
function ZiaFile(_a) {
|
|
14
|
-
var { name, icon = jsxRuntime.jsx(
|
|
14
|
+
var { name, icon = jsxRuntime.jsx(icons.FileIcon, {}), className, anotion, href } = _a, rest = tslib.__rest(_a, ["name", "icon", "className", "anotion", "href"]);
|
|
15
15
|
const validHref = typeof href === 'string' && href.trim() !== '';
|
|
16
16
|
const validAnotion = typeof anotion === 'string' && anotion.trim() !== '';
|
|
17
17
|
if (validHref) {
|
|
@@ -23,7 +23,7 @@ function ZiaFolder(_a) {
|
|
|
23
23
|
var { name, anotion, defaultOpen = false, className, children } = _a, props = tslib.__rest(_a, ["name", "anotion", "defaultOpen", "className", "children"]);
|
|
24
24
|
const [open, setOpen] = React.useState(defaultOpen);
|
|
25
25
|
const validAnotion = typeof anotion === 'string' && anotion.trim() !== '';
|
|
26
|
-
return (jsxRuntime.jsxs(collapsible.Collapsible, Object.assign({ open: open, onOpenChange: setOpen }, props, { children: [jsxRuntime.jsxs(collapsible.CollapsibleTrigger, { className: utils.cn(itemVariants, className, 'w-full'), children: [open ? jsxRuntime.jsx(
|
|
26
|
+
return (jsxRuntime.jsxs(collapsible.Collapsible, Object.assign({ open: open, onOpenChange: setOpen }, props, { children: [jsxRuntime.jsxs(collapsible.CollapsibleTrigger, { className: utils.cn(itemVariants, className, 'w-full'), children: [open ? jsxRuntime.jsx(icons.FolderOpenIcon, {}) : jsxRuntime.jsx(icons.FolderIcon, {}), jsxRuntime.jsx("span", { children: name }), validAnotion && (jsxRuntime.jsx("span", { className: anotionClass, children: anotion }))] }), jsxRuntime.jsx(collapsible.CollapsibleContent, { children: jsxRuntime.jsx("div", { className: "ms-2 flex flex-col border-l ps-2", children: children }) })] })));
|
|
27
27
|
}
|
|
28
28
|
|
|
29
29
|
exports.ZiaFile = ZiaFile;
|