import CharacterCount from '@tiptap/extension-character-count' import Placeholder from '@tiptap/extension-placeholder' import clsx from 'clsx' import { type JSX, Show, createEffect, createSignal, on } from 'solid-js' import { createTiptapEditor, useEditorHTML, useEditorIsEmpty } from 'solid-tiptap' import { Button } from '~/components/_shared/Button' import { useLocalize } from '~/context/localize' import { base } from '~/lib/editorExtensions' import { ToolbarControl as Control } from '../EditorToolbar/ToolbarControl' import { Editor } from '@tiptap/core' import { Portal } from 'solid-js/web' import { UploadModalContent } from '~/components/Upload/UploadModalContent' import { renderUploadedImage } from '~/components/Upload/renderUploadedImage' import { Icon } from '~/components/_shared/Icon/Icon' import { Modal } from '~/components/_shared/Modal' import { useUI } from '~/context/ui' import { UploadedFile } from '~/types/upload' import { InsertLinkForm } from '../EditorToolbar/InsertLinkForm' import styles from './MiniEditor.module.scss' interface MiniEditorProps { content?: string onChange?: (content: string) => void onSubmit?: (content: string) => void onCancel?: () => void limit?: number placeholder?: string } export default function MiniEditor(props: MiniEditorProps): JSX.Element { const { t } = useLocalize() const { showModal } = useUI() const [editorElement, setEditorElement] = createSignal() const [counter, setCounter] = createSignal(0) const [showLinkForm, setShowLinkForm] = createSignal(false) const editor = createTiptapEditor(() => ({ element: editorElement()!, extensions: [ ...base, Placeholder.configure({ emptyNodeClass: styles.emptyNode, placeholder: props.placeholder }), CharacterCount.configure({ limit: props.limit }) ], editorProps: { attributes: { class: styles.simplifiedEditorField } }, content: props.content || '', autofocus: 'end' })) const html = useEditorHTML(editor) const isEmpty = useEditorIsEmpty(editor) const toggleLinkForm = () => { setShowLinkForm(!showLinkForm()) // Если форма закрывается, возвращаем фокус редактору !showLinkForm() && editor()?.commands.focus() } const setLink = (url: string) => { url && editor()?.chain().focus().extendMarkRange('link').setLink({ href: url }).run() !url && editor()?.chain().focus().extendMarkRange('link').unsetLink().run() setShowLinkForm(false) } const removeLink = () => { editor()?.chain().focus().unsetLink().run() setShowLinkForm(false) } const handleLinkButtonClick = () => { if (editor()?.isActive('link')) { const previousUrl = editor()?.getAttributes('link').href const url = window.prompt('URL', previousUrl) url && setLink(url) } else { toggleLinkForm() } } createEffect(on(html, (c?: string) => c && props.onChange?.(c))) createEffect(() => { const textLength = editor()?.getText().length || 0 setCounter(textLength) const content = html() content && props.onChange?.(content) }) const handleSubmit = () => { html() && props.onSubmit?.(html() || '') editor()?.commands.clearContent(true) } return (
editor()?.chain().focus().toggleBold().run()} title={t('Bold')} > editor()?.chain().focus().toggleItalic().run()} title={t('Italic')} > Boolean(e?.isActive('link'))} > editor()?.chain().focus().toggleBlockquote().run()} title={t('Add blockquote')} > showModal('simplifiedEditorUploadImage')} title={t('Add image')} >
renderUploadedImage(editor() as Editor, image as UploadedFile)} />
0}> {counter()} / {props.limit || '∞'}
) }