@zjlab-fe/data-hub-ui 0.32.6 → 0.33.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (73) hide show
  1. package/dist/types/components/FileUploader/UploadStoreProvider/UploadStoreProvider.d.ts +4 -1
  2. package/dist/types/components/SDK-modal/document-link.d.ts +1 -3
  3. package/dist/types/components/SDK-modal/index.d.ts +4 -0
  4. package/dist/types/components/SDK-modal/inner-modal.d.ts +9 -0
  5. package/dist/types/components/SDK-modal/types.d.ts +4 -3
  6. package/dist/types/components/apply-perm-modal/index.d.ts +14 -5
  7. package/dist/types/components/confirm-again/index.d.ts +8 -1
  8. package/dist/types/components/copy/index.d.ts +9 -4
  9. package/dist/types/components/limit-credit-modal/index.d.ts +9 -3
  10. package/dist/types/components/tag-group-filter/dataSizeFilter.d.ts +0 -1
  11. package/dist/types/components/tag-group-filter/index.d.ts +4 -1
  12. package/dist/types/index.d.ts +7 -5
  13. package/dist/types/locale/index.d.ts +18 -0
  14. package/dist/types/locale/modalHolder.d.ts +11 -0
  15. package/dist/types/locale/resolveLocale.d.ts +9 -0
  16. package/dist/types/locale/translations.d.ts +808 -0
  17. package/dist/types/locale/types.d.ts +32 -0
  18. package/es/components/FileUploader/Locale/useTranslate.js +34 -11
  19. package/es/components/FileUploader/UploadStoreProvider/UploadStoreProvider.js +5 -3
  20. package/es/components/FileUploader/hooks/useOnMountedResumeUnfinished.js +6 -3
  21. package/es/components/SDK-modal/document-link.js +5 -2
  22. package/es/components/SDK-modal/index.js +29 -2
  23. package/es/components/SDK-modal/inner-modal.js +23 -12
  24. package/es/components/apply-perm-modal/index.js +20 -8
  25. package/es/components/confirm-again/index.js +12 -2
  26. package/es/components/copy/index.js +21 -7
  27. package/es/components/data-table/index.js +15 -4
  28. package/es/components/dataset-batch-action/index.js +48 -25
  29. package/es/components/file-preview/data-table/index.js +4 -3
  30. package/es/components/file-preview/index.js +5 -4
  31. package/es/components/file-uploader/components/uploader-drop-zone.js +4 -2
  32. package/es/components/file-uploader/components/uploader-file-item.js +12 -9
  33. package/es/components/file-uploader/components/uploader-file-list.js +6 -3
  34. package/es/components/file-uploader/components/uploader.js +4 -2
  35. package/es/components/file-uploader/components/uploading-status.js +18 -12
  36. package/es/components/header/index.js +3 -1
  37. package/es/components/input-tag/index.js +5 -2
  38. package/es/components/limit-credit-modal/index.js +38 -19
  39. package/es/components/menu/index.js +5 -2
  40. package/es/components/notion-editor/code-block/languages.js +1 -1
  41. package/es/components/notion-editor/index.js +34 -13
  42. package/es/components/operator-chain/components/AddButton.js +3 -1
  43. package/es/components/operator-chain/components/IOCard.js +4 -1
  44. package/es/components/operator-chain/components/VirtualDropdown.js +6 -3
  45. package/es/components/permission-editor/index.js +1 -0
  46. package/es/components/permission-editor/permissionEditModal/index.js +7 -4
  47. package/es/components/permission-editor/permissionEditor/index.js +40 -75
  48. package/es/components/permission-editor/permissionViewPopover/index.js +5 -2
  49. package/es/components/tag-group-filter/dataSizeFilter.js +6 -3
  50. package/es/components/tag-group-filter/index.js +2 -2
  51. package/es/components/tip-tap/bubble-menu.js +8 -3
  52. package/es/components/tip-tap/editor.js +5 -2
  53. package/es/components/tip-tap/extensions/index.js +1 -1
  54. package/es/components/tip-tap/toolbar/components/color-picker.js +3 -1
  55. package/es/components/tip-tap/toolbar/components/heading-dropdown.js +8 -5
  56. package/es/components/tip-tap/toolbar/components/link-button.js +4 -1
  57. package/es/components/tip-tap/toolbar/components/table-button.js +5 -2
  58. package/es/components/tip-tap/toolbar/index.js +4 -1
  59. package/es/components/uploadDrawer/fileUploadDrawer.js +6 -2
  60. package/es/components/uploadDrawer/fileUploadDrawerList.js +4 -1
  61. package/es/components/uploadDrawer/fileUploadDrawerListProgressButton.js +4 -2
  62. package/es/components/uploadDrawer/hooks/useCancelUpload.js +3 -1
  63. package/es/components/uploadDrawer/hooks/useFilterFiles.js +7 -4
  64. package/es/components/uploadDrawer/hooks/useFormatFiles.js +3 -1
  65. package/es/components/uploadDrawer/hooks/useResumeUnfinishedUploads.js +7 -6
  66. package/es/components/uploadDrawer/index.js +4 -2
  67. package/es/index.js +6 -5
  68. package/es/locale/index.js +64 -0
  69. package/es/locale/modalHolder.js +21 -0
  70. package/es/locale/resolveLocale.js +73 -0
  71. package/es/locale/translations.js +273 -0
  72. package/lib/index.js +1 -1
  73. package/package.json +7 -3
@@ -2,8 +2,8 @@ import { jsx, jsxs } from 'react/jsx-runtime';
2
2
  import { useRef } from 'react';
3
3
  import { Table } from 'antd';
4
4
  import { InfoCircleOutlined } from '@ant-design/icons';
5
- import i18next from 'i18next';
6
5
  import { cell, textContent, pagination, table, downloadTip } from './index.module.scss.js';
6
+ import { useLocale } from '../../../locale/index.js';
7
7
 
8
8
  const DEFAULT_MAX_LINES = 3;
9
9
  function getScrollHeight(containerHeight) {
@@ -49,7 +49,8 @@ function getTextWidth(text, style = {}) {
49
49
  function DataTable(props) {
50
50
  const { maxLines = DEFAULT_MAX_LINES, containerWidth = window.innerWidth - 24 } = props;
51
51
  const headerTextWidth = useRef([]);
52
- const locale = i18next.resolvedLanguage || localStorage.getItem('i18nextLng') || 'zh';
52
+ const { locale } = useLocale();
53
+ const texts = locale.FilePreview;
53
54
  if (headerTextWidth.current.length === 0) {
54
55
  props.head.forEach((item) => {
55
56
  headerTextWidth.current.push(getTextWidth(item));
@@ -82,7 +83,7 @@ function DataTable(props) {
82
83
  onChange: props.onPageChange,
83
84
  showTotal: () => {
84
85
  if (props.total && props.total > props.data.length) {
85
- return (jsxs("div", { className: downloadTip, children: [jsx(InfoCircleOutlined, {}), ' ', locale === 'zh' ? '请下载查看完整内容' : 'Please download to view the full content'] }));
86
+ return (jsxs("div", { className: downloadTip, children: [jsx(InfoCircleOutlined, {}), " ", texts.downloadFullContent] }));
86
87
  }
87
88
  else {
88
89
  return null;
@@ -10,12 +10,13 @@ import ParquetPreview from './parquet-preview/index.js';
10
10
  import TablePreview from './table-preview/index.js';
11
11
  import { Spin, Modal } from 'antd';
12
12
  import { useState, useEffect } from 'react';
13
- import i18next from 'i18next';
14
13
  import { wrap, spinWrap, modalWrap } from './index.module.scss.js';
14
+ import { useLocale } from '../../locale/index.js';
15
15
 
16
16
  function InnerFilePreview(props) {
17
17
  var _a, _b, _c;
18
- const locale = i18next.resolvedLanguage || localStorage.getItem('i18nextLng') || 'zh';
18
+ const { locale } = useLocale();
19
+ const texts = locale.FilePreview;
19
20
  const { filePath, tableConfig, jsonConfig } = props;
20
21
  const [isError, setIsError] = useState(false);
21
22
  const [isLoading, setIsLoading] = useState(true);
@@ -34,7 +35,7 @@ function InnerFilePreview(props) {
34
35
  };
35
36
  let result = null;
36
37
  if (isError) {
37
- result = jsx("div", { className: wrap, children: locale === 'zh' ? '获取文件失败' : 'Failed to get file' });
38
+ result = jsx("div", { className: wrap, children: texts.failedToGetFile });
38
39
  }
39
40
  else if (tableConfig) {
40
41
  result = jsx(TablePreview, Object.assign({}, props, { onSuccess: onSuccess }));
@@ -89,7 +90,7 @@ function InnerFilePreview(props) {
89
90
  result = (jsxs(Fragment, { children: [isLoading && spin, innerPreview] }));
90
91
  }
91
92
  else {
92
- result = (jsxs("div", { className: wrap, children: [locale === 'zh' ? '暂不支持' : 'Not supported', "\u00A0", ext, "\u00A0", locale === 'zh' ? '文件预览' : 'file preview'] }));
93
+ result = (jsxs("div", { className: wrap, children: [texts.notSupported, "\u00A0", ext, "\u00A0", texts.filePreview] }));
93
94
  }
94
95
  }
95
96
  if (props.openInModal) {
@@ -5,11 +5,13 @@ import { useDropZone } from './hooks/use-drop-zone.js';
5
5
  import { useFileValidation } from './hooks/use-file-validation.js';
6
6
  import useStyle from './theme.css.js';
7
7
  import useStyle$1 from './uploader-drop-zone.css.js';
8
+ import { useLocale } from '../../../locale/index.js';
8
9
 
9
10
  useStyle();
10
11
  useStyle$1();
11
12
  function UploaderDropZone(props) {
12
- const { accept = '', maxSize, maxFiles, directory = false, disabled = false, dragAreaDescription = '点击或拖拽上传文件', icon, classNames, onDrop, fileValidation, onError, } = props;
13
+ const { locale } = useLocale();
14
+ const { accept = '', maxSize, maxFiles, directory = false, disabled = false, dragAreaDescription, icon, classNames, onDrop, fileValidation, onError, } = props;
13
15
  const semanticClassNames = typeof classNames === 'function' ? classNames(props) : classNames;
14
16
  const inputRef = useRef(null);
15
17
  const { processFiles } = useFileValidation({ maxSize, maxFiles, fileValidation, onDrop, onError });
@@ -70,7 +72,7 @@ function UploaderDropZone(props) {
70
72
  ]
71
73
  .filter(Boolean)
72
74
  .join(' ');
73
- return (jsx("div", { className: `upload-drop-zone-container ${(semanticClassNames === null || semanticClassNames === void 0 ? void 0 : semanticClassNames.container) || ''}`, children: jsxs("div", { onDragEnter: handleDragEnter, onDragOver: handleDragOver, onDragLeave: handleDragLeave, onDrop: handleDrop, onClick: open, className: dragAreaClass, children: [jsx("input", { ref: inputRef, type: "file", multiple: !maxFiles || maxFiles > 1, accept: accept, onChange: handleFileSelect, className: semanticClassNames === null || semanticClassNames === void 0 ? void 0 : semanticClassNames.input, style: { display: 'none' } }), renderIcon(), jsx("p", { className: `upload-description ${(semanticClassNames === null || semanticClassNames === void 0 ? void 0 : semanticClassNames.description) || ''}`, children: dragAreaDescription })] }) }));
75
+ return (jsx("div", { className: `upload-drop-zone-container ${(semanticClassNames === null || semanticClassNames === void 0 ? void 0 : semanticClassNames.container) || ''}`, children: jsxs("div", { onDragEnter: handleDragEnter, onDragOver: handleDragOver, onDragLeave: handleDragLeave, onDrop: handleDrop, onClick: open, className: dragAreaClass, children: [jsx("input", { ref: inputRef, type: "file", multiple: !maxFiles || maxFiles > 1, accept: accept, onChange: handleFileSelect, className: semanticClassNames === null || semanticClassNames === void 0 ? void 0 : semanticClassNames.input, style: { display: 'none' } }), renderIcon(), jsx("p", { className: `upload-description ${(semanticClassNames === null || semanticClassNames === void 0 ? void 0 : semanticClassNames.description) || ''}`, children: dragAreaDescription !== null && dragAreaDescription !== void 0 ? dragAreaDescription : locale.FileUploaderV2.dropHint })] }) }));
74
76
  }
75
77
 
76
78
  export { UploaderDropZone };
@@ -3,6 +3,7 @@ import { UploadStatus } from '../constants.js';
3
3
  import { CircleProgress } from './circle-progress.js';
4
4
  import { FileIcon, PauseIcon, ResumeIcon, RetryIcon, CloseIcon } from './icons.js';
5
5
  import { UploadingStatus } from './uploading-status.js';
6
+ import { useLocale } from '../../../locale/index.js';
6
7
  import useStyle from './theme.css.js';
7
8
  import useStyle$1 from './uploader-file-item.css.js';
8
9
 
@@ -10,6 +11,8 @@ useStyle();
10
11
  useStyle$1();
11
12
  function UploaderFileItem(props) {
12
13
  const { file, classNames, onCancel, onRemove, onPause, onResume, onRetry } = props;
14
+ const { locale } = useLocale();
15
+ const texts = locale.FileUploaderV2;
13
16
  const semanticClassNames = typeof classNames === 'function' ? classNames(props) : classNames;
14
17
  const isFailed = file.status === UploadStatus.FAILED;
15
18
  const isSuccess = file.status === UploadStatus.SUCCESS;
@@ -29,21 +32,21 @@ function UploaderFileItem(props) {
29
32
  const getStatusText = () => {
30
33
  switch (file.status) {
31
34
  case UploadStatus.PENDING:
32
- return '等待上传';
35
+ return texts.waiting;
33
36
  case UploadStatus.PREPARING:
34
- return '准备中';
37
+ return texts.preparing;
35
38
  case UploadStatus.UPLOADING:
36
- return jsx(UploadingStatus, {}); // Will render UploadingStatus component instead
39
+ return jsx(UploadingStatus, {});
37
40
  case UploadStatus.PAUSED:
38
- return '已暂停';
41
+ return texts.paused;
39
42
  case UploadStatus.MERGING:
40
- return '合并中';
43
+ return texts.merging;
41
44
  case UploadStatus.SUCCESS:
42
- return '上传成功';
45
+ return texts.success;
43
46
  case UploadStatus.FAILED:
44
- return '上传失败';
47
+ return texts.failed;
45
48
  case UploadStatus.CANCELLED:
46
- return '已取消';
49
+ return texts.cancelled;
47
50
  default:
48
51
  return file.status;
49
52
  }
@@ -60,7 +63,7 @@ function UploaderFileItem(props) {
60
63
  return 'cancelled';
61
64
  return 'uploading';
62
65
  };
63
- return (jsxs("div", { className: `upload-file-item ${(semanticClassNames === null || semanticClassNames === void 0 ? void 0 : semanticClassNames.container) || ''}`, "data-status": getStatusAttribute(), children: [jsxs("div", { className: `upload-file-info ${(semanticClassNames === null || semanticClassNames === void 0 ? void 0 : semanticClassNames.info) || ''}`, children: [jsx("div", { className: `upload-file-icon ${(semanticClassNames === null || semanticClassNames === void 0 ? void 0 : semanticClassNames.icon) || ''}`, children: jsx(FileIcon, {}) }), jsxs("span", { className: `upload-file-name ${(semanticClassNames === null || semanticClassNames === void 0 ? void 0 : semanticClassNames.name) || ''}`, children: [file.fileName, file.relativePath && (jsx("span", { className: `upload-file-path ${(semanticClassNames === null || semanticClassNames === void 0 ? void 0 : semanticClassNames.relativePath) || ''}`, children: file.relativePath }))] })] }), jsxs("div", { className: `upload-file-status ${(semanticClassNames === null || semanticClassNames === void 0 ? void 0 : semanticClassNames.status) || ''}`, children: [jsx("span", { className: `upload-status-text ${(semanticClassNames === null || semanticClassNames === void 0 ? void 0 : semanticClassNames.statusText) || ''}`, children: getStatusText() }), jsx("div", { className: semanticClassNames === null || semanticClassNames === void 0 ? void 0 : semanticClassNames.progress, children: jsx(CircleProgress, { percent: file.progress, isFailed: isFailed, isSuccess: isSuccess }) }), showPause && (jsx("button", { className: `upload-action-btn upload-pause-btn ${(semanticClassNames === null || semanticClassNames === void 0 ? void 0 : semanticClassNames.pauseBtn) || ''}`, onClick: () => onPause === null || onPause === void 0 ? void 0 : onPause(file.id), title: "\u6682\u505C\u4E0A\u4F20", children: jsx(PauseIcon, {}) })), showResume && (jsx("button", { className: `upload-action-btn upload-resume-btn ${(semanticClassNames === null || semanticClassNames === void 0 ? void 0 : semanticClassNames.resumeBtn) || ''}`, onClick: () => onResume === null || onResume === void 0 ? void 0 : onResume(file.id), title: "\u7EE7\u7EED\u4E0A\u4F20", children: jsx(ResumeIcon, {}) })), showRetry && (jsx("button", { className: `upload-action-btn upload-retry-btn ${(semanticClassNames === null || semanticClassNames === void 0 ? void 0 : semanticClassNames.retryBtn) || ''}`, onClick: () => onRetry === null || onRetry === void 0 ? void 0 : onRetry(file.id), title: "\u91CD\u8BD5\u4E0A\u4F20", children: jsx(RetryIcon, {}) }))] }), jsx("button", { className: `upload-action-btn upload-close-btn ${(semanticClassNames === null || semanticClassNames === void 0 ? void 0 : semanticClassNames.closeBtn) || ''}`, onClick: handleClose, title: isFailed || isSuccess ? '移除' : '取消上传', children: jsx(CloseIcon, {}) })] }));
66
+ return (jsxs("div", { className: `upload-file-item ${(semanticClassNames === null || semanticClassNames === void 0 ? void 0 : semanticClassNames.container) || ''}`, "data-status": getStatusAttribute(), children: [jsxs("div", { className: `upload-file-info ${(semanticClassNames === null || semanticClassNames === void 0 ? void 0 : semanticClassNames.info) || ''}`, children: [jsx("div", { className: `upload-file-icon ${(semanticClassNames === null || semanticClassNames === void 0 ? void 0 : semanticClassNames.icon) || ''}`, children: jsx(FileIcon, {}) }), jsxs("span", { className: `upload-file-name ${(semanticClassNames === null || semanticClassNames === void 0 ? void 0 : semanticClassNames.name) || ''}`, children: [file.fileName, file.relativePath && (jsx("span", { className: `upload-file-path ${(semanticClassNames === null || semanticClassNames === void 0 ? void 0 : semanticClassNames.relativePath) || ''}`, children: file.relativePath }))] })] }), jsxs("div", { className: `upload-file-status ${(semanticClassNames === null || semanticClassNames === void 0 ? void 0 : semanticClassNames.status) || ''}`, children: [jsx("span", { className: `upload-status-text ${(semanticClassNames === null || semanticClassNames === void 0 ? void 0 : semanticClassNames.statusText) || ''}`, children: getStatusText() }), jsx("div", { className: semanticClassNames === null || semanticClassNames === void 0 ? void 0 : semanticClassNames.progress, children: jsx(CircleProgress, { percent: file.progress, isFailed: isFailed, isSuccess: isSuccess }) }), showPause && (jsx("button", { className: `upload-action-btn upload-pause-btn ${(semanticClassNames === null || semanticClassNames === void 0 ? void 0 : semanticClassNames.pauseBtn) || ''}`, onClick: () => onPause === null || onPause === void 0 ? void 0 : onPause(file.id), title: texts.pause, children: jsx(PauseIcon, {}) })), showResume && (jsx("button", { className: `upload-action-btn upload-resume-btn ${(semanticClassNames === null || semanticClassNames === void 0 ? void 0 : semanticClassNames.resumeBtn) || ''}`, onClick: () => onResume === null || onResume === void 0 ? void 0 : onResume(file.id), title: texts.resume, children: jsx(ResumeIcon, {}) })), showRetry && (jsx("button", { className: `upload-action-btn upload-retry-btn ${(semanticClassNames === null || semanticClassNames === void 0 ? void 0 : semanticClassNames.retryBtn) || ''}`, onClick: () => onRetry === null || onRetry === void 0 ? void 0 : onRetry(file.id), title: texts.retry, children: jsx(RetryIcon, {}) }))] }), jsx("button", { className: `upload-action-btn upload-close-btn ${(semanticClassNames === null || semanticClassNames === void 0 ? void 0 : semanticClassNames.closeBtn) || ''}`, onClick: handleClose, title: isFailed || isSuccess ? texts.remove : texts.cancelUpload, children: jsx(CloseIcon, {}) })] }));
64
67
  }
65
68
 
66
69
  export { UploaderFileItem };
@@ -1,5 +1,6 @@
1
1
  import { jsx, jsxs } from 'react/jsx-runtime';
2
2
  import { useUpload } from '../hooks/use-upload.js';
3
+ import { useLocale } from '../../../locale/index.js';
3
4
  import useStyle from './theme.css.js';
4
5
  import useStyle$1 from './uploader-file-list.css.js';
5
6
 
@@ -17,13 +18,15 @@ useStyle$1();
17
18
  * ```
18
19
  */
19
20
  function UploaderFileListLayout(props) {
20
- const { classNames, emptyText = '暂无文件', children } = props;
21
+ const { classNames, emptyText, children } = props;
22
+ const { locale } = useLocale();
23
+ const resolvedEmptyText = emptyText !== null && emptyText !== void 0 ? emptyText : locale.FileUploaderV2.empty;
21
24
  const semanticClassNames = typeof classNames === 'function' ? classNames(props) : classNames;
22
25
  const { files } = useUpload();
23
26
  if (files.length === 0) {
24
- return jsx("div", { className: `upload-file-list-empty ${(semanticClassNames === null || semanticClassNames === void 0 ? void 0 : semanticClassNames.empty) || ''}`, children: emptyText });
27
+ return (jsx("div", { className: `upload-file-list-empty ${(semanticClassNames === null || semanticClassNames === void 0 ? void 0 : semanticClassNames.empty) || ''}`, children: resolvedEmptyText }));
25
28
  }
26
- return (jsxs("div", { className: `upload-file-list-wrapper ${(semanticClassNames === null || semanticClassNames === void 0 ? void 0 : semanticClassNames.container) || ''}`, children: [jsxs("div", { className: `upload-file-list-title ${(semanticClassNames === null || semanticClassNames === void 0 ? void 0 : semanticClassNames.title) || ''}`, children: ["\u5F53\u524D\u4E0A\u4F20 (", files.length, ")"] }), jsx("div", { className: `upload-file-list ${(semanticClassNames === null || semanticClassNames === void 0 ? void 0 : semanticClassNames.listWrapper) || ''}`, children: children })] }));
29
+ return (jsxs("div", { className: `upload-file-list-wrapper ${(semanticClassNames === null || semanticClassNames === void 0 ? void 0 : semanticClassNames.container) || ''}`, children: [jsxs("div", { className: `upload-file-list-title ${(semanticClassNames === null || semanticClassNames === void 0 ? void 0 : semanticClassNames.title) || ''}`, children: [locale.FileUploaderV2.currentUpload, " (", files.length, ")"] }), jsx("div", { className: `upload-file-list ${(semanticClassNames === null || semanticClassNames === void 0 ? void 0 : semanticClassNames.listWrapper) || ''}`, children: children })] }));
27
30
  }
28
31
 
29
32
  export { UploaderFileListLayout };
@@ -6,6 +6,7 @@ import { DEFAULT_MAX_FILE_SIZE } from '../constants.js';
6
6
  import { UploaderDropZone } from './uploader-drop-zone.js';
7
7
  import { UploaderFileListLayout } from './uploader-file-list.js';
8
8
  import { UploaderFileItem } from './uploader-file-item.js';
9
+ import { useLocale } from '../../../locale/index.js';
9
10
  import { UploaderProgressBar } from './uploader-progress-bar.js';
10
11
  import { useUpload } from '../hooks/use-upload.js';
11
12
  import { TipIcon } from './icons.js';
@@ -40,7 +41,8 @@ useStyle$1();
40
41
  * ```
41
42
  */
42
43
  function Uploader(props) {
43
- const { handlers, runtime, dragAreaDescription = '点击或拖拽上传文件', accept = '', directory = false, maxFiles, maxSize = DEFAULT_MAX_FILE_SIZE, // 10GB default
44
+ const { locale } = useLocale();
45
+ const { handlers, runtime, dragAreaDescription, accept = '', directory = false, maxFiles, maxSize = DEFAULT_MAX_FILE_SIZE, // 10GB default
44
46
  classNames, onDropZoneError, fileValidation, showProgressBar = true, } = props;
45
47
  const SemanticClassNames = typeof classNames === 'function' ? classNames(props) : classNames;
46
48
  const { files, addFiles, startAll, cancel, removeFile, retry } = useUpload();
@@ -49,7 +51,7 @@ function Uploader(props) {
49
51
  startAll();
50
52
  }, [startAll]);
51
53
  const handleAddFiles = useCallback((dropped) => addFiles(dropped, { handlers }, runtime), [addFiles, handlers, runtime]);
52
- return (jsxs("div", { className: `styled-uploader-container ${(SemanticClassNames === null || SemanticClassNames === void 0 ? void 0 : SemanticClassNames.container) || ''}`, children: [jsx(UploaderDropZone, { accept: accept, directory: directory, maxFiles: maxFiles, maxSize: maxSize, dragAreaDescription: dragAreaDescription, onDrop: handleAddFiles, onError: onDropZoneError, fileValidation: fileValidation, classNames: SemanticClassNames === null || SemanticClassNames === void 0 ? void 0 : SemanticClassNames.dragZone }), jsxs("div", { className: "uploader-network-tip", children: [jsx("span", { className: "uploader-network-tip-icon", children: jsx(TipIcon, {}) }), jsx("span", { children: "\u4E0A\u4F20\u5931\u8D25\u591A\u4E3A\u7F51\u7EDC\u95EE\u9898\uFF0C\u8BF7\u518D\u6B21\u8FDB\u884C\u4E0A\u4F20\uFF08\u540C\u540D\u6587\u4EF6\u4F1A\u8FDB\u884C\u8986\u76D6\uFF09" })] }), showProgressBar && jsx(UploaderProgressBar, {}), jsx(UploaderFileListLayout, { classNames: SemanticClassNames === null || SemanticClassNames === void 0 ? void 0 : SemanticClassNames.fileList, children: files.map((file) => (jsx(UploaderFileItem, { file: file, onCancel: cancel, onRemove: removeFile, onRetry: retry, classNames: SemanticClassNames === null || SemanticClassNames === void 0 ? void 0 : SemanticClassNames.fileItem }, file.id))) })] }));
54
+ return (jsxs("div", { className: `styled-uploader-container ${(SemanticClassNames === null || SemanticClassNames === void 0 ? void 0 : SemanticClassNames.container) || ''}`, children: [jsx(UploaderDropZone, { accept: accept, directory: directory, maxFiles: maxFiles, maxSize: maxSize, dragAreaDescription: dragAreaDescription !== null && dragAreaDescription !== void 0 ? dragAreaDescription : locale.FileUploaderV2.dropHint, onDrop: handleAddFiles, onError: onDropZoneError, fileValidation: fileValidation, classNames: SemanticClassNames === null || SemanticClassNames === void 0 ? void 0 : SemanticClassNames.dragZone }), jsxs("div", { className: "uploader-network-tip", children: [jsx("span", { className: "uploader-network-tip-icon", children: jsx(TipIcon, {}) }), jsx("span", { children: locale.FileUploaderV2.uploadFailedTip })] }), showProgressBar && jsx(UploaderProgressBar, {}), jsx(UploaderFileListLayout, { classNames: SemanticClassNames === null || SemanticClassNames === void 0 ? void 0 : SemanticClassNames.fileList, children: files.map((file) => (jsx(UploaderFileItem, { file: file, onCancel: cancel, onRemove: removeFile, onRetry: retry, classNames: SemanticClassNames === null || SemanticClassNames === void 0 ? void 0 : SemanticClassNames.fileItem }, file.id))) })] }));
53
55
  }
54
56
 
55
57
  export { Uploader };
@@ -1,19 +1,25 @@
1
1
  import { jsxs, jsx } from 'react/jsx-runtime';
2
2
  import { useState, useEffect } from 'react';
3
+ import { useLocale } from '../../../locale/index.js';
3
4
  import useStyle from './uploading-status.css.js';
4
5
 
5
6
  useStyle();
6
- const UPLOADING_MESSAGES = [
7
- '上传中',
8
- '传输数据中',
9
- '正在处理',
10
- '上传进行中',
11
- '传输中,请稍候',
12
- '文件上传中',
13
- '数据传输中',
14
- '上传处理中',
15
- ];
7
+ function useUploadingMessages() {
8
+ const { locale } = useLocale();
9
+ const texts = locale.FileUploaderV2;
10
+ return [
11
+ texts.uploading,
12
+ texts.transferring,
13
+ texts.processing,
14
+ texts.uploadingInProgress,
15
+ texts.transferringWait,
16
+ texts.fileUploading,
17
+ texts.dataTransferring,
18
+ texts.uploadProcessing,
19
+ ];
20
+ }
16
21
  function UploadingStatus({ interval = 10000, className = '' }) {
22
+ const uploadingMessages = useUploadingMessages();
17
23
  const [messageIndex, setMessageIndex] = useState(0);
18
24
  const [animationState, setAnimationState] = useState('slide-in');
19
25
  const [dots, setDots] = useState('.');
@@ -26,7 +32,7 @@ function UploadingStatus({ interval = 10000, className = '' }) {
26
32
  setAnimationState('slide-up');
27
33
  // Change message after slide-up completes
28
34
  setTimeout(() => {
29
- setMessageIndex((prev) => (prev + 1) % UPLOADING_MESSAGES.length);
35
+ setMessageIndex((prev) => (prev + 1) % uploadingMessages.length);
30
36
  setAnimationState('slide-in');
31
37
  scheduleNextChange(); // Schedule next change
32
38
  }, 400); // Match animation duration
@@ -49,7 +55,7 @@ function UploadingStatus({ interval = 10000, className = '' }) {
49
55
  }, 500); // Change dots every 500ms
50
56
  return () => clearInterval(dotsTimer);
51
57
  }, []);
52
- return (jsxs("span", { className: `uploading-status ${className}`, children: [jsx("span", { className: `uploading-status-text ${animationState}`, children: UPLOADING_MESSAGES[messageIndex] }), jsx("span", { className: "uploading-dots", children: dots })] }));
58
+ return (jsxs("span", { className: `uploading-status ${className}`, children: [jsx("span", { className: `uploading-status-text ${animationState}`, children: uploadingMessages[messageIndex] }), jsx("span", { className: "uploading-dots", children: dots })] }));
53
59
  }
54
60
 
55
61
  export { UploadingStatus };
@@ -1,10 +1,12 @@
1
1
  import { jsxs, jsx } from 'react/jsx-runtime';
2
2
  import { Button } from 'antd';
3
3
  import { wrap, logo } from './index.module.scss.js';
4
+ import { useLocale } from '../../locale/index.js';
4
5
 
5
6
  function Header(props) {
6
7
  const { showLogin } = props;
7
- return (jsxs("div", { className: wrap, children: [jsx("img", { src: "https://www.unpkg.com/@zjlab-fe/fe-assets/logo-white.png", className: logo }), showLogin && jsx(Button, { ghost: true, children: "\u767B\u5F55" })] }));
8
+ const { locale } = useLocale();
9
+ return (jsxs("div", { className: wrap, children: [jsx("img", { src: "https://www.unpkg.com/@zjlab-fe/fe-assets/logo-white.png", className: logo }), showLogin && jsx(Button, { ghost: true, children: locale.Header.login })] }));
8
10
  }
9
11
 
10
12
  export { Header as default };
@@ -1,6 +1,7 @@
1
1
  import { jsx } from 'react/jsx-runtime';
2
2
  import { useState, useRef, useEffect } from 'react';
3
3
  import { Tag, Input } from 'antd';
4
+ import { useLocale } from '../../locale/index.js';
4
5
 
5
6
  /**
6
7
  * 输入标签
@@ -8,7 +9,9 @@ import { Tag, Input } from 'antd';
8
9
  * @returns
9
10
  */
10
11
  function InputTag(props) {
11
- const { value, onChange, placeholder = '请输入关键字', valueType, deduplicated = true, size, maxLength, disabled, } = props;
12
+ const { value, onChange, placeholder, valueType, deduplicated = true, size, maxLength, disabled } = props;
13
+ const { locale } = useLocale();
14
+ const resolvedPlaceholder = placeholder !== null && placeholder !== void 0 ? placeholder : locale.InputTag.placeholder;
12
15
  const [innerValue, setInnerValue] = useState([]);
13
16
  const [inputKey, setInputKey] = useState(1);
14
17
  const inputRef = useRef(null);
@@ -59,7 +62,7 @@ function InputTag(props) {
59
62
  if ((innerValue === null || innerValue === void 0 ? void 0 : innerValue.length) > 0) {
60
63
  prefix = innerValue.map((one, index) => (jsx(Tag, { closeIcon: !disabled, onClose: () => onclose(index), children: one }, index)));
61
64
  }
62
- return (jsx(Input, { disabled: disabled, size: size, ref: inputRef, placeholder: placeholder, prefix: prefix, onPressEnter: onPressEnter, maxLength: maxLength }, inputKey));
65
+ return (jsx(Input, { disabled: disabled, size: size, ref: inputRef, placeholder: resolvedPlaceholder, prefix: prefix, onPressEnter: onPressEnter, maxLength: maxLength }, inputKey));
63
66
  }
64
67
 
65
68
  export { InputTag as default };
@@ -1,36 +1,55 @@
1
+ import { __rest } from 'tslib';
1
2
  import { jsx, jsxs } from 'react/jsx-runtime';
2
3
  import { Modal, Space, Button } from 'antd';
3
4
  import { isPublicNetwork } from '@zjlab-fe/util';
4
5
  import { createRoot } from 'react-dom/client';
6
+ import { useLocale } from '../../locale/index.js';
7
+ import { useDataHubModal } from '../../locale/modalHolder.js';
5
8
 
6
- const LimitCreditModal = (props) => {
9
+ function handleApply() {
7
10
  const isPublic = isPublicNetwork();
8
- const handleOk = () => {
9
- if (isPublic) {
10
- window.open('https://alidocs.dingtalk.com/notable/share/form/v018oLl952Q1vXkzlap_dv19yqvsgs3oebp3pcjys_1qX0QQ0?source=link');
11
- }
12
- else {
13
- window.open('https://alidocs.dingtalk.com/notable/share/form/v011X3lE5jKezRB4lJb_dv19yqvsgs3oebp3pcjys_1qX0QQ0?source=link');
14
- }
15
- };
16
- return (jsx(Modal, Object.assign({}, props, {
17
- // classNames={{
18
- // content: 'modal-content-layout',
19
- // header: 'modal-title-font modal-title-layout',
20
- // body: 'modal-content-font modal-body-layout',
21
- // footer: 'modal-footer-layout',
22
- // }}
23
- title: jsx("div", { style: { textAlign: 'center', width: '100%' }, children: "\u63D0\u793A" }), footer: jsx("div", { style: { display: 'flex', justifyContent: 'center' }, children: jsxs(Space, { children: [jsx(Button, { onClick: props.onCancel, children: "\u53D6\u6D88" }), jsx(Button, { type: "primary", onClick: handleOk, children: "\u7533\u8BF7" })] }) }), children: jsx("div", { className: "modal-content-font", style: { textAlign: 'center' }, children: "\u989D\u5EA6\u5DF2\u7528\u5C3D\uFF0C\u8BF7\u70B9\u51FB\u7533\u8BF7\u3002" }) })));
11
+ if (isPublic) {
12
+ window.open('https://alidocs.dingtalk.com/notable/share/form/v018oLl952Q1vXkzlap_dv19yqvsgs3oebp3pcjys_1qX0QQ0?source=link');
13
+ }
14
+ else {
15
+ window.open('https://alidocs.dingtalk.com/notable/share/form/v011X3lE5jKezRB4lJb_dv19yqvsgs3oebp3pcjys_1qX0QQ0?source=link');
16
+ }
17
+ }
18
+ const LimitCreditModal = (props) => {
19
+ const { open, onCancel } = props, rest = __rest(props, ["open", "onCancel"]);
20
+ const { locale } = useLocale();
21
+ const texts = locale.LimitCreditModal;
22
+ return (jsx(Modal, Object.assign({}, rest, { open: open, onCancel: onCancel, title: jsx("div", { style: { textAlign: 'center', width: '100%' }, children: texts.title }), footer: jsx("div", { style: { display: 'flex', justifyContent: 'center' }, children: jsxs(Space, { children: [jsx(Button, { onClick: onCancel, children: texts.cancel }), jsx(Button, { type: "primary", onClick: handleApply, children: texts.apply })] }) }), children: jsx("div", { className: "modal-content-font", style: { textAlign: 'center' }, children: texts.content }) })));
24
23
  };
25
- LimitCreditModal.open = () => {
24
+ LimitCreditModal.open = (props) => {
26
25
  const div = document.createElement('div');
27
26
  document.body.appendChild(div);
28
27
  const root = createRoot(div);
29
28
  const destroy = () => {
29
+ var _a;
30
+ (_a = props === null || props === void 0 ? void 0 : props.onCancel) === null || _a === void 0 ? void 0 : _a.call(props);
30
31
  root.unmount();
31
32
  div.remove();
32
33
  };
33
34
  root.render(jsx(LimitCreditModal, { open: true, onCancel: destroy }));
35
+ return { destroy };
34
36
  };
37
+ function useLimitCreditModal() {
38
+ const { locale } = useLocale();
39
+ const modal = useDataHubModal();
40
+ return (props) => {
41
+ const texts = locale.LimitCreditModal;
42
+ return modal.confirm({
43
+ title: jsx("div", { style: { textAlign: 'center', width: '100%' }, children: texts.title }),
44
+ content: (jsx("div", { className: "modal-content-font", style: { textAlign: 'center' }, children: texts.content })),
45
+ icon: null,
46
+ okText: texts.apply,
47
+ cancelText: texts.cancel,
48
+ onOk: handleApply,
49
+ onCancel: props === null || props === void 0 ? void 0 : props.onCancel,
50
+ footer: (originNode) => jsx("div", { style: { display: 'flex', justifyContent: 'center' }, children: originNode }),
51
+ });
52
+ };
53
+ }
35
54
 
36
- export { LimitCreditModal as default };
55
+ export { LimitCreditModal as default, useLimitCreditModal };
@@ -4,6 +4,7 @@ import { useState, useEffect } from 'react';
4
4
  import { useNavigate, useLocation } from 'react-router-dom';
5
5
  import { "side-menu" as side_menu, "menu-content" as menu_content, "menu-content-contain" as menu_content_contain, "menu-content-title" as menu_content_title, "menu-content-subcontain" as menu_content_subcontain, icon, "trigger-icon" as trigger_icon, "menu-content-item" as menu_content_item, active, expanded, "link-type" as link_type } from './index.module.scss.js';
6
6
  import { Layout, Tooltip } from 'antd';
7
+ import { useLocale } from '../../locale/index.js';
7
8
 
8
9
  const { Sider } = Layout;
9
10
  /**
@@ -17,6 +18,8 @@ const { Sider } = Layout;
17
18
  */
18
19
  const MainLayoutSider = (props) => {
19
20
  const { menus, collapsed: propsCollapsed = false, onCollapse, onClick: propsonClick, onSelect, selectedKeys, } = props;
21
+ const { locale } = useLocale();
22
+ const texts = locale.Menu;
20
23
  useNavigate();
21
24
  const location = useLocation();
22
25
  const [internalCollapsed, setInternalCollapsed] = useState(propsCollapsed);
@@ -38,8 +41,8 @@ const MainLayoutSider = (props) => {
38
41
  const newCollapsed = !internalCollapsed;
39
42
  setInternalCollapsed(newCollapsed);
40
43
  onCollapse === null || onCollapse === void 0 ? void 0 : onCollapse(newCollapsed);
41
- }, children: [internalCollapsed ? jsx(MenuUnfoldOutlined, {}) : jsx(MenuFoldOutlined, {}), !internalCollapsed && jsx("span", { style: { marginLeft: '8px' }, children: "\u6536\u8D77\u5BFC\u822A" })] }));
42
- return internalCollapsed ? (jsx(Tooltip, { placement: "right", title: "\u5C55\u5F00\u5BFC\u822A", children: triggerIcon })) : (triggerIcon);
44
+ }, children: [internalCollapsed ? jsx(MenuUnfoldOutlined, {}) : jsx(MenuFoldOutlined, {}), !internalCollapsed && jsx("span", { style: { marginLeft: '8px' }, children: texts.collapseNav })] }));
45
+ return internalCollapsed ? (jsx(Tooltip, { placement: "right", title: texts.expandNav, children: triggerIcon })) : (triggerIcon);
43
46
  };
44
47
  const onMenuClick = (item) => {
45
48
  propsonClick === null || propsonClick === void 0 ? void 0 : propsonClick(item);
@@ -1,7 +1,7 @@
1
1
  const LANGUAGES = {
2
2
  // plain: { name: 'text', aliases: ['text', 'txt'] },
3
3
  nginx: { name: 'Nginx' },
4
- text: { name: '纯文本', aliases: ['plaintext', 'txt'] },
4
+ text: { name: 'Plain Text', aliases: ['plaintext', 'txt'] },
5
5
  javascript: { name: 'JavaScript', aliases: ['js'] },
6
6
  typescript: { name: 'TypeScript', aliases: ['ts'] },
7
7
  jsx: { name: 'JSX' },
@@ -1,12 +1,13 @@
1
1
  import { __awaiter } from 'tslib';
2
- import { jsxs, jsx } from 'react/jsx-runtime';
2
+ import { jsx, jsxs } from 'react/jsx-runtime';
3
3
  import { forwardRef, useRef, useState, useCallback, useEffect, useMemo, useImperativeHandle } from 'react';
4
4
  import { createReactBlockSpec, useCreateBlockNote, FormattingToolbarController, FormattingToolbar, getFormattingToolbarItems, BasicTextStyleButton } from '@blocknote/react';
5
5
  import { Extension } from '@tiptap/core';
6
6
  import { TextSelection } from 'prosemirror-state';
7
7
  import { BlockNoteSchema, defaultStyleSpecs, defaultInlineContentSpecs, defaultBlockSpecs } from '@blocknote/core';
8
8
  import { BlockNoteView } from '@blocknote/mantine';
9
- import { zh } from '@blocknote/core/locales';
9
+ import { en, zh } from '@blocknote/core/locales';
10
+ import { useLocale } from '../../locale/index.js';
10
11
  import '@blocknote/core/fonts/inter.css';
11
12
  import '@blocknote/mantine/style.css';
12
13
  import useStyle from './index.scss.js';
@@ -26,7 +27,13 @@ const CustomFileBlock = createReactBlockSpec({
26
27
  },
27
28
  content: 'none',
28
29
  }, {
29
- render: ({ block }) => (jsxs("div", { className: "data-hub-ui-custom-file-block", onClick: () => window.open(block.props.url, '_blank'), children: [jsx("div", { className: "data-hub-ui-custom-file-block__icon", children: "\uD83D\uDCC4" }), jsx("div", { className: "data-hub-ui-custom-file-block__info", children: jsx("div", { className: "data-hub-ui-custom-file-block__name", children: block.props.name || '未命名文件' }) })] })),
30
+ render: ({ block }) => {
31
+ const FileBlockView = () => {
32
+ const { locale } = useLocale();
33
+ return (jsxs("div", { className: "data-hub-ui-custom-file-block", onClick: () => window.open(block.props.url, '_blank'), children: [jsx("div", { className: "data-hub-ui-custom-file-block__icon", children: "\uD83D\uDCC4" }), jsx("div", { className: "data-hub-ui-custom-file-block__info", children: jsx("div", { className: "data-hub-ui-custom-file-block__name", children: block.props.name || locale.NotionEditor.unnamedFile }) })] }));
34
+ };
35
+ return jsx(FileBlockView, {});
36
+ },
30
37
  });
31
38
  // 创建自定义 Schema,替换默认 file 和 codeBlock 块
32
39
  const schema = BlockNoteSchema.create({
@@ -70,7 +77,7 @@ const getInlineText = (content) => {
70
77
  .join('')
71
78
  .trim();
72
79
  };
73
- const getHeadingTocItems = (blocks) => {
80
+ const getHeadingTocItems = (blocks, unnamedTitle) => {
74
81
  const tocItems = [];
75
82
  const walkBlocks = (items) => {
76
83
  items.forEach((block) => {
@@ -79,7 +86,7 @@ const getHeadingTocItems = (blocks) => {
79
86
  tocItems.push({
80
87
  id: block.id,
81
88
  level: Math.min(Math.max(level, 1), 6),
82
- title: getInlineText(block.content) || '未命名标题',
89
+ title: getInlineText(block.content) || unnamedTitle,
83
90
  });
84
91
  }
85
92
  if (Array.isArray(block.children) && block.children.length > 0) {
@@ -108,7 +115,10 @@ const parseCopyPasteBlocks = (plainText, docId) => {
108
115
  }
109
116
  };
110
117
  const NotionEditor = forwardRef(({ initContent, editable = false, className = '', docId, onChange, onImageUpload, onFileUpload, onImageUploadByUrl, }, ref) => {
111
- const placeholder = '输入 "/" 快速插入内容';
118
+ const { locale } = useLocale();
119
+ const texts = locale.NotionEditor;
120
+ const blockNoteDict = locale.locale === 'en' ? en : zh;
121
+ const placeholder = texts.placeholder;
112
122
  const docIdRef = useRef(docId);
113
123
  const containerRef = useRef(null);
114
124
  const [tocCollapsed, setTocCollapsed] = useState(false);
@@ -127,7 +137,7 @@ const NotionEditor = forwardRef(({ initContent, editable = false, className = ''
127
137
  return URL.createObjectURL(file);
128
138
  }), [onImageUpload, onFileUpload]);
129
139
  const editor = useCreateBlockNote({
130
- dictionary: Object.assign(Object.assign({}, zh), { placeholders: Object.assign(Object.assign({}, zh.placeholders), { default: placeholder, emptyDocument: placeholder }) }),
140
+ dictionary: Object.assign(Object.assign({}, blockNoteDict), { placeholders: Object.assign(Object.assign({}, blockNoteDict.placeholders), { default: placeholder, emptyDocument: placeholder }) }),
131
141
  initialContent: Array.isArray(initContent) && initContent.length > 0 ? initContent : undefined,
132
142
  schema: schema,
133
143
  setIdAttribute: true,
@@ -221,22 +231,33 @@ const NotionEditor = forwardRef(({ initContent, editable = false, className = ''
221
231
  useEffect(() => {
222
232
  if (editor) {
223
233
  editor.isEditable = editable;
234
+ if (window.location.hash) {
235
+ const id = window.location.hash.split('#')[1];
236
+ if (id) {
237
+ setTimeout(() => {
238
+ var _a;
239
+ // 将 hash 中指定 id 对应的 block 滚动到可视范围内
240
+ const target = (_a = containerRef.current) === null || _a === void 0 ? void 0 : _a.querySelector(`.data-hub-ui-blocknote-editor [data-id="${CSS.escape(id)}"]`);
241
+ target === null || target === void 0 ? void 0 : target.scrollIntoView({ behavior: 'smooth', block: 'start' });
242
+ }, 500);
243
+ }
244
+ }
224
245
  }
225
246
  }, [editor, editable]);
226
247
  const handleChange = useCallback(() => {
227
248
  if (editor) {
228
249
  const blocks = editor.document;
229
- setTocItems(getHeadingTocItems(blocks));
250
+ setTocItems(getHeadingTocItems(blocks, texts.unnamedTitle));
230
251
  onChange === null || onChange === void 0 ? void 0 : onChange(blocks);
231
252
  }
232
- }, [editor, onChange]);
253
+ }, [editor, onChange, texts.unnamedTitle]);
233
254
  useEffect(() => {
234
255
  if (editor) {
235
- setTocItems(getHeadingTocItems(editor.document));
256
+ setTocItems(getHeadingTocItems(editor.document, texts.unnamedTitle));
236
257
  }
237
- }, [editor]);
258
+ }, [editor, texts.unnamedTitle]);
238
259
  const showToc = tocItems.length > 0;
239
- const tocTitle = useMemo(() => (tocCollapsed ? '展开目录' : '收起目录'), [tocCollapsed]);
260
+ const tocTitle = useMemo(() => (tocCollapsed ? texts.expandToc : texts.collapseToc), [tocCollapsed, texts.expandToc, texts.collapseToc]);
240
261
  const handleTocItemClick = useCallback((blockId) => {
241
262
  var _a;
242
263
  const target = (_a = containerRef.current) === null || _a === void 0 ? void 0 : _a.querySelector(`.data-hub-ui-blocknote-editor [data-id="${CSS.escape(blockId)}"]`);
@@ -254,7 +275,7 @@ const NotionEditor = forwardRef(({ initContent, editable = false, className = ''
254
275
  focus: () => editor === null || editor === void 0 ? void 0 : editor.focus(),
255
276
  isEmpty: () => { var _a; return (_a = editor === null || editor === void 0 ? void 0 : editor.isEmpty) !== null && _a !== void 0 ? _a : true; },
256
277
  }));
257
- return (jsxs("div", { ref: containerRef, className: `data-hub-ui-blocknote-editor-wrapper ${tocCollapsed ? 'is-toc-collapsed' : ''} ${className}`, children: [jsx(BlockNoteView, { editor: editor, formattingToolbar: false, onChange: handleChange, theme: "light", className: "data-hub-ui-blocknote-editor", children: jsx(FormattingToolbarController, { formattingToolbar: () => (jsxs(FormattingToolbar, { children: [getFormattingToolbarItems(), jsx(BasicTextStyleButton, { basicTextStyle: "code" })] })) }) }), showToc && (jsxs("aside", { className: `data-hub-ui-blocknote-toc ${tocCollapsed ? 'is-collapsed' : ''}`, children: [jsxs("button", { type: "button", className: "data-hub-ui-blocknote-toc__toggle", "aria-label": tocTitle, "aria-expanded": !tocCollapsed, onClick: () => setTocCollapsed((value) => !value), children: [jsx("span", { children: "\u76EE\u5F55" }), jsx("span", { className: "data-hub-ui-blocknote-toc__toggle-icon", children: tocCollapsed ? '‹' : '›' })] }), !tocCollapsed && (jsx("nav", { className: "data-hub-ui-blocknote-toc__list", "aria-label": "\u6587\u6863\u76EE\u5F55", children: tocItems.map((item) => (jsx("button", { type: "button", className: "data-hub-ui-blocknote-toc__item", style: { '--toc-level': item.level }, title: item.title, onClick: () => handleTocItemClick(item.id), children: item.title }, item.id))) }))] }))] }));
278
+ return (jsxs("div", { ref: containerRef, className: `data-hub-ui-blocknote-editor-wrapper ${tocCollapsed ? 'is-toc-collapsed' : ''} ${className}`, children: [jsx(BlockNoteView, { editor: editor, formattingToolbar: false, onChange: handleChange, theme: "light", className: "data-hub-ui-blocknote-editor", children: jsx(FormattingToolbarController, { formattingToolbar: () => (jsxs(FormattingToolbar, { children: [getFormattingToolbarItems(), jsx(BasicTextStyleButton, { basicTextStyle: "code" })] })) }) }), showToc && (jsxs("aside", { className: `data-hub-ui-blocknote-toc ${tocCollapsed ? 'is-collapsed' : ''}`, children: [jsxs("button", { type: "button", className: "data-hub-ui-blocknote-toc__toggle", "aria-label": tocTitle, "aria-expanded": !tocCollapsed, onClick: () => setTocCollapsed((value) => !value), children: [jsx("span", { children: texts.tocLabel }), jsx("span", { className: "data-hub-ui-blocknote-toc__toggle-icon", children: tocCollapsed ? '‹' : '›' })] }), !tocCollapsed && (jsx("nav", { className: "data-hub-ui-blocknote-toc__list", "aria-label": texts.toc, children: tocItems.map((item) => (jsx("button", { type: "button", className: "data-hub-ui-blocknote-toc__item", style: { '--toc-level': item.level }, title: item.title, onClick: () => handleTocItemClick(item.id), children: item.title }, item.id))) }))] }))] }));
258
279
  });
259
280
  NotionEditor.displayName = 'NotionEditor';
260
281
 
@@ -3,13 +3,15 @@ import { Divider, Dropdown, Tooltip } from 'antd';
3
3
  import { PlusCircleOutlined } from '@ant-design/icons';
4
4
  import { "divider-block" as divider_block, "card-divider" as card_divider } from '../index.module.scss.js';
5
5
  import VirtualDropdown from './VirtualDropdown.js';
6
+ import { useLocale } from '../../../locale/index.js';
6
7
 
7
8
  function AddButton({ menu, isEdit, onClick }) {
9
+ const { locale } = useLocale();
8
10
  return (jsx("div", { className: divider_block, children: jsx(Divider, { className: card_divider, style: {
9
11
  borderColor: '#1775FE',
10
12
  margin: '0',
11
13
  padding: '0 10px 0 10px',
12
- }, children: jsx(Dropdown, { popupRender: () => jsx(VirtualDropdown, { menu: menu || [], onItemClick: onClick }), trigger: ['click'], children: jsx(Tooltip, { placement: "topLeft", title: '添加算子', children: jsx("span", { onClick: (e) => e.preventDefault(), style: {
14
+ }, children: jsx(Dropdown, { popupRender: () => jsx(VirtualDropdown, { menu: menu || [], onItemClick: onClick }), trigger: ['click'], children: jsx(Tooltip, { placement: "topLeft", title: locale.OperatorChain.addOperator, children: jsx("span", { onClick: (e) => e.preventDefault(), style: {
13
15
  color: '#1775FE',
14
16
  cursor: isEdit ? 'pointer' : 'not-allowed',
15
17
  height: '16px',
@@ -1,8 +1,11 @@
1
1
  import { jsx } from 'react/jsx-runtime';
2
2
  import { iocard, "iocard-body" as iocard_body, active } from '../index.module.scss.js';
3
+ import { useLocale } from '../../../locale/index.js';
3
4
 
4
5
  function IOCard({ isActive, onClick, id }) {
5
- return (jsx("div", { className: iocard, children: jsx("div", { className: `${iocard_body} ${isActive ? active : ''}`, onClick: () => onClick === null || onClick === void 0 ? void 0 : onClick(id || ''), children: jsx("div", { children: id === 'IMPORT' ? '输入数据集' : '输出数据集' }) }) }));
6
+ const { locale } = useLocale();
7
+ const texts = locale.OperatorChain;
8
+ return (jsx("div", { className: iocard, children: jsx("div", { className: `${iocard_body} ${isActive ? active : ''}`, onClick: () => onClick === null || onClick === void 0 ? void 0 : onClick(id || ''), children: jsx("div", { children: id === 'IMPORT' ? texts.inputDataset : texts.outputDataset }) }) }));
6
9
  }
7
10
 
8
11
  export { IOCard as default };
@@ -2,11 +2,14 @@ import { jsxs, jsx } from 'react/jsx-runtime';
2
2
  import React, { useState, useRef } from 'react';
3
3
  import { Input, Select } from 'antd';
4
4
  import { "filter-popup" as filter_popup, "filter-popup-top" as filter_popup_top, "virtual-dropdown-container" as virtual_dropdown_container, "virtual-dropdown-content" as virtual_dropdown_content, "virtual-dropdown-items" as virtual_dropdown_items, "virtual-dropdown-item" as virtual_dropdown_item } from '../index.module.scss.js';
5
+ import { useLocale } from '../../../locale/index.js';
5
6
 
6
7
  const { Search } = Input;
7
8
  const ITEM_HEIGHT = 32;
8
9
  const FIXED_HEIGHT = 420;
9
10
  function VirtualDropdown({ menu, onItemClick, onSelect, onInputChange }) {
11
+ const { locale } = useLocale();
12
+ const texts = locale.OperatorChain;
10
13
  const [scrollTop, setScrollTop] = useState(0);
11
14
  const [selectedType, setSelectedType] = useState('');
12
15
  const [searchValue, setSearchValue] = useState('');
@@ -24,8 +27,8 @@ function VirtualDropdown({ menu, onItemClick, onSelect, onInputChange }) {
24
27
  value: Number(value),
25
28
  }));
26
29
  // 添加默认的"全部"选项
27
- return [{ label: '全部类型', value: '' }, ...options];
28
- }, [menu]);
30
+ return [{ label: texts.allTypes, value: '' }, ...options];
31
+ }, [menu, texts.allTypes]);
29
32
  const visibleCount = Math.ceil(FIXED_HEIGHT / ITEM_HEIGHT);
30
33
  const startIndex = Math.floor(scrollTop / ITEM_HEIGHT);
31
34
  const endIndex = Math.min(startIndex + visibleCount, menu.length);
@@ -48,7 +51,7 @@ function VirtualDropdown({ menu, onItemClick, onSelect, onInputChange }) {
48
51
  return typeMatch && searchMatch;
49
52
  });
50
53
  const visibleItems = filteredMenu.slice(startIndex, endIndex);
51
- return (jsxs("div", { className: filter_popup, children: [jsxs("div", { className: filter_popup_top, children: [jsx(Select, { placeholder: "\u9009\u62E9\u7C7B\u578B", style: { width: 140 }, allowClear: true, onChange: handleSelectChange, options: typeOptions, defaultValue: '' }), jsx(Search, { placeholder: "\u641C\u7D22\u7B97\u5B50", style: { width: 200 }, allowClear: true, onChange: handleInputChange })] }), jsx("div", { ref: containerRef, onScroll: handleScroll, className: virtual_dropdown_container, style: {
54
+ return (jsxs("div", { className: filter_popup, children: [jsxs("div", { className: filter_popup_top, children: [jsx(Select, { placeholder: texts.selectType, style: { width: 140 }, allowClear: true, onChange: handleSelectChange, options: typeOptions, defaultValue: '' }), jsx(Search, { placeholder: texts.searchOperator, style: { width: 200 }, allowClear: true, onChange: handleInputChange })] }), jsx("div", { ref: containerRef, onScroll: handleScroll, className: virtual_dropdown_container, style: {
52
55
  maxHeight: FIXED_HEIGHT,
53
56
  }, children: jsx("div", { className: virtual_dropdown_content, style: { height: filteredMenu.length * ITEM_HEIGHT }, children: jsx("div", { className: virtual_dropdown_items, style: { transform: `translateY(${offsetY}px)` }, children: visibleItems.map((item) => (jsx("div", { onClick: () => onItemClick(item.id), className: virtual_dropdown_item, children: item.title || item.id }, item.id))) }) }) })] }));
54
57
  }