feat(thread-comment-ui): use tailwindcss to rewrite the style of thread-comment-ui (#5091)

This commit is contained in:
ZhangWei
2025-04-26 00:07:20 +08:00
committed by GitHub
parent 615e709e36
commit fa53a11658
15 changed files with 262 additions and 131 deletions
@@ -24118,20 +24118,20 @@ export const DEFAULT_WORKBOOK_DATA_DEMO: IWorkbookData = {
{
name: 'SHEET_UNIVER_THREAD_COMMENT_PLUGIN',
data: JSON.stringify({
'sheet-0011': [{ text: { textRuns: [], paragraphs: [{ startIndex: 3, paragraphStyle: {} }], sectionBreaks: [{ startIndex: 4 }], dataStream: '123\\n\\r', customRanges: [] }, dT: '2024/05/17 21:16', id: 'jwV0QtHwUbhG3o--iy1qa', ref: 'H9', personId: 'mockId', unitId: 'workbook-01', subUnitId: 'sheet-0011' }],
'sheet-0011': [{ text: { textRuns: [], paragraphs: [{ startIndex: 3, paragraphStyle: {} }], sectionBreaks: [{ startIndex: 4 }], dataStream: '123\r\n', customRanges: [] }, dT: '2024/05/17 21:16', id: 'jwV0QtHwUbhG3o--iy1qa', ref: 'H9', personId: 'Owner_qxVnhPbQ', unitId: 'workbook-01', subUnitId: 'sheet-0011' }],
'dv-test': [
{
text: {
textRuns: [],
paragraphs: [{ startIndex: 3, paragraphStyle: {} }],
sectionBreaks: [{ startIndex: 4 }],
dataStream: '1\\n\\r',
dataStream: '1\r\n',
customRanges: [],
},
dT: '2024/05/17 21:16',
id: '12',
ref: 'C6',
personId: 'mockId',
personId: '123',
unitId: 'workbook-01',
subUnitId: 'dv-test',
},
@@ -24140,13 +24140,13 @@ export const DEFAULT_WORKBOOK_DATA_DEMO: IWorkbookData = {
textRuns: [],
paragraphs: [{ startIndex: 3, paragraphStyle: {} }],
sectionBreaks: [{ startIndex: 4 }],
dataStream: '1\\n\\r',
dataStream: '1\r\n',
customRanges: [],
},
dT: '2024/05/17 21:16',
id: '1',
ref: 'B6',
personId: 'mockId',
personId: 'Owner_qxVnhPbQ',
unitId: 'workbook-01',
subUnitId: 'dv-test',
},
@@ -24155,13 +24155,13 @@ export const DEFAULT_WORKBOOK_DATA_DEMO: IWorkbookData = {
textRuns: [],
paragraphs: [{ startIndex: 3, paragraphStyle: {} }],
sectionBreaks: [{ startIndex: 4 }],
dataStream: '2\\n\\r',
dataStream: '2\r\n',
customRanges: [],
},
dT: '2024/05/17 21:16',
id: '2',
ref: 'B7',
personId: 'mockId',
personId: 'Owner_qxVnhPbQ',
unitId: 'workbook-01',
subUnitId: 'dv-test',
},
@@ -24170,13 +24170,13 @@ export const DEFAULT_WORKBOOK_DATA_DEMO: IWorkbookData = {
textRuns: [],
paragraphs: [{ startIndex: 3, paragraphStyle: {} }],
sectionBreaks: [{ startIndex: 4 }],
dataStream: '3\\n\\r',
dataStream: '3\r\n',
customRanges: [],
},
dT: '2024/05/17 21:16',
id: '3',
ref: 'B8',
personId: 'mockId',
personId: 'Owner_qxVnhPbQ',
unitId: 'workbook-01',
subUnitId: 'dv-test',
},
@@ -24185,13 +24185,13 @@ export const DEFAULT_WORKBOOK_DATA_DEMO: IWorkbookData = {
textRuns: [],
paragraphs: [{ startIndex: 3, paragraphStyle: {} }],
sectionBreaks: [{ startIndex: 4 }],
dataStream: '4\\n\\r',
dataStream: '4\r\n',
customRanges: [],
},
dT: '2024/05/17 21:16',
id: '4',
ref: 'B9',
personId: 'mockId',
personId: 'Owner_qxVnhPbQ',
unitId: 'workbook-01',
subUnitId: 'dv-test',
},
@@ -38,7 +38,6 @@ export const ReplaceSnapshotCommand: ICommand<IReplaceSnapshotCommandParams> = {
const univerInstanceService = accessor.get(IUniverInstanceService);
const commandService = accessor.get(ICommandService);
const docSelectionManagerService = accessor.get(DocSelectionManagerService);
const docDataModel = univerInstanceService.getUnit<DocumentDataModel>(unitId, UniverInstanceType.UNIVER_DOC);
const prevSnapshot = docDataModel?.getSelfOrHeaderFooterModel(segmentId).getSnapshot();
@@ -313,10 +313,8 @@ export class Editor extends Disposable implements IEditor {
// Set the new document data.
setDocumentData(data: IDocumentData, textRanges: Nullable<ITextRangeWithStyle[]>) {
const { id } = data;
this._commandService.syncExecuteCommand(ReplaceSnapshotCommand.id, {
unitId: id,
unitId: this.getEditorId(),
snapshot: data,
textRanges,
});
@@ -24,6 +24,7 @@ const enUS: typeof zhCN = {
filterEmpty: 'No match result',
reset: 'Reset Filter',
addComment: 'Add Comment',
solved: 'Solved',
},
editor: {
placeholder: 'Reply or add others with @',
@@ -24,6 +24,7 @@ const locale: typeof zhCN = {
filterEmpty: 'نتیجه ای یافت نشد',
reset: 'بازنشانی فیلتر',
addComment: 'افزودن نظر',
solved: 'حل شده',
},
editor: {
placeholder: 'پاسخ یا اضافه کردن دیگران با @',
@@ -24,6 +24,7 @@ const enUS: typeof zhCN = {
filterEmpty: 'Aucun résultat correspondant',
reset: 'Réinitialiser le filtre',
addComment: 'Ajouter un commentaire',
solved: 'Résolu',
},
editor: {
placeholder: 'Répondre ou ajouter d\'autres avec @',
@@ -22,6 +22,7 @@ export default {
filterEmpty: 'No match result',
reset: 'Reset Filter',
addComment: 'Add Comment',
solved: 'Solved',
},
editor: {
placeholder: 'Reply or add others with @',
@@ -24,6 +24,7 @@ const enUS: typeof zhCN = {
filterEmpty: 'Không có kết quả phù hợp',
reset: 'Đặt lại',
addComment: 'Thêm bình luận',
solved: 'Đã giải quyết',
},
editor: {
placeholder: 'Phản hồi',
@@ -22,6 +22,7 @@ export default {
filterEmpty: '没有匹配的结果',
reset: '重置',
addComment: '添加评论',
solved: '已解决',
},
editor: {
placeholder: '回复',
@@ -24,6 +24,7 @@ const enUS: typeof zhCN = {
filterEmpty: '沒有符合的結果',
reset: '重置',
addComment: '新增評論',
solved: '已解決',
},
editor: {
placeholder: '回覆',
@@ -14,11 +14,11 @@
* limitations under the License.
*/
import type { IDocumentBody, IDocumentData } from '@univerjs/core';
import type { IDocumentBody, IDocumentData, IUser } from '@univerjs/core';
import type { Editor, IKeyboardEventConfig } from '@univerjs/docs-ui';
import type { IThreadComment } from '@univerjs/thread-comment';
import { BuildTextUtils, DOCS_NORMAL_EDITOR_UNIT_ID_KEY, ICommandService, LocaleService, Tools, UniverInstanceType } from '@univerjs/core';
import { Button } from '@univerjs/design';
import { Button, clsx } from '@univerjs/design';
import { BreakLineCommand, IEditorService, RichTextEditor } from '@univerjs/docs-ui';
import { KeyCode, useDependency } from '@univerjs/ui';
import React, { forwardRef, useEffect, useImperativeHandle, useMemo, useRef, useState } from 'react';
@@ -82,8 +82,16 @@ export const ThreadCommentEditor = forwardRef<IThreadCommentEditorInstance, IThr
useImperativeHandle(ref, () => ({
reply(text) {
editor.current?.focus();
editor.current?.setDocumentData(getSnapshot(text));
if (!editor.current) {
return;
}
editorService.focus(editor.current!.getEditorId() ?? '');
const documentData = getSnapshot(text);
editor.current?.setDocumentData(documentData, [{
startOffset: documentData.body!.dataStream.length - 2,
endOffset: documentData.body!.dataStream.length - 2,
collapsed: true,
}]);
},
}));
@@ -123,7 +131,7 @@ export const ThreadCommentEditor = forwardRef<IThreadCommentEditorInstance, IThr
/>
{editing
? (
<div className={styles.threadCommentEditorButtons}>
<div className="univer-mt-3 univer-flex univer-flex-row univer-justify-end">
<Button
style={{ marginRight: 12 }}
onClick={() => {
@@ -148,3 +156,15 @@ export const ThreadCommentEditor = forwardRef<IThreadCommentEditorInstance, IThr
</div>
);
});
export const ThreadCommentSuggestion = ({ active, user }: { active: boolean; user: IUser }) => (
<div
className={clsx(
'univer-flex univer-items-center univer-text-sm univer-text-black',
{ 'univer-bg-gray-50': active }
)}
>
<img draggable={false} className="univer-mr-[6px] univer-h-6 univer-w-6 univer-rounded-full" src={user.avatar} />
<span>{user.name}</span>
</div>
);
@@ -14,8 +14,9 @@
* limitations under the License.
*/
import type { IDocumentBody } from '@univerjs/core';
import type { IThreadCommentMention } from '@univerjs/thread-comment';
import { CustomRangeType, getBodySlice, type IDocumentBody } from '@univerjs/core';
import { CustomRangeType, getBodySlice } from '@univerjs/core';
export type TextNode = {
type: 'text';
@@ -86,6 +87,7 @@ export const transformTextNodes2Document = (nodes: TextNode[]): IDocumentBody =>
startIndex: start,
endIndex: end,
properties: {},
wholeEntity: true,
});
break;
}
@@ -95,7 +97,7 @@ export const transformTextNodes2Document = (nodes: TextNode[]): IDocumentBody =>
}
});
str += '\n\r';
str += '\r\n';
return {
textRuns: [],
@@ -27,7 +27,6 @@ import React, { useEffect, useMemo, useRef, useState } from 'react';
import { SetActiveCommentOperation } from '../../commands/operations/comment.operations';
import { ThreadCommentPanelService } from '../../services/thread-comment-panel.service';
import { ThreadCommentTree } from '../thread-comment-tree';
import styles from './index.module.less';
export interface IThreadCommentPanelProps {
unitId: string;
@@ -161,6 +160,7 @@ export const ThreadCommentPanel = (props: IThreadCommentPanelProps) => {
const renderComment = (comment: IThreadComment) => (
<ThreadCommentTree
full
prefix={prefix}
getSubUnitName={getSubUnitName}
key={comment.id}
@@ -196,8 +196,8 @@ export const ThreadCommentPanel = (props: IThreadCommentPanelProps) => {
);
return (
<div className={styles.threadCommentPanel}>
<div className={styles.threadCommentPanelForms}>
<div className="univer-flex univer-min-h-full univer-flex-col univer-pb-3">
<div className="univer-mt-3 univer-flex univer-flex-row univer-justify-between">
{type === UniverInstanceType.UNIVER_SHEET
? (
<Select
@@ -241,37 +241,44 @@ export const ThreadCommentPanel = (props: IThreadCommentPanelProps) => {
]}
/>
</div>
{unSolvedComments.map(renderComment)}
{solvedComments.length ? <div className={styles.threadCommentPanelSolved}>已解决</div> : null}
{solvedComments.map(renderComment)}
{renderComments.length
? null
: (
<div className={styles.threadCommentPanelEmpty}>
{isFiltering ?
localeService.t('threadCommentUI.panel.filterEmpty')
: localeService.t('threadCommentUI.panel.empty')}
{renderComments.length === 0
? (
<div
className={`
univer-flex univer-flex-1 univer-flex-col univer-items-center univer-justify-center
univer-text-[13px] univer-text-gray-600
`}
>
{localeService.t('threadCommentUI.panel.empty')}
{isFiltering
? (
<Button
variant="link"
onClick={onReset}
>
{localeService.t('threadCommentUI.panel.reset')}
</Button>
<div className="univer-mt-2 univer-flex univer-flex-row">
<Button onClick={onReset}>
{localeService.t('threadCommentUI.panel.reset')}
</Button>
</div>
)
: (
<Button
id="thread-comment-add"
className={styles.threadCommentPanelAdd}
variant="primary"
onClick={onAdd}
disabled={disableAdd}
>
<IncreaseSingle />
{localeService.t('threadCommentUI.panel.addComment')}
</Button>
)}
: !disableAdd
? (
<div className="univer-mt-2 univer-flex univer-flex-row">
<Button onClick={onAdd}>
<IncreaseSingle className="univer-mr-[6px]" />
{localeService.t('threadCommentUI.panel.add')}
</Button>
</div>
)
: null}
</div>
)
: (
<div className="univer-mt-3 univer-flex univer-flex-col univer-gap-3">
{unSolvedComments.map(renderComment)}
{solvedComments.length > 0 && (
<div className="univer-text-xs">
{localeService.t('threadCommentUI.panel.solved')}
</div>
)}
{solvedComments.map(renderComment)}
</div>
)}
</div>
@@ -16,20 +16,21 @@
import type { IUser, UniverInstanceType } from '@univerjs/core';
import type { IAddCommentCommandParams, IThreadComment, IUpdateCommentCommandParams } from '@univerjs/thread-comment';
import type { IUniverUIConfig } from '@univerjs/ui';
import type { IThreadCommentEditorInstance } from '../thread-comment-editor';
import { generateRandomId, ICommandService, LocaleService, UserManagerService } from '@univerjs/core';
import { clsx, Dropdown, Tooltip } from '@univerjs/design';
import { DeleteSingle, MoreHorizontalSingle, ReplyToCommentSingle, ResolvedSingle, SolveSingle } from '@univerjs/icons';
import { AddCommentCommand, DeleteCommentCommand, DeleteCommentTreeCommand, getDT, ResolveCommentCommand, ThreadCommentModel, UpdateCommentCommand } from '@univerjs/thread-comment';
import { useDependency, useObservable } from '@univerjs/ui';
import { UI_PLUGIN_CONFIG_KEY, useConfigValue, useDependency, useObservable } from '@univerjs/ui';
import { useEffect, useMemo, useRef, useState } from 'react';
import { debounceTime } from 'rxjs';
import { SetActiveCommentOperation } from '../../commands/operations/comment.operations';
import { ThreadCommentEditor } from '../thread-comment-editor';
import { transformDocument2TextNodes, transformTextNodes2Document } from '../thread-comment-editor/util';
import styles from './index.module.less';
export interface IThreadCommentTreeProps {
full?: boolean;
id?: string;
unitId: string;
subUnitId: string;
@@ -47,6 +48,7 @@ export interface IThreadCommentTreeProps {
onAddComment?: (comment: IThreadComment) => boolean;
onDeleteComment?: (comment: IThreadComment) => boolean;
onResolve?: (resolved: boolean) => void;
style?: React.CSSProperties;
}
export interface IThreadCommentItemProps {
@@ -77,6 +79,8 @@ const ThreadCommentItem = (props: IThreadCommentItemProps) => {
const isCommentBySelf = currentUser?.userID === item.personId;
const isMock = item.id === MOCK_ID;
const [showReply, setShowReply] = useState(false);
const uiConfig = useConfigValue<IUniverUIConfig>(UI_PLUGIN_CONFIG_KEY);
const avatarFallback = uiConfig?.avatarFallback;
const handleDeleteItem = () => {
if (onDeleteComment?.(item) === false) {
@@ -97,65 +101,92 @@ const ThreadCommentItem = (props: IThreadCommentItemProps) => {
};
return (
<div className={styles.threadCommentItem} onMouseLeave={() => setShowReply(false)} onMouseEnter={() => setShowReply(true)}>
<img className={styles.threadCommentItemHead} src={user?.avatar} />
<div className={styles.threadCommentItemTitle}>
<div className={styles.threadCommentUsername}>
{user?.name || ' '}
</div>
<div>
{(isMock || resolved)
? null
: (
showReply
<div className="univer-relative univer-mb-3 univer-pl-[30px]" onMouseLeave={() => setShowReply(false)} onMouseEnter={() => setShowReply(true)}>
<div
className={`
univer-absolute univer-left-0 univer-top-0 univer-h-6 univer-w-6 univer-rounded-full univer-bg-cover
univer-bg-center univer-bg-no-repeat
`}
style={{
backgroundImage: `url(${user?.avatar || avatarFallback})`,
}}
/>
{user
? (
<div className="univer-mb-1 univer-flex univer-h-6 univer-items-center univer-justify-between">
<div className="univer-text-sm univer-font-medium univer-leading-5">
{user?.name || ' '}
</div>
<div>
{(isMock || resolved)
? null
: (
showReply && user
? (
<div
className={`
univer-ml-1 univer-inline-flex univer-h-6 univer-w-6
univer-cursor-pointer univer-items-center univer-justify-center
univer-rounded-[3px] univer-text-base
hover:univer-bg-gray-50
`}
onClick={() => onReply(user)}
>
<ReplyToCommentSingle />
</div>
)
: null
)}
{isCommentBySelf && !isMock && !resolved
? (
<div className={styles.threadCommentIcon} onClick={() => onReply(user)}>
<ReplyToCommentSingle />
</div>
)
: null
)}
{isCommentBySelf && !isMock && !resolved
? (
<Dropdown
overlay={(
<div className="univer-rounded-lg univer-p-4 univer-theme">
<ul
<Dropdown
overlay={(
<div className="univer-rounded-lg univer-p-4 univer-theme">
<ul
className={`
univer-m-0 univer-grid univer-list-none univer-gap-2 univer-p-0
univer-text-sm
[&_a]:univer-cursor-pointer [&_a]:univer-rounded [&_a]:univer-p-1
`}
>
<li>
<a
className="hover:univer-bg-gray-200"
onClick={() => onEditingChange?.(true)}
>
{localeService.t('threadCommentUI.item.edit')}
</a>
</li>
<li>
<a
className="hover:univer-bg-gray-200"
onClick={handleDeleteItem}
>
{localeService.t('threadCommentUI.item.delete')}
</a>
</li>
</ul>
</div>
)}
>
<div
className={`
univer-m-0 univer-grid univer-list-none univer-gap-2 univer-p-0
univer-text-sm
[&_a]:univer-cursor-pointer [&_a]:univer-rounded [&_a]:univer-p-1
univer-ml-1 univer-inline-flex univer-h-6 univer-w-6 univer-cursor-pointer
univer-items-center univer-justify-center univer-rounded-[3px]
univer-text-base
hover:univer-bg-gray-50
`}
>
<li>
<a
className="hover:univer-bg-gray-200"
onClick={() => onEditingChange?.(true)}
>
{localeService.t('threadCommentUI.item.edit')}
</a>
</li>
<li>
<a
className="hover:univer-bg-gray-200"
onClick={handleDeleteItem}
>
{localeService.t('threadCommentUI.item.delete')}
</a>
</li>
</ul>
</div>
)}
>
<div className={styles.threadCommentIcon}>
<MoreHorizontalSingle />
</div>
</Dropdown>
)
: null}
</div>
</div>
<div className={styles.threadCommentItemTime}>{item.dT}</div>
<MoreHorizontalSingle />
</div>
</Dropdown>
)
: null}
</div>
</div>
)
: null}
<div className="univer-mb-1 univer-text-xs univer-leading-[1.5] univer-text-gray-600">{item.dT}</div>
{editing
? (
<ThreadCommentEditor
@@ -184,14 +215,14 @@ const ThreadCommentItem = (props: IThreadCommentItemProps) => {
/>
)
: (
<div className={styles.threadCommentItemContent}>
<div className="univer-text-[13px] univer-leading-5 univer-text-black">
{transformDocument2TextNodes(item.text).map((paragraph, i) => (
<div key={i} className="univer-break-words">
{paragraph.map((item, i) => {
switch (item.type) {
case 'mention':
return (
<a className={styles.threadCommentItemAt} key={i}>
<a className="univer-text-blue-600" key={i}>
{item.content.label}
{' '}
</a>
@@ -227,6 +258,8 @@ export const ThreadCommentTree = (props: IThreadCommentTreeProps) => {
onDeleteComment,
onResolve,
type,
style,
full,
} = props;
const threadCommentModel = useDependency(ThreadCommentModel);
const [isHover, setIsHover] = useState(false);
@@ -308,9 +341,17 @@ export const ThreadCommentTree = (props: IThreadCommentTreeProps) => {
return (
<div
className={clsx(styles.threadComment, {
[styles.threadCommentActive]: !resolved && (showHighlight || isHover || prefix === 'cell'),
})}
className={clsx(
`
univer-relative univer-box-border univer-rounded-lg univer-border univer-border-solid
univer-border-gray-200 univer-bg-white univer-p-4
`,
full ? 'univer-w-full' : 'univer-w-[278px]',
{
'univer-shadow': !resolved && (showHighlight || isHover || prefix === 'cell'),
}
)}
style={style}
onClick={onClick}
id={`${prefix}-${unitId}-${subUnitId}-${id}`}
onMouseEnter={() => {
@@ -322,29 +363,68 @@ export const ThreadCommentTree = (props: IThreadCommentTreeProps) => {
setIsHover(false);
}}
>
{!resolved && showHighlight ? <div className={styles.threadCommentHighlight} /> : null}
<div className={styles.threadCommentTitle}>
<div className={styles.threadCommentTitlePosition}>
<div className={styles.threadCommentTitleHighlight} />
{!resolved && showHighlight
? (
<div
className={`
univer-absolute univer-left-0 univer-right-0 univer-top-0 univer-h-[6px]
univer-rounded-t-[6px] univer-bg-yellow-400
`}
/>
)
: null}
<div
className={`
univer-mb-4 univer-flex univer-flex-row univer-items-center univer-justify-between univer-text-sm
univer-leading-5
`}
>
<div className="univer-flex univer-flex-1 univer-flex-row univer-items-center univer-overflow-hidden">
<div
className={`
univer-mr-2 univer-h-[14px] univer-w-[3px] univer-flex-shrink-0 univer-flex-grow-0
univer-rounded-[1.5px] univer-bg-yellow-400
`}
/>
<Tooltip showIfEllipsis title={title}>
<div className={styles.threadCommentTitlePositionText}>
<div
className={`
univer-flex-1 univer-overflow-hidden univer-text-ellipsis univer-whitespace-nowrap
`}
>
{title}
</div>
</Tooltip>
</div>
{comments
? (
<div className={styles.threadCommentIconContainer}>
<div className="univer-flex univer-flex-shrink-0 univer-flex-grow-0 univer-flex-row">
<div
onClick={handleResolve}
className={styles.threadCommentIcon}
style={{ color: resolved ? 'rgb(var(--green-500))' : '' }}
className={clsx(
`
univer-ml-1 univer-inline-flex univer-h-6 univer-w-6 univer-cursor-pointer
univer-items-center univer-justify-center univer-rounded-[3px] univer-text-base
hover:univer-bg-gray-50
`,
{
'univer-text-green-500': resolved,
}
)}
>
{resolved ? <ResolvedSingle /> : <SolveSingle />}
</div>
{currentUser?.userID === comments.root.personId
? (
<div className={styles.threadCommentIcon} onClick={handleDeleteRoot}>
<div
className={`
univer-ml-1 univer-inline-flex univer-h-6 univer-w-6 univer-cursor-pointer
univer-items-center univer-justify-center univer-rounded-[3px]
univer-text-base
hover:univer-bg-gray-50
`}
onClick={handleDeleteRoot}
>
<DeleteSingle />
</div>
)
@@ -353,7 +433,14 @@ export const ThreadCommentTree = (props: IThreadCommentTreeProps) => {
)
: null}
</div>
<div className={styles.threadCommentContent} ref={scroller}>
<div
className={`
univer-max-h-[300px] univer-overflow-y-auto univer-overflow-x-hidden
[scrollbar-gutter:auto]
[scrollbar-width:thin]
`}
ref={scroller}
>
{renderComments.map(
(item) => (
<ThreadCommentItem
@@ -378,13 +465,19 @@ export const ThreadCommentTree = (props: IThreadCommentTreeProps) => {
return;
}
requestAnimationFrame(() => {
editorRef.current?.reply(transformTextNodes2Document([{
type: 'mention',
content: {
id: user.userID,
label: user.name,
editorRef.current?.reply(transformTextNodes2Document([
{
type: 'mention',
content: {
id: user.userID,
label: `@${user.name}`,
},
},
}]));
{
type: 'text',
content: ' ',
},
]));
});
}}
onAddComment={onAddComment}
@@ -31,6 +31,11 @@ export interface IUniverUIConfig extends IWorkbenchOptions {
menu?: MenuConfig;
popupRootId?: string;
/**
* The fallback avatar for user.
*/
avatarFallback?: string;
}
export const defaultPluginConfig: IUniverUIConfig = {};