Feature/paste image from buffer (#251)
Editor: Paste images from clipboard
This commit is contained in:
parent
f85a3e84fe
commit
f593d95358
|
@ -212,7 +212,6 @@
|
||||||
"Nothing here yet": "There's nothing here yet",
|
"Nothing here yet": "There's nothing here yet",
|
||||||
"Nothing is here": "There is nothing here",
|
"Nothing is here": "There is nothing here",
|
||||||
"Notifications": "Notifications",
|
"Notifications": "Notifications",
|
||||||
"Registered since {{date}}": "Registered since {{date}}",
|
|
||||||
"Or continue with social network": "Or continue with social network",
|
"Or continue with social network": "Or continue with social network",
|
||||||
"Or paste a link to an image": "Or paste a link to an image",
|
"Or paste a link to an image": "Or paste a link to an image",
|
||||||
"Ordered list": "Ordered list",
|
"Ordered list": "Ordered list",
|
||||||
|
@ -250,6 +249,7 @@
|
||||||
"Quotes": "Quotes",
|
"Quotes": "Quotes",
|
||||||
"Reason uknown": "Reason unknown",
|
"Reason uknown": "Reason unknown",
|
||||||
"Recent": "Fresh",
|
"Recent": "Fresh",
|
||||||
|
"Registered since {{date}}": "Registered since {{date}}",
|
||||||
"Remove link": "Remove link",
|
"Remove link": "Remove link",
|
||||||
"Reply": "Reply",
|
"Reply": "Reply",
|
||||||
"Report": "Complain",
|
"Report": "Complain",
|
||||||
|
@ -327,6 +327,7 @@
|
||||||
"Upload": "Upload",
|
"Upload": "Upload",
|
||||||
"Upload error": "Upload error",
|
"Upload error": "Upload error",
|
||||||
"Upload video": "Upload video",
|
"Upload video": "Upload video",
|
||||||
|
"Uploading image": "Uploading image",
|
||||||
"Username": "Username",
|
"Username": "Username",
|
||||||
"Userpic": "Userpic",
|
"Userpic": "Userpic",
|
||||||
"Users": "Users",
|
"Users": "Users",
|
||||||
|
|
|
@ -222,7 +222,6 @@
|
||||||
"Nothing here yet": "Здесь пока ничего нет",
|
"Nothing here yet": "Здесь пока ничего нет",
|
||||||
"Nothing is here": "Здесь ничего нет",
|
"Nothing is here": "Здесь ничего нет",
|
||||||
"Notifications": "Уведомления",
|
"Notifications": "Уведомления",
|
||||||
"Registered since {{date}}": "На сайте c {{date}}",
|
|
||||||
"Or continue with social network": "Или войдите через соцсеть",
|
"Or continue with social network": "Или войдите через соцсеть",
|
||||||
"Or paste a link to an image": "Или вставьте ссылку на изображение",
|
"Or paste a link to an image": "Или вставьте ссылку на изображение",
|
||||||
"Ordered list": "Нумерованный список",
|
"Ordered list": "Нумерованный список",
|
||||||
|
@ -264,6 +263,7 @@
|
||||||
"Quotes": "Цитаты",
|
"Quotes": "Цитаты",
|
||||||
"Reason uknown": "Причина неизвестна",
|
"Reason uknown": "Причина неизвестна",
|
||||||
"Recent": "Свежее",
|
"Recent": "Свежее",
|
||||||
|
"Registered since {{date}}": "На сайте c {{date}}",
|
||||||
"Release date...": "Дата выхода...",
|
"Release date...": "Дата выхода...",
|
||||||
"Remove link": "Убрать ссылку",
|
"Remove link": "Убрать ссылку",
|
||||||
"Reply": "Ответить",
|
"Reply": "Ответить",
|
||||||
|
@ -345,6 +345,7 @@
|
||||||
"Upload": "Загрузить",
|
"Upload": "Загрузить",
|
||||||
"Upload error": "Ошибка загрузки",
|
"Upload error": "Ошибка загрузки",
|
||||||
"Upload video": "Загрузить видео",
|
"Upload video": "Загрузить видео",
|
||||||
|
"Uploading image": "Загружаем изображение",
|
||||||
"Username": "Имя пользователя",
|
"Username": "Имя пользователя",
|
||||||
"Userpic": "Аватар",
|
"Userpic": "Аватар",
|
||||||
"Users": "Пользователи",
|
"Users": "Пользователи",
|
||||||
|
|
|
@ -44,6 +44,9 @@ import { EditorFloatingMenu } from './EditorFloatingMenu'
|
||||||
import './Prosemirror.scss'
|
import './Prosemirror.scss'
|
||||||
import { Image } from '@tiptap/extension-image'
|
import { Image } from '@tiptap/extension-image'
|
||||||
import { Footnote } from './extensions/Footnote'
|
import { Footnote } from './extensions/Footnote'
|
||||||
|
import { handleFileUpload } from '../../utils/handleFileUpload'
|
||||||
|
import { imageProxy } from '../../utils/imageProxy'
|
||||||
|
import { useSnackbar } from '../../context/snackbar'
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
shoutId: number
|
shoutId: number
|
||||||
|
@ -51,6 +54,17 @@ type Props = {
|
||||||
onChange: (text: string) => void
|
onChange: (text: string) => void
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const allowedImageTypes = new Set([
|
||||||
|
'image/bmp',
|
||||||
|
'image/gif',
|
||||||
|
'image/jpeg',
|
||||||
|
'image/jpg',
|
||||||
|
'image/png',
|
||||||
|
'image/tiff',
|
||||||
|
'image/webp',
|
||||||
|
'image/x-icon'
|
||||||
|
])
|
||||||
|
|
||||||
const yDocs: Record<string, Doc> = {}
|
const yDocs: Record<string, Doc> = {}
|
||||||
const providers: Record<string, HocuspocusProvider> = {}
|
const providers: Record<string, HocuspocusProvider> = {}
|
||||||
|
|
||||||
|
@ -61,6 +75,10 @@ export const Editor = (props: Props) => {
|
||||||
const [isCommonMarkup, setIsCommonMarkup] = createSignal(false)
|
const [isCommonMarkup, setIsCommonMarkup] = createSignal(false)
|
||||||
const [shouldShowTextBubbleMenu, setShouldShowTextBubbleMenu] = createSignal(false)
|
const [shouldShowTextBubbleMenu, setShouldShowTextBubbleMenu] = createSignal(false)
|
||||||
|
|
||||||
|
const {
|
||||||
|
actions: { showSnackbar }
|
||||||
|
} = useSnackbar()
|
||||||
|
|
||||||
const docName = `shout-${props.shoutId}`
|
const docName = `shout-${props.shoutId}`
|
||||||
|
|
||||||
if (!yDocs[docName]) {
|
if (!yDocs[docName]) {
|
||||||
|
@ -114,12 +132,73 @@ export const Editor = (props: Props) => {
|
||||||
content: 'figcaption image'
|
content: 'figcaption image'
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const handleClipboardPaste = async () => {
|
||||||
|
try {
|
||||||
|
const clipboardItems = await navigator.clipboard.read()
|
||||||
|
|
||||||
|
if (clipboardItems.length === 0) return
|
||||||
|
const [clipboardItem] = clipboardItems
|
||||||
|
const { types } = clipboardItem
|
||||||
|
const imageType = types.find((type) => allowedImageTypes.has(type))
|
||||||
|
|
||||||
|
if (!imageType) return
|
||||||
|
const blob = await clipboardItem.getType(imageType)
|
||||||
|
const extension = imageType.split('/')[1]
|
||||||
|
const file = new File([blob], `clipboardImage.${extension}`)
|
||||||
|
|
||||||
|
const uplFile = {
|
||||||
|
source: blob.toString(),
|
||||||
|
name: file.name,
|
||||||
|
size: file.size,
|
||||||
|
file
|
||||||
|
}
|
||||||
|
|
||||||
|
showSnackbar({ body: t('Uploading image') })
|
||||||
|
const result = await handleFileUpload(uplFile)
|
||||||
|
|
||||||
|
editor()
|
||||||
|
.chain()
|
||||||
|
.focus()
|
||||||
|
.insertContent({
|
||||||
|
type: 'capturedImage',
|
||||||
|
content: [
|
||||||
|
{
|
||||||
|
type: 'figcaption',
|
||||||
|
content: [
|
||||||
|
{
|
||||||
|
type: 'text',
|
||||||
|
text: result.originalFilename
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'image',
|
||||||
|
attrs: {
|
||||||
|
src: imageProxy(result.url)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
})
|
||||||
|
.run()
|
||||||
|
} catch (error) {
|
||||||
|
console.log('!!! Paste image Error:', error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const { initialContent } = props
|
const { initialContent } = props
|
||||||
|
|
||||||
const editor = createTiptapEditor(() => ({
|
const editor = createTiptapEditor(() => ({
|
||||||
element: editorElRef.current,
|
element: editorElRef.current,
|
||||||
editorProps: {
|
editorProps: {
|
||||||
attributes: {
|
attributes: {
|
||||||
class: 'articleEditor'
|
class: 'articleEditor'
|
||||||
|
},
|
||||||
|
transformPastedHTML(html) {
|
||||||
|
return html.replaceAll(/<img.*?>/g, '')
|
||||||
|
},
|
||||||
|
handlePaste: () => {
|
||||||
|
handleClipboardPaste()
|
||||||
|
return false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
extensions: [
|
extensions: [
|
||||||
|
@ -246,6 +325,7 @@ export const Editor = (props: Props) => {
|
||||||
TrailingNode,
|
TrailingNode,
|
||||||
Article
|
Article
|
||||||
],
|
],
|
||||||
|
enablePasteRules: [Link],
|
||||||
content: initialContent ?? null
|
content: initialContent ?? null
|
||||||
}))
|
}))
|
||||||
|
|
||||||
|
|
|
@ -15,7 +15,7 @@ export const renderUploadedImage = (editor: Editor, image: UploadedFile) => {
|
||||||
content: [
|
content: [
|
||||||
{
|
{
|
||||||
type: 'text',
|
type: 'text',
|
||||||
text: image.originalFilename
|
text: image.originalFilename ?? ''
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
|
Loading…
Reference in New Issue
Block a user