/* eslint-disable react/no-children-prop */ import { ChangeEvent, useCallback, useEffect, useMemo, useRef, useState, } from 'react' import { formattedShortTime } from '../../lib/dateFormatting' import { Box, HStack, SpanBox, VStack } from '../elements/LayoutPrimitives' import MarkdownIt from 'markdown-it' import MdEditor, { Plugins } from 'react-markdown-editor-lite' import 'react-markdown-editor-lite/lib/index.css' import ReactMarkdown from 'react-markdown' import throttle from 'lodash/throttle' import { updateHighlightMutation } from '../../lib/networking/mutations/updateHighlightMutation' import { Highlight } from '../../lib/networking/fragments/highlightFragment' import { Button } from '../elements/Button' import { ModalContent, ModalOverlay, ModalRoot, } from '../elements/ModalPrimitives' import { CloseButton } from '../elements/CloseButton' import { StyledText } from '../elements/StyledText' import remarkGfm from 'remark-gfm' import MDEditorSavePlugin from './MDEditorSavePlugin' import HandleFullScreen from './MDEditorSavePlugin' import Counter from './MDEditorSavePlugin' import { isDarkTheme } from '../../lib/themeUpdater' import { RcEditorStyles } from './RcEditorStyles' const mdParser = new MarkdownIt() MdEditor.use(Plugins.TabInsert, { tabMapValue: 1, // note that 1 means a '\t' instead of ' '. }) console.log() MdEditor.use(Counter) type NoteSectionProps = { targetId: string placeHolder: string mode: 'edit' | 'preview' setEditMode: (set: 'edit' | 'preview') => void text: string | undefined saveText: (text: string, completed: (success: boolean) => void) => void } export function ArticleNotes(props: NoteSectionProps): JSX.Element { const [lastSaved, setLastSaved] = useState(undefined) const saveText = useCallback( (text, updateTime) => { props.saveText(text, (success) => { if (success) { setLastSaved(updateTime) } }) }, [props] ) return ( ) } type HighlightViewNoteProps = { targetId: string placeHolder: string mode: 'edit' | 'preview' highlight: Highlight setEditMode: (set: 'edit' | 'preview') => void text: string | undefined updateHighlight: (highlight: Highlight) => void } export function HighlightViewNote(props: HighlightViewNoteProps): JSX.Element { const [lastSaved, setLastSaved] = useState(undefined) const saveText = useCallback( (text, updateTime) => { ;(async () => { const success = await updateHighlightMutation({ annotation: text, highlightId: props.highlight?.id, }) if (success) { setLastSaved(updateTime) props.highlight.annotation = text props.updateHighlight(props.highlight) } })() }, [props] ) return ( ) } type MarkdownNote = { targetId: string placeHolder: string text: string | undefined fillBackground: boolean | undefined lastSaved: Date | undefined saveText: (text: string, updateTime: Date) => void } export function MarkdownNote(props: MarkdownNote): JSX.Element { const editorRef = useRef(null) const [lastChanged, setLastChanged] = useState(undefined) const [errorSaving, setErrorSaving] = useState(undefined) const isDark = isDarkTheme() const saveRef = useRef(props.saveText) useEffect(() => { saveRef.current = props.saveText }, [props.lastSaved, lastChanged]) const debouncedSave = useMemo< (text: string, updateTime: Date) => void >(() => { const func = (text: string, updateTime: Date) => { saveRef.current?.(text, updateTime) } return throttle(func, 3000) }, []) const handleEditorChange = useCallback( ( data: { text: string; html: string }, event?: ChangeEvent | undefined ) => { if (event) { event.preventDefault() } const updateTime = new Date() setLastChanged(updateTime) localStorage.setItem(`note-${props.targetId}`, JSON.stringify(data)) debouncedSave(data.text, updateTime) }, [props.lastSaved, lastChanged] ) useEffect(() => { const saveMarkdownNote = () => { const md = editorRef.current?.getMdValue() if (md) { props.saveText(md, new Date()) } } document.addEventListener('saveMarkdownNote', saveMarkdownNote) return () => { document.removeEventListener('saveMarkdownNote', saveMarkdownNote) } }, [props, editorRef]) return ( ) => { if (event.code.toLowerCase() === 'escape') { event.preventDefault() event.stopPropagation() } }} > mdParser.render(text)} onChange={handleEditorChange} /> {errorSaving && ( {errorSaving} )} {props.lastSaved !== undefined ? ( <> {lastChanged === props.lastSaved ? 'Saved' : `Last saved ${formattedShortTime( props.lastSaved.toISOString() )}`} ) : null} ) }