mirror of
https://github.com/dream-num/univer.git
synced 2026-09-24 15:32:18 +08:00
feat(thread-comment-ui): use tailwindcss to rewrite the style of thread-comment-ui (#5091)
This commit is contained in:
@@ -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 = {};
|
||||
|
||||
Reference in New Issue
Block a user