138 lines
4.9 KiB
TypeScript
138 lines
4.9 KiB
TypeScript
import { loader, DiffEditor } from '@monaco-editor/react'
|
|
import * as monaco from 'monaco-editor/esm/vs/editor/editor.api'
|
|
import { useEffect, useState } from 'react'
|
|
import { useProject } from '../../context/Project/provider'
|
|
import type { DiffOnMount } from '@monaco-editor/react/'
|
|
import TextEditorButtons from './TextEditorButtons'
|
|
import createDiffEditorInteractions from '../../useCases/createDiffEditorInteractions'
|
|
import TextPreview from './TextPreview'
|
|
import createDebounce from '../../utils/createDebounce'
|
|
import { MagnifyingGlassMinusIcon, MagnifyingGlassPlusIcon } from '@heroicons/react/24/outline'
|
|
|
|
loader.config({
|
|
paths: {
|
|
vs: 'https://cdn.jsdelivr.net/npm/monaco-editor@0.34.0/min/vs',
|
|
},
|
|
})
|
|
|
|
let editorInteractions: ReturnType<typeof createDiffEditorInteractions>
|
|
const editorHeightOffset = 174
|
|
|
|
const fontSizeStep = 1
|
|
const maxFontSize = 36
|
|
|
|
let editorRefernce: monaco.editor.IStandaloneDiffEditor | null
|
|
|
|
const TextEditor = () => {
|
|
const { getSelectedDocument, getProcessedAreasByDocumentId, requestUpdateDocumentUserMarkdown, getUserMarkdownByDocumentId } = useProject()
|
|
const [editorHeight, setEditorHeight] = useState(window.innerHeight - editorHeightOffset)
|
|
const [editorValue, setEditorValue] = useState('')
|
|
const [isEditorReady, setIsEditorReady] = useState(false)
|
|
const [isPreviewOpen, setIsPreviewOpen] = useState(false)
|
|
const [modifiedEditorValue, setModifiedEditorValue] = useState('')
|
|
const [fontSize, setFontSize] = useState(16)
|
|
|
|
const selectedDocument = getSelectedDocument()
|
|
const selectedDocumentId = selectedDocument?.id || ''
|
|
|
|
const handleEditorDidMount: DiffOnMount = async (editor, _) => {
|
|
const currentDocumentId = selectedDocumentId
|
|
|
|
editorInteractions = createDiffEditorInteractions(editor)
|
|
const modifiedEditor = editor.getModifiedEditor()
|
|
const originalEditor = editor.getOriginalEditor()
|
|
|
|
setModifiedEditorValue(originalEditor.getValue())
|
|
|
|
try {
|
|
const initialStoredUserMarkdownResponse = await getUserMarkdownByDocumentId(selectedDocumentId)
|
|
if (initialStoredUserMarkdownResponse.value) {
|
|
setModifiedEditorValue(initialStoredUserMarkdownResponse.value)
|
|
modifiedEditor.getModel()?.setValue(initialStoredUserMarkdownResponse.value)
|
|
}
|
|
} catch (err) {
|
|
console.log(err)
|
|
}
|
|
|
|
modifiedEditor.onDidChangeModelContent(createDebounce(async () => {
|
|
const modifiedMarkdown = modifiedEditor.getValue()
|
|
requestUpdateDocumentUserMarkdown(currentDocumentId, modifiedMarkdown)
|
|
setModifiedEditorValue(modifiedMarkdown)
|
|
}))
|
|
|
|
editorRefernce = editor
|
|
setIsEditorReady(true)
|
|
}
|
|
|
|
useEffect(() => {
|
|
if (!selectedDocumentId) {
|
|
setEditorValue('# No Document Selected')
|
|
return
|
|
}
|
|
|
|
const requestProcessedArea = async () => {
|
|
try {
|
|
const response = await getProcessedAreasByDocumentId(selectedDocumentId)
|
|
if (!response || response.length === 0) return
|
|
const linesofArea = response.map(area => area.lines.map(line => line.fullText + '\n')).join('\n')
|
|
setEditorValue(linesofArea)
|
|
} catch (err) {
|
|
console.error(err)
|
|
setEditorValue('# No Areas on Document were textualized')
|
|
}
|
|
}
|
|
requestProcessedArea()
|
|
}, [selectedDocumentId, getProcessedAreasByDocumentId])
|
|
|
|
useEffect(() => {
|
|
editorRefernce?.updateOptions({ fontSize })
|
|
}, [fontSize, isEditorReady])
|
|
|
|
window.addEventListener('resize', () => {
|
|
setEditorHeight(window.innerHeight - editorHeightOffset)
|
|
})
|
|
|
|
return <div className='m-0 p-0 relative'>
|
|
<span className="flex z-0 rounded-md shadow-sm mb-2 justify-between align-top">
|
|
{isEditorReady
|
|
? <>
|
|
<TextEditorButtons
|
|
isPreviewOpen={isPreviewOpen}
|
|
togglePreview={() => setIsPreviewOpen(!isPreviewOpen)}
|
|
editorInteractions={editorInteractions}
|
|
/>
|
|
<div>
|
|
<div className='flex justify-evenly items-center mt-2 mb-0'>
|
|
<MagnifyingGlassMinusIcon className='w-4 h-4' />
|
|
<input
|
|
id="zoomRange" type="range" min={fontSizeStep} max={maxFontSize} step={fontSizeStep}
|
|
value={fontSize} className="w-[calc(100%-50px)] h-2 bg-indigo-200 rounded-lg appearance-none cursor-pointer p-0"
|
|
onChange={(e) => { setFontSize(e.currentTarget.valueAsNumber) }}
|
|
/>
|
|
<MagnifyingGlassPlusIcon className='w-4 h-4' />
|
|
</div>
|
|
|
|
</div>
|
|
</>
|
|
: ''
|
|
}
|
|
</span>
|
|
<DiffEditor
|
|
original={editorValue}
|
|
modified={modifiedEditorValue}
|
|
language='markdown'
|
|
height={`${editorHeight}px`}
|
|
onMount={handleEditorDidMount}
|
|
options={{
|
|
renderMarginRevertIcon: true,
|
|
enableSplitViewResizing: false,
|
|
glyphMargin: true,
|
|
}}
|
|
/>
|
|
|
|
{isPreviewOpen ? <TextPreview markdown={modifiedEditorValue} height={editorHeight} /> : ''}
|
|
</div>
|
|
}
|
|
|
|
export default TextEditor
|