mirror of
https://github.com/CherryHQ/cherry-studio.git
synced 2025-12-30 07:39:06 +08:00
161 lines
3.9 KiB
TypeScript
161 lines
3.9 KiB
TypeScript
import RichEditor from '@renderer/components/RichEditor'
|
|
import { RichEditorRef } from '@renderer/components/RichEditor/types'
|
|
import { Modal, ModalProps } from 'antd'
|
|
import { useEffect, useRef, useState } from 'react'
|
|
import { useTranslation } from 'react-i18next'
|
|
import styled from 'styled-components'
|
|
|
|
import { TopView } from '../TopView'
|
|
|
|
interface ShowParams {
|
|
content: string
|
|
modalProps?: ModalProps
|
|
showTranslate?: boolean
|
|
disableCommands?: string[] // 要禁用的命令列表
|
|
children?: (props: { onOk?: () => void; onCancel?: () => void }) => React.ReactNode
|
|
}
|
|
|
|
interface Props extends ShowParams {
|
|
resolve: (data: any) => void
|
|
}
|
|
|
|
const PopupContainer: React.FC<Props> = ({
|
|
content,
|
|
modalProps,
|
|
resolve,
|
|
children,
|
|
disableCommands = ['image', 'inlineMath'] // 默认禁用 image 命令
|
|
}) => {
|
|
const [open, setOpen] = useState(true)
|
|
const { t } = useTranslation()
|
|
const [richContent, setRichContent] = useState(content)
|
|
const editorRef = useRef<RichEditorRef>(null)
|
|
const isMounted = useRef(true)
|
|
|
|
useEffect(() => {
|
|
return () => {
|
|
isMounted.current = false
|
|
}
|
|
}, [])
|
|
|
|
const onOk = () => {
|
|
const finalContent = editorRef.current?.getMarkdown() || richContent
|
|
resolve(finalContent)
|
|
setOpen(false)
|
|
}
|
|
|
|
const onCancel = () => {
|
|
resolve(null)
|
|
setOpen(false)
|
|
}
|
|
|
|
const onClose = () => {
|
|
resolve(null)
|
|
}
|
|
|
|
const handleAfterOpenChange = (visible: boolean) => {
|
|
if (visible && editorRef.current) {
|
|
// Focus the editor after modal opens
|
|
setTimeout(() => {
|
|
editorRef.current?.focus()
|
|
}, 100)
|
|
}
|
|
}
|
|
|
|
const handleContentChange = (newContent: string) => {
|
|
setRichContent(newContent)
|
|
}
|
|
|
|
const handleMarkdownChange = (newMarkdown: string) => {
|
|
// 更新Markdown内容状态
|
|
setRichContent(newMarkdown)
|
|
}
|
|
|
|
// 处理命令配置
|
|
const handleCommandsReady = (commandAPI: Pick<RichEditorRef, 'unregisterToolbarCommand' | 'unregisterCommand'>) => {
|
|
// 禁用指定的命令
|
|
if (disableCommands?.length) {
|
|
disableCommands.forEach((commandId) => {
|
|
commandAPI.unregisterCommand(commandId)
|
|
})
|
|
}
|
|
}
|
|
|
|
RichEditPopup.hide = onCancel
|
|
|
|
return (
|
|
<Modal
|
|
title={t('common.edit')}
|
|
width="70vw"
|
|
style={{ maxHeight: '80vh' }}
|
|
transitionName="animation-move-down"
|
|
okText={t('common.save')}
|
|
{...modalProps}
|
|
open={open}
|
|
onOk={onOk}
|
|
onCancel={onCancel}
|
|
afterClose={onClose}
|
|
afterOpenChange={handleAfterOpenChange}
|
|
maskClosable={false}
|
|
keyboard={false}
|
|
centered>
|
|
<EditorContainer>
|
|
<RichEditor
|
|
ref={editorRef}
|
|
initialContent={content}
|
|
placeholder={t('richEditor.placeholder')}
|
|
onContentChange={handleContentChange}
|
|
onMarkdownChange={handleMarkdownChange}
|
|
onCommandsReady={handleCommandsReady}
|
|
minHeight={window.innerHeight * 0.7}
|
|
isFullWidth={true}
|
|
className="rich-edit-popup-editor"
|
|
/>
|
|
</EditorContainer>
|
|
<ChildrenContainer>{children && children({ onOk, onCancel })}</ChildrenContainer>
|
|
</Modal>
|
|
)
|
|
}
|
|
|
|
const TopViewKey = 'RichEditPopup'
|
|
|
|
const ChildrenContainer = styled.div`
|
|
position: relative;
|
|
`
|
|
|
|
const EditorContainer = styled.div`
|
|
position: relative;
|
|
|
|
.rich-edit-popup-editor {
|
|
border: 1px solid var(--color-border);
|
|
border-radius: 6px;
|
|
background: var(--color-background);
|
|
|
|
&:focus-within {
|
|
border-color: var(--color-primary);
|
|
box-shadow: 0 0 0 2px var(--color-primary-alpha);
|
|
}
|
|
}
|
|
`
|
|
|
|
export default class RichEditPopup {
|
|
static topviewId = 0
|
|
static hide() {
|
|
TopView.hide(TopViewKey)
|
|
}
|
|
static show(props: ShowParams) {
|
|
return new Promise<any>((resolve) => {
|
|
TopView.show(
|
|
<PopupContainer
|
|
{...props}
|
|
resolve={(v) => {
|
|
resolve(v)
|
|
TopView.hide(TopViewKey)
|
|
}}
|
|
/>,
|
|
TopViewKey
|
|
)
|
|
})
|
|
}
|
|
}
|